-/* Choose track ------------------------------------------------------------ */
-
-/* We don't use the built-in tree widgets because they require that you know
- * the children of a node on demand, and we have to wait for the server to tell
- * us. */
-
-/* Types */
-
-struct choosenode;
-
-struct displaydata {
- guint width; /* total width required */
- guint height; /* total height required */
-};
-
-/* instantiate the node vector type */
-VECTOR_TYPE(nodevector, struct choosenode *, xrealloc)
-
-struct choosenode {
- struct choosenode *parent; /* parent node */
- const char *path; /* full path or 0 */
- const char *sort; /* sort key */
- const char *display; /* display name */
- int pending; /* pending resolve queries */
- unsigned flags;
-#define CN_EXPANDABLE 0x0001 /* node is expandable */
-#define CN_EXPANDED 0x0002 /* node is expanded */
-/* Expandable items are directories; non-expandable ones are files */
-#define CN_DISPLAYED 0x0004 /* widget is displayed in layout */
-#define CN_SELECTED 0x0008 /* node is selected */
- struct nodevector children; /* vector of children */
- void (*fill)(struct choosenode *); /* request child fill or 0 for leaf */
- GtkWidget *container; /* the container for this row */
- GtkWidget *hbox; /* the hbox for this row */
- GtkWidget *arrow; /* arrow widget or 0 */
- GtkWidget *label; /* text label for this node */
- GtkWidget *marker; /* queued marker */
-};
-
-struct menuitem {
- /* Parameters */
- const char *name; /* name */
-
- /* Callbacks */
- void (*activate)(GtkMenuItem *menuitem, gpointer user_data);
- /* Called to activate the menu item. The user data is the choosenode the
- * pointer is over. */
-
- gboolean (*sensitive)(struct choosenode *cn);
- /* Called to determine whether the menu item should be sensitive. TODO */
-
- /* State */
- gulong handlerid; /* signal handler ID */
- GtkWidget *w; /* menu item widget */
-};
-
-/* Variables */
-
-static GtkWidget *chooselayout;
-static GtkWidget *searchentry; /* search terms */
-static struct choosenode *root;
-static struct choosenode *realroot;
-static GtkWidget *menu; /* our popup menu */
-static struct choosenode *last_click; /* last clicked node for selection */
-static int files_visible; /* total files visible */
-static int files_selected; /* total files selected */
-static int search_in_flight; /* a search is underway */
-static int search_obsolete; /* the current search is void */
-static char **searchresults; /* search results */
-static int nsearchresults; /* number of results */
-
-/* Forward Declarations */
-
-static void clear_children(struct choosenode *cn);
-static struct choosenode *newnode(struct choosenode *parent,
- const char *path,
- const char *display,
- const char *sort,
- unsigned flags,
- void (*fill)(struct choosenode *));
-static void fill_root_node(struct choosenode *cn);
-static void fill_letter_node(struct choosenode *cn);
-static void fill_directory_node(struct choosenode *cn);
-static void got_files(void *v, int nvec, char **vec);
-static void got_resolved_file(void *v, const char *track);
-static void got_dirs(void *v, int nvec, char **vec);
-
-static void expand_node(struct choosenode *cn);
-static void contract_node(struct choosenode *cn);
-static void updated_node(struct choosenode *cn, int redisplay);
-
-static void display_selection(struct choosenode *cn);
-static void clear_selection(struct choosenode *cn);
-
-static void redisplay_tree(void);
-static struct displaydata display_tree(struct choosenode *cn, int x, int y);
-static void undisplay_tree(struct choosenode *cn);
-static void initiate_search(void);
-static void delete_widgets(struct choosenode *cn);
-
-static void clicked_choosenode(GtkWidget attribute((unused)) *widget,
- GdkEventButton *event,
- gpointer user_data);
-
-static void activate_play(GtkMenuItem *menuitem, gpointer user_data);
-static void activate_remove(GtkMenuItem *menuitem, gpointer user_data);
-static void activate_properties(GtkMenuItem *menuitem, gpointer user_data);
-
-static gboolean sensitive_play(struct choosenode *cn);
-static gboolean sensitive_remove(struct choosenode *cn);
-static gboolean sensitive_properties(struct choosenode *cn);
-
-static struct menuitem menuitems[] = {
- { "Play", activate_play, sensitive_play, 0, 0 },
- { "Remove", activate_remove, sensitive_remove, 0, 0 },
- { "Properties", activate_properties, sensitive_properties, 0, 0 },
-};
-
-#define NMENUITEMS (int)(sizeof menuitems / sizeof *menuitems)
-
-/* Maintaining the data structure ------------------------------------------ */
-
-/* Create a new node */
-static struct choosenode *newnode(struct choosenode *parent,
- const char *path,
- const char *display,
- const char *sort,
- unsigned flags,
- void (*fill)(struct choosenode *)) {
- struct choosenode *const n = xmalloc(sizeof *n);
-
- D(("newnode %s %s", path, display));
- if(flags & CN_EXPANDABLE)
- assert(fill);
- else
- assert(!fill);
- n->parent = parent;
- n->path = path;
- n->display = display;
- n->sort = sort;
- n->flags = flags;
- nodevector_init(&n->children);
- n->fill = fill;
- if(parent)
- nodevector_append(&parent->children, n);
- return n;
-}
-
-/* Fill the root */
-static void fill_root_node(struct choosenode *cn) {
- int ch;
- char *name;
- struct callbackdata *cbd;
-
- D(("fill_root_node"));
- clear_children(cn);
- if(choosealpha) {
- if(!cn->children.nvec) { /* Only need to do this once */
- for(ch = 'A'; ch <= 'Z'; ++ch) {
- byte_xasprintf(&name, "%c", ch);
- newnode(cn, "<letter>", name, name, CN_EXPANDABLE, fill_letter_node);
- }
- newnode(cn, "<letter>", "*", "~", CN_EXPANDABLE, fill_letter_node);
- }
- updated_node(cn, 1);
- } else {
- /* More de-duping possible here */
- gtk_label_set_text(GTK_LABEL(report_label), "getting files");
- cbd = xmalloc(sizeof *cbd);
- cbd->u.choosenode = cn;
- disorder_eclient_dirs(client, got_dirs, "", 0, cbd);
- cbd = xmalloc(sizeof *cbd);
- cbd->u.choosenode = cn;
- disorder_eclient_files(client, got_files, "", 0, cbd);
- }
-}
-
-/* Clear all the children of CN */
-static void clear_children(struct choosenode *cn) {
- int n;
-
- D(("clear_children %s", cn->path));
- /* Recursively clear subtrees */
- for(n = 0; n < cn->children.nvec; ++n) {
- clear_children(cn->children.vec[n]);
- if(cn->children.vec[n]->container) {
- if(cn->children.vec[n]->arrow)
- gtk_widget_destroy(cn->children.vec[n]->arrow);
- gtk_widget_destroy(cn->children.vec[n]->label);
- if(cn->children.vec[n]->marker)
- gtk_widget_destroy(cn->children.vec[n]->marker);
- gtk_widget_destroy(cn->children.vec[n]->hbox);
- gtk_widget_destroy(cn->children.vec[n]->container);
- }
- }
- cn->children.nvec = 0;
-}