Index: gtk2.xml ================================================================== --- gtk2.xml +++ gtk2.xml @@ -1,8 +1,8 @@ - + @@ -45,17 +45,14 @@ 520 True True True - True True True - automatic - automatic True False 15 @@ -80,12 +77,10 @@ True True - automatic - automatic 540 200 True @@ -262,12 +257,10 @@ True True - automatic - automatic True False 15 @@ -461,11 +454,10 @@ 5 5 500 out - True False False True True @@ -614,11 +606,10 @@ 200 20 True True - True gtk-save-as False False True True @@ -684,11 +675,10 @@ True True False 20 - True gtk-home False False True True @@ -802,11 +792,10 @@ True True - True False False True True @@ -1091,234 +1080,19 @@ 0.94999999999999996 - True - False - 2 - - - True - False - end - - - - - - - - - - - - - - - - - - False - False - end - 0 - - - - - True - False - 20 - - - True - False - <b><big>search</big></b> - True - - - True - True - 0 - - - - - - - - True - False - - - True - False - 10 - for - - - True - True - 0 - - - - - True - True - True - True - A single word to search for in all stations. - - True - False - False - True - True - - - True - True - 1 - - - - - True - False - - - True - True - 2 - - - - - True - True - 2 - - - - - True - False - - - True - False - 10 - 10 - in - - - True - True - 0 - - - - - all channels - True - True - False - True - True - search_dialog_current - - - True - True - 1 - - - - - just current - True - True - False - True - True - search_dialog_all - - - True - True - 2 - - - - - True - True - 3 - - - - - - - - True - False - 20 - - - Cache _find - True - False - False - Start searching for above search term in the currently loaded station lists. Doesn't find *new* information, just looks through the known data. - image1 - half - True - - - - - True - True - 0 - - - - - Server _search - True - False - True - True - True - True - True - Instead of doing a cache search, go through the search functions on the directory service homepages. (UNIMPLEMENTED) - image2 - True - - - - True - True - 1 - - - - - True - True - 5 - - - - - True - True - 1 + False + + + False + + + True + True + 0 @@ -1406,622 +1180,23 @@ normal - True False - 2 - True - False - end - - - cancel - True - True - True - - - - False - False - 0 - - - - - ok - True - True - True - - - - False - False - 1 - - - - - False - True - end - 0 - - - - - True - False - 3 - 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - - Fri,Sat 20:00-21:00 - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + False True True - 1 + 0 - - timer_cancel - timer_ok - False @@ -2653,10 +1828,60 @@ + + + True + False + Channel tab position + True + + + True + False + + + True + False + Top + True + + + + + + True + False + Left + True + + + + + + True + False + Bottom + True + + + + + + True + False + Right + True + + + + + + + True False Save states Index: gtk3.xml ================================================================== --- gtk3.xml +++ gtk3.xml @@ -1895,10 +1895,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True True @@ -1911,10 +1947,16 @@ 2 1 2 + + + + + + @@ -2640,10 +2682,60 @@ + + + True + False + Channel tab position + True + + + True + False + + + True + False + Top + True + + + + + + True + False + Left + True + + + + + + True + False + Bottom + True + + + + + + True + False + Right + True + + + + + + + True False Save states Index: mygtk.py ================================================================== --- mygtk.py +++ mygtk.py @@ -299,12 +299,15 @@ r[wn]["icon_size"] = int(w.get_icon_size()) r[wn]["style"] = int(w.get_style()) # gtk.Notebook if t == gtk.Notebook: r[wn]["page"] = w.get_current_page() + r[wn]["tab_pos"] = int(w.get_tab_pos()) #print(r) return r + + gtk_position_type_enum = [gtk.POS_LEFT, gtk.POS_RIGHT, gtk.POS_TOP, gtk.POS_BOTTOM] #-- restore window and widget properties # # requires only the previously saved widget state dict @@ -339,10 +342,12 @@ if method == "style": w.set_style(args) # gtk.Notebook if method == "page": w.set_current_page(args) + if method == "tab_pos": + w.set_tab_pos(r[wn]["tab_pos"]) pass Index: st2.py ================================================================== --- st2.py +++ st2.py @@ -3,14 +3,14 @@ # api: python # type: application # title: streamtuner2 # description: Directory browser for internet radio / audio streams # depends: pygtk | pygi, threading, pyquery, kronos, requests -# version: 2.1.2 +# version: 2.1.3 # author: mario salzer # license: public domain -# url: http://freshmeat.net/projects/streamtuner2 +# url: http://freshcode.club/projects/streamtuner2 # config: # category: multimedia # # # @@ -191,10 +191,14 @@ "menu_toolbar_style_icons": lambda w: (self.toolbar.set_style(gtk.TOOLBAR_ICONS)), "menu_toolbar_style_both": lambda w: (self.toolbar.set_style(gtk.TOOLBAR_BOTH)), "menu_toolbar_size_small": lambda w: (self.toolbar.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)), "menu_toolbar_size_medium": lambda w: (self.toolbar.set_icon_size(gtk.ICON_SIZE_DND)), "menu_toolbar_size_large": lambda w: (self.toolbar.set_icon_size(gtk.ICON_SIZE_DIALOG)), + "menu_notebook_pos_top": lambda w: self.notebook_channels.set_tab_pos(2), + "menu_notebook_pos_left": lambda w: self.notebook_channels.set_tab_pos(0), + "menu_notebook_pos_right": lambda w: self.notebook_channels.set_tab_pos(1), + "menu_notebook_pos_bottom": lambda w: self.notebook_channels.set_tab_pos(3), # win_config "menu_properties": config_dialog.open, "config_cancel": config_dialog.hide, "config_save": config_dialog.save, "config_play_list_edit_col0": lambda w,path,txt: (config_dialog.list_edit(self.config_play, path, 0, txt)), @@ -232,44 +236,37 @@ # actually display main window gui_startup(98.9/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): if (name in self.channels): return self.channels[name] # like self.shoutcast else: return self.get_object(name) # or gives an error if neither exists - - # custom-named widgets are available from .widgets{} not via .get_widget() + # Custom-named widgets are available from .widgets{} not via .get_widget() def get_widget(self, name): if name in self.widgets: return self.widgets[name] else: return gtk.Builder.get_object(self, name) - - - - # returns the currently selected directory/channel object + # returns the currently selected directory/channel object (remembered position) def channel(self): return self.channels[self.current_channel] - + # returns the currently selected directory/channel object (from gtk) def current_channel_gtk(self): i = self.notebook_channels.get_current_page() try: return self.channel_names[i] except: return "bookmarks" - - # notebook tab clicked + # Notebook tab clicked def channel_switch(self, notebook, page, page_num=0, *args): # can be called from channelmenu as well: if type(page) == str: self.current_channel = page @@ -283,94 +280,81 @@ __print__(dbg.PROC, "channel_switch: try .first_show", self.channel().module); self.channel().first_show() except: __print__(dbg.INIT, "channel .first_show() initialization error") - - # convert ListStore iter to row number + # Convert ListStore iter to row number def rowno(self): (model, iter) = self.model_iter() return model.get_path(iter)[0] - - # currently selected entry in stations list, return complete data dict + # Currently selected entry in stations list, return complete data dict def row(self): return self.channel().stations() [self.rowno()] # return ListStore object and Iterator for currently selected row in gtk.TreeView station list def model_iter(self): return self.channel().gtk_list.get_selection().get_selected() - - # fetches a single varname from currently selected station entry + # Fetches a single varname from currently selected station entry def selected(self, name="url"): return self.row().get(name) + - - - - # play button + # Play button def on_play_clicked(self, widget, event=None, *args): row = self.row() if row: self.channel().play(row) [callback(row) for callback in self.hooks["play"]] - - # streamripper + # Recording: invoke streamripper for current stream URL def on_record_clicked(self, widget): row = self.row() action.record(row.get("url"), row.get("format", "audio/mpeg"), "url/direct", row=row) - - # browse stream + # Open stream homepage in web browser def on_homepage_stream_clicked(self, widget): url = self.selected("homepage") action.browser(url) - - # browse channel + # Browse to channel homepage (double click on notebook tab) def on_homepage_channel_clicked(self, widget, event=2): if event == 2 or event.type == gtk.gdk._2BUTTON_PRESS: __print__(dbg.UI, "dblclick") action.browser(self.channel().homepage) - - # reload stream list in current channel-category + # Reload stream list in current channel-category def on_reload_clicked(self, widget=None, reload=1): __print__(dbg.UI, "reload", reload, self.current_channel, self.channels[self.current_channel], self.channel().current) category = self.channel().current self.thread( lambda: ( self.channel().load(category,reload), reload and self.bookmarks.heuristic_update(self.current_channel,category) ) ) - - # thread a function, add to worker pool (for utilizing stop button) + # Thread a function, add to worker pool (for utilizing stop button) def thread(self, target, *args): thread = Thread(target=target, args=args) thread.start() self.working.append(thread) - - # stop reload/update threads + # Stop reload/update threads def on_stop_clicked(self, widget): while self.working: thread = self.working.pop() thread.stop() - - # click in category list + # Click in category list def on_category_clicked(self, widget, event, *more): category = self.channel().currentcat() __print__(dbg.UI, "on_category_clicked", category, self.current_channel) self.on_reload_clicked(None, reload=0) pass - - # add current selection to bookmark store + # Add current selection to bookmark store def bookmark(self, widget): self.bookmarks.add(self.row()) # code to update current list (set icon just in on-screen liststore, it would be updated with next display() anyhow - and there's no need to invalidate the ls cache, because that's referenced by model anyhow) try: (model,iter) = self.model_iter() @@ -378,48 +362,46 @@ except: pass # refresh bookmarks tab self.bookmarks.load(self.bookmarks.default) - - # reload category tree + # Reload category tree def update_categories(self, widget): Thread(target=self.channel().reload_categories).start() - - # menu invocation: refresh favicons for all stations in current streams category + # Menu invocation: refresh favicons for all stations in current streams category def update_favicons(self, widget): entries = self.channel().stations() favicon.download_all(entries) - - # save a file + # Save stream to file (.m3u) def save_as(self, widget): row = self.row() default_fn = row["title"] + ".m3u" fn = mygtk.save_file("Save Stream", None, default_fn, [(".m3u","*m3u"),(".pls","*pls"),(".xspf","*xspf"),(".smil","*smil"),(".asx","*asx"),("all files","*")]) if fn: action.save(row, fn) pass - - # save current stream URL into clipboard + # Save current stream URL into clipboard def menu_copy(self, w): gtk.clipboard_get().set_text(self.selected("url")) - - # remove an entry + # Remove a stream entry def delete_entry(self, w): n = self.rowno() del self.channel().stations()[ n ] self.channel().switch() self.channel().save() - - # stream right click + # Richt clicking a stream opens an action content menu def station_context_menu(self, treeview, event): return station_context_menu(treeview, event) # wrapper to the static function + + # Alternative Notebook channel tabs between TOP and LEFT position + def switch_notebook_tabs_position(self, w, pos): + self.notebook_channels.set_tab_pos(pos);