From 534c4e3c64bfde25777410eec8dc5709f77a9bc1 Mon Sep 17 00:00:00 2001 From: ayn2op Date: Wed, 7 Oct 2026 15:37:03 -0400 Subject: [PATCH] refactor(config)!: move non-style theme options to [ui] --- internal/config/config.toml | 70 +++++++----- internal/config/theme.go | 146 +++---------------------- internal/config/ui.go | 139 ++++++++++++++++++++++- internal/ui/chat/composer/model.go | 10 +- internal/ui/chat/guildstree/model.go | 5 +- internal/ui/chat/memberstree/model.go | 2 +- internal/ui/chat/mentionslist/model.go | 4 +- internal/ui/chat/messageslist/model.go | 12 +- internal/ui/login/model.go | 2 +- internal/ui/picker/picker.go | 6 +- internal/ui/tree/tree.go | 12 +- internal/ui/util.go | 17 +-- 12 files changed, 228 insertions(+), 197 deletions(-) diff --git a/internal/config/config.toml b/internal/config/config.toml index a208554..ddb8c04 100644 --- a/internal/config/config.toml +++ b/internal/config/config.toml @@ -69,6 +69,47 @@ arrows = ["◀", "▶"] # Whether clicking an arrow selects the tab next to the active one. clickable_arrows = true +[ui.title] +# "left", "center" or "right". +alignment = "left" + +[ui.footer] +alignment = "left" + +[ui.border] +enabled = true +padding = [0, 0, 1, 1] # [top, bottom, left, right] +# "hidden", "plain", "round", "thick" or "double". +normal_set = "round" +active_set = "round" + +[ui.guilds_tree] +auto_expand_folders = true +# Give tree-like shape +graphics = true + +[ui.members_tree] +# Give tree-like shape +graphics = true + +[ui.scroll_bar] +visibility = "auto" +# "minimal", "box_drawing", "vertical" or "double_vertical" +symbol_set = "box_drawing" + +[ui.messages_list] +reply_indicator = ">" +forwarded_indicator = "<" + +[ui.mentions_list] +# Note: width and height are capped to the available space +# Minimum width +# 0 = make the list as wide as possible +min_width = 20 +# Maximum height +# 0 = make the list as tall as needed +max_height = 0 + [timestamps] enabled = true # https://pkg.go.dev/time#Layout @@ -259,31 +300,18 @@ select_bottom = "end" # style = { foreground = "", background = "", attributes = "" or ["",""], underline = "", underline_color = "" } [theme.title] -alignment = "left" # `"left"`, `"center"`, or `"right"`. normal_style = { attributes = "dim" } active_style = { foreground = "green", attributes = "bold" } [theme.footer] -alignment = "left" normal_style = { attributes = "dim" } active_style = { foreground = "green", attributes = "bold" } [theme.border] -enabled = true -padding = [0, 0, 1, 1] # [top, bottom, left, right] - normal_style = { attributes = "dim" } active_style = { foreground = "green", attributes = "bold" } -# `"hidden"`, `"plain"`, `"round"`, `"thick"`, or `"double"`. -normal_set = "round" -active_set = "round" - [theme.guilds_tree] -auto_expand_folders = true - -# Give tree-like shape -graphics = true graphics_color = "default" # Direct-message recipient presence styles. @@ -293,8 +321,6 @@ dnd_style = { foreground = "red" } offline_style = { foreground = "gray" } [theme.members_tree] -# Give tree-like shape -graphics = true graphics_color = "default" # Styles of the status dot before each member. @@ -304,16 +330,10 @@ dnd_style = { foreground = "red" } offline_style = { foreground = "gray" } [theme.scroll_bar] -visibility = "auto" -# "minimal", "box_drawing", "vertical", or "double_vertical" -symbol_set = "box_drawing" track_style = { attributes = "dim" } thumb_style = {} [theme.messages_list] -reply_indicator = ">" -forwarded_indicator = "<" - mention_style = { foreground = "blue", attributes = "bold" } emoji_style = { foreground = "green" } url_style = { foreground = "blue" } @@ -336,14 +356,6 @@ footer_style = { attributes = ["dim", "italic"] } url_style = { foreground = "blue", underline = "solid" } [theme.mentions_list] -# Note: width and height are capped to the avaliable space -# Minimum width -# 0 = make the list as wide as possible -min_width = 20 -# Maximum height -# 0 = make the list as tall as needed -max_height = 0 - selected_style = { attributes = "reverse" } [theme.dialog] diff --git a/internal/config/theme.go b/internal/config/theme.go index 658fe57..6c66401 100644 --- a/internal/config/theme.go +++ b/internal/config/theme.go @@ -6,33 +6,11 @@ import ( "github.com/ayn2op/arikawa/v3/discord" "github.com/ayn2op/tview" - "github.com/ayn2op/tview/list" - "github.com/ayn2op/tview/scrollbar" "github.com/gdamore/tcell/v3" ) var errInvalidType = errors.New("invalid type") -type AlignmentWrapper struct{ tview.Alignment } - -func (aw *AlignmentWrapper) UnmarshalTOML(v any) error { - s, ok := v.(string) - if !ok { - return errInvalidType - } - switch s { - case "left": - aw.Alignment = tview.AlignmentLeft - case "center": - aw.Alignment = tview.AlignmentCenter - case "right": - aw.Alignment = tview.AlignmentRight - default: - return fmt.Errorf("unknown value: %q", s) - } - return nil -} - type StyleWrapper struct{ tview.Style } func (sw *StyleWrapper) UnmarshalTOML(v any) error { @@ -113,72 +91,6 @@ func (sw *StyleWrapper) parseAttr(s string) { } } -type BorderSetWrapper struct{ tview.BorderSet } - -func (bw *BorderSetWrapper) UnmarshalTOML(val any) error { - s, ok := val.(string) - if !ok { - return errInvalidType - } - switch s { - case "hidden": - bw.BorderSet = tview.BorderSetHidden() - case "plain": - bw.BorderSet = tview.BorderSetPlain() - case "round": - bw.BorderSet = tview.BorderSetRound() - case "thick": - bw.BorderSet = tview.BorderSetThick() - case "double": - bw.BorderSet = tview.BorderSetDouble() - default: - return fmt.Errorf("unknown value: %q", s) - } - return nil -} - -type SymbolSetWrapper struct{ scrollbar.SymbolSet } - -func (sw *SymbolSetWrapper) UnmarshalTOML(val any) error { - s, ok := val.(string) - if !ok { - return errInvalidType - } - switch s { - case "minimal": - sw.SymbolSet = scrollbar.SymbolSet{Thumb: "█", Begin: "▲", End: "▼"} - case "box_drawing", "boxdrawing", "box": - sw.SymbolSet = scrollbar.SymbolSet{Track: "│", Thumb: "█", Begin: "▲", End: "▼"} - case "vertical": - sw.SymbolSet = scrollbar.SymbolSetVertical() - case "double_vertical": - sw.SymbolSet = scrollbar.SymbolSetDoubleVertical() - default: - return fmt.Errorf("unknown value: %q", s) - } - return nil -} - -type ScrollBarVisibilityWrapper struct{ list.ScrollBarVisibility } - -func (vw *ScrollBarVisibilityWrapper) UnmarshalTOML(val any) error { - s, ok := val.(string) - if !ok { - return errInvalidType - } - switch s { - case "automatic", "auto": - vw.ScrollBarVisibility = list.ScrollBarVisibilityAutomatic - case "always": - vw.ScrollBarVisibility = list.ScrollBarVisibilityAlways - case "never", "hidden", "off": - vw.ScrollBarVisibility = list.ScrollBarVisibilityNever - default: - return fmt.Errorf("unknown value: %q", s) - } - return nil -} - type ( HelpTheme struct { ShortKeyStyle StyleWrapper `toml:"short_key_style"` @@ -192,40 +104,14 @@ type ( ActiveStyle StyleWrapper `toml:"active_style"` } - TitleTheme struct { - ThemeStyle - Alignment AlignmentWrapper `toml:"alignment"` - } - - FooterTheme struct { - ThemeStyle - Alignment AlignmentWrapper `toml:"alignment"` - } - - BorderTheme struct { - ThemeStyle - Enabled bool `toml:"enabled"` - Padding [4]int `toml:"padding"` - - NormalSet BorderSetWrapper `toml:"normal_set"` - ActiveSet BorderSetWrapper `toml:"active_set"` - } - - GuildsTreeTheme struct { - CommonTreeTheme - AutoExpandFolders bool `toml:"auto_expand_folders"` - } - MessagesListTheme struct { - ReplyIndicator string `toml:"reply_indicator"` - ForwardedIndicator string `toml:"forwarded_indicator"` - AuthorStyle StyleWrapper `toml:"author_style"` - MentionStyle StyleWrapper `toml:"mention_style"` - EmojiStyle StyleWrapper `toml:"emoji_style"` - URLStyle StyleWrapper `toml:"url_style"` - AttachmentStyle StyleWrapper `toml:"attachment_style"` - ReactionStyle StyleWrapper `toml:"reaction_style"` - OwnReactionStyle StyleWrapper `toml:"own_reaction_style"` + AuthorStyle StyleWrapper `toml:"author_style"` + MentionStyle StyleWrapper `toml:"mention_style"` + EmojiStyle StyleWrapper `toml:"emoji_style"` + URLStyle StyleWrapper `toml:"url_style"` + AttachmentStyle StyleWrapper `toml:"attachment_style"` + ReactionStyle StyleWrapper `toml:"reaction_style"` + OwnReactionStyle StyleWrapper `toml:"own_reaction_style"` MessageStyle StyleWrapper `toml:"message_style"` SelectedMessageStyle StyleWrapper `toml:"selected_message_style"` @@ -245,9 +131,6 @@ type ( } MentionsListTheme struct { - MinWidth uint `toml:"min_width"` - MaxHeight uint `toml:"max_height"` - SelectedStyle StyleWrapper `toml:"selected_style"` } @@ -257,17 +140,15 @@ type ( } ScrollBarTheme struct { - Visibility ScrollBarVisibilityWrapper `toml:"visibility"` - SymbolSet SymbolSetWrapper `toml:"symbol_set"` - TrackStyle StyleWrapper `toml:"track_style"` - ThumbStyle StyleWrapper `toml:"thumb_style"` + TrackStyle StyleWrapper `toml:"track_style"` + ThumbStyle StyleWrapper `toml:"thumb_style"` } Theme struct { - Title TitleTheme `toml:"title"` - Footer FooterTheme `toml:"footer"` - Border BorderTheme `toml:"border"` - GuildsTree GuildsTreeTheme `toml:"guilds_tree"` + Title ThemeStyle `toml:"title"` + Footer ThemeStyle `toml:"footer"` + Border ThemeStyle `toml:"border"` + GuildsTree CommonTreeTheme `toml:"guilds_tree"` MembersTree CommonTreeTheme `toml:"members_tree"` ScrollBar ScrollBarTheme `toml:"scroll_bar"` MessagesList MessagesListTheme `toml:"messages_list"` @@ -278,7 +159,6 @@ type ( ) type CommonTreeTheme struct { - Graphics bool `toml:"graphics"` GraphicsColor string `toml:"graphics_color"` OnlineStyle StyleWrapper `toml:"online_style"` diff --git a/internal/config/ui.go b/internal/config/ui.go index 81c2582..f8b5462 100644 --- a/internal/config/ui.go +++ b/internal/config/ui.go @@ -1,8 +1,110 @@ package config +import ( + "fmt" + + "github.com/ayn2op/tview" + "github.com/ayn2op/tview/list" + "github.com/ayn2op/tview/scrollbar" +) + +type AlignmentWrapper struct{ tview.Alignment } + +func (aw *AlignmentWrapper) UnmarshalTOML(v any) error { + s, ok := v.(string) + if !ok { + return errInvalidType + } + switch s { + case "left": + aw.Alignment = tview.AlignmentLeft + case "center": + aw.Alignment = tview.AlignmentCenter + case "right": + aw.Alignment = tview.AlignmentRight + default: + return fmt.Errorf("unknown value: %q", s) + } + return nil +} + +type BorderSetWrapper struct{ tview.BorderSet } + +func (bw *BorderSetWrapper) UnmarshalTOML(val any) error { + s, ok := val.(string) + if !ok { + return errInvalidType + } + switch s { + case "hidden": + bw.BorderSet = tview.BorderSetHidden() + case "plain": + bw.BorderSet = tview.BorderSetPlain() + case "round": + bw.BorderSet = tview.BorderSetRound() + case "thick": + bw.BorderSet = tview.BorderSetThick() + case "double": + bw.BorderSet = tview.BorderSetDouble() + default: + return fmt.Errorf("unknown value: %q", s) + } + return nil +} + +type SymbolSetWrapper struct{ scrollbar.SymbolSet } + +func (sw *SymbolSetWrapper) UnmarshalTOML(val any) error { + s, ok := val.(string) + if !ok { + return errInvalidType + } + switch s { + case "minimal": + sw.SymbolSet = scrollbar.SymbolSet{Thumb: "█", Begin: "▲", End: "▼"} + case "box_drawing", "boxdrawing", "box": + sw.SymbolSet = scrollbar.SymbolSet{Track: "│", Thumb: "█", Begin: "▲", End: "▼"} + case "vertical": + sw.SymbolSet = scrollbar.SymbolSetVertical() + case "double_vertical": + sw.SymbolSet = scrollbar.SymbolSetDoubleVertical() + default: + return fmt.Errorf("unknown value: %q", s) + } + return nil +} + +type ScrollBarVisibilityWrapper struct{ list.ScrollBarVisibility } + +func (vw *ScrollBarVisibilityWrapper) UnmarshalTOML(val any) error { + s, ok := val.(string) + if !ok { + return errInvalidType + } + switch s { + case "automatic", "auto": + vw.ScrollBarVisibility = list.ScrollBarVisibilityAutomatic + case "always": + vw.ScrollBarVisibility = list.ScrollBarVisibilityAlways + case "never", "hidden", "off": + vw.ScrollBarVisibility = list.ScrollBarVisibilityNever + default: + return fmt.Errorf("unknown value: %q", s) + } + return nil +} + type ( UIConfig struct { - Tabs TabsConfig `toml:"tabs"` + Tabs TabsConfig `toml:"tabs"` + Title TitleConfig `toml:"title"` + Footer TitleConfig `toml:"footer"` + Border BorderConfig `toml:"border"` + GuildsTree GuildsTreeConfig `toml:"guilds_tree"` + MembersTree TreeConfig `toml:"members_tree"` + ScrollBar ScrollBarConfig `toml:"scroll_bar"` + MessagesList MessagesListConfig `toml:"messages_list"` + MentionsList MentionsListConfig `toml:"mentions_list"` } TabsConfig struct { @@ -13,4 +115,39 @@ type ( Arrows [2]string `toml:"arrows"` ClickableArrows bool `toml:"clickable_arrows"` } + + TitleConfig struct { + Alignment AlignmentWrapper `toml:"alignment"` + } + + BorderConfig struct { + Enabled bool `toml:"enabled"` + Padding [4]int `toml:"padding"` + NormalSet BorderSetWrapper `toml:"normal_set"` + ActiveSet BorderSetWrapper `toml:"active_set"` + } + + TreeConfig struct { + Graphics bool `toml:"graphics"` + } + + GuildsTreeConfig struct { + TreeConfig + AutoExpandFolders bool `toml:"auto_expand_folders"` + } + + ScrollBarConfig struct { + Visibility ScrollBarVisibilityWrapper `toml:"visibility"` + SymbolSet SymbolSetWrapper `toml:"symbol_set"` + } + + MessagesListConfig struct { + ReplyIndicator string `toml:"reply_indicator"` + ForwardedIndicator string `toml:"forwarded_indicator"` + } + + MentionsListConfig struct { + MinWidth uint `toml:"min_width"` + MaxHeight uint `toml:"max_height"` + } ) diff --git a/internal/ui/chat/composer/model.go b/internal/ui/chat/composer/model.go index 0139c8a..6174ce0 100644 --- a/internal/ui/chat/composer/model.go +++ b/internal/ui/chat/composer/model.go @@ -152,7 +152,7 @@ func (m *Model) box(focused bool) box.Widget { Keybind(m.editAction). Focused(focused && !m.disabled). OnChange(func(a textarea.Change) tview.Msg { return editMsg(a) }) - return ui.Box(text, &m.cfg.Theme, focused).Title(m.title()).Footer(m.footer()) + return ui.Box(text, m.cfg, focused).Title(m.title()).Footer(m.footer()) } // title returns what the composer is doing: editing, replying, or nothing. @@ -523,16 +523,16 @@ func (p mentionsPopup) Handle(msg tview.Msg, area tview.Rectangle) tview.Msg { func (p mentionsPopup) area(area tview.Rectangle) tview.Rectangle { c := p.c borders := 0 - if c.cfg.Theme.Border.Enabled { + if c.cfg.UI.Border.Enabled { borders = 1 } x, _ := c.frame() maxW, maxH := area.Width, area.Height-c.Height() - if t := int(c.cfg.Theme.MentionsList.MaxHeight); t != 0 { + if t := int(c.cfg.UI.MentionsList.MaxHeight); t != 0 { maxH = min(maxH, t) } - h := min(c.mentionsList.ItemCount()+borders, maxH) + borders + c.cfg.Theme.Border.Padding[1] - w := int(c.cfg.Theme.MentionsList.MinWidth) + h := min(c.mentionsList.ItemCount()+borders, maxH) + borders + c.cfg.UI.Border.Padding[1] + w := int(c.cfg.UI.MentionsList.MinWidth) if w == 0 { w = maxW } else { diff --git a/internal/ui/chat/guildstree/model.go b/internal/ui/chat/guildstree/model.go index e7da169..cf7c801 100644 --- a/internal/ui/chat/guildstree/model.go +++ b/internal/ui/chat/guildstree/model.go @@ -54,7 +54,8 @@ func (m Model) View(focused bool) tview.Widget { m.root, m.selectionState, m.cfg, - m.cfg.Theme.GuildsTree.CommonTreeTheme, + m.cfg.Theme.GuildsTree, + m.cfg.UI.GuildsTree.Graphics, m.cfg.Keybinds.GuildsTree.TreeKeybinds, focused, onChange, @@ -163,7 +164,7 @@ func (m Model) createFolderNode(folder gateway.GuildFolder, guildsByID map[disco name = folder.Name } - folderNode := tree.NewNode(name).SetExpanded(m.cfg.Theme.GuildsTree.AutoExpandFolders) + folderNode := tree.NewNode(name).SetExpanded(m.cfg.UI.GuildsTree.AutoExpandFolders) if folder.Color != 0 { folderStyle := tcell.StyleDefault.Foreground(tcell.NewHexColor(int32(folder.Color))) m.setNodeLineStyle(folderNode, folderStyle) diff --git a/internal/ui/chat/memberstree/model.go b/internal/ui/chat/memberstree/model.go index 3b32100..7e702a5 100644 --- a/internal/ui/chat/memberstree/model.go +++ b/internal/ui/chat/memberstree/model.go @@ -85,7 +85,7 @@ func (m *Model) SetChannel(channel *discord.Channel) tview.Cmd { func (m Model) View(focused bool) tview.Widget { onChange := func(c tree.Change) tview.Msg { return Msg(c) } onSelect := func(n *tree.Node) tview.Msg { return SelectedMsg{Node: n} } - return uitree.New(m.root, m.selectionState, m.cfg, m.cfg.Theme.MembersTree, m.cfg.Keybinds.MembersTree, focused, onChange, onSelect).Title("Members") + return uitree.New(m.root, m.selectionState, m.cfg, m.cfg.Theme.MembersTree, m.cfg.UI.MembersTree.Graphics, m.cfg.Keybinds.MembersTree, focused, onChange, onSelect).Title("Members") } // Update returns m changed in response to msg and a command to run, or nil. diff --git a/internal/ui/chat/mentionslist/model.go b/internal/ui/chat/mentionslist/model.go index b0ef5ea..137b273 100644 --- a/internal/ui/chat/mentionslist/model.go +++ b/internal/ui/chat/mentionslist/model.go @@ -22,9 +22,9 @@ func NewModel(cfg *config.Config) Model { // View shows the list in a box whose bottom corners join the composer's border below it. func (m Model) View() tview.Widget { - set := m.cfg.Theme.Border.NormalSet.BorderSet + set := m.cfg.UI.Border.NormalSet.BorderSet set.BottomLeft, set.BottomRight = set.BottomT, set.BottomT - return ui.Box(m.listView(), &m.cfg.Theme, false).Title("Mentions").BorderSet(set) + return ui.Box(m.listView(), m.cfg, false).Title("Mentions").BorderSet(set) } func (Model) Init() tview.Cmd { return nil } diff --git a/internal/ui/chat/messageslist/model.go b/internal/ui/chat/messageslist/model.go index de24cc7..50b16a5 100644 --- a/internal/ui/chat/messageslist/model.go +++ b/internal/ui/chat/messageslist/model.go @@ -81,7 +81,7 @@ 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.Theme, focused).Title(m.title()).Footer(footer) + return ui.Box(m.listView(focused), m.cfg, focused).Title(m.title()).Footer(footer) } // title returns the selected channel and its topic, or "Messages" when none is selected. @@ -97,11 +97,11 @@ func (m Model) title() string { } func (m Model) listView(focused bool) list.Widget { - cfg := m.cfg.Theme.ScrollBar + cfg, theme := m.cfg.UI.ScrollBar, m.cfg.Theme.ScrollBar bar := scrollbar.New(). SymbolSet(cfg.SymbolSet.SymbolSet). - Style(cfg.TrackStyle.Style). - ThumbStyle(cfg.ThumbStyle.Style) + Style(theme.TrackStyle.Style). + ThumbStyle(theme.ThumbStyle.Style) return list.New(m.selectionState, len(m.items), m.buildItem). SelectedStyle(m.cfg.Theme.MessagesList.SelectedMessageStyle.Style). ScrollBar(bar, cfg.Visibility.ScrollBarVisibility). @@ -803,14 +803,14 @@ func (m Model) drawForwardedMessage(builder *richtext.Builder, message discord.M dimStyle := baseStyle.Dim(true) m.drawTimestamps(builder, message.Timestamp, baseStyle) m.drawAuthor(builder, message, baseStyle) - builder.Write(m.cfg.Theme.MessagesList.ForwardedIndicator+" ", dimStyle) + builder.Write(m.cfg.UI.MessagesList.ForwardedIndicator+" ", dimStyle) m.drawSnapshotContent(builder, message, message.MessageSnapshots[0].Message, baseStyle) builder.Write(" ("+m.formatTimestamp(message.MessageSnapshots[0].Message.Timestamp)+") ", dimStyle) } func (m Model) drawReplyMessage(builder *richtext.Builder, message discord.Message, baseStyle tview.Style, width int) { dimStyle := baseStyle.Dim(true) - builder.Write(m.cfg.Theme.MessagesList.ReplyIndicator+" ", dimStyle) + builder.Write(m.cfg.UI.MessagesList.ReplyIndicator+" ", dimStyle) if reference := message.ReferencedMessage; reference != nil { reference.GuildID = message.GuildID diff --git a/internal/ui/login/model.go b/internal/ui/login/model.go index 34e20e3..21e2485 100644 --- a/internal/ui/login/model.go +++ b/internal/ui/login/model.go @@ -65,7 +65,7 @@ func (m Model) View() tview.Widget { Content(content). Keybind(tabAction). OnSelect(func(i int) tview.Msg { return selectTabMsg(i) }) - return ui.Box(t, &m.cfg.Theme, false) + return ui.Box(t, m.cfg, false) } // tabs returns the login methods as tabs set up by the tabs config. diff --git a/internal/ui/picker/picker.go b/internal/ui/picker/picker.go index 352b382..fdcf31d 100644 --- a/internal/ui/picker/picker.go +++ b/internal/ui/picker/picker.go @@ -28,17 +28,17 @@ func (Model) Init() tview.Cmd { return nil } func (m Model) View(onSelect func(picker.Item) tview.Msg, onCancel tview.Msg) tview.Widget { cfg := m.cfg bar := scrollbar.New(). - SymbolSet(cfg.Theme.ScrollBar.SymbolSet.SymbolSet). + SymbolSet(cfg.UI.ScrollBar.SymbolSet.SymbolSet). Style(cfg.Theme.ScrollBar.TrackStyle.Style). ThumbStyle(cfg.Theme.ScrollBar.ThumbStyle.Style) p := picker.New(m.items, &m.searchState). - ScrollBar(bar, cfg.Theme.ScrollBar.Visibility.ScrollBarVisibility). + ScrollBar(bar, cfg.UI.ScrollBar.Visibility.ScrollBarVisibility). Keybind(bindKeys(cfg.Keybinds.Picker)). ListKeybind(ui.SelectionKeybind(cfg.Keybinds.Picker.SelectionKeybinds)). OnChange(func(c picker.Change) tview.Msg { return changeMsg(c) }). OnSelect(onSelect). OnCancel(onCancel) - return ui.Box(p, &cfg.Theme, true).Title(m.title) + return ui.Box(p, cfg, true).Title(m.title) } func (m Model) Update(msg tview.Msg) (Model, tview.Cmd) { diff --git a/internal/ui/tree/tree.go b/internal/ui/tree/tree.go index 0180f15..557ff89 100644 --- a/internal/ui/tree/tree.go +++ b/internal/ui/tree/tree.go @@ -11,11 +11,11 @@ import ( "github.com/gdamore/tcell/v3" ) -// New returns a boxed tree of the nodes under root, drawn with theme and moved with kbs, that turns changes and selected nodes into the messages onChange and onSelect return. -func New(root *tree.Node, selectionState tree.SelectionState, cfg *config.Config, theme config.CommonTreeTheme, kbs config.TreeKeybinds, focused bool, onChange func(tree.Change) tview.Msg, onSelect func(*tree.Node) tview.Msg) box.Widget { - set := cfg.Theme.Border.NormalSet.BorderSet +// New returns a boxed tree of the nodes under root, drawn with theme and graphics and moved with kbs, that turns changes and selected nodes into the messages onChange and onSelect return. +func New(root *tree.Node, selectionState tree.SelectionState, cfg *config.Config, theme config.CommonTreeTheme, graphics bool, kbs config.TreeKeybinds, focused bool, onChange func(tree.Change) tview.Msg, onSelect func(*tree.Node) tview.Msg) box.Widget { + set := cfg.UI.Border.NormalSet.BorderSet if focused { - set = cfg.Theme.Border.ActiveSet.BorderSet + set = cfg.UI.Border.ActiveSet.BorderSet } t := tree.New(root, selectionState). TopLevel(1). @@ -24,14 +24,14 @@ func New(root *tree.Node, selectionState tree.SelectionState, cfg *config.Config Collapsed: cfg.Sidebar.Markers.Collapsed, Leaf: cfg.Sidebar.Markers.Leaf, }). - Graphics(theme.Graphics). + Graphics(graphics). GraphicsSet(set). GraphicsStyle(tcell.StyleDefault.Foreground(tcell.GetColor(theme.GraphicsColor))). Keybind(bindKeys(kbs)). Focused(focused). OnChange(onChange). OnSelect(onSelect) - return ui.Box(t, &cfg.Theme, focused) + return ui.Box(t, cfg, focused) } func bindKeys(kbs config.TreeKeybinds) func(tview.KeyMsg) tree.Action { diff --git a/internal/ui/util.go b/internal/ui/util.go index e79f7ce..a293d2d 100644 --- a/internal/ui/util.go +++ b/internal/ui/util.go @@ -12,24 +12,25 @@ import ( "github.com/ayn2op/tview/box" ) -// Box returns child in a box styled by the theme, highlighted while focused. -func Box(child tview.Widget, theme *config.Theme, focused bool) box.Widget { - padding := theme.Border.Padding +// Box returns child in a box laid out and styled by cfg, highlighted while focused. +func Box(child tview.Widget, cfg *config.Config, focused bool) box.Widget { + ui, theme := cfg.UI, cfg.Theme + padding := ui.Border.Padding b := box.New(child). Padding(padding[0], padding[1], padding[2], padding[3]). - TitleAlignment(theme.Title.Alignment.Alignment). - FooterAlignment(theme.Footer.Alignment.Alignment) - if theme.Border.Enabled { + TitleAlignment(ui.Title.Alignment.Alignment). + FooterAlignment(ui.Footer.Alignment.Alignment) + if ui.Border.Enabled { b = b.Borders(tview.BordersAll) } if focused { return b.BorderStyle(theme.Border.ActiveStyle.Style). - BorderSet(theme.Border.ActiveSet.BorderSet). + BorderSet(ui.Border.ActiveSet.BorderSet). TitleStyle(theme.Title.ActiveStyle.Style). FooterStyle(theme.Footer.ActiveStyle.Style) } return b.BorderStyle(theme.Border.NormalStyle.Style). - BorderSet(theme.Border.NormalSet.BorderSet). + BorderSet(ui.Border.NormalSet.BorderSet). TitleStyle(theme.Title.NormalStyle.Style). FooterStyle(theme.Footer.NormalStyle.Style) }