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