diff --git a/NEWS b/NEWS index 75cc843..b198b5d 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ Unreleased * Added a "z" binding to center the view on the selected item + * Added a "?" binding to describe items in various tabs + * Made it possible to adjust the spectrum analyzer's FPS limit * Fixed possibility of connection timeouts with PulseAudio integration diff --git a/nncmpp.actions b/nncmpp.actions index 06ac727..38a8f76 100644 --- a/nncmpp.actions +++ b/nncmpp.actions @@ -36,6 +36,7 @@ PULSE_MUTE, Toggle PulseAudio sink mute CHOOSE, Choose item DELETE, Delete item +DESCRIBE, Describe item UP, Go up a level MULTISELECT, Toggle multiselect INCREMENTAL_SEARCH, Incremental search diff --git a/nncmpp.c b/nncmpp.c index 836f2ba..c450647 100644 --- a/nncmpp.c +++ b/nncmpp.c @@ -1298,6 +1298,7 @@ static struct app_context struct poller_timer message_timer; ///< Message timeout char *message; ///< Message to show in the statusbar + char *message_detail; ///< Non-emphasized part // Connection: @@ -1700,6 +1701,7 @@ app_free_context (void) poller_curl_free (&g.poller_curl); poller_free (&g.poller); free (g.message); + free (g.message_detail); if (g.tk) termo_destroy (g.tk); @@ -2239,21 +2241,28 @@ static void app_layout_statusbar (void) { struct layout l = {}; + chtype attrs[2] = { APP_ATTR (NORMAL), APP_ATTR (HIGHLIGHT) }; if (g.message) { - app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1)) - ->id = WIDGET_MESSAGE; - app_push_fill (&l, g.ui->label (APP_ATTR (HIGHLIGHT), g.message)) - ->id = WIDGET_MESSAGE; - app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1)) - ->id = WIDGET_MESSAGE; + app_push (&l, g.ui->padding (attrs[0], 0.25, 1)); + if (!g.message_detail) + app_push_fill (&l, g.ui->label (attrs[1], g.message)); + else + { + app_push (&l, g.ui->label (attrs[1], g.message)); + app_push_fill (&l, g.ui->label (attrs[0], g.message_detail)); + } + app_push (&l, g.ui->padding (attrs[0], 0.25, 1)); + app_flush_layout (&l); + LIST_FOR_EACH (struct widget, w, l.head) + w->id = WIDGET_MESSAGE; } else if (g.editor.line) { - app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1)); - app_push (&l, g.ui->editor (APP_ATTR (HIGHLIGHT))); - app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1)); + app_push (&l, g.ui->padding (attrs[0], 0.25, 1)); + app_push (&l, g.ui->editor (attrs[1])); + app_push (&l, g.ui->padding (attrs[0], 0.25, 1)); app_flush_layout (&l); } else if (g.client.state == MPD_CONNECTED) @@ -2375,6 +2384,27 @@ app_move_selection (int diff) return result; } +static void +app_show_message (char *message, char *detail) +{ + cstr_set (&g.message, message); + cstr_set (&g.message_detail, detail); + poller_timer_set (&g.message_timer, 5000); + app_invalidate (); +} + +static void +app_hide_message (void) +{ + if (!g.message) + return; + + cstr_set (&g.message, NULL); + cstr_set (&g.message_detail, NULL); + poller_timer_reset (&g.message_timer); + app_invalidate (); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void @@ -2558,17 +2588,6 @@ app_mpd_toggle (const char *name) return MPD_SIMPLE (name, value ? "0" : "1"); } -static void -app_hide_message (void) -{ - if (g.message) - { - cstr_set (&g.message, NULL); - poller_timer_reset (&g.message_timer); - app_invalidate (); - } -} - static bool app_process_action (enum action action) { @@ -2962,6 +2981,7 @@ g_normal_defaults[] = { "Enter", ACTION_CHOOSE }, { "Delete", ACTION_DELETE }, { "d", ACTION_DELETE }, + { "?", ACTION_DESCRIBE }, { "M-Up", ACTION_UP }, { "Backspace", ACTION_UP }, { "v", ACTION_MULTISELECT }, @@ -3238,6 +3258,12 @@ current_tab_on_action (enum action action) tab->item_mark = -1; return map && (id = compact_map_find (map, "id")) && MPD_SIMPLE ("playid", id); + case ACTION_DESCRIBE: + if (!map || !(id = compact_map_find (map, "file"))) + return false; + + app_show_message (xstrdup ("Path: "), xstrdup (id)); + return true; case ACTION_DELETE: { struct mpd_client *c = &g.client; @@ -3652,6 +3678,12 @@ library_tab_on_action (enum action action) } tab->item_mark = -1; return true; + case ACTION_DESCRIBE: + if (!*x->path) + break; + + app_show_message (xstrdup ("Path: "), xstrdup (x->path)); + return true; case ACTION_UP: { char *parent = library_tab_parent (); @@ -3990,6 +4022,9 @@ streams_tab_on_action (enum action action) case ACTION_MPD_ADD: streams_tab_process (uri, false, &e); break; + case ACTION_DESCRIBE: + app_show_message (xstrdup (uri), NULL); + break; default: return false; } @@ -4103,17 +4138,26 @@ help_tab_on_action (enum action action) { struct tab *tab = &g_help_tab.super; if (tab->item_selected < 0 - || tab->item_selected >= (int) g_help_tab.actions_len - || action != ACTION_CHOOSE) + || tab->item_selected >= (int) g_help_tab.actions_len) return false; - action = g_help_tab.actions[tab->item_selected]; - if (action == ACTION_NONE || action == ACTION_CHOOSE /* avoid recursion */) + enum action a = g_help_tab.actions[tab->item_selected]; + if (!a) + return false; + + if (action == ACTION_DESCRIBE) + { + char *name = xstrdup (g_action_names[a]); + cstr_transform (name, tolower_ascii); + app_show_message (xstrdup ("Configuration name: "), name); + return true; + } + if (action != ACTION_CHOOSE || a == ACTION_CHOOSE /* avoid recursion */) return false; // XXX: We can't propagate failure to ring the terminal/X11 bell, but we // don't want to let our caller show a bad "can't do that" message either. - return app_process_action (action), true; + return app_process_action (a), true; } static void @@ -6078,11 +6122,8 @@ x11_process_press (int x, int y, int button, int modifiers) cstr_set (&g.x11_selection, text); XSetSelectionOwner (g.dpy, XInternAtom (g.dpy, "CLIPBOARD", False), g.x11_window, CurrentTime); - - cstr_set (&g.message, - xstrdup_printf ("Text copied to clipboard: %s", g.x11_selection)); - poller_timer_set (&g.message_timer, 5000); - app_invalidate (); + app_show_message (xstrdup ("Text copied to clipboard: "), + xstrdup (g.x11_selection)); return true; out: @@ -6585,6 +6626,7 @@ app_on_message_timer (void *user_data) (void) user_data; cstr_set (&g.message, NULL); + cstr_set (&g.message_detail, NULL); app_invalidate (); } @@ -6601,12 +6643,13 @@ app_log_handler (void *user_data, const char *quote, const char *fmt, struct str message = str_make (); str_append (&message, quote); + size_t quote_len = message.len; str_append_vprintf (&message, fmt, ap); - // Show it to the user, then maybe log it elsewhere as well. - cstr_set (&g.message, xstrdup (message.str)); - poller_timer_set (&g.message_timer, 5000); - app_invalidate (); + // Show it prettified to the user, then maybe log it elsewhere as well. + message.str[0] = toupper_ascii (message.str[0]); + app_show_message (xstrndup (message.str, quote_len), + xstrdup (message.str + quote_len)); if (g_verbose_mode && (g.ui != &tui_ui || !isatty (STDERR_FILENO))) fprintf (stderr, "%s\n", message.str);