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