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.
User defined guides
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 /** Help line */ 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 r = 0.7; 55 g = 0.7; 56 b = 0.8; 57 a = 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 (double r, double g, double b, double a) { 106 this.r = r; 107 this.g = g; 108 this.b = b; 109 this.a = a; 110 } 111 112 public bool is_moving () { 113 return move; 114 } 115 116 public bool set_move (bool moving) { 117 bool r = move; 118 move = moving; 119 return (r == moving); 120 } 121 122 public bool button_press (uint button) { 123 Glyph g; 124 TextListener listener; 125 string position; 126 127 if (get_active ()) { 128 if (button == 3 || KeyBindings.has_shift ()) { 129 move = false; 130 position = @"$pos"; 131 132 listener = new TextListener (t_("Position"), position, t_("Move")); 133 134 listener.signal_text_input.connect ((text) => { 135 string submitted_value; 136 double parsed_value; 137 138 submitted_value = text.replace (",", "."); 139 parsed_value = double.parse (submitted_value); 140 141 pos = parsed_value; 142 143 position_updated (parsed_value); 144 GlyphCanvas.redraw (); 145 }); 146 147 listener.signal_submit.connect (() => { 148 MainWindow.native_window.hide_text_input (); 149 }); 150 151 MainWindow.native_window.set_text_listener (listener); 152 } else { 153 move = true; 154 } 155 156 g = MainWindow.get_current_glyph (); 157 g.store_undo_state (); 158 } else { 159 move = false; 160 active = false; 161 } 162 163 return move; 164 } 165 166 void redraw_line () { 167 double p; 168 Glyph g = MainWindow.get_current_glyph (); 169 170 if (vertical) { 171 p = Glyph.reverse_path_coordinate_x (pos); 172 queue_draw_area ((int)p - 100, 0, 200, g.allocation.height); 173 } else { 174 p = Glyph.reverse_path_coordinate_y (pos); 175 queue_draw_area (0, (int)p - 100, g.allocation.width, 300); 176 } 177 } 178 179 public void move_line_to (int x, int y, WidgetAllocation allocation) { 180 set_move (true); 181 event_move_to (x, y, allocation); 182 } 183 184 public bool event_move_to (int x, int y, WidgetAllocation allocation) { 185 double p, c; 186 bool a = false; 187 Glyph g = MainWindow.get_current_glyph (); 188 double ivz = 1/g.view_zoom; 189 double margin = 10; 190 double none = 0; 191 192 if (!moveable) { 193 return false; 194 } 195 196 if (is_vertical ()) { // over line handle (y) 197 if (y > g.allocation.height - 10) { 198 p = pos; 199 c = Glyph.path_coordinate_x (x); 200 a = (p - margin * ivz <= c <= p + margin * ivz); 201 } 202 203 if (a != get_active ()) { 204 redraw_line (); 205 } 206 207 set_active (a); 208 209 } else { // over line handle (x) 210 if (x > g.allocation.width - 10) { 211 p = pos; 212 c = Glyph.path_coordinate_y (y); 213 a = (p - margin * ivz <= c <= p + margin * ivz); 214 } 215 216 if (a != get_active ()) { 217 redraw_line (); 218 } 219 220 set_active (a); 221 } 222 223 // move the line 224 if (move) { 225 double np = pos; 226 redraw_line (); // clear old position 227 228 if (is_vertical ()) { 229 pos = Glyph.path_coordinate_x (x); 230 231 if (GridTool.is_visible ()) { 232 GridTool.tie_coordinate (ref pos, ref none); 233 } 234 redraw_line (); // draw at new position 235 } else { 236 pos = Glyph.path_coordinate_y (y); 237 238 if (GridTool.is_visible ()) { 239 GridTool.tie_coordinate (ref none, ref pos); 240 } 241 redraw_line (); 242 } 243 244 if (Math.fabs (np - pos) > 10) { 245 queue_draw_area (0, 0, g.allocation.width, g.allocation.height); 246 } 247 248 position_updated (pos); // signal update 249 250 BirdFont.get_current_font ().touch (); 251 } 252 253 if (GridTool.is_visible ()) { 254 GridTool.update_lines (); 255 } 256 257 return move; 258 } 259 260 public bool get_active () { 261 return active; 262 } 263 264 public void set_active (bool active) { 265 this.active = active; 266 } 267 268 public string get_label () { 269 return label; 270 } 271 272 public bool is_vertical () { 273 return vertical; 274 } 275 276 public int get_position_pixel () { 277 if (is_vertical ()) { 278 return Glyph.reverse_path_coordinate_x (pos); 279 } 280 281 return Glyph.reverse_path_coordinate_y (pos) ; 282 } 283 284 public double get_pos () { 285 return pos; 286 } 287 288 public void draw (Context cr, WidgetAllocation allocation) { 289 Glyph g = MainWindow.get_current_glyph (); 290 double p, h, w; 291 double size = (active) ? 8 : 5; 292 Text glyph_metrics; 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 cr.set_source_rgba (0, 0, 0.3, 1); 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 glyph_metrics.set_source_rgba (72 / 255.0, 72 / 255.0, 72 / 255.0, 1); 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 if (is_vertical ()) { 360 h = g.allocation.height; 361 cr.move_to (p + 8 , h - 30); 362 } else { 363 w = g.allocation.width; 364 cr.move_to (w - 70, p + 15); 365 } 366 367 cr.set_font_size (12); 368 cr.select_font_face ("Cantarell", FontSlant.NORMAL, FontWeight.BOLD); 369 370 cr.show_text (get_label ()); 371 cr.stroke (); 372 } 373 374 cr.restore (); 375 } 376 377 378 379 } 380 381 } 382