Skip to content

Commit 6c7afd5

Browse files
Make temp menu actually good
1 parent 27e8bf1 commit 6c7afd5

6 files changed

Lines changed: 180 additions & 59 deletions

File tree

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use moonraker_rs::{
88
cache::Cache, connector::{read_deserialize::OptionalPrinterEvent}, printer_objects::{NamedOptionalTemperatureFan, OptionalExtruder, OptionalHeaterBed, OptionalTemperatureFan, TemperatureConfiguration},
99
};
1010

11-
use crate::{config::{MoonrakerConfig, OptionalGcodeCommands}, event_loop::EventLoop, hardware::init_display, ui_functions::{register_extruder_extrude, register_extruder_load_filament, register_extruder_retract, register_extruder_unload_filament, register_filesystem_download_thumbnails, register_filesystem_list_files, register_printer_emergency_stop, register_printer_firmware_restart, register_printer_restart, register_temperature_set_new_target_temperature, register_util_format_bytes, register_util_image_exists, register_util_prettify_name}};
11+
use crate::{config::{MoonrakerConfig, OptionalGcodeCommands}, event_loop::EventLoop, hardware::init_display, ui_functions::*};
1212

1313
mod application_error;
1414
mod config;
@@ -88,6 +88,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
8888
register_util_image_exists(&ui);
8989
register_util_format_bytes(&ui);
9090
register_util_prettify_name(&ui);
91+
register_create_temperature_lists(&ui);
92+
register_convert_temperature_back(&ui);
9193

9294
register_printer_emergency_stop(&ui, &moonraker_connection);
9395
register_printer_firmware_restart(&ui, &moonraker_connection);

src/ui_functions/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod printer_emergency_stop;
88
pub mod printer_restart;
99
pub mod printer_firmware_restart;
1010
pub mod printer_execute_gcode_command;
11+
pub mod util_create_temperature_list;
1112

1213
pub use util_format_bytes::*;
1314
pub use filesystem_download_thumbnail::*;
@@ -18,4 +19,5 @@ pub use temperature_set_new_target_temperature::*;
1819
pub use printer_emergency_stop::*;
1920
pub use printer_restart::*;
2021
pub use printer_firmware_restart::*;
21-
pub use printer_execute_gcode_command::*;
22+
pub use printer_execute_gcode_command::*;
23+
pub use util_create_temperature_list::*;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel};
2+
3+
use crate::{AppWindow, Utils};
4+
5+
pub fn register_create_temperature_lists(ui : &AppWindow)
6+
{
7+
ui.global::<Utils>().on_create_temperature_lists(|presets| {
8+
let presets = presets.as_any().downcast_ref::<VecModel<i32>>().unwrap();
9+
let presets: Vec<i32> = presets.iter().collect();
10+
11+
let mut list: Vec<SharedString> = Vec::new();
12+
list.push(SharedString::from("Off"));
13+
for preset in presets {
14+
list.push(SharedString::from(format!("{}°C", preset)));
15+
}
16+
17+
list.push(SharedString::from("Set"));
18+
19+
ModelRc::new(VecModel::from(list))
20+
});
21+
}
22+
23+
pub fn register_convert_temperature_back(ui : &AppWindow)
24+
{
25+
ui.global::<Utils>().on_convert_temperature_back(|f| {
26+
let s = f.trim_end_matches("°C");
27+
match s.parse::<i32>() {
28+
Ok(v) => v,
29+
Err(_) => 0,
30+
}
31+
});
32+
}

ui/main.slint

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,6 @@ component MainView inherits Rectangle
159159
}
160160

161161
export component AppWindow inherits Window {
162-
width: 480px;
163-
height: 272px;
164-
165162
default-font-family: "Adwaita Sans";
166163

167164
if Webhooks.moonraker_connected && Webhooks.klipper_state == "Ready" : MainView {

ui/pages/temperature-page.slint

Lines changed: 140 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,25 @@ import { SmallButton } from "../components/small-button.slint";
33
import { TemperatureSensors, Utils, GcodeCommands } from "../state.slint";
44
import { TemperatureSensor } from "../types.slint";
55
import { Page } from "../components/page.slint";
6-
import { ScrollView, Palette } from "std-widgets.slint";
6+
import { ScrollView, Palette, ComboBox, StyleMetrics, Button, GroupBox, CheckBox } from "std-widgets.slint";
77
import { TemperatureEntry } from "../components/number-pad.slint";
88
import { Icons } from "../constants.slint";
99

1010
export component InteractableTemperatureElement {
1111
in property <Heater> heater;
1212
property <int> target: heater.target;
13-
property <string> friendly_name: Utils.prettify_name(heater.name);
14-
in property <bool> hide_temp_control: false;
13+
property <string> friendly-name: Utils.prettify_name(heater.name);
14+
in property <string> extra-text: "";
1515

1616
changed heater => {
1717
target = heater.target;
1818
}
1919

20-
callback on_manual_entry(internal_name: string, friendly_name: string);
20+
callback on_manual_entry(internal-name: string, friendly-name: string);
2121

2222
VerticalLayout {
2323
spacing: 10px;
24+
padding-top: 10px;
2425
HorizontalLayout {
2526
height: 30px;
2627
spacing: 10px;
@@ -34,47 +35,68 @@ export component InteractableTemperatureElement {
3435
: Icons.fan;
3536
}
3637

37-
Text {
38-
text: friendly_name;
39-
horizontal-stretch: 1;
40-
vertical-alignment: center;
41-
overflow: elide;
42-
}
38+
VerticalLayout {
39+
spacing: 2px;
40+
Text {
41+
text: friendly-name;
42+
horizontal-stretch: 1;
43+
vertical-alignment: center;
44+
overflow: elide;
45+
}
4346

44-
Text {
45-
text: target > 0
46-
? heater.temperature + "°C -> " + target + "°C"
47-
: heater.temperature + "°C";
48-
vertical-alignment: center;
49-
font-weight: 900;
47+
if extra-text != "": Text {
48+
text: extra-text;
49+
horizontal-stretch: 1;
50+
vertical-alignment: center;
51+
overflow: elide;
52+
font-size: 10px;
53+
}
5054
}
51-
}
5255

53-
@children
5456

55-
if !hide_temp_control: HorizontalLayout {
56-
spacing: 10px;
57-
height: 30px;
58-
SmallButton {
59-
text: "Off";
60-
clicked => {
61-
TemperatureSensors.set_new_target_temperature(heater.name, 0);
62-
}
63-
}
64-
for preset in heater.presets : SmallButton {
65-
text: preset + "°C";
66-
clicked => {
67-
TemperatureSensors.set_new_target_temperature(heater.name, preset);
68-
}
69-
}
70-
SmallButton {
71-
text: "Set";
72-
clicked => {
73-
on_manual_entry(heater.name, friendly_name);
57+
Rectangle {
58+
// TODO: Don't abuse combobox for this.
59+
ComboBox {
60+
model: Utils.create_temperature_lists(heater.presets);
61+
width: 90%;
62+
63+
selected(value) => {
64+
if value == "Off" {
65+
TemperatureSensors.set_new_target_temperature(heater.name, 0);
66+
}
67+
else if value == "Set" {
68+
on_manual_entry(heater.name, friendly-name);
69+
}
70+
else {
71+
TemperatureSensors.set_new_target_temperature(heater.name, Utils.convert_temperature_back(value));
72+
}
73+
}
74+
}
75+
76+
Rectangle {
77+
background: Palette.background;
78+
border-color: Palette.accent-background;
79+
border-width: 2px;
80+
border-radius: StyleMetrics.layout-padding / 2;
81+
82+
GridLayout {
83+
padding-left: StyleMetrics.layout-padding;
84+
padding-right: StyleMetrics.layout-padding;
85+
Text {
86+
text: target > 0
87+
? heater.temperature + "°C -> " + target + "°C"
88+
: heater.temperature + "°C";
89+
vertical-alignment: center;
90+
horizontal-alignment: right;
91+
font-weight: 900;
92+
}
93+
}
7494
}
7595
}
7696
}
7797

98+
@children
99+
78100
Rectangle { height: 1px; background: Palette.border; horizontal-stretch: 1; }
79101
}
80102
}
@@ -84,8 +106,10 @@ component ReadOnlyTemperatureElement
84106
in property <TemperatureSensor> temperature_sensor;
85107

86108
VerticalLayout {
109+
spacing: 10px;
110+
padding-top: 10px;
87111
HorizontalLayout {
88-
height: 40px;
112+
height: 30px;
89113
spacing: 10px;
90114

91115
Image {
@@ -110,43 +134,97 @@ component ReadOnlyTemperatureElement
110134
}
111135
}
112136

137+
export component FilamentMenuDialog inherits Rectangle {
138+
callback close();
139+
callback on_manual_entry(internal-name : string, friendly-name : string); // TODO: Make the temp numpad a popup
140+
141+
VerticalLayout {
142+
spacing: 10px;
143+
144+
SmallButton {
145+
height: 3rem;
146+
icon: Icons.close;
147+
text: "Back";
148+
clicked => { root.close(); }
149+
}
150+
151+
InteractableTemperatureElement {
152+
heater: TemperatureSensors.extruder;
153+
on_manual_entry(internal-name, friendly-name) => { root.on_manual_entry(internal-name, friendly-name); }
154+
}
155+
156+
157+
HorizontalLayout {
158+
spacing: StyleMetrics.layout-spacing;
159+
if GcodeCommands.extruder_retract_available || GcodeCommands.extruder_extrude_available: VerticalLayout {
160+
spacing: StyleMetrics.layout-spacing;
161+
if GcodeCommands.extruder_retract_available: SmallButton {
162+
icon: Icons.eject;
163+
text: "Retract";
164+
clicked => { GcodeCommands.extruder_retract(); }
165+
}
166+
if GcodeCommands.extruder_extrude_available: SmallButton {
167+
icon: Icons.arrow-down;
168+
text: "Extrude";
169+
clicked => { GcodeCommands.extruder_extrude(); }
170+
}
171+
}
172+
173+
if GcodeCommands.extruder_unload_filament_available || GcodeCommands.extruder_load_filament_available: VerticalLayout {
174+
spacing: StyleMetrics.layout-spacing;
175+
if GcodeCommands.extruder_unload_filament_available: SmallButton {
176+
text: "Unload filament";
177+
clicked => { GcodeCommands.extruder_unload_filament(); }
178+
}
179+
if GcodeCommands.extruder_load_filament_available: SmallButton {
180+
text: "Load filament";
181+
clicked => { GcodeCommands.extruder_load_filament(); }
182+
}
183+
}
184+
}
185+
}
186+
}
187+
113188
export component TemperaturePage inherits Page {
114189
header: "Temperature";
115190

191+
property <bool> is_filament_menu_open: false;
116192
property <int> selection : 0;
117193

118194
ScrollView {
119195
VerticalLayout {
120196
InteractableTemperatureElement {
121197
heater: TemperatureSensors.extruder;
122198
on_manual_entry(internal-name, friendly-name) => { t.open_keyboard(internal-name, friendly-name); }
123-
hide_temp_control: selection != 0;
199+
200+
SmallButton {
201+
height: 30px;
202+
text: "Filament options";
203+
clicked => { is_filament_menu_open = true; }
204+
}
124205

125206
// TODO: Split off into component
126207
// TODO: Find a better way to do those checks
208+
/*
127209
HorizontalLayout {
128-
height: 30px;
129-
SmallButton {
130-
border-radius: 0;
131-
background: selection == 0 ? Palette.control-background : transparent;
132-
text: "Temperature";
133-
clicked => { selection = 0; }
134-
}
210+
135211
if GcodeCommands.extruder_retract_available || GcodeCommands.extruder_extrude_available: SmallButton {
212+
height: 30px;
136213
border-radius: 0;
137-
background: selection == 1 ? Palette.control-background : transparent;
214+
background: selection == 0 ? Palette.control-background : transparent;
138215
text: "Extrude/Retract";
139-
clicked => { selection = 1; }
216+
clicked => { selection = 0; }
140217
}
141218
if GcodeCommands.extruder_unload_filament_available || GcodeCommands.extruder_load_filament_available: SmallButton {
219+
height: 30px;
142220
border-radius: 0;
143-
background: selection == 2 ? Palette.control-background : transparent;
221+
background: selection == 1 ? Palette.control-background : transparent;
144222
text: "Load/Unload";
145-
clicked => { selection = 2; }
223+
clicked => { selection = 1; }
146224
}
147225
}
148226
149-
if selection == 1: HorizontalLayout {
227+
if selection == 0: HorizontalLayout {
150228
height: 30px;
151229
spacing: 10px;
152230
if GcodeCommands.extruder_retract_available: SmallButton {
@@ -161,7 +239,7 @@ export component TemperaturePage inherits Page {
161239
}
162240
}
163241
164-
if selection == 2: HorizontalLayout {
242+
if selection == 1: HorizontalLayout {
165243
height: 30px;
166244
spacing: 10px;
167245
if GcodeCommands.extruder_unload_filament_available: SmallButton {
@@ -173,13 +251,21 @@ export component TemperaturePage inherits Page {
173251
clicked => { GcodeCommands.extruder_load_filament(); }
174252
}
175253
}
254+
*/
176255
}
177256

178257
if TemperatureSensors.heated_bed.name != "": InteractableTemperatureElement { heater: TemperatureSensors.heated_bed; on_manual_entry(internal-name, friendly-name) => { t.open_keyboard(internal-name, friendly-name); }}
179-
for temp_fan in TemperatureSensors.heater_fans: InteractableTemperatureElement { heater: temp_fan.heater;on_manual_entry(internal-name, friendly-name) => { t.open_keyboard(internal-name, friendly-name); } }
180-
for temp_sensor in TemperatureSensors.temperature_sensors: ReadOnlyTemperatureElement { temperature_sensor: temp_sensor; }
258+
for temp-fan in TemperatureSensors.heater_fans: InteractableTemperatureElement { heater: temp-fan.heater; extra-text: temp-fan.speed * 100 + "%"; on_manual_entry(internal-name, friendly-name) => { t.open_keyboard(internal-name, friendly-name); } }
259+
for temp-sensor in TemperatureSensors.temperature_sensors: ReadOnlyTemperatureElement { temperature_sensor: temp-sensor; }
181260
}
182261

262+
visible: !t.is_keyboard_open && !is_filament_menu_open;
263+
}
264+
265+
if is_filament_menu_open: FilamentMenuDialog {
266+
close => { is_filament_menu_open = false; }
267+
on_manual_entry(internal-name, friendly-name) => { t.open_keyboard(internal-name, friendly-name); }
268+
183269
visible: !t.is_keyboard_open;
184270
}
185271

ui/state.slint

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@ export global Utils
6060
pure callback image_exists(image: image) -> bool;
6161
pure callback format_bytes(size: int) -> string;
6262
pure callback prettify_name(name: string) -> string;
63+
pure callback create_temperature_lists(presets: [int]) -> [string];
64+
pure callback convert_temperature_back(preset : string) -> int;
6365
}

0 commit comments

Comments
 (0)