.
1 /*
2 Copyright (C) 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 using Math;
17
18 namespace BirdFont {
19
20 /** Table functions. */
21 public abstract class Table : FontDisplay {
22
23 double scroll = 0;
24 double page_height = 0;
25
26 WidgetAllocation allocation = new WidgetAllocation ();
27 Gee.ArrayList<int> column_width = new Gee.ArrayList<int> ();
28
29 public abstract void update_rows ();
30 public abstract Gee.ArrayList<Row> get_rows ();
31 public abstract void selected_row (Row row, int column, bool delete_button);
32
33 public override void draw (WidgetAllocation allocation, Context cr) {
34 bool color = (scroll + 1 % 2) == 0;
35
36 if (allocation.width != this.allocation.width
37 || allocation.height != this.allocation.height) {
38 this.allocation = allocation;
39 update_rows ();
40 update_scrollbar ();
41 }
42
43 layout ();
44
45 cr.save ();
46 Theme.color (cr, "Background 1");
47 cr.rectangle (0, 0, allocation.width, allocation.height);
48 cr.fill ();
49 cr.restore ();
50
51 foreach (Row r in get_rows ()) {
52 if (scroll < r.y < scroll + allocation.height
53 || scroll < r.y + r.get_height () < scroll + allocation.height) {
54
55 if (r.is_headline) {
56 draw_headline (allocation, cr, r, r.y - scroll);
57 } else {
58 draw_row (allocation, cr, r, r.y - scroll, color, true);
59 }
60
61 color = !color;
62 }
63 }
64 }
65
66 private void layout () {
67 int width;
68
69 column_width.clear ();
70
71 for (int i = 0; i <= Row.MAX_COLUMNS; i++) {
72 column_width.add (0);
73 }
74
75 page_height = 0;
76 foreach (Row row in get_rows ()) {
77 return_if_fail (row.columns <= column_width.size);
78
79 for (int i = 0; i < row.columns; i++) {
80 width = (int) row.get_column (i).get_sidebearing_extent ();
81 width += (int) (10 * MainWindow.units);
82
83 if (width < 100 * MainWindow.units) {
84 width = (int) (100 * MainWindow.units);
85 }
86
87 if (width > column_width.get (i)) {
88 column_width.set (i, width);
89 }
90 }
91
92 row.y = page_height;
93 page_height += row.get_height ();
94 }
95 }
96
97 private void draw_headline (WidgetAllocation allocation, Context cr,
98 Row row, double y) {
99
100 Text t;
101
102 cr.save ();
103 Theme.color (cr, "Foreground 1");
104 t = row.get_column (0);
105 t.widget_x = 40 * MainWindow.units;;
106 t.widget_y = y + 45 * MainWindow.units;
107 t.draw (cr);
108 cr.restore ();
109
110 }
111
112 private void draw_row (WidgetAllocation allocation, Context cr,
113 Row row, double y, bool color, bool dark) {
114
115 Text t;
116 double x;
117 double o;
118
119 o = color ? 1 : 0.5;
120 cr.save ();
121 Theme.color_opacity (cr, "Background 10", o);
122 cr.rectangle (0, y * MainWindow.units, allocation.width, 25 * MainWindow.units);
123 cr.fill ();
124 cr.restore ();
125
126 if (row.has_delete_button ()) {
127 cr.save ();
128 Theme.color (cr, "Foreground 1");
129 cr.set_line_width (1);
130 cr.move_to (10 * MainWindow.units, y + 15 * MainWindow.units);
131 cr.line_to (15 * MainWindow.units, y + 10 * MainWindow.units);
132 cr.move_to (10 * MainWindow.units, y + 10 * MainWindow.units);
133 cr.line_to (15 * MainWindow.units, y + 15 * MainWindow.units);
134 cr.stroke ();
135 cr.restore ();
136 }
137
138 return_if_fail (row.columns <= column_width.size);
139
140 x = 40 * MainWindow.units;
141 for (int i = 0; i < row.columns; i++) {
142 cr.save ();
143 Theme.color (cr, "Foreground 1");
144 t = row.get_column (i);
145 t.widget_x = x;
146 t.widget_y = y + 3 * MainWindow.units;
147 t.draw (cr);
148
149 x += column_width.get (i);
150
151 cr.restore ();
152 }
153 }
154
155 public override void button_release (int button, double ex, double ey) {
156 double x = 0;
157 int column = -1;
158 Row? selected = null;
159 bool over_delete = false;
160
161 if (button != 1) {
162 return;
163 }
164
165 foreach (Row r in get_rows ()) {
166 if (r.y <= ey + scroll <= r.y + r.get_height ()) {
167
168 x = 0;
169 for (int i = 0; i < r.columns; i++) {
170 return_if_fail (0 <= i < column_width.size);
171
172 if (x <= ex < x + column_width.get (i)) {
173 column = i;
174 }
175
176 x += column_width.get (i);
177 }
178
179 over_delete = (ex < 18 && r.has_delete_button ());
180
181 if (over_delete) {
182 column = -1;
183 }
184
185 if (!r.is_headline) {
186 selected = r;
187 }
188
189 break;
190 }
191 }
192
193 if (selected != null) {
194 selected_row ((!) selected, column, over_delete);
195 }
196
197 update_scrollbar ();
198 redraw_area (0, 0, allocation.width, allocation.height);
199 }
200
201 public override bool has_scrollbar () {
202 return true;
203 }
204
205 public override void scroll_wheel_down (double x, double y) {
206 scroll += 30;
207
208 if (scroll > page_height - allocation.height) {
209 scroll = page_height - allocation.height;
210 }
211
212 if (allocation.height > page_height) {
213 scroll = 0;
214 }
215
216 update_scrollbar ();
217 redraw_area (0, 0, allocation.width, allocation.height);
218 }
219
220 public override void scroll_wheel_up (double x, double y) {
221 scroll -= 30;
222
223 if (scroll < 0) {
224 scroll = 0;
225 }
226
227 update_scrollbar ();
228 redraw_area (0, 0, allocation.width, allocation.height);
229 }
230
231 public override void update_scrollbar () {
232 if (page_height == 0 || allocation.height >= page_height) {
233 MainWindow.set_scrollbar_size (0);
234 MainWindow.set_scrollbar_position (0);
235 } else {
236 MainWindow.set_scrollbar_size (allocation.height / page_height);
237 MainWindow.set_scrollbar_position (scroll / (page_height - allocation.height));
238 }
239 }
240
241 public override void scroll_to (double percent) {
242 scroll = percent * page_height;
243
244 if (scroll > page_height) {
245 scroll = (int) (page_height - allocation.height);
246 }
247
248 redraw_area (0, 0, allocation.width, allocation.height);
249 }
250
251 public override void selected_canvas () {
252 update_rows ();
253 update_scrollbar ();
254 }
255 }
256
257 }
258