diff --git a/_sample_configs/dynamic_sizing.yml b/_sample_configs/dynamic_sizing.yml new file mode 100644 index 0000000000..18f03c618a --- /dev/null +++ b/_sample_configs/dynamic_sizing.yml @@ -0,0 +1,23 @@ +wtf: + refreshInterval: 1 + openFileUtil: "open" + mods: + battery: + type: power + title: "⚡️" + enabled: true + position: + top: 0 + left: 0 + height: 1 + width: 1 + refreshInterval: 15 + security_info: + type: security + enabled: true + position: + top: 0 + left: 1 + height: 1 + width: 1 + refreshInterval: 3600 \ No newline at end of file diff --git a/cfg/common_settings.go b/cfg/common_settings.go index da30ba8456..c0c1707850 100644 --- a/cfg/common_settings.go +++ b/cfg/common_settings.go @@ -7,24 +7,6 @@ import ( "github.com/olebedev/config" ) -type Colors struct { - Background string - BorderFocusable string - BorderFocused string - BorderNormal string - Checked string - Foreground string - HighlightBack string - HighlightFore string - Text string - Title string - - Rows struct { - Even string - Odd string - } -} - type Module struct { Name string Type string @@ -42,11 +24,11 @@ type Sigils struct { } type Common struct { - Colors Module PositionSettings `help:"Defines where in the grid this module’s widget will be displayed."` Sigils + Colors ColorTheme Bordered bool `help:"Whether or not the module should be displayed with a border." values:"true, false" optional:"true" default:"true"` Enabled bool `help:"Whether or not this module is executed and if its data displayed onscreen." values:"true, false" optional:"true" default:"false"` Focusable bool `help:"Whether or not this module is focusable." values:"true, false" optional:"true" default:"false"` @@ -57,23 +39,44 @@ type Common struct { focusChar int `help:"Define one of the number keys as a short cut key to access the widget." optional:"true"` } +// NewCommonSettingsFromModule returns a common settings configuration tailed to the given module func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable bool, moduleConfig *config.Config, globalSettings *config.Config) *Common { - colorsConfig, _ := globalSettings.Get("wtf.colors") - sigilsPath := "wtf.sigils" + baseColors := NewDefaultColorTheme() + + colorsConfig, err := globalSettings.Get("wtf.colors") + if err != nil && strings.Contains(err.Error(), "Nonexistent map") { + // Create a default colors config to fill in for the missing one + // This comes into play when the configuration file does not contain a `colors:` key, i.e: + // + // wtf: + // # colors: <- missing + // refreshInterval: 1 + // openFileUtil: "open" + // + colorsConfig, _ = NewDefaultColorConfig() + } + + // And finally create a third instance to be the final default fallback in case there are empty or nil values in + // the colors extracted from the config file (aka colorsConfig) + defaultColorTheme := NewDefaultColorTheme() + + baseColors.BorderTheme.Focusable = moduleConfig.UString("colors.border.focusable", colorsConfig.UString("border.focusable", defaultColorTheme.BorderTheme.Focusable)) + baseColors.BorderTheme.Focused = moduleConfig.UString("colors.border.focused", colorsConfig.UString("border.focused", defaultColorTheme.BorderTheme.Focused)) + baseColors.BorderTheme.Unfocusable = moduleConfig.UString("colors.border.normal", colorsConfig.UString("border.normal", defaultColorTheme.BorderTheme.Unfocusable)) + + baseColors.CheckboxTheme.Checked = moduleConfig.UString("colors.checked", colorsConfig.UString("checked", defaultColorTheme.CheckboxTheme.Checked)) + + baseColors.RowTheme.EvenForeground = moduleConfig.UString("colors.rows.even", colorsConfig.UString("rows.even", "white")) + baseColors.RowTheme.OddForeground = moduleConfig.UString("colors.rows.odd", colorsConfig.UString("rows.odd", "lightblue")) + + baseColors.TextTheme.Subheading = moduleConfig.UString("colors.subheading", colorsConfig.UString("subheading", defaultColorTheme.TextTheme.Subheading)) + baseColors.TextTheme.Text = moduleConfig.UString("colors.text", colorsConfig.UString("text", defaultColorTheme.TextTheme.Text)) + baseColors.TextTheme.Title = moduleConfig.UString("colors.title", colorsConfig.UString("title", defaultColorTheme.TextTheme.Title)) + + baseColors.WidgetTheme.Background = moduleConfig.UString("colors.background", colorsConfig.UString("background", defaultColorTheme.WidgetTheme.Background)) common := Common{ - Colors: Colors{ - Background: moduleConfig.UString("colors.background", colorsConfig.UString("background", "transparent")), - BorderFocusable: moduleConfig.UString("colors.border.focusable", colorsConfig.UString("border.focusable", "red")), - BorderFocused: moduleConfig.UString("colors.border.focused", colorsConfig.UString("border.focused", "orange")), - BorderNormal: moduleConfig.UString("colors.border.normal", colorsConfig.UString("border.normal", "gray")), - Checked: moduleConfig.UString("colors.checked", colorsConfig.UString("checked", "white")), - Foreground: moduleConfig.UString("colors.foreground", colorsConfig.UString("foreground", "white")), - HighlightFore: moduleConfig.UString("colors.highlight.fore", colorsConfig.UString("highlight.fore", "black")), - HighlightBack: moduleConfig.UString("colors.highlight.back", colorsConfig.UString("highlight.back", "green")), - Text: moduleConfig.UString("colors.text", colorsConfig.UString("text", "white")), - Title: moduleConfig.UString("colors.title", colorsConfig.UString("title", "white")), - }, + Colors: baseColors, Module: Module{ Name: name, @@ -92,12 +95,10 @@ func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable boo focusChar: moduleConfig.UInt("focusChar", -1), } - common.Colors.Rows.Even = moduleConfig.UString("colors.rows.even", colorsConfig.UString("rows.even", "white")) - common.Colors.Rows.Odd = moduleConfig.UString("colors.rows.odd", colorsConfig.UString("rows.odd", "lightblue")) + sigilsPath := "wtf.sigils" common.Sigils.Checkbox.Checked = globalSettings.UString(sigilsPath+".checkbox.checked", "x") common.Sigils.Checkbox.Unchecked = globalSettings.UString(sigilsPath+".checkbox.unchecked", " ") - common.Sigils.Paging.Normal = globalSettings.UString(sigilsPath+".paging.normal", globalSettings.UString("wtf.paging.pageSigil", "*")) common.Sigils.Paging.Selected = globalSettings.UString(sigilsPath+".paging.select", globalSettings.UString("wtf.paging.selectedSigil", "_")) @@ -107,11 +108,19 @@ func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable boo /* -------------------- Exported Functions -------------------- */ func (common *Common) DefaultFocusedRowColor() string { - return fmt.Sprintf("%s:%s", common.Colors.HighlightFore, common.Colors.HighlightBack) + return fmt.Sprintf( + "%s:%s", + common.Colors.RowTheme.HighlightedForeground, + common.Colors.RowTheme.HighlightedBackground, + ) } func (common *Common) DefaultRowColor() string { - return fmt.Sprintf("%s:%s", common.Colors.Foreground, common.Colors.Background) + return fmt.Sprintf( + "%s:%s", + common.Colors.RowTheme.EvenForeground, + common.Colors.RowTheme.EvenBackground, + ) } func (common *Common) FocusChar() string { @@ -124,10 +133,10 @@ func (common *Common) FocusChar() string { func (common *Common) RowColor(idx int) string { if idx%2 == 0 { - return common.Colors.Rows.Even + return common.Colors.RowTheme.EvenForeground } - return common.Colors.Rows.Odd + return common.Colors.RowTheme.OddForeground } func (common *Common) RightAlignFormat(width int) string { diff --git a/cfg/default_color_theme.go b/cfg/default_color_theme.go new file mode 100644 index 0000000000..17c792caf8 --- /dev/null +++ b/cfg/default_color_theme.go @@ -0,0 +1,106 @@ +package cfg + +import ( + "github.com/olebedev/config" + "gopkg.in/yaml.v2" +) + +// BorderTheme defines the default color scheme for drawing widget borders +type BorderTheme struct { + Focusable string + Focused string + Unfocusable string +} + +// CheckboxTheme defines the default color scheme for drawing checkable rows in widgets +type CheckboxTheme struct { + Checked string +} + +// RowTheme defines the default color scheme for row text +type RowTheme struct { + EvenBackground string + EvenForeground string + + OddBackground string + OddForeground string + + HighlightedBackground string + HighlightedForeground string +} + +// TextTheme defines the default color scheme for text rendering +type TextTheme struct { + Subheading string + Text string + Title string +} + +type WidgetTheme struct { + Background string +} + +// ColorTheme is an alamgam of all the default color settings +type ColorTheme struct { + BorderTheme + CheckboxTheme + RowTheme + TextTheme + WidgetTheme +} + +// NewDefaultColorTheme creates and returns an instance of DefaultColorTheme +func NewDefaultColorTheme() ColorTheme { + defaultTheme := ColorTheme{ + BorderTheme: BorderTheme{ + Focusable: "blue", + Focused: "orange", + Unfocusable: "gray", + }, + + CheckboxTheme: CheckboxTheme{ + Checked: "white", + }, + + RowTheme: RowTheme{ + EvenBackground: "transparent", + EvenForeground: "white", + + OddBackground: "transparent", + OddForeground: "lightblue", + + HighlightedForeground: "black", + HighlightedBackground: "green", + }, + + TextTheme: TextTheme{ + Subheading: "red", + Text: "white", + Title: "green", + }, + + WidgetTheme: WidgetTheme{ + Background: "transparent", + }, + } + + return defaultTheme +} + +// NewDefaultColorConfig creates and returns a config.Config-compatible configuration struct +// using a DefaultColorTheme to pre-populate all the relevant values +func NewDefaultColorConfig() (*config.Config, error) { + colorTheme := NewDefaultColorTheme() + + yamlBytes, err := yaml.Marshal(colorTheme) + if err != nil { + return nil, err + } + + cfg, err := config.ParseYamlBytes(yamlBytes) + if err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/modules/docker/client.go b/modules/docker/client.go index c1944f06c0..d61e0a6323 100644 --- a/modules/docker/client.go +++ b/modules/docker/client.go @@ -41,13 +41,13 @@ func (widget *Widget) getSystemInfo() string { }{ { name: "name:", - value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.Name), + value: fmt.Sprintf("[%s]%s", widget.settings.common.Colors.RowTheme.EvenForeground, info.Name), }, { name: "version:", - value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.ServerVersion), + value: fmt.Sprintf("[%s]%s", widget.settings.common.Colors.RowTheme.EvenForeground, info.ServerVersion), }, { name: "root:", - value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.DockerRootDir), + value: fmt.Sprintf("[%s]%s", widget.settings.common.Colors.RowTheme.EvenForeground, info.DockerRootDir), }, { name: "containers:", @@ -57,15 +57,15 @@ func (widget *Widget) getSystemInfo() string { }, { name: "images:", - value: fmt.Sprintf("[%s]%d", widget.settings.common.Foreground, info.Images), + value: fmt.Sprintf("[%s]%d", widget.settings.common.Colors.RowTheme.EvenForeground, info.Images), }, { name: "volumes:", - value: fmt.Sprintf("[%s]%v", widget.settings.common.Foreground, len(diskUsage.Volumes)), + value: fmt.Sprintf("[%s]%v", widget.settings.common.Colors.RowTheme.EvenForeground, len(diskUsage.Volumes)), }, { name: "memory limit:", - value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, humanize.Bytes(uint64(info.MemTotal))), + value: fmt.Sprintf("[%s]%s", widget.settings.common.Colors.RowTheme.EvenForeground, humanize.Bytes(uint64(info.MemTotal))), }, { name: "disk usage:", @@ -76,19 +76,19 @@ func (widget *Widget) getSystemInfo() string { [%s]* [::b]total: [%s]%s[::-] `, widget.settings.labelColor, - widget.settings.common.Foreground, + widget.settings.common.Colors.RowTheme.EvenForeground, humanize.Bytes(uint64(duContainer)), widget.settings.labelColor, - widget.settings.common.Foreground, + widget.settings.common.Colors.RowTheme.EvenForeground, humanize.Bytes(uint64(duImg)), widget.settings.labelColor, - widget.settings.common.Foreground, + widget.settings.common.Colors.RowTheme.EvenForeground, humanize.Bytes(uint64(duVol)), widget.settings.labelColor, - widget.settings.common.Foreground, + widget.settings.common.Colors.RowTheme.EvenForeground, humanize.Bytes(uint64(duContainer+duImg+duVol))), }, } diff --git a/modules/feedreader/widget.go b/modules/feedreader/widget.go index 3fa40f1833..5648684b12 100644 --- a/modules/feedreader/widget.go +++ b/modules/feedreader/widget.go @@ -140,7 +140,7 @@ func (widget *Widget) content() (string, string, bool) { // Grays out viewed items in the list, while preserving background highlighting when selected rowColor = "gray" if idx == widget.Selected { - rowColor = fmt.Sprintf("gray:%s", widget.settings.common.Colors.HighlightBack) + rowColor = fmt.Sprintf("gray:%s", widget.settings.common.Colors.RowTheme.HighlightedBackground) } } diff --git a/modules/todo/display.go b/modules/todo/display.go index ca577aeea8..de7efe706a 100644 --- a/modules/todo/display.go +++ b/modules/todo/display.go @@ -49,8 +49,8 @@ func (widget *Widget) formattedItemLine(idx int, item *checklist.ChecklistItem, } if widget.View.HasFocus() && (item == selectedItem) { - foreColor = widget.settings.common.Colors.HighlightFore - backColor = widget.settings.common.Colors.HighlightBack + foreColor = widget.settings.common.Colors.RowTheme.HighlightedForeground + backColor = widget.settings.common.Colors.RowTheme.HighlightedBackground } row := fmt.Sprintf( diff --git a/modules/zendesk/widget.go b/modules/zendesk/widget.go index cdb8c1d787..286a4fb2b1 100644 --- a/modules/zendesk/widget.go +++ b/modules/zendesk/widget.go @@ -74,7 +74,7 @@ func (widget *Widget) content() (string, string, bool) { func (widget *Widget) format(ticket Ticket, idx int) string { textColor := widget.settings.common.Colors.Background if idx == widget.GetSelected() { - textColor = widget.settings.common.Colors.BorderFocused + textColor = widget.settings.common.Colors.BorderTheme.Focused } requesterName := widget.parseRequester(ticket) diff --git a/view/bargraph.go b/view/bargraph.go index 12706dc817..78764b6e43 100644 --- a/view/bargraph.go +++ b/view/bargraph.go @@ -107,12 +107,13 @@ func (widget *BarGraph) TextView() *tview.TextView { func (widget *BarGraph) createView(bordered bool) *tview.TextView { view := tview.NewTextView() - view.SetBackgroundColor(wtf.ColorFor(widget.commonSettings.Colors.Background)) + // view.SetBackgroundColor(wtf.ColorFor(widget.commonSettings.Colors.Background)) + view.SetBackgroundColor(wtf.ColorFor(widget.commonSettings.Colors.WidgetTheme.Background)) view.SetBorder(bordered) view.SetBorderColor(wtf.ColorFor(widget.BorderColor())) view.SetDynamicColors(true) view.SetTitle(widget.ContextualTitle(widget.CommonSettings().Title)) - view.SetTitleColor(wtf.ColorFor(widget.commonSettings.Colors.Title)) + view.SetTitleColor(wtf.ColorFor(widget.commonSettings.Colors.TextTheme.Title)) view.SetWrap(false) return view diff --git a/view/base.go b/view/base.go index 78c3dca75f..de62c85a76 100644 --- a/view/base.go +++ b/view/base.go @@ -49,10 +49,10 @@ func (base *Base) Bordered() bool { func (base *Base) BorderColor() string { if base.Focusable() { - return base.commonSettings.Colors.BorderFocusable + return base.commonSettings.Colors.BorderTheme.Focusable } - return base.commonSettings.Colors.BorderNormal + return base.commonSettings.Colors.BorderTheme.Unfocusable } func (base *Base) CommonSettings() *cfg.Common { diff --git a/view/text_widget.go b/view/text_widget.go index 41f96a9bb7..176bda8849 100644 --- a/view/text_widget.go +++ b/view/text_widget.go @@ -44,12 +44,12 @@ func (widget *TextWidget) Redraw(data func() (string, string, bool)) { func (widget *TextWidget) createView(bordered bool) *tview.TextView { view := tview.NewTextView() - view.SetBackgroundColor(wtf.ColorFor(widget.commonSettings.Colors.Background)) + view.SetBackgroundColor(wtf.ColorFor(widget.commonSettings.Colors.WidgetTheme.Background)) view.SetBorder(bordered) view.SetBorderColor(wtf.ColorFor(widget.BorderColor())) view.SetDynamicColors(true) - view.SetTextColor(wtf.ColorFor(widget.commonSettings.Colors.Text)) - view.SetTitleColor(wtf.ColorFor(widget.commonSettings.Colors.Title)) + view.SetTextColor(wtf.ColorFor(widget.commonSettings.Colors.TextTheme.Text)) + view.SetTitleColor(wtf.ColorFor(widget.commonSettings.Colors.TextTheme.Title)) view.SetWrap(false) return view