Compare commits

..
Author SHA1 Message Date
Hanif Koh 258bbee999 build_linux.sh: Forward Arguments After -- to the CMake Configure Step
Everything after `--` is appended, unchanged and last, to the cmake
configure line of the deps and OrcaSlicer builds, so a custom compiler,
compile flags or linker can be passed without adding an option to the
script for each one. The arguments are kept as an array, so a value with
spaces such as -DCMAKE_CXX_FLAGS="-O2 -march=native" survives, and they are
forwarded into the -g container. A stray argument without `--` aborts with
a message instead of reaching cmake as a path.

The existing DEPS_EXTRA_BUILD_ARGS and ORCA_EXTRA_BUILD_ARGS hooks are
unchanged and now mentioned in the usage text.
2026-10-14 14:45:30 +08:00
111 changed files with 175 additions and 6847 deletions
-89
View File
@@ -1,89 +0,0 @@
{
"name": "Goofoo",
"version": "02.04.00.01",
"force_update": "0",
"description": "Goofoo configurations",
"machine_model_list": [
{
"name": "Goofoo GP1",
"sub_path": "machine/Goofoo GP1.json"
},
{
"name": "Goofoo TurboM",
"sub_path": "machine/Goofoo TurboM.json"
},
{
"name": "Goofoo Velo+",
"sub_path": "machine/Goofoo Velo+.json"
},
{
"name": "Goofoo Velo+ Tool",
"sub_path": "machine/Goofoo Velo+ Tool.json"
}
],
"process_list": [
{
"name": "fdm_process_common",
"sub_path": "process/fdm_process_common.json"
},
{
"name": "fdm_process_klipper_common",
"sub_path": "process/fdm_process_klipper_common.json"
},
{
"name": "0.20mm Standard @Goofoo GP1",
"sub_path": "process/0.20mm Standard @Goofoo GP1.json"
},
{
"name": "0.20mm Standard @Goofoo TurboM",
"sub_path": "process/0.20mm Standard @Goofoo TurboM.json"
},
{
"name": "0.20mm Standard @Goofoo Velo+",
"sub_path": "process/0.20mm Standard @Goofoo Velo+.json"
},
{
"name": "0.30mm Standard @Goofoo Velo+",
"sub_path": "process/0.30mm Standard @Goofoo Velo+.json"
},
{
"name": "0.10mm Standard @Goofoo Velo+",
"sub_path": "process/0.10mm Standard @Goofoo Velo+.json"
}
],
"filament_list": [],
"machine_list": [
{
"name": "fdm_machine_common",
"sub_path": "machine/fdm_machine_common.json"
},
{
"name": "fdm_klipper_common",
"sub_path": "machine/fdm_klipper_common.json"
},
{
"name": "Goofoo GP1 0.4 nozzle",
"sub_path": "machine/Goofoo GP1 0.4 nozzle.json"
},
{
"name": "Goofoo TurboM 0.4 nozzle",
"sub_path": "machine/Goofoo TurboM 0.4 nozzle.json"
},
{
"name": "Goofoo Velo+ 0.2 nozzle",
"sub_path": "machine/Goofoo Velo+ 0.2 nozzle.json"
},
{
"name": "Goofoo Velo+ 0.4 nozzle",
"sub_path": "machine/Goofoo Velo+ 0.4 nozzle.json"
},
{
"name": "Goofoo Velo+ 0.6 nozzle",
"sub_path": "machine/Goofoo Velo+ 0.6 nozzle.json"
},
{
"name": "Goofoo Velo+ Tool 0.4",
"sub_path": "machine/Goofoo Velo+ Tool 0.4.json"
}
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

@@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<g id="Layer_1">
<title>Layer 1</title>
<text fill="#0000ff" x="31.38885" y="400.22266" id="svg_1" font-size="24" font-family="Noto Sans JP" text-anchor="start" xml:space="preserve" stroke="#0000ff" transform="matrix(2.19884 0 0 1.66297 -63.896 -416.238)">GP1</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 373 B

Binary file not shown.
@@ -1,7 +0,0 @@
<svg width="600" height="480" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<text transform="matrix(2.3401 0 0 1.462 -92.4668 -168.496)" stroke="#000" stroke-width="3" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_1" y="421.25588" x="52.33404" fill="#000000">TurboM</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 353 B

Binary file not shown.
@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="480" viewBox="0 0 600 480">
<g id="Layer_1">
<title>Layer 1</title>
<text transform="matrix(2.19884 0 0 1.66297 -203.896 -238.238)" stroke="#0000ff" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_1" y="400.22266" x="120.07198" fill="#0000ff">VELO+</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 376 B

Binary file not shown.
@@ -1,98 +0,0 @@
{
"type": "machine",
"name": "Goofoo GP1 0.4 nozzle",
"inherits": "fdm_klipper_common",
"from": "system",
"setting_id": "x4GJ08PooNDQ8WJj",
"instantiation": "true",
"nozzle_diameter": [
"0.4"
],
"default_filament_profile": [
"Goofoo ABS @System"
],
"printer_model": "Goofoo GP1",
"default_print_profile": "0.20mm Standard @Goofoo GP1",
"printer_variant": "0.4",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\n;G92 E0",
"change_filament_gcode": "G5",
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\n;layer\n;{if layer_num == 2}\n;M106 P1 S255\n;{endif}\nSET_PRINT_STATS_INFO CURRENT_LAYER=[layer_num]\n",
"machine_end_gcode": "; End G-code\nEND_PRINT",
"machine_pause_gcode": "G5",
"machine_start_gcode": "M117 Printing...\nM107 ; Turn off the fan\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nM104 S140\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n;G32 ;Load bed mesh\nG28 ;home\nG29 bed leveling\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG0 Z2.0 F600;\nG0 X50 Y10 F8000;\nG92 E0.0 ; reset extruder distance position\nG0 Z0.4 F600;\nG1 X100.0 E10 F3000.0 ; intro line\nG92 E0.0 ; reset extruder distance position\nG1 X200.0 E15 F3000.0 ; intro line\nG92 E0.0 ; reset extruder distance position\nG0 Z0.8 F600;\nG1 X100.0 E15 F3000.0 ; intro line\nG1 Z0.4 F600 ;Wipe\nG0 Y12 F6000 ;Wipe\nG1 X100 F6000 ;Wipe\nG0 Y8 F12000 ;Wipe\nG1 X200 F6000 ;Wipe\nG1 X190 Y12 F6000 ;Wipe\nG1 X180 Y8 F6000 ;Wipe\nG1 X170 Y12 F6000 ;Wipe\nG1 X160 Y8 F6000 ;Wipe\nG1 X150 Y12 F6000 ;Wipe\n;G0 Z2.0 F600;\nG92 E0.0 ; reset extruder distance position\n;START_PRINT",
"purge_in_prime_tower": "0",
"time_lapse_gcode": ";TIMELAPSE_TAKE_FRAME",
"printable_height": "250",
"printable_area": [
"0x0",
"250x0",
"250x250",
"0x250"
],
"deretraction_speed": [
"0"
],
"extruder_clearance_height_to_lid": "140",
"extruder_clearance_height_to_rod": "36",
"extruder_clearance_radius": "65",
"machine_max_acceleration_e": [
"20000",
"5000"
],
"machine_max_acceleration_retracting": [
"15000",
"5000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"1",
"2.5"
],
"machine_max_jerk_x": [
"5",
"9"
],
"machine_max_jerk_y": [
"5",
"9"
],
"machine_max_speed_e": [
"25",
"25"
],
"machine_max_speed_x": [
"500",
"200"
],
"machine_max_speed_y": [
"500",
"200"
],
"machine_max_speed_z": [
"12",
"12"
],
"retract_before_wipe": [
"100%"
],
"retract_length_toolchange": [
"10"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"retraction_speed": [
"50"
],
"thumbnails": "300x300/PNG",
"z_hop": [
"0"
],
"upward_compatible_machine": []
}
@@ -1,11 +0,0 @@
{
"type": "machine_model",
"name": "Goofoo GP1",
"nozzle_diameter": "0.4",
"bed_model": "Goofoo-GP1.stl",
"bed_texture": "Goofoo-GP1-texture.svg",
"family": "Goofoo",
"machine_tech": "FFF",
"model_id": "V003",
"default_materials": "Goofoo ABS @System"
}
@@ -1,54 +0,0 @@
{
"type": "machine",
"name": "Goofoo TurboM 0.4 nozzle",
"inherits": "fdm_klipper_common",
"from": "system",
"setting_id": "Wmdn5zTy1HH93Q5d",
"instantiation": "true",
"nozzle_diameter": [
"0.4"
],
"nozzle_type": "brass",
"printer_model": "Goofoo TurboM",
"printer_variant": "0.4",
"default_filament_profile": [
"Goofoo ABS @System"
],
"default_print_profile": "0.20mm Standard @Goofoo TurboM",
"printable_area": [
"0x0",
"230x0",
"230x200",
"0x200"
],
"extruder_clearance_height_to_lid": "350",
"extruder_clearance_height_to_rod": "60",
"extruder_clearance_radius": "50",
"machine_end_gcode": "M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG92 E0.0 ; reset extruder distance position;\nG1 E-1 F2100 ; retract\nG28 X Y; home X Y axis\n;M84 ; disable motors\nM107 ; turn off fan\n;SET_VELOCITY_LIMIT ACCEL_TO_DECEL=4000",
"machine_max_jerk_z": [
"3",
"0.4"
],
"machine_start_gcode": "M107 ; Turn off the fan\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\n\n\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG28 ;home\n\nG1 X2 Y10 F3000;\n\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\n\nG1 Z0.28 F240\n\nG92 E0\n\nG1 Y140 E10 F1500 ; prime the nozzle\n\nG1 X2.3 F5000\nG92 E0\n\nG1 Y10 E10 F1200 ; prime the nozzle\n;G0 Z2.0 F600;\nG92 E0.0 ; reset extruder distance position;\nM82\n;SET_PRESSURE_ADVANCE ADVANCE=0.05\n;SET_VELOCITY_LIMIT ACCEL_TO_DECEL=10000\n",
"printable_height": "200",
"z_hop": [
"0"
],
"machine_max_speed_e": [
"25",
"25"
],
"machine_max_speed_x": [
"500",
"200"
],
"machine_max_speed_y": [
"500",
"200"
],
"machine_max_speed_z": [
"12",
"12"
],
"upward_compatible_machine": []
}
@@ -1,11 +0,0 @@
{
"type": "machine_model",
"name": "Goofoo TurboM",
"nozzle_diameter": "0.4",
"bed_model": "Goofoo-TurboM.stl",
"bed_texture": "Goofoo-TurboM-texture.svg",
"family": "Goofoo",
"machine_tech": "FFF",
"model_id": "V002",
"default_materials": "Goofoo ABS @System"
}
@@ -1,106 +0,0 @@
{
"type": "machine",
"name": "Goofoo Velo+ 0.2 nozzle",
"inherits": "fdm_klipper_common",
"from": "system",
"setting_id": "wSr6VNECZHekeNRi",
"instantiation": "true",
"nozzle_diameter": [
"0.2"
],
"nozzle_type": "hardened_steel",
"printer_model": "Goofoo Velo+",
"printer_variant": "0.2",
"default_filament_profile": [
"Goofoo ABS @System"
],
"default_print_profile": "0.10mm Standard @Goofoo Velo+",
"printable_area": [
"0x0",
"600x0",
"600x500",
"0x500"
],
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
"printable_height": "600",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
"change_filament_gcode": "PAUSE",
"deretraction_speed": [
"0"
],
"extruder_clearance_height_to_lid": "350",
"extruder_clearance_height_to_rod": "60",
"extruder_clearance_radius": "50",
"machine_max_acceleration_e": [
"20000",
"5000"
],
"machine_max_acceleration_retracting": [
"15000",
"5000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"1",
"2.5"
],
"machine_max_jerk_x": [
"5",
"9"
],
"machine_max_jerk_y": [
"5",
"9"
],
"machine_max_speed_e": [
"50",
"25"
],
"machine_max_speed_x": [
"730",
"200"
],
"machine_max_speed_y": [
"730",
"200"
],
"machine_max_speed_z": [
"15",
"12"
],
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
"retract_before_wipe": [
"100%"
],
"retract_length_toolchange": [
"10"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"retraction_speed": [
"50"
],
"thumbnails": "300x300/PNG",
"z_hop": [
"0"
],
"machine_max_acceleration_travel": [
"10000",
"10000"
],
"max_layer_height": [
"0.16"
],
"min_layer_height": [
"0.04"
],
"upward_compatible_machine": []
}
@@ -1,100 +0,0 @@
{
"type": "machine",
"name": "Goofoo Velo+ 0.4 nozzle",
"inherits": "fdm_klipper_common",
"from": "system",
"setting_id": "XzHz1vNOYg3Ofe8X",
"instantiation": "true",
"nozzle_diameter": [
"0.4"
],
"nozzle_type": "hardened_steel",
"printer_model": "Goofoo Velo+",
"printer_variant": "0.4",
"default_filament_profile": [
"Goofoo ABS @System"
],
"default_print_profile": "0.20mm Standard @Goofoo Velo+",
"printable_area": [
"0x0",
"600x0",
"600x500",
"0x500"
],
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
"printable_height": "600",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
"change_filament_gcode": "PAUSE",
"deretraction_speed": [
"0"
],
"extruder_clearance_height_to_lid": "350",
"extruder_clearance_height_to_rod": "60",
"extruder_clearance_radius": "50",
"machine_max_acceleration_e": [
"20000",
"5000"
],
"machine_max_acceleration_retracting": [
"15000",
"5000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"1",
"2.5"
],
"machine_max_jerk_x": [
"5",
"9"
],
"machine_max_jerk_y": [
"5",
"9"
],
"machine_max_speed_e": [
"50",
"25"
],
"machine_max_speed_x": [
"730",
"200"
],
"machine_max_speed_y": [
"730",
"200"
],
"machine_max_speed_z": [
"15",
"12"
],
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
"retract_before_wipe": [
"100%"
],
"retract_length_toolchange": [
"10"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"retraction_speed": [
"50"
],
"thumbnails": "300x300/PNG",
"z_hop": [
"0"
],
"machine_max_acceleration_travel": [
"10000",
"10000"
],
"upward_compatible_machine": []
}
@@ -1,106 +0,0 @@
{
"type": "machine",
"name": "Goofoo Velo+ 0.6 nozzle",
"inherits": "fdm_klipper_common",
"from": "system",
"setting_id": "Pauu7JRq7u2OD6kv",
"instantiation": "true",
"nozzle_diameter": [
"0.6"
],
"nozzle_type": "hardened_steel",
"printer_model": "Goofoo Velo+",
"printer_variant": "0.6",
"default_filament_profile": [
"Goofoo ABS @System"
],
"default_print_profile": "0.30mm Standard @Goofoo Velo+",
"printable_area": [
"0x0",
"600x0",
"600x500",
"0x500"
],
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
"printable_height": "600",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0",
"change_filament_gcode": "PAUSE",
"deretraction_speed": [
"0"
],
"extruder_clearance_height_to_lid": "350",
"extruder_clearance_height_to_rod": "60",
"extruder_clearance_radius": "50",
"machine_max_acceleration_e": [
"20000",
"5000"
],
"machine_max_acceleration_retracting": [
"15000",
"5000"
],
"machine_max_acceleration_z": [
"100",
"200"
],
"machine_max_jerk_e": [
"1",
"2.5"
],
"machine_max_jerk_x": [
"5",
"9"
],
"machine_max_jerk_y": [
"5",
"9"
],
"machine_max_speed_e": [
"50",
"25"
],
"machine_max_speed_x": [
"730",
"200"
],
"machine_max_speed_y": [
"730",
"200"
],
"machine_max_speed_z": [
"15",
"12"
],
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] ; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
"retract_before_wipe": [
"100%"
],
"retract_length_toolchange": [
"10"
],
"retraction_length": [
"0.5"
],
"retraction_minimum_travel": [
"2"
],
"retraction_speed": [
"50"
],
"thumbnails": "300x300/PNG",
"z_hop": [
"0"
],
"machine_max_acceleration_travel": [
"10000",
"10000"
],
"max_layer_height": [
"0.4"
],
"min_layer_height": [
"0.12"
],
"upward_compatible_machine": []
}
@@ -1,152 +0,0 @@
{
"type": "machine",
"name": "Goofoo Velo+ Tool 0.4",
"inherits": "Goofoo Velo+ 0.4 nozzle",
"from": "system",
"setting_id": "ww39WeaF5nYks1em",
"instantiation": "true",
"nozzle_diameter": [
"0.4",
"0.4"
],
"printer_model": "Goofoo Velo+ Tool",
"change_filament_gcode": "T[next_extruder]\n;M104 S[nozzle_temperature_initial_layer] T[next_extruder]; 正式设置喷嘴温度(与切片设置一致)\n;M109 S[nozzle_temperature_initial_layer] T[next_extruder] ; 等待喷嘴温度稳定\n",
"default_nozzle_volume_type": [
"Standard",
"Standard"
],
"deretraction_speed": [
"0",
"0"
],
"extruder_colour": [
"#FCE94F",
"#FCE94F"
],
"extruder_offset": [
"0x0",
"0x0"
],
"extruder_printable_height": [
"0",
"0"
],
"extruder_type": [
"Direct Drive",
"Direct Drive"
],
"extruder_variant_list": [
"Direct Drive Standard",
"Direct Drive Standard"
],
"long_retractions_when_cut": [
"0",
"0"
],
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nT0\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
"machine_start_gcode": "G90 ; 绝对坐标模式\nM83 ; 挤出机相对模式\nM140 S[first_layer_bed_temperature] ; 设置热床温度\nM104 S140 T0 ; 临时喷嘴温度=切片首层设定(防止归零渗料)\nM104 S140 T1\nG4 S10 ; 预热等待10秒\nG28 ; 归零所有轴\nG1 Z50 F240 ; Z轴抬升\nG1 X2 Y10 F3000 ; 移动至起始位置\nM104 S[nozzle_temperature_initial_layer] T0 ; 正式设置喷嘴温度(与切片设置一致)\nM104 S[nozzle_temperature_initial_layer] T1 ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] T0; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] T0 ; 等待喷嘴温度稳定\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X2.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零\nG1 Z20 F240 ; Z轴抬升\nG1 X280 Y10 F3000 ; 移动至起始位置\nT1\nM104 S[nozzle_temperature_initial_layer] T1 ; 正式设置喷嘴温度(与切片设置一致)\nM190 S[bed_temperature_initial_layer_single] T1; 等待热床温度稳定\nM109 S[nozzle_temperature_initial_layer] T1; 等待喷嘴温度稳定\nG4 S10 ; 预热等待10秒\nG1 Z0.28 F240 ; 喷嘴下降至打印高度\nG92 E0 ; 挤出机归零\nG1 Y140 E10 F1500 ; 画第一条 priming 线\nG1 X282.3 F5000 ; X轴微调\nG92 E0 ; 挤出机归零\nG1 Y10 E10 F1200 ; 画第二条 priming 线\nG92 E0 ; 最终挤出机归零",
"max_layer_height": [
"0.32",
"0.32"
],
"min_layer_height": [
"0.08",
"0.08"
],
"nozzle_flush_dataset": [
"nil",
"0"
],
"nozzle_type": [
"nil",
"hardened_steel"
],
"nozzle_volume": [
"nil",
"0"
],
"printable_area": [
"0x0",
"300x0",
"300x300",
"0x300"
],
"printer_extruder_id": [
"1",
"2"
],
"printer_extruder_variant": [
"Direct Drive Standard",
"Direct Drive Standard"
],
"purge_in_prime_tower": "0",
"retract_before_wipe": [
"100%",
"100%"
],
"retract_length_toolchange": [
"10",
"10"
],
"retract_lift_above": [
"0",
"0"
],
"retract_lift_below": [
"0",
"0"
],
"retract_lift_enforce": [
"All Surfaces",
"All Surfaces"
],
"retract_restart_extra": [
"0",
"0"
],
"retract_restart_extra_toolchange": [
"0",
"0"
],
"retract_when_changing_layer": [
"1",
"1"
],
"retraction_distances_when_cut": [
"18",
"18"
],
"retraction_length": [
"0.5",
"0.5"
],
"retraction_minimum_travel": [
"2",
"2"
],
"retraction_speed": [
"50",
"50"
],
"single_extruder_multi_material": "0",
"travel_slope": [
"3",
"3"
],
"wipe": [
"1",
"1"
],
"wipe_distance": [
"1",
"1"
],
"z_hop": [
"0",
"0"
],
"z_hop_types": [
"Slope Lift",
"Slope Lift"
]
}
@@ -1,11 +0,0 @@
{
"type": "machine_model",
"name": "Goofoo Velo+ Tool",
"nozzle_diameter": "0.4",
"bed_model": "Goofoo-Velo+.stl",
"bed_texture": "Goofoo-Velo+-texture.svg",
"family": "Goofoo",
"machine_tech": "FFF",
"model_id": "V006",
"default_materials": "Goofoo ABS @System"
}
@@ -1,11 +0,0 @@
{
"type": "machine_model",
"name": "Goofoo Velo+",
"nozzle_diameter": "0.2;0.4;0.6",
"bed_model": "Goofoo-Velo+.stl",
"bed_texture": "Goofoo-Velo+-texture.svg",
"family": "Goofoo",
"machine_tech": "FFF",
"model_id": "V001",
"default_materials": "Goofoo ABS @System"
}
@@ -1,13 +0,0 @@
{
"type": "machine",
"name": "fdm_klipper_common",
"inherits": "fdm_machine_common",
"from": "system",
"instantiation": "false",
"gcode_flavor": "klipper",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n",
"machine_start_gcode": "G90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nM140 S{first_layer_bed_temperature[0]} ; set bed temp\nM104 S140 ; set temporary nozzle temp to prevent oozing\nG4 S10 ; wait 10s for preheating\nG28 ; home all axes\nG1 Z50 F240 ; raise Z axis\nG1 X2 Y10 F3000 ; move to start position\nM104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; wait for bed temp\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp\nG1 Z0.28 F240 ; lower nozzle to print height\nG92 E0 ; reset extrusion distance\nG1 Y140 E10 F1500 ; prime the nozzle\nG1 X2.3 F5000 ; slight X adjustment\nG92 E0 ; reset extrusion distance\nG1 Y10 E10 F1200 ; prime again\nG92 E0 ; final extrusion reset",
"machine_end_gcode": "{if max_layer_z < printable_height}G1 Z{z_offset+min(max_layer_z+2, printable_height)} F600 ; Move print head up{endif}\nG1 X5 Y{print_bed_max[1]*0.8} F{travel_speed*60} ; present print\n{if max_layer_z < printable_height-10}G1 Z{z_offset+min(max_layer_z+70, printable_height-10)} F600 ; Move print head further up{endif}\n{if max_layer_z < max_print_height*0.6}G1 Z{printable_height*0.6} F600 ; Move print head further up{endif}\nM140 S0 ; turn off heatbed\nM104 S0 ; turn off temperature\nM107 ; turn off fan\nM84 X Y E ; disable motors",
"change_filament_gcode": "PAUSE",
"machine_pause_gcode": "PAUSE"
}
@@ -1,118 +0,0 @@
{
"type": "machine",
"name": "fdm_machine_common",
"from": "system",
"instantiation": "false",
"printer_technology": "FFF",
"deretraction_speed": [
"40"
],
"extruder_colour": [
"#FCE94F"
],
"extruder_offset": [
"0x0"
],
"gcode_flavor": "marlin",
"machine_max_acceleration_e": [
"5000"
],
"machine_max_acceleration_extruding": [
"10000"
],
"machine_max_acceleration_retracting": [
"1000"
],
"machine_max_acceleration_x": [
"10000"
],
"machine_max_acceleration_y": [
"10000"
],
"machine_max_acceleration_z": [
"500"
],
"machine_max_speed_e": [
"60"
],
"machine_max_speed_x": [
"500"
],
"machine_max_speed_y": [
"500"
],
"machine_max_speed_z": [
"10"
],
"machine_max_jerk_e": [
"5"
],
"machine_max_jerk_x": [
"8"
],
"machine_max_jerk_y": [
"8"
],
"machine_max_jerk_z": [
"0.4"
],
"machine_min_extruding_rate": [
"0"
],
"machine_min_travel_rate": [
"0"
],
"max_layer_height": [
"0.32"
],
"min_layer_height": [
"0.08"
],
"printable_height": "250",
"extruder_clearance_radius": "65",
"extruder_clearance_height_to_rod": "36",
"extruder_clearance_height_to_lid": "140",
"nozzle_diameter": [
"0.4"
],
"printer_settings_id": "",
"printer_variant": "0.4",
"retraction_minimum_travel": [
"2"
],
"retract_before_wipe": [
"70%"
],
"retract_when_changing_layer": [
"1"
],
"retraction_length": [
"1"
],
"retract_length_toolchange": [
"1"
],
"z_hop": [
"0"
],
"retract_restart_extra": [
"0"
],
"retract_restart_extra_toolchange": [
"0"
],
"retraction_speed": [
"60"
],
"single_extruder_multi_material": "1",
"change_filament_gcode": "",
"wipe": [
"1"
],
"default_print_profile": "",
"machine_start_gcode": "G0 Z20 F9000\nG92 E0; G1 E-10 F1200\nG28\nM970 Q1 A10 B10 C130 K0\nM970 Q1 A10 B131 C250 K1\nM974 Q1 S1 P0\nM970 Q0 A10 B10 C130 H20 K0\nM970 Q0 A10 B131 C250 K1\nM974 Q0 S1 P0\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nG29 ;Home\nG90;\nG92 E0 ;Reset Extruder \nG1 Z2.0 F3000 ;Move Z Axis up \nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S205;\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder \nG1 X110 Y110 Z2.0 F3000 ;Move Z Axis up",
"machine_end_gcode": "M400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-4.0 F3600; retract \nG91\nG1 Z3;\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nG90 \nG0 X110 Y200 F3600 \nprint_end",
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
"machine_pause_gcode": "M601"
}
@@ -1,26 +0,0 @@
{
"type": "process",
"name": "0.10mm Standard @Goofoo Velo+",
"inherits": "0.20mm Standard @Goofoo Velo+",
"from": "system",
"setting_id": "dJV4bTrLbOPzW2YB",
"instantiation": "true",
"compatible_printers": [
"Goofoo Velo+ 0.2 nozzle"
],
"layer_height": "0.1",
"initial_layer_print_height": "0.1",
"bottom_shell_layers": "6",
"top_shell_layers": "12",
"wall_loops": "4",
"line_width": "0.22",
"initial_layer_line_width": "0.25",
"inner_wall_line_width": "0.22",
"outer_wall_line_width": "0.22",
"sparse_infill_line_width": "0.22",
"internal_solid_infill_line_width": "0.22",
"top_surface_line_width": "0.22",
"support_line_width": "0.22",
"support_top_z_distance": "0.1",
"support_bottom_z_distance": "0.1"
}
@@ -1,35 +0,0 @@
{
"type": "process",
"name": "0.20mm Standard @Goofoo GP1",
"inherits": "fdm_process_klipper_common",
"from": "system",
"setting_id": "zrscQBUxp6L7BlQ9",
"instantiation": "true",
"compatible_printers": [
"Goofoo GP1 0.4 nozzle"
],
"layer_height": "0.2",
"accel_to_decel_enable": "0",
"bridge_acceleration": "100%",
"bridge_speed": "100",
"brim_type": "no_brim",
"gap_infill_speed": "250",
"initial_layer_acceleration": "1000",
"initial_layer_infill_speed": "100",
"initial_layer_speed": "70",
"inner_wall_speed": "250",
"internal_bridge_speed": "200%",
"internal_solid_infill_speed": "250",
"outer_wall_acceleration": "5000",
"outer_wall_speed": "100",
"overhang_4_4_speed": "0",
"reduce_crossing_wall": "1",
"skirt_distance": "6",
"skirt_height": "1",
"skirt_loops": "1",
"sparse_infill_pattern": "grid",
"sparse_infill_speed": "250",
"top_surface_acceleration": "5000",
"top_surface_speed": "200",
"travel_acceleration": "5000"
}
@@ -1,67 +0,0 @@
{
"type": "process",
"name": "0.20mm Standard @Goofoo TurboM",
"inherits": "fdm_process_klipper_common",
"from": "system",
"setting_id": "LVXxUtAcYGCY6irA",
"instantiation": "true",
"compatible_printers": [
"Goofoo TurboM 0.4 nozzle"
],
"layer_height": "0.2",
"bridge_acceleration": "2000",
"bridge_speed": "60",
"brim_type": "no_brim",
"default_acceleration": "10000",
"enable_support": "1",
"exclude_object": "0",
"gap_infill_speed": "200",
"infill_anchor": "600%",
"infill_combination": "1",
"infill_wall_overlap": "15%",
"initial_layer_acceleration": "1000",
"initial_layer_line_width": "0.45",
"initial_layer_speed": "60",
"inner_wall_acceleration": "3000",
"inner_wall_line_width": "0.42",
"inner_wall_speed": "150",
"internal_solid_infill_acceleration": "3000",
"internal_solid_infill_line_width": "0.42",
"internal_solid_infill_speed": "150",
"line_width": "0.42",
"min_skirt_length": "0",
"minimum_sparse_infill_area": "70",
"only_one_wall_top": "1",
"outer_wall_acceleration": "2500",
"outer_wall_line_width": "0.42",
"outer_wall_speed": "100",
"reduce_crossing_wall": "1",
"skirt_distance": "6",
"skirt_height": "1",
"skirt_loops": "4",
"small_perimeter_speed": "200",
"sparse_infill_acceleration": "3000",
"sparse_infill_line_width": "0.42",
"sparse_infill_pattern": "grid",
"sparse_infill_speed": "150",
"support_base_pattern": "rectilinear",
"support_interface_bottom_layers": "-1",
"support_interface_pattern": "rectilinear",
"support_interface_spacing": "0",
"support_interface_speed": "100",
"support_interface_top_layers": "3",
"support_line_width": "0.35",
"support_object_xy_distance": "0.21",
"support_speed": "100",
"thick_bridges": "1",
"top_shell_layers": "6",
"top_shell_thickness": "0",
"top_surface_acceleration": "2500",
"top_surface_line_width": "0.42",
"top_surface_speed": "150",
"travel_acceleration": "10000",
"travel_speed": "200",
"wall_generator": "classic",
"wall_loops": "2",
"wall_sequence": "outer wall/inner wall"
}
@@ -1,70 +0,0 @@
{
"type": "process",
"name": "0.20mm Standard @Goofoo Velo+",
"inherits": "fdm_process_klipper_common",
"from": "system",
"setting_id": "iWjynhCcvbF8MWev",
"instantiation": "true",
"compatible_printers": [
"Goofoo Velo+ 0.4 nozzle",
"Goofoo Velo+ Tool 0.4"
],
"layer_height": "0.2",
"initial_layer_print_height": "0.2",
"bottom_shell_layers": "3",
"top_shell_layers": "6",
"bridge_acceleration": "2000",
"bridge_speed": "60",
"brim_type": "no_brim",
"default_acceleration": "10000",
"enable_support": "1",
"exclude_object": "0",
"gap_infill_speed": "200",
"infill_anchor": "600%",
"infill_combination": "1",
"infill_wall_overlap": "15%",
"initial_layer_acceleration": "1000",
"initial_layer_line_width": "0.45",
"initial_layer_speed": "60",
"inner_wall_acceleration": "3000",
"inner_wall_line_width": "0.42",
"inner_wall_speed": "150",
"internal_solid_infill_acceleration": "3000",
"internal_solid_infill_line_width": "0.42",
"internal_solid_infill_speed": "150",
"line_width": "0.42",
"min_skirt_length": "0",
"minimum_sparse_infill_area": "70",
"only_one_wall_top": "1",
"outer_wall_acceleration": "2500",
"outer_wall_line_width": "0.42",
"outer_wall_speed": "100",
"reduce_crossing_wall": "1",
"skirt_distance": "6",
"skirt_height": "1",
"skirt_loops": "4",
"small_perimeter_speed": "200",
"sparse_infill_acceleration": "3000",
"sparse_infill_line_width": "0.42",
"sparse_infill_pattern": "grid",
"sparse_infill_speed": "150",
"support_base_pattern": "rectilinear",
"support_interface_bottom_layers": "-1",
"support_interface_pattern": "rectilinear",
"support_interface_spacing": "0",
"support_interface_speed": "100",
"support_interface_top_layers": "3",
"support_line_width": "0.35",
"support_object_xy_distance": "0.21",
"support_speed": "100",
"thick_bridges": "1",
"top_shell_thickness": "0",
"top_surface_acceleration": "2500",
"top_surface_line_width": "0.42",
"top_surface_speed": "150",
"travel_acceleration": "10000",
"travel_speed": "300",
"wall_generator": "classic",
"wall_loops": "2",
"wall_sequence": "outer wall/inner wall"
}
@@ -1,13 +0,0 @@
{
"type": "process",
"name": "0.30mm Standard @Goofoo Velo+",
"inherits": "fdm_process_klipper_common",
"from": "system",
"setting_id": "mi8ogYOYpqb2x60z",
"instantiation": "true",
"compatible_printers": [
"Goofoo Velo+ 0.6 nozzle"
],
"initial_layer_print_height": "0.3",
"layer_height": "0.3"
}
@@ -1,91 +0,0 @@
{
"type": "process",
"name": "fdm_process_common",
"from": "system",
"instantiation": "false",
"seam_position": "aligned",
"resolution": "0.012",
"elefant_foot_compensation": "0.2",
"precise_outer_wall": "1",
"ironing_type": "no ironing",
"ironing_speed": "30",
"ironing_flow": "10%",
"ironing_spacing": "0.15",
"reduce_crossing_wall": "1",
"max_travel_detour_distance": "0",
"detect_overhang_wall": "1",
"wall_loops": "3",
"top_surface_pattern": "monotonicline",
"top_shell_layers": "5",
"top_shell_thickness": "0.7",
"bottom_surface_pattern": "monotonic",
"bottom_shell_layers": "4",
"bottom_shell_thickness": "0.5",
"sparse_infill_density": "15%",
"sparse_infill_pattern": "crosshatch",
"infill_wall_overlap": "23%",
"infill_direction": "45",
"minimum_sparse_infill_area": "15",
"infill_combination": "0",
"ensure_vertical_shell_thickness": "1",
"initial_layer_speed": "50",
"initial_layer_infill_speed": "50",
"initial_layer_travel_speed": "100%",
"outer_wall_speed": "125",
"inner_wall_speed": "250",
"sparse_infill_speed": "250",
"internal_solid_infill_speed": "200",
"top_surface_speed": "150",
"gap_infill_speed": "150",
"support_speed": "125",
"support_interface_speed": "80",
"enable_overhang_speed": "1",
"overhang_1_4_speed": "0",
"overhang_2_4_speed": "50",
"overhang_3_4_speed": "25",
"overhang_4_4_speed": "15",
"bridge_speed": "50",
"travel_speed": "300",
"default_acceleration": "2500",
"outer_wall_acceleration": "500",
"inner_wall_acceleration": "500",
"bridge_acceleration": "500",
"travel_acceleration": "2500",
"default_jerk": "15",
"outer_wall_jerk": "10",
"inner_wall_jerk": "15",
"infill_jerk": "15",
"top_surface_jerk": "12",
"initial_layer_jerk": "12",
"travel_jerk": "20",
"enable_support": "0",
"support_type": "normal(auto)",
"support_threshold_angle": "30",
"support_on_build_plate_only": "0",
"raft_layers": "0",
"support_filament": "0",
"support_interface_filament": "0",
"support_top_z_distance": "0.2",
"support_base_pattern": "default",
"support_base_pattern_spacing": "2.5",
"support_interface_top_layers": "2",
"support_interface_bottom_layers": "2",
"support_interface_spacing": "0.5",
"support_object_xy_distance": "0.5",
"bridge_no_support": "0",
"independent_support_layer_height": "1",
"tree_support_branch_angle": "30",
"tree_support_wall_count": "0",
"skirt_loops": "2",
"skirt_distance": "3",
"skirt_height": "1",
"brim_width": "5",
"brim_object_gap": "0.1",
"enable_prime_tower": "0",
"prime_tower_width": "60",
"wipe_tower_no_sparse_layers": "0",
"print_sequence": "by layer",
"spiral_mode": "0",
"reduce_infill_retraction": "1",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}.gcode"
}
@@ -1,23 +0,0 @@
{
"type": "process",
"name": "fdm_process_klipper_common",
"inherits": "fdm_process_common",
"from": "system",
"instantiation": "false",
"default_acceleration": "5000",
"top_surface_acceleration": "3000",
"travel_acceleration": "7000",
"inner_wall_acceleration": "5000",
"outer_wall_acceleration": "3000",
"initial_layer_acceleration": "500",
"initial_layer_speed": "50",
"initial_layer_infill_speed": "105",
"outer_wall_speed": "120",
"inner_wall_speed": "200",
"internal_solid_infill_speed": "200",
"top_surface_speed": "100",
"gap_infill_speed": "100",
"sparse_infill_speed": "200",
"travel_speed": "350",
"exclude_object": "1"
}
+1 -161
View File
@@ -1,6 +1,6 @@
{
"name": "OrcaFilamentLibrary",
"version": "02.04.00.16",
"version": "02.04.00.15",
"force_update": "0",
"description": "Orca Filament Library",
"filament_list": [
@@ -1396,10 +1396,6 @@
"name": "addnorth ABS rABS",
"sub_path": "filament/addnorth/BBL/addnorth ABS rABS.json"
},
{
"name": "Goofoo ABS @base",
"sub_path": "filament/Goofoo/Goofoo ABS @base.json"
},
{
"name": "NIT ABS @System",
"sub_path": "filament/NIT/NIT ABS @System.json"
@@ -1484,10 +1480,6 @@
"name": "Elegoo ASA-CF @base",
"sub_path": "filament/Elegoo/Elegoo ASA-CF @base.json"
},
{
"name": "Goofoo ASA @base",
"sub_path": "filament/Goofoo/Goofoo ASA @base.json"
},
{
"name": "Overture ASA @BBL X1",
"sub_path": "filament/Overture/BBL/Overture ASA @BBL X1.json"
@@ -1644,22 +1636,10 @@
"name": "addnorth PVDF Adamant S1",
"sub_path": "filament/addnorth/BBL/addnorth PVDF Adamant S1.json"
},
{
"name": "Goofoo PA @base",
"sub_path": "filament/Goofoo/Goofoo PA @base.json"
},
{
"name": "addnorth PA-CF Adura X",
"sub_path": "filament/addnorth/BBL/addnorth PA-CF Adura X.json"
},
{
"name": "Goofoo PA-CF @base",
"sub_path": "filament/Goofoo/Goofoo PA-CF @base.json"
},
{
"name": "Goofoo PA-GF10 @base",
"sub_path": "filament/Goofoo/Goofoo PA-GF10 @base.json"
},
{
"name": "INSLOGIC PA6-66 @BBL P2S",
"sub_path": "filament/INSLOGIC/BBL/INSLOGIC PA6-66 @BBL P2S.json"
@@ -1732,10 +1712,6 @@
"name": "COEX PCTG PRIME @System",
"sub_path": "filament/COEX/COEX PCTG PRIME @System.json"
},
{
"name": "Goofoo PE @base",
"sub_path": "filament/Goofoo/Goofoo PE @base.json"
},
{
"name": "Generic PE-CF @System",
"sub_path": "filament/Generic PE-CF @System.json"
@@ -2200,10 +2176,6 @@
"name": "addnorth PETG rPETG Matte",
"sub_path": "filament/addnorth/BBL/addnorth PETG rPETG Matte.json"
},
{
"name": "Goofoo PETG @base",
"sub_path": "filament/Goofoo/Goofoo PETG @base.json"
},
{
"name": "Generic PETG HF @System",
"sub_path": "filament/Generic PETG HF @System.json"
@@ -2264,10 +2236,6 @@
"name": "eSUN PETG @System",
"sub_path": "filament/eSUN/eSUN PETG @System.json"
},
{
"name": "Goofoo PHA @base",
"sub_path": "filament/Goofoo/Goofoo PHA @base.json"
},
{
"name": "AliZ PLA @P1-X1",
"sub_path": "filament/AliZ/BBL/AliZ PLA @P1-X1.json"
@@ -3152,10 +3120,6 @@
"name": "addnorth PLA rPLA RE-ADD",
"sub_path": "filament/addnorth/BBL/addnorth PLA rPLA RE-ADD.json"
},
{
"name": "Goofoo PLA @base",
"sub_path": "filament/Goofoo/Goofoo PLA @base.json"
},
{
"name": "addnorth PLA X-PLA High Speed",
"sub_path": "filament/addnorth/BBL/addnorth PLA X-PLA High Speed.json"
@@ -3172,10 +3136,6 @@
"name": "addnorth PLA-CF Carbon Fiber",
"sub_path": "filament/addnorth/BBL/addnorth PLA-CF Carbon Fiber.json"
},
{
"name": "Goofoo PLA-CF @base",
"sub_path": "filament/Goofoo/Goofoo PLA-CF @base.json"
},
{
"name": "INSLOGIC PLA Pro @BBL P2S",
"sub_path": "filament/INSLOGIC/BBL/INSLOGIC PLA Pro @BBL P2S.json"
@@ -3860,10 +3820,6 @@
"name": "FILL3D PPCF @System",
"sub_path": "filament/FILL3D/FILL3D PPCF @System.json"
},
{
"name": "Goofoo PP @base",
"sub_path": "filament/Goofoo/Goofoo PP @base.json"
},
{
"name": "Generic PP-CF @System",
"sub_path": "filament/Generic PP-CF @System.json"
@@ -3884,10 +3840,6 @@
"name": "Bambu PVA @System",
"sub_path": "filament/Bambu/Bambu PVA @System.json"
},
{
"name": "Goofoo PVA @base",
"sub_path": "filament/Goofoo/Goofoo PVA @base.json"
},
{
"name": "FDplast SBS @System",
"sub_path": "filament/FDplast/FDplast SBS @System.json"
@@ -4160,14 +4112,6 @@
"name": "addnorth TPU Pro Matte 95A",
"sub_path": "filament/addnorth/BBL/addnorth TPU Pro Matte 95A.json"
},
{
"name": "Goofoo 90A TPU @base",
"sub_path": "filament/Goofoo/Goofoo 90A TPU @base.json"
},
{
"name": "Goofoo 95A TPU @base",
"sub_path": "filament/Goofoo/Goofoo 95A TPU @base.json"
},
{
"name": "Overture TPU @BBL A1",
"sub_path": "filament/Overture/BBL/Overture TPU @BBL A1.json"
@@ -4212,30 +4156,10 @@
"name": "Overture TPU @System",
"sub_path": "filament/Overture/Overture TPU @System.json"
},
{
"name": "Goofoo ABS @System",
"sub_path": "filament/Goofoo/Goofoo ABS @System.json"
},
{
"name": "Elegoo ASA-CF @System",
"sub_path": "filament/Elegoo/Elegoo ASA-CF @System.json"
},
{
"name": "Goofoo ASA @System",
"sub_path": "filament/Goofoo/Goofoo ASA @System.json"
},
{
"name": "Goofoo PA @System",
"sub_path": "filament/Goofoo/Goofoo PA @System.json"
},
{
"name": "Goofoo PA-CF @System",
"sub_path": "filament/Goofoo/Goofoo PA-CF @System.json"
},
{
"name": "Goofoo PA-GF10 @System",
"sub_path": "filament/Goofoo/Goofoo PA-GF10 @System.json"
},
{
"name": "Elegoo PC-FR @System",
"sub_path": "filament/Elegoo/Elegoo PC-FR @System.json"
@@ -4252,14 +4176,6 @@
"name": "COEX PCTG PRIME @BBL A1M 0.8 nozzle",
"sub_path": "filament/COEX/BBL/COEX PCTG PRIME @BBL A1M 0.8 nozzle.json"
},
{
"name": "Goofoo PE @System",
"sub_path": "filament/Goofoo/Goofoo PE @System.json"
},
{
"name": "Goofoo PE-CF @base",
"sub_path": "filament/Goofoo/Goofoo PE-CF @base.json"
},
{
"name": "AliZ PETG-CF @P1-X1",
"sub_path": "filament/AliZ/BBL/AliZ PETG-CF @P1-X1.json"
@@ -4320,26 +4236,10 @@
"name": "Fiberon PETG-ESD @BBL X1",
"sub_path": "filament/Polymaker/BBL/Fiberon PETG-ESD @BBL X1.json"
},
{
"name": "Goofoo PETG @System",
"sub_path": "filament/Goofoo/Goofoo PETG @System.json"
},
{
"name": "Goofoo PETG HF @base",
"sub_path": "filament/Goofoo/Goofoo PETG HF @base.json"
},
{
"name": "addnorth PETG-CF Rigid X",
"sub_path": "filament/addnorth/BBL/addnorth PETG-CF Rigid X.json"
},
{
"name": "Goofoo PETG-CF @base",
"sub_path": "filament/Goofoo/Goofoo PETG-CF @base.json"
},
{
"name": "Goofoo PHA @System",
"sub_path": "filament/Goofoo/Goofoo PHA @System.json"
},
{
"name": "COEX PLA @BBL A1M 0.2 nozzle",
"sub_path": "filament/COEX/BBL/COEX PLA @BBL A1M 0.2 nozzle.json"
@@ -4404,14 +4304,6 @@
"name": "Elegoo Rapid PLA+ @System",
"sub_path": "filament/Elegoo/Elegoo Rapid PLA+ @System.json"
},
{
"name": "Goofoo PLA @System",
"sub_path": "filament/Goofoo/Goofoo PLA @System.json"
},
{
"name": "Goofoo PLA-CF @System",
"sub_path": "filament/Goofoo/Goofoo PLA-CF @System.json"
},
{
"name": "Numakers PLA+ @BBL A1",
"sub_path": "filament/Numakers/BBL/Numakers PLA+ @BBL A1.json"
@@ -5296,61 +5188,9 @@
"name": "COEX PLA+Silk @System",
"sub_path": "filament/COEX/COEX PLA+Silk @System.json"
},
{
"name": "Goofoo PLA Silk @base",
"sub_path": "filament/Goofoo/Goofoo PLA Silk @base.json"
},
{
"name": "Goofoo PP @System",
"sub_path": "filament/Goofoo/Goofoo PP @System.json"
},
{
"name": "Goofoo PP-CF @base",
"sub_path": "filament/Goofoo/Goofoo PP-CF @base.json"
},
{
"name": "Goofoo PP-GF @base",
"sub_path": "filament/Goofoo/Goofoo PP-GF @base.json"
},
{
"name": "Goofoo PVA @System",
"sub_path": "filament/Goofoo/Goofoo PVA @System.json"
},
{
"name": "Elegoo Rapid TPU 95A @System",
"sub_path": "filament/Elegoo/Elegoo Rapid TPU 95A @System.json"
},
{
"name": "Goofoo 90A TPU @System",
"sub_path": "filament/Goofoo/Goofoo 90A TPU @System.json"
},
{
"name": "Goofoo 95A TPU @System",
"sub_path": "filament/Goofoo/Goofoo 95A TPU @System.json"
},
{
"name": "Goofoo PE-CF @System",
"sub_path": "filament/Goofoo/Goofoo PE-CF @System.json"
},
{
"name": "Goofoo PETG HF @System",
"sub_path": "filament/Goofoo/Goofoo PETG HF @System.json"
},
{
"name": "Goofoo PETG-CF @System",
"sub_path": "filament/Goofoo/Goofoo PETG-CF @System.json"
},
{
"name": "Goofoo PLA Silk @System",
"sub_path": "filament/Goofoo/Goofoo PLA Silk @System.json"
},
{
"name": "Goofoo PP-CF @System",
"sub_path": "filament/Goofoo/Goofoo PP-CF @System.json"
},
{
"name": "Goofoo PP-GF @System",
"sub_path": "filament/Goofoo/Goofoo PP-GF @System.json"
}
],
"process_list": [],
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo 90A TPU @System",
"inherits": "Goofoo 90A TPU @base",
"from": "system",
"setting_id": "tjq76AQe9SCzZVo6",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,41 +0,0 @@
{
"type": "filament",
"name": "Goofoo 90A TPU @base",
"inherits": "Generic TPU @System",
"from": "system",
"filament_id": "OFlVOXX3",
"instantiation": "false",
"fan_cooling_layer_time": [
"60"
],
"fan_min_speed": [
"35"
],
"filament_max_volumetric_speed": [
"2"
],
"hot_plate_temp": [
"40"
],
"hot_plate_temp_initial_layer": [
"40"
],
"nozzle_temperature": [
"220"
],
"nozzle_temperature_initial_layer": [
"220"
],
"reduce_fan_stop_start_freq": [
"0"
],
"slow_down_layer_time": [
"5"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"TPU"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo 95A TPU @System",
"inherits": "Goofoo 95A TPU @base",
"from": "system",
"setting_id": "2YTvrE1gu1yHHTNM",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,38 +0,0 @@
{
"type": "filament",
"name": "Goofoo 95A TPU @base",
"inherits": "Generic TPU @System",
"from": "system",
"filament_id": "OFk50t30",
"instantiation": "false",
"fan_cooling_layer_time": [
"60"
],
"fan_min_speed": [
"35"
],
"hot_plate_temp": [
"40"
],
"hot_plate_temp_initial_layer": [
"40"
],
"nozzle_temperature": [
"220"
],
"nozzle_temperature_initial_layer": [
"220"
],
"reduce_fan_stop_start_freq": [
"0"
],
"slow_down_layer_time": [
"5"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"TPU"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo ABS @System",
"inherits": "Goofoo ABS @base",
"from": "system",
"setting_id": "UeINgPGH4eaSJinC",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,23 +0,0 @@
{
"type": "filament",
"name": "Goofoo ABS @base",
"inherits": "Generic ABS @System",
"from": "system",
"filament_id": "OFd3PmW4",
"instantiation": "false",
"close_fan_the_first_x_layers": [
"1"
],
"hot_plate_temp": [
"110"
],
"hot_plate_temp_initial_layer": [
"110"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"ABS"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo ASA @System",
"inherits": "Goofoo ASA @base",
"from": "system",
"setting_id": "9ohqNl44uygTPfS9",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,20 +0,0 @@
{
"type": "filament",
"name": "Goofoo ASA @base",
"inherits": "Generic ASA @System",
"from": "system",
"filament_id": "OFyncHIG",
"instantiation": "false",
"filament_flow_ratio": [
"0.93"
],
"hot_plate_temp_initial_layer": [
"100"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"ASA"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA @System",
"inherits": "Goofoo PA @base",
"from": "system",
"setting_id": "1ximJVgZZfGmGyzD",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,20 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA @base",
"inherits": "Generic PA @System",
"from": "system",
"filament_id": "OFc2x7Ly",
"instantiation": "false",
"filament_max_volumetric_speed": [
"12"
],
"reduce_fan_stop_start_freq": [
"1"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PA"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA-CF @System",
"inherits": "Goofoo PA-CF @base",
"from": "system",
"setting_id": "US4zznMNti8tLUHG",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,17 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA-CF @base",
"inherits": "Generic PA-CF @System",
"from": "system",
"filament_id": "OF7skcRj",
"instantiation": "false",
"filament_max_volumetric_speed": [
"12"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PA-CF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA-GF10 @System",
"inherits": "Goofoo PA-GF10 @base",
"from": "system",
"setting_id": "Lea3hf2lQG0M9eTC",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,23 +0,0 @@
{
"type": "filament",
"name": "Goofoo PA-GF10 @base",
"inherits": "Generic PA-CF @System",
"from": "system",
"filament_id": "OFtjqw2h",
"instantiation": "false",
"nozzle_temperature": [
"230"
],
"nozzle_temperature_initial_layer": [
"230"
],
"reduce_fan_stop_start_freq": [
"1"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PA-GF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PE @System",
"inherits": "Goofoo PE @base",
"from": "system",
"setting_id": "muNxvgr0vdavMaOJ",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PE @base",
"inherits": "Generic PE @System",
"from": "system",
"filament_id": "OFAln723",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PE"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PE-CF @System",
"inherits": "Goofoo PE-CF @base",
"from": "system",
"setting_id": "58fMbg6AClvalw5o",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PE-CF @base",
"inherits": "Generic PE-CF @System",
"from": "system",
"filament_id": "OF4Ll1Sk",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PE-CF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG @System",
"inherits": "Goofoo PETG @base",
"from": "system",
"setting_id": "a9OKgJeoJgzfZiAB",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,26 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG @base",
"inherits": "Generic PETG @System",
"from": "system",
"filament_id": "OFHdIbiu",
"instantiation": "false",
"hot_plate_temp": [
"80"
],
"hot_plate_temp_initial_layer": [
"80"
],
"nozzle_temperature": [
"240"
],
"nozzle_temperature_initial_layer": [
"240"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PETG"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG HF @System",
"inherits": "Goofoo PETG HF @base",
"from": "system",
"setting_id": "eMjhTRf5qPeeqSgk",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG HF @base",
"inherits": "Generic PETG HF @System",
"from": "system",
"filament_id": "OF5bjxyx",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PETG HF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG-CF @System",
"inherits": "Goofoo PETG-CF @base",
"from": "system",
"setting_id": "ULNFo6zjgjc5MEIa",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PETG-CF @base",
"inherits": "Generic PETG-CF @System",
"from": "system",
"filament_id": "OFo6Ff38",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PETG-CF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PHA @System",
"inherits": "Goofoo PHA @base",
"from": "system",
"setting_id": "cfdeMyqld72Lqh38",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PHA @base",
"inherits": "Generic PHA @System",
"from": "system",
"filament_id": "OFicmNhN",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PHA"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA @System",
"inherits": "Goofoo PLA @base",
"from": "system",
"setting_id": "UFWRE1b3706Cu1Iq",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,26 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA @base",
"inherits": "Generic PLA @System",
"from": "system",
"filament_id": "OFoq0Cmt",
"instantiation": "false",
"hot_plate_temp": [
"40"
],
"hot_plate_temp_initial_layer": [
"40"
],
"nozzle_temperature": [
"230"
],
"nozzle_temperature_initial_layer": [
"230"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PLA"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA Silk @System",
"inherits": "Goofoo PLA Silk @base",
"from": "system",
"setting_id": "2pW2NEoY4hFCkNun",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA Silk @base",
"inherits": "Generic PLA Silk @System",
"from": "system",
"filament_id": "OFpta2gc",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PLA Silk"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA-CF @System",
"inherits": "Goofoo PLA-CF @base",
"from": "system",
"setting_id": "R0UMDUPY9ryat8gQ",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,29 +0,0 @@
{
"type": "filament",
"name": "Goofoo PLA-CF @base",
"inherits": "Generic PLA-CF @System",
"from": "system",
"filament_id": "OFMNABGJ",
"instantiation": "false",
"filament_flow_ratio": [
"0.98"
],
"hot_plate_temp": [
"40"
],
"hot_plate_temp_initial_layer": [
"40"
],
"nozzle_temperature": [
"240"
],
"nozzle_temperature_initial_layer": [
"240"
],
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PLA-CF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP @System",
"inherits": "Goofoo PP @base",
"from": "system",
"setting_id": "TaB8JUtjJWgRcNrv",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP @base",
"inherits": "Generic PP @System",
"from": "system",
"filament_id": "OFlqlUSx",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PP"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP-CF @System",
"inherits": "Goofoo PP-CF @base",
"from": "system",
"setting_id": "uHocbocT6flJhlBz",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP-CF @base",
"inherits": "Generic PP-CF @System",
"from": "system",
"filament_id": "OFUUiuIV",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PP-CF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP-GF @System",
"inherits": "Goofoo PP-GF @base",
"from": "system",
"setting_id": "mns8gICV0aNwJ02L",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PP-GF @base",
"inherits": "Generic PP-GF @System",
"from": "system",
"filament_id": "OFaOhzl8",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PP-GF"
]
}
@@ -1,9 +0,0 @@
{
"type": "filament",
"name": "Goofoo PVA @System",
"inherits": "Goofoo PVA @base",
"from": "system",
"setting_id": "tUXbv31nYkXJ87OT",
"instantiation": "true",
"compatible_printers": []
}
@@ -1,14 +0,0 @@
{
"type": "filament",
"name": "Goofoo PVA @base",
"inherits": "Generic PVA @System",
"from": "system",
"filament_id": "OF86rkt6",
"instantiation": "false",
"filament_vendor": [
"Goofoo"
],
"filament_type": [
"PVA"
]
}
-410
View File
@@ -1,410 +0,0 @@
# /// script
# requires-python = ">=3.12"
#
# [tool.orcaslicer.plugin]
# id = "reload-local-bundle-demo"
# name = "Reload Local Bundle Demo"
# description = "Manages local filament, process, and printer profiles with live bundle reload."
# author = "OrcaSlicer contributors"
# version = "0.1.0"
# ///
"""A small interactive consumer of ``orca.host.preset.bundles.reload_local``."""
import json
import os
import tempfile
import orca
BUNDLE_ID = "reload-local-bundle-demo"
STATE_FILE = ".reload-local-bundle-demo-state.json"
DEMO_PRESETS = (
{
"id": "filament",
"name": "Local Bundle Demo Filament",
"kind": "Filament",
"type": "filament",
"directory": "filament",
"collection": "filaments",
"setting_key": "filament_settings_id",
},
{
"id": "process",
"name": "Local Bundle Demo Process",
"kind": "Process",
"type": "process",
"directory": "process",
"collection": "prints",
"setting_key": "print_settings_id",
},
{
"id": "printer",
"name": "Local Bundle Demo Printer",
"kind": "Printer",
"type": "machine",
"directory": "machine",
"collection": "printers",
"setting_key": "printer_settings_id",
},
)
def _data_dir():
parts = os.path.abspath(__file__).replace("\\", "/").split("/")
if "orca_plugins" not in parts:
raise RuntimeError("Install this file as a local OrcaSlicer plugin")
return "/".join(parts[: parts.index("orca_plugins")])
def _folder_from_preset_file(path):
parts = os.path.normpath(path or "").replace("\\", "/").split("/")
try:
return parts[parts.index("user") + 1]
except (ValueError, IndexError):
return None
def _bundle_dir(bundle):
for collection in (bundle.filaments, bundle.prints, bundle.printers):
for index in range(collection.size()):
folder = _folder_from_preset_file(collection.preset(index).file)
if folder:
return os.path.join(_data_dir(), "user", folder, "_local", BUNDLE_ID)
return os.path.join(_data_dir(), "user", "default", "_local", BUNDLE_ID)
def _source_path(bundle, item):
return os.path.join(_bundle_dir(bundle), item["directory"], item["name"] + ".json")
def _state_path(bundle):
return os.path.join(_bundle_dir(bundle), STATE_FILE)
def _write_json_atomic(path, value):
os.makedirs(os.path.dirname(path), exist_ok=True)
descriptor, temporary = tempfile.mkstemp(
prefix="." + os.path.basename(path) + ".", suffix=".tmp", dir=os.path.dirname(path)
)
try:
with os.fdopen(descriptor, "w", encoding="utf-8") as stream:
json.dump(value, stream, ensure_ascii=False, indent=2)
stream.write("\n")
os.replace(temporary, path)
except Exception:
try:
os.unlink(temporary)
except OSError:
pass
raise
def _remove_file(path):
try:
os.unlink(path)
except FileNotFoundError:
pass
def _read_state(bundle):
try:
with open(_state_path(bundle), "r", encoding="utf-8") as stream:
state = json.load(stream)
except FileNotFoundError:
return {"profiles": {}}
except (OSError, ValueError) as error:
raise RuntimeError("The demo state file cannot be read: %s" % error)
if not isinstance(state, dict) or not isinstance(state.get("profiles"), dict):
raise RuntimeError("The demo state file has an invalid shape")
return state
def _profile_state(state, item):
profiles = state["profiles"]
profile = profiles.get(item["id"])
if profile is None:
profile = {}
profiles[item["id"]] = profile
if not isinstance(profile, dict):
raise RuntimeError("The demo state for %s has an invalid shape" % item["name"])
profile["enabled"] = profile.get("enabled") is True
profile["deleted"] = profile.get("deleted") is True
if profile["deleted"]:
profile["enabled"] = False
profile["parent_name"] = str(profile.get("parent_name") or "")
return profile
def _collection(bundle, item):
return getattr(bundle, item["collection"])
def _target_name(item):
return "_local/%s/%s" % (BUNDLE_ID, item["name"])
def _parent_name(bundle, item):
collection = _collection(bundle, item)
own_names = {
_target_name(candidate)
for candidate in DEMO_PRESETS
if candidate["collection"] == item["collection"]
}
candidates = [collection.selected_preset()]
candidates.extend(collection.preset(index) for index in range(collection.size()))
for preset in candidates:
if preset.name not in own_names:
return preset.name
raise RuntimeError("A parent %s preset is required for this demo" % item["kind"].lower())
def _parent_is_live(bundle, item, name):
return bool(name) and name not in {_target_name(item)} and _collection(bundle, item).find_preset(name) is not None
def _profile(item, parent_name):
return {
"type": item["type"],
"name": item["name"],
"from": "User",
"instantiation": "true",
"version": "1.0.0",
"inherits": parent_name,
item["setting_key"]: item["name"],
}
def _reconcile(bundle, state):
for item in DEMO_PRESETS:
profile = _profile_state(state, item)
if profile["enabled"] and not profile["deleted"] and not _parent_is_live(bundle, item, profile["parent_name"]):
profile["parent_name"] = _parent_name(bundle, item)
for item in DEMO_PRESETS:
profile = _profile_state(state, item)
path = _source_path(bundle, item)
if profile["enabled"] and not profile["deleted"]:
_write_json_atomic(path, _profile(item, profile["parent_name"]))
else:
_remove_file(path)
_write_json_atomic(
os.path.join(_bundle_dir(bundle), "bundle_metadata.json"),
{"id": BUNDLE_ID, "name": "Reload Local Bundle Demo", "version": "0.1.0"},
)
_write_json_atomic(_state_path(bundle), state)
orca.host.preset.bundles.reload_local(BUNDLE_ID)
def _state_payload(bundle, state, message="", error=""):
items = []
for item in DEMO_PRESETS:
profile = _profile_state(state, item)
items.append(
{
"id": item["id"],
"name": item["name"],
"kind": item["kind"],
"enabled": profile["enabled"],
"deleted": profile["deleted"],
"loaded": _collection(bundle, item).find_preset(_target_name(item)) is not None,
}
)
return {
"command": "state",
"items": items,
"bundles": orca.host.preset.bundles.list_ids(),
"message": message,
"error": error,
}
PAGE = r"""<!doctype html>
<html><head><meta charset="utf-8"><style>
:root { color-scheme: light dark; font: 14px system-ui, sans-serif; }
body { margin: 0; padding: 16px; background: Canvas; color: CanvasText; }
.profiles { display: grid; gap: 9px; }
.profile { border: 1px solid rgba(127, 127, 127, .4); border-radius: 8px; padding: 11px; }
.top, .bottom { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.top { margin-bottom: 10px; }
.name { font-weight: 650; }
.kind, .message { color: GrayText; font-size: 12px; }
.status { border-radius: 999px; padding: 3px 8px; font-size: 12px; white-space: nowrap; }
.loaded { background: #0b8f5a; color: white; }
.disabled, .deleted { background: rgba(127, 127, 127, .25); }
.missing { background: #be4b0a; color: white; }
.toggle { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; }
.toggle input { position: absolute; opacity: 0; pointer-events: none; }
.switch { width: 34px; height: 20px; border-radius: 999px; background: rgba(127, 127, 127, .45); position: relative; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 14px; height: 14px; border-radius: 50%; background: white; transition: transform .15s ease; }
.toggle input:checked + .switch { background: #008f7a; }
.toggle input:checked + .switch::after { transform: translateX(14px); }
.toggle input:disabled + .switch, button:disabled { opacity: .5; cursor: wait; }
button { border: 0; border-radius: 6px; padding: 6px 10px; font: inherit; cursor: pointer; background: #b64036; color: white; }
button.secondary { background: rgba(127, 127, 127, .25); color: CanvasText; }
.actions { display: flex; justify-content: flex-end; margin-top: 14px; }
.message { min-height: 18px; margin-top: 10px; }
.error { color: #d13c32; }
.help { margin: 0 0 12px; color: GrayText; font-size: 12px; line-height: 1.4; }
.help summary { color: CanvasText; cursor: pointer; font-weight: 650; }
.help p { margin: 7px 0 0; }
h2 { margin: 16px 0 8px; font-size: 13px; }
.bundles { display: grid; gap: 6px; }
.bundle { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.bundle code { overflow-wrap: anywhere; }
</style></head><body>
<details class="help"><summary>How it works</summary><p>Each row controls one profile in this local bundle. A switch adds or removes its source file; Delete removes the demo record and Restore returns it disabled. Every action reloads this bundle across filament, process, and machine. Local bundles lists every bundle id that orca.host.preset.bundles.list_ids() reports; Reload calls orca.host.preset.bundles.reload_local() for that id.</p></details>
<div class="profiles" id="profiles"></div>
<h2>Local bundles</h2>
<div class="bundles" id="bundles"></div>
<div class="actions"><button class="secondary" id="close">Close</button></div>
<div class="message" id="message"></div>
<script>
'use strict';
const $ = id => document.getElementById(id);
let items = [];
let bundles = [];
let busy = false;
function esc(value) {
return String(value == null ? '' : value).replace(/[&<>"']/g, c =>
({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
function status(item) {
if (item.deleted) return ['deleted', 'Deleted'];
if (item.loaded) return ['loaded', 'Loaded'];
if (item.enabled) return ['missing', 'Missing after reload'];
return ['disabled', 'Not in Orca'];
}
function setBusy(value) {
document.querySelectorAll('[data-toggle], [data-action]').forEach(control => control.disabled = value);
}
function render(message, error) {
$('profiles').innerHTML = items.map(item => {
const state = status(item);
const deleted = item.deleted ? ' disabled' : '';
const action = item.deleted
? '<button class="secondary" data-action="restore" data-id="' + esc(item.id) + '">Restore</button>'
: '<button data-action="delete" data-id="' + esc(item.id) + '">Delete</button>';
return '<section class="profile"><div class="top"><div><div class="name">' + esc(item.name) +
'</div><div class="kind">' + esc(item.kind) + '</div></div><span class="status ' + state[0] +
'">' + state[1] + '</span></div><div class="bottom"><label class="toggle"><input type="checkbox" data-toggle="' +
esc(item.id) + '"' + (item.enabled ? ' checked' : '') + deleted + '><span class="switch"></span>Available in Orca</label>' +
action + '</div></section>';
}).join('');
$('bundles').innerHTML = bundles.length ? bundles.map(id =>
'<div class="bundle"><code>' + esc(id) + '</code><button class="secondary" data-action="reload_bundle" data-bundle="' +
esc(id) + '">Reload</button></div>').join('') : '<div class="kind">No local bundles found.</div>';
$('message').textContent = error || message || '';
$('message').className = error ? 'message error' : 'message';
if (busy) setBusy(true);
}
function post(message) {
busy = true;
setBusy(true);
$('message').textContent = 'Reloading local bundle…';
$('message').className = 'message';
orca.postMessage(message);
}
$('close').addEventListener('click', () => orca.close());
$('profiles').addEventListener('change', event => {
if (!busy && event.target.matches('[data-toggle]')) {
post({command: 'set_enabled', id: event.target.dataset.toggle, enabled: event.target.checked});
}
});
$('profiles').addEventListener('click', event => {
const button = event.target.closest('[data-action]');
if (!button || busy) return;
if (button.dataset.action === 'delete' && !confirm('Delete this demo profile from the local bundle?')) return;
post({command: button.dataset.action, id: button.dataset.id});
});
$('bundles').addEventListener('click', event => {
const button = event.target.closest('[data-action="reload_bundle"]');
if (button && !busy) post({command: 'reload_bundle', bundle_id: button.dataset.bundle});
});
orca.onMessage(message => {
if (!message || message.command !== 'state') return;
items = message.items || [];
bundles = message.bundles || [];
busy = false;
render(message.message, message.error);
});
orca.postMessage({command: 'state'});
</script></body></html>"""
class ReloadLocalBundleDemo(orca.script.ScriptPluginCapabilityBase):
window = None
def get_name(self):
return "Reload local bundle demo"
def execute(self):
try:
if self.window is not None and self.window.is_open():
self._post_state()
return orca.ExecutionResult.success("Reload local bundle demo refreshed.")
self.window = orca.host.ui.create_window(
title="Reload local bundle demo", html=PAGE, width=500, height=420,
on_message=self.on_message, on_close=self.on_close,
)
return orca.ExecutionResult.success("Reload local bundle demo opened.")
except Exception as error:
message = "Reload local bundle demo failed: %s" % error
orca.host.ui.message(message, title="Reload local bundle demo", buttons="ok", icon="error")
return orca.ExecutionResult.failure(orca.PluginResult.RecoverableError, message)
def on_close(self):
self.window = None
def _post_state(self, message="", error=""):
try:
bundle = orca.host.preset_bundle()
payload = _state_payload(bundle, _read_state(bundle), message, error)
except Exception as state_error:
payload = {"command": "state", "items": [], "message": message, "error": str(state_error)}
if self.window is not None and self.window.is_open():
self.window.post(payload)
def on_message(self, message):
try:
message = message or {}
bundle = orca.host.preset_bundle()
state = _read_state(bundle)
if message.get("command") == "state":
self._post_state()
return
if message.get("command") == "reload_bundle":
bundle_id = message.get("bundle_id")
if not isinstance(bundle_id, str) or not bundle_id:
raise RuntimeError("A bundle id is required")
orca.host.preset.bundles.reload_local(bundle_id)
self._post_state(message="Reloaded local bundle %s." % bundle_id)
return
item = next((item for item in DEMO_PRESETS if item["id"] == message.get("id")), None)
if item is None:
raise RuntimeError("Unknown demo preset")
profile = _profile_state(state, item)
command = message.get("command")
if command == "set_enabled":
enabled = message.get("enabled")
if not isinstance(enabled, bool):
raise RuntimeError("Preset availability must be a boolean")
if profile["deleted"]:
raise RuntimeError("Restore the deleted demo preset before enabling it")
profile["enabled"] = enabled
elif command == "delete":
profile.update({"enabled": False, "deleted": True, "parent_name": ""})
elif command == "restore":
profile.update({"enabled": False, "deleted": False, "parent_name": ""})
else:
raise RuntimeError("Unknown demo action")
_reconcile(bundle, state)
self._post_state(message="The change was applied. Check the corresponding preset selector in Orca.")
except Exception as error:
self._post_state(error=str(error))
@orca.plugin
class ReloadLocalBundleDemoPackage(orca.base):
def register_capabilities(self):
orca.register_capability(ReloadLocalBundleDemo)
+5 -16
View File
@@ -1822,7 +1822,7 @@ PresetCollection::UserPresetLoad PresetCollection::resolve_user_preset(
const boost::filesystem::path &file, const std::string &canonical_name,
const PresetOrigin &load_origin, ForwardCompatibilitySubstitutionRule substitution_rule,
const std::string &extruder_id_name, const std::string &extruder_variant_name,
std::set<std::string> *key_set1, std::set<std::string> *key_set2, bool read_only) const
std::set<std::string> *key_set1, std::set<std::string> *key_set2) const
{
UserPresetLoad out;
out.preset = Preset(m_type, canonical_name, false);
@@ -1856,10 +1856,7 @@ PresetCollection::UserPresetLoad PresetCollection::resolve_user_preset(
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
boost::optional<Semver> version = Semver::parse(version_str);
if (!version) {
out.errors.push_back((boost::format("invalid version %1% in config %2%") % version_str % preset.file).str());
return out;
}
if (!version) return out;
preset.version = *version;
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
@@ -1881,12 +1878,6 @@ PresetCollection::UserPresetLoad PresetCollection::resolve_user_preset(
inherit_preset = this->find_preset2(inherits_value);
Preset::normalize_inherits(config, inherit_preset);
}
// Local hot reload only supports FFF; no SLA default printer is installed.
if (read_only && load_origin.kind == PresetOrigin::Kind::LocalBundle && m_type == Preset::TYPE_PRINTER &&
Preset::printer_technology(config) != ptFFF) {
out.errors.push_back((boost::format("local bundle printer %1% is not FFF") % preset.file).str());
return out;
}
const Preset& default_preset = this->default_preset_for(config);
if (inherit_preset) {
preset.config = inherit_preset->config;
@@ -2051,7 +2042,7 @@ void PresetCollection::load_presets(
resolve_then_commit<CNumericLocalesSetter>(files.size(),
[&](size_t i) {
return this->resolve_user_preset(files[i].path, files[i].canonical_name, resolved_origin, substitution_rule,
extruder_id_name, extruder_variant_name, key_set1, key_set2, read_only);
extruder_id_name, extruder_variant_name, key_set1, key_set2);
},
[&](size_t i, UserPresetLoad &&loaded) {
// Resolve read the files without the lock, so another instance may have saved
@@ -2071,7 +2062,7 @@ void PresetCollection::load_presets(
if (! (on_disk == loaded.on_disk)) {
CNumericLocalesSetter locales_setter;
loaded = this->resolve_user_preset(files[i].path, files[i].canonical_name, resolved_origin, substitution_rule,
extruder_id_name, extruder_variant_name, key_set1, key_set2, read_only);
extruder_id_name, extruder_variant_name, key_set1, key_set2);
}
}
const bool leave_files = read_only || (! lock_path.empty() && ! instance_lock.locked());
@@ -3144,9 +3135,7 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
}
// Insert a new profile.
//BBS: add project embedded preset logic
// A G-code's settings are shown like a project's, so a preset made from them lives with the project
// rather than in the user's library.
bool from_project = boost::algorithm::iends_with(name, ".3mf") || is_gcode_file(name);
bool from_project = boost::algorithm::iends_with(name, ".3mf");
if (m_type == Preset::TYPE_PRINT)
cfg.option<ConfigOptionString >("print_settings_id", true)->value = new_name;
else if (m_type == Preset::TYPE_FILAMENT)
+1 -2
View File
@@ -991,8 +991,7 @@ private:
UserPresetLoad resolve_user_preset(const boost::filesystem::path &file, const std::string &canonical_name,
const PresetOrigin &load_origin, ForwardCompatibilitySubstitutionRule substitution_rule,
const std::string &extruder_id_name, const std::string &extruder_variant_name,
std::set<std::string> *key_set1, std::set<std::string> *key_set2,
bool read_only) const;
std::set<std::string> *key_set1, std::set<std::string> *key_set2) const;
// Install one resolved preset. The collection, its alias maps, the error count
// and the preset files on disk are touched here and only here.
+30 -435
View File
@@ -1,4 +1,3 @@
#include <array>
#include <atomic>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
@@ -57,10 +56,8 @@
#include <algorithm>
#include <cstdlib>
#include <mutex>
#include <numeric>
#include <set>
#include <shared_mutex>
#include <fstream>
#include <string>
#include <tuple>
@@ -1386,27 +1383,6 @@ std::string PresetBundle::get_hotend_model_for_printer_model(std::string model_n
return out;
}
static void load_bundle_presets(PresetBundle& bundle, const std::string& bundle_dir, BundleMetadata& metadata,
const PresetOrigin& origin, PresetsConfigSubstitutions& substitutions,
ForwardCompatibilitySubstitutionRule substitution_rule, bool read_only = false)
{
struct Collection {
PresetCollection& presets;
const char* directory;
std::vector<std::string>& names;
};
metadata.print_presets.clear();
metadata.filament_presets.clear();
metadata.printer_presets.clear();
for (Collection collection : {
Collection{ bundle.prints, PRESET_PRINT_NAME, metadata.print_presets },
Collection{ bundle.filaments, PRESET_FILAMENT_NAME, metadata.filament_presets },
Collection{ bundle.printers, PRESET_PRINTER_NAME, metadata.printer_presets } })
collection.presets.load_presets(bundle_dir, collection.directory, substitutions, substitution_rule,
[&](Preset& preset) { collection.names.push_back(preset.name); }, origin, read_only);
}
PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule substitution_rule, bool read_only)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and user is: " << user;
@@ -1455,8 +1431,19 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
BundleMetadata metadata;
if (!load_bundle_metadata(metadata_file, metadata)) continue;
load_bundle_presets(*this, bundle_dir, metadata, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id),
substitutions, substitution_rule, read_only);
metadata.print_presets.clear();
metadata.filament_presets.clear();
metadata.printer_presets.clear();
this->prints.load_presets(bundle_dir, PRESET_PRINT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.print_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
this->filaments.load_presets(bundle_dir, PRESET_FILAMENT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.filament_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
this->printers.load_presets(bundle_dir, PRESET_PRINTER_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.printer_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
metadata.bundle_type = BundleType::Local;
metadata.path = metadata_file.string();
@@ -1479,10 +1466,20 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
BundleMetadata metadata;
if (!load_bundle_metadata(metadata_file, metadata)) continue;
metadata.print_presets.clear();
metadata.filament_presets.clear();
metadata.printer_presets.clear();
metadata.is_subscribed = true;
load_bundle_presets(*this, bundle_dir, metadata, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id),
substitutions, substitution_rule, read_only);
this->prints.load_presets(bundle_dir, PRESET_PRINT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.print_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
this->filaments.load_presets(bundle_dir, PRESET_FILAMENT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.filament_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
this->printers.load_presets(bundle_dir, PRESET_PRINTER_NAME, substitutions, substitution_rule, [&](Preset& preset) {
metadata.printer_presets.push_back(preset.name);
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
metadata.bundle_type = BundleType::Subscribed;
metadata.path = metadata_file.string();
@@ -1537,335 +1534,6 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
return PresetsConfigSubstitutions();
}
static bool is_single_path_component(const std::string& value)
{
const fs::path path(value);
return !value.empty() && value != "." && value != ".." && value.find_first_of("/\\") == std::string::npos &&
!path.has_root_name() && !path.has_root_directory();
}
static bool check_local_bundle(PresetBundleMetadata& bundles, const fs::path& user_dir, const std::string& bundle_id,
BundleMetadata& metadata, std::string& error)
{
if (!is_single_path_component(bundle_id)) {
error = "Local bundle id must be a single path component";
return false;
}
const fs::path bundle_dir = user_dir / PRESET_LOCAL_DIR / bundle_id;
if (!fs::is_directory(bundle_dir)) {
error = "Local bundle directory does not exist";
return false;
}
if (fs::exists(user_dir / PRESET_SUBSCRIBED_DIR / bundle_id)) {
error = "A subscribed bundle already uses this id";
return false;
}
{
std::shared_lock<std::shared_mutex> lock(bundles.RWMtx);
const auto it = bundles.m_bundles.find(bundle_id);
if (it != bundles.m_bundles.end() && (it->second.bundle_type == BundleType::Subscribed || it->second.is_subscribed)) {
error = "A subscribed bundle already uses this id";
return false;
}
}
if (!metadata.load_from_json((bundle_dir / PRESET_BUNDLE_METADATA).string()) || metadata.id != bundle_id) {
error = "Local bundle metadata is missing, malformed, or has a different id";
return false;
}
return true;
}
std::vector<std::string> PresetBundle::list_local_bundle_ids(const std::string& preset_folder)
{
std::vector<std::string> ids;
const std::string user = preset_folder.empty() ? DEFAULT_USER_FOLDER_NAME : preset_folder;
if (!is_single_path_component(user))
return ids;
const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR / user;
const fs::path local_dir = user_dir / PRESET_LOCAL_DIR;
try {
if (!fs::is_directory(local_dir))
return ids;
for (const auto& entry : fs::directory_iterator(local_dir)) {
const std::string bundle_id = entry.path().filename().string();
try {
BundleMetadata metadata;
std::string error;
if (check_local_bundle(bundles, user_dir, bundle_id, metadata, error))
ids.push_back(bundle_id);
} catch (const std::exception& exception) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": skipping " << bundle_id << ": " << exception.what();
}
}
} catch (const std::exception& exception) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": " << exception.what();
}
std::sort(ids.begin(), ids.end());
return ids;
}
bool PresetBundle::reload_local_bundle(const std::string& preset_folder, const std::string& bundle_id, std::string* error)
{
auto fail = [error](const std::string& message) {
if (error != nullptr)
*error = message;
return false;
};
if (!is_single_path_component(bundle_id))
return fail("Local bundle id must be a single path component");
const std::string user = preset_folder.empty() ? DEFAULT_USER_FOLDER_NAME : preset_folder;
if (!is_single_path_component(user))
return fail("Preset folder must be a single path component");
try {
const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR / user;
const fs::path bundle_dir = user_dir / PRESET_LOCAL_DIR / bundle_id;
const fs::path metadata_file = bundle_dir / PRESET_BUNDLE_METADATA;
BundleMetadata metadata;
std::string check_error;
if (!check_local_bundle(bundles, user_dir, bundle_id, metadata, check_error))
return fail(check_error);
// Keep background preset sync from changing the collections between copying and committing them.
std::scoped_lock collection_lock(prints.m_mutex, filaments.m_mutex, printers.m_mutex);
const std::string target_prefix = std::string(PRESET_LOCAL_DIR) + "/" + bundle_id + "/";
const auto is_target = [&](const Preset& preset) {
return preset.bundle_id == bundle_id && boost::starts_with(preset.name, target_prefix);
};
struct Selection {
std::string name;
Preset base{Preset::TYPE_INVALID, std::string()};
Preset edited{Preset::TYPE_INVALID, std::string()};
std::vector<std::string> dirty_options;
};
auto snapshot = [&](const PresetCollection& collection, Selection& selection) {
selection.name = collection.get_selected_preset_name();
if (selection.name.empty())
return false;
for (const Preset& preset : collection.get_presets()) {
if (preset.name == selection.name) {
selection.base = preset;
selection.edited = collection.get_edited_preset();
selection.dirty_options = PresetCollection::dirty_options(&selection.edited, &selection.base);
return true;
}
}
return false;
};
Selection print_selection, filament_selection, printer_selection;
if (!snapshot(prints, print_selection) || !snapshot(filaments, filament_selection) || !snapshot(printers, printer_selection))
return fail("Preset selections are not initialized");
PresetBundle staged;
// Collection copies keep vendor pointers into the live vendor map, which is not replaced by this reload.
staged.prints = prints;
staged.filaments = filaments;
staged.printers = printers;
staged.filament_presets = filament_presets;
staged.project_config.apply_only(project_config, {"flush_volumes_matrix", "flush_volumes_vector", "flush_multiplier"});
auto remove_target = [&](PresetCollection& collection) {
auto begin = collection.m_presets.begin() + collection.m_num_default_presets;
collection.m_presets.erase(std::remove_if(begin, collection.m_presets.end(), is_target), collection.m_presets.end());
collection.sort_presets();
};
remove_target(staged.prints);
remove_target(staged.filaments);
remove_target(staged.printers);
const std::array<int, 3> errors_before = { staged.prints.error_count(), staged.filaments.error_count(), staged.printers.error_count() };
PresetsConfigSubstitutions substitutions;
load_bundle_presets(staged, bundle_dir.string(), metadata, PresetOrigin(PresetOrigin::Kind::LocalBundle, bundle_id),
substitutions, ForwardCompatibilitySubstitutionRule::Enable, true);
if (staged.prints.error_count() != errors_before[0] || staged.filaments.error_count() != errors_before[1] || staged.printers.error_count() != errors_before[2])
return fail("Local bundle contains an invalid preset");
auto dirty_target_was_removed = [&](const Selection& selection, const PresetCollection& collection) {
if (selection.dirty_options.empty() || !is_target(selection.base))
return false;
for (const Preset& preset : collection.get_presets())
if (preset.name == selection.name && is_target(preset))
return false;
return true;
};
if (dirty_target_was_removed(print_selection, staged.prints) ||
dirty_target_was_removed(filament_selection, staged.filaments) ||
dirty_target_was_removed(printer_selection, staged.printers))
return fail("A modified selected preset was removed or renamed");
auto external_child_name = [&](const PresetCollection& collection) {
auto depends_on_target = [&](const Preset& preset) {
if (is_target(preset))
return false;
const Preset* parent = &preset;
std::unordered_set<const Preset*> visited;
while ((parent = collection.get_preset_parent(*parent)) != nullptr && visited.insert(parent).second)
if (is_target(*parent))
return true;
for (const char* key : {"compatible_prints", "compatible_printers"}) {
const auto* names = preset.config.option<ConfigOptionStrings>(key);
if (names == nullptr)
continue;
const PresetCollection& referenced = std::string(key) == "compatible_printers" ? printers : prints;
for (const std::string& name : names->values) {
const Preset* dependency = referenced.find_preset(name, false);
if (dependency != nullptr && is_target(*dependency))
return true;
}
}
return false;
};
for (const Preset& preset : collection.get_presets())
if (depends_on_target(preset))
return preset.name;
if (depends_on_target(collection.get_edited_preset()))
return collection.get_edited_preset().name;
return std::string();
};
for (const PresetCollection* collection : std::array<const PresetCollection*, 3>{&prints, &filaments, &printers}) {
const std::string child_name = external_child_name(*collection);
if (!child_name.empty())
return fail("Preset outside this bundle depends on it: " + child_name);
}
auto restore_selection = [](PresetCollection& collection, const Selection& selection) {
if (collection.find_preset(selection.name, false, true) == nullptr) {
collection.select_preset(collection.first_visible_idx());
return false;
}
collection.select_preset_by_name(selection.name, true);
if (collection.get_selected_preset_name() != selection.name)
return false;
Preset& edited = collection.get_edited_preset();
for (const std::string& key : selection.dirty_options) {
if (const ConfigOption* option = selection.edited.config.option(key))
edited.config.set_key_value(key, option->clone());
else
edited.config.erase(key);
}
collection.update_dirty();
return true;
};
staged.prints.update_map_alias_to_profile_name();
staged.filaments.update_map_alias_to_profile_name();
staged.printers.update_map_alias_to_profile_name();
const bool printer_preserved = restore_selection(staged.printers, printer_selection);
const bool print_preserved = restore_selection(staged.prints, print_selection);
const bool filament_preserved = restore_selection(staged.filaments, filament_selection);
const auto selection_mode = [printer_preserved](bool selection_preserved) {
if (!selection_preserved)
return PresetSelectCompatibleType::Always;
return printer_preserved ? PresetSelectCompatibleType::Never : PresetSelectCompatibleType::OnlyIfWasCompatible;
};
if (staged.printers.get_edited_preset().printer_technology() != ptFFF)
return fail("Local bundle reload requires an FFF printer selection");
staged.update_compatible(selection_mode(print_preserved), selection_mode(filament_preserved));
for (std::string& name : staged.filament_presets)
if (boost::starts_with(name, target_prefix) && staged.filaments.find_preset(name, false) == nullptr)
name = staged.filaments.first_compatible().name;
staged.update_multi_material_filament_presets();
struct Collection
{
PresetCollection& live;
PresetCollection& candidate;
size_t original_size;
};
std::array<Collection, 3> collections{{{prints, staged.prints, prints.size()},
{filaments, staged.filaments, filaments.size()},
{printers, staged.printers, printers.size()}}};
for (size_t i = 0; i < collections.size(); ++i) {
const auto& collection = collections[i];
const auto dirty_options = collection.live.current_dirty_options();
if (dirty_options.empty())
continue;
if (collection.live.get_selected_preset_name() != collection.candidate.get_selected_preset_name())
return fail("Reload would discard a modified selected preset");
for (const std::string& key : dirty_options) {
const ConfigOption* before = collection.live.get_edited_preset().config.option(key);
const ConfigOption* after = collection.candidate.get_edited_preset().config.option(key);
if ((before == nullptr) != (after == nullptr) || (before != nullptr && *before != *after))
return fail("Reload would discard a modified preset option: " + key);
}
}
if (calibrate_printer != nullptr && staged.printers.find_preset(calibrate_printer->name, false, true) != nullptr)
staged.set_calibrate_printer(calibrate_printer->name);
std::array<std::pair<ConfigOptionFloats*, ConfigOptionFloats*>, 3> flush_options;
size_t i = 0;
for (const char* key : {"flush_volumes_matrix", "flush_volumes_vector", "flush_multiplier"})
flush_options[i++] = {project_config.option<ConfigOptionFloats>(key), staged.project_config.option<ConfigOptionFloats>(key)};
metadata.bundle_type = BundleType::Local;
metadata.is_subscribed = false;
metadata.update_available = false;
metadata.path = metadata_file.string();
fs::path local_dir = user_dir / PRESET_LOCAL_DIR;
std::unique_lock<std::shared_mutex> lock(bundles.RWMtx);
const auto existing = bundles.m_bundles.find(bundle_id);
if (existing != bundles.m_bundles.end() &&
(existing->second.bundle_type == BundleType::Subscribed || existing->second.is_subscribed))
return fail("A subscribed bundle already uses this id");
std::set<const Preset*> calibration_filaments;
const Preset* calibration_printer = nullptr;
try {
// Growing a deque preserves existing objects. Roll back appended copies if preparation fails.
for (size_t i = 0; i < collections.size(); ++i) {
auto& collection = collections[i];
while (collection.live.size() < collection.candidate.size())
collection.live.m_presets.emplace_back(collection.candidate.m_presets[collection.live.size()]);
}
auto calibration_preset = [](const Preset* preset, PresetCollection& live, PresetCollection& candidate) -> const Preset* {
if (preset == nullptr)
return nullptr;
if (preset == &candidate.get_edited_preset())
return &live.get_edited_preset();
const auto it = candidate.find_preset_internal(preset->name);
return &live.m_presets[it - candidate.m_presets.begin()];
};
calibration_printer = calibration_preset(staged.calibrate_printer, printers, staged.printers);
for (const Preset* preset : staged.calibrate_filaments)
calibration_filaments.insert(calibration_preset(preset, filaments, staged.filaments));
// Insertion is the last allocating operation. Replacing metadata only moves its members.
bundles.m_bundles.insert_or_assign(bundle_id, std::move(metadata));
} catch (...) {
for (size_t i = 0; i < collections.size(); ++i)
while (collections[i].live.size() > collections[i].original_size)
collections[i].live.m_presets.pop_back();
throw;
}
auto install_target = [](PresetCollection& live, PresetCollection& candidate) noexcept {
// Keep stored Preset references alive when the collection's layout is unchanged.
// Adding/removing presets retains the collection's usual sorted-position semantics.
for (size_t i = 0; i < candidate.size(); ++i)
live.m_presets[i] = std::move(candidate.m_presets[i]);
while (live.size() > candidate.size())
live.m_presets.pop_back();
live.m_map_alias_to_profile_name.swap(candidate.m_map_alias_to_profile_name);
// Move assignment does not allocate (including Semver); swapping Presets would construct temporary containers.
live.m_edited_preset = std::move(candidate.m_edited_preset);
live.m_saved_preset = std::move(candidate.m_saved_preset);
live.m_idx_selected = candidate.m_idx_selected;
};
for (size_t i = 0; i < collections.size(); ++i)
install_target(collections[i].live, collections[i].candidate);
filament_presets.swap(staged.filament_presets);
for (const auto& options : flush_options)
options.first->values.swap(options.second->values);
calibrate_printer = calibration_printer;
calibrate_filaments.swap(calibration_filaments);
dir_user_presets_local.swap(local_dir);
return true;
} catch (const std::exception& exception) {
return fail(std::string("Failed to reload local bundle: ") + exception.what());
}
}
PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig & config,
std::map<std::string, std::map<std::string, std::string>> &my_presets,
ForwardCompatibilitySubstitutionRule substitution_rule)
@@ -4230,8 +3898,6 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
// BBS: change directories by design
void PresetBundle::export_selections(AppConfig &config)
{
if (m_selection_export_blockers > 0)
return;
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() >= 1);
//assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front());
config.clear_section("presets");
@@ -5858,10 +5524,12 @@ DynamicPrintConfig PresetBundle::full_sla_config() const
ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
if (is_gcode_file(path)) {
DynamicPrintConfig config;
//BBS: add config related logs
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, gcodefile %1%, compatibility_rule %2%")%path %compatibility_rule;
ConfigSubstitutions config_substitutions;
DynamicPrintConfig config = config_from_gcode(path, compatibility_rule, config_substitutions);
config.apply(FullPrintConfig::defaults());
ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule);
Preset::normalize(config);
load_config_file_config(path, true, std::move(config));
return config_substitutions;
}
@@ -5869,83 +5537,10 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
//BBS: add config related logs
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" can not load config file %1% not from gcode")%path ;
throw Slic3r::RuntimeError((boost::format(L("Unknown configuration file: %1%")) % path).str());
return ConfigSubstitutions{};
}
DynamicPrintConfig PresetBundle::config_from_gcode(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule,
ConfigSubstitutions &substitutions) const
{
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
// The config block leaves a few project settings out (filament_colour_type, prime_volume_mode,
// flush_multiplier_fast); those keep this bundle's values rather than falling back to the defaults.
config.apply(this->project_config);
const DynamicPrintConfig base = config;
substitutions = config.load_from_gcode_file(path, compatibility_rule);
// An empty list of choices sets nothing: G-code written by a tool rather than from presets leaves per-extruder
// lists such as nozzle_volume_type empty, and the settings tabs expect a choice per extruder. An empty text
// list, such as filament_multi_colour, is a value of its own and stays.
for (const std::string &key : config.keys())
if (const ConfigOption *opt = config.option(key); opt->type() == coEnums && static_cast<const ConfigOptionVectorBase *>(opt)->size() == 0)
if (const ConfigOption *below = base.option(key); below != nullptr && static_cast<const ConfigOptionVectorBase *>(below)->size() > 0)
config.set_key_value(key, below->clone());
Preset::normalize(config);
// The block holds flush_volumes_matrix already multiplied by the multiplier the slice used, so a
// multiplier of 1 keeps the purge volumes the file was sliced with. G-code from before 2.3.2 held the
// plain matrix and loses a multiplier other than 1.
for (const char *key : { "flush_multiplier", "flush_multiplier_fast" })
if (auto *multiplier = config.option<ConfigOptionFloats>(key))
std::fill(multiplier->values.begin(), multiplier->values.end(), 1.);
return config;
}
std::optional<PresetBundle::Selection> PresetBundle::selection() const
{
auto capture = [](const PresetCollection &presets, Selection::Collection &out) {
if (std::any_of(presets.m_presets.begin(), presets.m_presets.end(), [](const Preset &preset) { return preset.is_project_embedded; }))
return false;
out.selected = presets.get_selected_preset_name();
out.edited = presets.get_edited_preset().config;
out.saved = presets.m_saved_preset.config;
out.visible.reserve(presets.m_presets.size());
for (const Preset &preset : presets.m_presets)
out.visible.push_back(preset.is_visible);
return true;
};
Selection selection;
if (!capture(this->prints, selection.prints) || !capture(this->filaments, selection.filaments) || !capture(this->printers, selection.printers))
return std::nullopt;
selection.filament_presets = this->filament_presets;
selection.project_config = this->project_config;
selection.extruder_ams_counts = this->extruder_ams_counts;
return selection;
}
void PresetBundle::restore_selection(const Selection &selection)
{
auto restore = [](PresetCollection &presets, const Selection::Collection &saved) {
presets.reset_project_embedded_presets();
// Before selecting: select_preset_by_name() passes over a hidden preset.
assert(presets.m_presets.size() == saved.visible.size());
for (size_t i = 0; i < std::min(presets.m_presets.size(), saved.visible.size()); ++i)
presets.m_presets[i].is_visible = saved.visible[i];
presets.select_preset_by_name(saved.selected, true);
presets.m_saved_preset.config = saved.saved;
presets.get_edited_preset().config = saved.edited;
presets.update_dirty();
};
restore(this->printers, selection.printers);
restore(this->prints, selection.prints);
restore(this->filaments, selection.filaments);
this->update_compatible(PresetSelectCompatibleType::Never);
this->update_multi_material_filament_presets();
// Last, as update_multi_material_filament_presets() resizes filament_presets and the flush data in project_config.
this->filament_presets = selection.filament_presets;
this->project_config = selection.project_config;
this->extruder_ams_counts = selection.extruder_ams_counts;
}
//some filament presets split from one to sperate ones
//following map recording these filament presets
-48
View File
@@ -302,9 +302,6 @@ public:
// BBS Load user presets
PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule, bool read_only = false);
PresetsConfigSubstitutions load_user_presets(AppConfig &config, std::map<std::string, std::map<std::string, std::string>>& my_presets, ForwardCompatibilitySubstitutionRule rule);
bool reload_local_bundle(const std::string& preset_folder, const std::string& bundle_id, std::string* error = nullptr);
std::vector<std::string> list_local_bundle_ids(const std::string& preset_folder);
// Orca: Import subscribed bundle presets (load and save to disk in one operation), handles one bundle at a time
PresetsConfigSubstitutions update_subscribed_presets(AppConfig& config,
const std::map<std::string, std::map<std::string, std::string>>& bundle_presets,
@@ -400,28 +397,6 @@ public:
std::vector<Preset*> get_current_project_embedded_presets();
void reset_project_embedded_presets();
// What importing a file's settings replaces, so that an import which fails part-way, or whose
// file is then rejected, can be undone without copying every preset.
struct Selection
{
struct Collection
{
std::string selected;
DynamicPrintConfig edited;
// The baseline saved_is_dirty() compares against, which feeds the project dirty state.
DynamicPrintConfig saved;
// By index: an import only inserts project-embedded presets, which a restore drops first.
std::vector<bool> visible;
};
Collection prints, filaments, printers;
std::vector<std::string> filament_presets;
DynamicPrintConfig project_config;
std::vector<std::map<int, int>> extruder_ams_counts;
};
// Nothing while project-embedded presets exist: a restore drops them, which would lose a loaded project's presets.
std::optional<Selection> selection() const;
void restore_selection(const Selection &selection);
//BBS: find printer model
std::string get_texture_for_printer_model(std::string model_name);
std::string get_stl_model_for_printer_model(std::string model_name);
@@ -430,21 +405,6 @@ public:
// Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config);
// While one lives, export_selections() writes nothing, so a selection only shown for a while (the
// settings of a G-code being previewed) is not remembered as the user's. It also covers the
// exports the GUI makes on its own while refreshing.
class SelectionExportBlocker
{
public:
explicit SelectionExportBlocker(PresetBundle &bundle) : m_bundle(bundle) { ++m_bundle.m_selection_export_blockers; }
~SelectionExportBlocker() { --m_bundle.m_selection_export_blockers; }
SelectionExportBlocker(const SelectionExportBlocker &) = delete;
SelectionExportBlocker &operator=(const SelectionExportBlocker &) = delete;
private:
PresetBundle &m_bundle;
};
// n is the total slot count, and growth appends at the raw tail - which is where the mixed
// slots live. A caller adding physical filaments has to add num_mixed_filaments() on top and
// then move the new slots ahead of the mixed tail, as Sidebar::add_custom_filament does.
@@ -586,11 +546,6 @@ public:
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
ConfigSubstitutions load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule);
// The settings an OrcaSlicer G-code was sliced with, from its config block, ready for load_config_model().
// Throws when the file carries no such block (another slicer, or the block was left out).
DynamicPrintConfig config_from_gcode(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule,
ConfigSubstitutions &substitutions) const;
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
// Load settings into the provided settings instance.
@@ -941,9 +896,6 @@ private:
std::string vendor_to_validate = "";
int m_errors = 0;
// The live SelectionExportBlockers.
int m_selection_export_blockers = 0;
// Helper function: save preset to bundle directory with common logic
bool save_preset_to_bundle_dir(Preset& preset, PresetCollection* collection,
const std::string& bundle_id, const std::string& type_subdir,
-7
View File
@@ -174,8 +174,6 @@ set(SLIC3R_GUI_SOURCES
GUI/Gizmos/GLGizmoAssembly.hpp
GUI/Gizmos/GLGizmoBase.cpp
GUI/Gizmos/GLGizmoBase.hpp
GUI/Gizmos/GLGizmoAlignment.cpp
GUI/Gizmos/GLGizmoAlignment.hpp
GUI/Gizmos/GLGizmoBrimEars.cpp
GUI/Gizmos/GLGizmoBrimEars.hpp
GUI/Gizmos/GLGizmoCut.cpp
@@ -685,8 +683,6 @@ set(SLIC3R_GUI_SOURCES
plugin/host/PluginHostUi.hpp
plugin/host/PluginPages.cpp
plugin/host/PluginPages.hpp
plugin/host/PluginResourceTextures.cpp
plugin/host/PluginResourceTextures.hpp
plugin/CloudPluginService.cpp
plugin/CloudPluginService.hpp
plugin/PluginFsUtils.cpp
@@ -710,9 +706,6 @@ set(SLIC3R_GUI_SOURCES
plugin/pluginTypes/pages/PagesPluginCapability.hpp
plugin/pluginTypes/pages/PagesPluginCapability.cpp
plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp
plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapability.hpp
plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapability.cpp
plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapabilityTrampoline.hpp
plugin/pluginTypes/script/ScriptPluginCapability.hpp
plugin/pluginTypes/script/ScriptPluginCapability.cpp
plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp
+1 -3
View File
@@ -1797,9 +1797,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
}
else {*/
//BBS: add only gcode mode
// When the file's own settings were loaded into the presets, the bed already is the file's, with the
// model and texture of a user or custom printer too, which the lookup below cannot resolve.
if (m_only_gcode_in_preview && !wxGetApp().plater()->gcode_settings_loaded()) {
if (m_only_gcode_in_preview) {
Pointfs printable_area;
//BBS: add bed exclude area
Pointfs bed_exclude_area = Pointfs();
+11 -11
View File
@@ -5520,7 +5520,7 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip)
m_tooltip.set_text(tooltip);
}
void GLCanvas3D::do_move(const std::string& snapshot_type, bool force_volume_move)
void GLCanvas3D::do_move(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
@@ -5552,18 +5552,10 @@ void GLCanvas3D::do_move(const std::string& snapshot_type, bool force_volume_mov
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object == nullptr)
if (model_object == nullptr)
continue;
if (force_volume_move || selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
else if (selection_mode == Selection::Instance) {
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
@@ -5572,6 +5564,14 @@ void GLCanvas3D::do_move(const std::string& snapshot_type, bool force_volume_mov
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
object_moved = true;
model_object->invalidate_bounding_box();
+1 -1
View File
@@ -1305,7 +1305,7 @@ public:
void set_tooltip(const std::string& tooltip);
// the following methods add a snapshot to the undo/redo stack, unless the given string is empty
void do_move(const std::string& snapshot_type, bool force_volume_move = false);
void do_move(const std::string& snapshot_type);
void do_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type);
void do_center();
-33
View File
@@ -251,11 +251,9 @@
#include "slic3r/GUI/ParamsDialog.hpp"
#include "slic3r/GUI/ParamsPanel.hpp"
#include "slic3r/GUI/PartPlate.hpp"
#include "slic3r/GUI/TextureLibrary.hpp"
#include "slic3r/GUI/Widgets/Button.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/plugin/host/PluginPages.hpp"
#include "slic3r/plugin/host/PluginResourceTextures.hpp"
#include <wx/defs.h>
#include "slic3r/GUI/Widgets/WebView.hpp"
#include <cwchar>
@@ -3055,37 +3053,6 @@ void GUI_App::init_plugin_gui_wiring()
refresh_plugins_dialog();
switch_printer_agent_after_unload(capability.plugin_key);
});
plugin_mgr.subscribe_on_load_callback([](const std::string& plugin_key) {
if (wxTheApp == nullptr || wxGetApp().is_closing())
return;
PluginResourceTextures::instance().on_plugin_register(plugin_key);
Slic3r::GUI::bump_texture_library_generation();
});
plugin_mgr.subscribe_on_unload_callback([](const std::string& plugin_key) {
if (wxTheApp == nullptr || wxGetApp().is_closing())
return;
PluginResourceTextures::instance().on_plugin_deregister(plugin_key);
Slic3r::GUI::bump_texture_library_generation();
});
plugin_mgr.subscribe_on_capability_load_callback([](const PluginCapabilityId& capability) {
if (capability.type != PluginCapabilityType::ResourceTexture)
return;
if (wxTheApp == nullptr || wxGetApp().is_closing())
return;
PluginResourceTextures::instance().on_cap_register(capability);
Slic3r::GUI::bump_texture_library_generation();
});
plugin_mgr.subscribe_on_capability_unload_callback([](const PluginCapabilityId& capability) {
if (capability.type != PluginCapabilityType::ResourceTexture)
return;
if (wxTheApp == nullptr || wxGetApp().is_closing())
return;
PluginResourceTextures::instance().on_cap_deregister(capability);
Slic3r::GUI::bump_texture_library_generation();
});
// Packs already loaded before this wiring, or in tests where no callback fires.
PluginResourceTextures::instance().initial_sweep();
Slic3r::GUI::bump_texture_library_generation();
}
bool GUI_App::on_init_inner()
+3 -251
View File
@@ -16,7 +16,6 @@
#include "Selection.hpp"
//BBS: add partplate related logic
#include "PartPlate.hpp"
#include "Gizmos/GLGizmoAlignment.hpp"
#include "Gizmos/GLGizmoEmboss.hpp"
#include "Gizmos/GLGizmoSVG.hpp"
@@ -1673,8 +1672,6 @@ void MenuFactory::create_extra_object_menu()
append_menu_item_merge_parts_to_single_part(&m_object_menu);
// Object Center
append_menu_item_center(&m_object_menu);
// Object Align/Distribute
append_menu_item_align_distribute(&m_object_menu);
// Object Drop
append_menu_item_drop(&m_object_menu);
// Object Split
@@ -1782,7 +1779,6 @@ void MenuFactory::create_text_part_menu()
append_menu_item_fix_through_cgal(menu);
append_menu_item_simplify(menu);
append_menu_item_center(menu);
append_menu_item_align_distribute(menu);
append_menu_items_mirror(menu);
menu->AppendSeparator();
append_menu_item_per_object_process(menu);
@@ -1815,7 +1811,6 @@ void MenuFactory::create_bbl_part_menu()
append_menu_item_simplify(menu);
append_menu_item_smooth_mesh(menu);
append_menu_item_center(menu);
append_menu_item_align_distribute(menu);
append_menu_item_drop(menu);
append_menu_items_mirror(menu);
wxMenu* split_menu = new wxMenu();
@@ -2141,7 +2136,6 @@ wxMenu* MenuFactory::multi_selection_menu()
index++;
}
append_menu_item_center(menu);
append_menu_item_align_distribute(menu);
append_menu_item_drop(menu);
append_menu_item_fix_through_cgal(menu);
//append_menu_item_simplify(menu);
@@ -2150,13 +2144,13 @@ wxMenu* MenuFactory::multi_selection_menu()
append_menu_item_set_printable(menu);
menu->AppendSeparator();
append_menu_item_set_auto_drop(menu);
menu->AppendSeparator();
append_menu_item_per_object_process(menu);
menu->AppendSeparator();
append_menu_items_convert_unit(menu);
append_menu_item_replace_all_with_stl(menu);
//BBS
@@ -2167,7 +2161,6 @@ wxMenu* MenuFactory::multi_selection_menu()
}
else {
append_menu_item_center(menu);
append_menu_item_align_distribute(menu);
append_menu_item_drop(menu);
append_menu_item_fix_through_cgal(menu);
//append_menu_item_simplify(menu);
@@ -2332,247 +2325,6 @@ void MenuFactory::append_menu_item_center(wxMenu* menu)
}, m_parent);
}
void MenuFactory::append_menu_item_align_distribute(wxMenu *menu)
{
wxMenu* align_distribute_menu = new wxMenu();
if (!align_distribute_menu)
return;
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Distribute left-right") + " (X)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->distribute_selection_x();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_X);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Distribute front-back") + " (Y)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->distribute_selection_y();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_Y);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Distribute top-bottom") + " (Z)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->distribute_selection_z();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_Z);
},
m_parent);
align_distribute_menu->AppendSeparator();
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align left") + " (-X)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_x_min();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::X_MIN);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align left-right center") + " (X)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_x_center();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_X);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align right") + " (+X)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_x_max();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::X_MAX);
},
m_parent);
align_distribute_menu->AppendSeparator();
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align front") + " (-Y)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_y_min();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::Y_MIN);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align front-back center") + " (Y)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_y_center();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_Y);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align back") + " (+Y)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_y_max();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::Y_MAX);
},
m_parent);
align_distribute_menu->AppendSeparator();
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align bottom") + " (-Z)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_z_min();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::Z_MIN);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align top-bottom center") + " (Z)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_z_center();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_Z);
},
m_parent);
append_menu_item(
align_distribute_menu, wxID_ANY, _L("Align top") + " (+Z)", "",
[](wxCommandEvent &) {
auto canvas3d = plater()->get_view3D_canvas3D();
canvas3d->get_gizmos_manager().check_object_located_outside_plate(true);
plater()->align_selection_z_max();
},
"", nullptr,
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
return alignment_helper.can_align(GLGizmoAlignment::AlignType::Z_MAX);
},
m_parent);
append_submenu(menu, align_distribute_menu, wxID_ANY, _L("Align/Distribute"), _L("Align and distribute objects"), "",
[]() {
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
auto canvas3d = plater()->get_view3D_canvas3D();
GLGizmoAlignment alignment_helper(*canvas3d);
bool has_any_align = alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_X) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_Y) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::CENTER_Z) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::X_MAX) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::X_MIN) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::Y_MAX) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::Y_MIN) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::Z_MAX) ||
alignment_helper.can_align(GLGizmoAlignment::AlignType::Z_MIN);
bool has_any_distribute = alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_X) ||
alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_Y) ||
alignment_helper.can_distribute(GLGizmoAlignment::AlignType::DISTRIBUTE_Z);
return has_any_align || has_any_distribute;
}, m_parent);
}
void MenuFactory::append_menu_item_drop(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Drop") , "",
-1
View File
@@ -175,7 +175,6 @@ private:
void append_menu_item_merge_to_single_object(wxMenu* menu);
void append_menu_item_merge_parts_to_single_part(wxMenu *menu);
void append_menu_items_mirror(wxMenu *menu);
void append_menu_item_align_distribute(wxMenu *menu);
void append_menu_item_precise_seam_submenu(wxMenu* menu);
void append_menu_item_invalidate_cut_info(wxMenu *menu);
void append_menu_item_edit_text(wxMenu *menu);
-694
View File
@@ -1,694 +0,0 @@
#include "GLGizmoAlignment.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r/Model.hpp"
namespace Slic3r {
namespace GUI {
GLGizmoAlignment::GLGizmoAlignment(GLCanvas3D& canvas) : m_canvas(canvas)
{
}
bool GLGizmoAlignment::align_objects(AlignType type, bool align_parent)
{
if (!validate_selection_for_align()) {
return false;
}
switch (type) {
case AlignType::CENTER_X: return align_to_center(type, align_parent);
case AlignType::CENTER_Y: return align_to_center(type, align_parent);
case AlignType::CENTER_Z: return align_to_center(type, align_parent);
case AlignType::Y_MAX: return align_to_y_max(align_parent);
case AlignType::Y_MIN: return align_to_y_min(align_parent);
case AlignType::X_MAX: return align_to_x_max(align_parent);
case AlignType::X_MIN: return align_to_x_min(align_parent);
case AlignType::Z_MAX: return align_to_z_max(align_parent);
case AlignType::Z_MIN: return align_to_z_min(align_parent);
default:
return false;
}
}
bool GLGizmoAlignment::distribute_objects(AlignType type)
{
if (!can_distribute(type)) {
return false;
}
switch (type) {
case AlignType::DISTRIBUTE_X:
return distribute_x();
case AlignType::DISTRIBUTE_Y:
return distribute_y();
case AlignType::DISTRIBUTE_Z:
return distribute_z();
default:
return false;
}
}
bool GLGizmoAlignment::align_to_y_max(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.max.y(); },
[](Vec3d& displacement, double target, double current_max) {
displacement.y() = target - current_max;
}, "Align Y Max", align_parent
);
}
bool GLGizmoAlignment::align_to_y_min(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.min.y(); },
[](Vec3d& displacement, double target, double current_min) {
displacement.y() = target - current_min;
}, "Align Y Min", align_parent
);
}
bool GLGizmoAlignment::align_to_x_max(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.max.x(); },
[](Vec3d& displacement, double target, double current_max) {
displacement.x() = target - current_max;
}, "Align X Max", align_parent
);
}
bool GLGizmoAlignment::align_to_x_min(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.min.x(); },
[](Vec3d& displacement, double target, double current_min) {
displacement.x() = target - current_min;
}, "Align X Min", align_parent
);
}
bool GLGizmoAlignment::align_to_center(AlignType type,bool align_parent)
{
const Selection& selection = get_selection();
std::string type_str = type == AlignType::CENTER_X ? "X" : (type == AlignType::CENTER_Y ? "Y" : "Z");
std::string operation_name = type == AlignType::CENTER_X ? "X Center" : (type == AlignType::CENTER_Y ? "Y Center" : "Z Center");
double selection_center = 0.f;
if (align_parent) {
selection_center = get_current_coord(operation_name, m_parent_box);
// Handle multiple volume selection
if (is_part_align_parent()) {
if (!take_snapshot("Align to parent center " + type_str)) {
return false;
}
get_selection().setup_cache();
auto selection_bbox = selection.get_bounding_box();
double current_coord = get_current_coord(operation_name, selection_bbox);
Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
// Move each selected volume to align to the center of their collective bounding box
for (unsigned int idx : selection.get_volume_idxs()) {
const GLVolume *volume = selection.get_volume(idx);
if (volume) {
get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), displacement);
}
}
finish_operation("Align to parent center " + type_str);
return true;
}
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.empty()) return false;
// Handle multiple objects or parts selection
BoundingBoxf3 selection_bbox = selection.get_bounding_box();
if (!take_snapshot("Align to parent center " + type_str)) {
return false;
}
get_selection().setup_cache();
double current_coord = get_current_coord(operation_name, big_bb);
Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
// Multiple objects: use selection bounding box for alignment
for (const auto &obj : objects) {
apply_transformation(obj.object_idx, obj.instance_idx, displacement);
}
finish_operation("Align to parent center " + type_str);
return true;
}
// Handle single object selection// Handle multiple volume selection
if (selection.is_single_full_object() ||
selection.is_multiple_volume() || selection.is_multiple_modifier() || selection.is_single_volume() || selection.is_single_modifier()) {
if (!take_snapshot("Align Parts Center " + type_str)){
return false;
}
get_selection().setup_cache();
BoundingBoxf3 selection_bbox = selection.get_bounding_box();
selection_center = get_current_coord(operation_name, selection_bbox);
// Move each selected volume to align to the center of their collective bounding box
for (unsigned int idx : selection.get_volume_idxs()) {
const GLVolume* volume = selection.get_volume(idx);
if (volume) {
auto temp_box = volume->transformed_convex_hull_bounding_box();
double current = get_current_coord(operation_name, temp_box);
double offset = selection_center - current;
Vec3d displacement = generate_displacement(operation_name, offset);
get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), displacement);
}
}
finish_operation("Align Parts Center" + type_str, true);
return true;
}
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.empty()) return false;
// Handle multiple objects or parts selection
if (selection.is_multiple_full_object()) {
BoundingBoxf3 selection_bbox = selection.get_bounding_box();
double selection_center = get_current_coord(operation_name, selection_bbox);
if (!take_snapshot("Align Objects Center" + type_str)) {
return false;
}
get_selection().setup_cache();
// Multiple objects: use selection bounding box for alignment
for (const auto& obj : objects) {
BoundingBoxf3 temp_bbox = obj.bbox;
double current_coord = get_current_coord(operation_name, temp_bbox);
Vec3d displacement = generate_displacement(operation_name, selection_center - current_coord);
apply_transformation(obj.object_idx, obj.instance_idx, displacement);
}
finish_operation("Align Objects Center" + type_str);
return true;
}
return false;
}
bool GLGizmoAlignment::align_to_z_max(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.max.z(); },
[](Vec3d& displacement, double target, double current_max) {
displacement.z() = target - current_max;
}, "Align Z Max", align_parent
);
}
bool GLGizmoAlignment::align_to_z_min(bool align_parent)
{
return align_objects_generic(
[](const ObjectInfo& obj) { return obj.bbox.min.z(); },
[](Vec3d& displacement, double target, double current_min) {
displacement.z() = target - current_min;
}, "Align Z Min", align_parent
);
}
bool GLGizmoAlignment::distribute_y()
{
return distribute_objects_generic(
[](const ObjectInfo& obj) { return obj.center.y(); },
1,
"Distribute Y"
);
}
bool GLGizmoAlignment::distribute_x()
{
return distribute_objects_generic(
[](const ObjectInfo& obj) { return obj.center.x(); },
0,
"Distribute X"
);
}
bool GLGizmoAlignment::distribute_z()
{
return distribute_objects_generic(
[](const ObjectInfo& obj) { return obj.center.z(); },
2,
"Distribute Z"
);
}
template<typename GetCoordFunc, typename SetCoordFunc>
bool GLGizmoAlignment::align_objects_generic(GetCoordFunc get_coord, SetCoordFunc set_coord, const std::string &operation_name ,bool align_parent)
{
const Selection& selection = get_selection();
if (align_parent) {
// Find reference coordinate
double reference_coord = get_current_coord(operation_name, m_parent_box);
// Handle parts selection differently
if (is_part_align_parent()) {
if (!take_snapshot("align to parent node " + operation_name)) {
return false;
}
get_selection().setup_cache();
// Get all selected volumes
std::vector<const GLVolume *> volumes;
for (unsigned int idx : selection.get_volume_idxs()) {
const GLVolume *volume = selection.get_volume(idx);
if (volume) { volumes.push_back(volume); }
}
if (volumes.empty())
return false;
BoundingBoxf3 selection_bbox = selection.get_bounding_box();
double current_coord = get_current_coord(operation_name, selection_bbox);
Vec3d displacement = generate_displacement(operation_name, reference_coord - current_coord);
for (const GLVolume *volume : volumes) {
if (displacement.norm() > 1e-6) {
get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), displacement);
}
}
finish_operation("align to parent node " + operation_name);
return true;
}
// Handle objects selection (original logic)
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.empty()) return false;
if (!take_snapshot("align to parent node " + operation_name)) { return false; }
get_selection().setup_cache();
double current_coord = get_current_coord(operation_name, big_bb);
Vec3d displacement = generate_displacement(operation_name, reference_coord - current_coord);
for (const auto &obj : objects) {
if (displacement.norm() > 1e-6) {
apply_transformation(obj.object_idx, obj.instance_idx, displacement);
}
}
finish_operation("align to parent node " + operation_name);
return true;
}
// Handle parts selection differently
if (selection.is_single_full_object() || selection.is_multiple_volume() || selection.is_multiple_modifier()) {
if (!take_snapshot(operation_name)) {
return false;
}
get_selection().setup_cache();
// Get all selected volumes
std::vector<const GLVolume*> volumes;
for (unsigned int idx : selection.get_volume_idxs()) {
const GLVolume* volume = selection.get_volume(idx);
if (volume) {
volumes.push_back(volume);
}
}
if (volumes.empty()) return false;
// Find reference coordinate
double reference_coord = 0.0;
bool first = true;
for (const GLVolume* volume : volumes) {
BoundingBoxf3 bbox = volume->transformed_convex_hull_bounding_box();
double coord = 0.0;
if (operation_name.find("X Max") != std::string::npos) {
coord = bbox.max.x();
} else if (operation_name.find("X Min") != std::string::npos) {
coord = bbox.min.x();
} else if (operation_name.find("Y Max") != std::string::npos) {
coord = bbox.max.y();
} else if (operation_name.find("Y Min") != std::string::npos) {
coord = bbox.min.y();
} else if (operation_name.find("Z Max") != std::string::npos) {
coord = bbox.max.z();
} else if (operation_name.find("Z Min") != std::string::npos) {
coord = bbox.min.z();
}
if (first) {
reference_coord = coord;
first = false;
} else {
if (operation_name.find("Max") != std::string::npos) {
reference_coord = std::max(reference_coord, coord);
} else if (operation_name.find("Min") != std::string::npos) {
reference_coord = std::min(reference_coord, coord);
}
}
}
for (const GLVolume* volume : volumes) {
BoundingBoxf3 bbox = volume->transformed_convex_hull_bounding_box();
double current_coord = 0.0;
if (operation_name.find("X Max") != std::string::npos) {
current_coord = bbox.max.x();
} else if (operation_name.find("X Min") != std::string::npos) {
current_coord = bbox.min.x();
} else if (operation_name.find("Y Max") != std::string::npos) {
current_coord = bbox.max.y();
} else if (operation_name.find("Y Min") != std::string::npos) {
current_coord = bbox.min.y();
} else if (operation_name.find("Z Max") != std::string::npos) {
current_coord = bbox.max.z();
} else if (operation_name.find("Z Min") != std::string::npos) {
current_coord = bbox.min.z();
}
Vec3d displacement = Vec3d::Zero();
if (operation_name.find("X") != std::string::npos) {
displacement.x() = reference_coord - current_coord;
} else if (operation_name.find("Y") != std::string::npos) {
displacement.y() = reference_coord - current_coord;
} else if (operation_name.find("Z") != std::string::npos) {
displacement.z() = reference_coord - current_coord;
}
if (displacement.norm() > 1e-6) {
get_selection().translate(volume->object_idx(), volume->instance_idx(), volume->volume_idx(), displacement);
}
}
finish_operation(operation_name,true);
return true;
}
// Handle objects selection (original logic)
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.empty()) return false;
if (!take_snapshot(operation_name)) {
return false;
}
get_selection().setup_cache();
double reference_coord = get_coord(objects[0]);
for (const auto& obj : objects) {
double coord = get_coord(obj);
if (operation_name.find("Max") != std::string::npos) {
reference_coord = std::max(reference_coord, coord);
} else if (operation_name.find("Min") != std::string::npos) {
reference_coord = std::min(reference_coord, coord);
}
}
for (const auto& obj : objects) {
double current_coord = get_coord(obj);
Vec3d displacement = Vec3d::Zero();
set_coord(displacement, reference_coord, current_coord);
if (displacement.norm() > 1e-6) {
apply_transformation(obj.object_idx, obj.instance_idx, displacement);
}
}
finish_operation(operation_name);
return true;
}
template<typename GetCoordFunc>
bool GLGizmoAlignment::distribute_objects_generic(GetCoordFunc get_coord, int axis, const std::string& operation_name)
{
const Selection& selection = get_selection();
if (selection.is_single_full_object() || selection.is_multiple_volume() || selection.is_multiple_modifier()) {
std::vector<const GLVolume*> volumes;
for (unsigned int idx : selection.get_volume_idxs()) {
const GLVolume* v = selection.get_volume(idx);
if (v) volumes.push_back(v);
}
if (volumes.size() < 3) return false;
if (!take_snapshot(operation_name)) {
return false;
}
get_selection().setup_cache();
struct VolEntry { const GLVolume* v; double coord; };
std::vector<VolEntry> entries;
entries.reserve(volumes.size());
for (const GLVolume* v : volumes) {
BoundingBoxf3 bbox = v->transformed_convex_hull_bounding_box();
Vec3d c = bbox.center();
double coord = (axis == 0 ? c.x() : axis == 1 ? c.y() : c.z());
entries.push_back({v, coord});
}
std::sort(entries.begin(), entries.end(), [](const VolEntry& a, const VolEntry& b){ return a.coord < b.coord; });
BoundingBoxf3 selection_bbox = selection.get_bounding_box();
BoundingBoxf3 left_bbox = entries.front().v->transformed_convex_hull_bounding_box();
BoundingBoxf3 right_bbox = entries.back().v->transformed_convex_hull_bounding_box();
auto axis_extent = [&](const BoundingBoxf3 &bb) { return (axis == 0 ? (bb.max.x() - bb.min.x()) : axis == 1 ? (bb.max.y() - bb.min.y()) : (bb.max.z() - bb.min.z())); };
double left_width = axis_extent(left_bbox);
double right_width = axis_extent(right_bbox);
double bbox_min = (axis == 0 ? selection_bbox.min.x() : axis == 1 ? selection_bbox.min.y() : selection_bbox.min.z());
double bbox_max = (axis == 0 ? selection_bbox.max.x() : axis == 1 ? selection_bbox.max.y() : selection_bbox.max.z());
double min_center = bbox_min + left_width * 0.5;
double max_center = bbox_max - right_width * 0.5;
double total_distance = max_center - min_center;
double interval = (entries.size() > 1) ? total_distance / (entries.size() - 1) : 0;
for (size_t i = 1; i < entries.size() - 1; ++i) {
double target_coord = min_center + i * interval;
double current_coord = entries[i].coord;
double offset = target_coord - current_coord;
if (std::abs(offset) > 1e-6) {
Vec3d displacement = Vec3d::Zero();
displacement[axis] = offset;
const GLVolume *v = entries[i].v;
get_selection().translate(v->object_idx(), v->instance_idx(), v->volume_idx(), displacement);
}
}
finish_operation(operation_name,true);
return true;
}
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.size() < 3) return false;
if (!take_snapshot(operation_name)) {
return false;
}
get_selection().setup_cache();
std::sort(objects.begin(), objects.end(),
[&get_coord](const ObjectInfo& a, const ObjectInfo& b) {
return get_coord(a) < get_coord(b);
});
double min_coord = get_coord(objects.front());
double max_coord = get_coord(objects.back());
double total_distance = max_coord - min_coord;
double interval = (objects.size() > 1) ? total_distance / (objects.size() - 1) : 0;
for (size_t i = 1; i < objects.size() - 1; ++i) {
double target_coord = min_coord + i * interval;
double current_coord = get_coord(objects[i]);
double offset = target_coord - current_coord;
if (std::abs(offset) > 1e-6) {
Vec3d displacement = Vec3d::Zero();
displacement[axis] = offset;
apply_transformation(objects[i].object_idx, objects[i].instance_idx, displacement);
}
}
finish_operation(operation_name);
return true;
}
bool GLGizmoAlignment::can_align(AlignType type) const
{
const Selection& selection = get_selection();
bool is_single_object = selection.is_single_full_object();
bool is_multiple_objects = selection.is_multiple_full_object();
bool is_single_part = selection.is_single_volume() || selection.is_single_modifier();
bool is_multiple_parts = selection.is_multiple_volume() || selection.is_multiple_modifier();
return validate_selection_for_align();
}
bool GLGizmoAlignment::can_distribute(AlignType type) const
{
const Selection& selection = get_selection();
if (selection.is_single_full_object()) {
size_t count = selection.get_volume_idxs().size();
if (count >= 3)
return true;
}
if (selection.is_single_volume() ||
selection.is_single_modifier()) {
return false;
}
if (selection.is_multiple_volume() || selection.is_multiple_modifier()) {
size_t count = selection.get_volume_idxs().size();
if (count < 3) return false;
return (type == AlignType::DISTRIBUTE_X ||
type == AlignType::DISTRIBUTE_Y ||
type == AlignType::DISTRIBUTE_Z);
}
if (selection.is_multiple_full_object()) {
BoundingBoxf3 big_bb;
auto objects = get_selected_objects_info(big_bb);
if (objects.size() < 3) return false;
return (type == AlignType::DISTRIBUTE_X || type == AlignType::DISTRIBUTE_Y || type == AlignType::DISTRIBUTE_Z);
}
return validate_selection_for_distribute();
}
double GLGizmoAlignment::get_current_coord(std::string operation_name, BoundingBoxf3 &bbox)
{
double current_coord = 0.0;
if (operation_name.find("X Max") != std::string::npos) {
current_coord = bbox.max.x();
} else if (operation_name.find("X Min") != std::string::npos) {
current_coord = bbox.min.x();
} else if (operation_name.find("Y Max") != std::string::npos) {
current_coord = bbox.max.y();
} else if (operation_name.find("Y Min") != std::string::npos) {
current_coord = bbox.min.y();
} else if (operation_name.find("Z Max") != std::string::npos) {
current_coord = bbox.max.z();
} else if (operation_name.find("Z Min") != std::string::npos) {
current_coord = bbox.min.z();
} else if (operation_name.find("X Center") != std::string::npos) {
current_coord = bbox.center().x();
} else if (operation_name.find("Y Center") != std::string::npos) {
current_coord = bbox.center().y();
} else if (operation_name.find("Z Center") != std::string::npos) {
current_coord = bbox.center().z();
}
return current_coord;
}
Vec3d GLGizmoAlignment::generate_displacement(std::string operation_name, double offset) {
Vec3d displacement = Vec3d::Zero();
if (operation_name.find("X") != std::string::npos) {
displacement.x() = offset;
} else if (operation_name.find("Y") != std::string::npos) {
displacement.y() = offset;
} else if (operation_name.find("Z") != std::string::npos) {
displacement.z() = offset;
}
return displacement;
}
bool GLGizmoAlignment::is_part_align_parent()
{
Selection &selection = get_selection();
if (selection.is_multiple_volume() || selection.is_multiple_modifier() || selection.is_single_volume() || selection.is_single_modifier()) {
return true;
}
return false;
}
std::vector<GLGizmoAlignment::ObjectInfo> GLGizmoAlignment::get_selected_objects_info(BoundingBoxf3 &big_bb) const
{
std::vector<ObjectInfo> objects;
Selection& selection = get_selection();
if (selection.is_empty()) return objects;
const auto& content = selection.get_content();
for (const auto& obj_it : content) {
for (const auto& inst_idx : obj_it.second) {
int obj_idx = obj_it.first;
if (obj_idx >= 0 && obj_idx < selection.get_model()->objects.size()) {
ModelObject* object = selection.get_model()->objects[obj_idx];
if (inst_idx >= 0 && inst_idx < object->instances.size()) {
BoundingBoxf3 bbox = object->instance_bounding_box(inst_idx);
big_bb.merge(bbox);
objects.emplace_back(obj_idx, inst_idx, bbox);
}
}
}
}
return objects;
}
void GLGizmoAlignment::set_parent_box(const BoundingBoxf3 &bb) {
m_parent_box = bb;
}
Selection& GLGizmoAlignment::get_selection() const
{
return m_canvas.get_selection();
}
bool GLGizmoAlignment::take_snapshot(const std::string& name)
{
wxGetApp().plater()->take_snapshot(name);
return true;
}
void GLGizmoAlignment::apply_transformation(int obj_idx, int inst_idx, const Vec3d& displacement)
{
get_selection().translate(obj_idx, inst_idx, displacement);
}
void GLGizmoAlignment::finish_operation(const std::string &operation_name, bool force_volume_move)
{
get_selection().notify_instance_update(-1, -1);
m_canvas.do_move(operation_name, force_volume_move);
}
bool GLGizmoAlignment::validate_selection_for_align() const
{
const Selection& selection = get_selection();
if (selection.is_single_full_object() ||
selection.is_single_volume() ||
selection.is_single_modifier()) {
return true;
}
return selection.get_volume_idxs().size() >= 2;
}
bool GLGizmoAlignment::validate_selection_for_distribute() const
{
const Selection& selection = get_selection();
if (selection.is_single_full_object() || selection.is_multiple_full_object()) {
std::set<int> object_indices;
for (int volume_idx : selection.get_volume_idxs()) {
const GLVolume* volume = selection.get_volume(volume_idx);
if (volume) {
object_indices.insert(volume->object_idx());
}
}
return object_indices.size() >= 3;
}
return selection.get_volume_idxs().size() >= 3;
}
} // namespace GUI
} // namespace Slic3r
@@ -1,95 +0,0 @@
#ifndef slic3r_GLGizmoAlignment_hpp_
#define slic3r_GLGizmoAlignment_hpp_
#include "libslic3r/Point.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "slic3r/GUI/Selection.hpp"
#include <vector>
#include <functional>
namespace Slic3r {
namespace GUI {
class GLCanvas3D;
class GLGizmoAlignment
{
public:
enum class AlignType {
NONE = -1,
CENTER_X,
CENTER_Y,
CENTER_Z,
Y_MAX,
Y_MIN,
X_MAX,
X_MIN,
Z_MAX,
Z_MIN,
DISTRIBUTE_X,
DISTRIBUTE_Y,
DISTRIBUTE_Z
};
struct ObjectInfo {
int object_idx;
int instance_idx;
BoundingBoxf3 bbox;
Vec3d center;
ObjectInfo(int obj_idx, int inst_idx, const BoundingBoxf3& bb)
: object_idx(obj_idx), instance_idx(inst_idx), bbox(bb), center(bb.center()) {}
};
explicit GLGizmoAlignment(GLCanvas3D& canvas);
~GLGizmoAlignment() = default;
bool align_objects(AlignType type,bool align_parent = false);
bool distribute_objects(AlignType type);
bool align_to_center(AlignType type,bool align_parent = false);
bool align_to_y_max(bool align_parent = false);
bool align_to_y_min(bool align_parent = false);
bool align_to_x_max(bool align_parent = false);
bool align_to_x_min(bool align_parent = false);
bool align_to_z_max(bool align_parent = false);
bool align_to_z_min(bool align_parent = false);
bool distribute_x();
bool distribute_y();
bool distribute_z();
bool can_align(AlignType type) const;
bool can_distribute(AlignType type) const;
std::vector<ObjectInfo> get_selected_objects_info(BoundingBoxf3 &big_bb) const;
double get_current_coord(std::string operation_name, BoundingBoxf3 &bbox);
Vec3d generate_displacement(std::string operation_name, double offset);
bool is_part_align_parent();
void set_parent_box(const BoundingBoxf3 &bb);
private:
GLCanvas3D& m_canvas;
template<typename GetCoordFunc, typename SetCoordFunc>
bool align_objects_generic(GetCoordFunc get_coord, SetCoordFunc set_coord, const std::string &operation_name, bool align_parent = false);
template<typename GetCoordFunc>
bool distribute_objects_generic(GetCoordFunc get_coord, int axis,
const std::string& operation_name);
Selection& get_selection() const;
bool take_snapshot(const std::string& name);
void apply_transformation(int obj_idx, int inst_idx, const Vec3d& displacement);
void finish_operation(const std::string &operation_name, bool force_volume_move = false);
bool validate_selection_for_align() const;
bool validate_selection_for_distribute() const;
private:
BoundingBoxf3 m_parent_box;
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLGizmoAlignment_hpp_
@@ -71,7 +71,6 @@
#include <array>
#include <cmath>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
@@ -3918,7 +3917,7 @@ void GLGizmoTextureDisplacement::set_layer_texture(TextureDisplacementLayer &lay
// the PNG the first time the layer is previewed or baked.
layer.image_data = tex->image_data;
// The user's own textures are listed most recently used first.
if (entry.source == TextureSource::User)
if (entry.is_user)
touch_user_texture(entry.path);
rebuild_preview();
@@ -3965,41 +3964,12 @@ void GLGizmoTextureDisplacement::render_texture_library_popup(const ImVec2 &pane
const float spacing = std::round(m_imgui->scaled(0.4f));
const float grid_w = 4.f * tile + 3.f * spacing;
const float gap = m_imgui->scaled(0.5f);
const ImGuiStyle &style = ImGui::GetStyle();
// A fixed size rather than a fit-to-content one. The width is the four-column grid plus the window
// padding and the scrollbar gutter, so the columns always fit and no horizontal scrollbar is needed.
// The height is a share of the window, not of the content, so it does not jump as packs load or
// sections collapse; the width derives from scaled values, so it tracks the DPI like the rest.
const float fixed_w = grid_w + 2.f * style.WindowPadding.x + style.ScrollbarSize;
// BeginPopup() ORs in ImGuiWindowFlags_AlwaysAutoResize (deps_src/imgui/imgui.cpp:8371) and no flag
// turns it back off. A SetNextWindowSize() overrides it for each axis it sets (imgui.cpp:5983-5996),
// so an explicit size is the only way to fix the popup's size; the window then scrolls its content.
//
// About 70% of the window, fixed for a given window, shortened only enough to keep a gap above and
// below, and floored at two frame heights so a very short window still shows something usable.
const ImGuiViewport *viewport = ImGui::GetMainViewport();
const float height = std::max(std::min(0.70f * viewport->Size.y, viewport->Size.y - 2.f * gap),
2.f * ImGui::GetFrameHeight());
// A 70%-tall popup cannot hang off the panel's top: anchored there, the side it grows to holds only
// about half the window. It uses the whole column beside the panel instead, filling from the top or
// the bottom of the viewport depending on which side of the panel's top has more room.
const float popup_top = panel_min.y + m_imgui->scaled(4.f);
const float space_below = viewport->Pos.y + viewport->Size.y - popup_top - gap;
const float space_above = popup_top - viewport->Pos.y - gap;
const bool grow_down = space_below >= space_above;
const float popup_y = grow_down ? viewport->Pos.y + gap
: viewport->Pos.y + viewport->Size.y - gap - height;
// Beside the panel rather than over it, so the layer being retextured stays in view: to its left when
// there is room (the docked panel sits against the right edge of the canvas), otherwise to its right.
const float width = viewport->Size.x > 0.f ? std::min(fixed_w, viewport->Size.x) : fixed_w;
const bool left = panel_min.x - gap - width >= 0.f;
const float popup_x = left ? panel_min.x - gap - width : panel_max.x + gap;
// Cond_Always, not Appearing: a viewport resize while the popup is open must move and resize it too.
ImGui::SetNextWindowPos(ImVec2(popup_x, popup_y), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
const float popup_w = grid_w + 2.f * ImGui::GetStyle().WindowPadding.x;
const bool left = panel_min.x - gap - popup_w >= 0.f;
ImGui::SetNextWindowPos(ImVec2(left ? panel_min.x - gap : panel_max.x + gap, panel_min.y + m_imgui->scaled(4.f)),
ImGuiCond_Appearing, ImVec2(left ? 1.f : 0.f, 0.f));
if (!ImGui::BeginPopup(popup_id))
return;
if (layer == nullptr) {
@@ -4013,12 +3983,6 @@ void GLGizmoTextureDisplacement::render_texture_library_popup(const ImVec2 &pane
m_imgui->pop_bold_font();
const std::vector<TextureLibraryEntry> &library = texture_library();
// A reinstalled pack can drop new bytes at a path already cached on this gizmo, and get_library_texture()
// caches a failure as well as a success, so a moved generation makes every cached entry suspect.
if (const uint64_t generation = texture_library_generation(); generation != m_library_generation) {
m_library_textures.clear();
m_library_generation = generation;
}
ImDrawList *dl = ImGui::GetWindowDrawList();
const ImU32 selected_col = ImGui::GetColorU32(ImGuiWrapper::COL_ORCA);
std::optional<TextureLibraryEntry> chosen;
@@ -4039,15 +4003,16 @@ void GLGizmoTextureDisplacement::render_texture_library_popup(const ImVec2 &pane
ImGui::Dummy(ImVec2(grid_w, float(rows) * tile + float(rows - 1) * spacing));
}
};
// One section's tiles, in the order the section holds them (shipped alphabetically, pack textures by
// name, the user's own most recently used first - the order texture_library() produced); a user tile
// carries a remove button on hover. Returns how many it drew.
const auto grid = [&](const ImVec2 &origin, const std::vector<const TextureLibraryEntry *> &entries, bool removable) {
// One group's tiles: shipped textures alphabetically, or the user's own most recently used first (the
// order texture_library() keeps), those with a remove button on hover. Returns how many it drew.
const auto grid = [&](const ImVec2 &origin, bool user) {
int n = 0;
for (const TextureLibraryEntry *entry : entries) {
for (const TextureLibraryEntry &entry : library) {
if (entry.is_user != user)
continue;
ImGui::SetCursorScreenPos(tile_pos(origin, n++));
ImGui::PushID(entry->path.c_str());
const LibraryTexture *tex = get_library_texture(entry->path);
ImGui::PushID(entry.path.c_str());
const LibraryTexture *tex = get_library_texture(entry.path);
GLTexture *thumb = tex != nullptr ? tex->thumbnail.get() : nullptr;
bool clicked = false;
if (thumb != nullptr) {
@@ -4065,17 +4030,15 @@ void GLGizmoTextureDisplacement::render_texture_library_popup(const ImVec2 &pane
} else {
clicked = ImGui::Button("?", ImVec2(tile, tile));
}
if (removable)
if (user)
ImGui::SetItemAllowOverlap(); // the remove button drawn over its corner takes its own clicks
const ImVec2 a = ImGui::GetItemRectMin(), b = ImGui::GetItemRectMax();
if (entry->path == layer->path)
if (entry.path == layer->path)
dl->AddRect(ImVec2(a.x - 1.f, a.y - 1.f), ImVec2(b.x + 1.f, b.y + 1.f), selected_col, 0.f, 0, 2.f);
if (ImGui::IsItemHovered())
m_imgui->tooltip(entry->name, m_imgui->scaled(18.f));
m_imgui->tooltip(entry.name, m_imgui->scaled(18.f));
// Clipped by the window's own clip rect, so a tile scrolled under the heading or the scrollbar
// does not offer its remove button. IsMouseHoveringRect() clips by default.
if (removable && ImGui::IsMouseHoveringRect(a, b)) {
if (user && ImGui::IsMouseHoveringRect(a, b)) {
const float r = std::round(tile * 0.17f);
const ImVec2 c(b.x - r - 2.f, a.y + r + 2.f);
ImGui::SetCursorScreenPos(ImVec2(c.x - r, c.y - r));
@@ -4088,105 +4051,41 @@ void GLGizmoTextureDisplacement::render_texture_library_popup(const ImVec2 &pane
if (hot)
m_imgui->tooltip(_u8L("Remove from My textures"), m_imgui->scaled(18.f));
if (remove_clicked)
to_remove = *entry;
to_remove = entry;
}
ImGui::PopID();
if (clicked)
chosen = *entry;
chosen = entry;
}
return n;
};
// Every section collapses; the state is remembered for the app run. Looked up by section name - the
// fixed Built-in / My textures keys, or a pack's display name. A capability name is unique per type
// across loaded packages (PluginManager::check_registry_locked, PluginManager.cpp:211-225), and it is
// stable across reinstalls, unlike the plugin_key, which is the wheel filename stem and so carries the
// version: keying on that would silently reset the user's collapse choice on every pack upgrade. A
// function-local static lives exactly as long as the app and never touches app_config: remembered
// while the popup closes and reopens, reset on restart.
static std::map<std::string, bool> s_section_collapsed; // true = collapsed; absent = expanded
// A section heading with its collapse control at the right edge of the grid: the triangle points
// down while the section is open and right while it is collapsed, and toggles it when clicked.
// Returns true when the section is open, so the caller knows whether to draw its grid.
const auto section_header = [&](const std::string &key, const std::string &title) {
bool &collapsed = s_section_collapsed[key]; // default-inserts false -> expanded
const ImVec2 row = ImGui::GetCursorScreenPos();
const float row_h = ImGui::GetFrameHeight();
ImGui::SetCursorScreenPos(ImVec2(row.x, row.y + (row_h - ImGui::GetTextLineHeight()) * 0.5f));
ImGui::TextDisabled("%s", title.c_str());
const bool clipped = ImGui::CalcTextSize(title.c_str()).x > grid_w - row_h - spacing;
if (clipped && ImGui::IsItemHovered())
m_imgui->tooltip(title, m_imgui->scaled(18.f)); // a long plugin-supplied name, cut by the fixed width
ImGui::SetCursorScreenPos(ImVec2(row.x + grid_w - row_h, row.y));
ImGui::PushID(key.c_str());
if (ImGui::ArrowButton("##collapse", collapsed ? ImGuiDir_Right : ImGuiDir_Down))
collapsed = !collapsed;
ImGui::PopID();
ImGui::SetCursorScreenPos(ImVec2(row.x, row.y + row_h + ImGui::GetStyle().ItemSpacing.y));
return !collapsed;
};
// One section per source: Built-in first, then one per pack, then My textures last (so the import tile
// and the help line keep describing the group they sit in). Pack entries are grouped by pack_name,
// which is the capability's get_name(): unique per capability type across loaded packages
// (PluginManager::check_registry_locked, PluginManager.cpp:211-225), so it identifies a pack both for
// grouping and for the remembered collapse state, and stands in for the section title. A section is
// identified by `builtin:`, `user:` or `pack:<name>`, so a pack named "builtin" cannot collide with
// the fixed Built-in section.
struct Section
ImGui::TextDisabled("%s", _u8L("Built-in").c_str());
{
std::string key;
std::string title;
TextureSource source;
std::vector<const TextureLibraryEntry *> entries;
};
std::vector<Section> sections;
std::map<std::string, size_t> pack_section; // pack_name -> index in `sections`
sections.push_back({ "builtin:", _u8L("Built-in"), TextureSource::Shipped, {} });
for (const TextureLibraryEntry &entry : library) {
if (entry.source == TextureSource::Shipped) {
sections.front().entries.push_back(&entry); // the section exists even when the library is empty
continue;
}
if (entry.source == TextureSource::User)
continue; // added below, so My textures stays last
const auto [it, inserted] = pack_section.emplace(entry.pack_name, sections.size());
if (inserted)
sections.push_back({ "pack:" + entry.pack_name, entry.pack_name, TextureSource::Plugin, {} });
sections[it->second].entries.push_back(&entry);
}
sections.push_back({ "user:", _u8L("My textures"), TextureSource::User, {} });
for (const TextureLibraryEntry &entry : library)
if (entry.source == TextureSource::User)
sections.back().entries.push_back(&entry);
for (const Section &section : sections) {
if (!section_header(section.key, section.title))
continue;
const ImVec2 origin = ImGui::GetCursorScreenPos();
const int count = grid(origin, section.entries, section.source == TextureSource::User);
if (section.source == TextureSource::User) {
ImGui::SetCursorScreenPos(tile_pos(origin, count));
if (ImGui::Button("+##import_texture", ImVec2(tile, tile)))
import_clicked = true;
if (ImGui::IsItemHovered())
m_imgui->tooltip(_u8L("Import your own image as a height map. It is converted to the format the slicer "
"bakes from and saved to your personal texture folder, kept separate from the "
"textures shipped with OrcaSlicer."),
m_imgui->scaled(20.f));
end_grid(origin, count + 1);
// Belongs to this section: it describes the import tile and the remove-on-hover tiles, both of
// which live here, so it is hidden with them rather than left describing controls off-screen.
ImGui::PushTextWrapPos(ImGui::GetCursorPosX() + grid_w);
ImGui::TextDisabled("%s", _u8L("PNG, JPG or BMP - converted to a height map on import. Hover one of yours to remove it.").c_str());
ImGui::PopTextWrapPos();
} else {
end_grid(origin, count);
if (section.source == TextureSource::Shipped && count == 0)
ImGui::TextDisabled("%s", _u8L("No textures found.").c_str());
}
const int count = grid(origin, false);
end_grid(origin, count);
if (count == 0)
ImGui::TextDisabled("%s", _u8L("No textures found.").c_str());
}
ImGui::TextDisabled("%s", _u8L("My textures").c_str());
{
const ImVec2 origin = ImGui::GetCursorScreenPos();
const int count = grid(origin, true);
ImGui::SetCursorScreenPos(tile_pos(origin, count));
if (ImGui::Button("+##import_texture", ImVec2(tile, tile)))
import_clicked = true;
if (ImGui::IsItemHovered())
m_imgui->tooltip(_u8L("Import your own image as a height map. It is converted to the format the slicer "
"bakes from and saved to your personal texture folder, kept separate from the "
"textures shipped with OrcaSlicer."),
m_imgui->scaled(20.f));
end_grid(origin, count + 1);
}
ImGui::PushTextWrapPos(ImGui::GetCursorPosX() + grid_w);
ImGui::TextDisabled("%s", _u8L("PNG, JPG or BMP - converted to a height map on import. Hover one of yours to remove it.").c_str());
ImGui::PopTextWrapPos();
if (chosen || import_clicked)
ImGui::CloseCurrentPopup();
@@ -1061,8 +1061,6 @@ private:
// Library textures the picker has shown at least once, keyed by file path (see LibraryTexture).
std::map<std::string, LibraryTexture> m_library_textures;
// Generation of the library the above were cached against; a change clears them.
uint64_t m_library_generation = 0;
// Everything the *unwrap* depends on. update_uv_editor() runs from rebuild_preview(), i.e. on
// every stroke end and every slider release - but depth/tiling/rotation/offset/blend change
-31
View File
@@ -470,37 +470,6 @@ bool GLGizmosManager::check_gizmos_closed_except(EType type) const
return true;
}
// Switches the active plate to the one containing the first selected object,
// so that subsequent operations (align/distribute) act on a plate the user
// can actually see.
void GLGizmosManager::check_object_located_outside_plate(bool change_plate)
{
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
auto curr_plate_index = plate_list.get_curr_plate_index();
Selection& selection = m_parent.get_selection();
auto idxs = selection.get_volume_idxs();
if (idxs.empty())
return;
const GLVolume* v = selection.get_volume(*idxs.begin());
int object_idx = v->object_idx();
const Model* model = m_parent.get_model();
if (object_idx < 0 || object_idx >= (int) model->objects.size())
return;
ModelObject* model_object = model->objects[object_idx];
for (size_t i = 0; i < plate_list.get_plate_count(); ++i) {
auto plate = plate_list.get_plate(i);
for (auto object : plate->get_objects_on_this_plate()) {
if (model_object == object) {
if (change_plate && curr_plate_index != (int) i)
plate_list.select_plate(i);
return;
}
}
}
}
void GLGizmosManager::set_hover_id(int id)
{
// Measure and assembly handles hover by itself
@@ -261,7 +261,6 @@ public:
void reset_all_states();
bool open_gizmo(EType type);
bool check_gizmos_closed_except(EType) const;
void check_object_located_outside_plate(bool change_plate = true);
void set_hover_id(int id);
+57 -236
View File
@@ -245,7 +245,6 @@
#include "Widgets/MultiNozzleSync.hpp" // NozzleOption, tryPopUpMultiNozzleDialog, setExtruderNozzleCount
#include "DeviceCore/DevNozzleSystem.h" // DevNozzle, GetExtNozzles / GetRackNozzles
#include "ProjectDirtyStateManager.hpp"
#include "Gizmos/GLGizmoAlignment.hpp"
#include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification
#include "Gizmos/GLGizmoSVG.hpp" // Drop SVG file
#include "Gizmos/GizmoObjectManipulation.hpp"
@@ -6014,8 +6013,7 @@ void Sidebar::add_custom_filament(wxColour new_col, const std::string& preset_na
bool Sidebar::is_new_project_in_gcode3mf()
{
// A .gcode previewed with its own settings shows them here too, and is closed the same way.
if (p->plater->using_exported_file() || p->plater->gcode_settings_loaded()) {
if (p->plater->using_exported_file()) {
auto filename = p->plater->get_preview_only_filename();
auto text = wxString::Format(_L("After completing your operation, %s project will be closed and create a new project."), filename);
MessageDialog dlg(wxGetApp().plater(), text, _L("Warning"),
@@ -7369,9 +7367,6 @@ struct Plater::priv
void enable_sidebar(bool enabled);
void collapse_sidebar(bool collapse);
void update_sidebar(bool force_update = false);
// The sidebar shows the selected presets, which a G-code previewed without its own settings has nothing to do
// with, so it stays hidden then. With the file's settings loaded it shows them, as for a .gcode.3mf.
bool gcode_preview_without_settings() const { return q->m_only_gcode && !q->m_gcode_settings_loaded; }
void reset_window_layout();
Sidebar::DockingState get_sidebar_docking_state();
void add_dock_pane(wxWindow* window, const std::string& name, const wxString& caption, const std::string& dock,
@@ -7485,18 +7480,6 @@ struct Plater::priv
void delete_all_objects_from_model();
void reset(bool apply_presets_change = false, bool reload_presets = true);
void center_selection();
void distribute_selection_x();
void distribute_selection_y();
void distribute_selection_z();
void align_selection_x_min();
void align_selection_x_center();
void align_selection_x_max();
void align_selection_y_min();
void align_selection_y_center();
void align_selection_y_max();
void align_selection_z_min();
void align_selection_z_center();
void align_selection_z_max();
void drop_selection();
void mirror(Axis axis);
void split_object(bool auto_drop = true);
@@ -8609,7 +8592,7 @@ void Plater::priv::select_next_view_3D()
void Plater::priv::enable_sidebar(bool enabled)
{
if (gcode_preview_without_settings())
if (q->m_only_gcode)
enabled = false;
sidebar_layout.is_enabled = enabled;
@@ -8618,7 +8601,7 @@ void Plater::priv::enable_sidebar(bool enabled)
void Plater::priv::collapse_sidebar(bool collapse)
{
if (gcode_preview_without_settings())
if (q->m_only_gcode)
return;
sidebar_layout.is_collapsed = collapse;
@@ -8881,64 +8864,6 @@ static void log_substitutions(const PresetsConfigSubstitutions& substitutions, c
log_substitutions(preset.substitutions, source + " (preset " + preset.preset_name + ")");
}
// After the settings of a project or a G-code were loaded into the presets: size the per-filament project
// lists to the loaded filament count, and drop state only a connected printer may set.
static void sync_loaded_project_filament_config(DynamicConfig& proj_cfg)
{
ConfigOptionStrings* filament_color = proj_cfg.opt<ConfigOptionStrings>("filament_colour");
if (filament_color) {
size_t filament_count = filament_color->size();
// Sync filament map
ConfigOptionInts* filament_map = proj_cfg.opt<ConfigOptionInts>("filament_map", true);
if (filament_map->size() != filament_count) {
filament_map->values.resize(filament_count, 1);
}
ConfigOptionInts* filament_nozzle_map = proj_cfg.opt<ConfigOptionInts>("filament_nozzle_map", true);
if (filament_nozzle_map->size() != filament_count) {
filament_nozzle_map->values.resize(filament_count, 0);
}
ConfigOptionInts* filament_volume_map = proj_cfg.opt<ConfigOptionInts>("filament_volume_map", true);
if (filament_volume_map->size() != filament_count) {
filament_volume_map->values.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
}
// Sync filament multi colour
ConfigOptionStrings* filament_multi_color = proj_cfg.opt<ConfigOptionStrings>("filament_multi_colour", true);
if (filament_multi_color->size() != filament_count) {
filament_multi_color->values.resize(filament_count);
}
// If there is no multi-color data or color is not match, use single color as default value
for (size_t i = 0; i < filament_count; i++) {
std::vector<std::string> colors = Slic3r::split_string(filament_multi_color->values[i], ' ');
if (i >= filament_multi_color->values.size() || colors.empty() || colors[0] != filament_color->values[i] ) {
filament_multi_color->values[i] = filament_color->values[i];
}
}
// Sync filament colour type
ConfigOptionStrings* filament_color_type = proj_cfg.opt<ConfigOptionStrings>("filament_colour_type", true);
if (filament_color_type && filament_color_type->size() != filament_count) {
filament_color_type->values.resize(filament_count);
for (size_t i = 0; i < filament_count; i++) {
if (i >= filament_color_type->values.size() || filament_color_type->values[i].empty()) {
filament_color_type->values[i] = "1";
}
}
}
}
// Filament Track Switch state is derived live from the connected
// printer; a loaded project must not carry a stale installed/active
// flag, so clear both and let device sync re-derive them.
if (auto* has_switcher = proj_cfg.opt<ConfigOptionBool>("has_filament_switcher"))
has_switcher->value = false;
if (auto* dynamic_map = proj_cfg.opt<ConfigOptionBool>("enable_filament_dynamic_map"))
dynamic_map->value = false;
}
// BBS: backup & restore
std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_files,
LoadStrategy strategy,
@@ -9755,7 +9680,58 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (file_wipe_tower_y)
*wipe_tower_y = *file_wipe_tower_y;
sync_loaded_project_filament_config(proj_cfg);
ConfigOptionStrings* filament_color = proj_cfg.opt<ConfigOptionStrings>("filament_colour");
if (filament_color) {
size_t filament_count = filament_color->size();
// Sync filament map
ConfigOptionInts* filament_map = proj_cfg.opt<ConfigOptionInts>("filament_map", true);
if (filament_map->size() != filament_count) {
filament_map->values.resize(filament_count, 1);
}
ConfigOptionInts* filament_nozzle_map = proj_cfg.opt<ConfigOptionInts>("filament_nozzle_map", true);
if (filament_nozzle_map->size() != filament_count) {
filament_nozzle_map->values.resize(filament_count, 0);
}
ConfigOptionInts* filament_volume_map = proj_cfg.opt<ConfigOptionInts>("filament_volume_map", true);
if (filament_volume_map->size() != filament_count) {
filament_volume_map->values.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
}
// Sync filament multi colour
ConfigOptionStrings* filament_multi_color = proj_cfg.opt<ConfigOptionStrings>("filament_multi_colour", true);
if (filament_multi_color->size() != filament_count) {
filament_multi_color->values.resize(filament_count);
}
// If there is no multi-color data or color is not match, use single color as default value
for (size_t i = 0; i < filament_count; i++) {
std::vector<std::string> colors = Slic3r::split_string(filament_multi_color->values[i], ' ');
if (i >= filament_multi_color->values.size() || colors.empty() || colors[0] != filament_color->values[i] ) {
filament_multi_color->values[i] = filament_color->values[i];
}
}
// Sync filament colour type
ConfigOptionStrings* filament_color_type = proj_cfg.opt<ConfigOptionStrings>("filament_colour_type", true);
if (filament_color_type && filament_color_type->size() != filament_count) {
filament_color_type->values.resize(filament_count);
for (size_t i = 0; i < filament_count; i++) {
if (i >= filament_color_type->values.size() || filament_color_type->values[i].empty()) {
filament_color_type->values[i] = "1";
}
}
}
}
// Filament Track Switch state is derived live from the connected
// printer; a loaded project must not carry a stale installed/active
// flag, so clear both and let device sync re-derive them.
if (auto* has_switcher = proj_cfg.opt<ConfigOptionBool>("has_filament_switcher"))
has_switcher->value = false;
if (auto* dynamic_map = proj_cfg.opt<ConfigOptionBool>("enable_filament_dynamic_map"))
dynamic_map->value = false;
}
// Update filament combobox after loading config
if (published_config.published) {
@@ -10926,78 +10902,6 @@ void Plater::priv::center_selection()
view3D->center_selected();
}
void Plater::priv::distribute_selection_x()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.distribute_objects(GLGizmoAlignment::AlignType::DISTRIBUTE_X);
}
void Plater::priv::distribute_selection_y()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.distribute_objects(GLGizmoAlignment::AlignType::DISTRIBUTE_Y);
}
void Plater::priv::distribute_selection_z()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.distribute_objects(GLGizmoAlignment::AlignType::DISTRIBUTE_Z);
}
void Plater::priv::align_selection_x_min()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::X_MIN);
}
void Plater::priv::align_selection_x_center()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::CENTER_X);
}
void Plater::priv::align_selection_x_max()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::X_MAX);
}
void Plater::priv::align_selection_y_min()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::Y_MIN);
}
void Plater::priv::align_selection_y_center()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::CENTER_Y);
}
void Plater::priv::align_selection_y_max()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::Y_MAX);
}
void Plater::priv::align_selection_z_min()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::Z_MIN);
}
void Plater::priv::align_selection_z_center()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::CENTER_Z);
}
void Plater::priv::align_selection_z_max()
{
GLGizmoAlignment alignment_helper(*view3D->get_canvas3d());
alignment_helper.align_objects(GLGizmoAlignment::AlignType::Z_MAX);
}
void Plater::priv::drop_selection()
{
view3D->drop_selected();
@@ -12656,7 +12560,7 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
// Add sidebar and toolbar collapse logic
if (panel == view3D || panel == preview) {
this->enable_sidebar(true);
this->enable_sidebar(!q->only_gcode_mode());
}
if (panel == preview) {
if (q->only_gcode_mode()) {
@@ -18163,80 +18067,11 @@ void Plater::load_gcode(const wxString& filename)
m_last_loaded_gcode = filename;
// An OrcaSlicer G-code carries the settings it was sliced with. They replace the selected presets as a
// .gcode.3mf's do, so unsaved preset changes get the save-or-discard choice of opening a project rather
// than the new project's choice to keep them.
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
const std::string path = into_u8(filename);
std::optional<DynamicPrintConfig> file_config;
ConfigSubstitutions substitutions;
{
wxBusyCursor wait;
try {
file_config = preset_bundle->config_from_gcode(path, ForwardCompatibilitySubstitutionRule::Enable, substitutions);
} catch (const std::exception& ex) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": no settings to load from " << path << ": " << ex.what();
}
}
// BSS: create a new project when load_gcode, force close previous one
if (file_config) {
auto check = [](bool yes_or_no) {
return yes_or_no || wxGetApp().check_and_save_current_preset_changes(_L("Load project"), _L("Some presets are modified."));
};
if (close_with_confirm(check) == wxID_CANCEL || new_project(true, true) != wxID_YES)
return;
} else if (new_project(false, true) != wxID_YES)
if (new_project(false, true) != wxID_YES)
return;
m_only_gcode = true;
m_gcode_settings_loaded = false;
// A previewed G-code's settings are not the selection the app should remember.
PresetBundle::SelectionExportBlocker no_selection_export(*preset_bundle);
// What loading the file's settings replaces, to put back if that load fails or the file is rejected.
std::optional<PresetBundle::Selection> previous;
if (file_config) {
previous = preset_bundle->selection();
if (!previous)
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": project presets are still loaded, not loading the settings of " << path;
}
auto unload_file_settings = [this, preset_bundle, &previous]() {
if (!previous)
return;
preset_bundle->restore_selection(*previous);
wxGetApp().load_current_presets(false, false);
// Switching back to the previous printer re-derives some project settings (TabPrinter::on_preset_loaded),
// and only the printer refresh shows them in the sidebar's flow selectors.
preset_bundle->project_config = std::move(previous->project_config);
sidebar().update_presets(Preset::TYPE_PRINTER);
reset_project_dirty_initial_presets();
update_project_dirty_from_presets();
m_gcode_settings_loaded = false;
// The rejections after the switch to the preview have already shown the sidebar with the file's settings.
enable_sidebar(false);
previous.reset();
};
if (previous) {
try {
preset_bundle->load_config_model(path, std::move(*file_config));
m_gcode_settings_loaded = true;
} catch (const std::exception& ex) {
unload_file_settings();
get_notification_manager()->push_notification(NotificationType::CustomNotification,
NotificationManager::NotificationLevel::WarningNotificationLevel,
GUI::format(_L("Failed loading file \"%1%\". An invalid configuration was found."), path) +
"\n" + ex.what());
}
}
if (m_gcode_settings_loaded) {
wxGetApp().load_current_presets(false, false);
sync_loaded_project_filament_config(preset_bundle->project_config);
sidebar().update_presets(Preset::TYPE_FILAMENT);
reset_project_dirty_initial_presets();
update_project_dirty_from_presets();
if (!substitutions.empty())
show_substitutions_info(substitutions, path);
}
// cleanup view before to start loading/processing
//BBS: update gcode to current partplate's
@@ -18264,7 +18099,6 @@ void Plater::load_gcode(const wxString& filename)
}
catch (const std::exception& ex)
{
unload_file_settings();
show_error(this, ex.what());
return;
}
@@ -18312,7 +18146,6 @@ void Plater::load_gcode(const wxString& filename)
p->preview->get_canvas3d()->zoom_to_plate(0);
if (p->preview->get_canvas3d()->get_gcode_layers_zs().empty()) {
unload_file_settings();
MessageDialog(this, format_wxstr(_L("The selected file:\n%1%\ndoes not contain valid G-code."), filename),
wxString(GCODEVIEWER_APP_NAME) + " - " + _L("An Error has occurred while loading the G-code file."), wxCLOSE | wxICON_WARNING | wxCENTRE).ShowModal();
set_project_filename(_L(DEFAULT_PROJECT_NAME));
@@ -22311,18 +22144,6 @@ void Plater::suppress_background_process(const bool stop_background_process)
BackgroundSlicingProcess& Plater::background_process() { return p->background_process; }
void Plater::center_selection() { p->center_selection(); }
void Plater::distribute_selection_x() { p->distribute_selection_x(); }
void Plater::distribute_selection_y() { p->distribute_selection_y(); }
void Plater::distribute_selection_z() { p->distribute_selection_z(); }
void Plater::align_selection_x_min() { p->align_selection_x_min(); }
void Plater::align_selection_x_center() { p->align_selection_x_center(); }
void Plater::align_selection_x_max() { p->align_selection_x_max(); }
void Plater::align_selection_y_min() { p->align_selection_y_min(); }
void Plater::align_selection_y_center() { p->align_selection_y_center(); }
void Plater::align_selection_y_max() { p->align_selection_y_max(); }
void Plater::align_selection_z_min() { p->align_selection_z_min(); }
void Plater::align_selection_z_center() { p->align_selection_z_center(); }
void Plater::align_selection_z_max() { p->align_selection_z_max(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object(bool auto_drop) { p->split_object(auto_drop); }
-17
View File
@@ -418,9 +418,6 @@ public:
bool is_gcode_3mf() { return m_exported_file; }
bool only_gcode_mode() { return m_only_gcode; }
void set_only_gcode(bool only_gcode) { m_only_gcode = only_gcode; }
// The previewed G-code's own settings were loaded into the presets, as a .gcode.3mf's are: the bed already is the
// one it was sliced for, and the sidebar shows them.
bool gcode_settings_loaded() const { return m_only_gcode && m_gcode_settings_loaded; }
//BBS: add only gcode mode
bool using_exported_file() { return m_exported_file; }
@@ -762,18 +759,6 @@ public:
//BBS: add clone logic
void clone_selection();
void center_selection();
void distribute_selection_x();
void distribute_selection_y();
void distribute_selection_z();
void align_selection_x_min();
void align_selection_x_center();
void align_selection_x_max();
void align_selection_y_min();
void align_selection_y_center();
void align_selection_y_max();
void align_selection_z_min();
void align_selection_z_center();
void align_selection_z_max();
void drop_selection();
void search(bool plater_is_active, Preset::Type type, wxWindow *tag, TextInput *etag, wxWindow *stag);
void mirror(Axis axis);
@@ -1097,8 +1082,6 @@ private:
wxString m_last_loaded_gcode;
//BBS: add only gcode mode
bool m_only_gcode { false };//just for .gcode file not for .gcode.3mf
// Set by load_gcode() for the file it previews, so it means nothing once m_only_gcode is cleared.
bool m_gcode_settings_loaded { false };
bool m_exported_file { false };
bool skip_thumbnail_invalid { false };
bool m_loading_project { false };
+10 -72
View File
@@ -1,7 +1,6 @@
#include "TextureLibrary.hpp"
#include <algorithm>
#include <atomic>
#include <boost/filesystem/operations.hpp>
#include <cstddef>
#include <boost/filesystem/directory.hpp>
@@ -22,7 +21,6 @@
#include <boost/system/error_code.hpp>
#include <vector>
#include <wx/app.h>
#include <wx/gdicmn.h>
#include <utility>
#include <wx/image.h>
@@ -38,9 +36,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/plugin/PluginFsUtils.hpp"
#include "slic3r/plugin/host/PluginResourceTextures.hpp"
namespace Slic3r::GUI {
namespace {
@@ -55,7 +50,7 @@ bool is_image_file(const boost::filesystem::path &path)
return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp";
}
void scan_dir(const boost::filesystem::path &dir, TextureSource source, std::vector<TextureLibraryEntry> &out)
void scan_dir(const boost::filesystem::path &dir, bool is_user, std::vector<TextureLibraryEntry> &out)
{
boost::system::error_code ec;
if (!boost::filesystem::is_directory(dir, ec))
@@ -65,43 +60,12 @@ void scan_dir(const boost::filesystem::path &dir, TextureSource source, std::vec
for (boost::filesystem::directory_iterator it(dir, ec), end; it != end && !ec; it.increment(ec)) {
if (!boost::filesystem::is_regular_file(it->path(), ec) || !is_image_file(it->path()))
continue;
out.push_back({ it->path().stem().string(), it->path().string(), source });
out.push_back({ it->path().stem().string(), it->path().string(), is_user });
}
std::sort(out.begin() + first, out.end(),
[](const TextureLibraryEntry &a, const TextureLibraryEntry &b) { return a.name < b.name; });
}
// Appends every loaded pack's textures, ordered by the pack's display name and then by file name. Each
// entry carries the contributing pack's display name, which the picker uses to group a pack's textures
// into one section; a pack name is unique among loaded packs of this capability type, so the name both
// groups the section and keeps its entries contiguous. A pack whose directory fails validation is
// skipped, so one bad pack never hides the others.
void scan_plugin_textures(std::vector<TextureLibraryEntry> &out)
{
std::vector<TextureLibraryEntry> found;
for (const ResourceTextureEntry &pack : PluginResourceTextures::instance().entries()) {
std::string error;
const std::vector<std::string> files =
collect_resource_texture_files(pack.texture_dir, pack.plugin_root, error);
if (!error.empty()) {
BOOST_LOG_TRIVIAL(warning) << "Texture pack '" << pack.display_name << "' was skipped: " << error;
continue;
}
for (const std::string &file : files) {
const boost::filesystem::path path(file);
found.push_back({ path.stem().string(), file, TextureSource::Plugin, pack.display_name });
}
}
std::stable_sort(found.begin(), found.end(), [](const TextureLibraryEntry &a, const TextureLibraryEntry &b) {
if (a.pack_name != b.pack_name)
return a.pack_name < b.pack_name;
return a.name < b.name;
});
for (TextureLibraryEntry &entry : found)
out.push_back(std::move(entry));
}
// True if the image carries any colour at all, i.e. some pixel's channels are not all equal. A
// photo saved as RGB but actually grey should still be stored as a grayscale PNG - it is a third of
// the bytes, and the colour feature keys off has_color(), so storing a grey image as RGB would offer
@@ -244,11 +208,6 @@ bool is_supported_height_map(const std::vector<unsigned char> &bytes)
std::vector<TextureLibraryEntry> g_library;
bool g_library_scanned = false;
// The generation g_library was last built from, so texture_library() can rescan after a pack change.
uint64_t g_library_scan_generation = 0;
// Bumped by plugin callbacks, read by the GUI frame. Atomic so a read never races a write.
std::atomic<uint64_t> g_library_generation{ 0 };
// Writes `bytes` into the user's own texture folder as `stem`.png, uniquified so an existing texture -
// shipped-name collision, or a second edit of the same source - is never overwritten. Returns the new
@@ -296,8 +255,6 @@ const size_t RECENT_MAX = 200;
std::vector<std::string> recent_texture_names()
{
std::vector<std::string> names;
if (wxTheApp == nullptr) // headless or shutting down: there is no app config to read
return names;
if (wxGetApp().app_config == nullptr)
return names;
const std::string value = wxGetApp().app_config->get(RECENT_SECTION, RECENT_KEY);
@@ -312,8 +269,6 @@ std::vector<std::string> recent_texture_names()
void store_recent_texture_names(std::vector<std::string> names)
{
if (wxTheApp == nullptr) // headless or shutting down: there is no app config to write
return;
if (wxGetApp().app_config == nullptr)
return;
if (names.size() > RECENT_MAX)
@@ -324,9 +279,8 @@ void store_recent_texture_names(std::vector<std::string> names)
wxGetApp().app_config->set(RECENT_SECTION, RECENT_KEY, value);
}
// Reorders the user's entries by recent use. Stable, so textures never used keep the name order
// scan_dir() gave them, after every used one. Only the user's own range is touched: shipped and pack
// entries must keep the order their scans produced.
// Reorders the user's entries (the tail of `library`) by recent use. Stable, so textures never used keep
// the name order scan_dir() gave them, after every used one.
void sort_user_textures(std::vector<TextureLibraryEntry> &library)
{
const std::vector<std::string> names = recent_texture_names();
@@ -337,11 +291,8 @@ void sort_user_textures(std::vector<TextureLibraryEntry> &library)
const auto it = rank.find(boost::filesystem::path(e.path).filename().string());
return it == rank.end() ? std::numeric_limits<int>::max() : it->second;
};
const auto first_user = std::find_if(library.begin(), library.end(),
[](const TextureLibraryEntry &e) { return e.source == TextureSource::User; });
const auto user_end = std::find_if(first_user, library.end(),
[](const TextureLibraryEntry &e) { return e.source != TextureSource::User; });
std::stable_sort(first_user, user_end,
const auto first_user = std::find_if(library.begin(), library.end(), [](const TextureLibraryEntry &e) { return e.is_user; });
std::stable_sort(first_user, library.end(),
[&rank_of](const TextureLibraryEntry &a, const TextureLibraryEntry &b) { return rank_of(a) < rank_of(b); });
}
@@ -360,16 +311,6 @@ bool in_user_texture_dir(const std::string &path)
} // namespace
uint64_t texture_library_generation()
{
return g_library_generation.load();
}
void bump_texture_library_generation()
{
g_library_generation.fetch_add(1);
}
std::string user_texture_dir()
{
const boost::filesystem::path dir = boost::filesystem::path(Slic3r::data_dir()) / "textures" / "displacement";
@@ -384,20 +325,17 @@ std::string user_texture_dir()
const std::vector<TextureLibraryEntry> &texture_library(bool force_rescan)
{
const uint64_t generation = texture_library_generation();
if (g_library_scanned && !force_rescan && generation == g_library_scan_generation)
if (g_library_scanned && !force_rescan)
return g_library;
g_library.clear();
scan_dir(boost::filesystem::path(Slic3r::resources_dir()) / "textures" / "displacement", TextureSource::Shipped, g_library);
scan_dir(boost::filesystem::path(Slic3r::resources_dir()) / "textures" / "displacement", false, g_library);
const std::string user_dir = user_texture_dir();
if (!user_dir.empty())
scan_dir(boost::filesystem::path(user_dir), TextureSource::User, g_library);
scan_dir(boost::filesystem::path(user_dir), true, g_library);
sort_user_textures(g_library);
scan_plugin_textures(g_library);
g_library_scan_generation = generation;
g_library_scanned = true;
g_library_scanned = true;
return g_library;
}
+11 -31
View File
@@ -1,7 +1,6 @@
#ifndef slic3r_TextureLibrary_hpp_
#define slic3r_TextureLibrary_hpp_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
@@ -11,45 +10,26 @@
namespace Slic3r::GUI {
// Where a library texture came from. The picker lists each source under its own heading.
enum class TextureSource { Shipped, User, Plugin };
// One selectable height-map texture in the texture-displacement gizmo's texture picker. A texture that
// came from a plugin pack also carries the provenance the picker groups its sections by.
// One selectable height-map texture in the texture-displacement gizmo's texture picker.
struct TextureLibraryEntry
{
std::string name; // display name (the file's stem, e.g. "Wood Grain")
std::string path; // absolute path on disk
TextureSource source; // which of the three sources it came from
std::string pack_name; // contributing pack's display name; empty for Shipped and User
std::string name; // display name (the file's stem, e.g. "Wood Grain")
std::string path; // absolute path on disk
bool is_user; // imported by the user, as opposed to shipped with OrcaSlicer
};
// Every available height-map texture, in the order the picker lists them: the ones shipped in
// resources/textures/displacement first, by name; then the user's own from <data_dir>/textures/displacement,
// most recently used first (see touch_user_texture()) and the rest by name; then the loaded texture
// packs, ordered by pack display name and then by file name.
// Every available height-map texture: the ones shipped in resources/textures/displacement first, sorted
// by name, then the user's own from <data_dir>/textures/displacement - most recently used first (see
// touch_user_texture()), then any never used, by name.
//
// The shipped and user textures live in separate directories deliberately: an app update replaces the
// resources tree wholesale, so anything the user imported has to sit somewhere that update can never
// overwrite or delete. Pack textures are read-only like the shipped ones. Every texture carries its
// `source`; a pack texture also carries `pack_name`, and the picker groups pack textures into one
// collapsible section per pack name. A pack's name is unique among loaded packs of this capability type -
// the loader refuses a collision with "Capability collision for type ... and name ...", see
// PluginManager::check_registry_locked (PluginManager.cpp:211-225) - so the name on its own identifies a
// section and keeps that pack's entries contiguous.
// The two live in separate directories deliberately: an app update replaces the resources tree
// wholesale, so anything the user imported has to sit somewhere that update can never overwrite or
// delete. `is_user` is what the picker uses to show them under separate headings.
//
// Scanned once and cached. Pass force_rescan after an import, or to pick up a file the user dropped
// into either folder by hand while the app was running. A rescan also happens on its own when the pack
// registry changes, which is what texture_library_generation() tracks.
// into either folder by hand while the app was running.
const std::vector<TextureLibraryEntry> &texture_library(bool force_rescan = false);
// Monotonic counter, bumped whenever the set of loaded texture packs changes. The GUI reads it to
// decide whether texture_library() must rescan, and plugin callbacks bump it. Safe to read from any
// thread at any time.
uint64_t texture_library_generation();
void bump_texture_library_generation();
// Moves one of the user's own textures to the front of the recently-used order texture_library() lists
// them in, and stores that order in the app config so it survives a restart. No-op for anything that is
// not in user_texture_dir().
-1
View File
@@ -529,7 +529,6 @@ std::string PluginConfig::capability_type_label(PluginCapabilityType type)
case PluginCapabilityType::Visualization: return _u8L("Visualization");
case PluginCapabilityType::Script: return _u8L("Script");
case PluginCapabilityType::SlicingPipeline: return _u8L("Slicing Pipeline");
case PluginCapabilityType::ResourceTexture: return _u8L("Resource Texture");
default: return _u8L("Unknown");
}
}
-73
View File
@@ -9,7 +9,6 @@
#include <boost/filesystem/directory.hpp>
#include <boost/filesystem/file_status.hpp>
#include <boost/log/trivial.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/nowide/fstream.hpp>
#include "PluginAuditManager.hpp"
@@ -1256,76 +1255,4 @@ boost::filesystem::path find_installed_plugin_entry(const boost::filesystem::pat
return {};
}
std::vector<std::string> collect_resource_texture_files(const std::string& dir,
const std::string& plugin_root,
std::string& error)
{
namespace fs = boost::filesystem;
// Picker sanity bound, not a security control: the popup draws every entry in its grid.
constexpr size_t kMaxResourceTextureFiles = 64;
std::vector<std::string> files;
error.clear();
if (dir.empty()) {
error = _u8L("Resource texture directory is not set");
return files;
}
if (plugin_root.empty()) {
error = _u8L("Plugin folder could not be determined.");
return files;
}
boost::system::error_code ec;
const fs::path resolved_dir = fs::weakly_canonical(fs::path(dir), ec);
if (ec) {
error = _u8L("Resource texture directory could not be resolved");
return files;
}
if (!fs::is_directory(resolved_dir, ec) || ec) {
error = _u8L("Resource texture path is not a directory");
return files;
}
const fs::path resolved_root = fs::weakly_canonical(fs::path(plugin_root), ec);
if (ec) {
error = _u8L("Plugin folder could not be resolved");
return files;
}
if (!is_inside_allowed_root(resolved_dir, resolved_root)) {
error = _u8L("Resource texture directory is outside the plugin folder");
return files;
}
for (fs::directory_iterator it(resolved_dir, ec), end; it != end && !ec; it.increment(ec)) {
const fs::path& path = it->path();
if (!fs::is_regular_file(path, ec) || ec)
continue;
std::string ext = path.extension().string();
boost::algorithm::to_lower(ext);
if (ext != ".png" && ext != ".jpg" && ext != ".jpeg" && ext != ".bmp")
continue;
// Re-check per file: a symlink inside the pack must not resolve outside it.
if (!is_inside_allowed_root(path, resolved_root))
continue;
files.push_back(path.string());
if (files.size() >= kMaxResourceTextureFiles)
break;
}
if (ec) {
error = _u8L("Resource texture directory could not be read");
return {};
}
return files;
}
} // namespace Slic3r
-6
View File
@@ -176,12 +176,6 @@ bool read_wheel_plugin_metadata(const boost::filesystem::path& whl_path, PluginD
// Returns the path to the entry file, or an empty path with error set if zero or multiple candidates.
boost::filesystem::path find_installed_plugin_entry(const boost::filesystem::path& plugin_dir, std::string& error);
// Validated non-recursive .png/.jpg/.jpeg/.bmp files directly inside `dir`, every one contained in
// `plugin_root`. Empty with `error` set on failure.
std::vector<std::string> collect_resource_texture_files(const std::string& dir,
const std::string& plugin_root,
std::string& error);
// Canonical writer: emits the .install_state.json schema for the given state.
bool write_install_state(const boost::filesystem::path& plugin_dir, const PluginInstallState& state);
// Builds a PluginInstallState from the descriptor and delegates to the canonical writer.
-32
View File
@@ -9,7 +9,6 @@
#include "PluginFsUtils.hpp"
#include "PythonInterpreter.hpp"
#include "PythonPluginBridge.hpp"
#include "pluginTypes/resourceTexture/ResourceTexturePluginCapability.hpp"
#include "libslic3r/Utils.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/format.hpp"
@@ -388,37 +387,6 @@ bool load(const PluginDescriptor& descriptor,
instance->set_config_ui_available(false);
}
// ResourceTexture capabilities resolve their texture directory here, under the
// GIL this block already holds, and cache the validated result. A resolution
// fault only costs this capability its textures, so it is caught locally like
// has_config_ui() above rather than failing the load.
if (auto* resource_texture = dynamic_cast<ResourceTexturePluginCapability*>(instance.get())) {
try {
const std::string texture_dir = resource_texture->get_texture_dir();
if (texture_dir.empty()) {
resource_texture->set_texture_dir({});
} else {
std::string texture_error;
collect_resource_texture_files(texture_dir, descriptor.plugin_root, texture_error);
if (texture_error.empty()) {
resource_texture->set_texture_dir(texture_dir);
} else {
BOOST_LOG_TRIVIAL(warning)
<< "Plugin capability '" << found.name << "' of plugin '" << descriptor.plugin_key
<< "': texture directory rejected (" << texture_error
<< "); the capability will provide no textures";
resource_texture->set_texture_dir({});
}
}
} catch (const std::exception& ex) {
BOOST_LOG_TRIVIAL(warning)
<< "Plugin capability '" << found.name << "' of plugin '" << descriptor.plugin_key
<< "': get_texture_dir() failed (" << ex.what()
<< "); the capability will provide no textures";
resource_texture->set_texture_dir({});
}
}
capabilities.push_back(std::move(instance));
}
} catch (const std::exception& ex) {
-3
View File
@@ -25,7 +25,6 @@
#include "PyPluginTrampoline.hpp"
#include "pluginTypes/printerAgent/PrinterAgentPluginCapability.hpp"
#include "pluginTypes/pages/PagesPluginCapability.hpp"
#include "pluginTypes/resourceTexture/ResourceTexturePluginCapability.hpp"
#include "pluginTypes/script/ScriptPluginCapability.hpp"
#include "pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp"
#include <pybind11/pytypes.h>
@@ -375,7 +374,6 @@ void bind_python_api(pybind11::module_& m)
.value("Visualization", PluginCapabilityType::Visualization)
.value("Script", PluginCapabilityType::Script)
.value("SlicingPipeline", PluginCapabilityType::SlicingPipeline)
.value("ResourceTexture", PluginCapabilityType::ResourceTexture)
.value("Unknown", PluginCapabilityType::Unknown)
.export_values();
@@ -529,7 +527,6 @@ void bind_python_api(pybind11::module_& m)
PagesPluginCapability::RegisterBindings(m);
ScriptPluginCapability::RegisterBindings(m);
SlicingPipelinePluginCapability::RegisterBindings(m);
ResourceTexturePluginCapability::RegisterBindings(m);
PluginHost::RegisterBindings(m);
BOOST_LOG_TRIVIAL(debug) << "Registered ScriptPluginCapability Python bindings";
+1 -5
View File
@@ -14,7 +14,7 @@
namespace Slic3r {
enum class PluginCapabilityType { PrinterConnection = 0, Pages, Analysis, Importer, Exporter, Visualization, Script, SlicingPipeline, ResourceTexture, Unknown };
enum class PluginCapabilityType { PrinterConnection = 0, Pages, Analysis, Importer, Exporter, Visualization, Script, SlicingPipeline, Unknown };
struct PluginCapabilityId
{
@@ -48,7 +48,6 @@ inline std::string plugin_capability_type_to_string(PluginCapabilityType type)
case PluginCapabilityType::Visualization: return "visualization";
case PluginCapabilityType::Script: return "script";
case PluginCapabilityType::SlicingPipeline: return "slicing-pipeline";
case PluginCapabilityType::ResourceTexture: return "resource-texture";
default: return "unknown";
}
}
@@ -64,7 +63,6 @@ inline std::string plugin_capability_type_display_name(PluginCapabilityType type
case PluginCapabilityType::Visualization: return "Visualization";
case PluginCapabilityType::Script: return "Script";
case PluginCapabilityType::SlicingPipeline: return "Slicing Pipeline";
case PluginCapabilityType::ResourceTexture: return "Resource Texture";
default: return "Unknown";
}
}
@@ -94,8 +92,6 @@ inline PluginCapabilityType plugin_capability_type_from_string(std::string_view
return PluginCapabilityType::Script;
if (lowered == "slicing-pipeline")
return PluginCapabilityType::SlicingPipeline;
if (lowered == "resource-texture")
return PluginCapabilityType::ResourceTexture;
return PluginCapabilityType::Unknown;
}
+1 -68
View File
@@ -1,27 +1,16 @@
#include "PluginHostBindings.hpp"
#include "PluginHostUi.hpp"
#include "slic3r/plugin/PluginBindingUtils.hpp"
#include <pybind11/pytypes.h>
#include <pybind11/cast.h>
#include <pybind11/pybind11.h>
#include "slic3r/plugin/PluginBindingUtils.hpp"
#include <cstddef>
#include <libslic3r/AppConfig.hpp>
#include <libslic3r/Preset.hpp>
#include <libslic3r/PresetBundle.hpp>
#include <memory>
#include <slic3r/GUI/GUI.hpp>
#include <slic3r/GUI/GUI_App.hpp>
#include <slic3r/GUI/MainFrame.hpp>
#include <slic3r/GUI/Plater.hpp>
#include <slic3r/GUI/Tab.hpp>
#include <pybind11/stl.h>
#include <stdexcept>
#include <string>
#include <vector>
@@ -48,66 +37,10 @@ PresetCollection& printer_presets(PresetBundle& bundle)
return static_cast<PresetCollection&>(bundle.printers);
}
void reload_local_bundle(const std::string& bundle_id)
{
bool reloaded = false;
std::string error;
PluginHostUi::run_on_ui_thread([&] {
GUI::GUI_App& app = GUI::wxGetApp();
if (app.is_closing())
throw std::runtime_error("OrcaSlicer is closing");
if (app.preset_bundle == nullptr)
throw std::runtime_error("Preset bundle is not available");
if (app.app_config == nullptr)
throw std::runtime_error("Application configuration is not available");
if (app.mainframe == nullptr)
throw std::runtime_error("OrcaSlicer main window is not available");
reloaded = app.preset_bundle->reload_local_bundle(app.app_config->get("preset_folder"), bundle_id, &error);
if (!reloaded)
return;
app.mainframe->update_side_preset_ui();
for (GUI::Tab* tab : app.tabs_list) {
tab->reload_config();
tab->update_changed_ui();
}
if (GUI::Plater* plater = app.plater())
plater->sidebar().update_all_preset_comboboxes();
});
if (!reloaded)
throw std::runtime_error(error.empty() ? "Local bundle was not reloaded" : error);
}
std::vector<std::string> list_bundle_ids()
{
std::vector<std::string> ids;
PluginHostUi::run_on_ui_thread([&] {
GUI::GUI_App& app = GUI::wxGetApp();
if (app.is_closing())
throw std::runtime_error("OrcaSlicer is closing");
if (app.preset_bundle == nullptr)
throw std::runtime_error("Preset bundle is not available");
if (app.app_config == nullptr)
throw std::runtime_error("Application configuration is not available");
ids = app.preset_bundle->list_local_bundle_ids(app.app_config->get("preset_folder"));
});
return ids;
}
} // namespace
void host_bindings::register_presets(py::module_& host)
{
auto preset = host.def_submodule("preset", "Preset operations");
auto bundles = preset.def_submodule("bundles", "Local preset bundle operations");
bundles.def("reload_local", &reload_local_bundle, py::arg("bundle_id"),
"Reload one local preset bundle from the active user's _local directory.");
bundles.def("list_ids", &list_bundle_ids,
"IDs of local preset bundles in the active user's _local directory that reload_local() accepts, "
"including bundles added after startup.");
py::enum_<Preset::Type>(host, "PresetType")
.value("Invalid", Preset::TYPE_INVALID)
.value("Print", Preset::TYPE_PRINT)
-5
View File
@@ -646,11 +646,6 @@ void plater_notification(GUI::NotificationManager::NotificationLevel notificatio
} // namespace
void PluginHostUi::run_on_ui_thread(std::function<void()> fn)
{
run_on_ui_blocking(std::move(fn));
}
void PluginHostUi::RegisterBindings(pybind11::module_& host)
{
auto ui = host.def_submodule(

Some files were not shown because too many files have changed in this diff Show More