00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00031 #include "stdinc.h"
00032
00033 #include "config.h"
00034 #include "gui.h"
00035 #include "gui_internal.h"
00036 #include "gui_vfslist.h"
00037 #include "vfs.h"
00038
00043 static int scrollpages;
00044
00049 static void
00050 gui_vfslist_cursor_adjust(struct gui_vfslist *gv)
00051 {
00052 struct vfsref *vr;
00053
00054
00055 if (gv->vr_selected == NULL)
00056 return;
00057
00058
00059 if (gv->idx_top > gv->idx_selected) {
00060
00061
00062
00063
00064 gv->vr_top = gv->vr_selected;
00065 gv->idx_top = gv->idx_selected;
00066 } else if (gv->idx_top + gv->winheight <= gv->idx_selected) {
00067
00068
00069
00070
00071
00072
00073 gv->vr_top = gv->vr_selected;
00074 gv->idx_top = gv->idx_selected;
00075 do {
00076 vr = vfs_list_prev(gv->vr_top);
00077 if (vr == NULL)
00078 break;
00079 gv->vr_top = vr;
00080 gv->idx_top--;
00081 } while (gv->idx_top + gv->winheight - 1 > gv->idx_selected);
00082 } else {
00083
00084
00085
00086
00087
00088
00089 while (gv->idx_top + gv->winheight - 1 > vfs_list_items(gv->list)) {
00090 vr = vfs_list_prev(gv->vr_top);
00091 if (vr == NULL)
00092 break;
00093 gv->vr_top = vr;
00094 gv->idx_top--;
00095 }
00096 }
00097 }
00098
00103 static unsigned int
00104 gui_vfslist_idxcol_width(struct gui_vfslist *gv)
00105 {
00106 unsigned int len, idx;
00107
00108 if (gv->list == NULL)
00109 return (0);
00110
00111
00112
00113
00114
00115 for (len = 1, idx = vfs_list_items(gv->list);idx >= 10;
00116 len++, idx /= 10);
00117
00118 return (len);
00119 }
00120
00124 static void
00125 gui_vfslist_percent(struct gui_vfslist *gv)
00126 {
00127 unsigned int bottom, length;
00128
00129 length = gv->list != NULL ? vfs_list_items(gv->list) : 0;
00130 bottom = gv->idx_top + gv->winheight - 1;
00131
00132 if (bottom >= length) {
00133
00134 if (gv->idx_top <= 1)
00135 strcpy(gv->percent, " (all) ");
00136 else
00137 strcpy(gv->percent, " (end) ");
00138 } else {
00139
00140 sprintf(gv->percent, " (%d%%) ", (bottom * 100) / length);
00141 }
00142 }
00143
00147 static void
00148 gui_vfslist_refresh(struct gui_vfslist *gv)
00149 {
00150 unsigned int i, idx, idxw, idxmaxw = 0;
00151 char num[16], mark;
00152 struct vfsref *vr;
00153
00154 if (gv->win == NULL)
00155 return;
00156
00157
00158 gui_vfslist_cursor_adjust(gv);
00159
00160 gui_lock();
00161 werase(gv->win);
00162
00163 vr = gv->vr_top;
00164 idx = gv->idx_top;
00165 if (gv->shownumbers)
00166 idxmaxw = gui_vfslist_idxcol_width(gv);
00167 for (i = 0; i < gv->winheight; i++) {
00168 if (vr == NULL) {
00169
00170 mvwaddch(gv->win, i, 0, ' ');
00171 wbkgdset(gv->win, COLOR_PAIR(GUI_COLOR_BLOCK));
00172 wclrtobot(gv->win);
00173 break;
00174 }
00175
00176
00177 g_assert((vr == gv->vr_selected) == (idx == gv->idx_selected));
00178
00179 if (vr == gv->vr_selected && gv->winfocused)
00180
00181 wbkgdset(gv->win, COLOR_PAIR(GUI_COLOR_SELECT));
00182 else if (vfs_marked(vr))
00183
00184 wbkgdset(gv->win, COLOR_PAIR(GUI_COLOR_MARKED));
00185 else if (vr == gv->vr_selected)
00186
00187 wbkgdset(gv->win, COLOR_PAIR(GUI_COLOR_DESELECT));
00188
00189
00190 if ((vr == gv->vr_selected) && !gui_draw_colors) {
00191 if (gv->winfocused)
00192 wattron(gv->win, A_BOLD);
00193 mvwaddch(gv->win, i, 0, '>');
00194 } else {
00195 mvwaddch(gv->win, i, 0, ' ');
00196 }
00197 wclrtoeol(gv->win);
00198
00199 if (gv->shownumbers) {
00200 idxw = snprintf(num, sizeof num, "%d", idx);
00201 mvwaddstr(gv->win, i, 1 + idxmaxw - idxw, num);
00202 waddstr(gv->win, ". ");
00203 waddstr(gv->win, vfs_name(vr));
00204 } else {
00205 waddstr(gv->win, vfs_name(vr));
00206 }
00207
00208
00209 mark = vfs_marking(vr);
00210 if (mark != '\0')
00211 waddch(gv->win, mark);
00212
00213 wbkgdset(gv->win, COLOR_PAIR(GUI_COLOR_BLOCK));
00214 wattroff(gv->win, A_BOLD);
00215
00216 vr = vfs_list_next(vr);
00217 idx++;
00218 }
00219
00220 wnoutrefresh(gv->win);
00221 gui_unlock();
00222
00223 gui_vfslist_percent(gv);
00224
00225 if (gv->callback != NULL)
00226 gv->callback();
00227 }
00228
00229 struct gui_vfslist *
00230 gui_vfslist_new(int shownumbers)
00231 {
00232 struct gui_vfslist *ret;
00233
00234 scrollpages = config_getopt_bool("gui.vfslist.scrollpages");
00235
00236 ret = g_slice_new0(struct gui_vfslist);
00237 ret->shownumbers = shownumbers;
00238
00239 return (ret);
00240 }
00241
00242 void
00243 gui_vfslist_destroy(struct gui_vfslist *gv)
00244 {
00245 if (gv->win != NULL)
00246 delwin(gv->win);
00247 g_slice_free(struct gui_vfslist, gv);
00248 }
00249
00250 void
00251 gui_vfslist_setlist(struct gui_vfslist *gv, const struct vfslist *vl)
00252 {
00253 gv->list = vl;
00254 gv->vr_top = gv->vr_selected = vfs_list_first(gv->list);
00255 gv->idx_top = gv->idx_selected = (gv->vr_selected != NULL) ? 1 : 0;
00256
00257 gui_vfslist_refresh(gv);
00258 }
00259
00260 int
00261 gui_vfslist_warn_isempty(struct gui_vfslist *gv)
00262 {
00263 if (gv->vr_selected == NULL) {
00264 gui_msgbar_warn(_("There are no songs."));
00265 return (1);
00266 } else {
00267 return (0);
00268 }
00269 }
00270
00271 void
00272 gui_vfslist_move(struct gui_vfslist *gv,
00273 int x, int y, int width, int height)
00274 {
00275 gui_lock();
00276 if (gv->win == NULL) {
00277 gv->win = newwin(height, width, y, x);
00278 } else {
00279 wresize(gv->win, height, width);
00280 mvwin(gv->win, y, x);
00281 }
00282 clearok(gv->win, TRUE);
00283 gui_unlock();
00284 gv->winheight = height;
00285
00286 gui_vfslist_refresh(gv);
00287 }
00288
00289 void
00290 gui_vfslist_setfocus(struct gui_vfslist *gv, int focus)
00291 {
00292 gv->winfocused = focus;
00293 gui_vfslist_refresh(gv);
00294 }
00295
00296 void
00297 gui_vfslist_setselected(struct gui_vfslist *gv, struct vfsref *vr,
00298 unsigned int index)
00299 {
00300 unsigned int i;
00301
00302 gv->vr_selected = gv->vr_top = vr;
00303 gv->idx_selected = gv->idx_top = index;
00304
00305
00306 for (i = 0; i < (gv->winheight - 1) / 2 &&
00307 vfs_list_prev(gv->vr_top) != NULL; i++) {
00308 gv->vr_top = vfs_list_prev(gv->vr_top);
00309 gv->idx_top--;
00310 }
00311
00312 gui_vfslist_refresh(gv);
00313 }
00314
00315 void
00316 gui_vfslist_cursor_up(struct gui_vfslist *gv)
00317 {
00318 struct vfsref *vr;
00319
00320 if (gui_vfslist_warn_isempty(gv))
00321 return;
00322
00323 vr = vfs_list_prev(gv->vr_selected);
00324 if (vr != NULL) {
00325 gv->vr_selected = vr;
00326 gv->idx_selected--;
00327
00328 if (scrollpages && gv->idx_top > gv->idx_selected) {
00329 gv->vr_top = vfs_list_first(gv->list);
00330 gv->idx_top = 1;
00331 }
00332
00333 gui_vfslist_refresh(gv);
00334 } else {
00335 gui_msgbar_warn(_("You are at the first song."));
00336 }
00337 }
00338
00339 void
00340 gui_vfslist_cursor_down(struct gui_vfslist *gv, int silent)
00341 {
00342 struct vfsref *vr;
00343
00344 if (gui_vfslist_warn_isempty(gv))
00345 return;
00346
00347 vr = vfs_list_next(gv->vr_selected);
00348 if (vr != NULL) {
00349 gv->vr_selected = vr;
00350 gv->idx_selected++;
00351
00352 g_assert(gv->idx_top + gv->winheight >= gv->idx_selected);
00353 if (scrollpages && gv->idx_top + gv->winheight == gv->idx_selected) {
00354 gv->vr_top = gv->vr_selected;
00355 gv->idx_top = gv->idx_selected;
00356 }
00357
00358 gui_vfslist_refresh(gv);
00359 } else if (!silent) {
00360 gui_msgbar_warn(_("You are at the last song."));
00361 }
00362 }
00363
00364 void
00365 gui_vfslist_cursor_head(struct gui_vfslist *gv)
00366 {
00367 if (gui_vfslist_warn_isempty(gv))
00368 return;
00369
00370 gv->vr_top = gv->vr_selected = vfs_list_first(gv->list);
00371 gv->idx_top = gv->idx_selected = (gv->vr_selected != NULL) ? 1 : 0;
00372
00373 gui_vfslist_refresh(gv);
00374 }
00375
00376 void
00377 gui_vfslist_cursor_tail(struct gui_vfslist *gv)
00378 {
00379 if (gui_vfslist_warn_isempty(gv))
00380 return;
00381
00382 gv->vr_selected = vfs_list_last(gv->list);
00383 gv->idx_selected = vfs_list_items(gv->list);
00384
00385 gui_vfslist_refresh(gv);
00386 }
00387
00388 void
00389 gui_vfslist_cursor_pageup(struct gui_vfslist *gv)
00390 {
00391 unsigned int i;
00392
00393 if (gui_vfslist_warn_isempty(gv))
00394 return;
00395
00396
00397 gv->vr_selected = vfs_list_next(gv->vr_top);
00398 gv->idx_selected = gv->idx_top + 1;
00399
00400
00401 for (i = 2; i < gv->winheight && gv->vr_top != NULL; i++) {
00402 gv->vr_top = vfs_list_prev(gv->vr_top);
00403 gv->idx_top--;
00404 }
00405 if (gv->vr_top == NULL) {
00406
00407 gv->vr_selected = gv->vr_top = vfs_list_first(gv->list);
00408 gv->idx_selected = gv->idx_top = 1;
00409 } else if (gv->vr_selected == NULL) {
00410
00411 gv->vr_selected = gv->vr_top;
00412 gv->idx_selected = gv->idx_top;
00413 }
00414
00415 gui_vfslist_refresh(gv);
00416 }
00417
00418 void
00419 gui_vfslist_cursor_pagedown(struct gui_vfslist *gv)
00420 {
00421 unsigned int i;
00422 struct vfsref *vr_toptmp = gv->vr_top;
00423
00424 if (gui_vfslist_warn_isempty(gv))
00425 return;
00426
00427
00428 for (i = 2; i < gv->winheight && gv->vr_top != NULL; i++) {
00429 gv->vr_top = vfs_list_next(gv->vr_top);
00430 gv->idx_top++;
00431 }
00432
00433 if (gv->vr_top == NULL) {
00434 gv->vr_top = vfs_list_last(gv->list);
00435 gv->idx_top = vfs_list_items(gv->list);
00436 }
00437 gv->vr_selected = gv->vr_top;
00438 gv->idx_selected = gv->idx_top;
00439
00440 gui_vfslist_cursor_adjust(gv);
00441 if (vr_toptmp == gv->vr_top) {
00442
00443
00444
00445
00446 gui_vfslist_cursor_tail(gv);
00447 } else {
00448 gui_vfslist_refresh(gv);
00449 }
00450 }
00451
00456 static void
00457 gui_vfslist_adjust_pre_removal(struct vfsref **vr, unsigned int *curidx,
00458 unsigned int newidx, int follow)
00459 {
00460 struct vfsref *vr_new;
00461 g_assert((*vr != NULL) && (*curidx > 0));
00462
00463 vr_new = vfs_list_next(*vr);
00464 if (*curidx > newidx) {
00465
00466 if (follow || vr_new == NULL) {
00467
00468 (*curidx)--;
00469 } else {
00470
00471 *vr = vr_new;
00472 }
00473 } else if (*curidx == newidx) {
00474
00475 if (vr_new != NULL) {
00476
00477 *vr = vr_new;
00478 } else {
00479
00480 *vr = vfs_list_prev(*vr);
00481 (*curidx)--;
00482 }
00483 }
00484
00485 g_assert((*vr == NULL) == (*curidx == 0));
00486 }
00487
00488 void
00489 gui_vfslist_notify_pre_removal(struct gui_vfslist *gv, unsigned int index)
00490 {
00491 gui_vfslist_adjust_pre_removal(&gv->vr_top, &gv->idx_top, index, 0);
00492 gui_vfslist_adjust_pre_removal(&gv->vr_selected, &gv->idx_selected,
00493 index, 1);
00494 }
00495
00500 static void
00501 gui_vfslist_adjust_post_insertion(struct gui_vfslist *gv, struct vfsref **vr,
00502 unsigned int *curidx, unsigned int newidx, int follow)
00503 {
00504 g_assert((*vr == NULL) == (*curidx == 0));
00505
00506 if (*curidx == 0) {
00507
00508 *vr = vfs_list_first(gv->list);
00509 *curidx = 1;
00510 } else if (*curidx >= newidx) {
00511
00512 if (follow) {
00513
00514 (*curidx)++;
00515 } else {
00516
00517 *vr = vfs_list_prev(*vr);
00518 }
00519 }
00520
00521 g_assert((*vr != NULL) && (*curidx > 0));
00522 }
00523
00524 void
00525 gui_vfslist_notify_post_insertion(struct gui_vfslist *gv, unsigned int index)
00526 {
00527 gui_vfslist_adjust_post_insertion(gv, &gv->vr_top, &gv->idx_top,
00528 index, 0);
00529 gui_vfslist_adjust_post_insertion(gv, &gv->vr_selected,
00530 &gv->idx_selected, index, 1);
00531 }
00532
00533 void
00534 gui_vfslist_notify_post_randomization(struct gui_vfslist *gv)
00535 {
00536 unsigned int idx;
00537
00538
00539
00540
00541
00542
00543
00544
00545 if (gv->idx_top > 0) {
00546
00547 for (idx = 1, gv->vr_top = vfs_list_first(gv->list);
00548 idx < gv->idx_top;
00549 idx++, gv->vr_top = vfs_list_next(gv->vr_top));
00550
00551 for (gv->vr_selected = gv->vr_top;
00552 idx < gv->idx_selected;
00553 idx++, gv->vr_selected = vfs_list_next(gv->vr_selected));
00554 }
00555 }
00556
00557 void
00558 gui_vfslist_notify_done(struct gui_vfslist *gv)
00559 {
00560 gui_vfslist_refresh(gv);
00561 }
00562
00563 int
00564 gui_vfslist_searchnext(struct gui_vfslist *gv, const struct vfsmatch *vm)
00565 {
00566 struct vfsref *vr;
00567 unsigned int idx;
00568
00569 g_assert(vm != NULL);
00570
00571 if (gv->vr_selected == NULL)
00572 return (-1);
00573
00574
00575 for (vr = vfs_list_next(gv->vr_selected), idx = gv->idx_selected + 1;
00576 vr != NULL; vr = vfs_list_next(vr), idx++) {
00577 if (vfs_match_compare(vm, vfs_name(vr))) {
00578 gui_msgbar_flush();
00579 goto found;
00580 }
00581 }
00582
00583
00584 for (vr = vfs_list_first(gv->list), idx = 1;
00585 vr != vfs_list_next(gv->vr_selected);
00586 vr = vfs_list_next(vr), idx++) {
00587 if (vfs_match_compare(vm, vfs_name(vr))) {
00588 gui_msgbar_warn(_("Search wrapped to top."));
00589 goto found;
00590 }
00591 }
00592
00593 return (-1);
00594
00595 found:
00596 gv->vr_selected = vr;
00597 gv->idx_selected = idx;
00598
00599
00600 return (0);
00601 }
00602
00603 void
00604 gui_vfslist_fullpath(struct gui_vfslist *gv)
00605 {
00606 char *msg;
00607
00608 if (gui_vfslist_warn_isempty(gv))
00609 return;
00610
00611 msg = g_strdup_printf("%s: %s",
00612 _("Full pathname"), vfs_filename(gv->vr_selected));
00613 gui_msgbar_warn(msg);
00614 g_free(msg);
00615 }