diff --git a/Makefile b/Makefile
index 483e10a..ba030dc 100644
--- a/Makefile
+++ b/Makefile
@@ -9,4 +9,4 @@ remove:
pamac-installer --remove tromjaro-theme-switcher
clean:
- $(RM) -rf src/ pkg/ icons.zip *.tar.zst
+ $(RM) -rf src/ pkg/ icons.tar.gz *.tar.zst
diff --git a/PKGBUILD b/PKGBUILD
index 670e90f..bf5932f 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -23,7 +23,7 @@ options=(!strip)
source=("themeSwitcher.nim"
"tromjaro-theme-switcher.desktop"
"tromjaro-theme-switcher.svg"
- "icons.zip::https://www.drive.tromsite.com/s/zFtCp3SkZ4NpKix/download")
+ "icons.tar.gz::https://www.drive.tromsite.com/s/ysM33nJAkpro85b/download/icons.tar.gz")
sha256sums=('SKIP'
'SKIP'
'SKIP'
@@ -34,29 +34,35 @@ prepare() {
mkdir -p "$HOME"/.choosenim
touch "$HOME"/.choosenim/analytics
}
- echo 'Install Nim if not already installed:'
- choosenim stable
- echo 'Update Nim to the latest stable release:'
- choosenim update stable
+ echo 'Install Nim if not already installed:'
+ choosenim stable
+ echo 'Update Nim to the latest stable release:'
+ choosenim update stable
echo 'Refresh nimble package list:'
- "$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim refresh
- echo 'Install owlkettle from the latest git commit:'
- "$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim install owlkettle
+ "$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim refresh
+ echo 'Install owlkettle from the latest git commit:'
+ "$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim install owlkettle
}
build(){
- echo 'Compile themeSwitcher.nim for release build:'
- "$HOME"/.nimble/bin/nim c -d:release --out:${srcdir}/themeSwitcher ${srcdir}/themeSwitcher.nim
+ echo 'Compile themeSwitcher.nim for release build:'
+ "$HOME"/.nimble/bin/nim c -d:release --out:${srcdir}/themeSwitcher ${srcdir}/themeSwitcher.nim
}
package() {
- # copy icons
- install -d ${pkgdir}/usr/share/tromjaro-theme-switcher/icons
- install -Dm644 ${srcdir}/icons/* ${pkgdir}/usr/share/tromjaro-theme-switcher/icons
+ # copy icons
+ install -d ${pkgdir}/usr/share/tromjaro-theme-switcher/icons/Styles
+ install -Dm644 ${srcdir}/icons/Styles/* ${pkgdir}/usr/share/tromjaro-theme-switcher/icons/Styles
- # copy executables
- install -Dm644 ${srcdir}/tromjaro-theme-switcher.desktop ${pkgdir}/usr/share/applications/tromjaro-theme-switcher.desktop
- install -Dm755 ${srcdir}/themeSwitcher ${pkgdir}/usr/bin/tromjaro-theme-switcher
+ for source_dir in "${srcdir}/icons/Accent Colors"/*; do
+ dest_dir="${pkgdir}/usr/share/tromjaro-theme-switcher/icons/Accent Colors/${source_dir##*/}"
+ install -d "$dest_dir"
+ install -Dm644 "$source_dir"/* "$dest_dir"
+ done
- # copy the icon
- install -d ${pkgdir}/usr/share/icons/hicolor/scalable/apps
- install -Dm644 ${srcdir}/tromjaro-theme-switcher.svg ${pkgdir}/usr/share/icons/hicolor/scalable/apps
+ # copy executables
+ install -Dm644 ${srcdir}/tromjaro-theme-switcher.desktop ${pkgdir}/usr/share/applications/tromjaro-theme-switcher.desktop
+ install -Dm755 ${srcdir}/themeSwitcher ${pkgdir}/usr/bin/tromjaro-theme-switcher
+
+ # copy the icon
+ install -d ${pkgdir}/usr/share/icons/hicolor/scalable/apps
+ install -Dm644 ${srcdir}/tromjaro-theme-switcher.svg ${pkgdir}/usr/share/icons/hicolor/scalable/apps
}
diff --git a/themeSwitcher.nim b/themeSwitcher.nim
index 37406a5..34156ab 100644
--- a/themeSwitcher.nim
+++ b/themeSwitcher.nim
@@ -1,19 +1,206 @@
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/os import symlinkExists, getConfigDir, `/`
+from std/strutils import split, endsWith, contains
from std/options import Option, some, get, isNone
-from std/strutils import split, endsWith
from std/strformat import fmt
import owlkettle
const
# Set the directory path where icons are stored
iconsDir = "/usr/share/tromjaro-theme-switcher/icons"
+ styleIconsDir = iconsDir / "Styles"
+ accentIconsDir = iconsDir / "Accent Colors"
# GTK CSS for overriding the default icon size of buttons
- gtkCSS = "button { -gtk-icon-size: 85px; }"
- applicationID = "com.tromjaro.ThemeSwitcher"
- themeColors = ["Grey", "Pink", "Green", "Orange", "Purple", "Yellow", "Teal"]
- themeStyles = ["Light", "Nord", "Dark", "Dark-Nord"]
+ gtkCSS = ".style-button { -gtk-icon-size: 100px; } .accent-button { -gtk-icon-size: 30px; }"
+ 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 = @[styleIconsDir]
+
+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)
+
+# Highlight current theme button
+var currentTheme = getCurrentTheme()
+
+var
+ oldConfigDir: Option[string]
+ configDirChanged: bool
+
+# Prevent loading GTK theme from ~/.config/gtk-4.0 directory when it is a symlink
+if symlinkExists(getConfigDir() / "gtk-4.0"):
+ if existsEnv("XDG_CONFIG_HOME"):
+ oldConfigDir = some(getEnv("XDG_CONFIG_HOME"))
+ putEnv("XDG_CONFIG_HOME", "/dev/null")
+ configDirChanged = true
+
+# Display the GTK-4 GUI using owlkettle
+viewable App:
+ hooks:
+ build:
+ # Reset the user's XDG_CONFIG_HOME variable back to what it was before
+ if configDirChanged == true:
+ if oldConfigDir.isNone():
+ delEnv("XDG_CONFIG_HOME")
+ else:
+ 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 = (0, 0)
+ 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))
+ 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))
+ # 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."
+
+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}"
+
+ result = gui:
+ Button:
+ icon = fmt"Colloid{shade}{style}"
+ tooltip = if shadeName == "": styleName else: fmt"{shadeName}-{styleName}"
+ style = if (shadeName, styleName) == (currentTheme.shade, currentTheme.style):
+ [StyleClass("style-button"), ButtonSuggested]
+ else:
+ [StyleClass("style-button"), ButtonFlat]
+
+ proc clicked() =
+ setTheme(theme)
+ # Highlight this button
+ currentTheme.shade = shadeName
+ currentTheme.style = styleName
+ if currentTheme.color == "":
+ currentTheme.color = "Blue"
+
+proc makeAccentButton(accentColor: string): Widget =
+ let
+ 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}"
+
+ result = gui:
+ Button:
+ icon = fmt"{accentColor}{style}{shade}"
+ tooltip = accentColor
+ style = if accentColor == currentTheme.color:
+ [StyleClass("accent-button"), ButtonSuggested]
+ else:
+ [StyleClass("accent-button"), ButtonFlat]
+
+ proc clicked() =
+ setTheme(theme)
+ # 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
@@ -40,7 +227,7 @@ 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.endsWith("-Dark-Nord"):
+ if themeName.endsWith("-Dark") or themeName.contains("-Dark-"):
setIconTheme("zafiro-dark")
else:
setIconTheme("zafiro")
@@ -52,80 +239,5 @@ proc setTheme(themeName: string) =
args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName])
# Send notification about the theme change
- sendNotification(applicationID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
- icon=fmt"{iconsDir}/{themeName}.svg")
-
-
-var
- oldConfigDir: Option[string]
- configDirChanged: bool
-
-# Prevent loading GTK theme from ~/.config/gtk-4.0 directory when it is a symlink
-if symlinkExists(getConfigDir() / "gtk-4.0"):
- if existsEnv("XDG_CONFIG_HOME"):
- oldConfigDir = some(getEnv("XDG_CONFIG_HOME"))
- putEnv("XDG_CONFIG_HOME", "/dev/null")
- configDirChanged = true
-
-# Display the GTK-4 GUI using owlkettle
-viewable App:
- highlightButton: array[2, string]
- hooks:
- build:
- # Reset the user's XDG_CONFIG_HOME variable back to what it was before
- if configDirChanged == true:
- if oldConfigDir.isNone():
- delEnv("XDG_CONFIG_HOME")
- else:
- putEnv("XDG_CONFIG_HOME", get(oldConfigDir))
-
- let currentTheme: string = execProcess("/usr/bin/xfconf-query",
- args=["--channel=xsettings", "--property=/Net/ThemeName"],
- options={})[0 .. ^2]
-
- let currentThemeSplit: seq[string] = currentTheme.split('-', 2)
-
- if currentThemeSplit.len() < 3 or currentThemeSplit[0] != "Colloid":
- return
-
- let currentThemeColor = currentThemeSplit[1]
- let currentThemeStyle = currentThemeSplit[2]
-
- # Highlight current theme button
- state.highlightButton = [currentThemeColor, currentThemeStyle]
-
-method view(app: AppState): Widget =
- result = gui:
- Window:
- title = "TROMjaro Theme Switcher"
- # Shrink window to the smallest size
- defaultSize = (0, 0)
- iconName = "tromjaro-theme-switcher"
- # Vertical box
- Box(orient = OrientY, margin = 7, spacing = 5):
- 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."
- for themeStyle in themeStyles:
- # Horizontal box
- Box(orient = OrientX, spacing = 5):
- for themeColor in themeColors:
- Button {.vAlign: AlignCenter, hAlign: AlignCenter.}:
- icon = fmt"Colloid-{themeColor}-{themeStyle}"
- # Teal-Dark-Nord theme will have "(default)" added to its tooltip
- tooltip = if (themeColor, themeStyle) == ("Teal", "Dark-Nord"):
- fmt"{themeColor}-{themeStyle} (default)"
- else:
- fmt"{themeColor}-{themeStyle}"
- style = if [themeColor, themeStyle] == app.highlightButton:
- ButtonSuggested
- else:
- ButtonFlat
- proc clicked() =
- setTheme(fmt"Colloid-{themeColor}-{themeStyle}")
- # Highlight this button
- app.highlightButton = [themeColor, themeStyle]
-
-brew(applicationID, gui(App()), icons=[iconsDir], stylesheets=[newStylesheet(gtkCSS)])
+ sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
+ icon=appLogo)