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.
Merge ../birdfont-2.x
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 } 196 197 previous = t; 198 first_row = false; 199 } 200 } 201 202 content_height += 5 * scale; 203 } 204 205 if (unlikely (content_height < 0)) { 206 warning (@"content_height < 0"); 207 } 208 } 209 210 public void set_scroll (double scroll) { 211 this.scroll = scroll; 212 } 213 214 public void set_offset (double ty) { 215 y = ty; 216 update_tool_position (); 217 } 218 219 public void redraw () { 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 cache () { 273 if (cached == null) { 274 Surface workbench = Screen.create_background_surface (1, 1); 275 Context context = new Context (workbench); 276 draw (context); 277 } 278 } 279 280 public void draw (Context cr) { 281 Surface cache; 282 283 if (unlikely (cached == null)) { 284 Context cc; 285 double text_height = 17 * Toolbox.get_scale (); 286 double offset_y = 0; 287 288 cache = Screen.create_background_surface (Toolbox.allocation_width, (int) (h + content_height)); 289 cc = new Context (cache); 290 cc.scale(Screen.get_scale(), Screen.get_scale()); 291 292 if (tool.size > 0 && headline != null) { 293 Theme.text_color (title, "Text Tool Box"); 294 title.set_font_size (text_height); 295 title.draw_at_top (cc, x, 0); 296 offset_y = text_height + HEADLINE_MARGIN; 297 } 298 299 draw_content (cc, offset_y); 300 cached = (!) cache; 301 } 302 303 if (cached != null) { 304 cache = (!) cached; 305 cr.set_antialias (Cairo.Antialias.NONE); 306 Screen.paint_background_surface (cr, cache, 0, (int) (y + scroll)); 307 } 308 } 309 310 public void draw_content (Context cr, double text_end) { 311 double offset_y = 0; 312 double offset_x = 0; 313 314 update_tool_position (); 315 316 if (tool.size > 0) { 317 offset_x = tool.get (0).x; 318 offset_y = tool.get (0).y - text_end; 319 } 320 321 cr.save (); 322 foreach (Tool t in tool) { 323 if (t.tool_is_visible ()) { 324 t.draw_tool (cr, offset_x - x, offset_y); 325 } 326 } 327 cr.restore (); 328 } 329 330 } 331 332 } 333