source: trunk/gui/scripts/videoparticle.tcl @ 3177

Last change on this file since 3177 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 21.1 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: videoparticle - mark a particle on a video frame
3#
4# ======================================================================
5#  AUTHOR:  Derrick Kearney, Purdue University
6#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
7#
8# See the file "license.terms" for information on usage and redistribution of
9# this file, and for a DISCLAIMER OF ALL WARRANTIES.
10# ======================================================================
11package require Itk
12package require BLT
13package require Img
14package require Rappture
15package require RapptureGUI
16
17itcl::class Rappture::VideoParticle {
18    inherit itk::Widget
19
20    itk_option define -halo halo Halo "10"
21    itk_option define -color color Color "green"
22    itk_option define -fncallback fncallback Fncallback ""
23    itk_option define -bindentercb bindentercb Bindentercb ""
24    itk_option define -bindleavecb bindleavecb Bindleavecb ""
25    itk_option define -trajcallback trajcallback Trajcallback ""
26    itk_option define -px2dist px2dist Px2dist ""
27    itk_option define -units units Units "m/s"
28    itk_option define -bindings bindings Bindings "enable"
29    itk_option define -ondelete ondelete Ondelete ""
30    itk_option define -onframe onframe Onframe ""
31    itk_option define -framerange framerange Framerange ""
32
33    constructor { name win args } {
34        # defined below
35    }
36    destructor {
37        # defined below
38    }
39
40    public method Show {args}
41    public method Hide {args}
42    public method Link {args}
43    public method Coords {args}
44    public method Frame {args}
45    public method drawVectors {}
46    public method next {args}
47    public method prev {args}
48    public method name {}
49
50    public variable  fncallback ""      ;# framenumber callback - tells what frame we are on
51    public variable  bindentercb ""     ;# enter binding callback - call this when entering the object
52    public variable  bindleavecb ""     ;# leave binding callback - call this when leaving the object
53    public variable  trajcallback ""    ;# trajectory callback - calculates and draws trajectory
54
55    public method Move {status x y}
56    public method Menu {args}
57
58    protected method Enter {}
59    protected method Leave {}
60    protected method CatchEvent {event}
61
62    protected method _fixValue {args}
63    protected method _fixPx2Dist {px2dist}
64    protected method _fixBindings {status}
65
66    private variable _canvas        ""  ;# canvas which owns the particle
67    private variable _name          ""  ;# id of the particle
68    private variable _color         ""  ;# color of the particle
69    private variable _frame          0  ;# frame number where this object lives
70    private variable _coords        ""  ;# list of coords where the object lives
71    private variable _halo           0  ;# about the diameter of the particle
72    private variable _x              0  ;# x coord when "pressed" for motion
73    private variable _y              0  ;# y coord when "pressed" for motion
74    private variable _nextnode      ""  ;# particle this particle points to
75    private variable _prevnode      ""  ;# particle this particle is pointed to by
76    private variable _link          ""  ;# tag of vector linking this and nextnode
77    private variable _units         ""  ;#
78    private variable _px2dist       ""  ;# variable associated with -px2dist
79}
80
81itk::usual VideoParticle {
82    keep -background -foreground -cursor -font
83    keep -plotbackground -plotforeground
84}
85
86# ----------------------------------------------------------------------
87# CONSTRUCTOR
88# ----------------------------------------------------------------------
89itcl::body Rappture::VideoParticle::constructor {name win args} {
90
91    set _name $name
92    set _canvas $win
93
94    # setup the particle control menu
95    itk_component add menu {
96        Rappture::Balloon $itk_interior.particlecontrols -title "Particle Controls"
97    }
98
99    set controls [$itk_component(menu) component inner]
100
101    # Frame number control
102    label $controls.framenuml -text "Frame" -font "Arial 9"\
103         -highlightthickness 0
104    Rappture::Spinint $controls.framenume \
105        -min 0 -width 5 -font "arial 9"
106
107    # Delete control
108    label $controls.deletel -text "Delete" -font "Arial 9" \
109        -highlightthickness 0
110    Rappture::Switch $controls.deleteb -showtext "false"
111    $controls.deleteb value false
112
113    # Save button
114    button $controls.saveb -text Save \
115        -relief raised -pady 0 -padx 0  -font "Arial 9" \
116        -command [itcl::code $this Menu deactivate save] \
117        -activebackground grey90
118
119    # Cancel button
120    button $controls.cancelb -text Cancel \
121        -relief raised -pady 0 -padx 0  -font "Arial 9" \
122        -command [itcl::code $this Menu deactivate cancel] \
123        -activebackground grey90
124
125
126    grid $controls.framenuml -column 0 -row 0 -sticky e
127    grid $controls.framenume -column 1 -row 0 -sticky w
128    grid $controls.deletel   -column 0 -row 1 -sticky e
129    grid $controls.deleteb   -column 1 -row 1 -sticky w
130    grid $controls.saveb     -column 0 -row 2 -sticky e
131    grid $controls.cancelb   -column 1 -row 2 -sticky w
132
133
134    grid columnconfigure $controls 0 -weight 1
135
136    # finish configuring the particle
137    eval itk_initialize $args
138
139    # set the frame for the particle
140    Frame [uplevel \#0 $fncallback]
141    bind ${_name}-FrameEvent <<Frame>> [itcl::code $this CatchEvent Frame]
142}
143
144# ----------------------------------------------------------------------
145# DESTRUCTOR
146# ----------------------------------------------------------------------
147itcl::body Rappture::VideoParticle::destructor {} {
148    configure -px2dist ""  ;# remove variable trace
149
150    Hide object
151
152    # delete the vectors originating from this particle
153    if {[string compare "" ${_nextnode}] != 0} {
154        ${_canvas} delete ${_link}
155        ${_nextnode} prev ${_prevnode}
156    }
157
158    # delete the vectors pointing to this particle
159    if {[string compare "" ${_prevnode}] != 0} {
160        ${_prevnode} next ${_nextnode}
161        ${_prevnode} drawVectors
162    }
163
164    _fixBindings disable
165
166    if {"" != $itk_option(-ondelete)} {
167        uplevel \#0 $itk_option(-ondelete)
168    }
169}
170
171# ----------------------------------------------------------------------
172#   Enter - bindings if the mouse enters the object's space
173# ----------------------------------------------------------------------
174itcl::body Rappture::VideoParticle::Enter {} {
175    uplevel \#0 $bindentercb
176}
177
178
179# ----------------------------------------------------------------------
180#   Leave - bindings if the mouse leaves the object's space
181# ----------------------------------------------------------------------
182itcl::body Rappture::VideoParticle::Leave {} {
183    uplevel \#0 $bindleavecb
184}
185
186
187# ----------------------------------------------------------------------
188#   CatchEvent - bindings for caught events
189# ----------------------------------------------------------------------
190itcl::body Rappture::VideoParticle::CatchEvent {event} {
191    switch -- $event {
192        "Frame" {
193            if {[uplevel \#0 $fncallback] == ${_frame}} {
194                ${_canvas} itemconfigure ${_name}-particle -fill red
195            } else {
196                ${_canvas} itemconfigure ${_name}-particle -fill ${_color}
197            }
198        }
199        default {
200            error "bad event \"$event\": should be one of Frame."
201        }
202
203    }
204}
205
206
207# ----------------------------------------------------------------------
208# Show - draw the particle
209#   particle - draw the particle on the canvas
210#   name - popup a ballon with the name of this object
211# ----------------------------------------------------------------------
212itcl::body Rappture::VideoParticle::Show {args} {
213    set option [lindex $args 0]
214    switch -- $option {
215        "object" {
216            foreach {x y} ${_coords} break
217            set coords [list [expr $x-${_halo}] [expr $y-${_halo}] \
218                             [expr $x+${_halo}] [expr $y+${_halo}]]
219            ${_canvas} create oval $coords \
220                -fill ${_color} \
221                -width 0 \
222                -tags "particle ${_name} ${_name}-particle"
223        }
224        "name" {
225
226        }
227        default {
228            error "bad option \"$option\": should be one of object, name."
229        }
230    }
231}
232
233# ----------------------------------------------------------------------
234# Hide
235#   particle - remove the particle from where it is drawn
236#   name - remove the popup with the name
237# ----------------------------------------------------------------------
238itcl::body Rappture::VideoParticle::Hide {args} {
239    set option [lindex $args 0]
240    switch -- $option {
241        "object" {
242            if {[llength $args] != 1} {
243                error "wrong # args: should be \"particle\""
244            }
245            ${_canvas} delete "${_name}"
246        }
247        "name" {
248
249        }
250        default {
251            error "bad option \"$option\": should be one of object, name."
252        }
253    }
254}
255
256# ----------------------------------------------------------------------
257# Move - move the object to a new location
258# ----------------------------------------------------------------------
259itcl::body Rappture::VideoParticle::Move {status x y} {
260    switch -- $status {
261        "press" {
262            set _x $x
263            set _y $y
264        }
265        "motion" {
266            ${_canvas} move ${_name} [expr $x-${_x}] [expr $y-${_y}]
267            foreach {x0 y0 x1 y1} [${_canvas} coords ${_name}-particle] break
268            set _coords [list [expr $x0+${_halo}] [expr $y0+${_halo}]]
269            set _x $x
270            set _y $y
271            drawVectors
272            if {[string compare "" ${_prevnode}] != 0} {
273                ${_prevnode} drawVectors
274            }
275        }
276        "release" {
277        }
278        default {
279            error "bad option \"$option\": should be one of press, motion, release."
280        }
281    }
282}
283
284# ----------------------------------------------------------------------
285# Menu - popup a menu with the particle controls
286#   create
287#   activate x y
288#   deactivate status
289# ----------------------------------------------------------------------
290itcl::body Rappture::VideoParticle::Menu {args} {
291    set option [lindex $args 0]
292    switch -- $option {
293        "activate" {
294            if {[llength $args] != 3} {
295                error "wrong # args: should be \"activate <x> <y>\""
296            }
297            foreach {x y} [lrange $args 1 end] break
298            set dir "left"
299            set x0 [winfo rootx ${_canvas}]
300            set y0 [winfo rooty ${_canvas}]
301            set w0 [winfo width ${_canvas}]
302            set h0 [winfo height ${_canvas}]
303            set x [expr $x0+$x]
304            set y [expr $y0+$y]
305            $itk_component(menu) activate @$x,$y $dir
306
307            # update the values in the menu
308            set controls [$itk_component(menu) component inner]
309            $controls.framenume value ${_frame}
310            $controls.deleteb value false
311        }
312        "deactivate" {
313            $itk_component(menu) deactivate
314            if {[llength $args] != 2} {
315                error "wrong # args: should be \"deactivate <status>\""
316            }
317            set status [lindex $args 1]
318            switch -- $status {
319                "save" {
320                    set controls [$itk_component(menu) component inner]
321
322                    set newframenum [$controls.framenume value]
323                    if {${_frame} != $newframenum} {
324                        Frame $newframenum
325                    }
326
327                    if {[$controls.deleteb value]} {
328                        itcl::delete object $this
329                    }
330                }
331                "cancel" {
332                }
333                "default" {
334                    error "bad value \"$status\": should be one of save, cancel"
335                }
336            }
337        }
338        default {
339            error "bad option \"$option\": should be one of activate, deactivate."
340        }
341    }
342}
343
344# ----------------------------------------------------------------------
345# Link - move the particle to a new location
346# ----------------------------------------------------------------------
347itcl::body Rappture::VideoParticle::Link {args} {
348    # add a new particle list of linked particles
349    foreach {p} $args break
350    $p prev $this
351    next $p
352    drawVectors
353}
354
355# ----------------------------------------------------------------------
356# drawVectors - draw vectors from this particle
357#               to all particles it is linked to.
358# ----------------------------------------------------------------------
359itcl::body Rappture::VideoParticle::drawVectors {} {
360
361    if {[string compare "" $trajcallback] != 0} {
362        set _link [uplevel \#0 $trajcallback $this ${_nextnode}]
363    }
364}
365
366
367# ----------------------------------------------------------------------
368#   Coords ?<x0> <y0>? - update the coordinates of this object
369# ----------------------------------------------------------------------
370itcl::body Rappture::VideoParticle::Coords {args} {
371    if {[llength $args] == 0} {
372        return ${_coords}
373    } elseif {[llength $args] == 1} {
374        foreach {x0 y0} [lindex $args 0] break
375    } elseif {[llength $args] == 2} {
376        foreach {x0 y0} $args break
377    } else {
378        error "wrong # args: should be \"Coords ?<x0> <y0>?\""
379    }
380
381    if {([string is double $x0] != 1)} {
382        error "bad value: \"$x0\": x coordinate should be a double"
383    }
384    if {([string is double $y0] != 1)} {
385        error "bad value: \"$y0\": y coordinate should be a double"
386    }
387
388    set _coords [list $x0 $y0]
389    set coords [list [expr $x0-${_halo}] [expr $y0-${_halo}] \
390                     [expr $x0+${_halo}] [expr $y0+${_halo}]]
391
392    if {[llength [${_canvas} find withtag ${_name}-particle]] > 0} {
393        eval ${_canvas} coords ${_name}-particle $coords
394    }
395
396    _fixValue
397    return ${_coords}
398}
399
400# ----------------------------------------------------------------------
401#   Frame ?<frameNum>? - update the frame this object is in
402# ----------------------------------------------------------------------
403itcl::body Rappture::VideoParticle::Frame {args} {
404    if {[llength $args] == 1} {
405        set val [lindex $args 0]
406        if {([string is integer $val] != 1)} {
407            error "bad value: \"$val\": frame number should be an integer"
408        }
409
410        set _frame $val
411
412        if {"" != $itk_option(-onframe)} {
413            uplevel \#0 $itk_option(-onframe) ${_frame}
414        }
415
416        drawVectors
417        if {[string compare "" ${_prevnode}] != 0} {
418            ${_prevnode} drawVectors
419        }
420    } elseif {[llength $args] != 0} {
421        error "wrong # args: should be \"Frame ?<number>?\""
422    }
423    return ${_frame}
424}
425
426
427# ----------------------------------------------------------------------
428# next - get/set the next particle
429# ----------------------------------------------------------------------
430itcl::body Rappture::VideoParticle::next {args} {
431    if {[llength $args] == 1} {
432        # set the next node
433        set _nextnode [lindex $args 0]
434        # drawVectors
435    }
436    return ${_nextnode}
437}
438
439# ----------------------------------------------------------------------
440# prev - get/set the prev particle
441# ----------------------------------------------------------------------
442itcl::body Rappture::VideoParticle::prev {args} {
443    if {[llength $args] == 1} {
444        # set the prev node
445        set _prevnode [lindex $args 0]
446    }
447    return ${_prevnode}
448}
449
450# ----------------------------------------------------------------------
451# name - get the name of the particle
452# ----------------------------------------------------------------------
453itcl::body Rappture::VideoParticle::name {} {
454    return ${_name}
455}
456
457# ----------------------------------------------------------------------
458# USAGE: _fixValue
459# Invoked automatically whenever the -px2dist associated with this
460# widget is modified.  Copies the value to the current settings for
461# the widget.
462# ----------------------------------------------------------------------
463itcl::body Rappture::VideoParticle::_fixValue {args} {
464    if {"" == $itk_option(-px2dist)} {
465        return
466    }
467    upvar #0 $itk_option(-px2dist) var
468
469    drawVectors
470}
471
472# ----------------------------------------------------------------------
473# USAGE: _fixPx2Dist
474# Invoked whenever the length part of the trajectory for this object
475# is changed by the user via the popup menu.
476# ----------------------------------------------------------------------
477itcl::body Rappture::VideoParticle::_fixPx2Dist {px2dist} {
478    if {"" == $itk_option(-px2dist)} {
479        return
480    }
481    upvar #0 $itk_option(-px2dist) var
482    set var $px2dist
483}
484
485# ----------------------------------------------------------------------
486# _fixBindings - enable/disable bindings
487#   enable
488#   disable
489# ----------------------------------------------------------------------
490itcl::body Rappture::VideoParticle::_fixBindings {status} {
491    switch -- $status {
492        "enable" {
493            ${_canvas} bind ${_name} <ButtonPress-1>   [itcl::code $this Move press %x %y]
494            ${_canvas} bind ${_name} <B1-Motion>       [itcl::code $this Move motion %x %y]
495            ${_canvas} bind ${_name} <ButtonRelease-1> [itcl::code $this Move release %x %y]
496
497            ${_canvas} bind ${_name} <ButtonPress-3>   [itcl::code $this Menu activate %x %y]
498
499            ${_canvas} bind ${_name} <Enter>           [itcl::code $this Enter]
500            ${_canvas} bind ${_name} <Leave>           [itcl::code $this Leave]
501
502            ${_canvas} bind ${_name} <B1-Enter>        { }
503            ${_canvas} bind ${_name} <B1-Leave>        { }
504            # bind ${_canvas} <<Frame>>                  +[itcl::code $this CatchEvent Frame]
505            bindtags ${_canvas} [concat ${_name}-FrameEvent [bindtags ${_canvas}]]
506        }
507        "disable" {
508            ${_canvas} bind ${_name} <ButtonPress-1>   { }
509            ${_canvas} bind ${_name} <B1-Motion>       { }
510            ${_canvas} bind ${_name} <ButtonRelease-1> { }
511
512            ${_canvas} bind ${_name} <ButtonPress-3>   { }
513
514            ${_canvas} bind ${_name} <Enter>           { }
515            ${_canvas} bind ${_name} <Leave>           { }
516
517            ${_canvas} bind ${_name} <B1-Enter>        { }
518            ${_canvas} bind ${_name} <B1-Leave>        { }
519            set tagnum [lsearch [bindtags ${_canvas}] "${_name}-FrameEvent"]
520            if {$tagnum >= 0} {
521                bindtags ${_canvas} [lreplace [bindtags ${_canvas}] $tagnum $tagnum]
522            }
523        }
524        default {
525            error "bad option \"$status\": should be one of enable, disable."
526        }
527    }
528}
529
530
531# ----------------------------------------------------------------------
532# CONFIGURATION OPTION: -halo
533# ----------------------------------------------------------------------
534itcl::configbody Rappture::VideoParticle::halo {
535    if {[string is double $itk_option(-halo)] == 1} {
536        set _halo $itk_option(-halo)
537    } else {
538        error "bad value: \"$itk_option(-halo)\": halo should be a number"
539    }
540}
541
542# ----------------------------------------------------------------------
543# CONFIGURATION OPTION: -color
544# ----------------------------------------------------------------------
545itcl::configbody Rappture::VideoParticle::color {
546    if {[string compare "" $itk_option(-color)] != 0} {
547        # FIXME how to tell if the color is valid?
548        set _color $itk_option(-color)
549    } else {
550        error "bad value: \"$itk_option(-color)\": should be a valid color"
551    }
552}
553
554# ----------------------------------------------------------------------
555# CONFIGURE: -px2dist
556# ----------------------------------------------------------------------
557itcl::configbody Rappture::VideoParticle::px2dist {
558    if {"" != $_px2dist} {
559        upvar #0 $_px2dist var
560        trace remove variable var write [itcl::code $this _fixValue]
561    }
562
563    set _px2dist $itk_option(-px2dist)
564
565    if {"" != $_px2dist} {
566        upvar #0 $_px2dist var
567        trace add variable var write [itcl::code $this _fixValue]
568
569        # sync to the current value of this variable
570        if {[info exists var]} {
571            _fixValue
572        }
573    }
574}
575
576
577# ----------------------------------------------------------------------
578# CONFIGURE: -units
579# ----------------------------------------------------------------------
580itcl::configbody Rappture::VideoParticle::units {
581    set _units $itk_option(-units)
582    # _fixValue
583}
584
585
586# ----------------------------------------------------------------------
587# CONFIGURE: -bindings
588# ----------------------------------------------------------------------
589itcl::configbody Rappture::VideoParticle::bindings {
590    _fixBindings $itk_option(-bindings)
591}
592
593# ----------------------------------------------------------------------
594# CONFIGURE: -framerange
595# ----------------------------------------------------------------------
596itcl::configbody Rappture::VideoParticle::framerange {
597    if {"" == $itk_option(-framerange)} {
598        return
599    }
600    if {[llength $itk_option(-framerange)] != 2} {
601        error "bad value \"$itk_option(-framerange)\": should be 2 integers"
602    }
603    foreach {min max} $itk_option(-framerange) break
604    if {!([string is integer $min]) || !([string is integer $max])} {
605        error "bad value \"$itk_option(-framerange)\": should be 2 integers"
606    }
607    set controls [$itk_component(menu) component inner]
608    $controls.framenume configure -min $min -max $max
609}
610
611# ----------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.