(Init): Added shit
This commit is contained in:
284
nirimod/pages/layout.py
Normal file
284
nirimod/pages/layout.py
Normal file
@@ -0,0 +1,284 @@
|
||||
"""Layout settings page."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "4.0")
|
||||
gi.require_version("Adw", "1")
|
||||
from gi.repository import Adw, Gtk
|
||||
|
||||
from nirimod.kdl_parser import KdlNode, find_or_create, set_child_arg, remove_child
|
||||
from nirimod.pages.base import BasePage
|
||||
|
||||
|
||||
CENTER_OPTIONS = ["never", "always", "on-overflow"]
|
||||
|
||||
|
||||
class LayoutPage(BasePage):
|
||||
def build(self) -> Gtk.Widget:
|
||||
tb, _, _, content = self._make_toolbar_page("Layout")
|
||||
self._content = content
|
||||
self._build_content()
|
||||
return tb
|
||||
|
||||
def _build_content(self):
|
||||
content = self._content
|
||||
nodes = self._nodes
|
||||
layout = find_or_create(nodes, "layout")
|
||||
|
||||
basic_grp = Adw.PreferencesGroup(title="General")
|
||||
|
||||
gaps_val = int(layout.child_arg("gaps") or 16)
|
||||
gaps_adj = Gtk.Adjustment(value=gaps_val, lower=0, upper=200, step_increment=2)
|
||||
gaps_row = Adw.SpinRow(title="Window Gaps (px)", adjustment=gaps_adj, digits=0)
|
||||
|
||||
gaps_row._last_val = gaps_val
|
||||
|
||||
def _on_gaps_changed(r, _):
|
||||
new_val = int(r.get_value())
|
||||
if new_val != getattr(r, "_last_val", None):
|
||||
r._last_val = new_val
|
||||
self._set_layout("gaps", new_val)
|
||||
|
||||
gaps_row.connect("notify::value", _on_gaps_changed)
|
||||
basic_grp.add(gaps_row)
|
||||
|
||||
cfc_model = Gtk.StringList.new(CENTER_OPTIONS)
|
||||
cfc_row = Adw.ComboRow(title="Center Focused Column", model=cfc_model)
|
||||
cur_cfc = layout.child_arg("center-focused-column") or "never"
|
||||
if cur_cfc in CENTER_OPTIONS:
|
||||
cfc_row.set_selected(CENTER_OPTIONS.index(cur_cfc))
|
||||
cfc_row.connect(
|
||||
"notify::selected",
|
||||
lambda r, _: self._set_layout(
|
||||
"center-focused-column", CENTER_OPTIONS[r.get_selected()]
|
||||
),
|
||||
)
|
||||
basic_grp.add(cfc_row)
|
||||
|
||||
prefer_csd_row = Adw.SwitchRow(
|
||||
title="Prefer No CSD", subtitle="Ask apps to omit client-side decorations"
|
||||
)
|
||||
prefer_csd_row.set_active(any(n.name == "prefer-no-csd" for n in nodes))
|
||||
prefer_csd_row.connect(
|
||||
"notify::active",
|
||||
lambda r, _: self._toggle_top("prefer-no-csd", r.get_active()),
|
||||
)
|
||||
basic_grp.add(prefer_csd_row)
|
||||
|
||||
bg_color_val = str(layout.child_arg("background-color") or "transparent")
|
||||
bg_row = Adw.EntryRow(title="Background Color (e.g. transparent, #000000)")
|
||||
bg_row.set_text(bg_color_val)
|
||||
bg_row.set_show_apply_button(True)
|
||||
bg_row.connect(
|
||||
"apply",
|
||||
lambda r: self._set_layout("background-color", r.get_text().strip()),
|
||||
)
|
||||
basic_grp.add(bg_row)
|
||||
|
||||
content.append(basic_grp)
|
||||
|
||||
dcw_grp = Adw.PreferencesGroup(title="Default Column Width")
|
||||
dcw_node = layout.get_child("default-column-width")
|
||||
|
||||
prop_val = 0.5
|
||||
fixed_val = 800
|
||||
use_fixed = False
|
||||
|
||||
if dcw_node:
|
||||
fc = dcw_node.get_child("fixed")
|
||||
pc = dcw_node.get_child("proportion")
|
||||
if fc and fc.args:
|
||||
fixed_val = int(fc.args[0])
|
||||
use_fixed = True
|
||||
elif pc and pc.args:
|
||||
prop_val = float(pc.args[0])
|
||||
|
||||
mode_model = Gtk.StringList.new(["Proportion", "Fixed (px)"])
|
||||
mode_row = Adw.ComboRow(title="Mode", model=mode_model)
|
||||
mode_row.set_selected(1 if use_fixed else 0)
|
||||
dcw_grp.add(mode_row)
|
||||
|
||||
prop_adj = Gtk.Adjustment(value=prop_val, lower=0.05, upper=1.0, step_increment=0.05)
|
||||
prop_spin = Gtk.SpinButton(adjustment=prop_adj, digits=2, climb_rate=1)
|
||||
prop_spin.set_valign(Gtk.Align.CENTER)
|
||||
prop_spin.connect("value-changed", lambda s: self._set_dcw_proportion(s.get_value()))
|
||||
prop_row = Adw.ActionRow(title="Proportion")
|
||||
prop_row.add_suffix(prop_spin)
|
||||
prop_row.set_visible(not use_fixed)
|
||||
dcw_grp.add(prop_row)
|
||||
|
||||
fixed_adj = Gtk.Adjustment(value=fixed_val, lower=100, upper=7680, step_increment=10)
|
||||
fixed_spin = Gtk.SpinButton(adjustment=fixed_adj, digits=0, climb_rate=1)
|
||||
fixed_spin.set_valign(Gtk.Align.CENTER)
|
||||
fixed_spin.connect("value-changed", lambda s: self._set_dcw_fixed(int(s.get_value())))
|
||||
fixed_row = Adw.ActionRow(title="Fixed Width (px)")
|
||||
fixed_row.add_suffix(fixed_spin)
|
||||
fixed_row.set_visible(use_fixed)
|
||||
dcw_grp.add(fixed_row)
|
||||
|
||||
def _on_mode_changed(r, _):
|
||||
is_fixed = r.get_selected() == 1
|
||||
prop_row.set_visible(not is_fixed)
|
||||
fixed_row.set_visible(is_fixed)
|
||||
if is_fixed:
|
||||
self._set_dcw_fixed(int(fixed_spin.get_value()))
|
||||
else:
|
||||
self._set_dcw_proportion(prop_spin.get_value())
|
||||
|
||||
mode_row.connect("notify::selected", _on_mode_changed)
|
||||
content.append(dcw_grp)
|
||||
|
||||
pw_grp = Adw.PreferencesGroup(title="Preset Column Widths (proportions)")
|
||||
pw_grp.set_description("Cycled through by Mod+R")
|
||||
pcw_node = layout.get_child("preset-column-widths")
|
||||
presets = []
|
||||
if pcw_node:
|
||||
for c in pcw_node.children:
|
||||
if c.name == "proportion" and c.args:
|
||||
presets.append(float(c.args[0]))
|
||||
self._preset_spins: list[Gtk.SpinButton] = []
|
||||
|
||||
for val in presets or [0.333, 0.5, 0.667]:
|
||||
self._add_preset_row(pw_grp, val)
|
||||
add_preset_btn = Gtk.Button(label="Add Preset")
|
||||
add_preset_btn.add_css_class("flat")
|
||||
add_preset_btn.connect("clicked", lambda *_: self._add_preset_row(pw_grp, 0.5))
|
||||
pw_grp.set_header_suffix(add_preset_btn)
|
||||
content.append(pw_grp)
|
||||
|
||||
struts_grp = Adw.PreferencesGroup(title="Struts (outer gaps, px)")
|
||||
struts_node = layout.get_child("struts")
|
||||
for side in ["left", "right", "top", "bottom"]:
|
||||
val = int(struts_node.child_arg(side) or 0) if struts_node else 0
|
||||
adj = Gtk.Adjustment(value=val, lower=0, upper=500, step_increment=4)
|
||||
row = Adw.SpinRow(title=side.capitalize(), adjustment=adj, digits=0)
|
||||
|
||||
row._last_val = val
|
||||
|
||||
def _on_strut_changed(r, _, s=side):
|
||||
new_val = int(r.get_value())
|
||||
if new_val != getattr(r, "_last_val", None):
|
||||
r._last_val = new_val
|
||||
self._set_strut(s, new_val)
|
||||
|
||||
row.connect("notify::value", _on_strut_changed)
|
||||
struts_grp.add(row)
|
||||
content.append(struts_grp)
|
||||
|
||||
def _add_preset_row(self, grp: Adw.PreferencesGroup, val: float):
|
||||
spin_adj = Gtk.Adjustment(value=val, lower=0.05, upper=1.0, step_increment=0.05)
|
||||
spin = Gtk.SpinButton(adjustment=spin_adj, digits=3, climb_rate=1)
|
||||
spin.set_valign(Gtk.Align.CENTER)
|
||||
self._preset_spins.append(spin)
|
||||
|
||||
row = Adw.ActionRow(title=f"Proportion {val:.3f}")
|
||||
spin.connect(
|
||||
"value-changed",
|
||||
lambda s, r=row: (
|
||||
r.set_title(f"Proportion {s.get_value():.3f}"),
|
||||
self._save_presets(),
|
||||
),
|
||||
)
|
||||
|
||||
del_btn = Gtk.Button(icon_name="user-trash-symbolic")
|
||||
del_btn.set_valign(Gtk.Align.CENTER)
|
||||
del_btn.add_css_class("flat")
|
||||
del_btn.add_css_class("error")
|
||||
|
||||
def _on_delete(s=spin):
|
||||
self._preset_spins.remove(s)
|
||||
grp.remove(row)
|
||||
self._save_presets()
|
||||
|
||||
del_btn.connect("clicked", lambda *_: _on_delete())
|
||||
row.add_suffix(spin)
|
||||
row.add_suffix(del_btn)
|
||||
grp.add(row)
|
||||
|
||||
def _save_presets(self):
|
||||
layout = find_or_create(self._nodes, "layout")
|
||||
pcw = layout.get_child("preset-column-widths")
|
||||
if pcw is None:
|
||||
pcw = KdlNode("preset-column-widths")
|
||||
layout.children.append(pcw)
|
||||
new_children = []
|
||||
for i, s in enumerate(self._preset_spins):
|
||||
if i < len(pcw.children):
|
||||
child = pcw.children[i]
|
||||
child.name = "proportion"
|
||||
child.args = [round(s.get_value(), 5)]
|
||||
new_children.append(child)
|
||||
else:
|
||||
new_children.append(KdlNode("proportion", args=[round(s.get_value(), 5)]))
|
||||
|
||||
salvaged = ""
|
||||
for i in range(len(self._preset_spins), len(pcw.children)):
|
||||
salvaged += pcw.children[i].leading_trivia
|
||||
if salvaged and new_children:
|
||||
new_children[-1].trailing_trivia += salvaged
|
||||
|
||||
pcw.children = new_children
|
||||
self._commit("preset column widths")
|
||||
|
||||
def _set_layout(self, key: str, value):
|
||||
layout = find_or_create(self._nodes, "layout")
|
||||
set_child_arg(layout, key, value)
|
||||
self._commit(f"layout {key}")
|
||||
|
||||
def _set_dcw_proportion(self, val: float):
|
||||
layout = find_or_create(self._nodes, "layout")
|
||||
dcw = layout.get_child("default-column-width")
|
||||
if dcw is None:
|
||||
dcw = KdlNode("default-column-width")
|
||||
layout.children.append(dcw)
|
||||
dcw.children = [KdlNode("proportion", args=[round(val, 4)])]
|
||||
self._commit("default column width proportion")
|
||||
|
||||
def _set_dcw_fixed(self, px: int):
|
||||
layout = find_or_create(self._nodes, "layout")
|
||||
dcw = layout.get_child("default-column-width")
|
||||
if dcw is None:
|
||||
dcw = KdlNode("default-column-width")
|
||||
layout.children.append(dcw)
|
||||
dcw.children = [KdlNode("fixed", args=[px])]
|
||||
self._commit("default column width fixed")
|
||||
|
||||
def _set_strut(self, side: str, val: int):
|
||||
layout = find_or_create(self._nodes, "layout")
|
||||
struts = layout.get_child("struts")
|
||||
if struts is None:
|
||||
struts = KdlNode("struts")
|
||||
layout.children.append(struts)
|
||||
if val > 0:
|
||||
set_child_arg(struts, side, val)
|
||||
else:
|
||||
remove_child(struts, side)
|
||||
self._commit(f"strut {side}")
|
||||
|
||||
def _toggle_top(self, key: str, enabled: bool):
|
||||
nodes = self._nodes
|
||||
existing = next((n for n in reversed(nodes) if n.name == key), None)
|
||||
|
||||
app_state = self._win.app_state
|
||||
if enabled and not existing:
|
||||
cache = getattr(app_state, "_removed_top_nodes", {})
|
||||
if key in cache:
|
||||
idx, node = cache[key]
|
||||
nodes.insert(min(idx, len(nodes)), node)
|
||||
else:
|
||||
nodes.append(KdlNode(key))
|
||||
elif not enabled and existing:
|
||||
if not hasattr(app_state, "_removed_top_nodes"):
|
||||
app_state._removed_top_nodes = {}
|
||||
app_state._removed_top_nodes[key] = (nodes.index(existing), existing)
|
||||
nodes.remove(existing)
|
||||
|
||||
self._commit(f"toggle {key}")
|
||||
|
||||
def refresh(self):
|
||||
for child in list(self._content):
|
||||
self._content.remove(child)
|
||||
self._build_content()
|
||||
Reference in New Issue
Block a user