|
| 1 | +#!/usr/bin/python3 |
| 2 | + |
| 3 | +import sys |
| 4 | +import os |
| 5 | +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) |
| 6 | + |
| 7 | +import gi |
| 8 | +gi.require_version('Gtk', '3.0') |
| 9 | +from gi.repository import Gtk |
| 10 | + |
| 11 | +from xapp.widgets import Dialog |
| 12 | + |
| 13 | +LOREM = ( |
| 14 | + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " |
| 15 | + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, " |
| 16 | + "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo " |
| 17 | + "consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " |
| 18 | + "cillum dolore eu fugiat nulla pariatur." |
| 19 | +) |
| 20 | + |
| 21 | + |
| 22 | +class DemoWindow(Gtk.Window): |
| 23 | + |
| 24 | + def __init__(self): |
| 25 | + super().__init__(title="XApp.widgets.Dialog() Demo") |
| 26 | + self.set_default_size(600, 500) |
| 27 | + self.set_border_width(12) |
| 28 | + |
| 29 | + outer_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12) |
| 30 | + |
| 31 | + grid = Gtk.Grid(column_spacing=12, row_spacing=8) |
| 32 | + |
| 33 | + xapp_header = Gtk.Label() |
| 34 | + xapp_header.set_markup("<b>XApp</b>") |
| 35 | + grid.attach(xapp_header, 0, 0, 1, 1) |
| 36 | + |
| 37 | + gtk_header = Gtk.Label() |
| 38 | + gtk_header.set_markup("<b>Gtk</b>") |
| 39 | + grid.attach(gtk_header, 1, 0, 1, 1) |
| 40 | + |
| 41 | + rows = [ |
| 42 | + ("Info", self._xapp_info, self._gtk_info), |
| 43 | + ("Warning", self._xapp_warning, self._gtk_warning), |
| 44 | + ("Error", self._xapp_error, self._gtk_error), |
| 45 | + ("Question", self._xapp_question, self._gtk_question), |
| 46 | + ("Custom", self._xapp_custom, self._gtk_custom), |
| 47 | + ("No title", self._xapp_no_title, self._gtk_no_title), |
| 48 | + ("Large text", self._xapp_large_text, self._gtk_large_text), |
| 49 | + ("Hint", self._xapp_hint, self._gtk_hint), |
| 50 | + ("Dialog no icon", self._xapp_dialog_no_icon, self._gtk_dialog_no_icon), |
| 51 | + ("Dialog icon", self._xapp_dialog_icon, self._gtk_dialog_icon), |
| 52 | + ("Widget", self._xapp_widget, self._gtk_widget), |
| 53 | + ] |
| 54 | + |
| 55 | + for row, (label, xapp_cb, gtk_cb) in enumerate(rows, start=1): |
| 56 | + xapp_btn = Gtk.Button(label=f"Show {label} dialog") |
| 57 | + xapp_btn.connect("clicked", xapp_cb) |
| 58 | + grid.attach(xapp_btn, 0, row, 1, 1) |
| 59 | + |
| 60 | + gtk_btn = Gtk.Button(label=f"Show {label} dialog") |
| 61 | + gtk_btn.connect("clicked", gtk_cb) |
| 62 | + grid.attach(gtk_btn, 1, row, 1, 1) |
| 63 | + |
| 64 | + outer_box.pack_start(grid, True, True, 0) |
| 65 | + |
| 66 | + self.result_label = Gtk.Label(label="Click a button to show a dialog.") |
| 67 | + outer_box.pack_start(self.result_label, False, False, 0) |
| 68 | + |
| 69 | + self.add(outer_box) |
| 70 | + self.connect("destroy", Gtk.main_quit) |
| 71 | + self.show_all() |
| 72 | + |
| 73 | + def _set_result(self, text): |
| 74 | + self.result_label.set_markup(f"<b>Result:</b> {text}") |
| 75 | + |
| 76 | + # XApp variants |
| 77 | + |
| 78 | + def _xapp_info(self, button): |
| 79 | + Dialog(self, "All done", "The operation completed successfully.").info() |
| 80 | + self._set_result("Info dialog closed") |
| 81 | + |
| 82 | + def _xapp_warning(self, button): |
| 83 | + Dialog(self, "Disk space low", "You have less than 500 MB remaining.").warning() |
| 84 | + self._set_result("Warning dialog closed") |
| 85 | + |
| 86 | + def _xapp_error(self, button): |
| 87 | + Dialog(self, "Could not save file", "Permission denied: /etc/hosts").error() |
| 88 | + self._set_result("Error dialog closed") |
| 89 | + |
| 90 | + def _xapp_question(self, button): |
| 91 | + confirmed = Dialog(self, "Delete item?", "This action cannot be undone.").question() |
| 92 | + self._set_result(f"Question answered: {'Yes' if confirmed else 'No'}") |
| 93 | + |
| 94 | + def _xapp_custom(self, button): |
| 95 | + dialog = Dialog(self, "Apply changes?", "Your settings will be saved and the service restarted.") |
| 96 | + dialog.add_button("Save", 1, "suggested-action") |
| 97 | + dialog.add_button("Discard", 2, "destructive-action") |
| 98 | + dialog.add_button("Cancel", 3) |
| 99 | + dialog.set_default_response(2) |
| 100 | + response = dialog.warning() |
| 101 | + self._set_result(f"Custom dialog response: {response}") |
| 102 | + |
| 103 | + def _xapp_no_title(self, button): |
| 104 | + Dialog(self, message="This dialog has no title.").info() |
| 105 | + self._set_result("No-title dialog closed") |
| 106 | + |
| 107 | + def _xapp_large_text(self, button): |
| 108 | + Dialog(self, "Lorem Ipsum", LOREM).info() |
| 109 | + self._set_result("Large text dialog closed") |
| 110 | + |
| 111 | + def _xapp_hint(self, button): |
| 112 | + Dialog(self, "Reset settings?", |
| 113 | + "All preferences will be restored to their defaults.", |
| 114 | + hint="This only affects the current user and can be undone by restoring a backup.").warning() |
| 115 | + self._set_result("Hint dialog closed") |
| 116 | + |
| 117 | + def _xapp_dialog_no_icon(self, button): |
| 118 | + Dialog(self, "Heads up", "This is a plain dialog with no icon.").dialog() |
| 119 | + self._set_result("Dialog (no icon) closed") |
| 120 | + |
| 121 | + def _xapp_dialog_icon(self, button): |
| 122 | + Dialog(self, "Bluetooth", "A new device has been paired.").dialog("bluetooth-symbolic") |
| 123 | + self._set_result("Dialog (icon) closed") |
| 124 | + |
| 125 | + def _xapp_widget(self, button): |
| 126 | + combo = Gtk.ComboBoxText() |
| 127 | + for opt in ("Option A", "Option B", "Option C"): |
| 128 | + combo.append_text(opt) |
| 129 | + combo.set_active(0) |
| 130 | + check = Gtk.CheckButton(label="Enable feature") |
| 131 | + dialog = Dialog(self, "Settings", "Configure the following options:") |
| 132 | + dialog.add_widget(combo) |
| 133 | + dialog.add_widget(check) |
| 134 | + response = dialog.info() |
| 135 | + if response == Gtk.ResponseType.OK: |
| 136 | + self._set_result(f"Widget dialog: {combo.get_active_text()!r}, enabled={check.get_active()}") |
| 137 | + else: |
| 138 | + self._set_result("Widget dialog cancelled") |
| 139 | + |
| 140 | + # Gtk variants |
| 141 | + |
| 142 | + def _gtk_info(self, button): |
| 143 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 144 | + message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, |
| 145 | + text="All done") |
| 146 | + dialog.format_secondary_text("The operation completed successfully.") |
| 147 | + dialog.run() |
| 148 | + dialog.destroy() |
| 149 | + self._set_result("Info dialog closed") |
| 150 | + |
| 151 | + def _gtk_warning(self, button): |
| 152 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 153 | + message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, |
| 154 | + text="Disk space low") |
| 155 | + dialog.format_secondary_text("You have less than 500 MB remaining.") |
| 156 | + dialog.run() |
| 157 | + dialog.destroy() |
| 158 | + self._set_result("Warning dialog closed") |
| 159 | + |
| 160 | + def _gtk_error(self, button): |
| 161 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 162 | + message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, |
| 163 | + text="Could not save file") |
| 164 | + dialog.format_secondary_text("Permission denied: /etc/hosts") |
| 165 | + dialog.run() |
| 166 | + dialog.destroy() |
| 167 | + self._set_result("Error dialog closed") |
| 168 | + |
| 169 | + def _gtk_question(self, button): |
| 170 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 171 | + message_type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.YES_NO, |
| 172 | + text="Delete item?") |
| 173 | + dialog.format_secondary_text("This action cannot be undone.") |
| 174 | + response = dialog.run() |
| 175 | + dialog.destroy() |
| 176 | + confirmed = response == Gtk.ResponseType.YES |
| 177 | + self._set_result(f"Question answered: {'Yes' if confirmed else 'No'}") |
| 178 | + |
| 179 | + def _gtk_custom(self, button): |
| 180 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 181 | + message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.NONE, |
| 182 | + text="Apply changes?") |
| 183 | + dialog.format_secondary_text("Your settings will be saved and the service restarted.") |
| 184 | + dialog.add_button("Save", 1) |
| 185 | + dialog.add_button("Discard", 2) |
| 186 | + dialog.add_button("Cancel", 3) |
| 187 | + dialog.get_widget_for_response(1).get_style_context().add_class("suggested-action") |
| 188 | + dialog.get_widget_for_response(2).get_style_context().add_class("destructive-action") |
| 189 | + response = dialog.run() |
| 190 | + dialog.destroy() |
| 191 | + self._set_result(f"Custom dialog response: {response}") |
| 192 | + |
| 193 | + def _gtk_no_title(self, button): |
| 194 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 195 | + message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK) |
| 196 | + dialog.format_secondary_text("This dialog has no title.") |
| 197 | + dialog.run() |
| 198 | + dialog.destroy() |
| 199 | + self._set_result("No-title dialog closed") |
| 200 | + |
| 201 | + def _gtk_large_text(self, button): |
| 202 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 203 | + message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, |
| 204 | + text="Lorem Ipsum") |
| 205 | + dialog.format_secondary_text(LOREM) |
| 206 | + dialog.run() |
| 207 | + dialog.destroy() |
| 208 | + self._set_result("Large text dialog closed") |
| 209 | + |
| 210 | + def _gtk_hint(self, button): |
| 211 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 212 | + message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK, |
| 213 | + text="Reset settings?") |
| 214 | + dialog.format_secondary_text("All preferences will be restored to their defaults.") |
| 215 | + hint_label = Gtk.Label() |
| 216 | + hint_label.set_markup('<small><i>This only affects the current user and can be undone by restoring a backup.</i></small>') |
| 217 | + hint_label.set_xalign(0) |
| 218 | + hint_label.set_line_wrap(True) |
| 219 | + dialog.get_message_area().pack_start(hint_label, False, False, 0) |
| 220 | + hint_label.show() |
| 221 | + dialog.run() |
| 222 | + dialog.destroy() |
| 223 | + self._set_result("Hint dialog closed") |
| 224 | + |
| 225 | + def _gtk_dialog_no_icon(self, button): |
| 226 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 227 | + message_type=Gtk.MessageType.OTHER, buttons=Gtk.ButtonsType.OK, |
| 228 | + text="Heads up") |
| 229 | + dialog.format_secondary_text("This is a plain dialog with no icon.") |
| 230 | + dialog.run() |
| 231 | + dialog.destroy() |
| 232 | + self._set_result("Dialog (no icon) closed") |
| 233 | + |
| 234 | + def _gtk_dialog_icon(self, button): |
| 235 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 236 | + message_type=Gtk.MessageType.OTHER, buttons=Gtk.ButtonsType.OK, |
| 237 | + text="Bluetooth") |
| 238 | + dialog.format_secondary_text("A new device has been paired.") |
| 239 | + image = Gtk.Image.new_from_icon_name("bluetooth", Gtk.IconSize.DIALOG) |
| 240 | + dialog.set_image(image) |
| 241 | + image.show() |
| 242 | + dialog.run() |
| 243 | + dialog.destroy() |
| 244 | + self._set_result("Dialog (icon) closed") |
| 245 | + |
| 246 | + def _gtk_widget(self, button): |
| 247 | + dialog = Gtk.MessageDialog(transient_for=self, modal=True, |
| 248 | + message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, |
| 249 | + text="Settings") |
| 250 | + dialog.format_secondary_text("Configure the following options:") |
| 251 | + combo = Gtk.ComboBoxText() |
| 252 | + for opt in ("Option A", "Option B", "Option C"): |
| 253 | + combo.append_text(opt) |
| 254 | + combo.set_active(0) |
| 255 | + check = Gtk.CheckButton(label="Enable feature") |
| 256 | + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) |
| 257 | + vbox.pack_start(combo, False, False, 0) |
| 258 | + vbox.pack_start(check, False, False, 0) |
| 259 | + dialog.get_message_area().pack_start(vbox, False, False, 0) |
| 260 | + vbox.show_all() |
| 261 | + dialog.run() |
| 262 | + self._set_result(f"Widget dialog: {combo.get_active_text()!r}, enabled={check.get_active()}") |
| 263 | + dialog.destroy() |
| 264 | + |
| 265 | + |
| 266 | +if __name__ == "__main__": |
| 267 | + window = DemoWindow() |
| 268 | + Gtk.main() |
0 commit comments