Add a new key: ~.
[herrie-working.git] / herrie / src / gui_browser.c
blobc4298741407c6fa40f9a34422a92a91a58587b50
1 /*
2 * Copyright (c) 2006-2009 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file gui_browser.c
28 * @brief File browser in textual user interface.
31 #include "stdinc.h"
33 #include "config.h"
34 #include "gui.h"
35 #include "gui_internal.h"
36 #include "gui_vfslist.h"
37 #include "playq.h"
38 #include "vfs.h"
40 /**
41 * @brief Reference to window with pathname of current folder.
43 static WINDOW *win_dirname;
44 /**
45 * @brief Reference to VFS object that is currently shown.
47 static struct vfsref *vr_curdir = NULL;
48 /**
49 * @brief List we use when displaying a file instead of a directory,
50 * containing only the file itself.
52 static struct vfslist vl_flist = VFSLIST_INITIALIZER;
53 /**
54 * @brief Reference to window used as the file browser.
56 static struct gui_vfslist *win_browser;
57 /**
58 * @brief The current filtering string that's being applied.
60 static char *locatestr = NULL;
62 /**
63 * @brief Refresh the bar above the filebrowser to contain the proper
64 * filename and percentage.
66 static void
67 gui_browser_dirname_refresh(void)
69 const char *percent;
70 int plen;
72 gui_lock();
74 werase(win_dirname);
75 if (vr_curdir != NULL) {
76 mvwaddstr(win_dirname, 0, 1, vfs_filename(vr_curdir));
77 if (locatestr != NULL) {
78 waddstr(win_dirname, " (");
79 waddstr(win_dirname, _("filter"));
80 waddstr(win_dirname, ": ");
81 waddstr(win_dirname, locatestr);
82 waddstr(win_dirname, ")");
86 percent = gui_vfslist_getpercentage(win_browser);
87 plen = strlen(percent);
88 mvwaddstr(win_dirname, 0, COLS - plen, percent);
89 wnoutrefresh(win_dirname);
91 gui_unlock();
94 /**
95 * @brief Clean up our pseudo-directory data.
97 static void
98 gui_browser_cleanup_flist(void)
100 struct vfsref *vr;
102 /* Close our fake view */
103 while ((vr = vfs_list_first(&vl_flist)) != NULL) {
104 vfs_list_remove(&vl_flist, vr);
105 vfs_close(vr);
108 g_free(locatestr);
109 locatestr = NULL;
112 void
113 gui_browser_init(void)
115 const char *defdir;
116 char *cwd;
118 win_dirname = newwin(1, 0, GUI_SIZE_BROWSER_DIRNAME_TOP, 0);
119 clearok(win_dirname, TRUE);
120 if (gui_draw_colors)
121 wbkgdset(win_dirname, COLOR_PAIR(GUI_COLOR_BAR));
122 else
123 wbkgdset(win_dirname, A_REVERSE);
125 win_browser = gui_vfslist_new(0);
126 gui_vfslist_setfocus(win_browser, 1);
127 gui_vfslist_setcallback(win_browser, gui_browser_dirname_refresh);
128 gui_browser_dirname_refresh();
130 defdir = config_getopt("gui.browser.defaultpath");
131 if (defdir[0] != '\0') {
132 /* Open predefined directory */
133 vr_curdir = vfs_lookup(defdir, NULL, NULL, 0);
134 } else {
135 /* Open current directory */
136 cwd = g_get_current_dir();
137 vr_curdir = vfs_lookup(cwd, NULL, NULL, 1);
138 g_free(cwd);
141 if (vr_curdir != NULL) {
142 vfs_populate(vr_curdir);
143 gui_vfslist_setlist(win_browser, vfs_population(vr_curdir));
144 } else {
145 gui_msgbar_warn(_("Unable to open initial directory."));
147 gui_vfslist_move(win_browser, 0, GUI_SIZE_BROWSER_TOP,
148 COLS, GUI_SIZE_BROWSER_HEIGHT);
151 void
152 gui_browser_destroy(void)
154 delwin(win_dirname);
155 gui_vfslist_destroy(win_browser);
157 /* Clean up our mess */
158 gui_browser_cleanup_flist();
159 if (vr_curdir != NULL)
160 vfs_close(vr_curdir);
163 void
164 gui_browser_resize(void)
166 gui_lock();
167 wresize(win_dirname, 1, COLS);
168 mvwin(win_dirname, GUI_SIZE_BROWSER_DIRNAME_TOP, 0);
169 clearok(win_dirname, TRUE);
170 gui_unlock();
172 gui_vfslist_move(win_browser, 0, GUI_SIZE_BROWSER_TOP,
173 COLS, GUI_SIZE_BROWSER_HEIGHT);
177 * Cursor manipulation
180 void
181 gui_browser_cursor_up(void)
183 gui_vfslist_cursor_up(win_browser);
186 void
187 gui_browser_cursor_down(void)
189 gui_vfslist_cursor_down(win_browser, 0);
192 void
193 gui_browser_cursor_pageup(void)
195 gui_vfslist_cursor_pageup(win_browser);
198 void
199 gui_browser_cursor_pagedown(void)
201 gui_vfslist_cursor_pagedown(win_browser);
204 void
205 gui_browser_cursor_head(void)
207 gui_vfslist_cursor_head(win_browser);
210 void
211 gui_browser_cursor_tail(void)
213 gui_vfslist_cursor_tail(win_browser);
217 * Change current directory
220 void
221 gui_browser_gotofile(struct vfsref *vr)
223 struct vfsref *vrp, *vrn;
224 unsigned int idx;
226 if ((vrp = vfs_lookup("..", NULL, vfs_filename(vr), 1)) == NULL)
227 goto bad;
228 if (vfs_populate(vrp) != 0) {
229 /* Permission denied? */
230 vfs_close(vrp);
231 goto bad;
234 for (vrn = vfs_list_first(vfs_population(vrp)), idx = 1;
235 vrn != NULL; vrn = vfs_list_next(vrn), idx++) {
236 /* Select the previous directory */
237 if (strcmp(vfs_name(vr), vfs_name(vrn)) == 0)
238 break;
241 /* Change the directory */
242 gui_browser_cleanup_flist();
243 vfs_close(vr_curdir);
244 vr_curdir = vrp;
245 gui_vfslist_setlist(win_browser, vfs_population(vr_curdir));
247 if (vrn != NULL)
248 gui_vfslist_setselected(win_browser, vrn, idx);
250 return;
251 bad:
252 gui_msgbar_warn(_("Unable to enter the parent directory."));
255 void
256 gui_browser_dir_parent(void)
259 if (vr_curdir == NULL)
260 return;
262 if (locatestr != NULL) {
263 /* First unset the filter if we have one */
264 gui_browser_cleanup_flist();
265 gui_vfslist_setlist(win_browser, vfs_population(vr_curdir));
266 return;
269 gui_browser_gotofile(vr_curdir);
272 void
273 gui_browser_dir_enter(void)
275 struct vfsref *vr;
277 if (gui_vfslist_warn_isempty(win_browser))
278 return;
280 vr = vfs_dup(gui_vfslist_getselected(win_browser));
281 if (vfs_populate(vr) != 0) {
282 if (vfs_populatable(vr)) {
283 /* Permission denied? */
284 gui_msgbar_warn(_("Unable to enter the "
285 "selected directory."));
287 vfs_close(vr);
288 return;
291 /* Change the directory */
292 gui_browser_cleanup_flist();
293 vfs_close(vr_curdir);
294 vr_curdir = vr;
295 gui_vfslist_setlist(win_browser, vfs_population(vr_curdir));
299 * Playlist manipulation
302 void
303 gui_browser_playq_add_tail(void)
305 struct vfsref *vr;
307 if (gui_vfslist_warn_isempty(win_browser))
308 return;
310 vr = gui_vfslist_getselected(win_browser);
311 playq_song_add_tail(vr);
312 gui_vfslist_cursor_down(win_browser, 1);
315 void
316 gui_browser_playq_add_head(void)
318 struct vfsref *vr;
320 if (gui_vfslist_warn_isempty(win_browser))
321 return;
323 vr = gui_vfslist_getselected(win_browser);
324 playq_song_add_head(vr);
325 gui_vfslist_cursor_down(win_browser, 1);
328 void
329 gui_browser_playq_add_after(void)
331 struct vfsref *vr;
333 if (gui_vfslist_warn_isempty(win_browser))
334 return;
336 vr = gui_vfslist_getselected(win_browser);
337 gui_playq_song_add_after(vr);
338 gui_vfslist_cursor_down(win_browser, 1);
341 void
342 gui_browser_playq_add_before(void)
344 struct vfsref *vr;
346 if (gui_vfslist_warn_isempty(win_browser))
347 return;
349 vr = gui_vfslist_getselected(win_browser);
350 gui_playq_song_add_before(vr);
351 gui_vfslist_cursor_down(win_browser, 1);
355 gui_browser_searchnext(const struct vfsmatch *vm)
357 return gui_vfslist_searchnext(win_browser, vm);
361 * @brief Change to a specified directory.
363 static void
364 gui_browser_do_chdir(const char *path)
366 int dir = 0;
367 struct vfsref *vr;
369 if (vr_curdir != NULL) {
370 /* Relative to the current node */
371 vr = vfs_lookup(path, NULL, vfs_filename(vr_curdir), 0);
372 } else {
373 /* Relative to the root */
374 vr = vfs_lookup(path, NULL, NULL, 0);
377 if (vr != NULL) {
378 if (vfs_populate(vr) == 0)
379 dir = 1;
380 else if (!vfs_playable(vr))
381 goto bad;
383 /* Replace old directory */
384 gui_browser_cleanup_flist();
385 if (vr_curdir != NULL)
386 vfs_close(vr_curdir);
387 vr_curdir = vr;
389 if (dir) {
390 /* Go inside the directory */
391 gui_vfslist_setlist(win_browser,
392 vfs_population(vr));
393 } else {
394 /* Create a fake directory */
395 vfs_list_insert_tail(&vl_flist, vfs_dup(vr));
396 gui_vfslist_setlist(win_browser, &vl_flist);
399 return;
402 bad: gui_msgbar_warn(_("Unable to display the file or directory."));
403 if (vr != NULL)
404 vfs_close(vr);
407 void
408 gui_browser_chdir(void)
410 char *path;
411 const char *curwd = NULL;
413 if (vr_curdir != NULL)
414 curwd = vfs_filename(vr_curdir);
416 path = gui_input_askstring(_("Change directory"), curwd, NULL);
417 if (path == NULL)
418 return;
420 gui_browser_do_chdir(path);
421 g_free(path);
424 void
425 gui_browser_setfocus(int focus)
427 gui_vfslist_setfocus(win_browser, focus);
430 void
431 gui_browser_write_playlist(void)
433 char *fn;
434 struct vfsref *vr;
436 fn = gui_input_askstring(_("Write playlist to file"), NULL, NULL);
437 if (fn == NULL)
438 return;
439 playq_lock();
440 vr = vfs_write_playlist(&playq_list, vr_curdir, fn);
441 playq_unlock();
442 g_free(fn);
444 if (vr == NULL) {
445 gui_msgbar_warn(_("Unable to write playlist."));
446 return;
448 vfs_populate(vr);
450 /* Replace old directory */
451 gui_browser_cleanup_flist();
452 if (vr_curdir != NULL)
453 vfs_close(vr_curdir);
454 vr_curdir = vr;
456 /* Go inside the directory */
457 gui_vfslist_setlist(win_browser, vfs_population(vr));
460 void
461 gui_browser_fullpath(void)
463 gui_vfslist_fullpath(win_browser);
467 gui_browser_locate(const struct vfsmatch *vm)
469 struct vfslist vl = VFSLIST_INITIALIZER;
471 if (vr_curdir == NULL)
472 return (-1);
474 /* Perform a search on the query */
475 vfs_locate(&vl, vr_curdir, vm);
476 if (vfs_list_empty(&vl))
477 return (-1);
479 gui_browser_cleanup_flist();
480 locatestr = g_strdup(vfs_match_value(vm));
481 vfs_list_move(&vl_flist, &vl);
482 gui_vfslist_setlist(win_browser, &vl_flist);
484 return (0);
487 void
488 gui_browser_gotofolder(void)
491 if (gui_vfslist_warn_isempty(win_browser))
492 return;
494 gui_browser_gotofile(gui_vfslist_getselected(win_browser));
497 void
498 gui_browser_gotohome(void)
500 gui_browser_do_chdir("~");