forked from tslocum/cview
parent
97f450fc34
commit
e20e58147f
@ -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
|
||||
}
|
@ -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