The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Line.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/Line.vala.
Ignore case in key bindings
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 17 namespace BirdFont { 18 19 /** Guide */ 20 public class Line : GLib.Object { 21 public static const bool VERTICAL = true; 22 public static const bool HORIZONTAL = false; 23 24 public bool dashed { get; set; } 25 26 public string label; 27 bool vertical; 28 string metrics; 29 30 public double pos; 31 32 bool active = false; 33 bool move = false; 34 35 public signal void queue_draw_area (int x, int y, int w, int h); 36 public signal void position_updated (double pos); 37 38 double r; 39 double g; 40 double b; 41 double a; 42 43 bool visible = true; 44 bool moveable = true; 45 46 public bool rsb = false; 47 public bool lsb = false; 48 49 public Line (string label = "No label set", double position = 10, bool vertical = false) { 50 this.label = label; 51 this.vertical = vertical; 52 this.pos = position; 53 54 dashed = false; 55 metrics = ""; 56 57 set_color_theme ("Guide 1"); 58 } 59 60 public Line copy () { 61 Line l = new Line (label, pos, vertical); 62 63 l.r = r; 64 l.g = g; 65 l.b = b; 66 l.a = a; 67 68 l.visible = visible; 69 l.dashed = dashed; 70 71 return l; 72 } 73 74 public void set_metrics (double m) { 75 string t = @"$m"; 76 string s = ""; 77 78 int i; 79 unichar c; 80 81 i = 0; 82 while (t.get_next_char (ref i, out c)) { 83 s = s + (!) c.to_string (); 84 85 if (i >= 5) { 86 break; 87 } 88 } 89 90 metrics = s; 91 } 92 93 public void set_visible (bool v) { 94 visible = v; 95 } 96 97 public bool is_visible () { 98 return visible; 99 } 100 101 public void set_moveable (bool m) { 102 moveable = m; 103 } 104 105 public void set_color_theme (string color) { 106 Color c = Theme.get_color (color); 107 108 r = c.r; 109 g = c.g; 110 b = c.b; 111 a = c.a; 112 } 113 114 public void set_color (double r, double g, double b, double a) { 115 this.r = r; 116 this.g = g; 117 this.b = b; 118 this.a = a; 119 } 120 121 public bool is_moving () { 122 return move; 123 } 124 125 public bool set_move (bool moving) { 126 bool r = move; 127 move = moving; 128 return (r == moving); 129 } 130 131 public bool button_press (uint button) { 132 Glyph g; 133 TextListener listener; 134 string position; 135 bool text_input = false; 136 137 if (get_active ()) { 138 if (button == 3 || KeyBindings.has_shift ()) { 139 move = false; 140 text_input = true; 141 142 g = MainWindow.get_current_glyph (); 143 if (lsb) { 144 position = @"$(g.get_left_side_bearing ())"; 145 } else if (rsb) { 146 position = @"$(g.get_right_side_bearing ())"; 147 } else { 148 position = @"$pos"; 149 } 150 151 listener = new TextListener (t_("Position"), position, t_("Move")); 152 153 listener.signal_text_input.connect ((text) => { 154 string submitted_value; 155 double parsed_value; 156 Glyph glyph; 157 double x1, y1, x2, y2; 158 159 glyph = MainWindow.get_current_glyph (); 160 submitted_value = text.replace (",", "."); 161 parsed_value = double.parse (submitted_value); 162 163 if (lsb) { 164 if (glyph.get_boundaries (out x1, out y1, out x2, out y2)) { 165 parsed_value = x1 - parsed_value; 166 } else { 167 parsed_value = glyph.right_limit - parsed_value; 168 } 169 } else if (rsb) { 170 if (glyph.get_boundaries (out x1, out y1, out x2, out y2)) { 171 parsed_value += x2; 172 } else { 173 parsed_value = glyph.left_limit - parsed_value; 174 } 175 } 176 177 pos = parsed_value; 178 position_updated (parsed_value); 179 GlyphCanvas.redraw (); 180 }); 181 182 listener.signal_submit.connect (() => { 183 TabContent.hide_text_input (); 184 }); 185 186 TabContent.show_text_input (listener); 187 } else { 188 move = true; 189 } 190 191 g = MainWindow.get_current_glyph (); 192 g.store_undo_state (); 193 } else { 194 move = false; 195 active = false; 196 } 197 198 return move || text_input; 199 } 200 201 void redraw_line () { 202 GlyphCanvas.redraw (); 203 } 204 205 public bool event_move_to (int x, int y, WidgetAllocation allocation) { 206 double p, c; 207 bool a = false; 208 Glyph g = MainWindow.get_current_glyph (); 209 double ivz = 1/g.view_zoom; 210 double margin = 10; 211 double none = 0; 212 213 if (!moveable) { 214 return false; 215 } 216 217 if (is_vertical ()) { // over line handle (y) 218 if (y > g.allocation.height - 10 * MainWindow.units 219 || y < 10 * MainWindow.units) { 220 221 p = pos; 222 c = Glyph.path_coordinate_x (x); 223 a = (p - margin * ivz <= c <= p + margin * ivz); 224 } 225 226 if (a != get_active ()) { 227 redraw_line (); 228 } 229 230 set_active (a); 231 232 } else { // over line handle (x) 233 if (x > g.allocation.width - 10 * MainWindow.units 234 || x < 10 * MainWindow.units) { 235 236 p = pos; 237 c = Glyph.path_coordinate_y (y); 238 a = (p - margin * ivz <= c <= p + margin * ivz); 239 } 240 241 if (a != get_active ()) { 242 redraw_line (); 243 } 244 245 set_active (a); 246 } 247 248 // move the line 249 if (move) { 250 double np = pos; 251 redraw_line (); // clear old position 252 253 if (is_vertical ()) { 254 pos = Glyph.path_coordinate_x (x); 255 256 if (GridTool.is_visible ()) { 257 GridTool.tie_coordinate (ref pos, ref none); 258 } 259 redraw_line (); // draw at new position 260 } else if (!GridTool.lock_grid) { 261 pos = Glyph.path_coordinate_y (y); 262 263 if (GridTool.is_visible ()) { 264 GridTool.tie_coordinate (ref none, ref pos); 265 } 266 redraw_line (); 267 } 268 269 if (Math.fabs (np - pos) > 10) { 270 queue_draw_area (0, 0, g.allocation.width, g.allocation.height); 271 } 272 273 position_updated (pos); // signal update 274 275 BirdFont.get_current_font ().touch (); 276 } 277 278 if (GridTool.is_visible ()) { 279 GridTool.update_lines (); 280 } 281 282 return move; 283 } 284 285 public bool get_active () { 286 return active; 287 } 288 289 public void set_active (bool active) { 290 Glyph g; 291 292 if (active) { 293 g = MainWindow.get_current_glyph (); 294 295 if (lsb) { 296 set_metrics (g.get_left_side_bearing ()); 297 } else if (rsb) { 298 set_metrics (g.get_right_side_bearing ()); 299 } 300 } 301 302 this.active = active; 303 } 304 305 public string get_label () { 306 return label; 307 } 308 309 public bool is_vertical () { 310 return vertical; 311 } 312 313 public int get_position_pixel () { 314 if (is_vertical ()) { 315 return Glyph.reverse_path_coordinate_x (pos); 316 } 317 318 return Glyph.reverse_path_coordinate_y (pos) ; 319 } 320 321 public double get_pos () { 322 return pos; 323 } 324 325 public void draw (Context cr, WidgetAllocation allocation) { 326 Glyph g = MainWindow.get_current_glyph (); 327 double p, h, w; 328 double size = (active) ? 8 : 5; 329 Text glyph_metrics; 330 Text line_label; 331 332 if (!visible) { 333 return; 334 } 335 336 cr.save (); 337 cr.set_line_width (1); 338 339 if (dashed) { 340 cr.set_dash ({20, 20}, 0); 341 } 342 343 if (active) { 344 Theme.color (cr, "Highlighted Guide"); 345 } else { 346 cr.set_source_rgba (r, this.g, b, a); 347 } 348 349 // Line 350 if (is_vertical ()) { 351 p = Glyph.reverse_path_coordinate_x (pos); 352 h = g.allocation.height; 353 354 cr.move_to (p, 0); 355 cr.line_to (p, h); 356 cr.stroke (); 357 358 cr.scale (1, 1); 359 360 if (moveable) { 361 cr.new_path (); 362 cr.move_to (p - size, h); 363 cr.line_to (p, h - size); 364 cr.line_to (p + size, h); 365 cr.close_path(); 366 cr.fill (); 367 368 cr.new_path (); 369 cr.move_to (p - size, 0); 370 cr.line_to (p, size); 371 cr.line_to (p + size, 0); 372 cr.close_path(); 373 cr.fill (); 374 375 if (get_active ()) { 376 glyph_metrics = new Text (metrics, 17); 377 Theme.text_color (glyph_metrics, "Highlighted Guide"); 378 glyph_metrics.widget_x = p + 10; 379 glyph_metrics.widget_y = h - 25; 380 glyph_metrics.draw (cr); 381 } 382 } 383 384 } else { 385 p = Glyph.reverse_path_coordinate_y (pos); 386 w = g.allocation.width; 387 388 cr.move_to (0, p); 389 cr.line_to (w, p); 390 cr.stroke (); 391 392 if (moveable) { 393 cr.new_path (); 394 cr.move_to (w, p - size); 395 cr.line_to (w - size, p); 396 cr.line_to (w, p + size); 397 cr.close_path(); 398 cr.fill (); 399 400 cr.new_path (); 401 cr.move_to (0, p - size); 402 cr.line_to (0 + size, p); 403 cr.line_to (0, p + size); 404 cr.close_path(); 405 cr.fill (); 406 } 407 } 408 409 // Label 410 if (get_active ()) { 411 line_label = new Text (get_label (), 19 * MainWindow.units); 412 413 if (is_vertical ()) { 414 line_label.widget_x = p + 8 * MainWindow.units; 415 line_label.widget_y = allocation.height - 55 * MainWindow.units; 416 } else { 417 line_label.widget_x = g.allocation.width 418 - 10 * MainWindow.units 419 - line_label.get_extent (); 420 421 line_label.widget_y = p + 10 * MainWindow.units; 422 } 423 424 if (active) { 425 Theme.text_color (line_label, "Highlighted Guide"); 426 } else { 427 line_label.set_source_rgba (r, this.g, b, a); 428 } 429 430 line_label.draw (cr); 431 } 432 433 cr.restore (); 434 } 435 } 436 437 } 438