1/*
2	Copyright (C) 2014 2015 Johan Mattsson
3
4	This library is free software; you can redistribute it and/or modify
5	it under the terms of the GNU Lesser General Public License as
6	published by the Free Software Foundation; either version 3 of the
7	License, or (at your option) any later version.
8
9	This library is distributed in the hope that it will be useful, but
10	WITHOUT ANY WARRANTY; without even the implied warranty of
11	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12	Lesser General Public License for more details.
13*/
14
15using Cairo;
16using Math;
17
18namespace BirdFont {
19
20internal abstract class SettingsDisplay : FontDisplay {
21
22	double scroll = 0;
23	double content_height = 1;
24	WidgetAllocation allocation;
25	public Gee.ArrayList<SettingsItem> tools;
26
27	public static SpinButton precision;
28
29	SettingsItem new_key_bindings = new SettingsItem.head_line ("");
30	public static bool update_key_bindings = false;
31
32	protected SettingsDisplay () {
33		allocation = new WidgetAllocation ();
34		tools = new Gee.ArrayList<SettingsItem> ();
35		content_height = 200;
36		precision = new SpinButton ("precision");
37	}
38
39	public abstract void create_setting_items ();
40
41	public override void draw (WidgetAllocation allocation, Context cr) {
42		this.allocation = allocation;
43
44		layout ();
45
46		// background
47		cr.save ();
48		cr.rectangle (0, 0, allocation.width, allocation.height);
49		cr.set_line_width (0);
50		Theme.color (cr, "Default Background");
51		cr.fill ();
52		cr.stroke ();
53		cr.restore ();
54
55		foreach (SettingsItem s in tools) {
56			if (-20 * MainWindow.units <= s.y <= allocation.height + 20 * MainWindow.units) {
57				s.draw (allocation, cr);
58			}
59		}
60	}
61
62	public void layout () {
63		double y = -scroll;
64		bool first = true;
65		foreach (SettingsItem s in tools) {
66
67			if (!first && s.headline) {
68				y += 30 * MainWindow.units;
69			}
70
71			s.y = y;
72
73			if (s.button != null) {
74				((!) s.button).y = y;
75				((!) s.button).x = 20 * MainWindow.units;
76			}
77
78			if (s.headline) {
79				y += 50 * MainWindow.units;
80			} else {
81				y += 40 * MainWindow.units;
82			}
83
84			first = false;
85		}
86
87		content_height = y + scroll;
88	}
89
90	void set_key_bindings (SettingsItem item) {
91		if (new_key_bindings.active) {
92			new_key_bindings.active = false;
93			update_key_bindings = false;
94		} else {
95			new_key_bindings.active = false;
96			new_key_bindings = item;
97			update_key_bindings = true;
98			new_key_bindings.active = true;
99		}
100	}
101
102	public override void key_release (uint keyval) {
103		SettingsItem old_key_binding;
104
105		if (!is_modifier_key (keyval) || keyval == Key.BACK_SPACE || keyval == Key.DEL) {
106			if (update_key_bindings) {
107				if (keyval == Key.BACK_SPACE || keyval == Key.DEL) {
108					update_key_bindings = false;
109					new_key_bindings.active = false;
110					new_key_bindings.menu_item.modifiers = NONE;
111					new_key_bindings.menu_item.key = '\0';
112				} else if (KeyBindings.get_mod_from_key (keyval) == NONE) {
113
114					if (has_key_binding (KeyBindings.modifier, (unichar) keyval)) {
115						old_key_binding = (!) get_key_binding (KeyBindings.modifier, (unichar) keyval);
116
117						if (same_scope (old_key_binding, new_key_bindings)) {
118							old_key_binding.menu_item.modifiers = NONE;
119							old_key_binding.menu_item.key = '\0';
120						}
121					}
122
123					new_key_bindings.menu_item.modifiers = KeyBindings.modifier;
124					new_key_bindings.menu_item.key = (unichar) keyval;
125					update_key_bindings = false;
126					new_key_bindings.active = false;
127				}
128
129				MainWindow.get_menu ().write_key_bindings ();
130				GlyphCanvas.redraw ();
131			}
132		}
133	}
134
135	/** Check if key binding is used in same tab. */
136	bool same_scope (SettingsItem key_binding1, SettingsItem key_binding2) {
137		foreach (string scope in key_binding1.menu_item.displays) {
138			if (key_binding2.menu_item.in_display (scope)) {
139				return true;
140			}
141		}
142
143		return false;
144	}
145
146	bool has_key_binding (uint modifier, unichar key) {
147		return get_key_binding (modifier, key) != null;
148	}
149
150	SettingsItem? get_key_binding (uint modifier, unichar key) {
151		foreach (SettingsItem i in tools) {
152			if (i.menu_item.modifiers == modifier && i.menu_item.key == key) {
153				return i;
154			}
155		}
156
157		return null;
158	}
159
160	public override void button_press (uint button, double x, double y) {
161		foreach (SettingsItem s in tools) {
162			if (s.handle_events && s.button != null) {
163				if (((!) s.button).is_over (x, y)) {
164
165					((!) s.button).set_selected (! ((!) s.button).selected);
166
167					if (((!) s.button).selected) {
168						((!) s.button).select_action ((!) s.button);
169					}
170
171					((!) s.button).panel_press_action ((!) s.button, button, x, y);
172				}
173			}
174		}
175		GlyphCanvas.redraw ();
176	}
177
178	public override void button_release (int button, double x, double y) {
179		foreach (SettingsItem s in tools) {
180			if (s.handle_events && s.button != null) {
181				((!) s.button).panel_release_action (((!) s.button), button, x, y);
182			}
183
184			if (s.key_bindings && s.y <= y < s.y + 40 * MainWindow.units && button == 1) {
185				set_key_bindings (s);
186			}
187		}
188		GlyphCanvas.redraw ();
189	}
190
191	public override void motion_notify (double x, double y) {
192		bool consumed = false;
193		bool active;
194		bool update = false;
195
196		foreach (SettingsItem si in tools) {
197
198			if (si.handle_events && si.button != null) {
199				active = ((!) si.button).is_over (x, y);
200
201				if (!active && ((!) si.button).is_active ()) {
202					((!) si.button).move_out_action ((!) si.button);
203				}
204
205				if (((!) si.button).set_active (active)) {
206					update = true;
207				}
208			}
209		}
210
211		foreach (SettingsItem s in tools) {
212			if (s.handle_events && s.button != null) {
213				if (((!) s.button).panel_move_action ((!) s.button, x, y)) {
214					consumed = true;
215				}
216			}
217		}
218
219		if (consumed || update) {
220			GlyphCanvas.redraw ();
221		}
222	}
223
224	public override string get_label () {
225		return t_("Settings");
226	}
227
228	public override string get_name () {
229		return "Settings";
230	}
231
232	public override bool has_scrollbar () {
233		return true;
234	}
235
236	public override void scroll_wheel (double x, double y, double pixeldelta, double dy) {
237		if (dy < 0) {
238			foreach (SettingsItem s in tools) {
239				if (s.handle_events && s.button != null) {
240					if (((!) s.button).is_over (x, y)) {
241						((!) s.button).scroll_wheel_down_action ((!) s.button);
242						return;
243					}
244				}
245			}
246		} else {
247			foreach (SettingsItem s in tools) {
248				if (s.handle_events && s.button != null) {
249					if (((!) s.button).is_over (x, y)) {
250						((!) s.button).scroll_wheel_up_action ((!) s.button);
251						return;
252					}
253				}
254			}
255		}
256
257		scroll -= dy * MainWindow.units;
258
259		if (scroll + allocation.height >=  content_height) {
260			scroll = content_height - allocation.height;
261		}
262
263		if (scroll < 0) {
264			scroll = 0;
265		}
266
267		update_scrollbar ();
268		GlyphCanvas.redraw ();
269	}
270
271	public override void selected_canvas () {
272		MainWindow.get_toolbox ().set_default_tool_size ();
273		update_scrollbar ();
274		GlyphCanvas.redraw ();
275	}
276
277	public override void update_scrollbar () {
278		double h = content_height - allocation.height;
279		MainWindow.set_scrollbar_size (allocation.height / content_height);
280		MainWindow.set_scrollbar_position (scroll /  h);
281	}
282
283	public override void scroll_to (double percent) {
284		double h = content_height - allocation.height;
285		scroll = percent * h;
286		GlyphCanvas.redraw ();
287	}
288}
289
290}
291