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