.
1 /*
2 Copyright (C) 2014 2015 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 using Cairo;
15 using Math;
16
17 namespace BirdFont {
18
19 public class FileDialogTab : FontDisplay {
20
21 int scroll = 0;
22 int visible_rows = 0;
23 WidgetAllocation allocation;
24 Gee.ArrayList<string> files;
25 Gee.ArrayList<string> directories;
26
27 string title;
28 FileChooser action;
29
30 File current_dir;
31
32 string selected_filename;
33 TextListener listener;
34
35 private static bool has_drive_letters = false;
36 private static Gee.ArrayList<string> drive_letters;
37
38 public FileDialogTab (string title, FileChooser action) {
39 this.title = title;
40 this.action = action;
41 allocation = new WidgetAllocation ();
42 files = new Gee.ArrayList<string> ();
43 directories = new Gee.ArrayList<string> ();
44
45 selected_canvas ();
46 }
47
48 public static void add_drive_letter (char c) {
49 if (!has_drive_letters) {
50 drive_letters = new Gee.ArrayList<string> ();
51 has_drive_letters = true;
52 }
53
54 drive_letters.add (@"$((!) c.to_string ()):\\");
55 }
56
57 public override void selected_canvas () {
58 string d;
59 show_text_area ("");
60
61 d = Preferences.get ("file_dialog_dir");
62
63 if (d == "") {
64 d = Environment.get_home_dir ();
65 }
66
67 propagate_files (d);
68
69 update_scrollbar ();
70 redraw_area (0, 0, allocation.width, allocation.height);
71 }
72
73 public void propagate_files (string dir) {
74 FileEnumerator enumerator;
75 FileInfo? file_info;
76 string fn;
77
78 files.clear ();
79 directories.clear ();
80
81 current_dir = File.new_for_path (dir);
82
83 Preferences.set ("file_dialog_dir", dir);
84
85 if (current_dir.get_parent () != null) {
86 directories.add ("..");
87 }
88
89 try {
90 enumerator = current_dir.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE, 0);
91
92 while ((file_info = enumerator.next_file ()) != null) {
93 fn = ((!)file_info).get_name ();
94 if (!fn.has_prefix (".")) {
95 if (((!)file_info).get_file_type () == FileType.DIRECTORY) {
96 directories.add (fn);
97 } else {
98 files.add (fn);
99 }
100 }
101 }
102 } catch (Error e) {
103 warning (e.message);
104 }
105
106 directories.sort ();
107
108 if (has_drive_letters) {
109 for (int i = drive_letters.size - 1; i >= 0; i--) {
110 directories.insert (0, drive_letters.get (i));
111 }
112 }
113
114 files.sort ();
115
116 scroll = 0;
117 update_scrollbar ();
118 }
119
120 public void show_text_area (string text) {
121 listener = new TextListener ("", text, this.title);
122
123 listener.signal_text_input.connect ((text) => {
124 selected_filename = text;
125 });
126
127 listener.signal_submit.connect (() => {
128 File f;
129
130 MainWindow.get_tab_bar ().close_display (this);
131
132 if (selected_filename == "") {
133 action.cancel ();
134 } else {
135 f = get_child (current_dir, selected_filename);
136 action.file_selected ((!)f.get_path ());
137 }
138 });
139
140 TabContent.show_text_input (listener);
141 }
142
143 public override void draw (WidgetAllocation allocation, Context cr) {
144 double y = 75 * MainWindow.units;
145 int s = 0;
146 bool color = (scroll % 2) == 0;
147
148 this.allocation = allocation;
149
150 visible_rows = (int) (allocation.height / 18.0);
151
152 cr.save ();
153 Theme.color (cr, "Background 4");
154 cr.rectangle (0, 0, allocation.width, allocation.height);
155 cr.fill ();
156 cr.restore ();
157
158 cr.save ();
159 Theme.color (cr, "Background 5");
160 cr.set_font_size (12);
161
162 foreach (string file in directories) {
163 if (s++ >= scroll) {
164 draw_row (allocation, cr, file, y, color, true);
165 y += 18 * MainWindow.units;
166 color = !color;
167 }
168 }
169
170 foreach (string file in files) {
171 if (s++ >= scroll) {
172 draw_row (allocation, cr, file, y, color, false);
173 y += 18 * MainWindow.units;
174 color = !color;
175 }
176 }
177
178 cr.restore ();
179 }
180
181 private static void draw_row (WidgetAllocation allocation, Context cr,
182 string file, double y, bool color, bool dark) {
183
184 if (color) {
185 if (dark) {
186 cr.save ();
187 Theme.color (cr, "Background 8");
188 cr.rectangle (0, y - 14 * MainWindow.units, allocation.width, 18 * MainWindow.units);
189 cr.fill ();
190 cr.restore ();
191 } else {
192 cr.save ();
193 Theme.color (cr, "Background 6");
194 cr.rectangle (0, y - 14 * MainWindow.units, allocation.width, 18 * MainWindow.units);
195 cr.fill ();
196 cr.restore ();
197 }
198 } else {
199 if (dark) {
200 cr.save ();
201 Theme.color (cr, "Background 9");
202 cr.rectangle (0, y - 14 * MainWindow.units, allocation.width, 18 * MainWindow.units);
203 cr.fill ();
204 cr.restore ();
205 } else {
206 cr.save ();
207 Theme.color (cr, "Foreground Inverted");
208 cr.rectangle (0, y - 14 * MainWindow.units, allocation.width, 18 * MainWindow.units);
209 cr.fill ();
210 cr.restore ();
211 }
212 }
213
214 // text
215 cr.save ();
216 if (dark) {
217 Theme.color (cr, "Foreground Inverted");
218 }
219 cr.move_to (60, y);
220 cr.set_font_size (12 * MainWindow.units);
221 cr.show_text (file);
222 cr.restore ();
223
224 }
225
226 public override void button_release (int button, double ex, double ey) {
227 int s = 0;
228 double y = 75 * MainWindow.units - 20 * MainWindow.units;
229 string selected;
230 bool dir = false;
231 File f;
232
233 selected = "";
234
235 foreach (string d in directories) {
236 if (s++ >= scroll) {
237 y += 18 * MainWindow.units;
238
239 if (y - 10 * MainWindow.units <= ey <= y + 5 * MainWindow.units) {
240 selected = d;
241 dir = true;
242 }
243 }
244 }
245
246 foreach (string file in files) {
247 if (s++ >= scroll) {
248 y += 18 * MainWindow.units;
249
250 if (y - 10 * MainWindow.units <= ey <= y + 5 * MainWindow.units) {
251 selected = file;
252 }
253 }
254 }
255
256 if (button == 1) {
257 if (!dir) {
258 selected_filename = selected;
259 show_text_area (selected);
260 } else {
261 if (selected == "..") {
262 propagate_files ((!)((!)current_dir.get_parent ()).get_path ());
263 } else {
264
265 if (selected.index_of (":\\") != -1) {
266 propagate_files (selected);
267 } else {
268 f = get_child (current_dir, selected);
269 propagate_files ((!) f.get_path ());
270 }
271 }
272 }
273 }
274
275 update_scrollbar ();
276 redraw_area (0, 0, allocation.width, allocation.height);
277 }
278
279 public override void double_click (uint button, double ex, double ey) {
280 File f;
281
282 button_release ((int) button, ex, ey);
283
284 if (is_null (selected_filename)) {
285 warning ("No file.");
286 return;
287 }
288
289 if (selected_filename != "") {
290 f = get_child (current_dir, selected_filename);
291 action.file_selected ((!)f.get_path ());
292 }
293 }
294
295 public override string get_label () {
296 return title;
297 }
298
299 public override string get_name () {
300 return "FileDialogTab";
301 }
302
303 public override bool has_scrollbar () {
304 return true;
305 }
306
307 public override void scroll_wheel_down (double x, double y) {
308 double rows = 4.16 + files.size + directories.size;
309 scroll += 3;
310
311 if (scroll > rows - visible_rows) {
312 scroll = (int) (rows - visible_rows);
313 }
314
315 if (visible_rows > rows) {
316 scroll = 0;
317 }
318
319 update_scrollbar ();
320 redraw_area (0, 0, allocation.width, allocation.height);
321 }
322
323 public override void scroll_wheel_up (double x, double y) {
324 scroll -= 3;
325
326 if (scroll < 0) {
327 scroll = 0;
328 }
329
330 update_scrollbar ();
331 redraw_area (0, 0, allocation.width, allocation.height);
332 }
333
334 public override void update_scrollbar () {
335 double rows = 4.16 + files.size + directories.size; // 4.16 rows under the text input
336
337 if (rows == 0 || visible_rows == 0) {
338 MainWindow.set_scrollbar_size (0);
339 MainWindow.set_scrollbar_position (0);
340 } else {
341 MainWindow.set_scrollbar_size (visible_rows / rows);
342 MainWindow.set_scrollbar_position (scroll / rows);
343 }
344 }
345
346 public override void scroll_to (double percent) {
347 double rows = 4.16 + files.size + directories.size;
348 scroll = (int) (percent * rows);
349
350 if (scroll > rows - visible_rows) {
351 scroll = (int) (rows - visible_rows);
352 }
353
354 redraw_area (0, 0, allocation.width, allocation.height);
355 }
356 }
357
358 }
359