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