Commit 13319c90 authored by Roman Alifanov's avatar Roman Alifanov

added `reset to default` button

parent a307d827
......@@ -36,6 +36,7 @@
gtype: string
backend: gsettings
key: org.gnome.desktop.interface.icon-theme
default: "Adwaita"
- name: Style
type: choice
gtype: string
......@@ -74,6 +75,7 @@
type: boolean
gtype: boolean
backend: gsettings
default: true
key: org.gnome.desktop.interface.clock-show-weekday
- name: Date
type: boolean
......@@ -136,6 +138,7 @@
gtype: d
backend: gsettings
key: org.gnome.desktop.interface.text-scaling-factor
default: 1.0
map:
upper: 3.0
lower: 0.5
......@@ -192,6 +195,7 @@
backend: file
key: XDG_DOCUMENTS_DIR
help: Select documents folder
default: "~/Документы"
params:
file_path: "~/.config/user-dirs.dirs"
map:
......@@ -236,6 +240,7 @@
backend: file
key: XDG_DOWNLOAD_DIR
help: Select downloads folder
default: "~/Загрузки"
params:
file_path: "~/.config/user-dirs.dirs"
map:
......
......@@ -169,6 +169,9 @@ class FileBackend(Backend):
entries = self.vars.get(key, [])
style = self._get_style_template()
key = os.path.expanduser(key)
key = os.path.expandvars(key)
if entries:
line_num, last_entry = entries[-1]
style = last_entry['style']
......
......@@ -114,6 +114,9 @@ class Setting:
current_value = self._get_backend_value()
return list(self.map.values()).index(current_value) if current_value in self.map.values() else 0
def _get_default_row_index(self):
return list(self.map.values()).index(self.default) if self.default in self.map.values() else None
def _get_backend_value(self):
value = None
......
from gi.repository import Gtk
class BaseWidget:
def __init__(self, setting):
self.setting = setting
self.reset_button = Gtk.Button(
icon_name="edit-undo-symbolic",
valign=Gtk.Align.CENTER,
halign=Gtk.Align.CENTER,
tooltip_text=_("Restore Default")
)
self.reset_button.add_css_class('flat')
self.reset_button.connect("clicked", self._on_reset_clicked)
self.reset_revealer = Gtk.Revealer(
transition_type=Gtk.RevealerTransitionType.CROSSFADE,
transition_duration=150,
child=self.reset_button,
reveal_child=False,
halign=Gtk.Align.END
)
def create_row(self):
raise NotImplementedError("Метод create_row должен быть реализован в подклассе")
def _on_reset_clicked(self, button):
raise NotImplementedError("Метод _on_reset_clicked должен быть реализован в подклассе")
from gi.repository import Adw
from gi.repository import Adw, Gtk
from .BaseWidget import BaseWidget
class BooleanWidget(BaseWidget):
def create_row(self):
row = Adw.SwitchRow(title=self.setting.name, subtitle=self.setting.help)
self.row = Adw.ActionRow(title=self.setting.name, subtitle=self.setting.help)
self.switch = Gtk.Switch(
valign=Gtk.Align.CENTER,
halign=Gtk.Align.CENTER,
)
self.switch.connect("notify::active", self._on_boolean_toggled)
control_box = Gtk.Box(spacing=6, orientation=Gtk.Orientation.HORIZONTAL)
control_box.append(self.reset_revealer)
control_box.append(self.switch)
self.row.add_suffix(control_box)
self._update_initial_state()
return self.row
def _update_initial_state(self):
current_value = self.setting._get_backend_value()
row.set_active(current_value == self.setting.map.get(True))
row.connect("notify::active", self._on_boolean_toggled)
return row
is_active = current_value == self.setting.map.get(True)
self.switch.set_active(is_active)
self._update_reset_visibility()
def _on_boolean_toggled(self, switch, _):
value = self.setting.map.get(True) if switch.get_active() else self.setting.map.get(False)
self.setting._set_backend_value(value)
self._update_reset_visibility()
def _on_reset_clicked(self, button):
default_value = self.setting.map.get(self.setting.default)
self.setting._set_backend_value(default_value)
self.switch.set_active(self.setting.default)
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = self.setting._get_backend_value()
default_value = self.setting.map.get(self.setting.default)
self.reset_revealer.set_reveal_child(
current_value != default_value if default_value is not None
else False
)
......@@ -3,12 +3,63 @@ from .BaseWidget import BaseWidget
class ChoiceWidget(BaseWidget):
def create_row(self):
row = Adw.ComboRow(title=self.setting.name, subtitle=self.setting.help)
row.set_model(Gtk.StringList.new(list(self.setting.map.keys())))
row.set_selected(self.setting._get_selected_row_index())
row.connect("notify::selected", self._on_choice_changed)
return row
def _on_choice_changed(self, combo_row, _):
selected_value = list(self.setting.map.values())[combo_row.get_selected()]
items = list(self.setting.map.keys())
self.row = Adw.ActionRow(title=self.setting.name, subtitle=self.setting.help)
self.dropdown = Gtk.DropDown.new_from_strings(items)
self.dropdown.set_halign(Gtk.Align.CENTER)
self.dropdown.set_valign(Gtk.Align.CENTER)
self._set_dropdown_width(items)
self.dropdown.set_selected(self.setting._get_selected_row_index())
self.dropdown.connect("notify::selected", self._on_choice_changed)
control_box = Gtk.Box(spacing=6, orientation=Gtk.Orientation.HORIZONTAL)
control_box.append(self.reset_revealer)
control_box.append(self.dropdown)
self.row.add_suffix(control_box)
self._update_reset_visibility()
return self.row
def _set_dropdown_width(self, items):
layout = self.dropdown.create_pango_layout("")
width = 0
for item in items:
layout.set_text(item)
text_width = layout.get_pixel_size()[0]
if text_width > width:
width = text_width
self.dropdown.set_size_request(width + 50, -1)
def _on_choice_changed(self, dropdown, _):
selected = dropdown.get_selected()
selected_value = list(self.setting.map.values())[selected]
self.setting._set_backend_value(selected_value)
self._update_reset_visibility()
def _on_reset_clicked(self, button):
default_value = self.setting._get_default_row_index()
if default_value is not None:
self.dropdown.set_selected(default_value)
self.setting._set_backend_value(self.setting.default)
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = self.setting._get_selected_row_index()
default_value = self.setting._get_default_row_index()
self.reset_revealer.set_reveal_child(
current_value != default_value
if default_value is not None
else False
)
\ No newline at end of file
from gi.repository import Adw
from gi.repository import Gtk, Adw
from .BaseWidget import BaseWidget
class EntryWidget(BaseWidget):
def create_row(self):
row = Adw.EntryRow(title=self.setting.name)
row.set_show_apply_button(True)
row.set_text(self.setting._get_backend_value())
row.connect("apply", self._on_text_changed)
return row
def _on_text_changed(self, entry_row):
self.setting._set_backend_value(entry_row.get_text())
self.row = Adw.ActionRow(title=self.setting.name)
self.entry = Gtk.Entry()
self.entry.set_halign(Gtk.Align.CENTER)
self.entry.set_text(self.setting._get_backend_value() or "")
self.entry.connect("activate", self._on_text_changed)
control_box = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
spacing=6,
margin_start=12,
valign=Gtk.Align.CENTER,
halign=Gtk.Align.CENTER,
)
control_box.append(self.reset_revealer)
control_box.append(self.entry)
self.row.add_suffix(control_box)
self._update_reset_visibility()
return self.row
def _on_text_changed(self, entry):
new_value = entry.get_text()
self.setting._set_backend_value(new_value)
self._update_reset_visibility()
def _on_reset_clicked(self, button):
default_value = self.setting.default
self.setting._set_backend_value(default_value)
self.entry.set_text(str(default_value))
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = self.entry.get_text() or ""
default_value = self.setting.default
has_default = self.setting.default is not None
is_default = current_value == default_value
self.reset_revealer.set_reveal_child(not is_default and has_default)
\ No newline at end of file
from gi.repository import Adw, Gtk
from gi.repository import Gio
import os
from .BaseWidget import BaseWidget
......@@ -7,7 +8,6 @@ from .BaseWidget import BaseWidget
class FileChooser(BaseWidget):
def create_row(self):
self.value_separated = False
self.multiple_mode = self.setting.map.get('multiple', False)
self.folder_mode = 'folder' in self.setting.map.get('extensions', [])
......@@ -17,7 +17,12 @@ class FileChooser(BaseWidget):
subtitle_selectable=True
)
control_box = Gtk.Box(spacing=6, margin_end=12)
control_box = Gtk.Box(
spacing=6,
margin_end=12,
halign=Gtk.Align.END
)
control_box.append(self.reset_revealer)
if not self.multiple_mode and not self.folder_mode:
self.entry = Gtk.Entry(
......@@ -45,9 +50,63 @@ class FileChooser(BaseWidget):
control_box.append(self.select_button)
row.add_suffix(control_box)
self._update_display()
self._update_reset_visibility()
return row
def _on_reset_clicked(self, button):
default_value = self.setting.default
if default_value is not None:
if isinstance(default_value, str) and default_value.startswith("file://"):
default_value = default_value[7:]
self.setting._set_backend_value(default_value)
self._update_display()
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = self.setting._get_backend_value()
default_value = self.setting.default
if isinstance(current_value, str) and current_value.startswith("file://"):
current_value = current_value[7:]
if current_value:
current_value = os.path.expanduser(current_value)
current_value = os.path.expandvars(current_value)
if default_value:
default_value = os.path.expanduser(default_value)
default_value = os.path.expandvars(default_value)
self.reset_revealer.set_reveal_child(
current_value != default_value if default_value is not None
else False
)
def _update_display(self):
current = self.setting._get_backend_value()
self._update_reset_visibility()
if current and isinstance(current, str) and current.startswith("file://"):
current = current[7:]
self.value_separated = True
if self.folder_mode:
self._update_folder_display(current)
elif self.multiple_mode:
self._update_multiple_files_display(current)
else:
self._update_single_file_display(current)
def _on_button_clicked(self, button):
dialog = Gtk.FileDialog()
......@@ -60,8 +119,12 @@ class FileChooser(BaseWidget):
# Установка начальной директории
current = self.setting._get_backend_value()
if current:
try:
current = os.path.expanduser(current)
current = os.path.expandvars(current)
current_file = Gio.File.new_for_path(current)
parent = current_file.get_parent() if not self.folder_mode else current_file
dialog.set_initial_folder(parent)
......@@ -108,8 +171,8 @@ class FileChooser(BaseWidget):
try:
file = dialog.open_finish(result)
if file:
self.setting._set_backend_value(file.get_path() if self.value_separated is False
else f"file://{file.get_path()}")
self.setting._set_backend_value(file.get_path())
self._update_display()
except Exception as e:
print(f"File selection error: {e}")
......@@ -133,19 +196,6 @@ class FileChooser(BaseWidget):
except Exception as e:
print(f"Folder selection error: {e}")
def _update_display(self):
current = self.setting._get_backend_value()
if current.startswith("file://"):
current = current[7:]
self.value_separated = True
if self.folder_mode:
self._update_folder_display(current)
elif self.multiple_mode:
self._update_multiple_files_display(current)
else:
self._update_single_file_display(current)
def _update_folder_display(self, current):
if current:
folder = Gio.File.new_for_path(current)
......@@ -166,9 +216,8 @@ class FileChooser(BaseWidget):
self.entry.set_tooltip_text(None)
def _on_entry_changed(self, entry):
if (not self.folder_mode and
not self.multiple_mode and
not self.setting._get_backend() is not None):
if not self.folder_mode and not self.multiple_mode:
path = entry.get_text().strip()
self.setting._set_backend_value(path if self.value_separated is False
else f"file://{path}")
\ No newline at end of file
self.setting._set_backend_value(path)
self._update_reset_visibility()
\ No newline at end of file
from gi.repository import Adw, Gtk
from .BaseWidget import BaseWidget
class NumStepper(BaseWidget):
def create_row(self):
map = self.setting.map
map_keys = list(self.setting.map.keys())
map_keys = list(map.keys())
row = Adw.ActionRow(
title=self.setting.name,
subtitle=self.setting.help,
activatable=False
)
row = Adw.SpinRow(
title=self.setting.name, subtitle=self.setting.help
self.spin = Gtk.SpinButton(
valign=Gtk.Align.CENTER,
halign=Gtk.Align.CENTER,
)
adjustment = Gtk.Adjustment(
value=self.setting._get_backend_value(),
lower=map["lower"], upper=map["upper"],
lower=map["lower"],
upper=map["upper"],
step_increment=map["step"],
)
row.set_adjustment(adjustment)
self.spin.set_adjustment(adjustment)
if "digits" in map_keys:
row.set_digits(map["digits"])
self.spin.set_digits(map["digits"])
control_box = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
spacing=6,
margin_start=12
)
control_box.append(self.reset_revealer)
control_box.append(self.spin)
row.add_suffix(control_box)
self.spin.connect("value-changed", self._on_num_changed)
self._update_reset_visibility()
adjustment.connect("value_changed", self._on_num_changed)
return row
def _on_num_changed(self, adj):
selected_value = adj.get_value()
def _on_num_changed(self, widget):
selected_value = widget.get_value()
self.setting._set_backend_value(selected_value)
self._update_reset_visibility()
def _on_reset_clicked(self, button):
default_value = self.setting.default
if default_value is not None:
self.setting._set_backend_value(default_value)
self.spin.set_value(float(default_value))
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = float(self.setting._get_backend_value())
default_value = self.setting.default
self.reset_revealer.set_reveal_child(
current_value != default_value if default_value is not None
else False
)
\ No newline at end of file
......@@ -16,12 +16,25 @@ class RadioChoiceWidget(BaseWidget):
)
main_box.set_child(content_box)
title_horizontal_box = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
hexpand=True,
)
content_box.append(title_horizontal_box)
title_box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
hexpand=True,
spacing=1,
)
title_horizontal_box.append(title_box)
title_label = Gtk.Label(
label=self.setting.name,
halign=Gtk.Align.START
halign=Gtk.Align.START,
)
content_box.append(title_label)
title_box.append(title_label)
if self.setting.help:
subtitle_label = Gtk.Label(
......@@ -33,15 +46,15 @@ class RadioChoiceWidget(BaseWidget):
subtitle_label.add_css_class("caption")
subtitle_label.add_css_class("dim-label")
content_box.append(subtitle_label)
title_box.append(subtitle_label)
radio_container = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=4
spacing=8
)
content_box.append(radio_container)
self.radio_buttons = {}
current_value = self.setting._get_backend_value()
group = None
......@@ -50,8 +63,9 @@ class RadioChoiceWidget(BaseWidget):
radio = Gtk.CheckButton(
label=label,
halign=Gtk.Align.START,
active=(value == current_value)
)
radio.set_active(value == current_value)
radio.add_css_class('selection-mode')
if group:
radio.set_group(group)
......@@ -60,6 +74,13 @@ class RadioChoiceWidget(BaseWidget):
radio.connect("toggled", self._on_toggle, value)
radio_container.append(radio)
self.radio_buttons[value] = radio
self.reset_revealer.set_halign(Gtk.Align.END)
title_horizontal_box.append(self.reset_revealer)
self._update_reset_visibility()
return main_box
......@@ -67,3 +88,24 @@ class RadioChoiceWidget(BaseWidget):
if button.get_active():
self.setting._set_backend_value(value)
self._update_reset_visibility()
def _on_reset_clicked(self, button):
default_value = self.setting.default
if default_value is not None:
self.setting._set_backend_value(default_value)
if default_value in self.radio_buttons:
self.radio_buttons[default_value].set_active(True)
self._update_reset_visibility()
def _update_reset_visibility(self):
current_value = self.setting._get_backend_value()
default_value = self.setting.default
self.reset_revealer.set_reveal_child(
current_value != default_value if default_value is not None
else False
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment