mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-14 03:11:19 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df38b0351d |
@@ -570,6 +570,11 @@ Details [source] (`Widgets/PopupWindow.cpp`).
|
||||
- On GTK the sub binds an idle handler. While both are shown and the cursor is over main but not over the
|
||||
sub, it builds a `wxMouseEvent(wxEVT_MOTION)` from `wxGetMousePosition()`, calls `mainDropDown->mouseMove(ev)`
|
||||
**directly** (nothing is posted), and calls `e.RequestMore()` to keep polling.
|
||||
- On GTK the sub also receives the wheel events the user raises over main: GDK sends a `wl_pointer.axis` only
|
||||
to the surface the pointer is over, and GTK then hands that `GDK_SCROLL` to the chain's grab widget, which is
|
||||
the sub. The sub installs a `GtkWidget::event` handler that replays the event on main with
|
||||
`gtk_propagate_event(main->GetConnectWidget(), event)` when the event's GDK window belongs to main
|
||||
(`DropDown::messureSize`).
|
||||
- **GTK wrapper sizing.** `messureSize` calls `gtk_window_resize` on `m_widget` after `SetSize`, because wxGTK's
|
||||
`DoSetSize` only uses `gtk_widget_set_size_request` ("gtk_window_resize does not work for GTK_WINDOW_POPUP",
|
||||
`src/gtk/popupwin.cpp:181-188`).
|
||||
@@ -607,6 +612,32 @@ Details [source] (`Widgets/PopupWindow.cpp`).
|
||||
```
|
||||
Cite: c0ae2bda99, b9ff15054f (`DropDown::mouseMove`, `DropDown::messureSize`, `DropDown::ShouldDismissOnTopWindowDeactivate`,
|
||||
`PopupWindow::ShouldDismissOnTopWindowDeactivate`).
|
||||
- **Rule:** On GTK, route a chained popup's wheel event by the GDK window it names, not by the grab widget and not
|
||||
by the global cursor position.
|
||||
**Why:** While the sub holds the grab, `gtk_main_do_event` hands every `GDK_SCROLL` of the chain to the grab
|
||||
widget (the sub) with its original, un-rebased coordinates [source] (`gtkmain.c:1789-1792`, 1923-1924), while
|
||||
GDK Wayland sends the axis to the surface under the pointer only (`pointer_handle_axis` → `create_scroll_event`,
|
||||
`gdkdevice-wayland.c:1929, 1527`). The sub therefore sees and consumes wheel events raised over main, so the
|
||||
main list never scrolls, on X11 and Wayland alike. A hit test against `wxGetMousePosition()` cannot replace the
|
||||
window test: global coordinates are unreliable on Wayland (`mouse-keyboard-focus.md`). `DropDown` connects a
|
||||
`GtkWidget::event` handler on the sub's `GtkWindow` (its `m_widget`), which is emitted before wx's
|
||||
`::scroll-event` handler on the same widget and suppresses it when it returns TRUE (`gtkwidget.c:7696`), then
|
||||
delivers the event with `gtk_propagate_event(main->GetConnectWidget(), event)`. Returning TRUE there also stops
|
||||
the parent-chain propagation.
|
||||
```cpp
|
||||
// Wrong: emitted on the popup's outer GtkWindow, where wx has no handlers at all
|
||||
g_signal_emit_by_name(main->m_widget, "scroll-event", event, &handled);
|
||||
// Right (wxGTK): replay GTK's own delivery on the widget wx listens to
|
||||
gtk_propagate_event(main->GetConnectWidget(), event);
|
||||
```
|
||||
**Where wx listens [source].** `wxPopupWindow::Create` builds a popup from two widgets: `m_widget` is the outer
|
||||
`GtkWindow` and `m_wxwindow` is a `wxPizza` child added to it. `wxWindowGTK::GetConnectWidget()` is
|
||||
`m_wxwindow ? m_wxwindow : m_widget`, and `ConnectWidget()` — which binds `button_press_event`, `motion_notify_event`
|
||||
and `scroll_event` — is called on that widget (`src/gtk/window.cpp` `Create`, `GetConnectWidget`). A signal emitted
|
||||
on the outer `GtkWindow` therefore reaches no wx handler; only events GTK delivers to the inner widget, or to a
|
||||
descendant of the grab widget, are seen by wx. `GTKGetConnectWindow()`/`GTKGetMainWindow()` are the matching
|
||||
GdkWindows.
|
||||
Cite: `DropDown::messureSize`, `DropDown::mouseWheelMoved`.
|
||||
- **Rule:** When shrinking a dropdown to fit above the display bottom, give up if fewer than two rows would
|
||||
remain.
|
||||
**Why:** On Wayland the popup can land where almost no vertical space is left. Clamping to that sliver made an
|
||||
|
||||
@@ -2602,13 +2602,12 @@ void GCodeProcessorResult::reset() {
|
||||
//BBS: add mutex for protection of gcode result
|
||||
lock();
|
||||
|
||||
// moves and lines_ends grow with the print: free them, as no reset result reuses the capacity.
|
||||
clear_and_shrink(moves);
|
||||
moves.clear();
|
||||
plate_mass = {};
|
||||
object_masses.clear();
|
||||
body_masses.clear();
|
||||
support_masses.clear();
|
||||
clear_and_shrink(lines_ends);
|
||||
lines_ends.clear();
|
||||
printable_area = Pointfs();
|
||||
//BBS: add bed exclude area
|
||||
bed_exclude_area = Pointfs();
|
||||
|
||||
@@ -3905,8 +3905,14 @@ void PresetBundle::export_selections(AppConfig &config)
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": printer %1%, print %2%, filaments[0] %3% ")%printers.get_selected_preset_name() % prints.get_selected_preset_name() %filament_presets[0];
|
||||
}
|
||||
|
||||
size_t PresetBundle::resize_project_filament_slots(size_t n)
|
||||
void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
||||
{
|
||||
unsigned old_filament_count = this->filament_presets.size();
|
||||
if (n > old_filament_count && old_filament_count != 0)
|
||||
filament_presets.resize(n, filament_presets.back());
|
||||
else {
|
||||
filament_presets.resize(n);
|
||||
}
|
||||
ConfigOptionStrings* filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
@@ -3932,25 +3938,9 @@ size_t PresetBundle::resize_project_filament_slots(size_t n)
|
||||
ams_multi_color_filment.resize(n);
|
||||
|
||||
resize_mixed_filament_metadata(project_config, old_slot_count, n);
|
||||
return old_slot_count;
|
||||
}
|
||||
|
||||
void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
||||
{
|
||||
unsigned old_filament_count = this->filament_presets.size();
|
||||
if (n > old_filament_count && old_filament_count != 0)
|
||||
filament_presets.resize(n, filament_presets.back());
|
||||
else {
|
||||
filament_presets.resize(n);
|
||||
}
|
||||
|
||||
const size_t old_slot_count = resize_project_filament_slots(n);
|
||||
|
||||
//BBS set new filament color to new_color
|
||||
if (!new_color.empty()) {
|
||||
ConfigOptionStrings* filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
for (size_t i = old_slot_count; i < n; i++) {
|
||||
filament_color->values[i] = new_color;
|
||||
filament_multi_color->values[i] = new_color;
|
||||
@@ -5387,23 +5377,6 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
|
||||
add_if_some_non_empty(std::move(print_compatible_printers), "print_compatible_printers");
|
||||
out.option<ConfigOptionStrings>("extruder_ams_count", true)->values = save_extruder_ams_count_to_string(this->extruder_ams_counts);
|
||||
|
||||
// The slice config is consumed by code that indexes per-slot arrays by material id
|
||||
// (MultiMaterialSegmentation sizes its state count from filament_colour). After the
|
||||
// producer-side lockstep in update_multi_material_filament_presets() these project-scoped
|
||||
// arrays are expected to be exactly num_filaments; the property the pipeline relies on is
|
||||
// that none is shorter (a short filament_colour was the OOB in #16432). Pad if needed.
|
||||
for (const char* per_slot_key : { "filament_colour", "filament_colour_type", "filament_multi_colour" }) {
|
||||
auto* per_slot_opt = dynamic_cast<ConfigOptionVectorBase*>(out.option(per_slot_key, true));
|
||||
if (per_slot_opt == nullptr)
|
||||
continue;
|
||||
if (per_slot_opt->size() < num_filaments) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "full_fff_config: per-slot array " << per_slot_key
|
||||
<< " has " << per_slot_opt->size() << " entries, padding to num_filaments=" << num_filaments;
|
||||
per_slot_opt->resize(num_filaments, FullPrintConfig::defaults().option(per_slot_key));
|
||||
}
|
||||
assert(per_slot_opt->size() >= num_filaments);
|
||||
}
|
||||
|
||||
out.option<ConfigOptionEnumGeneric>("printer_technology", true)->value = ptFFF;
|
||||
return out;
|
||||
}
|
||||
@@ -7938,15 +7911,6 @@ void PresetBundle::update_multi_material_filament_presets(size_t to_delete_filam
|
||||
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name :
|
||||
this->filament_presets.back());
|
||||
num_filaments = this->filament_presets.size();
|
||||
|
||||
// Keep the project-scoped per-slot arrays in lockstep with the padded preset list, so
|
||||
// consumers that size from filament_colour (MultiMaterialSegmentation) agree with those
|
||||
// that size from the preset list / filament_diameter (PrintObjectSlice). Grow only: a
|
||||
// colour array longer than the preset list is a valid state (a project with more slots
|
||||
// than nozzles) and must not be truncated here.
|
||||
const auto* filament_colour = this->project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
if (filament_colour == nullptr || filament_colour->values.size() < num_filaments)
|
||||
this->resize_project_filament_slots(num_filaments);
|
||||
}
|
||||
if (to_delete_filament_id == -1)
|
||||
to_delete_filament_id = num_filaments;
|
||||
|
||||
@@ -394,12 +394,6 @@ public:
|
||||
// slots live. A caller adding physical filaments has to add num_mixed_filaments() on top and
|
||||
// then move the new slots ahead of the mixed tail, as Sidebar::add_custom_filament does.
|
||||
void set_num_filaments(unsigned int n, std::string new_col = "");
|
||||
// Grow or shrink the project-scoped per-slot arrays (filament_colour, filament_colour_type,
|
||||
// filament_multi_colour, the filament maps and the mixed metadata) to n, without touching
|
||||
// filament_presets and without rebuilding flush volumes. Callers that resize filament_presets
|
||||
// must keep these arrays in lockstep with it. Returns the array size before the resize so the
|
||||
// caller can seed the new tail.
|
||||
size_t resize_project_filament_slots(size_t n);
|
||||
void update_num_filaments(unsigned int to_del_flament_id);
|
||||
|
||||
void get_ams_cobox_infos(AMSComboInfo &combox_info);
|
||||
|
||||
@@ -1073,14 +1073,8 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
|
||||
const auto &layer_ranges = print_object.shared_regions()->layer_ranges;
|
||||
double z = print_object.get_layer(int(range.begin()))->slice_z;
|
||||
auto it_layer_range = layer_range_first(layer_ranges, z);
|
||||
// The per-layer row width of the segmentation is the number of material channels it
|
||||
// was built with (filament_colour.size()). Size the bound from the data itself rather
|
||||
// than from filament_diameter.size(): those two arrays can diverge (the project's
|
||||
// colour array can end up shorter than the padded preset list), and trusting the
|
||||
// larger count reads past the end of every row.
|
||||
// BBS
|
||||
const size_t num_extruders = segmentation.empty() ? 0 : segmentation.front().size();
|
||||
assert(num_extruders == print_object.print()->config().filament_diameter.size());
|
||||
const size_t num_extruders = print_object.print()->config().filament_diameter.size();
|
||||
|
||||
struct ByExtruder {
|
||||
ExPolygons expolygons;
|
||||
@@ -1103,8 +1097,7 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance
|
||||
by_extruder.assign(num_extruders, ByExtruder());
|
||||
by_region.assign(layer.region_count(), ByRegion());
|
||||
bool layer_split = false;
|
||||
const size_t layer_channels = segmentation[layer_id].size();
|
||||
for (size_t extruder_id = 0; extruder_id < std::min(num_extruders, layer_channels); ++ extruder_id) {
|
||||
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
|
||||
ByExtruder ®ion = by_extruder[extruder_id];
|
||||
append(region.expolygons, std::move(segmentation[layer_id][extruder_id]));
|
||||
if (! region.expolygons.empty()) {
|
||||
|
||||
@@ -927,17 +927,15 @@ void ViewerImpl::reset()
|
||||
m_used_extruders.clear();
|
||||
m_total_time = { 0.0f, 0.0f };
|
||||
m_travels_time = { 0.0f, 0.0f };
|
||||
m_vertices.clear();
|
||||
m_vertices_colors.clear();
|
||||
// swap rather than clear: these are sized by the print, and a reset means the memory
|
||||
// should go back, not sit reserved until the next load
|
||||
std::vector<PathVertex>().swap(m_vertices);
|
||||
std::vector<float>().swap(m_vertices_colors);
|
||||
for (std::vector<float>& times : m_layer_start_times)
|
||||
std::vector<float>().swap(times);
|
||||
std::vector<uint32_t>().swap(m_layer_first_vertex);
|
||||
m_layers_in_vertex_order = false;
|
||||
// BitSet::clear() only zeroes the bits, it keeps the blocks allocated; load() builds a new
|
||||
// bitset anyway and it is never read while m_vertices is empty
|
||||
m_valid_lines_bitset = BitSet<>();
|
||||
m_valid_lines_bitset.clear();
|
||||
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
m_cog_marker.reset();
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
@@ -1836,7 +1834,6 @@ size_t ViewerImpl::get_used_cpu_memory() const
|
||||
ret += sizeof(m_extrusion_roles_colors);
|
||||
ret += sizeof(m_options_colors);
|
||||
ret += STDVEC_MEMSIZE(m_vertices, PathVertex);
|
||||
ret += STDVEC_MEMSIZE(m_vertices_colors, float);
|
||||
for (const std::vector<float>& times : m_layer_start_times)
|
||||
ret += STDVEC_MEMSIZE(times, float);
|
||||
ret += STDVEC_MEMSIZE(m_layer_first_vertex, uint32_t);
|
||||
|
||||
@@ -1610,12 +1610,6 @@ void PlaterPresetComboBox::show_default_color_picker()
|
||||
{
|
||||
DynamicPrintConfig* cfg = &wxGetApp().preset_bundle->project_config;
|
||||
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour")->clone());
|
||||
// The combo can outlive the project's colour array (e.g. a slot padded onto the printer's
|
||||
// nozzle count); guard before indexing so a stale slot index cannot read past the end.
|
||||
if (m_filament_idx < 0 || m_filament_idx >= static_cast<int>(colors->values.size())) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": m_filament_idx %1% out of range %2%") % m_filament_idx % colors->values.size();
|
||||
return;
|
||||
}
|
||||
wxColour current_clr(colors->values[m_filament_idx]);
|
||||
if (!current_clr.IsOk())
|
||||
current_clr = wxColour(0, 0, 0); // Don't set alfa to transparence
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/window.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
@@ -665,6 +666,35 @@ void DropDown::messureSize()
|
||||
sub->mainDropDown->mouseMove(ev);
|
||||
e.RequestMore();
|
||||
});
|
||||
// Orca: the submenu holds the GTK grab, so GTK gives it the wheel events of the whole
|
||||
// chain. GDK names the window under the cursor, so re-emit main's events on main.
|
||||
g_signal_connect(sub->m_widget, "event", G_CALLBACK(+[](GtkWidget *, GdkEvent *event, gpointer data) -> gboolean {
|
||||
auto *sub = static_cast<DropDown *>(data);
|
||||
DropDown *main = sub->mainDropDown;
|
||||
if (event->type != GDK_SCROLL || !main || !main->IsShown() || !sub->IsShown())
|
||||
return FALSE;
|
||||
gpointer owner = nullptr;
|
||||
if (event->any.window)
|
||||
gdk_window_get_user_data(event->any.window, &owner);
|
||||
GtkWidget *widget = (owner && GTK_IS_WIDGET(owner)) ? GTK_WIDGET(owner) : nullptr;
|
||||
bool for_main = widget && (widget == main->m_widget || gtk_widget_is_ancestor(widget, main->m_widget));
|
||||
bool for_sub = widget && (widget == sub->m_widget || gtk_widget_is_ancestor(widget, sub->m_widget));
|
||||
if (!for_main && for_sub) {
|
||||
// The compositor may keep the pointer focus on the submenu while the cursor is over main.
|
||||
wxPoint pt((int) event->scroll.x, (int) event->scroll.y);
|
||||
if (sub->GetClientRect().Contains(pt))
|
||||
return FALSE;
|
||||
wxPoint off = sub->GetScreenRect().GetTopLeft() - main->GetScreenRect().GetTopLeft();
|
||||
event->scroll.x += off.x;
|
||||
event->scroll.y += off.y;
|
||||
for_main = true;
|
||||
}
|
||||
if (!for_main)
|
||||
return FALSE;
|
||||
// wx connects its mouse handlers to GetConnectWidget(), the inner widget of the popup.
|
||||
gtk_propagate_event(main->GetConnectWidget(), event);
|
||||
return TRUE;
|
||||
}), sub);
|
||||
#endif
|
||||
subDropDown->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) {
|
||||
e.SetEventObject(this);
|
||||
|
||||
Reference in New Issue
Block a user