-static void clicked_choosenode(GtkWidget attribute((unused)) *widget,
- GdkEventButton *event,
- gpointer user_data) {
- struct choosenode *cn = user_data;
- int ind, last_ind, n;
-
- D(("clicked_choosenode %s", cn->path));
- if(event->type == GDK_BUTTON_RELEASE
- && event->button == 1) {
- /* Left click */
- if(cn->flags & CN_EXPANDABLE) {
- /* This is a directory. Flip its expansion status. */
- if(cn->flags & CN_EXPANDED)
- contract_node(cn);
- else
- expand_node(cn, 0/*!contingent*/);
- last_click = 0;
- } else {
- /* This is a file. Adjust selection status */
- /* TODO the basic logic here is essentially the same as that in queue.c.
- * Can we share code at all? */
- switch(event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) {
- case 0:
- clear_selection(root);
- set_selection(cn, 1);
- last_click = cn;
- break;
- case GDK_CONTROL_MASK:
- set_selection(cn, !(cn->flags & CN_SELECTED));
- last_click = cn;
- break;
- case GDK_SHIFT_MASK:
- case GDK_SHIFT_MASK|GDK_CONTROL_MASK:
- if(last_click && last_click->parent == cn->parent) {
- /* Figure out where the current and last clicks are in the list */
- ind = last_ind = -1;
- for(n = 0; n < cn->parent->children.nvec; ++n) {
- if(cn->parent->children.vec[n] == cn)
- ind = n;
- if(cn->parent->children.vec[n] == last_click)
- last_ind = n;
- }
- /* Test shouldn't ever fail, but still */
- if(ind >= 0 && last_ind >= 0) {
- if(!(event->state & GDK_CONTROL_MASK)) {
- for(n = 0; n < cn->parent->children.nvec; ++n)
- set_selection(cn->parent->children.vec[n], 0);
- }
- if(ind > last_ind)
- for(n = last_ind; n <= ind; ++n)
- set_selection(cn->parent->children.vec[n], 1);
- else
- for(n = ind; n <= last_ind; ++n)
- set_selection(cn->parent->children.vec[n], 1);
- if(event->state & GDK_CONTROL_MASK)
- last_click = cn;
- }
- }
- /* TODO trying to select a range that doesn't share a single parent
- * currently does not work, but it ought to. */
- break;
- }
- }
- } else if(event->type == GDK_BUTTON_RELEASE
- && event->button == 2) {
- /* Middle click - play the pointed track */
- if(!(cn->flags & CN_EXPANDABLE)) {
- clear_selection(root);
- set_selection(cn, 1);
- gtk_label_set_text(GTK_LABEL(report_label), "adding track to queue");
- disorder_eclient_play(client, cn->path, play_completed, 0);
- last_click = 0;
- }
- } else if(event->type == GDK_BUTTON_PRESS
- && event->button == 3) {
- struct choose_menuitem *const menuitems =
- (cn->flags & CN_EXPANDABLE ? dir_menuitems : track_menuitems);
- GtkWidget *const menu =
- (cn->flags & CN_EXPANDABLE ? dir_menu : track_menu);
- /* Right click. Pop up a menu. */
- /* If the current file isn't selected, switch the selection to just that.
- * (If we're looking at a directory then leave the selection alone.) */
- if(!(cn->flags & CN_EXPANDABLE) && !(cn->flags & CN_SELECTED)) {
- clear_selection(root);
- set_selection(cn, 1);
- last_click = cn;
- }
- /* Set the item sensitivity and callbacks */
- for(n = 0; menuitems[n].name; ++n) {
- if(menuitems[n].handlerid)
- g_signal_handler_disconnect(menuitems[n].w,
- menuitems[n].handlerid);
- gtk_widget_set_sensitive(menuitems[n].w,
- menuitems[n].sensitive(cn));
- menuitems[n].handlerid = g_signal_connect
- (menuitems[n].w, "activate", G_CALLBACK(menuitems[n].activate), cn);
- }
- set_tool_colors(menu);
- /* Pop up the menu */
- gtk_widget_show_all(menu);
- gtk_menu_popup(GTK_MENU(menu), 0, 0, 0, 0,
- event->button, event->time);
- }
-}
-
-/** @brief Called BY GTK+ to tell us the search entry box has changed */
-static void searchentry_changed(GtkEditable attribute((unused)) *editable,
- gpointer attribute((unused)) user_data) {
- initiate_search();
-}
-
-/* Track menu items -------------------------------------------------------- */
-
-/** @brief Recursive step for gather_selected() */
-static void recurse_selected(struct choosenode *cn, struct vector *v) {
- int n;
-
- if(cn->flags & CN_EXPANDABLE) {
- if(cn->flags & CN_EXPANDED)
- for(n = 0; n < cn->children.nvec; ++n)
- recurse_selected(cn->children.vec[n], v);
- } else {
- if((cn->flags & CN_SELECTED) && cn->path)
- vector_append(v, (char *)cn->path);
- }
-}
-
-/*** @brief Get a list of all the selected tracks */
-static const char **gather_selected(int *ntracks) {
- struct vector v;
-
- vector_init(&v);
- recurse_selected(root, &v);
- vector_terminate(&v);
- if(ntracks) *ntracks = v.nvec;
- return (const char **)v.vec;
-}
-
-/** @brief Called when the track menu's play option is activated */
-static void activate_track_play(GtkMenuItem attribute((unused)) *menuitem,
- gpointer attribute((unused)) user_data) {
- const char **tracks = gather_selected(0);
- int n;
-
- gtk_label_set_text(GTK_LABEL(report_label), "adding track to queue");
- for(n = 0; tracks[n]; ++n)
- disorder_eclient_play(client, tracks[n], play_completed, 0);
-}
-
-/** @brief Called when the menu's properties option is activated */
-static void activate_track_properties(GtkMenuItem attribute((unused)) *menuitem,
- gpointer attribute((unused)) user_data) {
- int ntracks;
- const char **tracks = gather_selected(&ntracks);
-
- properties(ntracks, tracks);
-}
-
-/** @brief Determine whether the menu's play option should be sensitive */
-static gboolean sensitive_track_play(struct choosenode attribute((unused)) *cn) {
- return (!!files_selected
- && (disorder_eclient_state(client) & DISORDER_CONNECTED));
-}
-
-/** @brief Determine whether the menu's properties option should be sensitive */
-static gboolean sensitive_track_properties(struct choosenode attribute((unused)) *cn) {
- return !!files_selected && (disorder_eclient_state(client) & DISORDER_CONNECTED);
-}
-
-/* Directory menu items ---------------------------------------------------- */
-
-/** @brief Return the file children of @p cn