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