...
1 package cview
2
3 import (
4 "sync"
5
6 "github.com/gdamore/tcell/v2"
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 if action == MouseMove {
136 mouseX, mouseY := event.Position()
137
138 for _, w := range wm.windows {
139 if w.dragWX != -1 || w.dragWY != -1 {
140 offsetX := w.x - mouseX
141 offsetY := w.y - mouseY
142
143 w.x -= offsetX + w.dragWX
144 w.y -= offsetY + w.dragWY
145
146 w.updateInnerRect()
147 consumed = true
148 }
149
150 if w.dragX != 0 {
151 if w.dragX == -1 {
152 offsetX := w.x - mouseX
153
154 if w.width+offsetX >= Styles.WindowMinWidth {
155 w.x -= offsetX
156 w.width += offsetX
157 }
158 } else {
159 offsetX := mouseX - (w.x + w.width) + 1
160
161 if w.width+offsetX >= Styles.WindowMinWidth {
162 w.width += offsetX
163 }
164 }
165
166 w.updateInnerRect()
167 consumed = true
168 }
169
170 if w.dragY != 0 {
171 if w.dragY == -1 {
172 offsetY := mouseY - (w.y + w.height) + 1
173
174 if w.height+offsetY >= Styles.WindowMinHeight {
175 w.height += offsetY
176 }
177 } else {
178 offsetY := w.y - mouseY
179
180 if w.height+offsetY >= Styles.WindowMinHeight {
181 w.y -= offsetY
182 w.height += offsetY
183 }
184 }
185
186 w.updateInnerRect()
187 consumed = true
188 }
189 }
190 } else if action == MouseLeftUp {
191 for _, w := range wm.windows {
192 w.dragX, w.dragY = 0, 0
193 w.dragWX, w.dragWY = -1, -1
194 }
195 }
196
197
198 var (
199 focusWindow *Window
200 focusWindowIndex int
201 )
202 for i := len(wm.windows) - 1; i >= 0; i-- {
203 if wm.windows[i].InRect(event.Position()) {
204 focusWindow = wm.windows[i]
205 focusWindowIndex = i
206 break
207 }
208 }
209 if focusWindow != nil {
210 if action == MouseLeftDown || action == MouseMiddleDown || action == MouseRightDown {
211 for _, w := range wm.windows {
212 if w != focusWindow {
213 w.Blur()
214 }
215 }
216
217 wm.windows = append(append(wm.windows[:focusWindowIndex], wm.windows[focusWindowIndex+1:]...), focusWindow)
218 }
219
220 return focusWindow.MouseHandler()(action, event, setFocus)
221 }
222
223 return consumed, nil
224 })
225 }
226
View as plain text