Creating Rollover Effects for Text Tags in GtkTexView Widgets with Gnocl

WJG (18/10/08) The Gtk way of event handling within text widgets is slightly different than in Tk. This, however, doesn't mean that we can't get the same effects. One such feature commonly encountered in Tk applications is a rollover effect on tagged text. Gtk has excellent support for signals, but not all of these are inherited completely. In some of my applications I like to differentiate tagged text as the mouse pointer skims across a window. Ok, it's not absolutely necessary, but I 'grew-up' with Tk and still like its distinctive features. So, here's the way to achieve the same effect responding to the Gtk motionNotify signal. It is not a perfect solution; there is no means of determining whether a tag area is 'entered' or 'left', simply if the tag has been crossed. Here's the gnocl code:


 # tagRollover.tcl

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

 package require Gnocl

 set text [gnocl::text ]

 # whenever the pointer moves, clear any rollOver highlight
 $text configure -onMotion {
        set w %w
                if {$_tag_rollOver_active != ""} {
                        $w tag configure $_tag_rollOver_active -foreground $_tag_rollOver(baseClr)
                        set _tag_rollOver_active ""
                }
 }

 # some global parameters..
 set _tag_rollOver(baseClr) blue
 set _tag_rollOver(highlight) red
 set _tag_rollOver_active ""

 set j 0

 # create new, rollOver tag
 $text tag create _tag_rollOver_[incr j] \
        -fontWeight bold \
        -foreground $_tag_rollOver(baseClr) \
        -onEvent {
                # there's no need for this, but it will help any newcomers understand the substitutions
                set t %t   ;# event type
                set w %w   ;# widget id
                set n %n   ;# tag name

                if { $t == "motionNotify" } {
                        # just incase these are adjacent tags
                        if { $_tag_rollOver_active != "" } {
                                $w tag configure $_tag_rollOver_active -foreground $_tag_rollOver(baseClr)
                        }
                        $w tag configure $n -foreground $_tag_rollOver(highlight)
                        set _tag_rollOver_active $n
                        break ;# tag event get priority, breaking at this point will not allow widget events to be processed
                }
        }

 # use it
 $text insert end "This is "
 $text insert end "Gnocl" -tags _tag_rollOver_$j
 $text insert end "! \n"

 # create further tags, this could be done under program control e.g. as a button formatting command.
 $text tag create _tag_rollOver_[incr j] \
        -fontWeight bold \
        -foreground $_tag_rollOver(baseClr) \
        -onEvent {
                set t %t
                set w %w
                if { $t == "motionNotify" } {
                        # just incase these are adjacent tags
                        if { $_tag_rollOver_active != "" } {
                                $w tag configure $_tag_rollOver_active -foreground $_tag_rollOver(baseClr)
                        }
                        $w tag configure %n -foreground $_tag_rollOver(highlight)
                        set _tag_rollOver_active %n
                }
                break ;# tag event get priority, breaking at this point will not allow widget events to be processed
        }

 # use it
 $text insert end "This too is "
 $text insert end "Gnocl" -tags _tag_rollOver_2
 $text insert end "! \n"

 gnocl::window -title "Text TagRollover Effects" -child $text
 gnocl::mainLoop