convert image settings to a panel in the in-tab UI case, incorporate imageData work...
authorRobert Kaiser <kairo@kairo.at>
Sun, 16 Jan 2011 16:10:22 +0000 (17:10 +0100)
committerRobert Kaiser <kairo@kairo.at>
Sun, 16 Jan 2011 16:10:22 +0000 (17:10 +0100)
xulapp/chrome/mandelbrot/content/mandelbrot-tab.xul
xulapp/chrome/mandelbrot/content/mandelbrot.js
xulapp/chrome/mandelbrot/locales/en-US/image-settings.dtd
xulapp/chrome/mandelbrot/skin/classic/mandelbrot.css

index a802ff5d1f051d6eef259ed1c4d41cbac8ba735a..1f15fb3f4c93f3bd065c199e4a869746165f1833 100644 (file)
@@ -47,6 +47,8 @@
   %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"
index 72154191907dd4592a2f881ac53280fcb87f9d85..95c0e1401eace09be8514a7cb85e4b837421fca5 100644 (file)
  *
  * 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
@@ -188,14 +190,21 @@ function drawLine(line, dimensions, canvas, context, iterMax, algorithm) {
   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);
@@ -674,7 +683,10 @@ function setPalette(aPaletteID) {
 }
 
 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() {
@@ -744,6 +756,152 @@ function errorConsole() {
   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
index 2433e060e24da624357bdff48f67725b61f8a82d..521b3b8357402765cb3539753fa67416a146ef08 100644 (file)
@@ -37,6 +37,7 @@
 
 <!ENTITY imageSettings.title   "Image Settings">
 <!ENTITY DrawImageButton.label "Draw Image">
+<!ENTITY closeSettings.label   "Close">
 
 <!ENTITY coord.title           "Coordinates">
 <!ENTITY coord.real.label      "Real">
index 07a31bb22c6d50e12d40e032888ab02baa1c0a73..a287ac5f95bc407eaed46607d1de192013f87ec8 100644 (file)
@@ -49,3 +49,16 @@ html|link {
 #tool-mandelbrot {
   list-style-image: url("chrome://mandelbrot/skin/mandelbrotIcon32.png");
 }
+
+titlebar {
+  background-color: ActiveCaption;
+  color: CaptionText;
+  font: caption;
+  font-weight: bold;
+  border-bottom: 1px solid ActiveBorder;
+}
+
+.coord-caption {
+  font-style: italic;
+  font-weight: bold;
+}