...
1 package cview
2
3 import (
4 "sync"
5
6 "github.com/gdamore/tcell/v3"
7 )
8
9
10 type WindowManager struct {
11 *Box
12
13 windows []*Window
14
15 sync.RWMutex
16 }
17
18
19 func NewWindowManager() *WindowManager {
20 return &WindowManager{
21 Box: NewBox(),
22 }
23 }
24
25
26 func (wm *WindowManager) Add(w ...*Window) {
27 wm.Lock()
28 defer wm.Unlock()
29
30 for _, window := range w {
31 window.SetBorder(true)
32 }
33
34 wm.windows = append(wm.windows, w...)
35 }
36
37
38 func (wm *WindowManager) Clear() {
39 wm.Lock()
40 defer wm.Unlock()
41
42 wm.windows = nil
43 }
44
45
46 func (wm *WindowManager) Focus(delegate func(p Primitive)) {
47 wm.Lock()
48 defer wm.Unlock()
49
50 if len(wm.windows) == 0 {
51 return
52 }
53
54 wm.windows[len(wm.windows)-1].Focus(delegate)
55 }
56
57
58 func (wm *WindowManager) HasFocus() bool {
59 wm.RLock()
60 defer wm.RUnlock()
61
62 for _, w := range wm.windows {
63 if w.HasFocus() {
64 return true
65 }
66 }
67
68 return false
69 }
70
71
72 func (wm *WindowManager) Draw(screen tcell.Screen) {
73 if !wm.GetVisible() {
74 return
75 }
76
77 wm.RLock()
78 defer wm.RUnlock()
79
80 wm.Box.Draw(screen)
81
82 x, y, width, height := wm.GetInnerRect()
83
84 var hasFullScreen bool
85 for _, w := range wm.windows {
86 if !w.fullscreen || !w.GetVisible() {
87 continue
88 }
89
90 hasFullScreen = true
91 w.SetRect(x-1, y, width+2, height+1)
92
93 w.Draw(screen)
94 }
95 if hasFullScreen {
96 return
97 }
98
99 for _, w := range wm.windows {
100 if !w.GetVisible() {
101 continue
102 }
103
104
105 margin := 3
106 wx, wy, ww, wh := w.GetRect()
107 ox, oy := wx, wy
108 if wx > x+width-margin {
109 wx = x + width - margin
110 }
111 if wx+ww < x+margin {
112 wx = x - ww + margin
113 }
114 if wy > y+height-margin {
115 wy = y + height - margin
116 }
117 if wy < y {
118 wy = y
119 }
120 if wx != ox || wy != oy {
121 w.SetRect(wx, wy, ww, wh)
122 }
123
124 w.Draw(screen)
125 }
126 }
127
128
129 func (wm *WindowManager) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
130 return wm.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
131 if !wm.InRect(event.Position()) {
132 return false, nil
133 }
134
135 switch action {
136 case MouseMove:
137 mouseX, mouseY := event.Position()
138
139 for _, w := range wm.windows {
140 if w.dragWX != -1 || w.dragWY != -1 {
141 offsetX := w.x - mouseX
142 offsetY := w.y - mouseY
143
144 w.x -= offsetX + w.dragWX
145 w.y -= offsetY + w.dragWY
146
147 w.updateInnerRect()
148 consumed = true
149 }
150
151 if w.dragX != 0 {
152 if w.dragX == -1 {
153 offsetX := w.x - mouseX
154
155 if w.width+offsetX >= Styles.WindowMinWidth {
156 w.x -= offsetX
157 w.width += offsetX
158 }
159 } else {
160 offsetX := mouseX - (w.x + w.width) + 1
161
162 if w.width+offsetX >= Styles.WindowMinWidth {
163 w.width += offsetX
164 }
165 }
166
167 w.updateInnerRect()
168 consumed = true
169 }
170
171 if w.dragY != 0 {
172 if w.dragY == -1 {
173 offsetY := mouseY - (w.y + w.height) + 1
174
175 if w.height+offsetY >= Styles.WindowMinHeight {
176 w.height += offsetY
177 }
178 } else {
179 offsetY := w.y - mouseY
180
181 if w.height+offsetY >= Styles.WindowMinHeight {
182 w.y -= offsetY
183 w.height += offsetY
184 }
185 }
186
187 w.updateInnerRect()
188 consumed = true
189 }
190 }
191 case MouseLeftUp:
192 for _, w := range wm.windows {
193 w.dragX, w.dragY = 0, 0
194 w.dragWX, w.dragWY = -1, -1
195 }
196 }
197
198
199 var (
200 focusWindow *Window
201 focusWindowIndex int
202 )
203 for i := len(wm.windows) - 1; i >= 0; i-- {
204 if wm.windows[i].InRect(event.Position()) {
205 focusWindow = wm.windows[i]
206 focusWindowIndex = i
207 break
208 }
209 }
210 if focusWindow != nil {
211 if action == MouseLeftDown || action == MouseMiddleDown || action == MouseRightDown {
212 for _, w := range wm.windows {
213 if w != focusWindow {
214 w.Blur()
215 }
216 }
217
218 wm.windows = append(append(wm.windows[:focusWindowIndex], wm.windows[focusWindowIndex+1:]...), focusWindow)
219 }
220
221 return focusWindow.MouseHandler()(action, event, setFocus)
222 }
223
224 return consumed, nil
225 })
226 }
227
View as plain text