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