@@ -29,6 +29,11 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
2929 }
3030 last := * selectedIndex
3131
32+ buttonBounds , err := c .layoutNext ()
33+ if err != nil {
34+ return nil , err
35+ }
36+
3237 id := c .idStack .push (idPart )
3338 dropdownContainer := c .container (id , 0 )
3439
@@ -41,6 +46,8 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
4146 dropdownContainer .open = false
4247 }
4348
49+ dropdownContainer .layout .Bounds = c .dropdownBounds (buttonBounds , len (options ))
50+
4451 _ = c .wrapEventHandlerAndError (func () (EventHandler , error ) {
4552 windowOptions := optionNoResize | optionNoTitle
4653
@@ -67,7 +74,7 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
6774 return nil , nil
6875 })
6976
70- return c . widget (id , optionAlignCenter , nil , func (bounds image.Rectangle , wasFocused bool ) EventHandler {
77+ e := c . widgetWithBounds (id , optionAlignCenter , buttonBounds , func (bounds image.Rectangle , wasFocused bool ) EventHandler {
7178 var e EventHandler
7279
7380 dropdownContainer := c .container (id , 0 )
@@ -91,27 +98,9 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
9198 dropdownContainer .open = false
9299 dropdownContainer .dropdownCloseTimer .stop ()
93100 } else {
94- wasClosedBefore := ! dropdownContainer .open
95-
96101 // Open the dropdown and cancel any pending close delay
97102 dropdownContainer .open = true
98103 dropdownContainer .dropdownCloseTimer .stop ()
99-
100- if wasClosedBefore {
101- dropdownPos := image .Pt (bounds .Min .X , bounds .Max .Y )
102- buttonWidth := bounds .Dx ()
103- st := c .style ()
104- optionHeight := st .defaultHeight + st .spacing
105- totalHeight := len (options )* optionHeight - st .spacing + st .padding * 2
106-
107- maxDropdownHeight := st .defaultHeight * 12 // around 10 items visible?
108- actualHeight := min (totalHeight , maxDropdownHeight )
109-
110- dropdownContainer .layout .Bounds = image.Rectangle {
111- Min : dropdownPos ,
112- Max : dropdownPos .Add (image .Pt (buttonWidth , actualHeight )),
113- }
114- }
115104 }
116105 }
117106 if last != * selectedIndex {
@@ -120,6 +109,9 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
120109
121110 return e
122111 }, func (bounds image.Rectangle ) {
112+ if ! c .currentContainer ().layout .BodyBounds .Overlaps (bounds ) {
113+ return
114+ }
123115 c .drawWidgetFrame (id , bounds , colorButton , optionAlignCenter )
124116
125117 arrowWidth := bounds .Dy ()
@@ -134,4 +126,34 @@ func (c *Context) dropdown(selectedIndex *int, options []string, idPart string)
134126 }
135127 c .drawIcon (icon , arrowBounds , c .style ().colors [colorText ])
136128 })
129+ return e , nil
130+ }
131+
132+ func (c * Context ) dropdownBounds (buttonBounds image.Rectangle , optionCount int ) image.Rectangle {
133+ st := c .style ()
134+ height := min (optionCount * (st .defaultHeight + st .spacing )- st .spacing + st .padding * 2 , st .defaultHeight * 12 )
135+ width := buttonBounds .Dx ()
136+ pos := image .Pt (buttonBounds .Min .X , buttonBounds .Max .Y )
137+
138+ if c .screenWidth > 0 {
139+ screenWidth := c .screenWidth / c .Scale ()
140+ width = min (width , screenWidth )
141+ pos .X = clamp (pos .X , 0 , screenWidth - width )
142+ }
143+ if c .screenHeight > 0 {
144+ screenHeight := c .screenHeight / c .Scale ()
145+ above := clamp (buttonBounds .Min .Y , 0 , screenHeight )
146+ below := screenHeight - clamp (buttonBounds .Max .Y , 0 , screenHeight )
147+ if height > below && above > below {
148+ height = min (height , above )
149+ pos .Y = above - height
150+ } else {
151+ height = min (height , below )
152+ pos .Y = screenHeight - below
153+ }
154+ }
155+ return image.Rectangle {
156+ Min : pos ,
157+ Max : pos .Add (image .Pt (width , height )),
158+ }
137159}
0 commit comments