mirror of
https://github.com/aclist/dztui.git
synced 2026-10-31 07:02:50 +01:00
chore: normalize dialogs
This commit is contained in:
1 parent
45bd0e16ec
commit
1bc21d6083
15 files changed
+283
-282
No files matched your search
@@ -26,6 +26,7 @@
|
|||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
- Bold labels inside frames
|
- Bold labels inside frames
|
||||||
|
- Unsticky keys when clicking sidebar
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ class Popup(Enum):
|
|||||||
NOTIFY = 2
|
NOTIFY = 2
|
||||||
CONFIRM = 3
|
CONFIRM = 3
|
||||||
ENTRY = 4
|
ENTRY = 4
|
||||||
RETURN = 5
|
|
||||||
MODLIST = 6
|
MODLIST = 6
|
||||||
DETAILS = 7
|
DETAILS = 7
|
||||||
QUIT = 8
|
QUIT = 8
|
||||||
|
|||||||
+10
-17
@@ -2,12 +2,14 @@ import logging
|
|||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import traceback
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, TYPE_CHECKING
|
from typing import Any, Callable, TYPE_CHECKING
|
||||||
|
|
||||||
import dzgui.api.pefile as PeFile
|
import dzgui.api.pefile as PeFile
|
||||||
import dzgui.util._json as JSON # noqa
|
import dzgui.util._json as JSON # noqa
|
||||||
|
from dzgui.views.dialogs.generic import ExceptionDialog
|
||||||
|
|
||||||
from dzgui.api.probe import test_steam_api, test_bm_api
|
from dzgui.api.probe import test_steam_api, test_bm_api
|
||||||
from dzgui.api.mods import (
|
from dzgui.api.mods import (
|
||||||
@@ -38,7 +40,7 @@ from dzgui.config import update
|
|||||||
from dzgui.config.query import lookup
|
from dzgui.config.query import lookup
|
||||||
from dzgui.config.userprefs import UserPrefs
|
from dzgui.config.userprefs import UserPrefs
|
||||||
from dzgui.controllers.model import ModelManager
|
from dzgui.controllers.model import ModelManager
|
||||||
from dzgui.util import cooldown, strings
|
from dzgui.util import strings
|
||||||
from dzgui.util.diag import write_diagnostic
|
from dzgui.util.diag import write_diagnostic
|
||||||
from dzgui.util._json import read_json, write_json
|
from dzgui.util._json import read_json, write_json
|
||||||
from dzgui.util.localize import number
|
from dzgui.util.localize import number
|
||||||
@@ -89,7 +91,6 @@ class Controller:
|
|||||||
self.crumbs_cache = ""
|
self.crumbs_cache = ""
|
||||||
self.mediator = AppNavigation()
|
self.mediator = AppNavigation()
|
||||||
self.prefs: UserPrefs
|
self.prefs: UserPrefs
|
||||||
self.cooldown = 0
|
|
||||||
|
|
||||||
self.model_manager = ModelManager()
|
self.model_manager = ModelManager()
|
||||||
|
|
||||||
@@ -291,14 +292,18 @@ class Controller:
|
|||||||
update.toggle_config(config, context)
|
update.toggle_config(config, context)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
self.spawn_dialog(strings.something_wrong, Popup.NOTIFY)
|
trace = traceback.format_exc()
|
||||||
|
dialog = ExceptionDialog(self, trace)
|
||||||
|
dialog.run()
|
||||||
|
|
||||||
def update_config(self, key: Preferences, value: str) -> None:
|
def update_config(self, key: Preferences, value: str) -> None:
|
||||||
try:
|
try:
|
||||||
update.write_config(self.prefs.paths.config, key, value)
|
update.write_config(self.prefs.paths.config, key, value)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
self.spawn_dialog(strings.something_wrong, Popup.NOTIFY)
|
trace = traceback.format_exc()
|
||||||
|
dialog = ExceptionDialog(self, trace)
|
||||||
|
dialog.run()
|
||||||
# TODO: suppress signals
|
# TODO: suppress signals
|
||||||
# then reenable (or it spawns dialog twice)
|
# then reenable (or it spawns dialog twice)
|
||||||
self.mediator.grid.notebook.settings.populate_settings()
|
self.mediator.grid.notebook.settings.populate_settings()
|
||||||
@@ -308,19 +313,6 @@ class Controller:
|
|||||||
#def present_toast(self, text: str) -> None:
|
#def present_toast(self, text: str) -> None:
|
||||||
# self.mediator.window.toast.set_text_and_fade(text)
|
# self.mediator.window.toast.set_text_and_fade(text)
|
||||||
|
|
||||||
def start_cooldown(self) -> None:
|
|
||||||
self.cooldown = cooldown.get_time()
|
|
||||||
|
|
||||||
def get_cooldown(self) -> None:
|
|
||||||
return self.cooldown
|
|
||||||
|
|
||||||
def manage_cooldown(self) -> bool:
|
|
||||||
if cooldown.is_elapsed(self.cooldown):
|
|
||||||
self.cooldown = cooldown.get_time()
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def open_keybindings(self) -> None:
|
def open_keybindings(self) -> None:
|
||||||
notebook = self.mediator.grid.notebook
|
notebook = self.mediator.grid.notebook
|
||||||
notebook.toggle_keybindings()
|
notebook.toggle_keybindings()
|
||||||
@@ -329,6 +321,7 @@ class Controller:
|
|||||||
notebook = self.mediator.grid.notebook
|
notebook = self.mediator.grid.notebook
|
||||||
notebook.focus_current()
|
notebook.focus_current()
|
||||||
|
|
||||||
|
# TODO: deprecated
|
||||||
def spawn_dialog(self, msg: str, mode: Popup) -> bool:
|
def spawn_dialog(self, msg: str, mode: Popup) -> bool:
|
||||||
"""
|
"""
|
||||||
Spawns a GenericDialog transient to the OuterWindow
|
Spawns a GenericDialog transient to the OuterWindow
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
- Bold labels inside frames
|
- Bold labels inside frames
|
||||||
|
- Unsticky keys when clicking sidebar
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
|
|||||||
+2
-6
@@ -3,14 +3,13 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from dzgui.api.mods import remove_stale_signatures
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from dzgui.api.mods import remove_stale_signatures
|
||||||
from dzgui.config.ipdb import get_ipdb
|
from dzgui.config.ipdb import get_ipdb
|
||||||
from dzgui.config.userprefs import UserPrefs
|
from dzgui.config.userprefs import UserPrefs
|
||||||
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
|
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
|
||||||
|
|
||||||
from dzgui.const.update import ALLOW_UPDATES
|
from dzgui.const.update import ALLOW_UPDATES
|
||||||
|
|
||||||
from dzgui.init.coords import get_local_coords
|
from dzgui.init.coords import get_local_coords
|
||||||
from dzgui.init.dayz import is_dayz_installed
|
from dzgui.init.dayz import is_dayz_installed
|
||||||
from dzgui.init.flock import lock_acquire
|
from dzgui.init.flock import lock_acquire
|
||||||
@@ -42,8 +41,6 @@ parser.add_argument("-u", "--uninstall", action="store_true", help=flags.uninsta
|
|||||||
parser.add_argument("-d", "--developers", action="store_true", help=flags.developers)
|
parser.add_argument("-d", "--developers", action="store_true", help=flags.developers)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -110,7 +107,6 @@ def main() -> None:
|
|||||||
# TODO: move into module
|
# TODO: move into module
|
||||||
if has_steam_client() is False:
|
if has_steam_client() is False:
|
||||||
EarlyAlertDialog(init.requires_steam)
|
EarlyAlertDialog(init.requires_steam)
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
is_dayz_installed(XDG.config)
|
is_dayz_installed(XDG.config)
|
||||||
is_dayz_running()
|
is_dayz_running()
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def get_time() -> int:
|
|
||||||
return int(datetime.now().timestamp())
|
|
||||||
|
|
||||||
# TODO: deprecated
|
|
||||||
#def write_time(path: Path) -> None:
|
|
||||||
# time = get_time()
|
|
||||||
# Path.write_text(str(time))
|
|
||||||
|
|
||||||
def is_elapsed(time_before: int) -> bool:
|
|
||||||
time_now = get_time()
|
|
||||||
if time_now - time_before <= 30:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
+18
-5
@@ -86,9 +86,10 @@ scan_servers = "Scan LAN servers"
|
|||||||
select_port = "Select the query port"
|
select_port = "Select the query port"
|
||||||
|
|
||||||
# Errors
|
# Errors
|
||||||
|
error_heading = "Error"
|
||||||
config_not_found = "DZGUI configuration file not found. Please exit and restart."
|
config_not_found = "DZGUI configuration file not found. Please exit and restart."
|
||||||
cannot_acquire_lock = "DZGUI is already open."
|
cannot_acquire_lock = "DZGUI is already open."
|
||||||
something_wrong = "Something went wrong."
|
something_wrong = "Something went wrong. See the detailed error below."
|
||||||
steam_key_missing = "No Steam API key is set."
|
steam_key_missing = "No Steam API key is set."
|
||||||
malformed_mods = "Found mods on system, but was unable to parse results."
|
malformed_mods = "Found mods on system, but was unable to parse results."
|
||||||
steam_missing = "Local Steam installation is not set, possibly malformed config file."
|
steam_missing = "Local Steam installation is not set, possibly malformed config file."
|
||||||
@@ -154,8 +155,6 @@ label_main_menu = "Main menu"
|
|||||||
# buttons
|
# buttons
|
||||||
ping_servers = "Ping servers"
|
ping_servers = "Ping servers"
|
||||||
debug_mode = "Debug mode"
|
debug_mode = "Debug mode"
|
||||||
keys_button = "Keys"
|
|
||||||
keys_tooltip = "Toggles the keybindings dialog"
|
|
||||||
debug_tooltip = (
|
debug_tooltip = (
|
||||||
"Used to perform a dry run without\n"
|
"Used to perform a dry run without\n"
|
||||||
"actually connecting to a server"
|
"actually connecting to a server"
|
||||||
@@ -539,6 +538,20 @@ connect_panel = ConnectPanel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
distance_suffix = "Distance: calculating..."
|
distance_suffix = "Distance: calculating..."
|
||||||
|
dialog_error = "ERROR"
|
||||||
|
|
||||||
refresh = "Refresh"
|
@dataclass(slots=True, frozen=True)
|
||||||
refresh_tooltip = "Refresh server data"
|
class AtomicButton:
|
||||||
|
refresh: str
|
||||||
|
refresh_tooltip: str
|
||||||
|
copy: str
|
||||||
|
keys: str
|
||||||
|
keys_tooltip: str
|
||||||
|
|
||||||
|
atomic_buttons = AtomicButton(
|
||||||
|
refresh="Refresh",
|
||||||
|
refresh_tooltip="Refresh server data",
|
||||||
|
copy="Copy",
|
||||||
|
keys="Keys",
|
||||||
|
keys_tooltip="Toggles the keybindings dialog",
|
||||||
|
)
|
||||||
+5
-1
@@ -8,7 +8,6 @@ import signal
|
|||||||
import subprocess
|
import subprocess
|
||||||
import textwrap
|
import textwrap
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
|
||||||
import typing # noqa
|
import typing # noqa
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
@@ -466,3 +465,8 @@ class App(Gtk.Application):
|
|||||||
self.win.halt_proc_and_quit()
|
self.win.halt_proc_and_quit()
|
||||||
|
|
||||||
MainController = Controller()
|
MainController = Controller()
|
||||||
|
|
||||||
|
# TODO: icon sanity check, log result
|
||||||
|
#theme = Gtk.IconTheme.get_default()
|
||||||
|
#icons = theme.list_icons(None)
|
||||||
|
#print("steam_tray_mono" in icons)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Callable, Self, TYPE_CHECKING
|
from typing import Self, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.util.strings import refresh, connect_panel
|
from dzgui.util.strings import atomic_buttons, connect_panel
|
||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
CLIPBOARD,
|
CLIPBOARD,
|
||||||
INPUT_KEYBOARD,
|
INPUT_KEYBOARD,
|
||||||
@@ -47,6 +47,8 @@ class IconTextButton(IconButton):
|
|||||||
super().__init__(icon, margin=5)
|
super().__init__(icon, margin=5)
|
||||||
self.set_label(label)
|
self.set_label(label)
|
||||||
|
|
||||||
|
self.set_focus_on_click(False)
|
||||||
|
|
||||||
|
|
||||||
class LargeIconTextButton(IconButton):
|
class LargeIconTextButton(IconButton):
|
||||||
def __init__(self, icon: str, label: str) -> None:
|
def __init__(self, icon: str, label: str) -> None:
|
||||||
@@ -56,12 +58,14 @@ class LargeIconTextButton(IconButton):
|
|||||||
self.set_image(LargeIcon(icon))
|
self.set_image(LargeIcon(icon))
|
||||||
|
|
||||||
|
|
||||||
class ClipboardButton(IconButton):
|
class ClipboardButton(IconTextButton):
|
||||||
def __init__(self, controller: "Controller", data: str) -> None:
|
def __init__(self, controller: "Controller", data: str) -> None:
|
||||||
super().__init__(CLIPBOARD)
|
super().__init__(CLIPBOARD, atomic_buttons.copy)
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.connect("clicked", self._on_button_clicked, data)
|
self.connect("clicked", self._on_button_clicked, data)
|
||||||
|
|
||||||
|
self.set_tooltip_text("Copy IP to clipboard")
|
||||||
|
|
||||||
def _on_button_clicked(self, button: Self, data: str) -> None:
|
def _on_button_clicked(self, button: Self, data: str) -> None:
|
||||||
self.controller.copy_clipboard(data)
|
self.controller.copy_clipboard(data)
|
||||||
|
|
||||||
@@ -74,19 +78,21 @@ class WebButton(IconTextButton):
|
|||||||
|
|
||||||
class RefreshButton(IconTextButton):
|
class RefreshButton(IconTextButton):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__(icon=REFRESH_ICON, label=refresh)
|
super().__init__(icon=REFRESH_ICON, label=atomic_buttons.refresh)
|
||||||
self.set_margin_top(10)
|
self.set_margin_top(10)
|
||||||
self.set_margin_start(80)
|
self.set_margin_start(80)
|
||||||
self.set_margin_end(80)
|
self.set_margin_end(80)
|
||||||
|
|
||||||
|
|
||||||
class KeysButton(IconTextButton):
|
class KeysButton(IconTextButton):
|
||||||
def __init__(self, label: str) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__(icon=INPUT_KEYBOARD, label=label)
|
super().__init__(icon=INPUT_KEYBOARD, label=atomic_buttons.keys)
|
||||||
self.set_margin_top(10)
|
self.set_margin_top(10)
|
||||||
self.set_margin_start(80)
|
self.set_margin_start(80)
|
||||||
self.set_margin_end(80)
|
self.set_margin_end(80)
|
||||||
|
|
||||||
|
self.set_tooltip_text(atomic_buttons.keys_tooltip)
|
||||||
|
|
||||||
|
|
||||||
class SteamConnectButton(LargeIconTextButton):
|
class SteamConnectButton(LargeIconTextButton):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.api.servers import validate_ip
|
from dzgui.api.servers import validate_ip
|
||||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, NO_PADDING
|
|
||||||
from dzgui.util.css import add_class, remove_class
|
from dzgui.util.css import add_class, remove_class
|
||||||
from dzgui.util.strings import connect_panel
|
from dzgui.util.strings import connect_panel
|
||||||
from dzgui.views.components.buttons import AddButton, ClipboardButton, SteamConnectButton
|
from dzgui.views.components.buttons import AddButton, ClipboardButton, SteamConnectButton
|
||||||
@@ -14,6 +13,9 @@ from gi.repository import Gtk, Gdk # noqa E402
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
|
COLS = 1
|
||||||
|
ROWS = 1
|
||||||
|
|
||||||
class LanPanel(Gtk.Frame):
|
class LanPanel(Gtk.Frame):
|
||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
super().__init__(margin_top=10, margin_bottom=5)
|
super().__init__(margin_top=10, margin_bottom=5)
|
||||||
@@ -24,26 +26,24 @@ class LanPanel(Gtk.Frame):
|
|||||||
self.set_label_widget(label)
|
self.set_label_widget(label)
|
||||||
|
|
||||||
radio1 = Gtk.RadioButton.new_with_label(None, "Default port (27016)")
|
radio1 = Gtk.RadioButton.new_with_label(None, "Default port (27016)")
|
||||||
radio2 = Gtk.RadioButton.new_from_widget(radio1)
|
radio2 = Gtk.RadioButton.new_with_label_from_widget(radio1, "Custom port")
|
||||||
# TODO: new_with_label_from_widget
|
|
||||||
radio2.set_label("Custom port")
|
|
||||||
|
|
||||||
self.entry = Gtk.Entry(placeholder_text="Query port", sensitive=False)
|
self.entry = Gtk.Entry(placeholder_text="Enter the query port (1-65535)", sensitive=False, hexpand=True)
|
||||||
self.button = Gtk.Button(label="Scan")
|
self.button = Gtk.Button(label="Scan")
|
||||||
radio1.connect("toggled", self._on_radio_toggled)
|
radio1.connect("toggled", self._on_radio_toggled)
|
||||||
|
|
||||||
# TODO: use grid, more column spacing
|
self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
||||||
hbox = Gtk.Box(margin=10, spacing=5, halign=Gtk.Align.START)
|
self.grid.attach(radio1, 0, 0, COLS, ROWS)
|
||||||
hbox.pack_start(radio1, NO_EXPAND, NO_FILL, NO_PADDING)
|
# TODO: expression to attach in a line
|
||||||
hbox.pack_start(radio2, NO_EXPAND, NO_FILL, NO_PADDING)
|
self.grid.attach_next_to(radio2, radio1, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
hbox.pack_start(self.entry, NO_EXPAND, NO_FILL, NO_PADDING)
|
self.grid.attach_next_to(self.entry, radio2, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
hbox.pack_start(self.button, NO_EXPAND, NO_FILL, NO_PADDING)
|
self.grid.attach_next_to(self.button, self.entry, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
|
|
||||||
self.add(hbox)
|
self.add(self.grid)
|
||||||
|
|
||||||
def _on_radio_toggled(self, button: Gtk.RadioButton) -> None:
|
def _on_radio_toggled(self, button: Gtk.RadioButton) -> None:
|
||||||
for el in self.entry, self.button:
|
self.entry.set_sensitive(not button.get_active())
|
||||||
el.set_sensitive(not button.get_active())
|
# TODO: validate custom port entry
|
||||||
|
|
||||||
class AddPanel(Gtk.Frame):
|
class AddPanel(Gtk.Frame):
|
||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
@@ -52,14 +52,10 @@ class AddPanel(Gtk.Frame):
|
|||||||
label = BoldLabel("Connect")
|
label = BoldLabel("Connect")
|
||||||
self.set_label_widget(label)
|
self.set_label_widget(label)
|
||||||
|
|
||||||
class ConnectPanel(Gtk.Box):
|
self.add_server = AddButton()
|
||||||
def __init__(self, controller: "Controller") -> None:
|
self.conn_server = SteamConnectButton()
|
||||||
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
self.conn_server.set_sensitive(False)
|
||||||
|
self.add_server.set_sensitive(False)
|
||||||
COLS = 1
|
|
||||||
ROWS = 1
|
|
||||||
self.classname = "invalid-entry"
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
self.entry = Gtk.Entry(
|
self.entry = Gtk.Entry(
|
||||||
placeholder_text=connect_panel.placeholder,
|
placeholder_text=connect_panel.placeholder,
|
||||||
@@ -69,24 +65,6 @@ class ConnectPanel(Gtk.Box):
|
|||||||
self.entry.connect("key-press-event", self._on_entry_keypress)
|
self.entry.connect("key-press-event", self._on_entry_keypress)
|
||||||
self.entry.connect("changed", self._on_text_changed)
|
self.entry.connect("changed", self._on_text_changed)
|
||||||
|
|
||||||
user_fav, self.fav_ip = self.controller.get_favorite()
|
|
||||||
|
|
||||||
server_name = f"{user_fav} ({self.fav_ip})" if user_fav is not None else connect_panel.no_fav
|
|
||||||
self.fav_label = Gtk.Label(label=server_name, track_visited_links=False, halign=Gtk.Align.START, hexpand=True)
|
|
||||||
scrollable_label = Gtk.ScrolledWindow()
|
|
||||||
scrollable_label.add(self.fav_label)
|
|
||||||
|
|
||||||
self.fav_button = SteamConnectButton()
|
|
||||||
self.fav_edit = Gtk.Button(label=connect_panel.edit)
|
|
||||||
|
|
||||||
self.add_server = AddButton()
|
|
||||||
self.conn_server = SteamConnectButton()
|
|
||||||
|
|
||||||
self.conn_server.set_sensitive(False)
|
|
||||||
self.add_server.set_sensitive(False)
|
|
||||||
if server_name is None:
|
|
||||||
self.fav_button.set_sensitive(False)
|
|
||||||
|
|
||||||
self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
||||||
self.grid.attach(self.entry, 0, 0, COLS, ROWS)
|
self.grid.attach(self.entry, 0, 0, COLS, ROWS)
|
||||||
|
|
||||||
@@ -98,32 +76,7 @@ class ConnectPanel(Gtk.Box):
|
|||||||
for el, sibling, pos, h_span, v_span in els:
|
for el, sibling, pos, h_span, v_span in els:
|
||||||
self.grid.attach_next_to(el, sibling, pos, h_span, v_span)
|
self.grid.attach_next_to(el, sibling, pos, h_span, v_span)
|
||||||
|
|
||||||
self.lan = LanPanel(self.controller)
|
self.add(self.grid)
|
||||||
self.add(self.lan)
|
|
||||||
|
|
||||||
label = BoldLabel("Favorite server")
|
|
||||||
frame = Gtk.Frame(margin_top=10, margin_bottom=5, label_widget=label)
|
|
||||||
b = ClipboardButton(self.controller, self.get_fav_ip())
|
|
||||||
b.set_focus_on_click(False)
|
|
||||||
b.set_tooltip_text("Copy IP to clipboard")
|
|
||||||
|
|
||||||
# FIXME: height of connect buttons is not equivalent
|
|
||||||
grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
|
||||||
grid.attach(scrollable_label, 0, 0, 3, ROWS)
|
|
||||||
grid.attach_next_to(b, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS)
|
|
||||||
grid.attach_next_to(self.fav_button, b, Gtk.PositionType.RIGHT, COLS, ROWS)
|
|
||||||
frame.add(grid)
|
|
||||||
self.add(frame)
|
|
||||||
|
|
||||||
label = BoldLabel("Connect")
|
|
||||||
frame = Gtk.Frame(margin_top=10, margin_bottom=5, label_widget=label)
|
|
||||||
frame.add(self.grid)
|
|
||||||
self.add(frame)
|
|
||||||
|
|
||||||
#self.lan.set_visible(False)
|
|
||||||
|
|
||||||
def get_fav_ip(self) -> str:
|
|
||||||
return self.fav_ip
|
|
||||||
|
|
||||||
def mark_valid(self) -> None:
|
def mark_valid(self) -> None:
|
||||||
self.conn_server.set_sensitive(True)
|
self.conn_server.set_sensitive(True)
|
||||||
@@ -152,12 +105,53 @@ class ConnectPanel(Gtk.Box):
|
|||||||
else:
|
else:
|
||||||
self.mark_invalid()
|
self.mark_invalid()
|
||||||
|
|
||||||
def set_fav_label(self, text: str) -> None:
|
|
||||||
# TODO: called by controller when changing fav
|
|
||||||
self.fav_label.set_text(text)
|
|
||||||
|
|
||||||
def _on_entry_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> None:
|
def _on_entry_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> None:
|
||||||
if event.keyval == Gdk.KEY_Escape:
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
# NOTE: unselect text
|
# NOTE: unselect text
|
||||||
entry.select_region(0, 0)
|
entry.select_region(0, 0)
|
||||||
self.controller.grab_active_treeview()
|
self.controller.grab_active_treeview()
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectPanel(Gtk.Box):
|
||||||
|
def __init__(self, controller: "Controller") -> None:
|
||||||
|
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
||||||
|
|
||||||
|
self.classname = "invalid-entry"
|
||||||
|
self.controller = controller
|
||||||
|
|
||||||
|
user_fav, self.fav_ip = self.controller.get_favorite()
|
||||||
|
|
||||||
|
server_name = f"{user_fav} ({self.fav_ip})" if user_fav is not None else connect_panel.no_fav
|
||||||
|
self.fav_label = Gtk.Label(label=server_name, track_visited_links=False, halign=Gtk.Align.START, hexpand=True)
|
||||||
|
scrollable_label = Gtk.ScrolledWindow()
|
||||||
|
scrollable_label.add(self.fav_label)
|
||||||
|
|
||||||
|
self.fav_button = SteamConnectButton()
|
||||||
|
self.fav_edit = Gtk.Button(label=connect_panel.edit)
|
||||||
|
if server_name is None:
|
||||||
|
self.fav_button.set_sensitive(False)
|
||||||
|
|
||||||
|
self.lan = LanPanel(self.controller)
|
||||||
|
self.add_panel = AddPanel(self.controller)
|
||||||
|
|
||||||
|
label = BoldLabel("Favorite server")
|
||||||
|
frame = Gtk.Frame(margin_top=10, margin_bottom=5, label_widget=label)
|
||||||
|
b = ClipboardButton(self.controller, self.get_fav_ip())
|
||||||
|
|
||||||
|
# FIXME: height of connect buttons is not equivalent
|
||||||
|
grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
||||||
|
grid.attach(scrollable_label, 0, 0, 3, ROWS)
|
||||||
|
grid.attach_next_to(b, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
|
grid.attach_next_to(self.fav_button, b, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
|
frame.add(grid)
|
||||||
|
|
||||||
|
for el in self.lan, frame, self.add_panel:
|
||||||
|
self.add(el)
|
||||||
|
|
||||||
|
def get_fav_ip(self) -> str:
|
||||||
|
return self.fav_ip
|
||||||
|
|
||||||
|
def set_fav_label(self, text: str) -> None:
|
||||||
|
# TODO: called by controller when changing fav
|
||||||
|
self.fav_label.set_text(text)
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ from dzgui.views.components.filter_panel import FilterPanel
|
|||||||
from dzgui.views.components.mod_panel import ModSelectionPanel
|
from dzgui.views.components.mod_panel import ModSelectionPanel
|
||||||
from dzgui.views.components.buttons import RefreshButton, KeysButton
|
from dzgui.views.components.buttons import RefreshButton, KeysButton
|
||||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, EXPAND, FILL, INPUT_KEYBOARD, NO_PADDING
|
from dzgui.const.constants import NO_EXPAND, NO_FILL, EXPAND, FILL, INPUT_KEYBOARD, NO_PADDING
|
||||||
from dzgui.util.strings import refresh_tooltip, refresh, keys_button, keys_tooltip
|
from dzgui.util.strings import atomic_buttons
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from GLib import SOURCE_REMOVE
|
from GLib import SOURCE_REMOVE
|
||||||
@@ -31,14 +31,13 @@ class RightPanel(Gtk.Box):
|
|||||||
|
|
||||||
self.refresh_button = RefreshButton()
|
self.refresh_button = RefreshButton()
|
||||||
# TODO: consolidate into class
|
# TODO: consolidate into class
|
||||||
self.refresh_button.set_tooltip_text(refresh_tooltip)
|
#self.refresh_button.set_tooltip_text(refresh_tooltip)
|
||||||
self.refresh_button.set_focus_on_click(False)
|
self.refresh_button.set_focus_on_click(False)
|
||||||
self.refresh_button.connect("clicked", self._on_refresh_clicked)
|
self.refresh_button.connect("clicked", self._on_refresh_clicked)
|
||||||
|
|
||||||
self.keys = KeysButton(keys_button)
|
self.keys = KeysButton()
|
||||||
self.keys.set_focus_on_click(False)
|
|
||||||
self.keys.set_tooltip_text(keys_tooltip)
|
|
||||||
self.keys.connect("clicked", self._on_keys_clicked)
|
self.keys.connect("clicked", self._on_keys_clicked)
|
||||||
|
#self.keys.set_focus_on_click(False)
|
||||||
|
|
||||||
for el in self.button_vbox, self.keys, self.filters_vbox, self.refresh_button:
|
for el in self.button_vbox, self.keys, self.filters_vbox, self.refresh_button:
|
||||||
self.pack_start(el, NO_EXPAND, FILL, NO_PADDING)
|
self.pack_start(el, NO_EXPAND, FILL, NO_PADDING)
|
||||||
@@ -61,13 +60,14 @@ class RightPanel(Gtk.Box):
|
|||||||
self.refresh_button.set_label(refresh)
|
self.refresh_button.set_label(refresh)
|
||||||
self.refresh_button.set_sensitive(True)
|
self.refresh_button.set_sensitive(True)
|
||||||
return GLib.SOURCE_REMOVE
|
return GLib.SOURCE_REMOVE
|
||||||
self.refresh_button.set_label(f"{refresh} ({str(self.time)})")
|
# TODO: abstract this formatting logic
|
||||||
|
self.refresh_button.set_label(f"{atomic_buttons.refresh} ({str(self.time)})")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _on_refresh_clicked(self, button: RefreshButton) -> None:
|
def _on_refresh_clicked(self, button: RefreshButton) -> None:
|
||||||
# TODO: could be internal to refresh button class
|
# TODO: could be internal to refresh button class
|
||||||
self.refresh_button.set_sensitive(False)
|
self.refresh_button.set_sensitive(False)
|
||||||
self.refresh_button.set_label(f"{refresh} ({str(self.time)})")
|
self.refresh_button.set_label(f"{atomic_buttons.refresh} ({str(self.time)})")
|
||||||
GLib.timeout_add_seconds(1, self.decrement)
|
GLib.timeout_add_seconds(1, self.decrement)
|
||||||
self.controller.refresh_tree()
|
self.controller.refresh_tree()
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
import textwrap
|
import textwrap
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
from dzgui.util.strings import dialog_error, dialog_header
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk # noqa E402
|
from gi.repository import Gtk # noqa E402
|
||||||
|
|
||||||
class EarlyAlertDialog(Gtk.MessageDialog):
|
class EarlyAlertDialog(Gtk.MessageDialog):
|
||||||
def __init__(self, string):
|
def __init__(self, string: str) -> None:
|
||||||
# TODO: strings
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
title="DZGUI - Dialog",
|
title=dialog_header,
|
||||||
flags=0,
|
text=dialog_error,
|
||||||
text="ERROR",
|
|
||||||
transient_for=None,
|
transient_for=None,
|
||||||
buttons=Gtk.ButtonsType.OK
|
buttons=Gtk.ButtonsType.OK
|
||||||
)
|
)
|
||||||
ok = self.action_area.get_children()[0]
|
|
||||||
ok.set_label("OK")
|
|
||||||
ok.connect("clicked", Gtk.main_quit)
|
|
||||||
|
|
||||||
msg = textwrap.fill(string, 50)
|
msg = textwrap.fill(string, 50)
|
||||||
self.format_secondary_text(msg)
|
self.format_secondary_text(msg)
|
||||||
@@ -28,8 +27,10 @@ class EarlyAlertDialog(Gtk.MessageDialog):
|
|||||||
|
|
||||||
self.set_default_size(250, 100)
|
self.set_default_size(250, 100)
|
||||||
|
|
||||||
self.connect("delete-event", Gtk.main_quit)
|
self.connect("response", self._on_response)
|
||||||
self.connect("destroy", Gtk.main_quit)
|
|
||||||
|
|
||||||
self.show_all()
|
self.run()
|
||||||
Gtk.main()
|
self.destroy()
|
||||||
|
|
||||||
|
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||||
|
sys.exit(1)
|
||||||
+149
-120
@@ -4,147 +4,103 @@ from typing import Any, Literal, Self, TYPE_CHECKING
|
|||||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, EXPAND, FILL
|
from dzgui.const.constants import NO_EXPAND, NO_FILL, EXPAND, FILL
|
||||||
from dzgui.const.enum import Popup, ButtonType, NotebookPage
|
from dzgui.const.enum import Popup, ButtonType, NotebookPage
|
||||||
from dzgui.util import strings
|
from dzgui.util import strings
|
||||||
|
from dzgui.views.components.buttons import ClipboardButton
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
|
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
class ExceptionDialog(Gtk.MessageDialog):
|
# TODO: reimplement as standalone dialogs
|
||||||
def __init__(self, controller: "Controller", trace: str):
|
# NOTE: steam deck prints <2> if dialog title is same as window title
|
||||||
super().__init__(
|
# case Popup.MODLIST:
|
||||||
transient_for=controller.mediator.window,
|
# dialog_type = Gtk.MessageType.INFO
|
||||||
message_type=Gtk.MessageType.ERROR,
|
# button_type = Gtk.ButtonsType.OK
|
||||||
buttons=Gtk.ButtonsType.OK,
|
# header_text = strings.modlist
|
||||||
text="Error",
|
# case Popup.DETAILS:
|
||||||
secondary_text="Something went wrong. See the detailed error below.",
|
# dialog_type = Gtk.MessageType.INFO
|
||||||
title=strings.dialog_header,
|
# button_type = Gtk.ButtonsType.OK
|
||||||
modal=True,
|
# header_text = strings.server_details
|
||||||
)
|
# TODO: unused
|
||||||
|
# def update_label(self, text: str) -> None:
|
||||||
# TODO: strings
|
# self.format_secondary_text(text)
|
||||||
self.set_size_request(550, 250)
|
|
||||||
|
|
||||||
from dzgui.views.components.buttons import ClipboardButton
|
|
||||||
content = self.get_content_area()
|
|
||||||
content.set_spacing(0)
|
|
||||||
|
|
||||||
box = Gtk.Box(hexpand=True, vexpand=True, orientation=Gtk.Orientation.VERTICAL)
|
|
||||||
textview = Gtk.TextView(wrap_mode=Gtk.WrapMode.WORD, editable=False, left_margin=10, right_margin=10)
|
|
||||||
textview.set_buffer(Gtk.TextBuffer(text=trace))
|
|
||||||
# NOTE: box expands to end of content area
|
|
||||||
box.pack_start(textview, EXPAND, FILL, 10)
|
|
||||||
|
|
||||||
action_area = self.get_action_area()
|
|
||||||
action_area.set_spacing(10)
|
|
||||||
action_area.set_margin_bottom(10)
|
|
||||||
action_area.set_layout(Gtk.ButtonBoxStyle.CENTER)
|
|
||||||
|
|
||||||
but = ClipboardButton(controller, trace)
|
|
||||||
# TODO: flag to set button with text, or other class
|
|
||||||
but.set_label("Copy")
|
|
||||||
action_area.pack_start(but, True, True, 10)
|
|
||||||
# NOTE: reverse button order after insertion
|
|
||||||
action_area.set_direction(Gtk.TextDirection.RTL)
|
|
||||||
content.add(box)
|
|
||||||
|
|
||||||
self.set_default_response(Gtk.ResponseType.OK)
|
|
||||||
self.connect("response", self._on_response)
|
|
||||||
self.show_all()
|
|
||||||
"""
|
|
||||||
usage:
|
|
||||||
from dzgui.views.dialogs.generic import ExceptionDialog
|
|
||||||
try:
|
|
||||||
a.banana()
|
|
||||||
except Exception as e:
|
|
||||||
trace = traceback.format_exc()
|
|
||||||
dialog = ExceptionDialog(MainController, trace)
|
|
||||||
dialog.run()
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
|
||||||
self.destroy()
|
|
||||||
|
|
||||||
|
|
||||||
class GenericDialog(Gtk.MessageDialog):
|
class GenericDialog(Gtk.MessageDialog):
|
||||||
def __init__(self, controller: "Controller", text: str, mode: Popup):
|
def __init__(self,
|
||||||
match mode:
|
controller: "Controller",
|
||||||
case Popup.WAIT:
|
text: str,
|
||||||
dialog_type = Gtk.MessageType.INFO
|
mtype: Gtk.MessageType,
|
||||||
button_type = Gtk.ButtonsType.NONE
|
buttons: Gtk.ButtonsType,
|
||||||
header_text = strings.wait
|
secondary: str
|
||||||
case Popup.NOTIFY | Popup.RETURN | Popup.QUIT:
|
) -> None:
|
||||||
dialog_type = Gtk.MessageType.INFO
|
super().__init__(
|
||||||
button_type = Gtk.ButtonsType.OK
|
|
||||||
header_text = strings.notice
|
|
||||||
case Popup.CONFIRM:
|
|
||||||
dialog_type = Gtk.MessageType.QUESTION
|
|
||||||
button_type = Gtk.ButtonsType.OK_CANCEL
|
|
||||||
header_text = strings.confirmation
|
|
||||||
case Popup.ENTRY:
|
|
||||||
dialog_type = Gtk.MessageType.QUESTION
|
|
||||||
button_type = Gtk.ButtonsType.OK_CANCEL
|
|
||||||
header_text = strings.input_required
|
|
||||||
case Popup.MODLIST:
|
|
||||||
dialog_type = Gtk.MessageType.INFO
|
|
||||||
button_type = Gtk.ButtonsType.OK
|
|
||||||
header_text = strings.modlist
|
|
||||||
case Popup.DETAILS:
|
|
||||||
dialog_type = Gtk.MessageType.INFO
|
|
||||||
button_type = Gtk.ButtonsType.OK
|
|
||||||
header_text = strings.server_details
|
|
||||||
|
|
||||||
Gtk.MessageDialog.__init__(
|
|
||||||
self,
|
|
||||||
transient_for=controller.mediator.window,
|
transient_for=controller.mediator.window,
|
||||||
message_type=dialog_type,
|
message_type=mtype,
|
||||||
buttons=button_type,
|
buttons=buttons,
|
||||||
text=header_text,
|
text=text,
|
||||||
secondary_text=textwrap.fill(text, 50),
|
secondary_text=secondary,
|
||||||
# NOTE: steam deck prints <2> if dialog title is same as window title
|
|
||||||
title=strings.dialog_header,
|
title=strings.dialog_header,
|
||||||
modal=True,
|
modal=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
if mode == Popup.WAIT:
|
|
||||||
dialogBox = self.get_content_area()
|
|
||||||
spinner = Gtk.Spinner()
|
|
||||||
dialogBox.pack_end(spinner, NO_EXPAND, NO_FILL, 0)
|
|
||||||
spinner.start()
|
|
||||||
self.connect("delete-event", self._on_dialog_delete)
|
|
||||||
|
|
||||||
if mode == Popup.RETURN:
|
|
||||||
button_label = strings.main_menu
|
|
||||||
ok = self.action_area.get_children()[0]
|
|
||||||
ok.set_label(button_label)
|
|
||||||
ok.connect("clicked", self._return_to_main_menu)
|
|
||||||
self.connect("delete-event", self._return_to_main_menu)
|
|
||||||
|
|
||||||
if mode == Popup.QUIT:
|
|
||||||
button_label = strings.exit_app
|
|
||||||
ok = self.action_area.get_children()[0]
|
|
||||||
ok.set_label(button_label)
|
|
||||||
ok.connect("clicked", self._quit)
|
|
||||||
self.connect("delete-event", self._quit)
|
|
||||||
|
|
||||||
self.set_default_response(Gtk.ResponseType.OK)
|
|
||||||
self.set_size_request(500, 0)
|
self.set_size_request(500, 0)
|
||||||
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
|
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
|
||||||
|
|
||||||
|
self.set_default_response(Gtk.ResponseType.OK)
|
||||||
|
self.connect("response", self._on_response)
|
||||||
|
|
||||||
self.action_area.set_layout(Gtk.ButtonBoxStyle.CENTER)
|
self.action_area.set_layout(Gtk.ButtonBoxStyle.CENTER)
|
||||||
self.action_area.set_margin_bottom(20)
|
self.action_area.set_margin_bottom(20)
|
||||||
self.outer = self.get_content_area()
|
self.outer = self.get_content_area()
|
||||||
self.outer.set_margin_start(30)
|
self.outer.set_margin_start(30)
|
||||||
self.outer.set_margin_end(30)
|
self.outer.set_margin_end(30)
|
||||||
|
|
||||||
def _quit(self, *args: Any) -> None:
|
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||||
self.controller.save_res_and_quit()
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class ConfirmationDialog(GenericDialog):
|
||||||
|
def __init__(self, controller: "Controller", secondary: str):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=strings.confirm,
|
||||||
|
mtype=Gtk.MessageType.QUESTION,
|
||||||
|
buttons=Gtk.ButtonsType.OK_CANCEL,
|
||||||
|
secondary=secondary,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NotifyDialog(GenericDialog):
|
||||||
|
def __init__(self, controller: "Controller", secondary: str):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=strings.notice,
|
||||||
|
mtype=Gtk.MessageType.INFO,
|
||||||
|
buttons=Gtk.ButtonsType.OK,
|
||||||
|
secondary=secondary,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WaitDialog(GenericDialog):
|
||||||
|
def __init__(self, controller: "Controller", secondary: str):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=strings.wait,
|
||||||
|
mtype=Gtk.MessageType.INFO,
|
||||||
|
buttons=Gtk.ButtonsType.NONE,
|
||||||
|
secondary=secondary,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.connect("delete-event", self._on_dialog_delete)
|
||||||
|
content = self.get_content_area()
|
||||||
|
spinner = Gtk.Spinner()
|
||||||
|
content.pack_end(spinner, NO_EXPAND, NO_FILL, 0)
|
||||||
|
|
||||||
|
spinner.start()
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
def _on_dialog_delete(
|
def _on_dialog_delete(
|
||||||
self, response_id: Gtk.ResponseType, event: Gdk.Event
|
self, response_id: Gtk.ResponseType, event: Gdk.Event
|
||||||
@@ -154,8 +110,81 @@ class GenericDialog(Gtk.MessageDialog):
|
|||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _return_to_main_menu(self, widget: Gtk.Widget) -> None:
|
|
||||||
self.controller.open_page(NotebookPage.MAIN)
|
|
||||||
|
|
||||||
def update_label(self, text: str) -> None:
|
class QuitDialog(GenericDialog):
|
||||||
self.format_secondary_text(text)
|
def __init__(self, controller: "Controller", secondary: str):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=strings.wait,
|
||||||
|
mtype=Gtk.MessageType.INFO,
|
||||||
|
buttons=Gtk.ButtonsType.NONE,
|
||||||
|
secondary=secondary,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.controller = controller
|
||||||
|
self.add_button(strings.exit_app, Gtk.ResponseType.OK)
|
||||||
|
|
||||||
|
self.connect("response", self._on_response)
|
||||||
|
self.connect("delete-event", self._on_response)
|
||||||
|
|
||||||
|
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||||
|
self.controller.save_res_and_quit()
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionDialog(GenericDialog):
|
||||||
|
"""
|
||||||
|
Error dialog with rich traceback.
|
||||||
|
Usage:
|
||||||
|
try:
|
||||||
|
foo()
|
||||||
|
except Exception:
|
||||||
|
trace = traceback.format_exc()
|
||||||
|
dialog = ExceptionDialog(Controller, trace)
|
||||||
|
dialog.run()
|
||||||
|
"""
|
||||||
|
def __init__(self, controller: "Controller", trace: str):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=strings.error_heading,
|
||||||
|
mtype=Gtk.MessageType.ERROR,
|
||||||
|
buttons=Gtk.ButtonsType.NONE,
|
||||||
|
secondary=strings.something_wrong,
|
||||||
|
)
|
||||||
|
|
||||||
|
# NOTE: box expands to end of content area
|
||||||
|
scrollable = Gtk.ScrolledWindow(
|
||||||
|
propagate_natural_height=True,
|
||||||
|
max_content_height=500
|
||||||
|
)
|
||||||
|
box = Gtk.Box(hexpand=True, vexpand=True, orientation=Gtk.Orientation.VERTICAL)
|
||||||
|
textview = Gtk.TextView(
|
||||||
|
wrap_mode=Gtk.WrapMode.WORD,
|
||||||
|
editable=False,
|
||||||
|
left_margin=10,
|
||||||
|
right_margin=10
|
||||||
|
)
|
||||||
|
textview.set_buffer(Gtk.TextBuffer(text=trace))
|
||||||
|
box.pack_start(textview, EXPAND, FILL, 10)
|
||||||
|
scrollable.add(box)
|
||||||
|
|
||||||
|
content = self.get_content_area()
|
||||||
|
content.set_spacing(0)
|
||||||
|
# FIXME: padding around top of content area when traceback is long
|
||||||
|
content.add(scrollable)
|
||||||
|
|
||||||
|
copy_button = ClipboardButton(controller, trace)
|
||||||
|
self.add_action_widget(copy_button, Gtk.ResponseType.NONE)
|
||||||
|
self.add_button("OK", Gtk.ResponseType.OK)
|
||||||
|
action_area = self.get_action_area()
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
self.connect("response", self._on_response)
|
||||||
|
|
||||||
|
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||||
|
match response:
|
||||||
|
case Gtk.ResponseType.OK:
|
||||||
|
self.destroy()
|
||||||
|
case Gtk.ResponseType.NONE:
|
||||||
|
return True # type: ignore
|
||||||
|
case Gtk.ResponseType.DELETE_EVENT:
|
||||||
|
self.destroy()
|
||||||
@@ -424,7 +424,6 @@ class Options(Gtk.Box):
|
|||||||
return box
|
return box
|
||||||
|
|
||||||
def populate_settings(self) -> None:
|
def populate_settings(self) -> None:
|
||||||
# TODO: controller.get_config()
|
|
||||||
prefs = self.controller.get_prefs()
|
prefs = self.controller.get_prefs()
|
||||||
if prefs.paths.config.is_file() is False:
|
if prefs.paths.config.is_file() is False:
|
||||||
# NOTE: in case file got deleted locally
|
# NOTE: in case file got deleted locally
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import pytest
|
|
||||||
import time
|
|
||||||
|
|
||||||
from dzgui.util import cooldown
|
|
||||||
|
|
||||||
|
|
||||||
def test_time_under():
|
|
||||||
time_before = cooldown.get_time()
|
|
||||||
time.sleep(1)
|
|
||||||
result = cooldown.is_elapsed(time_before)
|
|
||||||
assert result is False
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.slow
|
|
||||||
def test_time_over():
|
|
||||||
time_before = cooldown.get_time()
|
|
||||||
time.sleep(31)
|
|
||||||
result = cooldown.is_elapsed(time_before)
|
|
||||||
assert result is True
|
|
||||||
Reference in new issue
Block a user