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