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
    Edit - Delete


    No comments posted yet.

    Add Comment

    Title
    Author
     
    Content
    Show Smilies
    Security Code 3981750
    The Puppy Linux mascot?
    Password (to protect your identity)