Index: channels/configwin.py ================================================================== --- channels/configwin.py +++ channels/configwin.py @@ -64,15 +64,22 @@ w.set_default(val) # number elif isinstance(w, gtk.SpinButton): w.set_value(int(val)) # list - elif isinstance(w, gtk.ListStore) and isinstance(val, dict): + elif isinstance(w, gtk.ListStore): w.clear() - for k,v in val.items(): - w.append([k, v, uikit.app_bin_check(v)]) - w.append(["", "", gtk.STOCK_NEW]) + if isinstance(val, dict): + for k,v in val.items(): + w.append([k, v, uikit.app_bin_check(v)]) + w.append(["", "", gtk.STOCK_NEW]) + elif isinstance(val, list): + for row in val: + log.DATA(row) + w.append([str(e) for e in row]) + if len(val): + w.append(["" for e in val[0]]) #log.CONF("config load", prefix+key, val, type(w)) # Store gtk widget valus back into conf. dict def save_config(self, config, prefix="config_", save=0): for key,val in config.items(): @@ -90,14 +97,19 @@ # int elif isinstance(w, gtk.SpinButton): config[key] = int(w.get_value(val)) # dict elif isinstance(w, gtk.ListStore): - config[key] = {} - for row in w: - if row[0] and row[1]: - config[key][row[0]] = row[1] + if key in config and isinstance(config[key], list): + config[key] = [] + for row in w: + config[key].append([str(e) for e in row]) + else: + config[key] = {} + for row in w: + if row[0] and row[1]: + config[key][row[0]] = row[1] log.CONF("config save", prefix+key, val) # iterate over channel and feature plugins def add_plugins(self): Index: channels/specbuttons.py ================================================================== --- channels/specbuttons.py +++ channels/specbuttons.py @@ -5,11 +5,11 @@ # depends: streamtuner2 >= 2.2.0 # type: feature # category: ui # config: # { name: specbutton_rows, value: 2, max: 4, type: int, description: "Number of rows to arrange buttons in." } -# { name: specbuttons, type: dict, columns: "Icon,Command", description: "Icons can either be `gtk-xyz` internal names, or `/usr/share/icon/*.png` path names ← which icon basenames would be expanded into. Commands can be any external program." } +# { name: specbuttons, type: dict, columns: "Icon,Command", description: "Icons can be `gtk-xyz` internal names. Else use `/usr/share/icon/*.png` file names. Icon file basenames will be expanded into full paths. "} # doc: # http://fossil.include-once.org/streamtuner2/info/43b36ed35b1488d5 # # Adds the mini/extra buttons in the toolbar, which allow to control your # audio player or run other system commands. The configuration list is in Index: help/specbuttons.page ================================================================== --- help/specbuttons.page +++ help/specbuttons.page @@ -7,19 +7,20 @@ Toolbar application short cuts. - Extra/mini buttons + Special extra/mini buttons

Using the specbuttons plugin, you can define additional shortcuts. This is meant as convenience - allows to start other audio apps or system ontrols from within streamtuner2.

-

The settings list can be found in the Settings → Options tab. It - follows the layout of the player/recording configuration. Except - that it lists icons and their according action commands:

+

The settings list can be found with th plugin options in the + 🔌 Features tab. It follows the layout of the player/recording + configuration. Except that it lists icons and their according + action commands:

@@ -28,11 +29,11 @@

Icon

Cmd

gtk-media-forward

vlc next

terminal

xterm

./import.png

audacity %pls

gtk-icons -

Note that the icon name can either be Gtk-builtin icon. Their +

Note that the icon name can also be that of a Gtk-builtin icon. Their names always start with "gtk-", for example "gtk-cancel". You can find a list of all available builtins under http://www.pygtk.org/pygtk2reference/gtk-stock-items.html.

@@ -56,10 +57,17 @@ for all commands as well. So you can have additional play/record shortcuts.

+ icon rows +

With the "number of rows" setting, more buttons can be packed together. + It looks okay with up to 3 rows - when using the large sized main toolbar. + The defined icon shortcuts will always be packed column-wise.

+

The icon list isn't ordered. So you cannot - define which button appears first.

+ define which button appears first. (Albeit the plugin config + definition can be changed from 'dict' to 'table' now, and the plugin + required just a little editing then.)

Index: pluginconf.py ================================================================== --- pluginconf.py +++ pluginconf.py @@ -481,10 +481,14 @@ # typemap "bool" and "int" here if opt["type"] in ("bool", "boolean"): val = opt["value"].lower() in ("1", "true", "yes", "on") elif opt["type"] in ("int", "integer", "numeric"): val = int(opt["value"]) + elif opt["type"] in ("array", "table", "list"): + val = [ opt["value"].split(",") ] + elif opt["type"] in ("dict"): + val = dict(opt["value"].split(",")) else: val = str(opt["value"]) conf_options[opt["name"]] = val # Initial plugin activation status Index: uikit.py ================================================================== --- uikit.py +++ uikit.py @@ -510,19 +510,22 @@ # Config win table (editable dictionary, two columns w/ executable indicator pixbuf) @staticmethod def config_treeview(opt, columns=["Icon", "Command"]): - liststore = gtk.ListStore(str, str, str) - w = gtk.TreeView(liststore) lno = len(columns) + if lno == 2: + liststore = gtk.ListStore(str, str, str) + else: + liststore = gtk.ListStore(*[str for i in range(0, lno)]) + w = gtk.TreeView(liststore) # two text columns and renderers for i in range(0, lno): c = gtk.TreeViewColumn(columns[i]) c.set_resizable(True) c.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - c.set_fixed_width(150 + 75*i) + c.set_fixed_width(int(430/lno)) r = gtk.CellRendererText() c.pack_end(r, expand=True) r.set_property("editable", True) r.connect("edited", uikit.liststore_edit, (liststore, i)) c.add_attribute(r, "text", i) @@ -540,18 +543,19 @@ # Generic Gtk callback to update ListStore when entries get edited. # where user_data = (liststore, column #id) @staticmethod def liststore_edit(cell, row, text, user_data): #log.EDIT(cell, row, text, user_data) + row = int(row) liststore, column = user_data liststore[row][column] = text # update executable-indicator pixbuf - if column == 1 and len(liststore) == 3 and liststore[row][2].startswith("gtk."): + if column == 1 and len(liststore[0]) == 3 and liststore[row][2].startswith("gtk-"): liststore[row][2] = uikit.app_bin_check(text) - # add new row if editing last - if row == len(liststore) -1: - liststore.append(*["" for c in liststore[column]]) + # add new row when editing last one + if len(text) and (row + 1) == len(liststore): + liststore.append(["", "", "gtk-new"]) # return OK or CANCEL depending on availability of app @staticmethod def app_bin_check(v): bin = re.findall(r"(?