forked from tslocum/cview
Add Window and WindowManager
parent
97f450fc34
commit
e20e58147f
|
@ -1,5 +1,6 @@
|
|||
v1.5.0 (WIP)
|
||||
- Add scroll bar to TextView
|
||||
- Add Window and WindowManager
|
||||
- Add focus-driven style options
|
||||
- Add InputField autocomplete style options
|
||||
- Add arrow symbol to DropDown
|
||||
|
|
|
@ -18,12 +18,13 @@ Available widgets:
|
|||
|
||||
- __Input forms__ (including __input/password fields__, __drop-down selections__, __checkboxes__, and __buttons__)
|
||||
- Navigable multi-color __text views__
|
||||
- Selectable __lists__ with __context menus__
|
||||
- Modal __dialogs__
|
||||
- Horizontal and vertical __progress bars__
|
||||
- __Grid__, __Flexbox__ and __page layouts__
|
||||
- Sophisticated navigable __table views__
|
||||
- Flexible __tree views__
|
||||
- Selectable __lists__ with __context menus__
|
||||
- __Grid__, __Flexbox__ and __page layouts__
|
||||
- Modal __message windows__
|
||||
- Horizontal and vertical __progress bars__
|
||||
- Draggable and resizable __windows__
|
||||
- An __application__ wrapper
|
||||
|
||||
Widgets may be customized and extended to suit any application.
|
||||
|
|
|
@ -57,6 +57,7 @@ func main() {
|
|||
TreeView,
|
||||
Flex,
|
||||
Grid,
|
||||
Window,
|
||||
End,
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gitlab.com/tslocum/cview"
|
||||
)
|
||||
|
||||
const loremIpsumText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
|
||||
// Window returns the window page.
|
||||
func Window(nextSlide func()) (title string, content cview.Primitive) {
|
||||
wm := cview.NewWindowManager()
|
||||
|
||||
list := cview.NewList().
|
||||
AddItem(cview.NewListItem("Item #1")).
|
||||
AddItem(cview.NewListItem("Item #2")).
|
||||
AddItem(cview.NewListItem("Item #3")).
|
||||
AddItem(cview.NewListItem("Item #4")).
|
||||
AddItem(cview.NewListItem("Item #5")).
|
||||
AddItem(cview.NewListItem("Item #6")).
|
||||
AddItem(cview.NewListItem("Item #7")).
|
||||
ShowSecondaryText(false)
|
||||
|
||||
loremIpsum := cview.NewTextView().SetText(loremIpsumText)
|
||||
|
||||
w1 := cview.NewWindow(list).
|
||||
SetPosition(2, 2).
|
||||
SetSize(10, 7)
|
||||
|
||||
w2 := cview.NewWindow(loremIpsum).
|
||||
SetPosition(7, 4).
|
||||
SetSize(12, 12)
|
||||
|
||||
w1.SetTitle("List")
|
||||
w2.SetTitle("Lorem Ipsum")
|
||||
|
||||
wm.Add(w1, w2)
|
||||
|
||||
return "Window", wm
|
||||
}
|
30
doc.go
30
doc.go
|
@ -4,6 +4,21 @@ Package cview implements rich widgets for terminal based user interfaces.
|
|||
See the demos folder and the example application provided with the
|
||||
NewApplication documentation for usage examples.
|
||||
|
||||
Types
|
||||
|
||||
This package is built on top of tcell, which provides the types necessary to
|
||||
create a terminal-based application (e.g. EventKey). For information on
|
||||
inherited types see the tcell documentation.
|
||||
|
||||
tcell: https://github.com/gdamore/tcell
|
||||
|
||||
Base Primitive
|
||||
|
||||
Widgets must implement the Primitive interface. All widgets embed the base
|
||||
primitive, Box, and thus inherit its functions. This isn't necessarily
|
||||
required, but it makes more sense than reimplementing Box's functionality in
|
||||
each widget.
|
||||
|
||||
Widgets
|
||||
|
||||
The following widgets are available:
|
||||
|
@ -30,21 +45,6 @@ The following widgets are available:
|
|||
Widgets may be used without an application created via NewApplication, allowing
|
||||
them to be integrated into any tcell-based application.
|
||||
|
||||
Base Primitive
|
||||
|
||||
Widgets must implement the Primitive interface. All widgets embed the base
|
||||
primitive, Box, and thus inherit its functions. This isn't necessarily
|
||||
required, but it makes more sense than reimplementing Box's functionality in
|
||||
each widget.
|
||||
|
||||
Types
|
||||
|
||||
This package is built on top of tcell, which provides the types necessary to
|
||||
create a terminal-based application (e.g. EventKey). For information on
|
||||
inherited types see the tcell documentation.
|
||||
|
||||
tcell: https://github.com/gdamore/tcell
|
||||
|
||||
Concurrency
|
||||
|
||||
All functions may be called concurrently (they are thread-safe). When called
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,10 +3,10 @@ module gitlab.com/tslocum/cview
|
|||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200908121250-0c5e1e1720f1
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200921183946-6c71be68010f
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3
|
||||
github.com/mattn/go-runewidth v0.0.9
|
||||
github.com/rivo/uniseg v0.1.0
|
||||
gitlab.com/tslocum/cbind v0.1.2-0.20200826214515-b5f2c6a8711a
|
||||
golang.org/x/sys v0.0.0-20200908134130-d2e65c121b96 // indirect
|
||||
gitlab.com/tslocum/cbind v0.1.2
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
|
||||
)
|
||||
|
|
12
go.sum
12
go.sum
|
@ -1,8 +1,8 @@
|
|||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200908121250-0c5e1e1720f1 h1:ec/DAe6ms4fBkpSHObVDYU4N/w6Swd929zkN01g8ozY=
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200908121250-0c5e1e1720f1/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200921183946-6c71be68010f h1:fUyor2CR18vdlU4gjQhIjQErJwtia5OAvS/2U3hkJlI=
|
||||
github.com/gdamore/tcell/v2 v2.0.0-dev.0.20200921183946-6c71be68010f/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
|
@ -10,13 +10,13 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd
|
|||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
gitlab.com/tslocum/cbind v0.1.2-0.20200826214515-b5f2c6a8711a h1:6u2QDDcKdeFhyHT/srxPDzLfDJqwKTgy1v+3209LYBY=
|
||||
gitlab.com/tslocum/cbind v0.1.2-0.20200826214515-b5f2c6a8711a/go.mod h1:HfB7qAhHSZbn1rFK8M9SvSN5NG6ScAg/3h3iE6xdeeI=
|
||||
gitlab.com/tslocum/cbind v0.1.2 h1:ptDjO7WeOl1HglprsK18L8I9JeRkmtuBoBBaYw/6/Ow=
|
||||
gitlab.com/tslocum/cbind v0.1.2/go.mod h1:HfB7qAhHSZbn1rFK8M9SvSN5NG6ScAg/3h3iE6xdeeI=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
|
||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200908134130-d2e65c121b96 h1:gJciq3lOg0eS9fSZJcoHfv7q1BfC6cJfnmSSKL1yu3Q=
|
||||
golang.org/x/sys v0.0.0-20200908134130-d2e65c121b96/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
31
styles.go
31
styles.go
|
@ -22,21 +22,25 @@ type Theme struct {
|
|||
ContrastBackgroundColor tcell.Color // Background color for contrasting elements.
|
||||
MoreContrastBackgroundColor tcell.Color // Background color for even more contrasting elements.
|
||||
|
||||
// Scroll bar
|
||||
ScrollBarColor tcell.Color // Scroll bar color.
|
||||
|
||||
// Context menu
|
||||
ContextMenuPaddingTop int // Top padding.
|
||||
ContextMenuPaddingBottom int // Bottom padding.
|
||||
ContextMenuPaddingLeft int // Left padding.
|
||||
ContextMenuPaddingRight int // Right padding.
|
||||
|
||||
// Check box
|
||||
CheckBoxCheckedRune rune
|
||||
|
||||
// Context menu
|
||||
ContextMenuPaddingTop int
|
||||
ContextMenuPaddingBottom int
|
||||
ContextMenuPaddingLeft int
|
||||
ContextMenuPaddingRight int
|
||||
|
||||
// Drop down
|
||||
DropDownAbbreviationChars string // The chars to show when the option's text gets shortened.
|
||||
DropDownSymbol rune // The symbol to draw at the end of the field.
|
||||
|
||||
// Scroll bar
|
||||
ScrollBarColor tcell.Color
|
||||
|
||||
// Window
|
||||
WindowMinWidth int
|
||||
WindowMinHeight int
|
||||
}
|
||||
|
||||
// Styles defines the appearance of an application. The default is for a black
|
||||
|
@ -58,15 +62,18 @@ var Styles = Theme{
|
|||
ContrastBackgroundColor: tcell.ColorBlue.TrueColor(),
|
||||
MoreContrastBackgroundColor: tcell.ColorGreen.TrueColor(),
|
||||
|
||||
ScrollBarColor: tcell.ColorWhite.TrueColor(),
|
||||
CheckBoxCheckedRune: 'X',
|
||||
|
||||
ContextMenuPaddingTop: 0,
|
||||
ContextMenuPaddingBottom: 0,
|
||||
ContextMenuPaddingLeft: 1,
|
||||
ContextMenuPaddingRight: 1,
|
||||
|
||||
CheckBoxCheckedRune: 'X',
|
||||
|
||||
DropDownAbbreviationChars: "...",
|
||||
DropDownSymbol: '▼',
|
||||
|
||||
ScrollBarColor: tcell.ColorWhite.TrueColor(),
|
||||
|
||||
WindowMinWidth: 4,
|
||||
WindowMinHeight: 3,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
package cview
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
// Window is a draggable, resizable frame around a primitive.
|
||||
type Window struct {
|
||||
*Box
|
||||
|
||||
primitive Primitive
|
||||
|
||||
x, y int
|
||||
width, height int
|
||||
fullscreen bool
|
||||
|
||||
dragX, dragY int
|
||||
dragWX, dragWY int
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewWindow returns a new window around the given primitive.
|
||||
func NewWindow(primitive Primitive) *Window {
|
||||
w := &Window{
|
||||
Box: NewBox(),
|
||||
primitive: primitive,
|
||||
dragWX: -1,
|
||||
dragWY: -1,
|
||||
}
|
||||
w.Box.focus = w
|
||||
return w
|
||||
}
|
||||
|
||||
// SetPosition sets the position of the window.
|
||||
func (w *Window) SetPosition(x, y int) *Window {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
w.x, w.y = x, y
|
||||
return w
|
||||
}
|
||||
|
||||
// SetSize sets the size of the window.
|
||||
func (w *Window) SetSize(width, height int) *Window {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
w.width, w.height = width, height
|
||||
return w
|
||||
}
|
||||
|
||||
// SetFullscreen sets the flag indicating whether or not the the window should
|
||||
// be drawn fullscreen.
|
||||
func (w *Window) SetFullscreen(fullscreen bool) *Window {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
w.fullscreen = fullscreen
|
||||
return w
|
||||
}
|
||||
|
||||
// Focus is called when this primitive receives focus.
|
||||
func (w *Window) Focus(delegate func(p Primitive)) {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
w.Box.Focus(delegate)
|
||||
|
||||
w.primitive.Focus(delegate)
|
||||
}
|
||||
|
||||
// Blur is called when this primitive loses focus.
|
||||
func (w *Window) Blur() {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
w.Box.Blur()
|
||||
|
||||
w.primitive.Blur()
|
||||
}
|
||||
|
||||
// HasFocus returns whether or not this primitive has focus.
|
||||
func (w *Window) HasFocus() bool {
|
||||
w.RLock()
|
||||
defer w.RUnlock()
|
||||
|
||||
focusable := w.primitive.GetFocusable()
|
||||
if focusable != nil {
|
||||
return focusable.HasFocus()
|
||||
}
|
||||
|
||||
return w.Box.HasFocus()
|
||||
}
|
||||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (w *Window) Draw(screen tcell.Screen) {
|
||||
w.RLock()
|
||||
defer w.RUnlock()
|
||||
|
||||
w.Box.Draw(screen)
|
||||
|
||||
x, y, width, height := w.GetInnerRect()
|
||||
w.primitive.SetRect(x, y, width, height)
|
||||
w.primitive.Draw(screen)
|
||||
}
|
||||
|
||||
// InputHandler returns the handler for this primitive.
|
||||
func (w *Window) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||
return w.primitive.InputHandler()
|
||||
}
|
||||
|
||||
// MouseHandler returns the mouse handler for this primitive.
|
||||
func (w *Window) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
|
||||
return w.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
|
||||
if !w.InRect(event.Position()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if action == MouseLeftDown || action == MouseMiddleDown || action == MouseRightDown {
|
||||
setFocus(w)
|
||||
}
|
||||
|
||||
if action == MouseLeftDown {
|
||||
x, y, width, height := w.GetRect()
|
||||
mouseX, mouseY := event.Position()
|
||||
|
||||
leftEdge := mouseX == x
|
||||
rightEdge := mouseX == x+width-1
|
||||
bottomEdge := mouseY == y+height-1
|
||||
topEdge := mouseY == y
|
||||
|
||||
if mouseY >= y && mouseY <= y+height-1 {
|
||||
if leftEdge {
|
||||
w.dragX = -1
|
||||
} else if rightEdge {
|
||||
w.dragX = 1
|
||||
}
|
||||
}
|
||||
|
||||
if mouseX >= x && mouseX <= x+width-1 {
|
||||
if bottomEdge {
|
||||
w.dragY = -1
|
||||
} else if topEdge {
|
||||
if leftEdge || rightEdge {
|
||||
w.dragY = 1
|
||||
} else {
|
||||
w.dragWX = mouseX - x
|
||||
w.dragWY = mouseY - y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, capture = w.primitive.MouseHandler()(action, event, setFocus)
|
||||
return true, capture
|
||||
})
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
package cview
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
// WindowManager provides an area which windows may be added to.
|
||||
type WindowManager struct {
|
||||
*Box
|
||||
|
||||
windows []*Window
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewWindowManager returns a new window manager.
|
||||
func NewWindowManager() *WindowManager {
|
||||
return &WindowManager{
|
||||
Box: NewBox(),
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a window to the manager.
|
||||
func (wm *WindowManager) Add(w ...*Window) {
|
||||
wm.Lock()
|
||||
defer wm.Unlock()
|
||||
|
||||
wm.windows = append(wm.windows, w...)
|
||||
}
|
||||
|
||||
// Clear removes all windows from the manager.
|
||||
func (wm *WindowManager) Clear() {
|
||||
wm.Lock()
|
||||
defer wm.Unlock()
|
||||
|
||||
wm.windows = nil
|
||||
}
|
||||
|
||||
// Focus is called when this primitive receives focus.
|
||||
func (wm *WindowManager) Focus(delegate func(p Primitive)) {
|
||||
wm.Lock()
|
||||
defer wm.Unlock()
|
||||
|
||||
if len(wm.windows) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
wm.windows[len(wm.windows)-1].Focus(delegate)
|
||||
}
|
||||
|
||||
// HasFocus returns whether or not this primitive has focus.
|
||||
func (wm *WindowManager) HasFocus() bool {
|
||||
wm.RLock()
|
||||
defer wm.RUnlock()
|
||||
|
||||
for _, w := range wm.windows {
|
||||
if w.HasFocus() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (wm *WindowManager) Draw(screen tcell.Screen) {
|
||||
wm.RLock()
|
||||
defer wm.RUnlock()
|
||||
|
||||
x, y, width, height := wm.GetInnerRect()
|
||||
|
||||
var hasFullScreen bool
|
||||
for _, w := range wm.windows {
|
||||
if !w.fullscreen {
|
||||
continue
|
||||
}
|
||||
|
||||
w.SetBorder(false)
|
||||
w.SetRect(x, y+1, width, height-1)
|
||||
w.Draw(screen)
|
||||
|
||||
hasFullScreen = true
|
||||
}
|
||||
if hasFullScreen {
|
||||
return
|
||||
}
|
||||
|
||||
for _, w := range wm.windows {
|
||||
w.SetBorder(true)
|
||||
w.SetRect(x+w.x, x+w.y, w.width, w.height)
|
||||
w.Draw(screen)
|
||||
}
|
||||
}
|
||||
|
||||
// MouseHandler returns the mouse handler for this primitive.
|
||||
func (wm *WindowManager) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
|
||||
return wm.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
|
||||
if !wm.InRect(event.Position()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if action == MouseMove {
|
||||
x, y, _, _ := wm.GetInnerRect()
|
||||
mouseX, mouseY := event.Position()
|
||||
|
||||
for _, w := range wm.windows {
|
||||
if w.dragWX != -1 || w.dragWY != -1 {
|
||||
offsetX := w.x - (mouseX - x)
|
||||
offsetY := w.y - (mouseY - y)
|
||||
|
||||
w.x -= offsetX + w.dragWX
|
||||
w.y -= offsetY + w.dragWY
|
||||
|
||||
consumed = true
|
||||
}
|
||||
|
||||
if w.dragX != 0 {
|
||||
if w.dragX == -1 {
|
||||
offsetX := w.x - (mouseX - x)
|
||||
|
||||
if w.width+offsetX >= Styles.WindowMinWidth {
|
||||
w.x -= offsetX
|
||||
w.width += offsetX
|
||||
}
|
||||
} else {
|
||||
offsetX := mouseX - (x + w.x + w.width)
|
||||
|
||||
if w.width+offsetX >= Styles.WindowMinWidth {
|
||||
w.width += offsetX
|
||||
}
|
||||
}
|
||||
|
||||
consumed = true
|
||||
}
|
||||
|
||||
if w.dragY != 0 {
|
||||
if w.dragY == -1 {
|
||||
offsetY := mouseY - (y + w.y + w.height)
|
||||
|
||||
if w.height+offsetY >= Styles.WindowMinHeight {
|
||||
w.height += offsetY
|
||||
}
|
||||
} else {
|
||||
offsetY := w.y - (mouseY - y)
|
||||
|
||||
if w.height+offsetY >= Styles.WindowMinHeight {
|
||||
w.y -= offsetY
|
||||
w.height += offsetY
|
||||
}
|
||||
}
|
||||
|
||||
consumed = true
|
||||
}
|
||||
}
|
||||
} else if action == MouseLeftUp {
|
||||
for _, w := range wm.windows {
|
||||
w.dragX, w.dragY = 0, 0
|
||||
w.dragWX, w.dragWY = -1, -1
|
||||
}
|
||||
}
|
||||
|
||||
// Focus window on mousedown
|
||||
var (
|
||||
focusWindow *Window
|
||||
focusWindowIndex int
|
||||
)
|
||||
for i := len(wm.windows) - 1; i >= 0; i-- {
|
||||
if wm.windows[i].InRect(event.Position()) {
|
||||
focusWindow = wm.windows[i]
|
||||
focusWindowIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if focusWindow != nil {
|
||||
if action == MouseLeftDown || action == MouseMiddleDown || action == MouseRightDown {
|
||||
for _, w := range wm.windows {
|
||||
if w != focusWindow {
|
||||
w.Blur()
|
||||
}
|
||||
}
|
||||
|
||||
wm.windows = append(append(wm.windows[:focusWindowIndex], wm.windows[focusWindowIndex+1:]...), focusWindow)
|
||||
}
|
||||
|
||||
return focusWindow.MouseHandler()(action, event, setFocus)
|
||||
}
|
||||
|
||||
return consumed, nil
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue