some playing with bbs - new fm
[mirrors/Programs.git] / bash / bbs / utils / fm / fm / ui.c
CommitLineData
db4042d6
H
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
19WINDOW *tree_window, *info_window;
20GList *lines, *selected_line, *first_line, *last_line;
21
22void 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
31void 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
54void 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
67void refresh_screen(void)
68{
69 wnoutrefresh(tree_window);
70 wnoutrefresh(info_window);
71 doupdate();
72}
73
74void handle_sigwinch(int signal_number)
75{
76 ungetch(KEY_RESIZE);
77}
78
79void 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
102void 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
119void 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
164void clear_info(void)
165{
166 werase(info_window);
167}
168
169void 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
189void 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
202void 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
210void 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
226void 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
237void 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
253void 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
263void 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
270void 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
277void select_line(GList *line)
278{
279 select_nth_line(g_list_position(lines, line) - g_list_position(lines, selected_line));
280}
281
282void select_file(GNode *file)
283{
284 select_line(FILE(file)->line);
285}
286
287void 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
320void 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
342void 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
350void 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
363void 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.323425 seconds and 4 git commands to generate.