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

added `reset to default` button

parent a307d827
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
gtype: string gtype: string
backend: gsettings backend: gsettings
key: org.gnome.desktop.interface.icon-theme key: org.gnome.desktop.interface.icon-theme
default: "Adwaita"
- name: Style - name: Style
type: choice type: choice
gtype: string gtype: string
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
type: boolean type: boolean
gtype: boolean gtype: boolean
backend: gsettings backend: gsettings
default: true
key: org.gnome.desktop.interface.clock-show-weekday key: org.gnome.desktop.interface.clock-show-weekday
- name: Date - name: Date
type: boolean type: boolean
...@@ -136,6 +138,7 @@ ...@@ -136,6 +138,7 @@
gtype: d gtype: d
backend: gsettings backend: gsettings
key: org.gnome.desktop.interface.text-scaling-factor key: org.gnome.desktop.interface.text-scaling-factor
default: 1.0
map: map:
upper: 3.0 upper: 3.0
lower: 0.5 lower: 0.5
...@@ -192,6 +195,7 @@ ...@@ -192,6 +195,7 @@
backend: file backend: file
key: XDG_DOCUMENTS_DIR key: XDG_DOCUMENTS_DIR
help: Select documents folder help: Select documents folder
default: "~/Документы"
params: params:
file_path: "~/.config/user-dirs.dirs" file_path: "~/.config/user-dirs.dirs"
map: map:
...@@ -236,6 +240,7 @@ ...@@ -236,6 +240,7 @@
backend: file backend: file
key: XDG_DOWNLOAD_DIR key: XDG_DOWNLOAD_DIR
help: Select downloads folder help: Select downloads folder
default: "~/Загрузки"
params: params:
file_path: "~/.config/user-dirs.dirs" file_path: "~/.config/user-dirs.dirs"
map: map:
......
...@@ -169,6 +169,9 @@ class FileBackend(Backend): ...@@ -169,6 +169,9 @@ class FileBackend(Backend):
entries = self.vars.get(key, []) entries = self.vars.get(key, [])
style = self._get_style_template() style = self._get_style_template()
key = os.path.expanduser(key)
key = os.path.expandvars(key)
if entries: if entries:
line_num, last_entry = entries[-1] line_num, last_entry = entries[-1]
style = last_entry['style'] style = last_entry['style']
......
...@@ -114,6 +114,9 @@ class Setting: ...@@ -114,6 +114,9 @@ class Setting:
current_value = self._get_backend_value() current_value = self._get_backend_value()
return list(self.map.values()).index(current_value) if current_value in self.map.values() else 0 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): def _get_backend_value(self):
value = None value = None
......
from gi.repository import Gtk
class BaseWidget: class BaseWidget:
def __init__(self, setting): def __init__(self, setting):
self.setting = 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): def create_row(self):
raise NotImplementedError("Метод create_row должен быть реализован в подклассе") 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 from .BaseWidget import BaseWidget
class BooleanWidget(BaseWidget): class BooleanWidget(BaseWidget):
def create_row(self): 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() current_value = self.setting._get_backend_value()
row.set_active(current_value == self.setting.map.get(True)) is_active = current_value == self.setting.map.get(True)
row.connect("notify::active", self._on_boolean_toggled) self.switch.set_active(is_active)
return row self._update_reset_visibility()
def _on_boolean_toggled(self, switch, _): def _on_boolean_toggled(self, switch, _):
value = self.setting.map.get(True) if switch.get_active() else self.setting.map.get(False) value = self.setting.map.get(True) if switch.get_active() else self.setting.map.get(False)
self.setting._set_backend_value(value) 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 ...@@ -3,12 +3,63 @@ from .BaseWidget import BaseWidget
class ChoiceWidget(BaseWidget): class ChoiceWidget(BaseWidget):
def create_row(self): def create_row(self):
row = Adw.ComboRow(title=self.setting.name, subtitle=self.setting.help) items = list(self.setting.map.keys())
row.set_model(Gtk.StringList.new(list(self.setting.map.keys())))
row.set_selected(self.setting._get_selected_row_index()) self.row = Adw.ActionRow(title=self.setting.name, subtitle=self.setting.help)
row.connect("notify::selected", self._on_choice_changed)
return row
self.dropdown = Gtk.DropDown.new_from_strings(items)
def _on_choice_changed(self, combo_row, _): self.dropdown.set_halign(Gtk.Align.CENTER)
selected_value = list(self.setting.map.values())[combo_row.get_selected()] 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.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 from .BaseWidget import BaseWidget
class EntryWidget(BaseWidget): class EntryWidget(BaseWidget):
def create_row(self): def create_row(self):
row = Adw.EntryRow(title=self.setting.name) self.row = Adw.ActionRow(title=self.setting.name)
row.set_show_apply_button(True)
row.set_text(self.setting._get_backend_value()) self.entry = Gtk.Entry()
row.connect("apply", self._on_text_changed) self.entry.set_halign(Gtk.Align.CENTER)
return row
self.entry.set_text(self.setting._get_backend_value() or "")
def _on_text_changed(self, entry_row):
self.setting._set_backend_value(entry_row.get_text()) 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 Adw, Gtk
from gi.repository import Gio from gi.repository import Gio
import os
from .BaseWidget import BaseWidget from .BaseWidget import BaseWidget
...@@ -7,7 +8,6 @@ from .BaseWidget import BaseWidget ...@@ -7,7 +8,6 @@ from .BaseWidget import BaseWidget
class FileChooser(BaseWidget): class FileChooser(BaseWidget):
def create_row(self): def create_row(self):
self.value_separated = False self.value_separated = False
self.multiple_mode = self.setting.map.get('multiple', False) self.multiple_mode = self.setting.map.get('multiple', False)
self.folder_mode = 'folder' in self.setting.map.get('extensions', []) self.folder_mode = 'folder' in self.setting.map.get('extensions', [])
...@@ -17,7 +17,12 @@ class FileChooser(BaseWidget): ...@@ -17,7 +17,12 @@ class FileChooser(BaseWidget):
subtitle_selectable=True 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: if not self.multiple_mode and not self.folder_mode:
self.entry = Gtk.Entry( self.entry = Gtk.Entry(
...@@ -45,9 +50,63 @@ class FileChooser(BaseWidget): ...@@ -45,9 +50,63 @@ class FileChooser(BaseWidget):
control_box.append(self.select_button) control_box.append(self.select_button)
row.add_suffix(control_box) row.add_suffix(control_box)
self._update_display() self._update_display()
self._update_reset_visibility()
return row 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): def _on_button_clicked(self, button):
dialog = Gtk.FileDialog() dialog = Gtk.FileDialog()
...@@ -60,8 +119,12 @@ class FileChooser(BaseWidget): ...@@ -60,8 +119,12 @@ class FileChooser(BaseWidget):
# Установка начальной директории # Установка начальной директории
current = self.setting._get_backend_value() current = self.setting._get_backend_value()
if current: if current:
try: try:
current = os.path.expanduser(current)
current = os.path.expandvars(current)
current_file = Gio.File.new_for_path(current) current_file = Gio.File.new_for_path(current)
parent = current_file.get_parent() if not self.folder_mode else current_file parent = current_file.get_parent() if not self.folder_mode else current_file
dialog.set_initial_folder(parent) dialog.set_initial_folder(parent)
...@@ -108,8 +171,8 @@ class FileChooser(BaseWidget): ...@@ -108,8 +171,8 @@ class FileChooser(BaseWidget):
try: try:
file = dialog.open_finish(result) file = dialog.open_finish(result)
if file: if file:
self.setting._set_backend_value(file.get_path() if self.value_separated is False self.setting._set_backend_value(file.get_path())
else f"file://{file.get_path()}")
self._update_display() self._update_display()
except Exception as e: except Exception as e:
print(f"File selection error: {e}") print(f"File selection error: {e}")
...@@ -133,19 +196,6 @@ class FileChooser(BaseWidget): ...@@ -133,19 +196,6 @@ class FileChooser(BaseWidget):
except Exception as e: except Exception as e:
print(f"Folder selection error: {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): def _update_folder_display(self, current):
if current: if current:
folder = Gio.File.new_for_path(current) folder = Gio.File.new_for_path(current)
...@@ -166,9 +216,8 @@ class FileChooser(BaseWidget): ...@@ -166,9 +216,8 @@ class FileChooser(BaseWidget):
self.entry.set_tooltip_text(None) self.entry.set_tooltip_text(None)
def _on_entry_changed(self, entry): def _on_entry_changed(self, entry):
if (not self.folder_mode and if not self.folder_mode and not self.multiple_mode:
not self.multiple_mode and
not self.setting._get_backend() is not None):
path = entry.get_text().strip() path = entry.get_text().strip()
self.setting._set_backend_value(path if self.value_separated is False self.setting._set_backend_value(path)
else f"file://{path}")
\ No newline at end of file self._update_reset_visibility()
\ No newline at end of file
from gi.repository import Adw, Gtk from gi.repository import Adw, Gtk
from .BaseWidget import BaseWidget from .BaseWidget import BaseWidget
class NumStepper(BaseWidget): class NumStepper(BaseWidget):
def create_row(self): def create_row(self):
map = self.setting.map 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( self.spin = Gtk.SpinButton(
title=self.setting.name, subtitle=self.setting.help valign=Gtk.Align.CENTER,
halign=Gtk.Align.CENTER,
) )
adjustment = Gtk.Adjustment( adjustment = Gtk.Adjustment(
value=self.setting._get_backend_value(), value=self.setting._get_backend_value(),
lower=map["lower"], upper=map["upper"], lower=map["lower"],
upper=map["upper"],
step_increment=map["step"], step_increment=map["step"],
) )
row.set_adjustment(adjustment) self.spin.set_adjustment(adjustment)
if "digits" in map_keys: 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 return row
def _on_num_changed(self, adj): def _on_num_changed(self, widget):
selected_value = adj.get_value() selected_value = widget.get_value()
self.setting._set_backend_value(selected_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): ...@@ -16,12 +16,25 @@ class RadioChoiceWidget(BaseWidget):
) )
main_box.set_child(content_box) 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( title_label = Gtk.Label(
label=self.setting.name, 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: if self.setting.help:
subtitle_label = Gtk.Label( subtitle_label = Gtk.Label(
...@@ -33,15 +46,15 @@ class RadioChoiceWidget(BaseWidget): ...@@ -33,15 +46,15 @@ class RadioChoiceWidget(BaseWidget):
subtitle_label.add_css_class("caption") subtitle_label.add_css_class("caption")
subtitle_label.add_css_class("dim-label") subtitle_label.add_css_class("dim-label")
content_box.append(subtitle_label) title_box.append(subtitle_label)
radio_container = Gtk.Box( radio_container = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, orientation=Gtk.Orientation.VERTICAL,
spacing=4 spacing=8
) )
content_box.append(radio_container) content_box.append(radio_container)
self.radio_buttons = {}
current_value = self.setting._get_backend_value() current_value = self.setting._get_backend_value()
group = None group = None
...@@ -50,8 +63,9 @@ class RadioChoiceWidget(BaseWidget): ...@@ -50,8 +63,9 @@ class RadioChoiceWidget(BaseWidget):
radio = Gtk.CheckButton( radio = Gtk.CheckButton(
label=label, label=label,
halign=Gtk.Align.START, halign=Gtk.Align.START,
active=(value == current_value)
) )
radio.set_active(value == current_value) radio.add_css_class('selection-mode')
if group: if group:
radio.set_group(group) radio.set_group(group)
...@@ -60,6 +74,13 @@ class RadioChoiceWidget(BaseWidget): ...@@ -60,6 +74,13 @@ class RadioChoiceWidget(BaseWidget):
radio.connect("toggled", self._on_toggle, value) radio.connect("toggled", self._on_toggle, value)
radio_container.append(radio) 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 return main_box
...@@ -67,3 +88,24 @@ class RadioChoiceWidget(BaseWidget): ...@@ -67,3 +88,24 @@ class RadioChoiceWidget(BaseWidget):
if button.get_active(): if button.get_active():
self.setting._set_backend_value(value) 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