.
1 /*
2 Copyright (C) 2012 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
15 using Cairo;
16 using Math;
17
18 namespace BirdFont {
19
20 public class OverViewItem : GLib.Object {
21 public unichar character = '\0';
22 public GlyphCollection? glyphs;
23 public double x;
24 public double y;
25 public bool selected = false;
26 public CharacterInfo info;
27
28 public static double DEFAULT_WIDTH = 100;
29 public static double DEFAULT_HEIGHT = 130;
30 public static double DEFAULT_MARGIN = 20;
31
32 public static double width = 100;
33 public static double height = 130;
34 public static double margin = 20;
35
36 public static double glyph_scale = 1.0;
37
38 VersionList version_menu;
39 Text icon;
40
41 public OverViewItem (GlyphCollection? glyphs, unichar character, double x, double y) {
42 this.x = x;
43 this.y = y;
44 this.character = character;
45 this.glyphs = glyphs;
46 this.info = new CharacterInfo (character, glyphs);
47
48 icon = new Text ("dropdown_menu", 17);
49 icon.load_font ("icons.bf");
50 icon.use_cache (true);
51
52 if (glyphs != null) {
53 version_menu = new VersionList ((!) glyphs);
54 version_menu.add_glyph_item.connect ((glyph) => {
55 ((!) glyphs).insert_glyph (glyph, true);
56 });
57
58 version_menu.signal_delete_item.connect ((glyph_index) => {
59 OverView v = MainWindow.get_overview ();
60 version_menu = new VersionList ((!) glyphs);
61 v.update_item_list ();
62 GlyphCanvas.redraw ();
63 });
64 } else {
65 version_menu = new VersionList (new GlyphCollection (character, (!) character.to_string ()));
66 }
67 }
68
69 public string get_name () {
70 StringBuilder s;
71
72 if (glyphs != null) {
73 return ((!) glyphs).get_name ();
74 }
75
76 s = new StringBuilder ();
77 s.append_unichar (character);
78
79 return s.str;
80 }
81
82 public void set_selected (bool s) {
83 selected = s;
84 }
85
86 public static double full_width () {
87 return width + margin;
88 }
89
90 public static double full_height () {
91 return height + margin;
92 }
93
94 public bool click (uint button, double px, double py) {
95 bool a;
96 GlyphCollection g;
97 bool s = (x <= px <= x + width) && (y <= py <= y + height);
98
99 if (has_icons () && glyphs != null) {
100 g = (!) glyphs;
101
102 a = version_menu.menu_item_action (px, py); // select one item on the menu
103 if (a) {
104 return s;
105 }
106
107 version_menu.menu_icon_action (px, py); // click in the open menu
108 }
109
110 if (has_icons () && info.is_over_icon (px, py)) {
111 MainWindow.get_overview ().set_character_info (info);
112 }
113
114 return s;
115 }
116
117 public bool double_click (uint button, double px, double py) {
118 selected = (x <= px <= x + width) && (y <= py <= y + height);
119 return selected;
120 }
121
122 public bool is_on_screen (WidgetAllocation allocation) {
123 return y + height > 0 && y < allocation.height;
124 }
125
126 public void draw (WidgetAllocation allocation, Context cr) {
127 if (!is_on_screen (allocation)) {
128 return;
129 }
130
131 cr.save ();
132 Theme.color (cr, "Background 1");
133 cr.rectangle (x, y, width, height);
134 cr.fill ();
135 cr.restore ();
136
137 cr.save ();
138 Theme.color (cr, "Overview Item Border");
139 cr.rectangle (x, y, width, height);
140 cr.set_line_width (1);
141 cr.stroke ();
142 cr.restore ();
143
144 draw_thumbnail (cr, glyphs, x, y + height);
145 draw_caption (cr);
146 }
147
148 public void adjust_scale () {
149 double x1, x2, y1, y2, glyph_width, glyph_height, scale, gx;
150 Glyph g;
151 Font font;
152
153 if (glyphs != null) {
154 font = BirdFont.get_current_font ();
155 g = ((!) glyphs).get_current ();
156 g.boundaries (out x1, out y1, out x2, out y2);
157
158 glyph_width = x2 - x1;
159 glyph_height = y2 - y1;
160
161 if (glyph_scale == 1) {
162 // caption height is 20
163 glyph_scale = (height - 20) / (font.top_limit - font.bottom_limit);
164 }
165
166 scale = glyph_scale;
167 gx = ((width / scale) - glyph_width) / 2;
168
169 if (gx < 0) {
170 glyph_scale = 1 + 2 * gx / width;
171 }
172 }
173 }
174
175 private void draw_thumbnail (Context cr, GlyphCollection? gl, double x, double y) {
176 Glyph g;
177 Glyph? glyph;
178 Font font;
179 double gx, gy;
180 double x1, x2, y1, y2;
181 double scale_box;
182 double w, h;
183 double glyph_width, glyph_height;
184 Surface s;
185 Context c;
186 OverView o;
187 Color color = Color.black ();
188
189 w = width;
190 h = height;
191
192 scale_box = width / DEFAULT_WIDTH;
193
194 s = new Surface.similar (cr.get_target (), Content.COLOR_ALPHA, (int) w, (int) h - 20);
195 c = new Context (s);
196
197 if (gl != null) {
198 font = BirdFont.get_current_font ();
199 g = ((!) gl).get_current ();
200
201 c.save ();
202 g.boundaries (out x1, out y1, out x2, out y2);
203
204 glyph_width = x2 - x1;
205 glyph_height = y2 - y1;
206
207 gx = ((w / glyph_scale) - glyph_width) / 2;
208 gy = (h / glyph_scale) - 25 / glyph_scale;
209
210 c.save ();
211 c.scale (glyph_scale, glyph_scale);
212
213 g.add_help_lines ();
214
215 c.translate (gx - g.get_lsb () - Glyph.xc (), g.get_baseline () + gy - Glyph.yc ());
216
217 g.draw_paths (c, color);
218 c.restore ();
219 } else {
220 c.save ();
221 Text fallback = new Text ();
222 Theme.text_color (fallback, "Overview Glyph");
223 fallback.set_text ((!) character.to_string ());
224 double font_size = height * 0.8;
225 fallback.set_font_size (font_size);
226
227 gx = (width - fallback.get_extent ()) / 2.0;
228 gy = height - 30;
229 fallback.set_font_size (font_size);
230 fallback.draw_at_baseline (c, gx, gy);
231 c.restore ();
232 }
233
234 cr.save ();
235 cr.set_source_surface (s, x, y - h);
236 cr.paint ();
237 cr.restore ();
238 }
239
240 public bool has_icons () {
241 return width > 50;
242 }
243
244 public void draw_caption (Context cr) {
245 StringBuilder name = new StringBuilder ();
246 Cairo.Pattern p;
247 string text;
248 Text label;
249
250 name.append_unichar (character);
251
252 cr.save ();
253
254 cr.rectangle (x + 1, y + height - 20, width - 2, 20 - 1);
255
256 if (!selected) {
257 p = new Cairo.Pattern.linear (0.0, y + height - 20, 0.0, y + height);
258 Theme.gradient (p, "Overview Item 1", "Overview Item 2");
259 cr.set_source (p);
260 } else {
261 Theme.color (cr, "Selected Overview Item");
262 }
263
264 cr.fill ();
265
266 if (has_icons ()) {
267 draw_menu (cr);
268 draw_character_info_icon (cr);
269 }
270
271 text = (glyphs == null)
272 ? name.str
273 : ((!) glyphs).get_current ().name;
274
275 double w = has_icons () ? width - 43 : width;
276 label = new Text (text, 17);
277 label.truncate (w);
278 label.use_cache (true);
279
280 if (selected) {
281 Theme.text_color (label, "Overview Selected Foreground");
282 } else {
283 Theme.text_color (label, "Overview Foreground");
284 }
285
286 label.draw_at_baseline (cr, x + 0.08 * width, y + height - 6);
287 }
288
289 private void draw_character_info_icon (Context cr) {
290 double px = x + width - 17;
291 double py = y + height - 21;
292 info.set_position (px, py);
293 info.draw_icon (cr, selected);
294 }
295
296 public void hide_menu () {
297 version_menu.menu_visible = false;
298 }
299
300 private void draw_menu (Context cr) {
301 GlyphCollection g;
302
303 if (glyphs == null) {
304 return;
305 }
306
307 if (selected) {
308 Theme.text_color (icon, "Overview Selected Foreground");
309 } else {
310 Theme.text_color (icon, "Overview Foreground");
311 }
312
313 icon.draw_at_top (cr, x + width - 32, y + height - 19);
314
315 version_menu.set_position (x + width - 21, y + height - 18);
316 version_menu.draw_menu (cr);
317 }
318 }
319
320 }
321