Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,50 @@ jobs:
rpm -qip /root/rpmbuild/RPMS/*/*.rpm
'

build-themeeditor:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
rid: win-x64
- os: ubuntu-latest
rid: linux-x64
- os: ubuntu-latest
rid: linux-arm64
- os: macos-14
rid: osx-x64
- os: macos-latest
rid: osx-arm64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Restore
run: dotnet restore ThemeEditor/ThemeEditor.csproj -r ${{ matrix.rid }}

- name: Publish self-contained single-file
shell: bash
run: |
dotnet publish ThemeEditor/ThemeEditor.csproj \
-c Release \
-r ${{ matrix.rid }} \
--self-contained true \
--no-restore \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:DebugType=None \
-p:DebugSymbols=false \
-o publish
echo "=== ThemeEditor ${{ matrix.rid }} publish successful ==="
ls -la publish

build-freebsd:
runs-on: [self-hosted, freebsd]
timeout-minutes: 30
Expand Down
81 changes: 80 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,83 @@ jobs:
name: rpm-${{ matrix.arch }}
path: output/*.rpm

build-themeeditor:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
rid: win-x64
archive_ext: zip
- os: ubuntu-latest
rid: linux-x64
archive_ext: tar.gz
- os: ubuntu-latest
rid: linux-arm64
archive_ext: tar.gz
- os: macos-14
rid: osx-x64
archive_ext: tar.gz
- os: macos-latest
rid: osx-arm64
archive_ext: tar.gz
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Extract version from tag
id: version
shell: bash
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Restore
run: dotnet restore ThemeEditor/ThemeEditor.csproj -r ${{ matrix.rid }}

- name: Publish self-contained single-file
shell: bash
run: |
dotnet publish ThemeEditor/ThemeEditor.csproj \
-c Release \
-r ${{ matrix.rid }} \
--self-contained true \
--no-restore \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:DebugType=None \
-p:DebugSymbols=false \
-p:Version=${{ steps.version.outputs.version }} \
-o publish

- name: Package (zip)
if: matrix.archive_ext == 'zip'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path output | Out-Null
$name = "ThemeEditor-${{ steps.version.outputs.version }}-${{ matrix.rid }}.zip"
Compress-Archive -Path publish/* -DestinationPath "output/$name"

- name: Package (tar.gz)
if: matrix.archive_ext == 'tar.gz'
shell: bash
run: |
mkdir -p output
name="ThemeEditor-${{ steps.version.outputs.version }}-${{ matrix.rid }}.tar.gz"
tar -czf "output/$name" -C publish .

- name: Upload ThemeEditor artifact
uses: actions/upload-artifact@v4
with:
name: themeeditor-${{ matrix.rid }}
path: output/*

build-freebsd:
runs-on: [self-hosted, freebsd]
timeout-minutes: 30
Expand Down Expand Up @@ -166,7 +243,7 @@ jobs:
rm -rf dist repo

release:
needs: [build, build-rpm, build-freebsd]
needs: [build, build-rpm, build-freebsd, build-themeeditor]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
Expand All @@ -182,6 +259,8 @@ jobs:
packages/*.deb
packages/*.rpm
packages/*.pkg
packages/ThemeEditor-*.zip
packages/ThemeEditor-*.tar.gz
generate_release_notes: true
prerelease: ${{ contains(github.ref_name, '-') }}

Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,38 @@ Example:
expression precision(file::readline(F_PW, 3), 3) . ' kW '
```

## Theme Editor

A visual theme editor is included in the [`ThemeEditor/`](ThemeEditor/) directory. It is a cross-platform desktop application (Avalonia UI, .NET 10) that lets you open, preview, and edit lcd4linux theme config files without touching the raw text.

Features:
- Opens any lcd4linux `.conf` file and renders its widgets on a scaled canvas
- Drag widgets to reposition them; positions are written back to the `Layout` section on save
- Property panel on the right lets you edit widget fields — text, colors (with a color picker), numbers, dropdowns for `class` and `align` fields
- Image widgets display their actual image file on the canvas
- Zoom slider (50%–300%) for detailed layout work
- Undo/redo support
- Detects display orientation from the config (`Orientation` field) and sizes the canvas accordingly (480×320 landscape, 320×480 portrait)

### Building the Theme Editor

Requires the [.NET 10 SDK](https://dotnet.microsoft.com/download).

```bash
cd ThemeEditor
dotnet build
dotnet run
```

### Usage

1. Launch the editor and click **Load Theme**
2. Browse to a theme `.conf` file (e.g. `themes/SimpleWhite/dpf_simplewhite.conf`)
3. The display canvas shows all widgets at their configured positions
4. Click a widget to select it and edit its properties in the panel on the right
5. Drag widgets to reposition them on the canvas
6. Click **Save Theme** to write changes back to the original `.conf` file

## Themes

35+ pre-built themes are included in the [`themes/`](themes/) directory, covering system monitors, NAS dashboards, landscape layouts, cyberpunk/terminal styles, and more — in portrait and landscape orientations with color variants for each style.
Expand Down
16 changes: 16 additions & 0 deletions ThemeEditor/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ThemeEditor.App"
xmlns:local="using:ThemeEditor"
RequestedThemeVariant="Dark">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>

<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml" />
</Application.Styles>
</Application>
47 changes: 47 additions & 0 deletions ThemeEditor/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using ThemeEditor.ViewModels;
using ThemeEditor.Views;

namespace ThemeEditor;

public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}

base.OnFrameworkInitializationCompleted();
}

private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();

// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}
Binary file added ThemeEditor/Assets/avalonia-logo.ico
Binary file not shown.
Loading
Loading