The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Component.vala in birdui

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 birdui/Component.vala.
Merge branch '2.x' of github.com:johanmattssonm/birdfont
1 /* 2 Copyright (C) 2016 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 B; 16 using SvgBird; 17 using Gee; 18 using Cairo; 19 20 namespace Bird { 21 22 public abstract class Component : GLib.Object { 23 public double width { get; protected set; } 24 public double height { get; protected set; } 25 26 public double padded_width { 27 get { 28 return width + get_padding_top () + get_padding_bottom (); 29 } 30 } 31 32 public double padded_height { 33 get { 34 return height + get_padding_left () + get_padding_right (); 35 } 36 } 37 38 public double padded_x { 39 get { 40 return x + get_padding_top (); 41 } 42 } 43 44 public double padded_y { 45 get { 46 return y + get_padding_left (); 47 } 48 } 49 50 /** Vertical placement for this component relative to the parent container. */ 51 public double x { get; protected set; } 52 53 /** Horizontal placement for this component relative to the parent container. */ 54 public double y { get; protected set; } 55 56 /** The parts this component is made of. */ 57 protected ArrayList<Component> components = new ArrayList<Component> (); 58 59 XmlElement component_tag; 60 61 /** Style sheet and other SVG definitions. */ 62 Defs defs = new Defs (); 63 protected SvgStyle style = new SvgStyle (); 64 65 string? css_class = null; 66 string? id = null; 67 68 Overflow overflow = Overflow.VISIBLE; 69 70 public Component.load (string file_name, double width, double height) { 71 this.width = width; 72 this.height = height; 73 load_file (file_name, null); 74 layout (width, height); 75 } 76 77 /** Parse component ui file but don't do layout. */ 78 internal Component.load_component (string file_name, Component parent) { 79 load_file (file_name, parent); 80 } 81 82 public Component (XmlElement component_tag, Defs defs) { 83 this.defs = defs; 84 this.component_tag = component_tag; 85 set_identification (); 86 parse (component_tag); 87 } 88 89 public Component.embedded (XmlElement component_tag, Defs defs) { 90 this.defs = defs; 91 this.component_tag = component_tag; 92 set_identification (); 93 } 94 95 void set_identification () { 96 foreach (Attribute attribute in component_tag.get_attributes ()) { 97 string attribute_name = attribute.get_name (); 98 99 if (attribute_name == "id") { 100 id = attribute.get_content (); 101 } else if (attribute_name == "class") { 102 css_class = attribute.get_content (); 103 } 104 } 105 } 106 107 private void inherit_styles_sheet (Defs defs) { 108 this.defs = defs; 109 } 110 111 protected void parse_style (XmlElement style_tag) { 112 defs = defs.shallow_copy (); 113 StyleSheet style_sheet = StyleSheet.parse (defs, style_tag); 114 defs.style_sheet.merge (style_sheet); 115 } 116 117 protected void parse_svg (XmlElement svg_tag) { 118 foreach (Attribute attribute in svg_tag.get_attributes ()) { 119 string attribute_name = attribute.get_name (); 120 121 if (attribute_name == "file") { 122 string file_name = attribute.get_content (); 123 SvgComponent svg = new SvgComponent (svg_tag, defs, file_name); 124 add_component (svg); 125 } 126 } 127 } 128 129 protected void add_component (Component component) { 130 components.add (component); 131 component.set_style_properties (this); 132 } 133 134 protected void set_style_properties (Component parent) { 135 inherit_styles_sheet (parent.defs); 136 style = SvgStyle.parse (parent.defs, parent.style, component_tag); 137 set_overflow_property_from_css (); 138 set_identification (); 139 } 140 141 protected void set_overflow_property_from_css () { 142 string? css_overflow = style.get_css_property ("overflow"); 143 144 if (css_overflow != null) { 145 string overflow_property = (!) css_overflow; 146 147 if (overflow_property == "hidden") { 148 overflow = Overflow.HIDDEN; 149 } else if (overflow_property == "visible") { 150 overflow = Overflow.VISIBLE; 151 } 152 } 153 } 154 155 protected void parse_layout (XmlElement layout_tag) { 156 string type = ""; 157 158 foreach (Attribute attribute in layout_tag.get_attributes ()) { 159 string attribute_name = attribute.get_name (); 160 161 if (attribute_name == "type") { 162 type = attribute.get_content (); 163 } 164 } 165 166 if (type == "hbox") { 167 HBox hbox = new HBox (layout_tag, defs); 168 add_component (hbox); 169 } else if (type == "vbox") { 170 VBox vbox = new VBox (layout_tag, defs); 171 add_component (vbox); 172 } else { 173 warning (type + " layout of type is supported in this verison."); 174 } 175 } 176 177 protected void parse_component (XmlElement component_tag) { 178 foreach (Attribute attribute in component_tag.get_attributes ()) { 179 string attribute_name = attribute.get_name (); 180 181 if (attribute_name == "file") { 182 string file_name = attribute.get_content (); 183 UI ui = new UI.load_component (file_name, this); 184 185 foreach (Component component in ui.components) { 186 add_component (component); 187 188 SvgStyle copied_style; 189 copied_style = SvgStyle.parse (defs, style, component_tag); 190 copied_style.apply (component.style); 191 component.style = copied_style; 192 } 193 } 194 } 195 } 196 197 protected void parse (XmlElement component_tag) { 198 foreach (XmlElement tag in component_tag) { 199 string tag_name = tag.get_name (); 200 201 if (tag_name == "ui") { 202 parse (tag); 203 } else if (tag_name == "layout") { 204 parse_layout (tag); 205 } else if (tag_name == "component") { 206 parse_component (tag); 207 } else if (tag_name == "svg") { 208 parse_svg (tag); 209 } else if (tag_name == "style") { 210 parse_style (tag); 211 } else { 212 unused_tag (tag_name); 213 } 214 } 215 } 216 217 internal void unused_attribute (string attribute) { 218 warning ("The attribute " + attribute + " is not known in this version."); 219 } 220 221 internal void unused_tag (string tag_name) { 222 warning ("The tag " + tag_name + " is not known in this version."); 223 } 224 225 public void load_file (string file_name, Component? parent) { 226 if (file_name.has_suffix (".ui")) { 227 load_layout (file_name, parent); 228 } else if (file_name.has_suffix (".svg")) { 229 SvgComponent svg = new SvgComponent.for_file (file_name); 230 add_component (svg); 231 } else { 232 warning (file_name + " is not a ui file or svg file."); 233 } 234 } 235 236 public void load_layout (string file_name, Component? parent) { 237 string? path = find_file (file_name); 238 239 if (path == null) { 240 warning (file_name + " not found."); 241 return; 242 } 243 244 string xml_data; 245 File layout_file = File.new_for_path ((!) path); 246 247 try { 248 FileUtils.get_contents((!) layout_file.get_path (), out xml_data); 249 } catch (GLib.Error error) { 250 warning (error.message); 251 return; 252 } 253 254 XmlTree xml_parser = new XmlTree (xml_data); 255 XmlElement tag = xml_parser.get_root (); 256 257 if (parent == null) { 258 component_tag = tag; 259 defs = new Defs (); 260 } else { 261 Component p = (!) parent; 262 component_tag = p.component_tag; 263 defs = p.defs; 264 } 265 266 parse (tag); 267 } 268 269 public static string find_file (string file_name) { 270 File file = File.new_for_path ("birdui/" + file_name); 271 272 if (file.query_exists ()) { 273 return (!) file.get_path (); 274 } 275 276 return file_name; 277 } 278 279 public virtual void get_min_size (out double min_width, out double min_height) { 280 min_width = width; 281 min_height = height; 282 283 if (unlikely (components.size > 1)) { 284 warning ("A component has several parts but no layout has been set."); 285 } 286 287 foreach (Component component in components) { 288 component.get_min_size (out min_width, out min_height); 289 } 290 291 min_width += get_padding_left (); 292 min_width += get_padding_right (); 293 min_height += get_padding_top (); 294 min_height += get_padding_bottom (); 295 } 296 297 public virtual void layout (double parent_width, double parent_height) { 298 warning ("A component without a layout was added to the view."); 299 300 double w, h; 301 get_min_size (out w, out h); 302 303 width = w; 304 height = h; 305 306 foreach (Component component in components) { 307 component.layout (parent_width, parent_height); 308 } 309 } 310 311 public void clip (Context cairo) { 312 if (overflow == Overflow.HIDDEN) { 313 cairo.rectangle (0, 0, width, height); 314 cairo.clip (); 315 } 316 } 317 318 public abstract void draw (Context cairo); 319 320 public virtual void motion_notify_event (double x, double y) { 321 } 322 323 public virtual void button_press_event (uint button, double x, double y) { 324 } 325 326 public virtual string to_string () { 327 return @"$(component_tag.get_name ())"; 328 } 329 330 public void print_tree () { 331 print_tree_level (0); 332 } 333 334 protected void print_tree_level (int indent) { 335 for (int i = 0; i < indent; i++) { 336 print ("\t"); 337 } 338 339 print (@"$(to_string ()) width: $padded_width, height: $padded_height x $x y $y $(style)\n"); 340 341 foreach (Component component in components) { 342 component.print_tree_level (indent + 1); 343 } 344 } 345 346 protected double get_padding_bottom () { 347 return SvgFile.parse_number (style.get_css_property ("padding-bottom")); 348 } 349 350 protected double get_padding_top () { 351 return SvgFile.parse_number (style.get_css_property ("padding-top")); 352 } 353 354 protected double get_padding_left () { 355 return SvgFile.parse_number (style.get_css_property ("padding-left")); 356 } 357 358 protected double get_padding_right () { 359 return SvgFile.parse_number (style.get_css_property ("padding-right")); 360 } 361 362 protected void limit_size (ref double width, ref double height) { 363 string? min_width = style.get_css_property ("min-width"); 364 if (min_width != null) { 365 double w = SvgFile.parse_number (min_width); 366 if (width < w) { 367 width = w; 368 } 369 } 370 371 string? min_height = style.get_css_property ("min-height"); 372 if (min_height != null) { 373 double h = SvgFile.parse_number (min_height); 374 375 if (height < h) { 376 height = h; 377 } 378 } 379 380 string? max_width = style.get_css_property ("max-width"); 381 if (max_width != null) { 382 double w = SvgFile.parse_number (max_width); 383 384 if (width > w) { 385 width = w; 386 } 387 } 388 389 string? max_height = style.get_css_property ("max-height"); 390 if (max_height != null) { 391 double h = SvgFile.parse_number (max_height); 392 393 if (height > h) { 394 height = h; 395 } 396 } 397 398 if (width < 0) { 399 width = 0; 400 } 401 402 if (height < 0) { 403 height = 0; 404 } 405 } 406 } 407 408 } 409 410