Saturday, July 15, 2023

Custom Dialogs

 Description

 

 


## project chooser dialog
# @param   wid
# @returns  none
# @notes  Uses global array ::app to store restrieved values
proc conze_project_chooser_dialog { wid } {
       
    set dir $::app(dirs,projects)

    set vbox [gnocl::vBox -data 0]
    set lst [gnocl::list -columns 2 -types "string string" -headersVisible 0 ]
    $lst columnConfigure 1 -visible 0
    $vbox add $lst -fill {1 1} -expand 1
    
    # create list of available projects
    foreach d [lsort [glob -type d -directory $dir *]] {
        $lst add [list [list [file tail $d] $d]]
    }
    
    # to right align completely, set expand and fill to 0
    set hbox [gnocl::hBox]
    set b1 [gnocl::button -text Select \
            -data "$lst $wid" \
            -onClicked {
                set ::app(project) [lindex [[lindex %d 0] getRow \
                            [[lindex %d 0] getSelection]] 1]
                %t delete
                $::app(statusBar) push "Project [file tail $::app(project)] selected"
                conze_set_title
                conze_open [lindex %d 1]
                } ]
    
    set b2 [gnocl::button -text Cancel -onClicked { %t delete } ]
    
    $vbox add $hbox -expand 0 -fill 0 -align right
    $hbox add $b1
    $hbox add $b2

    $lst configure -data $b1 -onButtonRelease { if { "%t" == "button2Press" } { %d clicked } }

    # create custom dialog
    set win [gnocl::window \
        -visible 0 \
        -title "Select Conze Project" \
        -child $vbox \
        -height 480 \
        -width 320 \
        -data $lst \
        -typeHint dialog \
        -modal 1]
       
    $win centre
    $win configure -visible 1
               
}

Sunday, July 09, 2023

Creating a button box with right aligned widgets

The dialog widget has its own internal functionaluty to create and position buttons at the bottom right corner of the window container. When creating these for ourselves it must be born in mind that default settings for fill and expand are both 0.5. Failing to set these will always place the child objects in the centre, regardless of alignment. For most cases these defaults are acceptable but, to create that dialog-button arrangement, use the following snippet as a model!

  # to right align completely, set expand and fill to 0
set hbox [gnocl::hBox]
set b1 [gnocl::button -text Select \
            -data $lst 
            -onClicked { puts DO-SOMETHING-WITH-%d} ]
set b2 [gnocl::button -text Cancel -onClicked { puts DONE! } ]
$vbox add $hbox -expand 0 -fill 0 -align right
$hbox add $b1
$hbox add $b2

Friday, February 17, 2023

Changing Namespaces

I've been toying with the idea of changing the namespace used by gnocl, to something simplier, a proposition much more appealing now that I've begun migration to Gtk3 and soon to Gtk4. The changes from Gtk2 to Gtk4 will be subtantial due to many chages occuring within the Gtk api.

Before committing myself, I thought how it would be useful to swap namespaces on the fly. So, here's a first quick solution:

 

package require -exact Gnocl 0.9.96

proc xxxx {ns1 ns2}  {
    namespace eval ::${ns2} {}
    set map [list $ns1 $ns2]
    
    foreach type {commands vars procs } {
        foreach item [info $type ${ns1}::*] {
            set err ""
            catch { rename $item [string map $map $item] } err
            if { $err != "" } { puts $err }
        }
    }
    
    namespace delete $ns1
}

xxxx g

set b1 [g::button -text BUTTON]
set w1 [g::window -child $b1]
set l1 [g::label -text rename]

$w1 configure -child $l1 -title TEST

Friday, December 23, 2022

Testing for the Presence of Dependencies - commands

 



catch {exec pdfgrep > /dev/null &} res

if {![string is integer -strict $res]} {
    gnocl::dialog \
    -title "pdfSeach" \
    -text "<b>ERROR!\n\n</b> <b>pdfgrep</b> not present on this computer!\n\nInstall using:\n\n<b>sudo apt install pdfgrep</b>\n\n" 
    -type error 
    return -code error  
}

Monday, September 26, 2022

Making Runtime Proceedure Script Modifications.

When using Gnocl widgets only a single callback script is permitted. This differs somewhat to the underlying Gtk bindings api which allows for a chain of callback functions to be defined.  

Rather than trying to produce a convoluted means of setting complex callbacks in C, simple changes can be made during application runtime because Tcl, as a dynamic language, allows everything to be reconfigurable.

Using a simple procedure which takes three arguments: the name of the procedure to be modified, the script modifications and a flag specifying append or prepend, the following proof of concept script can created.  


# !/bin/sh
# the next line restarts using tclsh \

exec tclsh "$0" "$@"

proc p1 {str} { puts $str }

proc procModify {proc script {mode -append} } {

   set args [info args $proc]
   set body [string trim [info body $proc]]

   set box

    if { $mode == "-prepend" } {
        set body $script\n$body
    } else {
        set body $body\n$script
    }

    proc $proc $args $body

}

procModify p1 "puts DONE!"
procModify p1 "puts READY!" -prepend

p1 HI


Thursday, June 23, 2022

Text chopping and glueing.


 

 

 

# !/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

package require Gnocl

namespace eval text {}

## split text into enumerated list of paragraphs
# @param    txt        block of text to split
# @returns    enumerated list of paragraphs.

proc text::paras { txt } {
    set i 0
    foreach line [split $txt \n] {
        if { [string is space $line] } {
            incr i
        } else {
            dict append res $i "$line "
        }  
    }

    return $res
}

## split text into blocks based upon puncutation marks
# @param    txt        block of text to split
# @param    marks    valid list of punctuation marks
# @returns    enumerated list of blocks.

proc text::blocks {txt marks} {
    set i 0
    foreach ch [split $txt ""] {
        if { [string first $ch $marks] != -1 } { incr i}
        dict append res $i $ch
        if { [string first $ch $marks] != -1 } { incr i}
    }
    return $res
}

## concatenate enumerated list of text blocks
# @param    str
# @returns    concated text

proc text::recombine {str} {
    for {set k 0} {$k < [dict size $str]} {incr k} {
        append res [dict get $str $k]
    }
    return $res
}

## convenience wrapper around namespace procs
# @param    cmd
# @param    args
# @returns    formatted string
proc text {cmd args} {
    # check for valid command
    if { [lsearch [namespace eval ::text:: info procs] $cmd] < 0 } {
        set distanceToTop [info level]
        for {set i 0} {$i < $distanceToTop} {incr i} {
            set callerlevel [expr {$distanceToTop - $i}]
            append res [info level $callerlevel]\n
        }
        puts stderr "Error! No such command $cmd:\n$res"
        exit 0 }
    
    # call required command
    return [text::$cmd {*}$args]
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# demo
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


set txt(EN) \
{It was the best of times, it was the worst of times, it was the age of
wisdom, it was the age of foolishness, it was the epoch of belief, it
was the epoch of incredulity, it was the season of Light, it was the
season of Darkness, it was the spring of hope, it was the winter of
despair, we had everything before us, we had nothing before us, we were
all going direct to Heaven, we were all going direct the other way--in
short, the period was so far like the present period, that some of its
noisiest authorities insisted on its being received, for good or for
evil, in the superlative degree of comparison only.

There were a king with a large jaw and a queen with a plain face, on the
throne of England; there were a king with a large jaw and a queen with
a fair face, on the throne of France. In both countries it was clearer
than crystal to the lords of the State preserves of loaves and fishes,
that things in general were settled for ever.

It was the year of Our Lord one thousand seven hundred and seventy-five.
Spiritual revelations were conceded to England at that favoured period,
as at this. Mrs. Southcott had recently attained her five-and-twentieth
blessed birthday, of whom a prophetic private in the Life Guards had
heralded the sublime appearance by announcing that arrangements were
made for the swallowing up of London and Westminster. Even the Cock-lane
ghost had been laid only a round dozen of years, after rapping out its
messages, as the spirits of this very year last past (supernaturally
deficient in originality) rapped out theirs. Mere messages in the
earthly order of events had lately come to the English Crown and People,
from a congress of British subjects in America: which, strange
to relate, have proved more important to the human race than any
communications yet received through any of the chickens of the Cock-lane
brood.}

set txt(ZH) \
{大哉智度!萬聖資通,咸宗以成也。地合日照,無法不周,不恃不處,累彼有名,既外有名,亦病無形,兩忘玄莫,喟然無主,此智之紀也。

夫永壽莫美乎上乾,而齊之殤子;神偉莫美於凌虛,而同之[仁-二+肙]滯;至德莫大乎真人,而比之朽種;高妙莫大乎世雄,而喻之幻夢。

由此論之,亮為眾聖宗矣。何者?執道御有,卑高有差,此有為之域耳;非據真如、遊法性、冥然無名也。據真如、遊法性、冥然無名者,智度之奧室也。

名教遠想者,智度之蘧廬也。然在乎證者,莫不[貝*賓]其生無而惶胘;存乎邇者,莫不忿其蕩冥而誕誹。

道動必反,優劣致殊,眩誹不其宜乎!

不其宜乎!}


set marks(EN) [list .,\;:!?()]
set marks(ZH) [list ,。(;)?!]

set buff [text::paras $txt(EN)]

set blocks [text::blocks [dict get $buff 1] $marks(EN) ]

puts [dict get $buff 1]\n~~~~~
puts $blocks\n~~~~~
puts [text::recombine $blocks]\n~~~~~

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set paras [text paras $txt(ZH)]
set blocs [text blocks [dict get $paras 1] $marks(ZH) ]
puts $blocs
puts [text recombine $blocs]
text xx
 

json_shell_utils.tcl