#include "popup.h"
#include "choose.h"
+static void choose_playchildren_callback(GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data);
+static void choose_playchildren_received(void *v,
+ const char *err,
+ int nvec, char **vec);
+static void choose_playchildren_played(void *v, const char *err);
+
/** @brief Popup menu */
static GtkWidget *choose_menu;
0);
}
+/** @brief Play all children */
+static void choose_playchildren_activate
+ (GtkMenuItem attribute((unused)) *item,
+ gpointer attribute((unused)) userdata) {
+ /* Only one thing is selected */
+ gtk_tree_selection_selected_foreach(choose_selection,
+ choose_playchildren_callback,
+ 0);
+}
+
+static void choose_playchildren_callback(GtkTreeModel attribute((unused)) *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer attribute((unused)) data) {
+ /* Find the children and play them */
+ disorder_eclient_files(client, choose_playchildren_received,
+ choose_get_track(iter),
+ NULL/*re*/,
+ NULL);
+ /* Expand the node */
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(choose_view), path, FALSE);
+}
+
+static void choose_playchildren_received(void attribute((unused)) *v,
+ const char *err,
+ int nvec, char **vec) {
+ if(err) {
+ popup_protocol_error(0, err);
+ return;
+ }
+ for(int n = 0; n < nvec; ++n)
+ disorder_eclient_play(client, vec[n], choose_playchildren_played, NULL);
+}
+
+static void choose_playchildren_played(void attribute((unused)) *v,
+ const char *err) {
+ if(err) {
+ popup_protocol_error(0, err);
+ return;
+ }
+}
+
/** @brief Pop-up menu for choose */
static struct menuitem choose_menuitems[] = {
{
0
},
{
+ "Play children",
+ choose_playchildren_activate,
+ choose_selectchildren_sensitive, /* re-use */
+ 0,
+ 0
+ },
+ {
"Deselect all tracks",
choose_selectnone_activate,
choose_selectnone_sensitive,
void (*clicked)(GtkButton *button, gpointer userdata);
const char *tip;
GtkWidget *widget;
+ void (*pack)(GtkBox *box,
+ GtkWidget *child,
+ gboolean expand,
+ gboolean fill,
+ guint padding);
};
/* Variables --------------------------------------------------------------- */
/* Help */
-void popup_help(void);
+void popup_help(const char *what);
/* RTP */
#include <unistd.h>
/** @brief Display the manual page */
-void popup_help(void) {
+void popup_help(const char *what) {
char *path;
pid_t pid;
int w;
- byte_xasprintf(&path, "%s/index.html", dochtmldir);
+ if(!what)
+ what = "index.html";
+ byte_xasprintf(&path, "%s/%s", dochtmldir, what);
if(!(pid = xfork())) {
exitfn = _exit;
if(!xfork()) {
"Login",
login_ok,
"(Re-)connect using these settings",
- 0
+ 0,
+ NULL,
},
{
GTK_STOCK_CLOSE,
login_cancel,
"Discard changes and close window",
- 0
+ 0,
+ NULL,
},
};
choose-search.png choose.png disobedience-debian-menu.png \
disobedience-terminal.png disorder-email-confirm.png \
disorder-web-login.png login.png menu-control.png \
- menu-edit.png menu-help.png menu-server.png queue-menu.png \
+ menu-edit.png menu-help.png menu-server.png \
+ playlist-create.png playlist-picker-menu.png \
+ playlist-popup-menu.png playlist-window.png queue-menu.png \
queue.png queue2.png recent.png track-properties.png \
volume-slider.png
GtkWidget attribute((unused)) *menu_item) {
D(("manual_popup"));
- popup_help();
+ popup_help(NULL);
}
/** @brief Called when version arrives, displays about... popup */
gtk_widget_set_style(buttons[n].widget, tool_style);
g_signal_connect(G_OBJECT(buttons[n].widget), "clicked",
G_CALLBACK(buttons[n].clicked), 0);
- gtk_box_pack_start(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
+ void (*pack)(GtkBox *box,
+ GtkWidget *child,
+ gboolean expand,
+ gboolean fill,
+ guint padding);
+ if(!(pack = buttons[n].pack))
+ pack = gtk_box_pack_start;
+ pack(GTK_BOX(box), buttons[n].widget, FALSE, FALSE, 1);
gtk_widget_set_tooltip_text(buttons[n].widget, buttons[n].tip);
}
return box;
static gboolean playlist_picker_button(GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
+static gboolean playlist_editor_keypress(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data);
+static void playlist_editor_ok(GtkButton *button, gpointer userdata);
+static void playlist_editor_help(GtkButton *button, gpointer userdata);
/** @brief Playlist editing window */
static GtkWidget *playlist_window;
GTK_STOCK_ADD,
playlist_picker_add,
"Create a new playlist",
- 0
+ 0,
+ NULL,
},
{
GTK_STOCK_REMOVE,
playlist_picker_delete,
"Delete a playlist",
- 0
+ 0,
+ NULL,
},
};
#define NPLAYLIST_PICKER_BUTTONS (sizeof playlist_picker_buttons / sizeof *playlist_picker_buttons)
static GtkWidget *playlist_editor_private;
static int playlist_editor_setting_buttons;
+/** @brief Buttons for the playlist window */
+static struct button playlist_editor_buttons[] = {
+ {
+ GTK_STOCK_OK,
+ playlist_editor_ok,
+ "Close window",
+ 0,
+ gtk_box_pack_end,
+ },
+ {
+ GTK_STOCK_HELP,
+ playlist_editor_help,
+ "Go to manual",
+ 0,
+ gtk_box_pack_end,
+ },
+};
+
+#define NPLAYLIST_EDITOR_BUTTONS (int)(sizeof playlist_editor_buttons / sizeof *playlist_editor_buttons)
+
static GtkWidget *playlists_editor_create(void) {
assert(ql_playlist.view == NULL); /* better not be set up already */
gtk_box_pack_start(GTK_BOX(hbox), playlist_editor_private,
FALSE/*expand*/, FALSE/*fill*/, 0);
playlist_editor_set_buttons(0,0,0);
+ create_buttons_box(playlist_editor_buttons,
+ NPLAYLIST_EDITOR_BUTTONS,
+ hbox);
GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), init_queuelike(&ql_playlist),
+ GtkWidget *view = init_queuelike(&ql_playlist);
+ gtk_box_pack_start(GTK_BOX(vbox), view,
TRUE/*expand*/, TRUE/*fill*/, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox,
FALSE/*expand*/, FALSE/*fill*/, 0);
+ g_signal_connect(view, "key-press-event",
+ G_CALLBACK(playlist_editor_keypress), 0);
return vbox;
}
+static gboolean playlist_editor_keypress(GtkWidget attribute((unused)) *widget,
+ GdkEventKey *event,
+ gpointer attribute((unused)) user_data) {
+ if(event->state)
+ return FALSE;
+ switch(event->keyval) {
+ case GDK_BackSpace:
+ case GDK_Delete:
+ playlist_remove_activate(NULL, NULL);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
/** @brief Called when the public/private buttons are set */
static void playlist_editor_button_toggled(GtkToggleButton *tb,
gpointer userdata) {
ql_new_queue(&ql_playlist, newq);
}
+static void playlist_editor_ok(GtkButton attribute((unused)) *button,
+ gpointer attribute((unused)) userdata) {
+ gtk_widget_destroy(playlist_window);
+}
+
+static void playlist_editor_help(GtkButton attribute((unused)) *button,
+ gpointer attribute((unused)) userdata) {
+ popup_help("playlists.html");
+}
+
/* Playlist mutation -------------------------------------------------------- */
/** @brief State structure for guarded playlist modification
static void properties_ok(GtkButton *button, gpointer userdata);
static void properties_apply(GtkButton *button, gpointer userdata);
static void properties_cancel(GtkButton *button, gpointer userdata);
+static void properties_help(GtkButton *button, gpointer userdata);
static void properties_logged_in(const char *event,
void *eventdata,
/* Buttons that appear at the bottom of the window */
static struct button buttons[] = {
{
+ GTK_STOCK_HELP,
+ properties_help,
+ "Go to manual",
+ 0,
+ gtk_box_pack_start,
+ },
+ {
GTK_STOCK_OK,
properties_ok,
"Apply all changes and close window",
- 0
- },
- {
- GTK_STOCK_APPLY,
- properties_apply,
- "Apply all changes and keep window open",
- 0
+ 0,
+ gtk_box_pack_end,
},
{
GTK_STOCK_CANCEL,
properties_cancel,
"Discard all changes and close window",
- 0
+ 0,
+ gtk_box_pack_end
+ },
+ {
+ GTK_STOCK_APPLY,
+ properties_apply,
+ "Apply all changes and keep window open",
+ 0,
+ gtk_box_pack_end,
},
};
properties_event = 0;
}
+static void properties_help(GtkButton attribute((unused)) *button,
+ gpointer attribute((unused)) userdata) {
+ popup_help("properties.html");
+}
+
/** @brief Called when we've just logged in
*
* Destroys the current properties window.
GTK_STOCK_ADD,
users_add,
"Create a new user",
- 0
+ 0,
+ NULL,
},
{
GTK_STOCK_REMOVE,
users_delete,
"Delete a user",
- 0
+ 0,
+ NULL,
},
};
#define NUSERS_BUTTONS (sizeof users_buttons / sizeof *users_buttons)