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

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