some playing with bbs - new fm
[mirrors/Programs.git] / bash / bbs / utils / fm / fm / ui.c
1 /* Copyright (C) 2008 Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "fm.h"
18
19 WINDOW *tree_window, *info_window;
20 GList *lines, *selected_line, *first_line, *last_line;
21
22 void init_lines(void)
23 {
24 lines = g_list_append(lines, tree_root);
25 FILE(tree_root)->line = lines;
26 selected_line = lines;
27 first_line = lines;
28 update_last_line();
29 }
30
31 void init_curses(void)
32 {
33 int screen_size[2];
34
35 initscr();
36 #ifdef INOTIFY
37 halfdelay(GETCH_DELAY);
38 #else
39 cbreak();
40 #endif
41 nonl();
42 noecho();
43 keypad(stdscr, TRUE);
44 curs_set(0);
45 refresh();
46
47 getmaxyx(stdscr, screen_size[0], screen_size[1]);
48 tree_window = newwin(screen_size[0] - 1, screen_size[1], 0, 0);
49 info_window = newwin(1, screen_size[1], screen_size[0] - 1, 0);
50 scrollok(tree_window, TRUE);
51 idlok(tree_window, TRUE);
52 }
53
54 void init_ui(char *name)
55 {
56 init_curses();
57 init_tree(name);
58 init_lines();
59 print_line(FILE(tree_root)->line);
60 #ifdef INOTIFY
61 init_inotify(tree_root);
62 #endif
63 open_directory(tree_root);
64 refresh_screen();
65 }
66
67 void refresh_screen(void)
68 {
69 wnoutrefresh(tree_window);
70 wnoutrefresh(info_window);
71 doupdate();
72 }
73
74 void handle_sigwinch(int signal_number)
75 {
76 ungetch(KEY_RESIZE);
77 }
78
79 void print_lines(GList *start_line, GList *end_line, gboolean clear_bottom_lines)
80 {
81 GList *line_ptr;
82 int line_number;
83
84 if (end_line == NULL)
85 end_line = last_line;
86 else if (start_line != NULL) {
87 for (line_ptr = start_line;
88 g_list_position(first_line, line_ptr) < getmaxy(tree_window);
89 line_ptr = g_list_next(line_ptr)) {
90 print_line(line_ptr);
91 if (line_ptr == end_line)
92 break;
93 }
94 }
95 line_number = g_list_position(first_line, last_line) + 1;
96 if (clear_bottom_lines && line_number < getmaxy(tree_window)) {
97 wmove(tree_window, line_number, 0);
98 wclrtobot(tree_window);
99 }
100 }
101
102 void print_parents_lines(GList *line)
103 {
104 GNode *file_ptr;
105 int depth;
106
107 for (file_ptr = NODE(line)->parent, depth = g_node_depth(file_ptr) - 1;
108 !G_NODE_IS_ROOT(file_ptr); file_ptr = file_ptr->parent, depth--) {
109 if (file_ptr != g_node_last_sibling(file_ptr))
110 mvwaddch(tree_window, g_list_position(first_line, line),
111 2 * depth - 2, ACS_VLINE);
112 else
113 mvwaddch(tree_window, g_list_position(first_line, line),
114 2 * depth - 2, ' ');
115 mvwaddch(tree_window, g_list_position(first_line, line), 2 * depth - 1, ' ');
116 }
117 }
118
119 void print_line(GList *line)
120 {
121 int line_number = g_list_position(first_line, line);
122 GNode *file = NODE(line);
123 int depth = g_node_depth(file) - 1;
124 char *link_str;
125
126 wmove(tree_window, line_number, 0);
127 wclrtoeol(tree_window);
128
129 if (line == selected_line)
130 wattron(tree_window, A_REVERSE);
131
132 if (G_NODE_IS_ROOT(file)) {
133 wattron(tree_window, A_BOLD);
134 waddnstr(tree_window, FILE(file)->name, getmaxx(tree_window) - 1);
135 if (!g_str_has_suffix(FILE(file)->name, "/"))
136 waddch(tree_window, '/');
137 wattroff(tree_window, A_BOLD);
138 } else {
139 if (file != g_node_last_sibling(file))
140 mvwaddch(tree_window, line_number, 2 * depth - 2, ACS_LTEE);
141 else
142 mvwaddch(tree_window, line_number, 2 * depth - 2, ACS_LLCORNER);
143
144 waddch(tree_window, ACS_HLINE);
145 if (FILE(file)->link == TRUE) {
146 link_str = g_strdup_printf("%s -> %s", FILE(file)->name,
147 FILE(file)->link_path);
148 waddnstr(tree_window, link_str, getmaxx(tree_window) - 2 * depth - 1);
149 free(link_str);
150 } else
151 waddnstr(tree_window, FILE(file)->name,
152 getmaxx(tree_window) - 2 * depth - 1);
153
154 if (FILE(file)->type == directory_type && ((FILE(file)->link == TRUE &&
155 !g_str_has_suffix(FILE(file)->link_path, "/")) ||
156 (FILE(file)->link == FALSE &&
157 !g_str_has_suffix(FILE(file)->name, "/"))))
158 waddch(tree_window, '/');
159 print_parents_lines(line);
160 }
161 wattroff(tree_window, A_REVERSE);
162 }
163
164 void clear_info(void)
165 {
166 werase(info_window);
167 }
168
169 void print_info(char *message, gboolean bold)
170 {
171 static char *last_message = NULL;
172 static gboolean last_bold = FALSE;
173
174 if (message != NULL) {
175 if (last_message != NULL)
176 free(last_message);
177 last_message = strdup(message);
178 }
179 if (bold == TRUE || bold == FALSE)
180 last_bold = bold;
181 if (last_bold == TRUE)
182 wattron(info_window, A_BOLD);
183 werase(info_window);
184 if (last_message != NULL)
185 waddnstr(info_window, last_message, getmaxx(info_window));
186 wattroff(info_window, A_BOLD);
187 }
188
189 void print_error_info(int last_errno, char *file, int line, char *message)
190 {
191 char *message_format = "Error (%s:%i): %s";
192 char *message_str;
193
194 if (message != NULL)
195 message_str = g_strdup_printf(message_format, file, line, message);
196 else
197 message_str = g_strdup_printf(message_format, file, line, strerror(last_errno));
198 print_info(message_str, TRUE);
199 free(message_str);
200 }
201
202 void update_last_line(void)
203 {
204 if (g_list_length(first_line) > getmaxy(tree_window))
205 last_line = g_list_nth(first_line, getmaxy(tree_window) - 1);
206 else
207 last_line = g_list_last(lines);
208 }
209
210 void add_directory_content(GNode *directory)
211 {
212 GNode *file_ptr, *directory_sibling;
213 int position;
214
215 directory_sibling = get_next_file_not_deepper(directory);
216
217 for (position = g_list_position(lines, FILE(directory)->line) + 1,
218 file_ptr = g_node_first_child(directory);
219 file_ptr != NULL && file_ptr != directory_sibling;
220 position++, file_ptr = get_next_file(file_ptr)) {
221 lines = g_list_insert(lines, file_ptr, position);
222 FILE(file_ptr)->line = g_list_nth(lines, position);
223 }
224 }
225
226 void open_directory(GNode *directory)
227 {
228 if (FILE(directory)->read == FALSE && read_directory(directory) == FALSE)
229 return;
230
231 FILE(directory)->open = TRUE;
232 add_directory_content(directory);
233 update_last_line();
234 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
235 }
236
237 void close_directory(GNode *directory)
238 {
239 GNode *directory_sibling;
240 GList *line_ptr;
241
242 directory_sibling = get_next_file_not_deepper(directory);
243
244 for (line_ptr = g_list_next(FILE(directory)->line); line_ptr != NULL &&
245 NODE(line_ptr) != directory_sibling; line_ptr = g_list_next(FILE(directory)->line))
246 lines = g_list_delete_link(lines, line_ptr);
247
248 FILE(directory)->open = FALSE;
249 update_last_line();
250 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
251 }
252
253 void update_directory(GNode *directory)
254 {
255 close_directory(directory);
256 destroy_directory_content(directory);
257 open_directory(directory);
258
259 if (FILE(directory)->show_dotfiles == TRUE)
260 show_dotfiles(directory);
261 }
262
263 void show_dotfiles(GNode *directory)
264 {
265 add_dotfiles(directory);
266 update_last_line();
267 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
268 }
269
270 void hide_dotfiles(GNode *directory)
271 {
272 remove_dotfiles(directory);
273 update_last_line();
274 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
275 }
276
277 void select_line(GList *line)
278 {
279 select_nth_line(g_list_position(lines, line) - g_list_position(lines, selected_line));
280 }
281
282 void select_file(GNode *file)
283 {
284 select_line(FILE(file)->line);
285 }
286
287 void select_nth_line(int n_lines)
288 {
289 GList *old_selected_line;
290 int min_n_lines, max_n_lines;
291
292 if ((max_n_lines = g_list_length(selected_line) - 1) < n_lines)
293 n_lines = max_n_lines;
294 else if((min_n_lines = (int) g_list_length(selected_line) -
295 (int) g_list_length(lines)) > n_lines)
296 n_lines = min_n_lines;
297
298 old_selected_line = selected_line;
299 if (n_lines < 0)
300 selected_line = g_list_nth(lines, g_list_position(lines, selected_line) + n_lines);
301 else if (n_lines > 0)
302 selected_line = g_list_nth(selected_line, n_lines);
303
304 if (g_list_position(lines, selected_line) < g_list_position(lines, first_line))
305 scroll_tree(g_list_position(lines, selected_line) -
306 g_list_position(lines, first_line));
307 else if (g_list_position(lines, selected_line) > g_list_position(lines, last_line))
308 scroll_tree(g_list_position(lines, selected_line) -
309 g_list_position(lines, last_line));
310
311 if (n_lines != 0) {
312 print_line(selected_line);
313 if (g_list_position(lines, first_line) <= g_list_position(lines, old_selected_line) &&
314 g_list_position(lines, old_selected_line) <=
315 g_list_position(lines, last_line))
316 print_line(old_selected_line);
317 }
318 }
319
320 void scroll_tree(int n_lines)
321 {
322 int min_n_lines, max_n_lines;
323
324 if ((min_n_lines = -g_list_position(lines, first_line)) > n_lines)
325 n_lines = min_n_lines;
326 else if ((max_n_lines = g_list_length(last_line) - 1) < n_lines)
327 n_lines = max_n_lines;
328
329 wscrl(tree_window, n_lines);
330 if (n_lines < 0) {
331 first_line = g_list_nth(lines, g_list_position(lines, first_line) + n_lines);
332 update_last_line();
333 print_lines(first_line, g_list_nth(first_line, -n_lines), FALSE);
334 } else if (n_lines > 0) {
335 first_line = g_list_nth(first_line, n_lines);
336 update_last_line();
337 print_lines(g_list_nth(lines, g_list_position(lines, last_line) - n_lines),
338 last_line, TRUE);
339 }
340 }
341
342 void select_line_inside_window(void)
343 {
344 if (g_list_position(lines, selected_line) < g_list_position(lines, first_line))
345 select_line(first_line);
346 else if (g_list_position(lines, selected_line) > g_list_position(lines, last_line))
347 select_line(last_line);
348 }
349
350 void select_next_line_by_first_letter(char letter)
351 {
352 GList *line_ptr;
353
354 for (line_ptr = g_list_next(selected_line); line_ptr != NULL;
355 line_ptr = g_list_next(line_ptr)) {
356 if (FILE(NODE(line_ptr))->name[0] == letter) {
357 select_line(line_ptr);
358 return;
359 }
360 }
361 }
362
363 void select_previous_line_by_first_letter(char letter)
364 {
365 GList *line_ptr;
366
367 for (line_ptr = g_list_previous(selected_line); line_ptr != NULL;
368 line_ptr = g_list_previous(line_ptr)) {
369 if (FILE(NODE(line_ptr))->name[0] == letter) {
370 select_line(line_ptr);
371 return;
372 }
373 }
374 }
This page took 0.570354 seconds and 4 git commands to generate.