Gtkdialog - Dynamic tabs


I have earlier explained how I've extended gtkdialog to get 'new' widgets.
  • Knob
  • Right-click menu

  • This post will explain my setup to get dynamic tabs like you see in eg firefox and geany. As usual it includes a mix of gtkdialog code, svg and gtk theming.


    The challenge:
  • Gtkdialog does not allow to include code while running, so all code (tabs) has to be loaded at startup.
  • Using the <notebook> widget would work somehow if it could hide/show tabs. - it can't.
  • Using <togglebuttons> or <radiobuttons> are other option, but the input signal to these are 'true/false', not the name of the button, so this would be static - not our wish.
  • The example also uses rotated labels, which the mentioned widgets above can't do. Only the <text> widget can do that.
  • Another approach could be to use a svg image as the tab, but my experience is that svg requires height/width values, and that is hard to calculate since fonts differs a lot. The tabs name are editable and should support NLS, so width will change. We have to deal with this. We could include a specific font and font-size used for our app/tabs, but it would give some bloat and does not follow the global gtk-theme nor the global font-size.


  • The solution:
    My solution is built around the <eventbox> widget that holds the actions, while the <text> widget holds the label. A svg image marks the active tab, and a tiny gtk-theme helps us to highlight the tab when hovering. See it in use in pMusic 5.3.1 (or newer).




    The gtkdialog-code for one tab looks like this:
    <vbox spacing="0" visible="true" space-expand="false" space-fill="false">
    
    <hbox height-request="1" space-expand="true" space-fill="true">
    <hseparator height-request="1" width-request="12" space-expand="false" space-fill="false"></hseparator>
    <text space-expand="true" space-fill="true"><label>""</label></text>
    </hbox>
    <eventbox name="tab" space-expand="true" space-fill="true">
    <hbox>
    <vbox>
    <pixmap>
    <variable>PIX_TAB_1</variable>
    <width>20</width>
    <input file>/tmp/tab_1_icon.svg</input>
    </pixmap>
    </vbox>
    <text name="playqueue_tab" xalign="0" angle="270" wrap="false" space-expand="true" space-fill="true">
    <variable>TXT_TAB_1</variable>
    <input>cat /tmp/tab_1_NAME | sed -e "s%^%\n %" -e "s%$% %"</input>
    </text>
    </hbox>
    <action signal="enter-notify-event">disable:TXT_TAB_1</action>
    <action signal="leave-notify-event">enable:TXT_TAB_1</action>
    <action signal="button-press-event">if [[ $PTR_BTN -eq 3 ]]; then menu_tabs 1; else gxmessage "My actions"; fi</action>
    <action signal="button-release-event">activate:REFRESH_LIST</action>
    <action condition="command_is_true([[ $PTR_BTN -eq 3 ]] && echo true)" signal="button-release-event">activate:REFRESH_TABS</action>'
    </eventbox>
    <variable>VBOX_TAB_1</variable>
    </vbox>


    Hovering a tab activates signal="enter-notify-event" and disables the <text> widget in the tab. It might feels wrong to disable a widget we want to highlight, but this is one of the two methods I know to get a hovering effect on <text> widgets. (The other is to underline the text.) When the text get disabled, it receives the fg[INSENSITEVE] signal from the gtk-theme. If we override the theming, disabled widgets can look crisp. The class in the gtk-theme corresponds to <text name="tab" in the gtkdialog-code above.
    style "Tab"
    
    {
    fg[INSENSITIVE] = "#00CA10"
    }
    widget "*tab" style "Tab"


    Clicking on a tab executes its actions. Mouse left click shows the svg marker for this tab. All other tabs get a blank svg instead of the marker. A right click calls the function menu_tabs to show the menu. Here you can delete a tab, which is nothing else but hiding it. But since gtkdialog can't embed new code, we have to carefully keep this hidden tab for a next time. Therefor, I rebuild the tabs so the hidden ones always are at the end of the line - ready for next 'Add'.


    Posted on 11 Dec 2016, 19:48 by zigbert - Categories: Development
    Comments - Edit - Delete


    Slacko 700 Beta


    Slacko 700 is now in beta testing!

    It has been a bit over a month since slacko 700 alpha was first released and in that time we have squashed many bugs and have brought in may improvements.

    To get a copy just visit the puppy forum and grab either the Slacko 6.9.6.4 or Slacko64 6.9.6.4 iso image and burn it to a CD/DVD or copy it to a flash drive.

    Below is a preview of the default theme.



    Have fun testing and report any issues to the link above to the Puppy forum.

    Posted on 9 Oct 2016, 12:56 by 01micko - Categories: Development
    Comments - Edit - Delete


    AlbumArt in pMusic


    Albumart for playing track
    pMusic shows albumart in the main window if available. With the default frontend 'Manager' it is located at bottom-left corner. A larger view of the same image is found in the Trackinfo window. Click on it to see it in full size.




    The priority is:
  • 1. Look for embedded image in the audio-file.
  • 2. Look for image in the same directory as the audio-file.
    The image file should be named with 'front, albumart, album_art, cover or folder'.
  • 3. Look for image downloaded by pMusic previously.
    If set up to do so, pMusic will download the image file when albumart find one on the internet. More about this below.
  • 4. Grab image from URL defined in the database (DB).
    If pMusic previously found a matching albumart, but user has not set up pMusic to download it, the URL is stored in the DB for later use.
  • 5. Search on the internet for matching albumart.
    If no albumart exists embedded, locally or via URL, pMusic searches the internet for a matching albumart. This search depends on meta-tags for Artist and Album.





  • With these tags in place it searches www.albumart.org, www.seekacover.com and www.slothradio.com (in this priority order).
    Very recently, www.albumart.org went down, so you should update to pMusic 5.2.1 to include these multiple search-sites. All these sites uses www.amazon.com as their image source. In the future it would be great if we additionally could use google's image-search as well.

    If pMusic finds a matching albumart on the web, it will store the URL in the DB, to find it quicker next time. If activated, the image-file can be automatically downloaded to your harddrive when found. Since this will require some space, it is not set to be the default choice. Activate this feature in the Preferences.




    Search albumart
    If you let pMusic download albumart, you will after a while have a nice collection of images. So what do we do with these. They will of course show the playing albumart quicker, but more important; you can search within these and get a visual album search. The albumart search is activated in the search dock.




    When scaling the main window you will see that the albumarts won't scale to fit. Choose 'Update sizing' in the right-click menu. Here you can also choose size of the thumbs.


    Save albumart
    Save albumart means 2 different things.
    1. Save the found albumart to a local file
    2. Embed the albumart into the audio-file

    Both operations are done in the trackinfo window. Be aware that the masstagger allows you to embed one albumart into many files.
    There are corresponding functions for 'Delete albumart' in the Trackinfo window.





    Posted on 4 Oct 2016, 16:14 by zigbert - Categories: Development
    Comments - Edit - Delete


    Slacko 700 Development


    It's an exciting time to be a Puppy Linux user!

    The puppy build system (woof-CE) has been developing at a rapid pace with all new scripts and programs developed for the initial RAM disk (a.k.a initrd.gz) to refine how puppy searches for files and boots. This initiative has been taken up by gyro on the Puppy Linux Discussion Forum with assistance from jlist (a.k.a. wdlkmpx in woof-CE circles) in building new static binary programs that the initrd.gz needs, including busybox and some other utilities.

    I have released the first slacko64 alpha built with these changes and you can help out with testing if you desire by downloading a copy and joining in the discussion at the forum. A 32 bit version will be following soon.

    Have fun testing!

    Posted on 1 Sep 2016, 11:16 by 01micko - Categories: Development
    Comments - Edit - Delete


    Podcasts in pMusic


    pMusic 5.1.3 includes a new way of managing podcasts. There is no code left from the old grabber, and in fact, the new one can hardly be called a grabber at all - since the main idea is to stream podcasts directly from the web, instead of downloading them.


    Find podcast

    pMusic ships with a few podcast channels just as examples. These are of course not the one you like. - We are all unique. So, if interested in podcasts, you should do the one-click install of the index holding around 24 thousand channels. The web-address to every channel has been checked during index-build to be alive. All channels is linked to a category.



    Browse the categories and find your favorite channel. Double-click to check out the available podcasts, and double-click the podcast you like to hear it. - So simple.

    The podcasts you have listened to will be marked. The icon color changes from yellow to green (dot) when start playing. This will stay green also in the future, so you will easily see if there has been released new podcasts since last time. In the image below we see 2 fresh podcasts...



    The image also shows that you can search the huge podcast index. This must be activated in the search dock.


    Add podcast channel

    pMusic separates the podcast channels set up by the user from the indexed channels. This is shown in the image above as My Podcasts. You can of course add a new channel manually (menu->Music sources->Podcast->Setup), but if you find a channel in the index, it is easier to add it directly. Select the channel and click Add channel to My podcasts.




    Set timestamp

    If you start listening to a podcast, but does not have the spare time to hear everything, it would be great to store a timestamp to know where to start next time. This is done in Menu->Playqueue->Add timestamp to favorites. It will then show up in favorites, and double-click will start playing at given position.




    Download

    If you want to keep a podcast, it is of course possible to download it. Every podcast in the playqueue will be downloaded during export. Just remember that the Convert exported tracks option has to stay active.




    Posted on 24 Aug 2016, 19:35 by zigbert - Categories: Development
    Comments - Edit - Delete


    Gtkdialog right-click menu


    gtkdialog does not include support for right-click menu, but like the knob, there has been some workarounds for right-click menus as well. Let's look at one of the existing...

    The main structural solution has been around some years, and includes some basic knowledge of gtkdialog options.
    <window decorated="false" skip_taskbar_hint="true">
    
    <hbox scrollable="true" hscrollbar-policy="2" vscrollbar-policy="2" space-expand="true" space-fill="true">
    <vbox spacing="2">

    menuitem xml-code here

    </vbox>
    </hbox>
    <action signal="focus-out-event">EXIT:exit</action>
    </window>

  • Set decorated to false skips the window manager to draw window borders
  • skip_taskbar_hint avoids this app to show up in the tray/taskbar. After all this menu is a standalone app - but the user shouldn't notice it.
  • The signal focus-out-event exits the gui the focus is leaving the menu.
  • spacing is default 5 and will give a gap between the vertical widgets. To simulate a menu we want the highlight to move straight from one item to the next, so we don't want any spacing and set this to 0.
  • scrollable <hbox> gives us the 3D border. Other types of border can be set by the shadow-type option.
  • hscrollbar-policy avoids scrollbars.

  • This is much like any right-click menu works - so far, so good



    This is the minimal right-click menu in the tray manager (/usr/local/jwm_config/tray).
    The code for each menu-item is a combination of a <pixmap> and a <button> widget.
    <hbox>
    
    <pixmap height-request="18" icon_size="1" space-expand="false" space-fill="false">
    <input file stock="gtk-edit"></input>
    </pixmap>
    <button height-request="18" xalign="0" can-focus="no" relief="2" space-expand="true" space-fill="true">
    <label>"'$(gettext 'Manual edit')'"</label>
    <action>echo edit > /tmp/menu_OUTPUT</action>
    <action>EXIT:exit</action>
    </button>
    </hbox>


    The weaknesses shows up when using the default gtk-theme in Slacko-6.3.2, scaling the font, or using another language string that is longer than the default. This is critical when we move towards touch-screen layouts.



    Since the background color is similar to the 3D border in the menu, the menu 'melts' into the main gui, and we see only half of the border. The menu has a fixed size (defined in pixels), so it won't scale when needed. And why does it has a fixed size? The answer is because this is the way to avoid the menu to grey out parts of the main gui.
    Technical: Reducing the the default size of a button-widget (used in the menu) will grey out the main gui as long as the menu is run as a child of the background gui. We have to run it as a child process to keep the selection viewable in the main gui (see image below).


    The improvement process

    I have tested several solutions, and ended up with the following... for now. But the first thing to do is to define what criteria should be set for an optimal right-click menu?
    It should:
  • scale the gui depending on font size and NLS strings.
  • have a clear border defining its area.
  • show the selection in the main gui.
  • not grey out area in the main gui.
  • allow disabling of specific menu items.
  • highlight menuitem when hovering.
  • support icons.
  • be good looking, and follow the active gtk-theme.
  • allow embedded widgets for more complex menus (see image below).

  • Here follows my attempt for a better solution. Not 100%, but far closer than the previous one.




    The structural code in the first code snippet has not changed, but been extended to show the new border.

    
    
    <window decorated="false" skip_taskbar_hint="true" resizable="false" border-width="0" space-expand="true" space-fill="true">
    <eventbox name="rightclick_menu_frame" above-child="false">
    <vbox border-width="1">
    <eventbox>
    <vbox spacing="0" border-width="7">

    menuitem xml-code here

    </vbox>
    </eventbox>
    </vbox>
    </eventbox>
    <action signal="focus-out-event">EXIT:exit</action>
    </window>


    The <eventbox> widget makes it possible for us to set a unique background color for this widget in the gtk-theme. We do this before executing gtkdialog. The name rightclick_menu_frame corresponds to our style for the extended gtk-theme. Color is set to black (#000), and border width to 1 px. The second <eventbox> is only to draw a new background with the color taken from the global gtk-theme.

    echo 'style "Rightclick_menu" { bg[NORMAL] = "#888" }
    
    style "Rightclick_menu_frame" { bg[NORMAL] = "#000" }
    widget "*rightclick_menu" style "Rightclick_menu"
    widget "*rightclick_menu_frame" style "Rightclick_menu_frame"
    ' > $WORKDIR/gtkrc_menu
    export GTK2_RC_FILES=$WORKDIR/gtkrc_menu:/root/.gtkrc-2.0


    The code for the menu-items differs more from the previous attempt (snippet above). This one does not use the <button> widget as the previous, but the <text> widget. Since the <text> widget does not has any internal spacing as the <button> (between text/icon and the gtk-button), it handles down-scaling perfect, and does not grey out any area in the main gui. Also, the <pixmap> here, does not use the gtk-stock, but a defined file. For some reason, this works better for down-scaling as well. As mentioned above, we downscale the gui to better simulate a menu rather than looking like a 'normal' gui.

    The <text> widget and the <pixmap> widget does not support any <action>, but that is easily solved by putting them inside an <eventbox>, and let that one handle actions. The corresponding code for this new menu-item looks like this.

    <eventbox above-child="true" visible-window="true">
    
    <hbox spacing="7" border-width="3">
    <pixmap space-expand="false" space-fill="false">
    <height>18</height>
    <input file>/usr/share/pixmaps/puppy/remove.svg</input>
    </pixmap>
    <text xalign="0" space-expand="true" space-fill="true">
    <label>"'$(gettext 'Manual edit')'"</label>
    </text>
    </hbox>
    <action signal="enter-notify-event">hide:MENU_1</action>
    <action signal="enter-notify-event">show:MENU_1B</action>
    <variable>MENU_1</variable>
    </eventbox>
    <eventbox name="rightclick_menu" above-child="true" visible-window="true" visible="false">
    <hbox spacing="7" border-width="3">
    <pixmap space-expand="false" space-fill="false">
    <height>18</height>
    <input file>/usr/share/pixmaps/puppy/remove.svg</input>
    </pixmap>
    <text xalign="0" space-expand="true" space-fill="true">
    <label>"'$(gettext 'Manual edit')'"</label>
    </text>
    </hbox>
    <action signal="leave-notify-event">show:MENU_1</action>
    <action signal="leave-notify-event">hide:MENU_1B</action>
    <action signal="button-release-event">echo edit > '$WORKDIR'/tray_menu_OUTPUT</action>
    <action signal="button-release-event">EXIT:exit</action>
    <variable>MENU_1B</variable>
    </eventbox>


    As we see, it's actual 2 set of the same menu-item - one normal, and one highlighted. Switching between them (hide itself / show opponent) when getting the leave-notify-event signal. The highlight color is handled by the extended gtk-theme described above in the style Rightclick_menu. Truly, setting the highlight color to #888, does not follow the global gtk-theme. To do that, you have to grab the foreground color in the active theme. - Not to be described in this blogpost.

    The complete code is seen at github


    Posted on 4 Jul 2016, 08:09 by zigbert - Categories: Development
    Comments - Edit - Delete


    Pages: [1] [2] [3] [4]