Revision: 4861
http://sourceforge.net/p/vexi/code/4861
Author: clrg
Date: 2016-06-17 23:35:53 +0000 (Fri, 17 Jun 2016)
Log Message:
-----------
Refactor colorpicker
- clearer, commented code
- refactor to work using a colour "model"
- relabel 'intensity'->'value' as it was HSV logic, not HSI
- add spinners for colour components
- eliminate code fighting (functions calling each other unnecessarily)
- take out pointless threading
Modified Paths:
--------------
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/tool/colorpicker.t
Modified:
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/tool/colorpicker.t
===================================================================
--- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/tool/colorpicker.t
2016-06-17 22:18:09 UTC (rev 4860)
+++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/tool/colorpicker.t
2016-06-17 23:35:53 UTC (rev 4861)
@@ -1,12 +1,14 @@
-<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+<!-- Copyright 2016 - see COPYING for details [LGPL] -->
<vexi xmlns:ui="vexi://ui"
- xmlns:meta="vexi://meta"
- xmlns="org.vexi.tool"
- xmlns:lay="vexi.layout"
+ xmlns:meta="vexi://meta"
+ xmlns:lay="vexi.layout"
xmlns:util="vexi.util"
+ xmlns:theme="vexi.theme"
+ xmlns:role="org.vexi.lib.role"
xmlns:wi="vexi.widget"
- xmlns:sync="vexi.util.sync">
+ xmlns="org.vexi.tool">
+
<meta:doc>
<name>Colorpicker</name>
<desc>A 24-bit colorpicker</desc>
@@ -20,7 +22,7 @@
</todo>
</meta:doc>
- <ui:box>
+ <ui:box align="top">
<ui:box orient="vertical" shrink="true">
<ui:box>
<ui:box fill=":.image.colorpicker" id="colorpicker"
layout="layer" shrink="true">
@@ -38,9 +40,9 @@
<ui:box height="5"/>
<ui:box>
<wi:bevel thickness="2" form="down" width="135" height="30">
- <ui:box fill="#000000" id="colorleft"/>
+ <ui:box fill="#000000" id="colorleft"><ui:box/><ui:box
id="alphaleft" display="false"/></ui:box>
<ui:box fill="#000000" id="targetcolor"/>
- <ui:box fill="#FFFFFF" id="colorright"/>
+ <ui:box fill="#FFFFFF" id="colorright"><ui:box
id="alpharight" display="false"/><ui:box/></ui:box>
</wi:bevel>
<ui:box width="35"/>
</ui:box>
@@ -53,337 +55,470 @@
<ui:box width="30"/>
</ui:box>
</ui:box>
- <ui:box width="20" shrink="true" />
- <ui:box orient="vertical" shrink="true">
+ <ui:box id="trackers" orient="vertical" shrink="true">
<ui:box>
- <ui:box align="left" width="60" vshrink="true" text="Hue:" />
- <wi:slider minvalue="0" maxvalue="1" interval="0.001"
width="100" id="Hue" margin="5" />
- <ui:box align="left" width="55" id="HueValue" />
+ <role:tooltipable align="right" width="60" text="H:"
tooltip="Hue" />
+ <wi:slider id="Hue" part="hue" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="360" interval="1" value="0" />
+ <wi:spin id="HueValue" part="hue" align="left" width="55"
+ minvalue="0" maxvalue="360" interval="1" value="0" />
</ui:box>
<ui:box>
- <ui:box align="left" width="60" vshrink="true"
text="Saturation:" />
- <wi:slider minvalue="0" maxvalue="1" interval="0.001"
width="100" id="Saturation" margin="5" />
- <ui:box align="left" width="55" id="SaturationValue" />
+ <role:tooltipable align="right" width="60" text="S:"
tooltip="Saturation" />
+ <wi:slider id="Satur" part="saturation" minwidth="100"
margin="5 10"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ <wi:spin id="SaturValue" part="saturation" align="left"
width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
</ui:box>
<ui:box>
- <ui:box align="left" width="60" vshrink="true"
text="Intensity:" />
- <wi:slider minvalue="0" maxvalue="1" interval="0.001"
width="100" id="Intensity" margin="5" />
- <ui:box align="left" width="55" id="IntensityValue"/>
+ <role:tooltipable align="right" width="60" text="V:"
tooltip="Value" />
+ <wi:slider id="Value" part="value" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ <wi:spin id="ValueValue" part="value" align="left" width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
</ui:box>
<ui:box>
- <ui:box align="left" width="60" vshrink="true" text="Red:" />
- <wi:slider minvalue="0" maxvalue="255" interval="1"
vshrink="true" width="100" id="Red" margin="5" />
- <ui:box align="left" width="55" id="RedValue" />
+ <role:tooltipable align="right" width="60" text="R:"
tooltip="Red" />
+ <wi:slider id="Red" part="red" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ <wi:spin id="RedValue" part="red" width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
</ui:box>
<ui:box>
- <ui:box align="left" width="60" vshrink="true" text="Green:" />
- <wi:slider minvalue="0" maxvalue="255" interval="1"
vshrink="true" width="100" id="Green" margin="5" />
- <ui:box align="left" width="55" id="GreenValue" />
+ <role:tooltipable align="right" width="60" text="G:"
tooltip="Green" />
+ <wi:slider id="Green" part="green" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ <wi:spin id="GreenValue" part="green" align="left" width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
</ui:box>
<ui:box>
- <ui:box align="left" width="60" vshrink="true" text="Blue:" />
- <wi:slider minvalue="0" maxvalue="255" interval="1"
vshrink="true" width="100" id="Blue" margin="5" />
- <ui:box align="left" width="55" id="BlueValue" />
+ <role:tooltipable align="right" width="60" text="B:"
tooltip="Blue" />
+ <wi:slider id="Blue" part="blue" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="255" interval="1"value="0" />
+ <wi:spin id="BlueValue" part="blue" align="left" width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
</ui:box>
+ <ui:box id="AlphaUI" display="false">
+ <role:tooltipable align="right" width="60" text="A:"
tooltip="Alpha" />
+ <wi:slider id="Alpha" part="alpha" minwidth="100" margin="5 10"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ <wi:spin id="AlphaValue" part="alpha" align="left" width="55"
+ minvalue="0" maxvalue="255" interval="1" value="0" />
+ </ui:box>
</ui:box>
- ////////
- // api
- thisbox.h ++= function() { return $Hue.value; }
- thisbox.h ++= function(v) { $Hue.value = v; cascade = v; }
- thisbox.s ++= function() { return $Saturation.value; }
- thisbox.s ++= function(v) { $Saturation.value = v; cascade = v; }
- thisbox.n ++= function() { return $Intensity.value; }
- thisbox.n ++= function(v) { $Intensity.value = v; cascade = v; }
- thisbox.r ++= function() { return $Red.value; }
- thisbox.r ++= function(v) { $Red.value = v; cascade = v; }
- thisbox.g ++= function() { return $Green.value; }
- thisbox.g ++= function(v) { $Green.value = v; cascade = v; }
- thisbox.b ++= function() { return $Blue.value; }
- thisbox.b ++= function(v) { $Blue.value = v; cascade = v; }
- thisbox.color_left ++= function() { return $colorleft.fill; }
- thisbox.color_left ++= function(v) { $colorleft.fill = v; cascade = v;
}
- thisbox.color_right ++= function() { return $colorright.fill; }
- thisbox.color_right ++= function(v) { $colorright.fill = v; cascade =
v; }
+
- // deliberately shadowing api on box, set internal values without
triggering traps
- var r, g, b;
- var h, s, n;
+ ////////////////
+ // Color Model
- ////////
- // internal functions
- const hexdid = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F" ];
- const toHexColor = function(red, green, blue) {
- // REMARK - should be, but is, necessary
- // why are we receiving negative values?
- if (0>red) red = 0;
- if (0>green) green = 0;
- if (0>blue) blue = 0;
-
- return "#" + hexdid[vexi.math.floor(red/16)] +
hexdid[vexi.math.floor(red%16)]
- + hexdid[vexi.math.floor(green/16)] +
hexdid[vexi.math.floor(green%16)]
- + hexdid[vexi.math.floor(blue/16)] +
hexdid[vexi.math.floor(blue%16)];
+ const model = {
+ hasAlpha:true,
+ alpha:0, red:0, green:0, blue:0, // ARGB all 0-255
+ hue:0, saturation:0, value:0, // H 0-360, SI 0-255
}
-
-
-
- var threadsleeping = false;
- var lock_value = false;
- var lock_text = false;
- thisbox.update = function() {
- var hexval = toHexColor(r,g,b);
- // (not an input so no lock)
- $targetcolor.fill = hexval;
+ const getColorRGB = function() { return static.toHexColor(model); }
+
+ const updateColor = function() {
+ var hexcode = getColorRGB();
+ $targetcolor.fill = hexcode;
+ model.hexcode = hexcode;
+ return hexcode;
+ }
+
+
+
+ ////////////////
+ // Internal
+
+ var lock_HSV = false;
+ var lock_RGB = false;
+
+ const max = vexi.math.max;
+ const min = vexi.math.min;
+ const floor = vexi.math.floor;
+ const round = vexi.math.round;
+ const PI = vexi.math.PI;
+
+ const updateHSV = function() {
+ lock_HSV = true;
- $hexcode.text = hexval;
+ // https://en.wikipedia.org/wiki/HSL_and_HSV#General_approach
+ var R = model.red, G = model.green, B = model.blue;
- // REMARK - variable names possibly innaccurate but the math works
- var distance_from_center = s * $colorpicker.width / 2;
- var angle_from_center = (h + 0.25) * vexi.math.PI * 2;
- $circle.x = distance_from_center *
vexi.math.cos(angle_from_center);
- $circle.y = - (distance_from_center *
vexi.math.sin(angle_from_center));
- $gradient.marker.y = 0 - vexi.math.round(n * $gradient.height);
+ var priMax = max(max(R, G), B); // maximum primary color
+ var priMin = min(min(R, G), B); // minimum primary color
+ var chroma = priMax - priMin;
- // make sure there's a thread running, watching to see if rgb
remain
- // the same for more than one event cycle. If so, update the
gradient.
- if (!threadsleeping) {
- threadsleeping = true;
- vexi.thread = function() {
- while(true) {
- var r_ = r; var g_ = g; var b_ = b;
- vexi.thread.yield();
- if (r == r_ and g == g_ and b == b_) break;
- }
-
- // Recalculate the color from hsn, but this time with a
full intensity.
- var i_ = vexi.math.floor(h*6);
- var f_ = h*6 - i_;
- if (i_ == 0) i_ = 6; // Case 0 is the same as case
6.
- if (i_%2 == 0) f_ = 1 - f_; // If i_ is even
-
- var p_ = vexi.math.min(255, vexi.math.round((1 - s) *
255));
- var q_ = vexi.math.min(255, vexi.math.round((1 - s * f_) *
255));
-
- switch(i_) {
- case 1: $grad_back.fill = toHexColor(q_, 255, p_);
break;
- case 2: $grad_back.fill = toHexColor(p_, 255, q_);
break;
- case 3: $grad_back.fill = toHexColor(p_, q_, 255);
break;
- case 4: $grad_back.fill = toHexColor(q_, p_, 255);
break;
- case 5: $grad_back.fill = toHexColor(255, p_, q_);
break;
- case 6: $grad_back.fill = toHexColor(255, q_, p_);
break;
- default: $grad_back.fill = "#FFFFFF";
vexi.log.error("ERROR: update() i_="+i_+", which is outside range 0-6.");
- }
- threadsleeping = false;
+ // value is the same as the maximum part
+ model.value = priMax;
+
+ if (chroma == 0) {
+ // monochrome/greyscale
+ model.hue = model.saturation = 0;
+ } else {
+ model.saturation = (chroma / model.value) * 255;
+
+ // works out hue as a number between 0-6
+ var hue6 = (R == priMax)
+ ? (((G - B) / chroma) + 6) % 6 :
+ (G == priMax)
+ ? ((B - R) / chroma) + 2
+ //B == priMax
+ : ((R - G) / chroma) + 4;
+
+ // store hue as an angle
+ model.hue = 60 * hue6;
+ }
+ //trace("R:"+R+", G:"+G+", B:"+B+" -> H:"+model.hue+",
S:"+model.saturation+", V:"+model.value);
+ lock_HSV = false;
+ }
+
+
+
+ const updateRGB = function() {
+ lock_RGB = true;
+
+ if (model.saturation == 0) {
+ // no color; greyscale
+ model.red =
+ model.green =
+ model.blue = model.value;
+ } else {
+ // https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
+ var H = model.hue, S = model.saturation, V = model.value;
+
+ var chroma = V * (S/255);
+ var hue6 = H / 60;
+ var middle = chroma * (1 - vexi.math.abs((hue6%2)-1));
+ var priMin = V - chroma;
+ //trace("C:"+chroma+", h6:"+hue6+" -> X:"+middle+" m:"+priMin);
+
+ const setRGB = function(r, g, b) {
+ model.red = r + priMin;
+ model.green = g + priMin;
+ model.blue = b + priMin;
+ //trace("H:"+H+", S:"+S+", V:"+V+" -> R:"+model.red+"
G:"+model.green+" B:"+model.blue);
}
+
+ switch (floor(hue6)) {
+ case 6: // same as 0; circular
+ case 0: setRGB(chroma, middle, 0); break;
+ case 1: setRGB(middle, chroma, 0); break;
+ case 2: setRGB(0, chroma, middle); break;
+ case 3: setRGB(0, middle, chroma); break;
+ case 4: setRGB(middle, 0, chroma); break;
+ case 5: setRGB(chroma, 0, middle); break;
+ default: throw "Something went wrong! H:"+H+", S:"+S+",
V:"+V+" - H/60:"+hue6;
+ }
}
+ $hexcode.text = updateColor();
+ lock_RGB = false;
+ }
+
+
+
+ const updateCircle = function() {
+ const PI = vexi.math.PI;
+ const H = model.hue/360;
+ const S = model.saturation/255;
+ const distance_from_center = S * $colorpicker.width / 2;
+ const angle_from_center = (H + 0.25) * PI * 2;
- $Red.value = r;
- $Green.value = g;
- $Blue.value = b;
+ $circle.x = distance_from_center *
vexi.math.cos(angle_from_center);
+ $circle.y = - (distance_from_center *
vexi.math.sin(angle_from_center));
+ }
- $Hue.value = h;
- $Saturation.value = s;
- $Intensity.value = n;
+ $colorpicker.width ++= function(v) {
+ cascade = v;
+ updateCircle();
+ }
+
+
+
+ const updateGradient = function() {
+ const H = model.hue, S = model.saturation, V = model.value;
- $RedValue.text = r;
- $GreenValue.text = g;
- $BlueValue.text = b;
+ // set marker arrows
+ $gradient.marker.y = 0 - round((V/255) * $gradient.height);
- // REMARK - v>=0.001 check necessary to prevent really small
numbers (e.g. 4.513E4) appearing as >1
- $HueValue.text = (""+(h>=0.001?h:0)).substring(0,5);
- $SaturationValue.text = (""+s).substring(0,5);
- $IntensityValue.text = (""+n).substring(0,5);
- }
+ // Recalculate the color from HSV, but this time with a full value
+ const hue6 = H/60;
+ const hueN = floor(hue6);
+ // Invert hueD if hueN is even
+ const hueD = hueN%2 ? hue6-hueN : 1-(hue6-hueN);
- hsn_to_rgb = function() {
- if(lock_value) return;
- lock_value = true;
- try{
- if (s == 0) {
- // this line doesn't work with traps set on the
variables??
- // r = g = b = n * 255;
- var x = n * 255;
- b = x;
- r = x;
- g = x;
- } else {
- var i_ = vexi.math.floor(h*6);
- var f_ = h*6 - i_;
-
- if (i_%2 == 0) f_ = 1 - f_; // If i_ is even
-
- var v_ = vexi.math.round(n * 255);
- var p_ = vexi.math.round(n * (1 - s) * 255);
- var q_ = vexi.math.round(n * (1 - s * f_) * 255);
- if (i_ == 0) i_ = 6; // Case 0 is the same as case 6.
-
- switch (i_) {
- case 1: r = q_; g = v_; b = p_; break;
- case 2: r = p_; g = v_; b = q_; break;
- case 3: r = p_; g = q_; b = v_; break;
- case 4: r = q_; g = p_; b = v_; break;
- case 5: r = v_; g = p_; b = q_; break;
- case 6: r = v_; g = q_; b = p_; break;
- default: vexi.log.error("ERROR: i_="+i_+", which is
outside range 0-6.");
- }
- }
- update();
- }finally{
- lock_value = false;
+ // Secondary RGB component
+ const sec = min(255, round(255 - S));
+ // Tertiary RGB component
+ const ter = min(255, round(255 - S * hueD));
+
+ //trace("Gradient for H:"+H+", S:"+S);
+ //trace("h6:"+hue6+" hN:"+hueN+" hD:"+hueD+" -> sec:"+sec+"
ter:"+ter);
+
+ const getGradientHex = function(r, g, b) {
+ return static.toHexColor({red:r, green:g, blue:b});
}
- }
-
- rgb_to_hsn = function() {
- if(lock_value) return;
- lock_value = true;
- try{
- // both v_ and x_ are in range 0-1.
- var max = vexi.math.max(vexi.math.max(r, g), b);
- var min = vexi.math.min(vexi.math.min(r, g), b);
- var diff = (max - min)/255;
- var v_ = max/255;
- if (max == min) {
- h = s = 0; n = v_;
- } else {
- // FIXME: have taken an algorithm designed to spit out h
- // in range 0-6 and added /6 on the end; remodel
algorithm.
- var f_ = ( (r == min) ? g - b : ((g == min) ? b - r : r
- g) )/255; // f now in range 0-1.
- var i_ = (r == min) ? 3 : ((g == min) ? 5 : 1);
-
- h = (i_ - f_ / diff) / 6;
- s = (max - min) / max;
- n = v_;
- }
- update();
- }finally{
- lock_value = false;
+
+ switch(hueN) {
+ case 1: $grad_back.fill = getGradientHex(ter, 255, sec);
break;
+ case 2: $grad_back.fill = getGradientHex(sec, 255, ter);
break;
+ case 3: $grad_back.fill = getGradientHex(sec, ter, 255);
break;
+ case 4: $grad_back.fill = getGradientHex(ter, sec, 255);
break;
+ case 5: $grad_back.fill = getGradientHex(255, sec, ter);
break;
+ case 0: // hue[N]==0 and hue==360 (hueN==6) are the same thing
+ case 6: $grad_back.fill = getGradientHex(255, ter, sec);
break;
+ default: $grad_back.fill = "#FFFFFF";
+ vexi.log.error("ERROR: updateGradient()
hueN="+hueN+"; only 0-6 valid");
+ vexi.log.error("ERROR: updateGradient() hue="+H+",
saturation="+S);
}
}
-
- // HSN value updates
- const hsnTrap = function(v){
- cascade = v;
- if(lock_value) return;
-
- h = $Hue.value;
- s = $Saturation.value;
- n = $Intensity.value;
- hsn_to_rgb();
+
+
+ ////////////////
+ // Model / GUI interactions
+
+ const passive = { };
+ for (var k in model) passive[k] = true;
+
+ const sliders = {
+ alpha:$Alpha, red:$Red, green:$Green, blue:$Blue,
+ hue:$Hue, saturation:$Satur, value:$Value
};
+ const spinners = {
+ alpha:$AlphaValue, red:$RedValue, green:$GreenValue,
blue:$BlueValue,
+ hue:$HueValue, saturation:$SaturValue, value:$ValueValue
+ }
- const rgbTrap = function(v){
+ const modelHSV_put = function(v) {
+ const vR = round(v);
+ cascade = vR;
+
+ if (sliders[trapname].value != vR)
+ sliders[trapname].value = vR;
+ if (spinners[trapname].value != vR)
+ spinners[trapname].value = vR;
+ if (lock_HSV) return;
+
+ updateRGB();
+ updateCircle();
+ updateGradient();
+ }
+
+ model.hue ++= modelHSV_put;
+ model.saturation ++= modelHSV_put;
+ model.value ++= modelHSV_put;
+
+ const modelRGB_put = function(v) {
+ const vR = round(v);
+ cascade = vR;
+
+ if (sliders[trapname].value != vR)
+ sliders[trapname].value = vR;
+ if (spinners[trapname].value != vR)
+ spinners[trapname].value = vR;
+ if (lock_RGB) return;
+
+ updateHSV();
+ updateCircle();
+ updateGradient();
+ }
+
+ model.red ++= modelRGB_put;
+ model.green ++= modelRGB_put;
+ model.blue ++= modelRGB_put;
+
+
+ // slider/spin value updates - only update model if it differs
+ const widgetValuePut = function(v) {
+ if (0>v or v>trapee.maxvalue)
+ throw "Illegal "+trapee.part+" value: "+v;
+
cascade = v;
- if(lock_value) return;
-
- // WORKAROUND slider bug, reading less than 0 even when
- // never set as such ...
- r = vexi.math.max(0,$Red.value);
- g = vexi.math.max(0,$Green.value);
- b = vexi.math.max(0,$Blue.value);
- rgb_to_hsn();
+
+ const part = trapee.part;
+ if (v == model[part]) return;
+ model[part] = v;
};
-
- $Hue.value ++= hsnTrap;
- $Saturation.value ++= hsnTrap;
- $Intensity.value ++= hsnTrap;
- // RGB value updates
- $Red.value ++= rgbTrap;
- $Green.value ++= rgbTrap;
- $Blue.value ++= rgbTrap;
+ for (var k,slider in sliders)
+ slider.value ++= widgetValuePut;
+ for (var k,spinner in spinners)
+ spinner.value ++= widgetValuePut;
- $hexcode.text ++= function(v){
- if(lock_text) return;
- lock_text = true;
- try{
+
+
+ $hexcode.text ++= function(v) {
+ cascade = v;
- cascade = v;
- if(lock_value) return;
- if(v==null){
- v = "#000000";
- }
- if(v.length and v.charAt(0)!='#'){
- v = "#"+v;
- }
- while(7>v.length){
- v = v + "0";
- }
-
- var rgb = vexi.string.parseInt(v.substring(1), 16);
- r = (rgb>>16)%256;
- g = (rgb>>8)%256;
- b = rgb%256;
- rgb_to_hsn();
- }finally{
- lock_text = false;
- }
- };
+ // Verify
+ if (v==null) {
+ v = useAlpha ? "#ff000000" : "#000000";
+ }
+
+ if (typeof v != "string")
+ throw "Color value must be a string but '"+(typeof v)+"' was
put";
+ if (v.length and v.charAt(0)!='#')
+ throw "Color must be a hex formatted string";
+
+ switch (v.length) {
+ case 4: // #RGB
+ case 5: // #ARGB
+ case 7: // #RRGGBB
+ case 9: // #AARRGGBB
+ break;
+ default:
+ throw "String '"+v+"' is not a valid color";
+ }
+
+ if (lock_RGB) return;
+ try {
+ lock_RGB = true;
+ const fromHex = function(s) { return vexi.string.parseInt(s,
16); }
+ var offset = 0;
+
+ switch (v.length) {
+ case 4:
+ model.alpha = 255;
+ model.red = fromHex(v.substring(1,2)) * 16;
+ model.green = fromHex(v.substring(2,3)) * 16;
+ model.blue = fromHex(v.substring(3,4)) * 16;
+ break;
+ case 5:
+ model.alpha = fromHex(v.substring(1,2)) * 16;
+ model.red = fromHex(v.substring(2,3)) * 16;
+ model.green = fromHex(v.substring(3,4)) * 16;
+ model.blue = fromHex(v.substring(4,5)) * 16;
+ break;
+ case 7:
+ model.alpha = 255;
+ model.red = fromHex(v.substring(1,3));
+ model.green = fromHex(v.substring(3,5));
+ model.blue = fromHex(v.substring(5,7));
+ break;
+ case 9:
+ model.alpha = fromHex(v.substring(1,3));
+ model.red = fromHex(v.substring(3,5));
+ model.green = fromHex(v.substring(5,7));
+ model.blue = fromHex(v.substring(7,9));
+ break;
+ }
+
+ updateHSV();
+ updateGradient();
+ updateCircle();
+ updateColor();
+ } finally {
+ lock_RGB = false;
+ }
+ }
+
+ ////////////////
+ // Gradient Bar
-
- ////////
- // gradient bar
var eventObj;
- const gradient_move = function(v) {
+ const gradientPick = function(v) {
var pos = $gradient.mouse.y;
- if (pos > $gradient.height) {pos = $gradient.height;}
- else if (0 > pos) {pos = 0;}
- n = 1 - (pos/$gradient.height);
- hsn_to_rgb();
+ if (pos > $gradient.height)
+ pos = $gradient.height;
+ else if (0 > pos) pos = 0;
+ model.value = 255 - (255 * (pos/$gradient.height));
+ updateRGB();
return;
}
-
$gradient.Press1 ++= function(v) {
- gradient_move(v);
+ gradientPick();
eventObj = surface.event;
- eventObj.addMoveTrap(gradient_move);
+ eventObj.addMoveTrap(gradientPick);
eventObj.Release1 ++= function(v) {
eventObj._Release1 --= callee;
- eventObj.delMoveTrap(gradient_move);
+ eventObj.delMoveTrap(gradientPick);
return;
}
return;
}
-
- ////////
- // colour circle
- const color_move = function(v) {
- var cx = $colorpicker.mouse.x - $colorpicker.width / 2;
- var cy = -1 * ($colorpicker.mouse.y - $colorpicker.height / 2);
- h = (vexi.math.atan(cy / cx) / 2 + vexi.math.PI / 4) /
vexi.math.PI + (cx > 0 ? 0.5 : 0);
- s = vexi.math.min(1.0, vexi.math.sqrt(cy * cy + cx * cx) /
($colorpicker.width / 2));
- hsn_to_rgb();
+
+
+
+ ////////////////
+ // Colour Circle
+
+ const colorPick = function(v) {
+ lock_HSV = true;
+
+ const PI = vexi.math.PI;
+ const cx = $colorpicker.mouse.x - $colorpicker.width / 2;
+ const cy = -1 * ($colorpicker.mouse.y - $colorpicker.height / 2);
+ model.hue = 360 * (vexi.math.atan(cy / cx) / 2 + PI / 4) / PI +
(cx > 0 ? 180 : 0);
+
+ const SX = vexi.math.sqrt(cy * cy + cx * cx) / ($colorpicker.width
/ 2);
+ model.saturation = min(255, SX*255);
+
+ updateCircle();
+ updateGradient();
+ updateRGB();
+ lock_HSV = false;
return;
}
$colorpicker.Press1 ++= function(v) {
- color_move(v);
+ colorPick();
eventObj = surface.event;
- eventObj.addMoveTrap(color_move);
+ eventObj.addMoveTrap(colorPick);
eventObj.Release1 ++= function(v) {
eventObj._Release1 --= callee;
- eventObj.delMoveTrap(color_move);
+ eventObj.delMoveTrap(colorPick);
return;
}
return;
- }
+ }
- $Blue.value ++= function(v){
+
+
+ ////////////////
+ // Widget API
+
+ thisbox.compareLeft ++= function(v) { $alphaleft.fill =
$colorleft.fill = v; cascade = v; }
+ thisbox.compareRight ++= function(v) { $alpharight.fill =
$colorright.fill = v; cascade = v; }
+
+ thisbox.alphaEnabled ++= function(v) {
cascade = v;
- if(0>v) trace(new vexi.js.Exception(v));
- };
+ $Alpha.enabled = $AlphaValue.enabled = v;
+ $AlphaLeft.display = $AlphaRight.display = v;
+ }
+ // external value
+ util.redirect..addRedirect(thisbox, $hexcode, "text", "text");
+ util.sync..sync(thisbox, thisbox, "value", "text");
- // external value
- sync..sync(thisbox, $hexcode, "value", "text");
// initialize values
- value = "#7F7F7F";
+ text = arguments[0] ?: "#FFFFFFFF";
</ui:box>
+
+ const hexdid = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
"B", "C", "D", "E", "F" ];
+ const toHex = function(num) { return hexdid[vexi.math.floor(num/16)] +
hexdid[vexi.math.floor(num%16)]; }
+
+ static.toHexColor = function(model, withAlpha) {
+ const R = model.red, G = model.green, B = model.blue;
+
+ // REMARK - should be, but is, necessary
+ // why are we receiving negative values?
+ if (0>R) throw "red! "+R;
+ if (0>G) throw "green! "+G;
+ if (0>B) throw "blue! "+B;
+
+ var hex = "#";
+ if (withAlpha and model.hasAlpha)
+ hex += toHex(model.alpha);
+ return hex + toHex(R) + toHex(G) + toHex(B);
+ }
+
</vexi>
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are
consuming the most bandwidth. Provides multi-vendor support for NetFlow,
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports. http://sdm.link/zohomanageengine
_______________________________________________
Vexi-svn mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/vexi-svn