Commit Graph
30559 Commits
Author SHA1 Message Date
Ian Chua 274150af27 Merge branch 'main' into feat/plugin-storage-api 2026-08-05 20:11:29 +08:00
Ian Chua ae27a09ffe Merge remote-tracking branch 'origin/refactor/access-codes' into refactor/printer-agent-interface 2026-08-05 20:02:23 +08:00
Ian Chua cd33f589dc Merge branch 'main' into refactor/printer-agent-interface 2026-08-05 20:02:02 +08:00
Ian Chua 9ee736fe27 Merge branch 'main' into refactor/access-codes 2026-08-05 19:57:07 +08:00
Ian Chua ced1058b31 fix: naming and print host propagation 2026-08-05 19:52:51 +08:00
Ian Chua aae83220f1 fix: merge duplicated access code and allow empty access code in UI 2026-08-05 19:30:26 +08:00
SoftFever a10d9e77cf Make the wipe tower's planner flush and dwell work on Klipper (#15133)
# Description

On Klipper the wipe tower's motion-queue synchronization silently did
nothing. Klipper acts on commands the moment it parses them, and its
`G4` reads only `P` in milliseconds — it ignores `S` — so the `G4 S0`
the tower used to flush the queue before a temperature change never
synchronized anything, and the cooling delay after a filament's cooling
moves passed instantly instead of waiting. The tower now emits `M400`
for the flush and `G4 P<ms>` for the dwell when the flavor is Klipper.

Only `gcode_flavor = klipper` is affected; G-code for every other flavor
is byte-identical, so no shipped profile or existing project file
changes.

# Screenshots/Recordings/Graphs

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-08-05 18:21:05 +08:00
SoftFever 1d023216f2 clean up 2026-08-05 18:09:36 +08:00
SoftFever dc2796209f feat: printer agent UI (#15111)
# Description

Changes the device tab to render native wxWidgets UI and route the UI
via printer agents.

When the flag introduced in #15110 is enabled, the tab bar will show
both the native wxWidgets device tab and webview tab under the name
device (legacy)

This is a prerequisite for implementing the printer agent workflow.

<img width="3377" height="1378" alt="image"
src="https://github.com/user-attachments/assets/d72b646b-e6c6-4e10-b5d4-fc989debfca8"
/>
<img width="3377" height="1378" alt="image"
src="https://github.com/user-attachments/assets/2356c0f8-bffe-4cd5-bf4d-31f4b5c7706e"
/>

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-08-05 17:25:23 +08:00
SoftFever 194ef34080 Wait in the wipe tower with a millisecond dwell on Klipper
The wipe tower's "Delay after unloading" never happened on Klipper. It was
emitted as G4 S<seconds>, and Klipper's G4 reads only the P parameter, in
milliseconds, so the pause was silently skipped. The option now produces a
dwell Klipper actually performs.

Also corrects the planner flush rationale, which cited an extruder position
reset that Klipper resolves at parse time and does not need synchronized, and
adds end-to-end coverage that slices a two-filament print and checks the
emitted wipe tower G-code on both a Klipper and a non-Klipper flavor.

No change to any other firmware flavor's output, and no shipped profile sets a
non-zero delay, so no shipped profile's output moves either.
2026-08-05 17:15:35 +08:00
SoftFever 4e1caa39eb Flush the wipe tower planner queue with M400 on Klipper
The wipe tower emitted G4 S0 to make the firmware finish its queued moves
before commands that must not take effect early. Klipper's G4 reads only the
P parameter, so that flush never happened there and a temperature change could
land seconds ahead of the moves it was meant to follow. Klipper now gets M400
instead, through one helper shared by both wipe tower implementations.

No change to any other firmware flavor's output, so no shipped profile or saved
project is affected.
2026-08-05 17:15:35 +08:00
Ian Chua 38f5c84e7f fix: regression error 2026-08-05 16:20:58 +08:00
Tommaso Bianchi 0a2faedc32 Design: draw the mate connector, so its verse and polarity are visible
A mate connector was visible only to a program. resolve_datum_coordsys had exactly ONE consumer
in the whole tree -- McpControl.cpp, the agent socket -- so the frame every mate is built on
could not be seen at all, and the two questions a connector has to answer on sight had no
answer in the viewport: which way does Z point (the VERSE), and which of the pair is anchored
versus about to move (the POLARITY).

The glyph is Onshape's proven core plus the part nobody ships. Disc for the XY plane, one gold
quadrant for the roll -- the only in-glyph answer to "where is X", which matters because
Fastened and Slider lock the clocking -- and a Z arrow drawn on +Z ONLY, never double-headed.
Polarity is carried by the head: a filled cone travels, an open collar receives. Onshape,
Fusion, Inventor and FreeCAD all draw both ends of a mate identically, which is why "which part
moves?" is a standing complaint; nothing here invents new semantics, it just stops hiding them.

Polarity is read from the committed Mate features, not only from the open card. A connector some
mate drives must read as driven whenever it is on screen, or the glyph tells the truth only while
a dialog happens to be open. The card, when open, still wins -- that is the live intent.

Judged on the rig rather than in a mock, which changed three decisions:

- Three RGB axis arms lose to one Z arrow. Rendered side by side (SNAPORCA_GLYPH=A selects the
  Onshape-style trio), the three heads are as large as the 22 px disc, they bury the quadrant, and
  at an oblique angle they pile into a smudge -- and the trio is indistinguishable from the move
  gizmo and the bed triad, which are already RGB arrow trios in this viewport.

- Depth off floats, depth on tears. With GL_DEPTH_TEST off, connectors on faces pointing AWAY from
  the camera drew their discs over the solid, so the part looked covered in frames that were on its
  back. Turning depth on fixed that and immediately z-fought: the disc is exactly coplanar with its
  face and came out a broken dotted arc. Depth ON plus a 0.7*upp lift along Z buys both, and scaling
  the lift by upp keeps it sub-pixel instead of opening a visible gap on zoom-in.

- Foreshortening degenerates an arrow into a dot when the axis points at the camera. It now draws a
  ring instead of silently vanishing, which is what a naive projection does.

Everything is sized in screen pixels via upp = 1/zoom, like every other gizmo here: a connector is
a symbol, not a part, so it must not shrink with the model.

Research and the empirical findings are written up in DESIGN_MATE_CONNECTORS.md section 8b;
rig images in artifacts/shots/g-0*.png, vendor reference glyphs in artifacts/glyphs/.

Not fixed here, and recorded rather than papered over: the quadrant collapses to a blob at a
grazing angle, which is exactly when the roll is hardest to read (F4); roll-undefined in red makes
the least important connector the loudest thing on screen (F5); and a true grazing view, a curved
face, and overlap with the move gizmo are still untested. Also surfaced while testing and unrelated
to drawing: add_mate accepted a mate between two connectors on the SAME body and duly transformed
the body relative to itself -- a concrete instance of the missing validation already filed as G6.

Fork parity unchanged: DesignCanvas.cpp 16, DesignPanel.cpp 30, the other four files 0.
2026-08-05 09:50:09 +02:00
Ian Chua 4d8ce0e8a7 Merge branch 'main' into feat/printer-agent-ui 2026-08-05 13:40:20 +08:00
Ian Chua 38cb1ae8d1 Add developer flag for printer agents (#15110) 2026-08-05 13:40:05 +08:00
Ian Chua f3f44bffcb Merge branch 'feat/printer-agent-ui' of https://github.com/OrcaSlicer/OrcaSlicer into refactor/printer-agent-interface 2026-08-05 13:20:18 +08:00
Ian Chua 2d3e911efa Merge branch 'main' into refactor/printer-agent-interface 2026-08-05 13:16:47 +08:00
Ian Chua 32f82b64e7 fix: enable both device tabs 2026-08-05 13:07:32 +08:00
Ian Chua e56d7aeb80 Merge branch 'feat/printer-agent-ui' of https://github.com/OrcaSlicer/OrcaSlicer into feat/printer-agent-ui 2026-08-05 13:07:08 +08:00
Ian Chua 4758dc6c68 Merge branch 'main' into feat/printer-agent-ui 2026-08-05 13:06:47 +08:00
Ian Chua 596cbb8b2d Keep printer-agent error codes available to UI workflow 2026-08-05 11:39:37 +08:00
SoftFever 6312caaf13 Add filament_retract_length_toolchange/filament_retract_restart_extra_toolchange config and update tool changer printer's profiles (#15039)
* update snapmaker profiles. largely ported for Snapmaker Orca fork

* update prime volume

* set precise_outer_wall to 1

* Update per-material multi-tool ramming to the filament library

* Add per-filament overrides for toolchange retraction

* Set toolchange retraction per filament for Snapmaker U1

* set default support type to tree

* format snapmaker profiles
2026-08-05 00:13:27 +08:00
SoftFever 0051768206 Smooth out the spiral lift when arc fitting is disabled (#15118)
The linear approximation used a heuristic segment count clamped to 4..16, so the
lift ran as a coarse polygon. Every vertex is a direction change large enough to
hit the firmware's jerk limit, forcing a decelerate/accelerate at each corner —
the lift micro-stutters instead of running at speed. The segment count now comes
from the chord deviation against the slicing resolution, reusing
Geometry::ArcWelder::arc_discretization_steps, which keeps the turn at each
vertex shallow enough for the firmware to carry speed through the whole move.

Points are emitted through GCodeG1Formatter so they carry the same quantization
as the rest of the G-code, and the move comment now trails the feedrate line to
match _travel_to_z and the G2/G3 branch. No change when arc fitting is enabled.
2026-08-05 00:09:46 +08:00
Ian Bassi 1d078e005a Mouse ear Wiki redirect (#15115)
Based in https://github.com/OrcaSlicer/OrcaSlicer/pull/15015 and https://github.com/OrcaSlicer/OrcaSlicer_WIKI/pull/323
2026-08-04 11:37:05 -03:00
Kris AustinandNoisyfox 82759d3899 fix: make the error dialog caret point at the character it's blaming (#14886)
* fix: make the error dialog caret point at the character it's blaming

Custom G-code parse errors print the offending line with a '^' under the
character that broke, positioned with spaces so it only lines up in a
fixed-width font. Since v2.3.2 these dialogs rendered entirely in the
proportional UI font, so the caret drifted left of its column and landed
on unrelated text.

Render only the code excerpts (the offending source line and its caret) in
the fixed-width face, leaving the surrounding prose in the UI font, and
reserve the horizontal scrollbar's height so a long line does not clip.
Rename the flag to has_code_excerpts to match what it now means.

Fixes #14869

* refactor(GUI): use <code> instead of <tt> for error excerpts

wxHTML maps <tt>, <code>, <kbd> and <samp> to the same fixed-width
handler, so this renders identically. <code> is the non-deprecated
tag and matches what the original code used.

* fix(GUI): align the error caret with real spaces, not &nbsp;

The caret line was padded with &nbsp; so its spaces would survive inline
HTML. wxHTML measures every glyph by its font extent, so where the fixed
font lacks a U+00A0 glyph the fallback renders it about twice as wide, and
the all-&nbsp; caret line outran the source, drifting the ^ to the right.

Wrap the excerpts in a small <excerpt> tag, registered on the dialog's own
parser, that switches on wxHTML literal-whitespace mode so the caret uses
real spaces that match the source column in any font. It sits inside <code>
for the fixed face; <pre> would do both but forces a blank line above it.

---------

Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
2026-08-04 22:01:45 +08:00
Ian Bassi 59155f26ac Build Arch Fix (#15107)
Arch Fix
2026-08-04 21:56:15 +08:00
Ian Chua 56236f56a8 Add unsupported-command feedback to the device UI 2026-08-04 21:26:56 +08:00
Ian Chua 79dcace1ac Add unsupported-command feedback to the device UI 2026-08-04 21:26:50 +08:00
Ian Chua df5a08517a Keep printer-agent error codes with the interface 2026-08-04 19:44:39 +08:00
Andrew 5d953f915a Keep Bambu AMS dialect out of the agent waist
M620 is Bambu firmware dialect, not a
neutral command. Composing it in
MachineObject let non-Bambu agents
(Moonraker/Klipper) forward it and
report success on firmware that
cannot run it.

Agents now own the dialect: the
default refusal on IPrinterAgent
returns not-supported so the UI
can say so; BBLPrinterAgent keeps
the byte-identical composition.
2026-08-04 18:12:20 +08:00
Andrew dd2cb92685 Gate agent mode behind use_printer_agents toggle
Replace per-printer auto-activation
(is_current_printer_agent_plugin)
with a global experimental AppConfig
toggle, default off: legacy
print-host behavior is unchanged
until the user opts in. The toggle
drives device-tab routing, print
button defaults, connect-button
visibility and sidebar layout, and
dedups machine-select dialog opens.
2026-08-04 18:12:20 +08:00
Andrew b2f08c3ff8 Reset device selection on agent swap or unload (#124)
set_live_printer_agent centralizes
the swap: deselect the machine,
clear stale sidebar state and the
previous agent's Other Devices, then
install the new agent (or null when
its provider vanished). Plugin
load/unload callbacks refresh the
dropdown and re-run agent selection.
load_last_machine no longer falls
back to the first available machine.
2026-08-04 18:12:19 +08:00
Andrew 75a2460649 Replace fake-enum printer agent dropdown (#121)
A dedicated PrinterAgentChoice field
reads rows straight from the live
agent registry and stores the agent
id string, replacing the fake-coEnum
index mapping. The field moves to
TabPrinter and registers with the
searcher so UnsavedChanges renders
it; the PhysicalPrinterDialog copy
and its update hook are removed
(#125). switch_printer_agent now
resolves ids via
resolve_printer_agent_id.
2026-08-04 18:12:19 +08:00
Ian Chua 01493d4e3a Add developer flag for printer agents 2026-08-04 18:12:19 +08:00
Andrew 8dfc7a14b9 Gate agent mode behind use_printer_agents toggle
Replace per-printer auto-activation
(is_current_printer_agent_plugin)
with a global experimental AppConfig
toggle, default off: legacy
print-host behavior is unchanged
until the user opts in. The toggle
drives device-tab routing, print
button defaults, connect-button
visibility and sidebar layout, and
dedups machine-select dialog opens.
2026-08-04 18:12:11 +08:00
Andrew 1534268183 Reset device selection on agent swap or unload (#124)
set_live_printer_agent centralizes
the swap: deselect the machine,
clear stale sidebar state and the
previous agent's Other Devices, then
install the new agent (or null when
its provider vanished). Plugin
load/unload callbacks refresh the
dropdown and re-run agent selection.
load_last_machine no longer falls
back to the first available machine.
2026-08-04 18:12:11 +08:00
Andrew 501af81ba9 Replace fake-enum printer agent dropdown (#121)
A dedicated PrinterAgentChoice field
reads rows straight from the live
agent registry and stores the agent
id string, replacing the fake-coEnum
index mapping. The field moves to
TabPrinter and registers with the
searcher so UnsavedChanges renders
it; the PhysicalPrinterDialog copy
and its update hook are removed
(#125). switch_printer_agent now
resolves ids via
resolve_printer_agent_id.
2026-08-04 18:12:10 +08:00
Ian Chua 16c44940d2 Add developer flag for printer agents 2026-08-04 18:12:10 +08:00
yw4z 40eab797c6 match em_unit value for on_dpi_change for linux (#15043)
* Update GUI_Utils.hpp

* Update GUI_Utils.hpp
2026-08-04 08:45:31 +08:00
Kiss Lorand ca7fbfb007 Fix missing overhang wall when no partial counterbore bridge is generated (#15100) 2026-08-03 18:02:48 -03:00
Mikhail f. Shiryaev 7b404596e9 Add Skip G-code config block to exclude the config comments from G-code files (#12455)
Add feature to skip CONFIG_BLOCK in G-code files
2026-08-03 15:10:01 -03:00
Kris Austin 06ef58bad8 test: replace the disabled convex_hull_2d test (#14892)
test(libslic3r): replace the disabled convex_hull_2d test, closing #11269

The last "failing libslic3r test" from #11269 was the disabled
SCENARIO("2D convex hull of sinking object", "[3mf][.]") in test_3mf.cpp.
It checked ModelObject::convex_hull_2d for a sinking object against
PrusaSlicer's reference hull, but Orca's convex_hull_2d does not clip
geometry below the bed the way PrusaSlicer's its_convex_hull_2d_above does,
so the reference never matched. The test also wrote a debug mesh to a
hardcoded /tmp path and its comparison loop was inverted.

Remove it and add tests/libslic3r/test_model.cpp characterizing
convex_hull_2d on non-sinking transforms (identity and scale+offset),
where the projected footprint is unambiguous. Homed in a Model test file
since it exercises ModelObject, not 3MF.
2026-08-03 22:29:00 +08:00
SoftFever 74c4a7e450 Support printer specific filament profiles in the OrcaFilamentLibrary (#15101)
* Support printer specific filament profiles in the Orca Filament Library
2026-08-03 22:25:50 +08:00
Tommaso Bianchi 24f4076bb5 Design: the Hole and Thread cards say which face they are holding
snaporca-200 asked which of the two models of "the card's face input" is right,
because clicking empty canvas now clears the selection (snaporca-od0) and made
them visibly disagree: Thicken / Shell / Draft read the LIVE selection and their
label reverts to "(pick a solid face)", while Hole / Thread LATCH the face they
were opened or picked on and keep it. The complaint was that Hole then drills a
face you can no longer see selected.

Taken to the rig, that turns out to be the wrong half of the story. With Hole
open and its face picked, a click on empty canvas leaves the Ø6.0 ghost and its
dimension gizmo drawn on that exact face — the card was never operating in
secret, it was showing its target the strongest way a CAD tool can. Meanwhile
Draft, whose behaviour was held up as the honest one, threw the pick away and
had to be told the face again.

So neither model replaces the other. They are different in kind: Thicken /
Shell / Draft are operations whose operand IS the selected face, and Hole /
Thread are placement tools with their own plane state that a pick merely seeds.
The latch is also the kinder of the two now that empty clicks are a deliberate
gesture — a stray one costs Thicken a pick and costs Hole nothing.

What was genuinely missing is that nothing in those two cards NAMED the latched
face, so after such a click the only words on screen were the viewport's
"Nothing selected" over a ghost about to drill. Both cards now carry an "On
face" row, the way the other three already do:

  Hole    Face 5 | (none — uses Hole plane)
  Thread  Face 1 | Edge 2 | (none — uses Thread plane)

Thread names an edge when the cylinder came from a circular rim rather than a
cylindrical face, which the code already distinguished internally and never
said out loud.

Verified on both rigs, every state driven through the GUI: face pick on open
and on live pick, survival across a click on empty canvas, and the fallback
after choosing XY/XZ/YZ from the plane dropdown. Thread's edge branch was
exercised on a revolved tube's rim, its face branch on the same tube's outer
wall.

Filed while here, surfaced by the new row rather than caused by it —
snaporca-uif9: re-editing a stored Hole/Thread from the feature tree restores
f.plane into the dropdown but never clears m_hole_on_face, so the re-edit
silently reuses the PREVIOUS card's latched face. Now visible by name instead
of invisible.

Fork parity unchanged: DesignPanel.cpp 30, DesignPanel.hpp 0.
2026-08-03 15:06:17 +02:00
Tommaso Bianchi 93395b7888 Design: escalate on the entity that was picked, and let the chip follow the window
Both found by Kimi reviewing the previous two commits, both then reproduced here
before being touched.

snaporca-97z. The re-pick escalation required m_solid_sel, m_sel_body, m_sel_face AND
m_sel_edge to all match the previous pick. That looked stricter and was wrong: the
edge branch sets only m_sel_edge and m_solid_sel, leaving m_sel_face as whichever face
the ray happened to enter through — and a shared edge is entered through a different
face depending on which side you view it from. So picking an edge and picking that
same edge again from the other side compared equal edges, unequal faces, and refused
the escalation the status line had just promised. Now the comparison is made at the
level that was picked and nothing else. The edge id is already the stable global one
from edge_index_of, so it identifies the edge without help from the face.

Reproduced on the rig without needing to orbit, since two clicks 8px apart across an
edge enter through different faces:

  pick -> sel=3 body=0 face=5 edge=3
  ray  -> body=0 face=0
  re-pick -> escalated to whole body 0
  pick -> sel=1 body=0 face=-1 edge=-1

Same edge, face 5 then face 0, escalation fires. The old condition could not.

The frame-move case. The chip is anchored at an absolute screen position, and until now
nothing told it the window had moved — only a resize, a status change or a tab switch
re-placed it. Dragging the window by its title bar left it stranded where it was,
verified on the rig by moving the frame and watching it stay put. wxEVT_MOVE on the
top-level frame, alongside the ICONIZE and ACTIVATE binds from the previous commit.

Two related cases are filed rather than bound, because the list of window-geometry
events to chase is exactly what snaporca-lcq argues should stop: a layout change that
translates the canvas without resizing it, and wxEVT_DPI_CHANGED.

Not fixed, deliberately, and recorded on snaporca-97z: clicking the same FACE but
landing within the vertex or edge tolerance resolves to a different kind and so does
not escalate — that is the "smallest thing under the cursor" rule working as
documented; and a vertex re-pick after moving the body compares stale world
coordinates.

Verified on both rigs. The cross-face edge case was exercised on orca_cad;
DesignSketchTool.cpp is byte-identical across the forks, so snaporca inherits it, and
its face-level escalation and empty-click clear were re-checked there directly.

Fork parity unchanged: DesignSketchTool.cpp 0, DesignCanvas.cpp 16.
2026-08-03 14:17:57 +02:00
Tommaso Bianchi 6d1a4078ca Design: the status chip goes away with the window, not just with the page
Found by minimising the app on the rig with a face selected: the whole screen goes
black and the chip is still drawn on the bare desktop. A wxPopupWindow is
override-redirect — the window manager does not own it — so it neither iconises with
its frame nor stacks behind other applications. IsShownOnScreen does not catch this
either: an iconised frame still counts as shown, which is why the guard added for the
tab case sails straight past it.

So the frame has to say so itself: ICONIZE and ACTIVATE, both routed through the same
show_status_hud the page change already uses. Restoring is safe — a popup cannot take
focus, so our own Show() cannot re-trigger either event — and restoring while some
other page is up still leaves the chip down, because show_status_hud(true) goes
through place_status_hud's IsShownOnScreen guard.

Verified on both rigs: chip up, minimise -> screen black and empty, restore -> chip
back with its text and the face still selected. Restore while on Prepare -> chip stays
down.

This is the fourth defect from the same root, so snaporca-lcq now asks the question
these binds keep deferring: whether the line should be canvas content, like the view
cube and the round view buttons, rather than a window that has to be told about every
way a window can stop being visible.

Fork parity unchanged: DesignCanvas.cpp 16.
2026-08-03 13:36:09 +02:00
NoisyfoxandClaude dbb991bf07 Fix gizmo being closed after releasing mouse outside the gizmo floating window (#15095)
* Fix gizmo being closed after releasing mouse outside the gizmo floating window

The left up event of a drag started on the gizmo floating window (e.g.
selecting text in an input field) and released over the bed was treated
as a click on the plate, which deselected the objects and closed the
active gizmo. Add the ignore_left_up guard to the plate select branch,
matching the deselect branch above.

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Emboss gizmo being closed after releasing mouse outside its floating window

The Emboss gizmo has its own close-on-click-away handler
(on_mouse_change_selection) that was not protected against left up events
originating from ImGui windows, so the gizmo was still closed when a drag
started on its floating window (e.g. selecting text in the input field)
ended over the 3D scene. Expose the canvas's ignore_left_up state to
gizmos and skip the close check for such releases.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-03 18:34:15 +08:00
Noisyfox 66d3f3f9c3 imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds (#15052)
* imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds

In single-line mode, click and drag already clamped y to the line's
y-coordinate so the cursor would continue to follow the x-position when
the mouse went off the top or bottom of the text.  Multi-line mode did
not clamp, so stb_text_locate_coord() would return 0 (above) or n
(below), snapping the cursor to the very start or end of text and
ignoring the x-coordinate entirely.

Now both modes walk the row layout to compute the top of the first row
(y_min) and bottom of the last row (y_max, minus half a line height to
add tolerance for rounding), then clamp y to that range before passing
it to stb_text_locate_coord().  This means dragging or clicking above
the text now places the cursor on the first line at the x-coordinate,
and dragging/clicking below places it on the last line at the
x-coordinate, matching the single-line precedent.

* Fix issue that cursor cannot be placed at the last empty line
2026-08-03 18:34:05 +08:00
Tommaso Bianchi 9c3ce9b45e Design: clicking empty space lets go of the selection, and the status line follows its tab
Two things a click on nothing should already have done.

snaporca-od0. A click that hit no geometry left the solid selection standing. A
rubber band swept over empty space has always cleared it (pick_bodies_in_rectangle),
and the two gestures cannot disagree about the same outcome. The visible cost was in
the escalation that landed last commit: "click the face, click away, click the face
again" arrived as the SECOND click on the same face and took the whole body, when the
click away was the user letting go of it. Now the miss clears and says so.

This gives up something real, deliberately: Thicken / Shell / Draft hold their input
face in the panel's selection, so a stray click on empty canvas with one of those
cards open hands that face back. Their handlers already write the "(pick a solid
face)" placeholder and rebuild the ghost when the selection empties, so the card SAYS
it lost the pick rather than confirming against a face the viewport has stopped
highlighting. An orbit drag never reaches this branch — it exits at the 8px budget —
so panning the view still does not deselect.

snaporca-dlj. The status line is a wxPopupWindow, which is a TOP-LEVEL window: hiding
the Design page does not hide it. Select a face, switch to Prepare, and the chip was
still there reading "selected (whole body) — right-click for what applies to it" on a
tab with no such selection and no such menu. Same cause, second symptom: a status
update arriving while the page is hidden anchored against a client size that is not
the size the page will have, and parked the chip on the tab bar. So: an
IsShownOnScreen guard in place_status_hud, show_status_hud(bool) to take it down and
bring it back with its text intact, driven from the page-changed handler.

Verified on both rigs, not by reasoning about it: face 5 selected -> click bed ->
"Nothing selected", tint gone -> click the same face -> face 5 again, NOT the body ->
click it again with no click away -> whole body, so snaporca-gem is intact. Prepare ->
chip gone; back to Design -> chip returns. KEYTRACE across the round trip shows
shift+S then R still reaching the canvas (ui_mode 0 -> 1, Rectangle armed), which is
the focus theft this popup replaced a wxFrame to avoid.

Fork parity unchanged: DesignPanel.cpp 30, DesignCanvas.cpp 16, headers and
DesignSketchTool.cpp 0. MainFrame.cpp is outside that set and was edited per fork.
2026-08-03 11:05:45 +02:00
Ryan Hartman 6b5c8af1c8 Pin OpenSSL libdir so the bundled Python finds it (#15047)
On Linux the bundled CPython silently links the system OpenSSL instead of
the one built in deps/, and the dependency build then fails:

  install: cannot stat 'Modules/_ssl.cpython-312-x86_64-linux-gnu.so':
           No such file or directory

The chain:

  * OpenSSL's linux-x86_64 target sets multilib=64, so 'make install_sw'
    installs the static libs to <prefix>/lib64 while every other dependency
    in the prefix uses <prefix>/lib.
  * CPython's --with-openssl=<dir> only ever emits -L<dir>/lib. It does not
    look in lib64, so -lssl resolves to the system OpenSSL.
  * gcc -shared does not error on unresolved symbols, so the link appears to
    succeed. _ssl.c was compiled against the bundled 1.1.1w headers, which
    map SSL_get1_peer_certificate onto the pre-3.0 SSL_get_peer_certificate
    -- a symbol OpenSSL 3.x removed. The module then fails to import:

      _ssl failed to import: undefined symbol: SSL_get_peer_certificate
      Could not build the ssl module!

  * With no _ssl built, 'make install' cannot stat it and the build stops.

Passing --libdir=lib keeps the prefix single-layout, so CPython's -L<dir>/lib
finds the bundled static libraries and links against the headers it was
compiled with.

CMake-based dependencies were unaffected throughout, because CMake's
FindOpenSSL searches lib64 on its own; only CPython's autoconf path is
sensitive to this.

Affects any distribution where OpenSSL selects the lib64 layout, which is the
Fedora, openSUSE and Arch families. Debian and Ubuntu are unaffected, which is
why CI has not seen it.

Verified on Arch (GCC 16.1.1, CMake 4.4.2): the dependency build completes and
the bundled interpreter reports the bundled OpenSSL rather than the system one:

  $ deps/build/OrcaSlicer_dep/usr/local/libpython/bin/python3.12 \
      -c 'import ssl; print(ssl.OPENSSL_VERSION)'
  OpenSSL 1.1.1w  11 Sep 2023

Not verified on macOS or Windows. The flag is accepted by OpenSSL's Configure
on all platforms and Darwin targets do not set multilib, so it should be a
no-op there, but CI is the check.
2026-08-03 11:03:59 +08:00