commit 15a8fe2cf2b16af8739a7ec2b64b5c5f184161b8
parent 1bd07952245e3fc8ed95af0c1eff45938098b40b
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 16 Dec 2021 13:48:13 +0100
Implemented list navigation and other fixes
Diffstat:
7 files changed, 156 insertions(+), 61 deletions(-)
diff --git a/Makefile b/Makefile
@@ -11,7 +11,7 @@ clean:
%.o: %.c %.h
$(CC) -c -o $@ $< $(CFLAGS) $(LDLIBS)
-tmus: main.c util.o history.o link.o player.o tag.o track.o
+tmus: main.c util.o history.o link.o player.o tag.o track.o listnav.o
$(CC) -o $@ $^ $(CFLAGS) $(LDLIBS)
install:
diff --git a/listnav.c b/listnav.c
@@ -0,0 +1,43 @@
+#include "listnav.h"
+#include "util.h"
+
+#include <string.h>
+
+void
+listnav_init(struct listnav *nav)
+{
+ memset(nav, 0, sizeof(struct listnav));
+}
+
+void
+listnav_update_bounds(struct listnav *nav, int min, int max)
+{
+ nav->min = min;
+ nav->max = max;
+ nav->wmin = MAX(nav->wmin, nav->min);
+ nav->wmax = MIN(nav->wmin + nav->wlen, nav->max);
+ nav->sel = MIN(MAX(nav->sel, nav->wmin), nav->wmax - 1);
+}
+
+void
+listnav_update_wlen(struct listnav *nav, int wlen)
+{
+ nav->wlen = wlen;
+ nav->wmax = MIN(nav->wmin + nav->wlen, nav->max);
+ nav->sel = MIN(MAX(nav->sel, nav->wmin), nav->wmax - 1);
+}
+
+void
+listnav_update_sel(struct listnav *nav, int sel)
+{
+ nav->sel = MAX(MIN(sel, nav->max - 1), nav->min);
+
+ if (nav->sel >= nav->wmax) {
+ nav->wmax = nav->sel + 1;
+ nav->wmin = MAX(nav->min, nav->wmax - nav->wlen);
+ } else if (nav->sel < nav->wmin) {
+ nav->wmin = nav->sel;
+ nav->wmax = MIN(nav->wmin + nav->wlen, nav->max);
+ }
+}
+
diff --git a/listnav.h b/listnav.h
@@ -0,0 +1,18 @@
+#pragma once
+
+struct listnav {
+ /* current window */
+ int wmin, wmax, wlen;
+
+ /* selected item moving inside of window */
+ int sel;
+
+ /* bounds of actual list */
+ int min, max;
+};
+
+void listnav_init(struct listnav *nav);
+void listnav_update_bounds(struct listnav *nav, int min, int max);
+void listnav_update_wlen(struct listnav *nav, int wlen);
+void listnav_update_sel(struct listnav *nav, int sel);
+
diff --git a/main.c b/main.c
@@ -7,6 +7,7 @@
#include "tag.h"
#include "track.h"
#include "player.h"
+#include "listnav.h"
#include "mpd/player.h"
#include "curses.h"
@@ -70,14 +71,13 @@ struct cmd {
cmd_handler func;
};
-int style_attrs[STYLE_COUNT] = { 0 };
+int style_attrs[STYLE_COUNT];
const char *datadir;
int scrw, scrh;
int quit;
-float win_ratio;
-struct pane *pane_sel;
+struct pane *pane_sel, *pane_top_sel;
struct pane pane_left, pane_right, pane_bot;
struct pane *const panes[] = {
&pane_left,
@@ -85,20 +85,21 @@ struct pane *const panes[] = {
&pane_bot
};
-struct link tags;
-
-struct link tracks;
-struct link playlist;
-
completion_generator completion;
+struct pane *cmd_pane;
struct history search_history, command_history;
struct history *history;
int cmd_show, cmd_mode;
-int tag_index;
+struct pane *tag_pane;
+struct listnav tag_nav;
+struct link tags;
struct link tags_sel;
-int track_index;
+struct pane *track_pane;
+struct listnav track_nav;
+struct link playlist;
+struct link tracks;
void init(void);
void cleanup(void);
@@ -145,8 +146,21 @@ void
init(void)
{
quit = 0;
- win_ratio = 0.3f;
+ signal(SIGINT, exit);
+ atexit(cleanup);
+
+ history = &command_history;
+ history_init(&search_history);
+ history_init(&command_history);
+
+ datadir = getenv("TMUS_DATA");
+ ASSERT(datadir != NULL);
+ data_load();
+
+ player_init();
+
+ /* ncurses init */
initscr();
raw();
noecho();
@@ -157,10 +171,7 @@ init(void)
curs_set(0);
ESCDELAY = 0;
- history = &command_history;
- history_init(&search_history);
- history_init(&command_history);
-
+ memset(style_attrs, 0, sizeof(style_attrs));
style_init(STYLE_DEFAULT, COLOR_WHITE, COLOR_BLACK, 0);
style_init(STYLE_TITLE, COLOR_WHITE, COLOR_BLUE, A_BOLD);
style_init(STYLE_PANE_SEP, COLOR_BLUE, COLOR_BLACK, 0);
@@ -168,26 +179,16 @@ init(void)
style_init(STYLE_ITEM_HOVER, COLOR_WHITE, COLOR_BLUE, 0);
style_init(STYLE_ITEM_HOVER_SEL, COLOR_YELLOW, COLOR_BLUE, A_BOLD);
- pane_init(&pane_left, tag_input, tag_vis);
- pane_init(&pane_right, track_input, track_vis);
- pane_init(&pane_bot, cmd_input, cmd_vis);
+ pane_init((tag_pane = &pane_left), tag_input, tag_vis);
+ pane_init((track_pane = &pane_right), track_input, track_vis);
+ pane_init((cmd_pane = &pane_bot), cmd_input, cmd_vis);
pane_sel = &pane_left;
+ pane_top_sel = pane_sel;
- datadir = getenv("TMUS_DATA");
- ASSERT(datadir != NULL);
-
- track_index = 0;
- tag_index = 0;
tags_sel = LIST_HEAD;
-
- player_init();
-
- data_load();
-
- signal(SIGINT, exit);
-
- atexit(cleanup);
+ listnav_init(&tag_nav);
+ listnav_init(&track_nav);
}
void
@@ -286,7 +287,7 @@ tracks_save(struct tag *tag)
void
resize(void)
{
- int i;
+ int i, leftw;
getmaxyx(stdscr, scrh, scrw);
@@ -297,7 +298,8 @@ resize(void)
usleep(10000);
}
- pane_resize(&pane_left, 0, 0, win_ratio * scrw, scrh - 3);
+ leftw = MIN(40, 0.3f * scrw);
+ pane_resize(&pane_left, 0, 0, leftw, scrh - 3);
pane_resize(&pane_right, pane_left.ex + 1, 0, scrw, scrh - 3);
pane_resize(&pane_bot, 0, scrh - 3, scrw, scrh);
}
@@ -409,14 +411,13 @@ tag_input(wint_t c)
switch (c) {
case KEY_UP:
- tag_index = MAX(0, tag_index - 1);
+ listnav_update_sel(&tag_nav, tag_nav.sel - 1);
return 1;
case KEY_DOWN:
- tag_index = MIN(list_len(&tags) - 1,
- tag_index + 1);
+ listnav_update_sel(&tag_nav, tag_nav.sel + 1);
return 1;
case KEY_SPACE:
- cur = link_iter(tags.next, tag_index);
+ cur = link_iter(tags.next, tag_nav.sel);
ASSERT(cur != NULL);
tag = UPCAST(cur, struct tag);
if (tagrefs_incl(&tags_sel, tag)) {
@@ -425,6 +426,12 @@ tag_input(wint_t c)
tagrefs_add(&tags_sel, tag);
}
return 1;
+ case KEY_NPAGE:
+ listnav_update_sel(&track_nav, track_nav.sel - track_nav.wlen / 2);
+ return 1;
+ case KEY_PPAGE:
+ listnav_update_sel(&track_nav, track_nav.sel + track_nav.wlen / 2);
+ return 1;
}
return 0;
@@ -440,14 +447,17 @@ tag_vis(struct pane *pane, int sel)
werase(pane->win);
pane_title(pane, "Tags", sel);
+ listnav_update_bounds(&tag_nav, 0, list_len(&tags));
+ listnav_update_wlen(&tag_nav, pane->h - 1);
+
index = 0;
for (iter = tags.next; iter; iter = iter->next) {
tag = UPCAST(iter, struct tag);
tsel = tagrefs_incl(&tags_sel, tag);
- if (sel && index == tag_index && tsel)
+ if (sel && index == tag_nav.sel && tsel)
style_on(pane->win, STYLE_ITEM_HOVER_SEL);
- else if (sel && index == tag_index)
+ else if (sel && index == tag_nav.sel)
style_on(pane->win, STYLE_ITEM_HOVER);
else if (tsel)
style_on(pane->win, STYLE_ITEM_SEL);
@@ -455,9 +465,9 @@ tag_vis(struct pane *pane, int sel)
wmove(pane->win, 1 + index, 0);
wprintw(pane->win, "%*.*s", pane->w, pane->w, tag->name);
- if (index == tag_index && tsel)
+ if (index == tag_nav.sel && tsel)
style_off(pane->win, STYLE_ITEM_HOVER_SEL);
- else if (index == tag_index)
+ else if (index == tag_nav.sel)
style_off(pane->win, STYLE_ITEM_HOVER);
else if (tsel)
style_off(pane->win, STYLE_ITEM_SEL);
@@ -473,18 +483,24 @@ track_input(wint_t c)
switch (c) {
case KEY_UP:
- track_index = MAX(0, track_index - 1);
+ listnav_update_sel(&track_nav, track_nav.sel - 1);
return 1;
case KEY_DOWN:
- track_index = MIN(list_len(&tracks) - 1, track_index + 1);
+ listnav_update_sel(&track_nav, track_nav.sel + 1);
return 1;
case KEY_ENTER:
- link = link_iter(tracks.next, track_index);
+ link = link_iter(tracks.next, track_nav.sel);
ASSERT(link != NULL);
track = UPCAST(link, struct track);
player->track = track;
player_play_track(track);
return 1;
+ case KEY_NPAGE:
+ listnav_update_sel(&track_nav, track_nav.sel - track_nav.wlen / 2);
+ return 1;
+ case KEY_PPAGE:
+ listnav_update_sel(&track_nav, track_nav.sel + track_nav.wlen / 2);
+ return 1;
}
return 0;
@@ -500,28 +516,35 @@ track_vis(struct pane *pane, int sel)
werase(pane->win);
pane_title(pane, "Tracks", sel);
+ listnav_update_bounds(&track_nav, 0, list_len(&tracks));
+ listnav_update_wlen(&track_nav, pane->h - 1);
+
+ wmove(pane->win, 0, 45);
+ wprintw(pane->win, "%i %i", list_len(&tracks), track_nav.sel);
+
index = 0;
- for (iter = tracks.next; iter; iter = iter->next) {
+ for (iter = tracks.next; iter; iter = iter->next, index++) {
track = UPCAST(iter, struct track);
- if (sel && index == track_index && track == player->track)
+ if (index < track_nav.wmin) continue;
+ if (index >= track_nav.wmax) break;
+
+ if (sel && index == track_nav.sel && track == player->track)
style_on(pane->win, STYLE_ITEM_HOVER_SEL);
- else if (sel && index == track_index)
+ else if (sel && index == track_nav.sel)
style_on(pane->win, STYLE_ITEM_HOVER);
else if (track == player->track)
style_on(pane->win, STYLE_ITEM_SEL);
- wmove(pane->win, 1 + index, 0);
+ wmove(pane->win, 1 + index - track_nav.wmin, 0);
wprintw(pane->win, "%-*.*s", pane->w, pane->w, track->name);
- if (sel && index == track_index && track == player->track)
+ if (sel && index == track_nav.sel && track == player->track)
style_off(pane->win, STYLE_ITEM_HOVER_SEL);
- else if (sel && index == track_index)
+ else if (sel && index == track_nav.sel)
style_off(pane->win, STYLE_ITEM_HOVER);
else if (track == player->track)
style_off(pane->win, STYLE_ITEM_SEL);
-
- index++;
}
}
@@ -539,7 +562,7 @@ cmd_input(wint_t c)
switch (c) {
case KEY_ESC:
if (history->cmd == history->query) {
- pane_sel = NULL; /* TODO: save last and switch back */
+ pane_sel = pane_top_sel;
} else {
history->cmd = history->query;
}
@@ -554,7 +577,6 @@ cmd_input(wint_t c)
inputln_del(history->cmd, history->cmd->cur);
break;
case KEY_UP:
- // TODO: show visually that no more matches
history_next(history);
break;
case KEY_DOWN:
@@ -563,7 +585,7 @@ cmd_input(wint_t c)
case KEY_ENTER:
history_submit(history);
if (!*history->cmd->buf)
- pane_sel = NULL;
+ pane_sel = pane_top_sel;
break;
case KEY_TAB:
break;
@@ -636,15 +658,22 @@ main_input(wint_t c)
pane_sel = &pane_right;
else
pane_sel = &pane_left;
+ pane_top_sel = pane_sel;
break;
case KEY_ESC:
- pane_sel = NULL;
+ pane_sel = pane_top_sel;
break;
case KEY_LEFT:
- pane_sel = &pane_left;
+ if (player->track)
+ player_seek(MAX(player->time_pos - 10, 0));
break;
case KEY_RIGHT:
- pane_sel = &pane_right;
+ if (player->track) {
+ if (player->time_end > player->time_pos + 10)
+ player_seek(player->time_pos + 10);
+ else
+ player_next();
+ }
break;
case 't':
player_toggle_pause();
diff --git a/player.c b/player.c
@@ -125,6 +125,7 @@ player_play_track(struct track *track)
player_clear_msg();
player->track = track;
mpd_run_stop(player->conn);
+ mpd_run_clear(player->conn);
if (!mpd_run_add(player->conn, player->track->fpath)
|| !mpd_run_play(player->conn)) {
@@ -193,7 +194,11 @@ player_prev(void)
int
player_seek(int sec)
{
- /* TODO */
+ if (!mpd_run_seek_current(player->conn, sec, false)) {
+ PLAYER_STATUS(PLAYER_MSG_ERR, "Track seek failed");
+ return PLAYER_ERR;
+ }
+
return PLAYER_OK;
}
diff --git a/tmus b/tmus
Binary files differ.
diff --git a/util.c b/util.c
@@ -42,7 +42,7 @@ assert(int cond, const char *file, int line, const char *condstr)
{
if (cond) return;
- fprintf(stderr, "Assertion failed %s:%i (%s)", file, line, condstr);
+ fprintf(stderr, "Assertion failed %s:%i (%s)\n", file, line, condstr);
exit(1);
}