source: trunk/gui/scripts/dropdown.tcl @ 2652

Last change on this file since 2652 was 1929, checked in by gah, 14 years ago
File size: 6.2 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: dropdown - base class for drop-down panels
3#
4#  This is the base class for a family of drop-down widget panels.
5#  They might be used, for example, to build the drop-down list for
6#  a combobox.
7#
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005  Purdue Research Foundation
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16
17option add *Dropdown.textBackground white widgetDefault
18option add *Dropdown.outline black widgetDefault
19option add *Dropdown.borderwidth 1 widgetDefault
20option add *Dropdown.font -*-helvetica-medium-r-normal-*-12-* widgetDefault
21
22itcl::class Rappture::Dropdown {
23    inherit itk::Toplevel
24
25    itk_option define -outline outline Outline ""
26    itk_option define -postcommand postCommand PostCommand ""
27    itk_option define -unpostcommand unpostCommand UnpostCommand ""
28
29    constructor {args} { # defined below }
30
31    public method post {where args}
32    public method unpost {}
33
34    protected method _adjust {{widget ""}}
35
36    public proc outside {w x y}
37
38    bind RapptureDropdown <ButtonPress> \
39        {if {[Rappture::Dropdown::outside %W %X %Y]} {%W unpost}}
40}
41
42itk::usual Dropdown {
43    keep -background -outline -cursor -font
44}
45
46# ----------------------------------------------------------------------
47# CONSTRUCTOR
48# ----------------------------------------------------------------------
49itcl::body Rappture::Dropdown::constructor {args} {
50    wm overrideredirect $itk_component(hull) yes
51    wm withdraw $itk_component(hull)
52
53    component hull configure -borderwidth 1 -background black
54    itk_option remove hull.background hull.borderwidth
55
56    # add bindings to release the grab
57    set btags [bindtags $itk_component(hull)]
58    bindtags $itk_component(hull) [linsert $btags 1 RapptureDropdown]
59
60    eval itk_initialize $args
61}
62
63# ----------------------------------------------------------------------
64# USAGE: post @<x>,<y>
65# USAGE: post <widget> <justify>
66#
67# Clients use this to pop up the dropdown on the screen.  The position
68# should be either a specific location "@x,y", or a <widget> and its
69# justification.
70# ----------------------------------------------------------------------
71itcl::body Rappture::Dropdown::post {where args} {
72    set owner [expr {([winfo exists $where]) ? $where : ""}]
73    _adjust $owner    ;# make sure contents are up-to-date
74    update idletasks  ;# fix size info
75
76    if {[string length $itk_option(-postcommand)] > 0} {
77        set cmd [list uplevel #0 $itk_option(-postcommand)]
78        if {[catch $cmd result]} {
79            bgerror $result
80        }
81    }
82
83    set w [winfo width $itk_component(hull)]
84    set h [winfo height $itk_component(hull)]
85    set sw [winfo screenwidth $itk_component(hull)]
86    set sh [winfo screenheight $itk_component(hull)]
87
88    if {[regexp {^@([0-9]+),([0-9]+)$} $where match x y]} {
89        set xpos $x
90        set ypos $y
91    } elseif {[winfo exists $where]} {
92        set x0 [winfo rootx $where]
93        switch -- $args {
94            left { set xpos $x0 }
95            right { set xpos [expr {$x0 + [winfo width $where] - $sw}] }
96            default {
97                error "bad option \"$args\": should be left, right"
98            }
99        }
100        set ypos [expr {[winfo rooty $where]+[winfo height $where]}]
101    } else {
102        error "bad position \"$where\": should be widget name or @x,y"
103    }
104
105    # make sure the dropdown doesn't go off screen
106    if {$xpos > 0} {
107        # left-justified positions
108        if {$xpos + $w > $sw} {
109            set xpos [expr {$sw-$w}]
110            if {$xpos < 0} { set xpos 0 }
111        }
112        set xpos "+$xpos"
113    } else {
114        # right-justified positions
115        if {$xpos - $w < -$sw} {
116            set xpos [expr {-$sw+$w}]
117            if {$xpos > 0} { set xpos -1 }
118        }
119    }
120    if {$ypos + $h > $sh} {
121        set ypos [expr {$sh-$h}]
122        if {$ypos < 0} { set ypos 0 }
123    }
124
125    # post the dropdown on the screen
126    wm geometry $itk_component(hull) "$xpos+$ypos"
127    update
128
129    wm deiconify $itk_component(hull)
130    raise $itk_component(hull)
131
132    # grab the mouse pointer
133    update
134    while {[catch {grab set -global $itk_component(hull)}]} {
135        after 100
136    }
137}
138
139# ----------------------------------------------------------------------
140# USAGE: unpost
141#
142# Takes down the dropdown, if it is showing on the screen.
143# ----------------------------------------------------------------------
144itcl::body Rappture::Dropdown::unpost {} {
145    grab release $itk_component(hull)
146    wm withdraw $itk_component(hull)
147
148    if {[string length $itk_option(-unpostcommand)] > 0} {
149        set cmd [list uplevel #0 $itk_option(-unpostcommand)]
150        if {[catch $cmd result]} {
151            bgerror $result
152        }
153    }
154}
155
156# ----------------------------------------------------------------------
157# USAGE: _adjust
158#
159# This method is invoked each time the dropdown is posted to adjust
160# its size and contents.
161# ----------------------------------------------------------------------
162itcl::body Rappture::Dropdown::_adjust {{widget ""}} {
163    # derived classes redefine this to do something useful
164}
165
166# ----------------------------------------------------------------------
167# USAGE: outside <widget> <x> <y>
168#
169# Checks to see if the root coordinate <x>,<y> is outside of the
170# area for the <widget>.  Returns 1 if so, and 0 otherwise.
171# ----------------------------------------------------------------------
172itcl::body Rappture::Dropdown::outside {widget x y} {
173    return [expr {$x < [winfo rootx $widget]
174             || $x > [winfo rootx $widget]+[winfo width $widget]
175             || $y < [winfo rooty $widget]
176             || $y > [winfo rooty $widget]+[winfo height $widget]}]
177}
178
179# ----------------------------------------------------------------------
180# CONFIGURATION OPTION: -outline
181# ----------------------------------------------------------------------
182itcl::configbody Rappture::Dropdown::outline {
183    component hull configure -background $itk_option(-outline)
184}
Note: See TracBrowser for help on using the repository browser.