1/**
2 * $Id: mxAndroid.js,v 1.5 2014/01/21 12:32:06 mate Exp $
3 * Copyright (c) 2006-2013, JGraph Ltd
4 */
5
6//**********************************************************************************************************************************************************
7//Horizontal Tab Bar (LEGACY)
8//**********************************************************************************************************************************************************
9/**
10 * Extends mxShape.
11 */
12function mxShapeAndroidTabBar(bounds, fill, stroke, strokewidth)
13{
14	mxShape.call(this);
15	this.bounds = bounds;
16	this.fill = fill;
17	this.stroke = stroke;
18	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
19};
20
21/**
22 * Extends mxShape.
23 */
24mxUtils.extend(mxShapeAndroidTabBar, mxShape);
25
26mxShapeAndroidTabBar.prototype.cst = {
27		MAIN_TEXT : 'mainText',
28		SHAPE_TAB_BAR : 'mxgraph.android.tabBar',
29		TEXT_COLOR : 'textColor',
30		TEXT_COLOR2 : 'textColor2',
31		STROKE_COLOR2 : 'strokeColor2',
32		FILL_COLOR2 : 'fillColor2',
33		SELECTED : '+',			//must be 1 char
34		TEXT_SIZE : 'textSize'
35};
36
37/**
38 * Function: paintVertexShape
39 *
40 * Paints the vertex shape.
41 */
42mxShapeAndroidTabBar.prototype.paintVertexShape = function(c, x, y, w, h)
43{
44	var textStrings = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.MAIN_TEXT, '+Tab 1, Tab 2, Tab 3').toString().split(',');
45	var fontColor = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.TEXT_COLOR, 'none');
46	var selectedFontColor = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.TEXT_COLOR2, 'none');
47	var fontSize = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.TEXT_SIZE, '17').toString();
48	var frameColor = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, 'none');
49	var separatorColor = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.STROKE_COLOR2, 'none');
50	var bgColor = mxUtils.getValue(this.style, mxConstants.STYLE_FILLCOLOR, 'none');
51	var selectedFillColor = mxUtils.getValue(this.style, mxShapeAndroidTabBar.prototype.cst.FILL_COLOR2, 'none');
52	var buttonNum = textStrings.length;
53	var buttonWidths = new Array(buttonNum);
54	var buttonTotalWidth = 0;
55	var selectedButton = -1;
56	var labelOffset = 5;
57
58	for (var i = 0; i < buttonNum; i++)
59	{
60		var buttonText = textStrings[i];
61
62		if(buttonText.charAt(0) === mxShapeAndroidTabBar.prototype.cst.SELECTED)
63		{
64			buttonText = textStrings[i].substring(1);
65			selectedButton = i;
66		}
67
68		buttonWidths[i] = mxUtils.getSizeForString(buttonText, fontSize, mxConstants.DEFAULT_FONTFAMILY).width;
69
70		buttonTotalWidth += buttonWidths[i];
71	}
72
73	var trueH = Math.max(h, fontSize * 1.5, 7);
74	var minW = 2 * labelOffset * buttonNum + buttonTotalWidth;
75	var trueW = Math.max(w, minW);
76
77	c.translate(x, y);
78	this.background(c, trueW, trueH, buttonNum, buttonWidths, labelOffset, minW, frameColor, separatorColor, bgColor, selectedFillColor, selectedButton);
79	c.setShadow(false);
80
81	c.setFontStyle(mxConstants.FONT_BOLD);
82	var currWidth = 0;
83
84	for (var i = 0; i < buttonNum; i++)
85	{
86		if (i === selectedButton)
87		{
88			c.setFontColor(selectedFontColor);
89		}
90		else
91		{
92			c.setFontColor(fontColor);
93		}
94
95		currWidth = currWidth + labelOffset;
96		this.buttonText(c, currWidth, trueH, textStrings[i], buttonWidths[i], fontSize, minW, trueW);
97		currWidth = currWidth + buttonWidths[i] + labelOffset;
98	}
99};
100
101mxShapeAndroidTabBar.prototype.background = function(c, w, h, buttonNum, buttonWidths, labelOffset, minW, frameColor, separatorColor, bgColor, selectedFillColor, selectedButton)
102{
103	c.begin();
104
105	//draw the frame
106	c.setStrokeColor(frameColor);
107	c.setFillColor(bgColor);
108	c.rect(0, 0, w, h);
109	c.fillAndStroke();
110
111	//draw the button separators
112	c.setStrokeColor(separatorColor);
113	c.begin();
114	for (var i = 1; i < buttonNum; i++)
115	{
116		if (i !== selectedButton && i !== (selectedButton + 1))
117		{
118			var currWidth = 0;
119
120			for (var j = 0; j < i; j++)
121			{
122				currWidth += buttonWidths[j] + 2 * labelOffset;
123			}
124
125			currWidth = currWidth * w / minW;
126			c.moveTo(currWidth, h * 0.2);
127			c.lineTo(currWidth, h * 0.8);
128		}
129	}
130
131	c.stroke();
132
133	//draw the selected button
134	var buttonLeft = 0;
135	c.setFillColor(selectedFillColor);
136
137	for (var i = 0; i < selectedButton; i++)
138	{
139		buttonLeft += buttonWidths[i] + 2 * labelOffset;
140	}
141
142	buttonLeft = buttonLeft * w / minW;
143	var buttonRight = (buttonWidths[selectedButton] + 2 * labelOffset) * w / minW;
144	buttonRight += buttonLeft;
145
146	c.rect(buttonLeft, 0, buttonRight - buttonLeft, h);
147	c.fill();
148
149	c.setAlpha(1);
150	c.setFillColor('#33b5e5');
151	c.rect(buttonLeft, h * 0.9, buttonRight - buttonLeft, h * 0.1);
152	c.fill();
153};
154
155mxShapeAndroidTabBar.prototype.buttonText = function(c, w, h, textString, buttonWidth, fontSize, minW, trueW)
156{
157	if(textString.charAt(0) === mxShapeAndroidTabBar.prototype.cst.SELECTED)
158	{
159		textString = textString.substring(1);
160	}
161
162	c.begin();
163	c.setFontSize(fontSize);
164	c.text((w + buttonWidth * 0.5) * trueW / minW, h * 0.5, 0, 0, textString, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
165};
166
167mxCellRenderer.registerShape(mxShapeAndroidTabBar.prototype.cst.SHAPE_TAB_BAR, mxShapeAndroidTabBar);
168
169//**********************************************************************************************************************************************************
170//Android Phone Vertical
171//**********************************************************************************************************************************************************
172/**
173* Extends mxShape.
174*/
175function mxShapeAndroidPhone(bounds, fill, stroke, strokewidth)
176{
177	mxShape.call(this);
178	this.bounds = bounds;
179	this.fill = fill;
180	this.stroke = stroke;
181	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
182};
183
184/**
185* Extends mxShape.
186*/
187mxUtils.extend(mxShapeAndroidPhone, mxShape);
188
189/**
190* Function: paintVertexShape
191*
192* Paints the vertex shape.
193*/
194mxShapeAndroidPhone.prototype.paintVertexShape = function(c, x, y, w, h)
195{
196	c.translate(x, y);
197	var rSize = 25;
198
199	c.roundrect(0, 0, w, h, rSize, rSize);
200	c.fillAndStroke();
201
202	c.setShadow(false);
203
204	this.foreground(c, x, y, w, h, rSize);
205};
206
207mxShapeAndroidPhone.prototype.foreground = function(c, x, y, w, h, rSize)
208{
209	c.rect(w * 0.0625, h * 0.15, w * 0.875, h * 0.7);
210	c.stroke();
211
212	c.ellipse(w * 0.4875, h * 0.04125, w * 0.025, h * 0.0125);
213	c.stroke();
214
215	c.roundrect(w * 0.375, h * 0.075, w * 0.25, h * 0.01875, w * 0.02, h * 0.01);
216	c.stroke();
217	c.ellipse(w * 0.4, h * 0.875, w * 0.2, h * 0.1);
218	c.stroke();
219	c.roundrect(w * 0.4575, h * 0.905, w * 0.085, h * 0.04375, h * 0.00625, h * 0.00625);
220	c.stroke();
221};
222
223mxCellRenderer.registerShape('mxgraph.android.phone', mxShapeAndroidPhone);
224
225//**********************************************************************************************************************************************************
226//Android Status Bar
227//**********************************************************************************************************************************************************
228/**
229* Extends mxShape.
230*/
231function mxShapeAndroidStatusBar(bounds, fill, stroke, strokewidth)
232{
233	mxShape.call(this);
234	this.bounds = bounds;
235	this.fill = fill;
236	this.stroke = stroke;
237	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
238};
239
240/**
241* Extends mxShape.
242*/
243mxUtils.extend(mxShapeAndroidStatusBar, mxShape);
244
245/**
246* Function: paintVertexShape
247*
248* Paints the vertex shape.
249*/
250mxShapeAndroidStatusBar.prototype.paintVertexShape = function(c, x, y, w, h)
251{
252	c.translate(x, y);
253	this.background(c, x, y, w, h);
254	c.setShadow(false);
255	this.foreground(c, x, y, w, h);
256};
257
258mxShapeAndroidStatusBar.prototype.background = function(c, x, y, w, h)
259{
260	c.rect(0, 0, w, h);
261	c.fill();
262};
263
264mxShapeAndroidStatusBar.prototype.foreground = function(c, x, y, w, h)
265{
266	c.rect(0, 0, w, h);
267	c.fill();
268
269	c.setFontColor(mxUtils.getValue(this.style, mxConstants.STYLE_FONTCOLOR, '#222222'));
270	c.setFontSize(mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, '5'));
271	c.text(w - 30, h * 0.5 + 1, 0, 0, '12:00', mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
272
273	c.setFillColor('#444444');
274	c.begin();
275	c.moveTo(w - 37, h * 0.5 + 6);
276	c.lineTo(w - 37, h * 0.5 - 5);
277	c.lineTo(w - 36, h * 0.5 - 5);
278	c.lineTo(w - 36, h * 0.5 - 6);
279	c.lineTo(w - 32, h * 0.5 - 6);
280	c.lineTo(w - 32, h * 0.5 - 5);
281	c.lineTo(w - 31, h * 0.5 - 5);
282	c.lineTo(w - 31, h * 0.5 + 6);
283	c.close();
284	c.fill();
285
286	c.setFillColor(mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, 'none'));
287	c.ellipse(w - 56, h * 0.5 + 2, 2, 2);
288	c.fillAndStroke();
289
290	c.setStrokeWidth(2);
291	c.begin();
292	c.moveTo(w - 52, h * 0.5 + 1);
293	c.arcTo(3.5, 3.5, 0, 0, 0, w - 58, h * 0.5 + 1);
294	c.stroke();
295
296	c.begin();
297	c.moveTo(w - 50, h * 0.5 - 1);
298	c.arcTo(6, 6, 0, 0, 0, w - 60, h * 0.5 - 1);
299	c.stroke();
300
301	c.setStrokeWidth(1);
302
303	c.rect(w - 51, h * 0.5 + 5, 2, 1);
304	c.fill();
305
306	c.rect(w - 48, h * 0.5 + 2, 2, 4);
307	c.fill();
308
309	c.rect(w - 45, h * 0.5 - 1, 2, 7);
310	c.fill();
311
312	c.rect(w - 42, h * 0.5 - 4, 2, 10);
313	c.fill();
314
315	c.rect(w - 37, h * 0.5  - 2, 6, 8);
316	c.fill();
317
318};
319
320mxCellRenderer.registerShape('mxgraph.android.statusBar', mxShapeAndroidStatusBar);
321
322//**********************************************************************************************************************************************************
323//Checkbox Button Group
324//**********************************************************************************************************************************************************
325/**
326* Extends mxShape.
327*/
328function mxShapeAndroidCheckboxGroup(bounds, fill, stroke, strokewidth)
329{
330	mxShape.call(this);
331	this.bounds = bounds;
332	this.fill = fill;
333	this.stroke = stroke;
334	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
335};
336
337/**
338* Extends mxShape.
339*/
340mxUtils.extend(mxShapeAndroidCheckboxGroup, mxShape);
341
342mxShapeAndroidCheckboxGroup.prototype.cst = {
343		STYLE_TEXTCOLOR2 : 'textColor2',
344		STYLE_STROKECOLOR2 : 'strokeColor2',
345		BUTTON_TEXT : 'buttonText',
346		SELECTED : '+' 		//has to be one character long
347};
348
349/**
350* Function: paintVertexShape
351*
352* Paints the vertex shape.
353*/
354mxShapeAndroidCheckboxGroup.prototype.paintVertexShape = function(c, x, y, w, h)
355{
356	c.translate(x, y);
357
358	var fontColor = mxUtils.getValue(this.style, mxConstants.STYLE_TEXTCOLOR, '#666666');
359	var fontSize = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, '8').toString();
360	var optionText = mxUtils.getValue(this.style, mxShapeAndroidCheckboxGroup.prototype.cst.BUTTON_TEXT, 'Option 1').toString().split(',');
361	var strokeColor = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, 'none');
362	var strokeColor2 = mxUtils.getValue(this.style, mxShapeAndroidCheckboxGroup.prototype.cst.STYLE_STROKECOLOR2, 'none');
363
364	c.setStrokeColor(strokeColor2);
365	var optionNum = optionText.length;
366	var buttonSize = 5;
367	var lineH = Math.max(fontSize * 1.5, buttonSize);
368	var maxTextWidth = 0;
369	var selected = -1;
370	var labelOffset = 2.5;
371	var minH = optionNum * lineH;
372	var trueH = Math.max(h, minH);
373
374	//get min width and selected option
375	for (var i = 0; i < optionNum; i++)
376	{
377		var currText = optionText[i];
378
379		if(currText.charAt(0) === mxShapeAndroidCheckboxGroup.prototype.cst.SELECTED)
380		{
381			currText = optionText[i].substring(1);
382			selected = i;
383		}
384
385		var currWidth = mxUtils.getSizeForString(currText, fontSize, mxConstants.DEFAULT_FONTFAMILY).width;
386
387		if (currWidth > maxTextWidth)
388		{
389			maxTextWidth = currWidth;
390		}
391	}
392
393	var minW = 2 * labelOffset + maxTextWidth + 2 * buttonSize;
394	var trueW = Math.max(w, minW);
395
396	//draw the background
397	c.roundrect(0, 0, trueW, trueH, 2.5, 2.5);
398	c.fillAndStroke();
399	c.setShadow(false);
400
401	c.setFontSize(fontSize);
402	c.setFontColor(fontColor);
403	c.setStrokeColor(strokeColor);
404
405	for (var i = 0; i < optionNum; i++)
406	{
407		var currHeight = (i * lineH + lineH * 0.5) * trueH / minH;
408
409		var currText = optionText[i];
410
411		if(currText.charAt(0) === mxShapeAndroidCheckboxGroup.prototype.cst.SELECTED)
412		{
413			currText = optionText[i].substring(1);
414			selected = i;
415		}
416
417		c.text(buttonSize * 2 + labelOffset, currHeight, 0, 0, currText, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
418
419		var iconX = buttonSize * 0.5;
420		var iconY = currHeight - buttonSize * 0.5;
421
422		if (selected === i)
423		{
424			c.rect(iconX, iconY, buttonSize, buttonSize);
425			c.fillAndStroke();
426			c.begin();
427			c.moveTo(iconX + buttonSize * 0.25, iconY + buttonSize * 0.5);
428			c.lineTo(iconX + buttonSize * 0.5, iconY + buttonSize * 0.75);
429			c.lineTo(iconX + buttonSize * 0.75, iconY + buttonSize * 0.25);
430			c.stroke();
431		}
432		else
433		{
434			c.rect(iconX, iconY, buttonSize, buttonSize);
435			c.fillAndStroke();
436		}
437
438		selected = -1;
439	}
440};
441
442mxCellRenderer.registerShape('mxgraph.android.checkboxGroup', mxShapeAndroidCheckboxGroup);
443
444//**********************************************************************************************************************************************************
445//Radio Button Group
446//**********************************************************************************************************************************************************
447/**
448* Extends mxShape.
449*/
450function mxShapeAndroidRadioGroup(bounds, fill, stroke, strokewidth)
451{
452	mxShape.call(this);
453	this.bounds = bounds;
454	this.fill = fill;
455	this.stroke = stroke;
456	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
457};
458
459/**
460* Extends mxShape.
461*/
462mxUtils.extend(mxShapeAndroidRadioGroup, mxShape);
463
464mxShapeAndroidRadioGroup.prototype.cst = {
465		STYLE_TEXTCOLOR2 : 'textColor2',
466		STYLE_STROKECOLOR2 : 'strokeColor2',
467		BUTTON_TEXT : 'buttonText',
468		SELECTED : '+' 		//has to be one character long
469};
470
471/**
472* Function: paintVertexShape
473*
474* Paints the vertex shape.
475*/
476mxShapeAndroidRadioGroup.prototype.paintVertexShape = function(c, x, y, w, h)
477{
478	c.translate(x, y);
479
480	var fontColor = mxUtils.getValue(this.style, mxConstants.STYLE_TEXTCOLOR, '#666666');
481	var fontSize = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, '8').toString();
482	var optionText = mxUtils.getValue(this.style, mxShapeAndroidRadioGroup.prototype.cst.BUTTON_TEXT, 'Option 1').toString().split(',');
483	var strokeColor = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, 'none');
484	var strokeColor2 = mxUtils.getValue(this.style, mxShapeAndroidRadioGroup.prototype.cst.STYLE_STROKECOLOR2, 'none');
485
486	c.setStrokeColor(strokeColor2);
487
488	var optionNum = optionText.length;
489	var buttonSize = 5;
490	var lineH = Math.max(fontSize * 1.5, buttonSize);
491	var maxTextWidth = 0;
492	var selected = -1;
493	var labelOffset = 2.5;
494	var minH = optionNum * lineH;
495	var trueH = Math.max(h, minH);
496
497	//get min width and selected option
498	for (var i = 0; i < optionNum; i++)
499	{
500		var currText = optionText[i];
501
502		if(currText.charAt(0) === mxShapeAndroidRadioGroup.prototype.cst.SELECTED)
503		{
504			currText = optionText[i].substring(1);
505			selected = i;
506		}
507
508		var currWidth = mxUtils.getSizeForString(currText, fontSize, mxConstants.DEFAULT_FONTFAMILY).width;
509
510		if (currWidth > maxTextWidth)
511		{
512			maxTextWidth = currWidth;
513		}
514	}
515
516	var minW = 2 * labelOffset + maxTextWidth + 2 * buttonSize;
517	var trueW = Math.max(w, minW);
518
519	//draw the background
520	c.roundrect(0, 0, trueW, trueH, 2.5, 2.5);
521	c.fillAndStroke();
522	c.setShadow(false);
523
524	c.setFontSize(fontSize);
525	c.setFontColor(fontColor);
526	c.setStrokeColor(strokeColor);
527	c.setFillColor(strokeColor);
528
529	for (var i = 0; i < optionNum; i++)
530	{
531		var currHeight = (i * lineH + lineH * 0.5) * trueH / minH;
532
533		var currText = optionText[i];
534
535		if(currText.charAt(0) === mxShapeAndroidRadioGroup.prototype.cst.SELECTED)
536		{
537			currText = optionText[i].substring(1);
538			selected = i;
539		}
540
541		c.text(buttonSize * 2 + labelOffset, currHeight, 0, 0, currText, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
542
543		var iconX = buttonSize * 0.5;
544		var iconY = currHeight - buttonSize * 0.5;
545
546		if (selected === i)
547		{
548			c.ellipse(iconX, iconY, buttonSize, buttonSize);
549			c.stroke();
550			c.ellipse(iconX + buttonSize * 0.25, iconY + buttonSize * 0.25, buttonSize * 0.5, buttonSize * 0.5);
551			c.fillAndStroke();
552		}
553		else
554		{
555			c.ellipse(iconX, iconY, buttonSize, buttonSize);
556			c.stroke();
557		}
558	}
559};
560
561mxCellRenderer.registerShape('mxgraph.android.radioGroup', mxShapeAndroidRadioGroup);
562
563//**********************************************************************************************************************************************************
564//Menu Bar (LEGACY)
565//**********************************************************************************************************************************************************
566/**
567* Extends mxShape.
568*/
569function mxShapeAndroidMenuBar(bounds, fill, stroke, strokewidth)
570{
571	mxShape.call(this);
572	this.bounds = bounds;
573	this.fill = fill;
574	this.stroke = stroke;
575	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
576};
577
578/**
579* Extends mxShape.
580*/
581mxUtils.extend(mxShapeAndroidMenuBar, mxShape);
582
583mxShapeAndroidMenuBar.prototype.cst = {
584		MENU_TEXT : 'menuText'
585};
586
587/**
588* Function: paintVertexShape
589*
590* Paints the vertex shape.
591*/
592mxShapeAndroidMenuBar.prototype.paintVertexShape = function(c, x, y, w, h)
593{
594	var textStrings = mxUtils.getValue(this.style, mxShapeAndroidMenuBar.prototype.cst.MENU_TEXT, 'Item 1, Item 2, Item 3').toString().split(',');
595	var fontSize = mxUtils.getValue(this.style, mxConstants.STYLE_FONTSIZE, '12');
596	var buttonNum = textStrings.length;
597	var maxButtonWidth = 0;
598	var labelOffset = 2.5;
599
600	for (var i = 0; i < buttonNum; i++)
601	{
602		var buttonText = textStrings[i];
603
604		var currWidth = mxUtils.getSizeForString(buttonText, fontSize, mxConstants.DEFAULT_FONTFAMILY).width;
605
606		if (currWidth > maxButtonWidth)
607		{
608			maxButtonWidth = currWidth;
609		}
610	}
611
612	var minButtonHeight =  fontSize * 1.5;
613	var minH = buttonNum * minButtonHeight;
614	var trueH = Math.max(h, minH);
615	var minW = 2 * labelOffset + maxButtonWidth;
616	var trueW = Math.max(w, minW);
617
618	c.translate(x, y);
619
620	c.rect(0, 0, w, trueH);
621	c.fillAndStroke();
622
623	c.setShadow(false);
624
625	//draw the button separators
626	c.begin();
627
628	for (var i = 1; i < buttonNum; i++)
629	{
630			var currHeight = i * minButtonHeight * trueH / minH;
631			c.moveTo(0, currHeight);
632			c.lineTo(w, currHeight);
633	}
634
635	c.stroke();
636
637	for (var i = 0; i < buttonNum; i++)
638	{
639		currWidth = currWidth + labelOffset;
640		var currHeight = (i * minButtonHeight + minButtonHeight * 0.5) * trueH / minH;
641		c.text(10, currHeight, 0, 0, textStrings[i], mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
642	}
643};
644
645mxCellRenderer.registerShape('mxgraph.android.menuBar', mxShapeAndroidMenuBar);
646
647//**********************************************************************************************************************************************************
648//Text Selection Handles
649//**********************************************************************************************************************************************************
650/**
651* Extends mxShape.
652*/
653function mxShapeAndroidTextSelHandles(bounds, fill, stroke, strokewidth)
654{
655	mxShape.call(this);
656	this.bounds = bounds;
657	this.fill = fill;
658	this.stroke = stroke;
659	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
660};
661
662/**
663* Extends mxShape.
664*/
665mxUtils.extend(mxShapeAndroidTextSelHandles, mxShape);
666
667/**
668* Function: paintVertexShape
669*
670* Paints the vertex shape.
671*/
672mxShapeAndroidTextSelHandles.prototype.paintVertexShape = function(c, x, y, w, h)
673{
674	var strokeColor = mxUtils.getValue(this.style, mxConstants.STYLE_STROKECOLOR, 'none');
675	c.translate(x, y);
676
677	var handleSizeX = 15;
678	var barH = Math.max(0, h - handleSizeX * 1.5);
679	c.setAlpha(0.5);
680
681	c.rect(handleSizeX, 0, w - 2 * handleSizeX, barH);
682	c.fill();
683
684	c.begin();
685	c.moveTo(0, h - handleSizeX);
686	c.lineTo(handleSizeX * 0.5, h - handleSizeX * 1.5);
687	c.lineTo(handleSizeX, h - handleSizeX);
688	c.close();
689	c.moveTo(w - handleSizeX, h - handleSizeX);
690	c.lineTo(w - handleSizeX * 0.5, h - handleSizeX * 1.5);
691	c.lineTo(w, h - handleSizeX);
692	c.close();
693	c.fill();
694
695	c.setFillColor(strokeColor);
696	c.rect(0, h - handleSizeX, handleSizeX, handleSizeX);
697	c.fill();
698	c.rect(w - handleSizeX, h - handleSizeX, handleSizeX, handleSizeX);
699	c.fill();
700};
701
702mxCellRenderer.registerShape('mxgraph.android.textSelHandles', mxShapeAndroidTextSelHandles);
703
704//**********************************************************************************************************************************************************
705//Android Indeterminate Spinner
706//**********************************************************************************************************************************************************
707/**
708* Extends mxShape.
709*/
710function mxShapeAndroidIndeterminateSpinner(bounds, fill, stroke, strokewidth)
711{
712	mxShape.call(this);
713	this.bounds = bounds;
714	this.fill = fill;
715	this.stroke = stroke;
716	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
717};
718
719/**
720* Extends mxShape.
721*/
722mxUtils.extend(mxShapeAndroidIndeterminateSpinner, mxShape);
723
724/**
725* Function: paintVertexShape
726*
727* Paints the vertex shape.
728*/
729mxShapeAndroidIndeterminateSpinner.prototype.paintVertexShape = function(c, x, y, w, h)
730{
731	c.translate(x, y);
732	this.background(c, x, y, w, h);
733};
734
735mxShapeAndroidIndeterminateSpinner.prototype.background = function(c, x, y, w, h)
736{
737	c.setGradient('#aaaaaa', '#dddddd', w * 0.325, 0, w * 0.675, h * 0.5, mxConstants.DIRECTION_SOUTH, 1, 1);
738	c.begin();
739	c.moveTo(w * 0.5, h * 0.1);
740	c.arcTo(w * 0.4, h * 0.4, 0, 0, 0, w * 0.5, h * 0.9);
741	c.lineTo(w * 0.5, h);
742	c.arcTo(w * 0.5, h * 0.5, 0, 0, 1, w * 0.5, 0);
743	c.close();
744	c.fill();
745
746	c.setGradient('#ffffff', '#dddddd', w * 0.325, 0, w * 0.675, h * 0.5, mxConstants.DIRECTION_SOUTH, 1, 1);
747	c.begin();
748	c.moveTo(w * 0.5, h * 0.1);
749	c.arcTo(w * 0.4, h * 0.4, 0, 0, 1, w * 0.5, h * 0.9);
750	c.lineTo(w * 0.5, h);
751	c.arcTo(w * 0.5, h * 0.5, 0, 0, 0, w * 0.5, 0);
752	c.close();
753	c.fill();
754};
755
756mxCellRenderer.registerShape('mxgraph.android.indeterminateSpinner', mxShapeAndroidIndeterminateSpinner);
757
758//**********************************************************************************************************************************************************
759//Anchor (a dummy shape without visuals used for anchoring)
760//**********************************************************************************************************************************************************
761/**
762* Extends mxShape.
763*/
764function mxShapeAndroidAnchor(bounds, fill, stroke, strokewidth)
765{
766	mxShape.call(this);
767	this.bounds = bounds;
768};
769
770/**
771* Extends mxShape.
772*/
773mxUtils.extend(mxShapeAndroidAnchor, mxShape);
774
775mxShapeAndroidAnchor.prototype.cst = {
776		ANCHOR : 'mxgraph.android.anchor'
777};
778
779/**
780* Function: paintVertexShape
781*
782* Paints the vertex shape.
783*/
784mxShapeAndroidAnchor.prototype.paintVertexShape = function(c, x, y, w, h)
785{
786};
787
788mxCellRenderer.registerShape(mxShapeAndroidAnchor.prototype.cst.ANCHOR, mxShapeAndroidAnchor);
789
790//**********************************************************************************************************************************************************
791//Rounded rectangle (adjustable rounding)
792//**********************************************************************************************************************************************************
793/**
794* Extends mxShape.
795*/
796function mxShapeAndroidRRect(bounds, fill, stroke, strokewidth)
797{
798	mxShape.call(this);
799	this.bounds = bounds;
800	this.fill = fill;
801	this.stroke = stroke;
802	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
803};
804
805/**
806* Extends mxShape.
807*/
808mxUtils.extend(mxShapeAndroidRRect, mxShape);
809
810mxShapeAndroidRRect.prototype.cst = {
811		RRECT : 'mxgraph.android.rrect',
812		R_SIZE : 'rSize'
813};
814
815/**
816* Function: paintVertexShape
817*
818* Paints the vertex shape.
819*/
820mxShapeAndroidRRect.prototype.paintVertexShape = function(c, x, y, w, h)
821{
822	c.translate(x, y);
823
824	var rSize = parseInt(mxUtils.getValue(this.style, mxShapeAndroidRRect.prototype.cst.R_SIZE, '10'));
825	c.roundrect(0, 0, w, h, rSize);
826	c.fillAndStroke();
827};
828
829mxCellRenderer.registerShape(mxShapeAndroidRRect.prototype.cst.RRECT, mxShapeAndroidRRect);
830
831//**********************************************************************************************************************************************************
832//Checkbox
833//**********************************************************************************************************************************************************
834/**
835* Extends mxShape.
836*/
837function mxShapeAndroidCheckbox(bounds, fill, stroke, strokewidth)
838{
839	mxShape.call(this);
840	this.bounds = bounds;
841	this.fill = fill;
842	this.stroke = stroke;
843	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
844};
845
846/**
847* Extends mxShape.
848*/
849mxUtils.extend(mxShapeAndroidCheckbox, mxShape);
850
851mxShapeAndroidCheckbox.prototype.cst = {
852		CHECKBOX : 'mxgraph.android.checkbox'
853};
854
855/**
856* Function: paintVertexShape
857*
858* Paints the vertex shape.
859*/
860mxShapeAndroidCheckbox.prototype.paintVertexShape = function(c, x, y, w, h)
861{
862	c.translate(x, y);
863	c.rect(0, 0, w, h);
864	c.fillAndStroke();
865
866	c.begin();
867	c.moveTo(w * 0.8, h * 0.2);
868	c.lineTo(w * 0.4, h * 0.8);
869	c.lineTo(w * 0.25, h * 0.6);
870	c.stroke();
871};
872
873mxCellRenderer.registerShape(mxShapeAndroidCheckbox.prototype.cst.CHECKBOX, mxShapeAndroidCheckbox);
874
875//**********************************************************************************************************************************************************
876//Progress Bar
877//**********************************************************************************************************************************************************
878/**
879* Extends mxShape.
880*/
881function mxShapeAndroidProgressBar(bounds, fill, stroke, strokewidth)
882{
883	mxShape.call(this);
884	this.bounds = bounds;
885	this.fill = fill;
886	this.stroke = stroke;
887	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
888	this.dx1 = 0.8;
889	this.dx2 = 0.6;
890};
891
892/**
893* Extends mxShape.
894*/
895mxUtils.extend(mxShapeAndroidProgressBar, mxShape);
896
897mxShapeAndroidProgressBar.prototype.customProperties = [
898	{name: 'dx1', dispName: 'Middle Bar Length', type: 'float', min:0, max:1, defVal:0.8},
899	{name: 'dx2', dispName: 'Left Bar Length', type: 'float', min:0, max:1, defVal:0.6}
900];
901
902mxShapeAndroidProgressBar.prototype.cst = {
903		PROGRESS_BAR : 'mxgraph.android.progressBar'
904};
905
906/**
907* Function: paintVertexShape
908*
909* Paints the vertex shape.
910*/
911mxShapeAndroidProgressBar.prototype.paintVertexShape = function(c, x, y, w, h)
912{
913	var dx1 = w * Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx1', this.dx1))));
914	var dx2 = w * Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx2', this.dx2))));
915
916	c.translate(x, y);
917
918	c.save();
919	c.save();
920	c.setStrokeColor('#444444');
921	c.begin();
922	c.moveTo(0, h * 0.5);
923	c.lineTo(w , h * 0.5);
924	c.stroke();
925
926	c.restore();
927	c.setShadow(false);
928	c.begin();
929	c.moveTo(0, h * 0.5);
930	c.lineTo(dx1, h * 0.5);
931	c.stroke();
932
933	c.setStrokeColor('#000000');
934	c.setAlpha('0.2');
935	c.begin();
936	c.moveTo(0, h * 0.5);
937	c.lineTo(dx1, h * 0.5);
938	c.stroke();
939
940	c.restore();
941	c.setShadow(false);
942	c.begin();
943	c.moveTo(0, h * 0.5);
944	c.lineTo(dx2, h * 0.5);
945	c.stroke();
946};
947
948mxCellRenderer.registerShape(mxShapeAndroidProgressBar.prototype.cst.PROGRESS_BAR, mxShapeAndroidProgressBar);
949
950mxShapeAndroidProgressBar.prototype.constraints = null;
951
952Graph.handleFactory[mxShapeAndroidProgressBar.prototype.cst.PROGRESS_BAR] = function(state)
953{
954	var handles = [Graph.createHandle(state, ['dx1'], function(bounds)
955			{
956				var dx1 = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dx1', this.dx1))));
957
958				return new mxPoint(bounds.x + dx1 * bounds.width, bounds.y + bounds.height / 2);
959			}, function(bounds, pt)
960			{
961				this.state.style['dx1'] = Math.round(100 * Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width))) / 100;
962			})];
963
964	var handle2 = Graph.createHandle(state, ['dx2'], function(bounds)
965			{
966				var dx2 = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dx2', this.dx1))));
967
968				return new mxPoint(bounds.x + dx2 * bounds.width, bounds.y + bounds.height / 2);
969			}, function(bounds, pt)
970			{
971				this.state.style['dx2'] = Math.round(100 * Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width))) / 100;
972			});
973
974	handles.push(handle2);
975
976	return handles;
977}
978
979//**********************************************************************************************************************************************************
980//Progress Scrubber Disabled
981//**********************************************************************************************************************************************************
982/**
983* Extends mxShape.
984*/
985function mxShapeAndroidProgressScrubberDisabled(bounds, fill, stroke, strokewidth)
986{
987	mxShape.call(this);
988	this.bounds = bounds;
989	this.fill = fill;
990	this.stroke = stroke;
991	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
992	this.dx = 0.3;
993};
994
995/**
996* Extends mxShape.
997*/
998mxUtils.extend(mxShapeAndroidProgressScrubberDisabled, mxShape);
999
1000mxShapeAndroidProgressScrubberDisabled.prototype.customProperties = [
1001	{name: 'dx', dispName: 'Handle Position', type: 'float', min:0, max:1, defVal:0.3}
1002];
1003
1004mxShapeAndroidProgressScrubberDisabled.prototype.cst = {
1005		PROGRESS_SCRUBBER_DISABLED : 'mxgraph.android.progressScrubberDisabled'
1006};
1007
1008/**
1009* Function: paintVertexShape
1010*
1011* Paints the vertex shape.
1012*/
1013mxShapeAndroidProgressScrubberDisabled.prototype.paintVertexShape = function(c, x, y, w, h)
1014{
1015	var dx = w * Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
1016
1017	c.translate(x, y);
1018
1019	c.save();
1020	c.save();
1021	c.setStrokeColor('#444444');
1022	c.begin();
1023	c.moveTo(0, h * 0.5);
1024	c.lineTo(w, h * 0.5);
1025	c.stroke();
1026
1027	c.restore();
1028	c.setShadow(false);
1029	c.setAlpha('0.5');
1030	c.setFillColor('#666666');
1031	c.begin();
1032	var r = Math.min(h, w * 0.1) / 2;
1033	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1034	c.fill();
1035
1036	c.restore();
1037	c.setShadow(false);
1038	c.begin();
1039	var r = Math.min(h, w * 0.1) / 8;
1040	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1041	c.fill();
1042
1043};
1044
1045mxCellRenderer.registerShape(mxShapeAndroidProgressScrubberDisabled.prototype.cst.PROGRESS_SCRUBBER_DISABLED, mxShapeAndroidProgressScrubberDisabled);
1046
1047mxShapeAndroidProgressScrubberDisabled.prototype.constraints = null;
1048
1049Graph.handleFactory[mxShapeAndroidProgressScrubberDisabled.prototype.cst.PROGRESS_SCRUBBER_DISABLED] = function(state)
1050{
1051	var handles = [Graph.createHandle(state, ['dx'], function(bounds)
1052			{
1053				var dx = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dx', this.dx))));
1054
1055				return new mxPoint(bounds.x + dx * bounds.width, bounds.y + bounds.height / 2);
1056			}, function(bounds, pt)
1057			{
1058				this.state.style['dx'] = Math.round(100 * Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width))) / 100;
1059			})];
1060
1061	return handles;
1062}
1063
1064//**********************************************************************************************************************************************************
1065//Progress Scrubber Focused
1066//**********************************************************************************************************************************************************
1067/**
1068* Extends mxShape.
1069*/
1070function mxShapeAndroidProgressScrubberFocused(bounds, fill, stroke, strokewidth)
1071{
1072	mxShape.call(this);
1073	this.bounds = bounds;
1074	this.fill = fill;
1075	this.stroke = stroke;
1076	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1077	this.dx = 0.3;
1078};
1079
1080/**
1081* Extends mxShape.
1082*/
1083mxUtils.extend(mxShapeAndroidProgressScrubberFocused, mxShape);
1084
1085mxShapeAndroidProgressScrubberFocused.prototype.customProperties = [
1086	{name: 'dx', dispName: 'Handle Position', type: 'float', min:0, max:1, defVal:0.3}
1087];
1088
1089mxShapeAndroidProgressScrubberFocused.prototype.cst = {
1090		PROGRESS_SCRUBBER_FOCUSED : 'mxgraph.android.progressScrubberFocused'
1091};
1092
1093/**
1094* Function: paintVertexShape
1095*
1096* Paints the vertex shape.
1097*/
1098mxShapeAndroidProgressScrubberFocused.prototype.paintVertexShape = function(c, x, y, w, h)
1099{
1100	var dx = w * Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
1101	var fillColor = mxUtils.getValue(this.style, 'fillColor', '#ffffff');
1102
1103	c.translate(x, y);
1104
1105	c.save();
1106	c.save();
1107	c.setStrokeColor('#444444');
1108	c.begin();
1109	c.moveTo(0, h * 0.5);
1110	c.lineTo(w, h * 0.5);
1111	c.stroke();
1112
1113	c.restore();
1114	c.setShadow(false);
1115	c.setAlpha('0.75');
1116	c.begin();
1117	var r = Math.min(h, w * 0.1) / 2;
1118	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1119	c.fill();
1120
1121	c.restore();
1122	c.setShadow(false);
1123	c.setStrokeColor(fillColor);
1124
1125	c.begin();
1126	c.moveTo(0, h * 0.5);
1127	c.lineTo(dx, h * 0.5);
1128	c.stroke();
1129
1130	c.begin();
1131	var r = Math.min(h, w * 0.1) / 8;
1132	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1133	c.fill();
1134
1135};
1136
1137mxCellRenderer.registerShape(mxShapeAndroidProgressScrubberFocused.prototype.cst.PROGRESS_SCRUBBER_FOCUSED, mxShapeAndroidProgressScrubberFocused);
1138
1139mxShapeAndroidProgressScrubberFocused.prototype.constraints = null;
1140
1141Graph.handleFactory[mxShapeAndroidProgressScrubberFocused.prototype.cst.PROGRESS_SCRUBBER_FOCUSED] = function(state)
1142{
1143	var handles = [Graph.createHandle(state, ['dx'], function(bounds)
1144			{
1145				var dx = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dx', this.dx))));
1146
1147				return new mxPoint(bounds.x + dx * bounds.width, bounds.y + bounds.height / 2);
1148			}, function(bounds, pt)
1149			{
1150				this.state.style['dx'] = Math.round(100 * Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width))) / 100;
1151			})];
1152
1153	return handles;
1154}
1155
1156//**********************************************************************************************************************************************************
1157//Progress Scrubber Pressed
1158//**********************************************************************************************************************************************************
1159/**
1160* Extends mxShape.
1161*/
1162function mxShapeAndroidProgressScrubberPressed(bounds, fill, stroke, strokewidth)
1163{
1164	mxShape.call(this);
1165	this.bounds = bounds;
1166	this.fill = fill;
1167	this.stroke = stroke;
1168	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1169	this.dx = 0.3;
1170};
1171
1172/**
1173* Extends mxShape.
1174*/
1175mxUtils.extend(mxShapeAndroidProgressScrubberPressed, mxShape);
1176
1177mxShapeAndroidProgressScrubberPressed.prototype.customProperties = [
1178	{name: 'dx', dispName: 'Handle Position', type: 'float', min:0, max:1, defVal:0.3}
1179];
1180
1181mxShapeAndroidProgressScrubberPressed.prototype.cst = {
1182		PROGRESS_SCRUBBER_PRESSED : 'mxgraph.android.progressScrubberPressed'
1183};
1184
1185/**
1186* Function: paintVertexShape
1187*
1188* Paints the vertex shape.
1189*/
1190mxShapeAndroidProgressScrubberPressed.prototype.paintVertexShape = function(c, x, y, w, h)
1191{
1192	var dx = w * Math.max(0, Math.min(w, parseFloat(mxUtils.getValue(this.style, 'dx', this.dx))));
1193	var fillColor = mxUtils.getValue(this.style, 'fillColor', '#ffffff');
1194
1195	c.translate(x, y);
1196
1197	c.save();
1198	c.save();
1199	c.setStrokeColor('#444444');
1200	c.begin();
1201	c.moveTo(0, h * 0.5);
1202	c.lineTo(w, h * 0.5);
1203	c.stroke();
1204
1205	c.restore();
1206	c.setShadow(false);
1207	c.setStrokeColor(fillColor);
1208	c.setAlpha('0.5');
1209	c.begin();
1210	var r = Math.min(h, w * 0.1) / 2;
1211	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1212	c.fillAndStroke();
1213
1214	c.restore();
1215	c.setShadow(false);
1216	c.setStrokeColor(fillColor);
1217
1218	c.begin();
1219	c.moveTo(0, h * 0.5);
1220	c.lineTo(dx, h * 0.5);
1221	c.stroke();
1222
1223	c.begin();
1224	var r = Math.min(h, w * 0.1) / 8;
1225	c.ellipse(dx - r, h * 0.5 - r, 2 * r, 2 * r);
1226	c.fill();
1227
1228};
1229
1230mxCellRenderer.registerShape(mxShapeAndroidProgressScrubberPressed.prototype.cst.PROGRESS_SCRUBBER_PRESSED, mxShapeAndroidProgressScrubberPressed);
1231
1232mxShapeAndroidProgressScrubberPressed.prototype.constraints = null;
1233
1234Graph.handleFactory[mxShapeAndroidProgressScrubberPressed.prototype.cst.PROGRESS_SCRUBBER_PRESSED] = function(state)
1235{
1236	var handles = [Graph.createHandle(state, ['dx'], function(bounds)
1237			{
1238				var dx = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dx', this.dx))));
1239
1240				return new mxPoint(bounds.x + dx * bounds.width, bounds.y + bounds.height / 2);
1241			}, function(bounds, pt)
1242			{
1243				this.state.style['dx'] = Math.round(100 * Math.max(0, Math.min(1, (pt.x - bounds.x) / bounds.width))) / 100;
1244			})];
1245
1246	return handles;
1247}
1248
1249//**********************************************************************************************************************************************************
1250//Quickscroll
1251//**********************************************************************************************************************************************************
1252/**
1253* Extends mxShape.
1254*/
1255function mxShapeAndroidQuickscroll2(bounds, fill, stroke, strokewidth)
1256{
1257	mxShape.call(this);
1258	this.bounds = bounds;
1259	this.fill = fill;
1260	this.stroke = stroke;
1261	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1262	this.dy = 0.5;
1263};
1264
1265/**
1266* Extends mxShape.
1267*/
1268mxUtils.extend(mxShapeAndroidQuickscroll2, mxShape);
1269
1270mxShapeAndroidQuickscroll2.prototype.customProperties = [
1271	{name: 'dy', dispName: 'Handle Position', type: 'float', min:0, max:1, defVal:0.5}
1272];
1273
1274mxShapeAndroidQuickscroll2.prototype.cst = {
1275		QUICKSCROLL : 'mxgraph.android.quickscroll2'
1276};
1277
1278/**
1279* Function: paintVertexShape
1280*
1281* Paints the vertex shape.
1282*/
1283mxShapeAndroidQuickscroll2.prototype.paintVertexShape = function(c, x, y, w, h)
1284{
1285	var dy = Math.min(h - 20, Math.max(20, h * Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))))));
1286	var fillColor = mxUtils.getValue(this.style, 'fillColor', '#ffffff');
1287
1288	c.translate(x, y);
1289
1290	c.save();
1291	c.save();
1292	c.setStrokeColor('#cccccc');
1293	c.begin();
1294	c.moveTo(w - 3, 0);
1295	c.lineTo(w - 3, h);
1296	c.stroke();
1297
1298	c.restore();
1299	c.begin();
1300	c.roundrect(w - 6, dy - 10, 6, 20, 1, 1);
1301	c.fillAndStroke();
1302
1303	c.setFillColor('#cccccc');
1304	c.begin();
1305	c.rect(0, dy - 20, w - 18, 40);
1306	c.fill();
1307
1308	c.setFillColor('#666666');
1309	c.begin();
1310	c.moveTo(w - 18, dy - 20);
1311	c.lineTo(w - 6, dy);
1312	c.lineTo(w - 18, dy + 20);
1313	c.close();
1314	c.fill();
1315
1316	c.setFontSize('12');
1317	c.text((w - 18) * 0.5, dy, 0, 0, 'Aa', mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE, 0, null, 0, 0, 0);
1318};
1319
1320mxCellRenderer.registerShape(mxShapeAndroidQuickscroll2.prototype.cst.QUICKSCROLL, mxShapeAndroidQuickscroll2);
1321
1322mxShapeAndroidQuickscroll2.prototype.constraints = null;
1323
1324Graph.handleFactory[mxShapeAndroidQuickscroll2.prototype.cst.QUICKSCROLL] = function(state)
1325{
1326	var handles = [Graph.createHandle(state, ['dy'], function(bounds)
1327			{
1328				var dy = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dy', this.dy))));
1329
1330				return new mxPoint(bounds.x + bounds.width - 3, bounds.y + Math.min(bounds.height - 20, Math.max(20, dy * bounds.height)));
1331			}, function(bounds, pt)
1332			{
1333				this.state.style['dy'] = Math.round(1000 * Math.max(0, Math.min(1, (pt.y - bounds.y) / bounds.height))) / 1000;
1334			})];
1335
1336	return handles;
1337}
1338
1339//**********************************************************************************************************************************************************
1340//Quickscroll2
1341//**********************************************************************************************************************************************************
1342/**
1343* Extends mxShape.
1344*/
1345function mxShapeAndroidQuickscroll3(bounds, fill, stroke, strokewidth)
1346{
1347	mxShape.call(this);
1348	this.bounds = bounds;
1349	this.fill = fill;
1350	this.stroke = stroke;
1351	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1352	this.dy = 0.5;
1353};
1354
1355/**
1356* Extends mxShape.
1357*/
1358mxUtils.extend(mxShapeAndroidQuickscroll3, mxShape);
1359
1360mxShapeAndroidQuickscroll3.prototype.customProperties = [
1361	{name: 'dy', dispName: 'Handle Position', type: 'float', min:0, max:1, defVal:0.5}
1362];
1363
1364mxShapeAndroidQuickscroll3.prototype.cst = {
1365		QUICKSCROLL : 'mxgraph.android.quickscroll3'
1366};
1367
1368/**
1369* Function: paintVertexShape
1370*
1371* Paints the vertex shape.
1372*/
1373mxShapeAndroidQuickscroll3.prototype.paintVertexShape = function(c, x, y, w, h)
1374{
1375	var dy = Math.min(h - 10, Math.max(10, h * Math.max(0, Math.min(h, parseFloat(mxUtils.getValue(this.style, 'dy', this.dy))))));
1376	var fillColor = mxUtils.getValue(this.style, 'fillColor', '#ffffff');
1377
1378	c.translate(x, y);
1379
1380	c.save();
1381	c.setStrokeColor('#cccccc');
1382	c.begin();
1383	c.moveTo(w * 0.5, 0);
1384	c.lineTo(w * 0.5, h);
1385	c.stroke();
1386
1387	c.restore();
1388	c.begin();
1389	c.roundrect(w * 0.5 - 3, dy - 10, 6, 20, 1, 1);
1390	c.fillAndStroke();
1391};
1392
1393mxCellRenderer.registerShape(mxShapeAndroidQuickscroll3.prototype.cst.QUICKSCROLL, mxShapeAndroidQuickscroll3);
1394
1395mxShapeAndroidQuickscroll3.prototype.constraints = null;
1396
1397Graph.handleFactory[mxShapeAndroidQuickscroll3.prototype.cst.QUICKSCROLL] = function(state)
1398{
1399	var handles = [Graph.createHandle(state, ['dy'], function(bounds)
1400			{
1401				var dy = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.state.style, 'dy', this.dy))));
1402
1403				return new mxPoint(bounds.x + bounds.width * 0.5, bounds.y + Math.min(bounds.height - 10, Math.max(10, dy * bounds.height)));
1404			}, function(bounds, pt)
1405			{
1406				this.state.style['dy'] = Math.round(1000 * Math.max(0, Math.min(1, (pt.y - bounds.y) / bounds.height))) / 1000;
1407			})];
1408
1409	return handles;
1410}
1411
1412//**********************************************************************************************************************************************************
1413//Scrollbars
1414//**********************************************************************************************************************************************************
1415/**
1416* Extends mxShape.
1417*/
1418function mxShapeAndroidScrollbars2(bounds, fill, stroke, strokewidth)
1419{
1420	mxShape.call(this);
1421	this.bounds = bounds;
1422	this.fill = fill;
1423	this.stroke = stroke;
1424	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1425};
1426
1427/**
1428* Extends mxShape.
1429*/
1430mxUtils.extend(mxShapeAndroidScrollbars2, mxShape);
1431
1432mxShapeAndroidScrollbars2.prototype.cst = {
1433		SCROLLBARS : 'mxgraph.android.scrollbars2'
1434};
1435
1436/**
1437* Function: paintVertexShape
1438*
1439* Paints the vertex shape.
1440*/
1441mxShapeAndroidScrollbars2.prototype.paintVertexShape = function(c, x, y, w, h)
1442{
1443
1444	c.translate(x, y);
1445
1446	c.begin();
1447	c.rect(w - 5, 0, 5, h - 7);
1448	c.fillAndStroke();
1449
1450	c.begin();
1451	c.rect(0, h - 5, w - 7, 5);
1452	c.fillAndStroke();
1453};
1454
1455mxCellRenderer.registerShape(mxShapeAndroidScrollbars2.prototype.cst.SCROLLBARS, mxShapeAndroidScrollbars2);
1456
1457mxShapeAndroidScrollbars2.prototype.constraints = null;
1458
1459//**********************************************************************************************************************************************************
1460//Spinner
1461//**********************************************************************************************************************************************************
1462/**
1463* Extends mxShape.
1464*/
1465function mxShapeAndroidSpinner2(bounds, fill, stroke, strokewidth)
1466{
1467	mxShape.call(this);
1468	this.bounds = bounds;
1469	this.fill = fill;
1470	this.stroke = stroke;
1471	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
1472};
1473
1474/**
1475* Extends mxShape.
1476*/
1477mxUtils.extend(mxShapeAndroidSpinner2, mxShape);
1478
1479mxShapeAndroidSpinner2.prototype.cst = {
1480		SPINNER : 'mxgraph.android.spinner2'
1481};
1482
1483/**
1484* Function: paintVertexShape
1485*
1486* Paints the vertex shape.
1487*/
1488mxShapeAndroidSpinner2.prototype.paintVertexShape = function(c, x, y, w, h)
1489{
1490
1491	c.translate(x, y);
1492
1493	c.begin();
1494	c.moveTo(0, h);
1495	c.lineTo(w, h);
1496	c.stroke();
1497
1498	var s = Math.min(w / 10, h)
1499	c.begin();
1500	c.moveTo(w - s, h);
1501	c.lineTo(w, h - s);
1502	c.lineTo(w, h);
1503	c.close();
1504	c.fillAndStroke();
1505};
1506
1507mxCellRenderer.registerShape(mxShapeAndroidSpinner2.prototype.cst.SPINNER, mxShapeAndroidSpinner2);
1508
1509mxShapeAndroidSpinner2.prototype.constraints = null;
1510
1511