PageSourceSearch

https://www.toolpic.com/app/editor/js/draw_tools.js

js toolpic.com collected 2026-10-02 10:53:47 UTC 61,180 bytes, 1,702 lines download raw bytes

1/* global MAIN, HELPER, LAYER, EDIT, POP, GUI, EVENTS, IMAGE, EL, fx, ImageFilters, sketchy_brush, shaded_brush, chrome_brush, BezierCurveBrush */
2/* global WIDTH, HEIGHT, COLOR, canvas_active, canvas_front */
3
4var DRAW = new DRAW_TOOLS_CLASS();
5
6/** 
7 * manages draw tools
8 * 
9 * @author toolpic.com
10 */
11function DRAW_TOOLS_CLASS() {
12	
13	/**
14	 * user action for selected area
15	 */
16	this.select_square_action = '';
17	
18	/**
19	 * previous line coordinates [x, y]
20	 */
21	this.last_line = [];
22	
23	/**
24	 * user selected area config - array(x, y, width, height)
25	 */
26	this.select_data = false;
27	
28	/**
29	 * currently used tool
30	 */
31	this.active_tool = 'brush';
32	
33	/**
34	 * line points data for curved line
35	 */
36	var curve_points = [];
37	
38	/**
39	 * image data for cloning tool
40	 */
41	var clone_data = false;
42	
43	/**
44	 * fx library object
45	 */
46	var fx_filter = false;
47
48	//credits to Victor Haydin
49	this.toolFiller = function (context, W, H, x, y, color_to, sensitivity, anti_aliasing) {
50		canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
51		var img_tmp = canvas_front.getImageData(0, 0, W, H);
52		var imgData_tmp = img_tmp.data;
53
54		var img = context.getImageData(0, 0, W, H);
55		var imgData = img.data;
56		var k = ((y * (img.width * 4)) + (x * 4));
57		var dx = [0, -1, +1, 0];
58		var dy = [-1, 0, 0, +1];
59		var color_from = {
60			r: imgData[k + 0],
61			g: imgData[k + 1],
62			b: imgData[k + 2],
63			a: imgData[k + 3]
64		};
65		if (color_from.r == color_to.r && color_from.g == color_to.g && color_from.b == color_to.b && color_from.a == color_to.a) {
66			return false;
67		}
68		var stack = [];
69		stack.push([x, y]);
70		while (stack.length > 0) {
71			var curPoint = stack.pop();
72			for (var i = 0; i < 4; i++) {
73				var nextPointX = curPoint[0] + dx[i];
74				var nextPointY = curPoint[1] + dy[i];
75				if (nextPointX < 0 || nextPointY < 0 || nextPointX >= W || nextPointY >= H)
76					continue;
77				var k = (nextPointY * W + nextPointX) * 4;
78				if (imgData_tmp[k + 3] != 0)
79					continue; //already parsed
80
81				//check
82				if (Math.abs(imgData[k + 0] - color_from.r) <= sensitivity &&
83					Math.abs(imgData[k + 1] - color_from.g) <= sensitivity &&
84					Math.abs(imgData[k + 2] - color_from.b) <= sensitivity &&
85					Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
86
87					//fill pixel
88					imgData_tmp[k] = color_to.r; //r
89					imgData_tmp[k + 1] = color_to.g; //g
90					imgData_tmp[k + 2] = color_to.b; //b
91					imgData_tmp[k + 3] = color_to.a; //a
92
93					stack.push([nextPointX, nextPointY]);
94				}
95			}
96		}
97		canvas_front.putImageData(img_tmp, 0, 0);
98		if (anti_aliasing == true) {
99			context.shadowColor = "rgba(" + color_to.r + ", " + color_to.g + ", " + color_to.b + ", " + color_to.a / 255 + ")";
100			context.shadowBlur = 5;
101		}
102		context.drawImage(document.getElementById("canvas_front"), 0, 0);
103		//reset
104		context.shadowBlur = 0;
105	};
106	
107	this.tool_magic_wand = function (context, W, H, x, y, sensitivity, anti_aliasing) {
108		canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
109
110		canvas_front.rect(0, 0, WIDTH, HEIGHT);
111		canvas_front.fillStyle = "rgba(255, 255, 255, 0)";
112		canvas_front.fill();
113
114		var img_tmp = canvas_front.getImageData(0, 0, W, H);
115		var imgData_tmp = img_tmp.data;
116
117		var img = context.getImageData(0, 0, W, H);
118		var imgData = img.data;
119		var k = ((y * (img.width * 4)) + (x * 4));
120		var dx = [0, -1, +1, 0];
121		var dy = [-1, 0, 0, +1];
122		var color_to = {
123			r: 255,
124			g: 255,
125			b: 255,
126			a: 255
127		};
128		var color_from = {
129			r: imgData[k + 0],
130			g: imgData[k + 1],
131			b: imgData[k + 2],
132			a: imgData[k + 3]
133		};
134		if (color_from.r == color_to.r &&
135			color_from.g == color_to.g &&
136			color_from.b == color_to.b &&
137			color_from.a == 0) {
138			return false;
139		}
140		var stack = [];
141		stack.push([x, y]);
142		while (stack.length > 0) {
143			var curPoint = stack.pop();
144			for (var i = 0; i < 4; i++) {
145				var nextPointX = curPoint[0] + dx[i];
146				var nextPointY = curPoint[1] + dy[i];
147				if (nextPointX < 0 || nextPointY < 0 || nextPointX >= W || nextPointY >= H)
148					continue;
149				var k = (nextPointY * W + nextPointX) * 4;
150				if (imgData_tmp[k + 3] != 0)
151					continue; //already parsed
152
153				if (Math.abs(imgData[k] - color_from.r) <= sensitivity
154					&& Math.abs(imgData[k + 1] - color_from.g) <= sensitivity
155					&& Math.abs(imgData[k + 2] - color_from.b) <= sensitivity
156					&& Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
157					imgData_tmp[k] = color_to.r; //r
158					imgData_tmp[k + 1] = color_to.g; //g
159					imgData_tmp[k + 2] = color_to.b; //b
160					imgData_tmp[k + 3] = color_to.a; //a
161
162					stack.push([nextPointX, nextPointY]);
163				}
164			}
165		}
166		//destination-out + blur = anti-aliasing
167		if (anti_aliasing == true)
168			img_tmp = ImageFilters.StackBlur(img_tmp, 2);
169		canvas_front.putImageData(img_tmp, 0, 0);
170		context.globalCompositeOperation = "destination-out";
171		context.drawImage(document.getElementById("canvas_front"), 0, 0);
172		//reset
173		context.shadowBlur = 0;
174		context.globalCompositeOperation = 'source-over';
175	};
176	
177	//type = click, right_click, drag, move, release
178	this.select_tool = function (type, mouse, event) {
179		if (mouse == undefined)
180			return false;
181		if (mouse.valid == false)
182			return true;
183		if (mouse.click_valid == false)
184			return true;
185		if (event != undefined && event.target.id == "canvas_preview")
186			return true;
187		var active_layer_obj = document.getElementById(LAYER.layers[LAYER.layer_active].name);
188		
189		if (type == 'drag') {
190			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
191			
192			if(active_layer_obj.style.visibility != 'hidden'){
193				//hide active layer
194				active_layer_obj.style.visibility = 'hidden';
195			}
196			
197			if(EVENTS.ctrl_pressed == true){
198				//ctrl is pressed
199				var xx = mouse.x;
200				var yy = mouse.y;
201				if (Math.abs(mouse.click_x - mouse.x) < Math.abs(mouse.click_y - mouse.y))
202					xx = mouse.click_x;
203				else
204					yy = mouse.click_y;
205				canvas_front.drawImage(canvas_active(true), xx - mouse.click_x, yy - mouse.click_y);
206			}
207			else{
208				canvas_front.drawImage(canvas_active(true), mouse.x - mouse.click_x, mouse.y - mouse.click_y);
209			}
210		}
211		else if (type == 'release') {
212			//show active layer
213			active_layer_obj.style.visibility = 'visible';
214			
215			if (mouse.valid == false || mouse.click_x === false){
216				return false;
217			}
218			if (mouse.x - mouse.click_x == 0 && mouse.y - mouse.click_y == 0){
219				return false;
220			}
221			EDIT.save_state();
222			var tmp = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
223			canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
224			if(EVENTS.ctrl_pressed == true){
225				//ctrl is pressed
226				var xx = mouse.x;
227				var yy = mouse.y;
228				if (Math.abs(mouse.click_x - mouse.x) < Math.abs(mouse.click_y - mouse.y))
229					xx = mouse.click_x;
230				else
231					yy = mouse.click_y;
232				canvas_active().putImageData(tmp, xx - mouse.click_x, yy - mouse.click_y);
233			}
234			else{
235				canvas_active().putImageData(tmp, mouse.x - mouse.click_x, mouse.y - mouse.click_y);
236			}	
237		}
238	};
239	this.magic_wand = function (type, mouse, event) {
240		if (mouse.valid == false)
241			return true;
242		if (type == 'click') {
243			EDIT.save_state();
244			this.tool_magic_wand(canvas_active(), WIDTH, HEIGHT, mouse.x, mouse.y, GUI.action_data().attributes.power, GUI.action_data().attributes.anti_aliasing);
245		}
246	};
247	this.erase = function (type, mouse, event) {
248		if (mouse.valid == false || (mouse.click_valid == false && type != 'move'))
249			return true;
250		var strict = GUI.action_data().attributes.strict;
251		var size = GUI.action_data().attributes.size;
252		var is_circle = GUI.action_data().attributes.circle;
253		
254		var strict_element = document.getElementById('strict');
255		if(is_circle == false){
256			//hide strict controlls
257			if(strict_element != undefined)
258				strict_element.style.display = 'none';
259		}
260		else{
261			//show strict controlls
262			if(strict_element != undefined)
263				strict_element.style.display = 'block';
264		}
265
266		if (type == 'click') {
267			EDIT.save_state();
268			
269			canvas_active().beginPath();
270			canvas_active().lineWidth = size;
271			canvas_active().lineCap = 'round';
272			canvas_active().lineJoin = 'round';		
273			if (ALPHA < 255)
274				canvas_active().strokeStyle = "rgba(255, 255, 255, " + ALPHA / 255 / 10 + ")";
275			else
276				canvas_active().strokeStyle = "rgba(255, 255, 255, 1)";
277			
278			if (is_circle == false) {
279				//rectangle
280				canvas_active().save();
281				canvas_active().globalCompositeOperation = 'destination-out';
282				canvas_active().fillStyle = "rgba(255, 255, 255, " + ALPHA / 255 + ")";
283				canvas_active().fillRect(mouse.x - Math.ceil(size / 2) + 1, mouse.y - Math.ceil(size / 2) + 1, size, size);
284				canvas_active().restore();
285			}
286			else {
287				//circle
288				canvas_active().save();
289				
290				if (strict == false) {
291					var radgrad = canvas_active().createRadialGradient(
292						mouse.x, mouse.y, size / 8,
293						mouse.x, mouse.y, size / 2);
294					radgrad.addColorStop(0, "rgba(255, 255, 255, " + ALPHA / 255 + ")");
295					radgrad.addColorStop(1, "rgba(255, 255, 255, 0)");
296				}
297
298				//set Composite
299					canvas_active().globalCompositeOperation = 'destination-out';
300				if (strict == true)
301					canvas_active().fillStyle = "rgba(255, 255, 255, " + ALPHA / 255 + ")";
302				else
303					canvas_active().fillStyle = radgrad;
304				canvas_active().beginPath();
305				canvas_active().arc(mouse.x, mouse.y, size / 2, 0, Math.PI * 2, true);
306				canvas_active().fill();
307				canvas_active().restore();
308			}
309		}
310		else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
311			canvas_active().save();
312			
313			if (strict == false && is_circle == true) {
314				var radgrad = canvas_active().createRadialGradient(
315					mouse.x, mouse.y, size / 10,
316					mouse.x, mouse.y, size / 2);
317				if (ALPHA < 255)
318					radgrad.addColorStop(0, "rgba(255, 255, 255, " + ALPHA / 255 / 10 + ")");
319				else
320					radgrad.addColorStop(0, "rgba(255, 255, 255, 1)");
321				radgrad.addColorStop(1, "rgba(255, 255, 255, 0)");
322				canvas_active().strokeStyle = radgrad;
323			}
324			
325			canvas_active().save();
326			canvas_active().globalCompositeOperation = 'destination-out';
327
328			canvas_active().beginPath();
329			canvas_active().moveTo(mouse.last_x, mouse.last_y);
330			canvas_active().lineTo(mouse.x, mouse.y);
331			canvas_active().stroke();
332
333			canvas_active().restore();
334			
335			//show size
336			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
337			if (is_circle == false) {
338				canvas_front.lineWidth = 1;
339				EL.rectangle_dashed(canvas_front, mouse.x - Math.ceil(size / 2) + 1, mouse.y - Math.ceil(size / 2) + 1, mouse.x + Math.floor(size / 2), mouse.y + Math.floor(size / 2), 1, '#000000');
340			}
341			else {
342				EL.circle(canvas_front, mouse.x, mouse.y, size);
343			}
344		}
345		else if (type == 'move') {
346			var size1 = Math.floor((size) / 2);
347			var size2 = Math.floor((size) / 2);
348			if (size % 2 == 0)
349				size2--;
350			else {
351				size1--;
352			}
353
354			//show size
355			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
356			if (is_circle == false) {
357				canvas_front.lineWidth = 1;
358				EL.rectangle_dashed(canvas_front, mouse.x - Math.ceil(size / 2) + 1, mouse.y - Math.ceil(size / 2) + 1, mouse.x + Math.floor(size / 2), mouse.y + Math.floor(size / 2), 1, '#000000');
359			}
360			else {
361				EL.circle(canvas_front, mouse.x, mouse.y, size);
362			}
363		}
364	};
365	this.fill = function (type, mouse, event) {
366		if (mouse.valid == false){
367			return true;
368		}
369		if (type == 'click') {
370			if(ALPHA == 0){
371				POP.add({html: 'Alpha color can not be zero.'});
372				POP.show('Error', '.');
373				return;
374			}
375			
376			EDIT.save_state();
377			var color_to = HELPER.hex2rgb(COLOR);
378			color_to.a = ALPHA;
379			DRAW.toolFiller(canvas_active(), WIDTH, HEIGHT, mouse.x, mouse.y, color_to, GUI.action_data().attributes.power, GUI.action_data().attributes.anti_aliasing);
380		}
381	};
382	this.pick_color = function (type, mouse, event) {
383		if (mouse.valid == false)
384			return true;
385		if (type == 'click') {
386			var c = canvas_active().getImageData(mouse.x, mouse.y, 1, 1).data;
387			COLOR = "#" + ("000000" + HELPER.rgbToHex(c[0], c[1], c[2])).slice(-6);
388
389			if(c[3] > 0) {
390				//set alpha
391				ALPHA = c[3];
392				document.getElementById("rgb_a").value = ALPHA;
393			}
394
395			GUI.sync_colors();
396		}
397	};
398	this.pencil = function (type, mouse, event) {
399		if (mouse.valid == false || mouse.click_valid == false)
400			return true;
401		var color_rgb = HELPER.hex2rgb(COLOR);
402		if (type == 'click') {
403			EDIT.save_state();
404		}
405		else if (type == 'drag') {
406			//why no simple lines? this way turns off aliasing
407			if (mouse.last_x != false && mouse.last_y != false) {
408				//saving
409				dist_x = mouse.last_x - mouse.x;
410				dist_y = mouse.last_y - mouse.y;
411				distance = Math.sqrt((dist_x * dist_x) + (dist_y * dist_y));
412				radiance = Math.atan2(dist_y, dist_x);
413				for (var i = 0; i < distance; i++) {
414					x_tmp = mouse.x + Math.cos(radiance) * i;
415					y_tmp = mouse.y + Math.sin(radiance) * i;
416
417					x_tmp = Math.round(x_tmp);
418					y_tmp = Math.round(y_tmp);
419					var my_color = HELPER.hex2rgb(COLOR);
420					canvas_active().fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
421					canvas_active().fillRect(x_tmp, y_tmp, 1, 1);
422				}
423			}
424		}
425		else if (type == 'release') {
426			canvas_active().fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
427			canvas_active().fillRect(mouse.x, mouse.y, 1, 1);
428		}
429	};
430	this.line = function (type, mouse, event) {
431		if (mouse.click_valid == false)
432			return false;
433		var color_rgb = HELPER.hex2rgb(COLOR);
434
435		//horizontal/vertical only
436		var xx = mouse.x;
437		var yy = mouse.y;
438		var from_x = mouse.click_x;
439		var from_y = mouse.click_y;
440		var attribute_type = GUI.action_data().attributes.type;
441		if(attribute_type == undefined)
442			attribute_type = 'Simple';
443		
444		//set line endings
445		if(attribute_type == 'Simple'){
446			var lineCap = 'butt';
447		}
448		else{
449			var lineCap = 'round';
450		}
451		canvas_front.lineCap = lineCap;
452		canvas_active().lineCap = lineCap;
453			
454		if (type == 'move') {
455			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
456			canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
457			canvas_front.lineWidth = GUI.action_data().attributes.size;
458
459			if (attribute_type == 'Curve') {
460				//curve
461				if (curve_points.length == 2) {
462					canvas_front.beginPath();
463					canvas_front.moveTo(curve_points[0][0] + 0.5, curve_points[0][1] + 0.5);
464					canvas_front.quadraticCurveTo(mouse.x + 0.5, mouse.y + 0.5, curve_points[1][0], curve_points[1][1]);
465					canvas_front.stroke();
466				}
467			}
468		}
469		else if (type == 'drag') {
470			document.body.style.cursor = "crosshair";
471			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
472			canvas_front.beginPath();
473			canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
474			canvas_front.lineWidth = GUI.action_data().attributes.size;
475			if (attribute_type == 'Multi-line' && this.last_line[0] != undefined) {
476				from_x = this.last_line[0];
477				from_y = this.last_line[1];
478			}
479			if (EVENTS.ctrl_pressed == true) {
480				if (Math.abs(from_x - mouse.x) < Math.abs(from_y - mouse.y))
481					xx = from_x;
482				else
483					yy = from_y;
484			}
485
486			//arrow
487			if (attribute_type == 'Arrow') {
488				var headlen = GUI.action_data().attributes.size * 5;
489				if (headlen < 15)
490					headlen = 15;
491				EL.arrow(canvas_front, from_x + 0.5, from_y + 0.5, xx + 0.5, yy + 0.5, headlen);
492			}
493			//line
494			else {
495				canvas_front.moveTo(from_x + 0.5, from_y + 0.5);
496				canvas_front.lineTo(xx + 0.5, yy + 0.5);
497				canvas_front.stroke();
498			}
499		}
500		else if (type == 'click') {
501			//curve
502			if (attribute_type == 'Curve') {
503				EDIT.save_state();
504				
505				canvas_active().beginPath();
506				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
507				canvas_active().lineWidth = GUI.action_data().attributes.size;
508				if (EVENTS.ctrl_pressed == true) {
509					if (Math.abs(from_x - mouse.x) < Math.abs(from_y - mouse.y))
510						xx = from_x;
511					else
512						yy = from_y;
513				}
514				if (curve_points.length == 2) {
515					canvas_active().beginPath();
516					canvas_active().moveTo(curve_points[0][0] + 0.5, curve_points[0][1] + 0.5);
517					canvas_active().quadraticCurveTo(xx + 0.5, yy + 0.5, curve_points[1][0], curve_points[1][1]);
518					canvas_active().stroke();
519					curve_points = [];
520				}
521			}
522			if (attribute_type != 'Multi-line'){
523				//reset last line position
524				DRAW.last_line = [];
525			}
526		}
527		else if (type == 'release') {
528			document.body.style.cursor = "auto";
529			if (mouse.x - mouse.click_x == 0 && mouse.y - mouse.click_y == 0 && attribute_type != 'Multi-line')
530				return false;
531
532			EDIT.save_state();
533			
534			canvas_active().beginPath();
535			canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
536			canvas_active().lineWidth = GUI.action_data().attributes.size;
537			if (attribute_type == 'Multi-line' && this.last_line[0] != undefined) {
538				from_x = DRAW.last_line[0];
539				from_y = DRAW.last_line[1];
540			}
541			if (EVENTS.ctrl_pressed == true) {
542				if (Math.abs(from_x - mouse.x) < Math.abs(from_y - mouse.y))
543					xx = from_x;
544				else
545					yy = from_y;
546			}
547			//arrow
548			if (attribute_type == 'Arrow') {
549				var headlen = GUI.action_data().attributes.size * 5;
550				if (headlen < 15)
551					headlen = 15;
552				EL.arrow(canvas_active(), from_x + 0.5, from_y + 0.5, xx + 0.5, yy + 0.5, headlen);
553				this.last_line[0] = xx;
554				this.last_line[1] = yy;
555			}
556			//curve
557			else if (attribute_type == 'Curve') {
558				if (curve_points.length == 0 && (mouse.click_x != mouse.x || mouse.click_y != mouse.y)) {
559					curve_points.push([mouse.click_x, mouse.click_y]);
560					curve_points.push([xx, yy]);
561				}
562				else if (curve_points.length == 2)
563					curve_points = [];
564			}
565			//line
566			else {
567				EL.line(canvas_active(), from_x, from_y, xx, yy);
568				this.last_line[0] = xx;
569				this.last_line[1] = yy;
570			}
571		}
572	};
573	this.letters = function (type, mouse, event) {
574		var _this = this;
575		if (mouse.valid == false)
576			return true;
577		var xx = mouse.x;
578		var yy = mouse.y;
579		if (type == 'click') {
580			POP.add({name: "text", title: "Text:", value: "", type: 'textarea'});
581			POP.add({name: "size", title: "Size:", value: 20, range: [2, 1000], step: 2});
582			POP.add({name: "color", title: "Color:", value: "#000000", type: "color"});
583			POP.add({name: "style", title: "Font style:", values: ["Normal", "Italic", "Bold", "Bold Italic"], type: 'select'});
584			POP.add({name: "family", title: "Font family:", values: ["Arial", "Courier", "Impact", "Helvetica", "monospace", "Times New Roman", "Verdana"], type: 'select'});
585			POP.add({name: "size_3d", title: "3D size:", value: 0, range: [0, 200]});
586			POP.add({name: "pos_3d", title: "3D position:", values: ["Top-left", "Top-right", "Bottom-left", "Bottom-right"], type: 'select'});
587			POP.add({name: "shadow", title: "Shadow:", values: ["No", "Yes"]});
588			POP.add({name: "shadow_blur", title: "Shadow blur:", value: 6, range: [1, 20]});
589			POP.add({name: "shadow_color", title: "Shadow color:", value: "#000000", type: "color"});
590			POP.add({name: "fill_style", title: "Fill style:", values: ["Fill", "Stroke", "Both"], type: 'select'});
591			POP.add({name: "stroke_size", title: "Stroke size:", value: 1, range: [1, 100]});
592			POP.preview_in_main = true;
593			POP.show(
594				'Text', 
595				function (user_response) {
596					EDIT.save_state();
597					var trim_details = IMAGE.trim_info(canvas_active(true));
598					if (trim_details.empty == false) {
599						LAYER.layer_add();
600					}
601					text = user_response.text.split("\n");
602					for (var i in text) {
603						user_response.text = text[i];
604						var yyy = yy + i * (parseInt(user_response.size) + 2);
605						_this.letters_render(canvas_active(), xx, yyy, user_response);
606					}
607					canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
608				},
609				function (user_response) {
610					canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
611					text = user_response.text.split("\n");
612					for (var i in text) {
613						user_response.text = text[i];
614						var yyy = yy + i * (parseInt(user_response.size) + 2);
615						_this.letters_render(canvas_front, xx, yyy, user_response);
616					}
617				}
618			);
619		}
620	};
621	this.letters_render = function (canvas, xx, yy, user_response) {
622		var text = user_response.text;
623		var size = parseInt(user_response.size);
624		var color = user_response.color;
625		var dpth = parseInt(user_response.size_3d);
626		var pos_3d = user_response.pos_3d;
627		var shadow = user_response.shadow;
628		var shadow_blur = parseInt(user_response.shadow_blur);
629		var shadow_color = user_response.shadow_color;
630		var font = user_response.family;
631		var font_style = user_response.style;
632		var fill_style = user_response.fill_style;
633		var stroke_size = user_response.stroke_size;
634		var dx;
635		var dy;
636		if (pos_3d == "Top-left") {
637			dx = -1;
638			dy = -1;
639		}
640		else if (pos_3d == "Top-right") {
641			dx = 1;
642			dy = -1;
643		}
644		else if (pos_3d == "Bottom-left") {
645			dx = -1;
646			dy = 1;
647		}
648		else if (pos_3d == "Bottom-right") {
649			dx = 1;
650			dy = 1;
651		}
652
653		var color_rgb = HELPER.hex2rgb(color);
654		canvas.fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
655		canvas.font = font_style + " " + size + "px " + font;
656		var letters_height = HELPER.font_pixel_to_height(size);
657
658		//shadow
659		if (shadow == 'Yes') {
660			canvas.save();
661			canvas.shadowColor = shadow_color;
662			canvas.shadowBlur = shadow_blur;
663			canvas.shadowOffsetX = dx;
664			canvas.shadowOffsetY = dy;
665			canvas.fillText(text, xx + dx * (dpth - 1), yy + letters_height + dy * (dpth - 1));
666			canvas.restore();
667		}
668
669		//3d
670		if (dpth > 0) {
671			canvas.fillStyle = HELPER.darkenColor(COLOR, -30);
672			//canvas.fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
673			for (cnt = 0; cnt < dpth; cnt++)
674				canvas.fillText(text, xx + dx * cnt, yy + letters_height + dy * cnt);
675			//color_rgb = HELPER.hex2rgb(COLOR);
676		}
677
678		//main text
679		canvas.fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
680		canvas.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
681		canvas.lineWidth = stroke_size;
682		if (fill_style == 'Fill' || fill_style == 'Both')
683			canvas.fillText(text, xx, yy + letters_height);
684		if (fill_style == 'Stroke' || fill_style == 'Both')
685			canvas.strokeText(text, xx, yy + letters_height);
686
687		GUI.zoom();
688	};
689	this.draw_square = function (type, mouse, event) {
690		if (mouse.click_valid == false)
691			return true;
692		var color_rgb = HELPER.hex2rgb(COLOR);
693		var fill = GUI.action_data().attributes.fill;
694		var width = mouse.x - mouse.click_x;
695		var height = mouse.y - mouse.click_y;
696		var size = parseInt(GUI.action_data().attributes.size);
697			
698		if (type == 'drag') {
699			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
700			canvas_front.fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
701			canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
702			canvas_front.lineWidth = size;
703			
704			if (GUI.action_data().attributes.square == true)
705				EL.square(canvas_front, mouse.click_x, mouse.click_y, width, height, fill);
706			else
707				EL.rectangle(canvas_front, mouse.click_x, mouse.click_y, width, height, fill);
708		}
709		else if (type == 'release') {
710			if(mouse.x == mouse.click_x && mouse.y == mouse.click_y)
711				return false;
712			EDIT.save_state();
713			
714			canvas_active().fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
715			canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
716			canvas_active().lineWidth = size;
717			
718			if (GUI.action_data().attributes.square == true)
719				EL.square(canvas_active(), mouse.click_x, mouse.click_y, width, height, fill);
720			else
721				EL.rectangle(canvas_active(), mouse.click_x, mouse.click_y, width, height, fill);
722		}
723	};
724	this.draw_circle = function (type, mouse, event) {
725		if (mouse.click_valid == false)
726			return true;
727		var color_rgb = HELPER.hex2rgb(COLOR);
728		var size = parseInt(GUI.action_data().attributes.size);
729		if (type == 'drag') {
730			dist_x = mouse.x - mouse.click_x;
731			dist_y = mouse.y - mouse.click_y;
732			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
733			canvas_front.lineWidth = size;
734			if (GUI.action_data().attributes.circle == true)
735				dist_x = dist_y = Math.min(dist_x, dist_y);
736			if (GUI.action_data().attributes.fill == true)
737				EL.ellipse_by_center(canvas_front, mouse.click_x, mouse.click_y, dist_x * 2, dist_y * 2, "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")", true);
738			else
739				EL.ellipse_by_center(canvas_front, mouse.click_x, mouse.click_y, dist_x * 2, dist_y * 2, "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")");
740		}
741		else if (type == 'release') {
742			dist_x = mouse.x - mouse.click_x;
743			dist_y = mouse.y - mouse.click_y;
744			if(dist_x == 0 && dist_y == 0)
745				return false;
746			EDIT.save_state();
747			if (GUI.action_data().attributes.circle == true)
748				dist_x = dist_y = Math.min(dist_x, dist_y);
749			canvas_active().lineWidth = size;
750			if (GUI.action_data().attributes.fill == true)
751				EL.ellipse_by_center(canvas_active(), mouse.click_x, mouse.click_y, dist_x * 2, dist_y * 2, "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")", true);
752			else
753				EL.ellipse_by_center(canvas_active(), mouse.click_x, mouse.click_y, dist_x * 2, dist_y * 2, "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")");
754		}
755	};
756	this.update_brush = function () {
757		document.getElementById('anti_aliasing').style.display = '';
758		document.getElementById('smart_brush').style.display = '';
759		if (GUI.action_data().attributes.type != 'Brush'){
760			document.getElementById('anti_aliasing').style.display = 'none';
761			document.getElementById('smart_brush').style.display = 'none';
762		}
763	};
764	this.desaturate_tool = function (type, mouse, event) {
765		if (mouse.valid == false)
766			return true;
767		var size = GUI.action_data().attributes.size;
768		var xx = mouse.x - size / 2;
769		var yy = mouse.y - size / 2;
770		if (xx < 0)
771			xx = 0;
772		if (yy < 0)
773			yy = 0;
774
775		if (type == 'click') {
776			EDIT.save_state();
777			var imageData = canvas_active().getImageData(xx, yy, size, size);
778			var filtered = ImageFilters.GrayScale(imageData);	//add effect
779			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"), GUI.action_data().attributes.anti_aliasing);
780		}
781		else if (type == 'drag') {
782			var imageData = canvas_active().getImageData(xx, yy, size, size);
783			var filtered = ImageFilters.GrayScale(imageData);	//add effect
784			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"), GUI.action_data().attributes.anti_aliasing);
785		}
786		if (type == 'move' || type == 'drag') {
787			//show size
788			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
789			EL.circle(canvas_front, mouse.x, mouse.y, size);
790		}
791	};
792	this.brush = function (type, mouse, event) {
793		if (mouse.valid == false || (mouse.click_valid == false && type != 'move'))
794			return true;
795		var brush_type = GUI.action_data().attributes.type;
796		var color_rgb = HELPER.hex2rgb(COLOR);
797		var size = parseInt(GUI.action_data().attributes.size);
798		
799		if (type == 'click')
800			EDIT.save_state();
801		
802		if (brush_type == 'Brush') {
803			if (type == 'click') {
804				//init settings
805				canvas_active().beginPath();
806				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
807				canvas_active().lineWidth = size;
808				canvas_active().lineCap = 'round';
809				canvas_active().lineJoin = 'round';
810
811				canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
812				if (ALPHA < 255) {
813					canvas_front.beginPath();
814					canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
815					canvas_front.lineWidth = size;
816					canvas_front.lineCap = 'round';
817					canvas_front.lineJoin = 'round';
818				}
819				
820				//blur
821				canvas_active().shadowBlur = 0;
822				if (GUI.action_data().attributes.anti_aliasing == true) {
823					canvas_active().shadowColor = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
824					canvas_active().shadowBlur = Math.round(size);
825				}
826			}
827			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
828				
829				//detect line size
830				var max_speed = 20;
831				var power = 2; //how speed affects size
832				
833				if (GUI.action_data().attributes.smart_brush == true) {
834					var new_size = size + size / max_speed * mouse.speed_average * power;
835					new_size = Math.max(new_size, size/4);
836					new_size = Math.round(new_size);
837					canvas_front.lineWidth = new_size;		
838					canvas_active().lineWidth = new_size;
839				}
840				else{
841					canvas_front.lineWidth = size;		
842					canvas_active().lineWidth = size;
843				}
844				
845				if (ALPHA == 255)
846					canvas_active().beginPath();
847				canvas_active().moveTo(mouse.last_x, mouse.last_y);
848				canvas_active().lineTo(mouse.x, mouse.y);
849				if (ALPHA == 255)
850					canvas_active().stroke();
851
852				//now draw preview
853				if (ALPHA < 255) {
854					canvas_front.beginPath();
855					//clean from last line
856					canvas_front.globalCompositeOperation = "destination-out";
857					canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", 1)";
858					canvas_front.moveTo(mouse.last_x, mouse.last_y);
859					canvas_front.lineTo(mouse.x, mouse.y);
860					canvas_front.stroke();
861					//reset
862					canvas_front.strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
863					canvas_front.globalCompositeOperation = "source-over";
864					//draw new line segment
865					canvas_front.moveTo(mouse.last_x, mouse.last_y);
866					canvas_front.lineTo(mouse.x, mouse.y);
867					canvas_front.stroke();
868				}
869			}
870			else if (type == 'release') {
871				canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
872				//paint everything
873				canvas_active().stroke();
874
875				//if mouse was not moved
876				if (mouse.click_x == mouse.x && mouse.click_y == mouse.y) {
877					canvas_active().beginPath();
878					canvas_active().arc(mouse.x, mouse.y, size / 2, 0, 2 * Math.PI, false);
879					canvas_active().fillStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
880					canvas_active().fill();
881				}
882				canvas_active().shadowBlur = 0;
883			}
884			else if (type == 'move') {
885				//show size
886				canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
887				EL.circle(canvas_front, mouse.x, mouse.y, size);
888			}
889		}
890		else if (brush_type == 'BezierCurve') {
891			if (type == 'click')
892				BezierCurveBrush.startCurve(mouse.x, mouse.y);
893			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
894				var color_rgb = HELPER.hex2rgb(COLOR);
895				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
896				canvas_active().lineWidth = 0.5;
897
898				BezierCurveBrush.draw(canvas_active(), color_rgb, mouse.x, mouse.y, size);
899			}
900		}
901		else if (brush_type == 'Chrome') {
902			if (type == 'click') {
903				chrome_brush.init(canvas_active());
904				chrome_brush.strokeStart(mouse.x, mouse.y);
905			}
906			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
907				var color_rgb = HELPER.hex2rgb(COLOR);
908				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
909				canvas_active().lineWidth = 1;
910
911				chrome_brush.stroke(color_rgb, mouse.x, mouse.y, size);
912			}
913		}
914		else if (brush_type == 'Fur') {
915			if (type == 'click') {
916				points = new Array();
917				prevMouseX = mouse.x;
918				prevMouseY = mouse.y;
919				count = 0;
920			}
921			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
922				var color_rgb = HELPER.hex2rgb(COLOR);
923				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", 0.1)";
924				canvas_active().lineWidth = 1;
925
926				f = mouse.x;
927				c = mouse.y;
928				var e, b, a, g;
929				points.push([f, c]);
930				canvas_active().beginPath();
931				canvas_active().moveTo(prevMouseX, prevMouseY);
932				canvas_active().lineTo(f, c);
933				canvas_active().stroke();
934				for (e = 0; e < points.length; e++) {
935					b = points[e][0] - points[count][0];
936					a = points[e][1] - points[count][1];
937					g = b * b + a * a;
938					var g_size = Math.round(400 * size);
939					if (g < g_size && Math.random() > g / g_size) {
940						canvas_active().beginPath();
941						canvas_active().moveTo(f + (b * 0.5), c + (a * 0.5));
942						canvas_active().lineTo(f - (b * 0.5), c - (a * 0.5));
943						canvas_active().stroke();
944					}
945				}
946				prevMouseX = f;
947				prevMouseY = c;
948				count++;
949			}
950		}
951		else if (brush_type == 'Grouped') {
952			groups_n = size;
953			gsize = 10;
954			random_power = 5;
955
956			if (type == 'click') {
957				chrome_brush.init(canvas_active());
958				chrome_brush.strokeStart(mouse.x, mouse.y);
959				groups = [];
960
961				for (var g = 0; g < groups_n; g++) {
962					groups[g] = {};
963					groups[g].x = HELPER.getRandomInt(-gsize, gsize);
964					groups[g].y = HELPER.getRandomInt(-gsize, gsize);
965				}
966			}
967			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
968				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
969				canvas_active().lineWidth = 0.5;
970
971				for (var g in groups) {
972					canvas_active().beginPath();
973					canvas_active().moveTo(mouse.last_x + groups[g].x, mouse.last_y + groups[g].y);
974
975					//randomize here
976					groups[g].x += HELPER.getRandomInt(-random_power, random_power);
977					groups[g].y += HELPER.getRandomInt(-random_power, random_power);
978					if (groups[g].x < -gsize)
979						groups[g].x = -gsize + random_power;
980					if (groups[g].y < -gsize)
981						groups[g].y = -gsize + random_power;
982					if (groups[g].x > gsize)
983						groups[g].x = gsize - random_power;
984					if (groups[g].y > gsize)
985						groups[g].y = gsize - random_power;
986
987					canvas_active().lineTo(mouse.x + groups[g].x, mouse.y + groups[g].y);
988					canvas_active().stroke();
989				}
990			}
991		}
992		else if (brush_type == 'Shaded') {
993			if (type == 'click') {
994				shaded_brush.init(canvas_active());
995				shaded_brush.strokeStart(mouse.x, mouse.y);
996			}
997			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
998				var color_rgb = HELPER.hex2rgb(COLOR);
999				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
1000				canvas_active().lineWidth = 1;
1001
1002				shaded_brush.stroke(color_rgb, mouse.x, mouse.y, size);
1003			}
1004		}
1005		else if (brush_type == 'Sketchy') {
1006			if (type == 'click') {
1007				sketchy_brush.init(canvas_active());
1008				sketchy_brush.strokeStart(mouse.x, mouse.y);
1009			}
1010			else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
1011				var color_rgb = HELPER.hex2rgb(COLOR);
1012				canvas_active().strokeStyle = "rgba(" + color_rgb.r + ", " + color_rgb.g + ", " + color_rgb.b + ", " + ALPHA / 255 + ")";
1013				canvas_active().lineWidth = 1;
1014
1015				sketchy_brush.stroke(color_rgb, mouse.x, mouse.y, size);
1016			}
1017		}
1018	};
1019	this.gradient_tool = function (type, mouse, event) {
1020		if (mouse != undefined && mouse.valid == false && type != 'init')
1021			return true;
1022		var power = GUI.action_data().attributes.power;
1023		if (power > 99)
1024			power = 99;
1025
1026		if (type == 'init') {
1027			POP.add({name: "param1", title: "Color #1:", value: '#000000', type: 'color'});
1028			POP.add({name: "param2", title: "Transparency #1:", value: '255', range: [0, 255]});
1029			POP.add({name: "param3", title: "Color #2:", value: '#ffffff', type: 'color'});
1030			POP.add({name: "param4", title: "Transparency #2:", value: '255', range: [0, 255]});
1031			POP.show(
1032				'Gradient', 
1033				function (user_response) {
1034					color1 = HELPER.hex2rgb(user_response.param1);
1035					color1.a = parseInt(user_response.param2);
1036
1037					color2 = HELPER.hex2rgb(user_response.param3);
1038					color2.a = parseInt(user_response.param4);
1039				}
1040			);
1041		}
1042		else if (type == 'drag') {
1043			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1044
1045			if (GUI.action_data().attributes.radial == false) {
1046				//linear
1047				canvas_front.rect(0, 0, WIDTH, HEIGHT);
1048				
1049				var grd = canvas_front.createLinearGradient(
1050					mouse.click_x, mouse.click_y,
1051					mouse.x, mouse.y);
1052				
1053				grd.addColorStop(0, "rgba(" + color1.r + ", " + color1.g + ", " + color1.b + ", " + color1.a / 255 + ")");
1054				grd.addColorStop(1, "rgba(" + color2.r + ", " + color2.g + ", " + color2.b + ", " + color2.a / 255 + ")");
1055				canvas_front.fillStyle = grd;
1056				canvas_front.fill();
1057			}
1058			else {
1059				//radial
1060				var dist_x = mouse.click_x - mouse.x;
1061				var dist_y = mouse.click_y - mouse.y;
1062				var distance = Math.sqrt((dist_x * dist_x) + (dist_y * dist_y));
1063				var radgrad = canvas_front.createRadialGradient(
1064					mouse.click_x, mouse.click_y, distance * power / 100,
1065					mouse.click_x, mouse.click_y, distance);
1066				radgrad.addColorStop(0, "rgba(" + color1.r + ", " + color1.g + ", " + color1.b + ", " + color1.a / 255 + ")");
1067				radgrad.addColorStop(1, "rgba(" + color2.r + ", " + color2.g + ", " + color2.b + ", " + color2.a / 255 + ")");
1068
1069				canvas_front.fillStyle = radgrad;
1070				canvas_front.fillRect(0, 0, WIDTH, HEIGHT);
1071			}
1072			//draw line
1073			canvas_front.beginPath();
1074			canvas_front.strokeStyle = "#ff0000";
1075			canvas_front.lineWidth = 1;
1076			var xx = mouse.x;
1077			var yy = mouse.y;
1078			canvas_front.moveTo(mouse.click_x + 0.5, mouse.click_y + 0.5);
1079			canvas_front.lineTo(xx + 0.5, yy + 0.5);
1080			canvas_front.stroke();
1081		}
1082		else if (type == 'release') {
1083			EDIT.save_state();
1084			if (GUI.action_data().attributes.radial == false) {
1085				//linear
1086				canvas_active().rect(0, 0, WIDTH, HEIGHT);
1087				var grd = canvas_active().createLinearGradient(
1088					mouse.click_x, mouse.click_y,
1089					mouse.x, mouse.y);
1090				
1091				grd.addColorStop(0, "rgba(" + color1.r + ", " + color1.g + ", " + color1.b + ", " + color1.a / 255 + ")");
1092				grd.addColorStop(1, "rgba(" + color2.r + ", " + color2.g + ", " + color2.b + ", " + color2.a / 255 + ")");
1093				canvas_active().fillStyle = grd;
1094				canvas_active().fill();
1095			}
1096			else {
1097				//radial
1098				var dist_x = mouse.click_x - mouse.x;
1099				var dist_y = mouse.click_y - mouse.y;
1100				var distance = Math.sqrt((dist_x * dist_x) + (dist_y * dist_y));
1101				var radgrad = canvas_active().createRadialGradient(
1102					mouse.click_x, mouse.click_y, distance * power / 100,
1103					mouse.click_x, mouse.click_y, distance);
1104				radgrad.addColorStop(0, "rgba(" + color1.r + ", " + color1.g + ", " + color1.b + ", " + color1.a / 255 + ")");
1105				radgrad.addColorStop(1, "rgba(" + color2.r + ", " + color2.g + ", " + color2.b + ", " + color2.a / 255 + ")");
1106
1107				canvas_active().fillStyle = radgrad;
1108				canvas_active().fillRect(0, 0, WIDTH, HEIGHT);
1109			}
1110		}
1111	};
1112	this.blur_tool = function (type, mouse, event) {
1113		if (mouse.valid == false)
1114			return true;
1115		var size = parseInt(GUI.action_data().attributes.size);
1116		var xx = mouse.x - size / 2;
1117		var yy = mouse.y - size / 2;
1118		if (xx < 0)
1119			xx = 0;
1120		if (yy < 0)
1121			yy = 0;
1122		if (type == 'click') {
1123			EDIT.save_state();
1124			var param1 = parseInt(GUI.action_data().attributes.power);
1125			var imageData = canvas_active().getImageData(xx, yy, size, size);
1126			var filtered = ImageFilters.StackBlur(imageData, param1);	//add effect
1127			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"));
1128			
1129			//show size
1130			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1131			EL.circle(canvas_front, mouse.x, mouse.y, size);
1132		}
1133		else if (type == 'drag') {
1134			var param1 = parseInt(GUI.action_data().attributes.power);
1135			var imageData = canvas_active().getImageData(xx, yy, size, size);
1136			var filtered = ImageFilters.StackBlur(imageData, param1);	//add effect
1137			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"));
1138			
1139			//show size
1140			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1141			EL.circle(canvas_front, mouse.x, mouse.y, size);
1142		}
1143		else if (type == 'move') {
1144			//show size
1145			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1146			EL.circle(canvas_front, mouse.x, mouse.y, size);
1147		}
1148	};
1149	this.sharpen_tool = function (type, mouse, event) {
1150		if (mouse.valid == false)
1151			return true;
1152		var size = GUI.action_data().attributes.size;
1153		var param1 = 0.5;
1154		var xx = mouse.x - size / 2;
1155		var yy = mouse.y - size / 2;
1156		if (xx < 0)
1157			xx = 0;
1158		if (yy < 0)
1159			yy = 0;
1160
1161		if (type == 'click') {
1162			EDIT.save_state();
1163			var imageData = canvas_active().getImageData(xx, yy, size, size);
1164			var filtered = ImageFilters.Sharpen(imageData, param1);	//add effect
1165			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"));
1166			
1167			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1168			EL.circle(canvas_front, mouse.x, mouse.y, size);
1169		}
1170		else if (type == 'drag') {
1171			var imageData = canvas_active().getImageData(xx, yy, size, size);
1172			var filtered = ImageFilters.Sharpen(imageData, param1);	//add effect
1173			EL.image_round(canvas_active(), mouse.x, mouse.y, size, filtered, document.getElementById("canvas_front"));
1174			
1175			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1176			EL.circle(canvas_front, mouse.x, mouse.y, size);
1177		}
1178		else if (type == 'move') {
1179			//show size
1180			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1181			EL.circle(canvas_front, mouse.x, mouse.y, size);
1182		}
1183	};
1184	this.burn_dodge_tool = function (type, mouse, event) {
1185		if (mouse.valid == false)
1186			return true;
1187		var size = GUI.action_data().attributes.size;
1188		var power = GUI.action_data().attributes.power * 2.5;
1189
1190		canvas_active().save();
1191		if (type == 'click') {
1192			EDIT.save_state();
1193			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1194			canvas_front.save();
1195			EVENTS.clear_front_on_release = false;
1196
1197			//init settings
1198			canvas_active().beginPath();
1199			canvas_active().lineWidth = GUI.action_data().attributes.size;
1200			canvas_active().lineCap = 'round';
1201			canvas_active().lineJoin = 'round';
1202
1203			canvas_front.beginPath();
1204			if (GUI.action_data().attributes.burn == true)
1205				canvas_front.strokeStyle = "rgba(0, 0, 0, " + power / 255 + ")";
1206			else
1207				canvas_front.strokeStyle = "rgba(255, 255, 255, " + power / 255 + ")";
1208			canvas_front.lineWidth = GUI.action_data().attributes.size;
1209			canvas_front.lineCap = 'round';
1210			canvas_front.lineJoin = 'round';
1211		}
1212		else if (type == 'drag' && mouse.last_x != false && mouse.last_y != false) {
1213			//now draw preview
1214			canvas_front.beginPath();
1215			//clean from last line
1216			canvas_front.globalCompositeOperation = "destination-out";
1217			canvas_front.moveTo(mouse.last_x, mouse.last_y);
1218			canvas_front.lineTo(mouse.x, mouse.y);
1219			canvas_front.stroke();
1220			//reset
1221			canvas_front.globalCompositeOperation = "source-over";
1222			//draw new line segment
1223			canvas_front.moveTo(mouse.last_x, mouse.last_y);
1224			canvas_front.lineTo(mouse.x, mouse.y);
1225			canvas_front.stroke();
1226		}
1227		else if (type == 'release') {
1228			canvas_active().globalCompositeOperation = "soft-light";
1229			canvas_active().drawImage(document.getElementById("canvas_front"), 0, 0);
1230			canvas_active().globalCompositeOperation = "source-over";
1231			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1232			EVENTS.clear_front_on_release = true;
1233			
1234			//if mouse was not moved
1235			if (mouse.click_x == mouse.x && mouse.click_y == mouse.y) {
1236				canvas_active().globalCompositeOperation = "soft-light";
1237				canvas_active().beginPath();
1238				canvas_active().arc(mouse.x, mouse.y, GUI.action_data().attributes.size / 2, 0, 2 * Math.PI, false);
1239				if (GUI.action_data().attributes.burn == true) {
1240					canvas_active().fillStyle = "rgba(0, 0, 0, " + power / 255 + ")";
1241				}
1242				else {
1243					canvas_active().fillStyle = "rgba(255, 255, 255, " + power / 255 + ")";
1244				}
1245				canvas_active().fill();
1246				canvas_active().globalCompositeOperation = "source-over";
1247			}
1248			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1249			canvas_front.restore();
1250		}
1251		else if (type == 'move' && EVENTS.isDrag == false) {
1252			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1253			EL.circle(canvas_front, mouse.x, mouse.y, size);
1254		}
1255		canvas_active().restore();
1256	};
1257	this.crop_tool = function (type, mouse, event) {
1258		if (mouse.click_valid == false)
1259			return true;
1260		
1261		if (type == 'drag') {
1262			if (mouse.x < 0)
1263				mouse.x = 0;
1264			if (mouse.y < 0)
1265				mouse.y = 0;
1266			if (mouse.x >= WIDTH)
1267				mouse.x = WIDTH;
1268			if (mouse.y >= HEIGHT)
1269				mouse.y = HEIGHT;
1270			if (mouse.click_x >= WIDTH)
1271				mouse.click_x = WIDTH;
1272			if (mouse.click_y >= HEIGHT)
1273				mouse.click_y = HEIGHT;
1274			if (this.select_square_action == '') {
1275				document.body.style.cursor = "crosshair";
1276				canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1277				canvas_front.fillStyle = "rgba(0, 255, 0, 0.3)";
1278				canvas_front.fillRect(mouse.click_x, mouse.click_y, mouse.x - mouse.click_x, mouse.y - mouse.click_y);
1279			}
1280		}
1281		else if (type == 'move' && this.select_data != false) {
1282			if (EVENTS.isDrag == true)
1283				return true;
1284			canvas_front.lineWidth = 1;
1285			border_size = 5;
1286			this.select_square_action = '';
1287
1288			if (this.select_square_action == ''
1289				&& mouse.x > this.select_data.x && mouse.y > this.select_data.y
1290				&& mouse.x < this.select_data.x + this.select_data.w && mouse.y < this.select_data.y + this.select_data.h) {
1291				this.select_square_action = 'move';
1292				document.body.style.cursor = 'pointer';
1293			}
1294			if (this.select_square_action == '' && mouse.valid == true)
1295				document.body.style.cursor = "auto";
1296		}
1297		else if (type == 'release') {
1298			if (mouse.x < 0)
1299				mouse.x = 0;
1300			if (mouse.y < 0)
1301				mouse.y = 0;
1302			if (mouse.x >= WIDTH)
1303				mouse.x = WIDTH;
1304			if (mouse.y >= HEIGHT)
1305				mouse.y = HEIGHT;
1306			if (mouse.click_x >= WIDTH)
1307				mouse.click_x = WIDTH;
1308			if (mouse.click_y >= HEIGHT)
1309				mouse.click_y = HEIGHT;
1310
1311			if (this.select_square_action == '') {
1312				if (mouse.x != mouse.click_x && mouse.y != mouse.click_y) {
1313					this.select_data = {
1314						x: Math.min(mouse.x, mouse.click_x),
1315						y: Math.min(mouse.y, mouse.click_y),
1316						w: Math.abs(mouse.x - mouse.click_x),
1317						h: Math.abs(mouse.y - mouse.click_y)
1318					};
1319				}
1320			}
1321			GUI.draw_selected_area(true);
1322
1323			LAYER.update_info_block();
1324		}
1325		else if (type == 'click' && this.select_data != false) {
1326			document.body.style.cursor = "auto";
1327			if (mouse.x > this.select_data.x && mouse.y > this.select_data.y
1328				&& mouse.x < this.select_data.x + this.select_data.w && mouse.y < this.select_data.y + this.select_data.h) {
1329				EDIT.save_state();
1330				for (var i in LAYER.layers) {
1331					var layer = document.getElementById(LAYER.layers[i].name).getContext("2d");
1332
1333					var tmp = layer.getImageData(this.select_data.x, this.select_data.y, this.select_data.w, this.select_data.h);
1334					layer.clearRect(0, 0, WIDTH, HEIGHT);
1335					layer.putImageData(tmp, 0, 0);
1336				}
1337				
1338				//resize
1339				WIDTH = this.select_data.w;
1340				HEIGHT = this.select_data.h;
1341				LAYER.set_canvas_size();
1342
1343				EDIT.edit_clear();
1344			}
1345		}
1346	};
1347	this.clone_tool = function (type, mouse, event) {
1348		if (mouse.valid == false)
1349			return true;
1350		var size = GUI.action_data().attributes.size;
1351		var size_half = Math.round(size / 2);
1352
1353		if (type == 'click') {
1354			EDIT.save_state();
1355
1356			if (clone_data === false) {
1357				POP.add({html: 'Source is empty, right click on image first.'});
1358				POP.show('Error', '');
1359			}
1360			else {
1361				//draw rounded image
1362				EL.image_round(canvas_active(), mouse.x, mouse.y, size, clone_data, document.getElementById("canvas_front"), GUI.action_data().attributes.anti_aliasing);
1363			}
1364		}
1365		else if (type == 'right_click') {
1366			//save clone source
1367			clone_data = document.createElement("canvas");
1368			clone_data.width = size;
1369			clone_data.height = size;
1370			var xx = mouse.x - size_half;
1371			var yy = mouse.y - size_half;
1372			if (xx < 0)
1373				xx = 0;
1374			if (yy < 0)
1375				yy = 0;
1376			clone_data.getContext("2d").drawImage(canvas_active(true), xx, yy, size, size, 0, 0, size, size);
1377			return false;
1378		}
1379		else if (type == 'drag') {
1380			if (event.which == 3)
1381				return true;
1382			if (clone_data === false)
1383				return false;	//no source
1384
1385			//draw rounded image
1386			EL.image_round(canvas_active(), mouse.x, mouse.y, size, clone_data, document.getElementById("canvas_front"), GUI.action_data().attributes.anti_aliasing);
1387		}
1388		else if (type == 'move') {
1389			//show size
1390			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1391			EL.circle(canvas_front, mouse.x, mouse.y, size);
1392		}
1393	};
1394	this.select_square = function (type, mouse, event) {
1395		if (mouse.click_valid == false)
1396			return true;
1397		if (type == 'drag') {
1398			if (mouse.x < 0)
1399				mouse.x = 0;
1400			if (mouse.y < 0)
1401				mouse.y = 0;
1402			if (mouse.x >= WIDTH)
1403				mouse.x = WIDTH;
1404			if (mouse.y >= HEIGHT)
1405				mouse.y = HEIGHT;
1406			if (mouse.click_x >= WIDTH)
1407				mouse.click_x = WIDTH;
1408			if (mouse.click_y >= HEIGHT)
1409				mouse.click_y = HEIGHT;
1410			if (this.select_square_action == '') {
1411				//user still selecting area
1412				document.body.style.cursor = "crosshair";
1413				canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1414				canvas_front.fillStyle = "rgba(0, 255, 0, 0.3)";
1415				canvas_front.fillRect(mouse.click_x, mouse.click_y, mouse.x - mouse.click_x, mouse.y - mouse.click_y);
1416			}
1417			else {
1418				//drag
1419				if (this.select_square_action == 'move') {
1420					//move
1421					try {
1422						canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1423						canvas_front.drawImage(canvas_active(true),
1424							this.select_data.x, this.select_data.y, this.select_data.w, this.select_data.h,
1425							mouse.x - mouse.click_x + this.select_data.x,
1426							mouse.y - mouse.click_y + this.select_data.y,
1427							this.select_data.w,
1428							this.select_data.h);
1429						canvas_front.restore();
1430					}
1431					catch (err) {
1432						console.log("Error: " + err.message);
1433					}
1434				}
1435				else {
1436					//resize
1437					var s_x = this.select_data.x;
1438					var s_y = this.select_data.y;
1439					var d_x = this.select_data.w;
1440					var d_y = this.select_data.h;
1441					if (this.select_square_action == 'resize-left') {
1442						s_x += mouse.x - mouse.click_x;
1443						d_x -= mouse.x - mouse.click_x;
1444					}
1445					else if (this.select_square_action == 'resize-right')
1446						d_x += mouse.x - mouse.click_x;
1447					else if (this.select_square_action == 'resize-top') {
1448						s_y += mouse.y - mouse.click_y;
1449						d_y -= mouse.y - mouse.click_y;
1450					}
1451					else if (this.select_square_action == 'resize-bottom')
1452						d_y += mouse.y - mouse.click_y;
1453					else if (this.select_square_action == 'resize-1') {
1454						s_x += mouse.x - mouse.click_x;
1455						s_y += mouse.y - mouse.click_y;
1456						d_x -= mouse.x - mouse.click_x;
1457						d_y -= mouse.y - mouse.click_y;
1458					}
1459					else if (this.select_square_action == 'resize-2') {
1460						d_x += mouse.x - mouse.click_x;
1461						s_y += mouse.y - mouse.click_y;
1462						d_y -= mouse.y - mouse.click_y;
1463					}
1464					else if (this.select_square_action == 'resize-3') {
1465						d_x += mouse.x - mouse.click_x;
1466						d_y += mouse.y - mouse.click_y;
1467					}
1468					else if (this.select_square_action == 'resize-4') {
1469						s_x += mouse.x - mouse.click_x;
1470						d_x -= mouse.x - mouse.click_x;
1471						d_y += mouse.y - mouse.click_y;
1472					}
1473					var s_x = Math.max(s_x, 0);
1474					var s_y = Math.max(s_y, 0);
1475					var d_x = Math.max(d_x, 0);
1476					var d_y = Math.max(d_y, 0);
1477
1478					canvas_front.save();
1479					canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1480					
1481					canvas_front.webkitImageSmoothingEnabled = false;
1482					canvas_front.msImageSmoothingEnabled = false;
1483					canvas_front.imageSmoothingEnabled = false;
1484					
1485					canvas_front.drawImage(canvas_active(true),
1486						this.select_data.x, this.select_data.y, this.select_data.w, this.select_data.h,
1487						s_x, s_y, d_x, d_y);
1488					canvas_front.restore();
1489				}
1490			}
1491		}
1492		else if (type == 'move' && this.select_data != false) {
1493			if (EVENTS.isDrag == true)
1494				return true;
1495			canvas_front.lineWidth = 1;
1496			border_size = 5;
1497			this.select_square_action = '';
1498			var sr_size = Math.ceil(EVENTS.sr_size / GUI.ZOOM * 100);
1499
1500			//left
1501			if (this.check_mouse_pos(this.select_data.x, this.select_data.y + this.select_data.h / 2, sr_size, mouse.x, mouse.y) == true) {
1502				document.body.style.cursor = "w-resize";
1503				this.select_square_action = 'resize-left';
1504			}
1505			//top
1506			else if (this.check_mouse_pos(this.select_data.x + this.select_data.w / 2, this.select_data.y, sr_size, mouse.x, mouse.y) == true) {
1507				document.body.style.cursor = "n-resize";
1508				this.select_square_action = 'resize-top';
1509			}
1510			//right
1511			else if (this.check_mouse_pos(this.select_data.x + this.select_data.w - sr_size, this.select_data.y + this.select_data.h / 2, sr_size, mouse.x, mouse.y) == true) {
1512				document.body.style.cursor = "w-resize";
1513				this.select_square_action = 'resize-right';
1514			}
1515			//bottom
1516			else if (this.check_mouse_pos(this.select_data.x + this.select_data.w / 2, this.select_data.y + this.select_data.h - sr_size, sr_size, mouse.x, mouse.y) == true) {
1517				document.body.style.cursor = "n-resize";
1518				this.select_square_action = 'resize-bottom';
1519			}
1520
1521			//corner 1
1522			if (this.check_mouse_pos(this.select_data.x, this.select_data.y, sr_size, mouse.x, mouse.y) == true) {
1523				document.body.style.cursor = "nw-resize";
1524				this.select_square_action = 'resize-1';
1525			}
1526			//corner 2
1527			else if (this.check_mouse_pos(this.select_data.x + this.select_data.w - sr_size, this.select_data.y, sr_size, mouse.x, mouse.y) == true) {
1528				document.body.style.cursor = "ne-resize";
1529				this.select_square_action = 'resize-2';
1530			}
1531			//corner 3
1532			else if (this.check_mouse_pos(this.select_data.x + this.select_data.w - sr_size, this.select_data.y + this.select_data.h - sr_size, sr_size, mouse.x, mouse.y) == true) {
1533				document.body.style.cursor = "nw-resize";
1534				this.select_square_action = 'resize-3';
1535			}
1536			//corner 4
1537			else if (this.check_mouse_pos(this.select_data.x, this.select_data.y + this.select_data.h - sr_size, sr_size, mouse.x, mouse.y) == true) {
1538				document.body.style.cursor = "ne-resize";
1539				this.select_square_action = 'resize-4';
1540			}
1541
1542			if (this.select_square_action == ''
1543				&& mouse.x > this.select_data.x && mouse.y > this.select_data.y
1544				&& mouse.x < this.select_data.x + this.select_data.w && mouse.y < this.select_data.y + this.select_data.h) {
1545				this.select_square_action = 'move';
1546				document.body.style.cursor = "move";
1547			}
1548			if (this.select_square_action == '' && mouse.valid == true)
1549				document.body.style.cursor = "auto";
1550		}
1551		else if (type == 'release') {
1552			if (mouse.x < 0)
1553				mouse.x = 0;
1554			if (mouse.y < 0)
1555				mouse.y = 0;
1556			if (mouse.x >= WIDTH)
1557				mouse.x = WIDTH;
1558			if (mouse.y >= HEIGHT)
1559				mouse.y = HEIGHT;
1560			if (mouse.click_x >= WIDTH)
1561				mouse.click_x = WIDTH;
1562			if (mouse.click_y >= HEIGHT)
1563				mouse.click_y = HEIGHT;
1564
1565			if (this.select_square_action == '') {
1566				if (mouse.x != mouse.click_x && mouse.y != mouse.click_y) {
1567					this.select_data = {
1568						x: Math.min(mouse.x, mouse.click_x),
1569						y: Math.min(mouse.y, mouse.click_y),
1570						w: Math.abs(mouse.x - mouse.click_x),
1571						h: Math.abs(mouse.y - mouse.click_y)
1572					};
1573				}
1574			}
1575			else {
1576				if (mouse.x - mouse.click_x == 0 && mouse.y - mouse.click_y == 0)
1577					return false;				
1578				EDIT.save_state();
1579				
1580				if (this.select_square_action == 'move') {
1581					//move selected area
1582					if (this.select_data != false) {
1583						canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1584						canvas_front.drawImage(canvas_active(true), 0, 0);
1585						canvas_active().clearRect(this.select_data.x, this.select_data.y, this.select_data.w, this.select_data.h);
1586						canvas_active().drawImage(
1587							document.getElementById("canvas_front"),
1588							this.select_data.x, this.select_data.y,
1589							this.select_data.w, this.select_data.h,
1590							mouse.x - mouse.click_x + this.select_data.x, mouse.y - mouse.click_y + this.select_data.y,
1591							this.select_data.w, this.select_data.h);
1592							
1593						canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1594					}
1595					this.select_data.x += mouse.x - mouse.click_x;
1596					this.select_data.y += mouse.y - mouse.click_y;
1597				}
1598				else {
1599					//resize selected area
1600					var s_x = this.select_data.x;
1601					var s_y = this.select_data.y;
1602					var d_x = this.select_data.w;
1603					var d_y = this.select_data.h;
1604
1605					if (this.select_square_action == 'resize-left') {
1606						s_x += mouse.x - mouse.click_x;
1607						d_x -= mouse.x - mouse.click_x;
1608					}
1609					else if (this.select_square_action == 'resize-right')
1610						d_x += mouse.x - mouse.click_x;
1611					else if (this.select_square_action == 'resize-top') {
1612						s_y += mouse.y - mouse.click_y;
1613						d_y -= mouse.y - mouse.click_y;
1614					}
1615					else if (this.select_square_action == 'resize-bottom')
1616						d_y += mouse.y - mouse.click_y;
1617					else if (this.select_square_action == 'resize-1') {
1618						s_x += mouse.x - mouse.click_x;
1619						s_y += mouse.y - mouse.click_y;
1620						d_x -= mouse.x - mouse.click_x;
1621						d_y -= mouse.y - mouse.click_y;
1622					}
1623					else if (this.select_square_action == 'resize-2') {
1624						d_x += mouse.x - mouse.click_x;
1625						s_y += mouse.y - mouse.click_y;
1626						d_y -= mouse.y - mouse.click_y;
1627					}
1628					else if (this.select_square_action == 'resize-3') {
1629						d_x += mouse.x - mouse.click_x;
1630						d_y += mouse.y - mouse.click_y;
1631					}
1632					else if (this.select_square_action == 'resize-4') {
1633						s_x += mouse.x - mouse.click_x;
1634						d_x -= mouse.x - mouse.click_x;
1635						d_y += mouse.y - mouse.click_y;
1636					}
1637					var s_x = Math.max(s_x, 0);
1638					var s_y = Math.max(s_y, 0);
1639					var d_x = Math.max(d_x, 0);
1640					var d_y = Math.max(d_y, 0);
1641
1642					var tempCanvas = document.createElement("canvas");
1643					var tempCtx = tempCanvas.getContext("2d");
1644					tempCanvas.width = Math.max(d_x, this.select_data.w);
1645					tempCanvas.height = Math.max(d_y, this.select_data.h);
1646					tempCtx.drawImage(canvas_active(true), this.select_data.x, this.select_data.y, this.select_data.w, this.select_data.h, 0, 0, this.select_data.w, this.select_data.h);
1647
1648					canvas_active().clearRect(s_x, s_y, d_x, d_y);
1649					canvas_active().drawImage(tempCanvas, 0, 0, this.select_data.w, this.select_data.h, s_x, s_y, d_x, d_y);
1650
1651					this.select_data.x = s_x;
1652					this.select_data.y = s_y;
1653					this.select_data.w = d_x;
1654					this.select_data.h = d_y;
1655				}
1656			}
1657			GUI.draw_selected_area();
1658			LAYER.update_info_block();
1659		}
1660	};
1661
1662	this.check_mouse_pos = function (x, y, size, mouse_x, mouse_y) {
1663		if (mouse_x > x - Math.round(size) && mouse_x < x + Math.round(size))
1664			if (mouse_y > y - Math.round(size) && mouse_y < y + Math.round(size))
1665				return true;
1666		return false;
1667	};
1668	
1669	this.bulge_pinch_tool = function (type, mouse, event) {
1670		if (mouse.valid == false)
1671			return true;
1672		
1673		//make sure FX lib loaded
1674		if(fx_filter == false){
1675			fx_filter = fx.canvas();
1676		}
1677		
1678		var strength = GUI.action_data().attributes.size / 100;
1679		if(strength > 1)
1680			strength = 1;
1681		var radius = parseInt(GUI.action_data().attributes.radius);
1682		var bulge = GUI.action_data().attributes.bulge;
1683		if(bulge == false)
1684			strength = -1 * strength;
1685
1686		if (type == 'click') {
1687			EDIT.save_state();
1688			
1689			var texture = fx_filter.texture(canvas_active(true));
1690			fx_filter.draw(texture).bulgePinch(mouse.x, mouse.y, radius, strength).update();	//effect
1691			canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
1692			canvas_active().drawImage(fx_filter, 0, 0);
1693			GUI.zoom();
1694		}
1695		if (type == 'move') {
1696			var texture = fx_filter.texture(canvas_active(true));
1697			fx_filter.draw(texture).bulgePinch(mouse.x, mouse.y, radius, strength).update();	//effect
1698			canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
1699			canvas_front.drawImage(fx_filter, 0, 0);
1700		}
1701	};
1702}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.