Broke up UI into seperate file, reorganisation of dirtree, added ViewStack

This commit is contained in:
2025-12-02 23:04:11 +01:00
parent cc1401ff96
commit f8a10249bb
41 changed files with 2742 additions and 3564 deletions

View File

@@ -7,7 +7,7 @@
<key name="window-height" type="i">
<default>600</default>
</key>
<key name="window-maximized" type="i">
<key name="window-maximized" type="b">
<default>false</default>
</key>
</schema>

View File

@@ -5,33 +5,33 @@
<project_license>AGPL-3.0-or-later</project_license>
<name>Gnomeframe</name>
<summary>Keep the summary shorter, between 10 and 35 characters</summary>
<summary>A Warframe Companion</summary>
<description>
<p>No description</p>
<p>This is a companion-app for Warframe players on Linux, written in phython and GTK4/ADW with the help of GNOME Builder and PyGObject.</p>
</description>
<developer id="tld.vendor">
<name>valhrafnaz</name>
<name>gay.valhrafnaz</name>
</developer>
<!-- Required: Should be a link to the upstream homepage for the component -->
<url type="homepage">https://example.org/</url>
<url type="homepage">https://valhrafnaz.gay/gnomeframe</url>
<!-- Recommended: It is highly recommended for open-source projects to display the source code repository -->
<url type="vcs-browser">https://example.org/repository</url>
<url type="vcs-browser">https://git.valhrafnaz.gay/valhrafnaz/Gnomeframe</url>
<!-- Should point to the software's bug tracking system, for users to report new bugs -->
<url type="bugtracker">https://example.org/issues</url>
<url type="bugtracker">https://git.valhrafnaz.gay/valhrafnaz/Gnomeframe/issues</url>
<!-- Should link a FAQ page for this software, to answer some of the most-asked questions in detail -->
<!-- URLs of this type should point to a webpage where users can submit or modify translations of the upstream project -->
<url type="translate">https://example.org/translate</url>
<url type="faq">https://example.org/faq</url>
<url type="translate">https://valhrafnaz.gay/gnomeframe/translate</url>
<url type="faq">https://valhrafnaz.gay/gnomeframe/faq</url>
<!-- Should provide a web link to an online user's reference, a software manual or help page -->
<url type="help">https://example.org/help</url>
<url type="help">https://git.valhrafnaz.gay/valhrafnaz/Gnomeframe/wiki</url>
<!-- URLs of this type should point to a webpage showing information on how to donate to the described software project -->
<url type="donation">https://example.org/donate</url>
<url type="donation">https://valhrafnaz.gay/donate</url>
<!-- This could for example be an HTTPS URL to an online form or a page describing how to contact the developer -->
<url type="contact">https://example.org/contact</url>
<url type="contact">https://valhrafnaz.gay/gnomeframe</url>
<!-- URLs of this type should point to a webpage showing information on how to contribute to the described software project -->
<url type="contribute">https://example.org/contribute</url>
<url type="contribute">https://git.valhrafnaz.gay/valhrafnaz/Gnomeframe</url>
<translation type="gettext">gnomeframe</translation>
<!-- All graphical applications having a desktop file must have this tag in the MetaInfo.

View File

@@ -43,4 +43,4 @@ configure_file(
install_dir: get_option('datadir') / 'dbus-1' / 'services'
)
subdir('icons')
subdir('resources')

Binary file not shown.

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/gay/valhrafnaz/Gnomeframe/">
<file>style.css</file>
<file preprocess="xml-stripblanks">ui/window.ui</file>
<file preprocess="xml-stripblanks">ui/shortcuts-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/checklist.ui</file>
<file preprocess="xml-stripblanks">ui/home.ui</file>
<file preprocess="xml-stripblanks">ui/settings.ui</file>
<file preprocess="xml-stripblanks">ui/welcome.ui</file>
<file preprocess="xml-stripblanks" alias="floppy-symbolic.svg">icons/hicolor/symbolic/floppy-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="check-round-outline2-symbolic.svg">icons/hicolor/symbolic/check-round-outline2-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="compass2-symbolic.svg">icons/hicolor/symbolic/compass2-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="settings-symbolic.svg">icons/hicolor/symbolic/settings-symbolic.svg</file>
</gresource>
</gresources>

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 9.492188 0.140625 c -0.851563 -0.1640625 -1.722657 -0.1835938 -2.574219 -0.0664062 c -1.699219 0.2304692 -3.328125 1.0078122 -4.601563 2.2929692 c -2.546875 2.566406 -3.050781 6.539062 -1.230468 9.664062 c 1.824218 3.121094 5.527343 4.636719 9.019531 3.683594 c 3.488281 -0.949219 5.90625 -4.132813 5.890625 -7.75 c 0 -0.550782 -0.453125 -1 -1.003906 -0.996094 c -0.550782 0.003906 -0.996094 0.453125 -0.996094 1.003906 c 0.015625 2.722656 -1.792969 5.097656 -4.417969 5.816406 c -2.625 0.714844 -5.394531 -0.417968 -6.761719 -2.765624 c -1.371094 -2.351563 -0.996094 -5.316407 0.921875 -7.25 c 1.914063 -1.929688 4.875 -2.335938 7.238281 -0.984376 c 0.476563 0.273438 1.089844 0.109376 1.363282 -0.371093 c 0.273437 -0.480469 0.105468 -1.089844 -0.375 -1.367188 c -0.78125 -0.445312 -1.617188 -0.75 -2.472656 -0.910156 z m 0 0"/><path d="m 15.753906 3.65625 c 0.175782 -0.199219 0.261719 -0.460938 0.246094 -0.722656 c -0.019531 -0.265625 -0.140625 -0.511719 -0.339844 -0.6875 c -0.199218 -0.175782 -0.460937 -0.265625 -0.726562 -0.246094 c -0.265625 0.015625 -0.511719 0.140625 -0.6875 0.339844 l -6.296875 7.195312 l -2.242188 -2.246094 c -0.390625 -0.390624 -1.023437 -0.390624 -1.414062 0 c -0.1875 0.1875 -0.292969 0.445313 -0.292969 0.710938 s 0.105469 0.519531 0.292969 0.707031 l 3 3 c 0.195312 0.195313 0.464843 0.300781 0.742187 0.292969 c 0.277344 -0.011719 0.535156 -0.132812 0.71875 -0.34375 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 8 0 c -4.40625 0 -7.99609375 3.59375 -7.99609375 8 s 3.58984375 8 7.99609375 8 s 7.996094 -3.59375 7.996094 -8 s -3.589844 -8 -7.996094 -8 z m 0 2 c 3.324219 0 5.996094 2.675781 5.996094 6 s -2.671875 6 -5.996094 6 s -5.996094 -2.675781 -5.996094 -6 s 2.671875 -6 5.996094 -6 z m 3.40625 2 c -0.089844 -0.003906 -0.191406 0.015625 -0.289062 0.058594 l -4.507813 2.0625 c -0.21875 0.097656 -0.394531 0.273437 -0.496094 0.492187 l -2.058593 4.511719 c -0.238282 0.519531 0.296874 1.054688 0.816406 0.816406 l 4.511718 -2.058594 c 0.21875 -0.101562 0.394532 -0.277343 0.492188 -0.496093 l 2.0625 -4.507813 c 0.191406 -0.425781 -0.125 -0.859375 -0.53125 -0.878906 z m -3.410156 3 c 0.253906 0 0.511718 0.101562 0.703125 0.292969 c 0.390625 0.390625 0.390625 1.023437 0 1.414062 c -0.386719 0.386719 -1.019531 0.386719 -1.410157 0 c -0.386718 -0.390625 -0.386718 -1.023437 0 -1.414062 c 0.195313 -0.191407 0.453126 -0.292969 0.707032 -0.292969 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 562 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 7.5 1.019531 c -0.550781 0 -0.996094 0.445313 -0.996094 0.996094 v 0.453125 c -0.472656 0.128906 -0.929687 0.320312 -1.355468 0.566406 l -0.324219 -0.324218 c -0.390625 -0.390626 -1.019531 -0.390626 -1.410157 0 l -0.703124 0.707031 c -0.390626 0.390625 -0.390626 1.019531 0 1.410156 l 0.320312 0.320313 c -0.246094 0.425781 -0.433594 0.882812 -0.5625 1.355468 h -0.453125 c -0.550781 0 -0.996094 0.445313 -0.996094 0.996094 v 1 c 0 0.550781 0.445313 0.996094 0.996094 0.996094 h 0.449219 c 0.132812 0.472656 0.320312 0.929687 0.566406 1.355468 l -0.320312 0.320313 c -0.390626 0.390625 -0.390626 1.019531 0 1.410156 l 0.703124 0.707031 c 0.390626 0.390626 1.019532 0.390626 1.410157 0 l 0.320312 -0.320312 c 0.429688 0.242188 0.882813 0.433594 1.359375 0.558594 v 0.457031 c 0 0.550781 0.445313 0.996094 0.996094 0.996094 h 0.996094 c 0.554687 0 1 -0.445313 1 -0.996094 v -0.453125 c 0.472656 -0.128906 0.929687 -0.320312 1.355468 -0.566406 l 0.320313 0.324218 c 0.390625 0.390626 1.019531 0.390626 1.410156 0 l 0.707031 -0.707031 c 0.390626 -0.390625 0.390626 -1.019531 0 -1.410156 l -0.320312 -0.320313 c 0.242188 -0.425781 0.433594 -0.882812 0.558594 -1.355468 h 0.453125 c 0.554687 0 1 -0.445313 1 -0.996094 v -1 c 0 -0.550781 -0.445313 -0.996094 -1 -0.996094 h -0.449219 c -0.128906 -0.472656 -0.320312 -0.929687 -0.566406 -1.355468 l 0.324218 -0.320313 c 0.390626 -0.390625 0.390626 -1.019531 0 -1.410156 l -0.707031 -0.707031 c -0.390625 -0.390626 -1.019531 -0.390626 -1.410156 0 l -0.320313 0.320312 c -0.425781 -0.242188 -0.882812 -0.429688 -1.355468 -0.558594 v -0.457031 c 0 -0.550781 -0.445313 -0.996094 -1 -0.996094 z m 0.515625 3.976563 c 1.660156 0 3 1.34375 3 3 s -1.339844 3 -3 3 c -1.65625 0 -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,27 @@
pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name()
gnome = import('gnome')
blueprints = custom_target('blueprints',
input: files(
'ui/window.blp',
'ui/shortcuts-dialog.blp',
'ui/checklist.blp',
'ui/settings.blp',
'ui/welcome.blp',
'ui/home.blp'
),
output: '.',
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT', '@CURRENT_SOURCE_DIRECTORY@' , '@INPUT@'],
)
gnome.compile_resources('gnomeframe',
'gnomeframe.gresource.xml',
gresource_bundle: true,
install: true,
install_dir: pkgdatadir,
dependencies: blueprints,
)
subdir('icons')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
using Gtk 4.0;
using Adw 1;
template $HomePage: Box {
Adw.StatusPage {
title: _("Home");
Box {
Text {
text: _("This is a placeholder.");
}
}
}
}

25
data/resources/ui/home.ui Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT!
This file was @generated by blueprint-compiler. Instead, edit the
corresponding .blp file and regenerate this file with blueprint-compiler.
-->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="HomePage" parent="GtkBox">
<child>
<object class="AdwStatusPage">
<property name="title" translatable="yes">Home</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkText">
<property name="text" translatable="yes">This is a placeholder.</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,12 @@
using Gtk 4.0;
using Adw 1;
template $SettingsPage: Box {
Adw.Clamp {
Box {
Text {
text: _("This is a placeholder!");
}
}
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT!
This file was @generated by blueprint-compiler. Instead, edit the
corresponding .blp file and regenerate this file with blueprint-compiler.
-->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="SettingsPage" parent="GtkBox">
<child>
<object class="AdwClamp">
<child>
<object class="GtkBox">
<child>
<object class="GtkText">
<property name="text" translatable="yes">This is a placeholder!</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,9 @@
using Gtk 4.0;
using Adw 1;
Adw.Dialog {
title: _("Welcome to Gnomeframe!");
Text {
text: _("Thank you for installing Gnomeframe! Please note that this is a fan project. Digital Extremes Ltd, Warframe and the logo Warframe are registered trademarks. All rights are reserved worldwide. This application has no official link with Digital Extremes Ltd or Warframe. All artwork, screenshots, characters or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of Digital Extremes Ltd.");
}
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT!
This file was @generated by blueprint-compiler. Instead, edit the
corresponding .blp file and regenerate this file with blueprint-compiler.
-->
<interface>
<requires lib="gtk" version="4.0"/>
<object class="AdwDialog">
<property name="title" translatable="yes">Welcome to Gnomeframe!</property>
<child>
<object class="GtkText">
<property name="text" translatable="yes">Thank you for installing Gnomeframe! Please note that this is a fan project. Digital Extremes Ltd, Warframe and the logo Warframe are registered trademarks. All rights are reserved worldwide. This application has no official link with Digital Extremes Ltd or Warframe. All artwork, screenshots, characters or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of Digital Extremes Ltd.</property>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,66 @@
using Gtk 4.0;
using Adw 1;
template $GnomeframeWindow: Adw.ApplicationWindow {
default-width: 800;
default-height: 600;
title: "Gnomeframe";
content:
// Scaffolding
Adw.ToolbarView {
// Header bar
[top]
Adw.HeaderBar {
[start]
Button btn_save_as {
tooltip-text: _("Save as…");
icon-name: "floppy-symbolic";
}
[end]
MenuButton {
icon-name: "open-menu-symbolic";
menu-model: primary_menu;
tooltip-text: _("Main Menu");
primary: true;
}
title-widget:
Adw.ViewSwitcher {
policy: wide;
stack: viewstack;
};
}
// Main View
content:
Adw.ViewStack viewstack {
};
[bottom]
Adw.ViewSwitcherBar switcher_bar {
stack: viewstack;
}
};
}
menu primary_menu {
section {
item {
label: _("_Preferences");
action: "app.preferences";
}
item {
label: _("_Keyboard Shortcuts");
action: "win.show-help-overlay";
}
item {
label: _("_Help");
action: "app.help";
}
item {
label: _("_About Gnomeframe");
action: "app.about";
}
}
}

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT!
This file was @generated by blueprint-compiler. Instead, edit the
corresponding .blp file and regenerate this file with blueprint-compiler.
-->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="GnomeframeWindow" parent="AdwApplicationWindow">
<property name="default-width">800</property>
<property name="default-height">600</property>
<property name="title">Gnomeframe</property>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<child type="start">
<object class="GtkButton" id="btn_save_as">
<property name="tooltip-text" translatable="yes">Save as…</property>
<property name="icon-name">floppy-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkMenuButton">
<property name="icon-name">open-menu-symbolic</property>
<property name="menu-model">primary_menu</property>
<property name="tooltip-text" translatable="yes">Main Menu</property>
<property name="primary">true</property>
</object>
</child>
<property name="title-widget">
<object class="AdwViewSwitcher">
<property name="policy">1</property>
<property name="stack">viewstack</property>
</object>
</property>
</object>
</child>
<property name="content">
<object class="AdwViewStack" id="viewstack"></object>
</property>
<child type="bottom">
<object class="AdwViewSwitcherBar" id="switcher_bar">
<property name="stack">viewstack</property>
</object>
</child>
</object>
</property>
</template>
<menu id="primary_menu">
<section>
<item>
<attribute name="label" translatable="yes">_Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">app.help</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About Gnomeframe</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -24,7 +24,7 @@
],
"modules" : [
{
"name" : "gnomeframe",
"name" : "Gnomeframe",
"builddir" : true,
"buildsystem" : "meson",
"sources" : [

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/gay/valhrafnaz/Gnomeframe/">
<file>style.css</file>
<file preprocess="xml-stripblanks">ui/window.ui</file>
<file preprocess="xml-stripblanks">ui/shortcuts-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/checklist.ui</file>
<file preprocess="xml-stripblanks">icons/bw/scalable/floppy-symbolic.svg</file>
</gresource>
</gresources>

View File

View File

@@ -0,0 +1,46 @@
#!@PYTHON@
# gnomeframe.in
#
# Copyright 2025 nihil
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import os
import sys
import signal
import locale
import gettext
VERSION = '@VERSION@'
pkgdatadir = '@pkgdatadir@'
localedir = '@localedir@'
sys.path.insert(1, pkgdatadir)
signal.signal(signal.SIGINT, signal.SIG_DFL)
locale.bindtextdomain('gnomeframe', localedir)
locale.textdomain('gnomeframe')
gettext.install('gnomeframe', localedir)
if __name__ == '__main__':
import gi
from gi.repository import Gio
resource = Gio.Resource.load(os.path.join(pkgdatadir, 'gnomeframe.gresource'))
resource._register()
from gnomeframe import main
sys.exit(main.main(VERSION))

View File

@@ -0,0 +1,2 @@
# gnomeframe/pages/__init__.py
"""Subpackage that holds the individual ViewStack pages."""

View File

@@ -1,29 +1,13 @@
# window.py
#
# Copyright 2025 nihil
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import json
import os
import math
from pathlib import Path
from gi.repository import Gtk, Adw, GObject, GLib
TOTAL_WARFRAMES=62 # pre uriel, valid until 10-12-2025
TOTAL_PRIMES=49 # post gyre prime, valid until ca. may-2026
from gi.repository import Adw
from gi.repository import Gtk, Gio
from gi.repository import GLib
frame_button_ids = [
"ash",
@@ -151,45 +135,11 @@ frame_button_ids = [
]
def get_config_dir(app_id: str) -> Path:
base = Path(GLib.get_user_config_dir())
cfg_dir = base / app_id
cfg_dir.mkdir(parents=True, exist_ok=True)
print(f"Found config dir at: {cfg_dir}")
return cfg_dir
APP_ID = "gay.valhrafnaz.Gnomeframe"
CONFIG_DIR = get_config_dir(APP_ID)
CONFIG_FILE = CONFIG_DIR / "profile.json"
TOTAL_WARFRAMES=62 # pre uriel, valid until 10-12-2025
TOTAL_PRIMES=49 # post gyre prime, valid until ca. may-2026
def load_profile() -> dict[str, bool]:
try:
with CONFIG_FILE.open("r", encoding="utf-8") as f:
data = json.load(f)
return {k: bool(v) for k, v in data.items()}
except FileNotFoundError:
return {}
except (json.JSONDecodeError, OSError) as exc:
print(f"Could not load profile: {exc}")
return {}
def save_profile(state: dict[str, bool]) -> None:
try:
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
with CONFIG_FILE.open("w", encoding="utf-8") as f:
json.dump(state, f, indent=2, sort_keys=True)
except OSError as exc:
print(f"Failed to write profile: {exc}")
@Gtk.Template(resource_path='/gay/valhrafnaz/Gnomeframe/ui/compiled/window.ui')
class GnomeframeWindow(Adw.ApplicationWindow):
__gtype_name__ = 'GnomeframeWindow'
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/checklist.ui")
class ChecklistPage(Gtk.Box):
__gtype_name__ = "ChecklistPage"
# tooling for checklist
frame_box = Gtk.Template.Child()
btns_basic = Gtk.Template.Child()
btns_prime = Gtk.Template.Child()
@@ -197,41 +147,30 @@ class GnomeframeWindow(Adw.ApplicationWindow):
basic_percent = Gtk.Template.Child()
prime_counter = Gtk.Template.Child()
prime_percent = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._profile: dict[str, bool] = load_profile()
def __init__(self, *, parent: Adw.ViewStack, window):
super().__init__()
self._parent_window = window
parent.add_titled(self, "checklist", "Checklist")
wrapper = parent.get_page(self)
wrapper.set_icon_name("check-round-outline2-symbolic")
self._connect_frame_btns()
reset_action = Gio.SimpleAction.new("reset-selections", None)
reset_action.connect("activate", self._reset_all)
self.get_application().add_action(reset_action)
self.connect("close-request", self._on_close_request)
self._calc_frames()
# self.settings = Gio.Settings(schema_id="gay.valhrafnaz.Gnomeframe")
# self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
# self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
# self.settings.bind("window-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
def _connect_frame_btns(self):
button = self.btns_basic.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
btn_id = button.get_name()
button.set_active(self._profile.get(btn_id, False))
button.set_active(self._parent_window._profile.get(btn_id, False))
button.connect("toggled", self._on_button_toggled)
button = button.get_next_sibling()
button = self.btns_prime.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
btn_id = button.get_name()
button.set_active(self._profile.get(btn_id, False))
button.set_active(self._parent_window._profile.get(btn_id, False))
button.connect("toggled", self._on_button_toggled)
button = button.get_next_sibling()
@@ -271,25 +210,7 @@ class GnomeframeWindow(Adw.ApplicationWindow):
print("what")
return
self._profile[btn_id] = btn.get_active()
save_profile(self._profile)
super.save_profile(self._profile)
self._calc_frames()
def _reset_all(self, action, param):
self._profile.clear()
button = self.btns_basic.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
button.set_active(False)
button = button.get_next_sibling()
button = self.btns_prime.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
button.set_active(False)
button = button.get_next_sibling()
save_profile(self._profile)
def _on_close_request(self, *args):
save_profile(self._profile)
return False

View File

@@ -0,0 +1,16 @@
from gi.repository import Gtk, Adw, GObject, GLib
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/home.ui")
class HomePage(Gtk.Box):
__gtype_name__ = "HomePage"
def __init__(self, *, parent: Adw.ViewStack):
"""
`parent` is the ViewStack that will host this page.
By passing it to the superclass constructor we tell GTK to
insert the newly created page into that stack automatically.
"""
super().__init__()
parent.add_titled(self, "home", "Home")
wrapper = parent.get_page(self)
wrapper.set_icon_name("compass2-symbolic")

View File

@@ -0,0 +1,11 @@
from gi.repository import Gtk, Adw, GObject, GLib
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/settings.ui")
class SettingsPage(Gtk.Box):
__gtype_name__ = "SettingsPage"
def __init__(self, *, parent: Adw.ViewStack):
super().__init__()
parent.add_titled(self, "settings", "Settings")
wrapper = parent.get_page(self)
wrapper.set_icon_name("settings-symbolic")

112
src/gnomeframe/window.py Normal file
View File

@@ -0,0 +1,112 @@
# window.py
#
# Copyright 2025 nihil
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import json
import os
from pathlib import Path
from .pages.home import HomePage
from .pages.settings import SettingsPage
from .pages.checklist import ChecklistPage
from gi.repository import Adw
from gi.repository import Gtk, Gio
from gi.repository import GLib
def get_config_dir(app_id: str) -> Path:
base = Path(GLib.get_user_config_dir())
cfg_dir = base / app_id
cfg_dir.mkdir(parents=True, exist_ok=True)
print(f"Found config dir at: {cfg_dir}")
return cfg_dir
APP_ID = "gay.valhrafnaz.Gnomeframe"
CONFIG_DIR = get_config_dir(APP_ID)
CONFIG_FILE = CONFIG_DIR / "profile.json"
def load_profile() -> dict[str, bool]:
try:
with CONFIG_FILE.open("r", encoding="utf-8") as f:
data = json.load(f)
return {k: bool(v) for k, v in data.items()}
except FileNotFoundError:
return {}
except (json.JSONDecodeError, OSError) as exc:
print(f"Could not load profile: {exc}")
return {}
def save_profile(state: dict[str, bool]) -> None:
try:
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
with CONFIG_FILE.open("w", encoding="utf-8") as f:
json.dump(state, f, indent=2, sort_keys=True)
except OSError as exc:
print(f"Failed to write profile: {exc}")
@Gtk.Template(resource_path='/gay/valhrafnaz/Gnomeframe/ui/window.ui')
class GnomeframeWindow(Adw.ApplicationWindow):
__gtype_name__ = 'GnomeframeWindow'
viewstack = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._profile: dict[str, bool] = load_profile()
self._load_page_templates()
reset_action = Gio.SimpleAction.new("reset-selections", None)
reset_action.connect("activate", self._reset_all)
self.get_application().add_action(reset_action)
self.connect("close-request", self._on_close_request)
# self.settings = Gio.Settings(schema_id="gay.valhrafnaz.Gnomeframe")
# self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
# self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
# self.settings.bind("window-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
def _load_page_templates(self):
self.home_page = HomePage(parent=self.viewstack)
self.settings_page = SettingsPage(parent=self.viewstack)
self.checklist_page = ChecklistPage(parent=self.viewstack, window=self)
def _reset_all(self, action, param):
self._profile.clear()
button = self.checklist_page.btns_basic.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
button.set_active(False)
button = button.get_next_sibling()
button = self.checklist_page.btns_prime.get_first_child()
while button is not None:
if isinstance(button, Gtk.ToggleButton):
button.set_active(False)
button = button.get_next_sibling()
save_profile(self._profile)
def _on_close_request(self, *args):
save_profile(self._profile)
return False

View File

@@ -1,49 +1,58 @@
# src/meson.build
# -------------------------------------------------
# 1⃣ Set up paths that Builder already used
# -------------------------------------------------
pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name()
moduledir = pkgdatadir / 'gnomeframe'
gnome = import('gnome')
blueprints = custom_target('blueprints',
input: files(
'ui/window.blp',
'ui/shortcuts-dialog.blp',
'ui/checklist.blp',
),
output: '.',
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT', '@CURRENT_SOURCE_DIRECTORY@' , '@INPUT@'],
)
gnome.compile_resources('gnomeframe',
'gnomeframe.gresource.xml',
gresource_bundle: true,
install: true,
install_dir: pkgdatadir,
dependencies: blueprints,
)
moduledir = pkgdatadir / 'gnomeframe' # <-- this is where the *data* files go
# (the GResource generated in data/ will be installed there by the toplevel file)
# -------------------------------------------------
# 2⃣ Python helper
# -------------------------------------------------
python = import('python')
py_inst = python.find_installation('python3')
# -------------------------------------------------
# 3⃣ Configuration data (kept exactly as you had it)
# -------------------------------------------------
conf = configuration_data()
conf.set('PYTHON', python.find_installation('python3').full_path())
conf.set('PYTHON', py_inst.full_path())
conf.set('VERSION', meson.project_version())
conf.set('localedir', get_option('prefix') / get_option('localedir'))
conf.set('pkgdatadir', pkgdatadir)
configure_file(
input: 'gnomeframe.in',
input : 'gnomeframe.in',
output: 'gnomeframe',
configuration: conf,
install: true,
install_dir: get_option('bindir'),
install_mode: 'rwxr-xr-x'
configuration : conf,
install : true,
install_dir : get_option('bindir'), # the launcher script goes to /app/bin
install_mode : 'rwxr-xr-x'
)
gnomeframe_sources = [
'__init__.py',
'main.py',
'window.py',
]
# -------------------------------------------------
# 4⃣ Install the **Python package**
# -------------------------------------------------
# The package lives in src/gnomeframe/ (notice the extra directory level)
# We install the whole directory tree into the Python sitepackages location.
# Meson will create the correct destination, e.g.
# /app/lib/python3.11/site-packages/gnomeframe/
install_subdir(
'gnomeframe', # <-- source directory (relative to src/)
install_dir : py_inst.get_install_dir(), # sitepackages
)
install_data(gnomeframe_sources, install_dir: moduledir)
# -------------------------------------------------
# 5⃣ (Optional) Install any *nonPython* data that still lives
# in src/ (e.g. .desktop files, icons that you kept here)
# -------------------------------------------------
# If you have such files, list them here and install them to `moduledir`.
# Example (uncomment if you need it):
# data_files = ['some-icon.svg', 'org.example.myapp.desktop']
# install_data(data_files,
# install_dir : moduledir)
# -------------------------------------------------
# 6⃣ Nothing else to change the toplevel meson file
# already builds the GResource from data/resources/.
# -------------------------------------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff