The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

ColorPicker.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
Circle boundaries heads/master
1 /* 2 Copyright (C) 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 using SvgBird; 17 18 namespace BirdFont { 19 20 public class ColorPicker : Tool { 21 22 double hue = 0; 23 double s = 0; 24 double b = 0; 25 double a = 1; 26 27 public signal void fill_color_updated (); 28 public signal void stroke_color_updated (); 29 public signal void gradient_color_updated (); 30 31 bool update_color = false; 32 public double bar_height; 33 34 int selected_bar = 0; 35 36 public bool has_stroke_color = false; 37 bool stroke_selected = false; 38 39 public Color stroke_color = new Color (0, 0, 0, 1); 40 public Color fill_color = new Color (0, 0, 0, 1); 41 42 public LinearGradient gradient = new LinearGradient (); 43 bool update_gradient = false; 44 int bars; 45 Stop current_stop = new Stop (); 46 47 public ColorPicker (string tooltip = "") { 48 base (null, tooltip); 49 50 bar_height = 22 * Toolbox.get_scale (); 51 bars = 5; 52 h = bars * bar_height; 53 54 stroke_color_updated.connect (() => { 55 redraw (); 56 GlyphCanvas.redraw (); 57 }); 58 59 panel_press_action.connect ((selected, button, tx, ty) => { 60 if (y <= ty <= y + bars * bar_height) { 61 update_color = true; 62 selected_bar = (int) ((ty - y) / bar_height); 63 set_color_from_pointer (tx); 64 } 65 }); 66 67 panel_move_action.connect ((selected, button, tx, ty) => { 68 if (update_color) { 69 set_color_from_pointer (tx); 70 } 71 72 return false; 73 }); 74 75 panel_release_action.connect ((selected, button, tx, ty) => { 76 update_color = false; 77 }); 78 } 79 80 public void set_gradient (LinearGradient g, Stop stop, bool update_gradient) { 81 gradient = g; 82 this.update_gradient = update_gradient; 83 current_stop = stop; 84 redraw (); 85 } 86 87 public void set_color (Color c) { 88 c.to_hsva (out hue, out s, out b, out a); 89 } 90 91 public void set_color_from_pointer (double tx) { 92 if (tx > Toolbox.allocation_width) { 93 tx = Toolbox.allocation_width; 94 } 95 96 if (tx < 0) { 97 tx = 0; 98 } 99 100 if (selected_bar == 0) { 101 hue = (double) tx / Toolbox.allocation_width; 102 } else if (selected_bar == 1) { 103 s = (double) tx / Toolbox.allocation_width; 104 } else if (selected_bar == 2) { 105 b = (double) tx / Toolbox.allocation_width; 106 } else if (selected_bar == 3) { 107 a = (double) tx / Toolbox.allocation_width; 108 } else if (!update_gradient && selected_bar == 4) { 109 if (has_stroke_color) { 110 stroke_selected = tx > Toolbox.allocation_width / 2.0; 111 112 if (stroke_selected) { 113 set_color (stroke_color); 114 } else { 115 set_color (fill_color); 116 } 117 } 118 } else if (update_gradient && selected_bar == 4) { 119 if (gradient.stops.size > 0) { 120 int g = (int) ((tx / Toolbox.allocation_width) * gradient.stops.size); 121 return_if_fail (0 <= g < gradient.stops.size); 122 current_stop = gradient.stops.get (g); 123 set_color (new Color.create_copy (current_stop.color)); 124 } 125 } 126 127 if (selected_bar != 4) { 128 if (update_gradient) { 129 current_stop.color = new Color.hsba (hue, s, b, a); 130 gradient_color_updated (); 131 } else { 132 if (has_stroke_color && stroke_selected) { 133 stroke_color = new Color.hsba (hue, s, b, a); 134 stroke_color_updated (); 135 } else { 136 fill_color = new Color.hsba (hue, s, b, a); 137 fill_color_updated (); 138 } 139 } 140 } 141 } 142 143 public Color get_stroke_color () { 144 return stroke_color; 145 } 146 147 public Color get_fill_color () { 148 return fill_color; 149 } 150 151 public override void draw_tool (Context cr, double px, double py) { 152 draw_bars (cr, px, py); 153 draw_dial (cr, px, py, 0, hue); 154 draw_dial (cr, px, py, 1, s); 155 draw_dial (cr, px, py, 2, b); 156 draw_dial (cr, px, py, 3, a); 157 } 158 159 public void draw_bars (Context cr, double px, double py) { 160 double scale = Toolbox.get_scale (); 161 double step = 1.0 / Toolbox.allocation_width; 162 Color c; 163 double y = this.y - py; 164 165 for (double p = 0; p < 1; p += step) { 166 c = new Color.hsba (p, 1, 1, 1); 167 cr.save (); 168 cr.set_source_rgba (c.r, c.g, c.b, c.a); 169 cr.rectangle (p * Toolbox.allocation_width, y, scale, bar_height); 170 cr.fill (); 171 cr.restore (); 172 173 c = new Color.hsba (hue, p, 1, 1); 174 cr.save (); 175 cr.set_source_rgba (c.r, c.g, c.b, c.a); 176 cr.rectangle (p * Toolbox.allocation_width, y + bar_height, scale, bar_height); 177 cr.fill (); 178 cr.restore (); 179 180 c = new Color.hsba (hue, s, p, 1); 181 cr.save (); 182 cr.set_source_rgba (c.r, c.g, c.b, c.a); 183 cr.rectangle (p * Toolbox.allocation_width, y + 2 * bar_height, scale, bar_height); 184 cr.fill (); 185 cr.restore (); 186 187 c = new Color.hsba (hue, s, b, p); 188 cr.save (); 189 cr.set_source_rgba (c.r, c.g, c.b, c.a); 190 cr.rectangle (p * Toolbox.allocation_width, y + 3 * bar_height, scale, bar_height); 191 cr.fill (); 192 cr.restore (); 193 } 194 195 if (!update_gradient) { 196 if (!has_stroke_color) { 197 c = fill_color; 198 cr.save (); 199 cr.set_source_rgba (c.r, c.g, c.b, c.a); 200 cr.rectangle (0, y + 4 * bar_height, Toolbox.allocation_width, bar_height); 201 cr.fill (); 202 cr.restore (); 203 } else { 204 double cw = Toolbox.allocation_width / 2.0 - 2 * scale; 205 206 cr.save (); 207 cr.set_source_rgba (fill_color.r, fill_color.g, fill_color.b, fill_color.a); 208 cr.rectangle (0, y + 4 * bar_height, cw, bar_height); 209 cr.fill (); 210 cr.restore (); 211 212 cr.save (); 213 cr.set_source_rgba (stroke_color.r, stroke_color.g, stroke_color.b, stroke_color.a); 214 cr.rectangle (cw + 4 * scale, y + 4 * bar_height, cw, bar_height); 215 cr.fill (); 216 cr.restore (); 217 218 if (has_stroke_color) { 219 if (stroke_selected) { 220 cr.save (); 221 Theme.color (cr, "Tool Foreground"); 222 cr.set_line_width (1); 223 cr.rectangle (cw + 4 * scale, y + 4 * bar_height, cw, bar_height); 224 cr.stroke (); 225 cr.restore (); 226 } else { 227 cr.save (); 228 Theme.color (cr, "Tool Foreground"); 229 cr.set_line_width (1); 230 cr.rectangle (0, y + 4 * bar_height, cw, bar_height); 231 cr.stroke (); 232 cr.restore (); 233 } 234 } 235 } 236 } else { // update gradient 237 int stop_size = (int) ((double) Toolbox.allocation_width / gradient.stops.size); 238 for (int i = 0; i < gradient.stops.size; i++) { 239 Stop s = gradient.stops.get (i); 240 c = new Color.create_copy (s.color); 241 cr.save (); 242 cr.set_source_rgba (c.r, c.g, c.b, c.a); 243 cr.rectangle (i * stop_size, y + 4 * bar_height, stop_size, bar_height); 244 cr.fill (); 245 cr.restore (); 246 } 247 248 bool found = false; 249 for (int i = 0; i < gradient.stops.size; i++) { 250 Stop s = gradient.stops.get (i); 251 if (s == current_stop) { 252 found = true; 253 cr.save (); 254 Theme.color (cr, "Tool Foreground"); 255 cr.set_line_width (1); 256 cr.rectangle (i * stop_size, y + 4 * bar_height, stop_size, bar_height); 257 cr.stroke (); 258 cr.restore (); 259 } 260 } 261 262 if (!found) { 263 warning ("No stop selected."); 264 } 265 } 266 267 } 268 269 void draw_dial (Context cr, double px, double py, int bar_index, double val) { 270 double y = this.y - py; 271 double scale = Toolbox.get_scale (); 272 double p; 273 p = bar_index * bar_height; 274 275 return_if_fail (y + p + bar_height - 2 * scale > 0); 276 277 cr.save (); 278 cr.set_line_width (1 * scale); 279 cr.set_source_rgba (1, 1, 1, 1); 280 cr.move_to (val * Toolbox.allocation_width * scale - 3 * scale, y + p + bar_height); 281 cr.line_to (val * Toolbox.allocation_width, y + p + bar_height - 2 * scale); 282 cr.line_to (val * Toolbox.allocation_width + 3 * scale, y + p + bar_height); 283 cr.stroke_preserve (); 284 cr.set_source_rgba (0, 0, 0, 1); 285 cr.fill (); 286 cr.restore (); 287 288 cr.save (); 289 cr.set_line_width (1 * scale); 290 cr.set_source_rgba (1, 1, 1, 1); 291 cr.move_to (val * Toolbox.allocation_width * scale - 3 * scale, y + p); 292 cr.line_to (val * Toolbox.allocation_width, y + p + 2 * scale); 293 cr.line_to (val * Toolbox.allocation_width + 3 * scale, y + p); 294 cr.stroke_preserve (); 295 cr.set_source_rgba (0, 0, 0, 1); 296 cr.fill (); 297 cr.restore (); 298 } 299 } 300 301 } 302