summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcitrons <citrons@mondecitronne.com>2025-06-07 14:57:04 -0500
committercitrons <citrons@mondecitronne.com>2025-06-07 16:02:18 -0500
commit855e61c53c8a401c6f0be84a63808cb94cb19903 (patch)
tree5f03c5357cf6aa75db05376cf6a42cc67d1e33c8
parent553ebc26cda61b567418205f7ee60be122b3c84f (diff)
channel list scrolling
-rw-r--r--client/application.go16
-rw-r--r--client/buffer/buffer.go3
-rw-r--r--client/channel_list.go44
-rw-r--r--client/ui.go9
-rw-r--r--tui/layout.go38
-rw-r--r--tui/scroll_state.go43
6 files changed, 88 insertions, 65 deletions
diff --git a/client/application.go b/client/application.go
index b1fbf5b..f77e0e1 100644
--- a/client/application.go
+++ b/client/application.go
@@ -4,6 +4,7 @@ import (
"citrons.xyz/talk/client/client"
"citrons.xyz/talk/client/object"
"citrons.xyz/talk/client/window"
+ "citrons.xyz/talk/tui"
"citrons.xyz/talk/proto"
)
@@ -19,6 +20,7 @@ type application struct {
currentWindow window.Location
windowHist []window.Location
channelList channelList
+ channelScroll tui.ScrollState
redraw bool
cmdWindow cmdWindow
prompts []window.Prompt
@@ -209,9 +211,7 @@ func (a *application) join(channelName string) {
a.Request(proto.NewCmd("join", ch.Id), func(response proto.Command) {
switch response.Kind {
case "ok":
- a.channelList.add(channelName, channelLocation {id: ch.Id})
- a.goTo(channelLocation {id: ch.Id})
-
+ a.newChannel(*ch)
w := a.windowCache.Get(channelLocation {id: ch.Id})
switch w.(type) {
case *channelWindow:
@@ -233,9 +233,7 @@ func (a *application) createChannel(name string) {
switch response.Kind {
case "create":
if len(response.Args) > 0 {
- ch := response.Args[0]
- a.channelList.add(ch.Fields[""], channelLocation {id: ch.Id})
- a.goTo(channelLocation {id: ch.Id})
+ a.newChannel(response.Args[0])
}
case "fail":
if len(response.Args) > 0 {
@@ -246,6 +244,12 @@ func (a *application) createChannel(name string) {
})
}
+func (a *application) newChannel(ch proto.Object) {
+ a.channelList.add(ch.Fields[""], channelLocation {id: ch.Id})
+ a.channelScroll.Set(0)
+ a.goTo(channelLocation {id: ch.Id})
+}
+
func (a *application) getNick() string {
if !a.authenticated {
return ""
diff --git a/client/buffer/buffer.go b/client/buffer/buffer.go
index 9750932..b7e79e9 100644
--- a/client/buffer/buffer.go
+++ b/client/buffer/buffer.go
@@ -94,10 +94,11 @@ func (b *Buffer) AtTop() bool {
}
func (b *Buffer) Show(id string) (atTop bool) {
- tui.Push(id, tui.Box {
+ mouse := tui.Push(id, tui.Box {
Width: tui.Fill, Height: tui.Fill, Dir: tui.Up, Overflow: true,
Style: &tui.Style {Fg: tui.White, Bg: 232}, Scroll: &b.scroll,
})
+ b.scroll.ByMouse(mouse, true)
defer tui.Pop()
for m := b.bottom; m != nil; m = m.prev {
diff --git a/client/channel_list.go b/client/channel_list.go
index 6ac2141..f7413fd 100644
--- a/client/channel_list.go
+++ b/client/channel_list.go
@@ -52,9 +52,9 @@ func (cl *channelList) remove(location channelLocation) {
}
}
-func (cl *channelList) traverse(direction int) {
+func (cl *channelList) traverse(direction int) int {
if len(*cl) == 0 {
- return
+ return 0
}
var i int
@@ -73,6 +73,7 @@ func (cl *channelList) traverse(direction int) {
}
}
globalApp.goTo((*cl)[i].location)
+ return i
}
func (cl *channelList) add(name string, location channelLocation) {
@@ -81,8 +82,11 @@ func (cl *channelList) add(name string, location channelLocation) {
*cl = append([]channelListEntry {entry}, *cl...)
}
-func (cl *channelList) show() {
- mouse := tui.Push("channel list", tui.Box {Width: 12, Height: tui.Fill})
+func (cl *channelList) show(scroll *tui.ScrollState) {
+ mouse := tui.Push("channel list", tui.Box {
+ Width: 12, Height: tui.Fill, Overflow: true, Scroll: scroll,
+ })
+ scroll.ByMouse(mouse, false)
for i, entry := range *cl {
var style *tui.Style
if entry.location == globalApp.currentWindow {
@@ -95,20 +99,22 @@ func (cl *channelList) show() {
Width: tui.Fill, Height: 1, NoWrap: true, Style: style,
})
- if mouse.Pressed {
- globalApp.redraw = true
- entry.clicked = true
- }
- if mouse.Released {
- globalApp.redraw = true
- if entry.clicked {
- globalApp.goTo(entry.location)
- } else {
- for j, entry2 := range *cl {
- if entry2.clicked {
- entry2.clicked = false
- (*cl)[j] = entry
- entry = entry2
+ if mouse.Button == 0 {
+ if mouse.Pressed {
+ globalApp.redraw = true
+ entry.clicked = true
+ }
+ if mouse.Released {
+ globalApp.redraw = true
+ if entry.clicked {
+ globalApp.goTo(entry.location)
+ } else {
+ for j, entry2 := range *cl {
+ if entry2.clicked {
+ entry2.clicked = false
+ (*cl)[j] = entry
+ entry = entry2
+ }
}
}
}
@@ -124,7 +130,7 @@ func (cl *channelList) show() {
(*cl)[i] = entry
}
- if mouse.ReleasedAnywhere {
+ if mouse.Button == 0 && mouse.ReleasedAnywhere {
for i, entry := range *cl {
globalApp.redraw = globalApp.redraw || entry.clicked
entry.clicked = false
diff --git a/client/ui.go b/client/ui.go
index ab5e190..d3692ce 100644
--- a/client/ui.go
+++ b/client/ui.go
@@ -58,7 +58,6 @@ func (a *application) onInput(ev tui.Event) {
}
buf := win.Buffer()
- buf.Scroll(-ev.Mouse.Scroll * 5)
scroll := tui.Size().Height - 5
switch ev.Key {
@@ -96,9 +95,11 @@ func (a *application) onInput(ev tui.Event) {
}
case keys.Up | keys.Alt:
- a.channelList.traverse(-1)
+ index := a.channelList.traverse(-1)
+ a.channelScroll.Set(index - 5)
case keys.Down | keys.Alt:
- a.channelList.traverse(1)
+ index := a.channelList.traverse(1)
+ a.channelScroll.Set(index - 5)
case 'p' | keys.Ctrl:
a.traverseHistory(-1)
@@ -196,7 +197,7 @@ func (a *application) show() {
Dir: tui.Right,
})
- a.channelList.show()
+ a.channelList.show(&a.channelScroll)
tui.Push("border", tui.Box {Width: 1, Height: tui.Fill})
tui.Text(strings.Repeat("│", s.Height), nil)
tui.Pop()
diff --git a/tui/layout.go b/tui/layout.go
index 1835d72..ede0fa6 100644
--- a/tui/layout.go
+++ b/tui/layout.go
@@ -43,37 +43,8 @@ type textRun struct {
hasCursor bool
}
-type ScrollState struct {
- at string
- offset int
- absolute int
- atFirst bool
- atLast bool
-}
-
var Selected string
-func (s *ScrollState) ToStart() {
- *s = ScrollState {}
-}
-
-func (s *ScrollState) AtFirst() bool {
- return s.atFirst
-}
-
-func (s *ScrollState) AtLast() bool {
- return s.atLast
-}
-
-func (s *ScrollState) Scroll(amnt int) {
- s.offset += amnt
- s.absolute += amnt
-}
-
-func (s *ScrollState) Get() int {
- return s.absolute
-}
-
var layout struct {
front map[string]*Box
back map[string]*Box
@@ -319,12 +290,7 @@ func (b *Box) computePositions(axis int) {
if b.Dir.reverse() {
p = b.computedSize[axis] - p
}
- b.Scroll.absolute = p
- if !b.Dir.reverse() {
- b.Scroll.absolute += b.Scroll.offset
- } else {
- b.Scroll.absolute += b.Scroll.offset
- }
+ b.Scroll.absolute = p + b.Scroll.offset
}
if !b.Dir.reverse() {
@@ -467,10 +433,12 @@ func (b *Box) mouseEvents(ev MouseEvent) {
bev.Y -= b.computedRect.min[1]
bev.Pressed = false
bev.Released = false
+ bev.Scroll = 0
if bev.X >= 0 && bev.Y >= 0 &&
bev.X < b.computedSize[0] && bev.Y < b.computedSize[1] {
bev.Pressed = ev.Pressed
bev.Released = ev.Released
+ bev.Scroll = ev.Scroll
}
b.mouseEvent = bev
for _, c := range b.children {
diff --git a/tui/scroll_state.go b/tui/scroll_state.go
new file mode 100644
index 0000000..75797b1
--- /dev/null
+++ b/tui/scroll_state.go
@@ -0,0 +1,43 @@
+package tui
+
+type ScrollState struct {
+ at string
+ offset int
+ absolute int
+ atFirst bool
+ atLast bool
+}
+
+func (s *ScrollState) ToStart() {
+ *s = ScrollState {}
+}
+
+func (s *ScrollState) AtFirst() bool {
+ return s.atFirst
+}
+
+func (s *ScrollState) AtLast() bool {
+ return s.atLast
+}
+
+func (s *ScrollState) Scroll(amnt int) {
+ s.offset += amnt
+ s.absolute += amnt
+}
+
+func (s *ScrollState) ByMouse(ev MouseEvent, reverse bool) {
+ scroll := ev.Scroll * 5
+ if reverse {
+ scroll *= -1
+ }
+ s.Scroll(scroll)
+}
+
+func (s *ScrollState) Get() int {
+ return s.absolute
+}
+
+func (s *ScrollState) Set(amnt int) {
+ s.at = ""
+ s.absolute = amnt
+}