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