* feat: macro prompts close #1216 now the user can have confirmation on macros using this feature close #835 * prompt: remove separator and remove the header and close button if windowed * prompt: wakeup screen * prompt: slightly larger close icon
This commit is contained in:
parent
25ab9c962d
commit
1794d8aa24
@ -218,21 +218,30 @@ class KlippyGtk:
|
||||
if not self.screen.windowed:
|
||||
dialog.fullscreen()
|
||||
|
||||
max_buttons = 3 if self.screen.vertical_mode else 4
|
||||
if len(buttons) > max_buttons:
|
||||
buttons = buttons[:max_buttons]
|
||||
button_hsize = max(len(buttons), 3)
|
||||
for button in buttons:
|
||||
if 'style' in button:
|
||||
style = button['style']
|
||||
else:
|
||||
style = 'dialog-default'
|
||||
dialog.add_button(button['name'], button['response'])
|
||||
button = dialog.get_widget_for_response(button['response'])
|
||||
button.set_size_request((self.width - 30) / 3, self.height / 5)
|
||||
format_label(button, 3)
|
||||
button.set_size_request((self.width - 58) / button_hsize, self.height / 5)
|
||||
button.get_style_context().add_class(style)
|
||||
format_label(button, 2)
|
||||
|
||||
dialog.connect("response", self.screen.reset_screensaver_timeout)
|
||||
dialog.connect("response", callback, *args)
|
||||
dialog.get_style_context().add_class("dialog")
|
||||
|
||||
content_area = dialog.get_content_area()
|
||||
content_area.set_margin_start(15)
|
||||
content_area.set_margin_end(15)
|
||||
content_area.set_margin_top(15)
|
||||
content_area.set_margin_bottom(15)
|
||||
content_area.set_margin_start(5)
|
||||
content_area.set_margin_end(5)
|
||||
content_area.set_margin_top(5)
|
||||
content_area.set_margin_bottom(0)
|
||||
content.set_valign(Gtk.Align.CENTER)
|
||||
content_area.add(content)
|
||||
|
||||
|
106
ks_includes/widgets/prompts.py
Normal file
106
ks_includes/widgets/prompts.py
Normal file
@ -0,0 +1,106 @@
|
||||
import logging
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class Prompt:
|
||||
def __init__(self, screen):
|
||||
self.screen = screen
|
||||
self.gtk = screen.gtk
|
||||
self.window_title = 'KlipperScreen'
|
||||
self.text = self.header = ""
|
||||
self.buttons = []
|
||||
self.id = 1
|
||||
self.prompt = None
|
||||
|
||||
def decode(self, data):
|
||||
logging.info(f'{data}')
|
||||
if data.startswith('prompt_begin'):
|
||||
# action:prompt_begin <headline>
|
||||
self.header = data.replace('prompt_begin', '')
|
||||
if self.header:
|
||||
self.window_title = self.header
|
||||
self.text = ""
|
||||
self.buttons = []
|
||||
return
|
||||
elif data.startswith('prompt_text'):
|
||||
# action:prompt_text <text>
|
||||
self.text = data.replace('prompt_text ', '')
|
||||
return
|
||||
elif data.startswith('prompt_button ') or data.startswith('prompt_footer_button'):
|
||||
# action:prompt_button <label>|<gcode?>|<color?>
|
||||
# <label>: text of the button
|
||||
# <gcode?>: optional G-Code (Default is the label text)
|
||||
# <color?>: optional secondary, info, warning, error
|
||||
data = data.replace('prompt_button ', '')
|
||||
data = data.replace('prompt_footer_button ', '')
|
||||
params = data.split('|')
|
||||
if len(params) == 1:
|
||||
params.append(self.text)
|
||||
if len(params) > 3:
|
||||
logging.error('Unexpected number of parameters on the button')
|
||||
return
|
||||
self.set_button(*params)
|
||||
return
|
||||
elif data == 'prompt_show':
|
||||
self.show()
|
||||
return
|
||||
elif data == 'prompt_end':
|
||||
self.end()
|
||||
else:
|
||||
# Not implemented:
|
||||
# prompt_button_group_start
|
||||
# prompt_button_group_end
|
||||
logging.debug(f'Unknown option {data}')
|
||||
|
||||
def set_button(self, name, gcode, style='default'):
|
||||
logging.info(f'{name} {self.id} {gcode} {style}')
|
||||
self.buttons.append(
|
||||
{"name": name, "response": self.id, 'gcode': gcode, 'style': f'dialog-{style}'}
|
||||
)
|
||||
self.id += 1
|
||||
|
||||
def show(self):
|
||||
logging.info(f'Prompt {self.header} {self.text} {self.buttons}')
|
||||
|
||||
title = Gtk.Label(wrap=True, hexpand=True, vexpand=False, halign=Gtk.Align.CENTER, label=self.header)
|
||||
|
||||
close = self.gtk.Button("cancel", scale=self.gtk.bsidescale)
|
||||
close.set_hexpand(False)
|
||||
close.connect("clicked", self.end)
|
||||
|
||||
scroll = self.gtk.ScrolledWindow(steppers=False)
|
||||
scroll.set_vexpand(True)
|
||||
if self.screen.vertical_mode:
|
||||
scroll.set_size_request(self.gtk.width - 30, self.gtk.height * .6)
|
||||
else:
|
||||
scroll.set_size_request(self.gtk.width - 30, self.gtk.height * .4)
|
||||
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||
scroll.add(Gtk.Label(label=self.text, wrap=True, vexpand=True))
|
||||
|
||||
content = Gtk.Grid()
|
||||
if not self.screen.windowed:
|
||||
content.attach(title, 0, 0, 1, 1)
|
||||
content.attach(close, 1, 0, 1, 1)
|
||||
content.attach(scroll, 0, 1, 2, 1)
|
||||
|
||||
self.prompt = self.gtk.Dialog(
|
||||
self.window_title,
|
||||
self.buttons,
|
||||
content,
|
||||
self.response,
|
||||
)
|
||||
|
||||
def response(self, dialog, response_id):
|
||||
for button in self.buttons:
|
||||
if button['response'] == response_id:
|
||||
self.screen._send_action(None, "printer.gcode.script", {'script': button['gcode']})
|
||||
self.end()
|
||||
|
||||
def end(self, *args):
|
||||
if self.prompt is not None:
|
||||
self.gtk.remove_dialog(self.prompt)
|
||||
self.prompt = None
|
||||
self.screen.prompt = None
|
@ -309,7 +309,7 @@ class BasePanel(ScreenPanel):
|
||||
def show_update_dialog(self):
|
||||
if self.update_dialog is not None:
|
||||
return
|
||||
button = [{"name": _("Finish"), "response": Gtk.ResponseType.OK}]
|
||||
button = [{"name": _("Finish"), "response": Gtk.ResponseType.OK, "style": 'dialog-default'}]
|
||||
self.labels['update_progress'] = Gtk.Label()
|
||||
self.labels['update_progress'].set_halign(Gtk.Align.START)
|
||||
self.labels['update_progress'].set_valign(Gtk.Align.START)
|
||||
|
@ -402,8 +402,8 @@ class Panel(ScreenPanel):
|
||||
grid = self._gtk.HomogeneousGrid()
|
||||
grid.attach(label, 0, 0, 1, 1)
|
||||
buttons = [
|
||||
{"name": _("Apply"), "response": Gtk.ResponseType.APPLY},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Apply"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-default'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
self._gtk.Dialog(_("Save Z"), buttons, grid, self.save_confirm, device)
|
||||
|
||||
@ -438,8 +438,8 @@ class Panel(ScreenPanel):
|
||||
|
||||
def cancel(self, widget):
|
||||
buttons = [
|
||||
{"name": _("Cancel Print"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Cancel Print"), "response": Gtk.ResponseType.OK, "style": 'dialog-error'},
|
||||
{"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-info'}
|
||||
]
|
||||
if len(self._printer.get_stat("exclude_object", "objects")) > 1:
|
||||
buttons.insert(0, {"name": _("Exclude Object"), "response": Gtk.ResponseType.APPLY})
|
||||
|
@ -300,7 +300,7 @@ class Panel(ScreenPanel):
|
||||
|
||||
buttons = [
|
||||
{"name": _("Print"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
|
||||
label = Gtk.Label()
|
||||
|
@ -141,9 +141,9 @@ class Panel(ScreenPanel):
|
||||
vbox.add(label)
|
||||
scroll.add(vbox)
|
||||
recoverybuttons = [
|
||||
{"name": _("Recover Hard"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Recover Soft"), "response": Gtk.ResponseType.APPLY},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Recover Hard"), "response": Gtk.ResponseType.OK, "style": 'dialog-warning'},
|
||||
{"name": _("Recover Soft"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-info'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
self._gtk.Dialog(_("Recover"), recoverybuttons, scroll, self.reset_confirm, program)
|
||||
return
|
||||
@ -206,8 +206,8 @@ class Panel(ScreenPanel):
|
||||
scroll.add(vbox)
|
||||
|
||||
buttons = [
|
||||
{"name": _("Update"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Update"), "response": Gtk.ResponseType.OK, "style": 'dialog-info'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
self._gtk.Dialog(_("Update"), buttons, scroll, self.update_confirm, program)
|
||||
|
||||
@ -321,9 +321,9 @@ class Panel(ScreenPanel):
|
||||
vbox.add(label)
|
||||
scroll.add(vbox)
|
||||
buttons = [
|
||||
{"name": _("Host"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Printer"), "response": Gtk.ResponseType.APPLY},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Host"), "response": Gtk.ResponseType.OK, "style": 'dialog-info'},
|
||||
{"name": _("Printer"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-warning'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
if method == "reboot":
|
||||
title = _("Restart")
|
||||
|
13
screen.py
13
screen.py
@ -25,6 +25,7 @@ from ks_includes.files import KlippyFiles
|
||||
from ks_includes.KlippyGtk import KlippyGtk
|
||||
from ks_includes.printer import Printer
|
||||
from ks_includes.widgets.keyboard import Keyboard
|
||||
from ks_includes.widgets.prompts import Prompt
|
||||
from ks_includes.config import KlipperScreenConfig
|
||||
from panels.base_panel import BasePanel
|
||||
|
||||
@ -95,6 +96,7 @@ class KlipperScreen(Gtk.Window):
|
||||
wayland = False
|
||||
windowed = False
|
||||
notification_log = []
|
||||
prompt = None
|
||||
|
||||
def __init__(self, args):
|
||||
try:
|
||||
@ -769,7 +771,12 @@ class KlipperScreen(Gtk.Window):
|
||||
self.panels['splash_screen'].check_power_status()
|
||||
elif action == "notify_gcode_response" and self.printer.state not in ["error", "shutdown"]:
|
||||
if not (data.startswith("B:") or data.startswith("T:")):
|
||||
if data.startswith("echo: "):
|
||||
if data.startswith("// action:"):
|
||||
self.wake_screen()
|
||||
if self.prompt is None:
|
||||
self.prompt = Prompt(self)
|
||||
self.prompt.decode(data[10:])
|
||||
elif data.startswith("echo: "):
|
||||
self.show_popup_message(data[6:], 1)
|
||||
elif data.startswith("!! "):
|
||||
self.show_popup_message(data[3:], 3)
|
||||
@ -793,8 +800,8 @@ class KlipperScreen(Gtk.Window):
|
||||
|
||||
def _confirm_send_action(self, widget, text, method, params=None):
|
||||
buttons = [
|
||||
{"name": _("Accept"), "response": Gtk.ResponseType.OK},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
|
||||
{"name": _("Accept"), "response": Gtk.ResponseType.OK, "style": 'dialog-info'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
]
|
||||
|
||||
try:
|
||||
|
@ -292,18 +292,9 @@ trough {
|
||||
|
||||
.dialog button {
|
||||
padding: 1.5em;
|
||||
border-bottom: .4em solid @color3;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
border-bottom-color: @echo;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.distbutton_active {
|
||||
background-color: @active;
|
||||
font-weight: 600;
|
||||
@ -630,3 +621,28 @@ trough progress {
|
||||
}
|
||||
|
||||
.graph_label {border-left-width: .4em; border-left-style: solid;}
|
||||
|
||||
.dialog-error {
|
||||
border-bottom: .4em solid @error;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
border-bottom: .4em solid @warning;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
border-bottom: .4em solid @color4;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
border-bottom: .4em solid @color3;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
border-bottom: .4em solid @color2;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
border-bottom: .4em solid @color1;
|
||||
}
|
||||
|
||||
|
@ -176,17 +176,9 @@ textview .time {
|
||||
|
||||
.dialog button {
|
||||
background-color: @solarized-base02;
|
||||
border-bottom-color: @solarized-cyan;
|
||||
border-radius: .75em;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
border-bottom-color: @solarized-green;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
border-bottom-color: @solarized-red;
|
||||
}
|
||||
.tempbutton_top,
|
||||
.tempbutton,
|
||||
.tempbutton_bottom,
|
||||
@ -267,3 +259,27 @@ textview .time {
|
||||
.keyboard_pad {
|
||||
background-color: @solarized-base02;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
border-bottom-color: @solarized-red;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
border-bottom-color: @olarized-yellow;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
border-bottom-color: @solarized-cyan;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
border-bottom-color: @solarized-green;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
border-bottom-color: @solarized-magenta;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
border-bottom-color: @solarized-orange;
|
||||
}
|
@ -159,18 +159,9 @@ textview .time {
|
||||
|
||||
.dialog button {
|
||||
background-color: @buttons-bg;
|
||||
border-bottom-color: @active-dark;
|
||||
border-radius: .75em;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.tempbutton_top,
|
||||
.tempbutton,
|
||||
.tempbutton_bottom,
|
||||
@ -243,3 +234,27 @@ button.active {
|
||||
.keyboard_pad {
|
||||
background-color: @buttons-bg;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
border-bottom-color: @warning;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
border-bottom-color: @color4;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
border-bottom-color: @color2;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
border-bottom-color: @color1;
|
||||
}
|
@ -153,18 +153,9 @@ textview .time {
|
||||
|
||||
.dialog button {
|
||||
background-color: #252525;
|
||||
border-bottom-color: #252525;
|
||||
border-radius: .25em;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
border-bottom-color: #2f5631;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
border-bottom-color: #B71C1C;
|
||||
}
|
||||
|
||||
.tempbutton_top,
|
||||
.tempbutton,
|
||||
.tempbutton_bottom,
|
||||
@ -242,3 +233,27 @@ textview .time {
|
||||
.keyboard_pad {
|
||||
background-color: #090909;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
border-bottom-color: #CF6679;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
border-bottom-color: #f9b274;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
border-bottom-color: @color4;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
border-bottom-color: @color2;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
border-bottom-color: @color1;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
@define-color error #EF9A9A;
|
||||
@define-color echo #a1ef9a;
|
||||
@define-color popup #006064;
|
||||
@define-color dialog #80CBC4;
|
||||
@define-color textview #212121;
|
||||
|
||||
* {
|
||||
@ -206,27 +205,6 @@ textview .time {
|
||||
background-color: @bg;
|
||||
}
|
||||
|
||||
.dialog button {
|
||||
background-color: @dialog;
|
||||
border-bottom-color: @dialog;
|
||||
border-radius: .75em;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
background-color: @color3;
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
background-color: @error;
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) label ,
|
||||
.dialog button:nth-child(2) label {
|
||||
color: @text;
|
||||
}
|
||||
|
||||
.tempbutton_top,
|
||||
.tempbutton,
|
||||
.tempbutton_bottom,
|
||||
@ -307,3 +285,37 @@ textview .time {
|
||||
.keyboard_pad {
|
||||
background-color: @border;
|
||||
}
|
||||
|
||||
.dialog button {
|
||||
border-radius: .75em;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
background-color: @error;
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
background-color: @warning;
|
||||
border-bottom-color: @warning;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
background-color: @color4;
|
||||
border-bottom-color: @color4;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
background-color: @color3;
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
background-color: @color2;
|
||||
border-bottom-color: @color2;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
background-color: @color1;
|
||||
border-bottom-color: @color1;
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
@define-color bg #13181C;
|
||||
@define-color active #324A5E;
|
||||
@define-color error #981E1F;
|
||||
@define-color warning #f9a825;
|
||||
@define-color text white;
|
||||
@define-color text-inv black;
|
||||
@define-color lines #cccccc;
|
||||
@ -135,18 +136,6 @@ textview .time {
|
||||
background-color: @bg;
|
||||
}
|
||||
|
||||
.dialog button {
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(1) {
|
||||
border-bottom-color: @color4;
|
||||
}
|
||||
|
||||
.dialog button:nth-child(2) {
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.distbutton_active {
|
||||
background-color: @active;
|
||||
border-color: @color1;
|
||||
@ -203,3 +192,27 @@ textview .time {
|
||||
.keyboard_pad {
|
||||
background-color: @bg;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
border-bottom-color: @error;
|
||||
}
|
||||
|
||||
.dialog-warning {
|
||||
border-bottom-color: @warning;
|
||||
}
|
||||
|
||||
.dialog-info {
|
||||
border-bottom-color: @color4;
|
||||
}
|
||||
|
||||
.dialog-default {
|
||||
border-bottom-color: @color3;
|
||||
}
|
||||
|
||||
.dialog-secondary {
|
||||
border-bottom-color: @color2;
|
||||
}
|
||||
|
||||
.dialog-primary {
|
||||
border-bottom-color: @color1;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user