OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::GradientCurveEditor Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/GradientCurveEditor.hpp>

Inheritance diagram for Slic3r::GUI::GradientCurveEditor:
Collaboration diagram for Slic3r::GUI::GradientCurveEditor:

Public Types

using PointList = std::vector<GradientAnchor>

Public Member Functions

 GradientCurveEditor (wxWindow *parent, const wxColour &color_low=wxColour(217, 217, 217), const wxColour &color_high=wxColour(217, 217, 217))
 ~GradientCurveEditor () override
void set_points (const PointList &pts)
const PointList & get_points () const
void set_colors (const wxColour &color_low, const wxColour &color_high)
void set_selected_curve (int curve_idx)
int get_selected_curve () const
void reset_to_linear (double y0, double y1)
void reverse ()

Private Types

enum class  DragMode { None , Anchor }

Private Member Functions

void normalize_points ()
void emit_changed ()
void on_paint (wxPaintEvent &evt)
void on_left_down (wxMouseEvent &evt)
void on_left_up (wxMouseEvent &evt)
void on_right_down (wxMouseEvent &evt)
void on_motion (wxMouseEvent &evt)
void on_leave (wxMouseEvent &evt)
void on_size (wxSizeEvent &evt)
wxRect plot_rect () const
wxPoint2DDouble data_to_px_f (double x, double y) const
wxPoint data_to_px (double x, double y) const
void px_to_data (int px, int py, double &x, double &y) const
int hit_test (int px, int py) const
int hit_test_curve (int px, int py, int *seg_out=nullptr) const
double sample_curve_y (double x) const

Static Private Member Functions

static double to_stored_y (int curve_idx, double visual_y)
static double to_visual_y (int curve_idx, double stored_y)

Private Attributes

PointList m_points
wxColour m_color_low
wxColour m_color_high
int m_selected_curve = 0
DragMode m_drag_mode = DragMode::None
int m_drag_idx = -1
bool m_dragged_moved = false

Detailed Description

Member Typedef Documentation

◆ PointList

Member Enumeration Documentation

◆ DragMode

Enumerator
None 
Anchor 
64 {
65 None, // nothing armed
66 Anchor, // dragging an anchor (either existing or just inserted from a line hit)
67 };
@ None
Definition SketchEngine.hpp:180

Constructor & Destructor Documentation

◆ GradientCurveEditor()

Slic3r::GUI::GradientCurveEditor::GradientCurveEditor ( wxWindow * parent,
const wxColour & color_low = wxColour(217, 217, 217),
const wxColour & color_high = wxColour(217, 217, 217) )
54 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
55 , m_color_low(color_low)
56 , m_color_high(color_high)
57{
58 SetBackgroundStyle(wxBG_STYLE_PAINT);
59 SetBackgroundColour(wxGetApp().get_window_default_clr());
60 // Wide enough so the X-axis "Material Ratio" label fits past the arrow tip without overlap.
61 SetMinSize(FromDIP(wxSize(260, 200)));
62
63 reset_to_linear(0.10, 0.90);
64
65 Bind(wxEVT_PAINT, &GradientCurveEditor::on_paint, this);
66 Bind(wxEVT_LEFT_DOWN, &GradientCurveEditor::on_left_down, this);
67 Bind(wxEVT_LEFT_UP, &GradientCurveEditor::on_left_up, this);
68 Bind(wxEVT_RIGHT_DOWN, &GradientCurveEditor::on_right_down, this);
69 Bind(wxEVT_MOTION, &GradientCurveEditor::on_motion, this);
70 Bind(wxEVT_LEAVE_WINDOW,&GradientCurveEditor::on_leave, this);
71 Bind(wxEVT_SIZE, &GradientCurveEditor::on_size, this);
72 Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent&) {
74 m_drag_idx = -1;
75 m_dragged_moved = false;
76 });
77}
void reset_to_linear(double y0, double y1)
Definition GradientCurveEditor.cpp:109
bool m_dragged_moved
Definition GradientCurveEditor.hpp:115
int m_drag_idx
Definition GradientCurveEditor.hpp:114
wxColour m_color_high
Definition GradientCurveEditor.hpp:110
void on_paint(wxPaintEvent &evt)
Definition GradientCurveEditor.cpp:301
@ None
Definition GradientCurveEditor.hpp:65
void on_left_up(wxMouseEvent &evt)
Definition GradientCurveEditor.cpp:440
wxColour m_color_low
Definition GradientCurveEditor.hpp:109
void on_size(wxSizeEvent &evt)
Definition GradientCurveEditor.cpp:517
void on_leave(wxMouseEvent &evt)
Definition GradientCurveEditor.cpp:512
DragMode m_drag_mode
Definition GradientCurveEditor.hpp:113
void on_motion(wxMouseEvent &evt)
Definition GradientCurveEditor.cpp:478
void on_right_down(wxMouseEvent &evt)
Definition GradientCurveEditor.cpp:457
void on_left_down(wxMouseEvent &evt)
Definition GradientCurveEditor.cpp:368

References m_color_high, m_color_low, m_drag_idx, m_drag_mode, m_dragged_moved, None, on_leave(), on_left_down(), on_left_up(), on_motion(), on_paint(), on_right_down(), on_size(), and reset_to_linear().

Here is the call graph for this function:

◆ ~GradientCurveEditor()

Slic3r::GUI::GradientCurveEditor::~GradientCurveEditor ( )
override
80{
81 // See MixedFilamentDialog::~MixedFilamentDialog: a widget destroyed while it
82 // still holds the capture wedges mouse input for the whole application.
83 if (HasCapture())
84 ReleaseMouse();
85}

Member Function Documentation

◆ data_to_px()

wxPoint Slic3r::GUI::GradientCurveEditor::data_to_px ( double x,
double y ) const
private
186{
187 const wxPoint2DDouble p = data_to_px_f(x, y);
188 return wxPoint(static_cast<int>(std::lround(p.m_x)), static_cast<int>(std::lround(p.m_y)));
189}
wxPoint2DDouble data_to_px_f(double x, double y) const
Definition GradientCurveEditor.cpp:178

References data_to_px_f().

Referenced by hit_test(), and hit_test_curve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ data_to_px_f()

wxPoint2DDouble Slic3r::GUI::GradientCurveEditor::data_to_px_f ( double x,
double y ) const
private
179{
180 const wxRect r = plot_rect();
181 // y axis is inverted: y=1 should sit at the top.
182 return wxPoint2DDouble(r.x + x * r.width, r.y + (1.0 - y) * r.height);
183}
wxRect plot_rect() const
Definition GradientCurveEditor.cpp:172

References plot_rect().

Referenced by data_to_px(), and on_paint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ emit_changed()

void Slic3r::GUI::GradientCurveEditor::emit_changed ( )
private
166{
167 wxCommandEvent evt(wxEVT_GRADIENT_CURVE_CHANGED, GetId());
168 evt.SetEventObject(this);
169 ProcessWindowEvent(evt);
170}

Referenced by on_left_down(), on_left_up(), on_right_down(), reset_to_linear(), and reverse().

Here is the caller graph for this function:

◆ get_points()

const PointList & Slic3r::GUI::GradientCurveEditor::get_points ( ) const
inline
47{ return m_points; }
PointList m_points
Definition GradientCurveEditor.hpp:108

References m_points.

◆ get_selected_curve()

int Slic3r::GUI::GradientCurveEditor::get_selected_curve ( ) const
inline
55{ return m_selected_curve; }
int m_selected_curve
Definition GradientCurveEditor.hpp:112

References m_selected_curve.

◆ hit_test()

int Slic3r::GUI::GradientCurveEditor::hit_test ( int px,
int py ) const
private
208{
209 const int tol = FromDIP(kHitRadius);
210 int best_idx = -1;
211 int best_d2 = tol * tol;
212 for (size_t i = 0; i < m_points.size(); ++i) {
213 // Anchor visual y is curve-specific: component 1's anchor sits at (x, 1 - stored_y).
214 const double vy = to_visual_y(m_selected_curve, m_points[i].y);
215 const wxPoint p = data_to_px(m_points[i].x, vy);
216 const int dx = px - p.x;
217 const int dy = py - p.y;
218 const int d2 = dx * dx + dy * dy;
219 if (d2 <= best_d2) {
220 best_idx = static_cast<int>(i);
221 best_d2 = d2;
222 }
223 }
224 return best_idx;
225}
wxPoint data_to_px(double x, double y) const
Definition GradientCurveEditor.cpp:185
static double to_visual_y(int curve_idx, double stored_y)
Definition GradientCurveEditor.hpp:104
int64_t py(const Point &pt)
Definition ClipperUtils.cpp:208
int64_t px(const Point &pt)
Definition ClipperUtils.cpp:207

References data_to_px(), m_points, m_selected_curve, and to_visual_y().

Referenced by on_left_down(), and on_right_down().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_curve()

int Slic3r::GUI::GradientCurveEditor::hit_test_curve ( int px,
int py,
int * seg_out = nullptr ) const
private
228{
229 if (seg_out) *seg_out = -1;
230 if (m_points.size() < 2) return -1;
231 const int tol = FromDIP(kCurveHitRadius);
232 const int tol2 = tol * tol;
233
234 auto dist2_to_seg = [&](int ax, int ay, int bx, int by) -> int {
235 const double dx = bx - ax;
236 const double dy = by - ay;
237 const double l2 = dx * dx + dy * dy;
238 if (l2 == 0.0) {
239 const double ddx = px - ax;
240 const double ddy = py - ay;
241 return static_cast<int>(ddx * ddx + ddy * ddy);
242 }
243 double t = ((px - ax) * dx + (py - ay) * dy) / l2;
244 t = std::max(0.0, std::min(1.0, t));
245 const double ex = ax + t * dx;
246 const double ey = ay + t * dy;
247 const double ddx = px - ex;
248 const double ddy = py - ey;
249 return static_cast<int>(ddx * ddx + ddy * ddy);
250 };
251
252 // Hit-test against the same dense Hermite polyline that on_paint draws, so the
253 // clickable line follows the visual curve exactly (no offset on the bent parts).
254 // When a hit is found, also report the index of the left anchor of the data-space
255 // segment that covers cursor x; needed by the segment-bend interaction.
256 const wxRect rc = plot_rect();
257 const int samples = std::max(128, rc.width * 2);
258 auto seg_for_x = [&](double cursor_x) -> int {
259 for (size_t i = 1; i < m_points.size(); ++i) {
260 if (cursor_x <= m_points[i].x)
261 return static_cast<int>(i - 1);
262 }
263 return static_cast<int>(m_points.size() - 2);
264 };
265
266 auto curve_hit = [&](int curve_idx) -> bool {
267 wxPoint prev;
268 for (int s = 0; s <= samples; ++s) {
269 const double x = double(s) / samples;
270 const double y0 = sample_curve_y(x);
271 const double vy = to_visual_y(curve_idx, y0);
272 const wxPoint cur = data_to_px(x, vy);
273 if (s > 0 && dist2_to_seg(prev.x, prev.y, cur.x, cur.y) <= tol2)
274 return true;
275 prev = cur;
276 }
277 return false;
278 };
279
280 // Prefer the selected curve so overlapping segments don't unintentionally steal focus.
281 if (curve_hit(m_selected_curve)) {
282 if (seg_out) {
283 double nx = 0, dummy = 0;
284 px_to_data(px, py, nx, dummy);
285 *seg_out = seg_for_x(nx);
286 }
287 return m_selected_curve;
288 }
289 const int other = 1 - m_selected_curve;
290 if (curve_hit(other)) {
291 if (seg_out) {
292 double nx = 0, dummy = 0;
293 px_to_data(px, py, nx, dummy);
294 *seg_out = seg_for_x(nx);
295 }
296 return other;
297 }
298 return -1;
299}
void px_to_data(int px, int py, double &x, double &y) const
Definition GradientCurveEditor.cpp:191
double sample_curve_y(double x) const
Definition GradientCurveEditor.cpp:200
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:177

References data_to_px(), Slic3r::l2(), m_points, m_selected_curve, plot_rect(), px_to_data(), sample_curve_y(), and to_visual_y().

Referenced by on_left_down(), and on_right_down().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ normalize_points()

void Slic3r::GUI::GradientCurveEditor::normalize_points ( )
private
138{
139 if (m_points.empty()) {
140 GradientAnchor a0; a0.x = 0.0; a0.y = kGradientMinRatio;
141 GradientAnchor a1; a1.x = 1.0; a1.y = kGradientMaxRatio;
142 m_points.push_back(a0);
143 m_points.push_back(a1);
144 return;
145 }
146
147 for (auto& p : m_points) {
148 p.x = std::max(0.0, std::min(1.0, p.x));
149 p.y = std::max(kGradientMinRatio, std::min(kGradientMaxRatio, p.y));
150 }
151 std::sort(m_points.begin(), m_points.end(),
152 [](const GradientAnchor& a, const GradientAnchor& b) {
153 return a.x < b.x;
154 });
155
156 if (m_points.size() < 2) {
157 GradientAnchor tail; tail.x = 1.0; tail.y = m_points.front().y;
158 m_points.push_back(tail);
159 }
160
161 m_points.front().x = 0.0;
162 m_points.back().x = 1.0;
163}
constexpr double kGradientMinRatio
Definition FilamentMixer.hpp:40
constexpr double kGradientMaxRatio
Definition FilamentMixer.hpp:41

References Slic3r::kGradientMaxRatio, Slic3r::kGradientMinRatio, m_points, Slic3r::GradientAnchor::x, and Slic3r::GradientAnchor::y.

Referenced by set_points().

Here is the caller graph for this function:

◆ on_leave()

void Slic3r::GUI::GradientCurveEditor::on_leave ( wxMouseEvent & evt)
private
513{
514 evt.Skip();
515}

References Slic3r::GUI::wxMouseEvent.

Referenced by GradientCurveEditor().

Here is the caller graph for this function:

◆ on_left_down()

void Slic3r::GUI::GradientCurveEditor::on_left_down ( wxMouseEvent & evt)
private
369{
370 const wxPoint pos = evt.GetPosition();
371 m_dragged_moved = false;
372
373 // 1) Anchor on the selected curve takes precedence over everything else.
374 // Dragging an anchor resets its tangent overrides so the surrounding curve
375 // returns to PCHIP-default shape (matches user expectation that pulling an
376 // anchor "straightens out" the local mess).
377 const int idx = hit_test(pos.x, pos.y);
378 if (idx >= 0) {
380 m_drag_idx = idx;
381 // Only emit a change event when clearing the tangents actually mutates
382 // the curve. A plain click on an already-default anchor must not trigger
383 // re-slicing through the changed-event listener.
384 const bool had_tangent = std::isfinite(m_points[idx].m_in)
385 || std::isfinite(m_points[idx].m_out);
386 m_points[idx].m_in = std::numeric_limits<double>::quiet_NaN();
387 m_points[idx].m_out = std::numeric_limits<double>::quiet_NaN();
388 if (!HasCapture())
389 CaptureMouse();
390 Refresh();
391 if (had_tangent)
392 emit_changed();
393 return;
394 }
395
396 // 2) Line-body hit. Determine which curve and which segment.
397 int seg = -1;
398 const int curve_hit = hit_test_curve(pos.x, pos.y, &seg);
399 if (curve_hit < 0) {
401 evt.Skip();
402 return;
403 }
404
405 // 3) Non-selected curve hit -> switch selection only, no drag arming.
406 if (curve_hit != m_selected_curve) {
407 m_selected_curve = curve_hit;
409 Refresh();
410 evt.Skip();
411 return;
412 }
413
414 // 4) Selected curve line body hit -> insert a new anchor at cursor x (snapped
415 // to the current smooth curve so the initial click is visually invisible)
416 // and immediately enter Anchor drag mode. Bending the segment without
417 // inserting an anchor is not an option: a single cubic between two existing
418 // anchors cannot put its peak under an off-center cursor.
419 double nx = 0, dummy = 0;
420 px_to_data(pos.x, pos.y, nx, dummy);
421 if (nx <= 0.0 || nx >= 1.0 || seg < 0) {
423 evt.Skip();
424 return;
425 }
426 GradientAnchor a;
427 a.x = nx;
428 a.y = sample_curve_y(nx);
429 const size_t insert_idx = static_cast<size_t>(seg) + 1;
430 m_points.insert(m_points.begin() + insert_idx, a);
431
433 m_drag_idx = static_cast<int>(insert_idx);
434 if (!HasCapture())
435 CaptureMouse();
436 Refresh();
437 emit_changed();
438}
void emit_changed()
Definition GradientCurveEditor.cpp:165
@ Anchor
Definition GradientCurveEditor.hpp:66
int hit_test_curve(int px, int py, int *seg_out=nullptr) const
Definition GradientCurveEditor.cpp:227
int hit_test(int px, int py) const
Definition GradientCurveEditor.cpp:207
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References Anchor, emit_changed(), hit_test(), hit_test_curve(), m_drag_idx, m_drag_mode, m_dragged_moved, m_points, m_selected_curve, None, px_to_data(), sample_curve_y(), Slic3r::GUI::wxMouseEvent, Slic3r::GradientAnchor::x, and Slic3r::GradientAnchor::y.

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_left_up()

void Slic3r::GUI::GradientCurveEditor::on_left_up ( wxMouseEvent & evt)
private
441{
442 if (HasCapture())
443 ReleaseMouse();
444
445 // Anchor mode (either an existing anchor or one freshly inserted by on_left_down)
446 // already fired emit_changed on mouse_down; only fire again here if the user
447 // actually dragged so the slicer doesn't re-run on a pure click.
449 emit_changed();
450
452 m_drag_idx = -1;
453 m_dragged_moved = false;
454 (void)evt;
455}

References Anchor, emit_changed(), m_drag_idx, m_drag_mode, m_dragged_moved, None, and Slic3r::GUI::wxMouseEvent.

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_motion()

void Slic3r::GUI::GradientCurveEditor::on_motion ( wxMouseEvent & evt)
private
479{
480 if (!evt.LeftIsDown() || m_drag_mode != DragMode::Anchor) {
481 evt.Skip();
482 return;
483 }
484 if (static_cast<size_t>(m_drag_idx) >= m_points.size())
485 return;
486
487 const wxPoint pos = evt.GetPosition();
488 double nx = 0, vy = 0;
489 px_to_data(pos.x, pos.y, nx, vy);
490
491 auto& p = m_points[m_drag_idx];
492 const bool is_first = (m_drag_idx == 0);
493 const bool is_last = (static_cast<size_t>(m_drag_idx) + 1 == m_points.size());
494
495 // Endpoints stay locked at x=0 / x=1; interior anchors clamp into
496 // (left_neighbor.x, right_neighbor.x) so they can't cross or coincide.
497 if (!is_first && !is_last) {
498 const double xl = m_points[m_drag_idx - 1].x;
499 const double xr = m_points[m_drag_idx + 1].x;
500 const double eps = 1e-4;
501 nx = std::max(xl + eps, std::min(xr - eps, nx));
502 p.x = nx;
503 }
504 // y is constrained to the reserved blend band so neither component ever
505 // reaches 0% / 100%, matching the sampler's clamp.
506 p.y = std::max(kGradientMinRatio,
508 m_dragged_moved = true;
509 Refresh();
510}
static double to_stored_y(int curve_idx, double visual_y)
Definition GradientCurveEditor.hpp:101

References Anchor, Slic3r::kGradientMaxRatio, Slic3r::kGradientMinRatio, m_drag_idx, m_drag_mode, m_dragged_moved, m_points, m_selected_curve, px_to_data(), to_stored_y(), and Slic3r::GUI::wxMouseEvent.

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_paint()

void Slic3r::GUI::GradientCurveEditor::on_paint ( wxPaintEvent & evt)
private
302{
303 // Resolve theme colors every paint so dark-mode toggles (no re-construction) take
304 // effect without an explicit listener. Window bg is read from GUI_App, not
305 // GetBackgroundColour(), since the latter is snapshotted at construction time.
306 const wxColour bg = wxGetApp().get_window_default_clr();
307 const wxColour grid_color = StateColor::darkModeColorFor(kGridColor);
308 const wxColour axis_color = StateColor::darkModeColorFor(kAxisColor);
309 const wxColour label_muted = StateColor::darkModeColorFor(kLabelMuted);
310 const wxColour label_strong = StateColor::darkModeColorFor(kLabelStrong);
311 const wxColour point_fill = StateColor::darkModeColorFor(*wxWHITE);
312 // Softer than axis_color: the curve outline only has to lift the curve off the
313 // background, it must not compete with the structural axis / grid.
314 const wxColour outline_color = StateColor::darkModeColorFor(kOutlineColor);
315
316 wxAutoBufferedPaintDC raw_dc(this);
317 raw_dc.SetBackground(wxBrush(bg));
318 raw_dc.Clear();
319
320 // Render the plot (grid, axes, labels, curves, anchors) through the shared painter so the
321 // interactive editor and the Publish dialog's read-only preview stay pixel-identical. The
322 // curves are handed over as sub-pixel polylines and anti-alias inside the helper.
323 std::vector<MixedGradientCurve> curves;
324 std::vector<wxPoint2DDouble> anchors;
325 if (m_points.size() >= 2) {
326 auto color_for_curve = [&](int curve_idx) -> wxColour {
327 wxColour c = (curve_idx == 0) ? m_color_low : m_color_high;
328 // Transparent filaments (alpha == 0, e.g. #FFFFFF00) would be invisible.
329 if (c.Alpha() == 0)
330 c.Set(c.Red(), c.Green(), c.Blue(), 150);
331 return c;
332 };
333
334 auto build_polyline = [&](int curve_idx) -> std::vector<wxPoint2DDouble> {
335 const int samples = std::max(128, plot_rect().width * 2);
336 std::vector<wxPoint2DDouble> poly;
337 poly.reserve(samples + 1);
338 for (int s = 0; s <= samples; ++s) {
339 const double x = double(s) / samples;
340 const double y0 = sample_curve_y(x);
341 const double vy = to_visual_y(curve_idx, y0);
342 poly.push_back(data_to_px_f(x, vy));
343 }
344 return poly;
345 };
346
347 // Draw unselected first so the selected curve sits on top.
348 const int other = 1 - m_selected_curve;
349 for (const int idx : {other, m_selected_curve}) {
350 std::vector<wxPoint2DDouble> pts = build_polyline(idx);
351 if (pts.empty())
352 continue;
353 curves.push_back({std::move(pts), color_for_curve(idx), idx == m_selected_curve ? kStrokeSelected : kStrokeUnselected});
354 }
355
356 // Control points (selected curve only).
357 anchors.reserve(m_points.size());
358 for (size_t i = 0; i < m_points.size(); ++i) {
359 const double vy = to_visual_y(m_selected_curve, m_points[i].y);
360 anchors.push_back(data_to_px_f(m_points[i].x, vy));
361 }
362 }
363
364 const MixedGradientTheme theme{bg, grid_color, axis_color, label_muted, label_strong, outline_color, point_fill};
365 draw_mixed_gradient_plot(raw_dc, GetClientSize(), curves, anchors, theme);
366}
static wxColour darkModeColorFor(wxColour const &color)
Definition StateColor.cpp:219
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751
constexpr int kStrokeUnselected
Definition GradientCurveEditor.cpp:37
constexpr int kStrokeSelected
Definition GradientCurveEditor.cpp:38
void draw_mixed_gradient_plot(wxDC &raw_dc, const wxSize &canvas, const std::vector< MixedGradientCurve > &curves, const std::vector< wxPoint2DDouble > &anchors, const MixedGradientTheme &theme)
Definition FilamentBitmapUtils.cpp:537

References StateColor::darkModeColorFor(), data_to_px_f(), Slic3r::GUI::draw_mixed_gradient_plot(), m_color_high, m_color_low, m_points, m_selected_curve, plot_rect(), sample_curve_y(), and to_visual_y().

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_right_down()

void Slic3r::GUI::GradientCurveEditor::on_right_down ( wxMouseEvent & evt)
private
458{
459 const wxPoint pos = evt.GetPosition();
460 const int idx = hit_test(pos.x, pos.y);
461 if (idx > 0 && static_cast<size_t>(idx) + 1 < m_points.size()) {
462 // Interior anchor on the selected curve -> delete it. Endpoints stay locked.
463 m_points.erase(m_points.begin() + idx);
464 Refresh();
465 emit_changed();
466 return;
467 }
468 // Right-click on the non-selected curve switches selection (never deletes).
469 const int curve_hit = hit_test_curve(pos.x, pos.y);
470 if (curve_hit >= 0 && curve_hit != m_selected_curve) {
471 m_selected_curve = curve_hit;
472 Refresh();
473 return;
474 }
475 evt.Skip();
476}

References emit_changed(), hit_test(), hit_test_curve(), m_points, m_selected_curve, and Slic3r::GUI::wxMouseEvent.

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_size()

void Slic3r::GUI::GradientCurveEditor::on_size ( wxSizeEvent & evt)
private
518{
519 Refresh();
520 evt.Skip();
521}

Referenced by GradientCurveEditor().

Here is the caller graph for this function:

◆ plot_rect()

wxRect Slic3r::GUI::GradientCurveEditor::plot_rect ( ) const
private
173{
174 // Square 1:1 plot, shared with the Publish dialog's read-only preview.
175 return mixed_gradient_plot_rect(GetClientSize());
176}
wxRect mixed_gradient_plot_rect(const wxSize &sz)
Definition FilamentBitmapUtils.cpp:527

References Slic3r::GUI::mixed_gradient_plot_rect().

Referenced by data_to_px_f(), hit_test_curve(), on_paint(), and px_to_data().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ px_to_data()

void Slic3r::GUI::GradientCurveEditor::px_to_data ( int px,
int py,
double & x,
double & y ) const
private
192{
193 const wxRect r = plot_rect();
194 const double w = std::max(1, r.width);
195 const double h = std::max(1, r.height);
196 x = std::max(0.0, std::min(1.0, (px - r.x) / w));
197 y = std::max(0.0, std::min(1.0, 1.0 - (py - r.y) / h));
198}

References plot_rect().

Referenced by hit_test_curve(), on_left_down(), and on_motion().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset_to_linear()

void Slic3r::GUI::GradientCurveEditor::reset_to_linear ( double y0,
double y1 )
110{
111 auto clamp_y = [](double v) {
112 return std::max(kGradientMinRatio, std::min(kGradientMaxRatio, v));
113 };
114 m_points.clear();
115 GradientAnchor a0; a0.x = 0.0; a0.y = clamp_y(y0);
116 GradientAnchor a1; a1.x = 1.0; a1.y = clamp_y(y1);
117 m_points.push_back(a0);
118 m_points.push_back(a1);
120 Refresh();
121 emit_changed();
122}

References emit_changed(), Slic3r::kGradientMaxRatio, Slic3r::kGradientMinRatio, m_points, m_selected_curve, Slic3r::GradientAnchor::x, and Slic3r::GradientAnchor::y.

Referenced by GradientCurveEditor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reverse()

void Slic3r::GUI::GradientCurveEditor::reverse ( )
125{
126 // Mirror y around 0.5. Tangents are slopes dy/dx so they flip sign to keep the
127 // local shape consistent across the mirror; NaN tangents remain "use PCHIP default".
128 for (auto& p : m_points) {
129 p.y = 1.0 - p.y;
130 if (std::isfinite(p.m_in)) p.m_in = -p.m_in;
131 if (std::isfinite(p.m_out)) p.m_out = -p.m_out;
132 }
133 Refresh();
134 emit_changed();
135}

References emit_changed(), and m_points.

Here is the call graph for this function:

◆ sample_curve_y()

double Slic3r::GUI::GradientCurveEditor::sample_curve_y ( double x) const
private
201{
202 GradientCurve gc;
203 gc.points = m_points;
204 return sample_gradient_curve(gc, x);
205}
double sample_gradient_curve(const GradientCurve &c, double t)
Definition FilamentMixer.cpp:357

References m_points, Slic3r::GradientCurve::points, and Slic3r::sample_gradient_curve().

Referenced by hit_test_curve(), on_left_down(), and on_paint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_colors()

void Slic3r::GUI::GradientCurveEditor::set_colors ( const wxColour & color_low,
const wxColour & color_high )
95{
96 m_color_low = color_low;
97 m_color_high = color_high;
98 Refresh();
99}

References m_color_high, and m_color_low.

◆ set_points()

void Slic3r::GUI::GradientCurveEditor::set_points ( const PointList & pts)
88{
89 m_points = pts;
91 Refresh();
92}
void normalize_points()
Definition GradientCurveEditor.cpp:137

References m_points, and normalize_points().

Here is the call graph for this function:

◆ set_selected_curve()

void Slic3r::GUI::GradientCurveEditor::set_selected_curve ( int curve_idx)
102{
103 const int new_sel = (curve_idx == 0) ? 0 : 1;
104 if (m_selected_curve == new_sel) return;
105 m_selected_curve = new_sel;
106 Refresh();
107}

References m_selected_curve.

◆ to_stored_y()

double Slic3r::GUI::GradientCurveEditor::to_stored_y ( int curve_idx,
double visual_y )
inlinestaticprivate
101 {
102 return (curve_idx == 0) ? visual_y : (1.0 - visual_y);
103 }

Referenced by on_motion().

Here is the caller graph for this function:

◆ to_visual_y()

double Slic3r::GUI::GradientCurveEditor::to_visual_y ( int curve_idx,
double stored_y )
inlinestaticprivate
104 {
105 return (curve_idx == 0) ? stored_y : (1.0 - stored_y);
106 }

Referenced by hit_test(), hit_test_curve(), and on_paint().

Here is the caller graph for this function:

Member Data Documentation

◆ m_color_high

wxColour Slic3r::GUI::GradientCurveEditor::m_color_high
private

◆ m_color_low

wxColour Slic3r::GUI::GradientCurveEditor::m_color_low
private

◆ m_drag_idx

int Slic3r::GUI::GradientCurveEditor::m_drag_idx = -1
private

◆ m_drag_mode

DragMode Slic3r::GUI::GradientCurveEditor::m_drag_mode = DragMode::None
private

◆ m_dragged_moved

bool Slic3r::GUI::GradientCurveEditor::m_dragged_moved = false
private

◆ m_points

◆ m_selected_curve

int Slic3r::GUI::GradientCurveEditor::m_selected_curve = 0
private

The documentation for this class was generated from the following files: