The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Expander.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/Expander.vala.
Tip for deleting points
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 using Math; 17 18 namespace BirdFont { 19 20 public class Expander : GLib.Object { 21 22 private static const double HEADLINE_MARGIN = 4; 23 24 public double x = 7; 25 public double y = 5; 26 public double scroll = 0; 27 28 public double w = 6; 29 public double h = 5; 30 31 public double margin = 0; 32 33 protected double opacity = 0; 34 35 protected bool active = false; 36 37 public Gee.ArrayList<Tool> tool; 38 39 bool persist = false; 40 bool unique = false; 41 42 double content_height = 0; 43 44 string? headline; 45 Text title; 46 47 public bool visible = true; 48 Surface? cached = null; 49 50 public Expander (string? headline = null) { 51 this.headline = headline; 52 53 title = new Text (); 54 55 if (headline != null) { 56 title.set_text ((!) headline); 57 } 58 59 tool = new Gee.ArrayList<Tool> (); 60 } 61 62 public void clear_cache () { 63 cached = null; 64 } 65 66 public void set_headline (Text h) { 67 headline = h.get_text (); 68 title = h; 69 } 70 71 public double get_content_height () { 72 return content_height; 73 } 74 75 /** Returns true if tools can be used with the current canvas after 76 * they have been selectes and false if they are a commands to be executed. 77 */ 78 public bool is_persistent () { 79 return persist; 80 } 81 82 /** Returns true if all other tools in thid expander should be deselected 83 * when a tool is selected. 84 */ 85 public bool is_unique () { 86 return unique; 87 } 88 89 public void set_persistent (bool p) { 90 persist = p; 91 } 92 93 public void set_unique (bool u) { 94 unique = u; 95 } 96 97 public void update_tool_position () { 98 double scale = Toolbox.get_scale (); 99 double margin_small = 5 * scale; 100 double xt = x; 101 double yt = y + margin_small; // + scroll 102 bool new_row = false; 103 bool has_visible_tools = false; 104 Tool previous; 105 bool first_row; 106 107 foreach (Tool t in tool) { 108 if (t.tool_is_visible ()) { 109 has_visible_tools = true; 110 break; 111 } 112 } 113 114 if (!has_visible_tools) { 115 content_height = 0; 116 return; 117 } 118 119 foreach (Tool t in tool) { 120 if (t is ZoomBar) { 121 t.w = Toolbox.allocation_width * scale; 122 t.h = 10 * scale; // 7 123 } else if (t is LabelTool) { 124 t.w = Toolbox.allocation_width * scale; 125 t.h = 22 * scale; 126 } else if (t is FontName) { 127 t.w = Toolbox.allocation_width * scale; 128 t.h = 20 * scale; 129 } else if (t is KerningRange) { 130 t.w = Toolbox.allocation_width * scale; 131 t.h = 17 * scale; 132 } else if (t is LayerLabel) { 133 t.w = Toolbox.allocation_width * scale; 134 t.h = 21 * scale; 135 } else if (t is ColorPicker) { 136 t.w = Toolbox.allocation_width * scale; 137 t.h = 5 * ((ColorPicker) t).bar_height; 138 } else { 139 t.w = 33 * scale; 140 t.h = (33 / 1.11) * scale; 141 } 142 } 143 144 if (tool.size > 0) { 145 content_height = tool.get (0).h + margin_small; 146 } else { 147 content_height = 0; 148 } 149 150 if (headline != null && tool.size > 0) { 151 yt += 17 * scale + HEADLINE_MARGIN; 152 content_height += 17 * scale + HEADLINE_MARGIN; 153 } 154 155 if (tool.size > 0) { 156 previous = tool.get (0); 157 first_row = true; 158 foreach (Tool t in tool) { 159 if (t.tool_is_visible ()) { 160 new_row = xt + t.w > Toolbox.allocation_width - 7 * scale; 161 162 if (t is ZoomBar) { 163 t.x = xt; 164 t.y = yt; 165 yt += t.h + 7 * scale; 166 previous = t; 167 continue; 168 } 169 170 if (previous is ZoomBar) { 171 content_height += t.h; 172 } 173 174 if (new_row && !first_row) { 175 content_height += previous.h; 176 xt = x; 177 yt += previous.h; 178 179 if (!(t is LabelTool) && !(previous is LayerLabel)) { 180 yt += 7 * scale; 181 } 182 183 if (!(previous is LayerLabel)) { 184 content_height += margin_small; 185 } 186 } 187 188 t.x = xt; 189 t.y = yt; 190 191 xt += t.w + 7 * scale; 192 193 if (previous is ZoomBar) { 194 content_height += 7 * scale; 195 } else if (previous is KerningRange) { 196 content_height += 10 * scale; 197 } 198 199 previous = t; 200 first_row = false; 201 } 202 } 203 204 content_height += 5 * scale; 205 } 206 207 if (unlikely (content_height < 0)) { 208 warning (@"content_height < 0"); 209 } 210 } 211 212 public void set_scroll (double scroll) { 213 this.scroll = scroll; 214 } 215 216 public void set_offset (double ty) { 217 y = ty; 218 update_tool_position (); 219 } 220 221 public void redraw () { 222 Toolbox.redraw_tool_box (); 223 } 224 225 public void add_tool (Tool t, int position = -1) { 226 if (position < 0) { 227 tool.add (t); 228 } else { 229 return_if_fail (position <= tool.size); 230 tool.insert (position, t); 231 } 232 233 t.redraw_tool.connect (() => { 234 cached = null; 235 }); 236 237 update_tool_position (); 238 239 t.select_action.connect ((selected) => { 240 MainWindow.get_toolbox ().redraw ((int) x, (int) y, (int) w + 300, (int) (h + margin)); 241 242 if (is_unique ()) { 243 foreach (var deselected in tool) { 244 if (selected.get_id () != deselected.get_id ()) { 245 deselected.set_selected (false); 246 } 247 } 248 } 249 250 if (!selected.new_selection && selected.persistent) { 251 if (is_persistent ()) { 252 selected.set_selected (true); 253 } else { 254 selected.set_selected (false); 255 } 256 } 257 258 selected.new_selection = false; 259 }); 260 } 261 262 public bool is_over (double xp, double yp) { 263 double yt = y + scroll + 2; 264 return yt - 7 <= yp <= yt + 7 && xp < 17; 265 } 266 267 public bool set_active (bool a) { 268 bool r = (active != a); 269 opacity = (a) ? 1 : 0; 270 active = a; 271 return r; 272 } 273 274 public void cache () { 275 if (cached == null) { 276 Surface workbench = Screen.create_background_surface (1, 1); 277 Context context = new Context (workbench); 278 draw (context); 279 } 280 } 281 282 public void draw (Context cr) { 283 Surface cache; 284 285 if (unlikely (cached == null)) { 286 Context cc; 287 double text_height = 17 * Toolbox.get_scale (); 288 double offset_y = 0; 289 290 cache = Screen.create_background_surface (Toolbox.allocation_width, (int) (h + content_height)); 291 cc = new Context (cache); 292 cc.scale(Screen.get_scale(), Screen.get_scale()); 293 294 if (tool.size > 0 && headline != null) { 295 Theme.text_color (title, "Text Tool Box"); 296 title.set_font_size (text_height); 297 title.draw_at_top (cc, x, 0); 298 offset_y = text_height + HEADLINE_MARGIN; 299 } 300 301 draw_content (cc, offset_y); 302 cached = (!) cache; 303 } 304 305 if (cached != null) { 306 cache = (!) cached; 307 cr.set_antialias (Cairo.Antialias.NONE); 308 Screen.paint_background_surface (cr, cache, 0, (int) (y + scroll)); 309 } 310 } 311 312 public void draw_content (Context cr, double text_end) { 313 double offset_y = 0; 314 double offset_x = 0; 315 316 update_tool_position (); 317 318 if (tool.size > 0) { 319 offset_x = tool.get (0).x; 320 offset_y = tool.get (0).y - text_end; 321 } 322 323 cr.save (); 324 foreach (Tool t in tool) { 325 if (t.tool_is_visible ()) { 326 t.draw_tool (cr, offset_x - x, offset_y); 327 } 328 } 329 cr.restore (); 330 } 331 332 } 333 334 } 335