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