Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ ⎇ branch:  streamtuner2


Check-in [7b5b2a40e8]

Overview
Comment:Allow to supply ordered (key,value) list[] to mygtk.ComboBoxText. Config specifiers can use ID=abc|XY=xyz|... now.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7b5b2a40e8081a17b08a9ad3f7277edb8679731a
User & Date: mario on 2014-05-25 16:36:11
Other Links: manifest | tags
Context
2014-05-25
17:23
Simplify streamedit_ by reusing config_dialog.load_config() (Also allows to use a liststore table later..) check-in: 927dc82086 user: mario tags: trunk
16:36
Allow to supply ordered (key,value) list[] to mygtk.ComboBoxText. Config specifiers can use ID=abc|XY=xyz|... now. check-in: 7b5b2a40e8 user: mario tags: trunk
11:57
Use mygtk.ComboBoxText also for theme switcher button. Moved .vbox and .label creating into mygtk, ComboBoxText.set_default() now automatically adds non-predeclated/custom value at end of liststore. check-in: 9ad64ad53a user: mario tags: trunk
Changes

Modified channels/jamendo.py from [9ef2d05b7e] to [9a203fe500].

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
         "value":"ogg",
         "type": "text",
         "description":"Streaming format. Use 'ogg' for Vorbis, 'mp32' for MP3 with 192kbps/VBR, or 'mp31' for 96kbps MP3, and even 'flac' for lossless audio."
        },
        {"name": "jamendo_image_size",
         "value": "50",
         "type": "select",
         "select": "25|35|50|55|60|65|70|75|85|100|130|150|200|300",
         "description": "Preview images size (height and width in pixel) for albums or tracks."
        },
        {"name": "jamendo_count",
         "value": "1",
         "type":"text",
         "description": "How many result sets (200 entries each) to retrieve."
        }
    ]    







|
|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
         "value":"ogg",
         "type": "text",
         "description":"Streaming format. Use 'ogg' for Vorbis, 'mp32' for MP3 with 192kbps/VBR, or 'mp31' for 96kbps MP3, and even 'flac' for lossless audio."
        },
        {"name": "jamendo_image_size",
         "value": "50",
         "type": "select",
         "select": "25=25px|35=35px|50=50px|55=55px|60=60px|65=65px|70=70px|75=75px|85=85px|100=100px|130=130px|150=150px|200=200px|300=300px",
         "description": "Preview images size (height and width) for albums or tracks."
        },
        {"name": "jamendo_count",
         "value": "1",
         "type":"text",
         "description": "How many result sets (200 entries each) to retrieve."
        }
    ]    

Modified mygtk.py from [aef1299a5d] to [7b64057ace].

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438


439







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455


456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474






475
            b = gtk.HBox(homogeneous=False, spacing=10)
            b.set_property("visible", True)
            b.pack_start(w1, expand=False, fill=False)
            b.pack_start(w2, expand=True, fill=True)
            return b


        #
        @staticmethod
        def add_menu(menuwidget, label, action):
            m = gtk.MenuItem(label)
            m.connect("activate", action)
            m.show()
            menuwidget.add(m)
            

        # gtk.messagebox
        @staticmethod
        def msg(text, style=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE):
            m = gtk.MessageDialog(None, 0, style, buttons, message_format=text)
            m.show()
            m.connect("response", lambda *w: m.destroy())
            


# Implement text combobox,


# because debian packages lack the binding https://bugzilla.gnome.org/show_bug.cgi?id=660659







class ComboBoxText(gtk.ComboBox):

    ls = None

    def __init__(self, entries):

        # prepare widget
        gtk.ComboBox.__init__(self)
        self.set_property("visible", True)
        cell = gtk.CellRendererText()
        self.pack_start(cell, True)
        self.add_attribute(cell, "text", 1)

        # collect entries
        self.ls = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.set_model(self.ls)


        for value in entries:
            self.ls.append([value, value])
        
    # activate dropdown of given value
    def set_default(self, value):
        for index,row in enumerate(self.ls):
            if value in row:
                return self.set_active(index)
        # add as custom entry
        self.ls.append([value, value])
        self.set_active(index + 1)

    # fetch currently selected text entry
    def get_active_text(self):
        index = self.get_active()
        if index >= 0:
            return self.ls[index][0]
















|

















|
>
>
|
>
>
>
>
>
>
>
















>
>
|
|
















|
>
>
>
>
>
>

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
            b = gtk.HBox(homogeneous=False, spacing=10)
            b.set_property("visible", True)
            b.pack_start(w1, expand=False, fill=False)
            b.pack_start(w2, expand=True, fill=True)
            return b


        # Attach textual menu entry and callback
        @staticmethod
        def add_menu(menuwidget, label, action):
            m = gtk.MenuItem(label)
            m.connect("activate", action)
            m.show()
            menuwidget.add(m)
            

        # gtk.messagebox
        @staticmethod
        def msg(text, style=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE):
            m = gtk.MessageDialog(None, 0, style, buttons, message_format=text)
            m.show()
            m.connect("response", lambda *w: m.destroy())
            


# Text-only dropdown list.
#
# Necessary because gtk.ComboBoxText binding is absent in debian packages
# https://bugzilla.gnome.org/show_bug.cgi?id=660659
#
# This one implements a convenience method `.set_default()` to define the active
# selection by value, rather than by index.
#
# Can use a list[] of entries or a key->value dict{}, where the value becomes
# display text, and the key the internal value.
#
class ComboBoxText(gtk.ComboBox):

    ls = None

    def __init__(self, entries):

        # prepare widget
        gtk.ComboBox.__init__(self)
        self.set_property("visible", True)
        cell = gtk.CellRendererText()
        self.pack_start(cell, True)
        self.add_attribute(cell, "text", 1)

        # collect entries
        self.ls = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.set_model(self.ls)
        if type(entries[0]) is not tuple:
            entries = zip(entries, entries)
        for key,value in entries:
            self.ls.append([key, value])
        
    # activate dropdown of given value
    def set_default(self, value):
        for index,row in enumerate(self.ls):
            if value in row:
                return self.set_active(index)
        # add as custom entry
        self.ls.append([value, value])
        self.set_active(index + 1)

    # fetch currently selected text entry
    def get_active_text(self):
        index = self.get_active()
        if index >= 0:
            return self.ls[index][0]

    # Expand A=a|B=b|C=c option list into (key,value) tuple list, or A|B|C just into a list.
    @staticmethod
    def parse_options(opts, sep="|", assoc="="):
        if opts.find(assoc) >= 0:
            return [ (k,v) for k,v in (x.split(assoc, 1) for x in opts.split(sep)) ]
        else:
            return opts.split(sep) #dict( (v,v) for v in opts.split(sep) )

Modified st2.py from [d9136b2e9d] to [3e127b9d62].

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
                "streamedit_cancel": streamedit.cancel,
            }.items() ) + list( self.add_signals.items() ) ))
            
            # actually display main window
            gui_startup(99/100.0)
            self.win_streamtuner2.show()
            
            # WHY DON'T YOU WANT TO WORK?!
            #self.shoutcast.gtk_list.set_enable_search(True)
            #self.shoutcast.gtk_list.set_search_column(4)


          

        #-- Shortcut for glade.get_widget()
        # Allows access to widgets as direct attributes instead of using .get_widget()
        # Also looks in self.channels[] for the named channel plugins
        def __getattr__(self, name):







<
<
<
<







216
217
218
219
220
221
222




223
224
225
226
227
228
229
                "streamedit_cancel": streamedit.cancel,
            }.items() ) + list( self.add_signals.items() ) ))
            
            # actually display main window
            gui_startup(99/100.0)
            self.win_streamtuner2.show()
            





          

        #-- Shortcut for glade.get_widget()
        # Allows access to widgets as direct attributes instead of using .get_widget()
        # Also looks in self.channels[] for the named channel plugins
        def __getattr__(self, name):
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
                return gtk.Builder.get_object(self, name)
                


                
        # returns the currently selected directory/channel object
        def channel(self):
            #try:
                return self.channels[self.current_channel]
            #except Exception,e:
            #    print(e)
            #    self.notebook_channels.set_current_page(0)
            #    self.current_channel = "bookmarks"
            #    return self.channels["bookmarks"]

            
        def current_channel_gtk(self):
            i = self.notebook_channels.get_current_page()
            try: return self.channel_names[i]
            except: return "bookmarks"








<
|
<
<
<
<
<







241
242
243
244
245
246
247

248





249
250
251
252
253
254
255
                return gtk.Builder.get_object(self, name)
                


                
        # returns the currently selected directory/channel object
        def channel(self):

            return self.channels[self.current_channel]






            
        def current_channel_gtk(self):
            i = self.notebook_channels.get_current_page()
            try: return self.channel_names[i]
            except: return "bookmarks"

861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
                            
                        # display checkbox
                        if opt["type"] == "boolean":
                            cb = gtk.CheckButton(opt["description"])
                            self.add_( "config_"+opt["name"], cb, color=color )
                        # drop down list
                        elif opt["type"] == "select":
                            cb = ComboBoxText(opt["select"].split("|")) # custom mygtk widget
                            self.add_( "config_"+opt["name"], cb, opt["description"], color )
                        # text entry
                        else:
                            self.add_( "config_"+opt["name"], gtk.Entry(), opt["description"], color )

                # spacer 
                self.add_( "filler_pl_"+name, gtk.HSeparator() )







|







851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
                            
                        # display checkbox
                        if opt["type"] == "boolean":
                            cb = gtk.CheckButton(opt["description"])
                            self.add_( "config_"+opt["name"], cb, color=color )
                        # drop down list
                        elif opt["type"] == "select":
                            cb = ComboBoxText(ComboBoxText.parse_options(opt["select"])) # custom mygtk widget
                            self.add_( "config_"+opt["name"], cb, opt["description"], color )
                        # text entry
                        else:
                            self.add_( "config_"+opt["name"], gtk.Entry(), opt["description"], color )

                # spacer 
                self.add_( "filler_pl_"+name, gtk.HSeparator() )