The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

OverViewItem.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/OverViewItem.vala.
Display name for ligatures in overview
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 [CCode (cname = "draw_overview_glyph")] 19 public extern bool draw_overview_glyph (Context context, string font_file, double width, double height, unichar character); 20 21 namespace BirdFont { 22 23 public class OverViewItem : GLib.Object { 24 public unichar character = '\0'; 25 public GlyphCollection? glyphs; 26 public double x; 27 public double y; 28 public bool selected = false; 29 public CharacterInfo info; 30 31 public static double DEFAULT_WIDTH = 100; 32 public static double DEFAULT_HEIGHT = 130; 33 public static double DEFAULT_MARGIN = 20; 34 35 public static double width = 100; 36 public static double height = 130; 37 public static double margin = 20; 38 39 public static double glyph_scale = 1.0; 40 41 public VersionList version_menu; 42 Text label; 43 44 private Surface? cache = null; 45 46 public static Surface? label_background = null; 47 public static Surface? selected_label_background = null; 48 public static Surface? label_background_no_menu = null; 49 public static Surface? selected_label_background_no_menu = null; 50 51 public OverViewItem () { 52 } 53 54 public void set_character (unichar character) { 55 this.character = character; 56 } 57 58 public void set_glyphs (GlyphCollection? gc) { 59 glyphs = gc; 60 61 if (glyphs != null) { 62 version_menu = new VersionList ((!) glyphs); 63 version_menu.add_glyph_item.connect ((glyph) => { 64 ((!) glyphs).insert_glyph (glyph, true); 65 }); 66 67 version_menu.signal_delete_item.connect ((glyph_index) => { 68 OverView v = MainWindow.get_overview (); 69 version_menu = new VersionList ((!) glyphs); 70 v.update_item_list (); 71 GlyphCanvas.redraw (); 72 }); 73 } 74 75 info = new CharacterInfo (character, glyphs); 76 77 if (glyphs == null) { 78 label = new Text (); 79 } else { 80 if (character != '\0') { 81 label = new Text ((!) character.to_string (), 17); 82 } else { 83 label = new Text ((!) info.get_name (), 17); 84 } 85 86 truncate_label (); 87 } 88 89 draw_background (); 90 } 91 92 public void clear_cache () { 93 cache = null; 94 95 if (glyphs != null) { 96 Glyph g = ((!) glyphs).get_current (); 97 g.overview_thumbnail = null; 98 } 99 } 100 101 public void draw_glyph_from_font () { 102 if (glyphs == null) { 103 return; 104 } 105 106 Glyph g; 107 double gx, gy; 108 double x1, x2, y1, y2; 109 double scale_box; 110 double w, h; 111 double glyph_width, glyph_height; 112 Surface s; 113 Context c; 114 Color color = Color.black (); 115 116 g = ((!) glyphs).get_current (); 117 118 if (likely (g.overview_thumbnail != null)) { 119 cache = g.overview_thumbnail; 120 return; 121 } 122 123 w = width; 124 h = height; 125 126 scale_box = (height / DEFAULT_HEIGHT) * 0.65; 127 128 s = Screen.create_background_surface ((int) width, (int) height - 20); 129 c = new Context (s); 130 131 c.save (); 132 g.boundaries (out x1, out y1, out x2, out y2); 133 134 glyph_width = x2 - x1; 135 glyph_height = y2 - y1; 136 137 c.save (); 138 c.scale (scale_box * Screen.get_scale (), scale_box * Screen.get_scale ()); 139 140 g.add_help_lines (); 141 142 gx = ((w / scale_box) - glyph_width) / 2 - g.get_left_side_bearing (); 143 gy = h / scale_box + g.get_baseline () - 20 / scale_box - 20; 144 145 c.translate (gx - Glyph.xc () - g.get_lsb (), gy - Glyph.yc ()); 146 147 g.draw_paths (c, color); 148 c.restore (); 149 150 cache = s; 151 g.overview_thumbnail = s; 152 153 GlyphCanvas.redraw (); 154 } 155 156 public void draw_background () { 157 double scale_box; 158 double w, h; 159 Surface s; 160 Context c; 161 162 w = width; 163 h = height; 164 165 scale_box = width / DEFAULT_WIDTH; 166 s = Screen.create_background_surface ((int) width, (int) height - 20); 167 c = new Context (s); 168 169 if (glyphs != null) { // FIXME: lock 170 draw_glyph_from_font (); 171 } else { 172 c.scale (Screen.get_scale (), Screen.get_scale ()); 173 174 c.save (); 175 176 bool glyph_found; 177 string? font_file; 178 179 Theme.color (c, "Overview Glyph"); 180 181 font_file = FontCache.fallback_font.get_default_font_file (); 182 glyph_found = draw_overview_glyph (c, (!) font_file, width, height, character); 183 184 if (!glyph_found) { 185 font_file = find_font (FallbackFont.font_config, (!) character.to_string ()); 186 187 if (font_file != null) { 188 string path = (!) font_file; 189 190 if (!path.has_suffix("LastResort.ttf")) { 191 draw_overview_glyph (c, path, width, height, character); 192 } 193 } 194 } 195 196 c.restore (); 197 198 cache = s; 199 GlyphCanvas.redraw (); 200 } 201 } 202 203 public static void reset_label () { 204 label_background = null; 205 selected_label_background = null; 206 } 207 208 void truncate_label () { 209 double w = has_icons () ? width - 43 : width; 210 label.truncate (w); 211 } 212 213 public string get_name () { 214 StringBuilder s; 215 216 if (glyphs != null) { 217 return ((!) glyphs).get_name (); 218 } 219 220 s = new StringBuilder (); 221 s.append_unichar (character); 222 223 return s.str; 224 } 225 226 public void set_selected (bool s) { 227 selected = s; 228 } 229 230 public static double full_width () { 231 return width + margin; 232 } 233 234 public static double full_height () { 235 return height + margin; 236 } 237 238 public bool click (uint button, double px, double py) { 239 bool a; 240 GlyphCollection g; 241 bool s = (x <= px <= x + width) && (y <= py <= y + height); 242 243 if (has_icons () && glyphs != null) { 244 g = (!) glyphs; 245 version_menu.set_position (x + width - 21, y + height - 18); 246 a = version_menu.menu_item_action (px, py); // select one item on the menu 247 248 if (a) { 249 return s; 250 } 251 252 version_menu.menu_icon_action (px, py); // click in the open menu 253 } 254 255 info.set_position (x + width - 17, y + height - 22.5); 256 if (has_icons () && info.is_over_icon (px, py)) { 257 MainWindow.get_overview ().set_character_info (info); 258 } 259 260 return s; 261 } 262 263 public bool double_click (uint button, double px, double py) { 264 selected = (x <= px <= x + width) && (y <= py <= y + height); 265 return selected; 266 } 267 268 public bool is_on_screen (WidgetAllocation allocation) { 269 return y + height > 0 && y < allocation.height; 270 } 271 272 public void draw (WidgetAllocation allocation, Context cr) { 273 if (!is_on_screen (allocation)) { 274 return; 275 } 276 277 cr.save (); 278 Theme.color (cr, "Background 1"); 279 cr.rectangle (x, y, width, height); 280 cr.fill (); 281 cr.restore (); 282 283 cr.save (); 284 Theme.color (cr, "Overview Item Border"); 285 cr.rectangle (x, y, width, height); 286 cr.set_line_width (1); 287 cr.stroke (); 288 cr.restore (); 289 290 draw_thumbnail (cr, x, y + height); 291 292 draw_caption (cr); 293 draw_menu (cr); 294 } 295 296 private void draw_thumbnail (Context cr, double x, double y) { 297 if (cache != null) { 298 cr.save (); 299 cr.set_antialias (Cairo.Antialias.NONE); 300 cr.scale (1 / Screen.get_scale (), 1 / Screen.get_scale ()); 301 cr.set_source_surface ((!) cache, (int) (x * Screen.get_scale ()), (int) ((y - height)) * Screen.get_scale ()); 302 cr.paint (); 303 cr.restore (); 304 } 305 } 306 307 public bool has_icons () { 308 return width > 50; 309 } 310 311 public void draw_caption (Context cr) { 312 draw_label_background (cr); 313 314 cr.save (); 315 316 if (glyphs != null) { 317 if (selected) { 318 Theme.text_color (label, "Overview Selected Foreground"); 319 } else { 320 Theme.text_color (label, "Overview Foreground"); 321 } 322 323 label.draw_at_baseline (cr, x + 0.08 * width, y + height - 6); 324 } 325 326 cr.restore (); 327 } 328 329 public void create_label_background_cache (Context cr) { 330 Context cc; 331 Cairo.Pattern p; 332 Surface cache; 333 334 // unselected item 335 cache = Screen.create_background_surface ((int) width + 1, 20); 336 cc = new Context (cache); 337 cc.scale(Screen.get_scale(), Screen.get_scale()); 338 339 cc.rectangle (0, 0, width, 20 - 1); 340 p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20); 341 Theme.gradient (p, "Overview Item 1", "Overview Item 2"); 342 cc.set_source (p); 343 344 cc.fill (); 345 346 if (has_icons ()) { 347 draw_menu_icon (cc, false); 348 draw_character_info_icon (cc); 349 } 350 351 label_background = (!) cache; 352 353 // selected item 354 cache = Screen.create_background_surface ((int) width + 1, 20); 355 cc = new Context (cache); 356 cc.scale(Screen.get_scale(), Screen.get_scale()); 357 358 cc.rectangle (0, 0, width, 20 - 1); 359 360 Theme.color (cc, "Selected Overview Item"); 361 362 cc.fill (); 363 364 if (has_icons ()) { 365 draw_menu_icon (cc, true); 366 draw_character_info_icon (cc); 367 } 368 369 selected_label_background = (!) cache; 370 371 // deselected item without menu icon 372 cache = Screen.create_background_surface ((int) width, 20); 373 cc = new Context (cache); 374 cc.scale(Screen.get_scale(), Screen.get_scale()); 375 cc.rectangle (0, 0, width - 1, 20 - 1); 376 p = new Cairo.Pattern.linear (0.0, 0, 0.0, 20); 377 Theme.gradient (p, "Overview Item 1", "Overview Item 2"); 378 cc.set_source (p); 379 cc.fill (); 380 381 if (has_icons ()) { 382 draw_character_info_icon (cc); 383 } 384 385 label_background_no_menu = (!) cache; 386 387 // selected item 388 cache = Screen.create_background_surface ((int) width + 1, 20); 389 cc = new Context (cache); 390 cc.scale(Screen.get_scale(), Screen.get_scale()); 391 cc.rectangle (0, 0, width, 20 - 1); 392 Theme.color (cc, "Selected Overview Item"); 393 cc.fill (); 394 395 if (has_icons ()) { 396 draw_character_info_icon (cc); 397 } 398 399 selected_label_background_no_menu = (!) cache; 400 } 401 402 bool has_menu () { 403 return glyphs != null; 404 } 405 406 public void draw_label_background (Context cr) { 407 Surface cache; 408 bool icon; 409 410 if (unlikely (label_background == null)) { 411 create_label_background_cache (cr); 412 } 413 414 if (label_background != null 415 && selected_label_background != null 416 && label_background_no_menu != null 417 && selected_label_background_no_menu != null) { 418 419 icon = has_menu (); 420 if (selected && icon) { 421 cache = (!) selected_label_background; 422 } else if (!selected && icon) { 423 cache = (!) label_background; 424 } else if (selected && !icon) { 425 cache = (!) selected_label_background_no_menu; 426 } else { 427 cache = (!) label_background_no_menu; 428 } 429 430 Screen.paint_background_surface (cr, cache, (int) x, (int) (y + height - 19)); 431 } 432 } 433 434 private void draw_character_info_icon (Context cr) { 435 info.draw_icon (cr, selected, width - 17, -1.5); 436 } 437 438 public void hide_menu () { 439 if (!is_null (version_menu)) { 440 version_menu.menu_visible = false; 441 } 442 } 443 444 private void draw_menu_icon (Context cc, bool selected) { 445 Text icon; 446 447 icon = new Text ("dropdown_menu", 17); 448 icon.load_font ("icons.bf"); 449 450 if (selected) { 451 Theme.text_color (icon, "Overview Selected Foreground"); 452 } else { 453 Theme.text_color (icon, "Overview Foreground"); 454 } 455 456 icon.draw_at_top (cc, width - 32, 0); 457 } 458 459 private void draw_menu (Context cr) { 460 if (likely (glyphs == null || !version_menu.menu_visible)) { 461 return; 462 } 463 464 version_menu.draw_menu (cr); 465 } 466 } 467 468 } 469