Compare commits

..

9 Commits

Author SHA1 Message Date
SoftFever
2a862b5d5a Fix Linux/Wayland crash on Preview tab at startup 2026-05-20 01:52:49 +08:00
Ian Bassi
ff68a2859d Ignore Jerk values Warning if using JD (#13575)
* Ignore Jerk values if using JD

* add flavor check
2026-05-19 09:42:44 -03:00
SoftFever
46e47cec0a Fix ObjectTable crash on cell deselect after wxWidgets 3.3.2 upgrade (#13740)
GridCellSupportEditor::DoActivate dereferenced
grid->GetSelectedBlocks().begin() without checking against end(). In
wxWidgets 3.1.5 that range always contained at least one block; in 3.3.2
it is empty after the user deselects, and the dereference crashes inside
wxGridBlockCoords::GetLeftCol().

Fall back to the (row, col) that triggered activation when the selection
is empty, so the existing single-cell branch handles it. While here,
drop a dead local_table cast that was never read.
2026-05-19 18:14:33 +08:00
Ioannis Giannakas
f4a9830752 Fix reverse on even hint (#13739) 2026-05-19 10:50:26 +01:00
Brandon Wees
1f2ed70288 fix: macOS deep links after wxWidgets 3.3.2 upgrade (#13737)
Fix macOS orcaslicer:// deep links after wxWidgets 3.3.2 upgrade

Install an OrcaSlicer-owned kAEGetURL Apple Event handler from
on_init_inner(). The wxWidgets 3.3.2 handler registered in
applicationWillFinishLaunching: stopped delivering URL events to
GUI_App::MacOpenURL on macOS (#13119), so links from Printables /
Thingiverse opened a blank project instead of importing the model.

Registering our own handler late in startup is last-writer-wins on
NSAppleEventManager and routes back to the existing MacOpenURL ->
start_download path, restoring the pre-upgrade behavior without
touching wxWidgets.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 17:13:07 +08:00
Ioannis Giannakas
3370e224b2 Cooling: add per-printer non-zero fan PWM floor and fix N=0 fan ramp override (#13715)
* Cooling: add per-printer non-zero fan PWM floor and fix N=0 ramp override
* updated parameter naming
2026-05-19 09:40:53 +01:00
SoftFever
7fc1e109c5 delete misshaped profiles 2026-05-19 14:35:20 +08:00
SoftFever
374e4ad8a9 Follow up update for PR #13724: improve GC and shorten comments 2026-05-19 14:32:18 +08:00
SoftFever
d0fbda3af1 Fix Linux segfault when loading Fluidd/Mainsail printer hosts (#7210) (#13724)
* Fix Linux segfault when loading Fluidd/Mainsail printer hosts (#7210)

Co-authored-by: VittC <58783944+VittC@users.noreply.github.com>

* narrow down the changes

---------

Co-authored-by: VittC <58783944+VittC@users.noreply.github.com>
2026-05-19 14:26:34 +08:00
22 changed files with 279 additions and 346 deletions

View File

@@ -94,8 +94,8 @@ text = Switch workspaces\nYou can switch between <b>Prepare</b> and <b>Preview</
[hint:How to use keyboard shortcuts] [hint:How to use keyboard shortcuts]
text = How to use keyboard shortcuts\nDid you know that Orca Slicer offers a wide range of keyboard shortcuts and 3D scene operations? text = How to use keyboard shortcuts\nDid you know that Orca Slicer offers a wide range of keyboard shortcuts and 3D scene operations?
[hint:Reverse on odd] [hint:Reverse on even]
text = Reverse on odd\nDid you know that <b>Reverse on odd</b> feature can significantly improve the surface quality of your overhangs? text = Reverse on even\nDid you know that <b>Reverse on even</b> feature can significantly improve the surface quality of your overhangs? However, it can cause wall inconsistencies so use carefully!
[hint:Cut Tool] [hint:Cut Tool]
text = Cut Tool\nDid you know that you can cut a model at any angle and position with the cutting tool? text = Cut Tool\nDid you know that you can cut a model at any angle and position with the cutting tool?

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -1,237 +0,0 @@
{
"type": "machine",
"name": "Anet A8 Plus 0.4 nozzle",
"inherits": "",
"from": "User",
"adaptive_bed_mesh_margin": "0",
"auxiliary_fan": "0",
"bbl_use_printhost": "0",
"bed_custom_model": "",
"bed_custom_texture": "",
"bed_exclude_area": [
"0x0"
],
"bed_mesh_max": "99999,99999",
"bed_mesh_min": "-99999,-99999",
"bed_mesh_probe_distance": "50,50",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
"best_object_pos": "0.5,0.5",
"change_extrusion_role_gcode": "",
"change_filament_gcode": "M600",
"cooling_tube_length": "5",
"cooling_tube_retraction": "91.5",
"default_bed_type": "",
"default_filament_profile": [
"Anycubic Generic PLA"
],
"default_print_profile": "0.20mm Standard @Anycubic 4MaxPro2",
"deretraction_speed": [
"25"
],
"disable_m73": "0",
"emit_machine_limits_to_gcode": "1",
"enable_filament_ramming": "1",
"enable_long_retraction_when_cut": "0",
"extra_loading_move": "-2",
"extruder_clearance_height_to_lid": "140",
"extruder_clearance_height_to_rod": "36",
"extruder_clearance_radius": "65",
"extruder_colour": [
"#018001"
],
"extruder_offset": [
"0x0"
],
"fan_kickstart": "0",
"fan_speedup_overhangs": "1",
"fan_speedup_time": "0",
"gcode_flavor": "marlin",
"head_wrap_detect_zone": [],
"high_current_on_filament_swap": "0",
"host_type": "octoprint",
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
"long_retractions_when_cut": [
"0"
],
"machine_end_gcode": "M104 S0 ; turn off extruder heating\nM140 S0 ; turn off bed heating\nM107 ; turn off fans\nG91 ; relative positioning\nG0 Z+0.5 ; move Z up a tiny bit\nG90 ; absolute positioning\nG0 X135 Y105 F{machine_max_speed_x[0]*60} ; move extruder to center position\nG0 Z190.5 F{machine_max_speed_z[0]*60} ; lower the plattform to Z min\nM84 ; steppers off\nG90 ; absolute positioning\n",
"machine_load_filament_time": "0",
"machine_max_acceleration_e": [
"5000",
"5000"
],
"machine_max_acceleration_extruding": [
"1250",
"1250"
],
"machine_max_acceleration_retracting": [
"1250",
"1250"
],
"machine_max_acceleration_travel": [
"1500",
"1500"
],
"machine_max_acceleration_x": [
"1000",
"900"
],
"machine_max_acceleration_y": [
"1000",
"900"
],
"machine_max_acceleration_z": [
"1000",
"100"
],
"machine_max_jerk_e": [
"5",
"5"
],
"machine_max_jerk_x": [
"6",
"6"
],
"machine_max_jerk_y": [
"6",
"6"
],
"machine_max_jerk_z": [
"0.2",
"0.2"
],
"machine_max_junction_deviation": [
"0.10",
"0"
],
"machine_max_speed_e": [
"120",
"120"
],
"machine_max_speed_x": [
"200",
"200"
],
"machine_max_speed_y": [
"200",
"200"
],
"machine_max_speed_z": [
"64",
"16"
],
"machine_min_extruding_rate": [
"0",
"0"
],
"machine_min_travel_rate": [
"0",
"0"
],
"machine_pause_gcode": "M601",
"machine_start_gcode": "G21 ; metric values\nG90 ; absolute positioning\nM82 ; set extruder to absolute mode\nM140 S[first_layer_bed_temperature] ; set bed temp\nG28 X0 Y0 ; home X and Y\nG28 Z0 ; home Z\nG1 Z30 F{machine_max_speed_z[0]*60} ; move Z a bit down to not blow on the bed edge while heating\nG1 X10 F3900 ; let some space on x to prevent the filament cooling exhaust from beeing blocked by the servo motor\nM190 S[bed_temperature_initial_layer_single] ; wait for bed temp\nM104 S[nozzle_temperature_initial_layer] ; set extruder temp\nM106 S80 ; turn on fan to prevent air nozzle melt while heating up\nM109 S[nozzle_temperature_initial_layer] ; wait for extruder temp\nM107 ; start with the fan off\nG28 X0 ; goto X home again\nG92 E0 ; zero the extruded length\nG1 Z0.2 F360 ; move plattform upwards\n; extrude material next to the plattform (comment or remove following lines to disable)\nG1 F180 E20 ; extrude some material next to the plattform\nG92 E0 ; zero the extruded length\nG1 E-[retraction_length] F{retraction_speed[0]*60} ; do a filament retract\nG92 E0 ; zero the extruded length again\nG1 X5 F3900 ; move sideways to get rid of that string\nG1 E[retraction_length] F{retraction_speed[0]*60} ; do a filament deretract with retract parameters\nG92 E0 ; zero the extruded length again\n; draw intro line (comment or remove following lines to disable)\nG1 X30 E5 F700 ; draw intro line\nG92 E0 ; zero the extruded length\nG1 E-[retraction_length] F{retraction_speed[0]*60} ; do a filament retract\nG1 X40 Z2.0 ; move away from the introline\nG92 E0 ; zero the extruded length again\nG1 E[retraction_length] F{retraction_speed[0]*60} ; do a filament deretract with retract parameters\n; end of intro line code\nM117 Printing...\nG5",
"machine_tool_change_time": "0",
"machine_unload_filament_time": "0",
"manual_filament_change": "0",
"max_layer_height": [
"0.3"
],
"max_resonance_avoidance_speed": "120",
"min_layer_height": [
"0.07"
],
"min_resonance_avoidance_speed": "70",
"nozzle_diameter": [
"0.4"
],
"nozzle_height": "2.5",
"nozzle_hrc": "0",
"nozzle_type": "undefine",
"nozzle_volume": "0",
"parking_pos_retraction": "92",
"pellet_modded_printer": "0",
"preferred_orientation": "0",
"printable_area": [
"0x0",
"300x0",
"300x300",
"0x300"
],
"printable_height": "350",
"printer_model": "Anet A8 Plus",
"printer_notes": "",
"printer_settings_id": "Anet A8 Plus 0.4 nozzle",
"printer_structure": "undefine",
"printer_technology": "FFF",
"printer_variant": "0.4",
"printhost_authorization_type": "key",
"printhost_ssl_ignore_revoke": "0",
"printing_by_object_gcode": "",
"purge_in_prime_tower": "1",
"resonance_avoidance": "0",
"retract_before_wipe": [
"0%"
],
"retract_length_toolchange": [
"10"
],
"retract_lift_above": [
"0"
],
"retract_lift_below": [
"0"
],
"retract_lift_enforce": [
"All Surfaces"
],
"retract_restart_extra": [
"0"
],
"retract_restart_extra_toolchange": [
"0"
],
"retract_when_changing_layer": [
"1"
],
"retraction_distances_when_cut": [
"18"
],
"retraction_length": [
"2.5"
],
"retraction_minimum_travel": [
"2"
],
"retraction_speed": [
"35"
],
"scan_first_layer": "0",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"support_air_filtration": "1",
"support_chamber_temp_control": "1",
"support_multi_bed_types": "0",
"template_custom_gcode": "",
"thumbnails": "48x48/PNG,300x300/PNG",
"thumbnails_format": "PNG",
"time_cost": "0",
"time_lapse_gcode": "",
"travel_slope": [
"3"
],
"upward_compatible_machine": [],
"use_firmware_retraction": "0",
"use_relative_e_distances": "1",
"wipe": [
"1"
],
"wipe_distance": [
"1"
],
"z_hop": [
"0.4"
],
"z_hop_types": [
"Normal Lift"
],
"z_offset": "0"
}

View File

@@ -719,6 +719,9 @@ std::string CoolingBuffer::apply_layer_cooldown(
// Second generate the adjusted G-code. // Second generate the adjusted G-code.
std::string new_gcode; std::string new_gcode;
new_gcode.reserve(gcode.size() * 2); new_gcode.reserve(gcode.size() * 2);
// ORCA: per-printer minimum non-zero fan PWM. Applied at every part-cooling fan emission below so any
// non-zero command is raised to at least this percent (0 disables the clamp).
const unsigned int part_cooling_fan_min_pwm = static_cast<unsigned int>(std::max(0, m_config.part_cooling_fan_min_pwm.value));
bool overhang_fan_control= false; bool overhang_fan_control= false;
int overhang_fan_speed = 0; int overhang_fan_speed = 0;
bool internal_bridge_fan_control= false; // ORCA: Add support for separate internal bridge fan speed control bool internal_bridge_fan_control= false; // ORCA: Add support for separate internal bridge fan speed control
@@ -727,7 +730,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
int supp_interface_fan_speed = 0; int supp_interface_fan_speed = 0;
bool ironing_fan_control= false; // ORCA: Add support for ironing fan speed control bool ironing_fan_control= false; // ORCA: Add support for ironing fan speed control
int ironing_fan_speed = 0; // ORCA: Add support for ironing fan speed control int ironing_fan_speed = 0; // ORCA: Add support for ironing fan speed control
auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, part_cooling_fan_min_pwm,
&overhang_fan_control, &overhang_fan_speed, &overhang_fan_control, &overhang_fan_speed,
&internal_bridge_fan_control, &internal_bridge_fan_speed, &internal_bridge_fan_control, &internal_bridge_fan_speed,
&supp_interface_fan_control, &supp_interface_fan_speed, &supp_interface_fan_control, &supp_interface_fan_speed,
@@ -743,11 +746,11 @@ std::string CoolingBuffer::apply_layer_cooldown(
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer); int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed); supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed);
if (close_fan_the_first_x_layers <= 0 && full_fan_speed_layer > 0) { // ORCA: previously a silent override forced `close_fan_the_first_x_layers` from 0 up to 1 whenever a ramp
// When ramping up fan speed from close_fan_the_first_x_layers to full_fan_speed_layer, force close_fan_the_first_x_layers above zero, // was configured (`full_fan_speed_layer > 0`), so the first printed layer always had the fan disabled.
// so there will be a zero fan speed at least at the 1st layer. // That hid the user's literal "no cooling for the first 0 layers" setting and produced a non-zero starting
close_fan_the_first_x_layers = 1; // factor on the ramp denominator. The override has been removed: with N=0 and M>0 the ramp now genuinely
} // starts on layer 0 at a factor of 1/M and reaches 100% at layer M-1, matching the intent of the option.
if (int(layer_id) >= close_fan_the_first_x_layers) { if (int(layer_id) >= close_fan_the_first_x_layers) {
float fan_max_speed = EXTRUDER_CONFIG(fan_max_speed); float fan_max_speed = EXTRUDER_CONFIG(fan_max_speed);
float slow_down_layer_time = float(EXTRUDER_CONFIG(slow_down_layer_time)); float slow_down_layer_time = float(EXTRUDER_CONFIG(slow_down_layer_time));
@@ -806,7 +809,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
m_fan_speed = fan_speed_new; m_fan_speed = fan_speed_new;
m_current_fan_speed = fan_speed_new; m_current_fan_speed = fan_speed_new;
if (immediately_apply) if (immediately_apply)
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm);
} }
//BBS //BBS
if (additional_fan_speed_new != m_additional_fan_speed) { if (additional_fan_speed_new != m_additional_fan_speed) {
@@ -980,26 +983,26 @@ std::string CoolingBuffer::apply_layer_cooldown(
if (need_set_fan) { if (need_set_fan) {
if (fan_speed_change_requests[CoolingLine::TYPE_OVERHANG_FAN_START]){ if (fan_speed_change_requests[CoolingLine::TYPE_OVERHANG_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, overhang_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, overhang_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = overhang_fan_speed; m_current_fan_speed = overhang_fan_speed;
} else if (fan_speed_change_requests[CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START]){ // ORCA: Add support for separate internal bridge fan speed control } else if (fan_speed_change_requests[CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START]){ // ORCA: Add support for separate internal bridge fan speed control
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, internal_bridge_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, internal_bridge_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = internal_bridge_fan_speed; m_current_fan_speed = internal_bridge_fan_speed;
} }
else if (fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START]){ else if (fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = supp_interface_fan_speed; m_current_fan_speed = supp_interface_fan_speed;
} }
else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){ else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = ironing_fan_speed; m_current_fan_speed = ironing_fan_speed;
} }
else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){ else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed, part_cooling_fan_min_pwm);
fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false; fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false;
} }
else else
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed); new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm);
need_set_fan = false; need_set_fan = false;
} }
pos = line_end; pos = line_end;

View File

@@ -230,7 +230,10 @@ void FanMover::_remove_slow_fan(int16_t min_speed, float past_sec) {
std::string FanMover::_set_fan(int16_t speed) { std::string FanMover::_set_fan(int16_t speed) {
//const Tool* tool = m_writer.get_tool(m_currrent_extruder < 20 ? m_currrent_extruder : 0); //const Tool* tool = m_writer.get_tool(m_currrent_extruder < 20 ? m_currrent_extruder : 0);
return GCodeWriter::set_fan(m_writer.config.gcode_flavor.value, speed); // ORCA: apply the per-printer non-zero fan PWM floor so reposted fan commands respect the clamp too.
const int floor_pct = m_writer.config.part_cooling_fan_min_pwm.value;
const unsigned int part_cooling_fan_min_pwm = floor_pct > 0 ? static_cast<unsigned int>(floor_pct) : 0u;
return GCodeWriter::set_fan(m_writer.config.gcode_flavor.value, speed, part_cooling_fan_min_pwm);
} }

View File

@@ -1092,9 +1092,13 @@ std::string GCodeWriter::unlift()
return gcode; return gcode;
} }
std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, unsigned int speed) std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, unsigned int speed, unsigned int part_cooling_fan_min_pwm)
{ {
std::ostringstream gcode; std::ostringstream gcode;
// ORCA: clamp non-zero fan commands up to the configured PWM floor so fans that can't spool at low duty
// cycles still start reliably. Zero (fan off) is preserved exactly so disable-fan commands are never altered.
if (speed > 0 && part_cooling_fan_min_pwm > 0 && speed < part_cooling_fan_min_pwm)
speed = part_cooling_fan_min_pwm;
if (speed == 0) { if (speed == 0) {
switch (gcode_flavor) { switch (gcode_flavor) {
case gcfTeacup: case gcfTeacup:
@@ -1129,7 +1133,9 @@ std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, unsigned int sp
std::string GCodeWriter::set_fan(unsigned int speed) const std::string GCodeWriter::set_fan(unsigned int speed) const
{ {
//BBS //BBS
return GCodeWriter::set_fan(this->config.gcode_flavor, speed); // ORCA: pick up the per-printer PWM floor from the active config.
return GCodeWriter::set_fan(this->config.gcode_flavor, speed,
static_cast<unsigned int>(std::max(0, this->config.part_cooling_fan_min_pwm.value)));
} }
//BBS: set additional fan speed for BBS machine only //BBS: set additional fan speed for BBS machine only

View File

@@ -98,7 +98,9 @@ public:
void set_xy_offset(double x, double y) { m_x_offset = x; m_y_offset = y; } void set_xy_offset(double x, double y) { m_x_offset = x; m_y_offset = y; }
Vec2f get_xy_offset() { return Vec2f{m_x_offset, m_y_offset}; }; Vec2f get_xy_offset() { return Vec2f{m_x_offset, m_y_offset}; };
// To be called by the CoolingBuffer from another thread. // To be called by the CoolingBuffer from another thread.
static std::string set_fan(const GCodeFlavor gcode_flavor, unsigned int speed); // ORCA: `part_cooling_fan_min_pwm` (0-100, default 0) is a floor applied only when `speed` is non-zero, used to overcome
// PWM start-up thresholds on fans that won't spool below a certain duty cycle. A `speed` of 0 is always honoured.
static std::string set_fan(const GCodeFlavor gcode_flavor, unsigned int speed, unsigned int part_cooling_fan_min_pwm = 0);
// To be called by the main thread. It always emits the G-code, it does not remember the previous state. // To be called by the main thread. It always emits the G-code, it does not remember the previous state.
// Keeping the state is left to the CoolingBuffer, which runs asynchronously on another thread. // Keeping the state is left to the CoolingBuffer, which runs asynchronously on another thread.
std::string set_fan(unsigned int speed) const; std::string set_fan(unsigned int speed) const;

View File

@@ -1326,7 +1326,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
static std::vector<std::string> s_Preset_printer_options { static std::vector<std::string> s_Preset_printer_options {
"printer_technology", "printer_technology",
"printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", "printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs", "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs",
"single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type", "printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
"printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",

View File

@@ -133,6 +133,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"fan_cooling_layer_time", "fan_cooling_layer_time",
"full_fan_speed_layer", "full_fan_speed_layer",
"fan_kickstart", "fan_kickstart",
"part_cooling_fan_min_pwm",
"fan_speedup_overhangs", "fan_speedup_overhangs",
"fan_speedup_time", "fan_speedup_time",
"filament_colour", "filament_colour",
@@ -1753,46 +1754,47 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
}; };
std::string warning_key; std::string warning_key;
const auto max_junction_deviation = m_config.machine_max_junction_deviation.values[0];
const bool ignore_jerk_validation = m_config.gcode_flavor == gcfMarlinFirmware && max_junction_deviation > 0;
// check jerk // check jerk
if (m_default_object_config.default_jerk == 1 || m_default_object_config.outer_wall_jerk == 1 || if (!ignore_jerk_validation) {
m_default_object_config.inner_wall_jerk == 1) { if (m_default_object_config.default_jerk == 1 || m_default_object_config.outer_wall_jerk == 1 ||
warning->string = L("Setting the jerk speed too low could lead to artifacts on curved surfaces"); m_default_object_config.inner_wall_jerk == 1) {
if (m_default_object_config.outer_wall_jerk == 1) warning->string = L("Setting the jerk speed too low could lead to artifacts on curved surfaces");
warning_key = "outer_wall_jerk"; if (m_default_object_config.outer_wall_jerk == 1)
else if (m_default_object_config.inner_wall_jerk == 1) warning_key = "outer_wall_jerk";
warning_key = "inner_wall_jerk"; else if (m_default_object_config.inner_wall_jerk == 1)
else warning_key = "inner_wall_jerk";
warning_key = "default_jerk"; else
warning_key = "default_jerk";
warning->opt_key = warning_key; warning->opt_key = warning_key;
} }
if (warning_key.empty() && m_default_object_config.default_jerk > 0) { if (warning_key.empty() && m_default_object_config.default_jerk > 0) {
std::vector<std::string> jerk_to_check = {"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", std::vector<std::string> jerk_to_check = {"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk",
"top_surface_jerk", "initial_layer_jerk", "travel_jerk"}; "top_surface_jerk", "initial_layer_jerk", "travel_jerk"};
const auto max_jerk = std::min(m_config.machine_max_jerk_x.values[0], m_config.machine_max_jerk_y.values[0]); const auto max_jerk = std::min(m_config.machine_max_jerk_x.values[0], m_config.machine_max_jerk_y.values[0]);
warning_key.clear(); warning_key.clear();
if (m_default_object_config.default_jerk > 0) warning_key = check_motion_ability_object_setting(jerk_to_check, max_jerk);
warning_key = check_motion_ability_object_setting(jerk_to_check, max_jerk); if (!warning_key.empty()) {
if (!warning_key.empty()) { warning->string = L(
warning->string = L( "The jerk setting exceeds the printer's maximum jerk (machine_max_jerk_x/machine_max_jerk_y).\n"
"The jerk setting exceeds the printer's maximum jerk (machine_max_jerk_x/machine_max_jerk_y).\nOrca will " "Orca will automatically cap the jerk speed to ensure it doesn't surpass the printer's capabilities.\n"
"automatically cap the jerk speed to ensure it doesn't surpass the printer's capabilities.\nYou can adjust the " "You can adjust the maximum jerk setting in your printer's configuration to get higher speeds.");
"maximum jerk setting in your printer's configuration to get higher speeds."); warning->opt_key = warning_key;
warning->opt_key = warning_key; }
} }
} }
// Check junction deviation // Check junction deviation
const auto max_junction_deviation = m_config.machine_max_junction_deviation.values[0];
// Orca: Only marlin FW supports max junction deviation. Dont display warning if firmware is not supporting it. // Orca: Only marlin FW supports max junction deviation. Dont display warning if firmware is not supporting it.
const bool support_max_junction_deviation = ( m_config.gcode_flavor == gcfMarlinFirmware); const bool support_max_junction_deviation = ( m_config.gcode_flavor == gcfMarlinFirmware);
if (warning_key.empty() && m_default_object_config.default_junction_deviation.value > max_junction_deviation && support_max_junction_deviation) { if (warning_key.empty() && m_default_object_config.default_junction_deviation.value > max_junction_deviation && support_max_junction_deviation) {
warning->string = L( "Junction deviation setting exceeds the printer's maximum value " warning->string = L( "Junction deviation setting exceeds the printer's maximum value (machine_max_junction_deviation).\n"
"(machine_max_junction_deviation).\nOrca will " "Orca will automatically cap the junction deviation to ensure it doesn't surpass the printer's capabilities.\n"
"automatically cap the junction deviation to ensure it doesn't surpass the printer's " "You can adjust the machine_max_junction_deviation value in your printer's configuration to get higher limits.");
"capabilities.\nYou can adjust the "
"machine_max_junction_deviation value in your printer's configuration to get higher limits.");
warning->opt_key = warning_key; warning->opt_key = warning_key;
} }

View File

@@ -3724,6 +3724,28 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));
// ORCA: minimum non-zero part cooling fan speed.
def = this->add("part_cooling_fan_min_pwm", coInt);
def->label = L("Minimum non-zero part cooling fan speed");
def->tooltip = L("Some part-cooling fans cannot start spinning when commanded below a certain PWM duty cycle. "
"When set above 0, any non-zero part-cooling fan command will be raised to at least this percentage "
"so the fan reliably starts. A fan command of 0 (fan off) is always honoured exactly. "
"This clamp is applied after every other fan calculation (first-layer ramp, layer-time interpolation, "
"overhang/bridge/support-interface/ironing overrides), so scaling still operates within the range "
"[this value, 100%]."
"\nIf your firmware already disables the fan below a threshold (for example Klipper's "
"[fan] off_below: 0.10 shuts the fan off whenever the commanded duty cycle is below 10%), "
"this option and the firmware threshold should ideally be set to the same value. Matching them "
"(e.g. off_below: 0.10 in Klipper and 10% here) guarantees the slicer never emits a non-zero "
"value that the firmware would silently drop, and the fan never receives a value below the one "
"you know it can actually spool at."
"\nSet to 0 to deactivate.");
def->sidetext = L("%");
def->min = 0;
def->max = 100;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(0));
def = this->add("time_cost", coFloat); def = this->add("time_cost", coFloat);
def->label = L("Time cost"); def->label = L("Time cost");

View File

@@ -1309,6 +1309,10 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fan_kickstart)) ((ConfigOptionFloat, fan_kickstart))
((ConfigOptionBool, fan_speedup_overhangs)) ((ConfigOptionBool, fan_speedup_overhangs))
((ConfigOptionFloat, fan_speedup_time)) ((ConfigOptionFloat, fan_speedup_time))
// ORCA: minimum PWM (as a percent 0-100) emitted when the part-cooling fan is asked for a non-zero speed.
// Used to overcome the PWM start-up threshold on fans that cannot spool below a certain duty cycle.
// A value of 0 (the default) leaves behaviour unchanged. A fan command of 0 (off) is always honoured.
((ConfigOptionInt, part_cooling_fan_min_pwm))
((ConfigOptionFloats, filament_diameter)) ((ConfigOptionFloats, filament_diameter))
((ConfigOptionBoolsNullable, filament_adaptive_volumetric_speed)) ((ConfigOptionBoolsNullable, filament_adaptive_volumetric_speed))
((ConfigOptionStrings, volumetric_speed_coefficients)) ((ConfigOptionStrings, volumetric_speed_coefficients))

View File

@@ -687,6 +687,8 @@ if (APPLE)
GUI/Mouse3DHandlerMac.mm GUI/Mouse3DHandlerMac.mm
GUI/InstanceCheckMac.mm GUI/InstanceCheckMac.mm
GUI/InstanceCheckMac.h GUI/InstanceCheckMac.h
GUI/DeepLinkHandlerMac.mm
GUI/DeepLinkHandlerMac.h
GUI/GUI_UtilsMac.mm GUI/GUI_UtilsMac.mm
GUI/wxMediaCtrl2.mm GUI/wxMediaCtrl2.mm
GUI/wxMediaCtrl2.h GUI/wxMediaCtrl2.h

View File

@@ -0,0 +1,16 @@
#ifndef slic3r_GUI_DeepLinkHandlerMac_h_
#define slic3r_GUI_DeepLinkHandlerMac_h_
namespace Slic3r {
namespace GUI {
// Re-registers a Cocoa Apple Event handler for kInternetEventClass/kAEGetURL.
// Works around a regression observed after upgrading to wxWidgets 3.3.2 on
// macOS Tahoe (#13119) where wxWidgets' built-in handler is registered but
// never fires for orcaslicer:// deep links.
void register_mac_deep_link_handler();
} // namespace GUI
} // namespace Slic3r
#endif

View File

@@ -0,0 +1,41 @@
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#include <boost/log/trivial.hpp>
#include "DeepLinkHandlerMac.h"
#include "GUI_App.hpp"
@interface OrcaDeepLinkHandler : NSObject
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply;
@end
@implementation OrcaDeepLinkHandler
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply
{
NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
if (url == nil || url.length == 0)
return;
BOOST_LOG_TRIVIAL(info) << "Deep link received: " << [url UTF8String];
Slic3r::GUI::wxGetApp().MacOpenURL(wxString::FromUTF8([url UTF8String]));
}
@end
namespace Slic3r {
namespace GUI {
void register_mac_deep_link_handler()
{
static OrcaDeepLinkHandler *handler = nil;
if (handler == nil)
handler = [[OrcaDeepLinkHandler alloc] init];
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:handler
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
} // namespace GUI
} // namespace Slic3r

View File

@@ -11,7 +11,6 @@
#include "Downloader.hpp" #include "Downloader.hpp"
#include <boost/chrono/duration.hpp> #include <boost/chrono/duration.hpp>
#include <boost/log/detail/native_typeof.hpp> #include <boost/log/detail/native_typeof.hpp>
#include <libslic3r/Config.hpp>
#include <wx/event.h> #include <wx/event.h>
// Localization headers: include libslic3r version first so everything in this file // Localization headers: include libslic3r version first so everything in this file
@@ -101,6 +100,9 @@
#include "Mouse3DController.hpp" #include "Mouse3DController.hpp"
#include "RemovableDriveManager.hpp" #include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp" #include "InstanceCheck.hpp"
#ifdef __APPLE__
#include "DeepLinkHandlerMac.h"
#endif
#include "NotificationManager.hpp" #include "NotificationManager.hpp"
#include "UnsavedChangesDialog.hpp" #include "UnsavedChangesDialog.hpp"
#include "SavePresetDialog.hpp" #include "SavePresetDialog.hpp"
@@ -784,9 +786,20 @@ void GUI_App::post_init()
mainframe->select_tab(size_t(MainFrame::tp3DEditor)); mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D"); plater_->select_view_3D("3D");
//BBS init the opengl resource here //BBS init the opengl resource here
//#ifdef __linux__ if (!plater_->canvas3D()->get_wxglcanvas()->IsShownOnScreen() ||
if (plater_->canvas3D()->get_wxglcanvas()->IsShownOnScreen()&&plater_->canvas3D()->make_current_for_postinit()) { !plater_->canvas3D()->make_current_for_postinit()) {
//#endif BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": glcontext not ready, postpone init";
plater_->canvas3D()->enable_render(true);
plater_->canvas3D()->set_as_dirty();
#ifdef __linux__
// Wayland/EGL may not have committed the GL surface yet; ask the
// idle loop to retry post_init when the canvas is actually mapped.
// Without this, GL function pointers stay null and the first
// Preview focus crashes in Camera::apply_viewport.
m_post_initialized = false;
return;
#endif
} else {
Size canvas_size = plater_->canvas3D()->get_canvas_size(); Size canvas_size = plater_->canvas3D()->get_canvas_size();
wxGetApp().imgui()->set_display_size(static_cast<float>(canvas_size.get_width()), static_cast<float>(canvas_size.get_height())); wxGetApp().imgui()->set_display_size(static_cast<float>(canvas_size.get_width()), static_cast<float>(canvas_size.get_height()));
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", start to init opengl"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", start to init opengl";
@@ -806,14 +819,7 @@ void GUI_App::post_init()
plater_->canvas3D()->render(false); plater_->canvas3D()->render(false);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test";
} }
//#ifdef __linux__
} }
else {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "Found glcontext not ready, postpone the init";
plater_->canvas3D()->enable_render(true);
plater_->canvas3D()->set_as_dirty();
}
//#endif
if (is_editor()) if (is_editor())
mainframe->select_tab(size_t(0)); mainframe->select_tab(size_t(0));
if (app_config->get("default_page") == "1") if (app_config->get("default_page") == "1")
@@ -2548,6 +2554,12 @@ std::string get_system_info()
bool GUI_App::on_init_inner() bool GUI_App::on_init_inner()
{ {
wxLog::SetActiveTarget(new wxBoostLog()); wxLog::SetActiveTarget(new wxBoostLog());
#ifdef __APPLE__
// Override wxWidgets' kAEGetURL handler so orcaslicer:// deep links keep
// working after the wxWidgets 3.3.2 upgrade on macOS (#13119).
register_mac_deep_link_handler();
#endif
#if BBL_RELEASE_TO_PUBLIC #if BBL_RELEASE_TO_PUBLIC
wxLog::SetLogLevel(wxLOG_Message); wxLog::SetLogLevel(wxLOG_Message);
#endif #endif
@@ -4836,12 +4848,12 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
BOOST_LOG_TRIVIAL(warning) << "logout: http error 401."; BOOST_LOG_TRIVIAL(warning) << "logout: http error 401.";
this->request_user_logout(provider); this->request_user_logout(provider);
if (!m_show_http_error_msgdlg) { if (!m_show_http_errpr_msgdlg) {
MessageDialog msg_dlg(nullptr, _L("Login information expired. Please login again."), "", wxAPPLY | wxOK); MessageDialog msg_dlg(nullptr, _L("Login information expired. Please login again."), "", wxAPPLY | wxOK);
m_show_http_error_msgdlg = true; m_show_http_errpr_msgdlg = true;
auto modal_result = msg_dlg.ShowModal(); auto modal_result = msg_dlg.ShowModal();
if (modal_result == wxOK || modal_result == wxCLOSE) { if (modal_result == wxOK || modal_result == wxCLOSE) {
m_show_http_error_msgdlg = false; m_show_http_errpr_msgdlg = false;
return; return;
} }
} }
@@ -4849,40 +4861,6 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
} }
return; return;
} }
// No need to show dialog for 410: 410 means resource has been deleted from the server.
if (status == 410) {
BOOST_LOG_TRIVIAL(info) << "Http error 410.";
return;
}
static bool m_is_error_shown = false;
// Show general error notification for Orca Cloud API failures (not Bambu)
if (provider == ORCA_CLOUD_PROVIDER && status >= 400 && code != HttpErrorVersionLimited) {
wxString msg;
if (!error.empty()) {
msg = wxString::Format(_L("API error (HTTP %u): %s"), status, wxString::FromUTF8(error));
} else {
msg = wxString::Format(_L("API error (HTTP %u)"), status);
}
if (app_config->get_bool("developer_mode")) {
// Use notification manager if ImGui is ready; fall back to wxMessageBox on Linux
// where ImGui may not be initialized until the user switches to the Prepare tab.
if (wxGetApp().plater() != nullptr && wxGetApp().imgui()->display_initialized()) {
wxGetApp()
.plater()
->get_notification_manager()
->push_notification(NotificationType::PlaterError, NotificationManager::NotificationLevel::WarningNotificationLevel,
msg.ToUTF8().data());
}
}
if (!m_is_error_shown) {
m_is_error_shown = true;
wxMessageBox(msg, _L("Orca Cloud API Error"), wxOK | wxICON_ERROR, wxGetApp().mainframe);
}
}
} }
void GUI_App::enable_user_preset_folder(bool enable) void GUI_App::enable_user_preset_folder(bool enable)

View File

@@ -324,7 +324,7 @@ private:
bool m_is_dark_mode{ false }; bool m_is_dark_mode{ false };
bool m_adding_script_handler { false }; bool m_adding_script_handler { false };
bool m_side_popup_status{false}; bool m_side_popup_status{false};
bool m_show_http_error_msgdlg{false}; bool m_show_http_errpr_msgdlg{false};
bool m_show_error_msgdlg{false}; bool m_show_error_msgdlg{false};
wxString m_info_dialog_content; wxString m_info_dialog_content;
HttpServer m_http_server; HttpServer m_http_server;

View File

@@ -561,14 +561,23 @@ wxString GridCellSupportEditor::ms_stringValues[2] = { wxT(""), wxT("") };
void GridCellSupportEditor::DoActivate(int row, int col, wxGrid* grid) void GridCellSupportEditor::DoActivate(int row, int col, wxGrid* grid)
{ {
ObjectGrid* local_table = dynamic_cast<ObjectGrid*>(grid);
wxGridBlocks cell_array = grid->GetSelectedBlocks(); wxGridBlocks cell_array = grid->GetSelectedBlocks();
auto iter = cell_array.begin();
auto left_col = cell_array.begin()->GetLeftCol();
auto right_col = cell_array.begin()->GetRightCol(); int left_col, right_col, top_row, bottom_row;
auto top_row = cell_array.begin()->GetTopRow(); if (iter == cell_array.end()) {
auto bottom_row = cell_array.begin()->GetBottomRow(); // wxWidgets 3.3.x returns an empty range when nothing is selected;
// fall back to the cell that triggered activation so the single-cell
// branch below handles it.
left_col = right_col = col;
top_row = bottom_row = row;
} else {
left_col = iter->GetLeftCol();
right_col = iter->GetRightCol();
top_row = iter->GetTopRow();
bottom_row = iter->GetBottomRow();
}
if ((left_col == right_col) && if ((left_col == right_col) &&
(top_row == bottom_row)) { (top_row == bottom_row)) {
wxGridCellBoolEditor::DoActivate(row, col, grid); wxGridCellBoolEditor::DoActivate(row, col, grid);

View File

@@ -373,13 +373,12 @@ public:
//BBS //BBS
static int TOOLBAR_WINDOW_FLAGS; static int TOOLBAR_WINDOW_FLAGS;
bool display_initialized() const;
private: private:
void init_font(bool compress); void init_font(bool compress);
void init_input(); void init_input();
void init_style(); void init_style();
void render_draw_data(ImDrawData *draw_data); void render_draw_data(ImDrawData *draw_data);
bool display_initialized() const;
void destroy_font(); void destroy_font();
std::vector<unsigned char> load_svg(const std::string& bitmap_name, unsigned target_width, unsigned target_height, unsigned *outwidth, unsigned *outheight); std::vector<unsigned char> load_svg(const std::string& bitmap_name, unsigned target_width, unsigned target_height, unsigned *outwidth, unsigned *outheight);

View File

@@ -23,6 +23,81 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#ifdef __linux__
// Workaround for #7210: WebKitGTK crashes on vue-resize's hidden <object> probe used by
// older Fluidd/Mainsail pages. Swap that <object> for a <div> shim at appendChild time
// and bridge resize events through a fake contentDocument.defaultView so vue-resize keeps
// working. Workaround proposed by @VittC.
static void inject_vue_resize_workaround(wxWebView *webView)
{
webView->AddUserScript(
"(function() {"
" 'use strict';"
" function isVueResizeObject(el) {"
" return el && el.tagName === 'OBJECT'"
" && el.type === 'text/html'"
" && el.getAttribute('aria-hidden') === 'true'"
" && el.getAttribute('tabindex') === '-1';"
" }"
" function isResizeObserverParent(p) {"
" return p && p.classList && p.classList.contains('resize-observer');"
" }"
" function makeShim(orig, parentForRO) {"
" var shim = document.createElement('div');"
" shim.setAttribute('aria-hidden', 'true');"
" shim.setAttribute('tabindex', '-1');"
" shim.style.display = 'none';"
" var fakeWin = document.createElement('div');"
" var ro = null;"
" var origRemoveEL = fakeWin.removeEventListener.bind(fakeWin);"
" fakeWin.removeEventListener = function(type, fn, opts) {"
" origRemoveEL(type, fn, opts);"
" if (type === 'resize' && ro) { ro.disconnect(); ro = null; }"
" };"
" Object.defineProperty(shim, 'contentDocument', {"
" configurable: true,"
" get: function() { return { defaultView: fakeWin }; }"
" });"
" Object.defineProperty(shim, 'contentWindow', {"
" configurable: true,"
" get: function() { return fakeWin; }"
" });"
" if (typeof orig.onload === 'function') { shim.onload = orig.onload; }"
" queueMicrotask(function() {"
" if (parentForRO && typeof ResizeObserver !== 'undefined') {"
" ro = new ResizeObserver(function() {"
" fakeWin.dispatchEvent(new Event('resize'));"
" });"
" ro.observe(parentForRO);"
" }"
" if (typeof shim.onload === 'function') {"
" try { shim.onload(new Event('load')); } catch (e) {}"
" }"
" shim.dispatchEvent(new Event('load'));"
" });"
" return shim;"
" }"
" var origAppend = Node.prototype.appendChild;"
" Node.prototype.appendChild = function(child) {"
" if (isResizeObserverParent(this) && isVueResizeObject(child)) {"
" return origAppend.call(this, makeShim(child, this));"
" }"
" return origAppend.call(this, child);"
" };"
" var origInsertBefore = Node.prototype.insertBefore;"
" Node.prototype.insertBefore = function(child, ref) {"
" if (isResizeObserverParent(this) && isVueResizeObject(child)) {"
" return origInsertBefore.call(this, makeShim(child, this), ref);"
" }"
" return origInsertBefore.call(this, child, ref);"
" };"
" console.log('[vr-fix] vue-resize WebKitGTK patch active');"
"})();",
wxWEBVIEW_INJECT_AT_DOCUMENT_START
);
}
#endif
PrinterWebView::PrinterWebView(wxWindow *parent) PrinterWebView::PrinterWebView(wxWindow *parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
, m_browser(nullptr) , m_browser(nullptr)
@@ -43,6 +118,8 @@ PrinterWebView::PrinterWebView(wxWindow *parent)
} }
#ifdef __linux__ #ifdef __linux__
inject_vue_resize_workaround(m_browser);
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db"); auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend()); auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
auto wv_ctx = webkit_web_view_get_context(wv); auto wv_ctx = webkit_web_view_get_context(wv);
@@ -165,6 +242,10 @@ void PrinterWebView::SendAPIKey()
)", )",
m_apikey); m_apikey);
m_browser->RemoveAllUserScripts(); m_browser->RemoveAllUserScripts();
#ifdef __linux__
// Re-inject the vue-resize/WebKitGTK workaround that RemoveAllUserScripts just cleared.
inject_vue_resize_workaround(m_browser);
#endif
m_browser->AddUserScript(script); m_browser->AddUserScript(script);
m_browser->Reload(); m_browser->Reload();

View File

@@ -4500,6 +4500,8 @@ void TabPrinter::build_fff()
line.append_option(optgroup->get_option("fan_speedup_overhangs")); line.append_option(optgroup->get_option("fan_speedup_overhangs"));
optgroup->append_line(line); optgroup->append_line(line);
optgroup->append_single_option_line("fan_kickstart", "printer_basic_information_cooling_fan#fan-kick-start-time"); optgroup->append_single_option_line("fan_kickstart", "printer_basic_information_cooling_fan#fan-kick-start-time");
// ORCA: PWM floor for fans that won't spool at low duty cycles.
optgroup->append_single_option_line("part_cooling_fan_min_pwm", "printer_basic_information_cooling_fan#minimum-non-zero-part-cooling-fan-speed");
optgroup = page->new_optgroup(L("Extruder Clearance"), "param_extruder_clearance"); optgroup = page->new_optgroup(L("Extruder Clearance"), "param_extruder_clearance");
optgroup->append_single_option_line("extruder_clearance_radius", "printer_basic_information_extruder_clearance#radius"); optgroup->append_single_option_line("extruder_clearance_radius", "printer_basic_information_extruder_clearance#radius");