The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SpinButton.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/SpinButton.vala.
Ignore case in key bindings
1 /* 2 Copyright (C) 2012, 2014 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 public class SpinButton : Tool { 20 21 public signal void new_value_action (SpinButton selected); 22 23 bool negative = false; 24 25 public int8 n0 = 2; 26 public int8 n1 = 0; 27 public int8 n2 = 0; 28 public int8 n3 = 0; 29 public int8 n4 = 0; 30 31 bool value_from_motion = false; 32 double begin_y = 0; 33 int begin_value = 0; 34 35 int max = 99999; 36 int min = 0; 37 int step = 1; 38 39 bool big_number = false; 40 41 double last_active_time = 0; 42 bool waiting_for_icon_switch = false; 43 bool show_icon_tool_icon = false; 44 45 /** Lock the button to a fixed value. */ 46 public bool locked = false; 47 48 public SpinButton (string? name = null, string tip = "") { 49 base (null , tip); 50 51 if (name != null) { 52 base.name = (!) name; 53 } 54 55 set_icon ("spin_button"); 56 57 panel_press_action.connect ((selected, button, tx, ty) => { 58 double py = Math.fabs (y - ty); 59 int n = 0; 60 61 if (button == 3 || KeyBindings.modifier != NONE) { 62 set_from_text (); 63 n = 0; 64 set_selected (false); 65 return; 66 } 67 68 if (is_selected ()) { 69 if (button == 1) { 70 n = 1; 71 } else if (button == 2) { 72 n = 10; 73 } 74 75 for (int i = 0; i < n; i++) { 76 if (py < 9 && !locked) { 77 increase (); 78 } 79 80 if (py > 25 && !locked) { 81 decrease (); 82 } 83 } 84 } 85 86 value_from_motion = !locked; 87 88 begin_y = ty; 89 90 begin_value = get_int_value (); 91 92 if (button == 1) { 93 set_selected (true); 94 } 95 96 redraw (); 97 }); 98 99 panel_move_action.connect ((selected, button, tx, ty) => { 100 double d; 101 int new_value; 102 103 if (is_active ()) { 104 show_adjustmet_icon (); 105 } 106 107 if (value_from_motion && is_selected ()) { 108 d = (begin_y - ty) / 200; 109 d = (d < 0) ? -Math.pow (d, 2) : Math.pow (d, 2); 110 d *= 1000; 111 112 new_value = (int)(begin_value + d); 113 114 if (new_value < min) { 115 set_int_value (@"$min"); 116 } else if (new_value > max) { 117 set_int_value (@"$max"); 118 } else { 119 set_int_value (@"$new_value"); 120 } 121 122 redraw (); 123 } 124 125 return value_from_motion; 126 }); 127 128 panel_release_action.connect ((selected, button, tx, ty) => { 129 value_from_motion = false; 130 131 if (button == 1) { 132 set_selected (false); 133 } 134 135 redraw (); 136 }); 137 138 scroll_wheel_up_action.connect ((selected) => { 139 increase (); 140 return true; 141 }); 142 143 scroll_wheel_down_action.connect ((selected) => { 144 decrease (); 145 return true; 146 }); 147 } 148 149 public void show_icon (bool i) { 150 show_icon_tool_icon = i; 151 152 if (!show_icon_tool_icon) { 153 set_icon ("spin_button"); 154 } else { 155 set_icon ((!) base.name); 156 } 157 } 158 159 public void hide_value () { 160 set_icon (base.name); 161 waiting_for_icon_switch = false; 162 redraw (); 163 } 164 165 void show_adjustmet_icon () { 166 TimeoutSource timer; 167 168 set_icon ("spin_button"); 169 redraw (); 170 171 last_active_time = GLib.get_real_time (); 172 173 if (show_icon_tool_icon && !waiting_for_icon_switch) { 174 waiting_for_icon_switch = true; 175 176 timer = new TimeoutSource (100); 177 timer.set_callback (() => { 178 if (GLib.get_real_time () - last_active_time > 4000000) { 179 set_icon (base.name); 180 redraw (); 181 waiting_for_icon_switch = false; 182 } 183 184 return waiting_for_icon_switch; 185 }); 186 187 timer.attach (null); 188 } 189 } 190 191 public void set_big_number (bool b) { 192 big_number = b; 193 } 194 195 public static string convert_to_string (double val) { 196 SpinButton sb = new SpinButton (); 197 sb.set_value_round (val); 198 return sb.get_display_value (); 199 } 200 201 public static double convert_to_double (string val) { 202 SpinButton sb = new SpinButton (); 203 sb.set_int_value (val); 204 return sb.get_value (); 205 } 206 207 public void set_from_text () { 208 TextListener listener = new TextListener (t_("Set"), get_display_value (), t_("Close")); 209 210 listener.signal_text_input.connect ((text) => { 211 set_value (text); 212 redraw (); 213 }); 214 215 listener.signal_submit.connect (() => { 216 TabContent.hide_text_input (); 217 redraw (); 218 }); 219 220 TabContent.show_text_input (listener); 221 } 222 223 public void set_max (double max) { 224 if (big_number) { 225 max /= 100; 226 } 227 this.max = (int) Math.rint (max * 10000); 228 } 229 230 public void set_min (double min) { 231 if (big_number) { 232 min /= 100; 233 } 234 this.min = (int) Math.rint (min * 10000); 235 } 236 237 public void set_int_step (double step) { 238 if (big_number) { 239 step /= 100; 240 } 241 this.step = (int) Math.rint (step * 10000); 242 } 243 244 public void increase () { 245 int v; 246 247 v = get_int_value (); 248 v += step; 249 250 if (v > max) { 251 set_int_value (@"$max"); 252 } else { 253 set_int_value (@"$v"); 254 } 255 256 new_value_action (this); 257 redraw (); 258 } 259 260 public void decrease () { 261 int v; 262 263 v = get_int_value (); 264 v -= step; 265 266 if (v <= min) { 267 set_int_value (@"$min"); 268 } else { 269 set_int_value (@"$v"); 270 } 271 272 new_value_action (this); 273 redraw (); 274 } 275 276 public void set_int_value (string new_value) { 277 string v = new_value; 278 279 negative = v.has_prefix ("-"); 280 if (negative) { 281 v = v.replace ("-", ""); 282 } 283 284 while (!(v.char_count () >= 5)) { 285 v = "0" + v; 286 } 287 288 n0 = parse (v.substring (v.index_of_nth_char (0), 1)); 289 n1 = parse (v.substring (v.index_of_nth_char (1), 1)); 290 n2 = parse (v.substring (v.index_of_nth_char (2), 1)); 291 n3 = parse (v.substring (v.index_of_nth_char (3), 1)); 292 n4 = parse (v.substring (v.index_of_nth_char (4), 1)); 293 294 show_adjustmet_icon (); 295 new_value_action (this); 296 } 297 298 int8 parse (string s) { 299 int v = int.parse (s); 300 if (v < 0) { 301 warning ("Failed to parse integer."); 302 return 0; 303 } 304 return (int8) v; 305 } 306 307 public void set_value (string new_value, bool check_boundaries = true, bool emit_signal = true) { 308 string v = new_value.replace (",", "."); 309 int fv; 310 string separator = ""; 311 312 negative = v.has_prefix ("-"); 313 if (negative) { 314 v = v.replace ("-", ""); 315 } 316 317 if (big_number) { 318 if (v == "" || v == "0") { 319 v = "0.0000"; 320 } 321 322 while (v.has_prefix ("0") && !v.has_prefix ("0.")) { 323 v = v.substring (v.index_of_nth_char (1)); 324 } 325 326 fv = int.parse (v); 327 fv = (fv < 0) ? -fv : fv; 328 329 if (fv < 10) { 330 v = @"00$v"; 331 } else if (fv < 100) { 332 v = @"0$v"; 333 } 334 335 v = @"$v"; 336 } 337 338 while (v.char_count () < 6) { 339 if (v.index_of (".") == -1) { 340 v += "."; 341 } else { 342 v += "0"; 343 } 344 } 345 346 if (!big_number) { 347 n0 = (int8) int.parse (v.substring (v.index_of_nth_char (0), 1)); 348 separator = v.substring (v.index_of_nth_char (1), 1); 349 n1 = (int8) int.parse (v.substring (v.index_of_nth_char (2), 1)); 350 n2 = (int8) int.parse (v.substring (v.index_of_nth_char (3), 1)); 351 n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1)); 352 n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1)); 353 } else { 354 n0 = (int8) int.parse (v.substring (v.index_of_nth_char (0), 1)); 355 n1 = (int8) int.parse (v.substring (v.index_of_nth_char (1), 1)); 356 n2 = (int8) int.parse (v.substring (v.index_of_nth_char (2), 1)); 357 separator = v.substring (v.index_of_nth_char (3), 1); 358 n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1)); 359 n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1)); 360 } 361 362 if (separator != ".") { 363 warning (@"Expecting \".\" $new_value -> ($(v))"); 364 } 365 366 if (check_boundaries && get_int_value () > max) { 367 warning (@"Out of bounds ($new_value > $max)."); 368 set_value_round (max, false); 369 } 370 371 if (check_boundaries && get_int_value () < min) { 372 warning (@"Out of bounds ($new_value < $min)."); 373 set_value_round (min, false); 374 } 375 376 if (emit_signal) { 377 new_value_action (this); 378 } 379 380 show_adjustmet_icon (); 381 } 382 383 public void set_value_round (double v, bool check_boundaries = true, bool emit_signal = true) { 384 if (v == -0) { 385 v = 0; 386 } 387 388 set_value (@"$v".replace (",", "."), check_boundaries, emit_signal); 389 } 390 391 public double get_value () { 392 double r; 393 394 if (!big_number) { 395 r = n0 + (n1 / 10.0) + (n2 / 100.0) + (n3 / 1000.0) + (n4 / 1000.0); 396 } else { 397 r = (n0 * 100) + (n1 * 10) + n2 + (n3 / 10.0) + (n4 / 100.0); 398 } 399 400 return (negative) ? -r : r; 401 } 402 403 private int get_int_value () { 404 int r = n0 * 10000 + n1 * 1000 + n2 * 100 + n3 * 10 + n4; 405 return (negative) ? -r : r; 406 } 407 408 public string get_short_display_value () { 409 if (!big_number) { 410 return @"$n0.$n1$n2$n3"; 411 } 412 413 if (negative) { 414 if (n0 == 0 && n1 == 0) { 415 return @"-$n2.$n3$n4"; 416 } 417 418 if (n0 == 0) { 419 return @"-$n1$n2.$n3"; 420 } 421 422 return @"-$n0$n1$n2"; 423 } 424 425 if (n0 == 0 && n1 == 0) { 426 return @"$n2.$n3$n4"; 427 } 428 429 if (n0 == 0) { 430 return @"$n1$n2.$n3$n4"; 431 } 432 433 return @"$n0$n1$n2.$n3"; 434 } 435 436 public string get_display_value () { 437 string v; 438 439 if (!big_number) { 440 return @"$n0.$n1$n2$n3$n4"; 441 } 442 443 v = (negative) ? "-" : ""; 444 445 if (n0 == 0 && n1 == 0) { 446 v = @"$v$n2.$n3$n4"; 447 } else if (n0 == 0) { 448 v = @"$v$n1$n2.$n3$n4"; 449 } else { 450 v = @"$v$n0$n1$n2.$n3$n4"; 451 } 452 453 return v; 454 } 455 456 public override void draw_tool (Context cr, double px, double py) { 457 double scale = Toolbox.get_scale (); 458 double text_height = 14 * scale; 459 string display_value = get_short_display_value (); 460 Text text = new Text (display_value, text_height); 461 double x = x - px; 462 double y = y - py; 463 464 double text_x = x + (w - text.get_sidebearing_extent ()) / 2 + 1; 465 double text_y = y + (h - text_height) / 2; 466 467 if (!show_icon_tool_icon || waiting_for_icon_switch) { 468 if (is_selected ()) { 469 base.icon_color = "Active Spin Button"; 470 } else { 471 base.icon_color = "Spin Button"; 472 } 473 } else { 474 if (is_selected ()) { 475 base.icon_color = "Selected Tool Foreground"; 476 } else { 477 base.icon_color = "Tool Foreground"; 478 } 479 } 480 481 base.draw_tool (cr, px, py); 482 483 if (!show_icon_tool_icon || waiting_for_icon_switch) { 484 if (is_selected ()) { 485 Theme.text_color (text, "Selected Tool Foreground"); 486 } else { 487 Theme.text_color (text, "Tool Foreground"); 488 } 489 490 text.widget_x = text_x; 491 text.widget_y = text_y + text.get_decender (); 492 text.draw (cr); 493 } 494 } 495 } 496 497 } 498