source: trunk/gui/scripts/mainwin.tcl @ 45

Last change on this file since 45 was 45, checked in by mmc, 19 years ago

Fixed copy/paste with desktop to work properly. It was
relying on the clipboard when the selection and the
cutbuffer were not available. But that causes strange
behavior with the applet panel. Now that the clipboard
stuff is removed, it works better.

Also, changed the wrapping on text entries to "char"
instead of "word", which should be more intuitive for
users entering long lines.

File size: 12.4 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: mainwin - main application window for Rappture
3#
4#  This widget acts as the main window for a Rappture application.
5#  It can be configured to run in two modes:  1) normal desktop
6#  application, and 2) web-based application.  In web-based mode,
7#  the application window runs inside a VNC window, and it takes
8#  the full screen and blends in with the web page.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005
12#  Purdue Research Foundation, West Lafayette, IN
13# ======================================================================
14package require Itk
15package require BLT
16
17option add *MainWin.mode desktop widgetDefault
18option add *MainWin.borderWidth 0 widgetDefault
19option add *MainWin.relief raised widgetDefault
20option add *MainWin.anchor center widgetDefault
21option add *MainWin.titleFont \
22    -*-helvetica-bold-o-normal-*-*-140-* widgetDefault
23
24#
25# Tk text widget doesn't honor Ctrl-V by default.  Get rid
26# of the default binding so that Ctrl-V works for <<Paste>>
27# as expected.
28#
29bind Text <Control-KeyPress-v> {}
30
31#
32# Fix the built-in <<Paste>> bindings to work properly even
33# for the X11 windowing system.  By default, Tk won't replace
34# selected text in X11.  What kind of stupid nonsense is that?
35#
36bind Entry <<Paste>> {
37    catch {
38        # always replace existing selection
39        catch { %W delete sel.first sel.last }
40
41        %W insert insert [::tk::GetSelection %W CLIPBOARD]
42        tk::EntrySeeInsert %W
43    }
44}
45proc ::tk_textPaste w {
46    global tcl_platform
47    if {![catch {::tk::GetSelection $w CLIPBOARD} sel]} {
48        if {[catch {$w cget -autoseparators} oldSeparator]} {
49            # in case we're using an older version of Tk
50            set oldSeparator 0
51        }
52        if { $oldSeparator } {
53            $w configure -autoseparators 0
54            $w edit separator
55        }
56
57        # always replace existing selection
58        catch { $w delete sel.first sel.last }
59        $w insert insert $sel
60
61        if { $oldSeparator } {
62            $w edit separator
63            $w configure -autoseparators 1
64        }
65    }
66}
67
68# ======================================================================
69itcl::class Rappture::MainWin {
70    inherit itk::Toplevel
71
72    itk_option define -mode mode Mode ""
73    itk_option define -anchor anchor Anchor "center"
74    itk_option define -bgscript bgScript BgScript ""
75
76    constructor {args} { # defined below }
77
78    public method draw {option args}
79    public method syncCutBuffer {option args}
80
81    protected method _redraw {}
82
83    private variable _contents ""  ;# frame containing app
84    private variable _sync         ;# to sync current selection and cut buffer
85    private variable _bgscript ""  ;# script of background drawing cmds
86    private variable _bgparser ""  ;# parser for bgscript
87}
88                                                                               
89itk::usual MainWin {
90    keep -background -cursor foreground -font
91}
92
93# ----------------------------------------------------------------------
94# CONSTRUCTOR
95# ----------------------------------------------------------------------
96itcl::body Rappture::MainWin::constructor {args} {
97    itk_component add area {
98        canvas $itk_interior.area
99    } {
100        usual
101        rename -background -bgcolor bgColor Background
102    }
103    pack $itk_component(area) -expand yes -fill both
104    bind $itk_component(area) <Configure> [itcl::code $this _redraw]
105
106    itk_component add app {
107        frame $itk_component(area).app
108    } {
109        usual
110        keep -borderwidth -relief
111    }
112    bind $itk_component(app) <Configure> "
113        after cancel [itcl::code $this _redraw]
114        after idle [itcl::code $this _redraw]
115    "
116
117    itk_component add menu {
118        menu $itk_interior.menu
119    }
120    itk_component add filemenu {
121        menu $itk_component(menu).file
122    }
123    $itk_component(menu) add cascade -label "File" -underline 0 \
124        -menu $itk_component(filemenu)
125    $itk_component(filemenu) add command -label "Exit" -underline 1 \
126        -command exit
127
128    #
129    # Create a parser for the -bgscript option that can
130    # execute drawing commands on the canvas.  This allows
131    # us to draw a background that blends in with web pages.
132    #
133    set _bgparser [interp create -safe]
134    $_bgparser alias rectangle [itcl::code $this draw rectangle]
135    $_bgparser alias oval [itcl::code $this draw oval]
136    $_bgparser alias line [itcl::code $this draw line]
137    $_bgparser alias polygon [itcl::code $this draw polygon]
138    $_bgparser alias text [itcl::code $this draw text]
139    $_bgparser alias image [itcl::code $this draw image]
140
141    eval itk_initialize $args
142
143    bind RapptureMainWin <Destroy> { exit }
144    set btags [bindtags $itk_component(hull)]
145    bindtags $itk_component(hull) [lappend btags RapptureMainWin]
146
147    set _sync(cutbuffer) ""
148    set _sync(selection) ""
149
150    global tcl_platform
151    if {$tcl_platform(platform) == "unix"} {
152        # this sync stuff works only for X windows
153        blt::cutbuffer set ""
154        syncCutBuffer ifneeded
155    }
156}
157
158# ----------------------------------------------------------------------
159# USAGE: syncCutBuffer ifneeded
160# USAGE: syncCutBuffer transfer <offset> <maxchars>
161# USAGE: syncCutBuffer lostselection
162#
163# Invoked automatically whenever the mouse pointer enters or leaves
164# a main window to sync the cut buffer with the primary selection.
165# This helps applications work properly with the "Copy/Paste with
166# Desktop" option on the VNC applet for the nanoHUB.
167#
168# The "ifneeded" option syncs the cutbuffer and the primary selection
169# if either one has new data.
170#
171# The "fromselection" option syncs from the primary selection to the
172# cut buffer.  If there's a primary selection, it gets copied to the
173# cut buffer.
174# ----------------------------------------------------------------------
175itcl::body Rappture::MainWin::syncCutBuffer {option args} {
176    set mainwin $itk_component(hull)
177    switch -- $option {
178        ifneeded {
179            #
180            # See if the incoming cut buffer has changed.
181            # If so, then sync the new input to the primary selection.
182            #
183            set s [blt::cutbuffer get]
184            if {"" != $s && ![string equal $s $_sync(cutbuffer)]} {
185                set _sync(cutbuffer) $s
186
187                if {![string equal $s $_sync(selection)]
188                      && [selection own -selection PRIMARY] != $mainwin} {
189                    set _sync(selection) $s
190
191                    clipboard clear
192                    clipboard append -- $s
193                    selection handle -selection PRIMARY $mainwin \
194                        [itcl::code $this syncCutBuffer transfer]
195                    selection own -selection PRIMARY -command \
196                        [itcl::code $this syncCutBuffer lostselection] \
197                        $mainwin
198                }
199            }
200
201            #
202            # See if the selection has changed.  If so, then sync
203            # the new input to the cut buffer, so it's available
204            # outside the VNC client.
205            #
206            if {[catch {selection get -selection PRIMARY} s]} {
207                set s ""
208            }
209            if {"" != $s && ![string equal $s $_sync(selection)]} {
210                set _sync(selection) $s
211                blt::cutbuffer set $s
212            }
213
214            # do this again soon
215            after 1000 [itcl::code $this syncCutBuffer ifneeded]
216        }
217        transfer {
218            if {[llength $args] != 2} {
219                error "wrong # args: should be \"syncCutBuffer transfer offset max\""
220            }
221            set offset [lindex $args 0]
222            set maxchars [lindex $args 1]
223            return [string range $_currseln $offset [expr {$offset+$maxchars-1}]]
224        }
225        lostselection {
226            # nothing to do
227        }
228        default {
229            error "bad option \"$option\": should be ifneeded, transfer, or lostselection"
230        }
231    }
232}
233
234# ----------------------------------------------------------------------
235# USAGE: draw <option> ?<arg> <arg>...?
236#
237# Used by the -bgscript to draw items in the background area behind
238# the app when "-mode web" is active.  This allows an application
239# to create a background that blends seamlessly with the underlying
240# web page.
241# ----------------------------------------------------------------------
242itcl::body Rappture::MainWin::draw {option args} {
243    set w $itk_component(hull)
244    regsub -all {<w>} $args [winfo screenwidth $w] args
245    regsub -all {<h>} $args [winfo screenheight $w] args
246    eval $itk_component(area) create $option $args
247}
248
249# ----------------------------------------------------------------------
250# USAGE: _redraw
251#
252# Used internally to redraw the widget whenever it changes size.
253# This matters only when "-mode web" is active, when the background
254# area is actually visible.
255# ----------------------------------------------------------------------
256itcl::body Rappture::MainWin::_redraw {} {
257    $itk_component(area) delete all
258    if {$itk_option(-mode) == "web"} {
259        if {[catch {$_bgparser eval $itk_option(-bgscript)} result]} {
260            bgerror "$result\n    (while redrawing application background)"
261        }
262
263        set bd 0  ;# optional border
264        set sw [winfo width $itk_component(area)]
265        set sh [winfo height $itk_component(area)]
266
267        set clip 0
268        set w [winfo reqwidth $itk_component(app)]
269        set h [winfo reqheight $itk_component(app)]
270        if {$w > $sw-2*$bd} {
271            set $w [expr {$sw-2*$bd}]
272            set clip 1
273        }
274
275        set anchor $itk_option(-anchor)
276        switch -- $itk_option(-anchor) {
277            n {
278                set x [expr {$sw/2}]
279                set y $bd
280            }
281            s {
282                set x [expr {$sw/2}]
283                set y [expr {$sh-$bd}]
284            }
285            center {
286                set x [expr {$sw/2}]
287                set y [expr {$sh/2}]
288            }
289            w {
290                set x $bd
291                set y [expr {$sh/2}]
292            }
293            e {
294                set x [expr {$sw-$bd}]
295                set y [expr {$sh/2}]
296            }
297            nw {
298                set x $bd
299                set y $bd
300            }
301            ne {
302                set x [expr {$sw-$bd}]
303                set y $bd
304            }
305            sw {
306                set x $bd
307                set y [expr {$sh-$bd}]
308            }
309            se {
310                set x [expr {$sw-$bd}]
311                set y [expr {$sh-$bd}]
312            }
313            fill {
314                set anchor nw
315                set x $bd
316                set y $bd
317                set w [expr {$sw-2*$bd}]
318                set h [expr {$sh-2*$bd}]
319                set clip 1
320            }
321        }
322
323        # if the app is too big, use w/h. otherwise, 0,0 for default size
324        if {!$clip} {
325            set w 0
326            set h 0
327        }
328
329        $itk_component(area) create window $x $y \
330            -anchor $anchor -window $itk_component(app) \
331            -width $w -height $h
332    }
333}
334
335# ----------------------------------------------------------------------
336# OPTION: -mode
337# ----------------------------------------------------------------------
338itcl::configbody Rappture::MainWin::mode {
339    switch -- $itk_option(-mode) {
340        desktop {
341            component hull configure -menu $itk_component(hull).menu
342            pack $itk_component(app) -expand yes -fill both
343            wm geometry $itk_component(hull) ""
344        }
345        web {
346            component hull configure -menu ""
347            pack forget $itk_component(app)
348            set wx [winfo screenwidth $itk_component(hull)]
349            set wy [winfo screenheight $itk_component(hull)]
350            wm geometry $itk_component(hull) ${wx}x${wy}+0+0
351            _redraw
352        }
353        default {
354            error "bad value \"$itk_option(-mode)\": should be desktop or web"
355        }
356    }
357}
358
359# ----------------------------------------------------------------------
360# OPTION: -bgscript
361# ----------------------------------------------------------------------
362itcl::configbody Rappture::MainWin::bgscript {
363    _redraw
364}
365
366# ----------------------------------------------------------------------
367# OPTION: -anchor
368# ----------------------------------------------------------------------
369itcl::configbody Rappture::MainWin::anchor {
370    if {[lsearch {n s e w ne nw se sw center fill} $itk_option(-anchor)] < 0} {
371        error "bad anchor \"$itk_option(-anchor)\""
372    }
373    _redraw
374}
Note: See TracBrowser for help on using the repository browser.