WJG (01/08/16)
Gnocl provides a great toolkit for the creation of application UIs. Producing application modules which have complex layouts and can be used repeatedly calls for something more than the repetitive use of code, whether it be scripted, or loaded via a GtkBuilder UI xml description file. The following package, originally created as a template for use with the
Geany IDE, provides boilerplate code for the creation of reusable UI elements in the form of megawidgets. Scripted in a way as to be as close to the C core module implementation itself, this package provides programmer with the resources to define a complex medawidget layout and to apply any necessary reconfiguration of the components during runtime. As with all
Gnocl widgets, introspection is implemented along with a widget delete command. To facilitate global access to the widget, use of the -alias can be used in situations in which the widget registration name produced for the object via the Gnocl package may be difficult to obtain or, alternatively, a more descriptive name is preferred. In order to produce new UI constructions, simply apply a global replace on the keyword "_widget_" with a more relevant name.
The package itself contains a simple megawidget consisting of a container and button which can be substituted with more complex layouts and their callback handlers.
#{fileheader}
#---------------
# Boilerplate object builder package for Gnocl derived megawidgets.
# Based upon approach used in Gnocl source code.
#---------------
# USAGE: Substitute keyword "widget" for unique object type identifier.
#---------------
# !/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
package require Gnocl
package provide _widget_
namespace eval gnocl::_widget_ {}
#---------------
# lists of valid widget options, commands and components
#---------------
#
set gnocl::_widget_::opts { -text -onClicked -data -name -icon -alias -tooltip }
set gnocl::_widget_::cmds { configure cget class opts cmds delete }
#----------------
# storage variables initialized during run-time
#----------------
# gnocl::_widget_::names type: array
# gnocl::_widget_::components type: array
#---------------
# implement widget commands
#---------------
#
proc gnocl::_widget_::cmd { wid cmd args } {
gnocl::_widget_::check $cmd
# apply the commands
switch -- $cmd {
opts -
cmds { return [ lsort [ set gnocl::_widget_::$cmd ] ] }
class { return "_widget_"}
configure -
delete -
cget { eval "gnocl::_widget_::$cmd $wid $args" }
default { # shouldn't need to get here, but... }
}
}
#---------------
# retrieve current component values
#---------------
#
proc gnocl::_widget_::cget { wid args } {
# get list of members
foreach { w id } $gnocl::_widget_::components($wid) { set $w $id }
# obtain current settings
foreach { a b } $args {
# apply according to each component
switch -- $a {
-onClicked -
-text { return [ $but_1 cget $a ] }
-data { return [ $wid cget $a ] }
-name {
return $::gnocl::_widget_::names($wid) }
default { # shouldn't need to get here, but... }
}
}
}
#---------------
# check options and commands for valid values
#---------------
#
proc gnocl::_widget_::check { opts } {
# test for a valid options
if { [string first - $opts ] >= 0 } {
foreach { opt val } $opts {
if { [string first $opt $gnocl::_widget_::opts] == -1 } {
append errmsg [string repeat - 17]\n
append errmsg "ERROR! Invalid gnocl::gnocl::_widget_ option \"$opt\".\n"
append errmsg "Should be one of: [lsort $gnocl::_widget_::opts]\n"
append errmsg [string repeat - 17]\n
error $errmsg
}
}
return
}
# test for valid command
foreach { cmd } $opts {
if { [string first $cmd $gnocl::_widget_::cmds] == -1 } {
append errmsg [string repeat - 17]\n
append errmsg "ERROR! Invalid gnocl::gnocl::_widget_ command \"$cmd\".\n"
append errmsg "Should be one of: [lsort $gnocl::_widget_::cmds]\n"
append errmsg [string repeat - 17]\n
error $errmsg
}
}
}
#---------------
# configure widget components
#---------------
#
proc gnocl::_widget_::configure { wid args } {
gnocl::_widget_::check $args
# recover list of widget components
foreach {w id} $::gnocl::_widget_::components($wid) {set $w $id}
# apply new options
foreach {a b} $args {
# apply according to each component
switch -- $a {
-alias {
interp alias {} $b {} $wid
}
-name {
#interp alias {} $b {} $wid
proc ::$b {} "return [string trim $wid _]"
set ::gnocl::_widget_::names($wid) $b
# parray ::gnocl::_widget_::names
}
-text -
-icon -
-onClicked { $but_1 configure $a $b }
-data { $wid configure $a $b ; $but_1 configure $a $b }
default { # shouldn't need to get here, but... }
}
}
}
#---------------
# delete widget and clean up
#---------------
#
proc gnocl::_widget_::delete { wid } {
$wid delete
array unset gnocl::_widget_::names $wid
array unset gnocl::_widget_::components $wid
}
#---------------
# create and assemble widget components
#---------------
#
proc gnocl::_widget_::construct {} {
# create object container
set vbox [gnocl::vBox]
# create components
set but_1 [gnocl::button -text BUTTON]
# assemble components
$vbox add $but_1
# add to listing
set ::gnocl::_widget_::components(${vbox}_) [list but_1 $but_1]
#set ::gnocl::_widget_::components [list but_1 $but_1]
return $vbox
}
#---------------
# the widget command itself
#---------------
#
proc gnocl::widget { args } {
set wid [gnocl::_widget_::construct]
# overload the box to add commands
rename $wid ${wid}_
# configure
eval "gnocl::_widget_::configure ${wid}_ $args"
# widget command
proc $wid { cmd args } {
set wid [lindex [::info level 0] 0]
eval "gnocl::_widget_::cmd ${wid}_ $cmd $args"
}
return $wid
}
#===============
# DEMO
#===============
proc demo {} {
set wid(1) [gnocl::widget \
-text "HELLO CAMPERS!" \
-onClicked {
puts "HI DI HI! - %d"
} \
-name campers]
gnocl::window \
-child $wid(1) \
-setSize 0.2
$wid(1) configure -data "HO DI HO!"
puts "[[campers] class]"
[campers] configure -text NEW
set wid(2) [gnocl::widget -text "GOOD MORNING!" -onClicked {puts "GOOD AFTERNOON- %d"} -data BYE-BYE -name greeting ]
gnocl::window -child $wid(2) -x 600
puts data->[$wid(2) cget -data]
puts opts->[$wid(1) opts]
puts cmds->[$wid(2) cmds]
set wid(3) [gnocl::widget -text "OM MANI PADME HUM" -onClicked {puts "%d"} -data HRIH -name mantra ]
gnocl::window -child $wid(3) -x 800
$wid(1) configure -icon %#Open
$wid(2) configure -icon %#Close
$wid(3) configure -icon %#Help
# accessing names, set widget alias
[campers] configure -alias BOING
# using widget alias
BOING configure -tooltip ABCDEFG
}
demo