Skip to main content

Posts

Showing posts from 2021

October News...

 2021-10: gnocl::text o insertImage command enhanced to follow the insert command for text, ie.. $wid insertImage <pos> <imagename> -tags <taglist> Where image can take a standard image %-markup prefix gnocl::pango o new subcmds, markup2options, options2markup attempts to convert a pango markup string <span> tag to a list of text attibutes e.g.,  gnocl::pango markup2option "<span foreground='red' background='blue'>"   returns  {-foreground "red" -background "blue"} gnocl::pango option2markup {-foreground "red" -background "blue"}  returns "<span foreground='red' background='blue'>" created strings.h header file, keep decls for project string utilites gnocl::text o tag    new sub command - return character tag properties as pango markup   new options -underlineColor, -strikethroughColor, not use...

First Attempt at Accessing GObject Private Data - FAILED

When the toolbar is placed in the vertical alignment widget texts are still centred. I thought that making these alignable might be more aesthically pleasing. I didn't complete the job, but I did glean a little bit more on just how to access widget private data. It all seems to pivot around the G_TYPE_INSTANCE_GET_PRIVATE macro. #if 1 /* ATTEMPT TO LEFT ALIGN BUTTON TEXT */ struct _GtkToolButtonPrivate { GtkWidget *button ; gchar *stock_id ; gchar *icon_name ; gchar *label_text ; GtkWidget *label_widget ; GtkWidget *icon_widget ; GtkSizeGroup *text_size_group ; guint use_underline : 1 ; guint contents_invalid : 1 ; } ; typedef struct _GtkToolButtonPrivate GtkToolButtonPrivate ; struct _GtkToolButton { GtkToolItem parent ; /*< private >*/ GtkToolButtonPrivate *GSEAL ( priv ); } ; #define GTK_TOOL_BUTTON_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TOOL_BUTTON, GtkToolButtonPrivate)) GtkToolButton ...

Converting a Pango Markup Span Tag to a List of Text Widget Tag Options

Its always been a trouble task sharing formatted text between the gnocl::text widget and other display widgets such as the gnocl::label, gnocl::tree and gnocl::list widgets. This diffculty arises from not being able to define text attributes as pango markup, this is understandable given that fact that there is not a smooth overlap between the widget and pango attributes. What was needed was a way of bridging the two requirments, being able to take a markup <span> tag and converting to an -opt val list. Parsing markup strings using the pango api is not terribly helpful, it is complex and only works on complete strings, "<span .... ...>" would simply through up a pango formatting error. The solution has been much simpler by using a series of string mapping operations in the source module with the resul being the creation of a new gnocl::pango subcommand "markup2options". For instance, if:  set markup "<span font='Serif italic bold 24' fore...

String and Text Block Insertion Allowing for HTML/Pango String Markup

Tcl offers some really excelling string manipulation tools 'straight out of the box' although sometimes something extra might be needed. What if, for instance, the strings contain markup? Any markup is invisible on screen and so any string positioning needs to ignore the effects of that markup on the overall string length. This can be achieved by using a simple flag to keep track of where characters in a string are containtained within a markup substring or not. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 ## insert str1 into str2 at position pos, allow for pango/html markup # @param[in] str1 # @param[in] str2 # @param[in] pos # @param[in] opt # @return modified string proc string_insert { str1 str2 pos { opt "" } } { switch $opt { -markup { set flag 1 set i 0 set res "" foreach c [ split $str2 "...

Recent Changes October, 2021

Most significant change during September was the inclusion of the -spellcheck option for the gnocl::text widget.  2021-09: gnocl::text o new boolean option -spellcheck, cget also works,  gnocl::spellcheck o moved separate code back into the main module gnocl::labelEntry o added substitution strings %X %Y %W %H to -onIconPress/-onIconRelease callback scripts. o cget -variable now works gnocl::calendar o added substitution strings %D %M %Y to -onDoubleDaySelect callback script.

Creating icons from UTF-8 Characters.

Linux distros have heaps of pre-installed icons ready for use. I recently needed to create a toolbar menu which needed to access a set of unique icons which contained single characters. It was, in fact, a pull down menu for the insertion of 'special characters'. The Gtk+ api has complete functionality for creating icons from pixbufs and Gnocl providing convenient access.  Here's a screenshot and the script.     # !/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" package require Gnocl if { [namespace exists jmls] == 0} {     namespace eval jmls {} } set ::app(specialCharacters)  [list Section ¶ Paragraph § Separator • Left-Arrow ← Up-Arrow ↑ Right-Arrow → Down-Arrow ↓ Root √] proc jmls::charIcon {name ch} {          set pb1 [gnocl::pixBuf new -width 40 -height 40]     $pb1 text \         -position [list 15 30] \         -font [list...

September updates

August saw a few modifications to the core, largely in the form of resolving some minor issues adding some utility functionality.   2021-08:     gnocl::menu         o bug in configure -tearoff now fixed.     gnocl::notebook         o new tab option -tooltip     gnocl::text         o fixed problems with -onButtonPress/Release signal handling.           See gnoclConnectOptCmd.     gnocl::pointer         o new subcommand, monitor.     gnocl::timeOut         o now works properly.           Use as an alternative to Tcl after which does not work within a Gtk.     %c (child) substitution string added to -onKeyPress/Release callbacks           for Gtk...

gnocl::timeOut

I'm not certain what's going on, but running the Tcl after command within a Gnocl application results in the after command not working properly. No big problem. use the gnocl::timeOut command which offers the same basic functionality. gnocl::timer milliseconds script returns timerid To stop a timer, run gnocl::timer stop timerid Here's a sample script: # !/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" set i 0 set hb [gnocl::hBox] set lab [gnocl::label -variable i -baseFont {Sans 24}] set stop  [gnocl::button -text "STOP" -onClicked {  %w configure -sensitive 0 ; $start configure -sensitive 1 gnocl::timeOut stop $timer } -sensitive 0] set start [gnocl::button -text "START" -onClicked {  %w configure -sensitive 0 ; $stop configure -sensitive 1 set timer [gnocl::timeOut 1000 { incr i } ]  }] $hb add $lab -fill 1 -expand 1  $hb add "$start $stop" gnocl::window -title "Timed Counter" -child ...

Working with tagging words.

The problem, how to tag a block of text in a textwidget when only a row-col (line-offset) pairing is know? The Gnocl text widget has employed offsets for some time but this has always been in used in commands where the insertion point is used. Some recent changes to the getPos text subcommand will go some way in picking out words, lines etc., when using the "tag apply" instruction.  Previously, getPos would only return a line-offset pair based upon the current mouse pointer position over the widget, this has now become the default. The enhancements allow two arguments to be passed, a line-offset pair and a keyword. So, if the line-offset refers to a point mid-way in a word, its now possible to hold of other relative positions using keywords.   $text tag apply \ [$text getPos [list $a $b] wordStart] \ [$text getPos [list $a $b] wordEnd] \ -tags red

Working with long text tag names.

Pango is really useful for creating markup strings although it does some caveats. It is markup for display purposes and not interactive editing. Some work has been done in bridging the gap between the display widgets and the text editor by creating preset markup tags which are meaningful names as tag whilst being valid pango strings. Pango also has some convenience tags although extending this list is not possible at all, nor its is directly possible through the Gtk api to directly convert pango attributes to tag properties or vice versa.  To exchange formatted data between the text edit and display widgets needs a degree of creative programming on the part of the coder:   set txt [gnocl::text -useMarkup 0 -wrapMode word] gnocl::window -child $txt -setSize 0.2 -onDelete {exit} $txt tag create "<span rise='3000' font_size='small'>" -fontRise 3 -fontSize 8 -foreground red -editable 0 puts [$txt tag names] $txt insert end AAAA -tags [$txt tag names] $txt in...

July updates.

Added some useful functionality during June although some work still needs to be completed. The most annoying thing to be fixed was nagging issues over lineEnd and sentenceEnd, which was a simple logic matter. Of the most pleasing, reworking of dump. The aim being to provide the scripter with the ability to created serialized text files, Blog post to follow. 2021-06: gnocl::text o issues with lineEnd and sentenceEnd offset keywords now fixed.  gnocl::labelEntry o cget -value now works properly. gnocl::tmpFile o convenience command to create a temporary file name, with prefix. gnocl::languages o return information on languages supported and their naming conventions . gnocl::text o reworking dump command. o new tag option -markup, assign pango markup equivalent (not validated). o mark options -gravity and -visible can now be set on creation

Toggling Text Visibility

 A simple way of toggling text is to assign a tag and manipulate its -invisible option, again using the event handling capability of a tag to control the setting. Notice that the snippet below, for each array two tags are created _${a} and _${a}_ where the former is the display header with the control, and the latter the tag to be elided.  # !/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" package require Gnocl set txt [gnocl::text -tabs 150 -editable 0] gnocl::window -child $txt -onDelete { exit } -setSize 0.25 array set app [gnocl::application] array set fruit [list apple 1 bannana 2 cherry 3] array set cars [list morris a humber b austin c] proc addLabel {wid str tag} {      $wid addChild [gnocl::label -text $str]      $wid tag apply lineStart lineEnd -tags $tag      $wid insert end \n } proc tagClick {w n event} {      if { $event == "buttonPress-1" } {           $w t...

Getting Widget Style Properties

Until the move over to Gtk4, Gnocl is still built against the Gtk 2.21 libraries. One of the inconveniences of Gtk is getting and setting widget style settings which are considered to be set globally by the desktop style settings and not for the programmer to tinker around with. Needless to say, there are times when different defaults are preferred, largely to draw the users attention to 'something a bit different'. The function gtk_widget_modify_font  is a convenience function to set the widget basefont as shown in this snippet from the button.c module,  if ( options[baseFontIdx].status == GNOCL_STATUS_CHANGED ) { GtkWidget *label; label = gnoclFindChild ( GTK_WIDGET ( para->button ), GTK_TYPE_LABEL ); PangoFontDescription *font_desc = pango_font_description_from_string ( Tcl_GetString ( options[baseFontIdx].val.obj ) ); gtk_widget_modify_font ( GTK_WIDGET ( label ), font_desc ); pango_font_description_free ( font_desc ); } Unfortunately, there's no d...

Creating temporary files

The C stdio package has two function calls related to the creation of temporary files: tmpFile and tmpnam. The Glib too has similar functions in its api such as g_mkstemp, g_file_open_tmp and so on. For someone programming in C, both of these approaches are excellent resources but someones scripting in Tcl more suitable approaches can be taken these C procedures will require a significant amount code to produce an effective binding which, may not offer worthwhile advantages. The inclusion of a new command gnocl::tmpFile into to the core offers a convenient way of producing unique filenames. The command takes a single argument, an optional prefix, and returns a unique name with a randomized suffix. If a prefix is specified: puts [gnocl::tmpFile aaa] /tmp/aaa.SYzqiJQA8Eeg4GZC1eDb puts [gnocl::tmpFile bbb] /tmp/bbb.VIT88L2zjeynnHn5dVfH puts [gnocl::tmpFile ccc] /tmp/ccc.3IkQqXjYtwDowshdjjCc Without a prefix, the defaul 'TclScript' will be used. puts [gnocl::tmpFile] /tmp/TclScript...

May 2021 News!

 Just a handful on modifications this month.   2021-05:     gnocl::winfo parent $wid         o no longer crashed when parent == null.     gnocl::menu         o -data and cget -children now work correctly.     gnocl::text         o fixed minor internal issues relating to getPos, lineStart/lineEnd keyword usage.     gnocl::notebook         o intermittant crash using the remove/removePage subcommand fixed.         o began implementation of embedded tab widgets     gnocl::eventBox         o fixed problems with -child command.             (For some strange reason, the gnoclOptChild call would not work             for eventBoxes after it had be...

Removing a gnocl::application toplevel.

The gnocl::application command is a really use option to create a project ready front end. It creates all the necessary basics, containers, menubars, toolbars and status zones -- it even packs the whole lot into a toplevel window and returns the widget-ids of the contents. But what, as I recently needed, must be done when the application is the centre of a plug-in to be packed into some pre-existing container held in some other toplevel window?   Remove and repack!   The whole layout is contained in a frame, a widget ordinarily accessed. This needs to be removed from the default toplevel and repacked elsewhere.  Here's how to do it. array set app [gnocl::application]    $app(topLevel) remove $app(frame)    $app(topLevel) delete unset app(topLevel)

The recently added 'tabCondfigure' and 'tabCget' is now replaced with 'tab configure' and 'tab cget'.

I've just been working on the module to create the gnocl notebook widget, paying particular attention to the tab configuration options.   Earlier, and for convenience's sake, I added two commands tabConfigure and tagCget . All well and good, but the established practice of is to have the commands addressing the main container, and sub commands container objects, in the manner of the text and its tags and various other elements.   The reasoning for this is that the notebook tab contains a child widget, a label by default, which the Gtk api allows to be directly accessed or even replaced. This is how some applications are able to embed widgets into notebook tabs (take Geany for example).   Unlike text tags, which are the same class of object, the notebook tab ans a container can  become the parent of any other widget or even a boxed set of widgets. Aware of this, any specific cget or configure command needs to be customized in order to allow for this extra flexibilit...

Belated April updates....

  Overlooked posting April's updates. Here goes...  2021-04:     gnocl::window         o new commands: maximize, fullscreen. Take boolean arguments.         o problems with using -setSize after window first shown fixed.     gnocl::menu         o new option -widget for popup subcommand, position popup at bottom left corner of the specified widget.         o menu tearoff item no longer added by default. This due to "window show" revealing any hidden items.           The -tearoff option was added to emulate Tk, but in practice this rarely used.     gnocl::comboEntry         o new option -editable for gnocl::comboEntry         o new command clear, a synonym for set "".           Simply a con...

Simple string padding

Just a quick way of centering a substring within a space passed string.  Nothings perfect, especially when odd numbers are concerned.  proc pad { str max} {     set len [string length $str]          set tmp [string repeat " " $max]     set dif [expr $max-$len]     set fr [expr $dif/2]     set to [expr $fr+$len]      set str [string replace $tmp $fr $to $str]          return $str }

Text Widget List Viewer

    The list widget is a great tool for displaying related information in sets. That is a sample, distributed across rows and columns. To do this the list widget creates cells for each sample and allocated memory to handle its formatting and data. In practice, this means two 'blocks' for each piece of data. The information to display, and how to display it. This arrangement works fine for large humanly workable amounts of data, perhaps up to 1,500 or more rows. But, what about more, much, much more? I have a translation data set with source and target language pairs well in excess of 57,000 pairs. The list widget will handle these, but the delay receiving and rendering is far too long. The solution then, is to tweak the text widget to handle similar rows with a row picker. Sounds complicated, but its not. Just a couple of tweaks needed. Put the text widget inside an eventBox and then trap any direct events being passed to it, whilst allowing the scrolledWindow contain...

Zen and the Art of Computer Programming

When we learn to code we work on simple problems, maybe the sort of tasks that were originally used to test and develop our favourite languages, libraries and apis. In a nutshell, simple solutions to simple problems.  But, when complexity takes over, rules often go out of the window - there may be causes, but these cannot be easily identified and defined. The may be at a 'lower level', perhaps in dependencies or even compilation errors.  I've just had to resolve one such problem arising from the failure to display of child widgets in an eventBox . After modifying the gnoclOptChild code in the parseoptions.c module to offer the ability to replace child objects in a GtkBin , the new code worked for other GtkBin objects but not for an eventBox .  The solution was to copy the contents of the gnoclOptChild function and divide the code between the configure and cget module functions. This also needed a modification to the EBoxOptions array. Happy again now! So why the Zen...

Notebook Tabs with Embedded Widgets.

Ok, its of limited use but it is possible to embed user defined widgets in a notebook page tab. In all likelihood it will still be a label and a button embedded in hbox and not a list or tree view !  Including custom labels does have its drawbacks, its not really practicable to use accelerators in the same way and, if any commands or substitution strings are passed then these will return label widget-ids and not the label text string. # !/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" package require Gnocl set nb [gnocl::notebook] $nb addPage [gnocl::button -text HI] AAAAA $nb tabConfigure 0 -data 1 # label and box set hbox [gnocl::hBox -padding 0 -borderWidth 0] $hbox add [gnocl::label -text %_H_IHIHI] $hbox add [gnocl::image -image %#SaveAs -stockSize smallToolBar ] $nb label 0 $hbox puts [$nb getLabel 0] gnocl::window -child $nb

Setting Variables from Lists

The format for defining a Tcl proc is simply: proc name {var 1 var 2. . var n } { } There is a special keyword when defining the variable list, args . When placed at the end of proceedures argument list, it results all other values being passed as a single list. In effect then, it allows a Tcl proc to recieve a variable number of arguments. So, the above definition could be re-written as: proc name { args } { } The implication here is that keeping to a single string as an even numbered list tags and values, it becomes possible to define variables within the calling procedure. Once passed, these can be set using the standard Tcl foreach command. proc name { args } {      foreach {*}$args {break} } Now, this process can be taken one step further. Many system commands have values, commands and switches and it can be helpful to emulate these patterns within a Tcl script as it saves the mind power of having to switch between programming styles. The next step then is: proc n...

To Close or to Hide, that is the Question.

Sometimes you want make a popup window with some editing or parameter setting functionality which is a bit like a dialog , although floating palette is what immediately comes to mind.  The problem is though, that whilst it's easy to adjust the window decorations, to remove the delete icons, the window's pull-down menu will still have a close option which will, by default, destroy the window when clicked.  To disable this, and simply hide the window so that it can be show n again, set the -hideOnDelete option to 1.  Following this callback scripts can be used to respond to the visibility state of the window, acting as some form of Ok button if necessary.   # !/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" package require Gnocl set txt [gnocl::text] set win1 [gnocl::window -child $txt] \     -title Win1 -x 500 -y 400 -setSize 0.125 # EXTRA OPTIONS $win configure \      - hideOnDelete 1 \      -on...

Had a Real Pig of a Morning Today!

  I've spent the better part of half a day solving what really ought to a have been a trivial problem. Well, the solution was trivial but tracking down the cause of it all was very frustrating indeed! Consider this: set menu [gnoc::menu] Hitherto, in order to be compliant with now ancient formatting practices, a menu automatically has a tearoff item place at position 0 in the children list. So, to hide it, because we don't want one use: set menu [gnoc::menu -tearoff 0] or set menu [gnoc::menu] $menu configure -tearoff 0] So far, so good. But, if the gnocl::application command is used to produce a working UI framework, and extra widgets including addition menu bar items, and the show subcommand used for the application toplevel then BOOM!  The recently made menus without tearoffs suddenly got tearoffs again. 😠 The issue was that the existing menu.c configure function simply hid or showed the default tearoff item. This needs to be created or destroyed when needed. Well, job don...

Why didn't I do this before?

Sometimes its so much more convenient (and efficient) to implement something in C rather than Tcl: positioning a popup menu on screen is one of those situations. To this end a new option, -widget, has been added to the menu popup subcommand.  This causes the callback handler to determine screen coordinates from the on-screen location and height of the widget specified by the -widget option. Compare: $abut configure -onClicked "$menu popup -widget %w" With: $abut configure -data $menu -onClicked {         lassign [gnocl::winfo geometry %w] x y w h           %d popup [expr $x-4] [expr $y+$h] } This latter approach not only requires memory allocation using -data but 'pollutes' the global namespace with the extra variables 'x y w h' which might result in some form of conflict.  For those who notice, there is '+4' which is an attempt to handle the buttons style border-width setting. This isn't handled in the callback sc...

Namespace export-import, aliases and rename

      Namespaces are really useful in Tcl as they permit commands and variables to be conveniently grouped together. This means that common command names can be reused within specific contexts, and that variables can be 'hidden' away from errant command calls. All this extra security does come at a cost, a lost of unecessary and respetative typing. Using the gnocl:: namespace prefix is useful if, lets say, there is a need for mixed Tcl and Gnocl programming. But, if there isn't this need what can be done to alleviate the typing burden, albeit with some risks when coming to readability and portability between applications? Variables and commands embedded within a namespace can undergo export-import process or they can be renamed. The following code example shows how this can be done. When exporting and importing between namespaces its possible to have a naming conflict in the importing namespace. Tcl will pick this up and result in an error. Fortunately this only appl...

gnocl::unicode -a new command

Determining the language of the user's system and script of a text string     puts $env(LANG) puts $env(LANGUAGE) puts [gnocl::unicode script "我是英国人。"] puts [gnocl::unicode script "ཀརྨ"] puts [gnocl::unicode script "aṣṭa"] puts [gnocl::unicode script "ꛅꛇꛈ"]   puts [gnocl::unicode options] puts [gnocl::unicode commands]

March 2021 Updates and News

    Fashionably late? Maybe not. Here's a listing of the recent enhancements to the gnocl core modules. 2021-03:     gnocl::fileChooserButton         o -fileFilters option now works correctly     gnoclKeyboardCmd, retrieve keyboard state.         o Returns list of boolean for: NumLock CapsLock ScrollLock           For Overwrite Mode of text and entry widgets, obtain setting from wiget directly           using %w cget -overwrite.     gnocl::window, gnocl::frame, gnocl::expander, gnocl::handleBox, gnocl::scrolledWindow         o -onDelete %c string option added to handle GTK_BIN objects, return sole child widget.     gnocl::dialog         o new option -noButtons, creates a buttonless dialog, with        ...

Getting Keyboard Lock and Overwrite Settings

        #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" if { [catch { package present Gnocl } ] } { package require Gnocl } set win [gnocl::window -child [gnocl::text -name txt] -setSize 0.25] exec xmodmap -e "add mod3 = Scroll_Lock" txt configure -onKeyRelease {     lassign [gnocl::keyboard %w] NumLock CapsLock ScrollLock     set Overwrite [%w cget -overwrite]          foreach item {NumLock CapsLock ScrollLock Overwrite} {         puts "$item   [set $item]"     }      }

March Updates

  Just a few tweaks this month. 2021-02:    gnocl::stringUtils         o new subcommands,             totitle, convert string to title string by capitalizing all word initial characters             toroman, convert Arabic integer to Roman numerals     gnocl::notebook         o tearoff tab window will now contain the same text as the child tab         o new command -tabCget     gnocl::dialog         o dialog now registered to obtain a widget-id, not directly           returned but easily obtained by child widgets using the           [gnocl::winfo toplevel %w] command.     gnocl::tree/list         o -onSelectionChanged now su...

February 2021 Update

  A tad late in posting this month's news but here's what happened during January.    2021-01:     gnocl::window         o issues with snapshot subcommand fixed.           added snapshot options: -delay, -pointer, -color, -radius, and -alpha.     gnocl::pixBuf         o new creation option offScreen.     gnocl::offScreen         o new widget type.     gnocl::notebook         o fixed problems with -onCreateWindow and -detachable options.         o popupmenu labels now accept markup.         o tabConfigure -label, -detchable, -menuText, -menulabel, -position options now work         o tabConfigure -fill, -expand, -pack do workd, but may give unexpected results.   ...

Hybrid Menubar and Toolbar Tabber

The customary method of organizing application menubars and toolbars is in a vertical sequence. To save space, sometimes multiple tool sets can be embedded into a single bar. This is fine but what usually results is a duplication if the functionality offered in a pull-down menu and some toolbar button. This can cause a lot of clutter, not only on screen, but in the coding where the duplication is a occurring. For a user the on-screen clutter can be obtrusive as it begins to eat away at the screen space used by an application in both the horizontal and vertical dimensions. Too many on screen toolbars reduces the size of user work zones and tool many items per bar can result in windows whose resizing becomes constrained.   Multiple toolbars can be toggled on or off, but then a menu item, nested somewhere in menu in the toolbar needs to be created, the result more clutter. Complex GUI elements are not only demanding in terms of coding, but offputting to any new user who has grown...