diff --git a/themeSwitcher.nim b/themeSwitcher.nim
index 466bd3e..a02eba7 100644
--- a/themeSwitcher.nim
+++ b/themeSwitcher.nim
@@ -1,10 +1,9 @@
-from std/osproc import execProcess, ProcessOption, startProcess, waitForExit, close
from std/os import symlinkExists, getConfigDir, walkDirs, `/`
from std/envvars import existsEnv, getEnv, delEnv, putEnv
-from std/strutils import split, endsWith, contains
from std/options import Option, some, get, isNone
from std/strformat import fmt
-import owlkettle
+import pkg/owlkettle
+import ./themes
const
# Set the directory path where icons are stored
@@ -25,35 +24,21 @@ const
padding: 0.4em;
border-radius: 50%;
}
-
-#.accent-button.suggested-action {
-# outline-color: black;
-# outline-width: 0.05em;
-# outline-offset: -0.45em;
-}"""
- appID = "com.tromjaro.ThemeSwitcher"
- appLogo = "tromjaro-theme-switcher"
- themeShades = ["Light", "", "Dark"]
- themeStyles = ["Default", "Nord", "Dracula", "Catppuccin", "Everforest", "Gruvbox"]
- accentColors = ["Blue", "Red", "Purple", "Pink", "Teal", "Green", "Yellow", "Orange", "Grey"]
+"""
var iconsDirs: seq[string]
for dir in walkDirs(accentIconsDir / "*"):
iconsDirs.add(dir)
-type Theme = tuple[shade: string, style: string, color: string]
-
# Function prototypes
-proc getCurrentTheme(): Theme
proc makeThemeButton(shadeName: string, styleName: string): Widget
proc makeAccentButton(accentColor: string): Widget
-proc runCommand(command: string, args: openArray[string]): bool
-proc setIconTheme(iconName: string)
-proc enableDarkPanels(): bool
-proc setTheme(themeName: string)
+proc accentButtons(): Widget
+proc themeButtons(): Widget
+proc mainGUI(): Widget
-# Highlight current theme button
+# Keep track of current theme button
var currentTheme = getCurrentTheme()
var
@@ -68,6 +53,7 @@ if symlinkExists(getConfigDir() / "gtk-4.0"):
configDirChanged = true
# Display the GTK-4 GUI using owlkettle
+
viewable App:
hooks:
build:
@@ -79,106 +65,19 @@ viewable App:
putEnv("XDG_CONFIG_HOME", get(oldConfigDir))
method view(app: AppState): Widget =
- result = gui:
- Window:
- title = "TROMjaro Theme Switcher"
- # Shrink window to the smallest size
- defaultSize = (1, 1)
- iconName = appLogo
- # Vertical box
- Box(orient = OrientY, margin = 13, spacing = 10):
- Label:
- useMarkup=true
- text="STYLE"
- # Vertical box
- Box(orient = OrientY, spacing = 5):
- for shadeName in themeShades:
- # Horizontal box
- Box(orient = OrientX, spacing = 5):
- for styleName in themeStyles:
- insert(makeThemeButton(shadeName, styleName)) {.vAlign: AlignCenter, hAlign: AlignCenter.}
- Separator(margin = Margin(top: 5)) {.vAlign: AlignCenter.}
- Label:
- useMarkup=true
- text="ACCENT COLOR"
- # Horizontal box
- Box(orient = OrientX, spacing = 3):
- for accentColor in accentColors:
- insert(makeAccentButton(accentColor)) {.vAlign: AlignCenter, hAlign: AlignCenter.}
- Separator(margin = Margin(top: 12)) {.vAlign: AlignCenter.}
- # Vertical box
- Box(orient = OrientY):
- Label:
- text="A Theme Switcher for TROMjaro's default theme-set (Colloid) and icon-set (Zafiro)."
- Label {.vAlign: AlignStart.}:
- useMarkup = true
- text="NOTE: Some apps need to be reopened for the theme to be applied."
+ result = mainGUI()
brew(appID, gui(App()), icons=iconsDirs, stylesheets=[newStylesheet(gtkCSS)])
# Function declarations
-proc getCurrentTheme(): Theme =
- let currentThemeString = execProcess("/usr/bin/xfconf-query",
- args=["--channel=xsettings", "--property=/Net/ThemeName"],
- options={})[0 .. ^2]
-
- let words = currentThemeString.split('-')
- if words[0] != "Colloid":
- return
- var currentTheme: Theme = ("", "Default", "Blue")
-
- case len(words):
- of 1: discard
-
- of 2:
- let word1 = words[1]
- if word1 in accentColors:
- currentTheme.color = word1
- elif word1 in themeShades:
- currentTheme.shade = word1
- elif word1 in themeStyles:
- currentTheme.style = word1
- else:
- return
-
- of 3:
- let
- word1 = words[1]
- word2 = words[2]
- if (word1 in accentColors) and (word2 in themeShades):
- currentTheme.color = word1
- currentTheme.shade = word2
- elif (word1 in themeShades) and (word2 in themeStyles):
- currentTheme.shade = word1
- currentTheme.style = word2
- else:
- return
-
- of 4:
- let
- word1 = words[1]
- word2 = words[2]
- word3 = words[3]
- if (word1 in accentColors) and (word2 in themeShades) and (word3 in themeStyles):
- currentTheme.color = word1
- currentTheme.shade = word2
- currentTheme.style = word3
- else:
- return
-
- else:
- return
-
- result = currentTheme
-
proc makeThemeButton(shadeName: string, styleName: string): Widget =
let
shade = if shadeName == "": "" else: fmt"-{shadeName}"
style = if styleName == "Default": "" else: fmt"-{styleName}"
color = if currentTheme.color in ["Blue", ""]: "" else: fmt"-{currentTheme.color}"
- theme = fmt"Colloid{color}{shade}{style}"
+ themeString = fmt"Colloid{color}{shade}{style}"
result = gui:
Button:
@@ -191,7 +90,7 @@ proc makeThemeButton(shadeName: string, styleName: string): Widget =
[StyleClass("style-button"), ButtonFlat]
proc clicked() =
- setTheme(theme)
+ setTheme(themeString)
# Highlight this button
currentTheme.shade = shadeName
currentTheme.style = styleName
@@ -203,7 +102,7 @@ proc makeAccentButton(accentColor: string): Widget =
shade = if currentTheme.shade == "": "" else: fmt"-{currentTheme.shade}"
style = if currentTheme.style in ["Default", ""]: "" else: fmt"-{currentTheme.style}"
color = if accentColor == "Blue": "" else: fmt"-{accentColor}"
- theme = fmt"Colloid{color}{shade}{style}"
+ themeString = fmt"Colloid{color}{shade}{style}"
result = gui:
Button:
@@ -215,48 +114,56 @@ proc makeAccentButton(accentColor: string): Widget =
[StyleClass("accent-button"), ButtonFlat]
proc clicked() =
- setTheme(theme)
+ setTheme(themeString)
# Highlight this button
currentTheme.color = accentColor
if currentTheme.style == "":
currentTheme.style = "Default"
-proc runCommand(command: string, args: openArray[string]): bool =
- ## This will run a command with the given args and return true upon success
- let process = startProcess(command, args=args, options={poParentStreams})
- result = process.waitForExit() == 0
- process.close()
+proc themeButtons(): Widget =
+ gui:
+ # Vertical box
+ Box(orient = OrientY, spacing = 5):
+ for shadeName in themeShades:
+ # Horizontal box
+ Box(orient = OrientX, spacing = 5):
+ for styleName in themeStyles:
+ let themeButton = makeThemeButton(shadeName, styleName)
+ insert(themeButton) {.vAlign: AlignCenter, hAlign: AlignCenter.}
-proc setIconTheme(iconName: string) =
- # Change icon theme in XFCE
- discard runCommand("/usr/bin/xfconf-query",
- args=["--channel=xsettings", "--property=/Net/IconThemeName", "--create", "--type=string", "--set", iconName])
+proc accentButtons(): Widget =
+ gui:
+ # Horizontal box
+ Box(orient = OrientX, spacing = 3):
+ for accentColor in accentColors:
+ let accentButton = makeAccentButton(accentColor)
+ insert(accentButton) {.vAlign: AlignCenter, hAlign: AlignCenter.}
-proc enableDarkPanels(): bool =
- # Return if dark panels is already enabled
- if execProcess("/usr/bin/xfconf-query",
- args=["--channel=xfce4-panel", "--property=/panels/dark-mode"], options={}) == "true\n":
- return
- # Try to enable it and return true upon success
- result = runCommand("/usr/bin/xfconf-query",
- args=["--channel=xfce4-panel", "--property=/panels/dark-mode", "--create", "--type=bool", "--set=true"])
-
-proc setTheme(themeName: string) =
-
- var panelNotification: string
-
- # Set the icon theme and panel color according to the chosen theme
- if themeName.endsWith("-Dark") or themeName.contains("-Dark-"):
- setIconTheme("zafiro-dark")
- else:
- setIconTheme("zafiro")
- if enableDarkPanels():
- panelNotification = " with dark panels"
-
- # Change the main theme to the chosen one
- discard runCommand("/usr/bin/xfconf-query",
- args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName])
-
- # Send notification about the theme change
- sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
- icon=appLogo)
+proc mainGUI(): Widget =
+ gui:
+ Window:
+ title = "TROMjaro Theme Switcher"
+ # Shrink window to the smallest size
+ defaultSize = (1, 1)
+ iconName = appLogo
+ # Vertical box
+ Box(orient = OrientY, margin = 13, spacing = 10):
+ Label:
+ useMarkup=true
+ text="STYLE"
+ # Theme buttons
+ insert(themeButtons())
+ Separator(margin = Margin(top: 5)) {.vAlign: AlignCenter.}
+ Label:
+ useMarkup=true
+ text="ACCENT COLOR"
+ # Accent buttons
+ insert(accentButtons())
+ Separator(margin = Margin(top: 12)) {.vAlign: AlignCenter.}
+ # Vertical box
+ Box(orient = OrientY):
+ Label:
+ text="A Theme Switcher for TROMjaro's default theme-set (Colloid) and icon-set (Zafiro)."
+ Label {.vAlign: AlignStart.}:
+ useMarkup = true
+ text="NOTE: Some apps need to be reopened for the theme to be applied."
diff --git a/themes.nim b/themes.nim
new file mode 100644
index 0000000..6dd741e
--- /dev/null
+++ b/themes.nim
@@ -0,0 +1,111 @@
+from std/osproc import execProcess, ProcessOption, startProcess, waitForExit, close
+from std/strutils import split, endsWith, contains
+from std/strformat import fmt
+import pkg/owlkettle
+
+type Theme = tuple[color, shade, style: string]
+
+const
+ themeShades* = ["Light", "", "Dark"]
+ themeStyles* = ["Default", "Nord", "Dracula", "Catppuccin", "Everforest", "Gruvbox"]
+ accentColors* = ["Blue", "Red", "Purple", "Pink", "Teal", "Green", "Yellow", "Orange", "Grey"]
+ appID* = "com.tromjaro.ThemeSwitcher"
+ appLogo* = "tromjaro-theme-switcher"
+
+proc getCurrentTheme*(): Theme =
+ let currentThemeString = execProcess("/usr/bin/xfconf-query",
+ args=["--channel=xsettings", "--property=/Net/ThemeName"],
+ options={})[0 .. ^2]
+
+ # Split the theme string into words
+ let words = currentThemeString.split('-')
+ if words[0] != "Colloid":
+ return
+ var currentTheme: Theme = (color: "Blue", shade: "", style: "Default")
+
+ case len(words):
+ of 1: discard
+
+ # Match against Colloid-Color, Colloid-Shade, Colloid-Style
+ of 2:
+ let word1 = words[1]
+ if word1 in accentColors:
+ currentTheme.color = word1
+ elif word1 in themeShades:
+ currentTheme.shade = word1
+ elif word1 in themeStyles:
+ currentTheme.style = word1
+ else:
+ return
+
+ # Match against Colloid-Color-Shade, Colloid-Shade-Style
+ of 3:
+ let
+ word1 = words[1]
+ word2 = words[2]
+ if (word1 in accentColors) and (word2 in themeShades):
+ currentTheme.color = word1
+ currentTheme.shade = word2
+ elif (word1 in themeShades) and (word2 in themeStyles):
+ currentTheme.shade = word1
+ currentTheme.style = word2
+ else:
+ return
+
+ # Match against Colloid-Color-Shade-Style
+ of 4:
+ let
+ word1 = words[1]
+ word2 = words[2]
+ word3 = words[3]
+ if (word1 in accentColors) and (word2 in themeShades) and (word3 in themeStyles):
+ currentTheme.color = word1
+ currentTheme.shade = word2
+ currentTheme.style = word3
+ else:
+ return
+
+ else:
+ return
+
+ return currentTheme
+
+proc runCommand(command: string, args: openArray[string]): bool =
+ ## This will run a command with the given args and return true upon success
+ let process = startProcess(command, args=args, options={poParentStreams})
+ result = process.waitForExit() == 0
+ process.close()
+
+proc setIconTheme(iconName: string) =
+ # Change icon theme in XFCE
+ discard runCommand("/usr/bin/xfconf-query",
+ args=["--channel=xsettings", "--property=/Net/IconThemeName", "--create", "--type=string", "--set", iconName])
+
+proc enableDarkPanels(): bool =
+ # Return if dark panels is already enabled
+ if execProcess("/usr/bin/xfconf-query",
+ args=["--channel=xfce4-panel", "--property=/panels/dark-mode"], options={}) == "true\n":
+ return
+ # Try to enable it and return true upon success
+ result = runCommand("/usr/bin/xfconf-query",
+ args=["--channel=xfce4-panel", "--property=/panels/dark-mode", "--create", "--type=bool", "--set=true"])
+
+proc setTheme*(themeName: string) =
+
+ var panelNotification: string
+
+ # Set the icon theme and panel color according to the chosen theme
+ if themeName.endsWith("-Dark") or themeName.contains("-Dark-"):
+ setIconTheme("zafiro-dark")
+ else:
+ setIconTheme("zafiro")
+ if enableDarkPanels():
+ panelNotification = " with dark panels"
+
+ # Change the main theme to the chosen one
+ discard runCommand("/usr/bin/xfconf-query",
+ args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName])
+
+ # Send notification about the theme change
+ sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
+ icon=appLogo)