%brandDTD;
<!ENTITY % mandelbrotDTD SYSTEM "chrome://mandelbrot/locale/mandelbrot.dtd">
%mandelbrotDTD;
+ <!ENTITY % imgSettingsDTD SYSTEM "chrome://mandelbrot/locale/image-settings.dtd">
+ %imgSettingsDTD;
]>
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
</toolbarbutton>
</toolbar>
</toolbox>
+ <panel id="imgSettingsPanel"
+ level="floating"
+ titlebar="normal"
+ noautohide="true"
+ close="true"
+ onpopupshowing="initImgSettings();"
+ onpopuphiding="saveImgSettings();"
+ label="&imageSettings.title;">
+ <titlebar><label value="&imageSettings.title;"/></titlebar>
+ <groupbox>
+ <caption label="&coord.title;"/>
+ <description value="&coord.real.label;" class="coord-caption"/>
+ <hbox align="center">
+ <label value="&coord.min.label;" control="is_Cr_min"/>
+ <textbox id="is_Cr_min" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Cr', 'scale');"/>
+ <label value="&coord.max.label;" control="is_Cr_max"/>
+ <textbox id="is_Cr_max" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Cr', 'scale');"/>
+ <label value="&coord.scale.label;" control="is_Cr_scale"/>
+ <textbox id="is_Cr_scale" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Cr', 'max');"/>
+ </hbox>
+ <separator class="thin"/>
+ <description value="&coord.imag.label;" class="coord-caption"/>
+ <hbox align="center">
+ <label value="&coord.min.label;" control="is_Ci_min"/>
+ <textbox id="is_Ci_min" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Ci', 'scale');"/>
+ <label value="&coord.max.label;" control="is_Ci_max"/>
+ <textbox id="is_Ci_max" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Ci', 'scale');"/>
+ <label value="&coord.scale.label;" control="is_Ci_scale"/>
+ <textbox id="is_Ci_scale" size="10"
+ onchange="checkISValue(this, 'coord'); recalcCoord('Ci', 'max');"/>
+ </hbox>
+ </groupbox>
+
+ <hbox flex="1">
+ <groupbox>
+ <caption label="&img.size.title;"/>
+ <hbox align="center">
+ <label value="&img.width.label;" control="is_img_width"/>
+ <textbox id="is_img_width" size="4"
+ onchange="checkISValue(this, 'dim'); recalcCoord('Ci', 'scale');"/>
+ </hbox>
+ <hbox align="center">
+ <label value="&img.height.label;" control="is_img_height"/>
+ <textbox id="is_img_height" size="4"
+ onchange="checkISValue(this, 'dim'); recalcCoord('Cr', 'scale');"/>
+ </hbox>
+ </groupbox>
+
+ <groupbox>
+ <caption label="&preview.title;"/>
+ <hbox flex="1" pack="center" align="center">
+ <html:canvas id="is_mbrotPreview" width="50" height="50"></html:canvas>
+ </hbox>
+ <button id="is_previewButton" label="&previewDraw.label;" oncommand="drawPreview();"/>
+ </groupbox>
+
+ <groupbox>
+ <caption label="&options.title;"/>
+ <hbox align="center">
+ <checkbox id="is_syncProp"
+ onclick="checkProportions();"/>
+ <label value="&syncProp.label;" control="is_syncProp"/>
+ </hbox>
+ </groupbox>
+ </hbox>
+ <hbox>
+ <button id="is_closeButton" label="&closeSettings.label;" oncommand="closeImgSettings();"/>
+ <spacer flex="1"/>
+ <button id="is_drawButton" label="&DrawImageButton.label;" oncommand="closeImgSettings(); drawImage();"/>
+ </hbox>
+ </panel>
<hbox flex="1" pack="center" align="center">
<stack>
<html:canvas id="mbrotImage" width="300" height="300"
*
* The Initial Developer of the Original Code is
* Robert Kaiser <kairo@kairo.at>.
- * Portions created by the Initial Developer are Copyright (C) 2008
+ * Portions created by the Initial Developer are Copyright (C) 2008-2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Kaiser <kairo@kairo.at>
+ * prefiks (patch for some speedups)
+ * Boris Zbarsky <bzbarsky@mit.edu> (use imageData for canvas interaction)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
let Ci_max = dimensions[3];
let Ci_scale = Ci_max - Ci_min;
- let pixels = [];
+ let lines = Math.min(canvas.height - line, 8);
+ let imageData = context.createImageData(canvas.width, lines);
+ let pixels = imageData.data;
+ let idx = 0;
for (var img_y = line; img_y < canvas.height && img_y < line+8; img_y++)
for (let img_x = 0; img_x < canvas.width; img_x++) {
let C = new complex(Cr_min + (img_x / canvas.width) * Cr_scale,
Ci_min + (img_y / canvas.height) * Ci_scale);
- pixels.push.apply(pixels, drawPoint(context, img_x, img_y, C, iterMax, algorithm));
+ let colors = drawPoint(context, img_x, img_y, C, iterMax, algorithm);
+ pixels[idx++] = colors[0];
+ pixels[idx++] = colors[1];
+ pixels[idx++] = colors[2];
+ pixels[idx++] = colors[3];
}
- context.putImageData({width: canvas.width, height: pixels.length/4/canvas.width, data: pixels}, 0, line);
+ context.putImageData(imageData, 0, line);
if (img_y < canvas.height)
setTimeout(drawLine, 0, img_y, dimensions, canvas, context, iterMax, algorithm);
}
function imgSettings() {
- window.openDialog("chrome://mandelbrot/content/image-settings.xul");
+ if (document.getElementById("mandelbrotWindow").nodeName == "page")
+ document.getElementById("imgSettingsPanel").showPopup(null, "before_start");
+ else
+ window.openDialog("chrome://mandelbrot/content/image-settings.xul");
}
function updateDebugMenu() {
toOpenWindowByType("global:console", "chrome://global/content/console.xul");
}
+function initImgSettings() {
+ // Get values from prefs.
+ for each (let coord in ["Cr_min", "Cr_max", "Ci_min", "Ci_max"]) {
+ document.getElementById("is_" + coord).value =
+ roundCoord(parseFloat(gPref.getCharPref("mandelbrot.last_image." + coord)));
+ }
+ for each (let dim in ["width", "height"]) {
+ document.getElementById("is_img_" + dim).value =
+ gPref.getIntPref("mandelbrot.image." + dim);
+ }
+ document.getElementById("is_syncProp").checked =
+ gPref.getBoolPref("mandelbrot.syncProportions");
+
+ // Calculate scales.
+ recalcCoord("Cr", "scale");
+ recalcCoord("Ci", "scale");
+
+ // Clear the preview.
+ let canvas = document.getElementById("is_mbrotPreview");
+ let context = canvas.getContext("2d");
+ context.fillStyle = "rgba(255, 255, 255, 127)";
+ context.fillRect(0, 0, canvas.width, canvas.height);
+}
+
+function closeImgSettings() {
+ // Hide popup, which will automatically make a call to save values.
+ document.getElementById("imgSettingsPanel").hidePopup();
+}
+
+function saveImgSettings() {
+ // Get values to prefs.
+ for each (let coord in ["Cr_min", "Cr_max", "Ci_min", "Ci_max"]) {
+ gPref.setCharPref("mandelbrot.last_image." + coord,
+ document.getElementById("is_" + coord).value);
+ }
+ for each (let dim in ["width", "height"]) {
+ gPref.setIntPref("mandelbrot.image." + dim,
+ document.getElementById("is_img_" + dim).value);
+ }
+ gPref.setBoolPref("mandelbrot.syncProportions",
+ document.getElementById("is_syncProp").checked);
+}
+
+function checkISValue(textbox, type) {
+ if (type == "coord") {
+ textbox.value = roundCoord(parseFloat(textbox.value));
+ }
+ else if (type == "dim") {
+ textbox.value = parseInt(textbox.value);
+ }
+}
+
+function drawPreview() {
+ let canvas = document.getElementById("is_mbrotPreview");
+ let context = canvas.getContext("2d");
+
+ if (document.getElementById("is_img_width").value /
+ document.getElementById("is_img_height").value
+ < 80 / 50) {
+ canvas.height = 50;
+ canvas.width = canvas.height *
+ document.getElementById("is_img_width").value /
+ document.getElementById("is_img_height").value;
+ }
+ else {
+ canvas.width = 80;
+ canvas.height = canvas.width *
+ document.getElementById("is_imgHeight").value /
+ document.getElementById("is_imgWidth").value;
+ }
+
+ let Cr_min = parseFloat(document.getElementById("is_Cr_min").value);
+ let Cr_max = parseFloat(document.getElementById("is_Cr_max").value);
+ if ((Cr_min < -2) || (Cr_min > 2) ||
+ (Cr_max < -2) || (Cr_max > 2) || (Cr_min >= Cr_max)) {
+ Cr_min = -2.0; Cr_max = 1.0;
+ }
+
+ let Ci_min = parseFloat(document.getElementById("is_Ci_min").value);
+ let Ci_max = parseFloat(document.getElementById("is_Ci_max").value);
+ if ((Ci_min < -2) || (Ci_min > 2) ||
+ (Ci_max < -2) || (Ci_max > 2) || (Ci_min >= Ci_max)) {
+ Ci_min = -2.0; Ci_max = 1.0;
+ }
+
+ let iterMax = gPref.getIntPref("mandelbrot.iteration_max");
+ let algorithm = gPref.getCharPref("mandelbrot.use_algorithm");
+
+ context.fillStyle = "rgba(255, 255, 255, 127)";
+ context.fillRect(0, 0, canvas.width, canvas.height);
+
+ try {
+ var currentPalette = gPref.getCharPref("mandelbrot.color_palette");
+ }
+ catch(e) {
+ var currentPalette = "";
+ }
+ if (!currentPalette.length) {
+ currentPalette = "kairo";
+ }
+ gColorPalette = getColorPalette(currentPalette);
+
+ drawLine(0, [Cr_min, Cr_max, Ci_min, Ci_max],
+ canvas, context, iterMax, algorithm);
+}
+
+function recalcCoord(coord, target) {
+ let othercoord = (coord == "Ci") ? "Cr" : "Ci";
+ let owndim = (coord == "Ci") ? "height" : "width";
+ let otherdim = (coord == "Ci") ? "width" : "height";
+ if (target == "scale") {
+ var myscale =
+ parseFloat(document.getElementById("is_" + coord + "_max").value) -
+ parseFloat(document.getElementById("is_" + coord + "_min").value);
+ document.getElementById("is_" + coord + "_scale").value = roundCoord(myscale);
+ }
+ else if (target == 'max') {
+ let mymax =
+ parseFloat(document.getElementById("is_" + coord + "_min").value) +
+ parseFloat(document.getElementById("is_" + coord + "_scale").value);
+ document.getElementById("is_" + coord + "_max").value = roundCoord(mymax);
+ var myscale = document.getElementById("is_" + coord + "_scale").value;
+ }
+ if (document.getElementById("is_syncProp").checked) {
+ let otherscale = myscale *
+ document.getElementById("is_img_" + otherdim).value /
+ document.getElementById("is_img_" + owndim).value;
+ document.getElementById("is_" + othercoord + "_scale").value = roundCoord(otherscale);
+ let othermax =
+ parseFloat(document.getElementById("is_" + othercoord + "_min").value) +
+ parseFloat(document.getElementById("is_" + othercoord + "_scale").value);
+ document.getElementById("is_" + othercoord + "_max").value = roundCoord(othermax);
+ }
+}
+
+function checkProportions() {
+ if (!document.getElementById("is_syncProp").checked) {
+ recalcCoord("Cr", "scale");
+ }
+}
+
+function roundCoord(floatval) {
+ // We should round to 10 decimals here or so
+ return parseFloat(floatval.toFixed(10));
+}
+
/***** helper functions from external sources *****/
// function below is based on http://developer.mozilla.org/en/docs/Code_snippets:Canvas