Sunday, April 29, 2012

Obtaining Pango Markup Strings -80% done!

Got this Tcl formatting pango markup strings based upon predefined tags in a gnocl::text widget. At the moment a core set of tags is intialized by setting the -markupTags option to '1'. Like many instances of machine produced code the markup strings are lengthy! But it works. When I have the time I'll look at implementing a C version of the proc an incorporating it into the gnocl sources. At that point it might be worth considering the creation of a new gnocl widget for the task as a separate package.

#---------------
# obtain markup strings from gnocl::text object
#---------------
# args:
#    txt    gnocl text widget containing rich text
# return
#    string with suitable pango markups
# notes:
#    initialize preset markup tags in widget using the -markupTags 1 option
proc gnocl:text_pango {txt} {
    set str ""
    for {set line 0} {$line < [$txt getLineCount]} {incr line} {
        set char 0
        while  {$char < [$txt getLineLength $line]} {

            # get ch at specific line position
            set ch [ $txt get [::list $line $char] [::list $line [expr $char+1] ] ]

            # process active tags at this position in the line
            set tagON ""
            set tagOFF ""

            # get tags as a list
            set tags [$txt tag get [list $line $char]]
            foreach tag $tags {
                append tagON $tag
                if {[string first span $tag] != -1} {
                    lappend tagOFF </span>
                } else {
                    lappend tagOFF [string map [list < </] $tag ]
                }
            }

            # reverse the tagOff list, remove whitepaces
            set tagOFF [lreverse $tagOFF]
            set tagOFF [string map [list { } {}] $tagOFF]
           
            # add characers and markup to output string
            append str $tagON $ch $tagOFF
            incr char
        } ;# end while
     } ;# end for

    return $str
}

Saturday, April 28, 2012

Working on Tcl script to convert gnoc::text tags into pango markup strings.

Getting working pango strings from text widget contents is not a simple issue, the various Gtk/Gnome programming sites contain many references to the possibility but.. Ok, the purposes are different - pango is only for marking up short strings. I want, however to edit pango formatted gnocl::list/tree strings in my text editor. At the moment my solution is working, albeit with rather long, messy mark-up sequences. Why? Pango doesn't allow tags to be overlapped. For example:

tag1On asdasd tag2On asdasdad tag1Off sasdasd tag2Off

Would produce an error. This would have to be:

tag1On asdasd tag2On asdasdad tag2Off tag1Off tag2On sasdasd tag2Off

So far my solution has been to create markups for each character in a string. The next step is simplifying that string.


Sunday, April 22, 2012

Substring markup

I find the Tcl string map subcommand very useful and use it quite extensively in text manipulation. Here's an example of where I wanted to highlight substrings within a piece of text using pango markup.

#---------------
# test-substring-markup.tcl
#---------------
#!/bin/sh
#\
exec tclsh "$0" "$@"
package require Gnocl

#---------------
# search for str2 in str1, then add pango markup formatting
#---------------
proc markup_substring {str1 str2 format} {
    # add necessary quote marks around property values
    set format [string map [list = =\" { } {" }] "$format "]
    set str3 "<span $format>$str2</span>" ;#"
    return [string map [list $str2 $str3] $str1 ]
}


set lab [gnocl::label]
gnocl::window -child $lab -setSize 0.25

# set string text
set str "how now brown cow"

# markup first word
set str [markup_substring $str brown "foreground=red weight=bold background=yellow"]

# cascaded markup is possible but, problems will happen if the search string matches the markup statements.
set str [markup_substring $str cow "foreground=white underline=double background=black"]

$lab configure -text $str




Friday, April 20, 2012

Removed imageviewer reference in base distribution.

Whilst the GtkImageViewer widget is a pretty nice tool to use, its not built from default Gtk libraries and requires extra dependencies to be installed before successful compilation can be obtained. With this in mind, the gnocl::imageViewer command has been branched off into a package in its own right. This should enable most users to recompile with the minimal amount of fuss.

Removing widgets from gnocl::box containers

Hitherto it has been possible to add widgets to a box but not to remove them, perhaps for repacking or hiding. The addition of the remove command to the gnocl::box object will now allow this to be done.  Here's a demo script:

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

package require Gnocl

set title "Shared Buffer"

set tb [gnocl::textBuffer]
set tv(1) [gnocl::text -wrapMode word -buffer $tb]
set tv(2) [gnocl::text -wrapMode word -baseColor #FDFDB3 -buffer $tb]

$tv(1) lorem

# create maincontainer
set box(main) [gnocl::box \
    -orientation vertical \
    -align topLeft]
   
set box(texts) [gnocl::box \
    -orientation vertical \
    -children [list $tv(1)] \
    -fill {1 1} \
    -expand 1]

 # create toolBar
 set split 0
 set toolBar [gnocl::toolBar]
 $toolBar add widget [gnocl::toggleButton \
    -variable split \
    -text "Split" \
    -onToggled {
        if {$split} {
            $box(texts) add $tv(2) -fill {1 1} -expand 1
        } else {
        $box(texts) remove $tv(2)
        } }]

 # pack the main container
 $box(main) add $toolBar -fill {1 0} -expand 0
 $box(main) add $box(texts) -fill {1 1} -expand 1

 set main [gnocl::window \
    -title $title \
    -onDelete { exit } \
    -child $box(main) \
    -defaultWidth 480 \
    -defaultHeight 320]

gnocl::mainLoop



Monday, April 16, 2012

gnocl::menuItem: new option -data and new sub-command cget

I'm working on a script that requires popup menus to be built proceedurall and on-the-fly. As a result, there are a number of parameters that I want to send to the popup callback but without the expense of creating and managing global variables or namespaces. This is where the widget -data option comes in. It means that data strings can be conveniently grouped together with a widget, managed throught the Gtk libraries which is totally (hopefully!) secure. The following code-snipetts shows how it can be used.
 
#---------------
## display popup menu
#---------------
#\code
proc doTagPopup {args} {
   
    gnocl::setOpts [list a 1 b 2 c 3]
    gnocl::setOpts $args
   
    puts "a= $a b= $b c= $c"
    puts "w = $w ; t = $t ; n =$n"
   
    foreach {arg val} $args { puts "$arg = [set [string trimleft $arg -]]" }

    #set matches OM|MANI|PADME|HUM|HRIH
    if {$t == "buttonPress" && $b == "3" } {
       
        # these may need runtime re-definition
        proc doItem { w } {
            gnocl::setOpts [$w cget -data]
            puts ">[$widget tag ranges $tag]<"
            foreach {a b} [$widget tag properties $tag] {
                puts "\t$a = $b"
                }
            }
       
        set menu [gnocl::menu -title "menu" -tearoff 0]
       
        foreach word [split $matches |] {
            $menu add [gnocl::menuItem \
                -text $word \
                -data "-widget $w -word $word -tag $n" \
                -onClicked { doItem %w }  ]
            }
        $menu popup $x $y   
    }   
}
#\endcode

Monday, April 09, 2012

Talk to me Linux!

Just hacked together a simple proc to read text strings aloud using the espeak Linux command. Its good fun. It also shows how useful the gnocl::setOpts command  can be.

#---------------
# espeak.tcl
#---------------
## \file
# File documentation.
#\verbatim
#!/bin/sh
#\
exec tclsh "$0" "$@"
#\endverbatim

package require Gnocl

##
# -f <text file>
#       Text file to speak
# -a <integer>
#       Amplitude, 0 to 200, default is 100
# -g <integer>
#       Word gap. Pause between words, units of 10mS at the default speed
# -l <integer>
#       Line length. If not zero (which is the default), consider
#       lines less than this length as end-of-clause
# -p <integer>
#       Pitch adjustment, 0 to 99, default is 50
# -s <integer>
#       Speed in words per minute, 80 to 390, default is 170
# -v <voice name>
#       Use voice file of this name from espeak-data/voices
# -w <wave file name>
#       Write output to this WAV file, rather than speaking it directly
# -b   Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit
# -m   Interpret SSML markup, and ignore other < > tags
# -q   Quiet, don't produce any speech (may be useful with -x)
# -x   Write phoneme mnemonics to stdout
# -X   Write phonemes mnemonics and translation trace to stdout
# -z   No final sentence pause at the end of the text
proc readAloud {args} {
    # set defaults and parse args
    gnocl::setOpts "-a 5 -s 110 $args"
    eval exec espeak -a $a -s $s [list $t]
}

readAloud -t "How now brown cow. She sell sea shells by the sea shore. Peter Piper picked a peck of pickled peppers."

Friday, April 06, 2012