@@ -2,6 +2,8 @@ package container
2
2
3
3
import (
4
4
"image/color"
5
+ "runtime"
6
+ "strings"
5
7
6
8
"fyne.io/fyne/v2"
7
9
"fyne.io/fyne/v2/canvas"
@@ -34,8 +36,16 @@ type InnerWindow struct {
34
36
OnMinimized , OnMaximized , OnTappedBar , OnTappedIcon func () `json:"-"`
35
37
Icon fyne.Resource
36
38
37
- title string
38
- content * fyne.Container
39
+ // Alignment allows an inner window to specify if the buttons should be on the left
40
+ // (`ButtonAlignLeading`) or right of the window border.
41
+ //
42
+ // Since: 2.6
43
+ Alignment widget.ButtonAlign
44
+
45
+ title string
46
+ borderIcon * borderButton
47
+ content * fyne.Container
48
+ maximized bool
39
49
}
40
50
41
51
// NewInnerWindow creates a new window border around the given `content`, displaying the `title` along the top.
@@ -75,32 +85,43 @@ func (w *InnerWindow) CreateRenderer() fyne.WidgetRenderer {
75
85
})
76
86
buttons := NewCenter (NewHBox (close , min , max ))
77
87
78
- var icon fyne.CanvasObject
79
-
88
+ var iconObj fyne.CanvasObject
89
+ var borderIcon * borderButton
80
90
if w .Icon != nil {
81
- icon = newBorderButton (w .Icon , modeIcon , th , func () {
91
+ borderIcon = newBorderButton (w .Icon , modeIcon , th , func () {
82
92
if f := w .OnTappedIcon ; f != nil {
83
93
f ()
84
94
}
85
95
})
86
96
if w .OnTappedIcon == nil {
87
- icon .( * borderButton ) .Disable ()
97
+ borderIcon .Disable ()
88
98
}
99
+ iconObj = borderIcon
100
+ w .borderIcon = borderIcon
89
101
}
90
102
title := newDraggableLabel (w .title , w )
91
103
title .Truncation = fyne .TextTruncateEllipsis
92
104
93
105
height := w .Theme ().Size (theme .SizeNameWindowTitleBarHeight )
94
106
off := (height - title .labelMinSize ().Height ) / 2
95
- bar := NewBorder (nil , nil , buttons , icon ,
96
- New (layout .NewCustomPaddedLayout (off , 0 , 0 , 0 ), title ))
107
+ barMid := New (layout .NewCustomPaddedLayout (off , 0 , 0 , 0 ), title )
108
+ bar := NewBorder (nil , nil , buttons , iconObj , barMid )
109
+ if w .buttonPosition () == widget .ButtonAlignTrailing {
110
+ buttons := NewCenter (NewHBox (min , max , close ))
111
+ bar .Layout = layout .NewBorderLayout (nil , nil , iconObj , buttons )
112
+ }
113
+
97
114
bg := canvas .NewRectangle (th .Color (theme .ColorNameOverlayBackground , v ))
98
115
contentBG := canvas .NewRectangle (th .Color (theme .ColorNameBackground , v ))
99
116
corner := newDraggableCorner (w )
100
117
118
+ if w .content == nil {
119
+ w .content = NewPadded (canvas .NewRectangle (color .Transparent ))
120
+ }
101
121
objects := []fyne.CanvasObject {bg , contentBG , bar , w .content , corner }
102
122
return & innerWindowRenderer {ShadowingRenderer : intWidget .NewShadowingRenderer (objects , intWidget .DialogLevel ),
103
- win : w , bar : bar , buttons : []* borderButton {min , max , close }, bg : bg , corner : corner , contentBG : contentBG }
123
+ win : w , bar : bar , buttonBox : buttons , buttons : []* borderButton {close , min , max }, bg : bg ,
124
+ corner : corner , contentBG : contentBG , icon : borderIcon }
104
125
}
105
126
106
127
func (w * InnerWindow ) SetContent (obj fyne.CanvasObject ) {
@@ -109,6 +130,14 @@ func (w *InnerWindow) SetContent(obj fyne.CanvasObject) {
109
130
w .content .Refresh ()
110
131
}
111
132
133
+ // SetMaximized tells the window if the maximized state should be set or not.
134
+ //
135
+ // Since: 2.6
136
+ func (w * InnerWindow ) SetMaximized (max bool ) {
137
+ w .maximized = max
138
+ w .Refresh ()
139
+ }
140
+
112
141
func (w * InnerWindow ) SetPadded (pad bool ) {
113
142
if pad {
114
143
w .content .Layout = layout .NewPaddedLayout ()
@@ -123,16 +152,29 @@ func (w *InnerWindow) SetTitle(title string) {
123
152
w .Refresh ()
124
153
}
125
154
155
+ func (w * InnerWindow ) buttonPosition () widget.ButtonAlign {
156
+ if w .Alignment != widget .ButtonAlignCenter {
157
+ return w .Alignment
158
+ }
159
+
160
+ if runtime .GOOS == "windows" || runtime .GOOS == "linux" || strings .Contains (runtime .GOOS , "bsd" ) {
161
+ return widget .ButtonAlignTrailing
162
+ }
163
+ // macOS
164
+ return widget .ButtonAlignLeading
165
+ }
166
+
126
167
var _ fyne.WidgetRenderer = (* innerWindowRenderer )(nil )
127
168
128
169
type innerWindowRenderer struct {
129
170
* intWidget.ShadowingRenderer
130
171
131
- win * InnerWindow
132
- bar * fyne.Container
133
- buttons []* borderButton
134
- bg , contentBG * canvas.Rectangle
135
- corner fyne.CanvasObject
172
+ win * InnerWindow
173
+ bar , buttonBox * fyne.Container
174
+ buttons []* borderButton
175
+ icon * borderButton
176
+ bg , contentBG * canvas.Rectangle
177
+ corner fyne.CanvasObject
136
178
}
137
179
138
180
func (i * innerWindowRenderer ) Layout (size fyne.Size ) {
@@ -177,14 +219,48 @@ func (i *innerWindowRenderer) Refresh() {
177
219
i .contentBG .FillColor = th .Color (theme .ColorNameBackground , v )
178
220
i .contentBG .Refresh ()
179
221
222
+ var icon fyne.CanvasObject
223
+ if i .icon != nil {
224
+ icon = i .icon
225
+ }
226
+ if i .win .buttonPosition () == widget .ButtonAlignTrailing {
227
+ i .buttonBox .Objects [0 ].(* fyne.Container ).Objects = []fyne.CanvasObject {i .buttons [1 ], i .buttons [2 ], i .buttons [0 ]}
228
+ i .bar .Layout = layout .NewBorderLayout (nil , nil , icon , i .buttonBox )
229
+ } else {
230
+ i .buttonBox .Objects [0 ].(* fyne.Container ).Objects = []fyne.CanvasObject {i .buttons [0 ], i .buttons [1 ], i .buttons [2 ]}
231
+ i .bar .Layout = layout .NewBorderLayout (nil , nil , i .buttonBox , icon )
232
+ }
180
233
for _ , b := range i .buttons {
181
234
b .setTheme (th )
182
235
}
183
236
i .bar .Refresh ()
184
237
238
+ if i .win .OnMinimized == nil {
239
+ i .buttons [1 ].Disable ()
240
+ } else {
241
+ i .buttons [1 ].SetOnTapped (i .win .OnMinimized )
242
+ i .buttons [1 ].Enable ()
243
+ }
244
+
245
+ max := i .buttons [2 ]
246
+ if i .win .OnMaximized == nil {
247
+ i .buttons [2 ].Disable ()
248
+ } else {
249
+ max .SetOnTapped (i .win .OnMaximized )
250
+ max .Enable ()
251
+ }
252
+ if i .win .maximized {
253
+ max .b .SetIcon (theme .ViewRestoreIcon ())
254
+ } else {
255
+ max .b .SetIcon (theme .WindowMaximizeIcon ())
256
+ }
257
+
185
258
title := i .bar .Objects [0 ].(* fyne.Container ).Objects [0 ].(* draggableLabel )
186
259
title .SetText (i .win .title )
187
260
i .ShadowingRenderer .RefreshShadow ()
261
+ if i .icon != nil {
262
+ i .icon .b .SetIcon (i .win .Icon )
263
+ }
188
264
}
189
265
190
266
type draggableLabel struct {
@@ -279,6 +355,14 @@ func (b *borderButton) Disable() {
279
355
b .b .Disable ()
280
356
}
281
357
358
+ func (b * borderButton ) Enable () {
359
+ b .b .Enable ()
360
+ }
361
+
362
+ func (b * borderButton ) SetOnTapped (fn func ()) {
363
+ b .b .OnTapped = fn
364
+ }
365
+
282
366
func (b * borderButton ) MinSize () fyne.Size {
283
367
height := b .Theme ().Size (theme .SizeNameWindowButtonHeight )
284
368
return fyne .NewSquareSize (height )
0 commit comments