blogs.czapski.id.au Open in urlscan Pro
203.170.82.73  Public Scan

Submitted URL: http://blogs.czapski.id.au/tag/create-demonstration
Effective URL: https://blogs.czapski.id.au/tag/create-demonstration
Submission: On July 31 via api from US — Scanned from AU

Form analysis 1 forms found in the DOM

GET https://blogs.czapski.id.au/

<form method="get" id="searchform" action="https://blogs.czapski.id.au/">
  <input type="text" value="Search" name="s" id="s" onfocus="if (this.value == 'Search') {this.value = '';}" onblur="if (this.value == '') {this.value = 'Search';}">
  <input class="png_bg" type="submit" id="searchsubmit" value="Go">
</form>

Text Content

BLOGS.CZAPSKI.ID.AU

Articles on gtkdialog and demo image building. Formerly on JavaCAPS and SOA
Suite for healthcare integration.
 * 
 * About


May 21


GTKDIALOG – EXPLORING THE EVENTBOX OBJECT BY EXAMPLE

By Czapski Michael Demo Building, gtkdialog No Comments »

In this article I explore the gtkdialog EventBox object and its uses by example.
EventBox can be used, among other things, to provide background colour to other
objects, intercept and handle events and add frames around gtkdialog objects to
help visualise the space they occupy.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.

The examples in this article demonstrate the following uses of the EventBox:

 1. Providing background colour to HBox / VBox objects
 2. Applying font styles to text within EventBox and its content
 3. Unsing the EventBox to intercept mouse clicks on objects contained inside
    the EventBox
 4. Using the EventBox and styles to add a colour border to a window
 5. Using the EventBox and styles to add a “right-click” menu to an application
 6. Using the EventBox and styles to add visible borders to any/all gtldialog
    components


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad and gtkdialog are installed, as discussed in the
article “Install yad and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


EVENTBOX OBJECT MODEL

gtkdialog, based as it is on the GTK object model, leverages the GTK object
hierarchy. Consider the reference for the EventBox object at
http://01micko.com/reference/eventbox.html.

The very first link points to a GtkEventBox –
https://developer.gnome.org/gtk2/2.24/GtkEventBox.html.

In the GTK object hierarchy,
https://developer.gnome.org/gtk2/2.24/GtkEventBox.html#GtkEventBox.object-hierarchy,
the EventBox object is some levels below the GObject, the topmost object.



The GtkEventBox, and consequently the gtkdialog EventBox, object inherits from
the objects higher up in the hierarchy. This will come into play when we explore
attributes that can be set for an EventBox, and actions that can be configured
for an EventBox.


EVENTBOX ATTRIBUTES

The gtkdialog EventBox object is a container, of a sort, to which styles can be
applied, which can be “shown”/”hidden” and which can be “positioned” in the
object hierarchy in such a way that all of the children which it contains are
“beneath” it, so that the EventBox and not the children receives mouse clicks.

An example of an interface, which uses the EventBox object, and which will be
developed in this article, is shown here.



Reference documentation for the gtkdialog EventBox object,
http://01micko.com/reference/eventbox.html, provides a table of attributes
specific to this gtkdialog object and makes a reference to ancestor class
properties.

Attributes that can be configured for the eventbox widget are defined in the
widget’s reference page see
https://developer.gnome.org/gtk2/2.24/GtkEventBox.html, section Properties –
https://developer.gnome.org/gtk2/2.24/GtkEventBox.html#GtkEventBox.properties

Some of the properties are inherited from the parent objects, like GtkContainer
and GtkWidget. For example, border-width, which defines the amount of space
between the notebook frame and the notebook content, is inherited from the
GtkContainer.

Similarly, sensitive property is inherited from the GtkWidget and when set to
true effectively disables everything inside the eventbox container.

See the reference page:
file:///home/demo/gtkdialog-0.8.3/doc/reference/eventbox.html

To work out what attributes are actually supported, in this case by the eventbox
widget, we need to do some exploration. Discussion below goes into this to an
extent and I provided most of the useful attributes that can be set, both from
GtkWindow itself and inherited from GtkContainer and GtkWidget. The “Works?”
column indicates whether the attribute has a visible effect (Y), does not have a
visible effect (N) or I have not figured out a way to test whether it works or
not.

The table below summarised EventBox attributes/properties and indicates which
work with the gtkdialog and which do not as far as I can tell. “Do not” may well
be a function of me not seeing any visible difference with the property set to
different values. Some ancestor attributes/properties which are not really
useable from gtkdialog are omitted.

Name Description Value Default Works? In EventBox space-expand Pack widget
expanding into space true or false Y gtkdialog space-fill Pack widget filling
space true or false Y gtkdialog block-function-signals Block signal emissions
from functions true or false gtkdialog Inherited from GtkEventBox above-child
Whether the event-trapping window of the eventbox is above the window of the
child widget as opposed to below it. If true no clicks will be delivered to the
objects underneath the eventbox. true or false false Y GtkEventBox
visible-window Whether the event box is visible, as opposed to invisible and
only used to trap events. true or false false Y GtkEventBox Inherited from
gtkContainer border-width The width of the empty border outside the containers
children <=65535 0 Y can-default Whether the widget can be the default widget.



This does not seem to have any effect when applied to a Window object

true or false false Maybe



Makes no sense for this

GtkWidget can-focus Whether the widget can accept the input focus.



This does not seem to have any effect when applied to a Window object

true or false false Maybe



Makes no sense for this

GtkWidget has-default Whether the widget is the default widget.



This does not seem to have any effect when applied to a Window object

true or false false Maybe



Makes no sense for this

GtkWidget has-focus Whether the widget has the input focus.



This does not seem to have any effect when applied to a Window object

true or false false Maybe



Makes no sense for this

GtkWidget has-tooltip Whether this widget has a tooltip.



Disables tooltip display if tooltip is defined for the Window

true or false false Y GtkWidget height-request Override for height request of
the widget, or -1 if natural height should be used.



Has not effect of default-height is specified.

>=0 -1 Y GtkWidget is-focus Whether the widget is the focus widget within the
toplevel.



Does not seem to have any effect when applied to the Window object

true or false false Maybe



Makes no sense for this

GtkWidget name The name of the widget.



It can be used to address styling directves to a named object

string NULL GtkWidget receives-default If TRUE, the widget will receive the
default action when it is focused.



I don’t know what that is supposed to accomplish. Nothing visible happens
regardless of the property value.

true or false false Maybe



Makes no sense for this

GtkWidget sensitive Whether the widget responds to input.



FALSE disables all components contained in the eventbox.

true or false TRUE Y GtkWidget tooltip-markup The contents of the tooltip for
this widget.



Simple markup can be used to call out parts of tooltip text in.

See http://www.murga-linux.com/puppy/viewtopic.php?t=40418 for a markup explorer
tool.

Ineffective if tooltip-disabled is TRUE.

string NULL Y GtkWidget tooltip-text The contents of the tooltip for this
widget.



Ineffective if tooltip-disabled is TRUE.

string NULL Y GtkWidget visible Whether the widget is visible.



It is somewhat self-defeating to make a window invisible on creation unless it
is a “subsidiary” window and can be made visible form some other piece of logic.

true or false true Y GtkWidget width-request Override for width request of the
widget, or -1 if natural width should be used.



Has not effect if default-width is specified or if an outer container has a
width-request set.

>=0 -1 Y GtkWidget

The following example includes just about every attrivute which can be set for
the EventBox. We will explore what the various attribute settings do below.

First, let’s create an enumerations script which will supply human-readable
versions of enumerations and other numeric constants that may be used in the
scripts I show. See https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h, and
elsewhere, for sources of these enumerations.

If you have this enumerations source because you worked through the Notebook
example than you don’t need to re-create it. No new constants have been added.

mkdir -pv /tmp/scripts
cd /tmp/scripts
cat <<-'EOSOURCE' > gtkdialog.constants
# gtkdialog.constants
#
cstVersion=1.0.0
echo "Loading ${BASH_SOURCE[0]} version ${cstVersion} ..." 1>&2

# I prefer symbolic constants to numeric literals so I defined a bunch
# see https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h for specifics
#
BTN_IMG_POS_LEFT=0
BTN_IMG_POS_RIGHT=1
BTN_IMG_POS_ABOVE=2
BTN_IMG_POS_BELOW=3
WIN_ICON=access
WIN_DECORATED=true
WIN_RESIZABLE=true
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
WIN_POS=${GTK_WIN_POS_CENTER}
WIN_SKIP_TASKBAR_HINT=false
WIN_ALLOW_GROW=true
XALIGN_LEFT=0
XALIGN_RIGHT=1
XALIGN_CENTRE=0.5
YALIGN_TOP=0
YALIGN_BOTTOM=1
YALIGN_CENTRE=0.5
VSCROLLBAR_ALWAYS=0
VSCROLLBAR_AUTOMATIC=1
VSCROLLBAR_NEVER=2
HSCROLLBAR_ALWAYS=0
HSCROLLBAR_AUTOMATIC=1
HSCROLLBAR_NEVER=2
GTK_JUSTIFY_LEFT=0
GTK_JUSTIFY_RIGHT=1
GTK_JUSTIFY_CENTRE=2
TREE_SELECTION_MODE_NONE=0
TREE_SELECTION_MODE_SINGLE=1
TREE_SELECTION_MODE_BROWSE=2
TREE_SELECTION_MODE_MULTIPLE=3
TAB_POS_LEFT=0
TAB_POS_RIGHT=1
TAB_POS_ABOVE=2
TAB_POS_BELOW=3

EOSOURCE

above-child and visible-window attributes

In this section we will explore how the above-child and visible-window
attributes of the eventbox, combined with appropriate styles, affect the
appearance and function of the eventbox and its contents.

To create and exercise the first example execute the following commands, noting
that you will need to copy and paste the code into an editor window because it
is too large for a “here document”.

mkdir /tmp/scripts
cd /tmp/scripts
> /tmp/scripts/ex34.sh
chmod ug+x /tmp/scripts/ex34.sh

geany /tmp/scripts/ex34.sh & # until ## EOSCRIPT
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# window title
WIN_TITLE="EventBox Example"

# Size of the notebook and all content panels
#
_WIDTH_REQUEST=400
export _DATE_FORMAT_RFC3339_NS="--rfc-3339=ns"
export _DATE_FORMAT_TIMESTAMP="+%Y%m%d-%H%M%S.%N%z"

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox width-request="${_WIDTH_REQUEST}">

        <hbox>
            <hbox homogenous="true" space-fill="true" space-expand="true">
                <text><label>Some content goes here</label></text>
            </hbox>
        </hbox>

        $(: visible-window="false" blocks delivery of clicks to the content objects, including inner eventbox objects )
        $(: but it does not prevent keystrokes from selecting buttons and pressing on them, for example )
        <eventbox above-child="false" visible-window="true">
            <frame  Outer Frame  >
                <hbox>
                    <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
                      can-default="true" xx-info="has-default must have can-default"
                      has-default="true" xx-info="has-default and can-default must both be true for default to work"
                      >
                        <label> _Refresh </label>
                        <input file icon="system-config-date"></input>
                        <width>16</width>
                        <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_RFC3339_NS}' )">refresh:vDateFormatToggle</action>
                        <action function="refresh">vWindow</action>
                    </button>
                    <text xpad="1"><label>""</label></text>
                </hbox>

                $(: both above-child and visible-window have to be true for the event box to "block" clicks to the content )
                $(: both above-child and visible-window have to be true for the event box background colour to be seen )
                <eventbox above-child="false" visible-window="true" has-tooltip="true" tooltip-markup="This is <b>tooltip</b> for eventbox"
                          height-request="100" sensitive="true" visible="true" width-request="600">
                    <frame  Inner Frame  >
                        <hbox>
                            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true">
                                <label> _Update </label>
                                <input file icon="system-config-date"></input>
                                <width>16</width>
                                <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_TIMESTAMP}')">refresh:vDateFormatToggle</action>
                                <action function="refresh">vWindow</action>
                            </button>
                        </hbox>
                    </frame> $(: inner frame)
                   
                    <variable>vEventBoxOuter</variable>
                </eventbox>

            </frame> $(: outer frame)

            <variable>vEventBoxOuter</variable>
        </eventbox>

        <hbox>
            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
              can-default="true" has-default="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
            <text xpad="5"><label>""</label></text>
        </hbox>

        <entry visible="false">
            <default>false</default>
            <variable>vDateFormatToggle</variable>
            <input>fnDateFormatToggle</input>
        </entry>

    </vbox>


    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
    <variable>vWindow</variable>
    <input>fnShowTimestamp </input>
</window>
EODECK

#== Styles ==========================================
export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "outerFrameStyle" {
    bg[NORMAL]      = "slateblue"
    fg[NORMAL]      = "white"
    font_name="URW Gothic L Book 14"
}
style "innerFrameStyle" {
    bg[NORMAL]      = "white"
    fg[NORMAL]      = "navy"
    font_name="URW Gothic L Demi Oblique 10"
}

widget_class "<GtkWindow><GtkVBox><GtkEventBox>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkLabel>" style "outerFrameStyle"
# below will not show background of the eventbox if eventbox attribute visible="false"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame><GtkLabel>" style "innerFrameStyle"
EOSTYLEDEF

## -- post UI construction ---------------------
# fnDateFormatToggleNeeded '--rfc-3339=ns' or '-R'
fnDateFormatToggleNeeded() {
    local vWhatFormat="${1}"
    [[ "${vDateFormatToggle}" == "${vWhatFormat}" ]] && echo "false" || echo "true"
}
export -f fnDateFormatToggleNeeded

# fnDateFormatToggle
fnDateFormatToggle() {
    [[ "${vDateFormatToggle}" == "${_DATE_FORMAT_RFC3339_NS}" ]] && echo "${_DATE_FORMAT_TIMESTAMP}" || echo "${_DATE_FORMAT_RFC3339_NS}"
}
export -f fnDateFormatToggle

# fnShowTimestamp
fnShowTimestamp() {
    date ${vDateFormatToggle}
}
export -f fnShowTimestamp

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac

## EOSCRIPT

/tmp/scripts/ex34.sh

Executing this example unmodified produces the window which looks like that
shown earlier – reproduced for completeness:



Because some of the attributes of the EventBox, such as the above-child and the
visible-window do not produce visual effects but affect the behaviour of the
application it will be necessary to describe the outcome rather than simply show
a screenshot of it.

Click the Refresh and the Update buttons to see the window title change in
accordance with the date formatting logic triggered by each. Note that the title
window changes to display a timestamp and that the format of the timestamp
changes depending on which of the two buttons is clicked.

Now change the value of the attribute above-child to “true” and click the two
buttons as before. The code fragment here after this change is made is
reproduced below:

<eventbox above-child="true" visible-window="true" has-tooltip="true"
           tooltip-markup="This is <b>tooltip</b> for eventbox"
           height-request="100" sensitive="true" visible="true" width-request="600">
                    <frame  Inner Frame  >
                        <hbox>

Note that clicking on the “Update” button produces no effect. The
above-child=”true” places all elements contained inside the eventbox “beneath”
it so that it is the EventBox object that receives mouse clicks. If the event
box had a signal handler attached to it, as it does not in this case, this event
handler would intercept the clicks. Since there is no handler the clicks are
simply ignored. Note however that if you use the Tab key to “tab to” the
“Update” button, and it is selected, then pressing the Enter key will cause the
action associated with this button to be executed event when the above-child is
set to true.

Now change the above-child back to false and visible-window to true, as shown in
the code fragment below, then run the example.

<eventbox above-child="false" visible-window="false"
          has-tooltip="true" tooltip-markup="This is <b>tooltip</b> for eventbox"
          height-request="100" sensitive="true" visible="true" width-request="600">

Note that the appearance of the window has changed:



Because the inner EventBox’s visible-window property is set to false the visual
effects of the EventBox are not there – the background of the EventBox, which
was white when the visible-window property was true is no longer white. The area
of the inner EventBox takes on the appearance of the outer EventBox with its
background colour of slateblue. But, the inner eventbox still intercepts the
clicks made inside its borders even though the above-child is set to false –
click on the Update button and see.

Now set the outer eventbox visible-window attribute to false and see the effect
on the background colour and on the clickability of the Refresh button and run
the example – the Refresh button is no longer clickable and the entire area of
the outer EventBox, with its contained inner EventBox, has the default window
colour.

Now set the inner eventbox visible-window attribute to true and run the example.
The background colour of the inner EventBox is white but the Update button is
still not clickable even though both eventboxes have the above-child attribute
set to false.

This behaviour is, to me at least, counterintuitive but that’s what it is. Go
figure.


USING EVENTBOX TO CREATE A FRAMED “HELP WINDOW”

A handy trick, which nested eventbox elements afford, is the ability to create a
coloured “frame” around arbitrary content. The example below takes advantage of
this trick to create a framed “help window”.

The screenshot below shows what is meant:



The window with the red border and the white background is shown when the Help
button is clicked. Clicking on it or anywhere else other than on the Help button
makes this window disappear.

The red border and the white background to the content inside are accomplished
with the aid of the nested eventbox objects.

Execute the following commands, including copying and pasting the body of the
example between geany and EOSCRIPT.

Note the sections highlighted in bold. These are the major adifferences between
this example and the previous example.

mkdir /tmp/scripts
cd /tmp/scripts
> /tmp/scripts/ex35.sh
chmod ug+x /tmp/scripts/ex35.sh

geany /tmp/scripts/ex35.sh & # until ## EOSCRIPT
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"
export HELP_DIALOG_FILE="${LOCAL_DATA_DIR}/HELP_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# Size of the notebook and all content panels
#
_WIDTH_REQUEST=400
export _DATE_FORMAT_RFC3339_NS="--rfc-3339=ns"
export _DATE_FORMAT_TIMESTAMP="+%Y%m%d-%H%M%S.%N%z"

# construct UI
## Help UI
##
# window title
WIN_TITLE="Help on Event Box Example"

## =========================================================
## construct help panel
##
cat > ${HELP_DIALOG_FILE} <<-EODECK
<window 
    decorated="false" 
    skip_taskbar_hint="true"
    window_position="${GTK_WIN_POS_CENTER}"
> 
    <eventbox xwidth-request="200" name="outer_colour" above-child="false" visible-window="true" visible="true">
        <vbox border-width="3">
            <eventbox name="inner_colour" above-child="false" visible-window="true" visible="true">
                <text xpad="6" ypad="6" xalign="${XALIGN_LEFT}" justify="${GTK_JUSTIFY_LEFT}" selectable="false" use-markup="true">
                    <label>
"<span size='large'><b>${WIN_TITLE}</b></span>

This text goes into the help popup. This text goes into the help popup. This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.

<span size='x-small'>Enjoy.</span>"
                    </label>
                </text>
            </eventbox>
        </vbox>
    </eventbox>

    <variable>HELP_DIALOG</variable>
    <action signal="button-press-event" condition="command_is_true( [[ \$PTR_BTN == 1 ]] && echo true )">closewindow:HELP_DIALOG</action> 
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">closewindow:HELP_DIALOG</action> 
    <action signal="focus-out-event">closewindow:HELP_DIALOG</action>
</window>
EODECK
export HELP_DIALOG=$(cat ${HELP_DIALOG_FILE})

## main UI
##
# window title
WIN_TITLE="EventBox Example"

cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox width-request="${_WIDTH_REQUEST}">

        <hbox>
            <hbox homogenous="true" space-fill="true" space-expand="true">
                <text><label>Some content goes here</label></text>
            </hbox>
        </hbox>

        $(: visible-window="false" blocks delivery of clicks to the content objects, including inner eventbox objects )
        $(: but it does not prevent keystrokes from selecting buttons and pressing on them, for example )
        <eventbox above-child="false" visible-window="true">
            <frame  Outer Frame  >
                <hbox>
                    <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
                      can-default="true" xx-info="has-default must have can-default"
                      has-default="true" xx-info="has-default and can-default must both be true for default to work"
                      >
                        <label> _Refresh </label>
                        <input file icon="system-config-date"></input>
                        <width>16</width>
                        <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_RFC3339_NS}' )">refresh:vDateFormatToggle</action>
                        <action function="refresh">vWindow</action>
                    </button>
                    <text xpad="1"><label>""</label></text>
                </hbox>

                $(: both above-child and visible-window have to be true for the event box to "block" clicks to the content )
                $(: both above-child and visible-window have to be true for the event box background colour to be seen )
                <eventbox above-child="false" visible-window="true" has-tooltip="true" tooltip-markup="This is <b>tooltip</b> for eventbox"
                          height-request="100" sensitive="true" visible="true" width-request="600">
                    <frame  Inner Frame  >
                        <hbox>
                            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true">
                                <label> _Update </label>
                                <input file icon="system-config-date"></input>
                                <width>16</width>
                                <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_TIMESTAMP}')">refresh:vDateFormatToggle</action>
                                <action function="refresh">vWindow</action>
                            </button>
                        </hbox>

                    </frame> $(: inner frame)
                 
                    <variable>vEventBoxOuter</variable>
                </eventbox>

            </frame> $(: outer frame)

            <variable>vEventBoxOuter</variable>
        </eventbox>

        <hbox>
            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true">
                <label> _Help </label>
                <input file icon="gtk-help"></input>
                <width>16</width>
                <action>launch:HELP_DIALOG</action>
            </button>

            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
              can-default="true" has-default="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
            <text xpad="5"><label>""</label></text>
        </hbox>

        $(: 'invisible entry box for persisting the state of date format togge')
        <entry visible="false">
            <default>false</default>
            <variable>vDateFormatToggle</variable>
            <input>fnDateFormatToggle</input>
        </entry>

    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
    <variable>vWindow</variable>
    <input>fnShowTimestamp </input>
</window>
EODECK

#== Styles ==========================================
export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "outerFrameStyle" {
    bg[NORMAL]      = "slateblue"
    fg[NORMAL]      = "white"
    font_name="URW Gothic L Book 14"
}
style "innerFrameStyle" {
    bg[NORMAL]      = "white"
    fg[NORMAL]      = "navy"
    font_name="URW Gothic L Demi Oblique 10"
}

widget_class "<GtkWindow><GtkVBox><GtkEventBox>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkLabel>" style "outerFrameStyle"
# below will not show background of the eventbox if eventbox attribute visible="false"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame><GtkLabel>" style "innerFrameStyle"

style "outer_colour" { bg[NORMAL] = "#ff0000" }
widget "*outer_colour" style "outer_colour"
style "inner_colour" { bg[NORMAL] = "#ffffff" }
widget "*inner_colour" style "inner_colour"

EOSTYLEDEF

## -- post UI construction ---------------------
# fnDateFormatToggleNeeded '--rfc-3339=ns' or '-R'
fnDateFormatToggleNeeded() {
    local vWhatFormat="${1}"
    [[ "${vDateFormatToggle}" == "${vWhatFormat}" ]] && echo "false" || echo "true"
}
export -f fnDateFormatToggleNeeded

# fnDateFormatToggle
fnDateFormatToggle() {
    [[ "${vDateFormatToggle}" == "${_DATE_FORMAT_RFC3339_NS}" ]] && echo "${_DATE_FORMAT_TIMESTAMP}" || echo "${_DATE_FORMAT_RFC3339_NS}"
}
export -f fnDateFormatToggle

# fnShowTimestamp
fnShowTimestamp() {
    date ${vDateFormatToggle}
}
export -f fnShowTimestamp

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;

esac

##EOSCRIPT

 

/tmp/scripts/ex35.sh

There are a number of objects and patterns, apart from the eventbox, which this
example introduces. They will not be discussed here. Of passing note are the use
of the <eventbox><vbox><eventbox> construct to create the red border around the
inner eventbox and its content, the escape key and focus-out-event handlers and
the launch:HELP_WINDOW in the main window’s Help button, and
closewindow:HELP_WINDOW in the help window itself.

Run the example and click the Help button. The application will launch the help
window and make it disappear when the the escape key is pressed or when the
mouse is clicked anywhere outside the boundaries of the Help button.


USING EVENTBOX TO CREATE A POPUP MENU

In this example we expand the use of the nested evenboxes to create a
right-click popup menu.

The screenshot below shows what is meant:



The window with the red border and the white background, and the two checkboxes,
is shown when the right mouse button is clicked. Setting and unsetting
checkboxes is done as expected – click the checkbox or its label, use the
keyboard to alternate between selecting one or the other checkbox, press enter
or space to change the state of the selected checkbox. Clicking anywhere else
outside the boundaries of the menu makes this menu disappear.

The menu and menu handling in this example was inspired by the example at
http://blog.puppylinux.com/?viewDetailed=00030.

The red border and the white background to the content inside are accomplished
with the aid of the nested eventbox objects. Checkboxes and their handling are
the same regardless of what sor of window they are in.

In this example the state of the checkboxes must be persisted when the menu is
closed. Since gtkdialog does not have the mechanism to have a signal handler
directly programmatically set the value of a variable (push model) two
functionas are introduced to set and get the value of the checkbox using a file
in the file system for persistence. This was inspired by one of the gtkdialog
examples and may be explored in another article. For now it should suffice to
say that checking and unchecking one of the checkboxes casues the value of the
checkbox (true/false, checked/unchecked) to be written to a corresponding file
and the state of he checkboxes is read form these files whenever the popup menu
is shown. The values of the checkboxes are read in the Refresh and Update button
handler to control its logic.

Execute the following commands, including copying and pasting the body of the
example between geany and EOSCRIPT.

Note the sections highlighted in bold. These are the major adifferences between
this example and the previous example.

mkdir /tmp/scripts
cd /tmp/scripts
> /tmp/scripts/ex36.sh
chmod ug+x /tmp/scripts/ex36.sh

geany /tmp/scripts/ex36.sh & # until ## EOSCRIPT
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR} 
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"
export HELP_DIALOG_FILE="${LOCAL_DATA_DIR}/HELP_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"
export RCLK_DIALOG_FILE="${LOCAL_DATA_DIR}/RCLK_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# Size of the notebook and all content panels
#
_WIDTH_REQUEST=400
export _DATE_FORMAT_RFC3339_NS="--rfc-3339=ns"
export _DATE_FORMAT_TIMESTAMP="+%Y%m%d-%H%M%S.%N%z"

##### construct UI #############################
## pre-ui ccreate functions
# show right-click menu on right mouse button press in main window
#
fnAddRightClickActionsInline() {
echo "<action signal=\"button-press-event\" condition=\"command_is_true( [[ \$PTR_BTN == 3 ]] && echo true )\">\
launch:RIGHT_CLICK_DIALOG\
</action>"
}

:<<'NONFUNCTIONAL--------------------------------------------------------'
    fnUtlVarGet
    -----------
    Get a variable [maintained as a file] from the local data directory.
    On entry: $1 = name
    On exit: echoes value
NONFUNCTIONAL--------------------------------------------------------
fnUtlVarGet() {
    [[ ! -e $LOCAL_DATA_DIR/$1 ]] && touch $LOCAL_DATA_DIR/$1
    local input
    read -r input < $LOCAL_DATA_DIR/$1
    echo -n "$input"
}
export -f fnUtlVarGet
 
:<<'NONFUNCTIONAL--------------------------------------------------------'
    fnUtlVarSet
    -----------
    Set a variable [maintained as a file] within the local data directory.
    On entry: $1 = name
              $2 = value
NONFUNCTIONAL--------------------------------------------------------
fnUtlVarSet() {
    [[ ! -e $LOCAL_DATA_DIR/$1 ]] && touch $LOCAL_DATA_DIR/$1
    echo "$2" > $LOCAL_DATA_DIR/$1
}
export -f fnUtlVarSet
## right-click settings UI
##
 
## =========================================================
## construct right-click menu
##

fnUtlVarSet 'cbkShowRequest' "false"   # init right-click menu checkboxes to unset
fnUtlVarSet 'cbkShowResponse' "false"  # init right-click menu checkboxes to unset

cat > ${RCLK_DIALOG_FILE} <<-EODECK
<window 
    decorated="false" 
    skip_taskbar_hint="true"
    window_position="${GTK_WIN_POS_MOUSE}"
> 

$(:<<'COMMENT--------------------------------------------------'
This stuff was inspired by Gtkdialog right-click menu - http://blog.puppylinux.com/?viewDetailed=00030

COMMENT--------------------------------------------------
)
    <eventbox xwidth-request="200" name="outer_colour" above-child="false" visible-window="true" visible="true">
        <vbox border-width="3">
            <eventbox name="inner_colour" above-child="false" visible-window="true" visible="true">
                <vbox border-width="10">
                    <vbox>
                        <checkbox tooltip-text="Selecting this option will display the Requests which will govern date format" label="Show Date Format Request?" xalign="${XALIGN_LEFT}">
                            <variable>cbkShowRequest</variable>
                            <action condition="active_is_true(cbkShowRequest)">fnUtlVarSet 'cbkShowRequest' 'true'</action>
                            <action condition="active_is_false(cbkShowRequest)">fnUtlVarSet 'cbkShowRequest' 'false'</action>
                            <input>fnUtlVarGet 'cbkShowRequest'</input>
                        </checkbox>
                    </vbox>
                    <vbox>
                        <checkbox tooltip-text="Selecting this option will display the formatted date" label="Show Formatted Date?" xalign="${XALIGN_LEFT}">
                            <variable>cbkShowResponse</variable>
                            <action condition="active_is_true(cbkShowResponse)">fnUtlVarSet 'cbkShowResponse' 'true'</action>
                            <action condition="active_is_false(cbkShowResponse)">fnUtlVarSet 'cbkShowResponse' 'false'</action>
                            <input>fnUtlVarGet 'cbkShowResponse'</input>
                        </checkbox>
                    </vbox>
                </vbox>
            </eventbox>
        </vbox>
    </eventbox>
 
    <variable>RIGHT_CLICK_DIALOG</variable>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">closewindow:RIGHT_CLICK_DIALOG</action> 
    <action signal="focus-out-event">closewindow:RIGHT_CLICK_DIALOG</action>
 
</window>
EODECK

export RIGHT_CLICK_DIALOG=$(cat ${RCLK_DIALOG_FILE})

## Help UI
##
# window title
WIN_TITLE="Help on Event Box Example"

## =========================================================
## construct help panel
##
cat > ${HELP_DIALOG_FILE} <<-EODECK
<window 
 decorated="false" 
 skip_taskbar_hint="true"
 window_position="${GTK_WIN_POS_CENTER}"
> 
 <eventbox xwidth-request="200" name="outer_colour" above-child="false" visible-window="true" visible="true">
 <vbox border-width="3">
 <eventbox name="inner_colour" above-child="false" visible-window="true" visible="true">
 <text xpad="6" ypad="6" xalign="${XALIGN_LEFT}" justify="${GTK_JUSTIFY_LEFT}" selectable="false" use-markup="true">
 <label>
"<span size='large'><b>${WIN_TITLE}</b></span>

This text goes into the help popup. This text goes into the help popup. This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.
This text goes into the help popup.

<span size='x-small'>Enjoy.</span>"
 </label>
 </text>
 </eventbox>
 </vbox>
 </eventbox>

 <variable>HELP_DIALOG</variable>
 <action signal="button-press-event" condition="command_is_true( [[ \$PTR_BTN == 1 ]] && echo true )">closewindow:HELP_DIALOG</action> 
 <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">closewindow:HELP_DIALOG</action> 
 <action signal="focus-out-event">closewindow:HELP_DIALOG</action>
</window>
EODECK
export HELP_DIALOG=$(cat ${HELP_DIALOG_FILE})
## main UI
##
# window title
WIN_TITLE="EventBox Example"

cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox width-request="${_WIDTH_REQUEST}">

        <hbox>
            <hbox homogenous="true" space-fill="true" space-expand="true">
                <text><label>Some content goes here</label></text>
            </hbox>
        </hbox>

        $(: visible-window="false" blocks delivery of clicks to the content objects, including inner eventbox objects )
        $(: but it does not prevent keystrokes from selecting buttons and pressing on them, for example )
        <eventbox above-child="false" visible-window="true">
            <frame  Outer Frame  >
                <hbox>
                    <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
                      can-default="true" xx-info="has-default must have can-default"
                      has-default="true" xx-info="has-default and can-default must both be true for default to work"
                      >
                        <label> _Refresh </label>
                        <input file icon="system-config-date"></input>
                        <width>16</width>
                        <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_RFC3339_NS}' )">refresh:vDateFormatToggle</action>
                        <action function="refresh">vWindow</action>
                    </button>
                    <text xpad="1"><label>""</label></text>
                </hbox>

                $(: both above-child and visible-window have to be true for the event box to "block" clicks to the content )
                $(: both above-child and visible-window have to be true for the event box background colour to be seen )
                <eventbox above-child="false" visible-window="true" has-tooltip="true" tooltip-markup="This is <b>tooltip</b> for eventbox"
                          height-request="100" sensitive="true" visible="true" width-request="600">
                    <frame  Inner Frame  >
                        <hbox>
                            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true">
                                <label> _Update </label>
                                <input file icon="system-config-date"></input>
                                <width>16</width>
                                <action condition="command_is_true(fnDateFormatToggleNeeded '${_DATE_FORMAT_TIMESTAMP}')">refresh:vDateFormatToggle</action>
                                <action function="refresh">vWindow</action>
$(fnAddRightClickActionsInline eventbox)
                            </button>
                        </hbox>

                    </frame> $(: inner frame)

                    <variable>vEventBoxOuter</variable>
                </eventbox>
            </frame> $(: outer frame)

            <variable>vEventBoxOuter</variable>
$(fnAddRightClickActionsInline eventbox)
        </eventbox>

        <hbox>
            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true">
                <label> _Help </label>
                <input file icon="gtk-help"></input>
                <width>16</width>
                <action>launch:HELP_DIALOG</action>
            </button>

            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
              can-default="true" has-default="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
            <text xpad="5"><label>""</label></text>
        </hbox>

        $(: 'invisible entry box for persisting the state of date format togge')
        <entry visible="false">
            <default>false</default>
            <variable>vDateFormatToggle</variable>
            <input>fnDateFormatToggle</input>
        </entry>

    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
    <variable>vWindow</variable>
    <input>fnShowTimestamp </input>
</window>
EODECK

#== Styles ==========================================
export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "outerFrameStyle" {
    bg[NORMAL]      = "slateblue"
    fg[NORMAL]      = "white"
    font_name="URW Gothic L Book 14"
}
style "innerFrameStyle" {
    bg[NORMAL]      = "white"
    fg[NORMAL]      = "navy"
    font_name="URW Gothic L Demi Oblique 10"
}

widget_class "<GtkWindow><GtkVBox><GtkEventBox>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame>" style "outerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkLabel>" style "outerFrameStyle"
# below will not show background of the eventbox if eventbox attribute visible="false"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame>" style "innerFrameStyle"
widget_class "<GtkWindow><GtkVBox><GtkEventBox><GtkFrame><GtkContainer><GtkEventBox><GtkFrame><GtkLabel>" style "innerFrameStyle"

style "outer_colour" { bg[NORMAL] = "#ff0000" }
widget "*outer_colour" style "outer_colour"
style "inner_colour" { bg[NORMAL] = "#ffffff" }
widget "*inner_colour" style "inner_colour"

EOSTYLEDEF

## -- post UI construction ---------------------
# fnDateFormatToggleNeeded '--rfc-3339=ns' or '-R'
fnDateFormatToggleNeeded() {
    local vWhatFormat="${1}"
    [[ "${vDateFormatToggle}" == "${vWhatFormat}" ]] && echo "false" || echo "true"
}
export -f fnDateFormatToggleNeeded

# fnDateFormatToggle
fnDateFormatToggle() {
    [[ "${vDateFormatToggle}" == "${_DATE_FORMAT_RFC3339_NS}" ]] && echo "${_DATE_FORMAT_TIMESTAMP}" || echo "${_DATE_FORMAT_RFC3339_NS}"
}
export -f fnDateFormatToggle

# fnShowTimestamp
fnShowTimestamp() {
    [[ "${cbkShowRequest}" = "true" ]] && yad \
        --center --width=400 --image="gtk-dialog-info" --window-icon="gtk-dialog-info" --title="Date format" --text="Requesting date format ${vDateFormatToggle}" \
        --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
    vDate="$(date ${vDateFormatToggle})"
    [[ "${cbkShowResponse}" = "true" ]] && yad \
        --center --width=400 --image="gtk-dialog-info" --window-icon="gtk-dialog-info" --title="Formatted Date" --text="Formatted date: ${vDate}" \
        --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
    echo ${vDate}
}
export -f fnShowTimestamp

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSCRIPT



/tmp/scripts/ex36.sh

The screenshot shown before illustrates the application appearance when the
right-click menu is show. In the screenshot below one of the results of checking
the checkbox is shown, as an illustration of what the button handler does when
the checkboxes is checked.




USING EVENTBOXES TO ADD FRAMES TO OBJECTS

It may be hard to work out what space the various objects in a gtkdialog
application actually occupy on the screen because most, like text labels,
horizontal and vertical boxes, and others, do not have visible bounding boxes
which could be used to gauge that. In this example I demonstrate hos nested
event boxes can be used to add visible borders to all objects and how to quickly
remove them / make them invisible. This use of eventboxes is somewhat off-field
but somebody muight have a use for it, during development if not in an actual
useful applications.

The following screenshot illustrates one of the manifestations of this.



Execute the following commands, including copying and pasting the body of the
example between geany and EOSCRIPT.

mkdir /tmp/scripts
cd /tmp/scripts
> /tmp/scripts/ex37.sh
chmod ug+x /tmp/scripts/ex37.sh

geany /tmp/scripts/ex37.sh & # until ## EOSCRIPT
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR} 
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# local constants
#
_WIDTH_REQUEST=400
_SPACING=0

##### construct UI #############################

## pre-ui create functions
##
#_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">'; }
#endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }
_beginFrame() { echo -n ''; }
endFrame_() { echo -n ''; }

## right-click settings UI
##

## main UI
##
# window title
WIN_TITLE="EventBox Example $(basename $0)"

cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
$(_beginFrame)
    <vbox width-request="${_WIDTH_REQUEST}" spacing="${_SPACING}">
$(_beginFrame)
        <vbox spacing="${_SPACING}">
$(_beginFrame)
            <hbox spacing="${_SPACING}">
$(_beginFrame)
                <hbox spacing="${_SPACING}">
$(_beginFrame)
                    <text ypad="10" xpad="50" xalign="${XALIGN_LEFT}"><label>Some content goes here</label></text>
$(endFrame_)
$(_beginFrame)
                    <text xpad="50" label=""></text>
$(endFrame_)
                </hbox>
$(endFrame_)
            </hbox>
$(endFrame_)
        </vbox>
$(endFrame_)

$(_beginFrame)
        <vbox spacing="${_SPACING}">
$(_beginFrame)
            <hbox spacing="${_SPACING}">
$(_beginFrame)
                <hbox spacing="${_SPACING}">
$(_beginFrame)
                    <text xpad="30" label="CCCC"></text>
$(endFrame_)
$(_beginFrame)
                    <text xpad="30" label="BBBB"></text>
$(endFrame_)
$(_beginFrame)
                    <text xpad="30" label="AAAA"></text>
$(endFrame_)
$(_beginFrame)
                    <text xpad="45" label=""></text>
$(endFrame_)
                </hbox>
$(endFrame_)
            </hbox>
$(endFrame_)
        </vbox>
$(endFrame_)

$(_beginFrame)
        <vbox spacing="${_SPACING}">
$(_beginFrame)
            <hbox spacing="${_SPACING}">
$(_beginFrame)
                <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
                  can-default="true" has-default="true">
                    <label> _Quit </label>
                    <input file icon="gtk-quit"></input>
                    <width>16</width>
                    <action function="exit">QUIT</action>
                </button>
$(endFrame_)
$(_beginFrame)
                <text xpad="5"><label>""</label></text>
$(endFrame_)
            </hbox>
$(endFrame_)
        </vbox>

$(endFrame_)
    </vbox>
$(endFrame_)

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
    <variable>vWindow</variable>
    <input>fnShowTimestamp </input>
</window>
EODECK

#== Styles ==========================================
export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "outer_colour" { bg[NORMAL] = "blue" }
widget "*outer_colour" style "outer_colour"
style "inner_colour" { bg[NORMAL] = "green" }
widget "*inner_colour" style "inner_colour"

EOSTYLEDEF

## -- post UI construction ---------------------
# fnDateFormatToggleNeeded '--rfc-3339=ns' or '-R'
fnDateFormatToggleNeeded() {
    local vWhatFormat="${1}"
    [[ "${vDateFormatToggle}" == "${vWhatFormat}" ]] && echo "false" || echo "true"
}
export -f fnDateFormatToggleNeeded

# fnDateFormatToggle
fnDateFormatToggle() {
    [[ "${vDateFormatToggle}" == "${_DATE_FORMAT_RFC3339_NS}" ]] && echo "${_DATE_FORMAT_TIMESTAMP}" || echo "${_DATE_FORMAT_RFC3339_NS}"
}
export -f fnDateFormatToggle

# fnShowTimestamp
fnShowTimestamp() {
    [[ "${cbkShowRequest}" = "true" ]] && yad \
        --center --width=400 --image="gtk-dialog-info" --window-icon="gtk-dialog-info" --title="Date format" --text="Requesting date format ${vDateFormatToggle}" \
        --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
    vDate="$(date ${vDateFormatToggle})"
    [[ "${cbkShowResponse}" = "true" ]] && yad \
        --center --width=400 --image="gtk-dialog-info" --window-icon="gtk-dialog-info" --title="Formatted Date" --text="Formatted date: ${vDate}" \
        --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
    echo ${vDate}
}
export -f fnShowTimestamp

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac

## EOSCRIPT

 

/tmp/scripts/ex37.sh

Executing this script using the command above produces:



It is difficult to say, looking at the screenshot, what are the boundaries of
the various objects which are present inside the window.

Let’s consider the following code snippet:

$(_beginFrame)
    <vbox width-request="${_WIDTH_REQUEST}" spacing="${_SPACING}">
$(_beginFrame)
        <vbox spacing="${_SPACING}">
$(_beginFrame)
            <hbox spacing="${_SPACING}">
$(_beginFrame)
                <hbox spacing="${_SPACING}">
$(_beginFrame)
                    <text ypad="10" xpad="50" xalign="${XALIGN_LEFT}"><label>Some content goes here</label></text>
$(endFrame_)
$(_beginFrame)
                    <text xpad="50" label=""></text>
$(endFrame_)
                </hbox>
$(endFrame_)
            </hbox>
$(endFrame_)
        </vbox>
$(endFrame_)

Note the $(_beginFrame) and $(endFrame_) constructs.

Bash functions with the names _beginFrame and endFrame_ are executed at the time
the gtkdialog XML file is being written using the 'cat <<-EODECK >
${MAIN_DIALOG_FILE}' “here document” construct. Whatever these functions write
to the stdout becomes injected into the here document at that place.

In the following code fragment in the source given above note that the first
pair of _beginFrame and endFrame_ funcions is commented out and the second pair
is “active”. The active functions write an empty string to their stdout
consequently only a newline is injected into the gtkdialog definition at the
places they are invoked.

## pre-ui create functions
##
#_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">'; }
#endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }
_beginFrame() { echo -n ''; }
endFrame_() { echo -n ''; }

 Execute the following on the command line to see this. The following fragment
illustrates this:

/tmp/scripts/ex37.sh --dump | cat -n | more

     5        <vbox width-request="400" spacing="0">
     6   
     7            <vbox spacing="0">
     8   
     9                <hbox spacing="0">
    10   
    11                    <hbox spacing="0">
    12   
    13                        <text ypad="10" xpad="50" xalign="0"><label>Some content goes here</label></text>
    14   
    15   
    16                        <text xpad="50" label=""></text>
    17   
    18                    </hbox>
    19   
    20                </hbox>
    21   
    22            </vbox>

Now comment out the active functions and uncomment the inactive functions as
shown:

## pre-ui create functions
##
_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">'; }
endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }
#_beginFrame() { echo -n ''; }
#endFrame_() { echo -n ''; }

Execute the same command as before and note the output.

     4    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
     5        <vbox width-request="400" spacing="0">
     6    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
     7            <vbox spacing="0">
     8    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
     9                <hbox spacing="0">
    10    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
    11                    <hbox spacing="0">
    12    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
    13                        <text ypad="10" xpad="50" xalign="0"><label>Some content goes here</label></text>
    14    </hbox></eventbox></vbox></eventbox>
    15    <eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">
    16                        <text xpad="50" label=""></text>
    17    </hbox></eventbox></vbox></eventbox>
    18                    </hbox>
    19    </hbox></eventbox></vbox></eventbox>
    20                </hbox>
    21    </hbox></eventbox></vbox></eventbox>
    22            </vbox>
    23    </hbox></eventbox></vbox></eventbox>

 Text in bold highlights the code which was injected into the definition of the
UI.

Executing the example produces the visual appearance shown in the earlier
screenshot, repeated here:



To understand what this code does let’s have a look at the artefacts which are
“injected”.

The _beginFrame function emits the following code, here distributed over
multiple lines for ease of reading:

<eventbox name="outer_colour" border-width="1">
    <vbox border-width="1">
        <eventbox name="inner_colour" border-width="1">
            <hbox border-width="1">

The outer eventbox sets the background colour of all it contains to whatever the
style defines for the “outer_colour”, which in the example happens to be blue.

The vbox with the width of 1 causes a 1 pixel wide border to be shown. That
border’s colour is inherited from the outer eventbox and is of the colour that
eventbox’s style defines.

The inner eventbox sets the background colour of all of its content to the
inner_colour, which happens to be green.

The innermost hbox adds a 1 pixel border around anything it contains and that
border inherits the inner eventbox’s background colour.

Not the green 1 pixel border around the Quit button.

The injected _beginFrame code “starts” definitions of 4 containers. These
containers must be “finished”/”closed” so the endFrame_ function supplied the
closures:

            </hbox>
        </eventbox>
    </vbox>
</eventbox>

Now change the code for the _beginFrame so that it reads as follows and execute
the example:

## pre-ui create functions
##
_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="0">'; }
endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }

The ending hbox no longer provides the 1 pixel green inner border so the
application window now looks like:



Note that, for all intents and purposes the green 1 pixel border around the Quit
button is gone. The 1 pixel green borders around all the other components is
also gone, though it is harder to see. Scroll back to the previous screenshot
and compare them.

Now change the definitno so that the vbox border is 0 pixels and execute the
example:

## pre-ui create functions
##
_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="0"><eventbox name="inner_colour" border-width="1"><hbox border-width="0">'; }
endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }

This results in the following appearance:



The blue lines are even closer together.

Now change the border-width of the outer eventbox to 0 and execute the example:

_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="0"><vbox border-width="0"><eventbox name="inner_colour" border-width="1"><hbox border-width="0">'; }
endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }



Now change the border-width of the inner eventbox to 0 and execute the example:

_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="0"><vbox border-width="0"><eventbox name="inner_colour" border-width="0"><hbox border-width="0">'; }
endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }



The remaining blue areas are there because:

 1. The first text element definition adds 10 pixels padding above and below the
    text, ‘<text ypad=”10″ ‘ but the second does not
 2. The button is “taller” than the text to the right of it

Reset the values of the 4 border-width attribtes back to 1.

Notice that the vbox and hbox objects which are injected by the _beginFrame
function carry the spacing=”${_SPACING}” attribute. In the original source the
value of this attribute is defined as 0:

_SPACING=0

Change the value to 10 and execute the example:

_SPACING=10



Notice that extra space was added between the vboxes and between the hboxes.

Comment out the _beginFrame and endFrame_ functions which inject the extra code,
uncomment the _beginFrame and endFrame_ functions which do not inject the code
and execute the example.

###_beginFrame() { echo -n '<eventbox name="outer_colour" border-width="1"><vbox border-width="1"><eventbox name="inner_colour" border-width="1"><hbox border-width="1">'; }
###endFrame_() { echo -n '</hbox></eventbox></vbox></eventbox>'; }
_beginFrame() { echo -n ''; }
endFrame_() { echo -n ''; }

Compare the original windows and the window with the extra spacing added by the
hbox and vbox elements.



If one does not have a way to see the bounding boxes of the various elements it
is pretty much impossible to see what adds spaces, where and how much.


SUMMARY

We explored the styling of the notebook object and its content, reviewing in the
process how one can derive paths to various UI components which the widget_class
requires to apply styles.

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
bash • gtkdialog comments • gtkdialog documentation • gtkdialog eventbox •
gtkdialog eventboxstyle • gtkdialog examples • gtkdialog notebook example •
gtkdialog reference • gtkdialog structure • gtkdialog style • gtkdialog style
exaple • infrastructure demo • infrastructure demonstration • Linux demo • Linux
demo image • Linux demonstration image • Linux GUI • Linux UI • technical demo •
technical demonstration

May 07


GTKDIALOG – APPLYING STYLES TO NOTEBOOK ELEMENTS AND CONTENT EXAMPLES

By Czapski Michael Demo Building, gtkdialog No Comments »

In this article I explore the application of styles to gtkdialog Notebook object
components and content. GtkNotebook was discussed, and examples were provided in
the previous article. In this article one of the examples presented earlier will
expanded to include styling of label text, tab backgrounds and content.
Discussion of widget_class paths and how they can be worked out for specific
components in the gtkdialog UI containment hierarchy is also provided.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad and gtkdialog are installed, as discussed in the
article “Install yad and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


EXAMPLE APPLICATION WITH NO STYLING

Create the constants file and the example code using instructions provided
below, then execute the example application to see what an “unadorned”
application UI looks like.

First, create the source with the constants, some of which are used in this
example. If you worked through the previous article on the Notebook objects you
should have this file already available in /tmp/scripts or wherever you created
it.

mkdir -pv /tmp/scripts
cd /tmp/scripts
cat <<-'EOSOURCE' > gtkdialog.constants
# gtkdialog.constants
#
cstVersion=1.0.0
echo "Loading ${BASH_SOURCE[0]} version ${cstVersion} ..." 1>&2
 
# I prefer symbolic constants to numeric literals so I define a bunch
#
BTN_IMG_POS_LEFT=0
BTN_IMG_POS_RIGHT=1
BTN_IMG_POS_ABOVE=2
BTN_IMG_POS_BELOW=3
WIN_ICON=access
WIN_DECORATED=true
WIN_RESIZABLE=true
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
WIN_POS=${GTK_WIN_POS_CENTER}
WIN_SKIP_TASKBAR_HINT=false
WIN_ALLOW_GROW=true
XALIGN_LEFT=0
XALIGN_RIGHT=1
XALIGN_CENTRE=0.5
YALIGN_TOP=0
YALIGN_BOTTOM=1
YALIGN_CENTRE=0.5
VSCROLLBAR_ALWAYS=0
VSCROLLBAR_AUTOMATIC=1
VSCROLLBAR_NEVER=2
HSCROLLBAR_ALWAYS=0
HSCROLLBAR_AUTOMATIC=1
HSCROLLBAR_NEVER=2
GTK_JUSTIFY_LEFT=0
GTK_JUSTIFY_RIGHT=1
GTK_JUSTIFY_CENTRE=2
TREE_SELECTION_MODE_NONE=0
TREE_SELECTION_MODE_SINGLE=1
TREE_SELECTION_MODE_BROWSE=2
TREE_SELECTION_MODE_MULTIPLE=3
TAB_POS_LEFT=0
TAB_POS_RIGHT=1
TAB_POS_ABOVE=2
TAB_POS_BELOW=3
 
EOSOURCE

Now create and execute the example.

mkdir -pv /tmp/scripts
cd /tmp/scripts
> ex33.sh
chmod ug+x ex33.sh

geany ex32.sh & # copy and paste the code blow until ## EOSOURCE
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# set initial notebook page
echo 1 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE

# window title
WIN_TITLE="XDS.b Registry Browser"

# Size of the notebook and all content panels
#
_HEIGHT_REQUEST=375
_WIDTH_REQUEST=570

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox>

        <hbox homogeneous="true" sensitive="true" visible="true">

                $(: begin Notebook definition )
                <notebook height-request="${_HEIGHT_REQUEST}" width-request="${_WIDTH_REQUEST}"
                    tab-labels="Requests|Patients|Settings"
                    page="2"
                    tab-hborder="12" xx-tab-hborder="how much space to the left and right of the tab label text"
                    show-tabs="true" xx-show-tabs="as the name says - if false only the content of the 'page=x' tab will show"
                    homogeneous="true" space-fill="true" space-expand="true"
                    tab-pos="${TAB_POS_ABOVE}">

$(: TAB 1 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 1" spacing="2">
                        <text><label>Requests Panels Go Here</label></text>
                    </vbox> $(: end-notbook-tab="Tab 1" )

$(: TAB 2 -----------------------------------)
                    <vbox xx-notbook-tab="Tab 2">
                        <vbox spacing="2">
                            <text><label>Patient Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 2" )

$(: TAB 3 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 3" homogenous="true" space-fill="true" space-expand="true">
                    <eventbox>
                        <vbox>
                            <text><label>Settings Panels Go Here</label></text>
                        </vbox>
                    </eventbox>
                    </vbox> $(: end-notbook-tab="Tab 3" )

$(: End of tab content definitions -----------)

                </notebook>
        </hbox> $(: end Notebook definition )

$(: Common object - shown below the notebook --)

        <hbox>
            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true"
              can-default="true" xx-info="has-default must have can-default"
              has-default="true" xx-info="has-default and can-default must both be true for default to work"
              >
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
        </hbox>
    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EODECK

#== Styles ==========================================
:<<'WIDGET CONTAINMENT HIERARCHY  -------------------------------------'

Consider the following widget containment hierarchy when deriving paths
for styling objects.
Remember that some objects, like hbox and vbox, do not have visible
foreground or background to which styling can be usefully applied.
Remember too that in gtkdialog <text> is not a container/object - it is
syntactic sugar, and certain objects, like buttons, have implicit
containers which do appear in the XML we write for the UI.

window
    <vbox>
        <hbox                           - notebook outer container
            <notebook
                <vbox                   - tab 1
                    <text
                        <label>
                <vbox                   - tab 2
                    <vbox
                        <text>
                            <label
                <vbox                   - tab 3
                    <eventbox>
                        <vbox>
                            <text>
                                <label
        <hbox                           - bottom buttons outer container
            <button

Assuming that we want to change the font of specific labels,
following are the widget_class paths to use:

window.vbox.hbox.notebook.vbox.label
window.vbox.hbox.notebook.vbox.vbox.label
window.vbox.hbox.notebook.vbox.eventbox.vbox.label
window.vbox.hbox.button.hbox.hbox.label
- this one is counterintuitive - we don't have explicit hboxes in our code, right?
- see http://www.murga-linux.com/puppy/viewtopic.php?t=69188&start=2, which says specifically
- - <button> containing only a label is a GtkButton with GtkLabel
- - <button> containing only an image is a GtkButton containing a GtkImage
- - <button> containing a label and an image is a GtkButton containing a GtkHBox or GtkVBox itself containing a GtkLabel and GtkImage
- though even this does not really reflect the actual label containment hierarchy for the button label in this example

WIDGET CONTAINMENT HIERARCHY  -------------------------------------

export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "notebookStyle" {
    GtkNotebook::tab-overlap = -2
    GtkNotebook::tab-curvature = 0
    xthickness = 1
    ythickness = 1
    font_name="URW Gothic L Book 14"
    fg[NORMAL]="SaddleBrown"        # colours the tab label font
    bg[NORMAL]="powderblue"         # background colour to the notebook
}
style "settingsTabStyle" {
    bg[NORMAL]      = "navy"
    fg[NORMAL]      = "white"
    font_name="URW Gothic L Oblique 18"
}
style "buttonStyle" {
    bg[NORMAL]      = "white"
    fg[NORMAL]      = "navy"
    font_name="URW Gothic L Demi Oblique 10"
}

#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkLabel>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkVBox><GtkLabel>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox><GtkVBox><GtkLabel>" style "settingsTabStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox>" style "settingsTabStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox><GtkHBox><GtkLabel>" style "buttonStyle"
EOSTYLEDEF

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSOURCE

/tmp/scripts/ex33.sh

The “unadorned” application will look like that the illustration below.




WIDGET_CLASS PATHS

As discussed in the article on styling gtkdialog objects,
https://blogs.czapski.id.au/2017/04/gtkdialog-applying-styles-to-gtkdialog-applications,
there are three ways in which the specific object to which a style is to be
applied can be identified. In this article we use the widget_class and the paths
widget_class recognises.

widget_class excepts a path to the object(s) to which to apply a style. The path
must reflect the containment hierarchy of the target object(s), that is where in
the nesting hierarchy of UI elements this object is located. The path is a
dot-separated list of all the ancestor objects all the way from the Window
object.

Consider the following widget containment hierarchy when deriving paths for
styling objects.

window
    <vbox>
        <hbox                           - notebook outer container
            <notebook
                <vbox                   - tab 1
                    <text
                        <label>
                <vbox                   - tab 2
                    <vbox
                        <text>
                            <label
                <vbox                   - tab 3
                    <eventbox>
                        <vbox>
                            <text>
                                <label
        <hbox                           - bottom buttons outer container
            <button

Remember that some objects, like hbox and vbox, do not have visible foreground
or background to which styling can be usefully applied.

Remember too that in gtkdialog <text> is not a container/object – it is
syntactic sugar – and certain objects, like buttons, have implicit containers
which do not appear in the XML we write for the UI.

Assuming that we want to change the font of specific labels, following are the
widget_class paths to use:

window.vbox.hbox.notebook.vbox.label
window.vbox.hbox.notebook.vbox.vbox.label
window.vbox.hbox.notebook.vbox.eventbox.vbox.label
window.vbox.hbox.button.hbox.hbox.label

The path that leads to the label inside the button is counterintuitive – we
don’t have explicit hboxes in our code, right?  For reasons why this might be
the case see http://www.murga-linux.com/puppy/viewtopic.php?t=69188&start=2,
which says:

 * <button> containing only a label is a GtkButton with GtkLabel
 * <button> containing only an image is a GtkButton containing a GtkImage
 * <button> containing a label and an image is a GtkButton containing a GtkHBox
   or GtkVBox itself containing a GtkLabel and GtkImage

In our case we have a button with a label and an icon, so the third bullet would
apply, though even this does not really reflect the actual label containment
hierarchy for the button label in this example. Trial and error demonstrates
that the containment hierarchy for the label inside the button in his example is
actually:

window.vbox.hbox.button.hbox.hbox.label

There are two implicit hbox objects between the button and the its label.


APPLYING STYLES BY EXAMPLE

Locate the commented out section of the style definition in the source:

#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkLabel>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkVBox><GtkLabel>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook>" style "notebookStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox><GtkVBox><GtkLabel>" style "settingsTabStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox>" style "settingsTabStyle"
#widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox><GtkHBox><GtkLabel>" style "buttonStyle"

The first line applies the “notebookStyle” to the labels of the notebook,
changing their font and font colour.

The notebookStyle is defined as follows:

style "notebookStyle" {
    GtkNotebook::tab-overlap = -2
    GtkNotebook::tab-curvature = 0
    xthickness = 1
    ythickness = 1
    font_name="URW Gothic L Book 14"
    fg[NORMAL]="SaddleBrown"        # colours the tab label font
    bg[NORMAL]="powderblue"         # background colour to the notebook
}

Uncomment the first commented out line, save and execute the example to see the
effect:



Because the path of the widget_class is
“<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkLabel>” the style is applied to
the labels of the notbook tabs only. Since the labels don’t have background to
which background colour could be applied the bg[NORMAL] directive is ignored.

Uncomment the second commented out line, save and execute the example to see the
effect. You will not see the difference until you click on the “Patients” tab:



Because the path of the widget_class is
“<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkVBox><GtkLabel>” style
“notebookStyle” the style is applied to the label contained inside the text,
inside two nested VBox objects inside the notebook. Since the labels don’t have
background to which background colour could be applied the bg[NORMAL] directive
is ignored.

Uncomment the third commented out line, save and execute the example to see the
effect. You will not see the difference until you click on the “Patients” or
“Requests” tab:



Because the path of the widget_class is
“<GtkWindow><GtkVBox><GtkHBox><GtkNotebook>” the style “notebookStyle” is
applied to the background of the notebook tabs.

Before you ask why the style was applied to the Requests and patients, but not
to Settings – I have don’t have an answer. It is puzzling.

Consider the style “settingsTabStyle”:

style "settingsTabStyle" {
    bg[NORMAL]      = "navy"
    fg[NORMAL]      = "white"
    font_name="URW Gothic L Oblique 18"
}

The object to which this style is applied should have a navy background, white
foreground and specific font face, size and slant.

Uncomment the fourth commented out line, save and execute the example to see the
effect:



Because the path of the widget_class is
“<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox><GtkVBox><GtkLabel>”
the style “settingsTabStyle” is applied to the label of the content of the
settings tab.

Uncomment the fifth commented out line, save and execute the example to see the
effect:



Because the path of the widget_class is
“<GtkWindow><GtkVBox><GtkHBox><GtkNotebook><GtkVBox><GtkEventBox>” the style
“settingsTabStyle” is applied to the <eventbox> object the content of the
settings tab.

The eventbox object is an interesting object in that unlike the hbox or vbox it
does have a background to which colour can be applied. This property of the
eventbox is what is used in the example to give the settings tab background
colour different from that of the other tabs.

Now consider the style named “buttonStyle”.

style "buttonStyle" {
    bg[NORMAL]      = "white"
    fg[NORMAL]      = "navy"
    font_name="URW Gothic L Demi Oblique 10"
}

Uncomment the sixth and last commented out line, save and execute the example to
see the effect:



That text of the button label was changed from default.

Note that the widget_class path,
“<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox><GtkHBox><GtkLabel>”, has the
two extra implicit hbox components. I worked this out by successively trying:

"<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkLabel>" – did not work

"<GtkWindow><GtkVBox><GtkHBox><GtkButton>*<GtkLabel>" – worked

"<GtkWindow><GtkVBox><GtkHBox><GtkButton>*<GtkHBox>*<GtkLabel>" – worked

"<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox>*<GtkLabel>" – worked

"<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox><GtkLabel>" – did not work

"<GtkWindow><GtkVBox><GtkHBox><GtkButton><GtkHBox><GtkHBox><GtkLabel>" – worked

This was a bit tedious but not excessively so.


 SUMMARY

We explored the styling of the notebook object and its content, reviewing in the
process how one can derive paths to various UI components which the widget_class
requires to apply styles.

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
bash • gtkdialog comments • gtkdialog documentation • gtkdialog examples •
gtkdialog notebook • gtkdialog notebook example • gtkdialog notebook style •
gtkdialog reference • gtkdialog structure • gtkdialog style • gtkdialog style
exaple • infrastructure demo • infrastructure demonstration • Linux demo • Linux
demo image • Linux demonstration image • Linux GUI • Linux UI • technical demo •
technical demonstration

May 06


GTKDIALOG – EXPLORING THE NOTEBOOK OBJECT BY EXAMPLE

By Czapski Michael Demo Building, gtkdialog 2 Comments »

In this article I explore the gtkdialog Notebook object, its attributes and
actions, through increasingly more sophisticated examples. In passing, other
gtkdialog objects are used without much elaboration.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.

gtkdialog, based as it is on the GTK object model, leverages the GTK object
hierarchy. Consider the reference for the Notebook object at
http://01micko.com/reference/notebook.html.

The very first link points to a GtkNotebook –
https://developer.gnome.org/gtk2/2.24/GtkNotebook.html.

In the GTK object hierarchy,
https://developer.gnome.org/gtk2/2.24/GtkNotebook.html#GtkNotebook.object-hierarchy,
the Notebook object is some levels below the GObject, the topmost object.



As briefly discussed in the previous article the GtkNotebook, and consequently
the gtkdialog Notebook object inherit, as I understand it, from the objects
higher up in the hierarchy. This will come into play when we explore attributes
that can be set for a Notebook, and actions that can be configured for a
Notebook.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad and gtkdialog are installed, as discussed in the
article “Install yad and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


NOTEBOOK ATTRIBUTES

The gtkdialog Notebook object is a visible container of a sort. Its purpose it
to provide a tabbed container for collections of other  objects.

An example of a tabbed interface, which uses the Notebook object and which will
be developed in this article, is shown here as a bit of a teaser.



Reference documentation for the gtkdialog Notebook object,
http://01micko.com/reference/notebook.html, provides a table of attributes
specific to this gtkdialog object and makes a reference to ancestor class
properties.

Attributes that can be configured for the notebook widget are defined in the
widget’s reference page see
https://developer.gnome.org/gtk2/2.24/GtkNotebook.html, section Properties –
https://developer.gnome.org/gtk2/2.24/GtkNotebook.html#GtkNotebook.properties

Some of them are useful and some of them are not, as far as I am concerned or
can empirically determine. Changing values of some of them does not have visible
consequences.

Not all attributes/properties are recognised and acted upon by  gtkdialog. Some
of the properties are inherited from the parent objects, like GtkContainer and
GtkWidget. For example, border-width, which defines the amount of space between
the notebook frame and the notebook content, is inherited from the GtkContainer.

Similarly, sensitive property is inherited from the GtkWidget and when set to
false effectively disables everything inside the notebook container.

See the reference page:
file:///home/demo/gtkdialog-0.8.3/doc/reference/notebook.html

To work out what attributes are actually supported, in this case by the notebook
widget, we need to do some exploration. Discussion below goes into this to an
extent and I provided most of the useful attributes that can be set, both from
GtkWindow itself and inherited from GtkContainer and GtkWidget. The “Works?”
column indicates whether the attribute has a visible effect (Y), does not have a
visible effect (N) or I have not figured out a way to test whether it works or
not.

The table below summarised Notebook attributes/properties and indicates which
work with the gtkdialog and which do not as far as I can tell. “Do not” may well
be a function of me not seeing any visible difference with the property set to
different values. Some ancestor attributes/properties which are not really
useable from gtkdialog are omitted.

Name Description Value Default Works? In Notebook space-expand Pack widget
expanding into space true or false Y gtkdialog space-fill Pack widget filling
space true or false Y gtkdialog block-function-signals Block signal emissions
from functions true or false gtkdialog file-monitor Emit signal when input
file(s) change true or false gtkdialog auto-refresh Auto refresh when input
file(s) change true or false gtkdialog tab-base-index Tab label start page
number Integer N



 

gtkdialog tab-labels Tab labels label0 | label1 | … Y gtkdialog tab-prefix Tab
label prefix N gtkdialog tab-suffix Tab label suffix N gtkdialog Inherited from
GtkNotebook enable-popup If TRUE, pressing the right mouse button on the
notebook pops up a menu that you can use to go to a page true or false false Y
GtkNotebook group-id Group ID for tabs drag and drop >= -1 -1 GtkNotebook
group-name Group name for tabs drag and drop String NULL GtkNotebook homogeneous
Whether tabs should have homogeneous sizes true or false false Y GtkNotebook
page The index of the current page >= -1 -1 Y GtkNotebook scrollable If TRUE,
scroll arrows are added if there are too many tabs to fit true or false false Y
GtkNotebook show-border Whether the border should be shown or not true or false
true N GtkNotebook show-tabs Whether tabs should be shown or not true or false
true Y GtkNotebook tab-border Width of the border around the tab labels Int 2 y
GtkNotebook tab-hborder Width of the horizontal border of tab labels Int 2 Y
GtkNotebook tab-pos Which side of the notebook holds the tabs GtkPositionType



0 GTK_POS_LEFT

1 GTK_POS_RIGHT

2 GTK_POS_TOP

3 GTK_POS_BOTTOM

GTK_POS_TOP Y GtkNotebook tab-vborder Width of the vertical border of tab labels
Int 2 Y GtkNotebook GtkNotebook – child – there is no such thing in dtkdialog,
it seems detachable Whether the tab is detachable true or false false menu-label
The string displayed in the child’s menu entry String NULL N position The index
of the child in the parent >=-1 -1 N reorderable Whether the tab is reorderable
by user action or not true or false false N tab-expand Whether to expand the
child’s tab or not true or false false N tab-fill Whether the child’s tab should
fill the allocated area or not true or false true N tab-label The string
displayed on the child’s tab label String NULL N GtkNotebook – Style – no such
thing? arrow-spacing spacing between the scroll arrows and the tabs >=0 0 N
has-backward-stepper determines whether the standard backward arrow button is
displayed true or false true N has-forward-stepper determines whether the
standard forward arrow button is displayed true or false true N
has-secondary-backward-stepper determines whether a second backward arrow button
is displayed on the opposite end of the tab area true or false false N
has-secondary-forward-stepper determines whether a second forward arrow button
is displayed on the opposite end of the tab area true or false false N
tab-curvature defines size of tab curvature >=0 1 N tab-overlap defines size of
tab overlap area Int 2 N Inherited from gtkContainer border-width The width of
the empty border outside the containers children <=65535 0 Y can-default Whether
the widget can be the default widget.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget can-focus Whether the widget can accept the input
focus.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget has-default Whether the widget is the default
widget.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget has-focus Whether the widget has the input focus.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget has-tooltip Whether this widget has a tooltip.



Disables tooltip display if tooltip is defined for the Window

true or false false Y GtkWidget height-request Override for height request of
the widget, or -1 if natural height should be used.



Has not effect of default-height is specified.

>=0 -1 Y GtkWidget is-focus Whether the widget is the focus widget within the
toplevel.



Does not seem to have any effect when applied to the Window object

true or false false GtkWidget name The name of the widget.



It can be used to address styling directves to a named object

string NULL GtkWidget receives-default If TRUE, the widget will receive the
default action when it is focused.



I don’t know what that is supposed to accomplish. Nothing visible happens
regardless of the property value.

true or false false GtkWidget sensitive Whether the widget responds to input.



FALSE disables all components contained in the window.

true or false TRUE Y GtkWidget tooltip-markup The contents of the tooltip for
this widget.



Simple markup can be used to call out parts of tooltip text in.

See http://www.murga-linux.com/puppy/viewtopic.php?t=40418 for a markup explorer
tool.

Ineffective if tooltip-disabled is TRUE.

string NULL Y GtkWidget tooltip-text The contents of the tooltip for this
widget.



Ineffective if tooltip-disabled is TRUE.

string NULL Y GtkWidget visible Whether the widget is visible.



It is somewhat self-defeating to make a window invisible on creation unless it
is a “subsidiary” window and can be made visible form some other piece of logic.

true or false true Y GtkWidget width-request Override for width request of the
widget, or -1 if natural width should be used.



Has not effect if default-width is specified.

>=0 -1 Y GtkWidget

The following example includes just about every attribute that can be defined
for a Notebook object. Experiment with the various settings to see what you can
see.

First, let’s create an enumerations script which will supply human-readable
versions of enumerations and other numeric constants that may be used in the
scripts I show. See https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h, and
elsewhere, for sources of these enumerations.

mkdir -pv /tmp/scripts
cd /tmp/scripts
cat <<-'EOSOURCE' > gtkdialog.constants
# gtkdialog.constants
#
cstVersion=1.0.0
echo "Loading ${BASH_SOURCE[0]} version ${cstVersion} ..." 1>&2

# I prefer symbolic constants to numeric literals so I defined a bunch
# see https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h for specifics
#
BTN_IMG_POS_LEFT=0
BTN_IMG_POS_RIGHT=1
BTN_IMG_POS_ABOVE=2
BTN_IMG_POS_BELOW=3
WIN_ICON=access
WIN_DECORATED=true
WIN_RESIZABLE=true
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2
WIN_POS=${GTK_WIN_POS_CENTER}
WIN_SKIP_TASKBAR_HINT=false
WIN_ALLOW_GROW=true
XALIGN_LEFT=0
XALIGN_RIGHT=1
XALIGN_CENTRE=0.5
YALIGN_TOP=0
YALIGN_BOTTOM=1
YALIGN_CENTRE=0.5
VSCROLLBAR_ALWAYS=0
VSCROLLBAR_AUTOMATIC=1
VSCROLLBAR_NEVER=2
HSCROLLBAR_ALWAYS=0
HSCROLLBAR_AUTOMATIC=1
HSCROLLBAR_NEVER=2
GTK_JUSTIFY_LEFT=0
GTK_JUSTIFY_RIGHT=1
GTK_JUSTIFY_CENTRE=2
TREE_SELECTION_MODE_NONE=0
TREE_SELECTION_MODE_SINGLE=1
TREE_SELECTION_MODE_BROWSE=2
TREE_SELECTION_MODE_MULTIPLE=3
TAB_POS_LEFT=0
TAB_POS_RIGHT=1
TAB_POS_ABOVE=2
TAB_POS_BELOW=3

EOSOURCE

To create and exercise the first example execute the following commands, noting
that you will need to copy and paste the code into an editor window because it
is too large for a copy/paste as a “here document”. Explore the effects of
changing the various attributes of the Notebook object.

mkdir -pv /tmp/scripts
cd /tmp/scripts
> ex30.sh
chmod ug+x ex30.sh

geany ex30.sh & # copy and paste the code blow until ## EOSOURCE
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

# set initial notebook page
echo 1 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE

# window title
WIN_TITLE="XDS.b Registry Browser"

# Size of the notebook and all content panels
#
_HEIGHT_REQUEST=375
_WIDTH_REQUEST=570

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox>

        <hbox homogeneous="true" sensitive="true" visible="true">

                $(: begin Notebook definition )
                <notebook 
                    height-request="${_HEIGHT_REQUEST}"
                    width-request="${_WIDTH_REQUEST}"
                    tab-labels="Requests|Patients|Settings" xx-tab-labels="which will be shown on tabs"
                    page="1" xx-page="0 based tab number which will be initially shown"
                    enable-popup="true" xx-enable-popup="right-click will bring a list of tabs to select from"
                    show-border="true" xx-show-border="does not seem to do anything visible"
                    tab-border="2" xx-tab-border="how much space around text of tab label"
                    tab-hborder="2" xx-tab-hborder="how much space to the left and right of the tab label text"
                    tab-vborder="2" xx-tab-vborder="how much space to above and below the tab label text"
                    show-tabs="true" xx-show-tabs="as the name says - if false only the content of the 'page=x' tab will show"
                    homogeneous="true" xx-homogeneous="make the width of tabs the same"
                    space-fill="true"
                    space-expand="true"
                    scrollable="false" xx-scrollable="if notebook container width less than the width of all tabs adds left/right arrows to navigate between tabs"
                    tab-pos="${TAB_POS_ABOVE}"
                    border-width="0"
                    sensitive="true"
                    tooltip-markup="<span size='small'>This is an example of a <b>Notebook</b></span>"
                    has-tooltip="true"
                    visible="true"
                    >

$(: TAB 1 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 1">
                        <vbox spacing="2">
                            <text><label>Requests Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 1" )

$(: TAB 2 -----------------------------------)
                    <vbox xx-notbook-tab="Tab 2">
                        <vbox spacing="2">
                            <text><label>Patient Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 2" )

$(: TAB 3 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 3">
                        <vbox>
                            <text><label>Settings Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 3" )

$(: End of tab content definitions -----------)

                </notebook>

        </hbox> $(: end Notebook definition )

$(: Common object - shown below the notebook --)

        <hbox>
            <button width-request="100" homogenous="true" image-position="${BTN_IMG_POS_LEFT}" use-underline="true" 
              can-default="true" xx-info="has-default must have can-default"
              has-default="true" xx-info="has-default and can-default must both be true for default to work"
              >
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
        </hbox>
    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EODECK

# -- run the UI -----------------------------------------------------------------------------------------------

case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSOURCE

/tmp/scripts/ex30.sh

Exercising this example unmodified presents the following initial screen:



Changing the following attributes to the following values will produce a
somewhat different UI:

page="0" xx-page="0 based tab number which will be initially shown"
tab-hborder="12" xx-tab-hborder="how much space to the left and right of the tab label text"
tab-pos="${TAB_POS_LEFT}"
border-width="10"



Note that the right-click list of tab names, which can be used for navigation
between the tabs just as clicking on the tabs can, is enabled by setting the
enable-popup attribute to true.

page=”0″ causes the first tab to be the tab shown by default.

tab-border=”12″ adds space on either side of the label text.

tab-pos determines where the tabs will be shown. The enumeration is:

TAB_POS_LEFT=0
TAB_POS_RIGHT=1
TAB_POS_ABOVE=2
TAB_POS_BELOW=3

border-width adds whitespace on all sides of the notebook.

Explore other values of the various attributes and see what you can see.

Click the tabs, hover the mouse over the area of the notebook to see the
tooltip, etc..


SHOWING AND HIDING NOTEBOOK TABS

The example in the previous section showed a pretty ordinary use of the
Notebook. More sophisticated applications can be created by for example hiding
notebook tabs until they are needed, showing them on demand and hiding them
again when not required.

This example explores exactly this use case but it also shows how the “last
visible tab” can be “remembered” and activated when the visible-on-demand tab is
hidden again.

The example uses variables associated with the various objects like hbox, vbox,
notebook and button to manipulate their associated objects dynamically to
accomplish the desired effects.

The following screenshots show the various states of this application to
illustrate what is expected.



This is the initial state of the application.

Clicking the cogwheel button will show the Settings tab, which is initially
invisible.



Clicking the cogwheel button again hides the Settings tab and makes the tab
which was active before the button was clicked and the settings tab was shown
and activated, active again.

Recreate the application and convince yourself that this is indeed how the
application behaves.

The source code and commands to recreate the example are shown below. Specific
techniques will be discussed following the example code.

mkdir -pv /tmp/scripts
cd /tmp/scripts
> ex31.sh
chmod ug+x ex31.sh

geany ex31.sh & # copy and paste the code blow until ## EOSOURCE
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

WIN_TITLE="XDS.b Registry Browser"

# set initial notebook page - this determines which tab is initially shown
echo 0 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE

# Common size of all notebook content panels
#
_HEIGHT_REQUEST=375
_WIDTH_REQUEST=570

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}" 
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}" 
        auto-refresh="true" name="win0">
    <vbox>

        <hbox homogeneous="true" sensitive="true" visible="true"> $(: begin Notebook container definition )

                 <notebook $(: begin notebook definition )
                    height-request="${_HEIGHT_REQUEST}"
                    width-request="${_WIDTH_REQUEST}"
                    tab-labels="Requests|Patients|Settings" xx-tab-labels="which will be shown on tabs"
                    page="1" xx-page="0 based tab number which will be initially shown"
                    enable-popup="true" xx-enable-popup="right-click will bring a list of tabs to select from"
                    show-border="true" xx-show-border="does not seem to do anything visible"
                    tab-border="2" xx-tab-border="how much space around text of tab label"
                    tab-hborder="2" xx-tab-hborder="how much space to the left and right of the tab label text"
                    tab-vborder="2" xx-tab-vborder="how much space to above and below the tab label text"
                    show-tabs="true" xx-show-tabs="as the name says - if false only the content of the 'page=x' tab will show"
                    homogeneous="true" xx-homogeneous="make the width of tabs the same"
                    space-fill="true"
                    space-expand="true"
                    scrollable="false" xx-scrollable="if notebook container width less than the width of all tabs adds left/right arrows to navigate between tabs"
                    tab-pos="${TAB_POS_ABOVE}"
                    border-width="0"
                    sensitive="true"
                    tooltip-markup="<span size='small'>This is an example of a <b>Notebook</b></span>"
                    has-tooltip="true"
                    visible="true"
                    >

$(: TAB 1 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 1">
                        <vbox spacing="2">
                            <text><label>Requests Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 1" )

$(: TAB 2 -----------------------------------)
                    <vbox xx-notbook-tab="Tab 2">
                        <vbox spacing="2">
                            <text><label>Patient Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 2" )

$(: TAB 3 ------------------------------------)
                    $(: make this tab initially invisible by setting visible="false")
                    <vbox xx-notbook-tab="Tab 3" visible="false">
                        <vbox>
                            <text><label>Settings Panels Go Here</label></text>
                        </vbox>
                        $(: Variable name of the vbox/tab. )
                        $(: It is used to explicitly show/hide the vbox and its content )
                        <variable>vTab3</variable>
                    </vbox> $(: end-notbook-tab="Tab 3" )

$(: End of tab content definitions -----------)

                    <sensitive>true</sensitive>
                    $(: variable name of the notebook and all it contains )
                    $(: used to explicitly manage the notebook - like refreshing it )
                    <variable>vNotebook</variable>
                    $(: which tab to show when the control is first created and page=x attribute is not set )
                    $(: which tab to show when the control is refreshed )
                    <input file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</input>
                    $(: save the tab number when tabs are switched )
                    $(: used to resore the "last seen tab" when showing/hiding the settings tab )
                    <output file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT</output>
                    <action signal="focus-out-event" x-save-last-tab-number-in="output file">save:vNotebook</action>
                </notebook> $(: end Notebook definition )

$(: End Notebook definition -------------------)

        </hbox> $(: end Notebook container definition )
 
$(: Common object - shown below the notebook --)

        <hbox>

            $(: invisible entry for persisting the state of the toggle )
            $(: fnToggleSettingsTab toggles the value )
            <entry visible="false">
                <default>false</default>
                <variable>vSettingsToggle</variable>
                <input>fnToggleSettingsTab</input>
            </entry>
            $(: button which toggles between displying and hiding the settings tab )
            <button width-request="35" homogenous="true" image-position="0" use-underline="true"
              tooltip-text="Configure URLs and Credentials">
                <input file icon="ibus-setup"></input>
                <width>16</width>
                <variable>vSettingsButton</variable>
                $(: set toggle to opposite settings )
                <action>refresh:vSettingsToggle</action> 
                $(: hide the settings tab and restore the "last tab" value so that the tab shown before the button is clicked )
                $(: is shown when the settings tab is hidden )
                <action condition="command_is_false(echo \$vSettingsToggle)">hide:vTab3</action>
                <action condition="command_is_false(echo \$vSettingsToggle)">cp ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action> 
                $(: show the settings tab and save the "last tab" value so that the tab shown when the button is clicked )
                $(: is shown whent he settings are hidden again )
                <action condition="command_is_true(echo \$vSettingsToggle)">show:vTab3</action>
                <action condition="command_is_true(echo \$vSettingsToggle)">echo 2 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action> 
                $(: cause the changes to be reflected in the UI )
                <action>refresh:vNotebook</action>
            </button>

            <button width-request="100" 
              homogenous="true" 
              image-position="${BTN_IMG_POS_LEFT}"
              use-underline="true"
              can-default="true" xx-info="has-default must have can-default"
              has-default="true" xx-info="has-default and can-default must both be true for default to work"
              >
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
        </hbox>
    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EODECK

# -- Post UI Assembly Functions - used from UI after it is assembled ------------------------------------
#
# --------------------
# fnToggleSettingsTab - flips settings toggle
# controls whether the settings tab is visible or hidden 
# switches value of the entry to which it is hooked between true and false each time it is invoked
#
fnToggleSettingsTab() {
    [[ "${vSettingsToggle}" == "true" ]] && echo "false" || echo "true"
}
export -f fnToggleSettingsTab

# -- run the UI -----------------------------------------------------------------------------------------------
case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSOURCE

/tmp/scripts/ex31.sh

Note the lines highlighted in bold. These are the lines by which the two
examples differ.

Text in $(: … ) provides brief comments.

The following code fragment:

$(: make this tab initially invisible by setting visible="false")
<vbox xx-notbook-tab="Tab 3" visible="false">
    <vbox>
        <text><label>Settings Panels Go Here</label></text>
    </vbox>
    $(: Variable name of the vbox/tab. )
    $(: It is used to explicitly show/hide the vbox and its content )
    <variable>vTab3</variable>
</vbox> $(: end-notbook-tab="Tab 3" )

sets the visible attribute to false. This makes the Settings tab invisible when
the application starts.

Adding the variable to the definition makes it possible to refer to this vbox
object as an entity and is used to show and hide the vbox and its content.

The following code fragment:

                    <sensitive>true</sensitive>
                    $(: variable name of the notebook and all it contains )
                    $(: used to explicitly manage the notebook - like refreshing it )
                    <variable>vNotebook</variable>
                    $(: which tab to show when the control is first created and page=x attribute is not set )
                    $(: which tab to show when the control is refreshed )
                    <input file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</input>
                    $(: save the tab number when tabs are switched )
                    $(: used to restore the "last seen tab" when showing/hiding the settings tab )
                    <output file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT</output>
                    <action signal="focus-out-event" x-save-last-tab-number-in="output file">save:vNotebook</action>
                </notebook> $(: end Notebook definition )

$(: End Notebook definition -------------------)

        </hbox> $(: end Notebook container definition )

defines the variable for the entire notebook object – vNotebook. This variable
is used to trigger the “save” action, which gets executed whenever tabs are
changed, and to refresh the notebook, which causes the focus-out-event to be
delivered to the notebook object and thus cause the currently active tab number
to be written to the output file.

Elsewhere the content of the output file is copied to the input file so that the
correct tab is activated.

Consider the code below.

            $(: invisible entry for persisting the state of the toggle )
            $(: fnToggleSettingsTab toggles the value )
            <entry visible="false">
                <default>false</default>
                <variable>vSettingsToggle</variable>
                <input>fnToggleSettingsTab</input>
            </entry>

 First, we define an invisible “entry” object which we use to persist the
“state” of the settings tab – hidden or shown.

Consider the related code below:

# -- Post UI Assembly Functions - used from UI after it is assembled ------------------------------------
#
# --------------------
# fnToggleSettingsTab - flips settings toggle
# controls whether the settings tab is visible or hidden 
# switches value of the entry to which it is hooked between true and false each time it is invoked
#
fnToggleSettingsTab() {
    [[ "${vSettingsToggle}" == "true" ]] && echo "false" || echo "true"
}
export -f fnToggleSettingsTab

Here we define a function which cases the value of the variable vSettingsToggle
to be true or false, toggling between one and the other value each time the
function is executed.

Consider the following code, which makes use of the foregoing:

            $(: button which toggles between displying and hiding the settings tab )
            <button width-request="35" homogenous="true" image-position="0" use-underline="true"
              tooltip-text="Configure URLs and Credentials">
                <input file icon="ibus-setup"></input>
                <width>16</width>
                <variable>vSettingsButton</variable>
                $(: set toggle to opposite settings )
                <action>refresh:vSettingsToggle</action> 
                $(: hide the settings tab and restore the "last tab" value so that the tab shown before the button is clicked )
                $(: is shown when the settings tab is hidden )
                <action condition="command_is_false(echo \$vSettingsToggle)">hide:vTab3</action>
                <action condition="command_is_false(echo \$vSettingsToggle)">cp ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action> 
                $(: show the settings tab and save the "last tab" value so that the tab shown when the button is clicked )
                $(: is shown whent he settings are hidden again )
                <action condition="command_is_true(echo \$vSettingsToggle)">show:vTab3</action>
                <action condition="command_is_true(echo \$vSettingsToggle)">echo 2 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action> 
                $(: cause the changes to be reflected in the UI )
                <action>refresh:vNotebook</action>
            </button>

 Here we define a button with no label and with the icon image somewhat
indicative of its function. The button has a variable so that it can be
manipulated.

Each time the button is clicked the “refresh:vSettingsToggle” action causes the
vSettingsToggle invisible entry to execute the function associated with its
“input” attribute. This function alternates between emitting the literals true
and the literal false to stdout, which sets the variable to the corresponding
value.

The action_is_false condition checks the value of the vSettingsToggle and causes
its action to be executed if the value is false. In this case the result is that
the settings tab gets hidden and the saved value of the last active tab before
the settings button was clicked is copied to the file used as input to the
notebook object.

The action_is_true condition checks the value of the vSettingsToggle and causes
its action to be executed if the value is true. In this case the result is that
the settings tab gets shown and the value of the active tab is explicitly set to
2 (the third tab – 0-based numbering) in the file used as input to the notebook
object.

Finally the refresh:vNotebook action is executed and as a consequence the UI is
updated to show the results of the manipulations discussed above.

This example shows how notebook tabs can be shown and hidden on demand, how a
button can be instrumented to conditionally execute actions on other objects and
how active tab can be explicitly set at runtime depending on the needs of the UI
and the logic it implements.


SHOWING AND HIDING THE ENTIRE NOTEBOOK

In this example the entire notebook is alternately hidden and replaced with a
completely different object, of the same size, and then shown again. The example
shows how a “toggle” button can be simulated with two buttons of the same size
which are alternately shown and hidden.

This is not so much an example of Notebook use as it is an example of
dynamically replacing content of the window with different content of the same
size, simulating dynamic screen refresh.

Consider the screenshots:



Click the “Show Info” button and see the entire Notebook disappear and get
replaced with different content, and the text of the “Show Info” button label
apparently changing to “Hide Info”. Notice, too, the “settings” button getting
disabled and re-enabled depending on whether the Notbook content is visible.



Execute the following commands to recreate the application.

mkdir -pv /tmp/scripts
cd /tmp/scripts
> ex32.sh
chmod ug+x ex32.sh

geany ex32.sh & # copy and paste the code blow until ## EOSOURCE
#!/bin/bash

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    mkdir -p ${LOCAL_DATA_DIR}
    rm -R -f ${LOCAL_DATA_DIR}
}
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

# name temporary files and place them in the directory which will get deleted on termination of the script (most of the time)
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use instead of numeric values
source $(dirname ${0})/gtkdialog.constants

WIN_TITLE="XDS.b Registry Browser"

# set initial notebook page - this determines which tab is initially shown
echo 0 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE

# Common size of all notebook content panels
#
_HEIGHT_REQUEST=375
_WIDTH_REQUEST=570

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}" icon-name="${WIN_ICON}" decorated="${WIN_DECORATED}" resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}" skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}" allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true" name="win0">
    <vbox>

        <hbox homogeneous="true" sensitive="true" visible="true"> $(: begin Notebook container definition )

                 <notebook $(: begin notebook definition )
                    height-request="${_HEIGHT_REQUEST}"
                    width-request="${_WIDTH_REQUEST}"
                    tab-labels="Requests|Patients|Settings" xx-tab-labels="which will be shown on tabs"
                    page="1" xx-page="0 based tab number which will be initially shown"
                    enable-popup="true" xx-enable-popup="right-click will bring a list of tabs to select from"
                    show-border="true" xx-show-border="does not seem to do anything visible"
                    tab-border="2" xx-tab-border="how much space around text of tab label"
                    tab-hborder="2" xx-tab-hborder="how much space to the left and right of the tab label text"
                    tab-vborder="2" xx-tab-vborder="how much space to above and below the tab label text"
                    show-tabs="true" xx-show-tabs="as the name says - if false only the content of the 'page=x' tab will show"
                    homogeneous="true" xx-homogeneous="make the width of tabs the same"
                    space-fill="true"
                    space-expand="true"
                    scrollable="false" xx-scrollable="if notebook container width less than the width of all tabs adds left/right arrows to navigate between tabs"
                    tab-pos="${TAB_POS_ABOVE}"
                    border-width="0"
                    sensitive="true"
                    tooltip-markup="<span size='small'>This is an example of a <b>Notebook</b></span>"
                    has-tooltip="true"
                    visible="true"
                    >

$(: TAB 1 ------------------------------------)
                    <vbox xx-notbook-tab="Tab 1">
                        <vbox spacing="2">
                            <text><label>Requests Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 1" )

$(: TAB 2 -----------------------------------)
                    <vbox xx-notbook-tab="Tab 2">
                        <vbox spacing="2">
                            <text><label>Patient Panels Go Here</label></text>
                        </vbox>
                    </vbox> $(: end-notbook-tab="Tab 2" )

$(: TAB 3 ------------------------------------)
                    $(: make this tab initially invisible by setting visible="false")
                    <vbox xx-notbook-tab="Tab 3" visible="false">
                        <vbox>
                            <text><label>Settings Panels Go Here</label></text>
                        </vbox>
                        $(: Variable name of the vbox/tab. )
                        $(: It is used to explicitly show/hide the vbox and its content )
                        <variable>vTab3</variable>
                    </vbox> $(: end-notbook-tab="Tab 3" )

$(: End of tab content definitions -----------)

                    <sensitive>true</sensitive>
                    $(: variable name of the notebook and all it contains )
                    $(: used to explicitly manage the notebook - like refreshing it )
                    <variable>vNotebook</variable>
                    $(: which tab to show when the control is first created and page=x attribute is not set )
                    $(: which tab to show when the control is refreshed )
                    <input file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</input>
                    $(: save the tab number when tabs are switched )
                    $(: used to resore the "last seen tab" when showing/hiding the settings tab )
                    <output file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT</output>
                    <action signal="focus-out-event" x-save-last-tab-number-in="output file">save:vNotebook</action>
                </notebook> $(: end Notebook definition )

$(: End Notebook definition -------------------)

            <variable>vHBoxNotebook</variable>
        </hbox> $(: end Notebook container definition )

$(: alternative content - replaces the Notebook when shown - initially invisible )
        <hbox 
            height-request="${_HEIGHT_REQUEST}"
            width-request="${_WIDTH_REQUEST}"
            homogeneous="true" sensitive="true" visible="false" 
            >
            <vbox width-request="${_WIDTH_REQUEST}">
                <text><label>Patient Details Go Here</label></text>
            </vbox>
            <variable>vHBoxInfo</variable>
        </hbox> $(: vHBoxInfo)

$(: Common object - shown below the notebook and alternate content --)

        <hbox>

            $(: the two buttons below work as a toggle and switch between the notebook object and the text object )
            $(: onlt one button is visible at a time - Both occupy the same space giving is the "toggle" effect )
            $(: This button hides the notebook and the "show info " button, and shows the info panel in its place )
            <button visible="true" sensitive="true" width-request="100" homogenous="true" image-position="0"use-underline="true">
                <label> _Show Info </label>
                <input file icon="gtk-apply"></input>
                <width>16</width>
                <variable>vBtnShowInfo</variable>
                <action>hide:vHBoxNotebook</action> $(: hide notebook )
                <action>hide:vBtnShowInfo</action>  $(: hide self [button] )
                <action>show:vHBoxInfo</action>     $(: show info panel )
                <action>show:vBtnHideInfo</action>  $(: show button that will hide info panel again )
                <action>disable:vSettingsButton</action> $(: disable show settings button - notebook is hidden )
            </button>
            $(: This button hides the info panel and the "hide info " button, and shows the notebook back again )
            <button visible="false" sensitive="true" width-request="100" homogenous="true" image-position="0"use-underline="true">
                <label> _Hide Info </label>
                <input file icon="gtk-apply"></input>
                <width>16</width>
                <variable>vBtnHideInfo</variable>
                <action>hide:vHBoxInfo</action>
                <action>hide:vBtnHideInfo</action>
                <action>show:vHBoxNotebook</action>
                <action>show:vBtnShowInfo</action>
                <action>enable:vSettingsButton</action> $(: enable show settings button - notebook is visible )
            </button>

            $(: invisible entry for persisting the state of the toggle )
            $(: fnToggleSettingsTab toggles the value )
            <entry visible="false">
                <default>false</default>
                <variable>vSettingsToggle</variable>
                <input>fnToggleSettingsTab</input>
            </entry>
            $(: button which toggles between displying and hiding the settings tab )
            <button width-request="35" homogenous="true" image-position="0" use-underline="true"
              tooltip-text="Configure URLs and Credentials">
                <input file icon="ibus-setup"></input>
                <width>16</width>
                <variable>vSettingsButton</variable>
                $(: set toggle to opposite settings )
                <action>refresh:vSettingsToggle</action>
                $(: hide the settings tab and restore the "last tab" value so that the tab shown before the button is clicked )
                $(: is shown when the settings tab is hidden )
                <action condition="command_is_false(echo \$vSettingsToggle)">hide:vTab3</action>
                <action condition="command_is_false(echo \$vSettingsToggle)">cp ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action>
                $(: show the settings tab and save the "last tab" value so that the tab shown when the button is clicked )
                $(: is shown whent he settings are hidden again )
                <action condition="command_is_true(echo \$vSettingsToggle)">show:vTab3</action>
                <action condition="command_is_true(echo \$vSettingsToggle)">echo 2 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action>
                $(: cause the changes to be reflected in the UI )
                <action>refresh:vNotebook</action>
            </button>

            <button width-request="100"
              homogenous="true"
              image-position="${BTN_IMG_POS_LEFT}"
              use-underline="true"
              can-default="true" xx-info="has-default must have can-default"
              has-default="true" xx-info="has-default and can-default must both be true for default to work"
              >
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
        </hbox>
    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EODECK

# -- Post UI Assembly Functions - used from UI after it is assembled ------------------------------------
#

# --------------------
# fnToggleSettingsTab - flips settings toggle
# controls whether the settings tab is visible or hidden
# switches value of the entry to which it is hooked between true and false each time it is invoked
#
fnToggleSettingsTab() {
    [[ "${vSettingsToggle}" == "true" ]] && echo "false" || echo "true"
}
export -f fnToggleSettingsTab

# -- run the UI -----------------------------------------------------------------------------------------------
case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSOURCE

/tmp/scripts/ex32.sh

In this example an extra hbox with alternate content and two buttons were added
to the example ex31 to accomplish what was required. Inspect the code and figure
out what gets done. The embedded comments provide guidance.


MORE SOPHISTICATED EXAMPLE

The code for example whose screenshot was presented at the beginning of this
article as a tease is provided below. Explore the example to see how the
notebook object and the techniques discussed in this article can be put to use
in developing a useful application. The code related to interaction with the
backends was removed and replaced with data stubs as not relevant to the
gtkdialog discussion.

mkdir -pv /tmp/scripts
cd /tmp/scripts
> notebook.sh
chmod ug+x notebook.sh
geany notebook.sh & # until ## EOSOURCE
#!/bin/bash

:<<'COMMENT == ====================================================='
    XDS.b Registry Browser
COMMENT == =====================================================

appVersion=1.0.4
echo "Loading ${BASH_SOURCE[0]} version ${appVersion} ..." 1>&2
echo "Starting ${0} version ${appVersion} ..." 1>&2

# make bash strict
set -e
set -u
set -o pipefail

# this idiom adds a --debug flag and defines the expansion of dbg - if expanded to : rest of command is ignored
[ "--debug" = "${1:-}" ] && export dbg="" || export dbg=:

# make ERR trap global
set -o errtrace

# make directory for temporary files and have it and the content blown away at exit
#
export LOCAL_DATA_DIR="/dev/shm/$(basename ${0})"
$dbg echo 'LOCAL_DATA_DIR--->>>'"${LOCAL_DATA_DIR}"'<<<---' 1>&2
mkdir -p ${LOCAL_DATA_DIR}

fnHlrRemoveTmporaryFilesOnExit() {
    # remove all temporary files by blowing away the directory which contains them
    verify="" # -v
    mkdir -p ${verify} ${LOCAL_DATA_DIR}
    rm ${verify} -R -f ${LOCAL_DATA_DIR}
}
# Trap the signal "zero"
trap fnHlrRemoveTmporaryFilesOnExit 0 # clean up after any program end.

fnHlrProcessERR(){
    MYSELF="$0"   # equals to my script name
    LASTLINE="$1" # argument 1: last line of error occurence
    LASTERR="$2"  # argument 2: error code of last command
    echo "${MYSELF}: ${FUNCNAME} : line ${LASTLINE}: exit status of last command: ${LASTERR}" 1>&2
    local frame=0
    while caller $frame; do
      ((frame++));
    done
    echo "$*"
    fnHlrRemoveTmporaryFilesOnExit
}
export -f fnHlrProcessERR
# Trap the ERR signal - not as usefull as all that, but
trap 'fnHlrProcessERR 859 4175' ERR

export LC_ALL=C # disable unicode support
export oldPOSIXLY_CORRECT=${POSIXLY_CORRECT:-}
$dbg echo '${POSIXLY_CORRECT}-->>'"${POSIXLY_CORRECT:-}"'<<<---' 1>&2
unset POSIXLY_CORRECT   # disable posix compliance - it prevents process substitution working

# name temporary files
#
export MAIN_DIALOG_FILE="${LOCAL_DATA_DIR}/MAIN_DIALOG_FILE_${USER}_${BASHPID}.gtkdialog"
export baseSOAPExchangeFileName="rls_browser_${USER}_${BASHPID}"
export SOAPRequestFileName="${LOCAL_DATA_DIR}/${baseSOAPExchangeFileName}_request.xml"
export SOAPResponseFileName="${LOCAL_DATA_DIR}/${baseSOAPExchangeFileName}_response.xml"
export SOAPErrorFileName="${LOCAL_DATA_DIR}/${baseSOAPExchangeFileName}_response.error"
export SOAPResponseFormattedFileName="${LOCAL_DATA_DIR}/${baseSOAPExchangeFileName}_response.xml.xml"

$dbg echo '$MAIN_DIALOG_FILE--->>>'"$MAIN_DIALOG_FILE"'<<<---'
$dbg echo '$baseSOAPExchangeFileName--->>>'"$baseSOAPExchangeFileName"'<<<---'
$dbg echo '$SOAPRequestFileName--->>>'"$SOAPRequestFileName"'<<<---'
$dbg echo '$SOAPResponseFileName--->>>'"$SOAPResponseFileName"'<<<---'
$dbg echo '$SOAPErrorFileName--->>>'"$SOAPErrorFileName"'<<<---'
$dbg echo '$SOAPResponseFormattedFileName--->>>'"$SOAPResponseFormattedFileName"'<<<---'

# store config properties in the same directory as the script - not checking for permissions
#
export selfConfigPath="${0%%.sh}.properties"
export patientXSLPath="${0%%.sh}.xsl"

# -- Pre UI Assembly Functions - used to provide UI text ------------------------------------
#
fnUtlVarGet() {
    [[ ! -e $LOCAL_DATA_DIR/$1 ]] && touch $LOCAL_DATA_DIR/$1
    local input
    read -r input < $LOCAL_DATA_DIR/$1
    echo -n "$input"
}
export -f fnUtlVarGet

fnUtlVarSet() {
    [[ ! -e $LOCAL_DATA_DIR/$1 ]] && touch $LOCAL_DATA_DIR/$1
    echo "$2" > $LOCAL_DATA_DIR/$1
}
export -f fnUtlVarSet

evbb(){ echo '<eventbox>'; }
evbe(){ echo '</eventbox>'; }
#evbb(){ echo ''; }
#evbe(){ echo ''; }

# --
fnLoadConfiguration() {
    export gvDBHost="localhost"
    export gvDBPort="1521"
    export gvDBService="adtdb"
    export gvLOGDBUsername="LOG"
    export gvLOGDBPassword="password"
    export gvPIXServiceURL="http://pixservice:7654/PIXService"
    export gvOHMPIDomainOID="1.2.3.4.5.6.7.8.9"
}
fnLoadConfiguration

## first time init
fnUtlVarSet "PATIENT_DB_QUERY_FIRST_TIME" "TRUE"
fnUtlVarSet "REQUEST_DB_QUERY_FIRST_TIME" "TRUE"

# patient info file - start empty
echo '' > ${LOCAL_DATA_DIR}/PATIENT_INFO

##====================================================
[ -z ${GTKDIALOG:-} ] && GTKDIALOG=gtkdialog

# load symbolic constants I use intsead of numeric values
source $(dirname ${0})/gtkdialog.constants

WIN_TITLE="XDS.b Registry Browser"

# set initial notebook page
echo 1 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE

_HEIGHT_REQUEST=375 # 425
_WIDTH_REQUEST=570 # 490

# construct UI
cat <<-EODECK > ${MAIN_DIALOG_FILE}
<window title="${WIN_TITLE}"
        icon-name="${WIN_ICON}"
        decorated="${WIN_DECORATED}"
        resizable="${WIN_RESIZABLE}"
        window_position="${WIN_POS}"
        skip_taskbar_hint="${WIN_SKIP_TASKBAR_HINT}"
        allow-grow="${WIN_ALLOW_GROW}"
        auto-refresh="true"
        name="win0"
        >
    <vbox>

        <hbox homogeneous="true" xx-homogeneous="make the width of tabs the same"
            sensitive="true"
            visible="true"
            >
                <notebook $(: start notebook )
                    height-request="${_HEIGHT_REQUEST}" 
                    width-request="${_WIDTH_REQUEST}" 
                    tab-labels="Requests|Patients|Settings" xx-tab-labels="works"
                    xxxpage="0" xx-page="works, 0 based tab number which will be initially shown"
                    enable-popup="true" xx-enable-popup="right-click will bring a list of tabs to select from"
                    show-border="true" xx-show-border="does not seem to do anything visible"
                    tab-border="2" xx-tab-border="how much space around text of tab label"
                    tab-hborder="2" xx-tab-hborder="how much space to the left and right of the tab label text"
                    tab-vborder="2" xx-tab-vborder="how much space to above and below the tab label text"
                    show-tabs="true" xx-show-tabs="as the name says - if false only the content of the 'page=x' tab will show"
                    homogeneous="true" xx-homogeneous="make the width of tabs the same"
                    space-fill="true"
                    space-expand="true"
                    scrollable="false" xx-scrollable="if notebook container width less than the width of all tabs adds left/right arrows to navigate between tabs"
                    tab-pos="${TAB_POS_ABOVE}"
                    border-width="0"
                    sensitive="true"
                    xx-tooltip-markup="<span size='small'>This is a <b>Tooltip</b></span>"
                    xx-has-tooltip="true"
                    visible="true"
                    >

$(: TAB 1 ------------------------------------)

                    <vbox begin-notbook-tab="Tab 1">
                        <vbox spacing="2">
                            <hbox>
                                <button width-request="100" xalign="${XALIGN_LEFT}" can-default="true" has-default="true"
                                space-expand="false" space-fill="false" use-underline="true"
                                tooltip-text="Find requests received by XDS Registry" can-default="true"
                                has-default="true">
                                    <width>16</width>
                                    <input file icon="gtk-find"></input>
                                    <label> _Find </label>
                                    <variable export="false">btnFind</variable>
                                    <action type="clear">treeResultsRequestsList</action>
                                    <action type="refresh">treeResultsRequestsList</action>
                                </button>
                                <text xpad="3">
                                    <label>""</label>
                                </text>
                            </hbox>

                            <frame  Registry Requests  >
                                <hbox homogenous="true" space-expand="true" space-fill="true" space-expand="true"
                                  selectable="true" can-focus="true"
                                  height-request="280">
                                    <tree homogeneous="true" space-expand="true" space-fill="true" rules-hint="true"
                                      xalign="${XALIGN_CENTRE}" headers-visible="true" headers-clickable="true"
                                      hover-expand="false" hover-selection="false"
                                      selection-mode="${TREE_SELECTION_MODE_SINGLE}" vscrollbar-policy="${VSCROLLBAR_AUTOMATIC}"
                                      selectable="true" can-focus="true"
                                      exported-column="2" stock-id="gtk-dialog-question" auto-refresh="true"
                                      column-type="string|string|string|string|string"
                                      column-visible="true|true|false|true|true"
                                      column-sizing="1|1|1|1|0"
                                      >
                                        <label>"Request|From IP|Message Id|Timestamp|Pass"</label>
                                        <variable>treeResultsRequestsList</variable>
                                        <input>fnDoGetRequests</input>
                                        <action function="clear">vPatientInfo</action>
                                        <action>fnShowRequestInfo "\$treeResultsRequestsList"</action>
                                    </tree>
                                </hbox>
                            </frame>
                        </vbox>
                        <variable>vTab1</variable>
                    </vbox> $(: end-notbook-tab="Tab 1" )

$(: TAB 2 -----------------------------------)

                    <vbox xx-notbook-tab="Tab 2">
                        <vbox spacing="2">
                            <hbox>
                                <button width-request="100" xalign="${XALIGN_LEFT}" can-default="true" has-default="true" space-expand="false" space-fill="false" use-underline="true"
                                tooltip-text="Find Patients registered in XDS Registry" can-default="true" has-default="true">
                                    <width>16</width>
                                    <input file icon="gtk-find"></input>
                                    <label> _Find </label>
                                    <variable export="false">btnFind</variable>
                                    <action type="clear">treeResultsIDsList</action>
                                    <action type="refresh">treeResultsIDsList</action>
                                </button>
                                <text xpad="3">
                                    <label>""</label>
                                </text>
                            </hbox>

                            <frame  Registered Patients  >
                                <hbox homogenous="true" space-expand="true" space-fill="true" selectable="true" can-focus="true"
                                  height-request="280">
                                    <tree homogeneous="true" space-expand="true" space-fill="true" rules-hint="true"
                                      xalign="${XALIGN_CENTRE}" headers-visible="true" headers-clickable="true"
                                      hover-expand="false" hover-selection="false"
                                      selection-mode="${TREE_SELECTION_MODE_SINGLE}" vscrollbar-policy="${VSCROLLBAR_AUTOMATIC}"
                                      selectable="true" can-focus="true"
                                      exported-column="1" stock-id="gtk-dialog-question" auto-refresh="true"
                                      column-type="string|string|string|string"
                                      column-visible="false|true|false|true"
                                      column-sizing="1|1|1|0"
                                      >
                                        <label>"UUID|Patient Id|LastUpdated|Status"</label>
                                        <variable>treeResultsIDsList</variable>
                                        <input>fnDoGetPatientIDs</input>
                                        <action>fnShowPatientInfo "\$treeResultsIDsList"</action>

                                        <action>disable:vSettingsButton</action>
                                        <action>hide:vHBoxNotebook</action>

                                        <action>show:vHBoxInfo</action>
                                        <action>show:vBtnHideInfo</action>

                                        <action>refresh:vPatientInfo</action>
                                    </tree>
                                </hbox>
                            </frame>
                        </vbox>
                        <variable>vTab2</variable>
                    </vbox>

$(: TAB 3 ------------------------------------)

                    <vbox xx-notbook-tab="Tab 3" visible="false" enabled="false" comment="This is where applicaiton properties go">
                        <hbox>
                            <vbox homogenous="true" space-fill="true" space-expand="true">
                                <frame   XDS Registry Database   >
                                    <vbox height-request="85" x-width-request="220">
                                        <hbox spacing="2">
                                            $(evbb)<text><label>Hostname</label></text>$(evbe)
                                            $(evbb)<entry can-focus="true" has-focus="true" has-frame="false">
                                                <input>echo \$gvDBHost</input>
                                                <variable>vDBHost</variable>
                                                <width>120</width>
                                                <height>22</height>
                                            </entry>$(evbe)
                                        </hbox>
                                        <hbox spacing="2">
                                            $(evbb)<text><label>Port Number</label></text>$(evbe)
                                            $(evbb)<entry has-frame="false">
                                                <input>echo \$gvDBPort</input>
                                                <variable>vDBPort</variable>
                                                <width>60</width>
                                                <height>22</height>
                                            </entry>$(evbe)
                                            $(evbb)<text width-request="58"><label>""</label></text>$(evbe)
                                        </hbox>
                                        <hbox spacing="2">
                                            $(evbb)<text><label>Service Name</label></text>$(evbe)
                                            $(evbb)<entry has-frame="false">
                                                <input>echo \$gvDBService</input>
                                                <variable>vDBService</variable>
                                                <width>70</width>
                                                <height>22</height>
                                            </entry>$(evbe)
                                            $(evbb)<text width-request="48"><label>""</label></text>$(evbe)
                                        </hbox>
                                    </vbox>
                                </frame>
                            </vbox>
                           
                            <vbox homogenous="true" space-fill="true" space-expand="true">
                                <frame   LOG Database Schema   >
                                    <vbox height-request="85" x-width-request="220">
                                        <hbox spacing="2">
                                            $(evbb)<text><label>Username</label></text>$(evbe)
                                            $(evbb)<entry has-frame="false">
                                                <input>echo \$gvLOGDBUsername</input>
                                                <variable>vLOGDBUsername</variable>
                                                <width>120</width>
                                                <height>22</height>
                                            </entry>$(evbe)
                                        </hbox>
                                        <hbox spacing="2">
                                            $(evbb)<text><label>Password</label></text>$(evbe)
                                            $(evbb)<entry caps-lock-warning="true" has-frame="false">
                                                <input>echo \$gvLOGDBPassword</input>
                                                <variable>vLOGDBPassword</variable>
                                                <width>120</width>
                                                <height>22</height>
                                                <sensitive>password</sensitive>
                                            </entry>$(evbe)
                                        </hbox>
                                        <hbox>
                                            <button image-position="0" x="valid 0-3 - left, right, above, below"
                                  use-underline="true"
                                  >
                                                <label> T_est Connectivity </label>
                                                <input file icon="gtk-network"></input>
                                                <width>16</width>
                                                <action>fnTestDBConnectivity "true" "\$vDBHost" "\$vDBPort" "\$vDBService" "\$vLOGDBUsername" "\$vLOGDBPassword"</action>
                                            </button>
                                        </hbox>
                                    </vbox>
                                </frame>
                            </vbox>
                        </hbox>

                        <frame   PIX Service  >
                            <vbox height-request="60">
                                <hbox spacing="2">
                                    $(evbb)<text><label>OHMPI Domain OID</label></text>$(evbe)
                                    $(evbb)<entry caps-lock-warning="true" has-frame="false">
                                        <input>echo \$gvOHMPIDomainOID</input>
                                        <variable>vOHMPIDomainOID</variable>
                                        <width>340</width>
                                        <height>22</height>
                                    </entry>$(evbe)
                                </hbox>
                                <hbox spacing="2">
                                    $(evbb)<text><label>URL</label></text>$(evbe)
                                    $(evbb)<entry caps-lock-warning="true" has-frame="false">
                                        <input>echo \$gvPIXServiceURL</input>
                                        <variable>vPIXServiceURL</variable>
                                        <width>440</width>
                                        <height>22</height>
                                    </entry>$(evbe)
                                </hbox>
                                <hbox>
                                    <button image-position="0" x="valid 0-3 - left, right, above, below"
                                  use-underline="true"
                                  >
                                        <label> Test C_onnectivity </label>
                                        <input file icon="gtk-network"></input>
                                        <width>16</width>
                                        <action>fnTestURLConnectivity "true" "\$vPIXServiceURL"</action>
                                    </button>
                                </hbox>
                            </vbox>
                        </frame>
                        <variable>vTab3</variable>
                    </vbox>

                    <sensitive>true</sensitive>
                    <variable>vNotebook</variable>
                    <input file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</input>
                    <output file>${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT</output>
                    <action signal="focus-out-event" x-save-last-tab-number-in="output file">save:vNotebook</action>
                </notebook>

            <variable>vHBoxNotebook</variable>
        </hbox> $(: vHBoxNotebook )

        <hbox height-request="${_HEIGHT_REQUEST}"
            width-request="${_WIDTH_REQUEST}"
            show-border="true" xx-show-border="does not seem to do anything visible"
            homogeneous="true" xx-homogeneous="make the width of tabs the same"
            sensitive="true"
            visible="false"
            >
            <vbox width-request="${_WIDTH_REQUEST}">
                <text><label>Patient Details</label></text>
              <frame>
                <tree file-monitor="false" auto-refresh="false" vscrollbar-policy="${VSCROLLBAR_NEVER}"
                      homogeneous="true" space-expand="true" space-fill="true" rules-hint="true" headers-visible="false"
                      headers-clickable="false" hover-expand="false" hover-selection="false" selection-mode="0"
                      >
                    <label>a|b</label>
                    <variable>vPatientInfo</variable>
                    <input file>${LOCAL_DATA_DIR}/PATIENT_INFO</input>
                    <sensitive>true</sensitive>
                </tree>
              </frame>
            </vbox>
            <variable>vHBoxInfo</variable>
        </hbox> $(: vHBoxInfo)

        <hbox>
            <button visible="false" sensitive="true" width-request="100" homogenous="true" image-position="0"use-underline="true">
                <label> _Dismiss </label>
                <input file icon="gtk-apply"></input>
                <width>16</width>
                <variable>vBtnHideInfo</variable>
                <action>hide:vHBoxInfo</action>
                <action>show:vHBoxNotebook</action>
                <action>hide:vBtnHideInfo</action>
                <action>enable:vSettingsButton</action>
            </button>

            <button width-request="35" homogenous="true" image-position="0" use-underline="true"
              tooltip-text="Configure URLs and Credentials">
                <input file icon="ibus-setup"></input>
                <width>16</width>
                <variable>vSettingsButton</variable>
                <action>refresh:vSettingsToggle</action> $(: set toggle to opposite settings )
                <action condition="command_is_false(echo \$vSettingsToggle)">hide:vTab3</action>
                <action condition="command_is_false(echo \$vSettingsToggle)">cp ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE_OUT ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action>
                <action condition="command_is_true(echo \$vSettingsToggle)">show:vTab3</action>
                <action condition="command_is_true(echo \$vSettingsToggle)">echo 2 > ${LOCAL_DATA_DIR}/NOTEBOOK_PAGE</action>
                <action>refresh:vNotebook</action>
            </button>

            <button width-request="100"
              homogenous="true"
              image-position="0" x="valid 0-3 - left, right, above, below"
              use-underline="true"
              can-default="true" xx-info="has-default must have can-default"
              has-default="true" xx-info="has-default and can-default must bot be true for default to work"
              xxx-default="if entry has focus default setting for button does not work"
             >
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">QUIT</action>
            </button>
            <text xpad="3">
                <label>""</label>
            </text>
            <entry visible="false">
                <default>false</default>
                <variable>vSettingsToggle</variable>
                <input>fnToggleSettingsTab</input>
            </entry>
        </hbox>
    </vbox>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EODECK

#== Styles ==========================================
export GTK2_RC_FILES=${LOCAL_DATA_DIR}/gtkrc
cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}
style "tab3TextBoxes" {
    font_name="Sans Regular 10"
}
style "notebook" {
    GtkNotebook::tab-overlap = -2
    GtkNotebook::tab-curvature = 0
    xthickness = 1
    ythickness = 1
}
style "frameTitleStyle" {
    fg[NORMAL]      = "navy"
    font_name="CM Roman CE Regular 10"
}
style "entryStyle" {
    font_name="Monospace Regular 10"
    fg[NORMAL]="black"
}
style "headerStyle" = "frame" {
    fg[NORMAL]      = "navy"
    font_name="CM Roman CE Regular 12"
}

widget_class "*<GtkNotebook>" style "notebook"
widget_class "*.<GtkFrame>.<GtkLabel>" style "frameTitleStyle"
widget_class "*.<GtkEntry>*" style "entryStyle"
class "GtkEntry" style "entryStyle"

widget_class "<GtkWindow><GtkVBox><GtkNotebook><GtkVBox><GtkHBox><GtkEventBox>" style "tab3TextBoxes"
widget_class "<GtkWindow><GtkVBox><GtkNotebook><GtkVBox><GtkHBox><GtkEventBox><GtkLabel>" style "tab3TextBoxes"

widget_class "*<GtkNotebook>*<GtkEventBox>" style "tab3TextBoxes"
widget_class "*<GtkNotebook>*<GtkEventBox><GtkLabel>" style "tab3TextBoxes"

widget "win0.GtkVBox.GtkHBox.GtkVBox.GtkLabel" style "headerStyle"
EOSTYLEDEF

# -- Post UI Assembly Functions - used from UI after it is assembled ------------------------------------
#
# --------------------
# fnToggleSettingsTab
fnToggleSettingsTab() {
    [[ "${vSettingsToggle}" == "true" ]] && echo "false" || echo "true"
}
export -f fnToggleSettingsTab

# --------------------
# fnTestDBConnectivity "true/false" "\$vDBHost" "\$vDBPort" "\$vDBService" "\$vADTDBUsername" "\$vADTDBPassword"
fnTestDBConnectivity() {
    lvShowOKDialog="${1}"
    lvDBHost="${2}"
    lvDBPort="${3}"
    lvDBService="${4}"
    lvDBUsername="${5}"
    lvDBPassword="${6}"
    [[ "${lvShowOKDialog}" = "true" ]] && {
        yad \
            --center --width=400 --image="gtk-dialog-authentication" --window-icon="gtk-dialog-authentication" \
            --title="Failed connection" \
            --text="Failed to connect to database schema ${lvDBUsername}\nConnection: ${lvDBHost}:${lvDBPort}/${lvDBService}" \
            --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
    } || :
    return 0;
}
export -f fnTestDBConnectivity

# -----------------------------------------------
# fnTestURLConnectivity "true/false" "\$vPIXServiceURL"
fnTestURLConnectivity() {
    local lvShowOKDialog="${1}"
    local lvPIXServiceURL="${2}"
    fnUtlInvalidSomethingAlert "No Service" "PIX/PDQ Service is not available\nConnectivity test failed";
}
export -f fnTestURLConnectivity

# -----------------------------
# fnDoGetPatientIDs
fnDoGetPatientIDs() {
    [[ "$(fnUtlVarGet 'PATIENT_DB_QUERY_FIRST_TIME')" = "TRUE" ]] && {
        fnUtlVarSet "PATIENT_DB_QUERY_FIRST_TIME" "FALSE"
        return 0;
    } || :
    echo 'urn:uuid:7e762cc0-209b-406e-a752-5072a0ada6b5|0000000005^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|A'
    echo 'urn:uuid:ab0c5276-8df6-487d-96a4-1a531afa28a4|0000000004^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|A'
    echo 'urn:uuid:a2c7fe79-b830-40ff-8199-0db747873b31|0000000003^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|A'
    echo 'urn:uuid:a61c5ae9-366e-4e1f-955d-ff05571a37ee|0000000001^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|I'
    echo 'urn:uuid:ec3f4416-d3c8-4c48-90a1-068aaa06a6db|0000000002^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|A'
    echo 'urn:uuid:ae82e878-e5f0-4c4e-950b-22576de0a002|0000000000^^^&1.2.3.4.5.6.7.8.9&ISO|05-MAY-17|A'
}
export -f fnDoGetPatientIDs

# ---------------------------------
# fnDoGetRequests
fnDoGetRequests() {
#dbg=

    [[ "$(fnUtlVarGet 'REQUEST_DB_QUERY_FIRST_TIME')" = "TRUE" ]] && {
        fnUtlVarSet "REQUEST_DB_QUERY_FIRST_TIME" "FALSE"
        return 0;
    } || :
    echo 'PIDFEED.Add|localhost|b2e6eabb-7b32-409e-b6b2-eebddfdb56b6|20170505104319294|T'
    echo 'PIDFEED.Merge|localhost|1bb4afcb-8934-447a-9bdb-6c9066add528|20170505104424232|T'
    echo 'PIDFEED.Add|localhost|15b837e2-4963-441a-94b9-d7dc5861961a|20170505105033304|T'
    echo 'SubmitObjectsRequest.b|localhost|3c1c0037-0e20-4dd4-8c1b-819c2f58c301|20170505105141384|T'
    echo 'SQ.b FindDocuments|localhost|87010111-7513-44cd-ae1e-55324d1f4d64|20170505105249668|T'
    echo 'SQ.b GetSubmissionSetAndContents|localhost|b8616a98-3ca6-4cfe-98f0-0c4cd2209237|20170505105346116|T'
    echo 'SQ.b GetDocuments|localhost|0666024e-a16e-4edc-9bf1-51a5320308f5|20170505105426666|T'
    echo 'SQ.b FindDocuments|localhost|b0e67663-2f10-457a-a69d-22a0fb83d88a|20170505105519734|T'
    echo 'PIDFEED.Add|localhost|5e199a85-a105-4d86-b513-64a41580fc02|20170505115447445|T'
    echo 'SubmitObjectsRequest.b|localhost|1774af74-5332-49ac-a4bc-4a490ba8e8d5|20170505115740370|T'
    echo 'SQ.b FindDocuments|localhost|2e22762c-aa82-41a5-82eb-7fbbcff532ee|20170505115933070|T'
    echo ""
#dbg=:
}
export -f fnDoGetRequests

# ---------------------------------
# fnShowRequestInfo \$treeResultsRequestsList
fnShowRequestInfo() {
    local lvMessageId="${1}"
    fnUtlInvalidSomethingAlert "No Service" "XDS.b Regsitry is not able to supply data\nCannot show details for message ${lvMessageId}";
}
export -f fnShowRequestInfo

# --------------------------------
# fnShowPatientInfo "\$treeResultsIDsList"
fnShowPatientInfo() {
    local lvPatientId="${1}"
#dbg=
    echo "Patient Identifier:|${lvPatientId}" > ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Status|active'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo '|'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Demographics:'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Title|'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Give Name|John'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Family Name|Doe'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Gender|M'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Date of Birth|10/11/1999'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Social Security Number|200809101'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo '|'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Address:'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Street Address|33 Berry Street'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'City/Town|North Sydney'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'State|NSW'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo 'Postal Code|2060'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
    echo '|'  >> ${LOCAL_DATA_DIR}/PATIENT_INFO
#dbg=:
}
export -f fnShowPatientInfo

## --------------------------------------
function fnUtlInvalidSomethingAlert() {
invTitle=${1:-}
invMessage=${2:-}
    yad \
        --center --width=400 --image="gtk-dialog-error" --window-icon="gtk-dialog-error" --title="${invTitle}" --text="${invMessage}" \
        --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"
}
export -f fnUtlInvalidSomethingAlert

# -- run the UI -----------------------------------------------------------------------------------------------
case ${1:-} in
    -d | --dump) more "${MAIN_DIALOG_FILE}" ;;
    -f | --file) $GTKDIALOG --center --file=${MAIN_DIALOG_FILE} ;;
    -v | --variable) export MAIN_DIALOG=$(cat ${MAIN_DIALOG_FILE}); $GTKDIALOG --center --program=MAIN_DIALOG ;;
    *) $GTKDIALOG --file=${MAIN_DIALOG_FILE} ;;
esac
## EOSOURCE

/tmp/scripts/notebook.sh

I hope that this article helps you work with the gtkdialog notebook object.

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
bash • gtkdialog comments • gtkdialog documentation • gtkdialog examples •
gtkdialog hide • gtkdialog notebook • gtkdialog notebook example • gtkdialog
reference • gtkdialog show • gtkdialog structure • infrastructure demo •
infrastructure demonstration • Linux demo • Linux demo image • Linux
demonstration image • Linux GUI • Linux UI • technical demo • technical
demonstration

Apr 28


YAD – STYLING A DIALOG WITH A LABEL AND A BUTTON

By Czapski Michael Demo Building, yad No Comments »

It turns out that yad dialog boxes can be styles using exactly the same
technique as that I documented in the previous article for styling gtkdialog
applications. In this article I document the serendipitous discovery I made when
working with styles for gtkdialog applications so that you can take advantage of
it if you feel the need.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad is installed, as discussed in the article “Install yad
and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


APPLYING STYLES TO A YAD DIALOG BOX WITH A LABEL AND A BUTTON

See my earlier article, “gtkdialog – Applying styles to gtkdialog applications”,
at
https://blogs.czapski.id.au/2017/04/gtkdialog-applying-styles-to-gtkdialog-applications,
for context to this article – specifically for the discussion, references and
examples of styles that can be applied to GTK objects, both these that are used
by the gtkdialog applicaitns and evidently also by yad “applications”.

I am providing the example here, since the styling is covered in the previous
article, and the yad “application” in this example is trivial.

So, consider the following set of commands and a Bash script:

> /tmp/yadstyling_01.sh
chmod ug+x /tmp/yadstyling_01.sh
cat <<-'EODECK' > /tmp/yadstyling_01.sh
#!/bin/bash

export GTK2_RC_FILES=/tmp/gtkrc

cat <<-'EOSTYLEDEF' > ${GTK2_RC_FILES}

pixmap_path "/usr/share/backgrounds/cosmos/:/usr/share/backgrounds/nature/:/usr/share/backgrounds/scenery/:/usr/share/icons/gnome/scalable/actions"

style "windowStyle" {
    engine "pixmap" {
    image
      {
          function        = FLAT_BOX
          file            = "Garden.jpg"
          border          = { 0, 0, 0, 0 }
          stretch         = TRUE
          overlay_file    = "media-playback-pause.svg"
          overlay_stretch = FALSE
      }
  }
}

style "contentStyle" {
    fg[NORMAL]      = "brown"    # colour of the content text
    font_name="CM Roman CE Regular 10"
    GtkLabel::use-markup = TRUE
}

style "buttonStyle" {
    fg[NORMAL]      = "white"   # button label text colour
    fg[PRELIGHT]    = "yellow"  # button label text colour when mouse is over the button
    bg[NORMAL]      = "blue"    # button background colour
    bg[PRELIGHT]    = "navy"    # button background colour when mouse is over the button
    font_name       = "Fixed Italic 14"
    xthickness      = 6         # adds "border" on either side of the button
    ythickness      = 6         # adds "border" above and below the button
}

## the paths below apply the named styles to the yad dialog text and button

# gives the entire dialogue background colour
widget_class "<GtkWindow>" style "windowStyle"

# give the Button background colour
widget_class "<GtkWindow><GtkVBox><GtkContainer><GtkButton>" style "buttonStyle"

# gives the button text colour
widget_class "<GtkWindow><GtkVBox><GtkContainer><GtkButton><GtkContainer><GtkHBox><GtkLabel>" style "buttonStyle"

# gives the dialog text colour
widget_class "<GtkWindow><GtkVBox><GtkHBox><GtkVBox><GtkLabel>" style "contentStyle"

EOSTYLEDEF

yad \
    --center --width=400 --image="gtk-dialog-authentication" --window-icon="gtk-dialog-authentication" \
    --title="Succesful connection" \
    --text="Succesfully <b>connected</b> to <span size='large' color='black'>database</span> schema" \
    --button=" Dismiss!gtk-ok!Dismiss this dialogue:0"

EODECK

/tmp/yadstyling_01.sh

Executing this script produces the following:



Critical to the success of this endeavour are the wiget_class paths in the
.gtkrc style definitions. The specific paths I am using I worked out by trial
and error. This is the only way short of asking the authors,
https://www.mankier.com/1/yad#Authors, for the GTK paths to the various variants
of yad dialogues.

Experiment with the various style settings and see what you get.

 

Tagged with: bash GUI • bash yad • CentOS • create demo • create demonstration •
demo • demonstration • GTK • GTK GUI • infrastructure demo • infrastructure
demonstration • Linux demo • Linux demo image • Linux demonstration image •
Linux GUI • Linux UI • technical demo • technical demonstration • yad • yad bash
• yad examples

Apr 22


GTKDIALOG – APPLYING STYLES TO GTKDIALOG APPLICATIONS

By Czapski Michael gtkdialog 2 Comments »

In this article I explore application of styles, colours, backgrounds, fonts,
etc., to various gtkdialog application objects.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad and gtkdialog are installed, as discussed in the
article “Install yad and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


EXAMPLE OF STYLING – TEASER

There is a way to “style” gtkdialog objects, which works in some instances, and
which can be used as appropriate.

Consider the following example, which was implemented in an earlier article:

scriptName=ex19
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
    echo "$(date)"
}
export -f fnEchoDateTime

echo '
style "bgWhite" { bg[NORMAL] = "#FFFFFF" }
style "fgWhite" { fg[NORMAL] = "#FFFFFF" }
style "bgBlack" { bg[NORMAL] = "#000000" }
style "bgRed" { bg[NORMAL] = "#FF0000" }
style "fgRed" { fg[NORMAL] = "#FF0000" }
style "bgGreen" { bg[NORMAL] = "#FFFF00" }
style "fgGreen" { fg[NORMAL] = "#FFFF00" }
style "bgBlue" { bg[NORMAL] = "#0000FF" }
style "fgBlue" { fg[NORMAL] = "#0000FF" }

widget "MyWindowBg" style "bgBlack"
widget "MyWindowBg.GtkVBox.GtkHBox.MyButtonBg" style "bgGreen"

widget "MyWindowBg.GtkVBox.myEVB" style "bgBlue"

widget_class "*<GtkFrame>.GtkLabel" style "fgWhite"
widget_class "*<GtkFrame>.*.GtkLabel" style "fgGreen"
widget_class "*<GtkButton>.*.GtkLabel" style "fgRed"

' > /tmp/gtkrc_mono
export GTK2_RC_FILES=/tmp/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    name="MyWindowBg"
> 
    <vbox>
        <eventbox name="myEVB" above-child="false" visible-window="true">
        <frame   Description  >
            <text><label>This is an example window.</label></text>
        </frame>
        </eventbox>
        <hbox>
            <button name="MyButtonBg" use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

Here we define and use GTK styles to change foreground and/or background colours
of the various objects.

Here is how the application window looks.



This is just a brief teaser. How to apply styles to objects, what works and what
does not, etc., is covered in the following sections.


 SOME SOURCES OF INFORMATION

Let’s explore some sources of information for on styles that might work with
gtkdialog objects.

https://en.wikibooks.org/wiki/GTK%2B_By_Example/Theming

http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut.html – worth
exploring for the underlying concepts and considerations

http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-19.html –
specific discussion of styles


CONSTRUCTING STYLE AND MAKING GTKDIALOG USE IT

GTK loads and processes the GTK resource file, if one exists, which amongst
other things can contain style definitions. This is the method we use to provide
styles and define the objects to which they are to be applied. Consider the
following excerpt from example ex21 in the next section:

GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}

echo '
style "windowStyle" {
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
}

widget "MyWindow" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

The four key things to note are:

 1. The named style is defined (there can be as many styles as are needed)
 2. The style is associated with one or more “targets” – widget, widget_class or
    class (more on that in the next section)
 3. The styles and associations are written to a GTK resource file
 4. The shell variable GTK2_RC_FILES which points to that file is then exported
    so that it can be used by gtkdialog at runtime to locate the styles and
    objects to which to apply them

I am using different style resource files for different applications so that
each of my gtkdialog scripts manages its own styles.

The style definition follows this pattern:

style "<name>" {
    <style definitions>
}

Style are specified using syntax defined by GTK for gtk resources.

Consult GTK resources for reference:

 * https://developer.gnome.org/gtk2/stable/ – Gnome GTK 2 developer
   documentation in general
 * https://developer.gnome.org/gtk2/stable/gtk2-Resource-Files.html#gtk2-Resource-Files.description
   – Specific section on GTK resource files

Other discussions can be consulted at:

 * http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-19.html –
   specific discussion of styles
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes is tutorial on all
   manner of GTK appearance including styles.


STYLING THE WINDOW OBJECT AND ITS CHILDREN

Styles can be applied to the Window object using the name attribute of the
Window object and the appropriate definition of style.

Consider the following example to set the baseline for applying styles to a
Window object:

scriptName=ex20
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

GTKDIALOG=gtkdialog

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


This produces:



This is the default appearance in my environment without applying any styles.

It is possible, if perhaps not as useful as might at first appear, to apply an
image as a repeating motif to the window’s background. If the image is smaller
than the window it will be repeated. If the image is larger than the window the
top left portion of the image will be used.

Consider the following example:

scriptName=ex21
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

# pixmap images must be in the same folder as the gtkrc file 
# since the bg_pixmap style directive does not accept file path - just file name
#
# copy some images to the gtkrc file location
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}

GTKDIALOG=gtkdialog

echo '
style "windowStyle" {
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
}

widget "MyWindow" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono 
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

This produces the following:



Let’s consider the definition of the style:

GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}

echo '
style "windowStyle" {
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
}

widget "MyWindow" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

Here we set the background pixmap to use the emblem-unreadable.png. This image
will be repeated horizontally and vertically as the window background. The image
file must reside in the same directory as the resource file containing this
style definition (later in this article we will learn how to configure the gtkrc
so that the image does not have to be copied over). In the example above, we
copy it from its original location if it is not already there. You may or may
not have this specific image in your environment. If you don’t have it use a
different one.

The object to which the style is to be applied can be specified in a number of
ways.

GTKRC_LOCATION=/tmp
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp -v /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}

echo '
style "windowStyle" {
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
}

widget "MyWindow" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

In the example above we use the name of the widget to which this style is to be
applied. The name of the Window object, in this case, is used to make this
association:

<window
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>

Let’s modify this style so that it changes styles of other components. Consider
the following example:

scriptName=ex22
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

# pixmap images must be in the same folder as the gtkrc file
# since the bg_pixmap style directive does not accept file path - just file name
#
# copy some images to the gtkrc file location
[[ ! -f ${GTKRC_LOCATION}/bits.xpm ]] && cp /usr/share/emacs/23.1/etc/images/ezimage/bits.xpm ${GTKRC_LOCATION} # same place as the rc file
[[ ! -f ${GTKRC_LOCATION}/kill-group.xpm ]] && cp /usr/share/emacs/23.1/etc/images/gnus/kill-group.xpm ${GTKRC_LOCATION}
[[ ! -f ${GTKRC_LOCATION}/emblem-unreadable.png ]] && cp /usr/share/icons/gnome/32x32/emblems/emblem-unreadable.png ${GTKRC_LOCATION}

GTKDIALOG=gtkdialog

echo '
style "windowStyle" {
#    bg_pixmap[NORMAL] = "kill-group.xpm"
#    bg_pixmap[NORMAL] = "bits.xpm"
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
#    bg[NORMAL] = "#989898" # Grayish
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
#    fg[NORMAL] = "#FFFFFF"
}

widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

This produces the following:



Note that the window background acquires light blue tint. Note too that nothing
shows the dark blue colour. This is because the window object does not have
anything that has a visible foreground. The objects which have foreground, like
text and buttons, are nested inside the window object but since the style is to
be applied to the widget by name this style does not get propagated to child
objects.

Edit the example and change the two lines from:

widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"

to

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"

then re-execute the modified example. This produces the following:



Specifying ‘widget_class “<GtkWindow>*”‘ cause the style to be applied to the
Window objects and all the child objects in the hierarchy. In this case the
visible outcome is that the text of all the child objects (the only aspect of
these objects that has foreground to which to apply a foreground colour) turned
dark blue.

Experiment by changing style definition of fg[NORMAL] to use different colours.
There is discussion of GTK colours and how they can be specified at
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes/SymbolicColors.

One can apply styles to named widgets, to widget classes (and child objects) and
to GTK classes. There is a resource at
https://www.cs.tut.fi/lintula/manual/gtk/gtk/gtk-resource-files.html which has a
discussion of this topic in the section “Pathnames and patterns”.

Here we are going at a bit of a tangent, working with objects inside the Window,
to see how the window style is inherited and overridden.

Change the style definition in the example to read as follows and execute to see
the outcome:

echo '
style "windowStyle" {
#    bg_pixmap[NORMAL] = "kill-group.xpm"
#    bg_pixmap[NORMAL] = "bits.xpm"
    bg_pixmap[NORMAL] = "emblem-unreadable.png"
#    bg[NORMAL] = "#989898" # Grayish
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
#    fg[NORMAL] = "#FFFFFF"
}

style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}    

widget "MyWindow" style "windowStyle"
#widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style "buttonStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono

This produces the following:



Please note that specifying targets to which to apply styles is a bit tricky and
involves style merge priorities. For example the following will not produce the
desired outcome:

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style "buttonStyle"

 The windowStyle will be applied to all child objects and the style to be
applied to class GtkButton will be ignored. This is the consequence of GTK style
application priority – see
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes#Priority.

Change the definition as follows and re-execute the example:

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"

 This produces the following, which is what we expected to achieve in the first
place:



The child foreground style is used for everything except the GtkButton class
objects, because the GtkButton class style has the highest priority as far as
button styles go. See
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes#Priority for
discussion of this topic.

The style merging needs some exploration and some experimentation. Consider the
following change:

style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}   

style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
}   

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
#widget_class "*.GtkFrame.*" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"

Execute the example and see that the frame acquired a red border but the label
text and the text inside the frame are still the style of the window object.

Uncomment the ‘widget_class “*.GtkFrame.*” …’ and re-execute the example. Note
that the Frame title is now maroon but so is the label text inside the text
object. That’s because the specification “*.GtkFrame.*” applies the style to the
Frame and all it contains.

Modify the specification to read as shown below and re-execute the example.

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"

Note that the frame label is still maroon but the text object’s label is dark
blue, that is it inherits foreground colour from the Window style. This is
because we restricted the style application to GtkLabel under the GtkFrame only.

Let’s now explore how text can be styled with font specification. Reference:
https://developer.gnome.org/pango/stable/pango-Fonts.html.

Consider the following example:

scriptName=ex23
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

GTKDIALOG=gtkdialog

echo '
style "windowStyle" {
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
#    font_name="Bitstream Charter Italic 10"
#    font_name="Caladea Bold 10"
#    font_name="URW Gothic L Semi-Bold 12"
#    font_name="URW Chancery L Medium Italic 16"
#    font_name="Standard Symbols L 12"
#    font_name="Nimbus Sans L Condensed 14"
#    font_name="Fixed Bold 14"
    font_name="Carlito Bold 12"
}

style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}   

style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
}   

widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <fontbutton name="ButtonFont" width-request="100">
                <variable>btnFont</variable>
            </fontbutton>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

Note the font_family style property. The string consists of the Font Family
followed by font weight and font size.

Consider the font specifications. Uncomment one at a time and see the results.

style "windowStyle" {
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
#    font_name="Bitstream Charter Italic 10"
#    font_name="Caladea Bold 10"
#    font_name="URW Gothic L Semi-Bold 12"
#    font_name="URW Chancery L Medium Italic 16"
#    font_name="Standard Symbols L 12"
#    font_name="Nimbus Sans L Condensed 14"
#    font_name="Fixed Bold 14"
    font_name="Carlito Bold 12"
}

Use the font selection button to see what fonts, weights and sizes are available
and copy a string to use when applying font style to specific objects.

Add different font specification to the frameStyle and see the results.

style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
    font_name="URW Chancery L Medium Italic 18"
}

This produces the following:



The following example uses a different method to configure the window background
image and specifies the pixmap_path so that images do not need to be copied to
the same directory as the resource file. See some material at
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine

scriptName=ex24
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

GTKDIALOG=gtkdialog

echo '

pixmap_path "/usr/share/backgrounds/cosmos/:/usr/share/backgrounds/nature/:/usr/share/backgrounds/scenery/:/usr/share/icons/gnome/scalable/actions"

style "windowStyle" {
  engine "pixmap" {
    image
      {
          function        = FLAT_BOX
          file            = "Garden.jpg"
#          file            = "gtk-execute.svg"
#          file            = "list-remove.svg"
#          file            = "media-playback-pause.svg"
          border          = { 0, 0, 0, 0 }
          stretch         = TRUE
          overlay_file    = "media-playback-pause.svg"
          overlay_stretch = FALSE
      }
  }
}

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

This produces the following (note the “Pause” image over the top of the Garden
image. I expected this image to repeat but it did not and there is no
information on whether it can and how to make it.



We used the “pixmap” engine in the example above. That implies that there are
other engines so set’s have a go at different theme engines to see what outcomes
we will get.

Let’s install gtk2-engines* package.

sudo yum -y install gtk2-engines*

The following engines are now available.

ls -c1 /usr/lib64/gtk-2.0/2.10.0/engines | sort

libclearlooks.so
libcrux-engine.so
libglide.so
libhcengine.so
libindustrial.so
libmist.so
libpixmap.so
libredmond95.so
libsvg.so
libthinice.so

To work out the name of the engine strip the leading “lib” and the trailing
“.so” and use what’s left.

Explore the results of executing the following example while successively
uncommenting the different engine. The quick test of the differences is the
dialog box which is produced after clicking on the Font button.

scriptName=ex25
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKRC_LOCATION=/tmp

GTKDIALOG=gtkdialog

echo '

pixmap_path "/usr/share/backgrounds/cosmos/:/usr/share/backgrounds/nature/:/usr/share/backgrounds/scenery/:/usr/share/icons/gnome/scalable/actions"

style "windowStyle" {
  # from /usr/lib64/gtk-2.0/2.10.0/engines
#  engine "clearlooks" {}
#  engine "crux-engine" {}
#  engine "glide" {}
#  engine "hcengine" {}
#  engine "industrial" {}
#  engine "mist" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/MistEngine
#  engine "pixmap" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine
  engine "redmond95" {}
#  engine "thinice" {}
}

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"

' > ${GTKRC_LOCATION}/gtkrc_mono
export GTK2_RC_FILES=${GTKRC_LOCATION}/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <fontbutton></fontbutton>
            <button name="ButtonExit" use-underline="true" width-request="100" has-focus="true">
                <label> _Quit </label>
                <input file icon="gtk-quit"></input>
                <width>16</width>
                <action function="exit">vWindow</action>
            </button>
            <button name="ButtonCancel" use-underline="true" width-request="100">
                <label> _Cancel </label>
                <input file icon="gtk-cancel"></input>
                <width>16</width>
                <action function="closewindow">vWindow</action>
            </button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action>
</window>

EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

With the redmond95 engine I see something like this:



With the glide engine I see something like:



With clearlooks I see something like:



Unfortunately I could not find much information on what configuration options
are available for each of these engines. About the most I could find was for the
pixmap engine. Redmond95 is said to have no configuration options.  I was not
able to find any information about the industrial engine.

If you are inclined to explore the gtk themes there some information on the
topic on the Internet. I did not follow up on this to any great extent as it si
only marginally relevant to what I am trying to do in this series of articles.

There is some material on this topic at http://www.orford.org/gtk, particularly
section on fonts.

https://git.enlightenment.org/themes/detourious.git/plain/gtk/detourious/gtk-2.0/gtkrc
has a huge set of property specs which could be of interest for experimentation.
Inspect what that you see there and have a go at styling the example. For
example, change the style and target definitions in the example above to read as
follows and see what you can see. Experiment with changing the target from
widget_class to widget and changing foreground and background colours.

style "windowStyle" {
  # from /usr/lib64/gtk-2.0/2.10.0/engines
  engine "clearlooks" {}
#  engine "crux-engine" {}
#  engine "glide" {}
#  engine "hcengine" {}
#  engine "industrial" {}
#  engine "mist" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/MistEngine
#  engine "pixmap" {} # https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine
#  engine "redmond95" {}
#  engine "thinice" {}

    base[NORMAL]      = "#ff0000"
    base[PRELIGHT]    = "#ffff00"
    base[ACTIVE]      = "#ff00ff"
    base[SELECTED]    = "#00ff00"
    base[INSENSITIVE] = "#0000ff"

#    fg[NORMAL]      = "#ff0000"
#    fg[PRELIGHT]    = "#ffff00"
#    fg[ACTIVE]      = "#ff00ff"
#    fg[SELECTED]    = "#00ff00"
#    fg[INSENSITIVE] = "#0000ff"

    bg[NORMAL]      = "#ff0000"
    bg[PRELIGHT]    = "#ffff00"
    bg[ACTIVE]      = "#ff00ff"
    bg[SELECTED]    = "#00ff00"
    bg[INSENSITIVE] = "#0000ff"

}

#widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"

I see the following:



There are more examples at https://people.kth.se/~e95_fla/ex/gtkrc and,
undoubtedly, elsewhere.


NAMING STYLE TARGETS

It is possible and I imagine quite desirable to be able to apply specific style
to an individual component – say a label in a text object, the title of the
frame object and similar.

Examples shown so far use the style definitions to define styles and associate
these styles with specific objects by name (widget), specific widget
“collections” (widget_class) or specific classes of widget (class).

NAMED TARGETS

The ‘widget “name” style “style-name”‘ assignment cause the named style to be 
applied to a named object. Consider example ex23. As given it produces the
following look:



This is accomplished with the following specification that went into the gtk
resource file:

style "windowStyle" {
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
    font_name="Carlito Bold 12"
}

style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}   

style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
}   

widget_class "<GtkWindow>*" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
class "GtkFrame" style : highest "frameStyle"

Our GUI definition starts like this:
<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
...


Let’s modify the style and target definitions to read:

style "windowStyle" {
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
    font_name="Carlito Bold 12"
}

style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}   

style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
}   

widget "MyWindow" style "windowStyle"
##widget_class "<GtkWindow>*" style "windowStyle"
##class "GtkButton" style : highest "buttonStyle"
##widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
##class "GtkFrame" style : highest "frameStyle"

Executing the example with this change produces:



Because we are assigning the windowStyle to the object whose name is “MyWindow”
the style only applies to that object. The window gets a light blue background
but neither foreground colour nor font produce visible effects. This is because
the window object does not have any elements to which foreground or font style
directives can be applied.

This is an example of styling named objects.

Please note that styles are merged according to a set of built in rules so the
effect you get may not be the effect you expect. This is discussed in passing
elsewhere in this article but not formally or completely. Some experimentation
will be required and some frustration is to be expected.

CONTAINMENT HIERARCHY TARGETS

Let’s say that we want to apply the foreground and background colours to all
objects with components to which foreground and background colours can be
applied, starting with the window object and going down the containment
hierarch.

Change the style assignment definition to read:

##widget "MyWindow" style "windowStyle"
widget_class "<GtkWindow>*" style "windowStyle"
##class "GtkButton" style : highest "buttonStyle"
##widget_class "*.GtkFrame.GtkLabel" style "frameStyle"
##class "GtkFrame" style : highest "frameStyle"

Note the syntax: ‘<GtkWindow>*‘. Here the trailing asterisk means ‘and all down
the hierarchy’

This produces the following:



Dark blue foreground colour has been applied to every component within the
window containment hierarchy which has an element to which foreground colour can
be applied. In this case these are labels of the text and button objects.

Light blue background colour has been applied to every component within the
window containment hierarchy which has an element to which background colour can
be applied. In this case these are the window background and the ‘border’ of the
frame component.

Change the widget_class target to ‘<GtkWindow><GtkVBox><GtkFrame>*‘ and execute
the example. This produces the following:



Note that the window colour reverted to the default as did the colour of the
button labels text. This is because we explicitly targeted the style at the
frame object and its content.

Let’s zoom in a bit more into the frame and apply styling to just the frame
title with the following syntax: ‘<GtkWindow><GtkVBox><GtkFrame><GtkLabel>‘.
Note that we explicitly target just the frame label and nothing else.  Executing
the example produces the following:



As we would expect only the frame title is explicitly styled.

This discussion introduces, in passing, the object  hierarchy, or as I am
calling it the containment hierarchy. Frame label is contained within the frame,
which is contained within the vbox, which is contained within the window. This
is almost the explicit hierarchy we have in our GUI definition in the example:

<window 
    title="My Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    border-width="5"
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <text name="MyText">
                <label>This is an example window.</label>
            </text>
        </frame>
        ...

“Almost” because the “label” (GtkLabel) object is not explicitly specified in
the definition of the frame so one has to know or guess. Compare this to the
definition of the text object in which label is explicitly defined.

One way to not have to know or guess is to specify the asterisk instead of
<GtkLabel> in the target specification but that would style the frame label and
everything else that takes foreground and background colour and is contained
inside the frame as shown in the previous use case.

Let’s try the following – ‘<GtkWindow><GtkVBox><GtkFrame><GtkText><GtkLabel>‘.
Executing the example with this change produces a plain window with no styling
explicitly applied to any element.

Hang on, why is this not working? This is the object hierarchy, right? The GUI
definition says so!

Well, here is where knowing to look at the “Widget Construction” section at the
developer documentation at
http://www.murga-linux.com/puppy/viewtopic.php?t=69188&start=2 may give clues as
to what might be happening. See, for example, discussion of how the various
button types are constructed, paying attention to the containment hierarchy. To
quote an instance:

> <button> containing a label and an image is a GtkButton containing a GtkHBox
> or GtkVBox itself containing a GtkLabel and GtkImage (stock images are loaded
> by a dedicated function and hardcoded to GTK_ICON_SIZE_BUTTON)

Right. With this hint we can perhaps deduce that the text object is actually a
GtkHBox or a GtkVBox containing the GtkLabel object and we could try the
following, in turn:

widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkHBox><GtkLabel>" style "windowStyle"

Nope.

widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkLabel>" style "windowStyle"

Bingo! Only the inner text label got styled so this is the precise target
specification for the label of the text object.



Note in passing that even though we have a background colour defined the label
does not have a visible background.

Let’s see if the GtkVBox has a colourable background:

widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox>" style "windowStyle"

Nope. My experience is that neither HBox nor VBox have backgrounds that can be
coloured.

 

So how would one go about providing a colour background to a label?



Let’s change the definition of the content of the frame to read as follows:

...
    name="MyWindow"
> 
    <vbox>
        <frame   Description  >
            <eventbox>
                <text name="MyText">
                    <label>This is an example window.</label>
                </text>
            </eventbox>
        </frame>
        ...

Let’s change the styling target to read:

widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkEventBox>" style "windowStyle"

Notice what is happening. The frame contains the inner vbox which contains
whatever goes inside the frame. All the same, the <eventbox> object, which is
normally invisible, can have its background coloured, and by extension can be
used to apply styles to the objects it contains as would be achieved with the
addition of the trailing asterisk to the specification.

Executing the example with this change produces the following:



The label now has background colour.

The bottom line here is that using precise widget_class targets requires the
knowledge of how the hierarchy is implemented (see the web page quoted above),
and some guesswork and experimentation, like in the case of a label within text
within frame.

TARGETING CLASSES

Finally, one can apply style classes of objects.

Let’s try the following change:

style "windowStyle" {
    bg[NORMAL] = "lightblue"
    fg[NORMAL] = "darkblue"
}
style "buttonStyle" {
    bg[NORMAL] = "green"
    fg[NORMAL] = "brown"
}   
style "frameStyle" {
    bg[NORMAL] = "red"
    fg[NORMAL] = "maroon"
}   
style "labelStyle" {
    fg[NORMAL] = "darkblue"
    font_name="Bitstream Charter Italic 10"
}    

widget_class "<GtkWindow><GtkVBox><GtkFrame><GtkVBox><GtkEventBox>" style "windowStyle"
class "GtkButton" style : highest "buttonStyle"
class "GtkFrame" style : highest "frameStyle"
class "GtkLabel" style "labelStyle"

Executing the modified example produces the following:



The class target targets all objects of the class, applying the same style to
all.

Note the “style : highest” notation. This explicitly overrides the default style
merge mechanism, somewhat discussed under the heading “binding styles to widget
classes:” in http://www.orford.org/gtk/, and under the heading of “Priority” in
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes.

Though the document at http://www.orford.org/gtk/ is entitles “Gtk2 Theme
Creation Guide” it is actually quite enlightening for anyone who wants to style
objects in gtkdialog-based applications, as I have been doing in this article.
The “GTK Theming Tutorial” at
https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes is similarly useful in
this context even tough it might appear off-topic at first glance.


GTKRC EXAMPLES

Finally, review the gtkrc files for the various themes to see what you can see
there and to see if any of it might be of use to you when styling gtkdialog
widgets.

ls -C1 /usr/share/themes/*/gtk-2.0/gtkrc | sort

/usr/share/themes/ClearlooksClassic/gtk-2.0/gtkrc
/usr/share/themes/Clearlooks/gtk-2.0/gtkrc
/usr/share/themes/Crux/gtk-2.0/gtkrc
/usr/share/themes/Glider/gtk-2.0/gtkrc
/usr/share/themes/Glossy/gtk-2.0/gtkrc
/usr/share/themes/HighContrast/gtk-2.0/gtkrc
/usr/share/themes/HighContrastInverse/gtk-2.0/gtkrc
/usr/share/themes/HighContrastLargePrint/gtk-2.0/gtkrc
/usr/share/themes/HighContrastLargePrintInverse/gtk-2.0/gtkrc
/usr/share/themes/Industrial/gtk-2.0/gtkrc
/usr/share/themes/Inverted/gtk-2.0/gtkrc
/usr/share/themes/LargePrint/gtk-2.0/gtkrc
/usr/share/themes/LowContrast/gtk-2.0/gtkrc
/usr/share/themes/LowContrastLargePrint/gtk-2.0/gtkrc
/usr/share/themes/Mist/gtk-2.0/gtkrc
/usr/share/themes/Raleigh/gtk-2.0/gtkrc
/usr/share/themes/Simple/gtk-2.0/gtkrc
/usr/share/themes/Slider/gtk-2.0/gtkrc
/usr/share/themes/ThinIce/gtk-2.0/gtkrc


TOOLS FOR EXPLORING WIDGET STYLING AND COLOURS

GTK2-STYLES WIZARD

Andrew Karuse, who published the book “Foundations of GTK+ Development”
(http://www.apress.com/us/book/9781590597934), made available at
https://github.com/grayasm/git-main/tree/master/tutorial/andrew_krause_gtk%2B/13_all_together
the  source and related resources for a C++ application which allows one to
visually work with GTK styles for the various GTK widgets and save the resulting
GTK resources to a file. This in turn allows one to get the exact syntax needed
to implement these styles for the various widgets.

There is a YouTube video on this: https://youtu.be/EzkQAbP4My8. Watch the video
to see how to get and build the wizard, and how to use it construct a valid
gtkrc resource file that can be used with gtkdialog.

I have not been able to find an archive containing the sources and resources for
the convenience of the downloader and the zip archive downloadable from the
publisher’s book site does not have this application. While this makes life a
bit more difficult it is still possible to get and build the application.

The link quoted above gets one to this:



Download each file, one at a time, to a convenient directory, say gtk2-styles.
Make sure to follow the links until you see the raw source or the image and
download these.

cd ./gtk2-styles

In gtk2-styles.cpp change the declaration of the const char* rcfile so that it
does not initialise. If it does the make will fail with C++ errors.

struct AppData
{
//     const char* rcfile=NULL;
       const char* rcfile;

Build the application

make -k

Run the application

./gtk2-styles

Change styles of things for which you want to change styles then File->Save As
the file.

Copy the styles you changed into a gtkrc file which you use at runtime.

Here is an example of what the application looks like for a GtkButton:



Note the following:

 1. One can change colours (click on the colour box and one will get the usual
    colour picker) and the changes will be immediately reflected in the UI.
 2. One can change the numeric values for the various properties and the changes
    will be immediately reflected in the UI.
 3. Once can check and uncheck the checkboxes and the changes will be
    immediately reflected in the UI.
 4. One can hover over the buttons and click them to see the results of changes.

Explore the application and then File-Save As to a file to see what a gtkrc file
would look like with the changes you made to the styles provided by the default
theme. Note that the saved file will contain definitions for all the objects. If
you make small changes use just the changes in your gtkdialog application’s rc
file.

Note that if you do not make any changes and save the rc file it will be empty.

GPICK COLOUR PICKER

Sometimes one might want to match colours of the various elements in one’s
application with colours in used in some other application. For example I had an
occasion recently to build a gtkdialog-based applicaiotn that would invoke a
filrefox with a web page which used specific colours for specific elements like
table headers and fonts. To match the colour scheme I needed to know the hex
values of the specific colours. The handy tool I found on line is the gpick
colour picker. It is available at http://www.gpick.org/. The source distribution
requires a bunch of tools to build so rather than building from sources I opted
for finding and downloading the pre-built rpm.

cd ~/Downloads
wget ftp://fr2.rpmfind.net/linux/epel/6/x86_64/gpick-0.2.4-4.el6.x86_64.rpm
sudo yum localinstall -y gpick-0.2.4-4.el6.x86_64.rpm

gpick window looks like this when first started:



Note the Hex value of the colour under the cursor, which is what I was after.
There are a bunch of options and functionality I did not go into. Explore.

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
background • gtkdialog bash • gtkdialog color • gtkdialog colour • gtkdialog
comments • gtkdialog documentation • gtkdialog examples • gtkdialog reference •
gtkdialog structure • gtkdialog styles • gtkdialog styling • gtkdialog visual
styles • infrastructure demo • infrastructure demonstration • Linux demo • Linux
demo image • Linux demonstration image • Linux GUI • Linux UI • technical demo •
technical demonstration

Apr 09


GTKDIALOG – EXPLORING THE WINDOW OBJECT ATTRIBUTES AND ACTIONS BY EXAMPLE

By Czapski Michael gtkdialog No Comments »

In this article I explore the gtkdialog Window object, its attributes and
actions. In passing. other gtkdialog objects will be used without much
elaboration, that elaboration intended to follow in subsequent articles.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.

It appears that gtkdialog, based as it seems to be on the GTK object model,
leverages the GTK object hierarchy. Consider the reference for the Window object
at http://01micko.com/reference/window.html.

The very first link points to a GtkWindow –
http://developer.gnome.org/gtk2/2.24/GtkWindow.html.

In the GTK object hierarchy,
https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.object-hierarchy,
the Window object is several levels below the GObject, the topmost object.



As briefly discussed in the previous article the GtkWindow, and consequently the
gtkdialog Window, object inherit, as I understand it, from the objects higher up
in the hierarchy. This will come into play when we explore attributes that can
be set for a Window, and actions that can be configured for a Window.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog. For convenience I posted
the export of the VirtualBox image which would have been built if the reader
followed all the articles in the series “Build a Linux-based Infrastructure
Solution Demonstration Series” to date, that is to the 8th of March 2017. The
link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.

It also assumes that yad and gtkdialog are installed, as discussed in the
article “Install yad and gtkdialog”
(https://blogs.czapski.id.au/2017/04/gtkdialog-for-rapid-prototyping-of-linux-applications-install-gtkialog-and-yad)


WINDOW OBJECT ATTRIBUTES

The gtkdialog Window object is the outermost visible object in the hierarchy of
gtkdialog objects.

We explored the window object to an extent in the previous article, while
setting the context and discussing comments and similar matters. Let’s now
explore the Window object attributes more.

Reference documentation for the gtkdialog Window object,
http://01micko.com/reference/window.html, provides a table of attributes
specific to this gtkdialog object and makes a reference to ancestor class
properties.

Attributes that can be configured for the window widget are defined in the
widget’s reference page see
https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.object-hierarchy,
section Properties –
https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.properties

Some of them are useful and some of them are not, as far as I am concerned or
can empirically determine. Changing values of some of them do not have visible
consequences.

Not all attributes/properties are recognised and acted upon by  gtkdialog. Some
of the properties are inherited from the parent objects, like GtkContainer and
GtkWidget. For example, border-width, which defines the amount of space between
the window frame and the window content, is inherited from the GtkContainer.

Similarly, sensitive property is inherited from the GtkWidget and when set to
true effectively disables everything inside the window, except for the window
decorations like minimise, maximise and close. An “interesting” side effect of
this is that setting sensitive to false and decorated to false will take away
the means of closing the window except by killing the process which created the
window

Properties like window-position take one of the pre-defined enumeration values.

For window-position see
https://developer.gnome.org/gtk2/2.24/gtk2-Standard-Enumerations.html#GtkWindowPosition
or http://gtk.php.net/manual/en/html/gtk/gtk.enum.windowposition.html (which is
not directly related to gtkdialog as I use it but seems a good enough source of
enumerations which GTK defines and supports.

By the way, tooltip-markup causes warnings to be emitted to the console, which,
apart from being ugly, appear benign.

See the reference page:
file:///home/demo/gtkdialog-0.8.3/doc/reference/window.html

To work out what attributes are actually supported, in this case by the window
widget, we need to do some exploration. Discussion below goes into this to an
extent and I provided most of the useful attributes that can be set, both from
GtkWindow itself and inherited from GtkContainer and GtkWidget.

Let me reproduce the table and expand it to include inherited attributes which
empirical observation leads me to believe have a visual impact on the window
object.

The table below summarised Window attributes/properties and indicates which work
with the gtkdialog and which do not as far as I can tell. “Do not” may well be a
function of me not seeing any visible difference with the property set to
different values. Some ancestor attributes/properties which are not really
useable from gtkdialog are omitted.

Name Description Value Default From Since OK? image-name Image filename



I could not figure out what this does for a Window object.

gtkdialog 0.8.1 block-function-signals Block signal emissions from functions



I am not quite sure what this does for a Window object. See reference for where
this comes from. Perhaps you will get it.
http://www.murga-linux.com/puppy/viewtopic.php?p=544704#544704

true or false false gtkdialog 0.7.21 file-monitor Emit signal when input file(s)
change



If a file is specified as the value of the window’s <input file>xxxx</input>
directive, and this property is set to true, and the content of the file changes
then the signal of type “file-changed” will be emitted. If an <action
signal=”file-changed”>xxx</action> or its variant is defined then the action
will be executed.

true or false false gtkdialog 0.8.1 Y auto-refresh Auto refresh when input
file(s) change.



If a file is specified as the value of the window’s <input file>xxxx</input>
directive, and this property is set to true, and the content of the file changes
then the window’s title bar text will automatically display the content of the
file (or some reasonable leading part of it). If this property is false then the
input file change will not be reflected in the title bar.

true or false false gtkdialog 0.8.1 Y   accept-focus Whether the window should
receive the input focus. The title bar is greyed out on false but objects inside
the window are still active, for example, buttons are clickable on and do their
thing, but keystrokes are not delivered to the window. true or false true
GtkWindow Y allow-grow If TRUE, users can expand the window beyond its minimum
size. true or false true GtkWindow Y allow-shrink If TRUE, the window has no
minimum size. Setting this to TRUE seems pretty useless and perhaps unfriendly.
true or false true GtkWindow Y decorated Whether the window should be decorated
by the window manager, that is whether it should have the title bar and the
various buttons typically present there. true or false true GtkWindow Y
default-height The default height of the window, used when initially showing the
window. Must be >= -1.



The value of this attribute overrides the height-request value if one is
specified.

integer -1 GtkWindow Y default-width The default width of the window, used when
initially showing the window. Must be >= -1.



The value of this attribute overrides the width-request value if one is
specified.

integer -1 GtkWindow Y deletable Whether the window frame should have a close
button. true or false true GtkWindow Y icon-name The icon-name property
specifies the name of the themed icon to use as the window icon. File path
GtkWindow Y mnemonics-visible Whether mnemonics are currently visible in this
window. If buttons are defined and have “use-underline” attribute set to true
and a mnemonic indicated with the “_” before the character in the label, or are
“standard” buttons like OK or cancel, the indicated or default letter in the
label will be underlined when the window is drawn if this property is set to
true. true or false false GtkWindow Y resizable If TRUE, users can resize the
window. true or false true GtkWindow Y skip-pager-hint TRUE if the window should
not be shown in the pager. true or false false GtkWindow ? skip-taskbar-hint
TRUE if the window should not be shown in the task bar true or false false
GtkWindow Y title The title of the window. Overwritten by the <label>…</label>
directive if one is specified string GtkWindow Y type-hint These are hints for
the window manager that indicate what type of function the window has. The
window manager can use this when determining decoration and behaviour of the
window. See enumerations – link below. Does not seem useful in the gtkdialog
context. integer 0 GtkWindow Y window-position The initial position of the
window



GTK_WIN_POS_NONE=0

GTK_WIN_POS_CENTER=1

GTK_WIN_POS_MOUSE=2

Integer [0..2] 0 GtkWindow Y   border-width The amount of whitespace between the
window frame and the content of the window Integer 5 GtkContainer Y  
can-default Whether the widget can be the default widget.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget ? can-focus Whether the widget can accept the
input focus.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget ? has-default Whether the widget is the default
widget.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget ? has-focus Whether the widget has the input
focus.



This does not seem to have any effect when applied to a Window object

true or false false GtkWidget ? has-tooltip Whether this widget has a tooltip.
Disables tooltip display if tooltip is defined for the Window true or false
false GtkWidget Y height-request Override for height request of the widget, or
-1 if natural height should be used.



Has not effect of default-height is specified.

>=0 -1 GtkWidget Y is-focus Whether the widget is the focus widget within the
toplevel.



Does not seem to have any effect when applied to the Window object

true or false false GtkWidget ? name The name of the widget.



Nothing visible happens when this attribute is provided with a value.

string NULL GtkWidget ? receives-default If TRUE, the widget will receive the
default action when it is focused.



I don’t know what that is supposed to accomplish. Nothing visible happens
regardless of the property value.

true or false false GtkWidget ? sensitive Whether the widget responds to input.



FALSE disables all components contained in the window.

true or false TRUE GtkWidget Y style GtkStyle GtkWidget ??? tooltip-markup The
contents of the tooltip for this widget.



Simple markup can be used to call out parts of tooltip text in.

See http://www.murga-linux.com/puppy/viewtopic.php?t=40418 for a markup explorer
tool.

Ineffective if tooltip-disabled is TRUE.

string NULL GtkWidget Y tooltip-text The contents of the tooltip for this
widget.



Ineffective if tooltip-disabled is TRUE.

string NULL GtkWidget Y visible Whether the widget is visible.



It is somewhat self-defeating to make a window invisible on creation unless it
is a “subsidiary” window and can be made visible form some other piece of logic.

true or false true GtkWidget Y width-request Override for width request of the
widget, or -1 if natural width should be used.



Has not effect if default-width is specified.

>=0 -1 GtkWidget Y

The following example includes just about every attribute that can be defined
for a Window object. Experiment with the various settings to see what you can
see.

scriptName=ex09
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2


MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    decorated="true" this="shows the title bar and its nprmal decorations"
    allow-grow="true" this="can resize to be bigger"
    allow-shrink="true" this="can resize to be smaller - including making it practically invisible"
    xx-default-height="200" remove="xx- to enable the attribute and see how that affects height-request"
    xx-default-width="400" remove="xx- to enable the attribute and see how that affects width-request"
    resizable="true" xx-resizable="overrides default-height and default-width if set to false"  this="works"
    deletable="true" xx-deletable="this keep (default) or remove the close button" this="works"
    icon-name="gtk-apply" this="works - shows designated icon at the left of the title bar"
    modal="false" this="does not seem to be doing anything different on true and on false"
    skip-pager-hint="true" this="does not seem to be doing anything different on tru and on false"
    skip-taskbar-hint="false" this="seems to be preventing the window being listed in the window selector when true"
    title="My First Window" this="is selfexplanatory and works"
    window-position="${GTK_WIN_POS_CENTER}"
    border-width="5" xx-border-width="is an inherited GtkContainer property - see object hierarchy at https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.object-hierarchy"
    sensitive="true" xx-sensitive="is an inherited GtkWidget property that disables everything inside the window - see obect hierarchy"
    tooltip-markup="<span size='small'>This is a <b>window tooltip</b></span>"
    icon="gimp" this="does not do anything visible"
    mnemonics-visible="false" this="if buttons have underline for menemonics or are standard buttons mnemonics are initially underlined"
    accept-focus="true" this="if false makes window not focusaable (title bar is gray) - buttons are still clickable"
    window-position="${GTK_WIN_POS_CENTER}"
    auto-refresh="false" goes="with <input file>somefile</input>"
    border-width="5"
    can-default="false"
    can-focus="false"
    can-default="false"
    has-focus="false"
    has-tooltip="true"
    height-request="150" does="not have any effect if default-height is specified"
    width-request="400" does="not have any effect if default-width is specified"
    is-focus="true"
    name="myWindow"
    receives-focus="false"
    sensitive="true"
    xx-tooltip-text="This is a <b>window tooltip</b>"
    visible="true"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <label>Window Label</label>
    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>
$(:<<'COMMENT'
    <input file>/tmp/aa.txt</input>
COMMENT
)
    
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


See https://github.com/GNOME/gtk/blob/master/gdk/gdktypes.h for enumerations.


WINDOW OBJECT DIRECTIVES

Note that the window defines a bunch of window specific child objects, which the
reference calls directives – label, variable, input, etc..  These must be
specified after all the other window child objects else gtkdialog will throw a
hissy fit.

The label directive provides window title if title attribute is not set. If it
is set the label directive is ignored. Consider:

scriptName=ex10
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <label>Window Label</label>
    <variable>vWindow</variable>
$(:<<'COMMENT'
    <input>fnEchoDateTime</input>
    <input file>/tmp/aa.txt</input>
COMMENT
)
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


Consider a variant where the title attribute to the Window object is not
provided.

scriptName=ex11
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <label>Window Label</label>
    <variable>vWindow</variable>
$(:<<'COMMENT'
    <input>fnEchoDateTime</input>
    <input file>/tmp/aa.txt</input>
COMMENT
)
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


The sensitive directive does the same thing as the sensitive attribute to the
window tag – enables or disables window content. Consider:

scriptName=ex12
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <label>Window Label</label>
    <sensitive>false</sensitive>
    <variable>vWindow</variable>
$(:<<'COMMENT'
    <input>fnEchoDateTime</input>
    <input file>/tmp/aa.txt</input>
COMMENT
)
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh



The variable directive names the variable which can be used elsewhere to
reference the window and act upon it, for example disable or enable, activate or
deactivate, show or hide, refresh or clear, or set title. The example below
provides a variable name vWindow to allow the button’s action directive to
trigger the refresh action on the window. When the refresh action signal is
processed the function fnEchoDateTime will be executed and its output will be
provided to the Window object which will use it to set the window title.
Consider the following example. Click the Refresh button a few times with at
least 1 second between clicks and see what happens to the window title.

scriptName=ex13
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
             <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>

    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


The input directive can invoke logic which can return a string to which the
window title will be set when triggered by refresh of the variable named as the
window variable. See example above. This function, as all such functions invoked
by the gtkdialog, is expected to write to the stdout whatever text is supposed
to be the input to the object – in this case the window title.

The output file directive will cause the “value” of this object to be written to
the named file if the save action is triggered. In the case of the window object
the title will be written to the file. Consider:

scriptName=ex14
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Save window data">
                <label> _Save </label>
                <input file icon="gtk-save"></input>
                <width>16</width>
              <action function="save">vWindow</action>
            </button>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>

    <output file>/tmp/gtkd.out</output>

    <action signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


The action directive provides a mechanism for invoking logic when certain kinds
of events affecting the window object occur. The example above used the ‘<action
function="save">…</action>‘ markup to add an action to a button object, to be
invoked when the button is pressed. Another example would be invoking the close
window logic when ESC key is pressed. In the example above, the key-press-event
signal is intercepted in the action directive and if the raw key code was (0x9),
the Escape key, the gtkdialog calls the exit logic and the window is closed.


EXPLORING THE ACTION DIRECTIVE

Let’s consider the following signals, defined in the Window object reference:

Name Description Content Since action signal=”type” Execute command on signal
Shell command action signal=”type” Perform function on signal function:parameter
action signal=”type” condition=”type” Execute command on signal conditionally
Shell command 0.8.3 action signal=”type” condition=”type” Perform function on
signal conditionally function:parameter 0.8.3

In ex13, above, we used the “action function” and “action signal”, to save the
window title to a file and to exit the application respectively. Note that the
reference does not include the “action function” variant but it is supported and
works, as the example illustrates.

Explore the reference for the Window object,
http://01micko.com/reference/window.html, to see the signals and the functions
defined in that document.

The “action condition” construct is perhaps worth exploring as it is explained
what the “_is_true”/
_is_false” is supposed to return. To cut to the chase, the command or the
function is supposed to return the literal text “true” or “false”. The example
below extends the example above by making the save action conditional on the
file not already existing. This is contrived but makes the point.

Consider:

scriptName=ex15
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
    echo "$(date)"
}
export -f fnEchoDateTime

fnAlreadySaved() {
    vFileName="${1}"
    [[ -f ${vFileName} ]] && { echo "true" ; yad --title="File ${vFileName} exists" --text="File ${vFileName} exists - not saving" --center --image="gtk-dialog-error" --window-icon="gtk-dialog-error" --width=500 --height=100 --button="gtk-ok:0"; } || echo "false"
}
export -f fnAlreadySaved


GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text label="This is an example window."></text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Save window data">
                <label> _Save </label>
                <input file icon="gtk-save"></input>
                <width>16</width>
                <action function="save" condition="command_is_false(fnAlreadySaved /tmp/gtkd.out)">vWindow</action>
            </button>
            <button use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>

    <output file>/tmp/gtkd.out</output>

    <action signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

touch /tmp/gtkd.out; rm /tmp/gtkd.out; /tmp/${scriptName}.sh



EXPLORING “ACTION SIGNAL” DIRECTIVE

Let’s explore the “action signal” directive to see what sort of signals the
Window object receives.

From the reference:

> There is no default signal for this widget.
> 
> The “file-changed” signal is emitted if file-monitor is true and the input
> file being monitored has changed.
> 
> The following signals are connected-up for all widgets:
> 
> button-press-event
> button-release-event
> configure-event
> enter-notify-event
> leave-notify-event
> focus-in-event
> focus-out-event
> hide
> show
> realize
> key-press-event
> key-release-event
> map-event
> unmap-event

From examples, additional events:

> delete-event
> destroy-event

Consider the following example, which is based on the
/home/demo/gtkdialog-0.8.3/examples/miscellaneous/signals example.

scriptName=ex16
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window title="Signals" icon-name="gtk-dialog-warning">
    <vbox>
        <frame Widgets>
            <text>
                <label>Label</label>
                <action signal="button-press-event">echo Label: button-press-event</action>
                <action signal="button-release-event">echo Label: button-release-event</action>
                <action signal="configure-event">echo Label: configure-event</action>
                <action signal="enter-notify-event">echo Label: enter-notify-event</action>
                <action signal="leave-notify-event">echo Label: leave-notify-event</action>
                <action signal="focus-in-event">echo Label: focus-in-event</action>
                <action signal="focus-out-event">echo Label: focus-out-event</action>
                <action signal="key-press-event">echo Label: key-press-event</action>
                <action signal="key-release-event">echo Label: key-release-event</action>
                <action signal="hide">echo Label: hide</action>
                <action signal="show">echo Label: show</action>
                <action signal="realize">echo Label: realize</action>
                <action signal="map-event">echo Label: map-event</action>
                <action signal="unmap-event">echo Label: unmap-event</action>
            </text>
            <entry>
                <default>Entry</default>
                <action signal="button-press-event">echo Entry: button-press_event</action>
                <action signal="button-release-event">echo Entry: button-release-event</action>
                <action signal="configure-event">echo Entry: configure-event</action>
                <action signal="enter-notify-event">echo Entry: enter-notify-event</action>
                <action signal="leave-notify-event">echo Entry: leave-notify-event</action>
                <action signal="focus-in-event">echo Entry: focus-in-event</action>
                <action signal="focus-out-event">echo Entry: focus-out-event</action>
                <action signal="key-press-event">echo Entry: key-press-event</action>
                <action signal="key-release-event">echo Entry: key-release-event</action>
                <action signal="hide">echo Entry: hide</action>
                <action signal="show">echo Entry: show</action>
                <action signal="realize">echo Entry: realize</action>
                <action signal="map-event">echo Entry: map-event</action>
                <action signal="unmap-event">echo Entry: unmap-event</action>
            </entry>
        </frame>
        <hbox>
            <button ok>
                <action signal="button-press-event">echo Button: button-press_event</action>
                <action signal="button-release-event">echo Button: button-release-event</action>
                <action signal="configure-event">echo Button: configure-event</action>
                <action signal="enter-notify-event">echo Button: enter-notify-event</action>
                <action signal="leave-notify-event">echo Button: leave-notify-event</action>
                <action signal="focus-in-event">echo Button: focus-in-event</action>
                <action signal="focus-out-event">echo Button: focus-out-event</action>
                <action signal="key-press-event">echo Button: key-press-event</action>
                <action signal="key-release-event">echo Button: key-release-event</action>
                <action signal="hide">echo Button: hide</action>
                <action signal="show">echo Button: show</action>
                <action signal="realize">echo Button: realize</action>
                <action signal="map-event">echo Button: map-event</action>
                <action signal="unmap-event">echo Button: unmap-event</action>
            </button>
        </hbox>
    </vbox>
    <action signal="button-press-event">echo Window: button-press_event</action>
    <action signal="button-release-event">echo Window: button-release-event</action>
    <action signal="configure-event">echo Window: configure-event</action>
    <action signal="delete-event">echo Window: delete-event</action>
    <action signal="destroy-event">echo Window: destroy-event</action>
    <action signal="enter-notify-event">echo Window: enter-notify-event</action>
    <action signal="leave-notify-event">echo Window: leave-notify-event</action>
    <action signal="focus-in-event">echo Window: focus-in-event</action>
    <action signal="focus-out-event">echo Window: focus-out-event</action>
    <action signal="key-press-event">echo Window: key-press-event</action>
    <action signal="key-release-event">echo Window: key-release-event</action>
    <action signal="hide">echo Window: hide</action>
    <action signal="show">echo Window: show</action>
    <action signal="realize">echo Window: realize</action>
    <action signal="map-event">echo Window: map-event</action>
    <action signal="unmap-event">echo Window: unmap-event</action>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


Each if the events gives rise to an opportunity to hook in logic to be executed
when the event is triggered.

In examples ex15, the following stanza illustrates the handling of the
key-press-event in such a way that the exit function is called conditionally if
the key which was pressed was the Escape key (0x9).

<action signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9
]] && echo true )">EXIT:exit</action>


EXPLORING “ACTION FUNCTION” DIRECTIVE

From the reference (http://01micko.com/reference/window.html):

The following functions can be performed upon this widget by any widget capable
of emitting signals:

Type Description Parameter Since enable Sensitise widget Variable name disable
Desensitise widget Variable name show Show widget Variable name 0.8.1 hide Hide
widget Variable name 0.8.1 refresh Reload input data[1] Variable name 0.8.1 save
Save widget data Variable name 0.8.1 clear Remove all widget data Variable name
0.8.1

We used the “save” function in example ex15. Now we will consider disable,
enable, hide and show functions.

Let’s consider the following example:

scriptName=ex17
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
    echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text>
                <label>"This is an example window."</label>
                <variable>vText</variable>
            </text>
        </frame>
        <hbox>
            <button use-underline="true" tooltip-text="Hide Text">
                <label> _Hide </label>
                <variable>vBtnHide</variable>
                <action function="hide" condition="visible_is_true(vText)">vText</action>
                <action function="hide" condition="visible_is_true(vBtnHide)">vBtnHide</action>
                <action function="show" condition="visible_is_false(vBtnShow)">vBtnShow</action>
            </button>
            <button visible="false" use-underline="true" tooltip-text="Show Text">
                <label> _Show </label>
                <variable>vBtnShow</variable>
                <action function="show" condition="visible_is_false(vText)">vText</action>
                <action function="show" condition="visible_is_false(vBtnHide)">vBtnHide</action>
                <action function="hide" condition="visible_is_true(vBtnShow)">vBtnShow</action>
            </button>

            <button use-underline="true" tooltip-text="Disable Text">
                <label> _Disable </label>
                <variable>vBtnDisable</variable>
                <action function="disable" condition="sensitive_is_true(vText)">vText</action>
                <action function="hide" condition="visible_is_true(vBtnDisable)">vBtnDisable</action>
                <action function="show" condition="visible_is_false(vBtnEnable)">vBtnEnable</action>
            </button>
            <button visible="false" use-underline="true" tooltip-text="Enable Text">
                <label> _Enable </label>
                <variable>vBtnEnable</variable>
                <action function="enable" condition="sensitive_is_false(vText)">vText</action>
                <action function="show" condition="visible_is_false(vBtnDisable)">vBtnDisable</action>
                <action function="hide" condition="visible_is_true(vBtnEnable)">vBtnEnable</action>
            </button>

            <button use-underline="true" tooltip-text="update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>

    <output file>/tmp/gtkd.out</output>

    <action signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


In the script above we are not hiding/showing and enabling/disabling the window,
as we might, because as soon as we hide the window it will disappear and as soon
as we disable it we will not be able to do anything to it except close it using
the close “button” in the title bar. We are, instead, jumping ahead a bit,
hiding and showing the text object and enabling and disabling the text object.
This example also demonstrates how a “toggle” button can be implemented, in this
case by alternately hiding and showing two different buttons (hide and show,
disable/enable). The end-user impression will be that a single button changes
the label and the button function on click (hide/how, disable/enable).

To see how to hide/show and disable/enable the window object consider the
following, not particularly useful in practice, example:

scriptName=ex18
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
    echo "$(date)"
}
export -f fnEchoDateTime

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
>
    <vbox>
        <frame   Description  >
            <text>
                <label>"Click Hide or Disable and wait up to 5 seconds for the timer to trigger the reversal of the action."</label>
                <variable>vText</variable>
            </text>
        </frame>
        <hbox>
            <timer sensitive="false" milliseconds="true" interval="5000" visible="false" disabled="true">
                <variable>tmr0</variable>
                <action>show:vWindow</action>
            </timer>
            <timer sensitive="false" milliseconds="true" interval="5000" visible="false" disabled="true">
                <variable>tmr1</variable>
                <action>enable:vWindow</action>
            </timer>
            <button use-underline="true" tooltip-text="Hide Window">
                <label> _Hide </label>
                <action function="hide" condition="visible_is_true(vWindow)">vWindow</action>
                <action function="enable" condition="sensitive_is_false(tmr0)">tmr0</action>
            </button>
            <button use-underline="true" tooltip-text="Disable Window">
                <label> _Disable </label>
                <action function="disable" condition="sensitive_is_true(vWindow)">vWindow</action>
                <action function="enable" condition="sensitive_is_false(tmr1)">tmr1</action>
            </button>
            <button use-underline="true" tooltip-text="update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>

    <output file>/tmp/gtkd.out</output>

    <action signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 

</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


In the script above we are jumping ahead a bit and using timers to trigger
events that will show the hidden window and enable the disabled content after an
interval.

Perhaps provision of a bit of context is in order at this point for no other
reason than to make the basic action processing explicit.

Consider the two actions defined for the Hide button.

<action function="hide" condition="visible_is_true(vWindow)">vWindow</action>

<action function="enable" condition="sensitive_is_false(tmr0)">tmr0</action>

The first action will hide the window. The condition “visible_is_true(vWindow)”
is superfluous in this case because the button will only be visible if the
window is visible but it is there as an example of a conditional action.

The second action will enable a timer which will trigger its own action to
reverse the effect of the button press on the Window object after an interval of
up to 5 seconds.

Unless told otherwise, of which in a later article, the button press will cause
the two actions to be executed one after the other. There are some circumstances
in which execution of an action in the action list will prevent actions defined
after it being executed but these are rare circumstances, which will be
discussed in a subsequent article. One can have several actions which a button
press will trigger. Other active objects can have actions as well, as can be
seen with the timer objects and will be also seen in subsequent articles in
which other objects are discussed and used.

For the time being one can assume that all actions defined for an object, like a
window or a button, will get evaluated sequentially and will be executed if
appropriate (like for example if the condition is met).

The style attribute does nothing visible. It is quite likely that I don’t know
how to define a style. There is an alternative way to “style” objects which
works in some instances and can be used as appropriate.

Consider the following example:

scriptName=ex19
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

GTKDIALOG=gtkdialog

fnEchoDateTime() {
echo "$(date)"
}
export -f fnEchoDateTime

echo '
style "bgWhite" { bg[NORMAL] = "#FFFFFF" }
style "fgWhite" { fg[NORMAL] = "#FFFFFF" }
style "bgBlack" { bg[NORMAL] = "#000000" }
style "bgRed" { bg[NORMAL] = "#FF0000" }
style "fgRed" { fg[NORMAL] = "#FF0000" }
style "bgGreen" { bg[NORMAL] = "#FFFF00" }
style "fgGreen" { fg[NORMAL] = "#FFFF00" }
style "bgBlue" { bg[NORMAL] = "#0000FF" }
style "fgBlue" { fg[NORMAL] = "#0000FF" }

widget "MyWindowBg" style "bgBlack"
widget "MyWindowBg.GtkVBox.GtkHBox.MyButtonBg" style "bgGreen"

widget "MyWindowBg.GtkVBox.myEVB" style "bgBlue"

widget_class "*<GtkFrame>.GtkLabel" style "fgWhite"
widget_class "*<GtkFrame>.*.GtkLabel" style "fgGreen"
widget_class "*<GtkButton>.*.GtkLabel" style "fgRed"

' > /tmp/gtkrc_mono 
export GTK2_RC_FILES=/tmp/gtkrc_mono

GTK_WIN_POS_NONE=0
GTK_WIN_POS_CENTER=1
GTK_WIN_POS_MOUSE=2

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window 
    title="My First Window"
    window-position="${GTK_WIN_POS_CENTER}"
    default-width="400"
    name="MyWindowBg"
>
    <vbox>
        <eventbox name="myEVB" above-child="false" visible-window="true">
        <frame   Description  >
            <text><label>This is an example window.</label></text>
        </frame>
        </eventbox>
        <hbox>
            <button name="MyButtonBg" use-underline="true" tooltip-text="Refresh window variable - update date in window title">
                <label> _Refresh </label>
                <input file icon="gtk-refresh"></input>
                <width>16</width>
                <action function="refresh">vWindow</action>
            </button>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>

    <variable>vWindow</variable>
    <input>fnEchoDateTime</input>
    <action this-is-window="escape" signal="key-press-event" condition="command_is_true( [[ \$KEY_RAW = 0x9 ]] && echo true )">EXIT:exit</action> 
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh


Here we define and use GTK styles to change foreground and/or background colours
of the various objects.

Here is how the application window looks.



This is just a brief teaser. How to apply styles to objects, what works and what
does not, etc., may be covered in a future article.


EXPLORING WINDOW EXAMPLES

In /home/demo/gtkdialog-0.8.3/examples/window there are 3 examples. Review the
window GUI definitions and run the examples

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window --dump

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window_attributes --dump

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window_attributes

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window_signals --dump

/bin/sh /home/demo/gtkdialog-0.8.3/examples/window/window_signals

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
bash • gtkdialog bash examples • gtkdialog comments • gtkdialog documentation •
gtkdialog examples • gtkdialog reference • gtkdialog structure • gtkdialog
window • gtkdialog window attributes • gtkdialog window examples • gtkdialog
window object • infrastructure demo • infrastructure demonstration • Linux demo
• Linux demo image • Linux demonstration image • Linux GUI • Linux UI •
technical demo • technical demonstration

Apr 09


INTRODUCTION TO GTKDIALOG – APPLICATION STRUCTURE, EXAMPLES AND DOCUMENTATION

By Czapski Michael gtkdialog No Comments »

The biggest hurdle for a gtkdialog newbe, or at least so it was for me, was
getting handle on how to structure the code, where to find documentation and how
to use it, where to find examples and how to add comments to the code or comment
out blocks of code without braking scripts.

In this article I go over these topics in some detail. It seems necessary to
consider the basics before launching into more ambitious topics.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.


CREADITS:

Gtkdialog – A small utility for fast and easy GUI building.
2003-2007  László Pere <pipas@linux.pte.hu>
2011-2012  Thunor thunorsif@hotmail.com
Project site: https://code.google.com/archive/p/gtkdialog/
Original documentation: http://linux.pte.hu/~pipas/gtkdialog/
Most recent documentation (not very recent)
http://xpt.sourceforge.net/techdocs/language/gtkdialog/gtkde03-GtkdialogUserManual/.

The project home page contains links to other resources which are worth looking
at.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any Linux environment will do
just as well so long as it supports yad and gtkdialog.

For convenience I posted the export of the VirtualBox image which would have
been built if the reader followed all the articles in the series “Build a
Linux-based Infrastructure Solution Demonstration Series” to date, that is to
the 8th of March 2017. The link to the main article is
https://blogs.czapski.id.au/2017/04/virtualbox-image-with-content-as-built-so-far.


GTKDIALOG APPLICATION STRUCTURE AND BASIC INTERACTION WITH THE ENVIRONMENT

A gtkdialog application UI is, in effect, a window with content. Perhaps the
simplest reasonable gtkdialog application with gtkdialog GUI definition is shown
below:

touch /tmp/ex01.sh
chmod ug+x /tmp/ex01.sh

cat <<-'EOSCRIPT' > /tmp/ex01.sh
#!/bin/bash
MAIN_DIALOG_FILE=/tmp/ex01.gtkd

cat <<-'EOUIDFEINITION' > ${MAIN_DIALOG_FILE}
<window>
  <vbox>
    <text>
      <label>I am a window.</label>
    </text>
    <button ok></button>
  </vbox>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/ex01.sh

This application’s UI looks like this:



Note that the standard window controls, close, maximise, minimise and window
menu are provided, as is the title bar with some title even though we specified
neither in the UI definition.

The application has a text box with literal text we provided and a button with
the label we provided. Clicking the button will cause the UI to exit with the
following text emitted to stdout.

EXIT="OK"

The gtkdialog application consists of a GUI definition, expressed as
gtkdialog-specific XML structure, provided to a gtkdialog executable as a file
or as a shell variable.

The GUI definition specifies all the visual components, event handlers, actions,
etc.. More on the event handlers, actions and similar in a later article. For
now we will keep things simple.


COMMON GUI DEFINITION CONVENTION

In a typical gtkdialog example online, and in the examples found under
~/gtkdialog-0.8.3/examples/ you will see the following idiom for defining and
using gtkdialog UIs:

touch /tmp/ex02.sh
chmod ug+x /tmp/ex02.sh

cat <<-'EOSCRIPT' > /tmp/ex02.sh
#!/bin/bash

MAIN_DIALOG='
<window>
  <vbox>
    <text>
      <label>I am a window.</label>
    </text>
    <button ok></button>
  </vbox>
</window>
'
export MAIN_DIALOG

case ${1} in
    -d | --dump) echo ${MAIN_DIALOG} ;;
    *) gtkdialog --center ${MAIN_DIALOG} ;;
esac
EOSCRIPT

/tmp/ex02.sh

Here the GUI definition is explicitly assigned to a shell variable with “hard”
quotes surrounding it. I don’t like this idiom and I don’t use this idiom. The
reason is that shell quoting becomes quite tricky and error-prone as soon as the
GUI definition becomes more complex and GUI components invoke external commands
or shell functions with parameters, etc..

Instead, I use the ‘”here document” piped to a file’ idiom, like in the ex01.sh
example above. This is the idiom I will continue to use so you will need to
“translate” examples I use to examples provided with gtkdialog and seen online,
or translate them to my way of doing things, whichever you prefer.


HOW CAN GTKDIALOG APPLICATION INTERACT WITH THE ENVIRONMENT (BASIC)

It was briefly mentioned in the text following ex01.sh that when the OK button
is clicked the GUI is closed and gtkdialog emits to the stdout

EXIT="OK"

If there were other buttons and other variables defined and populated in the GUI
their names and values would similarly be emitted to the stdout.

Let’s try the following example to demonstrate this:

touch /tmp/ex03.sh
chmod ug+x /tmp/ex03.sh

cat <<-'EOSCRIPT' > /tmp/ex03.sh
#!/bin/bash
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-'EOUIDFEINITION' > ${MAIN_DIALOG_FILE}
<window>
  <vbox>
    <text>
      <label>I am a window.</label>
      <variable>vLabelVariable</variable>
    </text>
    <button ok></button>
    <button cancel></button>
  </vbox>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/ex03.sh

When the Cancel button is pressed the following is emitted to the stdout

vLabelVariable="I am a window."
EXIT="Cancel"

When the OK button is pressed the following is emitted to the stdout

vLabelVariable="I am a window."
EXIT="OK"

A script can intercept the value of the variables, for example the EXIT
variable, and alter subsequent processing as required.

Let’s modify the script so that it recognises the value of the EXIT variable.

cat <<-'EOSCRIPT' > /tmp/ex03.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-'EOUIDFEINITION' > ${MAIN_DIALOG_FILE}
<window>
  <vbox>
    <text>
      <label>I am a window.</label>
      <variable>vLabelVariable</variable>
    </text>
    <button ok></button>
    <button cancel></button>
  </vbox>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) RESULTS=$(gtkdialog --center --file=${MAIN_DIALOG_FILE}) ;;
esac

I=$IFS; IFS=""
for STATEMENTS in "${RESULTS}"; do
  echo 'STATEMENTS:-->>'"${STATEMENTS}"'<<--'
  eval $STATEMENTS
done
IFS=$I

if [[ "$EXIT" = "OK" ]]; then
  echo "You clicked OK with vLabelVariable containing '${vLabelVariable}'"
else
  echo "You pressed the Cancel button."
fi

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/ex03.sh

Executing this script produces:

STATEMENTS:-->>vLabelVariable="I am a window."
EXIT="OK"<<--
You clicked OK with vLabelVariable containing 'I am a window.'

A shell scripter will undoubtedly come up with alternate ways of getting at the
variable names and values.

Note that the content of the vLabelVariable is also emitted. This may or may not
be useful. It is possible to prevent the variable being emitted by providing the
export=”false” attribute when defining the variable in the GUI. The script
variant below illustrates this.

cat <<-'EOSCRIPT' > /tmp/ex03.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd

cat <<-'EOUIDFEINITION' > ${MAIN_DIALOG_FILE}
<window>
  <vbox>
    <text>
      <label>I am a window.</label>
      <variable export="false">vLabelVariable</variable>
    </text>
    <button ok></button>
    <button cancel></button>
  </vbox>
</window>
EOUIDFEINITION

case ${1} in
    -d | --dump) cat ${MAIN_DIALOG_FILE} ;;
    *) RESULTS=$(gtkdialog --center --file=${MAIN_DIALOG_FILE}) ;;
esac

I=$IFS; IFS=""
for STATEMENTS in "${RESULTS}"; do
  echo 'STATEMENTS:-->>'"${STATEMENTS}"'<<--'
  eval $STATEMENTS
done
IFS=$I

if [[ "$EXIT" = "OK" ]]; then
  echo "You clicked OK with vLabelVariable containing '${vLabelVariable}'"
else
  echo "You pressed the Cancel button."
fi

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/ex03.sh

Executing the modified script produces the following:

STATEMENTS:-->>EXIT="OK"<<--
You clicked OK with vLabelVariable containing ''

The variable vLabelVariable was not exported and its value is not available.

I am jumping ahead a bit here by making a reference to a forward topic. The
topic of bash functions used as callbacks and action logic will be dealt with
later. For now one needs to know that whether to use export=”false” is a
reasonably important decision because any variable defined with export=”false”
will not be visible in the shell environment of the callback/action functions so
will either be inaccessible or will have to be passed as an argument to a
callback/action function. I don’t see harm in not specifying export=”false”.
Perhaps there is a performance benefit is so doing.

More on the topic of callbacks and actions in a later article.


EXPLORE EXAMPLES

I confess that without the examples provided with the gtkdialog source
distribution and also available online at
https://github.com/01micko/gtkdialog/tree/master/examples I would have given up
on gtkdialog. The reference documentation is just that – reference – a place to
go to look up a specific piece of information knowing that such information can
be looked up in the reference.

A newbie needs to understand the broad capabilities, concepts and functionality,
and needs some elaboration. This sort of documentation is missing. True, there
are a few tutorials but they are hard to find and are pretty limited in the
coverage and scope, so examples are the best means of finding out what can be
done and how, unless a comprehensive tutorial becomes available.

Until it does, spend time looking at examples to see what the various tags and
attributes exist and what they accomplish. For this set of articles I installed
examples locally to ~/gtkdialog-0.8.3/examples. There is no index so explore
each on its own, or use the indexed and accessible source at the github URL
quoted above.

The simplest way is to invoke each example as a shells script, which is what
most of them are, and see what is shown, and then look at the script source to
see how it does it.

For example:

~/gtkdialog-0.8.3/examples/window/window



Then see what the GUI definition looks like

~/gtkdialog-0.8.3/examples/window/window --dump

<window>
    <vbox>
        <frame Description>
            <text>
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>
</window>

And finally, look at the source:

geany ~/gtkdialog-0.8.3/examples/window/window &

#!/bin/sh

GTKDIALOG=gtkdialog

MAIN_DIALOG='
<window>
    <vbox>
        <frame Description>
            <text>
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>
</window>
'
export MAIN_DIALOG

case $1 in
    -d | --dump) echo "$MAIN_DIALOG" ;;
    *) $GTKDIALOG --program=MAIN_DIALOG ;;
esac


REFERENCE DOCUMENTATION

Reference documentation is available in a number of places, and is more or less
useful, depending on a bunch of factors.

In the demo image it is available at ~/gtkdialog-0.8.3/doc/reference/. Again,
there is no index so pick the first HTML document that comes to hand and view it
in a web browser. Internal links will allow you to navigate from object to
object so this is not much of a drama. An index is available online at
http://01micko.com/reference/. So, locally:

firefox ~/gtkdialog-0.8.3/doc/reference/button.html &

For a newbie the first glance at this is somewhat off-putting. Still, note the
following:

 1. At the bottom of the page, and all other pages, is a list of hyperlinks to
    the various gtkdialog objects so you can navigate form button to text to
    window and so on
 2. The definition lists all the valid tags and discusses the various
    attributes, signals, functions, etc. – more on these topics in subsequent
    articles
 3. The tag attributes section lists all attributes specific to this tag, BUT it
    does not list these attributes which can be applied to the tag but which are
    inherited from the parent objects in the object hierarchy
 4. In this case the innocuous sentence “See the GtkButton widget and ancestor
    class properties.” hints that there may be other properties that can be
    applied to the button and links to the page which contains more on the
    topic. Note that this is an external link so an Internet connection will be
    needed to access it.
 5. The external source for GtkButton contains, amongst other things, the object
    hierarchy of which the button object is a child as well as a list of
    properties defined for that object. The hierarchy is navigable and inherited
    parent properties can be discovered by following the links.
 6. Not all defined properties, signals and functions are mapped by, and visible
    to, gtkdialog or useable from it. For example, the border-width property of
    the GtkContainer, which is a grandparent of the GtkButton, is useable from
    the GtkButton but the other two properties are not visible or useable
 7. One has to exercise one’s mind a bit to translate data types to what
    can/should be specified as the attribute value for a particular
    attribute/property, for example one would specify ‘<window border-width=”6″
    …’.

As I practice it, gtkdialog is pretty easy to work with to try various things.
Exploration of what the various attributes do to a GUI is pretty painless,
particularly once one knows how to effectively comment out blocks of gtkdialog
GUI definition XML for various experiments.

The following are links to material that I found useful when dealing with
specific topics in my work with gtkdialog so far. They are collected here for
ease of reference.

gtkdialog Refrences and Examples

 * https://github.com/oshazard/gtkdialog/ – gtkdlialog distribution at github
 * http://01micko.com/reference/ – Index of reference pages for all gtkdialog
   objects
 * http://www.murga-linux.com/puppy/viewtopic.php?t=69188&start=2 – gtkdialog
   development discussion – by my light the most useful I found so far
 * http://www.murga-linux.com/puppy/viewtopic.php?p=544704#544704 – another
   gtkdialog development discussion
 * https://github.com/01micko/gtkdialog/tree/master/examples – gtkdialog online
   examples – also distributed in the source package
 * https://developer.gnome.org/gtk2/stable/ – Gnome GTK 2 developer
   documentation in general – what sits under the covers
 * https://developer.gnome.org/gtk2/2.24/gtk2-Standard-Enumerations.html#GtkWindowPosition
   – Various GTK Enumerations
 * http://www.orford.org/gtk – fonts, gtkrc files, engines
 * https://developer.gnome.org/gtk2/stable/gtk2-Resource-Files.html#gtk2-Resource-Files.description
   – Specific section on GTK resource files
 * http://www.murga-linux.com/puppy/viewtopic.php?t=40418 – gtkdialog markup
   text editor/wizard
 * http://www.murga-linux.com/puppy/viewtopic.php?t=69282 –  Index of programs
   using gtkdialog

Themes and Styles

 * https://en.wikibooks.org/wiki/GTK%2B_By_Example/Theming – GTK Theming – to do
   with applying styles to GTKK applicaiton objects
 * http://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-19.html –
   specific discussion of styles
 * https://git.enlightenment.org/themes/detourious.git/plain/gtk/detourious/gtk-2.0/gtkrc
   – a huge set of property specs
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes – tutorial on all
   manner of GTK appearance including styles
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/MistEngine – Mist
   GTK theme engine
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkEngines/PixmapEngine –
   Pixmap GTK theme engine
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes#Priority – Priority
   of style merging
 * https://wiki.gnome.org/Attic/GnomeArt/Tutorials/GtkThemes/SymbolicColors –
   Discussion on colours
 * https://www.cs.tut.fi/lintula/manual/gtk/gtk/gtk-resource-files.html –
   Discussion in “Pathnames and patterns”

Object Hierarchy – Window

 * https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.object-hierarchy
   – GtkWindow Object hierarchy
 * https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.properties –
   GtkWindow Object Properties


COMMENTING OUT BLOCKS OF XML

One of the reasons I use ‘”here documents” piped to a file’ for persisting
gtkdialog GUI definitions is because I can easily comment out blocks of XML
without breaking gtkdialog at runtime.

Let’s consider what a person familiar with XML would try first:

touch /tmp/ex04.sh
chmod ug+x /tmp/ex04.sh

cat <<-'EOSCRIPT' > /tmp/ex04.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd

cat <<-'EOUIDFEINITION' > ${MAIN_DIALOG_FILE}
<window>
<vbox>
<!--
    <text>
      <label>I am a window.</label>
    </text>
-->
<button ok></button>
</vbox>
</window>
EOUIDFEINITION

case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/ex04.sh

Executing this script produces the following:

** ERROR **: gtkdialog: Error in line 4, near token 'string': syntax error

aborting...
/tmp/ex04.sh: line 18:  5569 Aborted                 (core dumped) gtkdialog --center --file=${MAIN_DIALOG_FILE}

Opps – no banana. Not only that, but the message is pretty cryptic, the line
number reference is to a line number in XML GUI definition and the error may not
actually be in the line being referenced. With large GUI definitions debugging
could be a headache.

One way to try to zoom in on the line number in the XML is to do the following,
bearing in mind that the line number in the error message may not be the line
number where the error is caused, and that some breakages prevent XML being
generated so this may not work at all:

/tmp/ex04.sh --dump | cat -n | more

1    <window>
2      <vbox>
3    <!--
4        <text>
5          <label>I am a window.</label>
6        </text>
7    -->
8        <button ok></button>
9      </vbox>
10    </window>

Note, too, that the script’s error line number is useless – it is the number of
the line where gtkdialog command is invoked. This will be particularly useless
when we start working with bash functions and errors will be reported with
respect to the line numbers inside the functions. But I am getting ahead of
myself.

Clearly, standard XML <!– commented out –> syntax does not work.

Let’s try a combination of shell techniques to do the job. Consider this script:

scriptName=ex05
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window>
<vbox>
$(:<<-'COMMENT--------------------'
    <text>
      <label>I am a window.</label>
    </text>
COMMENT--------------------
)
<button ok></button>
</vbox>
</window>
EOUIDFEINITION

case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh --dump

This produces the following:

<window>
<vbox>

<button ok></button>
</vbox>
</window>

Notice that the entire section of XML between and including <text>…</text> tags
has gone missing.

Let’s analyse what is happening.

 1. Inner “Here document” syntax “cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}”
    is different from the outer “Here document” syntax “cat <<-'EOSCRIPT' >
    /tmp/${scriptName}.sh“. Note the hard quotes around the here document
    delimiter ‘EOSCRIPT’. Quoting the document delimiter prevents bash from
    expanding commands and shell variables at the time the document is created.
    Let’s see what the document looks like after it is created:
    
     cat /tmp/${scriptName}.sh

#!/bin/bash
MAIN_DIALOG_FILE=${0}.gtkd
cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window>
<vbox>
$(:<<-'COMMENT--------------------'
<text>
<label>I am a window.</label>
</text>
COMMENT--------------------
)
<button ok></button>
</vbox>
</window>
EOUIDFEINITION
case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac
rm -f ${MAIN_DIALOG_FILE}


Note that the variables which would be expanded if the here document delimiter
was not hard quoted are not expanded.

 2. At runtime, when this script is executed, the inner “here document” will be
    created. This time the here document delimiter is not quoted so commands and
    variables will be expanded by the shell, resulting in the $() construct
    being executed. This construct is a “execute in a subshell” construct,
    causing bash to create a subshell and execute whatever is inside $() as a
    stream of commands right there and then, when the here document is being
    created, so that whatever output is produced by the subshell, if any, will
    get incorporated into the here document in its place.
    See, for example,
    http://unix.stackexchange.com/questions/147420/what-is-in-a-command for a
    discussion
 3. The command ‘:’ is a no-operation, or a null command for bash so there is no
    command to execute. Everything following ‘:’ will be ignored except for
    variable substitution and interpretation of shell-special characters. See
    http://stackoverflow.com/questions/3224878/what-is-the-purpose-of-the-colon-gnu-bash-builtin
    for a discussion.
 4. “<<-'COMMENT--------------------'” and everything following it until
    “COMMENT--------------------” is a “here document” which is ignored since
    ‘:’ causes it to be ignored. Hard-quoting the delimiter
    “COMMENT--------------------” prevents any $xxxx present in the text form
    being expanded by the shell and any shell-special characters, like <>|{},
    etc. from being interpreted, causing errors

In essence the entire $(….) disappears when the script executes and does not get
embedded in the xml document which gtkdialog executes. Great way to comment out
large chunks of XML when exploring with alternatives.


SHORT COMMENTS INSIDE GTKDIALOG XML

Two other techniques can be used to provide comments inside the gtkdialog GUI
XML.

I am again running ahead a bit but this is in a good cause Each object in
gtkdialog except “frame” can be decorated with a bunch of object-specific
attributes. Gtkdialog parser is very forgiving of attribute names which it does
not recognise so a sneaky way takes advantage of that fact is making it possible
to invent a tag name and have its value contain some comment text. Consider the
following script:

scriptName=ex06
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd

cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window xx-window-comment="this is a comment on the window tag">
<vbox>
<text xx-text-comment="I am using an unrecognised attribute to provide a comment">
<label>I am a window.</label>
</text>
<button ok></button>
</vbox>
</window>
EOUIDFEINITION

case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

The script happily executed because unknown attributes were ignored yet the
comment text is in the XML as can be readily seen:

/tmp/${scriptName}.sh --dump

<window xx-window-comment="this is a comment on the window tag">
<vbox>
<text xx-text-comment="I am using an unrecognised attribute to provide a comment">
<label>I am a window.</label>
</text>
<button ok></button>
</vbox>
</window>

Note that if a future version of gtkdialog tightens up parsing and rejects
unknown attribute names then scripts which use this technique will break.

The second method is a variation on the $(:…) technique, discussed above.

Consider the following script

scriptName=ex07
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd

cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window>
<vbox>
$(: this is a single line comment - to continue it over multiple lines \
one must provide line continuation to shell, \, and carry on. \
The $() construct must be closed with the )
<text>
<label>I am a window.</label>
</text>
<button ok></button>
</vbox>
</window>
EOUIDFEINITION

case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

Again, everything inside  $() disappeared.

/tmp/${scriptName}.sh --dump

<window>
<vbox>

<text>
<label>I am a window.</label>
</text>
<button ok></button>
</vbox>
</window>

Note that everything inside $() is expanded by the shell and special characters
are acted upon. Including < >, for example, will cause breakage – try it.
Consider the following script

scriptName=ex08
touch /tmp/${scriptName}.sh
chmod ug+x /tmp/${scriptName}.sh

cat <<-'EOSCRIPT' > /tmp/${scriptName}.sh
#!/bin/bash

MAIN_DIALOG_FILE=${0}.gtkd

cat <<-EOUIDFEINITION > ${MAIN_DIALOG_FILE}
<window>
<vbox>
$(: this is a single line comment - to continue it over multiple lines \
one must provide line continuation to shell, \, and carry on. \
The $() construct < > must be closed with the )
<text>
<label>I am a window.</label>
</text>
<button ok></button>
</vbox>
</window>
EOUIDFEINITION

case ${1} in
-d | --dump) cat ${MAIN_DIALOG_FILE} ;;
*) gtkdialog --center --file=${MAIN_DIALOG_FILE} ;;
esac

rm -f ${MAIN_DIALOG_FILE}
EOSCRIPT

/tmp/${scriptName}.sh

/tmp/ex08.sh: command substitution: line 6: syntax error near unexpected token `>'
/tmp/ex08.sh: command substitution: line 6: `: this is a single line comment - to continue it over multiple lines         one must provide line continuation to shell, \, and carry on.         The $() construct < > must be closed with the )'

** ERROR **: Error opening file '/tmp/ex08.sh.gtkd': No such file or directory
aborting...
/tmp/ex08.sh: line 19:  6225 Aborted                 (core dumped) gtkdialog --center --file=${MAIN_DIALOG_FILE}

If you use these kinds of comments watch out for shell-special characters.
Clearly this kind of comments is not suitable for commenting out chunks of XML.
While one can use these kinds comments it seems to me safer to use undefined
attributes for short comments and $(:<<-‘….’…) comments for large comments and
for commenting out blocks of XML in the gtkdialog GUI definitions.

Tagged with: CentOS • create demo • create demonstration • demo • demonstration
• GTK • GTK GUI • gtkdialog • gtkdialog bash examples • gtkdialog comments •
gtkdialog documentation • gtkdialog examples • gtkdialog reference • gtkdialog
structure • infrastructure demo • infrastructure demonstration • Linux demo •
Linux demo image • Linux demonstration image • Linux GUI • Linux UI • technical
demo • technical demonstration

Apr 09


GTKDIALOG EXPLORATION – ARTICLES AND EXAMPLES – SERIES INTRODUCTION

By Czapski Michael gtkdialog 3 Comments »

In this article I discuss my rationale for using gtkdialog and, more
importantly, I provide links to a growing list of articles on topics related to
gtkdialog – applying styles to gtkdialog applications, examples, exploration of
the various gtkdialog objects and suchlike.

Here is the list of my articles on the topic of gtkdialog:

 * VirtualBox Image with content as built so far – Download the VirtualBox Image
 * gtkdialog for rapid prototyping of Linux Applications – Install gtkialog and
   yad
 * gtkdialog – application structure, examples and documentation
 * gtkdialog – Exploring the Window object
 * gtkdialog – Applying styles to gtkdialog applications
 * gtkdialog – Exploring the Notebook object by example
 * gtkdialog – Applying Styles to Notebook Elements and Content Examples

My demos are typically designed to showcase back-end infrastructure, with one or
more integrated products delivering specific functionality to client
applications. The implication of, and the very point of, the infrastructure is
that it does deliver functionality to any front-end client application. It
shelters the front-end application from the complexities of integration of
multiple components, orchestrating functionality across disparate products and
platforms, and the need for the front-end developers to possess the requisite
skills to effectively work in such complex, multi-technology environments.

To prove the points I typically have technical artefacts stand in for the client
applications, for example using curl (https://curl.haxx.se/) or httpie
(https://httpie.org/). This approach strips all the non-essential, tool-induced
fluff, and exposes the bare requests and bare responses that the application
needs to exchange with the back-end to get the job done. In the case of SOAP Web
Services it would be the SOAP Requests and SOAP Responses. In the case of REST
web services it would be HTTP Requests, potentially with JSON POST data, and
REST Responses.

Alas, there are occasions when audience is not knowledgeable enough to
appreciate what the technical artefacts are doing and what that means for the
developer of the front-end application.

In the late 1990s early 2000s I was developing very complex and sophisticated
web applications for healthcare. I started modestly enough with a web
browser-based laboratory results reporting application using HTML 2 and a CERN
httpd web server with complex custom backend – see
https://blogs.czapski.id.au/wp-content/uploads/2010/03/for_blog_mczapski1.html
if you are curious what that looked like then. The paper as it looked when it
was hosted by Charles Sturt University in 1997 –
https://web.archive.org/web/19970607211224/http://www.csu.edu.au/special/conference/apwww95/papers95/mczapski/mczapski.html
– was archived in the Internet Archive by the WayBack Machine –
https://archive.org/web/). I progressed to HTML 4, JavaScript, Apache httpd and
custom Apache module for all the back-end database access and dynamic HTML
generation (that was before the days of AJAX and other server-side technologies,
so I invented my own serverside scripting methodology for the occasion).

All this is to say that when I started considering what technology I would use
to create demonstration applications to show the client-side of integration to
the back-end infrastructure for which I was building the demos I naturally
turned to the web technologies. That, it turned out, was a blind alley for me.
The time and effort investment necessary to choose from the plethora of
competing frameworks, the inevitable need to combine multiple frameworks and
technologies (like for example AngularJS, Backbone.io, Node.js, jQuery, etc., to
acquire sufficient skills to be reasonably proficient and to get the actual job
done seemed excessive. From my point of view the return on investment simply was
not there.

What I was after was a tool that would put a reasonably-looking UI on top of the
raw request/response exchanges with no need to write 3gl compiled code or Java
or such, install execution environments (like node.js, web servers or servlet
containers). It would ideally be invoked from the Linux shell with bunch of
command line arguments which would make it do what I needed it to do.

I turned to Linux UI tools, starting with zenity
(https://help.gnome.org/users/zenity/stable/), progressing through yad
(http://www.webupd8.org/2010/12/yad-zenity-on-steroids-display.html) and finally
stumbling upon gtkdialog
(http://www.tecmint.com/gtkdialog-create-graphical-interfaces-and-dialog-boxes/).

It turned out that yad is ideal for quick dialog boxes of the sort that shows
information and asks for OK or Cancel. It can do plenty more than that but I am
using it for just such simple things. There is enough information on line to get
one up to speed with yad pretty quickly for simple tasks. I built some UIs using
yad but I was not satisfied with the rigidity of the component layout mechanism
and the consequent lack of control over the layout.

I stumbled on the references to gtkdialog and started exploration. Alas,
documentation for gtkdialog is almost non-existent, and what information can be
had is scattered over group posts, blog articles and rather opaque reference
pages. This alone makes the entry cost pretty high. One has to be fairly
motivated to persevere with gtkdialog with no prior experience. I was reasonably
motivated but there was a point, which I documented in my internal notes, when I
concluded that it was “probably waste of time”. Still I persevered and I built a
few pretty sophisticated client applications using gtkdialog and bash – each
between 600 and 2000 lines of bash script. If you relate to these numbers then
you will appreciate that for me gtkdialog is very attractive. I can develop,
test and deploy a pretty sophisticated UI in a couple of days using bash as a
scripting language with ready access to all the tools and technologies I need to
do the back-end integration quickly and effectively.

Tagged with: bash gtkdialog • bash GUI • CentOS • create demo • create
demonstration • demo • demonstration • GTK • GTK GUI • gtkdialog • gtkdialog
bash • gtkdialog bash examples • gtkdialog comments • gtkdialog documentation •
gtkdialog examples • gtkdialog exploration • gtkdialog reference • gtkdialog
structure • gtkdialog tutorials • infrastructure demo • infrastructure
demonstration • Linux demo • Linux demo image • Linux demonstration image •
Linux GUI • Linux UI • technical demo • technical demonstration

Apr 08


GTKDIALOG FOR RAPID PROTOTYPING OF LINUX APPLICATIONS – INSTALL GTKIALOG AND YAD
FOR GRAPHICAL USER INTERFACES FOR BASH

By Czapski Michael gtkdialog No Comments »

In this article I walk through the steps that get the yad, gtkdialog and geany
installed and tested.

This is the next article in a series of articles on gtkdialog, “gtkdialog
Exploration – articles and examples”, which can be found at
https://blogs.czapski.id.au/2017/04/gtkdialog-exploration.


PRE-REQUISITES

This article assumes that the Virtual Box Machine Image created in accordance
with the instructions in the blog article to be found at
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image
is available but it is expected that pretty much any VirtualBox Linux disk will
do just as well so long as it supports yad and gtkdialog.

For convenience I posted the export of the VirtualBox image which would have
been built if the reader followed all the articles in the series “Build a
Linux-based Infrastructure Solution Demonstration Series” to date, that is to
the 8th of March 2017. The link to the main article is 
https://blogs.czapski.id.au/2016/10/build-a-linux-based-infrastructure-solution-demonstration-series.

In this article I am discussing how yad and gtkdialog can be obtained and
installed on CentOS 6.8. yad because I use it for simple OK/Cancel dialog boxes
and gtkdialog because I use it for the applications with reasonably
sophisticated functionality for which yad would be too cumbersome to use.


INSTALL YAD

Download yad from https://sourceforge.net/projects/yad-dialog/, build and
install.

cd ~/Downloads
wget https://downloads.sourceforge.net/project/yad-dialog/yad-0.38.2.tar.xz
tar xvf yad-0.38.2.tar.xz
cd yad-0.38.2
autoreconf -ivf
export CFLAGS="$CFLAGS -DPACKAGE_URL='\"http://yad-dialog.sf.net/\"'"
./configure
make
sudo make install

Is there help?

man yad

A simple information dialogue can be constructed as follows:

cat <<-'EODECK' > /tmp/yad01.sh
templateFile=/tmp/xml/GIndProv_template_request.xml
if [ ! -f ${templateFile} ]; then
    yad --title="Required XML Template does not exist" --text="Required XML Template\n${templateFile}\ndoes not exist - aborting" \
    --center --image="gtk-dialog-error" --window-icon="gtk-dialog-error" --width=500 --height=100 --button="gtk-ok:0"
    exit;
fi
EODECK

/bin/sh /tmp/yad01.sh



A more sophisticated dialog might look like this:

cat <<-'EODECK' > /tmp/yad_find_patient.sh
#!/bin/bash

fnUpdateFieldsSBR() {
    echo "3:${title:-MR}"
    echo "4:${lastName:-Smith}"
    echo "5:${gender:-Male}"
    echo "6:${ssn:-123456789}"

    echo "11:${firstName:-John}"
    echo "12:${suffix:-III}"
    echo "13:${dob:-10/10/1978}"
}
export -f fnUpdateFieldsSBR

yad \
--center \
--title="Find Patient by EUID" \
--text="<span size=\"xx-large\">Find Patient Details by EUID</span>\n" \
--form \
--width=550 \
--borders=5 \
--columns=2 \
--date-format="%m/%d/%Y" \
--align=right \
--field="Enterprise Unique ID" "${USAPatXEUIDX:-0001234567}" \
--field="Demographics:LBL" "" \
--field="Title:RO" "" \
--field="Last Name:RO" "" \
--field="Sex:RO" "" \
--field="Social Security Number:RO" "" \
--field="Options:LBL" "" \
--field="Show XML Request?:CHK" "FALSE" \
 \
--field "  Search!gtk-find:FBTN" "@bash -c \"fnUpdateFieldsSBR \"%16\" \"%8\" \"%1\"  \" " \
--field=":LBL" "" \
--field="First Name:RO" "" \
--field="Suffix:RO" "" \
--field="Date of Birth:RO" "" \
--field=".:LBL" "." \
--field=":LBL" "" \
--field="Show XML Response?:CHK" "FALSE" \
 \
--dialog-sep \
--button="Quit!gtk-quit:0"

EODECK
/bin/sh /tmp/yad_find_patient.sh




INSTALL GTKDIALOG

Download gtkdialog from
https://centos.pkgs.org/6/epel-x86_64/gtkdialog-0.8.3-8.el6.x86_64.rpm.html

# get and install the package
cd ~/Downloads
wget http://dl.fedoraproject.org/pub/epel/6/x86_64//gtkdialog-0.8.3-8.el6.x86_64.rpm
sudo yum localinstall -y gtkdialog-0.8.3-8.el6.x86_64.rpm

# get and install soruces for examples and documentation
wget https://fossies.org/linux/privat/old/gtkdialog-0.8.3.tar.gz
cd ~/
tar xvf ./Downloads/gtkdialog-0.8.3.tar.gz

Try a few examples provided in the source distribution to get some notion of
what can be accomplished with gtkdialog:

~/gtkdialog-0.8.3/examples/menu/menu
~/gtkdialog-0.8.3/examples/comboboxentry/comboboxentry_advanced
~/gtkdialog-0.8.3/examples/button/button_attributes
~/gtkdialog-0.8.3/examples/notebook/notebook_advanced

Take a look at reference and other documentation:

firefox file:///home/demo/gtkdialog-0.8.3/doc/reference/window.html &
firefox http://gtk.php.net/manual/en/html/gdk/gdk.enum.windowtypehint.html &


INSTALL GEANY

Download and install geany editor – it beats the gedit and other free
alternatives in my opinion

cd ~/Downloads
wget http://download.geany.org/geany-1.24.1.tar.gz

tar xvf geany-1.24.1.tar.gz
cd geany-1.24.1
./autogen.sh
make
sudo make install

Test:

cp -v /home/demo/gtkdialog-0.8.3/examples/window/window /tmp/gtk_window.sh
geany /tmp/gtk_window.sh &

Inspect the code in geany and press F5 to execute it.




GTKDIALOG HELLO WORLD

Create a modified script and experiment with the various settings of the window
attributes

cat <<-'EODECK' > /tmp/gtk_window.sh
#!/bin/bash
GTKDIALOG=gtkdialog

MAIN_DIALOG='
<window \
decorated="true" \
allow-grow="true" \
allow-shrink="true" \
default-height="200" \
default-width="400" \
resizable="true" xx-resizable="overrides default-height and default-width if set to false" \
deletable="true" xx-deletable="this keep (default) or remove the close button from the window title bar" \
icon-name="gtk-refresh" \
modal="false" \
skip-pager-hint="true" \
skip-taskbar-hint="false" \
title="My First Window" \
window-position="1" \
border-width="5" xx-border-width="is an inherited GtkContainer property - see object hierarchy at https://developer.gnome.org/gtk2/2.24/GtkWindow.html#GtkWindow.object-hierarchy" \
sensitive="true" xx-sensitive="is an inherited GtkWidget property that disables everything inside the window - see obect hierarchy" \
tooltip-markup="This is a <b>window tooltip</b>" xx-tooltip-markup="is inherited from GtkWidget" \
>
    <vbox>
        <frame   Description  >
            <text>
                <label>This is an example window.</label>
            </text>
        </frame>
        <hbox>
            <button ok></button>
            <button cancel></button>
        </hbox>
    </vbox>
</window>
'
export MAIN_DIALOG
case $1 in
    -d | --dump) echo "$MAIN_DIALOG" ;;
    *) $GTKDIALOG --program=MAIN_DIALOG ;;
esac
EODECK

/tmp/gtk_window.sh



Experiment with the setting of the Window object attributes and see what effect
the changes have on the appearance and behaviour of the window.

There is plenty more that can be done with gtkdialog. I intend to write more
articles on this topic as the time goes by. This article provides the tooling
for these later articles.

Tagged with: CentOS • create demo • create demonstration • demo • demonstration
• gtkdialog • infrastructure demo • infrastructure demonstration • Linux demo •
Linux demo image • Linux demonstration image • Linux UI • technical demo •
technical demonstration • yad

Apr 08


VIRTUALBOX IMAGE WITH CONTENT AS BUILT SO FAR – FOR DOWNLOAD AND IMPORT INTO
VIRTUALBOX

By Czapski Michael Demo Building No Comments »


INTRODUCTION

Please see the article “Build a Linux-based Infrastructure Solution
Demonstration Series”
(https://blogs.czapski.id.au/2016/10/build-a-linux-based-infrastructure-solution-demonstration-series)
for how this image came about and “gtkdialog Exploration”
(https://blogs.czapski.id.au/2017/04/gtkdialog-exploration) for the rationale,
introduction and links to articles in this series.

In this post I provide the link to the 7zip archive parts which put together
will provide the VirtualBox “.ova” export file. The “.ova” can be imported into
the VirtualBox 5.1.x as a new VirtualBox Machine Image.

This VirtualBox Machine Image has been built following steps in the series of
blog articles under the collective heading of “Build a Linux-based
Infrastructure Solution Demonstration Series”, to be found at
https://blogs.czapski.id.au/2016/10/build-a-linux-based-infrastructure-solution-demonstration-series.
It can be used as the basis for exploring other topics discussed in subsequent
blog articles whether in this series or in related series.


PRE-REQUISITES

This article assumes that the Virtual Box 5.1.x software
(https://www.virtualbox.org/) for the appropriate host OS has been installed.


DOWNLOAD IMAGE PARTS

The 7zip archive consists of 4 parts of around 650MB each, for a total of
reconstructed .ova file of 2.5GB. The imported machine will take about 6GB of
disk space.

Download the following to a suitable directory:

https://blogs.czapski.id.au/wp-content/uploads/2017/04/demo_v1.1.3_20170408.7z.001

https://blogs.czapski.id.au/wp-content/uploads/2017/04/demo_v1.1.3_20170408.7z.002

https://blogs.czapski.id.au/wp-content/uploads/2017/04/demo_v1.1.3_20170408.7z.003

https://blogs.czapski.id.au/wp-content/uploads/2017/04/demo_v1.1.3_20170408.7z.004


COMBINE PARTS INTO .OVA

Copy the parts to a suitable directory in a file system with at least 3 GB of
free space.

Open the first part with an archiver capable of dealing with 7zip archives and
extract the file demo_v1.1.3_20170408.ova.

On Windows in a command box the command might be like the following (substitute
drive letters and paths as appropriate, noting that -oO:\ points to the output
drive and directory and that there is a space between it and the name of the
output file which follows):

"C:\Program Files\7-Zip\7z.exe" e D:\demo_v1.1.3_20170408.7z.001 -oO:\ demo_v1.1.3_20170408.ova -y

 

7-Zip [64] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04

Scanning the drive for archives:
1 file, 681574400 bytes (650 MiB)

Extracting archive: D:\demo_v1.1.3_20170408.7z.001
--
Path = D:\demo_v1.1.3_20170408.7z.001
Type = Split
Physical Size = 681574400
Volumes = 4
Total Physical Size = 2546348186
----
Path = demo_v1.1.3_20170408.7z
Size = 2546348186
--
Path = demo_v1.1.3_20170408.7z
Type = 7z
Physical Size = 2546348186
Headers Size = 154
Method = Copy
Solid = -
Blocks = 1

Everything is Ok

Size:       2546348032
Compressed: 2546348186


IMPORT IMAGE

Use the VirtualBox Manager UI to import the .ova file.

Before you do, check where in your file system the machine directory will be
created and change as appropriate, bearing in mind that the target directory
must be on a device with at least 7GB of free space or that the directory has a
quote of at least 7GB of space if your environment uses disk space quotas:

File->Preferences->General->Default Machine Folder: ???

Once you are happy that the machine will go into the directory appropriate for
your environment import the machine image:

File->Import Appliance…

Locate the .ova file, change whatever machine settings seem in need of change,
like increase the amount of memory, the number of CPUs, etc., and Import.

Agree to the copyright statement (in which I claim no copyright or any other
rights).

On my machine the process takes about 2 minutes and produces a machine image
directory which uses approximately 6.6GB of space.


MAKE AND USE SNAPSHOTS

So that I have a known place to revert to if I mess something up, the first this
I always do after importing an image is to take a “as imported” snapshot. I also
take snapshots at various points in my work so that I don’t have too much to
re-do if I make am mistake and have to roll back and re-do some work. I
recommend that you consider this as a piece of good advice.



073_import_vm.png


CREDENTIALS

As discussed in the article “Configure Virtual Box Virtual Machine and Install
CentOS 6.8 Base Image”,
https://blogs.czapski.id.au/2016/10/configure-virtual-box-virtual-machine-and-install-centos-6-8-base-image,
all passwords configured to this point are “welcome1”. That includes the root
password. Change as necessary.

The image is configured in such a way that on boot the user “demo” will be
automatically logged in. That user is in the sudoers file and has passwordless
sudo rights.

Tagged with: CentOS • centos virtual machine • create demo • create
demonstration • demo • demo image vm • demonstration • gnome 2 • infrastructure
demo • infrastructure demonstration • Linux demo • Linux demo image • Linux
demonstration image • technical demo • technical demonstration • virtual machine
• virtualbox • virtualbox image

Previous Entries
 * Home
 * About


Free WordPress Themes
This blog used to have technical material on different topics relating to Sun
Java CAPS, OpenESB and SOA Suite for healthcare integration. New posts are not
going to be related to either of these. Of late the technical topics relate to
building Linux-based infrastructure demo images. What the future holds - who
knows ...


CATEGORIES  

 * API-First Development
 * Australian nbn ISP Internet
 * Demo Building
 * Development and Continuous Integration
 * gtkdialog
 * IPF Open eHealth Integration Platform
 * Java CAPS
 * Miscellaneous
 * OpenESB v2.3 Articles
 * Oracle
 * Oracle SOA Suite for healthcare integration
 * Personal
 * Software Development
 * Sun
 * Swagger
 * yad

 


TAGS  

5.1.3 bpel bpel 2.0 CAPS CentOS configure VirtualBox create demo create
demonstration demo demonstration development docker container eai glassfishesb
glassfish esb gnome 2 healthcare healthcare messaging hl7 hl7 messaging hl7 v2
hl7 v2 delimited hl7 v2 xml infrastructure demo infrastructure demonstration
install CentOS Java CAPS javacaps javacaps6 Java CAPS 6 jbi jcaps jms Linux demo
Linux demo image Linux demonstration image Linux UI openesb Oracle SOA Suite soa
SOA Suite for healthcare integration technical demo technical demonstration web
services ws-security
 


JAVA CAPS BASICSI, THE BOOK  


Part I: Table of Contents
Part II: Table of Contents
The book on Safari Books OnLine
 


RECENT POSTS  

 * Swagger Codegen in WSL Alpine August 9, 2020
 * Openapi Spec development using Swagger Editor in Container July 19, 2020
 * Swagger Environment for API Design and Testing – Workflow July 19, 2020
 * How to Use the Swagger Codegen 3.0 Docker Container July 12, 2020
 * Swagger Codegen 3.0 Docker Container July 11, 2020

 


ARCHIVES  

 * August 2020 (1)
 * July 2020 (6)
 * May 2020 (3)
 * February 2020 (1)
 * December 2017 (4)
 * May 2017 (3)
 * April 2017 (7)
 * December 2016 (2)
 * November 2016 (4)
 * October 2016 (9)
 * March 2013 (1)
 * February 2013 (2)
 * January 2013 (4)
 * December 2012 (2)
 * November 2012 (1)
 * September 2012 (1)
 * August 2012 (2)
 * December 2011 (2)
 * May 2011 (2)
 * April 2011 (1)
 * December 2010 (1)
 * October 2010 (2)
 * August 2010 (2)
 * June 2010 (6)
 * April 2010 (4)
 * March 2010 (3)
 * January 2010 (12)
 * November 2009 (2)
 * October 2009 (1)
 * September 2009 (5)
 * August 2009 (2)
 * July 2009 (7)
 * June 2009 (7)
 * May 2009 (5)
 * March 2009 (1)
 * February 2009 (5)
 * January 2009 (4)
 * December 2008 (2)
 * November 2008 (1)
 * August 2008 (2)
 * July 2008 (8)
 * June 2008 (4)
 * May 2008 (1)
 * April 2008 (2)
 * March 2008 (1)
 * February 2008 (1)
 * January 2008 (1)
 * December 2007 (2)
 * November 2007 (5)
 * October 2007 (6)

 


TWITTER  


 


--------------------------------------------------------------------------------