The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

DropMenu.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/DropMenu.vala.
Fix memory leak
1 /* 2 Copyright (C) 2012, 2014 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 17 namespace BirdFont { 18 19 public enum MenuDirection { 20 DROP_DOWN, 21 POP_UP; 22 } 23 24 public class DropMenu : GLib.Object { 25 26 public delegate void Selected (MenuAction self); 27 public signal void selected (DropMenu self); 28 29 double x = -1; 30 double y = -1; 31 double width = 0; 32 33 double menu_x = -1; 34 35 public bool menu_visible = false; 36 37 Gee.ArrayList <MenuAction> actions = new Gee.ArrayList <MenuAction> (); 38 39 const int item_height = 25; 40 41 MenuDirection direction = MenuDirection.DROP_DOWN; 42 43 public signal void signal_delete_item (int item_index); 44 45 public DropMenu () { 46 } 47 48 public MenuAction get_action_index (int index) { 49 if (!(0 <= index < actions.size)) { 50 warning (@"No action for index $index."); 51 return new MenuAction ("None"); 52 } 53 return actions.get (index); 54 } 55 56 public void recreate_index () { 57 int i = -1; 58 foreach (MenuAction a in actions) { 59 a.index = i; 60 i++; 61 } 62 } 63 64 public MenuAction get_action_no2 () { 65 if (actions.size < 2) { 66 warning ("No such action"); 67 return new MenuAction ("None"); 68 } 69 70 return actions.get (1); 71 } 72 73 public void deselect_all () { 74 foreach (MenuAction m in actions) { 75 m.set_selected (false); 76 } 77 } 78 79 public void set_direction (MenuDirection d) { 80 direction = d; 81 } 82 83 public void close () { 84 menu_visible = false; 85 } 86 87 public MenuAction add_item (string label) { 88 MenuAction m = new MenuAction (label); 89 add_menu_item (m); 90 return m; 91 } 92 93 public void add_menu_item (MenuAction m) { 94 m.parent = this; 95 actions.add (m); 96 } 97 98 public bool is_over_icon (double px, double py) { 99 if (x == -1 || y == -1) { 100 return false; 101 } 102 103 return x - 12 < px <= x && y - 5 < py < y + 12 + 5; 104 } 105 106 public bool menu_item_action (double px, double py) { 107 MenuAction? action; 108 MenuAction a; 109 MenuAction ma; 110 int index; 111 112 if (menu_visible) { 113 action = get_menu_action_at (px, py); 114 115 if (action != null) { 116 a = (!) action; 117 118 // action for the delete button 119 if (a.has_delete_button && menu_x + width - 13 < px <= menu_x + width) { 120 index = 0; 121 ma = actions.get (0); 122 while (true) { 123 if (a == ma) { 124 actions.remove_at (index); 125 signal_delete_item (index); 126 break; 127 } 128 129 if (ma == actions.get (actions.size - 1)) { 130 break; 131 } else { 132 ma = actions.get (index + 1); 133 index++; 134 } 135 } 136 return false; 137 } else { 138 a.action (a); 139 selected (this); 140 menu_visible = false; 141 } 142 143 return true; 144 } 145 } 146 147 return false; 148 } 149 150 public bool menu_icon_action (double px, double py) { 151 menu_visible = is_over_icon (px, py); 152 return menu_visible; 153 } 154 155 MenuAction? get_menu_action_at (double px, double py) { 156 double n = 0; 157 double ix, iy; 158 159 foreach (MenuAction item in actions) { 160 ix = menu_x - 6; 161 162 if (direction == MenuDirection.DROP_DOWN) { 163 iy = y + 12 + n * item_height; 164 } else { 165 iy = y - 24 - n * item_height; 166 } 167 168 if (ix <= px <= ix + width && iy <= py <= iy + item_height) { 169 return item; 170 } 171 172 n++; 173 } 174 175 return null; 176 } 177 178 public void set_position (double px, double py) { 179 x = px; 180 y = py; 181 182 foreach (MenuAction item in actions) { 183 if (item.text.get_sidebearing_extent () + 25 > width) { 184 width = item.text.get_sidebearing_extent () + 25; 185 } 186 } 187 188 if (x - width + 19 < 0) { 189 menu_x = 30; 190 } else { 191 menu_x = x - width; 192 } 193 } 194 195 public void draw_menu (Context cr) { 196 double ix, iy; 197 int n; 198 199 if (likely (!menu_visible)) { 200 return; 201 } 202 203 cr.save (); 204 Theme.color (cr, "Default Background"); 205 cr.rectangle (menu_x, y - actions.size * item_height, width, actions.size * item_height); 206 207 cr.fill_preserve (); 208 cr.stroke (); 209 cr.restore (); 210 211 cr.save (); 212 213 n = 0; 214 foreach (MenuAction item in actions) { 215 item.width = width; 216 217 iy = y - 8 - n * item_height; 218 ix = menu_x + 2; 219 220 item.draw (ix, iy, cr); 221 n++; 222 } 223 224 cr.restore (); 225 } 226 } 227 228 } 229