chiark / gitweb /
Playing checkbox in Disobedience choose tab is now only visible for
[disorder] / disobedience / choose.c
index a505478bb907fe45c6975fad076cf3f29e8d7529..d1d791a7dea598465c2c48b279b6c78094990089 100644 (file)
@@ -38,8 +38,6 @@
  * TODO:
  * - sweep up contracted nodes
  * - update when content may have changed (e.g. after a rescan)
- * - playing state
- * - display length of tracks
  */
 
 #include "disobedience.h"
@@ -68,6 +66,14 @@ struct choosedata *choose_iter_to_data(GtkTreeIter *iter) {
   return cd;
 }
 
+struct choosedata *choose_path_to_data(GtkTreePath *path) {
+  GtkTreeIter it[1];
+  gboolean itv = gtk_tree_model_get_iter(GTK_TREE_MODEL(choose_store),
+                                         it, path);
+  assert(itv);
+  return choose_iter_to_data(it);
+}
+
 /** @brief Remove node @p it and all its children
  * @param Iterator, updated to point to next
  * @return True if iterator remains valid
@@ -88,6 +94,38 @@ static gboolean choose_remove_node(GtkTreeIter *it) {
   return gtk_tree_store_remove(choose_store, it);
 }
 
+/** @brief Update length and state fields */
+static gboolean choose_set_state_callback(GtkTreeModel attribute((unused)) *model,
+                                          GtkTreePath attribute((unused)) *path,
+                                          GtkTreeIter *it,
+                                          gpointer attribute((unused)) data) {
+  struct choosedata *cd = choose_iter_to_data(it);
+  if(!cd)
+    return FALSE;                       /* Skip placeholders*/
+  if(cd->type == CHOOSE_FILE) {
+    const long l = namepart_length(cd->track);
+    char length[64];
+    if(l > 0)
+      byte_snprintf(length, sizeof length, "%ld:%02ld", l / 60, l % 60);
+    else
+      length[0] = 0;
+    gtk_tree_store_set(choose_store, it,
+                       LENGTH_COLUMN, length,
+                       STATE_COLUMN, queued(cd->track),
+                       -1);
+  }
+  return FALSE;                         /* continue walking */
+}
+
+/** @brief Called when the queue or playing track change */
+static void choose_set_state(const char attribute((unused)) *event,
+                             void attribute((unused)) *eventdata,
+                             void attribute((unused)) *callbackdata) {
+  gtk_tree_model_foreach(GTK_TREE_MODEL(choose_store),
+                         choose_set_state_callback,
+                         NULL);
+}
+
 /** @brief (Re-)populate a node
  * @param parent_ref Node to populate or NULL to fill root
  * @param nvec Number of children to add
@@ -177,7 +215,11 @@ static void choose_populate(GtkTreeRowReference *parent_ref,
                                                           vec[n],
                                                           "display"),
                          CHOOSEDATA_COLUMN, cd,
+                         ISFILE_COLUMN, type == CHOOSE_FILE,
                          -1);
+      /* Update length and state; we expect this to kick off length lookups
+       * rather than necessarily get the right value the first time round. */
+      choose_set_state_callback(0, 0, it, 0);
       ++inserted;
       /* If we inserted a directory, insert a placeholder too, so it appears to
        * have children; it will be deleted when we expand the directory. */
@@ -225,6 +267,36 @@ static void choose_files_completed(void *v,
   choose_populate(v, nvec, vec, CHOOSE_FILE);
 }
 
+void choose_play_completed(void attribute((unused)) *v,
+                           const char *error) {
+  if(error)
+    popup_protocol_error(0, error);
+}
+
+static void choose_state_toggled
+    (GtkCellRendererToggle attribute((unused)) *cell_renderer,
+     gchar *path_str,
+     gpointer attribute((unused)) user_data) {
+  GtkTreeIter it[1];
+  /* Identify the track */
+  gboolean itv =
+    gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(choose_store),
+                                        it,
+                                        path_str);
+  if(!itv)
+    return;
+  struct choosedata *cd = choose_iter_to_data(it);
+  if(!cd)
+    return;
+  if(cd->type != CHOOSE_FILE)
+    return;
+  if(queued(cd->track))
+    return;
+  disorder_eclient_play(client, xstrdup(cd->track),
+                        choose_play_completed, 0);
+  
+}
+
 static void choose_row_expanded(GtkTreeView attribute((unused)) *treeview,
                                 GtkTreeIter *iter,
                                 GtkTreePath *path,
@@ -252,20 +324,56 @@ static void choose_row_expanded(GtkTreeView attribute((unused)) *treeview,
 GtkWidget *choose_widget(void) {
   /* Create the tree store. */
   choose_store = gtk_tree_store_new(1 + CHOOSEDATA_COLUMN,
+                                    G_TYPE_BOOLEAN,
+                                    G_TYPE_STRING,
                                     G_TYPE_STRING,
+                                    G_TYPE_BOOLEAN,
                                     G_TYPE_POINTER);
 
   /* Create the view */
   choose_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(choose_store));
+  gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(choose_view), TRUE);
 
   /* Create cell renderers and columns */
-  GtkCellRenderer *r = gtk_cell_renderer_text_new();
-  GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
-    ("Track",
-     r,
-     "text", 0,
-     (char *)0);
-  gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
+  /* TODO use a table */
+  {
+    GtkCellRenderer *r = gtk_cell_renderer_text_new();
+    GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
+      ("Track",
+       r,
+       "text", NAME_COLUMN,
+       (char *)0);
+    gtk_tree_view_column_set_resizable(c, TRUE);
+    gtk_tree_view_column_set_reorderable(c, TRUE);
+    g_object_set(c, "expand", TRUE, (char *)0);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
+  }
+  {
+    GtkCellRenderer *r = gtk_cell_renderer_text_new();
+    GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
+      ("Length",
+       r,
+       "text", LENGTH_COLUMN,
+       (char *)0);
+    gtk_tree_view_column_set_resizable(c, TRUE);
+    gtk_tree_view_column_set_reorderable(c, TRUE);
+    g_object_set(r, "xalign", (gfloat)1.0, (char *)0);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
+  }
+  {
+    GtkCellRenderer *r = gtk_cell_renderer_toggle_new();
+    GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
+      ("Queued",
+       r,
+       "active", STATE_COLUMN,
+       "visible", ISFILE_COLUMN,
+       (char *)0);
+    gtk_tree_view_column_set_resizable(c, TRUE);
+    gtk_tree_view_column_set_reorderable(c, TRUE);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
+    g_signal_connect(r, "toggled",
+                     G_CALLBACK(choose_state_toggled), 0);
+  }
   
   /* The selection should support multiple things being selected */
   choose_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(choose_view));
@@ -279,6 +387,9 @@ GtkWidget *choose_widget(void) {
   /* Catch row expansions so we can fill in placeholders */
   g_signal_connect(choose_view, "row-expanded",
                    G_CALLBACK(choose_row_expanded), 0);
+
+  event_register("queue-list-changed", choose_set_state, 0);
+  event_register("playing-track-changed", choose_set_state, 0);
   
   /* Fill the root */
   disorder_eclient_files(client, choose_files_completed, "", NULL, NULL);