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

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

Inheritance diagram for Slic3r::GUI::MixedFilamentDialog:
Collaboration diagram for Slic3r::GUI::MixedFilamentDialog:

Public Member Functions

 MixedFilamentDialog (wxWindow *parent, const std::vector< std::string > &physical_colors, const std::vector< std::string > &physical_names, const std::vector< std::string > &physical_types={})
 MixedFilamentDialog (wxWindow *parent, const MixedFilamentResult &existing, const std::vector< std::string > &physical_colors, const std::vector< std::string > &physical_names, const std::vector< std::string > &physical_types={})
 ~MixedFilamentDialog ()
MixedFilamentResult get_result () const
void EndModal (int retCode) override
float scale_factor () const
float prev_scale_factor () const
void set_scale_factor (float v)
void set_prev_scale_factor (float v)
void set_em_unit (int v)
bool force_rescale () const
int em_unit () const
const wxFont & normal_font () const
void enable_force_rescale ()
int ShowModal ()

Protected Member Functions

void on_dpi_changed (const wxRect &suggested_rect) override
virtual void on_sys_color_changed ()

Private Member Functions

void build_ui ()
wxBoxSizer * create_preview_panel ()
wxBoxSizer * create_material_selection ()
wxBoxSizer * create_ratio_slider ()
wxBoxSizer * create_triangle_picker ()
wxBoxSizer * create_gradient_section ()
wxBoxSizer * create_recommendation_grid ()
wxBoxSizer * create_button_panel ()
void on_filament_changed ()
void on_ratio_changed (int new_ratio_a)
void on_gradient_toggled ()
void on_gradient_direction_changed ()
void on_gradient_curve_changed ()
void on_per_part_gradient_toggled ()
void on_add_material ()
void on_remove_material ()
void on_recommendation_clicked (unsigned int comp_a, unsigned int comp_b)
void on_recommendation_clicked_triple (unsigned int a, unsigned int b, unsigned int c)
void apply_manual_ratio (size_t idx, int value)
void apply_dragged_triangle_ratio (int r0, int r1, int r2)
void reset_manual_ratio_state ()
void refresh_ratio_labels ()
void sync_triangle_weights_from_ratios ()
void start_ratio_editor (size_t idx, wxWindow *anchor, const wxRect &anchor_rect)
void commit_ratio_editor (bool apply)
void commit_ratio_editor_from_background (wxMouseEvent &e)
void update_preview ()
void update_ok_button_state ()
void update_gradient_direction_items ()
void update_component_count_ui ()
wxSize compute_dialog_size () const
void rebuild_all_combos ()
void rebuild_recommendation_items ()
void refresh_curve_editor_colors ()
void paint_warning_panel (wxPaintEvent &evt)
wxBitmap make_swatch_bitmap (size_t idx)
void append_material_row ()
size_t num_components () const
unsigned int comp (size_t i) const
int ratio (size_t i) const
wxColour comp_colour (size_t i) const
void update_em_unit ()
bool is_new_scale_factor () const
void rescale (const wxRect &suggested_rect)

Static Private Member Functions

static void apply_uniform_label_width (wxStaticText *lbl)

Private Attributes

MixedFilamentResult m_result
std::vector< std::string > m_physical_colors
std::vector< std::string > m_physical_names
std::vector< std::string > m_physical_types
wxString m_type_mismatch_msg
std::vector< std::vector< unsigned int > > m_combo_to_physical
wxPanel * m_preview_canvas {nullptr}
wxPanel * m_summary_panel {nullptr}
std::vector< ComboBox * > m_combo_filaments
wxBoxSizer * m_material_rows_sizer {nullptr}
wxPanel * m_ratio_bar {nullptr}
wxPanel * m_triangle_panel {nullptr}
RatioLabelPanel * m_label_ratio_a {nullptr}
RatioLabelPanel * m_label_ratio_b {nullptr}
wxPanel * m_ratio_editor_panel {nullptr}
wxTextCtrl * m_ratio_editor {nullptr}
CheckBox * m_chk_gradient {nullptr}
wxStaticText * m_label_gradient {nullptr}
ComboBox * m_combo_gradient_dir {nullptr}
wxBoxSizer * m_gradient_sizer {nullptr}
GradientCurveEditor * m_curve_editor {nullptr}
wxBoxSizer * m_curve_sizer {nullptr}
CheckBox * m_chk_per_part_gradient {nullptr}
wxStaticText * m_label_per_part_gradient {nullptr}
wxBoxSizer * m_per_part_gradient_sizer {nullptr}
Button * m_btn_add_material {nullptr}
Button * m_btn_remove_material {nullptr}
Button * m_btn_ok {nullptr}
Button * m_btn_cancel {nullptr}
wxBoxSizer * m_warning_sizer {nullptr}
wxPanel * m_warning_panel {nullptr}
wxBoxSizer * m_ratio_sizer {nullptr}
wxBoxSizer * m_triangle_sizer {nullptr}
wxBoxSizer * m_right_sizer {nullptr}
wxScrolledWindow * m_recommendation_scroll {nullptr}
wxWrapSizer * m_recommendation_grid {nullptr}
bool m_ratio_dragging {false}
bool m_tri_dragging {false}
std::vector< size_t > m_ratio_manual_order
size_t m_ratio_editor_idx {0}
bool m_ratio_editor_committing {false}
wxWindow * m_ratio_editor_anchor {nullptr}
double m_tri_wx {0.333}
double m_tri_wy {0.333}
double m_tri_wz {0.334}
std::array< RatioLabelPanel *, 3 > m_triangle_ratio_labels {nullptr, nullptr, nullptr}
float m_scale_factor
int m_em_unit
wxFont m_normal_font
float m_prev_scale_factor
bool m_can_rescale
bool m_force_rescale
int m_new_font_point_size

Detailed Description

Constructor & Destructor Documentation

◆ MixedFilamentDialog() [1/2]

Slic3r::GUI::MixedFilamentDialog::MixedFilamentDialog ( wxWindow * parent,
const std::vector< std::string > & physical_colors,
const std::vector< std::string > & physical_names,
const std::vector< std::string > & physical_types = {} )
147 : DPIDialog(parent, wxID_ANY, _L("Add Mixed Filament"), wxDefaultPosition,
148 wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
149 , m_physical_colors(physical_colors)
150 , m_physical_names(physical_names)
151 , m_physical_types(physical_types)
152{
153 m_result.components = {1, (physical_colors.size() >= 2) ? 2u : 1u};
154 m_result.ratios = {50, 50};
155 build_ui();
156 wxGetApp().UpdateDlgDarkUI(this);
157}
#define _L(s)
Definition OBJ.cpp:34
MixedFilamentResult m_result
Definition MixedFilamentDialog.hpp:123
std::vector< std::string > m_physical_types
Definition MixedFilamentDialog.hpp:126
std::vector< std::string > m_physical_names
Definition MixedFilamentDialog.hpp:125
std::vector< std::string > m_physical_colors
Definition MixedFilamentDialog.hpp:124
void build_ui()
Definition MixedFilamentDialog.cpp:619

References _L, build_ui(), m_physical_colors, m_physical_names, m_physical_types, and m_result.

Here is the call graph for this function:

◆ MixedFilamentDialog() [2/2]

Slic3r::GUI::MixedFilamentDialog::MixedFilamentDialog ( wxWindow * parent,
const MixedFilamentResult & existing,
const std::vector< std::string > & physical_colors,
const std::vector< std::string > & physical_names,
const std::vector< std::string > & physical_types = {} )
176 : DPIDialog(parent, wxID_ANY, _L("Edit Mixed Filament"), wxDefaultPosition,
177 wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
178 , m_result(existing)
179 , m_physical_colors(physical_colors)
180 , m_physical_names(physical_names)
181 , m_physical_types(physical_types)
182{
183 if (m_result.components.size() < 2) {
184 m_result.components = {1, (physical_colors.size() >= 2) ? 2u : 1u};
185 m_result.ratios = {50, 50};
186 }
187 if (m_result.ratios.size() >= 3) {
188 int sum = 0;
189 for (int r : m_result.ratios) sum += r;
190 if (sum > 0) {
191 m_tri_wx = (double)m_result.ratios[0] / sum;
192 m_tri_wy = (double)m_result.ratios[1] / sum;
193 m_tri_wz = (double)m_result.ratios[2] / sum;
194 }
195 }
196 build_ui();
197 wxGetApp().UpdateDlgDarkUI(this);
198}
double m_tri_wz
Definition MixedFilamentDialog.hpp:176
double m_tri_wx
Definition MixedFilamentDialog.hpp:176
double m_tri_wy
Definition MixedFilamentDialog.hpp:176

References _L, m_physical_colors, m_physical_names, m_physical_types, and m_result.

◆ ~MixedFilamentDialog()

Slic3r::GUI::MixedFilamentDialog::~MixedFilamentDialog ( )
160{
161 // Backstop: a child must never be destroyed while it still holds the mouse
162 // capture. wxWidgets only asserts about this (compiled out in release), and
163 // the macOS port never unwinds its capture stack, so the stale entry would
164 // make wxNSWindow::sendEvent swallow every mouse event in the application.
165 if (m_ratio_bar && m_ratio_bar->HasCapture())
166 m_ratio_bar->ReleaseMouse();
167 if (m_triangle_panel && m_triangle_panel->HasCapture())
168 m_triangle_panel->ReleaseMouse();
169}
wxPanel * m_ratio_bar
Definition MixedFilamentDialog.hpp:137
wxPanel * m_triangle_panel
Definition MixedFilamentDialog.hpp:138

References m_ratio_bar, and m_triangle_panel.

Member Function Documentation

◆ append_material_row()

void Slic3r::GUI::MixedFilamentDialog::append_material_row ( )
private
289{
290 auto* row = new wxBoxSizer(wxHORIZONTAL);
291 auto* lbl = new wxStaticText(this, wxID_ANY,
292 wxString::Format(_L("Filament %d"), (int)(m_combo_filaments.size() + 1)));
293 lbl->SetFont(::Label::Body_12);
295 row->Add(lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(8));
296
297 auto* combo = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
298 wxSize(FromDIP(166), FromDIP(24)), 0, nullptr, wxCB_READONLY);
299 combo->SetKeepDropArrow(true);
300 combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_filament_changed(); });
301 row->Add(combo, 1, wxALIGN_CENTER_VERTICAL);
302
303 m_combo_filaments.push_back(combo);
304 m_combo_to_physical.push_back({});
305 m_material_rows_sizer->Add(row, 0, wxEXPAND | wxTOP, FromDIP(9));
306}
class WXDLLIMPEXP_FWD_CORE wxStaticText
Definition ProgressDialog.hpp:30
static wxFont Body_12
Definition Label.hpp:55
std::vector< ComboBox * > m_combo_filaments
Definition MixedFilamentDialog.hpp:135
std::vector< std::vector< unsigned int > > m_combo_to_physical
Definition MixedFilamentDialog.hpp:130
wxBoxSizer * m_material_rows_sizer
Definition MixedFilamentDialog.hpp:136
static void apply_uniform_label_width(wxStaticText *lbl)
Definition MixedFilamentDialog.cpp:268
void on_filament_changed()
Definition MixedFilamentDialog.cpp:1350

References _L, append_material_row(), apply_uniform_label_width(), Label::Body_12, m_combo_filaments, m_combo_to_physical, m_material_rows_sizer, on_filament_changed(), and wxStaticText.

Referenced by append_material_row(), create_material_selection(), on_add_material(), and on_recommendation_clicked_triple().

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

◆ apply_dragged_triangle_ratio()

void Slic3r::GUI::MixedFilamentDialog::apply_dragged_triangle_ratio ( int r0,
int r1,
int r2 )
private
429{
430 if (m_result.ratios.size() < 3)
431 return;
432
433 int ratios[3] = {
434 std::clamp(r0, MIN_COMPONENT_RATIO, 100),
435 std::clamp(r1, MIN_COMPONENT_RATIO, 100),
436 std::clamp(r2, MIN_COMPONENT_RATIO, 100)
437 };
438
439 int sum = ratios[0] + ratios[1] + ratios[2];
440 while (sum > 100) {
441 int idx = 0;
442 for (int i = 1; i < 3; ++i) {
443 if (ratios[i] > ratios[idx])
444 idx = i;
445 }
446 if (ratios[idx] <= MIN_COMPONENT_RATIO)
447 break;
448 --ratios[idx];
449 --sum;
450 }
451 while (sum < 100) {
452 int idx = 0;
453 for (int i = 1; i < 3; ++i) {
454 if (ratios[i] < ratios[idx])
455 idx = i;
456 }
457 ++ratios[idx];
458 ++sum;
459 }
460
461 m_result.ratios[0] = ratios[0];
462 m_result.ratios[1] = ratios[1];
463 m_result.ratios[2] = ratios[2];
467}
void update_preview()
Definition MixedFilamentDialog.cpp:1593
void reset_manual_ratio_state()
Definition MixedFilamentDialog.cpp:308
void sync_triangle_weights_from_ratios()
Definition MixedFilamentDialog.cpp:333
static constexpr int MIN_COMPONENT_RATIO
Definition MixedFilamentDialog.cpp:56

References apply_dragged_triangle_ratio(), m_result, Slic3r::GUI::MIN_COMPONENT_RATIO, reset_manual_ratio_state(), sync_triangle_weights_from_ratios(), and update_preview().

Referenced by apply_dragged_triangle_ratio(), and create_triangle_picker().

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

◆ apply_manual_ratio()

void Slic3r::GUI::MixedFilamentDialog::apply_manual_ratio ( size_t idx,
int value )
private
350{
351 const size_t n = num_components();
352 if (idx >= n)
353 return;
354 if (m_result.ratios.size() != n)
355 m_result.ratios.assign(n, n > 0 ? 100 / (int)n : 0);
356 bool manual_stale = false;
357 for (size_t o : m_ratio_manual_order) {
358 if (o >= n) { manual_stale = true; break; }
359 }
360 if (manual_stale)
362
363 int max_value = (int)(100 - (n - 1) * MIN_COMPONENT_RATIO);
364 value = std::clamp(value, MIN_COMPONENT_RATIO, std::max(MIN_COMPONENT_RATIO, max_value));
365
366 if (n == 2) {
367 if (idx == 0) {
368 m_result.ratios[0] = value;
369 m_result.ratios[1] = 100 - value;
370 } else {
371 m_result.ratios[1] = value;
372 m_result.ratios[0] = 100 - value;
373 }
374 m_result.ratios[0] = std::clamp(m_result.ratios[0], MIN_COMPONENT_RATIO, 100 - MIN_COMPONENT_RATIO);
375 m_result.ratios[1] = 100 - m_result.ratios[0];
376 } else if (n >= 3) {
377 m_result.ratios[idx] = value;
378 int remaining = 100 - value;
379
380 std::vector<size_t> others;
381 int others_sum = 0;
382 for (size_t i = 0; i < n; ++i) {
383 if (i == idx) continue;
384 others.push_back(i);
385 others_sum += m_result.ratios[i];
386 }
387
388 if (!others.empty()) {
389 if (others_sum > 0) {
390 int assigned = 0;
391 for (size_t k = 0; k < others.size(); ++k) {
392 int nv = (int)((double)remaining * m_result.ratios[others[k]] / others_sum + 0.5);
393 nv = std::max(nv, MIN_COMPONENT_RATIO);
394 m_result.ratios[others[k]] = nv;
395 assigned += nv;
396 }
397 while (assigned != remaining) {
398 if (assigned > remaining) {
399 int pick = -1;
400 for (size_t k = 0; k < others.size(); ++k)
401 if (m_result.ratios[others[k]] > MIN_COMPONENT_RATIO
402 && (pick < 0 || m_result.ratios[others[k]] > m_result.ratios[others[pick]]))
403 pick = (int)k;
404 if (pick < 0) break;
405 --m_result.ratios[others[pick]]; --assigned;
406 } else {
407 int pick = 0;
408 for (size_t k = 1; k < others.size(); ++k)
409 if (m_result.ratios[others[k]] > m_result.ratios[others[pick]])
410 pick = (int)k;
411 ++m_result.ratios[others[pick]]; ++assigned;
412 }
413 }
414 } else {
415 int base = remaining / (int)others.size();
416 for (size_t k = 0; k < others.size(); ++k)
417 m_result.ratios[others[k]] = base;
418 m_result.ratios[others.back()] += remaining - base * (int)others.size();
419 }
420 }
421 }
422
426}
void refresh_ratio_labels()
Definition MixedFilamentDialog.cpp:321
size_t num_components() const
Definition MixedFilamentDialog.hpp:118
std::vector< size_t > m_ratio_manual_order
Definition MixedFilamentDialog.hpp:171

References apply_manual_ratio(), m_ratio_manual_order, m_result, Slic3r::GUI::MIN_COMPONENT_RATIO, num_components(), refresh_ratio_labels(), reset_manual_ratio_state(), sync_triangle_weights_from_ratios(), and update_preview().

Referenced by apply_manual_ratio(), and commit_ratio_editor().

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

◆ apply_uniform_label_width()

void Slic3r::GUI::MixedFilamentDialog::apply_uniform_label_width ( wxStaticText * lbl)
staticprivate
269{
270 // A material row places the combo right after the label, so the combo x follows the label
271 // width and the rows drift apart with fonts that render digits at different advances (which
272 // is what macOS does). Reserve the width of the widest row label on every row instead.
273 // The label itself is used as the measuring device on purpose: SetMinSize overrides the
274 // control's own best size rather than being merged with it, and on macOS the native cell is
275 // wider than the plain text extent, so a wxDC-measured width would clip the text.
276 const wxString text = lbl->GetLabel();
277 int w = 0;
278 for (int i = 1; i <= MAX_COMPONENTS; ++i) {
279 lbl->SetLabel(wxString::Format(_L("Filament %d"), i));
280 lbl->InvalidateBestSize();
281 w = std::max(w, lbl->GetBestSize().x);
282 }
283 lbl->SetLabel(text);
284 lbl->InvalidateBestSize();
285 lbl->SetMinSize(wxSize(w, -1));
286}
static constexpr int MAX_COMPONENTS
Definition MixedFilamentDialog.cpp:55

References _L, apply_uniform_label_width(), Slic3r::GUI::MAX_COMPONENTS, and wxStaticText.

Referenced by append_material_row(), and apply_uniform_label_width().

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

◆ build_ui()

void Slic3r::GUI::MixedFilamentDialog::build_ui ( )
private
620{
621 SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
623 SetSize(FromDIP(439), FromDIP(580));
624
625 auto* main_sizer = new wxBoxSizer(wxVERTICAL);
626
627 auto* top_sizer = new wxBoxSizer(wxHORIZONTAL);
628 top_sizer->Add(create_preview_panel(), 0, wxALL, FromDIP(20));
629
630 m_right_sizer = new wxBoxSizer(wxVERTICAL);
631 m_right_sizer->Add(create_material_selection(), 0, wxEXPAND);
632 m_right_sizer->Add(create_gradient_section(), 0, wxEXPAND | wxTOP, FromDIP(7));
633
635 m_right_sizer->Add(m_ratio_sizer, 0, wxEXPAND | wxTOP, FromDIP(7));
636
638 m_right_sizer->Add(m_triangle_sizer, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(7));
639
640 top_sizer->Add(m_right_sizer, 1, wxTOP | wxRIGHT | wxBOTTOM, FromDIP(20));
641 main_sizer->Add(top_sizer, 0, wxEXPAND);
642
643 main_sizer->Add(create_recommendation_grid(), 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(25));
644
645 // Warning panel: red bordered box with exclamation icon + text
646 m_warning_sizer = new wxBoxSizer(wxVERTICAL);
647 m_warning_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(48)));
648 m_warning_panel->SetMinSize(wxSize(-1, FromDIP(48)));
649 m_warning_panel->SetBackgroundStyle(wxBG_STYLE_PAINT);
651 m_warning_sizer->Add(m_warning_panel, 0, wxEXPAND);
652 main_sizer->Add(m_warning_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, FromDIP(25));
653 m_warning_panel->Hide();
654
655 main_sizer->Add(create_button_panel(), 0, wxALIGN_RIGHT | wxALL, FromDIP(20));
656
657 SetSizer(main_sizer);
658
663
664 Layout();
665 CentreOnParent();
666}
wxBoxSizer * m_ratio_sizer
Definition MixedFilamentDialog.hpp:159
void update_component_count_ui()
Definition MixedFilamentDialog.cpp:1797
void paint_warning_panel(wxPaintEvent &evt)
Definition MixedFilamentDialog.cpp:1601
wxPanel * m_warning_panel
Definition MixedFilamentDialog.hpp:157
void update_ok_button_state()
Definition MixedFilamentDialog.cpp:1662
wxBoxSizer * create_button_panel()
Definition MixedFilamentDialog.cpp:1269
wxBoxSizer * create_gradient_section()
Definition MixedFilamentDialog.cpp:1067
wxBoxSizer * m_right_sizer
Definition MixedFilamentDialog.hpp:161
void commit_ratio_editor_from_background(wxMouseEvent &e)
Definition MixedFilamentDialog.cpp:607
wxBoxSizer * create_ratio_slider()
Definition MixedFilamentDialog.cpp:852
void rebuild_all_combos()
Definition MixedFilamentDialog.cpp:1287
wxBoxSizer * create_preview_panel()
Definition MixedFilamentDialog.cpp:668
wxBoxSizer * m_warning_sizer
Definition MixedFilamentDialog.hpp:156
wxBoxSizer * m_triangle_sizer
Definition MixedFilamentDialog.hpp:160
wxBoxSizer * create_triangle_picker()
Definition MixedFilamentDialog.cpp:928
wxBoxSizer * create_material_selection()
Definition MixedFilamentDialog.cpp:740
wxBoxSizer * create_recommendation_grid()
Definition MixedFilamentDialog.cpp:1130
static wxColour darkModeColorFor(wxColour const &color)
Definition StateColor.cpp:219

References build_ui(), commit_ratio_editor_from_background(), create_button_panel(), create_gradient_section(), create_material_selection(), create_preview_panel(), create_ratio_slider(), create_recommendation_grid(), create_triangle_picker(), StateColor::darkModeColorFor(), m_ratio_sizer, m_right_sizer, m_triangle_sizer, m_warning_panel, m_warning_sizer, paint_warning_panel(), rebuild_all_combos(), update_component_count_ui(), update_ok_button_state(), and update_preview().

Referenced by MixedFilamentDialog(), and build_ui().

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

◆ commit_ratio_editor()

void Slic3r::GUI::MixedFilamentDialog::commit_ratio_editor ( bool apply)
private
576{
578 return;
579
581
582 // Restore the hidden anchor before applying the ratio, so any sizer layout
583 // triggered by refresh_ratio_labels() accounts for the visible label.
584 m_ratio_editor_panel->Hide();
586 m_ratio_editor_anchor->Show();
587 m_ratio_editor_anchor = nullptr;
588 }
589
590 if (apply) {
591 wxString value = m_ratio_editor->GetValue();
592 value.Trim(true);
593 value.Trim(false);
594 if (value.EndsWith(wxT("%")))
595 value.RemoveLast();
596
597 long parsed = 0;
598 if (value.ToLong(&parsed))
600 else
602 }
603
605}
wxTextCtrl * m_ratio_editor
Definition MixedFilamentDialog.hpp:142
wxPanel * m_ratio_editor_panel
Definition MixedFilamentDialog.hpp:141
size_t m_ratio_editor_idx
Definition MixedFilamentDialog.hpp:172
void apply_manual_ratio(size_t idx, int value)
Definition MixedFilamentDialog.cpp:349
wxWindow * m_ratio_editor_anchor
Definition MixedFilamentDialog.hpp:174
bool m_ratio_editor_committing
Definition MixedFilamentDialog.hpp:173
static bool apply(std::optional< T > &val, const MinMax< T > &limit)
Definition Point.hpp:738

References Slic3r::apply(), apply_manual_ratio(), commit_ratio_editor(), m_ratio_editor, m_ratio_editor_anchor, m_ratio_editor_committing, m_ratio_editor_idx, m_ratio_editor_panel, and refresh_ratio_labels().

Referenced by commit_ratio_editor(), commit_ratio_editor_from_background(), create_ratio_slider(), create_triangle_picker(), and start_ratio_editor().

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

◆ commit_ratio_editor_from_background()

void Slic3r::GUI::MixedFilamentDialog::commit_ratio_editor_from_background ( wxMouseEvent & e)
private
608{
609 if (m_ratio_editor_panel && m_ratio_editor_panel->IsShown()) {
610 wxPoint mouse_in_panel = m_ratio_editor_panel->ScreenToClient(wxGetMousePosition());
611 if (!m_ratio_editor_panel->GetClientRect().Contains(mouse_in_panel))
613 }
614 e.Skip();
615}
void commit_ratio_editor(bool apply)
Definition MixedFilamentDialog.cpp:575

References commit_ratio_editor(), commit_ratio_editor_from_background(), m_ratio_editor_panel, and Slic3r::GUI::wxMouseEvent.

Referenced by build_ui(), and commit_ratio_editor_from_background().

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

◆ comp()

unsigned int Slic3r::GUI::MixedFilamentDialog::comp ( size_t i) const
inlineprivate
119{ return (i < m_result.components.size()) ? m_result.components[i] : 1; }

References m_result.

Referenced by comp_colour(), create_material_selection(), and update_gradient_direction_items().

Here is the caller graph for this function:

◆ comp_colour()

wxColour Slic3r::GUI::MixedFilamentDialog::comp_colour ( size_t i) const
private
208{
209 unsigned int c = comp(i);
210 if (c >= 1 && c <= m_physical_colors.size())
211 return wxColour(m_physical_colors[c - 1]);
212 return wxColour("#D9D9D9");
213}
unsigned int comp(size_t i) const
Definition MixedFilamentDialog.hpp:119

References comp(), comp_colour(), and m_physical_colors.

Referenced by comp_colour(), create_gradient_section(), create_preview_panel(), create_ratio_slider(), create_triangle_picker(), and refresh_curve_editor_colors().

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

◆ compute_dialog_size()

wxSize Slic3r::GUI::MixedFilamentDialog::compute_dialog_size ( ) const
private
1779{
1780 const bool is_three = (num_components() >= 3);
1781 const bool curve_visible = !is_three && m_result.gradient_enabled;
1782
1783 int w = FromDIP(439);
1784 int h = FromDIP(580);
1785 if (is_three) {
1786 h = FromDIP(680);
1787 } else if (curve_visible) {
1788 // Wider so the gradient editor can show "Material Ratio" intact;
1789 // +40 over the 3-color height to fit the curve editor while keeping the
1790 // recommendation list visible (it can still scroll if needed).
1791 w = FromDIP(470);
1792 h = FromDIP(720);
1793 }
1794 return wxSize(w, h);
1795}

References compute_dialog_size(), m_result, and num_components().

Referenced by compute_dialog_size(), on_gradient_toggled(), and update_component_count_ui().

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

◆ create_button_panel()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_button_panel ( )
private
1270{
1271 auto* sizer = new wxBoxSizer(wxHORIZONTAL);
1272
1273 m_btn_cancel = new Button(this, _L("Cancel"));
1275 m_btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { EndModal(wxID_CANCEL); });
1276
1277 m_btn_ok = new Button(this, _L("OK"));
1279 m_btn_ok->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { EndModal(wxID_OK); });
1280
1281 sizer->Add(m_btn_cancel, 0, wxRIGHT, FromDIP(12));
1282 sizer->Add(m_btn_ok, 0);
1283
1284 return sizer;
1285}
@ Confirm
Definition Button.hpp:25
@ Regular
Definition Button.hpp:24
@ Choice
Definition Button.hpp:33
void EndModal(int retCode) override
Definition GUI_Utils.hpp:305
Button * m_btn_ok
Definition MixedFilamentDialog.hpp:154
Button * m_btn_cancel
Definition MixedFilamentDialog.hpp:155

References _L, Choice, Confirm, create_button_panel(), Slic3r::GUI::DPIDialog::EndModal(), m_btn_cancel, m_btn_ok, and Regular.

Referenced by build_ui(), and create_button_panel().

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

◆ create_gradient_section()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_gradient_section ( )
private
1068{
1069 m_gradient_sizer = new wxBoxSizer(wxHORIZONTAL);
1070
1071 m_chk_gradient = new ::CheckBox(this);
1072 m_chk_gradient->SetValue(m_result.gradient_enabled);
1073 m_chk_gradient->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& e) { e.Skip(); on_gradient_toggled(); });
1074 m_gradient_sizer->Add(m_chk_gradient, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, FromDIP(4));
1075
1076 m_label_gradient = new wxStaticText(this, wxID_ANY, _L("Gradient Effect"));
1078 m_gradient_sizer->Add(m_label_gradient, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(8));
1079
1080 m_combo_gradient_dir = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1081 wxSize(FromDIP(152), FromDIP(24)), 0, nullptr, wxCB_READONLY);
1082 m_combo_gradient_dir->SetKeepDropArrow(true);
1084 m_combo_gradient_dir->SetSelection(m_result.gradient_direction);
1085 m_combo_gradient_dir->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_gradient_direction_changed(); });
1086 m_combo_gradient_dir->Show(m_result.gradient_enabled);
1087
1088 m_gradient_sizer->Add(m_combo_gradient_dir, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(8));
1089
1090 auto* outer = new wxBoxSizer(wxVERTICAL);
1091 outer->Add(m_gradient_sizer, 0, wxEXPAND);
1092
1093 // Custom curve editor: visible only when gradient is on and exactly 2 components are mixed.
1094 m_curve_sizer = new wxBoxSizer(wxVERTICAL);
1095 m_curve_editor = new GradientCurveEditor(this, comp_colour(0), comp_colour(1));
1096 if (!m_result.gradient_curve.empty())
1097 m_curve_editor->set_points(m_result.gradient_curve);
1098 else
1099 m_curve_editor->reset_to_linear((m_result.gradient_direction == 0) ? 0.9 : 0.1,
1100 (m_result.gradient_direction == 0) ? 0.1 : 0.9);
1101 m_curve_editor->Bind(wxEVT_GRADIENT_CURVE_CHANGED,
1102 [this](wxCommandEvent&) { on_gradient_curve_changed(); });
1103 m_curve_sizer->Add(m_curve_editor, 0, wxEXPAND | wxTOP, FromDIP(4));
1104
1105 outer->Add(m_curve_sizer, 0, wxEXPAND | wxTOP, FromDIP(6));
1106 const bool curve_visible = m_result.gradient_enabled && num_components() == 2;
1107 m_curve_sizer->ShowItems(curve_visible);
1108
1109 // Per-part gradient toggle sits BELOW the curve editor.
1110 m_per_part_gradient_sizer = new wxBoxSizer(wxHORIZONTAL);
1111
1112 m_chk_per_part_gradient = new ::CheckBox(this);
1113 m_chk_per_part_gradient->SetValue(m_result.per_part_gradient);
1114 m_chk_per_part_gradient->Bind(wxEVT_TOGGLEBUTTON,
1115 [this](wxCommandEvent& e) { e.Skip(); on_per_part_gradient_toggled(); });
1117 wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, FromDIP(4));
1118
1119 m_label_per_part_gradient = new wxStaticText(this, wxID_ANY, _L("Enable per-part gradient effect"));
1122 wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(8));
1123
1124 outer->Add(m_per_part_gradient_sizer, 0, wxEXPAND | wxTOP, FromDIP(2));
1125 m_per_part_gradient_sizer->ShowItems(m_result.gradient_enabled);
1126
1127 return outer;
1128}
static wxFont Body_13
Definition Label.hpp:54
ComboBox * m_combo_gradient_dir
Definition MixedFilamentDialog.hpp:145
GradientCurveEditor * m_curve_editor
Definition MixedFilamentDialog.hpp:147
CheckBox * m_chk_per_part_gradient
Definition MixedFilamentDialog.hpp:149
wxBoxSizer * m_curve_sizer
Definition MixedFilamentDialog.hpp:148
wxColour comp_colour(size_t i) const
Definition MixedFilamentDialog.cpp:207
wxBoxSizer * m_per_part_gradient_sizer
Definition MixedFilamentDialog.hpp:151
void update_gradient_direction_items()
Definition MixedFilamentDialog.cpp:1720
void on_gradient_toggled()
Definition MixedFilamentDialog.cpp:1377
wxStaticText * m_label_gradient
Definition MixedFilamentDialog.hpp:144
void on_gradient_direction_changed()
Definition MixedFilamentDialog.cpp:1412
void on_gradient_curve_changed()
Definition MixedFilamentDialog.cpp:1428
void on_per_part_gradient_toggled()
Definition MixedFilamentDialog.cpp:1435
CheckBox * m_chk_gradient
Definition MixedFilamentDialog.hpp:143
wxBoxSizer * m_gradient_sizer
Definition MixedFilamentDialog.hpp:146
wxStaticText * m_label_per_part_gradient
Definition MixedFilamentDialog.hpp:150

References _L, Label::Body_13, comp_colour(), create_gradient_section(), m_chk_gradient, m_chk_per_part_gradient, m_combo_gradient_dir, m_curve_editor, m_curve_sizer, m_gradient_sizer, m_label_gradient, m_label_per_part_gradient, m_per_part_gradient_sizer, m_result, num_components(), on_gradient_curve_changed(), on_gradient_direction_changed(), on_gradient_toggled(), on_per_part_gradient_toggled(), update_gradient_direction_items(), and wxStaticText.

Referenced by build_ui(), and create_gradient_section().

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

◆ create_material_selection()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_material_selection ( )
private
741{
742 auto* sizer = new wxBoxSizer(wxVERTICAL);
743
744 // Summary panel — draws N components dynamically
745 m_summary_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(234), FromDIP(40)));
746 m_summary_panel->SetBackgroundStyle(wxBG_STYLE_PAINT);
747 m_summary_panel->Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
748 wxBufferedPaintDC dc(m_summary_panel);
749 wxSize sz = m_summary_panel->GetClientSize();
750
751 wxColour sum_bg = StateColor::darkModeColorFor(wxColour("#F8F8F8"));
752 wxColour sum_text = StateColor::darkModeColorFor(wxColour("#262E30"));
753 dc.SetBrush(wxBrush(sum_bg));
754 dc.SetPen(*wxTRANSPARENT_PEN);
755 dc.DrawRectangle(0, 0, sz.GetWidth(), sz.GetHeight());
756
757 int swatch_sz = FromDIP(20);
758 int y_center = (sz.GetHeight() - swatch_sz) / 2;
759 int x = FromDIP(13);
760
761 dc.SetFont(::Label::Body_13);
762
763 auto draw_summary_swatch = [&](size_t comp_idx) {
764 unsigned int c = comp(comp_idx);
765 std::string color_hex = "#D9D9D9";
766 if (c >= 1 && c <= m_physical_colors.size())
767 color_hex = m_physical_colors[c - 1];
768 std::string label = std::to_string(c);
769 wxBitmap* icon = get_extruder_color_icon(color_hex, label, swatch_sz, swatch_sz);
770 if (icon && icon->IsOk())
771 dc.DrawBitmap(*icon, x, y_center);
772 x += swatch_sz + FromDIP(4);
773 };
774
775 if (m_result.gradient_enabled && num_components() == 2) {
776 size_t idx_a = (m_result.gradient_direction == 0) ? 0 : 1;
777 size_t idx_b = 1 - idx_a;
778 draw_summary_swatch(idx_a);
779
780 dc.SetTextForeground(sum_text);
781 wxString arrow = wxT("\u2192");
782 wxSize arrow_sz = dc.GetTextExtent(arrow);
783 dc.DrawText(arrow, x, y_center + (swatch_sz - arrow_sz.GetHeight()) / 2);
784 x += arrow_sz.GetWidth() + FromDIP(4);
785
786 draw_summary_swatch(idx_b);
787 } else {
788 for (size_t i = 0; i < num_components(); ++i) {
789 if (i > 0) {
790 dc.SetTextForeground(sum_text);
791 wxString plus = wxT("+");
792 wxSize plus_sz = dc.GetTextExtent(plus);
793 dc.DrawText(plus, x, y_center + (swatch_sz - plus_sz.GetHeight()) / 2);
794 x += plus_sz.GetWidth() + FromDIP(4);
795 }
796 draw_summary_swatch(i);
797
798 dc.SetTextForeground(sum_text);
799 wxString pct = wxString::Format(wxT("%d%%"), ratio(i));
800 wxSize pct_sz = dc.GetTextExtent(pct);
801 dc.DrawText(pct, x, y_center + (swatch_sz - pct_sz.GetHeight()) / 2);
802 x += pct_sz.GetWidth() + FromDIP(4);
803 }
804 }
805 });
806 sizer->Add(m_summary_panel, 0, wxEXPAND);
807
808 auto* sel_label = new wxStaticText(this, wxID_ANY, _L("Select Mixed Materials"));
809 sel_label->SetForegroundColour(StateColor::darkModeColorFor(COLOR_LABEL_MUTED));
810 sel_label->SetFont(::Label::Body_12);
811 sizer->Add(sel_label, 0, wxTOP, FromDIP(6));
812
813 m_material_rows_sizer = new wxBoxSizer(wxVERTICAL);
814
815 m_combo_filaments.clear();
816 m_combo_to_physical.clear();
817 for (size_t i = 0; i < m_result.components.size(); ++i)
819
820 sizer->Add(m_material_rows_sizer, 0, wxEXPAND);
821
822 auto* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
823
824 m_btn_add_material = new Button(this, _L("+ Add Material"));
825 m_btn_add_material->SetBackgroundColor(wxColour("#F8F8F8"));
826 m_btn_add_material->SetBorderColor(wxColour("#EEEEEE"));
827 // The disabled tone rides on the StateColor so Enable() alone repaints it, the way m_btn_ok does.
828 m_btn_add_material->SetTextColor(StateColor(
829 std::make_pair(wxColour("#ACACAC"), (int) StateColor::Disabled),
830 std::make_pair(wxColour("#262E30"), (int) StateColor::Normal)));
831 m_btn_add_material->SetMinSize(wxSize(-1, FromDIP(24)));
832 m_btn_add_material->SetCursor(wxCursor(wxCURSOR_HAND));
833 m_btn_add_material->EnableTooltipEvenDisabled();
834 m_btn_add_material->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { on_add_material(); });
835 btn_sizer->Add(m_btn_add_material, 1, wxRIGHT, FromDIP(6));
836
837 m_btn_remove_material = new Button(this, _L("- Delete Material"));
838 m_btn_remove_material->SetBackgroundColor(wxColour("#F8F8F8"));
839 m_btn_remove_material->SetBorderColor(wxColour("#EEEEEE"));
840 m_btn_remove_material->SetTextColor(wxColour("#262E30"));
841 m_btn_remove_material->SetMinSize(wxSize(-1, FromDIP(24)));
842 m_btn_remove_material->SetCursor(wxCursor(wxCURSOR_HAND));
843 m_btn_remove_material->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { on_remove_material(); });
844 m_btn_remove_material->Hide();
845 btn_sizer->Add(m_btn_remove_material, 1, 0, 0);
846
847 sizer->Add(btn_sizer, 0, wxEXPAND | wxTOP, FromDIP(9));
848
849 return sizer;
850}
Button * m_btn_remove_material
Definition MixedFilamentDialog.hpp:153
int ratio(size_t i) const
Definition MixedFilamentDialog.hpp:120
void append_material_row()
Definition MixedFilamentDialog.cpp:288
void on_add_material()
Definition MixedFilamentDialog.cpp:1441
void on_remove_material()
Definition MixedFilamentDialog.cpp:1490
Button * m_btn_add_material
Definition MixedFilamentDialog.hpp:152
wxPanel * m_summary_panel
Definition MixedFilamentDialog.hpp:134
@ Normal
Definition StateColor.hpp:16
@ Disabled
Definition StateColor.hpp:22
static const wxColour COLOR_LABEL_MUTED("#6B6A6A")
void plus(CGALMesh &A, CGALMesh &B)
Definition MeshBoolean.cpp:476
wxBitmap * get_extruder_color_icon(std::vector< std::string > colors, bool is_gradient, std::string label, int icon_width, int icon_height, const std::vector< wxColour > *ramp)
Definition wxExtensions.cpp:633

References _L, append_material_row(), Label::Body_12, Label::Body_13, Slic3r::GUI::COLOR_LABEL_MUTED(), comp(), create_material_selection(), StateColor::darkModeColorFor(), StateColor::Disabled, get_extruder_color_icon(), m_btn_add_material, m_btn_remove_material, m_combo_filaments, m_combo_to_physical, m_material_rows_sizer, m_physical_colors, m_result, m_summary_panel, StateColor::Normal, num_components(), on_add_material(), on_remove_material(), ratio(), and wxStaticText.

Referenced by build_ui(), and create_material_selection().

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

◆ create_preview_panel()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_preview_panel ( )
private
669{
670 auto* sizer = new wxBoxSizer(wxVERTICAL);
671
672 m_preview_canvas = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(129), FromDIP(129)));
673 m_preview_canvas->SetBackgroundStyle(wxBG_STYLE_PAINT);
674
675 m_preview_canvas->Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
676 wxBufferedPaintDC dc(m_preview_canvas);
677 wxSize sz = m_preview_canvas->GetClientSize();
678 size_t n = num_components();
679
680 dc.SetBrush(wxBrush(StateColor::darkModeColorFor(*wxWHITE)));
681 dc.SetPen(*wxTRANSPARENT_PEN);
682 dc.DrawRectangle(0, 0, sz.GetWidth(), sz.GetHeight());
683
684 if (n == 0) return;
685
686 int swatch_sz = FromDIP(80);
687 int x0 = (sz.GetWidth() - swatch_sz) / 2;
688 int y0 = (sz.GetHeight() - swatch_sz) / 2;
689 double radius = FromDIP(6);
690
691 if (m_result.gradient_enabled && n == 2) {
692 Slic3r::GradientCurve curve;
693 if (!m_result.gradient_curve.empty()) {
694 curve.points = m_result.gradient_curve;
695 } else {
696 double yStart = (m_result.gradient_direction == 0) ? kGradientMaxRatio : kGradientMinRatio;
697 double yEnd = (m_result.gradient_direction == 0) ? kGradientMinRatio : kGradientMaxRatio;
698 curve.points = {{0.0, yStart, NAN, NAN}, {1.0, yEnd, NAN, NAN}};
699 }
700
701 // Same sampler the sidebar, extruder icons and paint gizmo swatches use, so this
702 // preview and every swatch drawn for the filament agree on what it looks like.
703 auto ramp = sample_gradient_ramp(comp_colour(0), comp_colour(1), curve, std::max(80, swatch_sz));
704 fill_gradient_ramp_rect(dc, wxRect(x0, y0, swatch_sz, swatch_sz), ramp);
705
706 // Mask corners: overdraw a thick background-colored rounded rect frame
707 // so the inner edge forms the desired rounded corners.
708 // Known limitation: this assumes the panel background equals
709 // darkModeColorFor(white). wxGraphicsContext::Clip(path) is not
710 // available in our wxWidgets build (only Clip(wxRegion) exists).
711 int r = static_cast<int>(radius);
712 wxColour bg = StateColor::darkModeColorFor(*wxWHITE);
713 dc.SetBrush(*wxTRANSPARENT_BRUSH);
714 dc.SetPen(wxPen(bg, r * 2));
715 dc.DrawRoundedRectangle(x0 - r, y0 - r, swatch_sz + r * 2, swatch_sz + r * 2, radius * 2);
716 } else {
717 std::vector<wxColour> cols;
718 std::vector<double> weights;
719 for (size_t i = 0; i < n; ++i) {
720 cols.push_back(comp_colour(i));
721 weights.push_back(ratio(i) / 100.0);
722 }
723 wxColour mixed = blend_n_colors(cols, weights);
724 dc.SetBrush(wxBrush(mixed));
725 dc.SetPen(*wxTRANSPARENT_PEN);
726 dc.DrawRoundedRectangle(x0, y0, swatch_sz, swatch_sz, radius);
727 }
728 });
729
730 sizer->Add(m_preview_canvas, 0, wxALIGN_CENTER);
731
732 auto* label = new wxStaticText(this, wxID_ANY, _L("Effect Preview"));
733 label->SetForegroundColour(StateColor::darkModeColorFor(COLOR_LABEL_MUTED));
734 label->SetFont(::Label::Body_13);
735 sizer->Add(label, 0, wxALIGN_CENTER | wxTOP, FromDIP(4));
736
737 return sizer;
738}
wxPanel * m_preview_canvas
Definition MixedFilamentDialog.hpp:133
wxColour blend_n_colors(const std::vector< wxColour > &cols, const std::vector< double > &weights)
Definition FilamentBitmapUtils.cpp:101
void fill_gradient_ramp_rect(wxDC &dc, const wxRect &rect, const std::vector< wxColour > &ramp)
Definition FilamentBitmapUtils.cpp:189
std::vector< wxColour > sample_gradient_ramp(const wxColour &first, const wxColour &second, const Slic3r::GradientCurve &curve, int steps)
Definition FilamentBitmapUtils.cpp:118
constexpr double kGradientMinRatio
Definition FilamentMixer.hpp:40
constexpr double kGradientMaxRatio
Definition FilamentMixer.hpp:41
size_t cols(const T &raster)
Definition MarchingSquares.hpp:173
std::vector< GradientAnchor > points
Definition FilamentMixer.hpp:32

References _L, Slic3r::GUI::blend_n_colors(), Label::Body_13, Slic3r::GUI::COLOR_LABEL_MUTED(), comp_colour(), create_preview_panel(), StateColor::darkModeColorFor(), Slic3r::GUI::fill_gradient_ramp_rect(), Slic3r::kGradientMaxRatio, Slic3r::kGradientMinRatio, m_preview_canvas, m_result, num_components(), Slic3r::GradientCurve::points, ratio(), Slic3r::GUI::sample_gradient_ramp(), and wxStaticText.

Referenced by build_ui(), and create_preview_panel().

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

◆ create_ratio_slider()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_ratio_slider ( )
private
853{
854 auto* sizer = new wxBoxSizer(wxVERTICAL);
855
856 auto* ratio_label = new wxStaticText(this, wxID_ANY, _L("Ratio"));
857 ratio_label->SetForegroundColour(StateColor::darkModeColorFor(COLOR_LABEL_MUTED));
858 ratio_label->SetFont(::Label::Body_12);
859 sizer->Add(ratio_label, 0, wxBOTTOM, FromDIP(4));
860
861 m_ratio_bar = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(27)));
862 m_ratio_bar->SetMinSize(wxSize(-1, FromDIP(27)));
863 m_ratio_bar->SetBackgroundStyle(wxBG_STYLE_PAINT);
864
865 m_ratio_bar->Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
866 wxBufferedPaintDC dc(m_ratio_bar);
867 wxSize sz = m_ratio_bar->GetClientSize();
868 draw_mixed_ratio_blend_bar(dc, wxRect(0, 0, sz.GetWidth(), sz.GetHeight()),
869 comp_colour(0), comp_colour(1), ratio(1) / 100.0);
870 });
871
872 m_ratio_bar->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
875 m_ratio_dragging = true;
876 if (!m_ratio_bar->HasCapture())
877 m_ratio_bar->CaptureMouse();
878 int new_ratio = 100 - (int)(e.GetX() * 100.0 / m_ratio_bar->GetClientSize().GetWidth() + 0.5);
879 on_ratio_changed(std::max(MIN_COMPONENT_RATIO, std::min(100 - MIN_COMPONENT_RATIO, new_ratio)));
880 });
881
882 m_ratio_bar->Bind(wxEVT_MOTION, [this](wxMouseEvent& e) {
883 if (!m_ratio_dragging) return;
884 int new_ratio = 100 - (int)(e.GetX() * 100.0 / m_ratio_bar->GetClientSize().GetWidth() + 0.5);
885 on_ratio_changed(std::max(MIN_COMPONENT_RATIO, std::min(100 - MIN_COMPONENT_RATIO, new_ratio)));
886 });
887
888 // Key the release off the capture itself, not off the drag flag: the two can fall out of
889 // sync (a lost capture clears the flag on its own), and a capture that outlives the widget
890 // wedges mouse input for the whole application.
891 m_ratio_bar->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent&) {
892 m_ratio_dragging = false;
893 if (m_ratio_bar->HasCapture())
894 m_ratio_bar->ReleaseMouse();
895 });
896
897 m_ratio_bar->Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent&) {
898 m_ratio_dragging = false;
899 });
900
901 sizer->Add(m_ratio_bar, 0, wxEXPAND);
902
903 auto* pct_sizer = new wxBoxSizer(wxHORIZONTAL);
904 m_label_ratio_a = new RatioLabelPanel(this);
905 m_label_ratio_a->SetLabel(wxString::Format(wxT("%d%%"), ratio(0)));
906 m_label_ratio_b = new RatioLabelPanel(this);
907 m_label_ratio_b->SetLabel(wxString::Format(wxT("%d%%"), ratio(1)));
908 auto bind_ratio_click = [this](RatioLabelPanel* label, size_t idx) {
909 label->Bind(wxEVT_LEFT_DOWN, [this, label, idx](wxMouseEvent&) {
910 wxRect rect(wxPoint(0, 0), label->GetClientSize());
911 start_ratio_editor(idx, label, rect);
912 });
913 };
914 bind_ratio_click(m_label_ratio_a, 0);
915 bind_ratio_click(m_label_ratio_b, 1);
916 pct_sizer->Add(m_label_ratio_a, 0);
917 pct_sizer->AddStretchSpacer(1);
918 pct_sizer->Add(m_label_ratio_b, 0);
919 sizer->Add(pct_sizer, 0, wxEXPAND | wxTOP, FromDIP(2));
920
921 return sizer;
922}
void on_ratio_changed(int new_ratio_a)
Definition MixedFilamentDialog.cpp:1365
RatioLabelPanel * m_label_ratio_b
Definition MixedFilamentDialog.hpp:140
RatioLabelPanel * m_label_ratio_a
Definition MixedFilamentDialog.hpp:139
void start_ratio_editor(size_t idx, wxWindow *anchor, const wxRect &anchor_rect)
Definition MixedFilamentDialog.cpp:469
bool m_ratio_dragging
Definition MixedFilamentDialog.hpp:169
wxMouseEvent
Definition CameraPopup.cpp:47
void draw_mixed_ratio_blend_bar(wxDC &dc, const wxRect &rect, const wxColour &first, const wxColour &second, double second_fraction)
Definition FilamentBitmapUtils.cpp:680

References _L, Label::Body_12, Slic3r::GUI::COLOR_LABEL_MUTED(), commit_ratio_editor(), comp_colour(), create_ratio_slider(), StateColor::darkModeColorFor(), Slic3r::GUI::draw_mixed_ratio_blend_bar(), m_label_ratio_a, m_label_ratio_b, m_ratio_bar, m_ratio_dragging, m_ratio_editor_panel, Slic3r::GUI::MIN_COMPONENT_RATIO, on_ratio_changed(), ratio(), start_ratio_editor(), Slic3r::GUI::wxMouseEvent, and wxStaticText.

Referenced by build_ui(), and create_ratio_slider().

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

◆ create_recommendation_grid()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_recommendation_grid ( )
private
1131{
1132 auto* outer = new wxBoxSizer(wxVERTICAL);
1133
1134 auto* title_sizer = new wxBoxSizer(wxHORIZONTAL);
1135 auto* rec_label = new wxStaticText(this, wxID_ANY, _L("Mixing Recommendations"));
1136 rec_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#ACACAC")));
1137 rec_label->SetFont(::Label::Body_10);
1138 title_sizer->Add(rec_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(4));
1139
1140 auto* rec_line = new wxPanel(this, wxID_ANY);
1141 rec_line->SetMinSize(wxSize(-1, 1));
1142 rec_line->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#EEEEEE")));
1143 title_sizer->Add(rec_line, 1, wxALIGN_CENTER_VERTICAL);
1144
1145 outer->Add(title_sizer, 0, wxEXPAND | wxBOTTOM, FromDIP(4));
1146
1147 m_recommendation_scroll = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(116)));
1148 m_recommendation_scroll->SetScrollRate(0, FromDIP(20));
1149 m_recommendation_scroll->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F8F8F8")));
1150
1151 m_recommendation_grid = new wxWrapSizer(wxHORIZONTAL, wxREMOVE_LEADING_SPACES);
1152 auto* scroll_inner_sizer = new wxBoxSizer(wxVERTICAL);
1153 scroll_inner_sizer->Add(m_recommendation_grid, 1, wxEXPAND | wxLEFT | wxTOP, FromDIP(8));
1154 m_recommendation_scroll->SetSizer(scroll_inner_sizer);
1155
1157
1158 outer->Add(m_recommendation_scroll, 1, wxEXPAND | wxTOP, FromDIP(4));
1159 return outer;
1160}
static wxFont Body_10
Definition Label.hpp:56
void rebuild_recommendation_items()
Definition MixedFilamentDialog.cpp:1162
wxScrolledWindow * m_recommendation_scroll
Definition MixedFilamentDialog.hpp:163
wxWrapSizer * m_recommendation_grid
Definition MixedFilamentDialog.hpp:164

References _L, Label::Body_10, create_recommendation_grid(), StateColor::darkModeColorFor(), m_recommendation_grid, m_recommendation_scroll, rebuild_recommendation_items(), and wxStaticText.

Referenced by build_ui(), and create_recommendation_grid().

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

◆ create_triangle_picker()

wxBoxSizer * Slic3r::GUI::MixedFilamentDialog::create_triangle_picker ( )
private
929{
930 auto* sizer = new wxBoxSizer(wxVERTICAL);
931
932 int panel_w = FromDIP(160);
933 int panel_h = FromDIP(160);
934 m_triangle_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(panel_w, panel_h));
935 m_triangle_panel->SetMinSize(wxSize(panel_w, panel_h));
936 m_triangle_panel->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
937 m_triangle_panel->SetBackgroundStyle(wxBG_STYLE_PAINT);
938
939 auto get_vertices = [this]() -> std::tuple<TriPoint, TriPoint, TriPoint> {
940 wxSize sz = m_triangle_panel->GetClientSize();
941 double pw = sz.GetWidth(), ph = sz.GetHeight();
942 double margin = FromDIP(20);
943 double avail = std::min(pw, ph) - 2 * margin;
944 double side = avail;
945 double tri_h = side * std::sqrt(3.0) / 2.0;
946 double cx = pw / 2.0;
947 double top_y = (ph - tri_h) / 2.0;
948 double bot_y = top_y + tri_h;
949 TriPoint v0 = {cx, top_y}; // top
950 TriPoint v1 = {cx - side / 2.0, bot_y}; // bottom-left
951 TriPoint v2 = {cx + side / 2.0, bot_y}; // bottom-right
952 return {v0, v1, v2};
953 };
954
955 m_triangle_panel->Bind(wxEVT_PAINT, [this, get_vertices](wxPaintEvent&) {
956 wxBufferedPaintDC dc(m_triangle_panel);
957 wxSize sz = m_triangle_panel->GetClientSize();
958 auto [v0, v1, v2] = get_vertices();
959
960 // Draw the background, cached barycentric fill, outline and drag-handle marker through the
961 // shared picker painter (same geometry the read-only Publish preview uses).
966 StateColor::darkModeColorFor(wxColour("#CECECE")),
967 StateColor::darkModeColorFor(wxColour("#262E30")),
969
970 if (m_result.ratios.size() >= 3) {
971 dc.SetFont(::Label::Body_10);
972 wxSize ts0 = dc.GetTextExtent(wxString::Format(wxT("%d%%"), m_result.ratios[0]));
973 int top_label_y = std::max(0, (int)(v0.y - ts0.GetHeight() - FromDIP(4)));
974
975 dc.SetFont(::Label::Body_12);
976 dc.SetTextForeground(StateColor::darkModeColorFor(COLOR_LABEL_MUTED));
977 dc.DrawText(_L("Ratio"), FromDIP(2), top_label_y);
978
979 // Position the real RatioLabelPanel children
980 for (int i = 0; i < 3 && i < (int)m_triangle_ratio_labels.size(); ++i) {
981 if (!m_triangle_ratio_labels[i]) continue;
982 m_triangle_ratio_labels[i]->SetLabel(
983 wxString::Format(wxT("%d%%"), m_result.ratios[i]));
984 wxSize lsz = m_triangle_ratio_labels[i]->GetMinSize();
985 int lx = 0, ly = 0;
986 if (i == 0) {
987 lx = (int)(v0.x - lsz.GetWidth() / 2);
988 ly = top_label_y;
989 } else if (i == 1) {
990 lx = (int)(v1.x - lsz.GetWidth() / 2);
991 ly = (int)(v1.y + FromDIP(3));
992 } else {
993 lx = (int)(v2.x - lsz.GetWidth() / 2);
994 ly = (int)(v2.y + FromDIP(3));
995 }
996 m_triangle_ratio_labels[i]->SetSize(lx, ly, lsz.GetWidth(), lsz.GetHeight());
997 }
998 }
999 });
1000
1001 auto handle_mouse = [this, get_vertices](wxMouseEvent& e, bool is_down) {
1002 auto [v0, v1, v2] = get_vertices();
1003 TriPoint p = {(double)e.GetX(), (double)e.GetY()};
1004
1005 if (is_down) {
1006 // Only start dragging when the press lands inside the triangle;
1007 // clicks outside the triangle must not change the mix ratio.
1008 if (!tri_contains(p, v0, v1, v2))
1009 return;
1010 m_tri_dragging = true;
1011 if (!m_triangle_panel->HasCapture())
1012 m_triangle_panel->CaptureMouse();
1013 }
1014
1015 if (!m_tri_dragging) return;
1016
1017 TriPoint clamped = tri_clamp(p, v0, v1, v2);
1018 tri_barycentric(clamped, v0, v1, v2, m_tri_wx, m_tri_wy, m_tri_wz);
1019
1020 int r0 = (int)(m_tri_wx * 100 + 0.5);
1021 int r1 = (int)(m_tri_wy * 100 + 0.5);
1022 int r2 = 100 - r0 - r1;
1023 r0 = std::clamp(r0, 0, 100);
1024 r1 = std::clamp(r1, 0, 100);
1025 r2 = std::clamp(r2, 0, 100);
1026
1027 apply_dragged_triangle_ratio(r0, r1, r2);
1028 };
1029
1030 // Create 3 RatioLabelPanel children on the triangle panel
1031 m_triangle_ratio_labels.fill(nullptr);
1032 for (int i = 0; i < 3; ++i) {
1033 auto* lbl = new RatioLabelPanel(m_triangle_panel);
1034 lbl->SetLabel(wxString::Format(wxT("%d%%"),
1035 (i < (int)m_result.ratios.size()) ? m_result.ratios[i] : 33));
1036 size_t idx = (size_t)i;
1037 lbl->Bind(wxEVT_LEFT_DOWN, [this, lbl, idx](wxMouseEvent&) {
1038 wxRect rect(wxPoint(0, 0), lbl->GetClientSize());
1039 start_ratio_editor(idx, lbl, rect);
1040 });
1041 m_triangle_ratio_labels[i] = lbl;
1042 }
1043
1044 m_triangle_panel->Bind(wxEVT_LEFT_DOWN, [this, handle_mouse](wxMouseEvent& e) {
1046 commit_ratio_editor(true);
1047 handle_mouse(e, true);
1048 });
1049 m_triangle_panel->Bind(wxEVT_MOTION, [this, handle_mouse](wxMouseEvent& e) {
1050 if (m_tri_dragging)
1051 handle_mouse(e, false);
1052 });
1053 m_triangle_panel->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent&) {
1054 m_tri_dragging = false;
1055 if (m_triangle_panel->HasCapture())
1056 m_triangle_panel->ReleaseMouse();
1057 });
1058 m_triangle_panel->Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent&) {
1059 m_tri_dragging = false;
1060 });
1061
1062 sizer->Add(m_triangle_panel, 0);
1063
1064 return sizer;
1065}
std::array< RatioLabelPanel *, 3 > m_triangle_ratio_labels
Definition MixedFilamentDialog.hpp:178
bool m_tri_dragging
Definition MixedFilamentDialog.hpp:170
void apply_dragged_triangle_ratio(int r0, int r1, int r2)
Definition MixedFilamentDialog.cpp:428
void draw_mixed_triangle_picker(wxDC &dc, const wxSize &size, const std::array< wxColour, 3 > &colours, const std::array< double, 3 > &weights, const MixedTriangleTheme &theme)
Definition FilamentBitmapUtils.cpp:769
void tri_barycentric(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2, double &w0, double &w1, double &w2)
Definition FilamentBitmapUtils.cpp:53
TriPoint tri_clamp(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2)
Definition FilamentBitmapUtils.cpp:68
bool tri_contains(TriPoint p, TriPoint v0, TriPoint v1, TriPoint v2)
Definition FilamentBitmapUtils.cpp:43

References _L, apply_dragged_triangle_ratio(), Label::Body_10, Label::Body_12, Slic3r::GUI::COLOR_LABEL_MUTED(), commit_ratio_editor(), comp_colour(), create_triangle_picker(), StateColor::darkModeColorFor(), Slic3r::GUI::draw_mixed_triangle_picker(), m_ratio_editor_panel, m_result, m_tri_dragging, m_tri_wx, m_tri_wy, m_tri_wz, m_triangle_panel, m_triangle_ratio_labels, start_ratio_editor(), Slic3r::GUI::tri_barycentric(), Slic3r::GUI::tri_clamp(), Slic3r::GUI::tri_contains(), and Slic3r::GUI::wxMouseEvent.

Referenced by build_ui(), and create_triangle_picker().

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

◆ em_unit()

int Slic3r::GUI::DPIAware< wxDialog >::em_unit ( ) const
inlineinherited
203{ return m_em_unit; }
Definition GUI_Utils.hpp:107

Referenced by Slic3r::GUI::AuxiliaryDialog::AuxiliaryDialog(), Slic3r::GUI::CopyrightsDialog::CopyrightsDialog(), Slic3r::GUI::DesignTextDialog::DesignTextDialog(), Slic3r::GUI::EditGCodeDialog::EditGCodeDialog(), Slic3r::GUI::FileArchiveDialog::FileArchiveDialog(), Slic3r::GUI::MsgNoUpdates::MsgNoUpdates(), Slic3r::GUI::MsgUpdateForced::MsgUpdateForced(), Slic3r::GUI::OAuthDialog::OAuthDialog(), Slic3r::GUI::ParamsDialog::ParamsDialog(), Slic3r::GUI::PhysicalPrinterDialog::PhysicalPrinterDialog(), Slic3r::GUI::SettingsDialog::SettingsDialog(), anonymous_namespace{3DPrinterOS.cpp}::TokenAuthDialog::TokenAuthDialog(), anonymous_namespace{3DPrinterOS.cpp}::UploadOptionsDialog::UploadOptionsDialog(), Slic3r::GUI::PublishSettingsDialog::add_row_ui(), Slic3r::GUI::DiffPresetDialog::complete_dialog_creation(), Slic3r::GUI::DiffPresetDialog::create_edit_sizer(), Slic3r::GUI::DiffPresetDialog::create_presets_sizer(), Slic3r::GUI::DiffPresetDialog::create_tree(), Slic3r::GUI::ElegooPrintHostSendDialog::init(), Slic3r::GUI::FlashforgePrintHostSendDialog::init(), Slic3r::GUI::PrintHostSendDialog::init(), Slic3r::GUI::AboutDialog::on_dpi_changed(), Slic3r::GUI::AuxiliaryDialog::on_dpi_changed(), Slic3r::GUI::BedShapeDialog::on_dpi_changed(), Slic3r::GUI::ConfigWizard::on_dpi_changed(), Slic3r::GUI::CopyrightsDialog::on_dpi_changed(), Slic3r::GUI::DiffPresetDialog::on_dpi_changed(), Slic3r::GUI::EditGCodeDialog::on_dpi_changed(), Slic3r::GUI::FileArchiveDialog::on_dpi_changed(), Slic3r::GUI::OAuthDialog::on_dpi_changed(), Slic3r::GUI::ObjectTableDialog::on_dpi_changed(), Slic3r::GUI::ParamsDialog::on_dpi_changed(), Slic3r::GUI::PhysicalPrinterDialog::on_dpi_changed(), Slic3r::GUI::PrintHostQueueDialog::on_dpi_changed(), Slic3r::GUI::PurgeModeDialog::on_dpi_changed(), Slic3r::GUI::SavePresetDialog::on_dpi_changed(), Slic3r::GUI::SendSystemInfoDialog::on_dpi_changed(), Slic3r::GUI::SettingsDialog::on_dpi_changed(), and Slic3r::GUI::UnsavedChangesDialog::on_dpi_changed().

Here is the caller graph for this function:

◆ enable_force_rescale()

void Slic3r::GUI::DPIAware< wxDialog >::enable_force_rescale ( )
inlineinherited
206{ m_force_rescale = true; }

◆ EndModal()

void Slic3r::GUI::DPIDialog::EndModal ( int retCode)
inlineoverrideinherited
306 {
307 if (!dialogStack.empty() && dialogStack.front() != this) {
308 // This is a bug in wxWidgets
309 // when the dialog is not top modal dialog, EndModal() just hide dialog without quit
310 // the modal event loop. And the modal event loop blocks us from bottom widgets.
311 // Solution: let user click it manually or close outside. FIXME
312 BOOST_LOG_TRIVIAL(warning) << "DPIAware::EndModal Error: dialogStack is not empty, but top dialog is not this one. retCode=" << retCode;
313 return;
314 }
315
316 return wxDialog::EndModal(retCode);
317 }
std::deque< wxDialog * > dialogStack
Definition GUI_Utils.cpp:549

References Slic3r::GUI::dialogStack.

Referenced by Slic3r::GUI::CloneDialog::CloneDialog(), Slic3r::GUI::ConfigWizard::ConfigWizard(), Slic3r::GUI::CreatePresetSuccessfulDialog::CreatePresetSuccessfulDialog(), Slic3r::GUI::DeleteConfirmDialog::DeleteConfirmDialog(), Slic3r::GUI::DesignVariableDialog::DesignVariableDialog(), Slic3r::GUI::anonymous_namespace{PrintHostDialogs.cpp}::FlashforgeSlotDialog::FlashforgeSlotDialog(), Slic3r::GUI::GuideFrame::GuideFrame(), Slic3r::GUI::InputIpAddressDialog::InputIpAddressDialog(), Slic3r::GUI::ManualNozzleCountDialog::ManualNozzleCountDialog(), Slic3r::GUI::MsgUpdateConfig::MsgUpdateConfig(), Slic3r::GUI::MsgUpdateForced::MsgUpdateForced(), Slic3r::GUI::MultiChoiceDialog::MultiChoiceDialog(), Slic3r::GUI::NetworkErrorDialog::NetworkErrorDialog(), Slic3r::GUI::NetworkPluginRestartDialog::NetworkPluginRestartDialog(), Slic3r::GUI::PartSkipConfirmDialog::PartSkipConfirmDialog(), Slic3r::GUI::PhysicalPrinterDialog::PhysicalPrinterDialog(), Slic3r::GUI::PlateNameEditDialog::PlateNameEditDialog(), Slic3r::GUI::PlateSettingsDialog::PlateSettingsDialog(), Slic3r::GUI::PublishSettingsDialog::PublishSettingsDialog(), Slic3r::GUI::SelectMachineDialog::SelectMachineDialog(), Slic3r::GUI::SendFailedConfirm::SendFailedConfirm(), Slic3r::GUI::SendSystemInfoDialog::SendSystemInfoDialog(), Slic3r::GUI::ShortcutCaptureDialog::ShortcutCaptureDialog(), Slic3r::GUI::SingleChoiceDialog::SingleChoiceDialog(), StepMeshDialog::StepMeshDialog(), Slic3r::GUI::SyncAmsInfoDialog::SyncAmsInfoDialog(), anonymous_namespace{3DPrinterOS.cpp}::TokenAuthDialog::TokenAuthDialog(), Slic3r::GUI::UpdatePluginDialog::UpdatePluginDialog(), Slic3r::GUI::UpdateVersionDialog::UpdateVersionDialog(), Slic3r::GUI::wgtDeviceNozzleRackUpgradeDlg::wgtDeviceNozzleRackUpgradeDlg(), Slic3r::GUI::SavePresetDialog::accept(), Slic3r::GUI::MsgDialog::add_button(), Slic3r::GUI::TipsDialog::add_button(), Slic3r::GUI::FilamentPickerDialog::BindEvents(), Slic3r::GUI::PluginPickerDialog::build_capability_ui(), Slic3r::GUI::BedShapeDialog::build_dialog(), Slic3r::GUI::PluginPickerDialog::build_ui(), Slic3r::GUI::UnsavedChangesDialog::close(), Slic3r::GUI::FileArchiveDialog::create_btn_sizer(), Slic3r::GUI::ColorDecomposeDialog::create_button_panel(), Slic3r::GUI::MixedFilamentDialog::create_button_panel(), Slic3r::GUI::CreateFilamentPresetDialog::create_dialog_buttons(), Slic3r::GUI::CreatePresetForPrinterDialog::create_dialog_buttons(), Slic3r::GUI::EditFilamentPresetDialog::create_dialog_buttons(), Slic3r::GUI::ExportConfigsDialog::create_dialog_buttons(), Slic3r::GUI::PreferencesDialog::create_item_language_combobox(), Slic3r::GUI::PreferencesDialog::create_item_region_combobox(), Slic3r::GUI::PreferencesDialog::create_items(), Slic3r::GUI::CreatePrinterPresetDialog::create_page1_dialog_buttons(), Slic3r::GUI::CreatePrinterPresetDialog::create_page2_dialog_buttons(), Slic3r::GUI::ExportConfigsDialog::data_init(), Slic3r::GUI::WebDialog::destroy_silently(), Slic3r::GUI::EditFilamentPresetDialog::edit_preset(), Slic3r::GUI::ConnectPrinterDialog::end_modal(), Slic3r::GUI::PrintHostSendDialog::EndModal(), Slic3r::GUI::ColorPickerDialog::finish(), Slic3r::GUI::WebDialog::finish(), Slic3r::GUI::Newer3mfVersionDialog::get_btn_sizer(), Slic3r::GUI::ScoreDialog::get_button_sizer(), Slic3r::GUI::WebViewHostDialog::handle_common_script_command(), Slic3r::GUI::ExportPresetBundleDialog::InitExportData(), Slic3r::GUI::SelectMachineDialog::navigate_to_timelapse_page(), Slic3r::GUI::BindMachineDialog::on_bind_success(), Slic3r::GUI::ConnectPrinterDialog::on_button_confirm(), Slic3r::GUI::RecenterDialog::on_button_confirm(), Slic3r::GUI::BindMachineDialog::on_cancel(), Slic3r::GUI::EditCalibrationHistoryDialog::on_cancel(), Slic3r::GUI::InputIpAddressDialog::on_cancel(), Slic3r::GUI::NewCalibrationHistoryDialog::on_cancel(), Slic3r::GUI::OAuthDialog::on_cancel(), Slic3r::GUI::PingCodeBindDialog::on_cancel(), Slic3r::GUI::SelectMachineDialog::on_cancel(), Slic3r::GUI::SendToPrinterDialog::on_cancel(), Slic3r::GUI::SyncAmsInfoDialog::on_cancel(), Slic3r::GUI::UnBindMachineDialog::on_cancel(), Slic3r::GUI::WebDialog::on_close_window(), Slic3r::GUI::NetworkPluginDownloadDialog::on_dont_ask(), Slic3r::GUI::NetworkPluginDownloadDialog::on_download(), Slic3r::GUI::EditDevNameDialog::on_edit_name(), Slic3r::GUI::ConfirmBeforeSendDialog::on_hide(), Slic3r::GUI::PrivacyUpdateDialog::on_hide(), Slic3r::GUI::ShortcutCaptureDialog::on_key(), Slic3r::GUI::TextureImportDialog::on_ok_clicked(), Slic3r::GUI::FileArchiveDialog::on_open_button(), Slic3r::GUI::NetworkPluginDownloadDialog::on_remind_later(), Slic3r::GUI::ProjectDropDialog::on_select_cancel(), Slic3r::GUI::SavePresetDialog::on_select_cancel(), Slic3r::GUI::ProjectDropDialog::on_select_ok(), Slic3r::GUI::SendMultiMachinePage::on_send(), Slic3r::GUI::NetworkPluginDownloadDialog::on_skip(), Slic3r::GUI::TextureImportDialog::on_skip_clicked(), Slic3r::GUI::NetworkPluginDownloadDialog::on_skip_version(), Slic3r::GUI::Cornering_Test_Dlg::on_start(), Slic3r::GUI::FlowRateCalibrationDialog::on_start(), Slic3r::GUI::Input_Shaping_Damp_Test_Dlg::on_start(), Slic3r::GUI::Input_Shaping_Freq_Test_Dlg::on_start(), Slic3r::GUI::MaxVolumetricSpeed_Test_Dlg::on_start(), Slic3r::GUI::PA_Calibration_Dlg::on_start(), Slic3r::GUI::Retraction_Test_Dlg::on_start(), Slic3r::GUI::Temp_Calibration_Dlg::on_start(), Slic3r::GUI::VFA_Test_Dlg::on_start(), Slic3r::GUI::CalibrationDialog::on_start_calibration(), Slic3r::GUI::UnBindMachineDialog::on_unbind_printer(), Slic3r::GUI::PartSkipDialog::OnApplyDialog(), anonymous_namespace{3DPrinterOS.cpp}::TokenAuthDialog::OnCancel(), Slic3r::GUI::AboutDialog::onCloseDialog(), Slic3r::GUI::CopyrightsDialog::onCloseDialog(), Slic3r::GUI::MultiNozzleSyncDialog::OnRackStatusReadingFinished(), Slic3r::GUI::GuideFrame::OnScriptMessage(), Slic3r::GUI::InputIpAddressDialog::OnTimer(), Slic3r::GUI::KBShortcutsDialog::open_mouse_preferences(), Slic3r::GUI::TroubleshootDialog::PackAll(), Slic3r::GUI::TroubleshootDialog::RebuildSystemProfiles(), Slic3r::GUI::SpeedDialWebDialog::run_action(), Slic3r::GUI::OAuthDialog::Show(), Slic3r::GUI::MultiNozzleSyncDialog::UpdateButton(), and Slic3r::GUI::CreatePrinterPresetDialog::validate_input_valid().

◆ force_rescale()

bool Slic3r::GUI::DPIAware< wxDialog >::force_rescale ( ) const
inlineinherited
201{ return m_force_rescale; }

◆ get_result()

MixedFilamentResult Slic3r::GUI::MixedFilamentDialog::get_result ( ) const
inline
64{ return m_result; }

References m_result.

Referenced by Slic3r::GUI::Sidebar::add_mixed_filament(), and Slic3r::GUI::Sidebar::edit_mixed_filament().

Here is the caller graph for this function:

◆ is_new_scale_factor()

bool Slic3r::GUI::DPIAware< wxDialog >::is_new_scale_factor ( ) const
inlineprivateinherited
262{ return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; }

◆ make_swatch_bitmap()

wxBitmap Slic3r::GUI::MixedFilamentDialog::make_swatch_bitmap ( size_t idx)
private
245{
246 int swatch_sz = FromDIP(20);
247 int pad_left = FromDIP(2);
248 int pad_right = FromDIP(6);
249 int bmp_w = pad_left + swatch_sz + pad_right;
250 int bmp_h = swatch_sz;
251
252 // Reuse the sidebar clr_picker swatch (get_extruder_color_icon) so the
253 // checkerboard (transparent.svg tiling), border and label style match the
254 // sidebar exactly, instead of a self-drawn rounded rect / programmatic grid.
255 std::string color_hex = "#D9D9D9";
256 if (idx < m_physical_colors.size())
257 color_hex = m_physical_colors[idx];
258 std::string label = std::to_string(idx + 1);
259
260 wxBitmap* icon = get_extruder_color_icon(color_hex, label, swatch_sz, swatch_sz);
261
262 return make_alpha_bitmap(bmp_w, bmp_h, [&](wxDC& dc) {
263 if (icon && icon->IsOk())
264 dc.DrawBitmap(*icon, pad_left, 0);
265 });
266}
static wxBitmap make_alpha_bitmap(int w, int h, const std::function< void(wxDC &dc)> &draw_fn)
Definition MixedFilamentDialog.cpp:215

References get_extruder_color_icon(), m_physical_colors, Slic3r::GUI::make_alpha_bitmap(), and make_swatch_bitmap().

Referenced by make_swatch_bitmap(), and rebuild_all_combos().

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

◆ normal_font()

◆ num_components()

size_t Slic3r::GUI::MixedFilamentDialog::num_components ( ) const
inlineprivate
118{ return m_result.components.size(); }

References m_result.

Referenced by apply_manual_ratio(), compute_dialog_size(), create_gradient_section(), create_material_selection(), create_preview_panel(), on_add_material(), on_dpi_changed(), on_gradient_toggled(), on_recommendation_clicked_triple(), on_remove_material(), rebuild_recommendation_items(), update_component_count_ui(), and update_gradient_direction_items().

Here is the caller graph for this function:

◆ on_add_material()

void Slic3r::GUI::MixedFilamentDialog::on_add_material ( )
private
1442{
1443 size_t n = num_components();
1444 if (n >= (size_t)MAX_COMPONENTS) return;
1445
1446 unsigned int new_comp = 0;
1447 for (size_t j = 0; j < m_physical_names.size(); ++j) {
1448 unsigned int candidate = (unsigned int)(j + 1);
1449 bool used = false;
1450 for (auto c : m_result.components)
1451 if (c == candidate) { used = true; break; }
1452 if (!used) { new_comp = candidate; break; }
1453 }
1454 if (new_comp == 0) return;
1455 m_result.components.push_back(new_comp);
1456
1457 int each = 100 / (int)(n + 1);
1458 m_result.ratios.clear();
1459 int assigned = 0;
1460 for (size_t i = 0; i < n; ++i) {
1461 m_result.ratios.push_back(each);
1462 assigned += each;
1463 }
1464 m_result.ratios.push_back(100 - assigned);
1465
1466 if (m_result.ratios.size() >= 3) {
1467 int sum = 0;
1468 for (int r : m_result.ratios) sum += r;
1469 if (sum > 0) {
1470 m_tri_wx = (double)m_result.ratios[0] / sum;
1471 m_tri_wy = (double)m_result.ratios[1] / sum;
1472 m_tri_wz = (double)m_result.ratios[2] / sum;
1473 }
1474 }
1476
1478
1485
1486 Layout();
1487 Refresh();
1488}
void refresh_curve_editor_colors()
Definition MixedFilamentDialog.cpp:1342

References append_material_row(), m_physical_names, m_result, m_tri_wx, m_tri_wy, m_tri_wz, Slic3r::GUI::MAX_COMPONENTS, num_components(), on_add_material(), rebuild_all_combos(), rebuild_recommendation_items(), refresh_curve_editor_colors(), reset_manual_ratio_state(), update_component_count_ui(), update_ok_button_state(), and update_preview().

Referenced by create_material_selection(), and on_add_material().

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

◆ on_dpi_changed()

void Slic3r::GUI::MixedFilamentDialog::on_dpi_changed ( const wxRect & suggested_rect)
overrideprotectedvirtual

Implements Slic3r::GUI::DPIAware< wxDialog >.

201{
202 int h = (num_components() >= 3) ? FromDIP(680) : FromDIP(580);
203 SetSize(FromDIP(439), h);
204 Refresh();
205}

References num_components(), and on_dpi_changed().

Referenced by on_dpi_changed().

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

◆ on_filament_changed()

void Slic3r::GUI::MixedFilamentDialog::on_filament_changed ( )
private
1351{
1352 for (size_t i = 0; i < m_combo_filaments.size() && i < m_result.components.size(); ++i) {
1353 int sel = m_combo_filaments[i]->GetSelection();
1354 if (sel >= 0 && i < m_combo_to_physical.size() && sel < (int)m_combo_to_physical[i].size())
1355 m_result.components[i] = m_combo_to_physical[i][sel];
1356 }
1357
1363}

References m_combo_filaments, m_combo_to_physical, m_result, on_filament_changed(), rebuild_all_combos(), refresh_curve_editor_colors(), update_gradient_direction_items(), update_ok_button_state(), and update_preview().

Referenced by append_material_row(), and on_filament_changed().

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

◆ on_gradient_curve_changed()

void Slic3r::GUI::MixedFilamentDialog::on_gradient_curve_changed ( )
private
1429{
1430 if (m_curve_editor)
1431 m_result.gradient_curve = m_curve_editor->get_points();
1433}

References m_curve_editor, m_result, on_gradient_curve_changed(), and update_preview().

Referenced by create_gradient_section(), and on_gradient_curve_changed().

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

◆ on_gradient_direction_changed()

void Slic3r::GUI::MixedFilamentDialog::on_gradient_direction_changed ( )
private
1413{
1414 if (!m_combo_gradient_dir) return;
1415 m_result.gradient_direction = m_combo_gradient_dir->GetSelection();
1416
1417 // Mirror the user's custom curve around y=0.5 instead of resetting it, so
1418 // shape work (added anchors, bent segments) survives a direction toggle.
1419 // reverse() flips y and tangent signs consistently; default two-point
1420 // linear curves end up matching the new direction exactly (0.9->0.1 <-> 0.1->0.9).
1421 if (m_curve_editor) {
1422 m_curve_editor->reverse();
1423 m_result.gradient_curve = m_curve_editor->get_points();
1424 }
1426}

References m_combo_gradient_dir, m_curve_editor, m_result, on_gradient_direction_changed(), and update_preview().

Referenced by create_gradient_section(), and on_gradient_direction_changed().

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

◆ on_gradient_toggled()

void Slic3r::GUI::MixedFilamentDialog::on_gradient_toggled ( )
private
1378{
1379
1380 m_result.gradient_enabled = m_chk_gradient->GetValue();
1381
1382 if (m_ratio_sizer)
1383 m_ratio_sizer->ShowItems(!m_result.gradient_enabled && num_components() == 2);
1385 m_combo_gradient_dir->Show(m_result.gradient_enabled);
1387 m_per_part_gradient_sizer->ShowItems(m_result.gradient_enabled);
1388 if (m_curve_sizer)
1389 m_curve_sizer->ShowItems(m_result.gradient_enabled && num_components() == 2);
1390 if (!m_result.gradient_enabled) {
1391 m_result.per_part_gradient = false;
1393 }
1394
1395 // Toggling the curve editor changes the right column height (and width when
1396 // turning gradient on), so the dialog must follow or the recommendation list
1397 // gets squeezed off-screen. Same trick as 2-color -> 3-color switching.
1398 const wxSize new_size = compute_dialog_size();
1399 if (GetSize() != new_size) {
1400 const wxRect old_rect = GetRect();
1401 const wxPoint center(old_rect.x + old_rect.width / 2,
1402 old_rect.y + old_rect.height / 2);
1403 SetSize(new_size);
1404 SetPosition(wxPoint(center.x - new_size.x / 2,
1405 center.y - new_size.y / 2));
1406 }
1407
1408 Layout();
1409 Refresh();
1410}
wxSize compute_dialog_size() const
Definition MixedFilamentDialog.cpp:1778
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382

References Slic3r::center(), compute_dialog_size(), m_chk_gradient, m_chk_per_part_gradient, m_combo_gradient_dir, m_curve_sizer, m_per_part_gradient_sizer, m_ratio_sizer, m_result, num_components(), and on_gradient_toggled().

Referenced by create_gradient_section(), and on_gradient_toggled().

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

◆ on_per_part_gradient_toggled()

void Slic3r::GUI::MixedFilamentDialog::on_per_part_gradient_toggled ( )
private
1436{
1438 m_result.per_part_gradient = m_chk_per_part_gradient->GetValue();
1439}

References m_chk_per_part_gradient, m_result, and on_per_part_gradient_toggled().

Referenced by create_gradient_section(), and on_per_part_gradient_toggled().

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

◆ on_ratio_changed()

void Slic3r::GUI::MixedFilamentDialog::on_ratio_changed ( int new_ratio_a)
private
1366{
1367 if (m_result.ratios.size() < 2) return;
1368 m_result.ratios[0] = new_ratio_a;
1369 m_result.ratios[1] = 100 - new_ratio_a;
1370
1373
1375}

References m_result, on_ratio_changed(), refresh_ratio_labels(), reset_manual_ratio_state(), and update_preview().

Referenced by create_ratio_slider(), and on_ratio_changed().

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

◆ on_recommendation_clicked()

void Slic3r::GUI::MixedFilamentDialog::on_recommendation_clicked ( unsigned int comp_a,
unsigned int comp_b )
private
1527{
1528 while (m_material_rows_sizer->GetItemCount() > 2) {
1529 auto* sizer_item = m_material_rows_sizer->GetItem(m_material_rows_sizer->GetItemCount() - 1);
1530 if (sizer_item && sizer_item->GetSizer())
1531 sizer_item->GetSizer()->Clear(true);
1532 m_material_rows_sizer->Remove(m_material_rows_sizer->GetItemCount() - 1);
1533 }
1534
1535 while (m_combo_filaments.size() > 2)
1536 m_combo_filaments.pop_back();
1537 while (m_combo_to_physical.size() > 2)
1538 m_combo_to_physical.pop_back();
1539
1540 m_result.components = {comp_a, comp_b};
1541 m_result.ratios = {50, 50};
1542
1545
1552 Layout();
1553 Refresh();
1554}

References m_combo_filaments, m_combo_to_physical, m_material_rows_sizer, m_result, on_recommendation_clicked(), rebuild_all_combos(), refresh_curve_editor_colors(), refresh_ratio_labels(), reset_manual_ratio_state(), update_component_count_ui(), update_gradient_direction_items(), update_ok_button_state(), and update_preview().

Referenced by on_recommendation_clicked(), and rebuild_recommendation_items().

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

◆ on_recommendation_clicked_triple()

void Slic3r::GUI::MixedFilamentDialog::on_recommendation_clicked_triple ( unsigned int a,
unsigned int b,
unsigned int c )
private
1557{
1558 // Ensure we have exactly 3 combo rows
1559 if (num_components() < 3) {
1560 // Need to add a 3rd combo row
1561 while (m_combo_filaments.size() < 3)
1563 } else if (num_components() > 3) {
1564 while (m_material_rows_sizer->GetItemCount() > 3) {
1565 auto* sizer_item = m_material_rows_sizer->GetItem(m_material_rows_sizer->GetItemCount() - 1);
1566 if (sizer_item && sizer_item->GetSizer())
1567 sizer_item->GetSizer()->Clear(true);
1568 m_material_rows_sizer->Remove(m_material_rows_sizer->GetItemCount() - 1);
1569 }
1570 while (m_combo_filaments.size() > 3)
1571 m_combo_filaments.pop_back();
1572 while (m_combo_to_physical.size() > 3)
1573 m_combo_to_physical.pop_back();
1574 }
1575
1576 m_result.components = {a, b, c};
1577 m_result.ratios = {25, 25, 50};
1578 m_tri_wx = 0.25;
1579 m_tri_wy = 0.25;
1580 m_tri_wz = 0.50;
1582
1589 Layout();
1590 Refresh();
1591}

References append_material_row(), m_combo_filaments, m_combo_to_physical, m_material_rows_sizer, m_result, m_tri_wx, m_tri_wy, m_tri_wz, num_components(), on_recommendation_clicked_triple(), rebuild_all_combos(), refresh_curve_editor_colors(), reset_manual_ratio_state(), update_component_count_ui(), update_gradient_direction_items(), update_ok_button_state(), and update_preview().

Referenced by on_recommendation_clicked_triple(), and rebuild_recommendation_items().

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

◆ on_remove_material()

void Slic3r::GUI::MixedFilamentDialog::on_remove_material ( )
private
1491{
1492 if (num_components() <= 2)
1493 return;
1494
1495 m_result.components.resize(2);
1496 m_result.ratios = {50, 50};
1497 m_tri_wx = 0.5;
1498 m_tri_wy = 0.5;
1499 m_tri_wz = 0.0;
1500
1503
1504 if (m_material_rows_sizer && m_material_rows_sizer->GetItemCount() > 2) {
1505 auto* sizer_item = m_material_rows_sizer->GetItem(m_material_rows_sizer->GetItemCount() - 1);
1506 if (sizer_item && sizer_item->GetSizer())
1507 sizer_item->GetSizer()->Clear(true);
1508 m_material_rows_sizer->Remove(m_material_rows_sizer->GetItemCount() - 1);
1509 }
1510
1511 if (m_combo_filaments.size() > 2)
1512 m_combo_filaments.pop_back();
1513 if (m_combo_to_physical.size() > 2)
1514 m_combo_to_physical.pop_back();
1515
1522 Layout();
1523 Refresh();
1524}

References m_combo_filaments, m_combo_to_physical, m_material_rows_sizer, m_result, m_tri_wx, m_tri_wy, m_tri_wz, num_components(), on_remove_material(), rebuild_all_combos(), rebuild_recommendation_items(), refresh_curve_editor_colors(), refresh_ratio_labels(), reset_manual_ratio_state(), update_component_count_ui(), update_ok_button_state(), and update_preview().

Referenced by create_material_selection(), and on_remove_material().

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

◆ on_sys_color_changed()

◆ paint_warning_panel()

void Slic3r::GUI::MixedFilamentDialog::paint_warning_panel ( wxPaintEvent & evt)
private
1602{
1603 wxBufferedPaintDC dc(m_warning_panel);
1604 wxSize sz = m_warning_panel->GetClientSize();
1605
1606 dc.SetBrush(wxBrush(StateColor::darkModeColorFor(*wxWHITE)));
1607 dc.SetPen(*wxTRANSPARENT_PEN);
1608 dc.DrawRectangle(0, 0, sz.GetWidth(), sz.GetHeight());
1609
1610 dc.SetBrush(wxBrush(StateColor::darkModeColorFor(wxColour("#F8F8F8"))));
1611 dc.SetPen(wxPen(StateColor::darkModeColorFor(wxColour("#D01B1B")), 1));
1612 dc.DrawRoundedRectangle(0, 0, sz.GetWidth(), sz.GetHeight(), FromDIP(4));
1613
1614 int x = FromDIP(10);
1615 int cy = sz.GetHeight() / 2;
1616
1617 int icon_r = FromDIP(7);
1618 dc.SetBrush(wxBrush(StateColor::darkModeColorFor(wxColour("#D01B1B"))));
1619 dc.SetPen(*wxTRANSPARENT_PEN);
1620 dc.DrawCircle(x + icon_r, cy, icon_r);
1621 dc.SetFont(::Label::Body_10);
1622 dc.SetTextForeground(*wxWHITE);
1623 wxSize ex = dc.GetTextExtent(wxT("!"));
1624 dc.DrawText(wxT("!"), x + icon_r - ex.GetWidth() / 2, cy - ex.GetHeight() / 2);
1625 x += icon_r * 2 + FromDIP(6);
1626
1627 if (m_type_mismatch_msg.empty()) return;
1628
1629 dc.SetFont(::Label::Body_12);
1630 dc.SetTextForeground(StateColor::darkModeColorFor(wxColour("#D01B1B")));
1631 wxString msg = m_type_mismatch_msg;
1632 int avail_w = sz.GetWidth() - x - FromDIP(10);
1633 wxSize ts = dc.GetTextExtent(msg);
1634 if (ts.GetWidth() <= avail_w) {
1635 dc.DrawText(msg, x, cy - ts.GetHeight() / 2);
1636 } else {
1637 wxArrayString lines;
1638 wxString cur_line;
1639 wxArrayString words;
1640 wxStringTokenizer tkz(msg, wxT(" "), wxTOKEN_RET_EMPTY_ALL);
1641 while (tkz.HasMoreTokens()) words.Add(tkz.GetNextToken());
1642 if (words.empty()) words.Add(msg);
1643 for (size_t w = 0; w < words.size(); ++w) {
1644 wxString test = cur_line.empty() ? words[w] : cur_line + wxT(" ") + words[w];
1645 if (dc.GetTextExtent(test).GetWidth() > avail_w && !cur_line.empty()) {
1646 lines.Add(cur_line);
1647 cur_line = words[w];
1648 } else {
1649 cur_line = test;
1650 }
1651 }
1652 if (!cur_line.empty()) lines.Add(cur_line);
1653 if (lines.empty()) lines.Add(msg);
1654 int line_h = dc.GetTextExtent(wxT("Mg")).GetHeight();
1655 int total_h = (int)lines.size() * line_h;
1656 int y0 = (sz.GetHeight() - total_h) / 2;
1657 for (size_t l = 0; l < lines.size(); ++l)
1658 dc.DrawText(lines[l], x, y0 + (int)l * line_h);
1659 }
1660}
wxString m_type_mismatch_msg
Definition MixedFilamentDialog.hpp:127

References Label::Body_10, Label::Body_12, StateColor::darkModeColorFor(), m_type_mismatch_msg, m_warning_panel, and paint_warning_panel().

Referenced by build_ui(), and paint_warning_panel().

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

◆ prev_scale_factor()

float Slic3r::GUI::DPIAware< wxDialog >::prev_scale_factor ( ) const
inlineinherited
196{ return m_prev_scale_factor; }

◆ ratio()

int Slic3r::GUI::MixedFilamentDialog::ratio ( size_t i) const
inlineprivate
120{ return (i < m_result.ratios.size()) ? m_result.ratios[i] : 0; }

References m_result.

Referenced by create_material_selection(), create_preview_panel(), create_ratio_slider(), refresh_ratio_labels(), and start_ratio_editor().

Here is the caller graph for this function:

◆ rebuild_all_combos()

void Slic3r::GUI::MixedFilamentDialog::rebuild_all_combos ( )
private
1288{
1290
1291 for (size_t i = 0; i < m_combo_filaments.size(); ++i) {
1292 std::set<unsigned int> others_selected;
1293 std::set<std::string> others_types;
1294 for (size_t k = 0; k < m_result.components.size(); ++k) {
1295 if (k == i) continue;
1296 unsigned int phys = m_result.components[k];
1297 others_selected.insert(phys);
1298 if (phys >= 1 && phys <= m_physical_types.size())
1299 others_types.insert(m_physical_types[phys - 1]);
1300 }
1301
1302 auto* combo = m_combo_filaments[i];
1303 combo->Clear();
1304 m_combo_to_physical[i].clear();
1305
1306 int restore_sel = -1;
1307 unsigned int cur_phys = (i < m_result.components.size()) ? m_result.components[i] : 0;
1308
1309 if (cur_phys == 0) {
1310 combo->Append(_L("-- Select --"));
1311 m_combo_to_physical[i].push_back(0);
1312 restore_sel = 0;
1313 }
1314
1315 for (size_t j = 0; j < m_physical_names.size(); ++j) {
1316 unsigned int phys_1based = (unsigned int)(j + 1);
1317
1318 if (others_selected.count(phys_1based))
1319 continue;
1320
1321 int style = 0;
1322 if (!others_types.empty() && !m_physical_types.empty()) {
1323 std::string this_type = (j < m_physical_types.size()) ? m_physical_types[j] : "PLA";
1324 if (others_types.find(this_type) == others_types.end())
1326 }
1327
1328 int idx = combo->Append(wxString::FromUTF8(m_physical_names[j]), make_swatch_bitmap(j), style);
1329 m_combo_to_physical[i].push_back(phys_1based);
1330
1331 if (phys_1based == cur_phys)
1332 restore_sel = idx;
1333 }
1334
1335 if (restore_sel >= 0)
1336 combo->SetSelection(restore_sel);
1337 else if (combo->GetCount() > 0)
1338 combo->SetSelection(0);
1339 }
1340}
#define DD_ITEM_STYLE_DIMMED
Definition DropDown.hpp:28
#define style
Definition WipeTowerDialog.cpp:101
wxBitmap make_swatch_bitmap(size_t idx)
Definition MixedFilamentDialog.cpp:244

References _L, DD_ITEM_STYLE_DIMMED, m_combo_filaments, m_combo_to_physical, m_physical_names, m_physical_types, m_result, make_swatch_bitmap(), rebuild_all_combos(), and style.

Referenced by build_ui(), on_add_material(), on_filament_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and rebuild_all_combos().

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

◆ rebuild_recommendation_items()

void Slic3r::GUI::MixedFilamentDialog::rebuild_recommendation_items ( )
private
1163{
1165 return;
1166
1167 static constexpr int MAX_RECOMMENDATIONS = 100;
1168
1169 m_recommendation_scroll->Freeze();
1170 m_recommendation_grid->Clear(true);
1171
1172 size_t n = m_physical_colors.size();
1173 int count = 0;
1174
1175 // Group physical filaments by type (only same-type combos are recommended)
1176 std::map<std::string, std::vector<size_t>> type_groups;
1177 for (size_t i = 0; i < n; ++i) {
1178 std::string t = (i < m_physical_types.size()) ? m_physical_types[i] : "PLA";
1179 // Skip support filaments (type ends with "-S")
1180 if (t.size() >= 2 && t.compare(t.size() - 2, 2, "-S") == 0)
1181 continue;
1182 type_groups[t].push_back(i);
1183 }
1184
1185 if (num_components() >= 3) {
1186 // Three-color: C(g,3) x 3 variants per same-type group
1187 for (auto& [type, indices] : type_groups) {
1188 if (count >= MAX_RECOMMENDATIONS) break;
1189 size_t g = indices.size();
1190 for (size_t ai = 0; ai < g && count < MAX_RECOMMENDATIONS; ++ai) {
1191 for (size_t bi = ai + 1; bi < g && count < MAX_RECOMMENDATIONS; ++bi) {
1192 for (size_t ci = bi + 1; ci < g && count < MAX_RECOMMENDATIONS; ++ci) {
1193 size_t idx[3] = {indices[ai], indices[bi], indices[ci]};
1194 // 3 variants: each filament takes the 50% role in turn
1195 for (int dominant = 0; dominant < 3 && count < MAX_RECOMMENDATIONS; ++dominant) {
1196 size_t i0 = idx[(dominant + 1) % 3]; // 25%
1197 size_t i1 = idx[(dominant + 2) % 3]; // 25%
1198 size_t i2 = idx[dominant]; // 50%
1199
1200 wxColour ca(m_physical_colors[i0]);
1201 wxColour cb(m_physical_colors[i1]);
1202 wxColour cc(m_physical_colors[i2]);
1203 wxColour mixed = blend_n_colors({ca, cb, cc}, {0.25, 0.25, 0.50});
1204
1205 auto* item = new wxPanel(m_recommendation_scroll, wxID_ANY,
1206 wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)));
1207 item->SetBackgroundColour(mixed);
1208 item->SetCursor(wxCursor(wxCURSOR_HAND));
1209
1210 unsigned int ca_1 = (unsigned int)(i0 + 1);
1211 unsigned int cb_1 = (unsigned int)(i1 + 1);
1212 unsigned int cc_1 = (unsigned int)(i2 + 1);
1213 item->Bind(wxEVT_LEFT_UP, [this, ca_1, cb_1, cc_1](wxMouseEvent&) {
1214 on_recommendation_clicked_triple(ca_1, cb_1, cc_1);
1215 });
1216 item->SetToolTip(wxString::Format(wxT("%s + %s + %s"),
1217 wxString::FromUTF8(m_physical_names[i0]),
1218 wxString::FromUTF8(m_physical_names[i1]),
1219 wxString::FromUTF8(m_physical_names[i2])));
1220
1221 m_recommendation_grid->Add(item, 0, wxRIGHT | wxBOTTOM, FromDIP(6));
1222 ++count;
1223 }
1224 }
1225 }
1226 }
1227 }
1228 } else {
1229 // Two-color: C(g,2) per same-type group
1230 for (auto& [type, indices] : type_groups) {
1231 if (count >= MAX_RECOMMENDATIONS) break;
1232 size_t g = indices.size();
1233 for (size_t ai = 0; ai < g && count < MAX_RECOMMENDATIONS; ++ai) {
1234 for (size_t bi = ai + 1; bi < g && count < MAX_RECOMMENDATIONS; ++bi) {
1235 size_t i = indices[ai];
1236 size_t j = indices[bi];
1237
1238 wxColour ca(m_physical_colors[i]);
1239 wxColour cb(m_physical_colors[j]);
1240 wxColour mixed = blend_colors(ca, cb, 0.5);
1241
1242 auto* item = new wxPanel(m_recommendation_scroll, wxID_ANY,
1243 wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)));
1244 item->SetBackgroundColour(mixed);
1245 item->SetCursor(wxCursor(wxCURSOR_HAND));
1246
1247 unsigned int comp_a = (unsigned int)(i + 1);
1248 unsigned int comp_b = (unsigned int)(j + 1);
1249 item->Bind(wxEVT_LEFT_UP, [this, comp_a, comp_b](wxMouseEvent&) {
1250 on_recommendation_clicked(comp_a, comp_b);
1251 });
1252 item->SetToolTip(wxString::Format(wxT("%s + %s"),
1253 wxString::FromUTF8(m_physical_names[i]),
1254 wxString::FromUTF8(m_physical_names[j])));
1255
1256 m_recommendation_grid->Add(item, 0, wxRIGHT | wxBOTTOM, FromDIP(6));
1257 ++count;
1258 }
1259 }
1260 }
1261 }
1262
1263 m_recommendation_scroll->SetScrollbars(0, FromDIP(20), 0, 1);
1264 m_recommendation_scroll->FitInside();
1265 m_recommendation_scroll->Layout();
1267}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
void on_recommendation_clicked(unsigned int comp_a, unsigned int comp_b)
Definition MixedFilamentDialog.cpp:1526
void on_recommendation_clicked_triple(unsigned int a, unsigned int b, unsigned int c)
Definition MixedFilamentDialog.cpp:1556
static wxColour blend_colors(const wxColour &a, const wxColour &b, double ratio_a)
Definition MixedFilamentDialog.cpp:130

References Slic3r::GUI::blend_colors(), Slic3r::GUI::blend_n_colors(), count, m_physical_colors, m_physical_names, m_physical_types, m_recommendation_grid, m_recommendation_scroll, num_components(), on_recommendation_clicked(), on_recommendation_clicked_triple(), rebuild_recommendation_items(), and Slic3r::GUI::wxMouseEvent.

Referenced by create_recommendation_grid(), on_add_material(), on_remove_material(), and rebuild_recommendation_items().

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

◆ refresh_curve_editor_colors()

void Slic3r::GUI::MixedFilamentDialog::refresh_curve_editor_colors ( )
private
1343{
1344 if (m_curve_editor)
1345 m_curve_editor->set_colors(comp_colour(0), comp_colour(1));
1346}

References comp_colour(), m_curve_editor, and refresh_curve_editor_colors().

Referenced by on_add_material(), on_filament_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and refresh_curve_editor_colors().

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

◆ refresh_ratio_labels()

void Slic3r::GUI::MixedFilamentDialog::refresh_ratio_labels ( )
private
322{
323 if (m_label_ratio_a)
324 m_label_ratio_a->SetLabel(wxString::Format(wxT("%d%%"), ratio(0)));
325 if (m_label_ratio_b)
326 m_label_ratio_b->SetLabel(wxString::Format(wxT("%d%%"), ratio(1)));
327 if (m_ratio_sizer)
328 m_ratio_sizer->Layout();
330 m_triangle_panel->Refresh();
331}

References m_label_ratio_a, m_label_ratio_b, m_ratio_sizer, m_triangle_panel, ratio(), and refresh_ratio_labels().

Referenced by apply_manual_ratio(), commit_ratio_editor(), on_ratio_changed(), on_recommendation_clicked(), on_remove_material(), and refresh_ratio_labels().

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

◆ rescale()

void Slic3r::GUI::DPIAware< wxDialog >::rescale ( const wxRect & suggested_rect)
inlineprivateinherited
265 {
266 this->Freeze();
267
268 m_force_rescale = false;
269
270 // set normal application font as a current window font
271 m_normal_font = this->GetFont();
272
274
275 // rescale missed controls sizes and images
277
278 this->Layout();
279 this->Thaw();
280
281 // reset previous scale factor from current scale factor value
283 }
virtual void on_dpi_changed(const wxRect &suggested_rect)=0
void update_em_unit()
Definition GUI_Utils.hpp:249

◆ reset_manual_ratio_state()

void Slic3r::GUI::MixedFilamentDialog::reset_manual_ratio_state ( )
private
309{
310 m_ratio_manual_order.clear();
312 m_ratio_editor_panel->Hide();
313 // Restore any label hidden by an in-flight editor so it can never be left
314 // permanently invisible if the editor is dismissed without a commit.
316 m_ratio_editor_anchor->Show();
317 m_ratio_editor_anchor = nullptr;
318 }
319}

References m_ratio_editor_anchor, m_ratio_editor_panel, m_ratio_manual_order, and reset_manual_ratio_state().

Referenced by apply_dragged_triangle_ratio(), apply_manual_ratio(), on_add_material(), on_ratio_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and reset_manual_ratio_state().

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

◆ scale_factor()

float Slic3r::GUI::DPIAware< wxDialog >::scale_factor ( ) const
inlineinherited
195{ return m_scale_factor; }

◆ set_em_unit()

void Slic3r::GUI::DPIAware< wxDialog >::set_em_unit ( int v)
inlineinherited
200{ m_em_unit = v; }

◆ set_prev_scale_factor()

void Slic3r::GUI::DPIAware< wxDialog >::set_prev_scale_factor ( float v)
inlineinherited

◆ set_scale_factor()

void Slic3r::GUI::DPIAware< wxDialog >::set_scale_factor ( float v)
inlineinherited
198{ m_scale_factor = v; }

◆ ShowModal()

◆ start_ratio_editor()

void Slic3r::GUI::MixedFilamentDialog::start_ratio_editor ( size_t idx,
wxWindow * anchor,
const wxRect & anchor_rect )
private
470{
471 if (!anchor || idx >= m_result.ratios.size())
472 return;
475
477 wxColour bg = StateColor::darkModeColorFor(wxColour("#F8F8F8"));
478 wxColour fg = StateColor::darkModeColorFor(wxColour("#262E30"));
479
480 m_ratio_editor_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition,
481 wxDefaultSize, wxBORDER_SIMPLE);
482 m_ratio_editor_panel->SetBackgroundColour(bg);
483
484 auto* hsizer = new wxBoxSizer(wxHORIZONTAL);
485
486 m_ratio_editor = new wxTextCtrl(m_ratio_editor_panel, wxID_ANY, wxEmptyString,
487 wxDefaultPosition, wxDefaultSize,
488 wxTE_PROCESS_ENTER | wxTE_RIGHT | wxBORDER_NONE);
490 m_ratio_editor->SetMaxLength(3);
491 m_ratio_editor->SetBackgroundColour(bg);
492 m_ratio_editor->SetForegroundColour(fg);
493 // Default wxTextCtrl best width (~140px) is too wide for the sizer to
494 // shrink, which would push the "%" suffix out of the panel. Size the
495 // editor for the *widest* three digits rather than the largest accepted
496 // value: SetMaxLength above lets anything up to "888" be typed, and the
497 // macOS system font renders digits at different advances, so "100" is
498 // narrower than what the user can actually enter. GetSizeFromTextSize()
499 // then adds the platform's own text field margins; on macOS those margins
500 // are what clipped the digits.
501 {
502 wxClientDC mdc(m_ratio_editor);
503 mdc.SetFont(::Label::Body_10);
504 int digits_w = mdc.GetTextExtent(wxT("888")).GetWidth();
505 m_ratio_editor->SetMinSize(m_ratio_editor->GetSizeFromTextSize(digits_w));
506 }
507
508 auto* pct_label = new wxStaticText(m_ratio_editor_panel, wxID_ANY, wxT("%"));
509 pct_label->SetFont(::Label::Body_10);
510 pct_label->SetForegroundColour(fg);
511 pct_label->SetBackgroundColour(bg);
512 pct_label->SetMinSize(pct_label->GetBestSize());
513
514 hsizer->Add(m_ratio_editor, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
515 hsizer->Add(pct_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(2));
516 m_ratio_editor_panel->SetSizer(hsizer);
517 m_ratio_editor_panel->Hide();
518
519 m_ratio_editor->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { commit_ratio_editor(true); });
520 m_ratio_editor->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) {
522 e.Skip();
523 });
524 m_ratio_editor->Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) {
525 if (e.GetKeyCode() == WXK_ESCAPE)
526 commit_ratio_editor(false);
527 else
528 e.Skip();
529 });
530 }
531
532 m_ratio_editor_idx = idx;
533
534 // Keep the editor in the same window hierarchy as the clicked label so the
535 // z-order is reliable and the editor fully covers the anchor (dual-color
536 // labels live on the dialog, triple-color labels live on the triangle
537 // panel).
538 wxWindow* target_parent = anchor->GetParent();
539 if (target_parent && m_ratio_editor_panel->GetParent() != target_parent)
540 m_ratio_editor_panel->Reparent(target_parent);
541
542 // Hide the label being edited to avoid its (hover-state) text leaking out
543 // next to the editor; restored on commit.
544 m_ratio_editor_anchor = anchor;
545 anchor->Hide();
546
547 wxPoint pos = anchor->GetPosition() + anchor_rect.GetTopLeft();
548 // Match the editor to the label (hover box) size so the inline editor and
549 // the hover state look identical, but never go below what the digits and
550 // the "%" suffix need: the sizer takes any missing width out of the
551 // stretchable editor, which would clip the value.
552 wxSize needed = m_ratio_editor_panel->ClientToWindowSize(
553 m_ratio_editor_panel->GetSizer()->CalcMin());
554 wxSize size = anchor->GetSize();
555 size.SetWidth(std::max(size.GetWidth(), needed.GetWidth()));
556 size.SetHeight(std::max(size.GetHeight(), needed.GetHeight()));
557 // An editor wider than the label must still stay inside its parent, or the
558 // corner labels of the triangle picker would have it clipped at the edge.
559 if (wxWindow* editor_parent = m_ratio_editor_panel->GetParent()) {
560 wxSize avail = editor_parent->GetClientSize();
561 pos.x = std::clamp(pos.x, 0, std::max(0, avail.GetWidth() - size.GetWidth()));
562 pos.y = std::clamp(pos.y, 0, std::max(0, avail.GetHeight() - size.GetHeight()));
563 }
564 m_ratio_editor_panel->SetSize(wxRect(pos, size));
565 m_ratio_editor_panel->Layout();
566 m_ratio_editor->SetValue(wxString::Format(wxT("%d"), ratio(idx)));
567 m_ratio_editor_panel->Show();
568 m_ratio_editor_panel->Raise();
569 m_ratio_editor->SetFocus();
570 m_ratio_editor->SelectAll();
571 m_ratio_editor_panel->Refresh();
572 Update();
573}
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References Label::Body_10, commit_ratio_editor(), StateColor::darkModeColorFor(), m_ratio_editor, m_ratio_editor_anchor, m_ratio_editor_idx, m_ratio_editor_panel, m_result, ratio(), start_ratio_editor(), and wxStaticText.

Referenced by create_ratio_slider(), create_triangle_picker(), and start_ratio_editor().

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

◆ sync_triangle_weights_from_ratios()

void Slic3r::GUI::MixedFilamentDialog::sync_triangle_weights_from_ratios ( )
private
334{
335 if (m_result.ratios.size() < 3)
336 return;
337
338 int sum = 0;
339 for (int r : m_result.ratios)
340 sum += r;
341 if (sum <= 0)
342 return;
343
344 m_tri_wx = (double)m_result.ratios[0] / sum;
345 m_tri_wy = (double)m_result.ratios[1] / sum;
346 m_tri_wz = (double)m_result.ratios[2] / sum;
347}

References m_result, m_tri_wx, m_tri_wy, m_tri_wz, and sync_triangle_weights_from_ratios().

Referenced by apply_dragged_triangle_ratio(), apply_manual_ratio(), and sync_triangle_weights_from_ratios().

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

◆ update_component_count_ui()

void Slic3r::GUI::MixedFilamentDialog::update_component_count_ui ( )
private
1798{
1799 bool is_two = (num_components() == 2);
1800 bool is_three = (num_components() >= 3);
1801
1802 // Toggle ratio slider vs triangle picker
1803 if (m_ratio_sizer)
1804 m_ratio_sizer->ShowItems(is_two && !m_result.gradient_enabled);
1805 if (m_triangle_sizer)
1806 m_triangle_sizer->ShowItems(is_three);
1807
1808 // 3-color: hide gradient entirely, force off
1809 if (m_gradient_sizer) {
1810 bool show_gradient = is_two;
1811 m_chk_gradient->Show(show_gradient);
1812 if (m_label_gradient) m_label_gradient->Show(show_gradient);
1813 m_combo_gradient_dir->Show(show_gradient && m_result.gradient_enabled);
1815 m_per_part_gradient_sizer->ShowItems(show_gradient && m_result.gradient_enabled);
1816 if (m_curve_sizer)
1817 m_curve_sizer->ShowItems(show_gradient && m_result.gradient_enabled);
1818 }
1819 if (is_three) {
1820 m_result.gradient_enabled = false;
1821 if (m_chk_gradient) m_chk_gradient->SetValue(false);
1822 m_result.per_part_gradient = false;
1824 }
1825
1826 if (m_btn_add_material) {
1827 bool can_add = (num_components() < (size_t)MAX_COMPONENTS && m_physical_colors.size() > num_components());
1828 m_btn_add_material->Enable(can_add);
1829 m_btn_add_material->SetToolTip(can_add ? wxString()
1830 : (is_three ? _L("Maximum 3 materials for mixing") : _L("Maximum number of components reached")));
1831 }
1832
1834 m_btn_remove_material->Show(is_three);
1835 m_btn_remove_material->Enable(is_three);
1836 m_btn_remove_material->SetToolTip(is_three ? _L("Remove the third material") : wxString());
1837 }
1838
1839 const wxSize new_size = compute_dialog_size();
1840 const wxRect old_rect = GetRect();
1841 const wxPoint center(old_rect.x + old_rect.width / 2,
1842 old_rect.y + old_rect.height / 2);
1843 SetSize(new_size);
1844 SetPosition(wxPoint(center.x - new_size.x / 2,
1845 center.y - new_size.y / 2));
1846 Layout();
1847}

References _L, Slic3r::center(), compute_dialog_size(), m_btn_add_material, m_btn_remove_material, m_chk_gradient, m_chk_per_part_gradient, m_combo_gradient_dir, m_curve_sizer, m_gradient_sizer, m_label_gradient, m_per_part_gradient_sizer, m_physical_colors, m_ratio_sizer, m_result, m_triangle_sizer, Slic3r::GUI::MAX_COMPONENTS, num_components(), and update_component_count_ui().

Referenced by build_ui(), on_add_material(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and update_component_count_ui().

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

◆ update_em_unit()

void Slic3r::GUI::DPIAware< wxDialog >::update_em_unit ( )
inlineprivateinherited
250 {
251 // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3).
252 // So, calculate the m_em_unit value from the font size, as before
253#if !defined(__WXGTK__)
255#else
256 // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window.
257 m_em_unit = std::max<size_t>(10, this->GetTextExtent("m").x - 1);
258#endif // __WXGTK__
259 }

◆ update_gradient_direction_items()

void Slic3r::GUI::MixedFilamentDialog::update_gradient_direction_items ( )
private
1721{
1722 if (!m_combo_gradient_dir) return;
1723
1724 int prev_sel = m_combo_gradient_dir->GetSelection();
1725 m_combo_gradient_dir->Clear();
1726
1727 if (num_components() < 2) return;
1728
1729 auto make_direction_bitmap = [this](size_t idx_from, size_t idx_to) -> wxBitmap {
1730 int swatch_sz = FromDIP(20);
1731 int arrow_w = FromDIP(16);
1732 int gap = FromDIP(4);
1733 int bmp_w = swatch_sz + gap + arrow_w + gap + swatch_sz;
1734 int bmp_h = swatch_sz;
1735
1736 wxColour dir_text = StateColor::darkModeColorFor(wxColour("#262E30"));
1737
1738 return make_alpha_bitmap(bmp_w, bmp_h, [&](wxDC& dc) {
1739 dc.SetFont(::Label::Body_13);
1740
1741 auto draw_swatch = [&](int x, size_t idx) {
1742 std::string color_hex = "#D9D9D9";
1743 if (idx < m_physical_colors.size())
1744 color_hex = m_physical_colors[idx];
1745 std::string label = std::to_string(idx + 1);
1746 wxBitmap* icon = get_extruder_color_icon(color_hex, label, swatch_sz, swatch_sz);
1747 if (icon && icon->IsOk())
1748 dc.DrawBitmap(*icon, x, 0);
1749 };
1750
1751 int x = 0;
1752 draw_swatch(x, idx_from);
1753 x += swatch_sz + gap;
1754
1755 dc.SetTextForeground(dir_text);
1756 wxString arrow = wxT("\u2192");
1757 wxSize arrow_sz = dc.GetTextExtent(arrow);
1758 dc.DrawText(arrow, x + (arrow_w - arrow_sz.GetWidth()) / 2,
1759 (bmp_h - arrow_sz.GetHeight()) / 2);
1760 x += arrow_w + gap;
1761
1762 draw_swatch(x, idx_to);
1763 });
1764 };
1765
1766 size_t idx_a = (comp(0) >= 1) ? comp(0) - 1 : 0;
1767 size_t idx_b = (comp(1) >= 1) ? comp(1) - 1 : 1;
1768
1769 m_combo_gradient_dir->Append(wxT(" "), make_direction_bitmap(idx_a, idx_b));
1770 m_combo_gradient_dir->Append(wxT(" "), make_direction_bitmap(idx_b, idx_a));
1771
1772 if (prev_sel >= 0 && prev_sel < (int)m_combo_gradient_dir->GetCount())
1773 m_combo_gradient_dir->SetSelection(prev_sel);
1774 else
1775 m_combo_gradient_dir->SetSelection(0);
1776}

References Label::Body_13, comp(), StateColor::darkModeColorFor(), get_extruder_color_icon(), m_combo_gradient_dir, m_physical_colors, Slic3r::GUI::make_alpha_bitmap(), num_components(), and update_gradient_direction_items().

Referenced by create_gradient_section(), on_filament_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), and update_gradient_direction_items().

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

◆ update_ok_button_state()

void Slic3r::GUI::MixedFilamentDialog::update_ok_button_state ( )
private
1663{
1664 if (!m_btn_ok) return;
1665
1666 bool has_type_mismatch = false;
1667 if (!m_physical_types.empty() && m_result.components.size() >= 2) {
1668 std::map<std::string, std::vector<unsigned int>> type_groups;
1669 for (size_t i = 0; i < m_result.components.size(); ++i) {
1670 unsigned int phys = m_result.components[i];
1671 if (phys < 1 || phys > m_physical_types.size()) continue;
1672 type_groups[m_physical_types[phys - 1]].push_back(phys);
1673 }
1674 has_type_mismatch = type_groups.size() > 1;
1675 if (has_type_mismatch) {
1676 wxString parts;
1677 for (auto it = type_groups.begin(); it != type_groups.end(); ++it) {
1678 if (!parts.empty())
1679 parts += "; ";
1680 wxString slots;
1681 for (size_t j = 0; j < it->second.size(); ++j) {
1682 if (!slots.empty()) slots += ", ";
1683 slots += std::to_string(it->second[j]);
1684 }
1685 parts += wxString::Format(_L("Slot %s (%s)"), slots, wxString::FromUTF8(it->first));
1686 }
1687 m_type_mismatch_msg = wxString::Format(_L("Different filament types cannot be mixed: %s. Please select the same filament type."), parts);
1688 } else {
1689 m_type_mismatch_msg.clear();
1690 }
1691 } else {
1692 m_type_mismatch_msg.clear();
1693 }
1694
1695 bool has_unselected = false;
1696 for (unsigned int c : m_result.components) {
1697 if (c == 0) { has_unselected = true; break; }
1698 }
1699
1700 bool can_confirm = !has_type_mismatch && !has_unselected;
1701 // Enable() alone repaints the button: its StateColor carries the disabled grey.
1702 m_btn_ok->Enable(can_confirm);
1703 if (has_unselected)
1704 m_btn_ok->SetToolTip(_L("Please select a filament for all components"));
1705 else if (has_type_mismatch)
1706 m_btn_ok->SetToolTip(_L("Cannot mix different filament types"));
1707 else
1708 m_btn_ok->SetToolTip(wxEmptyString);
1709
1710 if (m_warning_panel) {
1711 m_warning_panel->Show(has_type_mismatch);
1712 // Force a repaint: when the panel is already visible and only the
1713 // mismatch text changes (e.g. PETG -> ABS), Show()/Layout() do not
1714 // generate a paint event, so paint_warning_panel keeps the stale text.
1715 m_warning_panel->Refresh();
1716 Layout();
1717 }
1718}

References _L, m_btn_ok, m_physical_types, m_result, m_type_mismatch_msg, m_warning_panel, and update_ok_button_state().

Referenced by build_ui(), on_add_material(), on_filament_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and update_ok_button_state().

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

◆ update_preview()

void Slic3r::GUI::MixedFilamentDialog::update_preview ( )
private
1594{
1595 if (m_preview_canvas) m_preview_canvas->Refresh();
1596 if (m_summary_panel) m_summary_panel->Refresh();
1597 if (m_ratio_bar) m_ratio_bar->Refresh();
1598 if (m_triangle_panel) m_triangle_panel->Refresh();
1599}

References m_preview_canvas, m_ratio_bar, m_summary_panel, m_triangle_panel, and update_preview().

Referenced by apply_dragged_triangle_ratio(), apply_manual_ratio(), build_ui(), on_add_material(), on_filament_changed(), on_gradient_curve_changed(), on_gradient_direction_changed(), on_ratio_changed(), on_recommendation_clicked(), on_recommendation_clicked_triple(), on_remove_material(), and update_preview().

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

Member Data Documentation

◆ m_btn_add_material

Button* Slic3r::GUI::MixedFilamentDialog::m_btn_add_material {nullptr}
private
152{nullptr};

Referenced by create_material_selection(), and update_component_count_ui().

◆ m_btn_cancel

Button* Slic3r::GUI::MixedFilamentDialog::m_btn_cancel {nullptr}
private
155{nullptr};

Referenced by create_button_panel().

◆ m_btn_ok

Button* Slic3r::GUI::MixedFilamentDialog::m_btn_ok {nullptr}
private
154{nullptr};

Referenced by create_button_panel(), and update_ok_button_state().

◆ m_btn_remove_material

Button* Slic3r::GUI::MixedFilamentDialog::m_btn_remove_material {nullptr}
private
153{nullptr};

Referenced by create_material_selection(), and update_component_count_ui().

◆ m_can_rescale

bool Slic3r::GUI::DPIAware< wxDialog >::m_can_rescale
privateinherited
235{ true };

◆ m_chk_gradient

CheckBox* Slic3r::GUI::MixedFilamentDialog::m_chk_gradient {nullptr}
private

◆ m_chk_per_part_gradient

CheckBox* Slic3r::GUI::MixedFilamentDialog::m_chk_per_part_gradient {nullptr}
private

◆ m_combo_filaments

◆ m_combo_gradient_dir

ComboBox* Slic3r::GUI::MixedFilamentDialog::m_combo_gradient_dir {nullptr}
private

◆ m_combo_to_physical

std::vector<std::vector<unsigned int> > Slic3r::GUI::MixedFilamentDialog::m_combo_to_physical
private

◆ m_curve_editor

GradientCurveEditor* Slic3r::GUI::MixedFilamentDialog::m_curve_editor {nullptr}
private

◆ m_curve_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_curve_sizer {nullptr}
private

◆ m_em_unit

int Slic3r::GUI::DPIAware< wxDialog >::m_em_unit
privateinherited

◆ m_force_rescale

bool Slic3r::GUI::DPIAware< wxDialog >::m_force_rescale
privateinherited
236{ false };

◆ m_gradient_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_gradient_sizer {nullptr}
private
146{nullptr};

Referenced by create_gradient_section(), and update_component_count_ui().

◆ m_label_gradient

wxStaticText* Slic3r::GUI::MixedFilamentDialog::m_label_gradient {nullptr}
private
144{nullptr};

Referenced by create_gradient_section(), and update_component_count_ui().

◆ m_label_per_part_gradient

wxStaticText* Slic3r::GUI::MixedFilamentDialog::m_label_per_part_gradient {nullptr}
private
150{nullptr};

Referenced by create_gradient_section().

◆ m_label_ratio_a

RatioLabelPanel* Slic3r::GUI::MixedFilamentDialog::m_label_ratio_a {nullptr}
private
139{nullptr};

Referenced by create_ratio_slider(), and refresh_ratio_labels().

◆ m_label_ratio_b

RatioLabelPanel* Slic3r::GUI::MixedFilamentDialog::m_label_ratio_b {nullptr}
private
140{nullptr};

Referenced by create_ratio_slider(), and refresh_ratio_labels().

◆ m_material_rows_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_material_rows_sizer {nullptr}
private

◆ m_new_font_point_size

int Slic3r::GUI::DPIAware< wxDialog >::m_new_font_point_size
privateinherited

◆ m_normal_font

wxFont Slic3r::GUI::DPIAware< wxDialog >::m_normal_font
privateinherited

◆ m_per_part_gradient_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_per_part_gradient_sizer {nullptr}
private

◆ m_physical_colors

◆ m_physical_names

std::vector<std::string> Slic3r::GUI::MixedFilamentDialog::m_physical_names
private

◆ m_physical_types

std::vector<std::string> Slic3r::GUI::MixedFilamentDialog::m_physical_types
private

◆ m_prev_scale_factor

float Slic3r::GUI::DPIAware< wxDialog >::m_prev_scale_factor
privateinherited

◆ m_preview_canvas

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_preview_canvas {nullptr}
private
133{nullptr};

Referenced by create_preview_panel(), and update_preview().

◆ m_ratio_bar

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_ratio_bar {nullptr}
private

◆ m_ratio_dragging

bool Slic3r::GUI::MixedFilamentDialog::m_ratio_dragging {false}
private
169{false};

Referenced by create_ratio_slider().

◆ m_ratio_editor

wxTextCtrl* Slic3r::GUI::MixedFilamentDialog::m_ratio_editor {nullptr}
private
142{nullptr};

Referenced by commit_ratio_editor(), and start_ratio_editor().

◆ m_ratio_editor_anchor

wxWindow* Slic3r::GUI::MixedFilamentDialog::m_ratio_editor_anchor {nullptr}
private

◆ m_ratio_editor_committing

bool Slic3r::GUI::MixedFilamentDialog::m_ratio_editor_committing {false}
private
173{false};

Referenced by commit_ratio_editor().

◆ m_ratio_editor_idx

size_t Slic3r::GUI::MixedFilamentDialog::m_ratio_editor_idx {0}
private
172{0};

Referenced by commit_ratio_editor(), and start_ratio_editor().

◆ m_ratio_editor_panel

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_ratio_editor_panel {nullptr}
private

◆ m_ratio_manual_order

std::vector<size_t> Slic3r::GUI::MixedFilamentDialog::m_ratio_manual_order
private

◆ m_ratio_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_ratio_sizer {nullptr}
private

◆ m_recommendation_grid

wxWrapSizer* Slic3r::GUI::MixedFilamentDialog::m_recommendation_grid {nullptr}
private

◆ m_recommendation_scroll

wxScrolledWindow* Slic3r::GUI::MixedFilamentDialog::m_recommendation_scroll {nullptr}
private

◆ m_result

◆ m_right_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_right_sizer {nullptr}
private
161{nullptr};

Referenced by build_ui().

◆ m_scale_factor

float Slic3r::GUI::DPIAware< wxDialog >::m_scale_factor
privateinherited

◆ m_summary_panel

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_summary_panel {nullptr}
private
134{nullptr};

Referenced by create_material_selection(), and update_preview().

◆ m_tri_dragging

bool Slic3r::GUI::MixedFilamentDialog::m_tri_dragging {false}
private
170{false};

Referenced by create_triangle_picker().

◆ m_tri_wx

double Slic3r::GUI::MixedFilamentDialog::m_tri_wx {0.333}
private

◆ m_tri_wy

double Slic3r::GUI::MixedFilamentDialog::m_tri_wy {0.333}
private

◆ m_tri_wz

double Slic3r::GUI::MixedFilamentDialog::m_tri_wz {0.334}
private

◆ m_triangle_panel

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_triangle_panel {nullptr}
private

◆ m_triangle_ratio_labels

std::array<RatioLabelPanel*, 3> Slic3r::GUI::MixedFilamentDialog::m_triangle_ratio_labels {nullptr, nullptr, nullptr}
private
178{nullptr, nullptr, nullptr};

Referenced by create_triangle_picker().

◆ m_triangle_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_triangle_sizer {nullptr}
private
160{nullptr};

Referenced by build_ui(), and update_component_count_ui().

◆ m_type_mismatch_msg

wxString Slic3r::GUI::MixedFilamentDialog::m_type_mismatch_msg
private

◆ m_warning_panel

wxPanel* Slic3r::GUI::MixedFilamentDialog::m_warning_panel {nullptr}
private
157{nullptr};

Referenced by build_ui(), paint_warning_panel(), and update_ok_button_state().

◆ m_warning_sizer

wxBoxSizer* Slic3r::GUI::MixedFilamentDialog::m_warning_sizer {nullptr}
private
156{nullptr};

Referenced by build_ui().


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