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

Last change on this file since 4730 was 3330, checked in by gah, 12 years ago

merge (by hand) with Rappture1.2 branch

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