Added some small boring scripts and programs writen in few last years
[mirrors/Programs.git] / bash / bbs / utils / fm / fm-1.0 / 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 cbreak();
37 nonl();
38 noecho();
39 keypad(stdscr, TRUE);
40 curs_set(0);
41 refresh();
42
43 getmaxyx(stdscr, screen_size[0], screen_size[1]);
44 tree_window = newwin(screen_size[0] - 1, screen_size[1], 0, 0);
45 info_window = newwin(1, screen_size[1], screen_size[0] - 1, 0);
46 scrollok(tree_window, TRUE);
47 idlok(tree_window, TRUE);
48 }
49
50 void init_ui(char *name)
51 {
52 init_curses();
53 init_tree(name);
54 init_lines();
55 print_line(FILE(tree_root)->line);
56 open_directory(tree_root);
57 refresh_screen();
58 }
59
60 void refresh_screen(void)
61 {
62 wnoutrefresh(tree_window);
63 wnoutrefresh(info_window);
64 doupdate();
65 }
66
67 void handle_sigwinch(int signal_number)
68 {
69 ungetch(KEY_RESIZE);
70 }
71
72 void print_lines(GList *start_line, GList *end_line, gboolean clear_bottom_lines)
73 {
74 GList *line_ptr;
75 int line_number;
76
77 if (end_line == NULL)
78 end_line = last_line;
79 else if (start_line != NULL) {
80 for (line_ptr = start_line;
81 g_list_position(first_line, line_ptr) < getmaxy(tree_window);
82 line_ptr = g_list_next(line_ptr)) {
83 print_line(line_ptr);
84 if (line_ptr == end_line)
85 break;
86 }
87 }
88 line_number = g_list_position(first_line, last_line) + 1;
89 if (clear_bottom_lines && line_number < getmaxy(tree_window)) {
90 wmove(tree_window, line_number, 0);
91 wclrtobot(tree_window);
92 }
93 }
94
95 void print_parents_lines(GList *line)
96 {
97 GNode *file_ptr;
98 int depth;
99
100 for (file_ptr = NODE(line)->parent, depth = g_node_depth(file_ptr) - 1;
101 !G_NODE_IS_ROOT(file_ptr); file_ptr = file_ptr->parent, depth--) {
102 if (file_ptr != g_node_last_sibling(file_ptr))
103 mvwaddch(tree_window, g_list_position(first_line, line),
104 2 * depth - 2, ACS_VLINE);
105 else
106 mvwaddch(tree_window, g_list_position(first_line, line),
107 2 * depth - 2, ' ');
108 mvwaddch(tree_window, g_list_position(first_line, line), 2 * depth - 1, ' ');
109 }
110 }
111
112 void print_line(GList *line)
113 {
114 int line_number = g_list_position(first_line, line);
115 GNode *file = NODE(line);
116 int depth = g_node_depth(file) - 1;
117 char *link_str;
118
119 wmove(tree_window, line_number, 0);
120 wclrtoeol(tree_window);
121
122 if (line == selected_line)
123 wattron(tree_window, A_REVERSE);
124
125 if (G_NODE_IS_ROOT(file)) {
126 wattron(tree_window, A_BOLD);
127 waddnstr(tree_window, FILE(file)->name, getmaxx(tree_window) - 1);
128 if (!g_str_has_suffix(FILE(file)->name, "/"))
129 waddch(tree_window, '/');
130 wattroff(tree_window, A_BOLD);
131 } else {
132 if (file != g_node_last_sibling(file))
133 mvwaddch(tree_window, line_number, 2 * depth - 2, ACS_LTEE);
134 else
135 mvwaddch(tree_window, line_number, 2 * depth - 2, ACS_LLCORNER);
136
137 waddch(tree_window, ACS_HLINE);
138 if (FILE(file)->link == TRUE) {
139 link_str = g_strdup_printf("%s -> %s", FILE(file)->name,
140 FILE(file)->link_path);
141 waddnstr(tree_window, link_str, getmaxx(tree_window) - 2 * depth - 1);
142 free(link_str);
143 } else
144 waddnstr(tree_window, FILE(file)->name,
145 getmaxx(tree_window) - 2 * depth - 1);
146
147 if (FILE(file)->type == directory_type && ((FILE(file)->link == TRUE &&
148 !g_str_has_suffix(FILE(file)->link_path, "/")) ||
149 (FILE(file)->link == FALSE &&
150 !g_str_has_suffix(FILE(file)->name, "/"))))
151 waddch(tree_window, '/');
152 print_parents_lines(line);
153 }
154 wattroff(tree_window, A_REVERSE);
155 }
156
157 void clear_info(void)
158 {
159 werase(info_window);
160 }
161
162 void print_info(char *message, gboolean bold)
163 {
164 static char *last_message = NULL;
165 static gboolean last_bold = FALSE;
166
167 if (message != NULL) {
168 if (last_message != NULL)
169 free(last_message);
170 last_message = strdup(message);
171 }
172 if (bold == TRUE || bold == FALSE)
173 last_bold = bold;
174 if (last_bold == TRUE)
175 wattron(info_window, A_BOLD);
176 werase(info_window);
177 if (last_message != NULL)
178 waddnstr(info_window, last_message, getmaxx(info_window));
179 wattroff(info_window, A_BOLD);
180 }
181
182 void print_error_info(int last_errno, char *file, int line, char *message)
183 {
184 char *message_format = "Error (%s:%i): %s";
185 char *message_str;
186
187 if (message != NULL)
188 message_str = g_strdup_printf(message_format, file, line, message);
189 else
190 message_str = g_strdup_printf(message_format, file, line, strerror(last_errno));
191 print_info(message_str, TRUE);
192 free(message_str);
193 }
194
195 void update_last_line(void)
196 {
197 if (g_list_length(first_line) > getmaxy(tree_window))
198 last_line = g_list_nth(first_line, getmaxy(tree_window) - 1);
199 else
200 last_line = g_list_last(lines);
201 }
202
203 void add_directory_content(GNode *directory)
204 {
205 GNode *file_ptr, *directory_sibling;
206 int position;
207
208 directory_sibling = get_next_file_not_deepper(directory);
209
210 for (position = g_list_position(lines, FILE(directory)->line) + 1,
211 file_ptr = g_node_first_child(directory);
212 file_ptr != NULL && file_ptr != directory_sibling;
213 position++, file_ptr = get_next_file(file_ptr)) {
214 lines = g_list_insert(lines, file_ptr, position);
215 FILE(file_ptr)->line = g_list_nth(lines, position);
216 }
217 }
218
219 void open_directory(GNode *directory)
220 {
221 if (FILE(directory)->read == FALSE && read_directory(directory) == FALSE)
222 return;
223
224 FILE(directory)->open = TRUE;
225 add_directory_content(directory);
226 update_last_line();
227 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
228 }
229
230 void close_directory(GNode *directory)
231 {
232 GNode *directory_sibling;
233 GList *line_ptr;
234
235 directory_sibling = get_next_file_not_deepper(directory);
236
237 for (line_ptr = g_list_next(FILE(directory)->line); line_ptr != NULL &&
238 NODE(line_ptr) != directory_sibling; line_ptr = g_list_next(FILE(directory)->line))
239 lines = g_list_delete_link(lines, line_ptr);
240
241 FILE(directory)->open = FALSE;
242 update_last_line();
243 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
244 }
245
246 void update_directory(GNode *directory)
247 {
248 close_directory(directory);
249 destroy_directory_content(directory);
250 open_directory(directory);
251
252 if (FILE(directory)->show_dotfiles == TRUE)
253 show_dotfiles(directory);
254 }
255
256 void show_dotfiles(GNode *directory)
257 {
258 add_dotfiles(directory);
259 update_last_line();
260 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
261 }
262
263 void hide_dotfiles(GNode *directory)
264 {
265 remove_dotfiles(directory);
266 update_last_line();
267 print_lines(g_list_next(FILE(directory)->line), last_line, TRUE);
268 }
269
270 void select_line(GList *line)
271 {
272 select_nth_line(g_list_position(lines, line) - g_list_position(lines, selected_line));
273 }
274
275 void select_file(GNode *file)
276 {
277 select_line(FILE(file)->line);
278 }
279
280 void select_nth_line(int n_lines)
281 {
282 GList *old_selected_line;
283 int min_n_lines, max_n_lines;
284
285 if ((max_n_lines = g_list_length(selected_line) - 1) < n_lines)
286 n_lines = max_n_lines;
287 else if((min_n_lines = (int) g_list_length(selected_line) -
288 (int) g_list_length(lines)) > n_lines)
289 n_lines = min_n_lines;
290
291 old_selected_line = selected_line;
292 if (n_lines < 0)
293 selected_line = g_list_nth(lines, g_list_position(lines, selected_line) + n_lines);
294 else if (n_lines > 0)
295 selected_line = g_list_nth(selected_line, n_lines);
296
297 if (g_list_position(lines, selected_line) < g_list_position(lines, first_line))
298 scroll_tree(g_list_position(lines, selected_line) -
299 g_list_position(lines, first_line));
300 else if (g_list_position(lines, selected_line) > g_list_position(lines, last_line))
301 scroll_tree(g_list_position(lines, selected_line) -
302 g_list_position(lines, last_line));
303
304 if (n_lines != 0) {
305 print_line(selected_line);
306 if (g_list_position(lines, first_line) <= g_list_position(lines, old_selected_line) &&
307 g_list_position(lines, old_selected_line) <=
308 g_list_position(lines, last_line))
309 print_line(old_selected_line);
310 }
311 }
312
313 void scroll_tree(int n_lines)
314 {
315 int min_n_lines, max_n_lines;
316
317 if ((min_n_lines = -g_list_position(lines, first_line)) > n_lines)
318 n_lines = min_n_lines;
319 else if ((max_n_lines = g_list_length(last_line) - 1) < n_lines)
320 n_lines = max_n_lines;
321
322 wscrl(tree_window, n_lines);
323 if (n_lines < 0) {
324 first_line = g_list_nth(lines, g_list_position(lines, first_line) + n_lines);
325 update_last_line();
326 print_lines(first_line, g_list_nth(first_line, -n_lines), FALSE);
327 } else if (n_lines > 0) {
328 first_line = g_list_nth(first_line, n_lines);
329 update_last_line();
330 print_lines(g_list_nth(lines, g_list_position(lines, last_line) - n_lines),
331 last_line, TRUE);
332 }
333 }
334
335 void select_line_inside_window(void)
336 {
337 if (g_list_position(lines, selected_line) < g_list_position(lines, first_line))
338 select_line(first_line);
339 else if (g_list_position(lines, selected_line) > g_list_position(lines, last_line))
340 select_line(last_line);
341 }
342
343 void select_next_line_by_first_letter(char letter)
344 {
345 GList *line_ptr;
346
347 for (line_ptr = g_list_next(selected_line); line_ptr != NULL;
348 line_ptr = g_list_next(line_ptr)) {
349 if (FILE(NODE(line_ptr))->name[0] == letter) {
350 select_line(line_ptr);
351 return;
352 }
353 }
354 }
355
356 void select_previous_line_by_first_letter(char letter)
357 {
358 GList *line_ptr;
359
360 for (line_ptr = g_list_previous(selected_line); line_ptr != NULL;
361 line_ptr = g_list_previous(line_ptr)) {
362 if (FILE(NODE(line_ptr))->name[0] == letter) {
363 select_line(line_ptr);
364 return;
365 }
366 }
367 }
This page took 0.497258 seconds and 4 git commands to generate.