mirror of
https://github.com/aclist/dztui.git
synced 2026-10-31 23:22:44 +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
+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.enum import Popup, ButtonType, NotebookPage
|
||||
from dzgui.util import strings
|
||||
from dzgui.views.components.buttons import ClipboardButton
|
||||
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
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()
|
||||
# TODO: reimplement as standalone dialogs
|
||||
# NOTE: steam deck prints <2> if dialog title is same as window title
|
||||
# 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
|
||||
# TODO: unused
|
||||
# def update_label(self, text: str) -> None:
|
||||
# self.format_secondary_text(text)
|
||||
|
||||
|
||||
class GenericDialog(Gtk.MessageDialog):
|
||||
def __init__(self, controller: "Controller", text: str, mode: Popup):
|
||||
match mode:
|
||||
case Popup.WAIT:
|
||||
dialog_type = Gtk.MessageType.INFO
|
||||
button_type = Gtk.ButtonsType.NONE
|
||||
header_text = strings.wait
|
||||
case Popup.NOTIFY | Popup.RETURN | Popup.QUIT:
|
||||
dialog_type = Gtk.MessageType.INFO
|
||||
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,
|
||||
def __init__(self,
|
||||
controller: "Controller",
|
||||
text: str,
|
||||
mtype: Gtk.MessageType,
|
||||
buttons: Gtk.ButtonsType,
|
||||
secondary: str
|
||||
) -> None:
|
||||
super().__init__(
|
||||
transient_for=controller.mediator.window,
|
||||
message_type=dialog_type,
|
||||
buttons=button_type,
|
||||
text=header_text,
|
||||
secondary_text=textwrap.fill(text, 50),
|
||||
# NOTE: steam deck prints <2> if dialog title is same as window title
|
||||
message_type=mtype,
|
||||
buttons=buttons,
|
||||
text=text,
|
||||
secondary_text=secondary,
|
||||
title=strings.dialog_header,
|
||||
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_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_margin_bottom(20)
|
||||
self.outer = self.get_content_area()
|
||||
self.outer.set_margin_start(30)
|
||||
self.outer.set_margin_end(30)
|
||||
|
||||
def _quit(self, *args: Any) -> None:
|
||||
self.controller.save_res_and_quit()
|
||||
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||
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(
|
||||
self, response_id: Gtk.ResponseType, event: Gdk.Event
|
||||
@@ -154,8 +110,81 @@ class GenericDialog(Gtk.MessageDialog):
|
||||
"""
|
||||
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:
|
||||
self.format_secondary_text(text)
|
||||
class QuitDialog(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.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()
|
||||
Reference in new issue
Block a user