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

Last change on this file since 3074 was 2747, checked in by ldelgass, 13 years ago

Remove stray character

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) 2005-2010  Purdue Research Foundation
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.