diff --git a/go.mod b/go.mod index e9fb09b..1257116 100644 --- a/go.mod +++ b/go.mod @@ -16,10 +16,10 @@ require ( github.com/alecthomas/chroma/v2 v2.27.0 github.com/ayn2op/arikawa/v3 v3.0.0-20261016043052-54a68a54e42e github.com/ayn2op/ningen/v3 v3.0.1-0.20261014035153-5e43590a1426 - github.com/ayn2op/tview v0.0.0-20261017205514-f83a3769b18a + github.com/ayn2op/tview v0.0.0-20261018225919-d32257af60fc github.com/bogdanfinn/fhttp v0.6.9 github.com/bogdanfinn/tls-client v1.16.0 - github.com/gdamore/tcell/v3 v3.6.0 + github.com/gdamore/tcell/v3 v3.6.1-0.20261018194208-6ad9db1fd512 github.com/gen2brain/malgo v0.11.26 github.com/gorilla/websocket v1.5.3 github.com/mattn/go-shellwords v1.0.16 @@ -51,7 +51,7 @@ require ( github.com/dchest/jsmin v1.0.0 // indirect github.com/disgoorg/godave v0.3.0 // indirect github.com/dlclark/regexp2/v2 v2.9.1 // indirect - github.com/ebitengine/purego v0.11.1 // indirect + github.com/ebitengine/purego v0.11.2 // indirect github.com/gdamore/encoding v1.0.1 // indirect github.com/godbus/dbus/v5 v5.2.4 // indirect github.com/gorilla/schema v1.4.1 // indirect diff --git a/go.sum b/go.sum index 76ea97b..2f5c09a 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/ayn2op/fhttp v0.6.10-0.20261016015330-2d5e34c6b935 h1:oVxkY1/nVsVQ8Cn github.com/ayn2op/fhttp v0.6.10-0.20261016015330-2d5e34c6b935/go.mod h1:7phoj3f/q54WuiTnCTlAhEoaVcdlruKkSzCSD47LzHk= github.com/ayn2op/ningen/v3 v3.0.1-0.20261014035153-5e43590a1426 h1:0ndRWpAiSSgR0z9b7K+pwMlCHEk3VzQeS5ls+zWtbr0= github.com/ayn2op/ningen/v3 v3.0.1-0.20261014035153-5e43590a1426/go.mod h1:4S2B9frwrjELeAldoqPgasA/VfnOySgRlektwYLuVks= -github.com/ayn2op/tview v0.0.0-20261017205514-f83a3769b18a h1:gJyFlYT+igFchVDNUMapJdy8iM0cVA0/LxOqZ8n6FZc= -github.com/ayn2op/tview v0.0.0-20261017205514-f83a3769b18a/go.mod h1:kn8Up2Tk2vhDUtW6H9nqAvRk9hDVyCzk18CCAo2qkjA= +github.com/ayn2op/tview v0.0.0-20261018225919-d32257af60fc h1:Siy7K+UEnISG7BVsrTxRqL81RGcU9H3NOvn11tiHfQ8= +github.com/ayn2op/tview v0.0.0-20261018225919-d32257af60fc/go.mod h1:kn8Up2Tk2vhDUtW6H9nqAvRk9hDVyCzk18CCAo2qkjA= github.com/bdandy/go-errors v1.2.2 h1:WdFv/oukjTJCLa79UfkGmwX7ZxONAihKu4V0mLIs11Q= github.com/bdandy/go-errors v1.2.2/go.mod h1:NkYHl4Fey9oRRdbB1CoC6e84tuqQHiqrOcZpqFEkBxM= github.com/bdandy/go-socks4 v1.2.3 h1:Q6Y2heY1GRjCtHbmlKfnwrKVU/k81LS8mRGLRlmDlic= @@ -44,12 +44,12 @@ github.com/disgoorg/godave v0.3.0 h1:37F3ZuiMd8/EXeoCtTeE8iP2eT2nWsfEa4/ITwoKfe4 github.com/disgoorg/godave v0.3.0/go.mod h1:OreAC3hpabr39bMVA+jwOVDq1EUPXH5A0XUBiZaDI1Y= github.com/dlclark/regexp2/v2 v2.9.1 h1:q6bZW/NN9VodqMjYXpuic2lZxdHPfFTzGS+MJxIJmKQ= github.com/dlclark/regexp2/v2 v2.9.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= -github.com/ebitengine/purego v0.11.1 h1:2zpWRSQNVKN4eKsKO9eM1ILDgWfYMY9GwqRmK6XeQ/0= -github.com/ebitengine/purego v0.11.1/go.mod h1:DCHPP08djqhNSoTfImcnHYQRZmd0qhakvrozqaEYhGQ= +github.com/ebitengine/purego v0.11.2 h1:WWiTx8rD8zYdOwSj8O/NiNbsOvSAgJMTlyV1XlbUSeU= +github.com/ebitengine/purego v0.11.2/go.mod h1:DCHPP08djqhNSoTfImcnHYQRZmd0qhakvrozqaEYhGQ= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= -github.com/gdamore/tcell/v3 v3.6.0 h1:jW20qS6Tm38KVDqLHq9KWSvyjNl00FbhbD8rIAnHBws= -github.com/gdamore/tcell/v3 v3.6.0/go.mod h1:CBZxkl2T+XxEyuBfOh4zaahqm27dngvhfBfCCZxJsgc= +github.com/gdamore/tcell/v3 v3.6.1-0.20261018194208-6ad9db1fd512 h1:cC1srpdzj/kwTj+kJ3sORrrd5C2Quu7scDy6oLxgBIg= +github.com/gdamore/tcell/v3 v3.6.1-0.20261018194208-6ad9db1fd512/go.mod h1:TMjaFRfs5NCU3o1aiuxoRHdEdyixCy1mdGcHdvj7lvc= github.com/gen2brain/malgo v0.11.26 h1:k5WcPIKw1bbJAbPqrvNPt7nehPLoaPNcOFde2+eruiM= github.com/gen2brain/malgo v0.11.26/go.mod h1:xLVG3ROA33Bzol1quF3e4ehqcFuqh8QK4B8T6LQUs/M= github.com/godbus/dbus/v5 v5.2.4 h1:F2gUCy++NMIxGmo9J+z5le/+ZC8W1OgeR51P4i9ZB/U= diff --git a/internal/ui/chat/composer/model.go b/internal/ui/chat/composer/model.go index 9bcc90e..f722185 100644 --- a/internal/ui/chat/composer/model.go +++ b/internal/ui/chat/composer/model.go @@ -155,7 +155,10 @@ func (m *Model) box(focused bool) box.Widget { Focused(focused && !m.disabled). OnInput(func(text string, cursor int) tview.Msg { return editMsg{text, cursor} }). Height(layout.Shrink.Max(m.cfg.Composer.MaxHeight)) - return ui.Box(text, m.cfg, focused).Title(m.title()).Footer(m.footer()).Height(layout.Shrink) + return ui.Box(text, m.cfg, focused). + Title(ui.Label(m.title(), m.cfg.Theme.Title, focused)). + Footer(ui.Label(m.footer(), m.cfg.Theme.Footer, focused)). + Height(layout.Shrink) } // title returns what the composer is doing: editing, replying, or nothing. diff --git a/internal/ui/chat/guildstree/model.go b/internal/ui/chat/guildstree/model.go index afc89e9..ede1b5f 100644 --- a/internal/ui/chat/guildstree/model.go +++ b/internal/ui/chat/guildstree/model.go @@ -72,8 +72,8 @@ func (m Model) View(focused bool) tview.Widget { onChange, onSelect, ). - Title("Guilds"). - Footer(m.voiceFooter()) + Title(ui.Label("Guilds", m.cfg.Theme.Title, focused)). + Footer(ui.Label(m.voiceFooter(), m.cfg.Theme.Footer, focused)) } func (m *Model) reset() *tree.Node { diff --git a/internal/ui/chat/memberstree/model.go b/internal/ui/chat/memberstree/model.go index ae07f42..3969efe 100644 --- a/internal/ui/chat/memberstree/model.go +++ b/internal/ui/chat/memberstree/model.go @@ -10,6 +10,7 @@ import ( "github.com/ayn2op/arikawa/v3/gateway" "github.com/ayn2op/arikawa/v3/state" "github.com/ayn2op/discordo/internal/config" + "github.com/ayn2op/discordo/internal/ui" uitree "github.com/ayn2op/discordo/internal/ui/tree" "github.com/ayn2op/ningen/v3" "github.com/ayn2op/tview" @@ -99,7 +100,7 @@ func (m Model) View(focused bool) tview.Widget { onChange, onSelect, ). - Title("Members") + Title(ui.Label("Members", m.cfg.Theme.Title, focused)) } // setCurrentNode selects node and scrolls to it. diff --git a/internal/ui/chat/mentionslist/model.go b/internal/ui/chat/mentionslist/model.go index 13e0bb9..c791cb4 100644 --- a/internal/ui/chat/mentionslist/model.go +++ b/internal/ui/chat/mentionslist/model.go @@ -35,7 +35,7 @@ func (m Model) View() tview.Widget { list, width = list.Width(layout.Fixed(max(int(cfg.MinWidth), m.maxDisplayWidth()))), layout.Shrink } - return ui.Box(list, m.cfg, false).Title("Mentions").BorderSet(set).Width(width).Height(layout.Shrink) + return ui.Box(list, m.cfg, false).Title(ui.Label("Mentions", m.cfg.Theme.Title, false)).BorderSet(set).Width(width).Height(layout.Shrink) } func (Model) Init() tview.Cmd { return nil } diff --git a/internal/ui/chat/messageslist/model.go b/internal/ui/chat/messageslist/model.go index 55a94fa..a4724df 100644 --- a/internal/ui/chat/messageslist/model.go +++ b/internal/ui/chat/messageslist/model.go @@ -83,7 +83,9 @@ func NewModel(cfg *config.Config, state *ningen.State) Model { // View shows the messages in a box titled with the channel and footed with footer, such as who is typing. func (m Model) View(focused bool, footer string) tview.Widget { - return ui.Box(m.listView(focused), m.cfg, focused).Title(m.title()).Footer(footer) + return ui.Box(m.listView(focused), m.cfg, focused). + Title(ui.Label(m.title(), m.cfg.Theme.Title, focused)). + Footer(ui.Label(footer, m.cfg.Theme.Footer, focused)) } // title returns the selected channel and its topic, or "Messages" when none is selected. diff --git a/internal/ui/chat/messageslist/voice.go b/internal/ui/chat/messageslist/voice.go index 3bf6293..0d41730 100644 --- a/internal/ui/chat/messageslist/voice.go +++ b/internal/ui/chat/messageslist/voice.go @@ -80,7 +80,7 @@ func (m Model) voiceMessageView(a discord.Attachment) tview.Widget { return rail[cell], style.Dim(true) }) - play := button.New().Label(symbol).OnClick(playMsg(a)) + play := button.New(text.New(symbol)).OnClick(playMsg(a)) return row.New(play, waveform, text.New(label)).Spacing(1).Height(layout.Fixed(1)) } diff --git a/internal/ui/login/model.go b/internal/ui/login/model.go index f2b76c3..00bb19d 100644 --- a/internal/ui/login/model.go +++ b/internal/ui/login/model.go @@ -1,6 +1,7 @@ package login import ( + "github.com/ayn2op/tview/layout" "github.com/ayn2op/tview/tabs" "github.com/ayn2op/discordo/internal/config" @@ -72,6 +73,7 @@ func (m Model) View() tview.Widget { func (m Model) tabs() tabs.Widget { cfg := m.cfg.UI.Tabs return tabs.New(m.password.Label(), m.qr.Label(), m.token.Label()). + Width(layout.Fill). Alignment(cfg.Alignment.HorizontalAlignment). Wrap(cfg.Wrap). Separator(cfg.Separator). diff --git a/internal/ui/login/password/model.go b/internal/ui/login/password/model.go index ca291bb..8a3ca74 100644 --- a/internal/ui/login/password/model.go +++ b/internal/ui/login/password/model.go @@ -73,8 +73,7 @@ func (m Model) View() tview.Widget { Focused(m.focus == focusPassword). OnInput(func(text string, cursor int) tview.Msg { return passwordMsg{text, cursor} }). OnSubmit(focusMsg(focusButton)) - submit := button.New(). - Label("Login"). + submit := button.New(text.New("Login")). Width(layout.Fixed(len("Login") + 4)). Focused(m.focus == focusButton). OnClick(submitMsg{}) diff --git a/internal/ui/login/token/model.go b/internal/ui/login/token/model.go index e215d4b..3024bdf 100644 --- a/internal/ui/login/token/model.go +++ b/internal/ui/login/token/model.go @@ -54,8 +54,7 @@ func (m Model) View() tview.Widget { Focused(!m.buttonFocused). OnInput(func(text string, cursor int) tview.Msg { return tokenMsg{text, cursor} }). OnSubmit(focusButtonMsg{}) - submit := button.New(). - Label("Login"). + submit := button.New(text.New("Login")). Width(layout.Fixed(len("Login") + 4)). Focused(m.buttonFocused). OnClick(submitMsg{}) diff --git a/internal/ui/picker/picker.go b/internal/ui/picker/picker.go index fb1ba17..1a8c3b0 100644 --- a/internal/ui/picker/picker.go +++ b/internal/ui/picker/picker.go @@ -38,7 +38,7 @@ func (m Model) View(onSelect func(picker.Item) tview.Msg, onCancel tview.Msg) tv OnChange(func(s *picker.SearchState) tview.Msg { return changeMsg(*s) }). OnSelect(onSelect). OnCancel(onCancel) - return ui.Box(p, cfg, true).Title(m.title) + return ui.Box(p, cfg, true).Title(ui.Label(m.title, cfg.Theme.Title, true)) } func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) { diff --git a/internal/ui/util.go b/internal/ui/util.go index ceff92e..c754024 100644 --- a/internal/ui/util.go +++ b/internal/ui/util.go @@ -10,6 +10,7 @@ import ( "github.com/ayn2op/ningen/v3" "github.com/ayn2op/tview" "github.com/ayn2op/tview/box" + "github.com/ayn2op/tview/text" ) // Box returns child in a box laid out and styled by cfg, highlighted while focused. @@ -24,15 +25,22 @@ func Box(child tview.Widget, cfg *config.Config, focused bool) box.Widget { b = b.Borders(tview.BordersAll) } if focused { - return b.BorderStyle(theme.Border.ActiveStyle.Style). - BorderSet(ui.Border.ActiveSet.BorderSet). - TitleStyle(theme.Title.ActiveStyle.Style). - FooterStyle(theme.Footer.ActiveStyle.Style) + return b.BorderStyle(theme.Border.ActiveStyle.Style).BorderSet(ui.Border.ActiveSet.BorderSet) } - return b.BorderStyle(theme.Border.NormalStyle.Style). - BorderSet(ui.Border.NormalSet.BorderSet). - TitleStyle(theme.Title.NormalStyle.Style). - FooterStyle(theme.Footer.NormalStyle.Style) + return b.BorderStyle(theme.Border.NormalStyle.Style).BorderSet(ui.Border.NormalSet.BorderSet) +} + +// Label returns s on one line in the style of theme for whether its pane is focused, as the title or footer of a box, or nil if s is empty, so the box keeps no row for it. +func Label(s string, theme config.StyleThemeConfig, focused bool) tview.Widget { + if s == "" { + return nil + } + + style := theme.NormalStyle.Style + if focused { + style = theme.ActiveStyle.Style + } + return text.New(s).Style(style).Wrapping(text.WrappingNone) } // ChannelToString returns how channel is shown in the UI: an icon for its type and its name, or the recipients' names for a DM.