# generic widgets for canvas dialogs
# Thorsten Renk 2018

# widget definitions ##############################################################

var cdlg_widget_box = {
	new: func (root, width, height, color, fill_color ) {
 	var wb = { parents: [cdlg_widget_box] };
		
	wb.width = width;
	wb.height = height;
	wb.color = color;
	wb.fill_color = fill_color;

	wb.graph = root.createChild("group", "box_widget");

	#var data = [[0.0, 0.0], [0.0, height], [width, height], [width, 0.0], [0.0, 0.0]];
	
	var data = [[0.0, 0.0], [-0.5 * width, 0.0], [-0.5*width, -height], [0.5*width, -height], [0.5*width, 0.0], [0.0, 0.0]];

	wb.frame = wb.graph.createChild("path", "")
        .setStrokeLineWidth(2)
        .setColor(color)
	.moveTo(data[0][0], data[0][1]);
	for (var i = 0; (i< size(data)-1); i=i+1) 
		{wb.frame.lineTo(data[i+1][0], data[i+1][1]);}

	wb.fill = wb.graph.createChild("path", "")
        .setStrokeLineWidth(2)
        .setColor(color)
	.setColorFill(fill_color)
	.moveTo(data[0][0], data[0][1]);
	for (var i = 0; (i< size(data)-1); i=i+1) 
		{wb.fill.lineTo(data[i+1][0], data[i+1][1]);}

	return wb;
	},


	setTranslation: func (x,y) {
		me.graph.setTranslation(x,y);

	},

	setPercentageHt: func (x) {

		if (x > 1.0)
			{x = 1.0;}
		else if (x < 0.0) {x = 0.0;}

		var red_ht = me.height * x;

		var cmd = [canvas.Path.VG_MOVE_TO, canvas.Path.VG_LINE_TO,
	  		canvas.Path.VG_LINE_TO,canvas.Path.VG_LINE_TO,canvas.Path.VG_LINE_TO];

		var draw = [0.0, 0.0, -0.5 * me.width, 0.0, -0.5*me.width, -red_ht, 0.5*me.width, -red_ht, 0.5*me.width, 0.0, 0.0, 0.0];


		me.fill.setData(cmd, draw);

	},

	setContextHelp: func (f) {

			me.frame.addEventListener("mouseover", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'left-right'}));
			f("mouseover");
		  	});

			me.frame.addEventListener("mouseout", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'inherit'}));
			f("mouseout");
		  	});

			me.fill.addEventListener("mouseover", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'left-right'}));
			f("mouseover");
		  	});

			me.fill.addEventListener("mouseout", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'inherit'}));
			f("mouseout");
		  	});



	},


};



# tank gauge ##############################################################

var cdlg_widget_tank = {
	new: func (root, radius, color, fill_color) {
	 	var wtk = { parents: [cdlg_widget_tank] };
		
		wtk.radius = radius;
		wtk.color = color;
		wtk.fill_color = fill_color;

		wtk.graph = root.createChild("group", "tank_widget");

		var data = [];


		for (var i = 0; i< 33; i=i+1)
			{
			var phi = i * 2.0 * math.pi/32.0;

			var x = radius * math.cos(phi);
			var y = radius * math.sin(phi);

			append(data, [x,y]);
			}


		wtk.frame = wtk.graph.createChild("path", "")
		.setStrokeLineWidth(2)
		.setColor(color)
		.moveTo(data[0][0], data[0][1]);
		for (var i = 0; (i< size(data)-1); i=i+1) 
			{wtk.frame.lineTo(data[i+1][0], data[i+1][1]);}

		wtk.fill = wtk.graph.createChild("path", "")
		.setStrokeLineWidth(2)
		.setColor(color)
		.setColorFill(fill_color)
		.moveTo(data[0][0], data[0][1]);
		for (var i = 0; (i< size(data)-1); i=i+1) 
			{wtk.fill.lineTo(data[i+1][0], data[i+1][1]);}



		return wtk;
	},

	setTranslation: func (x,y) {
		me.graph.setTranslation(x,y);

	},

	setPercentage: func (x) {

		if (x > 1.0)
			{x = 1.0;}
		else if (x < 0.0) {x = 0.0;}

		var red_ht = me.radius -2.0 * me.radius * x;
		var arg = me.radius * me.radius - red_ht * red_ht;
		if (arg < 0.0) {arg = 0.0;}

		var xlimit = math.sqrt(arg);
		
		var draw = [];
		var cmd = [];

		for (var i = 0; i< 33; i=i+1)
			{
			var phi = i * 2.0 * math.pi/32.0;

			var x = me.radius * math.cos(phi);
			var y = me.radius * math.sin(phi);

			
			if (y < red_ht) { y = red_ht; if (x>0.0) {x = xlimit;} else {x=-xlimit;} }

			append(draw,x);
			append(draw,y);
			append(cmd, canvas.Path.VG_LINE_TO);
			}

		cmd[0] = canvas.Path.VG_MOVE_TO; 

		me.fill.setData(cmd, draw);		

	},


	setContextHelp: func (f) {

			me.frame.addEventListener("mouseover", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'left-right'}));
			f("mouseover");
		  	});

			me.frame.addEventListener("mouseout", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'inherit'}));
			f("mouseout");
		  	});

			me.fill.addEventListener("mouseover", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'left-right'}));
			f("mouseover");
		  	});

			me.fill.addEventListener("mouseout", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'inherit'}));
			f("mouseout");
		  	});



	},


};


# property display labels ##############################################################

var cdlg_widget_property_label = {
	new: func (root, text, text_color = nil, color = nil, fill_color = nil ) {
 	var pl = { parents: [cdlg_widget_property_label] };
		
	pl.text_string = text;
	pl.unit_string = "";
	pl.unit_set = 0;
	pl.size = utf8.size(text);
	pl.limits = 0;
	pl.limit_upper = 1e6;
	pl.limit_lower = -1e6;
	pl.limit_violation = 0;

	if (text_color == nil) {text_color = [0.0, 0.0, 0.0];}
	pl.text_color = text_color;

	pl.font_scale_factor = 1.0;

	if (color == nil) 
		{pl.box_mode = 0;}
	else
		{
		pl.color = color;
		pl.box_mode = 1;
		}

	if (fill_color == nil)
		{
		pl.box_fill = 0;
		}
	else
		{
		pl.box_fill = 1;
		pl.fill_color = fill_color;
		}



	pl.graph = root.createChild("group", "property_label");



	if (pl.box_mode == 1)
		{
		var height = 25.0;
		var width = 10.0 * pl.size;
		var data = [[0.0, -0.8 * height], [-0.5 * width, -0.8 * height], [-0.5 * width, 0.2 * height], [0.5 * width, 0.2 * height], [0.5 * width, -0.8 * height],[0.0, -0.8 * height]];
		pl.box = pl.graph.createChild("path", "")
		.setStrokeLineWidth(2)
		.setColor(color)
		.moveTo(data[0][0], data[0][1]);
		for (var i = 0; (i< size(data)-1); i=i+1) 
			{pl.box.lineTo(data[i+1][0], data[i+1][1]);}

		if (pl.box_fill == 1)
			{
			pl.box.setColorFill(fill_color);
			}
		}

	
	pl.text = pl.graph.createChild("text")
      		.setText(text)
		.setColor(text_color)
		.setFontSize(15)
		#.setFont("LiberationFonts/LiberationMono-Bold.ttf")
		.setFont("LiberationFonts/LiberationSans-Bold.ttf")
		.setAlignment("center-bottom")
		.setRotation(0.0);

	pl.text.enableUpdate();

	pl.text.setTranslation(0.0, pl.getOffset(text));
	if (pl.box_mode == 1)
		{
		pl.box.setTranslation(0.0, -pl.getOffset(text));
		}
	
	return pl;
	},

	setTranslation: func (x,y) {
		me.graph.setTranslation(x,y);

	},

	updateText: func (text) {

		me.text.updateText(text);
	},

	setText: func (text) {

		me.text.setText(text);
	},
	
	
	setValue: func (value) {
	
		if (me.limits == 1)
			{
			me.check_limits(value);
			}
		me.text.updateText(me.formatValue(value));
	},
	
	formatValue: func (value) {
	
		var textString = me.formatFunction(value);
		return textString~me.unit_text;
	},
	
	
	formatFunction: func (value) {
	
		return sprintf("%0.0f", value);	
	},
	
	
	setUnit: func (unit) {
		
		me.unit_text = unit;
		me.unit_set = 1;
	
	},
	
	setLimits: func (lLower, lUpper) {
		me.limits = 1;
		me.limit_upper = lUpper;
		me.limit_lower = lLower;
	
	},
	
	check_limits: func (value) {
	
		if ((value < me.limit_lower) or (value > me.limit_upper))
			{
			if (me.limit_violation == 0)
				{
				me.text.setColor(1.0, 0.0, 0.0);
				me.limit_violation = 1;
				}
			}
		else	
			{
			if (me.limit_violation == 1)
				{
				me.text.setColor(me.text_color);
				me.limit_violation = 0;
				}
			}
	
	},

	setFont: func (font) {

		me.text.setFont(font);
	},

	setFontSize: func (size) {

		me.font_scale_factor = size/15.0;
		me.text.setFontSize(size);
	},

	setScale: func (x,y = nil) {

		me.graph.setScale(x,y);
	},

	setBoxScale: func (x,y = nil) {

		if (me.box_mode == 0) {return;}
		me.box.setScale(x,y);
	},

 

	getOffset: func (string) {
		return 0.0;
		var flag = 0;
		for (var i = 0; i < utf8.size(string); i=i+1)
			{
			var char = utf8.strc(string, i);

			if ((char == "y") or (char == "g") or (char == "j") or (char == "p") or (char == "q"))
				{
				flag == 1; break;
				}
			}
		if (flag == 0) {return -2.0;}
		else {return 0.0;}
	},

};

# infobox  ##############################################################

var cdlg_widget_infobox = {
	new: func (root, width, title, texts, corner_radius = 0.0, frame_color = nil, title_color = nil, title_fill = nil, text_color = nil, text_fill = nil) {

		var ib = { parents: [cdlg_widget_infobox] };
		
		ib.width = width;
		ib.title = title;
		ib.texts = texts;

		ib.unit = "";

		if (title_color == nil) {title_color = [0.0, 0.0, 0.0];}
		if (text_color == nil) {text_color = [0.0, 0.0, 0.0];}
		if (frame_color == nil) {frame_color = [0.0, 0.0, 0.0];}

		ib.title_color = title_color;
		ib.title_fill =  title_fill;
		ib.text_color = text_color;
		ib.text_fill = text_fill;
		ib.frame_color = frame_color;

		ib.font_size = 15;
		ib.num_lines = size(texts);
		ib.num_columns = size(texts[0]);
		ib.font_height = 25.0;

		ib.height = (ib.num_lines + 1) * ib.font_height;
		ib.corner_radius = corner_radius;


		ib.graph = root.createChild("group", "infobox");



		var data = [];
		var point = [0.0, -0.7* ib.font_height]; append(data, point);

		point = [ib.width * 0.5 - ib.corner_radius, - 0.7* ib.font_height]; append(data, point);
		point = [ib.width * 0.5 - ib.corner_radius * 0.617, - 0.7* ib.font_height + ib.corner_radius * 0.076]; append(data, point);
		point = [ib.width * 0.5 - ib.corner_radius * 0.293, - 0.7* ib.font_height + ib.corner_radius * 0.293]; append(data, point);
		point = [ib.width * 0.5 - ib.corner_radius * 0.076, - 0.7* ib.font_height + ib.corner_radius * 0.617]; append(data, point);
		point = [ib.width * 0.5, - 0.7* ib.font_height + ib.corner_radius]; append(data, point);

		point = [ib.width * 0.5, 0.3 * ib.font_height]; append(data, point);
		point = [-ib.width * 0.5, 0.3 * ib.font_height]; append(data, point);

		point = [-ib.width * 0.5, -0.7* ib.font_height + ib.corner_radius]; append(data, point);
		point = [-ib.width * 0.5 + ib.corner_radius * 0.076, -0.7* ib.font_height + ib.corner_radius * 0.617]; append(data, point);
		point = [-ib.width * 0.5 + ib.corner_radius * 0.293, -0.7* ib.font_height + ib.corner_radius * 0.293]; append(data, point);
		point = [-ib.width * 0.5 + ib.corner_radius * 0.617, -0.7* ib.font_height + ib.corner_radius * 0.076]; append(data, point);
		point = [-ib.width * 0.5 + ib.corner_radius, -0.7* ib.font_height]; append(data, point);
		point = [0.0, - 0.7 * ib.font_height]; append(data, point);

		ib.title_frame = ib.graph.createChild("path", "")
		.setStrokeLineWidth(2)
		.setColor(ib.frame_color)
		.moveTo(data[0][0], data[0][1]);
		for (var i = 0; (i< size(data)-1); i=i+1) 
			{ib.title_frame.lineTo(data[i+1][0], data[i+1][1]);}

		if (ib.title_fill != nil)
			{
			ib.title_frame.setColorFill(ib.title_fill);
			}


		data = [];


		point = [0.0, 0.3* ib.font_height]; append(data, point);
		point = [ib.width * 0.5, 0.3 * ib.font_height]; append(data, point);

		point = [ib.width * 0.5, 10.0 + ib.num_lines *  ib.font_height - ib.corner_radius]; append(data, point);
		point = [ib.width * 0.5 - ib.corner_radius * 0.293, 10.0 + ib.num_lines *  ib.font_height - ib.corner_radius * 0.293]; append(data, point);
		point = [ib.width * 0.5 - ib.corner_radius, 10.0 + ib.num_lines *  ib.font_height]; append(data, point);


		point = [-ib.width * 0.5 + ib.corner_radius, 10.0 + ib.num_lines *  ib.font_height]; append(data, point);
		point = [-ib.width * 0.5 + ib.corner_radius * 0.293, 10.0 + ib.num_lines *  ib.font_height - ib.corner_radius * 0.293]; append(data, point);
		point = [-ib.width * 0.5, 10.0 + ib.num_lines *  ib.font_height - ib.corner_radius]; append(data, point);

		point = [-ib.width * 0.5, 0.3 * ib.font_height]; append(data, point);
		point = [0.0, 0.3 * ib.font_height]; append(data, point);

		ib.text_frame = ib.graph.createChild("path", "")
		.setStrokeLineWidth(2)
		.setColor(ib.frame_color)
		.moveTo(data[0][0], data[0][1]);
		for (var i = 0; (i< size(data)-1); i=i+1) 
			{ib.text_frame.lineTo(data[i+1][0], data[i+1][1]);}

		if (ib.text_fill != nil)
			{
			ib.text_frame.setColorFill(ib.text_fill);
			}

		var offset = me.getOffset(title);

		ib.title_text = ib.graph.createChild("text")
	      		.setText(title)
			.setColor(text_color)
			.setFontSize(15)
			.setFont("LiberationFonts/LiberationSans-Bold.ttf")
			.setAlignment("center-bottom")
			.setTranslation(0, offset)
			.setRotation(0.0);

		ib.texts = [];
		ib.values = [];

		for (var i = 0; i< ib.num_lines; i=i+1)
			{

			var translation = 0.0;
			var alignment = "center-bottom";

			if (ib.num_columns == 2)
				{
				translation = -0.45 * ib.width;
				alignment = "left-bottom";
				}



			var tmp_text = ib.graph.createChild("text")
	      		.setText(texts[i][0])
			.setColor(text_color)
			.setFontSize(15)
			.setFont("LiberationFonts/LiberationSans-Bold.ttf")
			.setAlignment(alignment)
			.setTranslation(translation, 5.0 + (i+1) * ib.font_height)
			.setRotation(0.0);

			tmp_text.enableUpdate();

			if (ib.num_columns == 2)
				{
				append (ib.texts, tmp_text);
				}
			else
				{
				append (ib.values, tmp_text);
				}

			if (ib.num_columns == 2)
				{
				var tmp_value = ib.graph.createChild("text")
		      		.setText(texts[i][1])
				.setColor(text_color)
				.setFontSize(15)
				.setFont("LiberationFonts/LiberationSans-Bold.ttf")
				.setAlignment("left-bottom")
				.setTranslation(0.05 * ib.width, 5.0 + (i+1) * ib.font_height)
				.setRotation(0.0);

				tmp_value.enableUpdate();

				append (ib.values, tmp_value);

				}
			


			}


		return ib;

	}, 

	setTranslation: func (x,y) {

		me.graph.setTranslation(x,y);

	},


	setText: func (i, text) {
		
		me.texts[i].updateText(text);

	},

	setValueText: func (i, text) {
		
		me.values[i].updateText(text);

	},

	setUnit: func (unit) {

		me.unit = unit;

	},

	setValue: func (i, value) {
		
		var text = me.formatFunction(value)~me.unit;

		me.values[i].updateText(text);
	

	},

	formatFunction: func (value) {

		return sprintf("%d", value);

	},

	getOffset: func (string) {
		var flag = 0;
		for (var i = 0; i < utf8.size(string); i=i+1)
			{
			var char = utf8.strc(string, i);
			#print (char);

			if ((char == 112) or (char == 121) or (char == 106) or (char == 103) or (char == 113))
				{
				flag = 1; break;
				}
			}
		if (flag == 1) {return 4.0;}
		else {return 0.0;}
	},


};

# image stack ##############################################################

var cdlg_widget_img_stack = {

	new: func (root, stack, width, height, button_flag = 0) {
	 	var is = { parents: [cdlg_widget_img_stack] };
		
		is.root = root;
		is.width = width;
		is.height = height;
		is.index = 0;	
		is.button_flag = button_flag;

		is.n_elements = size(stack);
		
		is.stack = [];
		is.graph = root.createChild("group", "stack");

		for (var i = 0; i< is.n_elements; i = i+1)
			{

			
			var tmp_image = is.graph.createChild("image")
					.setFile(stack[i]);

			tmp_image.setVisible(0);

			append(is.stack, tmp_image);
			}

		is.stack[0].setVisible(1);


		is.graph.addEventListener("click", func() {

			if (is.button_flag == 0)
				{is.increment();}
			else if (is.button_flag == 1)
			   	{is.depress();}

			is.f();
		  	});

		return is;

	},

	setTranslation: func (x,y) {


		me.graph.setTranslation(x,y);

	},

	
	increment: func {

		me.index += 1;

		if (me.index == me.n_elements) {me.index = 0;}

		for (var i=0; i< me.n_elements; i=i+1)
			{
			if (me.index == i)
				{
				me.stack[i].setVisible(1);
				}
			else
				{
				me.stack[i].setVisible(0);
				}
			
			}

	},

	set_index: func (index) {

		me.index = index;

		if ((me.index > me.n_elements) or (me.index < 0)) {return;}

		for (var i=0; i< me.n_elements; i=i+1)
			{
			if (me.index == i)
				{
				me.stack[i].setVisible(1);
				}
			else
				{
				me.stack[i].setVisible(0);
				}
			
			}

	},

	depress: func {

		me.index = 1;
		me.stack[1].setVisible(1);
		me.stack[0].setVisible(0);

		settimer ( func {
			me.index = 0;
			me.stack[1].setVisible(0);
			me.stack[0].setVisible(1);

			}, 0.2);

	},

	setContextHelp: func (f) {

			me.graph.addEventListener("mouseover", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'left-right'}));
			f("mouseover");
		  	});

			me.graph.addEventListener("mouseout", func(e) {
			fgcommand("set-cursor", props.Node.new({'cursor':'inherit'}));
			f("mouseout");
		  	});



	},

	f: func {


		return;

	},



};

# analog gauge ##############################################################

var cdlg_widget_analog_gauge = {
	new: func (root, gauge_bg, gauge_needle , width, height) {
 	var ag = { parents: [cdlg_widget_analog_gauge] };

	ag.graph = root.createChild("group", "analog gauge");

	ag.gauge_background = ag.graph.createChild("image")
			.setFile(gauge_bg);

	ag.gauge_needle = ag.graph.createChild("image")
			.setFile(gauge_needle);

	ag.gauge_needle.setCenter(127,127);

	return ag;
	},

	setTranslation: func (x,y) {

		me.graph.setTranslation(x,y);

	},


	setAngle: func (angle) {

		me.gauge_needle.setRotation(angle);

	},

};


# clickspots ##############################################################

var cdlg_clickspot = {

	new: func (x,y,rw,rh,tab,type) {
	 	var cs = { parents: [cdlg_clickspot] };
		
		cs.x = x;
		cs.y = y;
		cs.rw = rw;
		cs.rh = rh;
		cs.fraction_up = 0.0;
		cs.fraction_right = 0.0;
		cs.tab = tab;
		cs.type = type;

		return cs;
	},

	check_event : func (click_x, click_y) {

		if (me.type = "rect") 
			{
			if ((math.abs(click_x - me.x) < me.rw) and (math.abs(click_y - me.y) < me.rh)) 					{
				me.update_fractions (click_x, click_y);
				me.f();
				return 1;
				}
			}
		else if (me.type = "circle") 
			{
			var click_r = math.sqrt((click_x - me.x) * (click_x - me.x) + (click_y - me.y) * (click_y - me.y));

			if (click_r < me.rw)
				{
				me.update_fractions (click_x, click_y);
				me.f();
				return 1;
				}
			}
		return 0;
	},

	update_fractions: func (click_x, click_y) {

		var y_rel = (click_y - me.y);
		var x_rel = (click_x - me.x);
		me.fraction_up = (-y_rel + me.rw)/(2.0 * me.rw);
		me.fraction_right = (x_rel + me.rw)/(2.0 * me.rw);

	},

	get_fraction_up: func {

		return me.fraction_up;

	},

	get_fraction_right: func {

		return me.fraction_right;

	},

	f: func {

		return;

	},

};