/***********************************************************************/
/*                                                                     */
/*      WebColorPicker :: Add/open a web color panel to the UI         */
/*                                                                     */
/*      [Ver: 1.00]    [Author: Marc Autret]    [Modif: 06/24/09]      */
/*      [Lang: EN]     [Req: InDesign CS4]      [Creat: 06/16/09]      */
/*                                                                     */
/*      Installation:                                                  */
/*                                                                     */
/*      1) Place the current file into Scripts/Scripts Panel/          */
/*                                                                     */
/*      2) Run InDesign                                                */
/*                                                                     */
/*      3) Exec script from Window > Automatisation > Scripts          */
/*         (double-click on the script name)                           */
/*                                                                     */
/*      Bugs & Feedback : marc{at}indiscripts{dot}com                  */
/*                        www.indiscripts.com                          */
/*                                                                     */
/***********************************************************************/

#targetengine session

/*str*/Number.prototype.toHexa = function(/*int*/digits)
//--------------------------------------
// Outputs this number as an hexadecimal string
// containing at least <digits> digits (zero-filled)
{
var r = this.toString(16).toUpperCase();
while (r.length < digits) r = '0'+r;
return(r);
}

String.RE_EXTRA_HEXAS = new RegExp("[^abcdef0123456789]","gi"); /*! bug ID, don't use [^a-f0-9] !*/
String.RE_HEXA_CHAR = new RegExp("^[a-f0-9]$","i");

/*str*/String.prototype.keepHexa = function(/*int*/digits)
//--------------------------------------
// Deletes all non-hexa characters from this string
// and keep just the first <digits> characters:
// Ex: "_azerty-123!" --> "ae12"  ( if <digits> == 4 )
{
return( this.replace(String.RE_EXTRA_HEXAS,"").substr(0,digits) );
}

/*bool*/String.prototype.isHexaChar = function()
//--------------------------------------
// Returns true if this string contains only
// one hexadecimal character; else return false
{
return( this.match(String.RE_HEXA_CHAR) != null );
}


//======================================
function TWebColorSlider(/*TWebColorPicker*/wcp_,/*int*/index_)
//======================================
// Encapsulates each channel slider inside a ScriptUI group
{
// PRIVATE SECTION
//--------------------------------------
var _rgbVals = [0,0,0];	// [0-1] representation of the color channel
var _uiRes;				// UI resource string
var _ui;				// top container (UI group)
var _keydownHandler;	// (fct) event handler: limits inputs to hexa
var _changeBySlider;	// (fct) set the slider's value
var _updateSwatch;		// (fct) updates the slider's swatch

_uiRes = "group {\
			spacing: 2,\
			alignChildren:['right','center'],\
			swatch: Panel {\
				alignment:['left','center'],\
				properties:{ borderStyle:'sunken' },\
				preferredSize:[18,18]\
				},\
			label: StaticText { },\
			slider: Slider {\
				minvalue:0, maxvalue:"+TWebColorSlider.range+"\
				},\
			hexa: EditText {\
				characters:3, justify:'right'\
				}\
			}";

_keydownHandler = function(/*KeyboardEvent*/ ev)
	{
	if ( !ev.keyName.isHexaChar() ) ev.preventDefault();
	}

_changeBySlider = function(/*str*/tmpStr)
		{
		_ui.slider.value = parseInt("0x"+tmpStr);
		_ui.slider.notify ("onChange");
		}
_updateSwatch = function ()
		{
		_rgbVals[index_] = _ui.slider.value / TWebColorSlider.range;
		var uiGfx = _ui.graphics;
		_ui.swatch.graphics.backgroundColor = uiGfx.newBrush (uiGfx.BrushType.SOLID_COLOR, _rgbVals);
		_ui.swatch.graphics.disabledBackgroundColor = _ui.swatch.graphics.backgroundColor;
		wcp_.updateRGBSwatch();
		}

_ui = wcp_.getContainer().add(_uiRes);
with (_ui)
	{
	label.graphics.font = wcp_.getUIFont();
	label.text = TWebColorSlider.colors[index_];
	slider.value = TWebColorSlider.range * wcp_.getRGBVals()[index_];
	slider.onChanging = slider.onChange = function()
		{
		var k = wcp_.getStrictColorK();
		var v = k*Math.round(this.value/k);
		if (this.value != v) this.value = v;
		this.parent.hexa.text = v.toHexa(2);
		if ( this.parent.hexa.active ) {wcp_.autotab(index_);}
		_updateSwatch();
		}
	hexa.graphics.font = wcp_.getUIFont();
	hexa.onChanging = function()
		{
		if ( this.text.length <= 0 ) return;
		var t = this.text.toUpperCase();
		var rp = t.keepHexa(2);
		if ( ( t.length == 1 ) && ( t == rp ) ) return;
		// change!
		_changeBySlider(rp);
		}
	hexa.onChange = function()
		{
		if (this.text.length < 2) _changeBySlider(this.text);
		}
	hexa.addEventListener ("keydown", _keydownHandler);
	}

// PUBLIC SECTION (INTERFACE)
//--------------------------------------
/*int*/ this.getColor = function() {return(_rgbVals[index_]);} /* 0 - 1 */
/*int*/ this.getValue = function() {return(_ui.slider.value);} /* 0 - 255 */
/*str*/ this.getText = function() {return(_ui.hexa.text);}
/*void*/this.update = function() {_ui.slider.notify("onChange");}
/*void*/this.activate = function() {_ui.hexa.active = true;}

// INIT.
//--------------------------------------
this.update();
}
// STATIC
//--------------------------------------
TWebColorSlider.colors = ['R','G','B'];
TWebColorSlider.range = 255;
//--------------------------------------



//======================================
function TWebColorPicker(/*[str]*/title_, /*[bool]*/strictMode_, /*[int[3]]*/rgbVals_, /*[str]*/colorPrefix_)
//======================================
// Encapsulates the Web Color Picker floating panel
// <title_> : title of the panel (opt.)
// <strictMode_> : initial state of the strict mode checkbox (opt.)
// <rgbVals_> : [r,g,b] representation of the initial color, in [0-1] values (opt.)
// <colorPrefix_> : prefix to be inserted in front of the color name (opt.)
{
var _colorPrefix;
var _rgbVals;
var _title;
var _strictMode;
var _fontSize;
var _swatchBorderWidth;
var _font;
var _enableUpdates;
var _initializeDrawingState;
var _drawRGBSwatch;
var _clickRGBSwatch;
var _uiRes;
var _w;
var _sliders;

_colorPrefix = ( typeof(colorPrefix_) != "undefined" ) ? colorPrefix_ : '#';
_rgbVals = ( typeof(rgbVals_) != "undefined" ) ? rgbVals_ : [1,1,1];
_title = ( typeof(title_) != "undefined" ) ? title_ : ' WebColorPicker';
_strictMode = (strictMode_) ? "true" : "false";
_fontSize = 10;
_swatchBorderWidth = 2;
_font = ScriptUI.newFont("palette", _fontSize);
_enableUpdates = false;

_uiRes = "palette {\
		text: '"+_title+"',\
		properties: { closeOnKey:'OSCmnd+W', independent:false},\
		orientation:'row',\
		grSliders: Group {\
			orientation: 'column',\
			alignChildren: ['fill','top'],\
			spacing: 2,\
			cbStrict: Checkbox {\
				text: 'Strict Mode',\
				value: "+_strictMode+"\
				},\
			spaceline: StaticText {\
				text: ' '\
				}\
			},\
		rgbSwatch: Group {\
			btn: Button {\
				preferredSize:[30,30],\
				helpTip:'Click here to add the color in the Swatches panel'\
				}\
			}\
		}";

_initializeDrawingState = function()
	{
	var b = _w.rgbSwatch.btn;
	var gfx = b.graphics;
	var btnW = b.size.width;
	var btnH = b.size.height;
	//	Define the top-left and bottom-right border paths
	var halfBorderW = _swatchBorderWidth / 2;
	gfx.newPath();
	gfx.moveTo (halfBorderW, btnH - halfBorderW);
	gfx.lineTo (halfBorderW, halfBorderW);
	gfx.lineTo (btnW - halfBorderW, halfBorderW);
	b.tlBorderPath = gfx.currentPath;
	gfx.newPath();
	gfx.moveTo (halfBorderW, btnH - halfBorderW);
	gfx.lineTo (btnW - halfBorderW, btnH - halfBorderW);
	gfx.lineTo (btnW - halfBorderW, halfBorderW);
	b.brBorderPath = gfx.currentPath;
	//	Define the border pens: use semi-transparent pens so the background color shows through
	b.highlightPen = gfx.newPen (gfx.PenType.SOLID_COLOR, [1, 1, 1, .4], _swatchBorderWidth);
	b.shadowPen = gfx.newPen (gfx.PenType.SOLID_COLOR, [.25, .25, .25, .4], _swatchBorderWidth);
	}
_drawRGBSwatch = function (drawingStateObj)
	{
	var gfx = this.graphics;
	gfx.strokePath (this.bgPen, this.tlBorderPath);
	gfx.strokePath (this.bgPen, this.brBorderPath);
	if ( this.active && drawingStateObj.leftButtonPressed )
		{
		gfx.strokePath (this.shadowPen, this.tlBorderPath);
		gfx.strokePath (this.highlightPen, this.brBorderPath);
		}
	else
		{
		gfx.strokePath (this.highlightPen, this.tlBorderPath);
		gfx.strokePath (this.shadowPen, this.brBorderPath);
		}
	}
_clickRGBSwatch = function()
	{
	var targetColors = ( app.documents.length > 0 ) ? app.activeDocument.colors : app.colors;
	var cValue = [_sliders.r.getValue(),_sliders.g.getValue(), _sliders.b.getValue()];
	var cName = _colorPrefix + _sliders.r.getText() + _sliders.g.getText() + _sliders.b.getText();
	try	{
		with( targetColors.add() )
			{
			space = ColorSpace.RGB;
			colorValue = cValue;
			name = cName;
			}
		}
	catch(ex)
		{
		alert(ex);
		}
	}

with(_w = new Window(_uiRes))
	{
	grSliders.cbStrict.onClick = function(){_sliders.update();}
	rgbSwatch.btn.onDraw = _drawRGBSwatch;
	rgbSwatch.btn.onClick = _clickRGBSwatch;
	}

// PUBLIC SECTION (INTERFACE)
//--------------------------------------
this.autotab = function(/*int*/ i_) {_sliders.activate((i_+1)%3);}
this.getContainer = function() {return(_w.grSliders);}
this.getUIFont = function() {return(_font);}
this.getRGBVals = function() {return(_rgbVals);}
this.updateRGBSwatch = function()
	{
	if (!_enableUpdates) return;
	_rgbVals[0] = _sliders.r.getColor();
	_rgbVals[1] = _sliders.g.getColor();
	_rgbVals[2] = _sliders.b.getColor();
	var swatchGfx = _w.rgbSwatch.graphics;
	swatchGfx.backgroundColor = swatchGfx.newBrush (swatchGfx.BrushType.SOLID_COLOR, _rgbVals);
	swatchGfx.disabledBackgroundColor = swatchGfx.backgroundColor;
	_w.rgbSwatch.btn.bgPen = swatchGfx.newPen(swatchGfx.PenType.SOLID_COLOR, _rgbVals, _swatchBorderWidth);
	}
this.getStrictColorK = function() {return( (_w.grSliders.cbStrict.value) ? 51 : 1 );}
this.center = function() {_w.center();}
this.show = function() {_w.show();}

// INIT.
//--------------------------------------
_sliders =
	{
	r: new TWebColorSlider(this, 0),
	g: new TWebColorSlider(this, 1),
	b: new TWebColorSlider(this, 2),
	update: function()		{for(var p in this) this[p].update();},
	activate: function(i_)	{this["rgb".substr(i_,1)].activate();}
	}

_enableUpdates = true;
_w.layout.layout(true);
with (_w.rgbSwatch)
	{
	size = btn.size;
	location = [btn.windowBounds.x, btn.windowBounds.y];
	btn.location = [0, 0];
	}
_initializeDrawingState ();
this.updateRGBSwatch();
_sliders.activate(0);
this.center();
}
//--------------------------------------


if ( typeof(wcp) == "undefined" )
	{
	wcp = new TWebColorPicker();
	}
wcp.show();