###################################################################################
2.) Syntax - How to use variables in the code.
###################################################################################

The basics of building a simple gui is told by the links in chapter 1.) You should have played a little bit before you continue.

About QUOTES
To show content of a variable in the gtkdialog code, we need to quote the variable in the gtkdialog code.

First realize that you put all the gtkdialog code into a variable - ie MAIN_WINDOW or Psync:
export Psync="<window title=\"Psync\"...........</window>"
if you now try to 'echo Psync' you'll get
<window title="Psync"...........</window>
which is correct code. But if you used ' instead of ", like this:
export Psync='<window title=\"Psync\"...........</window>'
you'll get
<window title=\"Psync\"...........</window>
This will give a syntax error.
export Psync='<window title="Psync"...........</window>'
will give correct syntax

Now using a variable like this:
TITLE=Psync
export Psync="<window title=\"$TITLE\"...........</window>"
returns
<window title="Psync"...........</window>
while
export Psync='<window title="$TITLE"...........</window>'
returns
<window title="$TITLE"...........</window>
and not the content of variable TITLE

Now return to the first example about quotes. This example combines the use of ' and ".

###################################################################################
3.) Let the script return data - Choose a proper coding structure
###################################################################################
The first step is to show a dialog window on your screen, then the next step is the interaction of the user with the gui. I think the easiest way is to divide guis into different groups. - Simple, Complex and Projects.

>>Simple
A simple dialog allows the user to give a response to a question/query on the screen:
- Do you want to continue?
- Please choose item in list
- ...
When the user click on the yes/no/cancel/ok-button the dialog exits and the script continues to evaluate the user input. Here is an example:

>>Complex
For more complex dialogs, we want to keep the gui alive even if the user clicks on something, so using an EXIT value is not the right choice. Calling pre-defined functions from inside the gtkdialog gui is a handy way to do this. We must remember to export all functions before executing our gui.

>>Project
When your project grows and its complexity makes it hard to work with, it's time to consider another approach. Splitting code into several files might be much more usable when working with your code. Group familiar functions into one file... In this example, the function-file must be saved in /root/test to work. Instead of sending <action> to EXIT, we send it to the file with the function 'now'.

NOTE, that I don't use an ordinary function (like the previous example), but a case command instead. The benefits are faster loading of your app since it does not read your functions into memory, but the greatest advantage is that you can edit the function while the gui is running. The downside are slower execution of the function.

>> If you want a second gtkdialog-gui to act on your main gui. You simply "launch" the second gui from the main gui. The negative aspect about this solution is that before showing the main gui, it has to load all the launchable scripts. This means slower startup.

>> Imagine that you start a background process to calculate the content of <list>. It will take too long to wait for the result before showing the gui. Imagine that you want to update the content in a gui from a separate app. Okay, here's the trick.....

Gtkdialog updates a progressbar with info from standard output. Most common are the 'cat' and 'echo' commands. First 'echo "text in bar"' (optional), then 'echo 50' or whatever % integer to define how long the process is come. When a progressbar achieves 100% done ('echo 100'), it activates its <actions>. So, as long as % is below 100, the actions are not run, but as soon as you 'echo 100' it will execute your defined actions. What is very good, is that you now can 'echo 0', and start all over again. Last stage is to define if you want the progressbar shown in your gui. add visible="false" to make it invisible.

>> If you want a frequent refreshing of a widget, the <timer> widget was introduced in gtkdialog 0.7.21.
<timer milliseconds="true" interval="500" visible="false">
Gtkdialog misses a tailbox widget, but using this solution it is easy to build our own tailbox.

>> Both <timer> and <progressbar> widgets uses cpu-power, and in a complex gui this could be a real pitfall. Here follows an explanation of how it is solved in pMusic. It is a way to update a complex gui on non-user actions. User-actions is mouse-clicks and key-entries, and is the common way to interact between user and gui. An example of updating the gui on a non-user-action in pMusic is the loading of id3-tags for files shown in the file-browser....

When clicking on a directory, the browser field refreshes and shows the content of the new directory. Now, pMusic continues with a background process to read the id3 information of the files. When finished, the browser field should be updated by the new info. - Without the user to click anywhere.

The solution is to either use a <progressbar> which runs its <action> when reaches 100% or a <timer> which acts at a given interval. Older Pmusic releases used the <progressbar> solution while recent code uses a <timer>. Both solutions has the downside that they use an amount of cpu power. In a complex gui with several non-user actions this could end up with several cpu-hungry <timers> updating their unique widget(s) of the gui.

pMusic has used 2 <timers> running constantly to update their defined gui-part. You might think that 1 <timer> would be enough, - it could refresh all wanted widgets - it wouldn't harm if the refreshing didn't change anything. BUT, refreshing has an effect on the focus handling. It simply resets the focus, which means that:
- scrolling in <table> is moved to top.
- what you are about to write in an <entry> is cleared.
- Your selected item in the <tree> is not selected anymore
- ...

The idea of pMusic 2.4.0 was to update all kinds of trackinfo (meta-tags, lyrics, albumart, discography, ...) when a new track starts playing. This would not be possible with the underlaying event-handling in pMusic because it would either suck your cpu-power (with several <timers>), or a global refreshing would make it impossible to be a user (because of focus issues). Also, there is a fact that too many refreshing <action> on a <timer> will increase cpu-usage as well.

So the solution has been to add ONE <timer>, which refreshes a small set of <checkboxes> that (if true) refreshes a single or group of widgets.

<checkboxes> can be set true or false by their <input file>, so we can simply 'echo true' to its <input file>. The <timer> runs its <actions> each second, and the <checkbox> will be refreshed by its <input file>. The code could look like this:

All actions will run only if value is true. To avoid more than one refreshing we reset <input file> and the <checkbox> value to false. Now it will be silent until the next time we 'echo true > inputfile'.

###################################################################################
5.) The benefits of a config file
###################################################################################

A config file is a nice way to store the settings in your program. At next startup, it will show the settings like you left them last time.

Set default status of Radiobuttons, Comboboxes...>> By default, gtkdialog always activates the first radiobutton and the first list-item for combobox.

An easy way to use a config file is to run it like an ordinary bash-script, and include variable definitions in it. It is most common to keep config files in home directory as a hidden file ($HOME/.testrc). The file might look like this:

Now let's go to the main script. For the radiobuttons and the entry, we set the <default> tag to the corresponding variable in the config file. Since the combobox doesn't support the <default> tag, we need a workaround. We simply build the combobox item-list so show our saved variable first.

The last codeline redirects output (variable values) to our config file instead of to the terminal.
Note that line 2 starts with a dot. It makes a huge difference if you skip it.
. $HOME/.config --> run script as a childprocess as the main process. The variable values in the config file are reachable for the main script.
$HOME/.config --> run script as a new process as the main process. The variable values in the config file will NOT be reachable for the main script.

How to store window size/placement>> This example shows how we can save settings for window size and placement for next startup. Be also aware that this solution makes it possible to let user rescale gui smaller than the default size. Normally you define the size of, for example, a <tree>, and the user can only resize the gui larger, but when using <window default_height="$HEIGHT" default_width="$WIDTH">, you don't need to define <height> and <width> for the tree widget.

Gtkdialog is not a fast gui-lib. If you are building a gui where speed matters, please check the following notes.

>> For an unknown reason, it is much faster to start your gtkdialog-xml-code from a file than from a variable.
gtkdialog --file=filenamegtkdialog --program=variable
The file alternative is highly recommended if your xml-code is getting complex.

>> Run large calculations as a background process. Pmusic builtin filebrowser (version 0.9) first shows songs in the directory, then it starts a background process to find meta information of the songs. When finished, it renders the song-list once again, now with complete information. How to use a background process with gtkdialog is explained in the chapter 'Let external code act on your gtkdialog gui'.

>> Even if gtkdialog is slow, your bash-code might make it MUCH slower. Be careful with the use of subshells, and slow commands such as sed, ps, expr, cat ... This is of course most important when building a loop.

The comparison of code shows how to do the same operation in 2 different ways. The speed differs a lot. First an example why you should avoid 'cat', then why never use 'expr' if speed matters. My system needed 4 seconds to calculate 1+1 thousand times with 'expr'. Using the builtin bash command it took 'no time'.

Code:

# time for I in $(seq 1 1000); do B="`cat /tmp/tmp`"; done
real 0m3.095s
# time `IFS=$'\n'; for I in $(seq 1 1000); do B=($(<"/tmp/tmp")); done`
real 0m0.927s

# time for I in $(seq 1 1000); do expr 1 + 1 > /dev/null; done
real 0m4.286s
# time for I in $(seq 1 1000); do A=$((1+1)); done
real 0m0.032s

>> There are many ways of building a gui. The pictures below shows the builtin file browser/filesearch in Pburn 2 (left) and Pburn 3. The code has shrunk from 3110 to 997 chars. It does exactly the same, and the speed improvement is notable.

<button>>> You can skip the button decoration.
<button relief="2">...</button>>> The image doesn't need to be left of label. It can be left/right/above/below. Values 0-3. Be aware that this seems to work only for icons in the gtk-stock.
<button use-stock="true" image-position="3">...</button>>> Use gtk-stock values
<button use-stock="true" label="gtk-quit"></button>>> Hotkey is set in 2 ways
<button use-stock="true" label="gtk-cancel">...</button><button use-underline="true"><label>_Cancel</label>...</button>>> Scale icon
<button height-request="50" width-request="80"><input file>file.jpg</input><height>40</height><width>70</width></button>

<progressbar>>> Avoid window to autoscale because of too much text in progressbar. You can truncate text at left (1), at right (3) or in the middle (2) by the ellipsize tag.
<progressbar text="Truncated the text in the middle" ellipsize="2"></progressbar>>> Define the text alignment by text-xalign and text-yalign tag. try out values from 0-3 for left, right and center.
<progressbar text-xalign="1" text-yalign="1">>> Do not show text
<progressbar show-text="false">>> Alternative bar outfit. - view blocks
<progressbar bar-style="1">>> Do not truncate result to block-size.
<progressbar discrete-blocks="25">>> Set orientation
0 - Horizontal - left to right.
1 - Horizontal - right to left.
2 - Vertical - bottom to top.
3 - Vertical - top to bottom.
<progressbar orientation="3">

Comments in your code
Gtkdialog doesn't support comments in its xml code. But if we convert all comments before execution, it works. The reason why I use double hash (##) for my comments, is because colors in a <span> tag might be defined as 'red' or '#FF0000'. The latter would be removed by using a single hash.

Code:

#!/bin/sh

XML='
<vbox> ##this is how to comment your xml code.
<text height-request="50"> ##force the text to take more space.
<label>Hello</label>
</text>
<hbox> ##hbox to align button to the right.
<button ok></button> ##button ok is fetched from the gtk stock.
</hbox>
</vbox>'

export GUI="`echo "$XML" | sed -e 's/##.*//'`"
gtkdialog -p GUI

Include code if.......
It is possible to build the gtkdialog out of many small pieces. Every piece is a variable and are put together when exporting the gtkdialog code. It is easy to think that a button should have different label depending on ........ Or like in the following example, - include a button if file/app/.. exists. Instead of defining all these pieces before the actual gtkdialog code, it is much more human readable if you define all 'inside' the gtkdialog code.

How to change the gui without restarting the app>> Recent Gtkdialog allows to hide/show widgets, To hide many widgets at once, you can hide a <hbox> or <vbox>. This will hide all widgets inside the box.

>>Another approach is to use the notebook attributes <notebook show-tabs="false" show-border="false">. Using several tabs in a notebook with hidden header, we can simulate a gui re-render. The only thing that is happening is that we switch tab, but since the user can't see those, he will be fooled...
More info here.

Control the icon/label of menuitems>> If you have met problems to show a certain icon and at the same time give it an unique label, this will illustrate how it is recommended to be implemented for the benefit of anyone and everyone.

Doing it this way makes GTK+ deal with the left-to-right and right-to-left internationalisation of the icons if applicable. You might be thinking that this isn't going to work because GTK+ will make a stock label "_Undo" and it will, but straight afterwards it will update the label with $LOC118 and additionally because it was initially a stock label, "use-underline" is already true so you can use underscores in your custom text.

Understand the alignment>> Gtkdialog tends to align objects to the right side of the window. Exceptions are radiobuttons and checkboxes which are aligned to the left. It is easy to center whatever object in your gui. Here's some alignment explanation:
- <hbox><button>...</button></hbox> will place button to the right.
- <button>...</button> and button will fill whole line.
- <hbox homogeneous=true><button>...</button></hbox> will place button in horizontal center.
- <hbox homogeneous=true><vbox homogeneous=true><button>...</button></vbox></hbox> will place button in center both vertical and horizontal.
- <hbox><text xalign="0">...</text></hbox> will place text at left. xalign/yalign may hold 0 (left), 1 (right) and 2 (center). xalign/yalign works for other widgets as well. For buttons they describe placement of label rather than button itself.

>> Using vertical rows can be troublesome, because often, the label defines the width of the objects. This leads to different width and it all looks crappy. You can override this by the attribute <vbox width-request="x">....</vbox>, where x represent the number of pixels for the width of the row. There is also a 'height-request' attribute.

Window header icon>> You can add your own icon (symlinks also work) if you place it in a gtk-theme directory structure as /usr/share/icons/hicolor/. ie. /usr/share/icons/hicolor/48x48/apps/games48.png
Now, run this command in the terminal to refresh the icon cache;

>> Move items in list by drag'n drop. (More info in this thread)
Using the reorderable option in the <tree> has some strange behavior. For example will items get swallowed when moving them onto another item. The workaround restores the list if the user moves item onto, instead of in between 2 other items... This code by MochiMoppel is a result of 2 cracked nuts:
- When moving an item in the list the $PTR_Y variable returns 0. A return value >0 gives us the info that the user is clicking rather than moving.
- Normally all <action>s defined for a widget are processed before built-in actions. The trick is to process a user defined <action> after a built-in action. An invisible button allows the code to run a user defined save action after a built-in reorder action."

Hotkeys>> An <action> signal inside the <window> widget gives the most direct hotkey
<action signal="key-press-event" condition="command_is_true( [ $(( ${KEY_MOD} & 5 )) = 5 ] && [ $KEY_RAW = 0x1b ] && echo true )">Refresh:varDATE</action>
SHIFT's state is held by by 0th bit and CTRL state by 2nd bit of $KEY_MOD variable (?????C?S) , so, in order to read their state correctly, we need to discard the rest of bits by logical AND: $(( $KEY_MOD & 5 )). If we would want SHIFT alone, it would be $(( $KEY_MOD & 1)) = 1, only CTRL - $(( $KEY_MOD & 4 )) = 4 and so on.
see this forum thread for more depth

>> Menuitems can set both accelerator key and modifier (SHIFT is 1, CTRL is 4 and ALT is 8 ). For a full list of accelerator key values check this<menuitem stock-id="gtk-quit" accel-key="0x51" accel-mods="4">

>> You can activate buttons by pressing keyboard combinations. simply add the attribute 'use-underline'. If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key.
<button use-underline="true"><label>_Refresh</label></button>
The defined char in the <label> + 'alt' key will activate given <action>.

Set a fixed size of a progressbar>> Progressbars are by default rather big. But it's not that easy to define the width of a progressbar. To do this you have to combine some attributes.

Define unique gtk-theme>> Sometimes it is nice to change the gtktheme just for my app. Like this I get more options for my gtkdialog script.

Gtkdialog does not support monospace in the <edit> widget, but I can make it work by adding a unique gtk-theme only for my app. The best way to this is to add my new gtk-theme on top of the already existing. Now my gtk-theme can hold ONLY information about monospace, else it will use gtk-settings specified by user.

By giving the text-widget a name (see example), it is possible to have a gtk-theme for only this unique text string. This also works for text in widgets like <entry>.

>> The option 'nolist' does avoid your app showing up in the taskbar.
>> The option 'sticky' shows your app on all desktops.
>> The option 'noborder' is equal to the gtkdialog attribute <window decorated="false">.
>> The option 'layer:x' defines if other windows should cover your app, or if it should be on top. layers can be 0-12 where 12 is the on-top setting.

Let entry accept (some) numbers only>> The following example shows how to limit the user input to a <entry>. Useful for 'all' kinds of settings.

MIME>> What should happen when the user double-clicks on an image-file in your gui. In some cases it is logical to show the image in an image-viewer.... but it is no need of linking all kinds of extensions to different programs. - It is already done by the filebrowser. Puppy uses 'rox' and if you execute 'rox /path/image.png' the image will show up in the defined viewer. Just as simple as that.

Checkbox with image>> This example shows how to add a image beside the label of a checkbox. Be aware that this tecnique only works for gtk stock-items.

Use a splash screen>> A splash screen could be useful if the startup time is increasing. The delay may occur for 2 reasons. There are several startup processes, or the gtkdialog code is heavy. The latter case makes it necessary to close the splash-window first when the main window is drawn on screen. We use the <window> signal 'show' to determine when the splash should be closed.

Advanced text layout>>Bold, italic and underline.
<text use-markup="true"><label>"<b><i><u>test</u></i></b>"</label></text>>> Gtkdialog supports colors and size with the <span> tag. The use-markup="true" must be included.
<text use-markup="true"><label>"<span color='"'#789978'"'>test</span>"</label></text>>> Text size is set by the <big> and <small> tags. Repeat (up to 3 times) to increase value.
<text use-markup="true"><label>"<big><big><big>test</big></big></big>"</label></text><text use-markup="true"><label>"<small><small><small>test</small></small></small>"</label></text>>> Vovchik has made an editor to test advanced text layout,
Check it out here.

Scroll text>> This example shows scrolling text in a <text> widget. This will work for other widgets as well.

Set font>> This is an example how to use other fonts even if gtkdialog hasn't an option to set this.

Gtkdialog does not support monospace in the <edit> widget, but I can make it work by adding a unique gtk-theme only for my app. The best way to this is to add my new gtk-theme on top of the already existing. Now my gtk-theme can hold ONLY information about monospace, else it will use gtk-settings specified by user.

By giving the text-widget a name (see example), it is possible to have a gtk-theme for only this unique text string. This also works for text in widgets like <entry>.

I would like to have a checkbox that would output to a list in a file that could then be used in a "for" statement. I'm afraid I don't understand the output of these GUI's, or any for that matter, although I have been able to modify other people's to suit my needs.

I've been learning the ins and outs of gtkdialog3 for a while but put it aside to study genie. Not much documentation for either genie or vala and so I went back to basics and reviewed the GTK+ documentation from http://library.gnome.org/devel/gtk/stable/gtkobjects.html. Whilst trying to convert the GTK+ offical c tutorial examples to genie I had an epiphany.

Widgets in gtkdialog3 can accept attributes (read properties) but little documentation was about and the examples hinted that there was more under the hood than shown. I also glanced at the glade interface and saw more evidence of props there but how to use them?

N.B. some properties are enumerated and can be replaced by integer values e.g in a window widget window-position=\"1\" means centre the window and window-position=\"2\" means follow cursor. A tip is when reading the documentation a tooltip indicates the property type
Also note that widgets have hierarchy and inherit from them (check out GtkWidget for example)Last edited by potong on Sun 14 Feb 2010, 04:52; edited 1 time in total

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou can download files in this forum