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