1 /*
2    voiceGUI.c
3    code for listing and selecting Gnaural voices
4    Depends on:
5    glib.h
6    gtk/gtk.h
7    main.h
8    voiceGUI.h
9    ScheduleGUI.h
10 
11    Theory: give main_UpdateGUI_Voices() a GtkVBox, and this fills it with a table
12 
13    Copyright (C) 2011  Bret Logan
14 
15    This program is free software; you can redistribute it and/or modify
16    it under the terms of the GNU General Public License as published by
17    the Free Software Foundation; either version 2 of the License, or
18    (at your option) any later version.
19 
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23    GNU General Public License for more details.
24 
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29 
30 //TODO:
31 // - 20100625: Duplicate Voices not actually updating list (i think it updates list before BB or SG have the new data)
32 // - 20100624: Make list NOT keep refilling from SG/BB, but literally delete the specific LIST row when voice deleted, etc.
33 // - 20100624: Verify that SG ID's can be in arbitrary order for everything to still function right
34 // - 20100623: figure out why main_UpdateGUI_Voices is getting called double times
35 // - 20100622: make voice list box sizeable
36 // - 20100623: make windows pop-out (dissociable)
37 // - 20100624: add "Solo"
38 // - 20100625: figure out why a voice has to be visible to be deleted
39 
40 #include <glib.h>
41 #include <gtk/gtk.h>
42 #include "main.h"
43 #include "voiceGUI.h"
44 #include "ScheduleGUI.h"
45 #include "BinauralBeat.h"
46 
47 /////////////////////////////////////////////////////////////
48 //Globals variables:
49 GtkWidget *VG_TreeView = NULL;  //GtkWidget so i can add to other widgets, but cast to GtkTreeView when needed
50 gboolean VG_RelistFlag = FALSE; //gets set to tell lister to redo list
51 enum
52 {
53  VG_COLUMN_COUNT,
54  VG_COLUMN_VIEW,
55  VG_COLUMN_MUTE,
56  VG_COLUMN_TYPE,
57  VG_COLUMN_DESC,
58  VG_COLUMN_COUNTTOTS,
59  VG_COLUMN_COUNTSELS,
60  VG_COLUMNCOUNT
61 };
62 
63 /////////////////////////////////////////////////////
64 //20070629: returns the SG_Voice that matches the ID or NULL if
65 //there is no match. Pray to god that IDs are always unique, 'k?
VG_GetVoice(int ID)66 SG_Voice *VG_GetVoice (int ID)
67 {
68  SG_Voice *curVoice = SG_FirstVoice;
69 
70  while (curVoice != NULL)
71  {
72   if (curVoice->ID == ID)
73   {
74    return curVoice;
75   }
76   curVoice = curVoice->NextVoice;
77  }
78  SG_DBGOUT_INT ("No SG ID", ID);
79  VG_RelistFlag = TRUE;
80  return NULL;
81 }
82 
83 /////////////////////////////////////////////////////
84 //20070629: returns the equivalent BB voice from a SG voice,
85 //needed because BB is arrays and SG linked-lists, but BB is always
86 //sync'd to SG's list order
87 //IMPORTANT: ERROR RETURNS -1
VG_GetVoiceIndex(SG_Voice * refVoice)88 int VG_GetVoiceIndex (SG_Voice * refVoice)
89 {
90  SG_Voice *curVoice = SG_FirstVoice;
91  int count = 0;
92 
93  while (curVoice != NULL)
94  {
95   if (curVoice == refVoice)
96   {
97    return count;
98   }
99   count++;
100   curVoice = curVoice->NextVoice;
101  }
102  SG_DBGOUT ("NO SUCH VOICE!");
103  VG_RelistFlag = TRUE;
104  return -1;
105 }
106 
107 /////////////////////////////////////
108 //20100624: status: works ok
VG_GetVoiceCount()109 gint VG_GetVoiceCount ()
110 {
111  return BB_VoiceCount;
112 }
113 
114 /////////////////////////////////////////////////////////
115 //20100623: need to rework
116 //Purpose: to manually highlight a specific entry in vgui
VG_List_SetSelectedVoice(GtkTreeModel * model,GtkTreeSelection * selection,gint index)117 void VG_List_SetSelectedVoice (GtkTreeModel * model,
118                                GtkTreeSelection * selection, gint index)
119 {
120  int i;
121  GtkTreeIter iter;
122  gtk_tree_model_get_iter_first (model, &iter);
123  for (i = 0; i < index; i++)
124   gtk_tree_model_iter_next (model, &iter);
125  gtk_tree_selection_select_iter (selection, &iter);
126 }
127 
128 /////////////////////////////////////
129 //20100622: status: works ok
VG_Checkbox_View(GtkCellRendererToggle * cell,gchar * path_str,gpointer data)130 static void VG_Checkbox_View (GtkCellRendererToggle * cell,
131                               gchar * path_str, gpointer data)
132 {
133  GtkTreeModel *model = (GtkTreeModel *) data;
134  GtkTreeIter iter;
135  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
136  gboolean CheckboxState;
137  gint voiceID;
138 
139  // get toggled iter and extract checkbox state and voiceID from it:
140  gtk_tree_model_get_iter (model, &iter, path);
141  gtk_tree_model_get (model, &iter, VG_COLUMN_VIEW, &CheckboxState,
142                      VG_COLUMN_COUNT, &voiceID, -1);
143 
144  SG_DBGOUT_INT ("View, SG ID", voiceID);
145 
146  //get voice index:
147  SG_Voice *curVoice = VG_GetVoice (voiceID);
148  if (NULL != curVoice)
149  {
150   curVoice->hide = CheckboxState;
151 
152   if (TRUE == curVoice->hide)
153   {
154    SG_VoiceTestLegalSelection ();
155    if (curVoice->state == SG_SELECTED)
156     curVoice->state = SG_UNSELECTED;
157   }
158  }
159 
160  // toggle the checkbox value FALSE/TRUE:
161  CheckboxState ^= 1;
162 
163  // set new value
164  gtk_list_store_set (GTK_LIST_STORE (model), &iter, VG_COLUMN_VIEW,
165                      CheckboxState, -1);
166 
167  // clean up
168  gtk_tree_path_free (path);
169  SG_ConvertDataToXY (main_drawing_area);        //20110519
170 }
171 
172 /////////////////////////////////////
173 //20100622
VG_Checkbox_Mute(GtkCellRendererToggle * cell,gchar * path_str,gpointer data)174 static void VG_Checkbox_Mute (GtkCellRendererToggle * cell,
175                               gchar * path_str, gpointer data)
176 {
177  GtkTreeModel *model = (GtkTreeModel *) data;
178  GtkTreeIter iter;
179  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
180  gboolean CheckboxState;
181  gint voiceID;
182 
183  // get toggled iter
184  gtk_tree_model_get_iter (model, &iter, path);
185  gtk_tree_model_get (model, &iter, VG_COLUMN_MUTE, &CheckboxState,
186                      VG_COLUMN_COUNT, &voiceID, -1);
187 
188  SG_DBGOUT_INT ("Mute, SG ID:", voiceID);
189 
190  // do something with the value
191  CheckboxState ^= 1;
192 
193  //get voice index:
194  SG_Voice *curVoice = VG_GetVoice (voiceID);
195  if (NULL != curVoice)
196  {
197   curVoice->mute = CheckboxState;
198   voiceID = VG_GetVoiceIndex (curVoice);
199   if (-1 != voiceID)
200   {
201    BB_Voice[voiceID].mute = CheckboxState;
202    SG_DBGOUT_INT ("Mute, BB ID", voiceID);
203   }
204  }
205  // set new value
206  gtk_list_store_set (GTK_LIST_STORE (model), &iter, VG_COLUMN_MUTE,
207                      CheckboxState, -1);
208  // clean up
209  gtk_tree_path_free (path);
210 }
211 
212 ////////////////////////////////
213 //20100622: status: working, not done
VG_onSelectionChange(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,gpointer userdata)214 gboolean VG_onSelectionChange (GtkTreeSelection * selection,
215                                GtkTreeModel * model,
216                                GtkTreePath * path,
217                                gboolean path_currently_selected,
218                                gpointer userdata)
219 {
220  //    g_print ("New Row Selected (%s line %d)\n",__FILE__, __LINE__);
221  GtkTreeIter iter;
222 
223  if (gtk_tree_model_get_iter (model, &iter, path))
224  {
225   int voiceID;
226   //20100624: voiceID should never be assumed to be an actual count
227   //index because it can be wildly out of whack when voices are deleted
228   gtk_tree_model_get (model, &iter, VG_COLUMN_COUNT, &voiceID, -1);
229   if (!path_currently_selected)
230   {
231    SG_DBGOUT_INT ("Selected SG Voice:", voiceID);
232    SG_SelectVoice (VG_GetVoice (voiceID));      //this looks for that ID, not using it a literal count
233   }
234   else
235   {
236    SG_DBGOUT_INT ("Unselected SG Voice:", voiceID);
237   }
238  }
239  //SG_DBGOUT_INT ("BB-VG=", VG_VerifyCount(GTK_TREE_VIEW (VG_TreeView)));
240  return TRUE;   // allow selection state to change
241 }
242 
243 ///////////////////////////////////////////////////////////////////
244 //20100622: Brings up Voices Properties box for selected row
245 //          status: working, not done
VG_onRightButton(GtkWidget * treeview,GdkEventButton * event,gpointer userdata)246 gboolean VG_onRightButton (GtkWidget * treeview,
247                            GdkEventButton * event, gpointer userdata)
248 {
249  if (NULL == gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)))
250  {
251   SG_DBGOUT ("Treeview == NULL");
252  }
253  //VG_RefillList (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));  //20100624 - critical!
254  // single click with the right mouse button:
255  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
256  {
257   //g_print ("Single right click on the tree view.\n");
258   SG_Voice *curVoice = SG_SelectVoice (NULL);   //return currently selected voice
259   main_VoicePropertiesDialog (main_drawing_area, curVoice);
260   //VG_DestroyTreeView ();
261   //VG_RefillList (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); //20100624 - critical!
262   //main_UpdateGUI_Voices (main_vboxVoices);
263 
264   // optional: select row if no row is selected or only
265   // one other row is selected
266   if (0)
267   {
268    GtkTreeSelection *selection;
269 
270    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
271 
272    // Note: gtk_tree_selection_count_selected_rows() does not
273    // exist in gtk+-2.0, only in gtk+ >= v2.2 !
274    if (gtk_tree_selection_count_selected_rows (selection) <= 1)
275    {
276     GtkTreePath *path;
277 
278     // Get tree path for row that was clicked
279     if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
280                                        (gint) event->x,
281                                        (gint) event->y,
282                                        &path, NULL, NULL, NULL))
283     {
284      gtk_tree_selection_unselect_all (selection);
285      gtk_tree_selection_select_path (selection, path);
286      gtk_tree_path_free (path);
287     }
288    }
289   }     // end of optional bit
290   //view_popup_menu(treeview, event, userdata);
291   return TRUE;  // we handled this
292  }
293  return FALSE;  // we did not handle this
294 }
295 
296 /////////////////////////////////////////////
297 //20100625 - gives user ability to edit descriptions on-the-fly
VG_EditDescription_callback(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,gpointer user_data)298 void VG_EditDescription_callback (GtkCellRendererText * cell,
299                                   gchar * path_string,
300                                   gchar * new_text, gpointer user_data)
301 {
302  int voiceID;
303  GtkTreeIter iter;
304  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (VG_TreeView));
305  gtk_tree_model_get_iter_from_string (model, &iter, path_string);
306  gtk_tree_model_get (model, &iter, VG_COLUMN_COUNT, &voiceID, -1);
307  SG_DBGOUT (new_text);
308  SG_Voice *curVoice = VG_GetVoice (voiceID);
309  if (NULL != curVoice)
310  {
311   SG_StringAllocateAndCopy (&(curVoice->description), (char *) new_text);
312   gtk_list_store_set (GTK_LIST_STORE (model), &iter, VG_COLUMN_DESC, new_text,
313                       -1);
314  }
315 }
316 
317 /////////////////////////////////////////////
318 //20100625 - toggles all-on or all off
VG_Mute_column_clicked(GtkTreeViewColumn * column,gpointer user_data)319 void VG_Mute_column_clicked (GtkTreeViewColumn * column, gpointer user_data)
320 {
321  SG_Voice *curVoice = SG_FirstVoice;
322  int VoiceIndex = 0;
323  static gboolean val = TRUE;
324 
325  while (curVoice != NULL)
326  {
327   curVoice->mute = BB_Voice[VoiceIndex].mute = val;
328   curVoice = curVoice->NextVoice;
329   ++VoiceIndex;
330  }
331  val ^= 1;
332  VG_FillList (GTK_TREE_VIEW (VG_TreeView));
333 }
334 
335 /////////////////////////////////////////////
336 //20100625 - toggles see-all or see-none
VG_View_column_clicked(GtkTreeViewColumn * column,gpointer user_data)337 void VG_View_column_clicked (GtkTreeViewColumn * column, gpointer user_data)
338 {
339  SG_Voice *curVoice = SG_FirstVoice;
340  static gboolean val = TRUE;
341 
342  while (curVoice != NULL)
343  {
344   curVoice->hide = val;
345   curVoice = curVoice->NextVoice;
346  }
347  val ^= 1;
348  VG_FillList (GTK_TREE_VIEW (VG_TreeView));
349  SG_ConvertDataToXY (main_drawing_area);        //20110519
350 }
351 
352 //=====================
353 /////////////////////////////////////////////
354 //20100622 - Adds columns to the List store. Called after
355 //           VG_List_CreateModel ()
VG_List_AddColumns(GtkTreeView * treeview)356 static void VG_List_AddColumns (GtkTreeView * treeview)
357 {
358  GtkCellRenderer *renderer;
359  GtkTreeViewColumn *column;
360  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
361 
362  //These are the columns:
363  // VG_COLUMN_COUNT,     int
364  // VG_COLUMN_VIEW,      checkbox
365  // VG_COLUMN_MUTE,      checkbox
366  // VG_COLUMN_TYPE,      string
367  // VG_COLUMN_DESC,      string
368  // VG_COLUMN_COUNTTOTS, int
369  // VG_COLUMN_COUNTSELS, int
370 
371  //Now for the actual columns:
372  // VG_COLUMN_COUNT, int:
373  renderer = gtk_cell_renderer_text_new ();
374  g_object_set (G_OBJECT (renderer), "foreground", "red", NULL);
375  column = gtk_tree_view_column_new_with_attributes ("ID",
376                                                     renderer,
377                                                     "text",
378                                                     VG_COLUMN_COUNT, NULL);
379  gtk_tree_view_column_set_sort_column_id (column, VG_COLUMN_COUNT);
380  gtk_tree_view_append_column (treeview, column);
381 
382  // VG_COLUMN_VIEW, checkbox:
383  renderer = gtk_cell_renderer_toggle_new ();
384  g_signal_connect (renderer, "toggled", G_CALLBACK (VG_Checkbox_View), model);
385  column =
386   gtk_tree_view_column_new_with_attributes ("View", renderer, "active",
387                                             VG_COLUMN_VIEW, NULL);
388  gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),        // set this column to a fixed sizing (of 50 pixels)
389                                   GTK_TREE_VIEW_COLUMN_FIXED);
390  gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
391  gtk_tree_view_column_set_clickable (column, TRUE);
392  gtk_tree_view_append_column (treeview, column);
393  g_signal_connect (G_OBJECT (column), "clicked",
394                    G_CALLBACK (VG_View_column_clicked), NULL);
395 
396  // VG_COLUMN_MUTE, checkbox:
397  renderer = gtk_cell_renderer_toggle_new ();
398  g_signal_connect (renderer, "toggled", G_CALLBACK (VG_Checkbox_Mute), model);
399  column =
400   gtk_tree_view_column_new_with_attributes ("Mute", renderer, "active",
401                                             VG_COLUMN_MUTE, NULL);
402  gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),        // set this column to a fixed sizing (of 50 pixels)
403                                   GTK_TREE_VIEW_COLUMN_FIXED);
404  gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
405  gtk_tree_view_column_set_clickable (column, TRUE);
406  gtk_tree_view_append_column (treeview, column);
407  g_signal_connect (G_OBJECT (column), "clicked",
408                    G_CALLBACK (VG_Mute_column_clicked), NULL);
409 
410  // VG_COLUMN_TYPE, string:
411  renderer = gtk_cell_renderer_text_new ();
412  g_object_set (G_OBJECT (renderer), "foreground", "blue", NULL);
413  column = gtk_tree_view_column_new_with_attributes ("Type",
414                                                     renderer,
415                                                     "text",
416                                                     VG_COLUMN_TYPE, NULL);
417  gtk_tree_view_column_set_sort_column_id (column, VG_COLUMN_TYPE);
418  gtk_tree_view_append_column (treeview, column);
419 
420  // VG_COLUMN_DESC, string:
421  renderer = gtk_cell_renderer_text_new ();
422  g_object_set (renderer, "editable", TRUE, NULL);
423  g_signal_connect (renderer, "edited",
424                    (GCallback) VG_EditDescription_callback, NULL);
425  column =
426   gtk_tree_view_column_new_with_attributes ("Description", renderer, "text",
427                                             VG_COLUMN_DESC, NULL);
428  gtk_tree_view_column_set_sort_column_id (column, VG_COLUMN_DESC);
429  gtk_tree_view_append_column (treeview, column);
430 
431  // VG_COLUMN_COUNTTOTS, int:
432  renderer = gtk_cell_renderer_text_new ();
433  column = gtk_tree_view_column_new_with_attributes ("Total",
434                                                     renderer,
435                                                     "text",
436                                                     VG_COLUMN_COUNTTOTS,
437                                                     NULL);
438  gtk_tree_view_column_set_sort_column_id (column, VG_COLUMN_COUNTTOTS);
439  gtk_tree_view_append_column (treeview, column);
440 
441  // VG_COLUMN_COUNTSELS, int:
442  renderer = gtk_cell_renderer_text_new ();
443  column = gtk_tree_view_column_new_with_attributes ("Selected",
444                                                     renderer,
445                                                     "text",
446                                                     VG_COLUMN_COUNTSELS,
447                                                     NULL);
448  gtk_tree_view_column_set_sort_column_id (column, VG_COLUMN_COUNTSELS);
449  gtk_tree_view_append_column (treeview, column);
450 }
451 
452 /////////////////////////////////////////////
453 //20100622 - creates the List store and adds my data to it. Called
454 //           first, before VG_List_AddColumns
VG_List_CreateModel()455 static GtkTreeModel *VG_List_CreateModel ()
456 {
457  GtkListStore *store;
458  GtkTreeIter iter;
459 
460  //"Another way to refer to a row in a list or tree is GtkTreeIter. A tree iter is just a structure that contains a couple of pointers that mean something to the model you are using. Tree iters are used internally by models, and they often contain a direct pointer to the internal data of the row in question. You should never look at the content of a tree iter and you must not modify it directly either."
461 
462  // create list store
463  store = gtk_list_store_new (VG_COLUMNCOUNT,    // total count of colums
464                              G_TYPE_INT,        // VG_COLUMN_COUNT
465                              G_TYPE_BOOLEAN,    // VG_COLUMN_VIEW
466                              G_TYPE_BOOLEAN,    // VG_COLUMN_MUTE
467                              G_TYPE_STRING,     // VG_COLUMN_TYPE
468                              G_TYPE_STRING,     // VG_COLUMN_DESC
469                              G_TYPE_INT,        // VG_COLUMN_COUNTTOTS
470                              G_TYPE_INT // VG_COLUMN_COUNTSELS
471   );
472 
473  // add data to the list store
474  int VoiceIndex = 0;
475  int dpcount_all = 0;
476  int dpcount_selected = 0;
477  SG_Voice *curVoice = SG_FirstVoice;
478 
479  /* populate the model: */
480  while (curVoice != NULL)
481  {
482   main_sTmp[0] = '\0';
483   main_VoiceInfoFormatter_type (curVoice, main_sTmp);
484   SG_CountVoiceDPs (curVoice, &dpcount_all, &dpcount_selected);
485   gtk_list_store_append (store, &iter);
486   gtk_list_store_set (store, &iter,
487                       VG_COLUMN_COUNT, curVoice->ID,
488                       VG_COLUMN_VIEW, TRUE == curVoice->hide ? FALSE : TRUE,
489                       VG_COLUMN_MUTE, BB_Voice[VoiceIndex].mute,
490                       VG_COLUMN_TYPE, main_sTmp,
491                       VG_COLUMN_DESC, curVoice->description,
492                       VG_COLUMN_COUNTTOTS, dpcount_all,
493                       VG_COLUMN_COUNTSELS, dpcount_selected, -1);
494 
495   //main loop update
496   ++VoiceIndex;
497   curVoice = curVoice->NextVoice;
498  }
499  ////////////////////////////////
500 
501  return GTK_TREE_MODEL (store);
502 }
503 
504 /////////////////////////////////////////////////////////
505 //20100624: hopefully fast count of rows
VG_CountRows(GtkTreeView * treeview)506 gint VG_CountRows (GtkTreeView * treeview)
507 {
508  int count = 0;
509  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
510  GtkTreeIter iter;
511  gtk_tree_model_get_iter_first (model, &iter);
512  do
513  {
514   //gtk_tree_model_get (model, &iter, VG_COLUMN_COUNT, &voiceID, -1);
515   //gtk_list_store_set (GTK_LIST_STORE (model), &iter, VG_COLUMN_COUNT, i++, -1);
516   ++count;
517  }
518  while (FALSE != gtk_tree_model_iter_next (model, &iter));
519  return count;
520 }
521 
522    /////////////////////////////////////////////////////////
523    //20100624: Makes sure BB/SG have same number of voices as VG
524    //returns TRUE of counts were already sync'd
VG_VerifyCount(GtkTreeView * treeview)525 int VG_VerifyCount (GtkTreeView * treeview)
526 {
527  return (BB_VoiceCount - VG_CountRows (GTK_TREE_VIEW (treeview)));
528 }
529 
530 /////////////////////////////////////////////////////////
531 //20100624: Only deletes it if it's full
VG_DestroyTreeView()532 void VG_DestroyTreeView ()
533 {
534  if (NULL != VG_TreeView)
535  {
536   SG_DBGOUT ("Destroying old VG_TreeView");
537   gtk_widget_destroy (VG_TreeView);
538   VG_TreeView = NULL;
539  }
540 }
541 
542 /////////////////////////////////////////////
543 //20100624
VG_FillList(GtkTreeView * treeview)544 void VG_FillList (GtkTreeView * treeview)
545 {
546  SG_Voice *curVoice;
547  int voiceID;
548  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
549  GtkTreeIter iter;
550  gtk_tree_model_get_iter_first (model, &iter);
551 
552  // add data to the list store
553  int dpcount_all = 0;
554  int dpcount_selected = 0;
555 
556  // populate the model:
557  do
558  {
559   //first get the voiceID:
560   gtk_tree_model_get (model, &iter, VG_COLUMN_COUNT, &voiceID, -1);
561   //now match it up to the correct SG_Voice:
562   curVoice = VG_GetVoice (voiceID);
563   if (curVoice != NULL)
564   {
565    main_sTmp[0] = '\0';
566    main_VoiceInfoFormatter_type (curVoice, main_sTmp);
567    SG_CountVoiceDPs (curVoice, &dpcount_all, &dpcount_selected);
568    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
569                        VG_COLUMN_COUNT, curVoice->ID,
570                        VG_COLUMN_VIEW, TRUE == curVoice->hide ? FALSE : TRUE,
571                        VG_COLUMN_MUTE, curVoice->mute,
572                        VG_COLUMN_TYPE, main_sTmp,
573                        VG_COLUMN_DESC, curVoice->description,
574                        VG_COLUMN_COUNTTOTS, dpcount_all,
575                        VG_COLUMN_COUNTSELS, dpcount_selected, -1);
576   }
577   else
578   {
579    //bad news if we got here - probably means SG has uncaringly
580    //reordered IDs, gotta rebuild. THAT'S A BUG
581    VG_DestroyTreeView ();
582    return;
583   }
584 
585   //  gtk_list_store_set (GTK_LIST_STORE (model), &iter, VG_COLUMN_COUNT, i++, -1);
586  }
587  while (FALSE != gtk_tree_model_iter_next (model, &iter));
588 }
589 
590 /////////////////////////////////////////////////////////
591 //20100622: the big one.
592 //Purpose:
593 // - (once for init only) create a scrollable window to put inside GtkVBox user gives me
594 // - (once for init and then time a voice is added or subtracted) create a list to store SG/BB data
595 // - (every call) Be sure BB_VoiceCount and number of rows is identical (adding or subtracting as needed)
596 // - refill list with things that can change (more complicated than it seems, as list order is arbitrary)
main_UpdateGUI_Voices(GtkVBox * mainbox)597 void main_UpdateGUI_Voices (GtkVBox * mainbox)
598 {
599  static GtkWidget *sw = NULL;   //create so I can delete something inside box user passed me
600  static int CellHeight = 24;    //arbitrary, gets set for-real later
601  //############
602  //First do the stuff that only happens once:
603  //Create the scrollwindow to put in user's box if it doesn't exist yet:
604  if (NULL == sw)
605  {
606   //  gtk_widget_destroy (sw);
607   //Make a scrollable window to put in user's thang:
608   sw = gtk_scrolled_window_new (NULL, NULL);
609   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
610                                        GTK_SHADOW_ETCHED_IN);
611   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
612                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
613   gtk_box_pack_start (GTK_BOX (mainbox), sw, TRUE, TRUE, 0);
614  }
615 
616  //Create the list if it doesn't exist yet:
617  if (TRUE == VG_RelistFlag || NULL == VG_TreeView || 0 != VG_VerifyCount (GTK_TREE_VIEW (VG_TreeView))) //this part is a hack because i am finding weirdness in Voice IDs
618  {
619   VG_RelistFlag = FALSE;
620   SG_DBGOUT ("Creating new VG_TreeView");
621   // create tree model by loading my data
622   GtkTreeModel *treemodel = VG_List_CreateModel ();
623 
624   VG_DestroyTreeView ();        //only does it if != NULL
625 
626   // create tree view
627   VG_TreeView = gtk_tree_view_new_with_model (treemodel);
628   //gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE) ;
629   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (VG_TreeView), TRUE);
630   gtk_tree_view_set_search_column (GTK_TREE_VIEW (VG_TreeView),
631                                    VG_COLUMN_DESC);
632   GtkTreeSelection *selection =
633    gtk_tree_view_get_selection (GTK_TREE_VIEW (VG_TreeView));
634   gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
635 
636   //start 20110519
637   int i = 0;
638   SG_Voice *selVoice = SG_SelectVoice (NULL);
639   if (NULL != selVoice)
640   {
641    i = VG_GetVoiceIndex (selVoice);
642    if (-1 == i)
643     i = 0;
644   }
645   VG_List_SetSelectedVoice (treemodel, selection, i);   //20100624: need to rework
646   //end 20110519
647 
648   //two different approaches to doing this, using the more dedicated one:
649   // g_signal_connect(selection, "changed",  G_CALLBACK(VG_onSelectionChange), NULL);
650   gtk_tree_selection_set_select_function (selection, VG_onSelectionChange,
651                                           NULL, NULL);
652 
653   //to determine when right mouse button is pressed:
654   g_signal_connect (VG_TreeView, "button-press-event",
655                     (GCallback) VG_onRightButton, NULL);
656 
657   g_object_unref (treemodel);   //20100624: WHAT? Apparently OK, i use gtk_tree_view_get_model
658 
659   gtk_container_add (GTK_CONTAINER (sw), VG_TreeView);
660 
661   // add columns to the tree view
662   VG_List_AddColumns (GTK_TREE_VIEW (VG_TreeView));
663 
664   //get height here so i don't have to do it over and over:
665   gtk_tree_view_column_cell_get_size (gtk_tree_view_get_column
666                                       (GTK_TREE_VIEW (VG_TreeView), 0), NULL,
667                                       NULL, NULL, NULL, &CellHeight);
668   //SG_DBGOUT_INT ("row height:", CellHeight);
669   CellHeight += 2;
670   gtk_widget_show_all (sw);
671  }
672  //End of stuff only done once
673  //############
674 
675  // 20100623: try to keep a sensible amount of list showing:
676  if (6 > VG_GetVoiceCount ())
677  {
678   gtk_widget_set_usize (sw, 600, CellHeight * (1 + VG_GetVoiceCount ()));
679  }
680  else
681  {
682   gtk_widget_set_usize (sw, 600, CellHeight * 6);
683  }
684 
685  VG_FillList (GTK_TREE_VIEW (VG_TreeView));
686 }
687