mirror of
https://github.com/aclist/dztui.git
synced 2026-10-30 14:42:54 +01:00
feat: ExceptionDialog WIP
This commit is contained in:
1 parent
59ef15073f
commit
45bd0e16ec
7 files changed
+122
-31
No files matched your search
+11
-2
@@ -15,12 +15,21 @@
|
|||||||
- Developers page (and -d flag)
|
- Developers page (and -d flag)
|
||||||
- Redact API key in log table
|
- Redact API key in log table
|
||||||
- Integrate add/connect widgets into main menu
|
- Integrate add/connect widgets into main menu
|
||||||
|
- Favorite/connect/LAN panels integrated with server views
|
||||||
|
- Colorized IP/ID validation
|
||||||
|
- Visual icons
|
||||||
|
- Integrated server notebook
|
||||||
|
- Retain position on servers
|
||||||
|
- Propagate width changes to all tables
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Add icon to keys button
|
|
||||||
- Add icons to API buttons
|
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
|
- Bold labels inside frames
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
|
- Copy favorite server IP to clipboard
|
||||||
|
- Set favorite server from tables
|
||||||
|
- Detailed/copyable trace in critical error dialogs
|
||||||
|
- Local documentation
|
||||||
+11
-2
@@ -15,12 +15,21 @@
|
|||||||
- Developers page (and -d flag)
|
- Developers page (and -d flag)
|
||||||
- Redact API key in log table
|
- Redact API key in log table
|
||||||
- Integrate add/connect widgets into main menu
|
- Integrate add/connect widgets into main menu
|
||||||
|
- Favorite/connect/LAN panels integrated with server views
|
||||||
|
- Colorized IP/ID validation
|
||||||
|
- Visual icons
|
||||||
|
- Integrated server notebook
|
||||||
|
- Retain position on servers
|
||||||
|
- Propagate width changes to all tables
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Add icon to keys button
|
|
||||||
- Add icons to API buttons
|
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
|
- Bold labels inside frames
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
|
- Copy favorite server IP to clipboard
|
||||||
|
- Set favorite server from tables
|
||||||
|
- Detailed/copyable trace in critical error dialogs
|
||||||
|
- Local documentation
|
||||||
@@ -8,6 +8,7 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import Callable, Self, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.util.strings import refresh, connect_panel
|
from dzgui.util.strings import refresh, connect_panel
|
||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
CLIPBOARD,
|
CLIPBOARD,
|
||||||
@@ -12,6 +14,9 @@ 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
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
|
|
||||||
class Icon(Gtk.Image):
|
class Icon(Gtk.Image):
|
||||||
def __init__(self, name: str, l_margin=0) -> None:
|
def __init__(self, name: str, l_margin=0) -> None:
|
||||||
@@ -52,8 +57,13 @@ class LargeIconTextButton(IconButton):
|
|||||||
|
|
||||||
|
|
||||||
class ClipboardButton(IconButton):
|
class ClipboardButton(IconButton):
|
||||||
def __init__(self) -> None:
|
def __init__(self, controller: "Controller", data: str) -> None:
|
||||||
super().__init__(CLIPBOARD)
|
super().__init__(CLIPBOARD)
|
||||||
|
self.controller = controller
|
||||||
|
self.connect("clicked", self._on_button_clicked, data)
|
||||||
|
|
||||||
|
def _on_button_clicked(self, button: Self, data: str) -> None:
|
||||||
|
self.controller.copy_clipboard(data)
|
||||||
|
|
||||||
|
|
||||||
class WebButton(IconTextButton):
|
class WebButton(IconTextButton):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from dzgui.api.servers import validate_ip
|
|||||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, NO_PADDING
|
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, IconTextButton, SteamConnectButton, WebButton
|
from dzgui.views.components.buttons import AddButton, ClipboardButton, SteamConnectButton
|
||||||
from dzgui.views.components.labels import BoldLabel
|
from dzgui.views.components.labels import BoldLabel
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@@ -18,31 +18,40 @@ 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)
|
||||||
|
|
||||||
# TODO: use grid, more column spacing
|
|
||||||
# TODO: hide lan panel on other tabs
|
# TODO: hide lan panel on other tabs
|
||||||
hbox = Gtk.Box(margin=10, spacing=5, halign=Gtk.Align.START)
|
|
||||||
# TODO: strings
|
# TODO: strings
|
||||||
label = BoldLabel("LAN query port")
|
label = BoldLabel("LAN query port")
|
||||||
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_from_widget(radio1)
|
||||||
|
# TODO: new_with_label_from_widget
|
||||||
radio2.set_label("Custom port")
|
radio2.set_label("Custom port")
|
||||||
self.entry = Gtk.Entry(placeholder_text="Query port")
|
|
||||||
|
self.entry = Gtk.Entry(placeholder_text="Query port", sensitive=False)
|
||||||
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)
|
||||||
#hbox.pack_start(label, NO_EXPAND, NO_FILL, NO_PADDING)
|
|
||||||
|
# TODO: use grid, more column spacing
|
||||||
|
hbox = Gtk.Box(margin=10, spacing=5, halign=Gtk.Align.START)
|
||||||
hbox.pack_start(radio1, NO_EXPAND, NO_FILL, NO_PADDING)
|
hbox.pack_start(radio1, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
hbox.pack_start(radio2, NO_EXPAND, NO_FILL, NO_PADDING)
|
hbox.pack_start(radio2, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
hbox.pack_start(self.entry, NO_EXPAND, NO_FILL, NO_PADDING)
|
hbox.pack_start(self.entry, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
hbox.pack_start(self.button, NO_EXPAND, NO_FILL, NO_PADDING)
|
hbox.pack_start(self.button, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
self.entry.set_sensitive(False)
|
|
||||||
self.button.set_sensitive(False)
|
|
||||||
self.add(hbox)
|
self.add(hbox)
|
||||||
|
|
||||||
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:
|
for el in self.entry, self.button:
|
||||||
el.set_sensitive(not button.get_active())
|
el.set_sensitive(not button.get_active())
|
||||||
|
|
||||||
|
class AddPanel(Gtk.Frame):
|
||||||
|
def __init__(self, controller: "Controller") -> None:
|
||||||
|
super().__init__(margin_top=10, margin_bottom=5)
|
||||||
|
|
||||||
|
label = BoldLabel("Connect")
|
||||||
|
self.set_label_widget(label)
|
||||||
|
|
||||||
class ConnectPanel(Gtk.Box):
|
class ConnectPanel(Gtk.Box):
|
||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
||||||
@@ -60,9 +69,9 @@ 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, user_ip = self.controller.get_favorite()
|
user_fav, self.fav_ip = self.controller.get_favorite()
|
||||||
|
|
||||||
server_name = f"{user_fav} ({user_ip})" if user_fav is not None else connect_panel.no_fav
|
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)
|
self.fav_label = Gtk.Label(label=server_name, track_visited_links=False, halign=Gtk.Align.START, hexpand=True)
|
||||||
scrollable_label = Gtk.ScrolledWindow()
|
scrollable_label = Gtk.ScrolledWindow()
|
||||||
scrollable_label.add(self.fav_label)
|
scrollable_label.add(self.fav_label)
|
||||||
@@ -78,18 +87,10 @@ class ConnectPanel(Gtk.Box):
|
|||||||
if server_name is None:
|
if server_name is None:
|
||||||
self.fav_button.set_sensitive(False)
|
self.fav_button.set_sensitive(False)
|
||||||
|
|
||||||
add_label = BoldLabel(connect_panel.add_con)
|
|
||||||
conn_label = BoldLabel(connect_panel.favorite)
|
|
||||||
|
|
||||||
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(conn_label, 0, 0, COLS, ROWS)
|
|
||||||
self.grid.attach(self.entry, 0, 0, COLS, ROWS)
|
self.grid.attach(self.entry, 0, 0, COLS, ROWS)
|
||||||
|
|
||||||
els = (
|
els = (
|
||||||
#(scrollable_label, conn_label, Gtk.PositionType.RIGHT, 3, ROWS),
|
|
||||||
#(self.fav_button, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS),
|
|
||||||
#(add_label, conn_label, Gtk.PositionType.BOTTOM, COLS, ROWS),
|
|
||||||
#(self.entry, scrollable_label, Gtk.PositionType.BOTTOM, COLS, ROWS),
|
|
||||||
(self.add_server, self.entry, Gtk.PositionType.RIGHT, COLS, ROWS),
|
(self.add_server, self.entry, Gtk.PositionType.RIGHT, COLS, ROWS),
|
||||||
(self.conn_server, self.add_server, Gtk.PositionType.RIGHT, COLS, ROWS),
|
(self.conn_server, self.add_server, Gtk.PositionType.RIGHT, COLS, ROWS),
|
||||||
)
|
)
|
||||||
@@ -102,9 +103,11 @@ class ConnectPanel(Gtk.Box):
|
|||||||
|
|
||||||
label = BoldLabel("Favorite server")
|
label = BoldLabel("Favorite server")
|
||||||
frame = Gtk.Frame(margin_top=10, margin_bottom=5, label_widget=label)
|
frame = Gtk.Frame(margin_top=10, margin_bottom=5, label_widget=label)
|
||||||
b = ClipboardButton()
|
b = ClipboardButton(self.controller, self.get_fav_ip())
|
||||||
|
b.set_focus_on_click(False)
|
||||||
b.set_tooltip_text("Copy IP to clipboard")
|
b.set_tooltip_text("Copy IP to clipboard")
|
||||||
b.connect("clicked", self._on_ip_clicked, user_ip)
|
|
||||||
|
# FIXME: height of connect buttons is not equivalent
|
||||||
grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
||||||
grid.attach(scrollable_label, 0, 0, 3, ROWS)
|
grid.attach(scrollable_label, 0, 0, 3, ROWS)
|
||||||
grid.attach_next_to(b, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS)
|
grid.attach_next_to(b, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||||
@@ -117,10 +120,10 @@ class ConnectPanel(Gtk.Box):
|
|||||||
frame.add(self.grid)
|
frame.add(self.grid)
|
||||||
self.add(frame)
|
self.add(frame)
|
||||||
|
|
||||||
self.lan.set_visible(False)
|
#self.lan.set_visible(False)
|
||||||
|
|
||||||
def _on_ip_clicked(self, button: Gtk.Button, ip: str) -> None:
|
def get_fav_ip(self) -> str:
|
||||||
self.controller.copy_clipboard(ip)
|
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)
|
||||||
@@ -151,7 +154,6 @@ class ConnectPanel(Gtk.Box):
|
|||||||
|
|
||||||
def set_fav_label(self, text: str) -> None:
|
def set_fav_label(self, text: str) -> None:
|
||||||
# TODO: called by controller when changing fav
|
# TODO: called by controller when changing fav
|
||||||
# TODO: href logic
|
|
||||||
self.fav_label.set_text(text)
|
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:
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ class RightPanel(Gtk.Box):
|
|||||||
self.sel_panel = ModSelectionPanel(controller)
|
self.sel_panel = ModSelectionPanel(controller)
|
||||||
|
|
||||||
self.refresh_button = RefreshButton()
|
self.refresh_button = RefreshButton()
|
||||||
|
# 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.connect("clicked", self._on_refresh_clicked)
|
self.refresh_button.connect("clicked", self._on_refresh_clicked)
|
||||||
|
|
||||||
self.keys = KeysButton(keys_button)
|
self.keys = KeysButton(keys_button)
|
||||||
@@ -63,6 +65,7 @@ class RightPanel(Gtk.Box):
|
|||||||
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
|
||||||
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"{refresh} ({str(self.time)})")
|
||||||
GLib.timeout_add_seconds(1, self.decrement)
|
GLib.timeout_add_seconds(1, self.decrement)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import textwrap
|
import textwrap
|
||||||
from typing import Any, Literal, TYPE_CHECKING
|
from typing import Any, Literal, Self, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.const.constants import NO_EXPAND, NO_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
|
||||||
|
|
||||||
@@ -13,6 +13,63 @@ 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):
|
||||||
|
def __init__(self, controller: "Controller", trace: str):
|
||||||
|
super().__init__(
|
||||||
|
transient_for=controller.mediator.window,
|
||||||
|
message_type=Gtk.MessageType.ERROR,
|
||||||
|
buttons=Gtk.ButtonsType.OK,
|
||||||
|
text="Error",
|
||||||
|
secondary_text="Something went wrong. See the detailed error below.",
|
||||||
|
title=strings.dialog_header,
|
||||||
|
modal=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: strings
|
||||||
|
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, controller: "Controller", text: str, mode: Popup):
|
||||||
match mode:
|
match mode:
|
||||||
@@ -41,7 +98,6 @@ class GenericDialog(Gtk.MessageDialog):
|
|||||||
button_type = Gtk.ButtonsType.OK
|
button_type = Gtk.ButtonsType.OK
|
||||||
header_text = strings.server_details
|
header_text = strings.server_details
|
||||||
|
|
||||||
# NOTE: steam deck prints <2> if dialog title is same as window title
|
|
||||||
Gtk.MessageDialog.__init__(
|
Gtk.MessageDialog.__init__(
|
||||||
self,
|
self,
|
||||||
transient_for=controller.mediator.window,
|
transient_for=controller.mediator.window,
|
||||||
@@ -49,6 +105,7 @@ class GenericDialog(Gtk.MessageDialog):
|
|||||||
buttons=button_type,
|
buttons=button_type,
|
||||||
text=header_text,
|
text=header_text,
|
||||||
secondary_text=textwrap.fill(text, 50),
|
secondary_text=textwrap.fill(text, 50),
|
||||||
|
# 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,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user