mirror of
https://github.com/obsqrbtz/clrsync.git
synced 2026-04-09 12:37:41 +03:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 613c2c80f5 | |||
| 1a1747a472 | |||
| 57c3c55a94 | |||
| d4ff415f45 | |||
| 4c0502d8ee | |||
| 0acb36445f | |||
| b08ba4d754 | |||
| 231e9f0176 | |||
| b98761a172 | |||
| 92b06a9e0c | |||
| 019b0db522 | |||
| 58eff4d97e | |||
| b4ca5e1912 | |||
| 899a5d50c4 | |||
| 2813a8bd05 | |||
| e6bac8e220 | |||
| 5bb8a687ea | |||
| 10516212bf | |||
| 89888adf8d | |||
| c58ff17289 | |||
| ef0854aa39 | |||
| 1c2486d476 | |||
| d4c563f585 | |||
| f7c290110e | |||
| 659c5f28e5 | |||
| cd817446b0 | |||
| a5d6503305 | |||
| 8a2b224fd3 | |||
| 4b4af0f8fe | |||
| d40b436461 | |||
| 8d73df8fb8 | |||
| c4bab31e3b | |||
| 8e65c52adc | |||
| 164e6f9ac0 | |||
| d951f8d9c8 | |||
| 794193209b | |||
| 2a10aa0226 | |||
| 8caddbbb80 | |||
| c1474ccf0c | |||
| db4cc383d4 | |||
| 52a4b096a5 | |||
| 1e2c7faa38 | |||
| cc4d8f9dbd | |||
| ad92d366b2 | |||
| e44d441453 | |||
| bb1c14d566 | |||
| 2714ae51b7 | |||
| 881bc6e739 | |||
| 65e54f9c0b | |||
| 2c452cb395 | |||
| 2a81fa7b1b | |||
| cf8c93e31b | |||
| 8770dbcef8 | |||
| 236f948fcf | |||
| 3350c41ccc | |||
| 44a34eb216 | |||
| 7535bb51ce | |||
| 4c135edc95 | |||
| 813396920c | |||
| 0cee625e8b | |||
| dfbcdb6e1c | |||
| 23a6a9245d | |||
| 93ab7bef81 | |||
| 792aed7439 | |||
| 38318f0205 | |||
| 8a9695f3b8 | |||
| dd38d08914 | |||
| f55d224fab | |||
| 931277291b | |||
| d8baae2ae9 | |||
| 5dafb6ce8c | |||
| 6c0fffafd3 | |||
| ae5ce52d1d | |||
| f968e23541 | |||
| 6cc3de8e44 | |||
| dbaf693fee | |||
| 2220bfb5de | |||
| 264fc6ce54 | |||
| 33bca75990 | |||
| 1afb9428bd | |||
| f263e31d7d | |||
| 5d87e8df3c | |||
| f39d22b5e3 | |||
| 082d0db47b | |||
| 60d6992850 |
45
.github/workflows/Test PKGBUILD-git.yml
vendored
Normal file
45
.github/workflows/Test PKGBUILD-git.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Test PKGBUILD-git
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
pull_request:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: archlinux:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup Arch
|
||||||
|
run: |
|
||||||
|
pacman -Sy --noconfirm --needed base-devel git sudo
|
||||||
|
useradd -m builder
|
||||||
|
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set permissions
|
||||||
|
run: chown -R builder:builder .
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
sudo -u builder bash -c '
|
||||||
|
cd AUR
|
||||||
|
makepkg -p PKGBUILD-git -si --noconfirm
|
||||||
|
'
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
clrsync_cli --help
|
||||||
|
pacman -Ql clrsync-git
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: clrsync-git
|
||||||
|
path: AUR/*.pkg.tar.zst
|
||||||
33
.github/workflows/Test flake.yml
vendored
Normal file
33
.github/workflows/Test flake.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: Test flake.nix
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
pull_request:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@v31
|
||||||
|
with:
|
||||||
|
extra_nix_config: |
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
|
||||||
|
- name: Build clrsync package
|
||||||
|
run: |
|
||||||
|
nix --extra-experimental-features "flakes nix-command" build .#packages.x86_64-linux.clrsync
|
||||||
|
|
||||||
|
- name: Enter devShell
|
||||||
|
run: |
|
||||||
|
nix --extra-experimental-features "flakes nix-command" develop .#default --command true
|
||||||
|
|
||||||
|
- name: Test clrsync CLI
|
||||||
|
run: |
|
||||||
|
nix --extra-experimental-features "flakes nix-command" run .#clrsync-cli -- --help
|
||||||
139
.github/workflows/publish-release.yml
vendored
Normal file
139
.github/workflows/publish-release.yml
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
name: Build and Release Packages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
outputs:
|
||||||
|
artifact-path: ${{ steps.upload.outputs.artifact-path }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install NSIS
|
||||||
|
run: choco install nsis --no-progress -y
|
||||||
|
|
||||||
|
- name: Setup MSVC
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
|
- name: Configure project
|
||||||
|
run: cmake -B build -S . -A x64
|
||||||
|
|
||||||
|
- name: Build project
|
||||||
|
run: cmake --build build --config Release
|
||||||
|
|
||||||
|
- name: Generate NSIS installer
|
||||||
|
run: cd build && cpack -G NSIS
|
||||||
|
|
||||||
|
- name: Upload installer
|
||||||
|
id: upload
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: windows-installer
|
||||||
|
path: build/*.exe
|
||||||
|
|
||||||
|
build-ubuntu:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
artifact-path: ${{ steps.upload.outputs.artifact-path }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y cmake build-essential git \
|
||||||
|
libglfw3-dev libfreetype6-dev libfontconfig1-dev \
|
||||||
|
libx11-dev libxrandr-dev libxi-dev libgtk-3-dev \
|
||||||
|
mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev \
|
||||||
|
libxinerama-dev libxcursor-dev libxkbcommon-dev
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_GLFW=OFF
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build --config Release
|
||||||
|
|
||||||
|
- name: Package DEB
|
||||||
|
run: cd build && cpack -G DEB
|
||||||
|
|
||||||
|
- name: Upload DEB
|
||||||
|
id: upload
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: deb-package
|
||||||
|
path: build/*.deb
|
||||||
|
|
||||||
|
build-fedora:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: fedora:latest
|
||||||
|
outputs:
|
||||||
|
artifact-path: ${{ steps.upload.outputs.artifact-path }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
dnf install -y cmake gcc gcc-c++ make rpm-build git \
|
||||||
|
glfw-devel freetype-devel fontconfig-devel \
|
||||||
|
libX11-devel libXrandr-devel libXi-devel \
|
||||||
|
mesa-libGL-devel mesa-libGLU-devel \
|
||||||
|
libXinerama-devel libXcursor-devel \
|
||||||
|
wayland-devel wayland-protocols-devel gtk3-devel
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_GLFW=ON
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build --config Release
|
||||||
|
|
||||||
|
- name: Package RPM
|
||||||
|
run: cd build && cpack -G RPM
|
||||||
|
|
||||||
|
- name: Upload RPM
|
||||||
|
id: upload
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: rpm-package
|
||||||
|
path: build/*.rpm
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: [build-windows, build-ubuntu, build-fedora]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Download Windows artifact
|
||||||
|
uses: actions/download-artifact@v6
|
||||||
|
with:
|
||||||
|
name: windows-installer
|
||||||
|
path: artifacts/
|
||||||
|
|
||||||
|
- name: Download DEB artifact
|
||||||
|
uses: actions/download-artifact@v6
|
||||||
|
with:
|
||||||
|
name: deb-package
|
||||||
|
path: artifacts/
|
||||||
|
|
||||||
|
- name: Download RPM artifact
|
||||||
|
uses: actions/download-artifact@v6
|
||||||
|
with:
|
||||||
|
name: rpm-package
|
||||||
|
path: artifacts/
|
||||||
|
|
||||||
|
- name: Create Release and Upload Assets
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
|
name: Release ${{ github.ref_name }}
|
||||||
|
artifacts: |
|
||||||
|
artifacts/*.exe
|
||||||
|
artifacts/*.deb
|
||||||
|
artifacts/*.rpm
|
||||||
32
.gitignore
vendored
32
.gitignore
vendored
@@ -3,16 +3,21 @@
|
|||||||
.vs
|
.vs
|
||||||
out
|
out
|
||||||
|
|
||||||
/build
|
build/
|
||||||
/builddir
|
build-msvc/
|
||||||
/build-*
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
cmake_install.cmake
|
||||||
|
Makefile
|
||||||
|
*.cmake
|
||||||
|
|
||||||
/subprojects/glfw-*
|
AUR/clrsync-git
|
||||||
/subprojects/imgui-*
|
AUR/pkg
|
||||||
/subprojects/sdl2-*
|
AUR/src
|
||||||
/subprojects/freetype-*
|
|
||||||
/subprojects/libpng-*
|
result
|
||||||
/subprojects/packagecache
|
result-*
|
||||||
|
.direnv/
|
||||||
|
|
||||||
*.log
|
*.log
|
||||||
*tar.zst
|
*tar.zst
|
||||||
@@ -22,3 +27,12 @@ out
|
|||||||
*.bak
|
*.bak
|
||||||
*.tmp
|
*.tmp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|||||||
28
.vscode/launch.json
vendored
28
.vscode/launch.json
vendored
@@ -5,18 +5,17 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "CLI",
|
"name": "Debug current target (GDB)",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/builddir/clrsync_cli",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--apply",
|
"--apply",
|
||||||
"--theme",
|
"--theme",
|
||||||
"dark"
|
"dark"
|
||||||
],
|
],
|
||||||
"preLaunchTask": "Build (meson)",
|
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/builddir",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
@@ -34,33 +33,20 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GUI",
|
"name": "Debug current target (LLDB)",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/builddir/clrsync_gui",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--apply",
|
"--apply",
|
||||||
"--theme",
|
"--theme",
|
||||||
"dark"
|
"dark"
|
||||||
],
|
],
|
||||||
"preLaunchTask": "Build (meson)",
|
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/builddir",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
"MIMode": "gdb",
|
"MIMode": "lldb",
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "Set Disassembly Flavor to Intel",
|
|
||||||
"text": "-gdb-set disassembly-flavor intel",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"C_Cpp.default.compileCommands": "/home/dan/src/clrsync/builddir/compile_commands.json",
|
|
||||||
"C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild",
|
|
||||||
"clangd.arguments": [
|
|
||||||
"--compile-commands-dir=${workspaceFolder}/builddir",
|
|
||||||
"--completion-style=detailed",
|
|
||||||
"--header-insertion=never"
|
|
||||||
],
|
|
||||||
}
|
|
||||||
22
.vscode/tasks.json
vendored
22
.vscode/tasks.json
vendored
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "cppbuild",
|
|
||||||
"label": "Build (meson)",
|
|
||||||
"command": "meson",
|
|
||||||
"args": [
|
|
||||||
"compile",
|
|
||||||
"-C",
|
|
||||||
"builddir"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2.0.0"
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,35 @@
|
|||||||
# Maintainer: Daniel Dada <dan@binarygoose.dev>
|
# Maintainer: Daniel Dada <dan@binarygoose.dev>
|
||||||
pkgname=clrsync
|
pkgname=clrsync
|
||||||
pkgver=0.1.2
|
pkgver=0.1.6
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Color scheme manager"
|
pkgdesc="Color scheme manager"
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
url="https://github.com/obsqrbtz/clrsync"
|
url="https://github.com/obsqrbtz/clrsync"
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
|
|
||||||
depends=(
|
depends=(
|
||||||
glfw-x11
|
glfw
|
||||||
freetype2
|
freetype2
|
||||||
fontconfig
|
fontconfig
|
||||||
|
mesa
|
||||||
|
libglvnd
|
||||||
|
libxcursor
|
||||||
|
gtk3
|
||||||
|
)
|
||||||
|
|
||||||
|
makedepends=(
|
||||||
|
cmake
|
||||||
|
glfw
|
||||||
libx11
|
libx11
|
||||||
libxrandr
|
libxrandr
|
||||||
libxi
|
libxi
|
||||||
mesa
|
|
||||||
libglvnd
|
|
||||||
libxinerama
|
libxinerama
|
||||||
libxcursor
|
libxcursor
|
||||||
|
wayland
|
||||||
|
wayland-protocols
|
||||||
|
gtk3
|
||||||
)
|
)
|
||||||
makedepends=('cmake')
|
|
||||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/obsqrbtz/clrsync/archive/refs/tags/v$pkgver.tar.gz")
|
source=("$pkgname-$pkgver.tar.gz::https://github.com/obsqrbtz/clrsync/archive/refs/tags/v$pkgver.tar.gz")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
@@ -26,6 +37,7 @@ build() {
|
|||||||
cd "$pkgname-$pkgver"
|
cd "$pkgname-$pkgver"
|
||||||
cmake -B build -S . \
|
cmake -B build -S . \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DUSE_SYSTEM_GLFW=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr
|
-DCMAKE_INSTALL_PREFIX=/usr
|
||||||
cmake --build build
|
cmake --build build
|
||||||
}
|
}
|
||||||
@@ -33,5 +45,5 @@ build() {
|
|||||||
package() {
|
package() {
|
||||||
cd "$pkgname-$pkgver"
|
cd "$pkgname-$pkgver"
|
||||||
DESTDIR="$pkgdir" cmake --install build
|
DESTDIR="$pkgdir" cmake --install build
|
||||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||||
}
|
}
|
||||||
55
AUR/PKGBUILD-git
Normal file
55
AUR/PKGBUILD-git
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Maintainer: Daniel Dada <dan@binarygoose.dev>
|
||||||
|
pkgname=clrsync-git
|
||||||
|
pkgver=r22.d8baae2
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Color scheme manager (git version)"
|
||||||
|
arch=('x86_64')
|
||||||
|
url="https://github.com/obsqrbtz/clrsync"
|
||||||
|
license=('MIT')
|
||||||
|
depends=(
|
||||||
|
glfw
|
||||||
|
freetype2
|
||||||
|
fontconfig
|
||||||
|
mesa
|
||||||
|
libglvnd
|
||||||
|
libxcursor
|
||||||
|
gtk3
|
||||||
|
)
|
||||||
|
|
||||||
|
makedepends=(
|
||||||
|
cmake
|
||||||
|
git
|
||||||
|
glfw
|
||||||
|
libx11
|
||||||
|
libxrandr
|
||||||
|
libxi
|
||||||
|
libxinerama
|
||||||
|
libxcursor
|
||||||
|
wayland
|
||||||
|
wayland-protocols
|
||||||
|
gtk3
|
||||||
|
)
|
||||||
|
provides=('clrsync')
|
||||||
|
conflicts=('clrsync')
|
||||||
|
source=("$pkgname::git+https://github.com/obsqrbtz/clrsync.git")
|
||||||
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd "$srcdir/$pkgname"
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$srcdir/$pkgname"
|
||||||
|
cmake -B build -S . \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DUSE_SYSTEM_GLFW=ON \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
cmake --build build
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "$srcdir/$pkgname"
|
||||||
|
DESTDIR="$pkgdir" cmake --install build
|
||||||
|
install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||||
|
}
|
||||||
@@ -6,19 +6,30 @@ pkgdesc="Color scheme manager"
|
|||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
url="https://github.com/obsqrbtz/clrsync"
|
url="https://github.com/obsqrbtz/clrsync"
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
|
|
||||||
depends=(
|
depends=(
|
||||||
glfw-x11
|
glfw
|
||||||
freetype2
|
freetype2
|
||||||
fontconfig
|
fontconfig
|
||||||
|
mesa
|
||||||
|
libglvnd
|
||||||
|
libxcursor
|
||||||
|
gtk3
|
||||||
|
)
|
||||||
|
|
||||||
|
makedepends=(
|
||||||
|
cmake
|
||||||
|
glfw
|
||||||
libx11
|
libx11
|
||||||
libxrandr
|
libxrandr
|
||||||
libxi
|
libxi
|
||||||
mesa
|
|
||||||
libglvnd
|
|
||||||
libxinerama
|
libxinerama
|
||||||
libxcursor
|
libxcursor
|
||||||
|
wayland
|
||||||
|
wayland-protocols
|
||||||
|
gtk3
|
||||||
)
|
)
|
||||||
makedepends=('cmake')
|
|
||||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/obsqrbtz/clrsync/archive/refs/tags/v$pkgver.tar.gz")
|
source=("$pkgname-$pkgver.tar.gz::https://github.com/obsqrbtz/clrsync/archive/refs/tags/v$pkgver.tar.gz")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
@@ -26,6 +37,7 @@ build() {
|
|||||||
cd "$pkgname-$pkgver"
|
cd "$pkgname-$pkgver"
|
||||||
cmake -B build -S . \
|
cmake -B build -S . \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DUSE_SYSTEM_GLFW=ON \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr
|
-DCMAKE_INSTALL_PREFIX=/usr
|
||||||
cmake --build build
|
cmake --build build
|
||||||
}
|
}
|
||||||
@@ -33,5 +45,5 @@ build() {
|
|||||||
package() {
|
package() {
|
||||||
cd "$pkgname-$pkgver"
|
cd "$pkgname-$pkgver"
|
||||||
DESTDIR="$pkgdir" cmake --install build
|
DESTDIR="$pkgdir" cmake --install build
|
||||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||||
}
|
}
|
||||||
185
CMakeLists.txt
185
CMakeLists.txt
@@ -1,16 +1,61 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(clrsync VERSION 0.1.2 LANGUAGES CXX)
|
project(clrsync VERSION 0.1.6 LANGUAGES CXX)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
option(USE_SYSTEM_GLFW "Use system-installed GLFW instead of fetching it statically" OFF)
|
||||||
|
message(STATUS "USE_SYSTEM_GLFW: ${USE_SYSTEM_GLFW}")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(CMAKE_INSTALL_PREFIX "C:/Program Files/clrsync")
|
||||||
|
set(CMAKE_INSTALL_BINDIR "bin")
|
||||||
|
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||||
|
set(CMAKE_INSTALL_DATADIR "share")
|
||||||
|
set(CMAKE_INSTALL_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
|
||||||
|
if(DEFINED CLRSYNC_SEMVER)
|
||||||
|
set(SEMVER "${CLRSYNC_SEMVER}")
|
||||||
|
else()
|
||||||
|
find_package(Git QUIET)
|
||||||
|
|
||||||
|
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||||
|
execute_process(
|
||||||
|
COMMAND git describe --tags --long --always
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_DESCRIBE
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(GIT_DESCRIBE MATCHES "^[vV]?[0-9]+\\.[0-9]+\\.[0-9]+-[0-9]+-g[0-9a-f]+")
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^[vV]?([0-9]+\\.[0-9]+\\.[0-9]+)-([0-9]+)-g([0-9a-f]+)"
|
||||||
|
"\\1+git.g\\3"
|
||||||
|
SEMVER "${GIT_DESCRIBE}"
|
||||||
|
)
|
||||||
|
elseif(GIT_DESCRIBE)
|
||||||
|
set(SEMVER "${PROJECT_VERSION}.git.${GIT_DESCRIBE}")
|
||||||
|
else()
|
||||||
|
set(SEMVER "${PROJECT_VERSION}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "clrsync version: ${SEMVER}")
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_SOURCE_DIR}/src/core/version.hpp.in
|
${CMAKE_SOURCE_DIR}/src/core/version.hpp.in
|
||||||
${CMAKE_SOURCE_DIR}/src/core/version.hpp
|
${CMAKE_SOURCE_DIR}/src/core/version.hpp
|
||||||
@@ -18,132 +63,30 @@ configure_file(
|
|||||||
)
|
)
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_SOURCE_DIR}/PKGBUILD.in
|
${CMAKE_SOURCE_DIR}/VERSION.in
|
||||||
${CMAKE_SOURCE_DIR}/PKGBUILD
|
${CMAKE_SOURCE_DIR}/VERSION
|
||||||
@ONLY
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(OpenGL REQUIRED)
|
configure_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/AUR/PKGBUILD.in
|
||||||
if(WIN32)
|
${CMAKE_SOURCE_DIR}/AUR/PKGBUILD
|
||||||
include(FetchContent)
|
@ONLY
|
||||||
FetchContent_Declare(
|
|
||||||
freetype
|
|
||||||
URL https://download.savannah.gnu.org/releases/freetype/freetype-2.14.1.tar.gz
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(freetype)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
|
||||||
glfw
|
|
||||||
GIT_REPOSITORY https://github.com/glfw/glfw.git
|
|
||||||
GIT_TAG 3.3.10
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(glfw)
|
|
||||||
|
|
||||||
else()
|
|
||||||
find_package(Freetype REQUIRED)
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
find_package(Fontconfig REQUIRED)
|
|
||||||
pkg_check_modules(GLFW REQUIRED glfw3)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CORE_SOURCES
|
|
||||||
src/core/palette/color.cpp
|
|
||||||
src/core/io/toml_file.cpp
|
|
||||||
src/core/config/config.cpp
|
|
||||||
src/core/utils.cpp
|
|
||||||
src/core/version.cpp
|
|
||||||
src/core/theme/theme_template.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(clrsync_core SHARED ${CORE_SOURCES})
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
target_include_directories(clrsync_core PUBLIC src SYSTEM lib)
|
include(Dependencies)
|
||||||
target_compile_definitions(clrsync_core PRIVATE
|
include(ImGui)
|
||||||
CLRSYNC_DATADIR=\"${CMAKE_INSTALL_FULL_DATADIR}/clrsync\"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(clrsync_cli src/cli/main.cpp)
|
add_subdirectory(src/core)
|
||||||
target_include_directories(clrsync_cli PRIVATE src SYSTEM lib)
|
add_subdirectory(src/cli)
|
||||||
target_link_libraries(clrsync_cli PRIVATE clrsync_core)
|
add_subdirectory(src/gui)
|
||||||
|
|
||||||
set(GUI_SOURCES
|
include(Install)
|
||||||
src/gui/main.cpp
|
include(Packaging)
|
||||||
src/gui/color_scheme_editor.cpp
|
|
||||||
src/gui/template_editor.cpp
|
|
||||||
src/gui/palette_controller.cpp
|
|
||||||
src/gui/template_controller.cpp
|
|
||||||
lib/color_text_edit/TextEditor.cpp
|
|
||||||
src/gui/imgui_helpers.cpp
|
|
||||||
src/gui/imgui_helpers.hpp
|
|
||||||
src/gui/about_window.cpp
|
|
||||||
src/gui/settings_window.cpp
|
|
||||||
src/gui/font_loader.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(clrsync_gui ${GUI_SOURCES})
|
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||||
target_include_directories(clrsync_gui PRIVATE src SYSTEM lib)
|
message(STATUS "CMAKE_INSTALL_FULL_DATADIR: ${CMAKE_INSTALL_FULL_DATADIR}")
|
||||||
|
|
||||||
if(WIN32)
|
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||||
target_link_libraries(clrsync_gui PRIVATE clrsync_core glfw freetype imgui OpenGL::GL)
|
message(STATUS "CMAKE_INSTALL_FULL_DATADIR: ${CMAKE_INSTALL_FULL_DATADIR}")
|
||||||
else()
|
|
||||||
target_include_directories(clrsync_gui PRIVATE ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(clrsync_gui PRIVATE clrsync_core imgui ${FREETYPE_LIBRARIES} ${GLFW_LIBRARIES} X11 Xrandr Xi Fontconfig::Fontconfig OpenGL::GL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(imgui_SOURCE_DIR lib/imgui)
|
|
||||||
add_library(imgui STATIC
|
|
||||||
${imgui_SOURCE_DIR}/imgui.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_draw.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_widgets.cpp
|
|
||||||
${imgui_SOURCE_DIR}/imgui_tables.cpp
|
|
||||||
${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
|
||||||
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
|
|
||||||
${imgui_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(imgui PUBLIC SYSTEM
|
|
||||||
${imgui_SOURCE_DIR}
|
|
||||||
${imgui_SOURCE_DIR}/backends
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_include_directories(imgui PUBLIC ${GLFW_INCLUDE_DIRS} ${freetype_SOURCE_DIR}/include)
|
|
||||||
else()
|
|
||||||
target_include_directories(imgui PUBLIC ${GLFW_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(imgui PUBLIC glfw OpenGL::GL freetype)
|
|
||||||
target_compile_definitions(imgui PUBLIC IMGUI_ENABLE_FREETYPE)
|
|
||||||
|
|
||||||
install(TARGETS clrsync_core
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS clrsync_cli
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS clrsync_gui
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES
|
|
||||||
example_config/config.toml
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
|
||||||
)
|
|
||||||
|
|
||||||
install(DIRECTORY example_config/templates
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
|
||||||
FILES_MATCHING PATTERN "*"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(DIRECTORY example_config/palettes
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
|
||||||
FILES_MATCHING PATTERN "*.toml"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
install(FILES resources/clrsync.desktop
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|||||||
419
README.md
419
README.md
@@ -1,6 +1,40 @@
|
|||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://nixos.wiki/wiki/Flakes)
|
||||||
|
|
||||||
# clrsync
|
# clrsync
|
||||||
|
|
||||||
A theme management tool for synchronizing color schemes across multiple applications. clrsync allows you to define color palettes once and apply them consistently to all your terminal emulators, editors, and other configurable applications.
|
**Notice:** This application is not yet released and is subject to change.
|
||||||
|
|
||||||
|
A theme management tool for synchronizing color schemes across multiple applications. clrsync allows to define color palettes once and apply them consistently to all configurable applications.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
|
||||||
|
- [Features](#features)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Linux](#linux)
|
||||||
|
- [Ubuntu](#ubuntu)
|
||||||
|
- [Fedora](#fedora)
|
||||||
|
- [NixOS](#nixos)
|
||||||
|
- [Home Manager Module](#home-manager-module)
|
||||||
|
- [Package](#package)
|
||||||
|
- [Install to profile](#install-to-profile)
|
||||||
|
- [Run without installing](#run-without-installing)
|
||||||
|
- [Windows](#windows)
|
||||||
|
- [Other systems](#other-systems)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [With CMake](#with-cmake)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Palette Files](#palette-files)
|
||||||
|
- [Template Files](#template-files)
|
||||||
|
- [Color Format Specifiers](#color-format-specifiers)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [CLI](#cli)
|
||||||
|
- [GUI](#gui)
|
||||||
|
- [Acknowledgments](#acknowledgments)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -8,46 +42,230 @@ A theme management tool for synchronizing color schemes across multiple applicat
|
|||||||
- **CLI & GUI**: Choose between a command-line interface or a graphical editor
|
- **CLI & GUI**: Choose between a command-line interface or a graphical editor
|
||||||
- **Live Reload**: Define post-apply hooks (configurable per template)
|
- **Live Reload**: Define post-apply hooks (configurable per template)
|
||||||
- **Flexible Color Formats**: Support for HEX, RGB, HSL with multi-component access (e.g., `{color.r}`, `{color.hex}`, `{color.hsl}`)
|
- **Flexible Color Formats**: Support for HEX, RGB, HSL with multi-component access (e.g., `{color.r}`, `{color.hex}`, `{color.hsl}`)
|
||||||
- **Pre-built Themes**: Includes popular themes
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
#### Ubuntu
|
||||||
|
|
||||||
|
1. Download the latest .deb from the [releases page](https://github.com/obsqrbtz/clrsync/releases)
|
||||||
|
2. Install the package
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo dpkg -i clrsync-<version>.deb
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fedora
|
||||||
|
|
||||||
|
1. Download the latest .rpm from the [releases page](https://github.com/obsqrbtz/clrsync/releases)
|
||||||
|
|
||||||
|
2. Install the package
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo rpm -i clrsync-<version>.rpm
|
||||||
|
|
||||||
|
# or
|
||||||
|
|
||||||
|
sudo dnf install clrsync-<version>.rpm
|
||||||
|
```
|
||||||
|
|
||||||
|
#### NixOS
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Home Manager Module</summary>
|
||||||
|
|
||||||
|
1. Add clrsync to your flake inputs
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
home-manager.url = "github:nix-community/home-manager";
|
||||||
|
|
||||||
|
clrsync.url = "github:obsqrbtz/clrsync";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add clrsync to flake outputs
|
||||||
|
|
||||||
|
```nix
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
home-manager,
|
||||||
|
clrsync,
|
||||||
|
...
|
||||||
|
}@inputs:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# ...
|
||||||
|
homeConfigurations.<Your user name> = home-manager.lib.homeManagerConfiguration {
|
||||||
|
inherit pkgs;
|
||||||
|
extraSpecialArgs = { inherit inputs; };
|
||||||
|
modules = [
|
||||||
|
./home.nix
|
||||||
|
clrsync.homeModules.default
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Configure in home manager
|
||||||
|
|
||||||
|
```nix
|
||||||
|
programs.clrsync = {
|
||||||
|
package = inputs.clrsync.packages.x86_64-linux.default;
|
||||||
|
defaultTheme = "dark";
|
||||||
|
palettesPath = "~/.config/clrsync/palettes";
|
||||||
|
font = "JetBrainsMono Nerd Font Mono";
|
||||||
|
fontSize = 14;
|
||||||
|
applyTheme = true;
|
||||||
|
|
||||||
|
templates = {
|
||||||
|
kitty = {
|
||||||
|
enabled = true;
|
||||||
|
inputPath = "~/.config/clrsync/templates/kitty.conf";
|
||||||
|
outputPath = "~/.config/kitty/clrsync.conf";
|
||||||
|
reloadCmd = "pkill -SIGUSR1 kitty";
|
||||||
|
};
|
||||||
|
|
||||||
|
rofi = {
|
||||||
|
enabled = true;
|
||||||
|
inputPath = "~/.config/clrsync/templates/rofi.rasi";
|
||||||
|
outputPath = "~/.config/rofi/clrsync.rasi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Rebuild
|
||||||
|
|
||||||
|
```nix
|
||||||
|
home-manager switch --flake .
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Package</summary>
|
||||||
|
|
||||||
|
1. Add clrsync to your flake inputs
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
clrsync.url = "github:obsqrbtz/clrsync";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install the package
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# In NixOS configuration.nix:
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
inputs.clrsync.overlays.default
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
clrsync
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
Or for home manager:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# flake.nix
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [
|
||||||
|
clrsync.overlays.default
|
||||||
|
];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# home.nix
|
||||||
|
home.packages = [
|
||||||
|
clrsync
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Use the app manually
|
||||||
|
|
||||||
|
```shell
|
||||||
|
clrsync_gui
|
||||||
|
|
||||||
|
# or
|
||||||
|
clrsync_cli --apply --theme dark
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Install to profile</summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
nix profile add github:obsqrbtz/clrsync
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Run without installing</summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
nix run github:obsqrbtz/clrsync
|
||||||
|
nix run github:obsqrbtz/clrsync#clrsync-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
1. Download the latest installer from the [releases page](https://github.com/obsqrbtz/clrsync/releases)
|
||||||
|
2. Run the installer and follow the wizard
|
||||||
|
3. Optionally, add the installation dir to your PATH for easier CLI access
|
||||||
|
|
||||||
|
### Other systems
|
||||||
|
|
||||||
|
Follow the steps from Building section then install with cmake:
|
||||||
|
```bash
|
||||||
|
cd build
|
||||||
|
cmake --install .
|
||||||
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- C++20 compatible compiler (GCC, Clang, or MSVC)
|
- C++20 compatible compiler (GCC, Clang, or MSVC)
|
||||||
- CMake or Meson
|
- CMake
|
||||||
- OpenGL
|
- OpenGL
|
||||||
|
- glfw
|
||||||
|
- fontconfig
|
||||||
|
- freetype
|
||||||
|
|
||||||
### Using CMake
|
### With CMake
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
cmake --build .
|
cmake --build .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Meson
|
|
||||||
|
|
||||||
```bash
|
|
||||||
meson setup builddir
|
|
||||||
meson compile -C builddir
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
After building, you'll have:
|
|
||||||
- `clrsync_cli` - CLI
|
|
||||||
- `clrsync_gui` - GUI
|
|
||||||
- `libclrsync_core` - Shared lib
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Create a configuration file at `~/.config/clrsync/config.toml`:
|
Edit or create a configuration file at `~/.config/clrsync/config.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[general]
|
[general]
|
||||||
palettes_path = "~/.config/clrsync/palettes"
|
palettes_path = "~/.config/clrsync/palettes"
|
||||||
default_theme = "dark"
|
default_theme = "cursed"
|
||||||
|
|
||||||
[templates.kitty]
|
[templates.kitty]
|
||||||
input_path = "~/.config/clrsync/templates/kitty.conf"
|
input_path = "~/.config/clrsync/templates/kitty.conf"
|
||||||
@@ -58,79 +276,109 @@ reload_cmd = "pkill -SIGUSR1 kitty"
|
|||||||
|
|
||||||
### Palette Files
|
### Palette Files
|
||||||
|
|
||||||
Create palette files in your `palettes_path` directory:
|
<details>
|
||||||
|
<summary>Example palette file</summary>
|
||||||
|
|
||||||
|
Create palette files in your `palettes_path` directory:
|
||||||
```toml
|
```toml
|
||||||
# ~/.config/clrsync/palettes/dark.toml
|
# ~/.config/clrsync/palettes/dark.toml
|
||||||
[general]
|
[general]
|
||||||
name = "dark"
|
name = 'cursed'
|
||||||
|
|
||||||
[colors]
|
[colors]
|
||||||
background = "#111318FF"
|
accent = '#B44242FF'
|
||||||
surface = "#1E1F25FF"
|
background = '#151515FF'
|
||||||
surface_variant = "#282A2FFF"
|
base00 = '#151515FF'
|
||||||
|
base01 = '#B44242FF'
|
||||||
foreground = "#E2E2E9FF"
|
base02 = '#95A328FF'
|
||||||
foreground_secondary = "#A8ABB3FF"
|
base03 = '#E1C135FF'
|
||||||
|
base04 = '#60928FFF'
|
||||||
accent = "#00AA56FF"
|
base05 = '#7C435AFF'
|
||||||
outline = "#44474FFF"
|
base06 = '#A48B4AFF'
|
||||||
shadow = "#00000080"
|
base07 = '#C2C2B0FF'
|
||||||
cursor = "#FFFFFFFF"
|
base08 = '#3F3639FF'
|
||||||
|
base09 = '#DC7671FF'
|
||||||
error = "#FF5F5FFF"
|
base0A = '#E8E85AFF'
|
||||||
warning = "#FFC966FF"
|
base0B = '#9E9052FF'
|
||||||
success = "#6AD68BFF"
|
base0C = '#76C39BFF'
|
||||||
info = "#5DB2FFFF"
|
base0D = '#86596CFF'
|
||||||
|
base0E = '#CEB34FFF'
|
||||||
term_black = "#111318FF"
|
base0F = '#B0AFA8FF'
|
||||||
term_red = "#FF5F5FFF"
|
border = '#3F3639FF'
|
||||||
term_green = "#00AA56FF"
|
border_focused = '#E1C135FF'
|
||||||
term_yellow = "#FFC966FF"
|
cursor = '#E1C135FF'
|
||||||
term_blue = "#5DB2FFFF"
|
editor_background = '#151515FF'
|
||||||
term_magenta = "#DEBCDFFF"
|
editor_command = '#CEB34FFF'
|
||||||
term_cyan = "#86C9FFFF"
|
editor_comment = '#3F3639FF'
|
||||||
term_white = "#E2E2E9FF"
|
editor_disabled = '#3F3639FF'
|
||||||
|
editor_emphasis = '#DC7671FF'
|
||||||
term_black_bright = "#33353AFF"
|
editor_error = '#B44242FF'
|
||||||
term_red_bright = "#FFB780FF"
|
editor_inactive = '#3F3639FF'
|
||||||
term_green_bright = "#00CC6AFF"
|
editor_line_number = '#86596CFF'
|
||||||
term_yellow_bright = "#FFD580FF"
|
editor_link = '#60928FFF'
|
||||||
term_blue_bright = "#86C9FFFF"
|
editor_main = '#C2C2B0FF'
|
||||||
term_magenta_bright = "#F0D6F0FF"
|
editor_selected = '#3F3639FF'
|
||||||
term_cyan_bright = "#BFEFFFFF"
|
editor_selection_inactive = '#2A2A2AFF'
|
||||||
term_white_bright = "#FFFFFFFF"
|
editor_string = '#76C39BFF'
|
||||||
|
editor_success = '#95A328FF'
|
||||||
|
editor_warning = '#E1C135FF'
|
||||||
|
error = '#B44242FF'
|
||||||
|
foreground = '#C2C2B0FF'
|
||||||
|
info = '#60928FFF'
|
||||||
|
on_background = '#C2C2B0FF'
|
||||||
|
on_error = '#151515FF'
|
||||||
|
on_info = '#151515FF'
|
||||||
|
on_success = '#151515FF'
|
||||||
|
on_surface = '#C2C2B0FF'
|
||||||
|
on_surface_variant = '#C2C2B0FF'
|
||||||
|
on_warning = '#151515FF'
|
||||||
|
success = '#95A328FF'
|
||||||
|
surface = '#1C1C1CFF'
|
||||||
|
surface_variant = '#1C1C1CFF'
|
||||||
|
warning = '#E1C135FF'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### Template Files
|
### Template Files
|
||||||
|
|
||||||
Create template files using color variables with flexible format specifiers:
|
<details>
|
||||||
|
<summary>Example template file</summary>
|
||||||
|
|
||||||
|
Create template files at `~/.config/clrsync/templates` using color variables:
|
||||||
```conf
|
```conf
|
||||||
# ~/.config/clrsync/templates/kitty.conf
|
# ~/.config/clrsync/templates/kitty.conf
|
||||||
cursor {foreground}
|
cursor {cursor}
|
||||||
cursor_text_color {background}
|
cursor_text_color {background}
|
||||||
|
|
||||||
foreground {foreground}
|
foreground {foreground}
|
||||||
background {background}
|
background {background}
|
||||||
selection_foreground {foreground_secondary}
|
selection_foreground {on_surface}
|
||||||
selection_background {surface}
|
selection_background {surface}
|
||||||
url_color {accent}
|
url_color {accent}
|
||||||
|
color0 {base00}
|
||||||
color0 {background}
|
color8 {base08}
|
||||||
color1 {term_red}
|
color1 {base01}
|
||||||
color2 {term_green}
|
color9 {base09}
|
||||||
color3 {term_yellow}
|
color2 {base02}
|
||||||
color4 {term_blue}
|
color10 {base0A}
|
||||||
color5 {term_magenta}
|
color3 {base03}
|
||||||
color6 {term_cyan}
|
color11 {base0B}
|
||||||
color7 {term_white}
|
color4 {base04}
|
||||||
|
color12 {base0C}
|
||||||
|
color5 {base05}
|
||||||
|
color13 {base0D}
|
||||||
|
color6 {base06}
|
||||||
|
color14 {base0E}
|
||||||
|
color7 {base07}
|
||||||
|
color15 {base0F}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Color Format Specifiers
|
</details>
|
||||||
|
|
||||||
Access color components using dot notation:
|
<details>
|
||||||
|
<summary>Color Format Specifiers</summary>
|
||||||
|
|
||||||
|
Format colors using dot notation:
|
||||||
```conf
|
```conf
|
||||||
# HEX formats
|
# HEX formats
|
||||||
{color} # Default: #RRGGBB
|
{color} # Default: #RRGGBB
|
||||||
@@ -160,6 +408,8 @@ Access color components using dot notation:
|
|||||||
{color.a} # Alpha component
|
{color.a} # Alpha component
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
@@ -176,7 +426,7 @@ clrsync_cli --apply
|
|||||||
|
|
||||||
Apply a specific theme:
|
Apply a specific theme:
|
||||||
```bash
|
```bash
|
||||||
clrsync_cli --apply --theme rose-pine
|
clrsync_cli --apply --theme cursed
|
||||||
```
|
```
|
||||||
|
|
||||||
Apply a theme from a file path:
|
Apply a theme from a file path:
|
||||||
@@ -202,32 +452,17 @@ clrsync_gui
|
|||||||
```
|
```
|
||||||
|
|
||||||
The GUI provides:
|
The GUI provides:
|
||||||
|
|
||||||
- **Color Scheme Editor**: Visual palette editor with color pickers
|
- **Color Scheme Editor**: Visual palette editor with color pickers
|
||||||
- **Template Editor**: Edit template files
|
- **Template Editor**: Edit template files
|
||||||
- **Live Preview**: See changes in real-time
|
- **Live Preview**: See changes in real-time
|
||||||
|
|
||||||
## Example Themes
|
|
||||||
|
|
||||||
The project includes several pre-configured themes in `example_config/palettes/`:
|
|
||||||
- `dark.toml`
|
|
||||||
- `light.toml`
|
|
||||||
- `flexoki.toml`
|
|
||||||
- `flexoki-light.toml`
|
|
||||||
- `rose-pine.toml`
|
|
||||||
- `rose-pine-moon.toml`
|
|
||||||
- `rose-pine-dawn.toml`
|
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
This project uses the following open-source libraries:
|
- **[matugen](https://github.com/InioX/matugen)** - A material you color generation tool
|
||||||
|
|
||||||
- **[Dear ImGui](https://github.com/ocornut/imgui)** - Bloat-free graphical user interface library for C++
|
- **[Dear ImGui](https://github.com/ocornut/imgui)** - Bloat-free graphical user interface library for C++
|
||||||
- **[GLFW](https://www.glfw.org/)** - Multi-platform library for OpenGL, OpenGL ES and Vulkan development
|
- **[GLFW](https://www.glfw.org/)** - Multi-platform library for OpenGL, OpenGL ES and Vulkan development
|
||||||
- **[toml++](https://github.com/marzer/tomlplusplus)** - Header-only TOML config file parser and serializer for C++17
|
- **[toml++](https://github.com/marzer/tomlplusplus)** - Header-only TOML config file parser and serializer for C++17
|
||||||
- **[argparse](https://github.com/p-ranav/argparse)** - Argument Parser for Modern C++
|
- **[argparse](https://github.com/p-ranav/argparse)** - Argument Parser for Modern C++
|
||||||
- **[ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit)** - Syntax highlighting text editor for ImGui
|
- **[ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit)** - Syntax highlighting text editor for ImGui
|
||||||
|
- **cursed** by **[pyratebeard](https://pyratebeard.net)** - Color scheme
|
||||||
Special thanks to the creators of the included color schemes:
|
|
||||||
- **[Flexoki](https://stephango.com/flexoki)** by Steph Ango
|
|
||||||
- **[Rosé Pine](https://rosepinetheme.com/)** by the Rosé Pine team
|
|
||||||
|
|
||||||
1
VERSION.in
Normal file
1
VERSION.in
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@PROJECT_VERSION@
|
||||||
BIN
assets/screenshot.png
Normal file
BIN
assets/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 370 KiB |
100
cmake/Dependencies.cmake
Normal file
100
cmake/Dependencies.cmake
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
freetype
|
||||||
|
URL https://download.savannah.gnu.org/releases/freetype/freetype-2.14.1.tar.gz
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(freetype)
|
||||||
|
elseif(APPLE)
|
||||||
|
option(USE_SYSTEM_GLFW ON)
|
||||||
|
find_package(Freetype REQUIRED)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
find_package(BZip2 REQUIRED)
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
|
||||||
|
|
||||||
|
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
|
||||||
|
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if(PkgConfig_FOUND)
|
||||||
|
pkg_check_modules(HARFBUZZ harfbuzz)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
find_package(Freetype REQUIRED)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
find_package(Fontconfig REQUIRED)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
find_package(BZip2 REQUIRED)
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
|
||||||
|
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
|
||||||
|
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
|
||||||
|
|
||||||
|
pkg_check_modules(HARFBUZZ harfbuzz)
|
||||||
|
pkg_check_modules(WAYLAND_CLIENT wayland-client)
|
||||||
|
pkg_check_modules(WAYLAND_EGL wayland-egl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LINUX)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(USE_SYSTEM_GLFW)
|
||||||
|
if(APPLE)
|
||||||
|
find_package(glfw3 QUIET)
|
||||||
|
if(glfw3_FOUND)
|
||||||
|
set(GLFW_FOUND TRUE)
|
||||||
|
set(GLFW_LIBRARIES glfw)
|
||||||
|
else()
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GLFW REQUIRED glfw3)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
pkg_check_modules(GLFW REQUIRED glfw3)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
glfw
|
||||||
|
GIT_REPOSITORY https://github.com/glfw/glfw.git
|
||||||
|
GIT_TAG 3.4
|
||||||
|
)
|
||||||
|
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(glfw)
|
||||||
|
set(GLFW_FOUND TRUE)
|
||||||
|
set(GLFW_INCLUDE_DIRS ${glfw_SOURCE_DIR}/include)
|
||||||
|
set(GLFW_LIBRARIES glfw)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FREETYPE_EXTRA_LIBS "")
|
||||||
|
if(BROTLIDEC_LIBRARY AND BROTLICOMMON_LIBRARY)
|
||||||
|
list(APPEND FREETYPE_EXTRA_LIBS ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
|
||||||
|
message(STATUS "Found Brotli libraries")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(HARFBUZZ_FOUND)
|
||||||
|
list(APPEND FREETYPE_EXTRA_LIBS ${HARFBUZZ_LIBRARIES})
|
||||||
|
message(STATUS "Found HarfBuzz")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(WAYLAND_LIBS "")
|
||||||
|
if(NOT APPLE)
|
||||||
|
if(WAYLAND_CLIENT_FOUND)
|
||||||
|
list(APPEND WAYLAND_LIBS ${WAYLAND_CLIENT_LIBRARIES})
|
||||||
|
message(STATUS "Found Wayland client")
|
||||||
|
endif()
|
||||||
|
if(WAYLAND_EGL_FOUND)
|
||||||
|
list(APPEND WAYLAND_LIBS ${WAYLAND_EGL_LIBRARIES})
|
||||||
|
message(STATUS "Found Wayland EGL")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
32
cmake/ImGui.cmake
Normal file
32
cmake/ImGui.cmake
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
set(IMGUI_SOURCE_DIR ${CMAKE_SOURCE_DIR}/lib/imgui)
|
||||||
|
|
||||||
|
add_library(imgui STATIC
|
||||||
|
${IMGUI_SOURCE_DIR}/imgui.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/imgui_draw.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/imgui_widgets.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/imgui_tables.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
|
||||||
|
${IMGUI_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(imgui PUBLIC SYSTEM
|
||||||
|
${IMGUI_SOURCE_DIR}
|
||||||
|
${IMGUI_SOURCE_DIR}/backends
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(imgui PUBLIC IMGUI_ENABLE_FREETYPE)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_include_directories(imgui PUBLIC ${GLFW_INCLUDE_DIRS} ${freetype_SOURCE_DIR}/include)
|
||||||
|
target_link_libraries(imgui PUBLIC freetype)
|
||||||
|
else()
|
||||||
|
target_include_directories(imgui PUBLIC ${GLFW_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(imgui PRIVATE
|
||||||
|
Freetype::Freetype
|
||||||
|
${FREETYPE_EXTRA_LIBS}
|
||||||
|
ZLIB::ZLIB
|
||||||
|
BZip2::BZip2
|
||||||
|
PNG::PNG
|
||||||
|
)
|
||||||
|
endif()
|
||||||
39
cmake/Install.cmake
Normal file
39
cmake/Install.cmake
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
install(TARGETS clrsync_core
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
COMPONENT Core
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS clrsync_cli
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
COMPONENT CLI
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS clrsync_gui
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
COMPONENT GUI
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES example_config/config.toml
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
||||||
|
COMPONENT Core
|
||||||
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY example_config/templates
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
||||||
|
COMPONENT Core
|
||||||
|
FILES_MATCHING PATTERN "*"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY example_config/palettes
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/clrsync
|
||||||
|
COMPONENT Core
|
||||||
|
FILES_MATCHING PATTERN "*.toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
install(FILES resources/clrsync.desktop
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
|
||||||
|
COMPONENT Core
|
||||||
|
)
|
||||||
|
endif()
|
||||||
41
cmake/Packaging.cmake
Normal file
41
cmake/Packaging.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.txt")
|
||||||
|
set(CPACK_PACKAGE_NAME "clrsync")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "Daniel Dada")
|
||||||
|
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Color scheme manager")
|
||||||
|
set(CPACK_GENERATOR "NSIS;DEB;RPM")
|
||||||
|
|
||||||
|
# Components
|
||||||
|
set(CPACK_COMPONENTS_ALL Core GUI CLI)
|
||||||
|
set(CPACK_COMPONENT_CORE_DISPLAY_NAME "Core Library")
|
||||||
|
set(CPACK_COMPONENT_CORE_DESCRIPTION "clrsync core library and default configs (required)")
|
||||||
|
set(CPACK_COMPONENT_CORE_REQUIRED ON)
|
||||||
|
set(CPACK_COMPONENT_GUI_DISPLAY_NAME "GUI Application")
|
||||||
|
set(CPACK_COMPONENT_GUI_DESCRIPTION "clrsync GUI app")
|
||||||
|
set(CPACK_COMPONENT_GUI_DEPENDS Core)
|
||||||
|
set(CPACK_COMPONENT_CLI_DISPLAY_NAME "Command Line Tool")
|
||||||
|
set(CPACK_COMPONENT_CLI_DESCRIPTION "clrsync CLI app")
|
||||||
|
set(CPACK_COMPONENT_CLI_DEPENDS Core)
|
||||||
|
|
||||||
|
# NSIS
|
||||||
|
set(CPACK_NSIS_INSTALLED_NAME "clrsync")
|
||||||
|
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
|
||||||
|
set(CPACK_NSIS_MODIFY_PATH ON)
|
||||||
|
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||||
|
set(CPACK_NSIS_MENU_LINKS "bin/clrsync_gui.exe" "clrsync")
|
||||||
|
set(CPACK_NSIS_CREATE_DESKTOP_LINKS "bin/clrsync_gui.exe;clrsync")
|
||||||
|
|
||||||
|
# Debian
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Daniel Dada <dan@binarygoose.dev>")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libglfw3, libfreetype6")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||||
|
|
||||||
|
# RPM
|
||||||
|
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||||
|
set(CPACK_RPM_PACKAGE_GROUP "Applications/System")
|
||||||
|
set(CPACK_RPM_PACKAGE_URL "https://github.com/obsqrbtz/clrsync")
|
||||||
|
set(CPACK_RPM_PACKAGE_REQUIRES "freetype, glfw, fontconfig")
|
||||||
|
|
||||||
|
include(CPack)
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#A6D189FF'
|
|
||||||
background = '#303446FF'
|
|
||||||
border_emphasized = '#8CAAEEFF'
|
|
||||||
border_focused = '#A6D189FF'
|
|
||||||
border_window = '#51576DFF'
|
|
||||||
cursor = '#F2D5CFFF'
|
|
||||||
editor_background = '#303446FF'
|
|
||||||
error = '#E78284FF'
|
|
||||||
floating_window_background = '#414559FF'
|
|
||||||
foreground = '#C6D0F5FF'
|
|
||||||
foreground_emphasis = '#C6D0F5FF'
|
|
||||||
foreground_secondary = '#B5BFE2FF'
|
|
||||||
info = '#8CAAEEFF'
|
|
||||||
menu_option_background = '#414559FF'
|
|
||||||
outline = '#51576DFF'
|
|
||||||
popup_background = '#292C3CFF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#292C3CFF'
|
|
||||||
success = '#A6D189FF'
|
|
||||||
surface = '#292C3CFF'
|
|
||||||
surface_variant = '#414559FF'
|
|
||||||
syntax_error = '#E78284FF'
|
|
||||||
syntax_function = '#8CAAEEFF'
|
|
||||||
syntax_keyword = '#CA9EE6FF'
|
|
||||||
syntax_operator = '#99D1DBFF'
|
|
||||||
syntax_special_keyword = '#E5C890FF'
|
|
||||||
term_black = '#51576DFF'
|
|
||||||
term_black_bright = '#626880FF'
|
|
||||||
term_blue = '#8CAAEEFF'
|
|
||||||
term_blue_bright = '#8CAAEEFF'
|
|
||||||
term_cyan = '#81C8BEFF'
|
|
||||||
term_cyan_bright = '#81C8BEFF'
|
|
||||||
term_green = '#A6D189FF'
|
|
||||||
term_green_bright = '#A6D189FF'
|
|
||||||
term_magenta = '#F4B8E4FF'
|
|
||||||
term_magenta_bright = '#F4B8E4FF'
|
|
||||||
term_red = '#E78284FF'
|
|
||||||
term_red_bright = '#E78284FF'
|
|
||||||
term_white = '#B5BFE2FF'
|
|
||||||
term_white_bright = '#A5ADCEFF'
|
|
||||||
term_yellow = '#E5C890FF'
|
|
||||||
term_yellow_bright = '#E5C890FF'
|
|
||||||
terminal_gray = '#626880FF'
|
|
||||||
text_command = '#A6D189FF'
|
|
||||||
text_comment = '#737994FF'
|
|
||||||
text_disabled = '#737994FF'
|
|
||||||
text_emphasis = '#C6D0F5FF'
|
|
||||||
text_error = '#E78284FF'
|
|
||||||
text_inactive = '#838BA7FF'
|
|
||||||
text_line_number = '#737994FF'
|
|
||||||
text_link = '#8CAAEEFF'
|
|
||||||
text_main = '#C6D0F5FF'
|
|
||||||
text_selected = '#62688038'
|
|
||||||
text_selection_inactive = '#51576D38'
|
|
||||||
text_string = '#A6D189FF'
|
|
||||||
text_success = '#A6D189FF'
|
|
||||||
text_warning = '#E5C890FF'
|
|
||||||
warning = '#EF9F76FF'
|
|
||||||
warning_emphasis = '#E5C890FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'catppuccin-frappe'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#40A02BFF'
|
|
||||||
background = '#EFF1F5FF'
|
|
||||||
border_emphasized = '#1E66F5FF'
|
|
||||||
border_focused = '#40A02BFF'
|
|
||||||
border_window = '#CCD0DAFF'
|
|
||||||
cursor = '#DC8A78FF'
|
|
||||||
editor_background = '#EFF1F5FF'
|
|
||||||
error = '#D20F39FF'
|
|
||||||
floating_window_background = '#E6E9EFFF'
|
|
||||||
foreground = '#4C4F69FF'
|
|
||||||
foreground_emphasis = '#4C4F69FF'
|
|
||||||
foreground_secondary = '#6C6F85FF'
|
|
||||||
info = '#1E66F5FF'
|
|
||||||
menu_option_background = '#E6E9EFFF'
|
|
||||||
outline = '#CCD0DAFF'
|
|
||||||
popup_background = '#DCE0E8FF'
|
|
||||||
shadow = '#00000040'
|
|
||||||
sidebar_background = '#DCE0E8FF'
|
|
||||||
success = '#40A02BFF'
|
|
||||||
surface = '#DCE0E8FF'
|
|
||||||
surface_variant = '#E6E9EFFF'
|
|
||||||
syntax_error = '#D20F39FF'
|
|
||||||
syntax_function = '#1E66F5FF'
|
|
||||||
syntax_keyword = '#8839EFFF'
|
|
||||||
syntax_operator = '#04A5E5FF'
|
|
||||||
syntax_special_keyword = '#DF8E1DFF'
|
|
||||||
term_black = '#5C5F77FF'
|
|
||||||
term_black_bright = '#6C6F85FF'
|
|
||||||
term_blue = '#1E66F5FF'
|
|
||||||
term_blue_bright = '#1E66F5FF'
|
|
||||||
term_cyan = '#179299FF'
|
|
||||||
term_cyan_bright = '#179299FF'
|
|
||||||
term_green = '#40A02BFF'
|
|
||||||
term_green_bright = '#40A02BFF'
|
|
||||||
term_magenta = '#EA76CBFF'
|
|
||||||
term_magenta_bright = '#EA76CBFF'
|
|
||||||
term_red = '#D20F39FF'
|
|
||||||
term_red_bright = '#D20F39FF'
|
|
||||||
term_white = '#4C4F69FF'
|
|
||||||
term_white_bright = '#4C4F69FF'
|
|
||||||
term_yellow = '#DF8E1DFF'
|
|
||||||
term_yellow_bright = '#DF8E1DFF'
|
|
||||||
terminal_gray = '#9CA0B0FF'
|
|
||||||
text_command = '#40A02BFF'
|
|
||||||
text_comment = '#ACB0BEFF'
|
|
||||||
text_disabled = '#ACB0BEFF'
|
|
||||||
text_emphasis = '#4C4F69FF'
|
|
||||||
text_error = '#D20F39FF'
|
|
||||||
text_inactive = '#8C8FA1FF'
|
|
||||||
text_line_number = '#ACB0BEFF'
|
|
||||||
text_link = '#1E66F5FF'
|
|
||||||
text_main = '#4C4F69FF'
|
|
||||||
text_selected = '#CCD0DA38'
|
|
||||||
text_selection_inactive = '#DCE0E838'
|
|
||||||
text_string = '#40A02BFF'
|
|
||||||
text_success = '#40A02BFF'
|
|
||||||
text_warning = '#DF8E1DFF'
|
|
||||||
warning = '#FE640BFF'
|
|
||||||
warning_emphasis = '#DF8E1DFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'catppuccin-latte'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#A6DA95FF'
|
|
||||||
background = '#24273AFF'
|
|
||||||
border_emphasized = '#8AADF4FF'
|
|
||||||
border_focused = '#A6DA95FF'
|
|
||||||
border_window = '#494D64FF'
|
|
||||||
cursor = '#F4DBD6FF'
|
|
||||||
editor_background = '#24273AFF'
|
|
||||||
error = '#ED8796FF'
|
|
||||||
floating_window_background = '#363A4FFF'
|
|
||||||
foreground = '#CAD3F5FF'
|
|
||||||
foreground_emphasis = '#CAD3F5FF'
|
|
||||||
foreground_secondary = '#B8C0E0FF'
|
|
||||||
info = '#8AADF4FF'
|
|
||||||
menu_option_background = '#363A4FFF'
|
|
||||||
outline = '#494D64FF'
|
|
||||||
popup_background = '#1E2030FF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#1E2030FF'
|
|
||||||
success = '#A6DA95FF'
|
|
||||||
surface = '#1E2030FF'
|
|
||||||
surface_variant = '#363A4FFF'
|
|
||||||
syntax_error = '#ED8796FF'
|
|
||||||
syntax_function = '#8AADF4FF'
|
|
||||||
syntax_keyword = '#C6A0F6FF'
|
|
||||||
syntax_operator = '#91D7E3FF'
|
|
||||||
syntax_special_keyword = '#EED49FFF'
|
|
||||||
term_black = '#494D64FF'
|
|
||||||
term_black_bright = '#5B6078FF'
|
|
||||||
term_blue = '#8AADF4FF'
|
|
||||||
term_blue_bright = '#8AADF4FF'
|
|
||||||
term_cyan = '#8BD5CAFF'
|
|
||||||
term_cyan_bright = '#8BD5CAFF'
|
|
||||||
term_green = '#A6DA95FF'
|
|
||||||
term_green_bright = '#A6DA95FF'
|
|
||||||
term_magenta = '#F5BDE6FF'
|
|
||||||
term_magenta_bright = '#F5BDE6FF'
|
|
||||||
term_red = '#ED8796FF'
|
|
||||||
term_red_bright = '#ED8796FF'
|
|
||||||
term_white = '#B8C0E0FF'
|
|
||||||
term_white_bright = '#A5ADCBFF'
|
|
||||||
term_yellow = '#EED49FFF'
|
|
||||||
term_yellow_bright = '#EED49FFF'
|
|
||||||
terminal_gray = '#5B6078FF'
|
|
||||||
text_command = '#A6DA95FF'
|
|
||||||
text_comment = '#6E738DFF'
|
|
||||||
text_disabled = '#6E738DFF'
|
|
||||||
text_emphasis = '#CAD3F5FF'
|
|
||||||
text_error = '#ED8796FF'
|
|
||||||
text_inactive = '#8087A2FF'
|
|
||||||
text_line_number = '#6E738DFF'
|
|
||||||
text_link = '#8AADF4FF'
|
|
||||||
text_main = '#CAD3F5FF'
|
|
||||||
text_selected = '#5B607838'
|
|
||||||
text_selection_inactive = '#494D6438'
|
|
||||||
text_string = '#A6DA95FF'
|
|
||||||
text_success = '#A6DA95FF'
|
|
||||||
text_warning = '#EED49FFF'
|
|
||||||
warning = '#F5A97FFF'
|
|
||||||
warning_emphasis = '#EED49FFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'catppuccin-macchiato'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#A6E3A1FF'
|
|
||||||
background = '#1E1E2EFF'
|
|
||||||
border_emphasized = '#89B4FAFF'
|
|
||||||
border_focused = '#A6E3A1FF'
|
|
||||||
border_window = '#45475AFF'
|
|
||||||
cursor = '#F5E0DCFF'
|
|
||||||
editor_background = '#1E1E2EFF'
|
|
||||||
error = '#F38BA8FF'
|
|
||||||
floating_window_background = '#313244FF'
|
|
||||||
foreground = '#CDD6F4FF'
|
|
||||||
foreground_emphasis = '#CDD6F4FF'
|
|
||||||
foreground_secondary = '#BAC2DEFF'
|
|
||||||
info = '#89B4FAFF'
|
|
||||||
menu_option_background = '#313244FF'
|
|
||||||
outline = '#45475AFF'
|
|
||||||
popup_background = '#181825FF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#181825FF'
|
|
||||||
success = '#A6E3A1FF'
|
|
||||||
surface = '#181825FF'
|
|
||||||
surface_variant = '#313244FF'
|
|
||||||
syntax_error = '#F38BA8FF'
|
|
||||||
syntax_function = '#89B4FAFF'
|
|
||||||
syntax_keyword = '#CBA6F7FF'
|
|
||||||
syntax_operator = '#89DCEBFF'
|
|
||||||
syntax_special_keyword = '#F9E2AFFF'
|
|
||||||
term_black = '#45475AFF'
|
|
||||||
term_black_bright = '#585B70FF'
|
|
||||||
term_blue = '#89B4FAFF'
|
|
||||||
term_blue_bright = '#89B4FAFF'
|
|
||||||
term_cyan = '#94E2D5FF'
|
|
||||||
term_cyan_bright = '#94E2D5FF'
|
|
||||||
term_green = '#A6E3A1FF'
|
|
||||||
term_green_bright = '#A6E3A1FF'
|
|
||||||
term_magenta = '#F5C2E7FF'
|
|
||||||
term_magenta_bright = '#F5C2E7FF'
|
|
||||||
term_red = '#F38BA8FF'
|
|
||||||
term_red_bright = '#F38BA8FF'
|
|
||||||
term_white = '#BAC2DEFF'
|
|
||||||
term_white_bright = '#A6ADC8FF'
|
|
||||||
term_yellow = '#F9E2AFFF'
|
|
||||||
term_yellow_bright = '#F9E2AFFF'
|
|
||||||
terminal_gray = '#585B70FF'
|
|
||||||
text_command = '#A6E3A1FF'
|
|
||||||
text_comment = '#6C7086FF'
|
|
||||||
text_disabled = '#6C7086FF'
|
|
||||||
text_emphasis = '#CDD6F4FF'
|
|
||||||
text_error = '#F38BA8FF'
|
|
||||||
text_inactive = '#7F849CFF'
|
|
||||||
text_line_number = '#6C7086FF'
|
|
||||||
text_link = '#89B4FAFF'
|
|
||||||
text_main = '#CDD6F4FF'
|
|
||||||
text_selected = '#585B7038'
|
|
||||||
text_selection_inactive = '#45475A38'
|
|
||||||
text_string = '#A6E3A1FF'
|
|
||||||
text_success = '#A6E3A1FF'
|
|
||||||
text_warning = '#F9E2AFFF'
|
|
||||||
warning = '#FAB387FF'
|
|
||||||
warning_emphasis = '#F9E2AFFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'catppuccin-mocha'
|
|
||||||
@@ -1,63 +1,54 @@
|
|||||||
[colors]
|
[colors]
|
||||||
accent = '#00AA56FF'
|
accent = '#9A8652FF'
|
||||||
background = '#111318FF'
|
background = '#111111FF'
|
||||||
border_emphasized = '#5DB2FFFF'
|
base00 = '#111111FF'
|
||||||
border_focused = '#00AA56FF'
|
base01 = '#668A51FF'
|
||||||
border_window = '#44474FFF'
|
base02 = '#9A8652FF'
|
||||||
cursor = '#FFFFFFFF'
|
base03 = '#B47837FF'
|
||||||
editor_background = '#111318FF'
|
base04 = '#9A5552FF'
|
||||||
error = '#FF5F5FFF'
|
base05 = '#AA477BFF'
|
||||||
floating_window_background = '#282A2FFF'
|
base06 = '#3A898CFF'
|
||||||
foreground = '#E2E2E9FF'
|
base07 = '#B5B5B5FF'
|
||||||
foreground_emphasis = '#FFFFFFFF'
|
base08 = '#AA4E4AFF'
|
||||||
foreground_secondary = '#A8ABB3FF'
|
base09 = '#A9DC86FF'
|
||||||
info = '#5DB2FFFF'
|
base0A = '#B6AB82FF'
|
||||||
menu_option_background = '#282A2FFF'
|
base0B = '#C5916BFF'
|
||||||
outline = '#44474FFF'
|
base0C = '#AC7676FF'
|
||||||
popup_background = '#1E1F25FF'
|
base0D = '#B0779EFF'
|
||||||
shadow = '#00000080'
|
base0E = '#849899FF'
|
||||||
sidebar_background = '#1E1F25FF'
|
base0F = '#D2D2D2FF'
|
||||||
success = '#6AD68BFF'
|
border = '#242424FF'
|
||||||
surface = '#1E1F25FF'
|
border_focused = '#2E2E2EFF'
|
||||||
surface_variant = '#282A2FFF'
|
cursor = '#D2D2D2FF'
|
||||||
syntax_error = '#FF5F5FFF'
|
editor_background = '#111111FF'
|
||||||
syntax_function = '#86C9FFFF'
|
editor_command = '#3A898CFF'
|
||||||
syntax_keyword = '#DEBCDFFF'
|
editor_comment = '#849899FF'
|
||||||
syntax_operator = '#A8ABB3FF'
|
editor_disabled = '#849899FF'
|
||||||
syntax_special_keyword = '#FFC966FF'
|
editor_emphasis = '#A9DC86FF'
|
||||||
term_black = '#111318FF'
|
editor_error = '#AA4E4AFF'
|
||||||
term_black_bright = '#33353AFF'
|
editor_inactive = '#849899FF'
|
||||||
term_blue = '#5DB2FFFF'
|
editor_line_number = '#849899FF'
|
||||||
term_blue_bright = '#86C9FFFF'
|
editor_link = '#B0779EFF'
|
||||||
term_cyan = '#86C9FFFF'
|
editor_main = '#D2D2D2FF'
|
||||||
term_cyan_bright = '#BFEFFFFF'
|
editor_selected = '#242424FF'
|
||||||
term_green = '#00AA56FF'
|
editor_selection_inactive = '#1D1C1CFF'
|
||||||
term_green_bright = '#00CC6AFF'
|
editor_string = '#9A8652FF'
|
||||||
term_magenta = '#DEBCDFFF'
|
editor_success = '#668A51FF'
|
||||||
term_magenta_bright = '#F0D6F0FF'
|
editor_warning = '#B47837FF'
|
||||||
term_red = '#FF5F5FFF'
|
error = '#AA4E4AFF'
|
||||||
term_red_bright = '#FFB780FF'
|
foreground = '#D2D2D2FF'
|
||||||
term_white = '#E2E2E9FF'
|
info = '#3A898CFF'
|
||||||
term_white_bright = '#FFFFFFFF'
|
on_background = '#D4D4D4FF'
|
||||||
term_yellow = '#FFC966FF'
|
on_error = '#D2D2D2FF'
|
||||||
term_yellow_bright = '#FFD580FF'
|
on_info = '#D2D2D2FF'
|
||||||
terminal_gray = '#33353AFF'
|
on_success = '#D2D2D2FF'
|
||||||
text_command = '#00AA56FF'
|
on_surface = '#D4D4D4FF'
|
||||||
text_comment = '#44474FFF'
|
on_surface_variant = '#D4D4D4FF'
|
||||||
text_disabled = '#44474FFF'
|
on_warning = '#D2D2D2FF'
|
||||||
text_emphasis = '#FFFFFFFF'
|
success = '#668A51FF'
|
||||||
text_error = '#FF5F5FFF'
|
surface = '#111111FF'
|
||||||
text_inactive = '#A8ABB3FF'
|
surface_variant = '#191919FF'
|
||||||
text_line_number = '#44474FFF'
|
warning = '#B47837FF'
|
||||||
text_link = '#5DB2FFFF'
|
|
||||||
text_main = '#E2E2E9FF'
|
|
||||||
text_selected = '#FFFFFF1A'
|
|
||||||
text_selection_inactive = '#A8ABB338'
|
|
||||||
text_string = '#6AD68BFF'
|
|
||||||
text_success = '#6AD68BFF'
|
|
||||||
text_warning = '#FFC966FF'
|
|
||||||
warning = '#FFC966FF'
|
|
||||||
warning_emphasis = '#FFD580FF'
|
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
name = 'dark'
|
name = 'dark'
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#A7C080FF'
|
|
||||||
background = '#272E33FF'
|
|
||||||
border_emphasized = '#7FBBB3FF'
|
|
||||||
border_focused = '#A7C080FF'
|
|
||||||
border_window = '#475258FF'
|
|
||||||
cursor = '#D3C6AAFF'
|
|
||||||
editor_background = '#272E33FF'
|
|
||||||
error = '#E67E80FF'
|
|
||||||
floating_window_background = '#3D484DFF'
|
|
||||||
foreground = '#D3C6AAFF'
|
|
||||||
foreground_emphasis = '#D3C6AAFF'
|
|
||||||
foreground_secondary = '#9DA9A0FF'
|
|
||||||
info = '#7FBBB3FF'
|
|
||||||
menu_option_background = '#3D484DFF'
|
|
||||||
outline = '#475258FF'
|
|
||||||
popup_background = '#2E383CFF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#2E383CFF'
|
|
||||||
success = '#A7C080FF'
|
|
||||||
surface = '#2E383CFF'
|
|
||||||
surface_variant = '#3D484DFF'
|
|
||||||
syntax_error = '#E67E80FF'
|
|
||||||
syntax_function = '#7FBBB3FF'
|
|
||||||
syntax_keyword = '#D699B6FF'
|
|
||||||
syntax_operator = '#83C092FF'
|
|
||||||
syntax_special_keyword = '#DBBC7FFF'
|
|
||||||
term_black = '#475258FF'
|
|
||||||
term_black_bright = '#4F585EFF'
|
|
||||||
term_blue = '#7FBBB3FF'
|
|
||||||
term_blue_bright = '#7FBBB3FF'
|
|
||||||
term_cyan = '#83C092FF'
|
|
||||||
term_cyan_bright = '#83C092FF'
|
|
||||||
term_green = '#A7C080FF'
|
|
||||||
term_green_bright = '#A7C080FF'
|
|
||||||
term_magenta = '#D699B6FF'
|
|
||||||
term_magenta_bright = '#D699B6FF'
|
|
||||||
term_red = '#E67E80FF'
|
|
||||||
term_red_bright = '#E67E80FF'
|
|
||||||
term_white = '#D3C6AAFF'
|
|
||||||
term_white_bright = '#D3C6AAFF'
|
|
||||||
term_yellow = '#DBBC7FFF'
|
|
||||||
term_yellow_bright = '#DBBC7FFF'
|
|
||||||
terminal_gray = '#4F585EFF'
|
|
||||||
text_command = '#A7C080FF'
|
|
||||||
text_comment = '#859289FF'
|
|
||||||
text_disabled = '#859289FF'
|
|
||||||
text_emphasis = '#D3C6AAFF'
|
|
||||||
text_error = '#E67E80FF'
|
|
||||||
text_inactive = '#7A8478FF'
|
|
||||||
text_line_number = '#859289FF'
|
|
||||||
text_link = '#7FBBB3FF'
|
|
||||||
text_main = '#D3C6AAFF'
|
|
||||||
text_selected = '#543A4838'
|
|
||||||
text_selection_inactive = '#51404538'
|
|
||||||
text_string = '#A7C080FF'
|
|
||||||
text_success = '#A7C080FF'
|
|
||||||
text_warning = '#DBBC7FFF'
|
|
||||||
warning = '#E69875FF'
|
|
||||||
warning_emphasis = '#DBBC7FFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'everforest-dark-hard'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#A7C080FF'
|
|
||||||
background = '#2D353BFF'
|
|
||||||
border_emphasized = '#7FBBB3FF'
|
|
||||||
border_focused = '#A7C080FF'
|
|
||||||
border_window = '#475258FF'
|
|
||||||
cursor = '#D3C6AAFF'
|
|
||||||
editor_background = '#2D353BFF'
|
|
||||||
error = '#E67E80FF'
|
|
||||||
floating_window_background = '#3D484DFF'
|
|
||||||
foreground = '#D3C6AAFF'
|
|
||||||
foreground_emphasis = '#D3C6AAFF'
|
|
||||||
foreground_secondary = '#9DA9A0FF'
|
|
||||||
info = '#7FBBB3FF'
|
|
||||||
menu_option_background = '#3D484DFF'
|
|
||||||
outline = '#475258FF'
|
|
||||||
popup_background = '#343F44FF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#343F44FF'
|
|
||||||
success = '#A7C080FF'
|
|
||||||
surface = '#343F44FF'
|
|
||||||
surface_variant = '#3D484DFF'
|
|
||||||
syntax_error = '#E67E80FF'
|
|
||||||
syntax_function = '#7FBBB3FF'
|
|
||||||
syntax_keyword = '#D699B6FF'
|
|
||||||
syntax_operator = '#83C092FF'
|
|
||||||
syntax_special_keyword = '#DBBC7FFF'
|
|
||||||
term_black = '#475258FF'
|
|
||||||
term_black_bright = '#4F585EFF'
|
|
||||||
term_blue = '#7FBBB3FF'
|
|
||||||
term_blue_bright = '#7FBBB3FF'
|
|
||||||
term_cyan = '#83C092FF'
|
|
||||||
term_cyan_bright = '#83C092FF'
|
|
||||||
term_green = '#A7C080FF'
|
|
||||||
term_green_bright = '#A7C080FF'
|
|
||||||
term_magenta = '#D699B6FF'
|
|
||||||
term_magenta_bright = '#D699B6FF'
|
|
||||||
term_red = '#E67E80FF'
|
|
||||||
term_red_bright = '#E67E80FF'
|
|
||||||
term_white = '#D3C6AAFF'
|
|
||||||
term_white_bright = '#D3C6AAFF'
|
|
||||||
term_yellow = '#DBBC7FFF'
|
|
||||||
term_yellow_bright = '#DBBC7FFF'
|
|
||||||
terminal_gray = '#4F585EFF'
|
|
||||||
text_command = '#A7C080FF'
|
|
||||||
text_comment = '#859289FF'
|
|
||||||
text_disabled = '#859289FF'
|
|
||||||
text_emphasis = '#D3C6AAFF'
|
|
||||||
text_error = '#E67E80FF'
|
|
||||||
text_inactive = '#7A8478FF'
|
|
||||||
text_line_number = '#859289FF'
|
|
||||||
text_link = '#7FBBB3FF'
|
|
||||||
text_main = '#D3C6AAFF'
|
|
||||||
text_selected = '#543A4838'
|
|
||||||
text_selection_inactive = '#51404538'
|
|
||||||
text_string = '#A7C080FF'
|
|
||||||
text_success = '#A7C080FF'
|
|
||||||
text_warning = '#DBBC7FFF'
|
|
||||||
warning = '#E69875FF'
|
|
||||||
warning_emphasis = '#DBBC7FFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'everforest-dark'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#8DA101FF'
|
|
||||||
background = '#FFF9E8FF'
|
|
||||||
border_emphasized = '#3A94C5FF'
|
|
||||||
border_focused = '#8DA101FF'
|
|
||||||
border_window = '#E6E2CCFF'
|
|
||||||
cursor = '#5C6A72FF'
|
|
||||||
editor_background = '#FFF9E8FF'
|
|
||||||
error = '#F85552FF'
|
|
||||||
floating_window_background = '#F4F0D9FF'
|
|
||||||
foreground = '#5C6A72FF'
|
|
||||||
foreground_emphasis = '#5C6A72FF'
|
|
||||||
foreground_secondary = '#939F91FF'
|
|
||||||
info = '#3A94C5FF'
|
|
||||||
menu_option_background = '#F4F0D9FF'
|
|
||||||
outline = '#E6E2CCFF'
|
|
||||||
popup_background = '#FDFCEEFF'
|
|
||||||
shadow = '#00000040'
|
|
||||||
sidebar_background = '#FDFCEEFF'
|
|
||||||
success = '#8DA101FF'
|
|
||||||
surface = '#FDFCEEFF'
|
|
||||||
surface_variant = '#F4F0D9FF'
|
|
||||||
syntax_error = '#F85552FF'
|
|
||||||
syntax_function = '#3A94C5FF'
|
|
||||||
syntax_keyword = '#DF69BAFF'
|
|
||||||
syntax_operator = '#35A77CFF'
|
|
||||||
syntax_special_keyword = '#DFA000FF'
|
|
||||||
term_black = '#E6E2CCFF'
|
|
||||||
term_black_bright = '#D8CAACFF'
|
|
||||||
term_blue = '#3A94C5FF'
|
|
||||||
term_blue_bright = '#3A94C5FF'
|
|
||||||
term_cyan = '#35A77CFF'
|
|
||||||
term_cyan_bright = '#35A77CFF'
|
|
||||||
term_green = '#8DA101FF'
|
|
||||||
term_green_bright = '#8DA101FF'
|
|
||||||
term_magenta = '#DF69BAFF'
|
|
||||||
term_magenta_bright = '#DF69BAFF'
|
|
||||||
term_red = '#F85552FF'
|
|
||||||
term_red_bright = '#F85552FF'
|
|
||||||
term_white = '#5C6A72FF'
|
|
||||||
term_white_bright = '#5C6A72FF'
|
|
||||||
term_yellow = '#DFA000FF'
|
|
||||||
term_yellow_bright = '#DFA000FF'
|
|
||||||
terminal_gray = '#D8CAACFF'
|
|
||||||
text_command = '#8DA101FF'
|
|
||||||
text_comment = '#A6B0A0FF'
|
|
||||||
text_disabled = '#A6B0A0FF'
|
|
||||||
text_emphasis = '#5C6A72FF'
|
|
||||||
text_error = '#F85552FF'
|
|
||||||
text_inactive = '#939F91FF'
|
|
||||||
text_line_number = '#A6B0A0FF'
|
|
||||||
text_link = '#3A94C5FF'
|
|
||||||
text_main = '#5C6A72FF'
|
|
||||||
text_selected = '#EAE4D938'
|
|
||||||
text_selection_inactive = '#F0EBDB38'
|
|
||||||
text_string = '#8DA101FF'
|
|
||||||
text_success = '#8DA101FF'
|
|
||||||
text_warning = '#DFA000FF'
|
|
||||||
warning = '#F57D26FF'
|
|
||||||
warning_emphasis = '#DFA000FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'everforest-light'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#66800BFF'
|
|
||||||
background = '#FFFCF0FF'
|
|
||||||
border_emphasized = '#205EA6FF'
|
|
||||||
border_focused = '#66800BFF'
|
|
||||||
border_window = '#DAD8CEFF'
|
|
||||||
cursor = '#100F0FFF'
|
|
||||||
editor_background = '#FFFCF0FF'
|
|
||||||
error = '#AF3029FF'
|
|
||||||
floating_window_background = '#F2F0E5FF'
|
|
||||||
foreground = '#100F0FFF'
|
|
||||||
foreground_emphasis = '#100F0FFF'
|
|
||||||
foreground_secondary = '#403E3CFF'
|
|
||||||
info = '#205EA6FF'
|
|
||||||
menu_option_background = '#F2F0E5FF'
|
|
||||||
outline = '#DAD8CEFF'
|
|
||||||
popup_background = '#F2F0E5FF'
|
|
||||||
shadow = '#00000040'
|
|
||||||
sidebar_background = '#F2F0E5FF'
|
|
||||||
success = '#66800BFF'
|
|
||||||
surface = '#F2F0E5FF'
|
|
||||||
surface_variant = '#E6E4D9FF'
|
|
||||||
syntax_error = '#AF3029FF'
|
|
||||||
syntax_function = '#205EA6FF'
|
|
||||||
syntax_keyword = '#5E409DFF'
|
|
||||||
syntax_operator = '#24837BFF'
|
|
||||||
syntax_special_keyword = '#AD8301FF'
|
|
||||||
term_black = '#FFFCF0FF'
|
|
||||||
term_black_bright = '#6F6E69FF'
|
|
||||||
term_blue = '#205EA6FF'
|
|
||||||
term_blue_bright = '#205EA6FF'
|
|
||||||
term_cyan = '#24837BFF'
|
|
||||||
term_cyan_bright = '#24837BFF'
|
|
||||||
term_green = '#66800BFF'
|
|
||||||
term_green_bright = '#66800BFF'
|
|
||||||
term_magenta = '#A02F6FFF'
|
|
||||||
term_magenta_bright = '#A02F6FFF'
|
|
||||||
term_red = '#AF3029FF'
|
|
||||||
term_red_bright = '#AF3029FF'
|
|
||||||
term_white = '#100F0FFF'
|
|
||||||
term_white_bright = '#100F0FFF'
|
|
||||||
term_yellow = '#AD8301FF'
|
|
||||||
term_yellow_bright = '#AD8301FF'
|
|
||||||
terminal_gray = '#6F6E69FF'
|
|
||||||
text_command = '#66800BFF'
|
|
||||||
text_comment = '#878580FF'
|
|
||||||
text_disabled = '#B7B5ACFF'
|
|
||||||
text_emphasis = '#100F0FFF'
|
|
||||||
text_error = '#AF3029FF'
|
|
||||||
text_inactive = '#6F6E69FF'
|
|
||||||
text_line_number = '#878580FF'
|
|
||||||
text_link = '#205EA6FF'
|
|
||||||
text_main = '#100F0FFF'
|
|
||||||
text_selected = '#E6E4D938'
|
|
||||||
text_selection_inactive = '#F2F0E538'
|
|
||||||
text_string = '#66800BFF'
|
|
||||||
text_success = '#66800BFF'
|
|
||||||
text_warning = '#AD8301FF'
|
|
||||||
warning = '#BC5215FF'
|
|
||||||
warning_emphasis = '#AD8301FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'flexoki-light'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#879A39FF'
|
|
||||||
background = '#100F0FFF'
|
|
||||||
border_emphasized = '#4385BEFF'
|
|
||||||
border_focused = '#879A39FF'
|
|
||||||
border_window = '#282726FF'
|
|
||||||
cursor = '#CECDC3FF'
|
|
||||||
editor_background = '#100F0FFF'
|
|
||||||
error = '#D14D41FF'
|
|
||||||
floating_window_background = '#1C1B1AFF'
|
|
||||||
foreground = '#CECDC3FF'
|
|
||||||
foreground_emphasis = '#E6E4D9FF'
|
|
||||||
foreground_secondary = '#B7B5ACFF'
|
|
||||||
info = '#4385BEFF'
|
|
||||||
menu_option_background = '#1C1B1AFF'
|
|
||||||
outline = '#282726FF'
|
|
||||||
popup_background = '#1C1B1AFF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#1C1B1AFF'
|
|
||||||
success = '#879A39FF'
|
|
||||||
surface = '#1C1B1AFF'
|
|
||||||
surface_variant = '#282726FF'
|
|
||||||
syntax_error = '#D14D41FF'
|
|
||||||
syntax_function = '#4385BEFF'
|
|
||||||
syntax_keyword = '#8B7EC8FF'
|
|
||||||
syntax_operator = '#3AA99FFF'
|
|
||||||
syntax_special_keyword = '#D0A215FF'
|
|
||||||
term_black = '#100F0FFF'
|
|
||||||
term_black_bright = '#6F6E69FF'
|
|
||||||
term_blue = '#4385BEFF'
|
|
||||||
term_blue_bright = '#4385BEFF'
|
|
||||||
term_cyan = '#3AA99FFF'
|
|
||||||
term_cyan_bright = '#3AA99FFF'
|
|
||||||
term_green = '#879A39FF'
|
|
||||||
term_green_bright = '#879A39FF'
|
|
||||||
term_magenta = '#CE5D97FF'
|
|
||||||
term_magenta_bright = '#CE5D97FF'
|
|
||||||
term_red = '#D14D41FF'
|
|
||||||
term_red_bright = '#D14D41FF'
|
|
||||||
term_white = '#CECDC3FF'
|
|
||||||
term_white_bright = '#E6E4D9FF'
|
|
||||||
term_yellow = '#D0A215FF'
|
|
||||||
term_yellow_bright = '#D0A215FF'
|
|
||||||
terminal_gray = '#6F6E69FF'
|
|
||||||
text_command = '#879A39FF'
|
|
||||||
text_comment = '#575653FF'
|
|
||||||
text_disabled = '#403E3CFF'
|
|
||||||
text_emphasis = '#E6E4D9FF'
|
|
||||||
text_error = '#D14D41FF'
|
|
||||||
text_inactive = '#6F6E69FF'
|
|
||||||
text_line_number = '#575653FF'
|
|
||||||
text_link = '#4385BEFF'
|
|
||||||
text_main = '#CECDC3FF'
|
|
||||||
text_selected = '#28272638'
|
|
||||||
text_selection_inactive = '#1C1B1A38'
|
|
||||||
text_string = '#879A39FF'
|
|
||||||
text_success = '#879A39FF'
|
|
||||||
text_warning = '#D0A215FF'
|
|
||||||
warning = '#DA702CFF'
|
|
||||||
warning_emphasis = '#D0A215FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'flexoki'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#B8BB26FF'
|
|
||||||
background = '#282828FF'
|
|
||||||
border_emphasized = '#83A598FF'
|
|
||||||
border_focused = '#B8BB26FF'
|
|
||||||
border_window = '#504945FF'
|
|
||||||
cursor = '#EBDBB2FF'
|
|
||||||
editor_background = '#282828FF'
|
|
||||||
error = '#FB4934FF'
|
|
||||||
floating_window_background = '#3C3836FF'
|
|
||||||
foreground = '#EBDBB2FF'
|
|
||||||
foreground_emphasis = '#FBF1C7FF'
|
|
||||||
foreground_secondary = '#D5C4A1FF'
|
|
||||||
info = '#83A598FF'
|
|
||||||
menu_option_background = '#3C3836FF'
|
|
||||||
outline = '#504945FF'
|
|
||||||
popup_background = '#32302FFF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#32302FFF'
|
|
||||||
success = '#B8BB26FF'
|
|
||||||
surface = '#32302FFF'
|
|
||||||
surface_variant = '#3C3836FF'
|
|
||||||
syntax_error = '#FB4934FF'
|
|
||||||
syntax_function = '#83A598FF'
|
|
||||||
syntax_keyword = '#D3869BFF'
|
|
||||||
syntax_operator = '#8EC07CFF'
|
|
||||||
syntax_special_keyword = '#FABD2FFF'
|
|
||||||
term_black = '#282828FF'
|
|
||||||
term_black_bright = '#928374FF'
|
|
||||||
term_blue = '#458588FF'
|
|
||||||
term_blue_bright = '#83A598FF'
|
|
||||||
term_cyan = '#689D6AFF'
|
|
||||||
term_cyan_bright = '#8EC07CFF'
|
|
||||||
term_green = '#98971AFF'
|
|
||||||
term_green_bright = '#B8BB26FF'
|
|
||||||
term_magenta = '#B16286FF'
|
|
||||||
term_magenta_bright = '#D3869BFF'
|
|
||||||
term_red = '#CC241DFF'
|
|
||||||
term_red_bright = '#FB4934FF'
|
|
||||||
term_white = '#A89984FF'
|
|
||||||
term_white_bright = '#EBDBB2FF'
|
|
||||||
term_yellow = '#D79921FF'
|
|
||||||
term_yellow_bright = '#FABD2FFF'
|
|
||||||
terminal_gray = '#928374FF'
|
|
||||||
text_command = '#B8BB26FF'
|
|
||||||
text_comment = '#928374FF'
|
|
||||||
text_disabled = '#665C54FF'
|
|
||||||
text_emphasis = '#FBF1C7FF'
|
|
||||||
text_error = '#FB4934FF'
|
|
||||||
text_inactive = '#7C6F64FF'
|
|
||||||
text_line_number = '#7C6F64FF'
|
|
||||||
text_link = '#83A598FF'
|
|
||||||
text_main = '#EBDBB2FF'
|
|
||||||
text_selected = '#665C5438'
|
|
||||||
text_selection_inactive = '#50494538'
|
|
||||||
text_string = '#B8BB26FF'
|
|
||||||
text_success = '#B8BB26FF'
|
|
||||||
text_warning = '#FABD2FFF'
|
|
||||||
warning = '#FE8019FF'
|
|
||||||
warning_emphasis = '#FABD2FFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'gruvbox-dark'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#B8BB26FF'
|
|
||||||
background = '#1D2021FF'
|
|
||||||
border_emphasized = '#83A598FF'
|
|
||||||
border_focused = '#B8BB26FF'
|
|
||||||
border_window = '#504945FF'
|
|
||||||
cursor = '#EBDBB2FF'
|
|
||||||
editor_background = '#1D2021FF'
|
|
||||||
error = '#FB4934FF'
|
|
||||||
floating_window_background = '#3C3836FF'
|
|
||||||
foreground = '#EBDBB2FF'
|
|
||||||
foreground_emphasis = '#FBF1C7FF'
|
|
||||||
foreground_secondary = '#D5C4A1FF'
|
|
||||||
info = '#83A598FF'
|
|
||||||
menu_option_background = '#3C3836FF'
|
|
||||||
outline = '#504945FF'
|
|
||||||
popup_background = '#282828FF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#282828FF'
|
|
||||||
success = '#B8BB26FF'
|
|
||||||
surface = '#282828FF'
|
|
||||||
surface_variant = '#3C3836FF'
|
|
||||||
syntax_error = '#FB4934FF'
|
|
||||||
syntax_function = '#83A598FF'
|
|
||||||
syntax_keyword = '#D3869BFF'
|
|
||||||
syntax_operator = '#8EC07CFF'
|
|
||||||
syntax_special_keyword = '#FABD2FFF'
|
|
||||||
term_black = '#1D2021FF'
|
|
||||||
term_black_bright = '#928374FF'
|
|
||||||
term_blue = '#458588FF'
|
|
||||||
term_blue_bright = '#83A598FF'
|
|
||||||
term_cyan = '#689D6AFF'
|
|
||||||
term_cyan_bright = '#8EC07CFF'
|
|
||||||
term_green = '#98971AFF'
|
|
||||||
term_green_bright = '#B8BB26FF'
|
|
||||||
term_magenta = '#B16286FF'
|
|
||||||
term_magenta_bright = '#D3869BFF'
|
|
||||||
term_red = '#CC241DFF'
|
|
||||||
term_red_bright = '#FB4934FF'
|
|
||||||
term_white = '#A89984FF'
|
|
||||||
term_white_bright = '#EBDBB2FF'
|
|
||||||
term_yellow = '#D79921FF'
|
|
||||||
term_yellow_bright = '#FABD2FFF'
|
|
||||||
terminal_gray = '#928374FF'
|
|
||||||
text_command = '#B8BB26FF'
|
|
||||||
text_comment = '#928374FF'
|
|
||||||
text_disabled = '#665C54FF'
|
|
||||||
text_emphasis = '#FBF1C7FF'
|
|
||||||
text_error = '#FB4934FF'
|
|
||||||
text_inactive = '#7C6F64FF'
|
|
||||||
text_line_number = '#7C6F64FF'
|
|
||||||
text_link = '#83A598FF'
|
|
||||||
text_main = '#EBDBB2FF'
|
|
||||||
text_selected = '#665C5438'
|
|
||||||
text_selection_inactive = '#50494538'
|
|
||||||
text_string = '#B8BB26FF'
|
|
||||||
text_success = '#B8BB26FF'
|
|
||||||
text_warning = '#FABD2FFF'
|
|
||||||
warning = '#FE8019FF'
|
|
||||||
warning_emphasis = '#FABD2FFF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'gruvbox-dark-hard'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#79740EFF'
|
|
||||||
background = '#F9F5D7FF'
|
|
||||||
border_emphasized = '#076678FF'
|
|
||||||
border_focused = '#79740EFF'
|
|
||||||
border_window = '#D5C4A1FF'
|
|
||||||
cursor = '#282828FF'
|
|
||||||
editor_background = '#F9F5D7FF'
|
|
||||||
error = '#9D0006FF'
|
|
||||||
floating_window_background = '#F2E5BCFF'
|
|
||||||
foreground = '#3C3836FF'
|
|
||||||
foreground_emphasis = '#282828FF'
|
|
||||||
foreground_secondary = '#504945FF'
|
|
||||||
info = '#076678FF'
|
|
||||||
menu_option_background = '#F2E5BCFF'
|
|
||||||
outline = '#D5C4A1FF'
|
|
||||||
popup_background = '#FBF1C7FF'
|
|
||||||
shadow = '#00000040'
|
|
||||||
sidebar_background = '#FBF1C7FF'
|
|
||||||
success = '#79740EFF'
|
|
||||||
surface = '#FBF1C7FF'
|
|
||||||
surface_variant = '#F2E5BCFF'
|
|
||||||
syntax_error = '#9D0006FF'
|
|
||||||
syntax_function = '#076678FF'
|
|
||||||
syntax_keyword = '#8F3F71FF'
|
|
||||||
syntax_operator = '#427B58FF'
|
|
||||||
syntax_special_keyword = '#B57614FF'
|
|
||||||
term_black = '#F9F5D7FF'
|
|
||||||
term_black_bright = '#928374FF'
|
|
||||||
term_blue = '#076678FF'
|
|
||||||
term_blue_bright = '#458588FF'
|
|
||||||
term_cyan = '#427B58FF'
|
|
||||||
term_cyan_bright = '#689D6AFF'
|
|
||||||
term_green = '#79740EFF'
|
|
||||||
term_green_bright = '#98971AFF'
|
|
||||||
term_magenta = '#8F3F71FF'
|
|
||||||
term_magenta_bright = '#B16286FF'
|
|
||||||
term_red = '#9D0006FF'
|
|
||||||
term_red_bright = '#CC241DFF'
|
|
||||||
term_white = '#7C6F64FF'
|
|
||||||
term_white_bright = '#3C3836FF'
|
|
||||||
term_yellow = '#B57614FF'
|
|
||||||
term_yellow_bright = '#D79921FF'
|
|
||||||
terminal_gray = '#928374FF'
|
|
||||||
text_command = '#79740EFF'
|
|
||||||
text_comment = '#928374FF'
|
|
||||||
text_disabled = '#D5C4A1FF'
|
|
||||||
text_emphasis = '#282828FF'
|
|
||||||
text_error = '#9D0006FF'
|
|
||||||
text_inactive = '#A89984FF'
|
|
||||||
text_line_number = '#A89984FF'
|
|
||||||
text_link = '#076678FF'
|
|
||||||
text_main = '#3C3836FF'
|
|
||||||
text_selected = '#D5C4A138'
|
|
||||||
text_selection_inactive = '#EBDBB238'
|
|
||||||
text_string = '#79740EFF'
|
|
||||||
text_success = '#79740EFF'
|
|
||||||
text_warning = '#B57614FF'
|
|
||||||
warning = '#AF3A03FF'
|
|
||||||
warning_emphasis = '#B57614FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'gruvbox-light-hard'
|
|
||||||
@@ -1,63 +1,54 @@
|
|||||||
[colors]
|
[colors]
|
||||||
accent = '#007A35FF'
|
accent = '#9A8652FF'
|
||||||
background = '#FFFFFFFF'
|
background = '#E0E0E0FF'
|
||||||
border_emphasized = '#3399FFFF'
|
base00 = '#E0E0E0FF'
|
||||||
border_focused = '#007A35FF'
|
base01 = '#668A51FF'
|
||||||
border_window = '#CCCCCCFF'
|
base02 = '#9A8652FF'
|
||||||
cursor = '#111318FF'
|
base03 = '#B47837FF'
|
||||||
editor_background = '#FFFFFFFF'
|
base04 = '#9A5552FF'
|
||||||
error = '#D00000FF'
|
base05 = '#AA477BFF'
|
||||||
floating_window_background = '#E8E8E8FF'
|
base06 = '#3A898CFF'
|
||||||
foreground = '#1E1F25FF'
|
base07 = '#5A5A5AFF'
|
||||||
foreground_emphasis = '#111318FF'
|
base08 = '#AA4E4AFF'
|
||||||
foreground_secondary = '#44474FFF'
|
base09 = '#4A7A2EFF'
|
||||||
info = '#3399FFFF'
|
base0A = '#7A6A42FF'
|
||||||
menu_option_background = '#E8E8E8FF'
|
base0B = '#A5714BFF'
|
||||||
outline = '#CCCCCCFF'
|
base0C = '#8C5656FF'
|
||||||
popup_background = '#F5F5F5FF'
|
base0D = '#90577EFF'
|
||||||
shadow = '#000000FF'
|
base0E = '#2A6A6DFF'
|
||||||
sidebar_background = '#F5F5F5FF'
|
base0F = '#2A2A2AFF'
|
||||||
success = '#008833FF'
|
border = '#C5C5C5FF'
|
||||||
surface = '#F5F5F5FF'
|
border_focused = '#B9B9B9FF'
|
||||||
surface_variant = '#E8E8E8FF'
|
cursor = '#2A2A2AFF'
|
||||||
syntax_error = '#D00000FF'
|
editor_background = '#E0E0E0FF'
|
||||||
syntax_function = '#0066CCFF'
|
editor_command = '#3A898CFF'
|
||||||
syntax_keyword = '#9933CCFF'
|
editor_comment = '#849899FF'
|
||||||
syntax_operator = '#44474FFF'
|
editor_disabled = '#A0A0A0FF'
|
||||||
syntax_special_keyword = '#FF9900FF'
|
editor_emphasis = '#4A7A2EFF'
|
||||||
term_black = '#111318FF'
|
editor_error = '#AA4E4AFF'
|
||||||
term_black_bright = '#888888FF'
|
editor_inactive = '#A0A0A0FF'
|
||||||
term_blue = '#3399FFFF'
|
editor_line_number = '#9A9A95FF'
|
||||||
term_blue_bright = '#66B2FFFF'
|
editor_link = '#90577EFF'
|
||||||
term_cyan = '#0066CCFF'
|
editor_main = '#2A2A2AFF'
|
||||||
term_cyan_bright = '#99DDFFFF'
|
editor_selected = '#C9C9C9FF'
|
||||||
term_green = '#007A35FF'
|
editor_selection_inactive = '#D2D2D2FF'
|
||||||
term_green_bright = '#33CC66FF'
|
editor_string = '#9A8652FF'
|
||||||
term_magenta = '#9933CCFF'
|
editor_success = '#668A51FF'
|
||||||
term_magenta_bright = '#CC99CCFF'
|
editor_warning = '#B47837FF'
|
||||||
term_red = '#D00000FF'
|
error = '#AA4E4AFF'
|
||||||
term_red_bright = '#FF6666FF'
|
foreground = '#2A2A2AFF'
|
||||||
term_white = '#FFFFFFFF'
|
info = '#3A898CFF'
|
||||||
term_white_bright = '#FFFFFFFF'
|
on_background = '#2A2A2AFF'
|
||||||
term_yellow = '#FF9900FF'
|
on_error = '#FAFAF8FF'
|
||||||
term_yellow_bright = '#FFCC80FF'
|
on_info = '#FAFAF8FF'
|
||||||
terminal_gray = '#CCCCCCFF'
|
on_success = '#FAFAF8FF'
|
||||||
text_command = '#007A35FF'
|
on_surface = '#2A2A2AFF'
|
||||||
text_comment = '#888888FF'
|
on_surface_variant = '#3A3A3AFF'
|
||||||
text_disabled = '#CCCCCCFF'
|
on_warning = '#FAFAF8FF'
|
||||||
text_emphasis = '#111318FF'
|
success = '#668A51FF'
|
||||||
text_error = '#D00000FF'
|
surface = '#E0E0E0FF'
|
||||||
text_inactive = '#44474FFF'
|
surface_variant = '#CECECEFF'
|
||||||
text_line_number = '#888888FF'
|
warning = '#B47837FF'
|
||||||
text_link = '#3399FFFF'
|
|
||||||
text_main = '#1E1F25FF'
|
|
||||||
text_selected = '#D6D6D6FF'
|
|
||||||
text_selection_inactive = '#888888FF'
|
|
||||||
text_string = '#008833FF'
|
|
||||||
text_success = '#008833FF'
|
|
||||||
text_warning = '#FF9900FF'
|
|
||||||
warning = '#FF9900FF'
|
|
||||||
warning_emphasis = '#FFCC80FF'
|
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
name = 'light'
|
name = 'light'
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#286983FF'
|
|
||||||
background = '#FAF4EDFF'
|
|
||||||
border_emphasized = '#907AA9FF'
|
|
||||||
border_focused = '#286983FF'
|
|
||||||
border_window = '#CECACDFF'
|
|
||||||
cursor = '#575279FF'
|
|
||||||
editor_background = '#FAF4EDFF'
|
|
||||||
error = '#B4637AFF'
|
|
||||||
floating_window_background = '#F2E9E1FF'
|
|
||||||
foreground = '#575279FF'
|
|
||||||
foreground_emphasis = '#111318FF'
|
|
||||||
foreground_secondary = '#797593FF'
|
|
||||||
info = '#907AA9FF'
|
|
||||||
menu_option_background = '#F2E9E1FF'
|
|
||||||
outline = '#9893A5FF'
|
|
||||||
popup_background = '#FFFAF3FF'
|
|
||||||
shadow = '#00000020'
|
|
||||||
sidebar_background = '#FFFAF3FF'
|
|
||||||
success = '#286983FF'
|
|
||||||
surface = '#FFFAF3FF'
|
|
||||||
surface_variant = '#F2E9E1FF'
|
|
||||||
syntax_error = '#B4637AFF'
|
|
||||||
syntax_function = '#907AA9FF'
|
|
||||||
syntax_keyword = '#D7827EFF'
|
|
||||||
syntax_operator = '#797593FF'
|
|
||||||
syntax_special_keyword = '#EA9D34FF'
|
|
||||||
term_black = '#FAF4EDFF'
|
|
||||||
term_black_bright = '#DFDAD9FF'
|
|
||||||
term_blue = '#907AA9FF'
|
|
||||||
term_blue_bright = '#66B2FFFF'
|
|
||||||
term_cyan = '#56949FFF'
|
|
||||||
term_cyan_bright = '#99DDFFFF'
|
|
||||||
term_green = '#286983FF'
|
|
||||||
term_green_bright = '#33CC66FF'
|
|
||||||
term_magenta = '#D7827EFF'
|
|
||||||
term_magenta_bright = '#CC99CCFF'
|
|
||||||
term_red = '#B4637AFF'
|
|
||||||
term_red_bright = '#FF6666FF'
|
|
||||||
term_white = '#575279FF'
|
|
||||||
term_white_bright = '#111318FF'
|
|
||||||
term_yellow = '#EA9D34FF'
|
|
||||||
term_yellow_bright = '#FFCC80FF'
|
|
||||||
terminal_gray = '#CCCCCCFF'
|
|
||||||
text_command = '#286983FF'
|
|
||||||
text_comment = '#9893A5FF'
|
|
||||||
text_disabled = '#9893A5FF'
|
|
||||||
text_emphasis = '#111318FF'
|
|
||||||
text_error = '#B4637AFF'
|
|
||||||
text_inactive = '#797593FF'
|
|
||||||
text_line_number = '#9893A5FF'
|
|
||||||
text_link = '#907AA9FF'
|
|
||||||
text_main = '#575279FF'
|
|
||||||
text_selected = '#DFDAD979'
|
|
||||||
text_selection_inactive = '#79759338'
|
|
||||||
text_string = '#286983FF'
|
|
||||||
text_success = '#286983FF'
|
|
||||||
text_warning = '#EA9D34FF'
|
|
||||||
warning = '#EA9D34FF'
|
|
||||||
warning_emphasis = '#FFD580FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'rose-pine-dawn'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[general]
|
|
||||||
name = "rose-pine-moon"
|
|
||||||
|
|
||||||
[colors]
|
|
||||||
accent = "#3e8fb0FF"
|
|
||||||
background = "#232136FF"
|
|
||||||
border_emphasized = "#c4a7e7FF"
|
|
||||||
border_focused = "#3e8fb0FF"
|
|
||||||
border_window = "#56526eFF"
|
|
||||||
cursor = "#e0def4FF"
|
|
||||||
editor_background = "#232136FF"
|
|
||||||
error = "#eb6f92FF"
|
|
||||||
floating_window_background = "#393552FF"
|
|
||||||
foreground = "#e0def4FF"
|
|
||||||
foreground_emphasis = "#ffffffFF"
|
|
||||||
foreground_secondary = "#908caaFF"
|
|
||||||
info = "#c4a7e7FF"
|
|
||||||
menu_option_background = "#393552FF"
|
|
||||||
outline = "#6e6a86FF"
|
|
||||||
popup_background = "#2a273fff"
|
|
||||||
shadow = "#00000080"
|
|
||||||
sidebar_background = "#2a273fff"
|
|
||||||
success = "#3e8fb0FF"
|
|
||||||
surface = "#2a273fff"
|
|
||||||
surface_variant = "#393552FF"
|
|
||||||
syntax_error = "#eb6f92FF"
|
|
||||||
syntax_function = "#c4a7e7FF"
|
|
||||||
syntax_keyword = "#ea9a97FF"
|
|
||||||
syntax_operator = "#908caaFF"
|
|
||||||
syntax_special_keyword = "#f6c177FF"
|
|
||||||
term_black = "#232136FF"
|
|
||||||
term_black_bright = "#44415aFF"
|
|
||||||
term_blue = "#c4a7e7FF"
|
|
||||||
term_blue_bright = "#66b2ffff"
|
|
||||||
term_cyan = "#9ccfd8FF"
|
|
||||||
term_cyan_bright = "#bfefffff"
|
|
||||||
term_green = "#3e8fb0FF"
|
|
||||||
term_green_bright = "#00cc6aff"
|
|
||||||
term_magenta = "#ea9a97FF"
|
|
||||||
term_magenta_bright = "#f0d6f0FF"
|
|
||||||
term_red = "#eb6f92FF"
|
|
||||||
term_red_bright = "#ffb780FF"
|
|
||||||
term_white = "#e0def4FF"
|
|
||||||
term_white_bright = "#ffffffFF"
|
|
||||||
term_yellow = "#f6c177FF"
|
|
||||||
term_yellow_bright = "#ffd580FF"
|
|
||||||
terminal_gray = "#33353AFF"
|
|
||||||
text_command = "#3e8fb0FF"
|
|
||||||
text_comment = "#6e6a86FF"
|
|
||||||
text_disabled = "#6e6a86FF"
|
|
||||||
text_emphasis = "#ffffffFF"
|
|
||||||
text_error = "#eb6f92FF"
|
|
||||||
text_inactive = "#908caaFF"
|
|
||||||
text_line_number = "#6e6a86FF"
|
|
||||||
text_link = "#c4a7e7FF"
|
|
||||||
text_main = "#e0def4FF"
|
|
||||||
text_selected = "#56526e1A"
|
|
||||||
text_selection_inactive = "#908caa38"
|
|
||||||
text_string = "#3e8fb0FF"
|
|
||||||
text_success = "#3e8fb0FF"
|
|
||||||
text_warning = "#f6c177FF"
|
|
||||||
warning = "#f6c177FF"
|
|
||||||
warning_emphasis = "#ffd580FF"
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[colors]
|
|
||||||
accent = '#31748FFF'
|
|
||||||
background = '#191724FF'
|
|
||||||
border_emphasized = '#C4A7E7FF'
|
|
||||||
border_focused = '#31748FFF'
|
|
||||||
border_window = '#524F67FF'
|
|
||||||
cursor = '#E0DEF4FF'
|
|
||||||
editor_background = '#191724FF'
|
|
||||||
error = '#EB6F92FF'
|
|
||||||
floating_window_background = '#26233AFF'
|
|
||||||
foreground = '#E0DEF4FF'
|
|
||||||
foreground_emphasis = '#FFFFFFFF'
|
|
||||||
foreground_secondary = '#908CAAFF'
|
|
||||||
info = '#C4A7E7FF'
|
|
||||||
menu_option_background = '#26233AFF'
|
|
||||||
outline = '#6E6A86FF'
|
|
||||||
popup_background = '#1F1D2EFF'
|
|
||||||
shadow = '#00000080'
|
|
||||||
sidebar_background = '#1F1D2EFF'
|
|
||||||
success = '#31748FFF'
|
|
||||||
surface = '#1F1D2EFF'
|
|
||||||
surface_variant = '#26233AFF'
|
|
||||||
syntax_error = '#EB6F92FF'
|
|
||||||
syntax_function = '#C4A7E7FF'
|
|
||||||
syntax_keyword = '#EBBCBAFF'
|
|
||||||
syntax_operator = '#908CAAFF'
|
|
||||||
syntax_special_keyword = '#F6C177FF'
|
|
||||||
term_black = '#191724FF'
|
|
||||||
term_black_bright = '#403D52FF'
|
|
||||||
term_blue = '#C4A7E7FF'
|
|
||||||
term_blue_bright = '#C4A7E7FF'
|
|
||||||
term_cyan = '#9CCFD8FF'
|
|
||||||
term_cyan_bright = '#9CCFD8FF'
|
|
||||||
term_green = '#31748FFF'
|
|
||||||
term_green_bright = '#31748FFF'
|
|
||||||
term_magenta = '#EBBCBAFF'
|
|
||||||
term_magenta_bright = '#F0D6F0FF'
|
|
||||||
term_red = '#EB6F92FF'
|
|
||||||
term_red_bright = '#EB6F92FF'
|
|
||||||
term_white = '#E0DEF4FF'
|
|
||||||
term_white_bright = '#FFFFFFFF'
|
|
||||||
term_yellow = '#F6C177FF'
|
|
||||||
term_yellow_bright = '#F6C177FF'
|
|
||||||
terminal_gray = '#33353AFF'
|
|
||||||
text_command = '#31748FFF'
|
|
||||||
text_comment = '#6E6A86FF'
|
|
||||||
text_disabled = '#6E6A86FF'
|
|
||||||
text_emphasis = '#FFFFFFFF'
|
|
||||||
text_error = '#EB6F92FF'
|
|
||||||
text_inactive = '#908CAAFF'
|
|
||||||
text_line_number = '#6E6A86FF'
|
|
||||||
text_link = '#C4A7E7FF'
|
|
||||||
text_main = '#E0DEF4FF'
|
|
||||||
text_selected = '#524F671A'
|
|
||||||
text_selection_inactive = '#908CAA38'
|
|
||||||
text_string = '#31748FFF'
|
|
||||||
text_success = '#31748FFF'
|
|
||||||
text_warning = '#F6C177FF'
|
|
||||||
warning = '#F6C177FF'
|
|
||||||
warning_emphasis = '#F6C177FF'
|
|
||||||
|
|
||||||
[general]
|
|
||||||
name = 'rose-pine'
|
|
||||||
@@ -1,36 +1,36 @@
|
|||||||
# BASE COLORS (raw)
|
# BASE COLORS (raw)
|
||||||
color1.raw {term_red}
|
color1.raw {base01}
|
||||||
|
|
||||||
# HEX
|
# HEX
|
||||||
color1.hex {term_red.hex}
|
color1.hex {base01.hex}
|
||||||
color1.hex.stripped {term_red.hex_stripped}
|
color1.hex.stripped {base01.hex_stripped}
|
||||||
|
|
||||||
color1.hexa {term_red.hexa}
|
color1.hexa {base01.hexa}
|
||||||
color1.hexa.stripped {term_red.hexa_stripped}
|
color1.hexa.stripped {base01.hexa_stripped}
|
||||||
|
|
||||||
# RGB (0–255)
|
# RGB (0–255)
|
||||||
color1.rgb {term_red.rgb}
|
color1.rgb {base01.rgb}
|
||||||
color1.r {term_red.r}
|
color1.r {base01.r}
|
||||||
color1.g {term_red.g}
|
color1.g {base01.g}
|
||||||
color1.b {term_red.b}
|
color1.b {base01.b}
|
||||||
|
|
||||||
# RGBA (A = 0–1 normalized)
|
# RGBA (A = 0–1 normalized)
|
||||||
color1.rgba {term_red.rgba}
|
color1.rgba {base01.rgba}
|
||||||
color1.a {term_red.a}
|
color1.a {base01.a}
|
||||||
|
|
||||||
# HSL (normalized 0–1 for s,l, integers for h)
|
# HSL (normalized 0–1 for s,l, integers for h)
|
||||||
color1.hsl {term_red.hsl}
|
color1.hsl {base01.hsl}
|
||||||
color1.h {term_red.h}
|
color1.h {base01.h}
|
||||||
color1.s {term_red.s}
|
color1.s {base01.s}
|
||||||
color1.l {term_red.l}
|
color1.l {base01.l}
|
||||||
|
|
||||||
# HSLA
|
# HSLA
|
||||||
color1.hsla {term_red.hsla}
|
color1.hsla {base01.hsla}
|
||||||
color1.hsla_a {term_red.hsla_a}
|
color1.hsla_a {base01.hsla_a}
|
||||||
|
|
||||||
# Combined custom formats
|
# Combined custom formats
|
||||||
color1.r-g-b {term_red.r}-{term_red.g}-{term_red.b}
|
color1.r-g-b {base01.r}-{base01.g}-{base01.b}
|
||||||
color1.r-g-b-a {term_red.r}-{term_red.g}-{term_red.b}-{term_red.a}
|
color1.r-g-b-a {base01.r}-{base01.g}-{base01.b}-{base01.a}
|
||||||
|
|
||||||
color1.h-s-l {term_red.h}-{term_red.s}-{term_red.l}
|
color1.h-s-l {base01.h}-{base01.s}-{base01.l}
|
||||||
color1.h-s-l-a {term_red.h}-{term_red.s}-{term_red.l}-{term_red.hsla_a}
|
color1.h-s-l-a {base01.h}-{base01.s}-{base01.l}-{base01.hsla_a}
|
||||||
@@ -1,32 +1,32 @@
|
|||||||
cursor {foreground}
|
cursor {cursor}
|
||||||
cursor_text_color {background}
|
cursor_text_color {background}
|
||||||
|
|
||||||
foreground {foreground}
|
foreground {foreground}
|
||||||
background {background}
|
background {background}
|
||||||
selection_foreground {foreground_secondary}
|
selection_foreground {on_surface}
|
||||||
selection_background {surface}
|
selection_background {surface}
|
||||||
url_color {accent}
|
url_color {accent}
|
||||||
|
|
||||||
color8 {surface_variant}
|
color0 {base00}
|
||||||
color0 {background}
|
color8 {base08}
|
||||||
|
|
||||||
color1 {term_red}
|
color1 {base01}
|
||||||
color9 {term_red_bright}
|
color9 {base09}
|
||||||
|
|
||||||
color2 {term_green}
|
color2 {base02}
|
||||||
color10 {term_green_bright}
|
color10 {base0A}
|
||||||
|
|
||||||
color3 {term_yellow}
|
color3 {base03}
|
||||||
color11 {term_yellow_bright}
|
color11 {base0B}
|
||||||
|
|
||||||
color4 {term_blue}
|
color4 {base04}
|
||||||
color12 {term_blue_bright}
|
color12 {base0C}
|
||||||
|
|
||||||
color5 {term_magenta}
|
color5 {base05}
|
||||||
color13 {term_magenta_bright}
|
color13 {base0D}
|
||||||
|
|
||||||
color6 {term_cyan}
|
color6 {base06}
|
||||||
color14 {term_cyan_bright}
|
color14 {base0E}
|
||||||
|
|
||||||
color15 {term_white_bright}
|
color7 {base07}
|
||||||
color7 {term_white}
|
color15 {base0F}
|
||||||
@@ -3,33 +3,39 @@ vim.cmd("syntax reset")
|
|||||||
vim.g.colors_name = "clrsync"
|
vim.g.colors_name = "clrsync"
|
||||||
|
|
||||||
local palette = {
|
local palette = {
|
||||||
-- TextEditor
|
-- Editor colors
|
||||||
Default = "{text_main.hex}",
|
Default = "{editor_main.hex}",
|
||||||
Keyword = "{syntax_keyword.hex}",
|
Keyword = "{editor_command.hex}",
|
||||||
Number = "{text_warning.hex}",
|
Number = "{editor_warning.hex}",
|
||||||
String = "{text_string.hex}",
|
String = "{editor_string.hex}",
|
||||||
CharLiteral = "{text_string.hex}",
|
CharLiteral = "{editor_string.hex}",
|
||||||
Punctuation = "{text_main.hex}",
|
Punctuation = "{editor_main.hex}",
|
||||||
Preprocessor = "{syntax_special_keyword.hex}",
|
Preprocessor = "{editor_emphasis.hex}",
|
||||||
Identifier = "{text_main.hex}",
|
Identifier = "{editor_main.hex}",
|
||||||
KnownIdentifier = "{text_link.hex}",
|
KnownIdentifier = "{editor_link.hex}",
|
||||||
PreprocIdentifier = "{text_link.hex}",
|
PreprocIdentifier = "{editor_link.hex}",
|
||||||
|
|
||||||
Comment = "{text_comment.hex}",
|
Comment = "{editor_comment.hex}",
|
||||||
MultiLineComment = "{text_comment.hex}",
|
MultiLineComment = "{editor_comment.hex}",
|
||||||
|
|
||||||
Background = "{editor_background.hex}",
|
Background = "{editor_background.hex}",
|
||||||
Cursor = "{cursor.hex}",
|
Cursor = "{cursor.hex}",
|
||||||
|
|
||||||
Selection = "{text_selected.hex}",
|
Selection = "{editor_selected.hex}",
|
||||||
ErrorMarker = "{syntax_error.hex}",
|
ErrorMarker = "{editor_error.hex}",
|
||||||
Breakpoint = "{syntax_error.hex}",
|
Breakpoint = "{editor_error.hex}",
|
||||||
|
|
||||||
LineNumber = "{text_line_number.hex}",
|
LineNumber = "{editor_line_number.hex}",
|
||||||
CurrentLineFill = "{surface_variant.hex}",
|
CurrentLineFill = "{surface_variant.hex}",
|
||||||
CurrentLineFillInactive = "{surface.hex}",
|
CurrentLineFillInactive = "{surface.hex}",
|
||||||
|
|
||||||
CurrentLineEdge = "{border_emphasized.hex}",
|
CurrentLineEdge = "{border_focused.hex}",
|
||||||
|
|
||||||
|
-- Semantic colors
|
||||||
|
Success = "{success.hex}",
|
||||||
|
Warning = "{warning.hex}",
|
||||||
|
Error = "{error.hex}",
|
||||||
|
Info = "{info.hex}",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Helper function to set highlights in Neovim
|
-- Helper function to set highlights in Neovim
|
||||||
@@ -59,7 +65,7 @@ set_hl("Type", { fg = palette.Keyword })
|
|||||||
set_hl("Special", { fg = palette.PreprocIdentifier })
|
set_hl("Special", { fg = palette.PreprocIdentifier })
|
||||||
set_hl("Underlined", { fg = palette.KnownIdentifier })
|
set_hl("Underlined", { fg = palette.KnownIdentifier })
|
||||||
set_hl("Error", { fg = palette.ErrorMarker, bg = palette.Background })
|
set_hl("Error", { fg = palette.ErrorMarker, bg = palette.Background })
|
||||||
set_hl("Todo", { fg = palette.Text, bg = palette.Keyword })
|
set_hl("Todo", { fg = palette.Default, bg = palette.Keyword })
|
||||||
|
|
||||||
-- Floating windows
|
-- Floating windows
|
||||||
set_hl("NormalFloat", { bg = palette.Background })
|
set_hl("NormalFloat", { bg = palette.Background })
|
||||||
@@ -70,12 +76,12 @@ set_hl("Pmenu", { bg = palette.Background })
|
|||||||
set_hl("PmenuSel", { bg = palette.Keyword, fg = palette.Background })
|
set_hl("PmenuSel", { bg = palette.Keyword, fg = palette.Background })
|
||||||
|
|
||||||
-- Git and diagnostic highlights
|
-- Git and diagnostic highlights
|
||||||
set_hl("DiffAdd", { fg = palette.Success or palette.Default, bg = palette.Background })
|
set_hl("DiffAdd", { fg = palette.Success, bg = palette.Background })
|
||||||
set_hl("DiffChange", { fg = palette.Keyword, bg = palette.Background })
|
set_hl("DiffChange", { fg = palette.Keyword, bg = palette.Background })
|
||||||
set_hl("DiffDelete", { fg = palette.ErrorMarker, bg = palette.Background })
|
set_hl("DiffDelete", { fg = palette.ErrorMarker, bg = palette.Background })
|
||||||
set_hl("DiagnosticError", { fg = palette.ErrorMarker })
|
set_hl("DiagnosticError", { fg = palette.Error })
|
||||||
set_hl("DiagnosticWarn", { fg = palette.Number })
|
set_hl("DiagnosticWarn", { fg = palette.Warning })
|
||||||
set_hl("DiagnosticInfo", { fg = palette.Keyword })
|
set_hl("DiagnosticInfo", { fg = palette.Info })
|
||||||
set_hl("DiagnosticHint", { fg = palette.PreprocIdentifier })
|
set_hl("DiagnosticHint", { fg = palette.PreprocIdentifier })
|
||||||
|
|
||||||
-- Treesitter links
|
-- Treesitter links
|
||||||
|
|||||||
54
extra/palletes/cursed-light.toml
Normal file
54
extra/palletes/cursed-light.toml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
[colors]
|
||||||
|
accent = '#95A328FF'
|
||||||
|
background = '#F5F5F5FF'
|
||||||
|
base00 = '#F5F5F5FF'
|
||||||
|
base01 = '#B44242FF'
|
||||||
|
base02 = '#95A328FF'
|
||||||
|
base03 = '#C9A305FF'
|
||||||
|
base04 = '#60928FFF'
|
||||||
|
base05 = '#7C435AFF'
|
||||||
|
base06 = '#A48B4AFF'
|
||||||
|
base07 = '#3D3D2FFF'
|
||||||
|
base08 = '#C0C0B8FF'
|
||||||
|
base09 = '#DC7671FF'
|
||||||
|
base0A = '#D4D430FF'
|
||||||
|
base0B = '#9E9052FF'
|
||||||
|
base0C = '#76C39BFF'
|
||||||
|
base0D = '#86596CFF'
|
||||||
|
base0E = '#B89A1FFF'
|
||||||
|
base0F = '#4F4F48FF'
|
||||||
|
border = '#D0D0C8FF'
|
||||||
|
border_focused = '#C9A305FF'
|
||||||
|
cursor = '#C9A305FF'
|
||||||
|
editor_background = '#F5F5F5FF'
|
||||||
|
editor_command = '#B89A1FFF'
|
||||||
|
editor_comment = '#A0A098FF'
|
||||||
|
editor_disabled = '#C0C0B8FF'
|
||||||
|
editor_emphasis = '#DC7671FF'
|
||||||
|
editor_error = '#B44242FF'
|
||||||
|
editor_inactive = '#A0A098FF'
|
||||||
|
editor_line_number = '#86596CFF'
|
||||||
|
editor_link = '#60928FFF'
|
||||||
|
editor_main = '#3D3D2FFF'
|
||||||
|
editor_selected = '#D0D0C8FF'
|
||||||
|
editor_selection_inactive = '#E0E0D8FF'
|
||||||
|
editor_string = '#5FA37BFF'
|
||||||
|
editor_success = '#95A328FF'
|
||||||
|
editor_warning = '#C9A305FF'
|
||||||
|
error = '#B44242FF'
|
||||||
|
foreground = '#3D3D2FFF'
|
||||||
|
info = '#60928FFF'
|
||||||
|
on_background = '#3D3D2FFF'
|
||||||
|
on_error = '#F5F5F5FF'
|
||||||
|
on_info = '#F5F5F5FF'
|
||||||
|
on_success = '#F5F5F5FF'
|
||||||
|
on_surface = '#3D3D2FFF'
|
||||||
|
on_surface_variant = '#CCCCCCFF'
|
||||||
|
on_warning = '#F5F5F5FF'
|
||||||
|
success = '#95A328FF'
|
||||||
|
surface = '#E8E8E8FF'
|
||||||
|
surface_variant = '#D0D0C8FF'
|
||||||
|
warning = '#C9A305FF'
|
||||||
|
|
||||||
|
[general]
|
||||||
|
name = 'cursed-light'
|
||||||
54
extra/palletes/cursed.toml
Normal file
54
extra/palletes/cursed.toml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
[colors]
|
||||||
|
accent = '#95A328FF'
|
||||||
|
background = '#151515FF'
|
||||||
|
base00 = '#151515FF'
|
||||||
|
base01 = '#B44242FF'
|
||||||
|
base02 = '#95A328FF'
|
||||||
|
base03 = '#E1C135FF'
|
||||||
|
base04 = '#60928FFF'
|
||||||
|
base05 = '#7C435AFF'
|
||||||
|
base06 = '#A48B4AFF'
|
||||||
|
base07 = '#C2C2B0FF'
|
||||||
|
base08 = '#3F3639FF'
|
||||||
|
base09 = '#DC7671FF'
|
||||||
|
base0A = '#E8E85AFF'
|
||||||
|
base0B = '#9E9052FF'
|
||||||
|
base0C = '#76C39BFF'
|
||||||
|
base0D = '#86596CFF'
|
||||||
|
base0E = '#CEB34FFF'
|
||||||
|
base0F = '#B0AFA8FF'
|
||||||
|
border = '#3F3639FF'
|
||||||
|
border_focused = '#E1C135FF'
|
||||||
|
cursor = '#E1C135FF'
|
||||||
|
editor_background = '#151515FF'
|
||||||
|
editor_command = '#CEB34FFF'
|
||||||
|
editor_comment = '#7A7A7AFF'
|
||||||
|
editor_disabled = '#3F3639FF'
|
||||||
|
editor_emphasis = '#DC7671FF'
|
||||||
|
editor_error = '#B44242FF'
|
||||||
|
editor_inactive = '#3F3639FF'
|
||||||
|
editor_line_number = '#86596CFF'
|
||||||
|
editor_link = '#60928FFF'
|
||||||
|
editor_main = '#C2C2B0FF'
|
||||||
|
editor_selected = '#3F3639FF'
|
||||||
|
editor_selection_inactive = '#2A2A2AFF'
|
||||||
|
editor_string = '#76C39BFF'
|
||||||
|
editor_success = '#95A328FF'
|
||||||
|
editor_warning = '#E1C135FF'
|
||||||
|
error = '#B44242FF'
|
||||||
|
foreground = '#C2C2B0FF'
|
||||||
|
info = '#60928FFF'
|
||||||
|
on_background = '#C2C2B0FF'
|
||||||
|
on_error = '#151515FF'
|
||||||
|
on_info = '#151515FF'
|
||||||
|
on_success = '#151515FF'
|
||||||
|
on_surface = '#C2C2B0FF'
|
||||||
|
on_surface_variant = '#CCCCCCFF'
|
||||||
|
on_warning = '#151515FF'
|
||||||
|
success = '#95A328FF'
|
||||||
|
surface = '#1C1C1CFF'
|
||||||
|
surface_variant = '#1C1C1CFF'
|
||||||
|
warning = '#E1C135FF'
|
||||||
|
|
||||||
|
[general]
|
||||||
|
name = 'cursed'
|
||||||
54
extra/palletes/nord.toml
Normal file
54
extra/palletes/nord.toml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
[colors]
|
||||||
|
accent = '#5E81ACFF'
|
||||||
|
background = '#2E3440FF'
|
||||||
|
base00 = '#2E3440FF'
|
||||||
|
base01 = '#BF616AFF'
|
||||||
|
base02 = '#A3BE8CFF'
|
||||||
|
base03 = '#EBCB8BFF'
|
||||||
|
base04 = '#81A1C1FF'
|
||||||
|
base05 = '#B48EADFF'
|
||||||
|
base06 = '#88C0D0FF'
|
||||||
|
base07 = '#E5E9F0FF'
|
||||||
|
base08 = '#4C566AFF'
|
||||||
|
base09 = '#D08770FF'
|
||||||
|
base0A = '#EBCB8BFF'
|
||||||
|
base0B = '#A3BE8CFF'
|
||||||
|
base0C = '#8FBCBBFF'
|
||||||
|
base0D = '#5E81ACFF'
|
||||||
|
base0E = '#B48EADFF'
|
||||||
|
base0F = '#ECEFF4FF'
|
||||||
|
border = '#4C566AFF'
|
||||||
|
border_focused = '#88C0D0FF'
|
||||||
|
cursor = '#D8DEE9FF'
|
||||||
|
editor_background = '#2E3440FF'
|
||||||
|
editor_command = '#81A1C1FF'
|
||||||
|
editor_comment = '#616E88FF'
|
||||||
|
editor_disabled = '#4C566AFF'
|
||||||
|
editor_emphasis = '#B48EADFF'
|
||||||
|
editor_error = '#BF616AFF'
|
||||||
|
editor_inactive = '#616E88FF'
|
||||||
|
editor_line_number = '#4C566AFF'
|
||||||
|
editor_link = '#88C0D0FF'
|
||||||
|
editor_main = '#D8DEE9FF'
|
||||||
|
editor_selected = '#434C5EFF'
|
||||||
|
editor_selection_inactive = '#3B4252FF'
|
||||||
|
editor_string = '#A3BE8CFF'
|
||||||
|
editor_success = '#A3BE8CFF'
|
||||||
|
editor_warning = '#EBCB8BFF'
|
||||||
|
error = '#BF616AFF'
|
||||||
|
foreground = '#D8DEE9FF'
|
||||||
|
info = '#5E81ACFF'
|
||||||
|
on_background = '#D8DEE9FF'
|
||||||
|
on_error = '#2E3440FF'
|
||||||
|
on_info = '#2E3440FF'
|
||||||
|
on_success = '#2E3440FF'
|
||||||
|
on_surface = '#ECEFF4FF'
|
||||||
|
on_surface_variant = '#ECEFF4FF'
|
||||||
|
on_warning = '#2E3440FF'
|
||||||
|
success = '#A3BE8CFF'
|
||||||
|
surface = '#3B4252FF'
|
||||||
|
surface_variant = '#434C5EFF'
|
||||||
|
warning = '#EBCB8BFF'
|
||||||
|
|
||||||
|
[general]
|
||||||
|
name = 'nord'
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764950072,
|
||||||
|
"narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "f61125a668a320878494449750330ca58b78c557",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
94
flake.nix
Normal file
94
flake.nix
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
description = "clrsync - Color scheme manager";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self, nixpkgs, ... }:
|
||||||
|
let
|
||||||
|
supportedSystems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
];
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
||||||
|
|
||||||
|
baseVersion = nixpkgs.lib.removeSuffix "\n" (builtins.readFile ./VERSION);
|
||||||
|
|
||||||
|
semver =
|
||||||
|
if self ? rev then
|
||||||
|
"${baseVersion}+git.${builtins.substring 0 7 self.rev}"
|
||||||
|
else
|
||||||
|
"${baseVersion}+dev";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = forAllSystems (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
clrsync = pkgs.callPackage ./package.nix { inherit semver; };
|
||||||
|
default = clrsync;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
homeModules = {
|
||||||
|
default = import ./home-manager-module.nix self;
|
||||||
|
clrsync = self.homeModules.default;
|
||||||
|
};
|
||||||
|
|
||||||
|
apps = forAllSystems (system: {
|
||||||
|
clrsync-gui = {
|
||||||
|
type = "app";
|
||||||
|
program = "${self.packages.${system}.clrsync}/bin/clrsync_gui";
|
||||||
|
meta = {
|
||||||
|
description = "clrsync gui app";
|
||||||
|
license = self.packages.x86_64-linux.licenses.mit;
|
||||||
|
maintainers = [ "Daniel Dada" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clrsync-cli = {
|
||||||
|
type = "app";
|
||||||
|
program = "${self.packages.${system}.clrsync}/bin/clrsync_cli";
|
||||||
|
meta = {
|
||||||
|
description = "clrsync cli app";
|
||||||
|
license = self.packages.x86_64-linux.licenses.mit;
|
||||||
|
maintainers = [ "Daniel Dada" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
default = self.apps.${system}.clrsync-cli;
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forAllSystems (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
clrsync = self.packages.${system}.clrsync;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
inputsFrom = [ clrsync ];
|
||||||
|
packages = with pkgs; [
|
||||||
|
cmake
|
||||||
|
ninja
|
||||||
|
clang-tools
|
||||||
|
gdb
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export CMAKE_GENERATOR="Ninja"
|
||||||
|
export CMAKE_EXPORT_COMPILE_COMMANDS=1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
overlays.default = final: prev: {
|
||||||
|
clrsync = self.packages.${final.system}.clrsync;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
155
home-manager-module.nix
Normal file
155
home-manager-module.nix
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
flake:
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.programs.clrsync;
|
||||||
|
|
||||||
|
clrsyncPackage = flake.packages.${pkgs.system}.default;
|
||||||
|
|
||||||
|
templateType = types.submodule {
|
||||||
|
options = {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable this template.";
|
||||||
|
};
|
||||||
|
inputPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Path to the template input file.";
|
||||||
|
};
|
||||||
|
outputPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Path where the generated output will be written.";
|
||||||
|
};
|
||||||
|
reloadCmd = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = "Command to run after generating the output.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configFormat = pkgs.formats.toml { };
|
||||||
|
configFile = configFormat.generate "config.toml" {
|
||||||
|
general = {
|
||||||
|
default_theme = cfg.defaultTheme;
|
||||||
|
palettes_path = cfg.palettesPath;
|
||||||
|
font = cfg.font;
|
||||||
|
font_size = cfg.fontSize;
|
||||||
|
};
|
||||||
|
templates = mapAttrs (
|
||||||
|
name: template: {
|
||||||
|
enabled = template.enabled;
|
||||||
|
input_path = template.inputPath;
|
||||||
|
output_path = template.outputPath;
|
||||||
|
reload_cmd = template.reloadCmd;
|
||||||
|
}
|
||||||
|
) cfg.templates;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.programs.clrsync = {
|
||||||
|
enable = mkEnableOption "clrsync color synchronization";
|
||||||
|
|
||||||
|
defaultTheme = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "cursed";
|
||||||
|
description = "Default theme to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
palettesPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "~/.config/clrsync/palettes";
|
||||||
|
description = "Path to color palettes directory.";
|
||||||
|
};
|
||||||
|
|
||||||
|
font = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "JetBrainsMono Nerd Font Mono";
|
||||||
|
description = "Font family to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
fontSize = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 14;
|
||||||
|
description = "Font size.";
|
||||||
|
};
|
||||||
|
|
||||||
|
templates = mkOption {
|
||||||
|
type = types.attrsOf templateType;
|
||||||
|
default = { };
|
||||||
|
description = "Template configurations.";
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
kitty = {
|
||||||
|
enabled = true;
|
||||||
|
inputPath = "~/.config/clrsync/templates/kitty.conf";
|
||||||
|
outputPath = "~/.config/kitty/kitty_test.conf";
|
||||||
|
reloadCmd = "pkill -SIGUSR1 kitty";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
applyTheme = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to apply the default theme on activation.";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemdTarget = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "graphical-session.target";
|
||||||
|
description = "Systemd target to bind the clrsync service to.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = [ clrsyncPackage ];
|
||||||
|
|
||||||
|
xdg.enable = true;
|
||||||
|
|
||||||
|
home.activation.clrsyncDesktop = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
if [ -d "$HOME/.nix-profile/share/applications" ]; then
|
||||||
|
${pkgs.desktop-file-utils}/bin/update-desktop-database "$HOME/.nix-profile/share/applications" || true
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
xdg.configFile."clrsync/config.toml" = {
|
||||||
|
source = configFile;
|
||||||
|
force = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.activation.clrsyncConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
run --quiet mkdir -p $HOME/.config/clrsync
|
||||||
|
run --quiet cp -f ${configFile} $HOME/.config/clrsync/config.toml
|
||||||
|
'';
|
||||||
|
|
||||||
|
home.activation.clrsyncApply = mkIf cfg.applyTheme (
|
||||||
|
lib.hm.dag.entryAfter [ "clrsyncConfig" ] ''
|
||||||
|
run --quiet ${clrsyncPackage}/bin/clrsync_cli --apply --theme ${cfg.defaultTheme}
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
systemd.user.services.clrsync = mkIf cfg.applyTheme {
|
||||||
|
Unit = {
|
||||||
|
Description = "Apply clrsync color palette";
|
||||||
|
After = [ cfg.systemdTarget ];
|
||||||
|
PartOf = [ cfg.systemdTarget ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${clrsyncPackage}/bin/clrsync_cli --apply --theme ${cfg.defaultTheme}";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ cfg.systemdTarget ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
107
meson.build
107
meson.build
@@ -1,107 +0,0 @@
|
|||||||
project('clrsync', 'cpp',
|
|
||||||
version : '0.1.0',
|
|
||||||
default_options : [
|
|
||||||
'cpp_std=c++20',
|
|
||||||
'buildtype=debug',
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
imgui_dep = dependency('imgui-docking',
|
|
||||||
fallback : ['imgui-docking', 'imgui_dep'],
|
|
||||||
default_options : [
|
|
||||||
'default_library=static',
|
|
||||||
'opengl=enabled',
|
|
||||||
'glfw=enabled',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
imgui_dep = declare_dependency(
|
|
||||||
compile_args: ['-DIMGUI_ENABLE_FREETYPE'],
|
|
||||||
dependencies: [imgui_dep]
|
|
||||||
)
|
|
||||||
|
|
||||||
glfw_dep = dependency('glfw3', fallback : ['glfw', 'glfw_dep'])
|
|
||||||
gl_dep = dependency('gl')
|
|
||||||
|
|
||||||
freetype_dep = dependency('freetype2')
|
|
||||||
|
|
||||||
inc_dirs = include_directories('src')
|
|
||||||
lib_inc_dirs = include_directories('lib')
|
|
||||||
|
|
||||||
cpp_args = []
|
|
||||||
if host_machine.system() == 'windows'
|
|
||||||
compiler = meson.get_compiler('cpp')
|
|
||||||
if compiler.get_id() == 'msvc'
|
|
||||||
cpp_args += ['/EHsc']
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
core_sources = [
|
|
||||||
'src/core/palette/color.cpp',
|
|
||||||
'src/core/io/toml_file.cpp',
|
|
||||||
'src/core/config/config.cpp',
|
|
||||||
'src/core/utils.cpp',
|
|
||||||
'src/core/version.cpp',
|
|
||||||
'src/core/theme/theme_template.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
text_edit_sources = [
|
|
||||||
'lib/color_text_edit/TextEditor.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
clrsync_core = static_library(
|
|
||||||
'clrsync_core',
|
|
||||||
core_sources,
|
|
||||||
include_directories : [inc_dirs, lib_inc_dirs],
|
|
||||||
cpp_args : cpp_args,
|
|
||||||
)
|
|
||||||
|
|
||||||
clrsync_core_dep = declare_dependency(
|
|
||||||
link_with : clrsync_core,
|
|
||||||
include_directories : [inc_dirs, lib_inc_dirs],
|
|
||||||
)
|
|
||||||
|
|
||||||
clrsync_cli = executable(
|
|
||||||
'clrsync_cli',
|
|
||||||
'src/cli/main.cpp',
|
|
||||||
include_directories : [inc_dirs, lib_inc_dirs],
|
|
||||||
link_with : clrsync_core,
|
|
||||||
cpp_args : cpp_args,
|
|
||||||
)
|
|
||||||
|
|
||||||
gui_sources = [
|
|
||||||
'src/gui/main.cpp',
|
|
||||||
'src/gui/color_scheme_editor.cpp',
|
|
||||||
'src/gui/template_editor.cpp',
|
|
||||||
'src/gui/palette_controller.cpp',
|
|
||||||
'src/gui/template_controller.cpp',
|
|
||||||
'src/gui/imgui_helpers.cpp',
|
|
||||||
'src/gui/about_window.cpp',
|
|
||||||
'src/gui/settings_window.cpp',
|
|
||||||
'src/gui/font_loader.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
clrsync_gui_link_args = []
|
|
||||||
|
|
||||||
fontconfig_dep = dependency('', required : false)
|
|
||||||
if host_machine.system() == 'linux'
|
|
||||||
fontconfig_dep = dependency('fontconfig', required : true)
|
|
||||||
clrsync_gui_link_args += ['-lX11', '-lXrandr', '-lXi']
|
|
||||||
endif
|
|
||||||
|
|
||||||
clrsync_gui = executable(
|
|
||||||
'clrsync_gui',
|
|
||||||
gui_sources,
|
|
||||||
text_edit_sources,
|
|
||||||
include_directories : [inc_dirs, lib_inc_dirs],
|
|
||||||
dependencies : [
|
|
||||||
clrsync_core_dep,
|
|
||||||
imgui_dep,
|
|
||||||
freetype_dep,
|
|
||||||
glfw_dep,
|
|
||||||
gl_dep,
|
|
||||||
fontconfig_dep,
|
|
||||||
],
|
|
||||||
cpp_args : cpp_args,
|
|
||||||
link_args : clrsync_gui_link_args
|
|
||||||
)
|
|
||||||
104
package.nix
Normal file
104
package.nix
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
cmake,
|
||||||
|
git,
|
||||||
|
pkg-config,
|
||||||
|
makeWrapper,
|
||||||
|
wrapGAppsHook3,
|
||||||
|
wayland-protocols,
|
||||||
|
glfw,
|
||||||
|
freetype,
|
||||||
|
fontconfig,
|
||||||
|
mesa,
|
||||||
|
xorg,
|
||||||
|
wayland,
|
||||||
|
libxkbcommon,
|
||||||
|
zlib,
|
||||||
|
bzip2,
|
||||||
|
wayland-scanner,
|
||||||
|
gtk3,
|
||||||
|
glib,
|
||||||
|
gsettings-desktop-schemas,
|
||||||
|
semver,
|
||||||
|
}:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "clrsync";
|
||||||
|
|
||||||
|
version = semver;
|
||||||
|
|
||||||
|
src = lib.cleanSourceWith {
|
||||||
|
src = ./.;
|
||||||
|
filter =
|
||||||
|
path: type:
|
||||||
|
let
|
||||||
|
baseName = baseNameOf path;
|
||||||
|
in
|
||||||
|
!(
|
||||||
|
lib.hasSuffix ".o" baseName
|
||||||
|
|| lib.hasSuffix ".a" baseName
|
||||||
|
|| baseName == "build"
|
||||||
|
|| baseName == "CMakeCache.txt"
|
||||||
|
|| baseName == "CMakeFiles"
|
||||||
|
|| baseName == ".git"
|
||||||
|
|| baseName == "result"
|
||||||
|
|| baseName == ".direnv"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
git
|
||||||
|
pkg-config
|
||||||
|
makeWrapper
|
||||||
|
wrapGAppsHook3
|
||||||
|
wayland-protocols
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
glfw
|
||||||
|
freetype
|
||||||
|
fontconfig
|
||||||
|
xorg.libXcursor
|
||||||
|
mesa
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXrandr
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXinerama
|
||||||
|
wayland
|
||||||
|
wayland-scanner
|
||||||
|
wayland-protocols
|
||||||
|
libxkbcommon
|
||||||
|
zlib
|
||||||
|
bzip2
|
||||||
|
gtk3
|
||||||
|
gsettings-desktop-schemas
|
||||||
|
glib
|
||||||
|
];
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
"-DUSE_SYSTEM_GLFW=ON"
|
||||||
|
"-DCLRSYNC_SEMVER=${version}"
|
||||||
|
];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
cmake --install . --prefix $out
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
dontWrapGApps = false;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Color scheme manager with GUI and CLI";
|
||||||
|
homepage = "https://github.com/obsqrbtz/clrsync";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
mainProgram = "clrsync_gui";
|
||||||
|
maintainers = [ "Daniel Dada" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
8
src/cli/CMakeLists.txt
Normal file
8
src/cli/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
add_executable(clrsync_cli main.cpp)
|
||||||
|
|
||||||
|
target_include_directories(clrsync_cli PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
SYSTEM ${CMAKE_SOURCE_DIR}/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(clrsync_cli PRIVATE clrsync_core)
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
#include <core/utils.hpp>
|
|
||||||
#include <core/config/config.hpp>
|
#include <core/config/config.hpp>
|
||||||
|
#include <core/error.hpp>
|
||||||
#include <core/io/toml_file.hpp>
|
#include <core/io/toml_file.hpp>
|
||||||
#include <core/palette/palette_file.hpp>
|
#include <core/palette/palette_file.hpp>
|
||||||
#include <core/palette/palette_manager.hpp>
|
#include <core/palette/palette_manager.hpp>
|
||||||
#include <core/theme/theme_template.hpp>
|
|
||||||
#include <core/theme/theme_renderer.hpp>
|
#include <core/theme/theme_renderer.hpp>
|
||||||
|
#include <core/theme/theme_template.hpp>
|
||||||
|
#include <core/utils.hpp>
|
||||||
#include <core/version.hpp>
|
#include <core/version.hpp>
|
||||||
|
|
||||||
void handle_show_vars()
|
void handle_show_vars()
|
||||||
@@ -21,8 +22,7 @@ void handle_show_vars()
|
|||||||
void handle_list_themes()
|
void handle_list_themes()
|
||||||
{
|
{
|
||||||
auto palette_manager = clrsync::core::palette_manager<clrsync::core::io::toml_file>();
|
auto palette_manager = clrsync::core::palette_manager<clrsync::core::io::toml_file>();
|
||||||
palette_manager.load_palettes_from_directory(
|
palette_manager.load_palettes_from_directory(clrsync::core::config::instance().palettes_path());
|
||||||
clrsync::core::config::instance().palettes_path());
|
|
||||||
|
|
||||||
const auto &palettes = palette_manager.palettes();
|
const auto &palettes = palette_manager.palettes();
|
||||||
std::cout << "Available themes:" << std::endl;
|
std::cout << "Available themes:" << std::endl;
|
||||||
@@ -36,16 +36,17 @@ int handle_apply_theme(const argparse::ArgumentParser &program, const std::strin
|
|||||||
{
|
{
|
||||||
clrsync::core::theme_renderer<clrsync::core::io::toml_file> renderer;
|
clrsync::core::theme_renderer<clrsync::core::io::toml_file> renderer;
|
||||||
std::string theme_identifier;
|
std::string theme_identifier;
|
||||||
|
clrsync::core::Result<void> result = clrsync::core::Ok();
|
||||||
|
|
||||||
if (program.is_used("--theme"))
|
if (program.is_used("--theme"))
|
||||||
{
|
{
|
||||||
theme_identifier = program.get<std::string>("--theme");
|
theme_identifier = program.get<std::string>("--theme");
|
||||||
renderer.apply_theme(theme_identifier);
|
result = renderer.apply_theme(theme_identifier);
|
||||||
}
|
}
|
||||||
else if (program.is_used("--path"))
|
else if (program.is_used("--path"))
|
||||||
{
|
{
|
||||||
theme_identifier = program.get<std::string>("--path");
|
theme_identifier = program.get<std::string>("--path");
|
||||||
renderer.apply_theme_from_path(theme_identifier);
|
result = renderer.apply_theme_from_path(theme_identifier);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -55,43 +56,41 @@ int handle_apply_theme(const argparse::ArgumentParser &program, const std::strin
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
theme_identifier = default_theme;
|
theme_identifier = default_theme;
|
||||||
renderer.apply_theme(theme_identifier);
|
result = renderer.apply_theme(theme_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to apply theme: " << result.error().description() << std::endl;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Applied theme " << theme_identifier << std::endl;
|
std::cout << "Applied theme " << theme_identifier << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_config(const std::string &config_path)
|
clrsync::core::Result<void> initialize_config(const std::string &config_path)
|
||||||
{
|
{
|
||||||
auto conf = std::make_unique<clrsync::core::io::toml_file>(config_path);
|
auto conf = std::make_unique<clrsync::core::io::toml_file>(config_path);
|
||||||
clrsync::core::config::instance().initialize(std::move(conf));
|
return clrsync::core::config::instance().initialize(std::move(conf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_argument_parser(argparse::ArgumentParser &program)
|
void setup_argument_parser(argparse::ArgumentParser &program)
|
||||||
{
|
{
|
||||||
program.add_argument("-a", "--apply")
|
program.add_argument("-a", "--apply").help("applies default theme").flag();
|
||||||
.help("applies default theme")
|
|
||||||
.flag();
|
|
||||||
|
|
||||||
program.add_argument("-c", "--config")
|
program.add_argument("-c", "--config")
|
||||||
.default_value(clrsync::core::get_default_config_path())
|
.default_value(clrsync::core::get_default_config_path())
|
||||||
.help("sets config file path")
|
.help("sets config file path")
|
||||||
.metavar("PATH");
|
.metavar("PATH");
|
||||||
|
|
||||||
program.add_argument("-l", "--list-themes")
|
program.add_argument("-l", "--list-themes").help("lists available themes").flag();
|
||||||
.help("lists available themes")
|
|
||||||
.flag();
|
|
||||||
|
|
||||||
program.add_argument("-s", "--show-vars")
|
program.add_argument("-s", "--show-vars").help("shows color keys").flag();
|
||||||
.help("shows color keys")
|
|
||||||
.flag();
|
|
||||||
|
|
||||||
auto &group = program.add_mutually_exclusive_group();
|
auto &group = program.add_mutually_exclusive_group();
|
||||||
group.add_argument("-t", "--theme")
|
group.add_argument("-t", "--theme").help("sets theme <theme_name> to apply");
|
||||||
.help("sets theme <theme_name> to apply");
|
group.add_argument("-p", "--path").help("sets theme file <path/to/theme> to apply");
|
||||||
group.add_argument("-p", "--path")
|
|
||||||
.help("sets theme file <path/to/theme> to apply");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@@ -112,13 +111,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
std::string config_path = program.get<std::string>("--config");
|
std::string config_path = program.get<std::string>("--config");
|
||||||
|
|
||||||
try
|
auto config_result = initialize_config(config_path);
|
||||||
|
if (!config_result)
|
||||||
{
|
{
|
||||||
initialize_config(config_path);
|
std::cerr << "Error loading config: " << config_result.error().description() << std::endl;
|
||||||
}
|
|
||||||
catch (const std::exception &err)
|
|
||||||
{
|
|
||||||
std::cerr << "Error loading config: " << err.what() << std::endl;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
src/core/CMakeLists.txt
Normal file
21
src/core/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
set(CORE_SOURCES
|
||||||
|
palette/color.cpp
|
||||||
|
io/toml_file.cpp
|
||||||
|
config/config.cpp
|
||||||
|
utils.cpp
|
||||||
|
version.cpp
|
||||||
|
theme/theme_template.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
|
|
||||||
|
add_library(clrsync_core SHARED ${CORE_SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(clrsync_core PUBLIC
|
||||||
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
SYSTEM ${CMAKE_SOURCE_DIR}/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(clrsync_core PUBLIC
|
||||||
|
CLRSYNC_DATADIR=\"${CMAKE_INSTALL_FULL_DATADIR}/clrsync\"
|
||||||
|
)
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "core/utils.hpp"
|
||||||
|
#include "core/error.hpp"
|
||||||
|
|
||||||
#include <core/palette/color.hpp>
|
#include <core/palette/color.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <stdexcept>
|
#include <fstream>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "windows.h"
|
||||||
|
#endif
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
@@ -12,46 +19,118 @@ config &config::instance()
|
|||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::initialize(std::unique_ptr<clrsync::core::io::file> file)
|
Result<void> config::initialize(std::unique_ptr<clrsync::core::io::file> file)
|
||||||
{
|
{
|
||||||
copy_default_configs();
|
copy_default_configs();
|
||||||
m_file = std::move(file);
|
m_file = std::move(file);
|
||||||
if (m_file)
|
if (!m_file)
|
||||||
if (!m_file->parse())
|
return Err<void>(error_code::config_missing, "Config file is missing");
|
||||||
throw std::runtime_error{"Could not parse config file"};
|
|
||||||
|
auto parse_result = m_file->parse();
|
||||||
|
if (!parse_result)
|
||||||
|
return Err<void>(error_code::config_invalid, parse_result.error().message, parse_result.error().context);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path config::get_user_config_dir()
|
std::filesystem::path config::get_user_config_dir()
|
||||||
{
|
{
|
||||||
|
std::filesystem::path home = normalize_path("~");
|
||||||
|
return home / ".config" / "clrsync";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path config::get_data_dir()
|
||||||
|
{
|
||||||
|
if (std::filesystem::exists(CLRSYNC_DATADIR))
|
||||||
|
return {CLRSYNC_DATADIR};
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (const char *appdata = std::getenv("APPDATA"))
|
char buffer[MAX_PATH];
|
||||||
return fs::path(appdata) / "clrsync";
|
GetModuleFileNameA(nullptr, buffer, MAX_PATH);
|
||||||
else
|
std::filesystem::path exe_path(buffer);
|
||||||
return fs::path("C:/clrsync");
|
std::filesystem::path data_dir = exe_path.parent_path().parent_path() / "share" / "clrsync";
|
||||||
|
return data_dir;
|
||||||
#else
|
#else
|
||||||
if (const char *xdg = std::getenv("XDG_CONFIG_HOME"))
|
if (std::filesystem::exists("/usr/share/clrsync"))
|
||||||
return std::filesystem::path(xdg) / "clrsync";
|
return {"/usr/share/clrsync"};
|
||||||
else if (const char *home = std::getenv("HOME"))
|
if (std::filesystem::exists("/usr/local/share/clrsync"))
|
||||||
return std::filesystem::path(home) / ".config/clrsync";
|
return {"/usr/local/share/clrsync"};
|
||||||
else
|
return {};
|
||||||
return std::filesystem::path("/tmp/clrsync");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void config::copy_file(const std::filesystem::path &src, const std::filesystem::path &dst)
|
||||||
|
{
|
||||||
|
if (std::filesystem::exists(dst))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::ifstream in(src, std::ios::binary);
|
||||||
|
std::ofstream out(dst, std::ios::binary);
|
||||||
|
|
||||||
|
if (!in || !out)
|
||||||
|
return;
|
||||||
|
|
||||||
|
out << in.rdbuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config::copy_dir(const std::filesystem::path &src, const std::filesystem::path &dst)
|
||||||
|
{
|
||||||
|
if (!std::filesystem::exists(src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto const &entry : std::filesystem::recursive_directory_iterator(src))
|
||||||
|
{
|
||||||
|
auto rel = std::filesystem::relative(entry.path(), src);
|
||||||
|
auto out = dst / rel;
|
||||||
|
|
||||||
|
if (entry.is_directory())
|
||||||
|
{
|
||||||
|
std::filesystem::create_directories(out);
|
||||||
|
}
|
||||||
|
else if (entry.is_regular_file())
|
||||||
|
{
|
||||||
|
copy_file(entry.path(), out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void config::copy_default_configs()
|
void config::copy_default_configs()
|
||||||
{
|
{
|
||||||
std::filesystem::path user_config = get_user_config_dir();
|
std::filesystem::path user_dir = get_user_config_dir();
|
||||||
|
std::filesystem::path system_dir = get_data_dir();
|
||||||
|
|
||||||
|
std::filesystem::create_directories(user_dir);
|
||||||
|
|
||||||
|
if (system_dir.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!std::filesystem::exists(user_config))
|
|
||||||
{
|
{
|
||||||
std::filesystem::create_directories(user_config);
|
auto src = system_dir / "config.toml";
|
||||||
|
auto dst = user_dir / "config.toml";
|
||||||
|
if (!std::filesystem::exists(dst))
|
||||||
|
copy_file(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path default_dir = CLRSYNC_DATADIR;
|
{
|
||||||
std::filesystem::copy(default_dir / "config.toml", user_config / "config.toml");
|
auto src = system_dir / "templates";
|
||||||
std::filesystem::copy(default_dir / "templates", user_config / "templates",
|
auto dst = user_dir / "templates";
|
||||||
std::filesystem::copy_options::recursive);
|
|
||||||
std::filesystem::copy(default_dir / "palettes", user_config / "palettes",
|
if (!std::filesystem::exists(dst))
|
||||||
std::filesystem::copy_options::recursive);
|
std::filesystem::create_directories(dst);
|
||||||
|
|
||||||
|
copy_dir(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto src = system_dir / "palettes";
|
||||||
|
auto dst = user_dir / "palettes";
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(dst))
|
||||||
|
std::filesystem::create_directories(dst);
|
||||||
|
|
||||||
|
copy_dir(src, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,50 +162,79 @@ const uint32_t config::font_size() const
|
|||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::set_default_theme(const std::string &theme)
|
Result<void> config::set_default_theme(const std::string &theme)
|
||||||
{
|
{
|
||||||
if (m_file)
|
if (!m_file)
|
||||||
{
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
m_file->set_value("general", "default_theme", theme);
|
m_file->set_value("general", "default_theme", theme);
|
||||||
m_file->save_file();
|
return m_file->save_file();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::set_palettes_path(const std::string &path)
|
Result<void> config::set_palettes_path(const std::string &path)
|
||||||
{
|
{
|
||||||
if (m_file)
|
if (!m_file)
|
||||||
{
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
m_file->set_value("general", "palettes_path", path);
|
m_file->set_value("general", "palettes_path", path);
|
||||||
m_file->save_file();
|
return m_file->save_file();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::set_font(const std::string &font)
|
Result<void> config::set_font(const std::string &font)
|
||||||
{
|
{
|
||||||
if (m_file)
|
if (!m_file)
|
||||||
{
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
m_file->set_value("general", "font", font);
|
m_file->set_value("general", "font", font);
|
||||||
m_file->save_file();
|
return m_file->save_file();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void config::set_font_size(int font_size)
|
Result<void> config::set_font_size(int font_size)
|
||||||
{
|
{
|
||||||
if (m_file)
|
if (!m_file)
|
||||||
{
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
m_file->set_value("general", "font_size", font_size);
|
m_file->set_value("general", "font_size", font_size);
|
||||||
m_file->save_file();
|
return m_file->save_file();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void config::update_template(const std::string &key,
|
Result<void> config::update_template(const std::string &key,
|
||||||
const clrsync::core::theme_template &theme_template)
|
const clrsync::core::theme_template &theme_template)
|
||||||
{
|
{
|
||||||
|
if (!m_file)
|
||||||
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
m_themes[key] = theme_template;
|
m_themes[key] = theme_template;
|
||||||
m_file->set_value("templates." + key, "input_path", theme_template.template_path());
|
m_file->set_value("templates." + key, "input_path", theme_template.template_path());
|
||||||
m_file->set_value("templates." + key, "output_path", theme_template.output_path());
|
m_file->set_value("templates." + key, "output_path", theme_template.output_path());
|
||||||
m_file->set_value("templates." + key, "enabled", theme_template.enabled());
|
m_file->set_value("templates." + key, "enabled", theme_template.enabled());
|
||||||
m_file->set_value("templates." + key, "reload_cmd", theme_template.reload_command());
|
m_file->set_value("templates." + key, "reload_cmd", theme_template.reload_command());
|
||||||
m_file->save_file();
|
return m_file->save_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> config::remove_template(const std::string &key)
|
||||||
|
{
|
||||||
|
if (!m_file)
|
||||||
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
|
auto it = m_themes.find(key);
|
||||||
|
if (it == m_themes.end())
|
||||||
|
return Err<void>(error_code::template_not_found, "Template not found", key);
|
||||||
|
|
||||||
|
std::filesystem::path template_file = it->second.template_path();
|
||||||
|
if (std::filesystem::exists(template_file))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
std::filesystem::remove(template_file);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to delete template file", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_themes.erase(it);
|
||||||
|
|
||||||
|
m_file->remove_section("templates." + key);
|
||||||
|
|
||||||
|
return m_file->save_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, clrsync::core::theme_template> config::templates()
|
const std::unordered_map<std::string, clrsync::core::theme_template> config::templates()
|
||||||
@@ -149,21 +257,21 @@ const std::unordered_map<std::string, clrsync::core::theme_template> config::tem
|
|||||||
theme.set_enabled(false);
|
theme.set_enabled(false);
|
||||||
}
|
}
|
||||||
theme.set_reload_command(std::get<std::string>(current["reload_cmd"]));
|
theme.set_reload_command(std::get<std::string>(current["reload_cmd"]));
|
||||||
theme.load_template();
|
(void)theme.load_template();
|
||||||
m_themes.insert({theme.name(), theme});
|
m_themes.insert({theme.name(), theme});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_themes;
|
return m_themes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clrsync::core::theme_template &config::template_by_name(const std::string &name) const
|
Result<const clrsync::core::theme_template*> config::template_by_name(const std::string &name) const
|
||||||
{
|
{
|
||||||
auto it = m_themes.find(name);
|
auto it = m_themes.find(name);
|
||||||
if (it != m_themes.end())
|
if (it != m_themes.end())
|
||||||
{
|
{
|
||||||
return it->second;
|
return Ok(&it->second);
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Template not found: " + name);
|
return Err<const clrsync::core::theme_template*>(error_code::template_not_found, "Template not found", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <core/io/file.hpp>
|
#include <core/io/file.hpp>
|
||||||
#include <core/theme/theme_template.hpp>
|
#include <core/theme/theme_template.hpp>
|
||||||
|
#include <core/error.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -14,24 +15,26 @@ class config
|
|||||||
public:
|
public:
|
||||||
static config &instance();
|
static config &instance();
|
||||||
|
|
||||||
void initialize(std::unique_ptr<clrsync::core::io::file> file);
|
Result<void> initialize(std::unique_ptr<clrsync::core::io::file> file);
|
||||||
|
|
||||||
const std::string font() const;
|
const std::string font() const;
|
||||||
const uint32_t font_size() const;
|
const uint32_t font_size() const;
|
||||||
const std::string &palettes_path();
|
const std::string &palettes_path();
|
||||||
const std::string default_theme() const;
|
const std::string default_theme() const;
|
||||||
const std::unordered_map<std::string, clrsync::core::theme_template> templates();
|
const std::unordered_map<std::string, clrsync::core::theme_template> templates();
|
||||||
const clrsync::core::theme_template &template_by_name(const std::string &name) const;
|
Result<const clrsync::core::theme_template*> template_by_name(const std::string &name) const;
|
||||||
std::filesystem::path get_user_config_dir();
|
std::filesystem::path get_user_config_dir();
|
||||||
|
|
||||||
|
|
||||||
void set_default_theme(const std::string &theme);
|
Result<void> set_default_theme(const std::string &theme);
|
||||||
void set_palettes_path(const std::string &path);
|
Result<void> set_palettes_path(const std::string &path);
|
||||||
void set_font(const std::string &font);
|
Result<void> set_font(const std::string &font);
|
||||||
void set_font_size(int font_size);
|
Result<void> set_font_size(int font_size);
|
||||||
|
|
||||||
void update_template(const std::string &key,
|
Result<void> update_template(const std::string &key,
|
||||||
const clrsync::core::theme_template &theme_template);
|
const clrsync::core::theme_template &theme_template);
|
||||||
|
Result<void> remove_template(const std::string &key);
|
||||||
|
static std::filesystem::path get_data_dir();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
config() = default;
|
config() = default;
|
||||||
@@ -41,6 +44,8 @@ class config
|
|||||||
std::string m_palettes_dir{};
|
std::string m_palettes_dir{};
|
||||||
std::unique_ptr<io::file> m_file;
|
std::unique_ptr<io::file> m_file;
|
||||||
std::unordered_map<std::string, theme_template> m_themes{};
|
std::unordered_map<std::string, theme_template> m_themes{};
|
||||||
|
static void copy_file(const std::filesystem::path& src, const std::filesystem::path& dst);
|
||||||
|
static void copy_dir(const std::filesystem::path& src, const std::filesystem::path& dst);
|
||||||
void copy_default_configs();
|
void copy_default_configs();
|
||||||
};
|
};
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
207
src/core/error.hpp
Normal file
207
src/core/error.hpp
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
#ifndef CLRSYNC_CORE_ERROR_HPP
|
||||||
|
#define CLRSYNC_CORE_ERROR_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace clrsync::core
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class error_code
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
|
||||||
|
file_not_found,
|
||||||
|
file_open_failed,
|
||||||
|
file_write_failed,
|
||||||
|
file_read_failed,
|
||||||
|
dir_create_failed,
|
||||||
|
|
||||||
|
parse_failed,
|
||||||
|
invalid_format,
|
||||||
|
|
||||||
|
config_missing,
|
||||||
|
config_invalid,
|
||||||
|
|
||||||
|
template_not_found,
|
||||||
|
template_load_failed,
|
||||||
|
template_apply_failed,
|
||||||
|
|
||||||
|
palette_not_found,
|
||||||
|
palette_load_failed,
|
||||||
|
|
||||||
|
init_failed,
|
||||||
|
invalid_arg,
|
||||||
|
resource_missing,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char* error_code_string(error_code code)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case error_code::unknown: return "Unknown error";
|
||||||
|
case error_code::file_not_found: return "File not found";
|
||||||
|
case error_code::file_open_failed: return "Failed to open file";
|
||||||
|
case error_code::file_write_failed: return "Failed to write file";
|
||||||
|
case error_code::file_read_failed: return "Failed to read file";
|
||||||
|
case error_code::dir_create_failed: return "Failed to create directory";
|
||||||
|
case error_code::parse_failed: return "Parse failed";
|
||||||
|
case error_code::invalid_format: return "Invalid format";
|
||||||
|
case error_code::config_missing: return "Configuration missing";
|
||||||
|
case error_code::config_invalid: return "Configuration invalid";
|
||||||
|
case error_code::template_not_found: return "Template not found";
|
||||||
|
case error_code::template_load_failed: return "Failed to load template";
|
||||||
|
case error_code::template_apply_failed: return "Failed to apply template";
|
||||||
|
case error_code::palette_not_found: return "Palette not found";
|
||||||
|
case error_code::palette_load_failed: return "Failed to load palette";
|
||||||
|
case error_code::init_failed: return "Initialization failed";
|
||||||
|
case error_code::invalid_arg: return "Invalid argument";
|
||||||
|
case error_code::resource_missing: return "Resource missing";
|
||||||
|
default: return "Unknown error code";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Error
|
||||||
|
{
|
||||||
|
error_code code;
|
||||||
|
std::string message;
|
||||||
|
std::string context;
|
||||||
|
|
||||||
|
Error(error_code c) : code(c), message(error_code_string(c)) {}
|
||||||
|
|
||||||
|
Error(error_code c, std::string msg)
|
||||||
|
: code(c), message(std::move(msg)) {}
|
||||||
|
|
||||||
|
Error(error_code c, std::string msg, std::string ctx)
|
||||||
|
: code(c), message(std::move(msg)), context(std::move(ctx)) {}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
if (context.empty())
|
||||||
|
return message;
|
||||||
|
return message + " [" + context + "]";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class [[nodiscard]] Result
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::variant<T, Error> m_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Result(T value) : m_data(std::move(value)) {}
|
||||||
|
|
||||||
|
Result(Error error) : m_data(std::move(error)) {}
|
||||||
|
|
||||||
|
bool is_ok() const { return std::holds_alternative<T>(m_data); }
|
||||||
|
|
||||||
|
bool is_error() const { return std::holds_alternative<Error>(m_data); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return is_ok(); }
|
||||||
|
|
||||||
|
T& value() & { return std::get<T>(m_data); }
|
||||||
|
const T& value() const & { return std::get<T>(m_data); }
|
||||||
|
T&& value() && { return std::get<T>(std::move(m_data)); }
|
||||||
|
|
||||||
|
const Error& error() const { return std::get<Error>(m_data); }
|
||||||
|
|
||||||
|
T value_or(T default_value) const
|
||||||
|
{
|
||||||
|
return is_ok() ? std::get<T>(m_data) : std::move(default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> ok() const
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
return std::get<T>(m_data);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Error> err() const
|
||||||
|
{
|
||||||
|
if (is_error())
|
||||||
|
return std::get<Error>(m_data);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
auto map(F&& func) -> Result<decltype(func(std::declval<T>()))>
|
||||||
|
{
|
||||||
|
using U = decltype(func(std::declval<T>()));
|
||||||
|
if (is_ok())
|
||||||
|
return Result<U>(func(std::get<T>(m_data)));
|
||||||
|
return Result<U>(std::get<Error>(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
auto and_then(F&& func) -> decltype(func(std::declval<T>()))
|
||||||
|
{
|
||||||
|
if (is_ok())
|
||||||
|
return func(std::get<T>(m_data));
|
||||||
|
using ResultType = decltype(func(std::declval<T>()));
|
||||||
|
return ResultType(std::get<Error>(m_data));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class [[nodiscard]] Result<void>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::optional<Error> m_error;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Result() : m_error(std::nullopt) {}
|
||||||
|
|
||||||
|
Result(Error error) : m_error(std::move(error)) {}
|
||||||
|
|
||||||
|
bool is_ok() const { return !m_error.has_value(); }
|
||||||
|
|
||||||
|
bool is_error() const { return m_error.has_value(); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return is_ok(); }
|
||||||
|
|
||||||
|
const Error& error() const { return *m_error; }
|
||||||
|
|
||||||
|
std::optional<Error> err() const { return m_error; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> Ok(T value)
|
||||||
|
{
|
||||||
|
return Result<T>(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Result<void> Ok()
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> Err(Error error)
|
||||||
|
{
|
||||||
|
return Result<T>(std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> Err(error_code code)
|
||||||
|
{
|
||||||
|
return Result<T>(Error(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> Err(error_code code, std::string message)
|
||||||
|
{
|
||||||
|
return Result<T>(Error(code, std::move(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> Err(error_code code, std::string message, std::string context)
|
||||||
|
{
|
||||||
|
return Result<T>(Error(code, std::move(message), std::move(context)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace clrsync::core
|
||||||
|
|
||||||
|
#endif // CLRSYNC_CORE_ERROR_HPP
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <core/error.hpp>
|
||||||
|
|
||||||
using value_type = std::variant<std::string, uint32_t, int, bool>;
|
using value_type = std::variant<std::string, uint32_t, int, bool>;
|
||||||
|
|
||||||
@@ -14,7 +15,8 @@ class file
|
|||||||
public:
|
public:
|
||||||
file() = default;
|
file() = default;
|
||||||
file(std::string path) {};
|
file(std::string path) {};
|
||||||
virtual bool parse() { return false; };
|
virtual ~file() = default;
|
||||||
|
virtual Result<void> parse() { return Ok(); };
|
||||||
virtual const std::string get_string_value(const std::string §ion,
|
virtual const std::string get_string_value(const std::string §ion,
|
||||||
const std::string &key) const
|
const std::string &key) const
|
||||||
{
|
{
|
||||||
@@ -39,7 +41,8 @@ class file
|
|||||||
}
|
}
|
||||||
virtual void insert_or_update_value(const std::string §ion, const std::string &key,
|
virtual void insert_or_update_value(const std::string §ion, const std::string &key,
|
||||||
const value_type &value) {};
|
const value_type &value) {};
|
||||||
virtual void save_file() {};
|
virtual void remove_section(const std::string §ion) {};
|
||||||
|
virtual Result<void> save_file() { return Ok(); };
|
||||||
};
|
};
|
||||||
} // namespace clrsync::core::io
|
} // namespace clrsync::core::io
|
||||||
#endif
|
#endif
|
||||||
@@ -8,15 +8,16 @@ namespace clrsync::core::io
|
|||||||
{
|
{
|
||||||
toml_file::toml_file(std::string path)
|
toml_file::toml_file(std::string path)
|
||||||
{
|
{
|
||||||
m_path = expand_user(path);
|
m_path = normalize_path(path).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool toml_file::parse()
|
Result<void> toml_file::parse()
|
||||||
{
|
{
|
||||||
if (!std::filesystem::exists(m_path))
|
if (!std::filesystem::exists(m_path))
|
||||||
return false;
|
return Err<void>(error_code::file_not_found, "File does not exist", m_path);
|
||||||
|
|
||||||
m_file = toml::parse_file(m_path);
|
m_file = toml::parse_file(m_path);
|
||||||
return true;
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string toml_file::get_string_value(const std::string §ion,
|
const std::string toml_file::get_string_value(const std::string §ion,
|
||||||
@@ -63,7 +64,7 @@ std::map<std::string, value_type> toml_file::get_table(const std::string §io
|
|||||||
else if (auto d = val.value<double>())
|
else if (auto d = val.value<double>())
|
||||||
result[std::string(p.first.str())] = static_cast<uint32_t>(*d);
|
result[std::string(p.first.str())] = static_cast<uint32_t>(*d);
|
||||||
else
|
else
|
||||||
result[std::string(p.first.str())] = {}; // fallback for unsupported types
|
result[std::string(p.first.str())] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -91,11 +92,42 @@ void toml_file::insert_or_update_value(const std::string §ion, const std::st
|
|||||||
std::visit([&](auto &&v) { tbl->insert_or_assign(key, v); }, value);
|
std::visit([&](auto &&v) { tbl->insert_or_assign(key, v); }, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void toml_file::save_file()
|
void toml_file::remove_section(const std::string §ion)
|
||||||
{
|
{
|
||||||
|
toml::table *tbl = m_file.as_table();
|
||||||
|
auto parts = split(section, '.');
|
||||||
|
|
||||||
|
if (parts.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < parts.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
auto *sub = (*tbl)[parts[i]].as_table();
|
||||||
|
if (!sub)
|
||||||
|
return;
|
||||||
|
tbl = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl->erase(parts.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> toml_file::save_file()
|
||||||
|
{
|
||||||
|
try {
|
||||||
std::filesystem::create_directories(std::filesystem::path(m_path).parent_path());
|
std::filesystem::create_directories(std::filesystem::path(m_path).parent_path());
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return Err<void>(error_code::dir_create_failed, e.what(), m_path);
|
||||||
|
}
|
||||||
|
|
||||||
std::ofstream stream(m_path, std::ios::binary);
|
std::ofstream stream(m_path, std::ios::binary);
|
||||||
|
if (!stream)
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to open file for writing", m_path);
|
||||||
|
|
||||||
stream << m_file;
|
stream << m_file;
|
||||||
|
if (!stream)
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to write to file", m_path);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> toml_file::split(const std::string &s, char delim) const
|
std::vector<std::string> toml_file::split(const std::string &s, char delim) const
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef CLRSYNC_CORE_IO_TOML_FILE_HPP
|
#ifndef CLRSYNC_CORE_IO_TOML_FILE_HPP
|
||||||
#define CLRSYNC_CORE_IO_TOML_FILE_HPP
|
#define CLRSYNC_CORE_IO_TOML_FILE_HPP
|
||||||
#include <core/io/file.hpp>
|
#include <core/io/file.hpp>
|
||||||
|
#include <core/error.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <toml/toml.hpp>
|
#include <toml/toml.hpp>
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ class toml_file : public file
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit toml_file(std::string path);
|
explicit toml_file(std::string path);
|
||||||
bool parse() override;
|
Result<void> parse() override;
|
||||||
const std::string get_string_value(const std::string §ion,
|
const std::string get_string_value(const std::string §ion,
|
||||||
const std::string &key) const override;
|
const std::string &key) const override;
|
||||||
uint32_t get_uint_value(const std::string §ion, const std::string &key) const override;
|
uint32_t get_uint_value(const std::string §ion, const std::string &key) const override;
|
||||||
@@ -18,7 +19,8 @@ class toml_file : public file
|
|||||||
std::map<std::string, value_type> get_table(const std::string §ion_path) const override;
|
std::map<std::string, value_type> get_table(const std::string §ion_path) const override;
|
||||||
void insert_or_update_value(const std::string §ion, const std::string &key,
|
void insert_or_update_value(const std::string §ion, const std::string &key,
|
||||||
const value_type &value) override;
|
const value_type &value) override;
|
||||||
void save_file() override;
|
void remove_section(const std::string §ion) override;
|
||||||
|
Result<void> save_file() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
toml::parse_result m_file{};
|
toml::parse_result m_file{};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,55 +1,141 @@
|
|||||||
#ifndef CLRSYNC_CORE_PALETTE_COLOR_KEYS_HPP
|
#ifndef CLRSYNC_CORE_PALETTE_COLOR_KEYS_HPP
|
||||||
#define CLRSYNC_CORE_PALETTE_COLOR_KEYS_HPP
|
#define CLRSYNC_CORE_PALETTE_COLOR_KEYS_HPP
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
constexpr const char *COLOR_KEYS[] = {
|
constexpr const char* COLOR_KEYS[] = {
|
||||||
// UI / Surfaces
|
// General UI
|
||||||
"background", // main window / editor background
|
"background",
|
||||||
"surface", // panels, cards
|
"on_background",
|
||||||
"surface_variant", // alternate rows, subtle panels
|
|
||||||
"foreground", // main text
|
|
||||||
"foreground_secondary", // secondary text / hints
|
|
||||||
"accent", // buttons, highlights, selection
|
|
||||||
"outline", // borders, outlines
|
|
||||||
"shadow", // drop shadows / depth
|
|
||||||
"cursor", // caret / text cursor
|
|
||||||
|
|
||||||
// Editor-specific surfaces
|
"surface",
|
||||||
"editor_background", "sidebar_background", "popup_background", "floating_window_background",
|
"on_surface",
|
||||||
"menu_option_background",
|
|
||||||
|
|
||||||
// Editor text roles
|
"surface_variant",
|
||||||
"text_main", "text_emphasis", "text_command", "text_inactive", "text_disabled",
|
"on_surface_variant",
|
||||||
"text_line_number", "text_selected", "text_selection_inactive",
|
|
||||||
|
|
||||||
// Editor / Window borders
|
"border_focused",
|
||||||
"border_window", "border_focused", "border_emphasized",
|
"border",
|
||||||
|
|
||||||
// Syntax highlighting
|
"foreground",
|
||||||
"syntax_function", "syntax_error", "syntax_keyword", "syntax_special_keyword",
|
|
||||||
"syntax_operator",
|
|
||||||
|
|
||||||
// Semantic text colors
|
"cursor",
|
||||||
"text_error", "text_warning", "text_link", "text_comment", "text_string", "text_success",
|
"accent",
|
||||||
"warning_emphasis", "foreground_emphasis",
|
|
||||||
|
|
||||||
// Extra
|
// Semantic
|
||||||
"terminal_gray",
|
"success",
|
||||||
|
"info",
|
||||||
|
"warning",
|
||||||
|
"error",
|
||||||
|
|
||||||
// Semantic / Status
|
"on_success",
|
||||||
"error", "warning", "success", "info",
|
"on_info",
|
||||||
|
"on_warning",
|
||||||
|
"on_error",
|
||||||
|
|
||||||
// Terminal colors (normal)
|
// Editor
|
||||||
"term_black", "term_red", "term_green", "term_yellow", "term_blue", "term_magenta", "term_cyan",
|
"editor_background",
|
||||||
"term_white",
|
"editor_command",
|
||||||
|
"editor_comment",
|
||||||
|
"editor_disabled",
|
||||||
|
"editor_emphasis",
|
||||||
|
"editor_error",
|
||||||
|
"editor_inactive",
|
||||||
|
"editor_line_number",
|
||||||
|
"editor_link",
|
||||||
|
"editor_main",
|
||||||
|
"editor_selected",
|
||||||
|
"editor_selection_inactive",
|
||||||
|
"editor_string",
|
||||||
|
"editor_success",
|
||||||
|
"editor_warning",
|
||||||
|
|
||||||
// Terminal colors (bright)
|
// Terminal
|
||||||
"term_black_bright", "term_red_bright", "term_green_bright", "term_yellow_bright",
|
"base00",
|
||||||
"term_blue_bright", "term_magenta_bright", "term_cyan_bright", "term_white_bright"};
|
"base01",
|
||||||
|
"base02",
|
||||||
|
"base03",
|
||||||
|
"base04",
|
||||||
|
"base05",
|
||||||
|
"base06",
|
||||||
|
"base07",
|
||||||
|
"base08",
|
||||||
|
"base09",
|
||||||
|
"base0A",
|
||||||
|
"base0B",
|
||||||
|
"base0C",
|
||||||
|
"base0D",
|
||||||
|
"base0E",
|
||||||
|
"base0F",
|
||||||
|
};
|
||||||
|
|
||||||
constexpr size_t NUM_COLOR_KEYS = std::size(COLOR_KEYS);
|
constexpr size_t NUM_COLOR_KEYS = std::size(COLOR_KEYS);
|
||||||
|
|
||||||
|
inline const std::unordered_map<std::string, uint32_t> DEFAULT_COLORS = {
|
||||||
|
{"background", 0x111111ff},
|
||||||
|
{"on_background", 0xd4d4d4ff},
|
||||||
|
|
||||||
|
{"surface", 0x111111ff},
|
||||||
|
{"on_surface", 0xd4d4d4ff},
|
||||||
|
|
||||||
|
{"surface_variant", 0x191919ff},
|
||||||
|
{"on_surface_variant", 0xd4d4d4ff},
|
||||||
|
|
||||||
|
{"border_focused", 0x2e2e2eff},
|
||||||
|
{"border", 0x242424ff},
|
||||||
|
|
||||||
|
{"foreground", 0xd2d2d2ff},
|
||||||
|
|
||||||
|
{"cursor", 0xd2d2d2ff},
|
||||||
|
{"accent", 0x9a8652ff},
|
||||||
|
|
||||||
|
{"success", 0x668a51ff},
|
||||||
|
{"info", 0x3a898cff},
|
||||||
|
{"warning", 0xb47837ff},
|
||||||
|
{"error", 0xaa4e4aff},
|
||||||
|
|
||||||
|
{"on_success", 0xd2d2d2ff},
|
||||||
|
{"on_info", 0xd2d2d2ff},
|
||||||
|
{"on_warning", 0xd2d2d2ff},
|
||||||
|
{"on_error", 0xd2d2d2ff},
|
||||||
|
|
||||||
|
{"editor_background", 0x111111ff},
|
||||||
|
{"editor_command", 0x3a898cff},
|
||||||
|
{"editor_comment", 0x849899ff},
|
||||||
|
{"editor_disabled", 0x849899ff},
|
||||||
|
{"editor_emphasis", 0xa9dc86ff},
|
||||||
|
{"editor_error", 0xaa4e4aff},
|
||||||
|
{"editor_inactive", 0x849899ff},
|
||||||
|
{"editor_line_number", 0x849899ff},
|
||||||
|
{"editor_link", 0xb0779eff},
|
||||||
|
{"editor_main", 0xd2d2d2ff},
|
||||||
|
{"editor_selected", 0x242424ff},
|
||||||
|
{"editor_selection_inactive", 0x1d1c1cff},
|
||||||
|
{"editor_string", 0x9a8652ff},
|
||||||
|
{"editor_success", 0x668a51ff},
|
||||||
|
{"editor_warning", 0xb47837ff},
|
||||||
|
|
||||||
|
{"base00", 0x111111ff},
|
||||||
|
{"base01", 0x668a51ff},
|
||||||
|
{"base02", 0x9a8652ff},
|
||||||
|
{"base03", 0xb47837ff},
|
||||||
|
{"base04", 0x9a5552ff},
|
||||||
|
{"base05", 0xaa477bff},
|
||||||
|
{"base06", 0x3a898cff},
|
||||||
|
{"base07", 0xb5b5b5ff},
|
||||||
|
{"base08", 0xaa4e4aff},
|
||||||
|
{"base09", 0xa9dc86ff},
|
||||||
|
{"base0A", 0xb6ab82ff},
|
||||||
|
{"base0B", 0xc5916bff},
|
||||||
|
{"base0C", 0xac7676ff},
|
||||||
|
{"base0D", 0xb0779eff},
|
||||||
|
{"base0E", 0x849899ff},
|
||||||
|
{"base0F", 0xd2d2d2ff},
|
||||||
|
};
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <core/palette/color.hpp>
|
#include <core/palette/color.hpp>
|
||||||
|
#include <core/palette/color_keys.hpp>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
@@ -37,9 +38,16 @@ class palette
|
|||||||
{
|
{
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
static color default_color{};
|
auto default_it = DEFAULT_COLORS.find(key);
|
||||||
|
if (default_it != DEFAULT_COLORS.end())
|
||||||
|
{
|
||||||
|
static color default_color;
|
||||||
|
default_color.set(default_it->second);
|
||||||
return default_color;
|
return default_color;
|
||||||
}
|
}
|
||||||
|
static color empty_color{};
|
||||||
|
return empty_color;
|
||||||
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, color> &colors() const
|
const std::unordered_map<std::string, color> &colors() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,14 +26,26 @@ template <typename FileType> class palette_file
|
|||||||
if (!m_file->parse())
|
if (!m_file->parse())
|
||||||
return false;
|
return false;
|
||||||
m_palette.set_name(m_file->get_string_value("general", "name"));
|
m_palette.set_name(m_file->get_string_value("general", "name"));
|
||||||
|
|
||||||
|
for (const auto &color_key : COLOR_KEYS)
|
||||||
|
{
|
||||||
|
auto it = DEFAULT_COLORS.find(color_key);
|
||||||
|
if (it != DEFAULT_COLORS.end())
|
||||||
|
{
|
||||||
|
m_palette.set_color(color_key, core::color(it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &color_key : COLOR_KEYS)
|
for (const auto &color_key : COLOR_KEYS)
|
||||||
{
|
{
|
||||||
auto color_str = m_file->get_string_value("colors", color_key);
|
auto color_str = m_file->get_string_value("colors", color_key);
|
||||||
core::color color{0x000000FF};
|
|
||||||
if (!color_str.empty())
|
if (!color_str.empty())
|
||||||
|
{
|
||||||
|
core::color color;
|
||||||
color.from_hex_string(color_str);
|
color.from_hex_string(color_str);
|
||||||
m_palette.set_color(color_key, color);
|
m_palette.set_color(color_key, color);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
core::palette palette() const
|
core::palette palette() const
|
||||||
@@ -52,7 +64,7 @@ template <typename FileType> class palette_file
|
|||||||
}
|
}
|
||||||
void save()
|
void save()
|
||||||
{
|
{
|
||||||
m_file->save_file();
|
(void)m_file->save_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define CLRSYNC_CORE_PALETTE_PALETTE_MANAGER_HPP
|
#define CLRSYNC_CORE_PALETTE_PALETTE_MANAGER_HPP
|
||||||
|
|
||||||
#include "core/utils.hpp"
|
#include "core/utils.hpp"
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -18,7 +19,9 @@ template <typename FileType> class palette_manager
|
|||||||
palette_manager() = default;
|
palette_manager() = default;
|
||||||
void load_palettes_from_directory(const std::string &directory_path)
|
void load_palettes_from_directory(const std::string &directory_path)
|
||||||
{
|
{
|
||||||
auto directory_path_expanded = expand_user(directory_path);
|
std::filesystem::path directory_path_expanded = normalize_path(directory_path);
|
||||||
|
if (!std::filesystem::exists(directory_path_expanded))
|
||||||
|
return;
|
||||||
for (const auto &entry : std::filesystem::directory_iterator(directory_path_expanded))
|
for (const auto &entry : std::filesystem::directory_iterator(directory_path_expanded))
|
||||||
{
|
{
|
||||||
if (entry.is_regular_file())
|
if (entry.is_regular_file())
|
||||||
@@ -31,8 +34,9 @@ template <typename FileType> class palette_manager
|
|||||||
}
|
}
|
||||||
void save_palette_to_file(const palette &pal, const std::string &directory_path) const
|
void save_palette_to_file(const palette &pal, const std::string &directory_path) const
|
||||||
{
|
{
|
||||||
std::string file_path = directory_path + "/" + pal.name() + ".toml";
|
std::filesystem::path dir_path = normalize_path(directory_path);
|
||||||
palette_file<FileType> pal_file(file_path);
|
std::filesystem::path file_path = dir_path / (pal.name() + ".toml");
|
||||||
|
palette_file<FileType> pal_file(file_path.string());
|
||||||
pal_file.save_palette(pal);
|
pal_file.save_palette(pal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <core/config/config.hpp>
|
#include <core/config/config.hpp>
|
||||||
#include <core/palette/palette_manager.hpp>
|
#include <core/palette/palette_manager.hpp>
|
||||||
#include <core/theme/template_manager.hpp>
|
#include <core/theme/template_manager.hpp>
|
||||||
|
#include <core/error.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
@@ -18,39 +19,53 @@ template <typename FileType> class theme_renderer
|
|||||||
m_template_manager = template_manager<FileType>();
|
m_template_manager = template_manager<FileType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_theme(const std::string &theme_name)
|
Result<void> apply_theme(const std::string &theme_name)
|
||||||
{
|
{
|
||||||
auto palette = m_pal_manager.get_palette(theme_name);
|
auto palette = m_pal_manager.get_palette(theme_name);
|
||||||
if (!palette)
|
if (!palette)
|
||||||
throw std::runtime_error("Palette not found: " + theme_name);
|
return Err<void>(error_code::palette_not_found, "Palette not found", theme_name);
|
||||||
apply_palette_to_all_templates(*palette);
|
return apply_palette_to_all_templates(*palette);
|
||||||
}
|
}
|
||||||
void apply_theme_from_path(const std::string &path)
|
|
||||||
|
Result<void> apply_theme_from_path(const std::string &path)
|
||||||
{
|
{
|
||||||
auto palette = m_pal_manager.load_palette_from_file(path);
|
auto palette = m_pal_manager.load_palette_from_file(path);
|
||||||
apply_palette_to_all_templates(palette);
|
return apply_palette_to_all_templates(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
palette_manager<FileType> m_pal_manager;
|
palette_manager<FileType> m_pal_manager;
|
||||||
template_manager<FileType> m_template_manager;
|
template_manager<FileType> m_template_manager;
|
||||||
|
|
||||||
void apply_palette_to_all_templates(const palette &pal)
|
Result<void> apply_palette_to_all_templates(const palette &pal)
|
||||||
{
|
{
|
||||||
for (auto &t_pair : m_template_manager.templates())
|
for (auto &t_pair : m_template_manager.templates())
|
||||||
{
|
{
|
||||||
auto &tmpl = t_pair.second;
|
auto &tmpl = t_pair.second;
|
||||||
if (!tmpl.enabled())
|
if (!tmpl.enabled())
|
||||||
continue;
|
continue;
|
||||||
tmpl.load_template();
|
|
||||||
|
auto load_result = tmpl.load_template();
|
||||||
|
if (!load_result)
|
||||||
|
return load_result;
|
||||||
|
|
||||||
tmpl.apply_palette(pal);
|
tmpl.apply_palette(pal);
|
||||||
tmpl.save_output();
|
|
||||||
|
auto save_result = tmpl.save_output();
|
||||||
|
if (!save_result)
|
||||||
|
return save_result;
|
||||||
|
|
||||||
if (!tmpl.reload_command().empty())
|
if (!tmpl.reload_command().empty())
|
||||||
{
|
{
|
||||||
std::system(tmpl.reload_command().c_str());
|
int result = std::system(tmpl.reload_command().c_str());
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Command " << tmpl.reload_command() << " failed with code " << result << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
#include "theme_template.hpp"
|
#include "theme_template.hpp"
|
||||||
#include "core/utils.hpp"
|
#include "core/utils.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
theme_template::theme_template(const std::string &name, const std::string &template_path,
|
theme_template::theme_template(const std::string &name, const std::string &template_path,
|
||||||
const std::string &out_path)
|
const std::string &out_path)
|
||||||
: m_name(name), m_template_path(expand_user(template_path)),
|
: m_name(name), m_template_path(normalize_path(template_path).string()),
|
||||||
m_output_path(expand_user(out_path))
|
m_output_path(normalize_path(out_path).string())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ const std::string &theme_template::template_path() const
|
|||||||
|
|
||||||
void theme_template::set_template_path(const std::string &path)
|
void theme_template::set_template_path(const std::string &path)
|
||||||
{
|
{
|
||||||
m_template_path = expand_user(path);
|
m_template_path = normalize_path(path).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &theme_template::output_path() const
|
const std::string &theme_template::output_path() const
|
||||||
@@ -40,16 +40,24 @@ const std::string &theme_template::output_path() const
|
|||||||
|
|
||||||
void theme_template::set_output_path(const std::string &path)
|
void theme_template::set_output_path(const std::string &path)
|
||||||
{
|
{
|
||||||
m_output_path = expand_user(path);
|
m_output_path = normalize_path(path).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void theme_template::load_template()
|
Result<void> theme_template::load_template()
|
||||||
{
|
{
|
||||||
|
if (!std::filesystem::exists(m_template_path))
|
||||||
|
{
|
||||||
|
return Err<void>(error_code::template_not_found, "Template file is missing", m_template_path);
|
||||||
|
}
|
||||||
|
|
||||||
std::ifstream input(m_template_path, std::ios::binary);
|
std::ifstream input(m_template_path, std::ios::binary);
|
||||||
if (!input)
|
if (!input)
|
||||||
throw std::runtime_error("Failed to open template file: " + m_template_path);
|
{
|
||||||
|
return Err<void>(error_code::template_load_failed, "Failed to open template file", m_template_path);
|
||||||
|
}
|
||||||
|
|
||||||
m_template_data.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
|
m_template_data.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
void theme_template::apply_palette(const core::palette &palette)
|
void theme_template::apply_palette(const core::palette &palette)
|
||||||
@@ -82,14 +90,30 @@ void theme_template::apply_palette(const core::palette &palette)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void theme_template::save_output() const
|
Result<void> theme_template::save_output() const
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
std::filesystem::create_directories(std::filesystem::path(m_output_path).parent_path());
|
std::filesystem::create_directories(std::filesystem::path(m_output_path).parent_path());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
return Err<void>(error_code::dir_create_failed, e.what(), m_output_path);
|
||||||
|
}
|
||||||
|
|
||||||
std::ofstream output(m_output_path, std::ios::binary);
|
std::ofstream output(m_output_path, std::ios::binary);
|
||||||
if (!output)
|
if (!output)
|
||||||
throw std::runtime_error("Failed to write output file: " + m_output_path);
|
{
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to open output file for writing", m_output_path);
|
||||||
|
}
|
||||||
|
|
||||||
output << m_processed_data;
|
output << m_processed_data;
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to write to output file", m_output_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &theme_template::raw_template() const
|
const std::string &theme_template::raw_template() const
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define clrsync_CORE_IO_THEME_TEMPLATE_HPP
|
#define clrsync_CORE_IO_THEME_TEMPLATE_HPP
|
||||||
|
|
||||||
#include <core/palette/palette.hpp>
|
#include <core/palette/palette.hpp>
|
||||||
|
#include <core/error.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
@@ -26,11 +27,11 @@ class theme_template
|
|||||||
|
|
||||||
void set_output_path(const std::string &path);
|
void set_output_path(const std::string &path);
|
||||||
|
|
||||||
void load_template();
|
Result<void> load_template();
|
||||||
|
|
||||||
void apply_palette(const core::palette &palette);
|
void apply_palette(const core::palette &palette);
|
||||||
|
|
||||||
void save_output() const;
|
Result<void> save_output() const;
|
||||||
|
|
||||||
const std::string &raw_template() const;
|
const std::string &raw_template() const;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
@@ -13,22 +14,21 @@ void print_color_keys()
|
|||||||
|
|
||||||
std::string get_default_config_path()
|
std::string get_default_config_path()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
const char* env_path = std::getenv("CLRSYNC_CONFIG_PATH");
|
||||||
const char *appdata = std::getenv("APPDATA"); // "C:\Users\<User>\AppData\Roaming"
|
if (env_path && env_path[0] != '\0')
|
||||||
if (!appdata)
|
return normalize_path(env_path).string();
|
||||||
throw std::runtime_error("APPDATA environment variable not set");
|
|
||||||
return std::string(appdata) + "\\clrsync\\config.toml";
|
std::filesystem::path home = normalize_path("~");
|
||||||
#else
|
std::filesystem::path config_path = home / ".config" / "clrsync" / "config.toml";
|
||||||
const char *home = std::getenv("HOME");
|
return config_path.string();
|
||||||
if (!home)
|
|
||||||
throw std::runtime_error("HOME environment variable not set");
|
|
||||||
return std::string(home) + "/.config/clrsync/config.toml";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string expand_user(const std::string &path)
|
std::string expand_user(const std::string &path)
|
||||||
{
|
{
|
||||||
if (!path.empty() && path[0] == '~')
|
if (path.empty() || path[0] != '~')
|
||||||
|
return path;
|
||||||
|
|
||||||
|
if (path.length() == 1 || path[1] == '/' || path[1] == '\\')
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const char *home = std::getenv("USERPROFILE");
|
const char *home = std::getenv("USERPROFILE");
|
||||||
@@ -37,9 +37,20 @@ std::string expand_user(const std::string &path)
|
|||||||
#endif
|
#endif
|
||||||
if (!home)
|
if (!home)
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
|
if (path.length() == 1)
|
||||||
|
return std::string(home);
|
||||||
|
|
||||||
return std::string(home) + path.substr(1);
|
return std::string(home) + path.substr(1);
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path normalize_path(const std::string &path)
|
||||||
|
{
|
||||||
|
std::string expanded = expand_user(path);
|
||||||
|
std::filesystem::path fs_path(expanded);
|
||||||
|
return fs_path.lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define CLRSYNC_CORE_UTILS_HPP
|
#define CLRSYNC_CORE_UTILS_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include <core/palette/color_keys.hpp>
|
#include <core/palette/color_keys.hpp>
|
||||||
|
|
||||||
@@ -10,5 +11,6 @@ namespace clrsync::core
|
|||||||
void print_color_keys();
|
void print_color_keys();
|
||||||
std::string get_default_config_path();
|
std::string get_default_config_path();
|
||||||
std::string expand_user(const std::string &path);
|
std::string expand_user(const std::string &path);
|
||||||
|
std::filesystem::path normalize_path(const std::string &path);
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
#endif // CLRSYNC_CORE_UTILS_HPP
|
#endif // CLRSYNC_CORE_UTILS_HPP
|
||||||
@@ -4,7 +4,6 @@ namespace clrsync::core
|
|||||||
{
|
{
|
||||||
const std::string version_string()
|
const std::string version_string()
|
||||||
{
|
{
|
||||||
return "v" + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + "." +
|
return GIT_SEMVER;
|
||||||
std::to_string(VERSION_PATCH);
|
|
||||||
}
|
}
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
#ifndef CLRSYNC_CORE_VERSION_HPP
|
#ifndef CLRSYNC_CORE_VERSION_HPP
|
||||||
#define CLRSYNC_CORE_VERSION_HPP
|
#define CLRSYNC_CORE_VERSION_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr uint8_t VERSION_MAJOR = 0;
|
const std::string GIT_SEMVER = "0.1.6+git.g1a1747a";
|
||||||
constexpr uint8_t VERSION_MINOR = 1;
|
|
||||||
constexpr uint8_t VERSION_PATCH = 2;
|
|
||||||
|
|
||||||
const std::string version_string();
|
const std::string version_string();
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
#ifndef CLRSYNC_CORE_VERSION_HPP
|
#ifndef CLRSYNC_CORE_VERSION_HPP
|
||||||
#define CLRSYNC_CORE_VERSION_HPP
|
#define CLRSYNC_CORE_VERSION_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace clrsync::core
|
namespace clrsync::core
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr uint8_t VERSION_MAJOR = @PROJECT_VERSION_MAJOR@;
|
const std::string GIT_SEMVER = "@SEMVER@";
|
||||||
constexpr uint8_t VERSION_MINOR = @PROJECT_VERSION_MINOR@;
|
|
||||||
constexpr uint8_t VERSION_PATCH = @PROJECT_VERSION_PATCH@;
|
|
||||||
|
|
||||||
const std::string version_string();
|
const std::string version_string();
|
||||||
} // namespace clrsync::core
|
} // namespace clrsync::core
|
||||||
|
|||||||
72
src/gui/CMakeLists.txt
Normal file
72
src/gui/CMakeLists.txt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
set(GUI_SOURCES
|
||||||
|
main.cpp
|
||||||
|
color_scheme_editor.cpp
|
||||||
|
color_table_renderer.cpp
|
||||||
|
preview_renderer.cpp
|
||||||
|
theme_applier.cpp
|
||||||
|
template_editor.cpp
|
||||||
|
palette_controller.cpp
|
||||||
|
template_controller.cpp
|
||||||
|
imgui_helpers.cpp
|
||||||
|
imgui_helpers.hpp
|
||||||
|
about_window.cpp
|
||||||
|
settings_window.cpp
|
||||||
|
font_loader.cpp
|
||||||
|
file_browser.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/lib/color_text_edit/TextEditor.cpp
|
||||||
|
)
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND GUI_SOURCES file_browser_macos.mm)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_executable(clrsync_gui WIN32 ${GUI_SOURCES})
|
||||||
|
else()
|
||||||
|
add_executable(clrsync_gui ${GUI_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(clrsync_gui PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
SYSTEM ${CMAKE_SOURCE_DIR}/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(clrsync_gui PRIVATE
|
||||||
|
clrsync_core
|
||||||
|
glfw
|
||||||
|
imgui
|
||||||
|
OpenGL::GL
|
||||||
|
shell32
|
||||||
|
ole32
|
||||||
|
uuid
|
||||||
|
comdlg32
|
||||||
|
shlwapi
|
||||||
|
)
|
||||||
|
if (MSVC)
|
||||||
|
target_link_options(clrsync_gui PRIVATE /ENTRY:mainCRTStartup)
|
||||||
|
endif()
|
||||||
|
elseif(APPLE)
|
||||||
|
target_link_libraries(clrsync_gui PRIVATE
|
||||||
|
clrsync_core
|
||||||
|
glfw
|
||||||
|
imgui
|
||||||
|
OpenGL::GL
|
||||||
|
"-framework Cocoa"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_link_libraries(clrsync_gui PRIVATE
|
||||||
|
clrsync_core
|
||||||
|
imgui
|
||||||
|
${GLFW_LIBRARIES}
|
||||||
|
${WAYLAND_LIBS}
|
||||||
|
X11
|
||||||
|
Xrandr
|
||||||
|
Xi
|
||||||
|
Fontconfig::Fontconfig
|
||||||
|
OpenGL::GL
|
||||||
|
${GTK3_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(clrsync_gui PRIVATE ${GTK3_INCLUDE_DIRS})
|
||||||
|
target_compile_options(clrsync_gui PRIVATE ${GTK3_CFLAGS_OTHER})
|
||||||
|
endif()
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#include "about_window.hpp"
|
#include "about_window.hpp"
|
||||||
#include "core/version.hpp"
|
#include "core/version.hpp"
|
||||||
|
#include "imgui_helpers.hpp"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
about_window::about_window()
|
about_window::about_window()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void about_window::render()
|
void about_window::render(const clrsync::core::palette& pal)
|
||||||
{
|
{
|
||||||
if (!m_visible)
|
if (!m_visible)
|
||||||
return;
|
return;
|
||||||
@@ -18,24 +19,24 @@ void about_window::render()
|
|||||||
const float window_width = ImGui::GetContentRegionAvail().x;
|
const float window_width = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
ImGui::PushFont(ImGui::GetFont());
|
ImGui::PushFont(ImGui::GetFont());
|
||||||
const char* title = "clrsync";
|
const char *title = "clrsync";
|
||||||
const float title_size = ImGui::CalcTextSize(title).x;
|
const float title_size = ImGui::CalcTextSize(title).x;
|
||||||
ImGui::SetCursorPosX((window_width - title_size) * 0.5f);
|
ImGui::SetCursorPosX((window_width - title_size) * 0.5f);
|
||||||
ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s", title);
|
ImVec4 title_color = palette_utils::get_color(pal, "info", "accent");
|
||||||
|
ImGui::TextColored(title_color, "%s", title);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
std::string version = "Version " + clrsync::core::version_string();
|
std::string version = "Version " + clrsync::core::version_string();
|
||||||
const float version_size = ImGui::CalcTextSize(version.c_str()).x;
|
const float version_size = ImGui::CalcTextSize(version.c_str()).x;
|
||||||
ImGui::SetCursorPosX((window_width - version_size) * 0.5f);
|
ImGui::SetCursorPosX((window_width - version_size) * 0.5f);
|
||||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "%s", version.c_str());
|
ImVec4 subtitle_color = palette_utils::get_color(pal, "editor_inactive", "foreground");
|
||||||
|
ImGui::TextColored(subtitle_color, "%s", version.c_str());
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
ImGui::TextWrapped(
|
ImGui::TextWrapped("A color scheme management tool.");
|
||||||
"A color scheme management tool."
|
|
||||||
);
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
@@ -45,24 +46,41 @@ void about_window::render()
|
|||||||
|
|
||||||
ImGui::Text("Links:");
|
ImGui::Text("Links:");
|
||||||
|
|
||||||
if (ImGui::Button("GitHub Repository", ImVec2(200, 0)))
|
const float button_width = 200.0f;
|
||||||
|
const float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
const float total_width = 2.0f * button_width + spacing;
|
||||||
|
ImGui::SetCursorPosX((window_width - total_width) * 0.5f);
|
||||||
|
|
||||||
|
if (ImGui::Button("GitHub Repository", ImVec2(button_width, 0)))
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
system("start https://github.com/obsqrbtz/clrsync");
|
system("start https://github.com/obsqrbtz/clrsync");
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
system("open https://github.com/obsqrbtz/clrsync");
|
system("open https://github.com/obsqrbtz/clrsync");
|
||||||
#else
|
#else
|
||||||
system("xdg-open https://github.com/obsqrbtz/clrsync");
|
system("xdg-open https://github.com/obsqrbtz/clrsync");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::Button("Documentation", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
system("start https://binarygoose.dev/projects/clrsync/overview/");
|
||||||
|
#elif __APPLE__
|
||||||
|
system("open https://binarygoose.dev/projects/clrsync/overview/");
|
||||||
|
#else
|
||||||
|
system("xdg-open https://binarygoose.dev/projects/clrsync/overview/");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "MIT License");
|
ImVec4 license_color = palette_utils::get_color(pal, "editor_inactive", "foreground");
|
||||||
|
ImGui::TextColored(license_color, "MIT License");
|
||||||
ImGui::TextWrapped(
|
ImGui::TextWrapped(
|
||||||
"Copyright (c) 2025 Daniel Dada\n\n"
|
"Copyright (c) 2025 Daniel Dada\n\n"
|
||||||
"Permission is hereby granted, free of charge, to any person obtaining a copy "
|
"Permission is hereby granted, free of charge, to any person obtaining a copy "
|
||||||
@@ -72,18 +90,7 @@ void about_window::render()
|
|||||||
"copies of the Software, and to permit persons to whom the Software is "
|
"copies of the Software, and to permit persons to whom the Software is "
|
||||||
"furnished to do so, subject to the following conditions:\n\n"
|
"furnished to do so, subject to the following conditions:\n\n"
|
||||||
"The above copyright notice and this permission notice shall be included in all "
|
"The above copyright notice and this permission notice shall be included in all "
|
||||||
"copies or substantial portions of the Software."
|
"copies or substantial portions of the Software.");
|
||||||
);
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
const float button_width = 120.0f;
|
|
||||||
ImGui::SetCursorPosX((window_width - button_width) * 0.5f);
|
|
||||||
if (ImGui::Button("Close", ImVec2(button_width, 0)))
|
|
||||||
{
|
|
||||||
m_visible = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
#ifndef CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
#ifndef CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
||||||
#define CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
#define CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
||||||
|
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
|
|
||||||
class about_window
|
class about_window
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
about_window();
|
about_window();
|
||||||
void render();
|
void render(const clrsync::core::palette& pal);
|
||||||
|
void render() { render(m_default_palette); }
|
||||||
void show() { m_visible = true; }
|
void show() { m_visible = true; }
|
||||||
void hide() { m_visible = false; }
|
void hide() { m_visible = false; }
|
||||||
bool is_visible() const { return m_visible; }
|
bool is_visible() const { return m_visible; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_visible{false};
|
bool m_visible{false};
|
||||||
|
clrsync::core::palette m_default_palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
#endif // CLRSYNC_GUI_ABOUT_WINDOW_HPP
|
||||||
@@ -1,78 +1,26 @@
|
|||||||
#include "color_scheme_editor.hpp"
|
#include "color_scheme_editor.hpp"
|
||||||
#include "template_editor.hpp"
|
|
||||||
#include "color_text_edit/TextEditor.h"
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "imgui_helpers.hpp"
|
||||||
|
#include "template_editor.hpp"
|
||||||
|
#include "settings_window.hpp"
|
||||||
|
#include "theme_applier.hpp"
|
||||||
|
#include <iostream>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
|
|
||||||
color_scheme_editor::color_scheme_editor()
|
color_scheme_editor::color_scheme_editor()
|
||||||
{
|
{
|
||||||
m_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
|
const auto ¤t = m_controller.current_palette();
|
||||||
m_editor.SetText(R"(#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
if (!current.colors().empty())
|
||||||
|
|
||||||
// Expands ~ to the user's home directory
|
|
||||||
std::string expand_user(const std::string &path)
|
|
||||||
{
|
|
||||||
if (path.empty()) return "";
|
|
||||||
|
|
||||||
std::string result;
|
|
||||||
if (path[0] == '~')
|
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
theme_applier::apply_to_imgui(current);
|
||||||
const char* home = std::getenv("USERPROFILE");
|
m_preview.apply_palette(current);
|
||||||
#else
|
|
||||||
const char* home = std::getenv("HOME");
|
|
||||||
#endif
|
|
||||||
result = home ? std::string(home) : "~";
|
|
||||||
result += path.substr(1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = path;
|
std::cout << "WARNING: No palette loaded, skipping theme application\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lists all files in a directory
|
|
||||||
std::vector<std::string> list_files(const std::string &dir_path)
|
|
||||||
{
|
|
||||||
std::vector<std::string> files;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (const auto &entry : fs::directory_iterator(dir_path))
|
|
||||||
{
|
|
||||||
if (entry.is_regular_file())
|
|
||||||
files.push_back(entry.path().string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::string path = expand_user("~/Documents");
|
|
||||||
std::cout << "Listing files in: " << path << std::endl;
|
|
||||||
|
|
||||||
auto files = list_files(path);
|
|
||||||
for (const auto &f : files)
|
|
||||||
std::cout << " " << f << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
})");
|
|
||||||
|
|
||||||
m_editor.SetShowWhitespaces(false);
|
|
||||||
apply_palette_to_imgui();
|
|
||||||
apply_palette_to_editor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void color_scheme_editor::notify_palette_changed()
|
void color_scheme_editor::notify_palette_changed()
|
||||||
@@ -81,6 +29,18 @@ void color_scheme_editor::notify_palette_changed()
|
|||||||
{
|
{
|
||||||
m_template_editor->apply_current_palette(m_controller.current_palette());
|
m_template_editor->apply_current_palette(m_controller.current_palette());
|
||||||
}
|
}
|
||||||
|
if (m_settings_window)
|
||||||
|
{
|
||||||
|
m_settings_window->set_palette(m_controller.current_palette());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_scheme_editor::apply_themes()
|
||||||
|
{
|
||||||
|
const auto ¤t = m_controller.current_palette();
|
||||||
|
theme_applier::apply_to_imgui(current);
|
||||||
|
m_preview.apply_palette(current);
|
||||||
|
notify_palette_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void color_scheme_editor::render_controls_and_colors()
|
void color_scheme_editor::render_controls_and_colors()
|
||||||
@@ -91,7 +51,8 @@ void color_scheme_editor::render_controls_and_colors()
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::BeginChild("ColorTableContent", ImVec2(0, 0), false);
|
ImGui::BeginChild("ColorTableContent", ImVec2(0, 0), false);
|
||||||
render_color_table();
|
m_color_table.render(m_controller.current_palette(), m_controller,
|
||||||
|
[this]() { apply_themes(); });
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
@@ -101,7 +62,7 @@ void color_scheme_editor::render_preview()
|
|||||||
{
|
{
|
||||||
ImGui::Begin("Color Preview");
|
ImGui::Begin("Color Preview");
|
||||||
|
|
||||||
render_preview_content();
|
m_preview.render(m_controller.current_palette());
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
@@ -111,11 +72,14 @@ void color_scheme_editor::render_controls()
|
|||||||
const auto ¤t = m_controller.current_palette();
|
const auto ¤t = m_controller.current_palette();
|
||||||
const auto &palettes = m_controller.palettes();
|
const auto &palettes = m_controller.palettes();
|
||||||
|
|
||||||
const float avail_width = ImGui::GetContentRegionAvail().x;
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6, 8));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 5));
|
||||||
|
|
||||||
ImGui::Text("Color Scheme:");
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Palette:");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(std::min(200.0f, avail_width * 0.3f));
|
|
||||||
|
ImGui::SetNextItemWidth(200.0f);
|
||||||
if (ImGui::BeginCombo("##scheme", current.name().c_str()))
|
if (ImGui::BeginCombo("##scheme", current.name().c_str()))
|
||||||
{
|
{
|
||||||
for (const auto &name : palettes | std::views::keys)
|
for (const auto &name : palettes | std::views::keys)
|
||||||
@@ -124,46 +88,58 @@ void color_scheme_editor::render_controls()
|
|||||||
if (ImGui::Selectable(name.c_str(), selected))
|
if (ImGui::Selectable(name.c_str(), selected))
|
||||||
{
|
{
|
||||||
m_controller.select_palette(name);
|
m_controller.select_palette(name);
|
||||||
apply_palette_to_imgui();
|
apply_themes();
|
||||||
apply_palette_to_editor();
|
|
||||||
notify_palette_changed();
|
|
||||||
}
|
}
|
||||||
if (selected)
|
if (selected)
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
}
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Select a color palette to edit");
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
|
||||||
|
|
||||||
static char new_palette_name_buf[128] = "";
|
static char new_palette_name_buf[128] = "";
|
||||||
if (ImGui::Button("New"))
|
if (ImGui::Button(" + New "))
|
||||||
{
|
{
|
||||||
new_palette_name_buf[0] = 0;
|
new_palette_name_buf[0] = 0;
|
||||||
ImGui::OpenPopup("New Palette");
|
ImGui::OpenPopup("New Palette");
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Create a new palette");
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal("New Palette", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
if (ImGui::BeginPopupModal("New Palette", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
{
|
{
|
||||||
ImGui::Text("New palette name:");
|
ImGui::Text("Enter a name for the new palette:");
|
||||||
ImGui::InputText("##new_palette_input", new_palette_name_buf,
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(250);
|
||||||
|
ImGui::InputTextWithHint("##new_palette_input", "Palette name...", new_palette_name_buf,
|
||||||
IM_ARRAYSIZE(new_palette_name_buf));
|
IM_ARRAYSIZE(new_palette_name_buf));
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
bool can_create = strlen(new_palette_name_buf) > 0;
|
||||||
|
|
||||||
|
if (!can_create)
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
|
||||||
if (ImGui::Button("Create", ImVec2(120, 0)))
|
if (ImGui::Button("Create", ImVec2(120, 0)))
|
||||||
{
|
|
||||||
if (strlen(new_palette_name_buf) > 0)
|
|
||||||
{
|
{
|
||||||
m_controller.create_palette(new_palette_name_buf);
|
m_controller.create_palette(new_palette_name_buf);
|
||||||
apply_palette_to_imgui();
|
m_controller.select_palette(new_palette_name_buf);
|
||||||
apply_palette_to_editor();
|
apply_themes();
|
||||||
notify_palette_changed();
|
|
||||||
new_palette_name_buf[0] = 0;
|
new_palette_name_buf[0] = 0;
|
||||||
}
|
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!can_create)
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
||||||
@@ -176,358 +152,53 @@ void color_scheme_editor::render_controls()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Save"))
|
if (ImGui::Button(" Save "))
|
||||||
{
|
{
|
||||||
m_controller.save_current_palette();
|
m_controller.save_current_palette();
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Save current palette to file");
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Delete"))
|
auto error = palette_utils::get_color(current, "error");
|
||||||
|
auto error_hover = ImVec4(error.x * 1.1f, error.y * 1.1f, error.z * 1.1f,
|
||||||
|
error.w);
|
||||||
|
auto error_active = ImVec4(error.x * 0.8f, error.y * 0.8f, error.z * 0.8f,
|
||||||
|
error.w);
|
||||||
|
auto on_error = palette_utils::get_color(current, "on_error");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, error);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, error_hover);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, error_active);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, on_error);
|
||||||
|
if (ImGui::Button(" Delete "))
|
||||||
{
|
{
|
||||||
m_controller.delete_current_palette();
|
m_show_delete_confirmation = true;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Delete current palette");
|
||||||
|
|
||||||
|
if (m_show_delete_confirmation)
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Delete Palette?");
|
||||||
|
m_show_delete_confirmation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
palette_utils::render_delete_confirmation_popup("Delete Palette?", current.name(), "palette",
|
||||||
|
current, [this]() {
|
||||||
|
m_controller.delete_current_palette();
|
||||||
|
apply_themes();
|
||||||
|
});
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Apply"))
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 16);
|
||||||
|
|
||||||
|
if (ImGui::Button(" Apply Theme "))
|
||||||
{
|
{
|
||||||
m_controller.apply_current_theme();
|
m_controller.apply_current_theme();
|
||||||
}
|
}
|
||||||
}
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Apply current palette to all enabled templates");
|
||||||
void color_scheme_editor::render_color_table()
|
|
||||||
{
|
ImGui::PopStyleVar(2);
|
||||||
const auto ¤t = m_controller.current_palette();
|
|
||||||
|
|
||||||
if (current.colors().empty())
|
|
||||||
{
|
|
||||||
ImGui::Text("No palette loaded");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Text("Color Variables");
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
auto render_color_row = [&](const std::string &name) {
|
|
||||||
const auto &colors = current.colors();
|
|
||||||
auto it = colors.find(name);
|
|
||||||
if (it == colors.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const clrsync::core::color &col = it->second;
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(0);
|
|
||||||
ImGui::TextUnformatted(name.c_str());
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
{
|
|
||||||
std::string hex_str = col.to_hex_string();
|
|
||||||
char buf[9];
|
|
||||||
strncpy(buf, hex_str.c_str(), sizeof(buf));
|
|
||||||
buf[8] = 0;
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
||||||
if (ImGui::InputText(("##hex_" + name).c_str(), buf, sizeof(buf),
|
|
||||||
ImGuiInputTextFlags_CharsUppercase))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
clrsync::core::color new_color;
|
|
||||||
new_color.from_hex_string(buf);
|
|
||||||
m_controller.set_color(name, new_color);
|
|
||||||
apply_palette_to_imgui();
|
|
||||||
apply_palette_to_editor();
|
|
||||||
notify_palette_changed();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(2);
|
|
||||||
ImGui::PushID(name.c_str());
|
|
||||||
float c[4] = {((col.hex() >> 24) & 0xFF) / 255.0f, ((col.hex() >> 16) & 0xFF) / 255.0f,
|
|
||||||
((col.hex() >> 8) & 0xFF) / 255.0f, (col.hex() & 0xFF) / 255.0f};
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
||||||
if (ImGui::ColorEdit4(("##color_" + name).c_str(), c,
|
|
||||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel |
|
|
||||||
ImGuiColorEditFlags_AlphaBar))
|
|
||||||
{
|
|
||||||
uint32_t r = (uint32_t)(c[0] * 255.0f);
|
|
||||||
uint32_t g = (uint32_t)(c[1] * 255.0f);
|
|
||||||
uint32_t b = (uint32_t)(c[2] * 255.0f);
|
|
||||||
uint32_t a = (uint32_t)(c[3] * 255.0f);
|
|
||||||
uint32_t hex = (r << 24) | (g << 16) | (b << 8) | a;
|
|
||||||
|
|
||||||
m_controller.set_color(name, clrsync::core::color(hex));
|
|
||||||
apply_palette_to_imgui();
|
|
||||||
apply_palette_to_editor();
|
|
||||||
notify_palette_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto draw_table = [&](const char *title, const std::vector<const char *> &keys) {
|
|
||||||
ImGui::TextUnformatted(title);
|
|
||||||
|
|
||||||
if (ImGui::BeginTable(title, 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
|
||||||
{
|
|
||||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 160.0f);
|
|
||||||
ImGui::TableSetupColumn("HEX", ImGuiTableColumnFlags_WidthFixed, 90.0f);
|
|
||||||
ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthStretch);
|
|
||||||
ImGui::TableHeadersRow();
|
|
||||||
|
|
||||||
for (auto *k : keys)
|
|
||||||
render_color_row(k);
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
};
|
|
||||||
|
|
||||||
draw_table("UI / Surfaces", {"background", "surface", "surface_variant", "foreground",
|
|
||||||
"foreground_secondary", "accent", "outline", "shadow", "cursor"});
|
|
||||||
|
|
||||||
draw_table("Editor Surfaces", {"editor_background", "sidebar_background", "popup_background",
|
|
||||||
"floating_window_background", "menu_option_background"});
|
|
||||||
|
|
||||||
draw_table("Editor Text",
|
|
||||||
{"text_main", "text_emphasis", "text_command", "text_inactive", "text_disabled",
|
|
||||||
"text_line_number", "text_selected", "text_selection_inactive"});
|
|
||||||
|
|
||||||
draw_table("Window Borders", {"border_window", "border_focused", "border_emphasized"});
|
|
||||||
|
|
||||||
draw_table("Syntax Highlighting", {"syntax_function", "syntax_error", "syntax_keyword",
|
|
||||||
"syntax_special_keyword", "syntax_operator"});
|
|
||||||
|
|
||||||
draw_table("Semantic Text",
|
|
||||||
{"text_error", "text_warning", "text_link", "text_comment", "text_string",
|
|
||||||
"text_success", "warning_emphasis", "foreground_emphasis"});
|
|
||||||
|
|
||||||
draw_table("Extra", {"terminal_gray"});
|
|
||||||
|
|
||||||
draw_table("Status Colors", {"error", "warning", "success", "info"});
|
|
||||||
|
|
||||||
draw_table("Terminal Colors",
|
|
||||||
{"term_black", "term_red", "term_green", "term_yellow", "term_blue", "term_magenta",
|
|
||||||
"term_cyan", "term_white", "term_black_bright", "term_red_bright",
|
|
||||||
"term_green_bright", "term_yellow_bright", "term_blue_bright",
|
|
||||||
"term_magenta_bright", "term_cyan_bright", "term_white_bright"});
|
|
||||||
}
|
|
||||||
|
|
||||||
void color_scheme_editor::render_preview_content()
|
|
||||||
{
|
|
||||||
const auto ¤t = m_controller.current_palette();
|
|
||||||
|
|
||||||
auto get_color = [&](const std::string &key) -> ImVec4 {
|
|
||||||
auto it = current.colors().find(key);
|
|
||||||
if (it != current.colors().end())
|
|
||||||
{
|
|
||||||
const auto &col = it->second;
|
|
||||||
const uint32_t hex = col.hex();
|
|
||||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
|
||||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
|
||||||
}
|
|
||||||
return {1, 1, 1, 1};
|
|
||||||
};
|
|
||||||
|
|
||||||
const ImVec4 editor_bg = get_color("editor_background");
|
|
||||||
const ImVec4 fg = get_color("foreground");
|
|
||||||
const ImVec4 accent = get_color("accent");
|
|
||||||
const ImVec4 outline = get_color("outline");
|
|
||||||
const ImVec4 error = get_color("error");
|
|
||||||
const ImVec4 warning = get_color("warning");
|
|
||||||
const ImVec4 success = get_color("success");
|
|
||||||
const ImVec4 info = get_color("info");
|
|
||||||
|
|
||||||
const float avail_height = ImGui::GetContentRegionAvail().y;
|
|
||||||
const float code_preview_height = std::max(250.0f, avail_height * 0.55f);
|
|
||||||
|
|
||||||
ImGui::Text("Code Editor:");
|
|
||||||
|
|
||||||
m_editor.Render("##CodeEditor", ImVec2(0, code_preview_height), true);
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Text("Terminal Preview:");
|
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, editor_bg);
|
|
||||||
ImGui::BeginChild("TerminalPreview", ImVec2(0, 0), true);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, outline);
|
|
||||||
|
|
||||||
struct term_line
|
|
||||||
{
|
|
||||||
const char *text{};
|
|
||||||
ImVec4 col;
|
|
||||||
};
|
|
||||||
term_line term_lines[] = {
|
|
||||||
{"$ ls -la", fg},
|
|
||||||
{"drwxr-xr-x 5 user group 4096 Dec 2 10:30 .", accent},
|
|
||||||
{"Build successful", success},
|
|
||||||
{"Error: file not found", error},
|
|
||||||
{"Warning: low disk space", warning},
|
|
||||||
{"Info: update available", info},
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto &[text, col] : term_lines)
|
|
||||||
{
|
|
||||||
ImGui::TextColored(col, "%s", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopStyleColor(2);
|
|
||||||
ImGui::EndChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
void color_scheme_editor::apply_palette_to_editor()
|
|
||||||
{
|
|
||||||
const auto ¤t = m_controller.current_palette();
|
|
||||||
|
|
||||||
auto get_color_u32 = [&](const std::string &key) -> uint32_t {
|
|
||||||
auto it = current.colors().find(key);
|
|
||||||
if (it != current.colors().end())
|
|
||||||
{
|
|
||||||
const auto &col = it->second;
|
|
||||||
const uint32_t hex = col.hex();
|
|
||||||
// Convert from RRGGBBAA to AABBGGRR (ImGui format)
|
|
||||||
const uint32_t r = (hex >> 24) & 0xFF;
|
|
||||||
const uint32_t g = (hex >> 16) & 0xFF;
|
|
||||||
const uint32_t b = (hex >> 8) & 0xFF;
|
|
||||||
const uint32_t a = hex & 0xFF;
|
|
||||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
|
||||||
}
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto palette = m_editor.GetPalette();
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("text_main");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("syntax_keyword");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("text_warning");
|
|
||||||
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("text_string");
|
|
||||||
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("text_string");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32("text_main");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32("syntax_special_keyword");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("text_main");
|
|
||||||
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("text_link");
|
|
||||||
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32("text_link");
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32("text_comment");
|
|
||||||
palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32("text_comment");
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32("editor_background");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor");
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32("text_selected");
|
|
||||||
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("syntax_error");
|
|
||||||
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("syntax_error");
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32("text_line_number");
|
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
|
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
|
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32("border_emphasized");
|
|
||||||
|
|
||||||
m_editor.SetPalette(palette);
|
|
||||||
}
|
|
||||||
|
|
||||||
void color_scheme_editor::apply_palette_to_imgui() const
|
|
||||||
{
|
|
||||||
const auto ¤t = m_controller.current_palette();
|
|
||||||
|
|
||||||
auto getColor = [&](const std::string &key) -> ImVec4 {
|
|
||||||
auto it = current.colors().find(key);
|
|
||||||
if (it != current.colors().end())
|
|
||||||
{
|
|
||||||
const uint32_t hex = it->second.hex();
|
|
||||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
|
||||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
|
||||||
}
|
|
||||||
return {1, 1, 1, 1};
|
|
||||||
};
|
|
||||||
|
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
|
|
||||||
const ImVec4 bg = getColor("editor_background");
|
|
||||||
const ImVec4 sidebar = getColor("sidebar_background");
|
|
||||||
const ImVec4 popup = getColor("popup_background");
|
|
||||||
const ImVec4 menuOpt = getColor("menu_option_background");
|
|
||||||
|
|
||||||
const ImVec4 surface = getColor("surface");
|
|
||||||
const ImVec4 surfaceVariant = getColor("surface_variant");
|
|
||||||
|
|
||||||
const ImVec4 fg = getColor("text_main");
|
|
||||||
const ImVec4 fgSecondary = getColor("text_inactive");
|
|
||||||
|
|
||||||
const ImVec4 accent = getColor("accent");
|
|
||||||
|
|
||||||
const ImVec4 border = getColor("border_window");
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_WindowBg] = bg;
|
|
||||||
style.Colors[ImGuiCol_ChildBg] = surface;
|
|
||||||
style.Colors[ImGuiCol_PopupBg] = popup;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Border] = border;
|
|
||||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0);
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Text] = fg;
|
|
||||||
style.Colors[ImGuiCol_TextDisabled] = fgSecondary;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Header] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
|
||||||
style.Colors[ImGuiCol_HeaderActive] = accent;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Button] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
|
||||||
style.Colors[ImGuiCol_ButtonActive] = accent;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_FrameBg] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_FrameBgHovered] =
|
|
||||||
ImVec4(surfaceVariant.x * 1.1f, surfaceVariant.y * 1.1f, surfaceVariant.z * 1.1f, 1.0f);
|
|
||||||
style.Colors[ImGuiCol_FrameBgActive] =
|
|
||||||
ImVec4(surfaceVariant.x * 1.2f, surfaceVariant.y * 1.2f, surfaceVariant.z * 1.2f, 1.0f);
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_TitleBg] = sidebar;
|
|
||||||
style.Colors[ImGuiCol_TitleBgActive] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_TitleBgCollapsed] = sidebar;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_ScrollbarBg] = surface;
|
|
||||||
style.Colors[ImGuiCol_ScrollbarGrab] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
|
||||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = accent;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_SliderGrab] = accent;
|
|
||||||
style.Colors[ImGuiCol_SliderGrabActive] =
|
|
||||||
ImVec4(accent.x * 1.2f, accent.y * 1.2f, accent.z * 1.2f, 1.0f);
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_CheckMark] = accent;
|
|
||||||
style.Colors[ImGuiCol_ResizeGrip] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
|
||||||
style.Colors[ImGuiCol_ResizeGripActive] = accent;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Tab] = surface;
|
|
||||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
|
||||||
style.Colors[ImGuiCol_TabActive] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_TabUnfocused] = surface;
|
|
||||||
style.Colors[ImGuiCol_TabUnfocusedActive] = surfaceVariant;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_TableHeaderBg] = surfaceVariant;
|
|
||||||
style.Colors[ImGuiCol_TableBorderStrong] = border;
|
|
||||||
style.Colors[ImGuiCol_TableBorderLight] =
|
|
||||||
ImVec4(border.x * 0.7f, border.y * 0.7f, border.z * 0.7f, border.w);
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_TableRowBg] = ImVec4(0, 0, 0, 0);
|
|
||||||
style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(fg.x, fg.y, fg.z, 0.06f);
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_Separator] = border;
|
|
||||||
style.Colors[ImGuiCol_SeparatorHovered] = accent;
|
|
||||||
style.Colors[ImGuiCol_SeparatorActive] = accent;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_MenuBarBg] = menuOpt;
|
|
||||||
|
|
||||||
style.Colors[ImGuiCol_DockingPreview] = ImVec4(accent.x, accent.y, accent.z, 0.7f);
|
|
||||||
style.Colors[ImGuiCol_DockingEmptyBg] = bg;
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
#ifndef CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
#ifndef CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
||||||
#define CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
#define CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
||||||
|
|
||||||
#include "color_text_edit/TextEditor.h"
|
|
||||||
#include "palette_controller.hpp"
|
#include "palette_controller.hpp"
|
||||||
|
#include "color_table_renderer.hpp"
|
||||||
|
#include "preview_renderer.hpp"
|
||||||
|
|
||||||
class template_editor;
|
class template_editor;
|
||||||
|
class settings_window;
|
||||||
|
|
||||||
class color_scheme_editor
|
class color_scheme_editor
|
||||||
{
|
{
|
||||||
@@ -14,20 +16,20 @@ public:
|
|||||||
void render_controls_and_colors();
|
void render_controls_and_colors();
|
||||||
void render_preview();
|
void render_preview();
|
||||||
void set_template_editor(template_editor* editor) { m_template_editor = editor; }
|
void set_template_editor(template_editor* editor) { m_template_editor = editor; }
|
||||||
|
void set_settings_window(settings_window* window) { m_settings_window = window; }
|
||||||
const palette_controller& controller() const { return m_controller; }
|
const palette_controller& controller() const { return m_controller; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render_controls();
|
void render_controls();
|
||||||
void render_color_table();
|
void apply_themes();
|
||||||
void render_preview_content();
|
|
||||||
|
|
||||||
void apply_palette_to_editor();
|
|
||||||
void apply_palette_to_imgui() const;
|
|
||||||
void notify_palette_changed();
|
void notify_palette_changed();
|
||||||
|
|
||||||
palette_controller m_controller;
|
palette_controller m_controller;
|
||||||
TextEditor m_editor;
|
color_table_renderer m_color_table;
|
||||||
|
preview_renderer m_preview;
|
||||||
template_editor* m_template_editor{nullptr};
|
template_editor* m_template_editor{nullptr};
|
||||||
|
settings_window* m_settings_window{nullptr};
|
||||||
|
bool m_show_delete_confirmation{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
#endif // CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
||||||
199
src/gui/color_table_renderer.cpp
Normal file
199
src/gui/color_table_renderer.cpp
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#include "color_table_renderer.hpp"
|
||||||
|
#include "imgui_helpers.hpp"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
bool color_table_renderer::matches_filter(const std::string& name) const
|
||||||
|
{
|
||||||
|
if (m_filter_text[0] == '\0')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string filter_lower = m_filter_text;
|
||||||
|
std::string name_lower = name;
|
||||||
|
|
||||||
|
std::transform(filter_lower.begin(), filter_lower.end(), filter_lower.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
|
return name_lower.find(filter_lower) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_table_renderer::render_color_row(const std::string &name,
|
||||||
|
const clrsync::core::palette& current,
|
||||||
|
palette_controller& controller,
|
||||||
|
const OnColorChangedCallback& on_changed)
|
||||||
|
{
|
||||||
|
if (!matches_filter(name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const clrsync::core::color &col = current.get_color(name);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
const float key_col_width = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
|
ImVec4 text_color = palette_utils::get_color(current, "info", "accent");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
||||||
|
const bool copied = ImGui::Selectable(name.c_str(), false, 0, ImVec2(key_col_width, 0.0f));
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||||
|
ImGui::SetTooltip("Click to copy: {%s.hex}", name.c_str());
|
||||||
|
}
|
||||||
|
if (copied)
|
||||||
|
{
|
||||||
|
std::string template_var = "{" + name + ".hex}";
|
||||||
|
ImGui::SetClipboardText(template_var.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
{
|
||||||
|
std::string hex_str = col.to_hex_string();
|
||||||
|
char buf[9];
|
||||||
|
strncpy(buf, hex_str.c_str(), sizeof(buf));
|
||||||
|
buf[8] = 0;
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
|
if (ImGui::InputText(("##hex_" + name).c_str(), buf, sizeof(buf),
|
||||||
|
ImGuiInputTextFlags_CharsUppercase))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clrsync::core::color new_color;
|
||||||
|
new_color.from_hex_string(buf);
|
||||||
|
controller.set_color(name, new_color);
|
||||||
|
if (on_changed)
|
||||||
|
on_changed();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(2);
|
||||||
|
ImGui::PushID(name.c_str());
|
||||||
|
float c[4] = {((col.hex() >> 24) & 0xFF) / 255.0f, ((col.hex() >> 16) & 0xFF) / 255.0f,
|
||||||
|
((col.hex() >> 8) & 0xFF) / 255.0f, (col.hex() & 0xFF) / 255.0f};
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
|
if (ImGui::ColorEdit4(("##color_" + name).c_str(), c,
|
||||||
|
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel |
|
||||||
|
ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreviewHalf))
|
||||||
|
{
|
||||||
|
uint32_t r = (uint32_t)(c[0] * 255.0f);
|
||||||
|
uint32_t g = (uint32_t)(c[1] * 255.0f);
|
||||||
|
uint32_t b = (uint32_t)(c[2] * 255.0f);
|
||||||
|
uint32_t a = (uint32_t)(c[3] * 255.0f);
|
||||||
|
uint32_t hex = (r << 24) | (g << 16) | (b << 8) | a;
|
||||||
|
|
||||||
|
controller.set_color(name, clrsync::core::color(hex));
|
||||||
|
if (on_changed)
|
||||||
|
on_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_table_renderer::render(const clrsync::core::palette& current,
|
||||||
|
palette_controller& controller,
|
||||||
|
const OnColorChangedCallback& on_changed)
|
||||||
|
{
|
||||||
|
if (current.colors().empty())
|
||||||
|
{
|
||||||
|
ImVec4 warning_color = palette_utils::get_color(current, "warning", "accent");
|
||||||
|
ImGui::TextColored(warning_color, "No palette loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 6));
|
||||||
|
|
||||||
|
ImGui::Text("Filter:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(200);
|
||||||
|
bool filter_changed = ImGui::InputTextWithHint("##color_filter", "Search colors...",
|
||||||
|
m_filter_text, sizeof(m_filter_text));
|
||||||
|
|
||||||
|
if (m_filter_text[0] != '\0')
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SmallButton("X"))
|
||||||
|
{
|
||||||
|
m_filter_text[0] = '\0';
|
||||||
|
filter_changed = true;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Clear filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
auto draw_table = [&](const char *title, const char* id, const std::vector<const char *> &keys) {
|
||||||
|
bool has_matches = false;
|
||||||
|
for (auto *k : keys)
|
||||||
|
{
|
||||||
|
if (matches_filter(k))
|
||||||
|
{
|
||||||
|
has_matches = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_matches)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, palette_utils::get_color(current, "accent"));
|
||||||
|
bool header_open = ImGui::TreeNodeEx(title, ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAvailWidth);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (header_open)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginTable(id, 3,
|
||||||
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp))
|
||||||
|
{
|
||||||
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 160.0f);
|
||||||
|
ImGui::TableSetupColumn("HEX", ImGuiTableColumnFlags_WidthFixed, 95.0f);
|
||||||
|
ImGui::TableSetupColumn("Color", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
for (auto *k : keys)
|
||||||
|
render_color_row(k, current, controller, on_changed);
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_table("General UI", "##general_ui", {"background", "on_background", "surface", "on_surface",
|
||||||
|
"surface_variant", "on_surface_variant", "foreground",
|
||||||
|
"cursor", "accent"});
|
||||||
|
|
||||||
|
draw_table("Borders", "##borders", {"border_focused", "border"});
|
||||||
|
|
||||||
|
draw_table("Semantic Colors", "##semantic", {"success", "info", "warning", "error",
|
||||||
|
"on_success", "on_info", "on_warning", "on_error"});
|
||||||
|
|
||||||
|
draw_table("Editor", "##editor", {"editor_background", "editor_command", "editor_comment",
|
||||||
|
"editor_disabled", "editor_emphasis", "editor_error",
|
||||||
|
"editor_inactive", "editor_line_number", "editor_link",
|
||||||
|
"editor_main", "editor_selected", "editor_selection_inactive",
|
||||||
|
"editor_string", "editor_success", "editor_warning"});
|
||||||
|
|
||||||
|
draw_table("Terminal (Base16)", "##terminal", {"base00", "base01", "base02", "base03",
|
||||||
|
"base04", "base05", "base06", "base07",
|
||||||
|
"base08", "base09", "base0A", "base0B",
|
||||||
|
"base0C", "base0D", "base0E", "base0F"});
|
||||||
|
}
|
||||||
30
src/gui/color_table_renderer.hpp
Normal file
30
src/gui/color_table_renderer.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||||
|
#define CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||||
|
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
|
#include "palette_controller.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class color_table_renderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using OnColorChangedCallback = std::function<void()>;
|
||||||
|
|
||||||
|
void render(const clrsync::core::palette& palette,
|
||||||
|
palette_controller& controller,
|
||||||
|
const OnColorChangedCallback& on_changed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void render_color_row(const std::string& name,
|
||||||
|
const clrsync::core::palette& palette,
|
||||||
|
palette_controller& controller,
|
||||||
|
const OnColorChangedCallback& on_changed);
|
||||||
|
|
||||||
|
bool matches_filter(const std::string& name) const;
|
||||||
|
|
||||||
|
char m_filter_text[128] = {0};
|
||||||
|
bool m_show_only_modified{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||||
263
src/gui/file_browser.cpp
Normal file
263
src/gui/file_browser.cpp
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
#include "file_browser.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commdlg.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace file_dialogs {
|
||||||
|
|
||||||
|
std::string open_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
OPENFILENAMEA ofn;
|
||||||
|
char file[MAX_PATH] = "";
|
||||||
|
|
||||||
|
std::string filter_str = "All Files (*.*)\0*.*\0";
|
||||||
|
|
||||||
|
ZeroMemory(&ofn, sizeof(ofn));
|
||||||
|
ofn.lStructSize = sizeof(ofn);
|
||||||
|
ofn.hwndOwner = GetActiveWindow();
|
||||||
|
ofn.lpstrFile = file;
|
||||||
|
ofn.nMaxFile = sizeof(file);
|
||||||
|
ofn.lpstrFilter = filter_str.c_str();
|
||||||
|
ofn.nFilterIndex = 1;
|
||||||
|
ofn.lpstrTitle = title.c_str();
|
||||||
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
|
||||||
|
|
||||||
|
if (!initial_path.empty() && std::filesystem::exists(initial_path)) {
|
||||||
|
std::filesystem::path p(initial_path);
|
||||||
|
if (std::filesystem::is_directory(p)) {
|
||||||
|
ofn.lpstrInitialDir = initial_path.c_str();
|
||||||
|
} else {
|
||||||
|
std::string dir = p.parent_path().string();
|
||||||
|
std::string name = p.filename().string();
|
||||||
|
ofn.lpstrInitialDir = dir.c_str();
|
||||||
|
strncpy(file, name.c_str(), sizeof(file) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetOpenFileNameA(&ofn)) {
|
||||||
|
return std::string(file);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string save_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
OPENFILENAMEA ofn;
|
||||||
|
char file[MAX_PATH] = "";
|
||||||
|
|
||||||
|
std::string filter_str = "All Files\0*.*\0\0";
|
||||||
|
|
||||||
|
ZeroMemory(&ofn, sizeof(ofn));
|
||||||
|
ofn.lStructSize = sizeof(ofn);
|
||||||
|
ofn.hwndOwner = GetActiveWindow();
|
||||||
|
ofn.lpstrFile = file;
|
||||||
|
ofn.nMaxFile = sizeof(file);
|
||||||
|
ofn.lpstrFilter = filter_str.c_str();
|
||||||
|
ofn.nFilterIndex = 1;
|
||||||
|
ofn.lpstrTitle = title.c_str();
|
||||||
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR;
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
std::filesystem::path p(initial_path);
|
||||||
|
if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) {
|
||||||
|
ofn.lpstrInitialDir = initial_path.c_str();
|
||||||
|
} else {
|
||||||
|
std::string dir = p.parent_path().string();
|
||||||
|
std::string name = p.filename().string();
|
||||||
|
if (std::filesystem::exists(dir)) {
|
||||||
|
ofn.lpstrInitialDir = dir.c_str();
|
||||||
|
strncpy(file, name.c_str(), sizeof(file) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSaveFileNameA(&ofn)) {
|
||||||
|
return std::string(file);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string select_folder_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path) {
|
||||||
|
IFileOpenDialog *pFileOpen;
|
||||||
|
|
||||||
|
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
|
||||||
|
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
DWORD dwFlags;
|
||||||
|
if (SUCCEEDED(pFileOpen->GetOptions(&dwFlags))) {
|
||||||
|
pFileOpen->SetOptions(dwFlags | FOS_PICKFOLDERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring wtitle(title.begin(), title.end());
|
||||||
|
pFileOpen->SetTitle(wtitle.c_str());
|
||||||
|
|
||||||
|
if (!initial_path.empty() && std::filesystem::exists(initial_path)) {
|
||||||
|
IShellItem *psi = NULL;
|
||||||
|
std::wstring winitial(initial_path.begin(), initial_path.end());
|
||||||
|
hr = SHCreateItemFromParsingName(winitial.c_str(), NULL, IID_IShellItem, (void**)&psi);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
pFileOpen->SetFolder(psi);
|
||||||
|
psi->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = pFileOpen->Show(GetActiveWindow());
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
IShellItem *pItem;
|
||||||
|
hr = pFileOpen->GetResult(&pItem);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
PWSTR pszFilePath;
|
||||||
|
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
std::wstring wpath(pszFilePath);
|
||||||
|
std::string result(wpath.begin(), wpath.end());
|
||||||
|
CoTaskMemFree(pszFilePath);
|
||||||
|
pItem->Release();
|
||||||
|
pFileOpen->Release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
pItem->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pFileOpen->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif !defined(__APPLE__)
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
namespace file_dialogs {
|
||||||
|
|
||||||
|
std::string open_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
if (!gtk_init_check(nullptr, nullptr)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkFileChooserNative *native = gtk_file_chooser_native_new(
|
||||||
|
title.c_str(),
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
"_Open",
|
||||||
|
"_Cancel");
|
||||||
|
|
||||||
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
std::filesystem::path p(initial_path);
|
||||||
|
if (std::filesystem::exists(p)) {
|
||||||
|
if (std::filesystem::is_directory(p)) {
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, initial_path.c_str());
|
||||||
|
} else {
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, p.parent_path().c_str());
|
||||||
|
gtk_file_chooser_set_current_name(chooser, p.filename().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
char* filename = gtk_file_chooser_get_filename(chooser);
|
||||||
|
if (filename) {
|
||||||
|
result = filename;
|
||||||
|
g_free(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string save_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
if (!gtk_init_check(nullptr, nullptr)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkFileChooserNative *native = gtk_file_chooser_native_new(
|
||||||
|
title.c_str(),
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
"_Save",
|
||||||
|
"_Cancel");
|
||||||
|
|
||||||
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
std::filesystem::path p(initial_path);
|
||||||
|
if (std::filesystem::exists(p.parent_path())) {
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, p.parent_path().c_str());
|
||||||
|
gtk_file_chooser_set_current_name(chooser, p.filename().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
char* filename = gtk_file_chooser_get_filename(chooser);
|
||||||
|
if (filename) {
|
||||||
|
result = filename;
|
||||||
|
g_free(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string select_folder_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path) {
|
||||||
|
if (!gtk_init_check(nullptr, nullptr)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkFileChooserNative *native = gtk_file_chooser_native_new(
|
||||||
|
title.c_str(),
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||||
|
"_Select",
|
||||||
|
"_Cancel");
|
||||||
|
|
||||||
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
|
||||||
|
|
||||||
|
if (!initial_path.empty() && std::filesystem::exists(initial_path)) {
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, initial_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
char* filename = gtk_file_chooser_get_filename(chooser);
|
||||||
|
if (filename) {
|
||||||
|
result = filename;
|
||||||
|
g_free(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
20
src/gui/file_browser.hpp
Normal file
20
src/gui/file_browser.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef CLRSYNC_GUI_FILE_BROWSER_HPP
|
||||||
|
#define CLRSYNC_GUI_FILE_BROWSER_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace file_dialogs {
|
||||||
|
std::string open_file_dialog(const std::string& title = "Open File",
|
||||||
|
const std::string& initial_path = "",
|
||||||
|
const std::vector<std::string>& filters = {});
|
||||||
|
|
||||||
|
std::string save_file_dialog(const std::string& title = "Save File",
|
||||||
|
const std::string& initial_path = "",
|
||||||
|
const std::vector<std::string>& filters = {});
|
||||||
|
|
||||||
|
std::string select_folder_dialog(const std::string& title = "Select Folder",
|
||||||
|
const std::string& initial_path = "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CLRSYNC_GUI_FILE_BROWSER_HPP
|
||||||
80
src/gui/file_browser_macos.mm
Normal file
80
src/gui/file_browser_macos.mm
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include "file_browser.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
namespace file_dialogs {
|
||||||
|
|
||||||
|
std::string open_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||||
|
[panel setCanChooseFiles:YES];
|
||||||
|
[panel setCanChooseDirectories:NO];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:initial_path.c_str()]];
|
||||||
|
[panel setDirectoryURL:url];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([panel runModal] == NSModalResponseOK) {
|
||||||
|
NSURL* url = [[panel URLs] objectAtIndex:0];
|
||||||
|
return std::string([[url path] UTF8String]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string save_file_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path,
|
||||||
|
const std::vector<std::string>& filters) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSSavePanel* panel = [NSSavePanel savePanel];
|
||||||
|
[panel setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
std::filesystem::path p(initial_path);
|
||||||
|
if (std::filesystem::exists(p.parent_path())) {
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:p.parent_path().c_str()]];
|
||||||
|
[panel setDirectoryURL:url];
|
||||||
|
[panel setNameFieldStringValue:[NSString stringWithUTF8String:p.filename().c_str()]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([panel runModal] == NSModalResponseOK) {
|
||||||
|
NSURL* url = [panel URL];
|
||||||
|
return std::string([[url path] UTF8String]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string select_folder_dialog(const std::string& title,
|
||||||
|
const std::string& initial_path) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||||
|
[panel setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||||
|
[panel setCanChooseFiles:NO];
|
||||||
|
[panel setCanChooseDirectories:YES];
|
||||||
|
[panel setAllowsMultipleSelection:NO];
|
||||||
|
|
||||||
|
if (!initial_path.empty()) {
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:initial_path.c_str()]];
|
||||||
|
[panel setDirectoryURL:url];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([panel runModal] == NSModalResponseOK) {
|
||||||
|
NSURL* url = [[panel URLs] objectAtIndex:0];
|
||||||
|
return std::string([[url path] UTF8String]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -41,7 +41,12 @@ static std::string search_registry_for_font(HKEY root_key, const char* subkey, c
|
|||||||
std::string reg_font_name = value_name;
|
std::string reg_font_name = value_name;
|
||||||
std::transform(reg_font_name.begin(), reg_font_name.end(), reg_font_name.begin(), ::tolower);
|
std::transform(reg_font_name.begin(), reg_font_name.end(), reg_font_name.begin(), ::tolower);
|
||||||
|
|
||||||
if (reg_font_name.find(font_name_lower) != std::string::npos)
|
std::string reg_font_name_clean = reg_font_name;
|
||||||
|
size_t type_pos = reg_font_name_clean.find(" (");
|
||||||
|
if (type_pos != std::string::npos)
|
||||||
|
reg_font_name_clean = reg_font_name_clean.substr(0, type_pos);
|
||||||
|
|
||||||
|
if (reg_font_name_clean == font_name_lower)
|
||||||
{
|
{
|
||||||
std::string font_file = reinterpret_cast<char*>(value_data);
|
std::string font_file = reinterpret_cast<char*>(value_data);
|
||||||
|
|
||||||
@@ -118,25 +123,27 @@ std::vector<unsigned char> font_loader::load_font_macos(const char* font_name)
|
|||||||
if (!desc)
|
if (!desc)
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
CTFontRef font = CTFontCreateWithFontDescriptor(desc, 0, nullptr);
|
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
|
||||||
CFRelease(desc);
|
CFRelease(desc);
|
||||||
|
|
||||||
if (!font)
|
if (!url)
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
CFDataRef data = CTFontCopyTable(font, kCTFontTableCFF, 0);
|
CFDataRef data = nullptr;
|
||||||
if (!data)
|
Boolean success = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, nullptr, nullptr, nullptr);
|
||||||
data = CTFontCopyTable(font, kCTFontTableHead, 0);
|
CFRelease(url);
|
||||||
|
|
||||||
if (data)
|
if (success && data)
|
||||||
{
|
{
|
||||||
CFIndex size = CFDataGetLength(data);
|
CFIndex size = CFDataGetLength(data);
|
||||||
|
if (size > 100)
|
||||||
|
{
|
||||||
out.resize(size);
|
out.resize(size);
|
||||||
CFDataGetBytes(data, CFRangeMake(0, size), out.data());
|
CFDataGetBytes(data, CFRangeMake(0, size), out.data());
|
||||||
|
}
|
||||||
CFRelease(data);
|
CFRelease(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFRelease(font);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,3 +233,101 @@ void font_loader::pop_font()
|
|||||||
{
|
{
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> font_loader::get_system_fonts()
|
||||||
|
{
|
||||||
|
std::vector<std::string> fonts;
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
auto enumerate_registry_fonts = [&fonts](HKEY root_key, const char* subkey)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
if (RegOpenKeyExA(root_key, subkey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char value_name[512];
|
||||||
|
DWORD value_name_size;
|
||||||
|
DWORD index = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
value_name_size = sizeof(value_name);
|
||||||
|
LONG result = RegEnumValueA(hKey, index++, value_name, &value_name_size, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::string font_name = value_name;
|
||||||
|
size_t pos = font_name.find(" (");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
font_name = font_name.substr(0, pos);
|
||||||
|
|
||||||
|
if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end())
|
||||||
|
fonts.push_back(font_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
enumerate_registry_fonts(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
|
||||||
|
enumerate_registry_fonts(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
CTFontCollectionRef collection = CTFontCollectionCreateFromAvailableFonts(nullptr);
|
||||||
|
if (collection)
|
||||||
|
{
|
||||||
|
CFArrayRef fontDescriptors = CTFontCollectionCreateMatchingFontDescriptors(collection);
|
||||||
|
CFRelease(collection);
|
||||||
|
|
||||||
|
if (fontDescriptors)
|
||||||
|
{
|
||||||
|
CFIndex count = CFArrayGetCount(fontDescriptors);
|
||||||
|
for (CFIndex i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fontDescriptors, i);
|
||||||
|
CFStringRef fontName = (CFStringRef)CTFontDescriptorCopyAttribute(descriptor, kCTFontDisplayNameAttribute);
|
||||||
|
|
||||||
|
if (fontName)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
if (CFStringGetCString(fontName, buffer, sizeof(buffer), kCFStringEncodingUTF8))
|
||||||
|
{
|
||||||
|
std::string font_name = buffer;
|
||||||
|
if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end())
|
||||||
|
fonts.push_back(font_name);
|
||||||
|
}
|
||||||
|
CFRelease(fontName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(fontDescriptors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
FcInit();
|
||||||
|
FcPattern* pattern = FcPatternCreate();
|
||||||
|
FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, nullptr);
|
||||||
|
FcFontSet* fs = FcFontList(nullptr, pattern, os);
|
||||||
|
|
||||||
|
if (fs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fs->nfont; i++)
|
||||||
|
{
|
||||||
|
FcChar8* family = nullptr;
|
||||||
|
if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch)
|
||||||
|
{
|
||||||
|
std::string font_name = reinterpret_cast<const char*>(family);
|
||||||
|
if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end())
|
||||||
|
fonts.push_back(font_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FcFontSetDestroy(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
FcObjectSetDestroy(os);
|
||||||
|
FcPatternDestroy(pattern);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::sort(fonts.begin(), fonts.end());
|
||||||
|
return fonts;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ class font_loader
|
|||||||
public:
|
public:
|
||||||
font_loader() = default;
|
font_loader() = default;
|
||||||
|
|
||||||
// Loads system font by name and returns an ImFont* or nullptr.
|
|
||||||
ImFont* load_font(const char* font_name, float size_px);
|
ImFont* load_font(const char* font_name, float size_px);
|
||||||
void push_default_font();
|
void push_default_font();
|
||||||
void pop_font();
|
void pop_font();
|
||||||
|
|
||||||
|
std::vector<std::string> get_system_fonts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string find_font_path(const char* font_name);
|
std::string find_font_path(const char* font_name);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
@@ -11,14 +12,30 @@
|
|||||||
|
|
||||||
GLFWwindow * init_glfw()
|
GLFWwindow * init_glfw()
|
||||||
{
|
{
|
||||||
if (!glfwInit()) return nullptr;
|
glfwSetErrorCallback([](int error, const char* description) {
|
||||||
|
std::cerr << "GLFW Error " << error << ": " << description << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!glfwInit())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to initialize GLFW\n";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
|
#else
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
|
#endif
|
||||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
||||||
|
|
||||||
GLFWwindow* w = glfwCreateWindow(1280, 720, "clrsync", nullptr, nullptr);
|
GLFWwindow* w = glfwCreateWindow(1280, 720, "clrsync", nullptr, nullptr);
|
||||||
if (!w) return nullptr;
|
if (!w)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to create GLFW window\n";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
glfwMakeContextCurrent(w);
|
glfwMakeContextCurrent(w);
|
||||||
glfwSwapInterval(1);
|
glfwSwapInterval(1);
|
||||||
@@ -36,7 +53,11 @@ void init_imgui(GLFWwindow* window, const std::string& ini_path)
|
|||||||
|
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
ImGui_ImplOpenGL3_Init("#version 130");
|
#ifdef __APPLE__
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 150");
|
||||||
|
#else
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 120");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin_frame()
|
void begin_frame()
|
||||||
@@ -60,7 +81,6 @@ void render_menu_bar(about_window* about, settings_window* settings)
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem("Exit"))
|
if (ImGui::MenuItem("Exit"))
|
||||||
{
|
{
|
||||||
// Will be handled by checking window should close
|
|
||||||
glfwSetWindowShouldClose(glfwGetCurrentContext(), GLFW_TRUE);
|
glfwSetWindowShouldClose(glfwGetCurrentContext(), GLFW_TRUE);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
@@ -87,15 +107,16 @@ void setup_main_dockspace(bool& first_time)
|
|||||||
ImGui::SetNextWindowViewport(viewport->ID);
|
ImGui::SetNextWindowViewport(viewport->ID);
|
||||||
|
|
||||||
constexpr ImGuiWindowFlags flags =
|
constexpr ImGuiWindowFlags flags =
|
||||||
// ImGuiWindowFlags_NoTitleBar |
|
ImGuiWindowFlags_NoTitleBar |
|
||||||
ImGuiWindowFlags_NoCollapse |
|
ImGuiWindowFlags_NoCollapse |
|
||||||
ImGuiWindowFlags_NoResize |
|
ImGuiWindowFlags_NoResize |
|
||||||
ImGuiWindowFlags_NoMove |
|
ImGuiWindowFlags_NoMove |
|
||||||
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||||
ImGuiWindowFlags_NoNavFocus;
|
ImGuiWindowFlags_NoNavFocus |
|
||||||
|
ImGuiWindowFlags_MenuBar;
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 1.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));
|
||||||
ImGui::Begin("MainDockSpace", nullptr, flags);
|
ImGui::Begin("MainDockSpace", nullptr, flags);
|
||||||
ImGui::PopStyleVar(3);
|
ImGui::PopStyleVar(3);
|
||||||
@@ -110,20 +131,23 @@ void setup_main_dockspace(bool& first_time)
|
|||||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace);
|
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace);
|
||||||
ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
|
ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
|
||||||
|
|
||||||
ImGuiID left, right;
|
ImGuiID center, right;
|
||||||
ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.45f, &left, &right);
|
ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 0.5f, &right, ¢er);
|
||||||
|
|
||||||
ImGuiID right_top, right_bottom;
|
ImGuiDockNode* center_node = ImGui::DockBuilderGetNode(center);
|
||||||
ImGui::DockBuilderSplitNode(right, ImGuiDir_Up, 0.6f, &right_top, &right_bottom);
|
if (center_node)
|
||||||
|
{
|
||||||
|
center_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::DockBuilderDockWindow("Templates", left);
|
ImGui::DockBuilderDockWindow("Color Schemes", right);
|
||||||
ImGui::DockBuilderDockWindow("Color Schemes", right_top);
|
ImGui::DockBuilderDockWindow("Color Preview", center);
|
||||||
ImGui::DockBuilderDockWindow("Color Preview", right_bottom);
|
ImGui::DockBuilderDockWindow("Templates", center);
|
||||||
|
|
||||||
ImGui::DockBuilderFinish(dockspace_id);
|
ImGui::DockBuilderFinish(dockspace_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::DockSpace(dockspace_id, ImVec2{0,0});
|
ImGui::DockSpace(dockspace_id, ImVec2{0,0}, ImGuiDockNodeFlags_None);
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,3 +172,95 @@ void shutdown(GLFWwindow* window)
|
|||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace palette_utils
|
||||||
|
{
|
||||||
|
|
||||||
|
ImVec4 get_color(const clrsync::core::palette& pal, const std::string& key, const std::string& fallback)
|
||||||
|
{
|
||||||
|
auto colors = pal.colors();
|
||||||
|
if (colors.empty())
|
||||||
|
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
auto it = colors.find(key);
|
||||||
|
if (it == colors.end() && !fallback.empty())
|
||||||
|
{
|
||||||
|
it = colors.find(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != colors.end())
|
||||||
|
{
|
||||||
|
const auto& col = it->second;
|
||||||
|
const uint32_t hex = col.hex();
|
||||||
|
const float r = ((hex >> 24) & 0xFF) / 255.0f;
|
||||||
|
const float g = ((hex >> 16) & 0xFF) / 255.0f;
|
||||||
|
const float b = ((hex >> 8) & 0xFF) / 255.0f;
|
||||||
|
const float a = (hex & 0xFF) / 255.0f;
|
||||||
|
return ImVec4(r, g, b, a);
|
||||||
|
}
|
||||||
|
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_color_u32(const clrsync::core::palette& pal, const std::string& key, const std::string& fallback)
|
||||||
|
{
|
||||||
|
auto colors = pal.colors();
|
||||||
|
if (colors.empty())
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
|
||||||
|
auto it = colors.find(key);
|
||||||
|
if (it == colors.end() && !fallback.empty())
|
||||||
|
{
|
||||||
|
it = colors.find(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != colors.end())
|
||||||
|
{
|
||||||
|
const auto& col = it->second;
|
||||||
|
const uint32_t hex = col.hex();
|
||||||
|
const uint32_t r = (hex >> 24) & 0xFF;
|
||||||
|
const uint32_t g = (hex >> 16) & 0xFF;
|
||||||
|
const uint32_t b = (hex >> 8) & 0xFF;
|
||||||
|
const uint32_t a = hex & 0xFF;
|
||||||
|
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||||
|
}
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool render_delete_confirmation_popup(const std::string& popup_title, const std::string& item_name,
|
||||||
|
const std::string& item_type, const clrsync::core::palette& pal,
|
||||||
|
const std::function<void()>& on_delete)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if (ImGui::BeginPopupModal(popup_title.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImVec4 warning_color = get_color(pal, "warning", "accent");
|
||||||
|
ImGui::TextColored(warning_color, "Are you sure you want to delete '%s'?", item_name.c_str());
|
||||||
|
ImGui::Text("This action cannot be undone.");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
float button_width = 120.0f;
|
||||||
|
float total_width = 2.0f * button_width + ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
float window_width = ImGui::GetContentRegionAvail().x;
|
||||||
|
ImGui::SetCursorPosX((window_width - total_width) * 0.5f);
|
||||||
|
|
||||||
|
if (ImGui::Button("Delete", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
on_delete();
|
||||||
|
result = true;
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Cancel", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#define CLRSYNC_IMGUI_HELPERS_HPP
|
#define CLRSYNC_IMGUI_HELPERS_HPP
|
||||||
|
|
||||||
#include "gui/about_window.hpp"
|
#include "gui/about_window.hpp"
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
@@ -15,4 +18,20 @@ void end_frame(GLFWwindow* window);
|
|||||||
void shutdown(GLFWwindow* window);
|
void shutdown(GLFWwindow* window);
|
||||||
void render_menu_bar(about_window* about, settings_window* settings);
|
void render_menu_bar(about_window* about, settings_window* settings);
|
||||||
|
|
||||||
|
namespace palette_utils
|
||||||
|
{
|
||||||
|
ImVec4 get_color(const clrsync::core::palette& pal, const std::string& key, const std::string& fallback = "");
|
||||||
|
uint32_t get_color_u32(const clrsync::core::palette& pal, const std::string& key, const std::string& fallback = "");
|
||||||
|
bool render_delete_confirmation_popup(const std::string& popup_title, const std::string& item_name,
|
||||||
|
const std::string& item_type, const clrsync::core::palette& pal,
|
||||||
|
const std::function<void()>& on_delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace imgui_helpers
|
||||||
|
{
|
||||||
|
inline ImVec4 get_palette_color(const clrsync::core::palette& pal, const std::string& key, const std::string& fallback = "") {
|
||||||
|
return palette_utils::get_color(pal, key, fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CLRSYNC_IMGUI_HELPERS_HPP
|
#endif // CLRSYNC_IMGUI_HELPERS_HPP
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <GLFW/glfw3native.h>
|
||||||
|
|
||||||
|
|
||||||
#include "core/config/config.hpp"
|
#include "core/config/config.hpp"
|
||||||
#include "core/io/toml_file.hpp"
|
#include "core/io/toml_file.hpp"
|
||||||
#include "core/utils.hpp"
|
#include "core/utils.hpp"
|
||||||
|
#include "core/error.hpp"
|
||||||
|
|
||||||
#include "color_scheme_editor.hpp"
|
#include "color_scheme_editor.hpp"
|
||||||
#include "gui/font_loader.hpp"
|
#include "gui/font_loader.hpp"
|
||||||
@@ -18,7 +21,14 @@ int main(int, char**)
|
|||||||
{
|
{
|
||||||
auto config_path = clrsync::core::get_default_config_path();
|
auto config_path = clrsync::core::get_default_config_path();
|
||||||
auto conf = std::make_unique<clrsync::core::io::toml_file>(config_path);
|
auto conf = std::make_unique<clrsync::core::io::toml_file>(config_path);
|
||||||
clrsync::core::config::instance().initialize(std::move(conf));
|
|
||||||
|
auto init_result = clrsync::core::config::instance().initialize(std::move(conf));
|
||||||
|
if (!init_result)
|
||||||
|
{
|
||||||
|
std::cerr << "Fatal error: " << init_result.error().description() << std::endl;
|
||||||
|
std::cerr << "Hint: Set CLRSYNC_CONFIG_PATH environment variable or ensure config exists at: " << config_path << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path base = config_path;
|
std::filesystem::path base = config_path;
|
||||||
static std::string ini_path = (base.parent_path() / "layout.ini").string();
|
static std::string ini_path = (base.parent_path() / "layout.ini").string();
|
||||||
@@ -27,6 +37,18 @@ int main(int, char**)
|
|||||||
GLFWwindow* window = init_glfw();
|
GLFWwindow* window = init_glfw();
|
||||||
if (!window) return 1;
|
if (!window) return 1;
|
||||||
|
|
||||||
|
printf("GLFV Version: %s\n", glfwGetVersionString());
|
||||||
|
|
||||||
|
std::cout << "GLFW runtime platform: ";
|
||||||
|
switch (glfwGetPlatform()) {
|
||||||
|
case GLFW_PLATFORM_WAYLAND: std::cout << "Wayland\n"; break;
|
||||||
|
case GLFW_PLATFORM_X11: std::cout << "X11\n"; break;
|
||||||
|
case GLFW_PLATFORM_COCOA: std::cout << "Cocoa\n"; break;
|
||||||
|
case GLFW_PLATFORM_WIN32: std::cout << "Win32\n"; break;
|
||||||
|
default: std::cout << "Unknown\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init_imgui(window, ini_path);
|
init_imgui(window, ini_path);
|
||||||
|
|
||||||
font_loader loader;
|
font_loader loader;
|
||||||
@@ -43,7 +65,9 @@ int main(int, char**)
|
|||||||
settings_window settingsWindow;
|
settings_window settingsWindow;
|
||||||
|
|
||||||
colorEditor.set_template_editor(&templateEditor);
|
colorEditor.set_template_editor(&templateEditor);
|
||||||
|
colorEditor.set_settings_window(&settingsWindow);
|
||||||
templateEditor.apply_current_palette(colorEditor.controller().current_palette());
|
templateEditor.apply_current_palette(colorEditor.controller().current_palette());
|
||||||
|
settingsWindow.set_palette(colorEditor.controller().current_palette());
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window))
|
||||||
{
|
{
|
||||||
@@ -53,10 +77,10 @@ int main(int, char**)
|
|||||||
|
|
||||||
render_menu_bar(&aboutWindow, &settingsWindow);
|
render_menu_bar(&aboutWindow, &settingsWindow);
|
||||||
setup_main_dockspace(first_time);
|
setup_main_dockspace(first_time);
|
||||||
|
templateEditor.render();
|
||||||
colorEditor.render_controls_and_colors();
|
colorEditor.render_controls_and_colors();
|
||||||
colorEditor.render_preview();
|
colorEditor.render_preview();
|
||||||
templateEditor.render();
|
aboutWindow.render(colorEditor.controller().current_palette());
|
||||||
aboutWindow.render();
|
|
||||||
settingsWindow.render();
|
settingsWindow.render();
|
||||||
|
|
||||||
loader.pop_font();
|
loader.pop_font();
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ palette_controller::palette_controller()
|
|||||||
if (m_palettes.empty())
|
if (m_palettes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
auto default_theme = clrsync::core::config::instance().default_theme();
|
||||||
m_current_palette = m_palettes[clrsync::core::config::instance().default_theme()];
|
auto it = m_palettes.find(default_theme);
|
||||||
} catch (...) {
|
if (it != m_palettes.end()) {
|
||||||
|
m_current_palette = it->second;
|
||||||
|
} else {
|
||||||
m_current_palette = m_palettes.begin()->second;
|
m_current_palette = m_palettes.begin()->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,12 +30,11 @@ void palette_controller::select_palette(const std::string& name)
|
|||||||
|
|
||||||
void palette_controller::create_palette(const std::string& name)
|
void palette_controller::create_palette(const std::string& name)
|
||||||
{
|
{
|
||||||
clrsync::core::palette new_palette = m_current_palette;
|
clrsync::core::palette new_palette(name);
|
||||||
new_palette.set_name(name);
|
|
||||||
|
|
||||||
auto colors = m_current_palette.colors();
|
for (const auto& [key, hex_value] : clrsync::core::DEFAULT_COLORS)
|
||||||
for (auto& pair : colors) {
|
{
|
||||||
new_palette.set_color(pair.first, pair.second);
|
new_palette.set_color(key, clrsync::core::color(hex_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dir = clrsync::core::config::instance().palettes_path();
|
auto dir = clrsync::core::config::instance().palettes_path();
|
||||||
@@ -59,7 +60,7 @@ void palette_controller::delete_current_palette()
|
|||||||
void palette_controller::apply_current_theme() const
|
void palette_controller::apply_current_theme() const
|
||||||
{
|
{
|
||||||
clrsync::core::theme_renderer<clrsync::core::io::toml_file> theme_renderer;
|
clrsync::core::theme_renderer<clrsync::core::io::toml_file> theme_renderer;
|
||||||
theme_renderer.apply_theme(m_current_palette.name());
|
(void)theme_renderer.apply_theme(m_current_palette.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void palette_controller::set_color(const std::string& key, const clrsync::core::color& color)
|
void palette_controller::set_color(const std::string& key, const clrsync::core::color& color)
|
||||||
|
|||||||
248
src/gui/preview_renderer.cpp
Normal file
248
src/gui/preview_renderer.cpp
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
#include "preview_renderer.hpp"
|
||||||
|
#include "theme_applier.hpp"
|
||||||
|
#include "imgui_helpers.hpp"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
preview_renderer::preview_renderer()
|
||||||
|
{
|
||||||
|
m_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
|
||||||
|
m_editor.SetText(R"(#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
std::string expand_user(const std::string &path)
|
||||||
|
{
|
||||||
|
if (path.empty()) return "";
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (path[0] == '~')
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
const char* home = std::getenv("USERPROFILE");
|
||||||
|
#else
|
||||||
|
const char* home = std::getenv("HOME");
|
||||||
|
#endif
|
||||||
|
result = home ? std::string(home) : "~";
|
||||||
|
result += path.substr(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> list_files(const std::string &dir_path)
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (const auto &entry : fs::directory_iterator(dir_path))
|
||||||
|
{
|
||||||
|
if (entry.is_regular_file())
|
||||||
|
files.push_back(entry.path().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::string path = expand_user("~/Documents");
|
||||||
|
std::cout << "Listing files in: " << path << std::endl;
|
||||||
|
|
||||||
|
auto files = list_files(path);
|
||||||
|
for (const auto &f : files)
|
||||||
|
std::cout << " " << f << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})");
|
||||||
|
|
||||||
|
m_editor.SetShowWhitespaces(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImVec4 hex_to_imvec4(uint32_t hex)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
((hex >> 24) & 0xFF) / 255.0f,
|
||||||
|
((hex >> 16) & 0xFF) / 255.0f,
|
||||||
|
((hex >> 8) & 0xFF) / 255.0f,
|
||||||
|
(hex & 0xFF) / 255.0f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void preview_renderer::apply_palette(const clrsync::core::palette& palette)
|
||||||
|
{
|
||||||
|
theme_applier::apply_to_editor(m_editor, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preview_renderer::render_code_preview()
|
||||||
|
{
|
||||||
|
const float avail_height = ImGui::GetContentRegionAvail().y;
|
||||||
|
const float code_preview_height = std::max(250.0f, avail_height * 0.50f);
|
||||||
|
|
||||||
|
ImGui::Text("Code Editor Preview:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled("(editor_* colors)");
|
||||||
|
m_editor.Render("##CodeEditor", ImVec2(0, code_preview_height), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preview_renderer::render_terminal_preview(const clrsync::core::palette& current)
|
||||||
|
{
|
||||||
|
auto get_color = [&](const std::string &key) -> ImVec4 {
|
||||||
|
const auto &col = current.get_color(key);
|
||||||
|
return hex_to_imvec4(col.hex());
|
||||||
|
};
|
||||||
|
const ImVec4 bg = get_color("base00");
|
||||||
|
const ImVec4 fg = get_color("base07");
|
||||||
|
const ImVec4 cursor_col = get_color("cursor");
|
||||||
|
const ImVec4 border_col = get_color("border");
|
||||||
|
|
||||||
|
const ImVec4 black = get_color("base00");
|
||||||
|
const ImVec4 red = get_color("base01");
|
||||||
|
const ImVec4 green = get_color("base02");
|
||||||
|
const ImVec4 yellow = get_color("base03");
|
||||||
|
const ImVec4 blue = get_color("base04");
|
||||||
|
const ImVec4 magenta = get_color("base05");
|
||||||
|
const ImVec4 cyan = get_color("base06");
|
||||||
|
const ImVec4 white = get_color("base07");
|
||||||
|
|
||||||
|
const ImVec4 bright_black = get_color("base08");
|
||||||
|
const ImVec4 bright_red = get_color("base09");
|
||||||
|
const ImVec4 bright_green = get_color("base0A");
|
||||||
|
const ImVec4 bright_yellow = get_color("base0B");
|
||||||
|
const ImVec4 bright_blue = get_color("base0C");
|
||||||
|
const ImVec4 bright_magenta = get_color("base0D");
|
||||||
|
const ImVec4 bright_cyan = get_color("base0E");
|
||||||
|
const ImVec4 bright_white = get_color("base0F");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Text("Terminal Preview:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled("(base00-base0F colors)");
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, border_col);
|
||||||
|
|
||||||
|
const float terminal_height = std::max(200.0f, ImGui::GetContentRegionAvail().y - 10.0f);
|
||||||
|
ImGui::BeginChild("TerminalPreview", ImVec2(0, terminal_height), true);
|
||||||
|
|
||||||
|
ImGui::TextColored(green, "user@host");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, ":");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(blue, "~/projects");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, "$ ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, "ls -la");
|
||||||
|
|
||||||
|
ImGui::TextColored(fg, "total 48");
|
||||||
|
ImGui::TextColored(blue, "drwxr-xr-x");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(fg, " 5 user group 4096 Dec 2 10:30 ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(blue, ".");
|
||||||
|
|
||||||
|
ImGui::TextColored(blue, "drwxr-xr-x");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(fg, " 3 user group 4096 Dec 1 09:15 ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(blue, "..");
|
||||||
|
|
||||||
|
ImGui::TextColored(fg, "-rw-r--r--");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(fg, " 1 user group 1234 Dec 2 10:30 ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, "README.md");
|
||||||
|
|
||||||
|
ImGui::TextColored(fg, "-rwxr-xr-x");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(fg, " 1 user group 8192 Dec 2 10:28 ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(green, "build.sh");
|
||||||
|
|
||||||
|
ImGui::TextColored(cyan, "lrwxrwxrwx");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(fg, " 1 user group 24 Dec 1 15:00 ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(cyan, "config -> ~/.config/app");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::TextColored(green, "user@host");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, ":");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(blue, "~/projects");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, "$ ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(fg, "git status");
|
||||||
|
|
||||||
|
ImGui::TextColored(fg, "On branch ");
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGui::TextColored(green, "main");
|
||||||
|
ImGui::TextColored(fg, "Changes to be committed:");
|
||||||
|
ImGui::TextColored(green, " modified: src/main.cpp");
|
||||||
|
ImGui::TextColored(green, " new file: src/utils.hpp");
|
||||||
|
ImGui::TextColored(fg, "Changes not staged:");
|
||||||
|
ImGui::TextColored(red, " modified: README.md");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::TextColored(fg, "ANSI Colors (0-7 / 8-15):");
|
||||||
|
|
||||||
|
const float box_size = 20.0f;
|
||||||
|
const float spacing = 4.0f;
|
||||||
|
ImVec2 start_pos = ImGui::GetCursorScreenPos();
|
||||||
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
std::array<ImVec4, 8> normal_colors = {black, red, green, yellow, blue, magenta, cyan, white};
|
||||||
|
for (size_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
ImVec2 p0 = ImVec2(start_pos.x + i * (box_size + spacing), start_pos.y);
|
||||||
|
ImVec2 p1 = ImVec2(p0.x + box_size, p0.y + box_size);
|
||||||
|
draw_list->AddRectFilled(p0, p1, ImGui::ColorConvertFloat4ToU32(normal_colors[i]));
|
||||||
|
draw_list->AddRect(p0, p1, ImGui::ColorConvertFloat4ToU32(border_col));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<ImVec4, 8> bright_colors = {bright_black, bright_red, bright_green, bright_yellow,
|
||||||
|
bright_blue, bright_magenta, bright_cyan, bright_white};
|
||||||
|
for (size_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
ImVec2 p0 = ImVec2(start_pos.x + i * (box_size + spacing), start_pos.y + box_size + spacing);
|
||||||
|
ImVec2 p1 = ImVec2(p0.x + box_size, p0.y + box_size);
|
||||||
|
draw_list->AddRectFilled(p0, p1, ImGui::ColorConvertFloat4ToU32(bright_colors[i]));
|
||||||
|
draw_list->AddRect(p0, p1, ImGui::ColorConvertFloat4ToU32(border_col));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Dummy(ImVec2(8 * (box_size + spacing), 2 * box_size + spacing + 4));
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void preview_renderer::render(const clrsync::core::palette& current)
|
||||||
|
{
|
||||||
|
if (current.colors().empty())
|
||||||
|
{
|
||||||
|
ImVec4 error_color = palette_utils::get_color(current, "error", "accent");
|
||||||
|
ImGui::TextColored(error_color, "Current palette is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_code_preview();
|
||||||
|
render_terminal_preview(current);
|
||||||
|
}
|
||||||
22
src/gui/preview_renderer.hpp
Normal file
22
src/gui/preview_renderer.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||||
|
#define CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||||
|
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
|
#include "color_text_edit/TextEditor.h"
|
||||||
|
|
||||||
|
class preview_renderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
preview_renderer();
|
||||||
|
|
||||||
|
void render(const clrsync::core::palette& palette);
|
||||||
|
void apply_palette(const clrsync::core::palette& palette);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void render_code_preview();
|
||||||
|
void render_terminal_preview(const clrsync::core::palette& palette);
|
||||||
|
|
||||||
|
TextEditor m_editor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
#include "settings_window.hpp"
|
#include "settings_window.hpp"
|
||||||
#include "core/config/config.hpp"
|
#include "core/config/config.hpp"
|
||||||
|
#include "core/error.hpp"
|
||||||
#include "gui/font_loader.hpp"
|
#include "gui/font_loader.hpp"
|
||||||
|
#include "gui/imgui_helpers.hpp"
|
||||||
|
#include "gui/file_browser.hpp"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
settings_window::settings_window()
|
settings_window::settings_window()
|
||||||
: m_font_size(14)
|
: m_font_size(14), m_selected_font_idx(0), m_settings_changed(false), m_current_tab(0)
|
||||||
{
|
{
|
||||||
m_default_theme[0] = '\0';
|
m_default_theme[0] = '\0';
|
||||||
m_palettes_path[0] = '\0';
|
m_palettes_path[0] = '\0';
|
||||||
m_font[0] = '\0';
|
m_font[0] = '\0';
|
||||||
|
|
||||||
|
font_loader loader;
|
||||||
|
m_available_fonts = loader.get_system_fonts();
|
||||||
|
|
||||||
load_settings();
|
load_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,109 +25,39 @@ void settings_window::render()
|
|||||||
if (!m_visible)
|
if (!m_visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_FirstUseEver);
|
ImGui::SetNextWindowSize(ImVec2(700, 500), ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||||
|
|
||||||
if (ImGui::Begin("Settings", &m_visible))
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse;
|
||||||
|
if (ImGui::Begin("Settings", &m_visible, window_flags))
|
||||||
{
|
{
|
||||||
ImGui::Text("General Settings");
|
if (ImGui::BeginTabBar("SettingsTabs", ImGuiTabBarFlags_None))
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
ImGui::Text("Default Theme:");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(300.0f);
|
|
||||||
ImGui::InputText("##default_theme", m_default_theme, sizeof(m_default_theme));
|
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
{
|
||||||
ImGui::SetTooltip("The default color scheme to load on startup");
|
if (ImGui::BeginTabItem("General"))
|
||||||
|
{
|
||||||
|
render_general_tab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
if (ImGui::BeginTabItem("Appearance"))
|
||||||
|
|
||||||
ImGui::Text("Palettes Path:");
|
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
||||||
ImGui::InputText("##palettes_path", m_palettes_path, sizeof(m_palettes_path));
|
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
{
|
||||||
ImGui::SetTooltip("Directory where color palettes are stored\nSupports ~ for home directory");
|
render_appearance_tab();
|
||||||
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::EndTabBar();
|
||||||
|
|
||||||
ImGui::Text("Font:");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(300.0f);
|
|
||||||
ImGui::InputText("##font", m_font, sizeof(m_font));
|
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
|
||||||
ImGui::SetTooltip("Font");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
render_status_messages();
|
||||||
|
|
||||||
ImGui::Text("Font Size:");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(100.0f);
|
|
||||||
ImGui::InputInt("##font_size", &m_font_size, 1, 1);
|
|
||||||
if (m_font_size < 8) m_font_size = 8;
|
|
||||||
if (m_font_size > 48) m_font_size = 48;
|
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
|
||||||
ImGui::SetTooltip("Font size");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
if (!m_error_message.empty())
|
|
||||||
{
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
|
|
||||||
ImGui::TextWrapped("%s", m_error_message.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::Spacing();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
render_action_buttons();
|
||||||
|
|
||||||
if (ImGui::Button("OK", ImVec2(120, 0)))
|
|
||||||
{
|
|
||||||
apply_settings();
|
|
||||||
m_visible = false;
|
|
||||||
m_error_message = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Apply", ImVec2(120, 0)))
|
|
||||||
{
|
|
||||||
apply_settings();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Reset to Defaults", ImVec2(150, 0)))
|
|
||||||
{
|
|
||||||
strncpy(m_default_theme, "dark", sizeof(m_default_theme));
|
|
||||||
strncpy(m_palettes_path, "~/.config/clrsync/palettes", sizeof(m_palettes_path));
|
|
||||||
strncpy(m_font, "JetBrains Mono Nerd Font", sizeof(m_font));
|
|
||||||
m_font_size = 14;
|
|
||||||
m_error_message = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
|
||||||
{
|
|
||||||
load_settings();
|
|
||||||
m_visible = false;
|
|
||||||
m_error_message = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void settings_window::load_settings()
|
void settings_window::load_settings()
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
auto& cfg = clrsync::core::config::instance();
|
auto& cfg = clrsync::core::config::instance();
|
||||||
|
|
||||||
std::string default_theme = cfg.default_theme();
|
std::string default_theme = cfg.default_theme();
|
||||||
@@ -135,26 +72,24 @@ void settings_window::load_settings()
|
|||||||
strncpy(m_font, font.c_str(), sizeof(m_font) - 1);
|
strncpy(m_font, font.c_str(), sizeof(m_font) - 1);
|
||||||
m_font[sizeof(m_font) - 1] = '\0';
|
m_font[sizeof(m_font) - 1] = '\0';
|
||||||
|
|
||||||
|
m_selected_font_idx = 0;
|
||||||
|
for (int i = 0; i < static_cast<int>(m_available_fonts.size()); i++)
|
||||||
|
{
|
||||||
|
if (m_available_fonts[i] == font)
|
||||||
|
{
|
||||||
|
m_selected_font_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_font_size = cfg.font_size();
|
m_font_size = cfg.font_size();
|
||||||
|
|
||||||
m_error_message = "";
|
m_error_message.clear();
|
||||||
}
|
m_settings_changed = false;
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
m_error_message = std::string("Failed to load settings: ") + e.what();
|
|
||||||
|
|
||||||
// Set defaults on error
|
|
||||||
strncpy(m_default_theme, "dark", sizeof(m_default_theme));
|
|
||||||
strncpy(m_palettes_path, "~/.config/clrsync/palettes", sizeof(m_palettes_path));
|
|
||||||
strncpy(m_font, "JetBrains Mono Nerd Font", sizeof(m_font));
|
|
||||||
m_font_size = 14;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void settings_window::apply_settings()
|
void settings_window::apply_settings()
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
auto& cfg = clrsync::core::config::instance();
|
auto& cfg = clrsync::core::config::instance();
|
||||||
|
|
||||||
if (strlen(m_default_theme) == 0)
|
if (strlen(m_default_theme) == 0)
|
||||||
@@ -181,21 +116,255 @@ void settings_window::apply_settings()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.set_default_theme(m_default_theme);
|
auto result1 = cfg.set_default_theme(m_default_theme);
|
||||||
cfg.set_palettes_path(m_palettes_path);
|
if (!result1)
|
||||||
cfg.set_font(m_font);
|
{
|
||||||
cfg.set_font_size(m_font_size);
|
m_error_message = "Failed to set default theme: " + result1.error().description();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result2 = cfg.set_palettes_path(m_palettes_path);
|
||||||
|
if (!result2)
|
||||||
|
{
|
||||||
|
m_error_message = "Failed to set palettes path: " + result2.error().description();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result3 = cfg.set_font(m_font);
|
||||||
|
if (!result3)
|
||||||
|
{
|
||||||
|
m_error_message = "Failed to set font: " + result3.error().description();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result4 = cfg.set_font_size(m_font_size);
|
||||||
|
if (!result4)
|
||||||
|
{
|
||||||
|
m_error_message = "Failed to set font size: " + result4.error().description();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
font_loader fn_loader;
|
font_loader fn_loader;
|
||||||
auto font = fn_loader.load_font(m_font, m_font_size);
|
auto font = fn_loader.load_font(m_font, m_font_size);
|
||||||
if (font)
|
if (font)
|
||||||
ImGui::GetIO().FontDefault = font;
|
ImGui::GetIO().FontDefault = font;
|
||||||
|
|
||||||
m_error_message = "";
|
m_error_message.clear();
|
||||||
}
|
m_settings_changed = false;
|
||||||
catch (const std::exception& e)
|
}
|
||||||
|
|
||||||
|
void settings_window::render_general_tab()
|
||||||
|
{
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
auto accent_color = palette_utils::get_color(m_current_palette, "accent");
|
||||||
|
ImGui::TextColored(accent_color, "Theme Settings");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::Text("Default Theme:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
show_help_marker("The default color scheme to load on startup");
|
||||||
|
ImGui::SetNextItemWidth(-100.0f);
|
||||||
|
if (ImGui::InputText("##default_theme", m_default_theme, sizeof(m_default_theme)))
|
||||||
|
m_settings_changed = true;
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::TextColored(accent_color, "Path Settings");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::Text("Palettes Directory:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
show_help_marker("Directory where color palettes are stored\nSupports ~ for home directory");
|
||||||
|
ImGui::SetNextItemWidth(-120.0f);
|
||||||
|
if (ImGui::InputText("##palettes_path", m_palettes_path, sizeof(m_palettes_path)))
|
||||||
|
m_settings_changed = true;
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Browse"))
|
||||||
{
|
{
|
||||||
m_error_message = std::string("Failed to apply settings: ") + e.what();
|
std::string selected_path = file_dialogs::select_folder_dialog("Select Palettes Directory", m_palettes_path);
|
||||||
|
if (!selected_path.empty()) {
|
||||||
|
strncpy(m_palettes_path, selected_path.c_str(), sizeof(m_palettes_path) - 1);
|
||||||
|
m_palettes_path[sizeof(m_palettes_path) - 1] = '\0';
|
||||||
|
m_settings_changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void settings_window::render_appearance_tab()
|
||||||
|
{
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
auto accent_color = palette_utils::get_color(m_current_palette, "accent");
|
||||||
|
ImGui::TextColored(accent_color, "Font Settings");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::Text("Font Family:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
show_help_marker("Select font family for the application interface");
|
||||||
|
ImGui::SetNextItemWidth(-1.0f);
|
||||||
|
if (ImGui::BeginCombo("##font", m_font))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(m_available_fonts.size()); i++)
|
||||||
|
{
|
||||||
|
bool is_selected = (i == m_selected_font_idx);
|
||||||
|
if (ImGui::Selectable(m_available_fonts[i].c_str(), is_selected))
|
||||||
|
{
|
||||||
|
m_selected_font_idx = i;
|
||||||
|
strncpy(m_font, m_available_fonts[i].c_str(), sizeof(m_font) - 1);
|
||||||
|
m_font[sizeof(m_font) - 1] = '\0';
|
||||||
|
m_settings_changed = true;
|
||||||
|
}
|
||||||
|
if (is_selected)
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::Text("Font Size:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
show_help_marker("Font size for the application interface (8-48)");
|
||||||
|
ImGui::SetNextItemWidth(120.0f);
|
||||||
|
int old_size = m_font_size;
|
||||||
|
if (ImGui::SliderInt("##font_size", &m_font_size, 8, 48, "%d px"))
|
||||||
|
{
|
||||||
|
if (old_size != m_font_size)
|
||||||
|
m_settings_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Reset"))
|
||||||
|
{
|
||||||
|
m_font_size = 14;
|
||||||
|
m_settings_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_window::render_status_messages()
|
||||||
|
{
|
||||||
|
if (!m_error_message.empty())
|
||||||
|
{
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
auto error_bg_color = palette_utils::get_color(m_current_palette, "error");
|
||||||
|
auto error_text_color = palette_utils::get_color(m_current_palette, "on_error");
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, error_bg_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, error_bg_color);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 4.0f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 1.0f);
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("##error_box", ImVec2(0, 0), ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Borders))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, error_text_color);
|
||||||
|
ImGui::TextWrapped("Error: %s", m_error_message.c_str());
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(error_bg_color.x * 0.8f, error_bg_color.y * 0.8f, error_bg_color.z * 0.8f, error_bg_color.w));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(error_bg_color.x * 0.6f, error_bg_color.y * 0.6f, error_bg_color.z * 0.6f, error_bg_color.w));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, error_text_color);
|
||||||
|
|
||||||
|
if (ImGui::Button("Dismiss##error"))
|
||||||
|
m_error_message.clear();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_window::render_action_buttons()
|
||||||
|
{
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
float button_width = 100.0f;
|
||||||
|
float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
float window_width = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
|
float total_buttons_width = 4 * button_width + 3 * spacing;
|
||||||
|
float start_pos = (window_width - total_buttons_width) * 0.5f;
|
||||||
|
|
||||||
|
if (start_pos > 0)
|
||||||
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + start_pos);
|
||||||
|
|
||||||
|
if (ImGui::Button("OK", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
apply_settings();
|
||||||
|
if (m_error_message.empty())
|
||||||
|
{
|
||||||
|
m_visible = false;
|
||||||
|
m_settings_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
bool apply_disabled = !m_settings_changed;
|
||||||
|
if (apply_disabled)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Apply", ImVec2(button_width, 0)) && !apply_disabled)
|
||||||
|
{
|
||||||
|
apply_settings();
|
||||||
|
if (m_error_message.empty())
|
||||||
|
{
|
||||||
|
m_settings_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apply_disabled)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::Button("Reset", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
reset_to_defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::Button("Cancel", ImVec2(button_width, 0)))
|
||||||
|
{
|
||||||
|
load_settings();
|
||||||
|
m_visible = false;
|
||||||
|
m_error_message.clear();
|
||||||
|
m_settings_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_window::show_help_marker(const char* desc)
|
||||||
|
{
|
||||||
|
ImGui::TextDisabled("(?)");
|
||||||
|
if (ImGui::BeginItemTooltip())
|
||||||
|
{
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(desc);
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings_window::reset_to_defaults()
|
||||||
|
{
|
||||||
|
strncpy(m_default_theme, "dark", sizeof(m_default_theme));
|
||||||
|
strncpy(m_palettes_path, "~/.config/clrsync/palettes", sizeof(m_palettes_path));
|
||||||
|
strncpy(m_font, "JetBrains Mono Nerd Font", sizeof(m_font));
|
||||||
|
m_font_size = 14;
|
||||||
|
m_error_message.clear();
|
||||||
|
m_settings_changed = true;
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#ifndef CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
#ifndef CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
||||||
#define CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
#define CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
||||||
|
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class settings_window
|
class settings_window
|
||||||
{
|
{
|
||||||
@@ -16,6 +18,17 @@ private:
|
|||||||
void load_settings();
|
void load_settings();
|
||||||
void save_settings();
|
void save_settings();
|
||||||
void apply_settings();
|
void apply_settings();
|
||||||
|
void render_general_tab();
|
||||||
|
void render_appearance_tab();
|
||||||
|
void render_status_messages();
|
||||||
|
void render_action_buttons();
|
||||||
|
void show_help_marker(const char* desc);
|
||||||
|
void reset_to_defaults();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_palette(const clrsync::core::palette& palette) {
|
||||||
|
m_current_palette = palette;
|
||||||
|
}
|
||||||
|
|
||||||
bool m_visible{false};
|
bool m_visible{false};
|
||||||
|
|
||||||
@@ -24,7 +37,14 @@ private:
|
|||||||
char m_font[128];
|
char m_font[128];
|
||||||
int m_font_size;
|
int m_font_size;
|
||||||
|
|
||||||
|
std::vector<std::string> m_available_fonts;
|
||||||
|
int m_selected_font_idx;
|
||||||
|
|
||||||
std::string m_error_message;
|
std::string m_error_message;
|
||||||
|
bool m_settings_changed;
|
||||||
|
int m_current_tab;
|
||||||
|
|
||||||
|
clrsync::core::palette m_current_palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
#endif // CLRSYNC_GUI_SETTINGS_WINDOW_HPP
|
||||||
@@ -11,7 +11,16 @@ void template_controller::set_template_enabled(const std::string& key, bool enab
|
|||||||
auto it = m_templates.find(key);
|
auto it = m_templates.find(key);
|
||||||
if (it != m_templates.end()) {
|
if (it != m_templates.end()) {
|
||||||
it->second.set_enabled(enabled);
|
it->second.set_enabled(enabled);
|
||||||
clrsync::core::config::instance().update_template(key, it->second);
|
(void)clrsync::core::config::instance().update_template(key, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_controller::set_template_input_path(const std::string& key, const std::string& path)
|
||||||
|
{
|
||||||
|
auto it = m_templates.find(key);
|
||||||
|
if (it != m_templates.end()) {
|
||||||
|
it->second.set_template_path(path);
|
||||||
|
(void)clrsync::core::config::instance().update_template(key, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,7 +29,7 @@ void template_controller::set_template_output_path(const std::string& key, const
|
|||||||
auto it = m_templates.find(key);
|
auto it = m_templates.find(key);
|
||||||
if (it != m_templates.end()) {
|
if (it != m_templates.end()) {
|
||||||
it->second.set_output_path(path);
|
it->second.set_output_path(path);
|
||||||
clrsync::core::config::instance().update_template(key, it->second);
|
(void)clrsync::core::config::instance().update_template(key, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,10 +38,20 @@ void template_controller::set_template_reload_command(const std::string& key, co
|
|||||||
auto it = m_templates.find(key);
|
auto it = m_templates.find(key);
|
||||||
if (it != m_templates.end()) {
|
if (it != m_templates.end()) {
|
||||||
it->second.set_reload_command(cmd);
|
it->second.set_reload_command(cmd);
|
||||||
clrsync::core::config::instance().update_template(key, it->second);
|
(void)clrsync::core::config::instance().update_template(key, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool template_controller::remove_template(const std::string& key)
|
||||||
|
{
|
||||||
|
auto result = clrsync::core::config::instance().remove_template(key);
|
||||||
|
if (result) {
|
||||||
|
m_templates.erase(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void template_controller::refresh()
|
void template_controller::refresh()
|
||||||
{
|
{
|
||||||
m_templates = m_template_manager.templates();
|
m_templates = m_template_manager.templates();
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ public:
|
|||||||
template_controller();
|
template_controller();
|
||||||
[[nodiscard]] const std::unordered_map<std::string, clrsync::core::theme_template>& templates() const { return m_templates; }
|
[[nodiscard]] const std::unordered_map<std::string, clrsync::core::theme_template>& templates() const { return m_templates; }
|
||||||
void set_template_enabled(const std::string& key, bool enabled);
|
void set_template_enabled(const std::string& key, bool enabled);
|
||||||
|
void set_template_input_path(const std::string& key, const std::string& path);
|
||||||
void set_template_output_path(const std::string& key, const std::string& path);
|
void set_template_output_path(const std::string& key, const std::string& path);
|
||||||
void set_template_reload_command(const std::string& key, const std::string& cmd);
|
void set_template_reload_command(const std::string& key, const std::string& cmd);
|
||||||
|
bool remove_template(const std::string& key);
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,14 +1,35 @@
|
|||||||
#include "template_editor.hpp"
|
#include "template_editor.hpp"
|
||||||
#include "core/config/config.hpp"
|
#include "core/config/config.hpp"
|
||||||
#include "core/theme/theme_template.hpp"
|
#include "core/theme/theme_template.hpp"
|
||||||
|
#include "core/palette/color_keys.hpp"
|
||||||
|
#include "core/utils.hpp"
|
||||||
|
#include "imgui_helpers.hpp"
|
||||||
|
#include "file_browser.hpp"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
template_editor::template_editor()
|
namespace {
|
||||||
: m_template_name("new_template")
|
const std::vector<std::string> COLOR_FORMATS = {
|
||||||
|
"hex", "hex_stripped", "hexa", "hexa_stripped",
|
||||||
|
"r", "g", "b", "a",
|
||||||
|
"rgb", "rgba",
|
||||||
|
"h", "s", "l",
|
||||||
|
"hsl", "hsla"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template_editor::template_editor() : m_template_name("new_template")
|
||||||
{
|
{
|
||||||
|
m_autocomplete_bg_color = ImVec4(0.12f, 0.12f, 0.15f, 0.98f);
|
||||||
|
m_autocomplete_border_color = ImVec4(0.4f, 0.4f, 0.45f, 1.0f);
|
||||||
|
m_autocomplete_selected_color = ImVec4(0.25f, 0.45f, 0.75f, 0.9f);
|
||||||
|
m_autocomplete_text_color = ImVec4(0.85f, 0.85f, 0.9f, 1.0f);
|
||||||
|
m_autocomplete_selected_text_color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
m_autocomplete_dim_text_color = ImVec4(0.6f, 0.6f, 0.7f, 1.0f);
|
||||||
|
|
||||||
TextEditor::LanguageDefinition lang;
|
TextEditor::LanguageDefinition lang;
|
||||||
lang.mName = "Template";
|
lang.mName = "Template";
|
||||||
|
|
||||||
@@ -26,59 +47,291 @@ template_editor::template_editor()
|
|||||||
"'([^']*)'", TextEditor::PaletteIndex::String));
|
"'([^']*)'", TextEditor::PaletteIndex::String));
|
||||||
|
|
||||||
m_editor.SetLanguageDefinition(lang);
|
m_editor.SetLanguageDefinition(lang);
|
||||||
m_editor.SetText("# Enter your template here\n# Use {color_key} for color variables\n# Examples: {color.hex}, {color.rgb}, {color.r}\n\n");
|
m_editor.SetText("# Enter your template here\n# Use {color_key} for color variables\n# "
|
||||||
|
"Examples: {color.hex}, {color.rgb}, {color.r}\n\n");
|
||||||
m_editor.SetShowWhitespaces(false);
|
m_editor.SetShowWhitespaces(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::apply_current_palette(const clrsync::core::palette& pal)
|
void template_editor::apply_current_palette(const clrsync::core::palette &pal)
|
||||||
{
|
{
|
||||||
|
m_current_palette = pal;
|
||||||
auto colors = pal.colors();
|
auto colors = pal.colors();
|
||||||
auto get_color_u32 = [&](const std::string &key) -> uint32_t {
|
if (colors.empty())
|
||||||
auto it = colors.find(key);
|
return;
|
||||||
if (it != colors.end())
|
auto get_color_u32 = [&](const std::string &key, const std::string &fallback = "") -> uint32_t {
|
||||||
{
|
return palette_utils::get_color_u32(pal, key, fallback);
|
||||||
const auto &col = it->second;
|
|
||||||
const uint32_t hex = col.hex();
|
|
||||||
// Convert from RRGGBBAA to AABBGGRR (ImGui format)
|
|
||||||
const uint32_t r = (hex >> 24) & 0xFF;
|
|
||||||
const uint32_t g = (hex >> 16) & 0xFF;
|
|
||||||
const uint32_t b = (hex >> 8) & 0xFF;
|
|
||||||
const uint32_t a = hex & 0xFF;
|
|
||||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
|
||||||
}
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto palette = m_editor.GetPalette();
|
auto palette = m_editor.GetPalette();
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("text_main");
|
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("editor_main", "foreground");
|
||||||
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("syntax_keyword");
|
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("editor_command", "accent");
|
||||||
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("text_warning");
|
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("editor_warning", "warning");
|
||||||
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("text_string");
|
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("editor_string", "success");
|
||||||
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("text_string");
|
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("editor_string", "success");
|
||||||
palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32("text_main");
|
palette[int(TextEditor::PaletteIndex::Punctuation)] =
|
||||||
palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32("syntax_special_keyword");
|
get_color_u32("editor_main", "foreground");
|
||||||
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("text_main");
|
palette[int(TextEditor::PaletteIndex::Preprocessor)] =
|
||||||
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("text_link");
|
get_color_u32("editor_emphasis", "accent");
|
||||||
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32("text_link");
|
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("editor_main", "foreground");
|
||||||
|
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("editor_link", "info");
|
||||||
|
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] =
|
||||||
|
get_color_u32("editor_link", "info");
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32("text_comment");
|
palette[int(TextEditor::PaletteIndex::Comment)] =
|
||||||
palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32("text_comment");
|
get_color_u32("editor_comment", "editor_inactive");
|
||||||
|
palette[int(TextEditor::PaletteIndex::MultiLineComment)] =
|
||||||
|
get_color_u32("editor_comment", "editor_inactive");
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32("editor_background");
|
palette[int(TextEditor::PaletteIndex::Background)] =
|
||||||
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor");
|
get_color_u32("editor_background", "background");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor", "accent");
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32("text_selected");
|
palette[int(TextEditor::PaletteIndex::Selection)] =
|
||||||
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("syntax_error");
|
get_color_u32("editor_selected", "surface_variant");
|
||||||
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("syntax_error");
|
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("editor_error", "error");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("editor_error", "error");
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32("text_line_number");
|
palette[int(TextEditor::PaletteIndex::LineNumber)] =
|
||||||
|
get_color_u32("editor_line_number", "editor_inactive");
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
|
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
|
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
|
||||||
|
|
||||||
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32("border_emphasized");
|
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] =
|
||||||
|
get_color_u32("border_focused", "border");
|
||||||
|
|
||||||
m_editor.SetPalette(palette);
|
m_editor.SetPalette(palette);
|
||||||
|
|
||||||
|
m_autocomplete_bg_color = palette_utils::get_color(pal, "surface", "background");
|
||||||
|
m_autocomplete_bg_color.w = 0.98f;
|
||||||
|
m_autocomplete_border_color = palette_utils::get_color(pal, "border", "surface_variant");
|
||||||
|
m_autocomplete_selected_color = palette_utils::get_color(pal, "accent", "surface_variant");
|
||||||
|
m_autocomplete_text_color = palette_utils::get_color(pal, "on_surface", "foreground");
|
||||||
|
m_autocomplete_selected_text_color = palette_utils::get_color(pal, "on_surface", "foreground");
|
||||||
|
m_autocomplete_dim_text_color = palette_utils::get_color(pal, "on_surface_variant", "editor_inactive");
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_editor::update_autocomplete_suggestions()
|
||||||
|
{
|
||||||
|
m_autocomplete_suggestions.clear();
|
||||||
|
|
||||||
|
auto cursor = m_editor.GetCursorPosition();
|
||||||
|
std::string line = m_editor.GetCurrentLineText();
|
||||||
|
int col = cursor.mColumn;
|
||||||
|
|
||||||
|
// Check if inside '{'
|
||||||
|
int brace_pos = -1;
|
||||||
|
for (int i = col - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (i < (int)line.length())
|
||||||
|
{
|
||||||
|
if (line[i] == '{')
|
||||||
|
{
|
||||||
|
brace_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (line[i] == '}' || line[i] == ' ' || line[i] == '\t')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brace_pos < 0)
|
||||||
|
{
|
||||||
|
m_show_autocomplete = false;
|
||||||
|
m_autocomplete_dismissed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_autocomplete_dismissed)
|
||||||
|
{
|
||||||
|
bool should_reset_dismissal = false;
|
||||||
|
|
||||||
|
if (cursor.mLine != m_dismiss_position.mLine ||
|
||||||
|
brace_pos != m_dismiss_brace_pos ||
|
||||||
|
abs(cursor.mColumn - m_dismiss_position.mColumn) > 3)
|
||||||
|
{
|
||||||
|
should_reset_dismissal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_reset_dismissal)
|
||||||
|
{
|
||||||
|
m_autocomplete_dismissed = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_show_autocomplete = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_autocomplete_prefix = line.substr(brace_pos + 1, col - brace_pos - 1);
|
||||||
|
m_autocomplete_start_pos = TextEditor::Coordinates(cursor.mLine, brace_pos + 1);
|
||||||
|
|
||||||
|
size_t dot_pos = m_autocomplete_prefix.find('.');
|
||||||
|
|
||||||
|
if (dot_pos != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string color_key = m_autocomplete_prefix.substr(0, dot_pos);
|
||||||
|
std::string format_prefix = m_autocomplete_prefix.substr(dot_pos + 1);
|
||||||
|
|
||||||
|
bool valid_key = false;
|
||||||
|
for (size_t i = 0; i < clrsync::core::NUM_COLOR_KEYS; ++i)
|
||||||
|
{
|
||||||
|
if (clrsync::core::COLOR_KEYS[i] == color_key)
|
||||||
|
{
|
||||||
|
valid_key = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_key)
|
||||||
|
{
|
||||||
|
for (const auto &fmt : COLOR_FORMATS)
|
||||||
|
{
|
||||||
|
if (format_prefix.empty() ||
|
||||||
|
fmt.find(format_prefix) == 0 ||
|
||||||
|
fmt.find(format_prefix) != std::string::npos)
|
||||||
|
{
|
||||||
|
m_autocomplete_suggestions.push_back(color_key + "." + fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < clrsync::core::NUM_COLOR_KEYS; ++i)
|
||||||
|
{
|
||||||
|
std::string key = clrsync::core::COLOR_KEYS[i];
|
||||||
|
if (m_autocomplete_prefix.empty() ||
|
||||||
|
key.find(m_autocomplete_prefix) == 0 ||
|
||||||
|
key.find(m_autocomplete_prefix) != std::string::npos)
|
||||||
|
{
|
||||||
|
m_autocomplete_suggestions.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(m_autocomplete_suggestions.begin(), m_autocomplete_suggestions.end(),
|
||||||
|
[this](const std::string &a, const std::string &b) {
|
||||||
|
bool a_prefix = a.find(m_autocomplete_prefix) == 0;
|
||||||
|
bool b_prefix = b.find(m_autocomplete_prefix) == 0;
|
||||||
|
if (a_prefix != b_prefix)
|
||||||
|
return a_prefix;
|
||||||
|
return a < b;
|
||||||
|
});
|
||||||
|
|
||||||
|
m_show_autocomplete = !m_autocomplete_suggestions.empty();
|
||||||
|
if (m_show_autocomplete && m_autocomplete_selected >= (int)m_autocomplete_suggestions.size())
|
||||||
|
{
|
||||||
|
m_autocomplete_selected = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_editor::render_autocomplete(const ImVec2& editor_pos)
|
||||||
|
{
|
||||||
|
if (!m_show_autocomplete || m_autocomplete_suggestions.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
float line_height = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
float char_width = ImGui::GetFontSize() * 0.5f;
|
||||||
|
auto cursor = m_editor.GetCursorPosition();
|
||||||
|
|
||||||
|
const float line_number_width = 50.0f;
|
||||||
|
|
||||||
|
ImVec2 popup_pos;
|
||||||
|
popup_pos.x = editor_pos.x + line_number_width + (m_autocomplete_start_pos.mColumn * char_width);
|
||||||
|
popup_pos.y = editor_pos.y + ((cursor.mLine + 1) * line_height);
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(300, 0));
|
||||||
|
|
||||||
|
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize;
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 6));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 2));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, m_autocomplete_bg_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, m_autocomplete_border_color);
|
||||||
|
|
||||||
|
if (ImGui::Begin("##autocomplete", nullptr, flags))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
|
||||||
|
if (m_autocomplete_prefix.find('.') != std::string::npos)
|
||||||
|
ImGui::Text("Formats");
|
||||||
|
else
|
||||||
|
ImGui::Text("Color Keys");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
int max_items = std::min((int)m_autocomplete_suggestions.size(), 8);
|
||||||
|
|
||||||
|
for (int i = 0; i < max_items; ++i)
|
||||||
|
{
|
||||||
|
const auto &suggestion = m_autocomplete_suggestions[i];
|
||||||
|
bool is_selected = (i == m_autocomplete_selected);
|
||||||
|
|
||||||
|
if (is_selected)
|
||||||
|
{
|
||||||
|
ImVec4 selected_hover = m_autocomplete_selected_color;
|
||||||
|
selected_hover.w = std::min(selected_hover.w + 0.1f, 1.0f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Header, m_autocomplete_selected_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, selected_hover);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_selected_text_color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImVec4 normal_bg = m_autocomplete_bg_color;
|
||||||
|
normal_bg.w = 0.5f;
|
||||||
|
ImVec4 hover_bg = m_autocomplete_selected_color;
|
||||||
|
hover_bg.w = 0.3f;
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Header, normal_bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hover_bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_text_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string display_text = " " + suggestion;
|
||||||
|
|
||||||
|
if (ImGui::Selectable(display_text.c_str(), is_selected,
|
||||||
|
ImGuiSelectableFlags_None, ImVec2(0, 0)))
|
||||||
|
{
|
||||||
|
auto start = m_autocomplete_start_pos;
|
||||||
|
auto end = m_editor.GetCursorPosition();
|
||||||
|
m_editor.SetSelection(start, end);
|
||||||
|
m_editor.Delete();
|
||||||
|
m_editor.InsertText(suggestion + "}");
|
||||||
|
m_show_autocomplete = false;
|
||||||
|
m_autocomplete_dismissed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
if (is_selected && ImGui::IsWindowAppearing())
|
||||||
|
{
|
||||||
|
ImGui::SetScrollHereY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_autocomplete_suggestions.size() > 8)
|
||||||
|
{
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
|
||||||
|
ImGui::Text(" +%d more", (int)m_autocomplete_suggestions.size() - 8);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, m_autocomplete_dim_text_color);
|
||||||
|
ImGui::Text(" Tab/Enter: accept | Esc: dismiss");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
|
ImGui::PopStyleVar(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::render()
|
void template_editor::render()
|
||||||
@@ -102,26 +355,118 @@ void template_editor::render()
|
|||||||
render_editor();
|
render_editor();
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (m_show_delete_confirmation)
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Delete Template?");
|
||||||
|
m_show_delete_confirmation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
palette_utils::render_delete_confirmation_popup(
|
||||||
|
"Delete Template?", m_template_name, "template", m_current_palette,
|
||||||
|
[this]() {
|
||||||
|
bool success = m_template_controller.remove_template(m_template_name);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
new_template();
|
||||||
|
refresh_templates();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_validation_error = "Failed to delete template";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::render_controls()
|
void template_editor::render_controls()
|
||||||
{
|
{
|
||||||
if (ImGui::Button("New Template"))
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 8));
|
||||||
|
|
||||||
|
if (ImGui::Button(" + New "))
|
||||||
{
|
{
|
||||||
new_template();
|
new_template();
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Create a new template");
|
||||||
|
|
||||||
ImGui::SameLine();
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||||
if (ImGui::Button("Save"))
|
ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyPressed(ImGuiKey_S))
|
||||||
{
|
{
|
||||||
save_template();
|
save_template();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Template Name:");
|
if (ImGui::Button(" Save "))
|
||||||
|
{
|
||||||
|
save_template();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Save template (Ctrl+S)");
|
||||||
|
|
||||||
|
if (m_is_editing_existing)
|
||||||
|
{
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(150.0f);
|
auto error = palette_utils::get_color(m_current_palette, "error");
|
||||||
|
auto error_hover = ImVec4(error.x * 1.1f, error.y * 1.1f, error.z * 1.1f,
|
||||||
|
error.w);
|
||||||
|
auto error_active = ImVec4(error.x * 0.8f, error.y * 0.8f, error.z * 0.8f,
|
||||||
|
error.w);
|
||||||
|
auto on_error = palette_utils::get_color(m_current_palette, "on_error");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, error);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, error_hover);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, error_active);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, on_error);
|
||||||
|
if (ImGui::Button(" Delete "))
|
||||||
|
{
|
||||||
|
delete_template();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Delete this template");
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
|
||||||
|
|
||||||
|
bool enabled_changed = false;
|
||||||
|
if (m_enabled)
|
||||||
|
{
|
||||||
|
ImVec4 success_color = palette_utils::get_color(m_current_palette, "success", "accent");
|
||||||
|
ImVec4 success_on_color = palette_utils::get_color(m_current_palette, "on_success", "on_surface");
|
||||||
|
ImVec4 success_hover = ImVec4(success_color.x * 1.2f, success_color.y * 1.2f, success_color.z * 1.2f, 0.6f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(success_color.x, success_color.y, success_color.z, 0.5f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, success_hover);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_CheckMark, success_on_color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImVec4 error_color = palette_utils::get_color(m_current_palette, "error", "accent");
|
||||||
|
ImVec4 error_on_color = palette_utils::get_color(m_current_palette, "on_error", "on_surface");
|
||||||
|
ImVec4 error_hover = ImVec4(error_color.x * 1.2f, error_color.y * 1.2f, error_color.z * 1.2f, 0.6f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(error_color.x, error_color.y, error_color.z, 0.5f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, error_hover);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_CheckMark, error_on_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled_changed = ImGui::Checkbox("Enabled", &m_enabled);
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
if (enabled_changed && m_is_editing_existing)
|
||||||
|
{
|
||||||
|
m_template_controller.set_template_enabled(m_template_name, m_enabled);
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Enable/disable this template for theme application");
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Name:");
|
||||||
|
ImGui::SameLine(80);
|
||||||
|
ImGui::SetNextItemWidth(180.0f);
|
||||||
char name_buf[256] = {0};
|
char name_buf[256] = {0};
|
||||||
snprintf(name_buf, sizeof(name_buf), "%s", m_template_name.c_str());
|
snprintf(name_buf, sizeof(name_buf), "%s", m_template_name.c_str());
|
||||||
if (ImGui::InputText("##template_name", name_buf, sizeof(name_buf)))
|
if (ImGui::InputText("##template_name", name_buf, sizeof(name_buf)))
|
||||||
@@ -132,22 +477,51 @@ void template_editor::render_controls()
|
|||||||
m_validation_error = "";
|
m_validation_error = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Unique name for this template");
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::AlignTextToFramePadding();
|
||||||
if (ImGui::Checkbox("Enabled", &m_enabled))
|
ImGui::Text("Input:");
|
||||||
|
ImGui::SameLine(80);
|
||||||
|
ImGui::SetNextItemWidth(-120.0f);
|
||||||
|
char input_path_buf[512] = {0};
|
||||||
|
snprintf(input_path_buf, sizeof(input_path_buf), "%s", m_input_path.c_str());
|
||||||
|
if (ImGui::InputTextWithHint("##input_path", "Path to template file...",
|
||||||
|
input_path_buf, sizeof(input_path_buf)))
|
||||||
{
|
{
|
||||||
|
m_input_path = input_path_buf;
|
||||||
|
if (!m_input_path.empty())
|
||||||
|
{
|
||||||
|
m_validation_error = "";
|
||||||
|
}
|
||||||
if (m_is_editing_existing)
|
if (m_is_editing_existing)
|
||||||
{
|
{
|
||||||
m_template_controller.set_template_enabled(m_template_name, m_enabled);
|
m_template_controller.set_template_input_path(m_template_name, m_input_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Output Path:");
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
if (ImGui::Button("Browse##input"))
|
||||||
|
{
|
||||||
|
std::string selected_path = file_dialogs::open_file_dialog("Select Template File", m_input_path);
|
||||||
|
if (!selected_path.empty()) {
|
||||||
|
m_input_path = selected_path;
|
||||||
|
if (m_is_editing_existing) {
|
||||||
|
m_template_controller.set_template_input_path(m_template_name, m_input_path);
|
||||||
|
}
|
||||||
|
m_validation_error = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Path where the template source file is stored");
|
||||||
|
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Output:");
|
||||||
|
ImGui::SameLine(80);
|
||||||
|
ImGui::SetNextItemWidth(-120.0f);
|
||||||
char path_buf[512] = {0};
|
char path_buf[512] = {0};
|
||||||
snprintf(path_buf, sizeof(path_buf), "%s", m_output_path.c_str());
|
snprintf(path_buf, sizeof(path_buf), "%s", m_output_path.c_str());
|
||||||
if (ImGui::InputText("##output_path", path_buf, sizeof(path_buf)))
|
if (ImGui::InputTextWithHint("##output_path", "Path for generated config...",
|
||||||
|
path_buf, sizeof(path_buf)))
|
||||||
{
|
{
|
||||||
m_output_path = path_buf;
|
m_output_path = path_buf;
|
||||||
if (!m_output_path.empty())
|
if (!m_output_path.empty())
|
||||||
@@ -159,13 +533,29 @@ void template_editor::render_controls()
|
|||||||
m_template_controller.set_template_output_path(m_template_name, m_output_path);
|
m_template_controller.set_template_output_path(m_template_name, m_output_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Reload Command:");
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Browse##output"))
|
||||||
|
{
|
||||||
|
std::string selected_path = file_dialogs::save_file_dialog("Select Output File", m_output_path);
|
||||||
|
if (!selected_path.empty()) {
|
||||||
|
m_output_path = selected_path;
|
||||||
|
if (m_is_editing_existing) {
|
||||||
|
m_template_controller.set_template_output_path(m_template_name, m_output_path);
|
||||||
|
}
|
||||||
|
m_validation_error = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Path where the processed config will be written");
|
||||||
|
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Reload:");
|
||||||
|
ImGui::SameLine(80);
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
char reload_buf[512] = {0};
|
char reload_buf[512] = {0};
|
||||||
snprintf(reload_buf, sizeof(reload_buf), "%s", m_reload_command.c_str());
|
snprintf(reload_buf, sizeof(reload_buf), "%s", m_reload_command.c_str());
|
||||||
if (ImGui::InputText("##reload_cmd", reload_buf, sizeof(reload_buf)))
|
if (ImGui::InputTextWithHint("##reload_cmd", "Command to reload app (optional)...",
|
||||||
|
reload_buf, sizeof(reload_buf)))
|
||||||
{
|
{
|
||||||
m_reload_command = reload_buf;
|
m_reload_command = reload_buf;
|
||||||
if (m_is_editing_existing)
|
if (m_is_editing_existing)
|
||||||
@@ -173,10 +563,14 @@ void template_editor::render_controls()
|
|||||||
m_template_controller.set_template_reload_command(m_template_name, m_reload_command);
|
m_template_controller.set_template_reload_command(m_template_name, m_reload_command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("Shell command to run after applying theme (e.g., 'pkill -USR1 kitty')");
|
||||||
|
|
||||||
if (!m_validation_error.empty())
|
if (!m_validation_error.empty())
|
||||||
{
|
{
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
|
ImGui::Spacing();
|
||||||
|
ImVec4 error_color = palette_utils::get_color(m_current_palette, "error", "accent");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, error_color);
|
||||||
ImGui::TextWrapped("%s", m_validation_error.c_str());
|
ImGui::TextWrapped("%s", m_validation_error.c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
@@ -184,45 +578,163 @@ void template_editor::render_controls()
|
|||||||
|
|
||||||
void template_editor::render_editor()
|
void template_editor::render_editor()
|
||||||
{
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4));
|
||||||
|
|
||||||
if (!m_is_editing_existing)
|
if (!m_is_editing_existing)
|
||||||
{
|
{
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 0.8f, 0.4f, 1.0f));
|
ImVec4 success_color = palette_utils::get_color(m_current_palette, "success", "accent");
|
||||||
ImGui::Text("New Template");
|
ImGui::PushStyleColor(ImGuiCol_Text, success_color);
|
||||||
|
ImGui::Text(" New Template");
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui::Text("Editing: %s", m_template_name.c_str());
|
ImGui::Text(" %s", m_template_name.c_str());
|
||||||
|
auto trim_right = [](const std::string &s) -> std::string {
|
||||||
|
size_t end = s.find_last_not_of("\r\n");
|
||||||
|
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string current_content = trim_right(m_editor.GetText());
|
||||||
|
std::string saved_content = trim_right(m_saved_content);
|
||||||
|
|
||||||
|
m_has_unsaved_changes = (current_content != saved_content);
|
||||||
|
if (m_has_unsaved_changes)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImVec4 warning_color = palette_utils::get_color(m_current_palette, "warning", "accent");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, warning_color);
|
||||||
|
ImGui::Text("(unsaved)");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
bool consume_keys = false;
|
||||||
|
|
||||||
|
if (m_show_autocomplete && ImGui::IsKeyPressed(ImGuiKey_Escape, false))
|
||||||
|
{
|
||||||
|
m_show_autocomplete = false;
|
||||||
|
m_autocomplete_dismissed = true;
|
||||||
|
|
||||||
|
m_dismiss_position = m_editor.GetCursorPosition();
|
||||||
|
|
||||||
|
std::string line = m_editor.GetCurrentLineText();
|
||||||
|
m_dismiss_brace_pos = -1;
|
||||||
|
for (int i = m_dismiss_position.mColumn - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (i < (int)line.length() && line[i] == '{')
|
||||||
|
{
|
||||||
|
m_dismiss_brace_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
consume_keys = true;
|
||||||
|
}
|
||||||
|
else if (m_show_autocomplete && !m_autocomplete_suggestions.empty())
|
||||||
|
{
|
||||||
|
int max_visible = std::min((int)m_autocomplete_suggestions.size(), 8);
|
||||||
|
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow, false))
|
||||||
|
{
|
||||||
|
m_autocomplete_selected = (m_autocomplete_selected + 1) % max_visible;
|
||||||
|
consume_keys = true;
|
||||||
|
}
|
||||||
|
else if (ImGui::IsKeyPressed(ImGuiKey_UpArrow, false))
|
||||||
|
{
|
||||||
|
m_autocomplete_selected = (m_autocomplete_selected - 1 + max_visible) % max_visible;
|
||||||
|
consume_keys = true;
|
||||||
|
}
|
||||||
|
else if (ImGui::IsKeyPressed(ImGuiKey_Tab, false) ||
|
||||||
|
ImGui::IsKeyPressed(ImGuiKey_Enter, false))
|
||||||
|
{
|
||||||
|
auto start = m_autocomplete_start_pos;
|
||||||
|
auto end = m_editor.GetCursorPosition();
|
||||||
|
m_editor.SetSelection(start, end);
|
||||||
|
m_editor.Delete();
|
||||||
|
m_editor.InsertText(m_autocomplete_suggestions[m_autocomplete_selected] + "}");
|
||||||
|
m_show_autocomplete = false;
|
||||||
|
m_autocomplete_dismissed = false;
|
||||||
|
consume_keys = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consume_keys)
|
||||||
|
{
|
||||||
|
m_editor.SetHandleKeyboardInputs(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 editor_pos = ImGui::GetCursorScreenPos();
|
||||||
|
|
||||||
m_editor.Render("##TemplateEditor", ImVec2(0, 0), true);
|
m_editor.Render("##TemplateEditor", ImVec2(0, 0), true);
|
||||||
|
|
||||||
|
if (consume_keys)
|
||||||
|
{
|
||||||
|
m_editor.SetHandleKeyboardInputs(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_autocomplete_suggestions();
|
||||||
|
render_autocomplete(editor_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::render_template_list()
|
void template_editor::render_template_list()
|
||||||
{
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
|
||||||
|
|
||||||
ImGui::Text("Templates");
|
ImGui::Text("Templates");
|
||||||
|
ImGui::SameLine(ImGui::GetContentRegionAvail().x - 20);
|
||||||
|
ImGui::TextDisabled("(%d)", (int)m_template_controller.templates().size());
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (!m_is_editing_existing)
|
if (!m_is_editing_existing)
|
||||||
{
|
{
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 0.8f, 0.4f, 1.0f));
|
ImVec4 success_color = palette_utils::get_color(m_current_palette, "success", "accent");
|
||||||
ImGui::Selectable("* New Template *", true);
|
ImVec4 success_bg = ImVec4(success_color.x, success_color.y, success_color.z, 0.5f);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PushStyleColor(ImGuiCol_Text, success_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Header, success_bg);
|
||||||
|
ImGui::Selectable("+ New Template", true);
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &templates = m_template_controller.templates();
|
const auto &templates = m_template_controller.templates();
|
||||||
|
|
||||||
for (const auto &key : templates | std::views::keys)
|
for (const auto &[key, tmpl] : templates)
|
||||||
{
|
{
|
||||||
const bool selected = (m_template_name == key && m_is_editing_existing);
|
const bool selected = (m_template_name == key && m_is_editing_existing);
|
||||||
|
|
||||||
|
if (!tmpl.enabled())
|
||||||
|
{
|
||||||
|
ImVec4 disabled_color = palette_utils::get_color(m_current_palette, "on_surface_variant", "editor_inactive");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, disabled_color);
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::Selectable(key.c_str(), selected))
|
if (ImGui::Selectable(key.c_str(), selected))
|
||||||
{
|
{
|
||||||
load_template(key);
|
load_template(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tmpl.enabled())
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Template: %s", key.c_str());
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Status: %s", tmpl.enabled() ? "Enabled" : "Disabled");
|
||||||
|
if (!tmpl.output_path().empty())
|
||||||
|
ImGui::Text("Output: %s", tmpl.output_path().c_str());
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool template_editor::is_valid_path(const std::string &path)
|
bool template_editor::is_valid_path(const std::string &path)
|
||||||
@@ -280,6 +792,10 @@ void template_editor::save_template()
|
|||||||
trimmed_name.erase(0, trimmed_name.find_first_not_of(" \t\n\r"));
|
trimmed_name.erase(0, trimmed_name.find_first_not_of(" \t\n\r"));
|
||||||
trimmed_name.erase(trimmed_name.find_last_not_of(" \t\n\r") + 1);
|
trimmed_name.erase(trimmed_name.find_last_not_of(" \t\n\r") + 1);
|
||||||
|
|
||||||
|
std::string trimmed_input_path = m_input_path;
|
||||||
|
trimmed_input_path.erase(0, trimmed_input_path.find_first_not_of(" \t\n\r"));
|
||||||
|
trimmed_input_path.erase(trimmed_input_path.find_last_not_of(" \t\n\r") + 1);
|
||||||
|
|
||||||
std::string trimmed_path = m_output_path;
|
std::string trimmed_path = m_output_path;
|
||||||
trimmed_path.erase(0, trimmed_path.find_first_not_of(" \t\n\r"));
|
trimmed_path.erase(0, trimmed_path.find_first_not_of(" \t\n\r"));
|
||||||
trimmed_path.erase(trimmed_path.find_last_not_of(" \t\n\r") + 1);
|
trimmed_path.erase(trimmed_path.find_last_not_of(" \t\n\r") + 1);
|
||||||
@@ -290,6 +806,12 @@ void template_editor::save_template()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trimmed_input_path.empty())
|
||||||
|
{
|
||||||
|
m_validation_error = "Error: Input path cannot be empty!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (trimmed_path.empty())
|
if (trimmed_path.empty())
|
||||||
{
|
{
|
||||||
m_validation_error = "Error: Output path cannot be empty!";
|
m_validation_error = "Error: Output path cannot be empty!";
|
||||||
@@ -305,54 +827,55 @@ void template_editor::save_template()
|
|||||||
|
|
||||||
m_validation_error = "";
|
m_validation_error = "";
|
||||||
|
|
||||||
|
auto &cfg = clrsync::core::config::instance();
|
||||||
|
|
||||||
|
std::filesystem::path template_file = clrsync::core::normalize_path(trimmed_input_path);
|
||||||
|
|
||||||
|
auto parent_dir = template_file.parent_path();
|
||||||
|
if (!parent_dir.empty() && !std::filesystem::exists(parent_dir))
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto &cfg = clrsync::core::config::instance();
|
std::filesystem::create_directories(parent_dir);
|
||||||
std::string palettes_path = cfg.palettes_path();
|
|
||||||
std::filesystem::path templates_dir =
|
|
||||||
std::filesystem::path(palettes_path).parent_path() / "templates";
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(templates_dir))
|
|
||||||
{
|
|
||||||
std::filesystem::create_directories(templates_dir);
|
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
std::filesystem::path template_file;
|
|
||||||
if (m_is_editing_existing)
|
|
||||||
{
|
{
|
||||||
const auto &existing_template = cfg.template_by_name(trimmed_name);
|
m_validation_error = "Error: Could not create directory for input path";
|
||||||
template_file = existing_template.template_path();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
template_file = templates_dir / trimmed_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string template_content = m_editor.GetText();
|
std::string template_content = m_editor.GetText();
|
||||||
|
|
||||||
std::ofstream out(template_file);
|
std::ofstream out(template_file);
|
||||||
if (out.is_open())
|
if (!out.is_open())
|
||||||
{
|
{
|
||||||
|
m_validation_error = "Failed to write template file";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
out << template_content;
|
out << template_content;
|
||||||
out.close();
|
out.close();
|
||||||
}
|
|
||||||
|
|
||||||
clrsync::core::theme_template tmpl(trimmed_name, template_file.string(), trimmed_path);
|
clrsync::core::theme_template tmpl(trimmed_name, template_file.string(), trimmed_path);
|
||||||
tmpl.set_reload_command(m_reload_command);
|
tmpl.set_reload_command(m_reload_command);
|
||||||
tmpl.set_enabled(m_enabled);
|
tmpl.set_enabled(m_enabled);
|
||||||
|
|
||||||
cfg.update_template(trimmed_name, tmpl);
|
auto result = cfg.update_template(trimmed_name, tmpl);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
m_validation_error = "Error saving template: " + result.error().description();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_template_name = trimmed_name;
|
m_template_name = trimmed_name;
|
||||||
|
m_input_path = trimmed_input_path;
|
||||||
m_output_path = trimmed_path;
|
m_output_path = trimmed_path;
|
||||||
m_is_editing_existing = true;
|
m_is_editing_existing = true;
|
||||||
|
m_saved_content = m_editor.GetText();
|
||||||
|
m_has_unsaved_changes = false;
|
||||||
|
|
||||||
refresh_templates();
|
refresh_templates();
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
m_validation_error = std::string("Error saving template: ") + e.what();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::load_template(const std::string &name)
|
void template_editor::load_template(const std::string &name)
|
||||||
@@ -364,14 +887,13 @@ void template_editor::load_template(const std::string &name)
|
|||||||
{
|
{
|
||||||
const auto &tmpl = it->second;
|
const auto &tmpl = it->second;
|
||||||
m_template_name = name;
|
m_template_name = name;
|
||||||
|
m_input_path = tmpl.template_path();
|
||||||
m_output_path = tmpl.output_path();
|
m_output_path = tmpl.output_path();
|
||||||
m_reload_command = tmpl.reload_command();
|
m_reload_command = tmpl.reload_command();
|
||||||
m_enabled = tmpl.enabled();
|
m_enabled = tmpl.enabled();
|
||||||
m_is_editing_existing = true;
|
m_is_editing_existing = true;
|
||||||
m_validation_error = "";
|
m_validation_error = "";
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::ifstream in(tmpl.template_path());
|
std::ifstream in(tmpl.template_path());
|
||||||
if (in.is_open())
|
if (in.is_open())
|
||||||
{
|
{
|
||||||
@@ -384,11 +906,12 @@ void template_editor::load_template(const std::string &name)
|
|||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
m_editor.SetText(content);
|
m_editor.SetText(content);
|
||||||
|
m_saved_content = content;
|
||||||
|
m_has_unsaved_changes = false;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
{
|
||||||
m_validation_error = std::string("Error loading template: ") + e.what();
|
m_validation_error = "Error loading template: Failed to open file";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,12 +919,26 @@ void template_editor::load_template(const std::string &name)
|
|||||||
void template_editor::new_template()
|
void template_editor::new_template()
|
||||||
{
|
{
|
||||||
m_template_name = "new_template";
|
m_template_name = "new_template";
|
||||||
m_editor.SetText("# Enter your template here\n# Use {color_key} for color variables\n# Examples: {color.hex}, {color.rgb}, {color.r}\n\n");
|
std::string default_content =
|
||||||
|
"# Enter your template here\n# Use {color_key} for color variables\n# "
|
||||||
|
"Examples: {color.hex}, {color.rgb}, {color.r}\n\n";
|
||||||
|
m_editor.SetText(default_content);
|
||||||
|
m_saved_content = default_content;
|
||||||
|
m_input_path = "";
|
||||||
m_output_path = "";
|
m_output_path = "";
|
||||||
m_reload_command = "";
|
m_reload_command = "";
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
m_is_editing_existing = false;
|
m_is_editing_existing = false;
|
||||||
m_validation_error = "";
|
m_validation_error = "";
|
||||||
|
m_has_unsaved_changes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_editor::delete_template()
|
||||||
|
{
|
||||||
|
if (!m_is_editing_existing || m_template_name.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_show_delete_confirmation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_editor::refresh_templates()
|
void template_editor::refresh_templates()
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#include "template_controller.hpp"
|
#include "template_controller.hpp"
|
||||||
#include <core/palette/palette.hpp>
|
#include <core/palette/palette.hpp>
|
||||||
#include "color_text_edit/TextEditor.h"
|
#include "color_text_edit/TextEditor.h"
|
||||||
|
#include "imgui.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class template_editor
|
class template_editor
|
||||||
{
|
{
|
||||||
@@ -17,10 +19,13 @@ private:
|
|||||||
void render_controls();
|
void render_controls();
|
||||||
void render_editor();
|
void render_editor();
|
||||||
void render_template_list();
|
void render_template_list();
|
||||||
|
void render_autocomplete(const ImVec2& editor_pos);
|
||||||
|
void update_autocomplete_suggestions();
|
||||||
|
|
||||||
void save_template();
|
void save_template();
|
||||||
void load_template(const std::string &name);
|
void load_template(const std::string &name);
|
||||||
void new_template();
|
void new_template();
|
||||||
|
void delete_template();
|
||||||
void refresh_templates();
|
void refresh_templates();
|
||||||
|
|
||||||
bool is_valid_path(const std::string &path);
|
bool is_valid_path(const std::string &path);
|
||||||
@@ -29,12 +34,34 @@ private:
|
|||||||
TextEditor m_editor;
|
TextEditor m_editor;
|
||||||
|
|
||||||
std::string m_template_name;
|
std::string m_template_name;
|
||||||
|
std::string m_input_path;
|
||||||
std::string m_output_path;
|
std::string m_output_path;
|
||||||
std::string m_reload_command;
|
std::string m_reload_command;
|
||||||
std::string m_validation_error;
|
std::string m_validation_error;
|
||||||
|
std::string m_saved_content;
|
||||||
|
bool m_has_unsaved_changes = false;
|
||||||
|
|
||||||
bool m_enabled{true};
|
bool m_enabled{true};
|
||||||
bool m_is_editing_existing{false};
|
bool m_is_editing_existing{false};
|
||||||
|
bool m_show_delete_confirmation{false};
|
||||||
|
|
||||||
|
bool m_show_autocomplete{false};
|
||||||
|
bool m_autocomplete_dismissed{false};
|
||||||
|
TextEditor::Coordinates m_dismiss_position;
|
||||||
|
int m_dismiss_brace_pos{-1};
|
||||||
|
std::vector<std::string> m_autocomplete_suggestions;
|
||||||
|
int m_autocomplete_selected{0};
|
||||||
|
std::string m_autocomplete_prefix;
|
||||||
|
TextEditor::Coordinates m_autocomplete_start_pos;
|
||||||
|
|
||||||
|
ImVec4 m_autocomplete_bg_color;
|
||||||
|
ImVec4 m_autocomplete_border_color;
|
||||||
|
ImVec4 m_autocomplete_selected_color;
|
||||||
|
ImVec4 m_autocomplete_text_color;
|
||||||
|
ImVec4 m_autocomplete_selected_text_color;
|
||||||
|
ImVec4 m_autocomplete_dim_text_color;
|
||||||
|
|
||||||
|
clrsync::core::palette m_current_palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLRSYNC_GUI_TEMPLATE_EDITOR_HPP
|
#endif // CLRSYNC_GUI_TEMPLATE_EDITOR_HPP
|
||||||
153
src/gui/theme_applier.cpp
Normal file
153
src/gui/theme_applier.cpp
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#include "theme_applier.hpp"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
namespace theme_applier
|
||||||
|
{
|
||||||
|
|
||||||
|
static uint32_t get_color_u32(const clrsync::core::palette& current, const std::string &key)
|
||||||
|
{
|
||||||
|
const auto &col = current.get_color(key);
|
||||||
|
const uint32_t hex = col.hex();
|
||||||
|
// Convert from RRGGBBAA to AABBGGRR (ImGui format)
|
||||||
|
const uint32_t r = (hex >> 24) & 0xFF;
|
||||||
|
const uint32_t g = (hex >> 16) & 0xFF;
|
||||||
|
const uint32_t b = (hex >> 8) & 0xFF;
|
||||||
|
const uint32_t a = hex & 0xFF;
|
||||||
|
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_to_editor(TextEditor& editor, const clrsync::core::palette& current)
|
||||||
|
{
|
||||||
|
auto palette = editor.GetPalette();
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32(current, "editor_main");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32(current, "editor_command");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32(current, "editor_warning");
|
||||||
|
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32(current, "editor_string");
|
||||||
|
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32(current, "editor_string");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32(current, "editor_main");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32(current, "editor_emphasis");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32(current, "editor_main");
|
||||||
|
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32(current, "editor_link");
|
||||||
|
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32(current, "editor_link");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32(current, "editor_comment");
|
||||||
|
palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32(current, "editor_comment");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32(current, "editor_background");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32(current, "cursor");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32(current, "editor_selected");
|
||||||
|
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32(current, "editor_error");
|
||||||
|
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32(current, "editor_error");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32(current, "editor_line_number");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32(current, "surface_variant");
|
||||||
|
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32(current, "surface");
|
||||||
|
|
||||||
|
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32(current, "border_focused");
|
||||||
|
|
||||||
|
editor.SetPalette(palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_to_imgui(const clrsync::core::palette& current)
|
||||||
|
{
|
||||||
|
auto getColor = [&](const std::string &key) -> ImVec4 {
|
||||||
|
const auto &col = current.get_color(key);
|
||||||
|
const uint32_t hex = col.hex();
|
||||||
|
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
||||||
|
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
|
||||||
|
const ImVec4 bg = getColor("background");
|
||||||
|
const ImVec4 onBg = getColor("on_background");
|
||||||
|
const ImVec4 surface = getColor("surface");
|
||||||
|
const ImVec4 onSurface = getColor("on_surface");
|
||||||
|
const ImVec4 surfaceVariant = getColor("surface_variant");
|
||||||
|
const ImVec4 onSurfaceVariant = getColor("on_surface_variant");
|
||||||
|
const ImVec4 fg = getColor("foreground");
|
||||||
|
const ImVec4 fgInactive = getColor("editor_inactive");
|
||||||
|
const ImVec4 accent = getColor("accent");
|
||||||
|
const ImVec4 border = getColor("border");
|
||||||
|
|
||||||
|
const ImVec4 error = getColor("error");
|
||||||
|
const ImVec4 onError = getColor("on_error");
|
||||||
|
const ImVec4 success = getColor("success");
|
||||||
|
const ImVec4 onSuccess = getColor("on_success");
|
||||||
|
const ImVec4 warning = getColor("warning");
|
||||||
|
const ImVec4 onWarning = getColor("on_warning");
|
||||||
|
const ImVec4 info = getColor("info");
|
||||||
|
const ImVec4 onInfo = getColor("on_info");
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_WindowBg] = bg;
|
||||||
|
style.Colors[ImGuiCol_ChildBg] = surface;
|
||||||
|
style.Colors[ImGuiCol_PopupBg] = surface;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Border] = border;
|
||||||
|
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0);
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Text] = onSurface;
|
||||||
|
style.Colors[ImGuiCol_TextDisabled] = onSurfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_TextSelectedBg] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Header] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||||
|
style.Colors[ImGuiCol_HeaderActive] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Button] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||||
|
style.Colors[ImGuiCol_ButtonActive] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_FrameBg] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_FrameBgHovered] =
|
||||||
|
ImVec4(surfaceVariant.x * 1.1f, surfaceVariant.y * 1.1f, surfaceVariant.z * 1.1f, 1.0f);
|
||||||
|
style.Colors[ImGuiCol_FrameBgActive] =
|
||||||
|
ImVec4(surfaceVariant.x * 1.2f, surfaceVariant.y * 1.2f, surfaceVariant.z * 1.2f, 1.0f);
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_TitleBg] = surface;
|
||||||
|
style.Colors[ImGuiCol_TitleBgActive] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_TitleBgCollapsed] = surface;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_ScrollbarBg] = surface;
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrab] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrabActive] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_SliderGrab] = accent;
|
||||||
|
style.Colors[ImGuiCol_SliderGrabActive] =
|
||||||
|
ImVec4(accent.x * 1.2f, accent.y * 1.2f, accent.z * 1.2f, 1.0f);
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_CheckMark] = accent;
|
||||||
|
style.Colors[ImGuiCol_ResizeGrip] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||||
|
style.Colors[ImGuiCol_ResizeGripActive] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Tab] = surface;
|
||||||
|
style.Colors[ImGuiCol_TabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||||
|
style.Colors[ImGuiCol_TabActive] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_TabUnfocused] = surface;
|
||||||
|
style.Colors[ImGuiCol_TabUnfocusedActive] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_TabSelectedOverline] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_TableHeaderBg] = surfaceVariant;
|
||||||
|
style.Colors[ImGuiCol_TableBorderStrong] = border;
|
||||||
|
style.Colors[ImGuiCol_TableBorderLight] =
|
||||||
|
ImVec4(border.x * 0.7f, border.y * 0.7f, border.z * 0.7f, border.w);
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_TableRowBg] = ImVec4(0, 0, 0, 0);
|
||||||
|
style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(onSurfaceVariant.x, onSurfaceVariant.y, onSurfaceVariant.z, 0.06f);
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_Separator] = border;
|
||||||
|
style.Colors[ImGuiCol_SeparatorHovered] = accent;
|
||||||
|
style.Colors[ImGuiCol_SeparatorActive] = accent;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_MenuBarBg] = surface;
|
||||||
|
|
||||||
|
style.Colors[ImGuiCol_DockingPreview] = ImVec4(accent.x, accent.y, accent.z, 0.7f);
|
||||||
|
style.Colors[ImGuiCol_DockingEmptyBg] = bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace theme_applier
|
||||||
13
src/gui/theme_applier.hpp
Normal file
13
src/gui/theme_applier.hpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||||
|
#define CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||||
|
|
||||||
|
#include "core/palette/palette.hpp"
|
||||||
|
#include "color_text_edit/TextEditor.h"
|
||||||
|
|
||||||
|
namespace theme_applier
|
||||||
|
{
|
||||||
|
void apply_to_imgui(const clrsync::core::palette& pal);
|
||||||
|
void apply_to_editor(TextEditor& editor, const clrsync::core::palette& pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[wrap-file]
|
|
||||||
directory = freetype-2.14.1
|
|
||||||
source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.14.1.tar.xz
|
|
||||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/freetype2_2.14.1-1/freetype-2.14.1.tar.xz
|
|
||||||
source_filename = freetype-2.14.1.tar.xz
|
|
||||||
source_hash = 32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc
|
|
||||||
wrapdb_version = 2.14.1-1
|
|
||||||
|
|
||||||
[provide]
|
|
||||||
dependency_names = freetype2
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[wrap-file]
|
|
||||||
directory = glfw-3.4
|
|
||||||
source_url = https://github.com/glfw/glfw/archive/refs/tags/3.4.tar.gz
|
|
||||||
source_filename = glfw-3.4.tar.gz
|
|
||||||
source_hash = c038d34200234d071fae9345bc455e4a8f2f544ab60150765d7704e08f3dac01
|
|
||||||
patch_filename = glfw_3.4-1_patch.zip
|
|
||||||
patch_url = https://wrapdb.mesonbuild.com/v2/glfw_3.4-1/get_patch
|
|
||||||
patch_hash = 58a6a6cdb28195d7f7e6f5de85dff7044d378e49b46bf1d4a9b04c97ed93e6b0
|
|
||||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/glfw_3.4-1/glfw-3.4.tar.gz
|
|
||||||
wrapdb_version = 3.4-1
|
|
||||||
|
|
||||||
[provide]
|
|
||||||
glfw3 = glfw_dep
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user