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