diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index a0eef72fea..9f7094700d 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -159,7 +159,61 @@ sub new { } } }; + + # callbacks for toolbar + my $on_action_add = sub { + $self->add; + }; + + my $on_action_delete = sub { + $self->remove(); + }; + + my $on_action_deleteall = sub { + $self->reset; + }; + + my $on_action_arrange = sub { + $self->arrange; + }; + + my $on_action_more = sub { + $self->increase; + }; + + my $on_action_fewer = sub { + $self->decrease; + }; + + my $on_action_ccw45 = sub { + $self->rotate(45, Z, 'relative'); + }; + + my $on_action_cw45 = sub { + $self->rotate(-45, Z, 'relative'); + }; + + my $on_action_scale = sub { + $self->changescale(undef); + }; + + my $on_action_split = sub { + $self->split_object; + }; + my $on_action_cut = sub { + $self->object_cut_dialog; + }; + + my $on_action_settings = sub { + $self->object_settings_dialog; + }; + + my $on_action_layersediting = sub { + my $state = Slic3r::GUI::_3DScene::is_toolbar_item_pressed($self->{canvas3D}, "layersediting"); + $self->on_layer_editing_toggled($state); + }; + # Initialize 3D plater if ($Slic3r::GUI::have_OpenGL) { $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config}); @@ -179,7 +233,21 @@ sub new { Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); + Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add); + Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete); + Slic3r::GUI::_3DScene::register_action_deleteall_callback($self->{canvas3D}, $on_action_deleteall); + Slic3r::GUI::_3DScene::register_action_arrange_callback($self->{canvas3D}, $on_action_arrange); + Slic3r::GUI::_3DScene::register_action_more_callback($self->{canvas3D}, $on_action_more); + Slic3r::GUI::_3DScene::register_action_fewer_callback($self->{canvas3D}, $on_action_fewer); + Slic3r::GUI::_3DScene::register_action_ccw45_callback($self->{canvas3D}, $on_action_ccw45); + Slic3r::GUI::_3DScene::register_action_cw45_callback($self->{canvas3D}, $on_action_cw45); + Slic3r::GUI::_3DScene::register_action_scale_callback($self->{canvas3D}, $on_action_scale); + Slic3r::GUI::_3DScene::register_action_split_callback($self->{canvas3D}, $on_action_split); + Slic3r::GUI::_3DScene::register_action_cut_callback($self->{canvas3D}, $on_action_cut); + Slic3r::GUI::_3DScene::register_action_settings_callback($self->{canvas3D}, $on_action_settings); + Slic3r::GUI::_3DScene::register_action_layersediting_callback($self->{canvas3D}, $on_action_layersediting); Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1); + Slic3r::GUI::_3DScene::enable_toolbar($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1); Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1); @@ -248,50 +316,50 @@ sub new { } }); - # toolbar for object manipulation - if (!&Wx::wxMSW) { - Wx::ToolTip::Enable(1); - $self->{htoolbar} = Wx::ToolBar->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE | wxTAB_TRAVERSAL); - $self->{htoolbar}->AddTool(TB_ADD, L("Add…"), Wx::Bitmap->new(Slic3r::var("brick_add.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_REMOVE, L("Delete"), Wx::Bitmap->new(Slic3r::var("brick_delete.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_RESET, L("Delete All"), Wx::Bitmap->new(Slic3r::var("cross.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_ARRANGE, L("Arrange"), Wx::Bitmap->new(Slic3r::var("bricks.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddSeparator; - $self->{htoolbar}->AddTool(TB_MORE, L("More"), Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_FEWER, L("Fewer"), Wx::Bitmap->new(Slic3r::var("delete.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddSeparator; - $self->{htoolbar}->AddTool(TB_45CCW, L("45° ccw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_anticlockwise.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_45CW, L("45° cw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_clockwise.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_SCALE, L("Scale…"), Wx::Bitmap->new(Slic3r::var("arrow_out.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_SPLIT, L("Split"), Wx::Bitmap->new(Slic3r::var("shape_ungroup.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_CUT, L("Cut…"), Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddSeparator; - $self->{htoolbar}->AddTool(TB_SETTINGS, L("Settings…"), Wx::Bitmap->new(Slic3r::var("cog.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_LAYER_EDITING, L('Layer Editing'), Wx::Bitmap->new(Slic3r::var("variable_layer_height.png"), wxBITMAP_TYPE_PNG), wxNullBitmap, 1, 0, 'Layer Editing'); - } else { - my %tbar_buttons = ( - add => L("Add…"), - remove => L("Delete"), - reset => L("Delete All"), - arrange => L("Arrange"), - increase => "", - decrease => "", - rotate45ccw => "", - rotate45cw => "", - changescale => L("Scale…"), - split => L("Split"), - cut => L("Cut…"), - settings => L("Settings…"), - layer_editing => L("Layer editing"), - ); - $self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL); - for (qw(add remove reset arrange increase decrease rotate45ccw rotate45cw changescale split cut settings)) { - $self->{"btn_$_"} = Wx::Button->new($self, -1, $tbar_buttons{$_}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - $self->{btoolbar}->Add($self->{"btn_$_"}); - } - $self->{"btn_layer_editing"} = Wx::ToggleButton->new($self, -1, $tbar_buttons{'layer_editing'}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - $self->{btoolbar}->Add($self->{"btn_layer_editing"}); - } +# # toolbar for object manipulation +# if (!&Wx::wxMSW) { +# Wx::ToolTip::Enable(1); +# $self->{htoolbar} = Wx::ToolBar->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE | wxTAB_TRAVERSAL); +# $self->{htoolbar}->AddTool(TB_ADD, L("Add…"), Wx::Bitmap->new(Slic3r::var("brick_add.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_REMOVE, L("Delete"), Wx::Bitmap->new(Slic3r::var("brick_delete.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_RESET, L("Delete All"), Wx::Bitmap->new(Slic3r::var("cross.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_ARRANGE, L("Arrange"), Wx::Bitmap->new(Slic3r::var("bricks.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddSeparator; +# $self->{htoolbar}->AddTool(TB_MORE, L("More"), Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_FEWER, L("Fewer"), Wx::Bitmap->new(Slic3r::var("delete.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddSeparator; +# $self->{htoolbar}->AddTool(TB_45CCW, L("45° ccw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_anticlockwise.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_45CW, L("45° cw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_clockwise.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_SCALE, L("Scale…"), Wx::Bitmap->new(Slic3r::var("arrow_out.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_SPLIT, L("Split"), Wx::Bitmap->new(Slic3r::var("shape_ungroup.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_CUT, L("Cut…"), Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddSeparator; +# $self->{htoolbar}->AddTool(TB_SETTINGS, L("Settings…"), Wx::Bitmap->new(Slic3r::var("cog.png"), wxBITMAP_TYPE_PNG), ''); +# $self->{htoolbar}->AddTool(TB_LAYER_EDITING, L('Layer Editing'), Wx::Bitmap->new(Slic3r::var("variable_layer_height.png"), wxBITMAP_TYPE_PNG), wxNullBitmap, 1, 0, 'Layer Editing'); +# } else { +# my %tbar_buttons = ( +# add => L("Add…"), +# remove => L("Delete"), +# reset => L("Delete All"), +# arrange => L("Arrange"), +# increase => "", +# decrease => "", +# rotate45ccw => "", +# rotate45cw => "", +# changescale => L("Scale…"), +# split => L("Split"), +# cut => L("Cut…"), +# settings => L("Settings…"), +# layer_editing => L("Layer editing"), +# ); +# $self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL); +# for (qw(add remove reset arrange increase decrease rotate45ccw rotate45cw changescale split cut settings)) { +# $self->{"btn_$_"} = Wx::Button->new($self, -1, $tbar_buttons{$_}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); +# $self->{btoolbar}->Add($self->{"btn_$_"}); +# } +# $self->{"btn_layer_editing"} = Wx::ToggleButton->new($self, -1, $tbar_buttons{'layer_editing'}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); +# $self->{btoolbar}->Add($self->{"btn_layer_editing"}); +# } ### Panel for right column $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); @@ -371,39 +439,39 @@ sub new { EVT_BUTTON($self, $self->{btn_reslice}, \&reslice); EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); - if ($self->{htoolbar}) { - EVT_TOOL($self, TB_ADD, sub { $self->add; }); - EVT_TOOL($self, TB_REMOVE, sub { $self->remove() }); # explicitly pass no argument to remove - EVT_TOOL($self, TB_RESET, sub { $self->reset; }); - EVT_TOOL($self, TB_ARRANGE, sub { $self->arrange; }); - EVT_TOOL($self, TB_MORE, sub { $self->increase; }); - EVT_TOOL($self, TB_FEWER, sub { $self->decrease; }); - EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45, Z, 'relative') }); - EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45, Z, 'relative') }); - EVT_TOOL($self, TB_SCALE, sub { $self->changescale(undef); }); - EVT_TOOL($self, TB_SPLIT, sub { $self->split_object; }); - EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog }); - EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog }); - EVT_TOOL($self, TB_LAYER_EDITING, sub { - my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D}); - $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state); - $self->on_layer_editing_toggled(! $state); - }); - } else { - EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; }); - EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove - EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; }); - EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; }); - EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; }); - EVT_BUTTON($self, $self->{btn_decrease}, sub { $self->decrease; }); - EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45, Z, 'relative') }); - EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45, Z, 'relative') }); - EVT_BUTTON($self, $self->{btn_changescale}, sub { $self->changescale(undef); }); - EVT_BUTTON($self, $self->{btn_split}, sub { $self->split_object; }); - EVT_BUTTON($self, $self->{btn_cut}, sub { $_[0]->object_cut_dialog }); - EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog }); - EVT_TOGGLEBUTTON($self, $self->{btn_layer_editing}, sub { $self->on_layer_editing_toggled($self->{btn_layer_editing}->GetValue); }); - } +# if ($self->{htoolbar}) { +# EVT_TOOL($self, TB_ADD, sub { $self->add; }); +# EVT_TOOL($self, TB_REMOVE, sub { $self->remove() }); # explicitly pass no argument to remove +# EVT_TOOL($self, TB_RESET, sub { $self->reset; }); +# EVT_TOOL($self, TB_ARRANGE, sub { $self->arrange; }); +# EVT_TOOL($self, TB_MORE, sub { $self->increase; }); +# EVT_TOOL($self, TB_FEWER, sub { $self->decrease; }); +# EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45, Z, 'relative') }); +# EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45, Z, 'relative') }); +# EVT_TOOL($self, TB_SCALE, sub { $self->changescale(undef); }); +# EVT_TOOL($self, TB_SPLIT, sub { $self->split_object; }); +# EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog }); +# EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog }); +# EVT_TOOL($self, TB_LAYER_EDITING, sub { +# my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D}); +# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state); +# $self->on_layer_editing_toggled(! $state); +# }); +# } else { +# EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; }); +# EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove +# EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; }); +# EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; }); +# EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; }); +# EVT_BUTTON($self, $self->{btn_decrease}, sub { $self->decrease; }); +# EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45, Z, 'relative') }); +# EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45, Z, 'relative') }); +# EVT_BUTTON($self, $self->{btn_changescale}, sub { $self->changescale(undef); }); +# EVT_BUTTON($self, $self->{btn_split}, sub { $self->split_object; }); +# EVT_BUTTON($self, $self->{btn_cut}, sub { $_[0]->object_cut_dialog }); +# EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog }); +# EVT_TOGGLEBUTTON($self, $self->{btn_layer_editing}, sub { $self->on_layer_editing_toggled($self->{btn_layer_editing}->GetValue); }); +# } $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self)) for grep defined($_), @@ -560,10 +628,10 @@ sub new { my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1); $hsizer->Add($self->{right_panel}, 0, wxEXPAND | wxLEFT | wxRIGHT, 3); - + my $sizer = Wx::BoxSizer->new(wxVERTICAL); - $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar}; - $sizer->Add($self->{btoolbar}, 0, wxEXPAND, 0) if $self->{btoolbar}; +# $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar}; +# $sizer->Add($self->{btoolbar}, 0, wxEXPAND, 0) if $self->{btoolbar}; $sizer->Add($hsizer, 1, wxEXPAND, 0); $sizer->SetSizeHints($self); @@ -629,13 +697,14 @@ sub on_layer_editing_toggled { Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state); if ($new_state && ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D})) { # Initialization of the OpenGL shaders failed. Disable the tool. - if ($self->{htoolbar}) { - $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); - $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); - } else { - $self->{"btn_layer_editing"}->Disable; - $self->{"btn_layer_editing"}->SetValue(0); - } +# if ($self->{htoolbar}) { +# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); +# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); +# } else { +# $self->{"btn_layer_editing"}->Disable; +# $self->{"btn_layer_editing"}->SetValue(0); +# } + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0); } $self->{canvas3D}->Refresh; $self->{canvas3D}->Update; @@ -950,6 +1019,8 @@ sub increase { } else { $self->update; } + + $self->selection_changed; # refresh info (size, volume etc.) $self->schedule_background_process; } @@ -1919,23 +1990,25 @@ sub on_config_change { $self->Layout; } elsif ($opt_key eq 'variable_layer_height') { if ($config->get('variable_layer_height') != 1) { - if ($self->{htoolbar}) { - $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); - $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); - } else { - $self->{"btn_layer_editing"}->Disable; - $self->{"btn_layer_editing"}->SetValue(0); - } +# if ($self->{htoolbar}) { +# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0); +# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0); +# } else { +# $self->{"btn_layer_editing"}->Disable; +# $self->{"btn_layer_editing"}->SetValue(0); +# } + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0); Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, 0); $self->{canvas3D}->Refresh; $self->{canvas3D}->Update; } elsif (Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D})) { # Want to allow the layer editing, but do it only if the OpenGL supports it. - if ($self->{htoolbar}) { - $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1); - } else { - $self->{"btn_layer_editing"}->Enable; - } +# if ($self->{htoolbar}) { +# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1); +# } else { +# $self->{"btn_layer_editing"}->Enable; +# } + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 1); } } elsif ($opt_key eq 'extruder_colour') { $update_scheduled = 1; @@ -2103,20 +2176,21 @@ sub object_list_changed { # Enable/disable buttons depending on whether there are any objects on the platter. my $have_objects = @{$self->{objects}} ? 1 : 0; - my $variable_layer_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D}); - if ($self->{htoolbar}) { - # On OSX or Linux - $self->{htoolbar}->EnableTool($_, $have_objects) - for (TB_RESET, TB_ARRANGE, TB_LAYER_EDITING); - $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0) if (! $variable_layer_height_allowed); - } else { - # On MSW - my $method = $have_objects ? 'Enable' : 'Disable'; - $self->{"btn_$_"}->$method - for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode layer_editing); - $self->{"btn_layer_editing"}->Disable if (! $variable_layer_height_allowed); - } +# if ($self->{htoolbar}) { +# # On OSX or Linux +# $self->{htoolbar}->EnableTool($_, $have_objects) +# for (TB_RESET, TB_ARRANGE); +# } else { +# # On MSW +# my $method = $have_objects ? 'Enable' : 'Disable'; +# $self->{"btn_$_"}->$method +# for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode); +# } + for my $toolbar_item (qw(deleteall arrange)) { + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_objects); + } + my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file}; my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1; # $model_fits == 1 -> ModelInstance::PVS_Partly_Outside @@ -2130,17 +2204,56 @@ sub selection_changed { my ($self) = @_; my ($obj_idx, $object) = $self->selected_object; my $have_sel = defined $obj_idx; + my $layers_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D}) && $have_sel; $self->{right_panel}->Freeze; - if ($self->{htoolbar}) { - # On OSX or Linux - $self->{htoolbar}->EnableTool($_, $have_sel) - for (TB_REMOVE, TB_MORE, TB_FEWER, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_CUT, TB_SETTINGS); - } else { - # On MSW - my $method = $have_sel ? 'Enable' : 'Disable'; - $self->{"btn_$_"}->$method - for grep $self->{"btn_$_"}, qw(remove increase decrease rotate45cw rotate45ccw changescale split cut settings); +# if ($self->{htoolbar}) { +# # On OSX or Linux +# $self->{htoolbar}->EnableTool($_, $have_sel) +# for (TB_REMOVE, TB_MORE, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_CUT, TB_SETTINGS); +# +# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, $layers_height_allowed); +# +# if ($have_sel) { +# my $model_object = $self->{model}->objects->[$obj_idx]; +# $self->{htoolbar}->EnableTool(TB_FEWER, $model_object->instances_count > 1); +# } else { +# $self->{htoolbar}->EnableTool(TB_FEWER, 0); +# } +# +# } else { +# # On MSW +# my $method = $have_sel ? 'Enable' : 'Disable'; +# $self->{"btn_$_"}->$method +# for grep $self->{"btn_$_"}, qw(remove increase rotate45cw rotate45ccw changescale split cut settings); +# +# if ($layers_height_allowed) { +# $self->{"btn_layer_editing"}->Enable; +# } else { +# $self->{"btn_layer_editing"}->Disable; +# } +# +# if ($have_sel) { +# my $model_object = $self->{model}->objects->[$obj_idx]; +# if ($model_object->instances_count > 1) { +# $self->{"btn_decrease"}->Enable; +# } else { +# $self->{"btn_decrease"}->Disable; +# } +# } else { +# $self->{"btn_decrease"}->Disable; +# } +# } + + for my $toolbar_item (qw(delete more fewer ccw45 cw45 scale split cut settings)) { + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_sel); + } + + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", $layers_height_allowed); + + if ($have_sel) { + my $model_object = $self->{model}->objects->[$obj_idx]; + Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "fewer", $model_object->instances_count > 1); } if ($self->{object_info_size}) { # have we already loaded the info pane? diff --git a/resources/icons/toolbar.png b/resources/icons/toolbar.png new file mode 100644 index 0000000000..e45f4989f0 Binary files /dev/null and b/resources/icons/toolbar.png differ diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index f1609bc14a..be9c7e47b7 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -196,9 +196,11 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/GUI/GLCanvas3DManager.hpp ${LIBDIR}/slic3r/GUI/GLCanvas3DManager.cpp ${LIBDIR}/slic3r/GUI/GLGizmo.hpp - ${LIBDIR}/slic3r/GUI/GLGizmo.cpp + ${LIBDIR}/slic3r/GUI/GLGizmo.cpp ${LIBDIR}/slic3r/GUI/GLTexture.hpp - ${LIBDIR}/slic3r/GUI/GLTexture.cpp + ${LIBDIR}/slic3r/GUI/GLTexture.cpp + ${LIBDIR}/slic3r/GUI/GLToolbar.hpp + ${LIBDIR}/slic3r/GUI/GLToolbar.cpp ${LIBDIR}/slic3r/GUI/Preferences.cpp ${LIBDIR}/slic3r/GUI/Preferences.hpp ${LIBDIR}/slic3r/GUI/Preset.cpp diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 0709271b8c..5bb0a3be94 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1852,6 +1852,11 @@ void _3DScene::enable_gizmos(wxGLCanvas* canvas, bool enable) s_canvas_mgr.enable_gizmos(canvas, enable); } +void _3DScene::enable_toolbar(wxGLCanvas* canvas, bool enable) +{ + s_canvas_mgr.enable_toolbar(canvas, enable); +} + void _3DScene::enable_shader(wxGLCanvas* canvas, bool enable) { s_canvas_mgr.enable_shader(canvas, enable); @@ -1872,6 +1877,16 @@ void _3DScene::allow_multisample(wxGLCanvas* canvas, bool allow) s_canvas_mgr.allow_multisample(canvas, allow); } +void _3DScene::enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable) +{ + s_canvas_mgr.enable_toolbar_item(canvas, name, enable); +} + +bool _3DScene::is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name) +{ + return s_canvas_mgr.is_toolbar_item_pressed(canvas, name); +} + void _3DScene::zoom_to_bed(wxGLCanvas* canvas) { s_canvas_mgr.zoom_to_bed(canvas); @@ -2007,6 +2022,71 @@ void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, voi s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback); } +void _3DScene::register_action_add_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_add_callback(canvas, callback); +} + +void _3DScene::register_action_delete_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_delete_callback(canvas, callback); +} + +void _3DScene::register_action_deleteall_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_deleteall_callback(canvas, callback); +} + +void _3DScene::register_action_arrange_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_arrange_callback(canvas, callback); +} + +void _3DScene::register_action_more_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_more_callback(canvas, callback); +} + +void _3DScene::register_action_fewer_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_fewer_callback(canvas, callback); +} + +void _3DScene::register_action_ccw45_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_ccw45_callback(canvas, callback); +} + +void _3DScene::register_action_cw45_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_cw45_callback(canvas, callback); +} + +void _3DScene::register_action_scale_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_scale_callback(canvas, callback); +} + +void _3DScene::register_action_split_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_split_callback(canvas, callback); +} + +void _3DScene::register_action_cut_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_cut_callback(canvas, callback); +} + +void _3DScene::register_action_settings_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_settings_callback(canvas, callback); +} + +void _3DScene::register_action_layersediting_callback(wxGLCanvas* canvas, void* callback) +{ + s_canvas_mgr.register_action_layersediting_callback(canvas, callback); +} + static inline int hex_digit_to_int(const char c) { return diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 1265bc20de..92bebe7e69 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -503,11 +503,15 @@ public: static void enable_picking(wxGLCanvas* canvas, bool enable); static void enable_moving(wxGLCanvas* canvas, bool enable); static void enable_gizmos(wxGLCanvas* canvas, bool enable); + static void enable_toolbar(wxGLCanvas* canvas, bool enable); static void enable_shader(wxGLCanvas* canvas, bool enable); static void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable); static void enable_dynamic_background(wxGLCanvas* canvas, bool enable); static void allow_multisample(wxGLCanvas* canvas, bool allow); + static void enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable); + static bool is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name); + static void zoom_to_bed(wxGLCanvas* canvas); static void zoom_to_volumes(wxGLCanvas* canvas); static void select_view(wxGLCanvas* canvas, const std::string& direction); @@ -540,6 +544,20 @@ public: static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); + static void register_action_add_callback(wxGLCanvas* canvas, void* callback); + static void register_action_delete_callback(wxGLCanvas* canvas, void* callback); + static void register_action_deleteall_callback(wxGLCanvas* canvas, void* callback); + static void register_action_arrange_callback(wxGLCanvas* canvas, void* callback); + static void register_action_more_callback(wxGLCanvas* canvas, void* callback); + static void register_action_fewer_callback(wxGLCanvas* canvas, void* callback); + static void register_action_ccw45_callback(wxGLCanvas* canvas, void* callback); + static void register_action_cw45_callback(wxGLCanvas* canvas, void* callback); + static void register_action_scale_callback(wxGLCanvas* canvas, void* callback); + static void register_action_split_callback(wxGLCanvas* canvas, void* callback); + static void register_action_cut_callback(wxGLCanvas* canvas, void* callback); + static void register_action_settings_callback(wxGLCanvas* canvas, void* callback); + static void register_action_layersediting_callback(wxGLCanvas* canvas, void* callback); + static std::vector load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector instance_idxs); static std::vector load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 92bde34ce7..3e03ade960 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1473,6 +1473,13 @@ float GLCanvas3D::Gizmos::_get_total_overlay_height() const const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 }; const unsigned char GLCanvas3D::WarningTexture::Opacity = 255; +GLCanvas3D::WarningTexture::WarningTexture() + : GUI::GLTexture() + , m_original_width(0) + , m_original_height(0) +{ +} + bool GLCanvas3D::WarningTexture::generate(const std::string& msg) { reset(); @@ -1482,13 +1489,21 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg) wxMemoryDC memDC; // select default font - memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + font.MakeLarger(); + font.MakeBold(); + memDC.SetFont(font); // calculates texture size wxCoord w, h; memDC.GetTextExtent(msg, &w, &h); - m_width = (int)w; - m_height = (int)h; + + int pow_of_two_size = next_highest_power_of_2((int)std::max(w, h)); + + m_original_width = (int)w; + m_original_height = (int)h; + m_width = pow_of_two_size; + m_height = pow_of_two_size; // generates bitmap wxBitmap bitmap(m_width, m_height); @@ -1540,10 +1555,51 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg) return true; } +void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const +{ + if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) + { + ::glDisable(GL_DEPTH_TEST); + ::glPushMatrix(); + ::glLoadIdentity(); + + const Size& cnv_size = canvas.get_canvas_size(); + float zoom = canvas.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float left = (-0.5f * (float)m_original_width) * inv_zoom; + float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom; + float right = left + (float)m_original_width * inv_zoom; + float bottom = top - (float)m_original_height * inv_zoom; + + float uv_left = 0.0f; + float uv_top = 0.0f; + float uv_right = (float)m_original_width / (float)m_width; + float uv_bottom = (float)m_original_height / (float)m_height; + + GLTexture::Quad_UVs uvs; + uvs.left_top = { uv_left, uv_top }; + uvs.left_bottom = { uv_left, uv_bottom }; + uvs.right_bottom = { uv_right, uv_bottom }; + uvs.right_top = { uv_right, uv_top }; + + GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); + + ::glPopMatrix(); + ::glEnable(GL_DEPTH_TEST); + } +} + const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; const unsigned char GLCanvas3D::LegendTexture::Background_Color[3] = { 9, 91, 134 }; const unsigned char GLCanvas3D::LegendTexture::Opacity = 255; +GLCanvas3D::LegendTexture::LegendTexture() + : GUI::GLTexture() + , m_original_width(0) + , m_original_height(0) +{ +} + bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors) { reset(); @@ -1576,10 +1632,15 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c max_text_height = std::max(max_text_height, (int)h); } - m_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width); - m_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square; + m_original_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width); + m_original_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square; if (items_count > 1) - m_height += (items_count - 1) * Px_Square_Contour; + m_original_height += (items_count - 1) * Px_Square_Contour; + + int pow_of_two_size = next_highest_power_of_2(std::max(m_original_width, m_original_height)); + + m_width = pow_of_two_size; + m_height = pow_of_two_size; // generates bitmap wxBitmap bitmap(m_width, m_height); @@ -1688,6 +1749,40 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c return true; } +void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const +{ + if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) + { + ::glDisable(GL_DEPTH_TEST); + ::glPushMatrix(); + ::glLoadIdentity(); + + const Size& cnv_size = canvas.get_canvas_size(); + float zoom = canvas.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; + float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; + float right = left + (float)m_original_width * inv_zoom; + float bottom = top - (float)m_original_height * inv_zoom; + + float uv_left = 0.0f; + float uv_top = 0.0f; + float uv_right = (float)m_original_width / (float)m_width; + float uv_bottom = (float)m_original_height / (float)m_height; + + GLTexture::Quad_UVs uvs; + uvs.left_top = { uv_left, uv_top }; + uvs.left_bottom = { uv_left, uv_bottom }; + uvs.right_bottom = { uv_right, uv_bottom }; + uvs.right_top = { uv_right, uv_top }; + + GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); + + ::glPopMatrix(); + ::glEnable(GL_DEPTH_TEST); + } +} + GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const { GizmosMap::const_iterator it = m_gizmos.find(m_current); @@ -1698,6 +1793,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) : m_canvas(canvas) , m_context(nullptr) , m_timer(nullptr) + , m_toolbar(*this) , m_config(nullptr) , m_print(nullptr) , m_model(nullptr) @@ -1707,6 +1803,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_force_zoom_to_bed_enabled(false) , m_apply_zoom_to_volumes_filter(false) , m_hover_volume_id(-1) + , m_toolbar_action_running(false) , m_warning_texture_enabled(false) , m_legend_texture_enabled(false) , m_picking_enabled(false) @@ -1813,6 +1910,9 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (m_gizmos.is_enabled() && !m_gizmos.init()) return false; + if (!_init_toolbar()) + return false; + m_initialized = true; return true; @@ -2076,6 +2176,11 @@ void GLCanvas3D::enable_gizmos(bool enable) m_gizmos.set_enabled(enable); } +void GLCanvas3D::enable_toolbar(bool enable) +{ + m_toolbar.set_enabled(enable); +} + void GLCanvas3D::enable_shader(bool enable) { m_shader_enabled = enable; @@ -2096,6 +2201,19 @@ void GLCanvas3D::allow_multisample(bool allow) m_multisample_allowed = allow; } +void GLCanvas3D::enable_toolbar_item(const std::string& name, bool enable) +{ + if (enable) + m_toolbar.enable_item(name); + else + m_toolbar.disable_item(name); +} + +bool GLCanvas3D::is_toolbar_item_pressed(const std::string& name) const +{ + return m_toolbar.is_item_pressed(name); +} + void GLCanvas3D::zoom_to_bed() { _zoom_to_bounding_box(m_bed.get_bounding_box()); @@ -2225,6 +2343,7 @@ void GLCanvas3D::render() _render_warning_texture(); _render_legend_texture(); _render_gizmo(); + _render_toolbar(); _render_layer_editing_overlay(); m_canvas->SwapBuffers(); @@ -2527,6 +2646,84 @@ void GLCanvas3D::register_on_update_geometry_info_callback(void* callback) m_on_update_geometry_info_callback.register_callback(callback); } +void GLCanvas3D::register_action_add_callback(void* callback) +{ + if (callback != nullptr) + m_action_add_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_delete_callback(void* callback) +{ + if (callback != nullptr) + m_action_delete_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_deleteall_callback(void* callback) +{ + if (callback != nullptr) + m_action_deleteall_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_arrange_callback(void* callback) +{ + if (callback != nullptr) + m_action_arrange_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_more_callback(void* callback) +{ + if (callback != nullptr) + m_action_more_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_fewer_callback(void* callback) +{ + if (callback != nullptr) + m_action_fewer_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_ccw45_callback(void* callback) +{ + if (callback != nullptr) + m_action_ccw45_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_cw45_callback(void* callback) +{ + if (callback != nullptr) + m_action_cw45_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_scale_callback(void* callback) +{ + if (callback != nullptr) + m_action_scale_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_split_callback(void* callback) +{ + if (callback != nullptr) + m_action_split_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_cut_callback(void* callback) +{ + if (callback != nullptr) + m_action_cut_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_settings_callback(void* callback) +{ + if (callback != nullptr) + m_action_settings_callback.register_callback(callback); +} + +void GLCanvas3D::register_action_layersediting_callback(void* callback) +{ + if (callback != nullptr) + m_action_layersediting_callback.register_callback(callback); +} + void GLCanvas3D::bind_event_handlers() { if (m_canvas != nullptr) @@ -2704,6 +2901,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; m_layers_editing.last_object_id = layer_editing_object_idx; bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position); + int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position); if (evt.Entering()) { @@ -2723,6 +2921,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.LeftDClick() && (m_hover_volume_id != -1)) m_on_double_click_callback.call(); + else if (evt.LeftDClick() && (toolbar_contains_mouse != -1)) + { + m_toolbar_action_running = true; + m_toolbar.do_action((unsigned int)toolbar_contains_mouse); + } else if (evt.LeftDown() || evt.RightDown()) { // If user pressed left or right button we first check whether this happened @@ -2761,6 +2964,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); m_dirty = true; } + else if (toolbar_contains_mouse != -1) + { + m_toolbar_action_running = true; + m_toolbar.do_action((unsigned int)toolbar_contains_mouse); + } else { // Select volume in this 3D canvas. @@ -2817,9 +3025,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.RightDown()) { - // if right clicking on volume, propagate event through callback - if (m_volumes.volumes[volume_idx]->hover) - m_on_right_click_callback.call(pos.x, pos.y); + // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while + // the context menu is already shown, ensuring it to disappear if the mouse is outside any volume + m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y); + render(); + if (m_hover_volume_id != -1) + { + // if right clicking on volume, propagate event through callback (shows context menu) + if (m_volumes.volumes[volume_idx]->hover) + m_on_right_click_callback.call(pos.x, pos.y); + } } } } @@ -3018,10 +3233,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) _on_move(volume_idxs); } - else if (!m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) + else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) { // deselect and propagate event through callback - if (m_picking_enabled) + if (m_picking_enabled && !m_toolbar_action_running) { deselect_volumes(); _on_select(-1); @@ -3053,6 +3268,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); m_mouse.dragging = false; + m_toolbar_action_running = false; m_dirty = true; } else if (evt.Moving()) @@ -3119,6 +3335,12 @@ void GLCanvas3D::reset_legend_texture() m_legend_texture.reset(); } +void GLCanvas3D::set_tooltip(const std::string& tooltip) +{ + if (m_canvas != nullptr) + m_canvas->SetToolTip(tooltip); +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; @@ -3130,6 +3352,143 @@ void GLCanvas3D::_force_zoom_to_bed() m_force_zoom_to_bed_enabled = false; } +bool GLCanvas3D::_init_toolbar() +{ + if (!m_toolbar.is_enabled()) + return true; + + if (!m_toolbar.init("toolbar.png", 36, 1, 1)) + { + // unable to init the toolbar texture, disable it + m_toolbar.set_enabled(false); + return true; + } + +// m_toolbar.set_layout_type(GLToolbar::Layout::Vertical); + m_toolbar.set_layout_type(GLToolbar::Layout::Horizontal); + m_toolbar.set_separator_size(5); + m_toolbar.set_gap_size(2); + + GLToolbarItem::Data item; + + item.name = "add"; + item.tooltip = GUI::L_str("Add..."); + item.sprite_id = 0; + item.is_toggable = false; + item.action_callback = &m_action_add_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "delete"; + item.tooltip = GUI::L_str("Delete"); + item.sprite_id = 1; + item.is_toggable = false; + item.action_callback = &m_action_delete_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "deleteall"; + item.tooltip = GUI::L_str("Delete all"); + item.sprite_id = 2; + item.is_toggable = false; + item.action_callback = &m_action_deleteall_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "arrange"; + item.tooltip = GUI::L_str("Arrange"); + item.sprite_id = 3; + item.is_toggable = false; + item.action_callback = &m_action_arrange_callback; + if (!m_toolbar.add_item(item)) + return false; + + if (!m_toolbar.add_separator()) + return false; + + item.name = "more"; + item.tooltip = GUI::L_str("Add instance"); + item.sprite_id = 4; + item.is_toggable = false; + item.action_callback = &m_action_more_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "fewer"; + item.tooltip = GUI::L_str("Remove instance"); + item.sprite_id = 5; + item.is_toggable = false; + item.action_callback = &m_action_fewer_callback; + if (!m_toolbar.add_item(item)) + return false; + + if (!m_toolbar.add_separator()) + return false; + + item.name = "ccw45"; + item.tooltip = GUI::L_str("Rotate CCW 45 degrees"); + item.sprite_id = 6; + item.is_toggable = false; + item.action_callback = &m_action_ccw45_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "cw45"; + item.tooltip = GUI::L_str("Rotate CW 45 degrees"); + item.sprite_id = 7; + item.is_toggable = false; + item.action_callback = &m_action_cw45_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "scale"; + item.tooltip = GUI::L_str("Scale..."); + item.sprite_id = 8; + item.is_toggable = false; + item.action_callback = &m_action_scale_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "split"; + item.tooltip = GUI::L_str("Split"); + item.sprite_id = 9; + item.is_toggable = false; + item.action_callback = &m_action_split_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "cut"; + item.tooltip = GUI::L_str("Cut..."); + item.sprite_id = 10; + item.is_toggable = false; + item.action_callback = &m_action_cut_callback; + if (!m_toolbar.add_item(item)) + return false; + + if (!m_toolbar.add_separator()) + return false; + + item.name = "settings"; + item.tooltip = GUI::L_str("Settings..."); + item.sprite_id = 11; + item.is_toggable = false; + item.action_callback = &m_action_settings_callback; + if (!m_toolbar.add_item(item)) + return false; + + item.name = "layersediting"; + item.tooltip = GUI::L_str("Layers editing"); + item.sprite_id = 12; + item.is_toggable = true; + item.action_callback = &m_action_layersediting_callback; + if (!m_toolbar.add_item(item)) + return false; + + enable_toolbar_item("add", true); + + return true; +} + void GLCanvas3D::_resize(unsigned int w, unsigned int h) { if ((m_canvas == nullptr) && (m_context == nullptr)) @@ -3353,6 +3712,20 @@ void GLCanvas3D::_deregister_callbacks() m_on_gizmo_scale_uniformly_callback.deregister_callback(); m_on_gizmo_rotate_callback.deregister_callback(); m_on_update_geometry_info_callback.deregister_callback(); + + m_action_add_callback.deregister_callback(); + m_action_delete_callback.deregister_callback(); + m_action_deleteall_callback.deregister_callback(); + m_action_arrange_callback.deregister_callback(); + m_action_more_callback.deregister_callback(); + m_action_fewer_callback.deregister_callback(); + m_action_ccw45_callback.deregister_callback(); + m_action_cw45_callback.deregister_callback(); + m_action_scale_callback.deregister_callback(); + m_action_split_callback.deregister_callback(); + m_action_cut_callback.deregister_callback(); + m_action_settings_callback.deregister_callback(); + m_action_layersediting_callback.deregister_callback(); } void GLCanvas3D::_mark_volumes_for_layer_height() const @@ -3464,6 +3837,8 @@ void GLCanvas3D::_picking_pass() const m_gizmos.update_hover_state(*this, pos); else m_gizmos.reset_all_states(); + + m_toolbar.update_hover_state(pos); } } @@ -3568,32 +3943,7 @@ void GLCanvas3D::_render_warning_texture() const if (!m_warning_texture_enabled) return; - // If the warning texture has not been loaded into the GPU, do it now. - unsigned int tex_id = m_warning_texture.get_id(); - if (tex_id > 0) - { - int w = m_warning_texture.get_width(); - int h = m_warning_texture.get_height(); - if ((w > 0) && (h > 0)) - { - ::glDisable(GL_DEPTH_TEST); - ::glPushMatrix(); - ::glLoadIdentity(); - - const Size& cnv_size = get_canvas_size(); - float zoom = get_camera_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - float l = (-0.5f * (float)w) * inv_zoom; - float t = (-0.5f * (float)cnv_size.get_height() + (float)h) * inv_zoom; - float r = l + (float)w * inv_zoom; - float b = t - (float)h * inv_zoom; - - GLTexture::render_texture(tex_id, l, r, b, t); - - ::glPopMatrix(); - ::glEnable(GL_DEPTH_TEST); - } - } + m_warning_texture.render(*this); } void GLCanvas3D::_render_legend_texture() const @@ -3601,32 +3951,7 @@ void GLCanvas3D::_render_legend_texture() const if (!m_legend_texture_enabled) return; - // If the legend texture has not been loaded into the GPU, do it now. - unsigned int tex_id = m_legend_texture.get_id(); - if (tex_id > 0) - { - int w = m_legend_texture.get_width(); - int h = m_legend_texture.get_height(); - if ((w > 0) && (h > 0)) - { - ::glDisable(GL_DEPTH_TEST); - ::glPushMatrix(); - ::glLoadIdentity(); - - const Size& cnv_size = get_canvas_size(); - float zoom = get_camera_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; - float l = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; - float t = (0.5f * (float)cnv_size.get_height()) * inv_zoom; - float r = l + (float)w * inv_zoom; - float b = t - (float)h * inv_zoom; - - GLTexture::render_texture(tex_id, l, r, b, t); - - ::glPopMatrix(); - ::glEnable(GL_DEPTH_TEST); - } - } + m_legend_texture.render(*this); } void GLCanvas3D::_render_layer_editing_overlay() const @@ -3713,6 +4038,12 @@ void GLCanvas3D::_render_gizmo() const m_gizmos.render(*this, _selected_volumes_bounding_box()); } +void GLCanvas3D::_render_toolbar() const +{ + _resize_toolbar(); + m_toolbar.render(); +} + float GLCanvas3D::_get_layers_editing_cursor_z_relative() const { return m_layers_editing.get_cursor_z_relative(*this); @@ -4964,5 +5295,36 @@ bool GLCanvas3D::_is_any_volume_outside() const return false; } +void GLCanvas3D::_resize_toolbar() const +{ + Size cnv_size = get_canvas_size(); + float zoom = get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + switch (m_toolbar.get_layout_type()) + { + default: + case GLToolbar::Layout::Horizontal: + { + // centers the toolbar on the top edge of the 3d scene + unsigned int toolbar_width = m_toolbar.get_width(); + float top = (0.5f * (float)cnv_size.get_height() - 2.0f) * inv_zoom; + float left = -0.5f * (float)toolbar_width * inv_zoom; + m_toolbar.set_position(top, left); + break; + } + case GLToolbar::Layout::Vertical: + { + // centers the toolbar on the right edge of the 3d scene + unsigned int toolbar_width = m_toolbar.get_width(); + unsigned int toolbar_height = m_toolbar.get_height(); + float top = 0.5f * (float)toolbar_height * inv_zoom; + float left = (0.5f * (float)cnv_size.get_width() - toolbar_width - 2.0f) * inv_zoom; + m_toolbar.set_position(top, left); + break; + } + } +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index ae20882fc6..e1b323a748 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -2,7 +2,7 @@ #define slic3r_GLCanvas3D_hpp_ #include "../../slic3r/GUI/3DScene.hpp" -#include "../../slic3r/GUI/GLTexture.hpp" +#include "../../slic3r/GUI/GLToolbar.hpp" class wxTimer; class wxSizeEvent; @@ -400,8 +400,15 @@ public: static const unsigned char Background_Color[3]; static const unsigned char Opacity; + int m_original_width; + int m_original_height; + public: + WarningTexture(); + bool generate(const std::string& msg); + + void render(const GLCanvas3D& canvas) const; }; class LegendTexture : public GUI::GLTexture @@ -415,8 +422,15 @@ public: static const unsigned char Background_Color[3]; static const unsigned char Opacity; + int m_original_width; + int m_original_height; + public: + LegendTexture(); + bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors); + + void render(const GLCanvas3D& canvas) const; }; private: @@ -433,6 +447,7 @@ private: Shader m_shader; Mouse m_mouse; mutable Gizmos m_gizmos; + mutable GLToolbar m_toolbar; mutable GLVolumeCollection m_volumes; DynamicPrintConfig* m_config; @@ -445,6 +460,7 @@ private: bool m_force_zoom_to_bed_enabled; bool m_apply_zoom_to_volumes_filter; mutable int m_hover_volume_id; + bool m_toolbar_action_running; bool m_warning_texture_enabled; bool m_legend_texture_enabled; bool m_picking_enabled; @@ -482,6 +498,20 @@ private: PerlCallback m_on_gizmo_rotate_callback; PerlCallback m_on_update_geometry_info_callback; + PerlCallback m_action_add_callback; + PerlCallback m_action_delete_callback; + PerlCallback m_action_deleteall_callback; + PerlCallback m_action_arrange_callback; + PerlCallback m_action_more_callback; + PerlCallback m_action_fewer_callback; + PerlCallback m_action_ccw45_callback; + PerlCallback m_action_cw45_callback; + PerlCallback m_action_scale_callback; + PerlCallback m_action_split_callback; + PerlCallback m_action_cut_callback; + PerlCallback m_action_settings_callback; + PerlCallback m_action_layersediting_callback; + public: GLCanvas3D(wxGLCanvas* canvas); ~GLCanvas3D(); @@ -539,11 +569,15 @@ public: void enable_picking(bool enable); void enable_moving(bool enable); void enable_gizmos(bool enable); + void enable_toolbar(bool enable); void enable_shader(bool enable); void enable_force_zoom_to_bed(bool enable); void enable_dynamic_background(bool enable); void allow_multisample(bool allow); + void enable_toolbar_item(const std::string& name, bool enable); + bool is_toolbar_item_pressed(const std::string& name) const; + void zoom_to_bed(); void zoom_to_volumes(); void select_view(const std::string& direction); @@ -584,6 +618,20 @@ public: void register_on_gizmo_rotate_callback(void* callback); void register_on_update_geometry_info_callback(void* callback); + void register_action_add_callback(void* callback); + void register_action_delete_callback(void* callback); + void register_action_deleteall_callback(void* callback); + void register_action_arrange_callback(void* callback); + void register_action_more_callback(void* callback); + void register_action_fewer_callback(void* callback); + void register_action_ccw45_callback(void* callback); + void register_action_cw45_callback(void* callback); + void register_action_scale_callback(void* callback); + void register_action_split_callback(void* callback); + void register_action_cut_callback(void* callback); + void register_action_settings_callback(void* callback); + void register_action_layersediting_callback(void* callback); + void bind_event_handlers(); void unbind_event_handlers(); @@ -601,10 +649,14 @@ public: void reset_legend_texture(); + void set_tooltip(const std::string& tooltip); + private: bool _is_shown_on_screen() const; void _force_zoom_to_bed(); + bool _init_toolbar(); + void _resize(unsigned int w, unsigned int h); BoundingBoxf3 _max_bounding_box() const; @@ -630,6 +682,7 @@ private: void _render_layer_editing_overlay() const; void _render_volumes(bool fake_colors) const; void _render_gizmo() const; + void _render_toolbar() const; float _get_layers_editing_cursor_z_relative() const; void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); @@ -687,6 +740,8 @@ private: bool _is_any_volume_outside() const; + void _resize_toolbar() const; + static std::vector _parse_colors(const std::vector& colors); }; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 5249f6dc4f..0fe24ed43f 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -404,6 +404,13 @@ void GLCanvas3DManager::enable_gizmos(wxGLCanvas* canvas, bool enable) it->second->enable_gizmos(enable); } +void GLCanvas3DManager::enable_toolbar(wxGLCanvas* canvas, bool enable) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->enable_toolbar(enable); +} + void GLCanvas3DManager::enable_shader(wxGLCanvas* canvas, bool enable) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -432,6 +439,19 @@ void GLCanvas3DManager::allow_multisample(wxGLCanvas* canvas, bool allow) it->second->allow_multisample(allow); } +void GLCanvas3DManager::enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->enable_toolbar_item(name, enable); +} + +bool GLCanvas3DManager::is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name) const +{ + CanvasesMap::const_iterator it = _get_canvas(canvas); + return (it != m_canvases.end()) ? it->second->is_toolbar_item_pressed(name) : false; +} + void GLCanvas3DManager::zoom_to_bed(wxGLCanvas* canvas) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -675,6 +695,97 @@ void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* ca it->second->register_on_update_geometry_info_callback(callback); } +void GLCanvas3DManager::register_action_add_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_add_callback(callback); +} + +void GLCanvas3DManager::register_action_delete_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_delete_callback(callback); +} + +void GLCanvas3DManager::register_action_deleteall_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_deleteall_callback(callback); +} + +void GLCanvas3DManager::register_action_arrange_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_arrange_callback(callback); +} + +void GLCanvas3DManager::register_action_more_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_more_callback(callback); +} + +void GLCanvas3DManager::register_action_fewer_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_fewer_callback(callback); +} + +void GLCanvas3DManager::register_action_ccw45_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_ccw45_callback(callback); +} + +void GLCanvas3DManager::register_action_cw45_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_cw45_callback(callback); +} + +void GLCanvas3DManager::register_action_scale_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_scale_callback(callback); +} + +void GLCanvas3DManager::register_action_split_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_split_callback(callback); +} + +void GLCanvas3DManager::register_action_cut_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_cut_callback(callback); +} + +void GLCanvas3DManager::register_action_settings_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_settings_callback(callback); +} + +void GLCanvas3DManager::register_action_layersediting_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_action_layersediting_callback(callback); +} + GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 55c42fda69..58ee1c9d98 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -110,11 +110,15 @@ public: void enable_picking(wxGLCanvas* canvas, bool enable); void enable_moving(wxGLCanvas* canvas, bool enable); void enable_gizmos(wxGLCanvas* canvas, bool enable); + void enable_toolbar(wxGLCanvas* canvas, bool enable); void enable_shader(wxGLCanvas* canvas, bool enable); void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable); void enable_dynamic_background(wxGLCanvas* canvas, bool enable); void allow_multisample(wxGLCanvas* canvas, bool allow); + void enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable); + bool is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name) const; + void zoom_to_bed(wxGLCanvas* canvas); void zoom_to_volumes(wxGLCanvas* canvas); void select_view(wxGLCanvas* canvas, const std::string& direction); @@ -157,6 +161,20 @@ public: void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); + void register_action_add_callback(wxGLCanvas* canvas, void* callback); + void register_action_delete_callback(wxGLCanvas* canvas, void* callback); + void register_action_deleteall_callback(wxGLCanvas* canvas, void* callback); + void register_action_arrange_callback(wxGLCanvas* canvas, void* callback); + void register_action_more_callback(wxGLCanvas* canvas, void* callback); + void register_action_fewer_callback(wxGLCanvas* canvas, void* callback); + void register_action_ccw45_callback(wxGLCanvas* canvas, void* callback); + void register_action_cw45_callback(wxGLCanvas* canvas, void* callback); + void register_action_scale_callback(wxGLCanvas* canvas, void* callback); + void register_action_split_callback(wxGLCanvas* canvas, void* callback); + void register_action_cut_callback(wxGLCanvas* canvas, void* callback); + void register_action_settings_callback(wxGLCanvas* canvas, void* callback); + void register_action_layersediting_callback(wxGLCanvas* canvas, void* callback); + private: CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas); CanvasesMap::const_iterator _get_canvas(wxGLCanvas* canvas) const; diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index 18c9f5dea0..235e3d93b6 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -12,6 +12,8 @@ namespace Slic3r { namespace GUI { +GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; + GLTexture::GLTexture() : m_id(0) , m_width(0) @@ -128,6 +130,11 @@ const std::string& GLTexture::get_source() const } void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) +{ + render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs); +} + +void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const GLTexture::Quad_UVs& uvs) { ::glEnable(GL_BLEND); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -138,10 +145,10 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); ::glBegin(GL_QUADS); - ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(left, bottom); - ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(right, bottom); - ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(right, top); - ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(left, top); + ::glTexCoord2f(uvs.left_bottom.u, uvs.left_bottom.v); ::glVertex2f(left, bottom); + ::glTexCoord2f(uvs.right_bottom.u, uvs.right_bottom.v); ::glVertex2f(right, bottom); + ::glTexCoord2f(uvs.right_top.u, uvs.right_top.v); ::glVertex2f(right, top); + ::glTexCoord2f(uvs.left_top.u, uvs.left_top.v); ::glVertex2f(left, top); ::glEnd(); ::glBindTexture(GL_TEXTURE_2D, 0); diff --git a/xs/src/slic3r/GUI/GLTexture.hpp b/xs/src/slic3r/GUI/GLTexture.hpp index 3113fcab20..e027bd152f 100644 --- a/xs/src/slic3r/GUI/GLTexture.hpp +++ b/xs/src/slic3r/GUI/GLTexture.hpp @@ -10,6 +10,23 @@ namespace GUI { class GLTexture { + public: + struct UV + { + float u; + float v; + }; + + struct Quad_UVs + { + UV left_bottom; + UV right_bottom; + UV right_top; + UV left_top; + }; + + static Quad_UVs FullTextureUVs; + protected: unsigned int m_id; int m_width; @@ -30,6 +47,7 @@ namespace GUI { const std::string& get_source() const; static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); + static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs); protected: unsigned int _generate_mipmaps(wxImage& image); diff --git a/xs/src/slic3r/GUI/GLToolbar.cpp b/xs/src/slic3r/GUI/GLToolbar.cpp new file mode 100644 index 0000000000..fd993f5a2e --- /dev/null +++ b/xs/src/slic3r/GUI/GLToolbar.cpp @@ -0,0 +1,721 @@ +#include "GLToolbar.hpp" + +#include "../../slic3r/GUI/GLCanvas3D.hpp" + +#include + +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +GLToolbarItem::Data::Data() + : name("") + , tooltip("") + , sprite_id(-1) + , is_toggable(false) + , action_callback(nullptr) +{ +} + +GLToolbarItem::GLToolbarItem(GLToolbarItem::EType type, const GLToolbarItem::Data& data) + : m_type(type) + , m_state(Disabled) + , m_data(data) +{ +} + +GLToolbarItem::EState GLToolbarItem::get_state() const +{ + return m_state; +} + +void GLToolbarItem::set_state(GLToolbarItem::EState state) +{ + m_state = state; +} + +const std::string& GLToolbarItem::get_name() const +{ + return m_data.name; +} + +const std::string& GLToolbarItem::get_tooltip() const +{ + return m_data.tooltip; +} + +void GLToolbarItem::do_action() +{ + if (m_data.action_callback != nullptr) + m_data.action_callback->call(); +} + +bool GLToolbarItem::is_enabled() const +{ + return m_state != Disabled; +} + +bool GLToolbarItem::is_hovered() const +{ + return (m_state == Hover) || (m_state == HoverPressed); +} + +bool GLToolbarItem::is_pressed() const +{ + return (m_state == Pressed) || (m_state == HoverPressed); +} + +bool GLToolbarItem::is_toggable() const +{ + return m_data.is_toggable; +} + +bool GLToolbarItem::is_separator() const +{ + return m_type == Separator; +} + +void GLToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const +{ + GLTexture::render_sub_texture(tex_id, left, right, bottom, top, _get_uvs(texture_size, border_size, icon_size, gap_size)); +} + +GLTexture::Quad_UVs GLToolbarItem::_get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const +{ + GLTexture::Quad_UVs uvs; + + float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f; + + float scaled_icon_size = (float)icon_size * inv_texture_size; + float scaled_border_size = (float)border_size * inv_texture_size; + float scaled_gap_size = (float)gap_size * inv_texture_size; + float stride = scaled_icon_size + scaled_gap_size; + + float left = scaled_border_size + (float)m_state * stride; + float right = left + scaled_icon_size; + float top = scaled_border_size + (float)m_data.sprite_id * stride; + float bottom = top + scaled_icon_size; + + uvs.left_top = { left, top }; + uvs.left_bottom = { left, bottom }; + uvs.right_bottom = { right, bottom }; + uvs.right_top = { right, top }; + + return uvs; +} + +GLToolbar::ItemsIconsTexture::ItemsIconsTexture() + : items_icon_size(0) + , items_icon_border_size(0) + , items_icon_gap_size(0) +{ +} + +GLToolbar::Layout::Layout() + : type(Horizontal) + , top(0.0f) + , left(0.0f) + , separator_size(0.0f) + , gap_size(0.0f) +{ +} + +GLToolbar::GLToolbar(GLCanvas3D& parent) + : m_parent(parent) + , m_enabled(false) +{ +} + +bool GLToolbar::init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size) +{ + std::string path = resources_dir() + "/icons/"; + bool res = !icons_texture_filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture_filename, false); + if (res) + { + m_icons_texture.items_icon_size = items_icon_size; + m_icons_texture.items_icon_border_size = items_icon_border_size; + m_icons_texture.items_icon_gap_size = items_icon_gap_size; + } + + return res; +} + +GLToolbar::Layout::Type GLToolbar::get_layout_type() const +{ + return m_layout.type; +} + +void GLToolbar::set_layout_type(GLToolbar::Layout::Type type) +{ + m_layout.type = type; +} + +void GLToolbar::set_position(float top, float left) +{ + m_layout.top = top; + m_layout.left = left; +} + +void GLToolbar::set_separator_size(float size) +{ + m_layout.separator_size = size; +} + +void GLToolbar::set_gap_size(float size) +{ + m_layout.gap_size = size; +} + +bool GLToolbar::is_enabled() const +{ + return m_enabled; +} + +void GLToolbar::set_enabled(bool enable) +{ + m_enabled = true; +} + +bool GLToolbar::add_item(const GLToolbarItem::Data& data) +{ + GLToolbarItem* item = new GLToolbarItem(GLToolbarItem::Action, data); + if (item == nullptr) + return false; + + m_items.push_back(item); + return true; +} + +bool GLToolbar::add_separator() +{ + GLToolbarItem::Data data; + GLToolbarItem* item = new GLToolbarItem(GLToolbarItem::Separator, data); + if (item == nullptr) + return false; + + m_items.push_back(item); + return true; +} + +float GLToolbar::get_width() const +{ + switch (m_layout.type) + { + default: + case Layout::Horizontal: + { + return _get_width_horizontal(); + } + case Layout::Vertical: + { + return _get_width_vertical(); + } + } +} + +float GLToolbar::get_height() const +{ + switch (m_layout.type) + { + default: + case Layout::Horizontal: + { + return _get_height_horizontal(); + } + case Layout::Vertical: + { + return _get_height_vertical(); + } + } +} + +void GLToolbar::enable_item(const std::string& name) +{ + for (GLToolbarItem* item : m_items) + { + if ((item->get_name() == name) && (item->get_state() == GLToolbarItem::Disabled)) + { + item->set_state(GLToolbarItem::Normal); + return; + } + } +} + +void GLToolbar::disable_item(const std::string& name) +{ + for (GLToolbarItem* item : m_items) + { + if (item->get_name() == name) + { + item->set_state(GLToolbarItem::Disabled); + return; + } + } +} + +bool GLToolbar::is_item_pressed(const std::string& name) const +{ + for (GLToolbarItem* item : m_items) + { + if (item->get_name() == name) + return item->is_pressed(); + } + + return false; +} + +void GLToolbar::update_hover_state(const Pointf& mouse_pos) +{ + if (!m_enabled) + return; + + switch (m_layout.type) + { + default: + case Layout::Horizontal: + { + _update_hover_state_horizontal(mouse_pos); + break; + } + case Layout::Vertical: + { + _update_hover_state_vertical(mouse_pos); + break; + } + } +} + +int GLToolbar::contains_mouse(const Pointf& mouse_pos) const +{ + if (!m_enabled) + return -1; + + switch (m_layout.type) + { + default: + case Layout::Horizontal: + { + return _contains_mouse_horizontal(mouse_pos); + } + case Layout::Vertical: + { + return _contains_mouse_vertical(mouse_pos); + } + } +} + +void GLToolbar::do_action(unsigned int item_id) +{ + if (item_id < (unsigned int)m_items.size()) + { + GLToolbarItem* item = m_items[item_id]; + if ((item != nullptr) && !item->is_separator() && item->is_hovered()) + { + if (item->is_toggable()) + { + GLToolbarItem::EState state = item->get_state(); + if (state == GLToolbarItem::Hover) + item->set_state(GLToolbarItem::HoverPressed); + else if (state == GLToolbarItem::HoverPressed) + item->set_state(GLToolbarItem::Hover); + + m_parent.render(); + item->do_action(); + } + else + { + item->set_state(GLToolbarItem::HoverPressed); + m_parent.render(); + item->do_action(); + if (item->get_state() != GLToolbarItem::Disabled) + { + // the item may get disabled during the action, if not, set it back to hover state + item->set_state(GLToolbarItem::Hover); + m_parent.render(); + } + } + } + } +} + +void GLToolbar::render() const +//void GLToolbar::render(const Pointf& mouse_pos) const +{ + if (!m_enabled || m_items.empty()) + return; + + ::glDisable(GL_DEPTH_TEST); + + ::glPushMatrix(); + ::glLoadIdentity(); + + switch (m_layout.type) + { + default: + case Layout::Horizontal: + { + _render_horizontal(); + break; + } + case Layout::Vertical: + { + _render_vertical(); + break; + } + } + + ::glPopMatrix(); +} + +float GLToolbar::_get_width_horizontal() const +{ + return _get_main_size(); +} + +float GLToolbar::_get_width_vertical() const +{ + return m_icons_texture.items_icon_size; +} + +float GLToolbar::_get_height_horizontal() const +{ + return m_icons_texture.items_icon_size; +} + +float GLToolbar::_get_height_vertical() const +{ + return _get_main_size(); +} + +float GLToolbar::_get_main_size() const +{ + float size = 0.0f; + for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i) + { + if (m_items[i]->is_separator()) + size += m_layout.separator_size; + else + size += (float)m_icons_texture.items_icon_size; + } + + if (m_items.size() > 1) + size += ((float)m_items.size() - 1.0f) * m_layout.gap_size; + + return size; +} + +void GLToolbar::_update_hover_state_horizontal(const Pointf& mouse_pos) +{ + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = m_parent.get_canvas_size(); + Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + std::string tooltip = ""; + + for (GLToolbarItem* item : m_items) + { + if (item->is_separator()) + left += separator_stride; + else + { + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + GLToolbarItem::EState state = item->get_state(); + bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top); + + switch (state) + { + case GLToolbarItem::Normal: + { + if (inside) + item->set_state(GLToolbarItem::Hover); + + break; + } + case GLToolbarItem::Hover: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLToolbarItem::Normal); + + break; + } + case GLToolbarItem::Pressed: + { + if (inside) + item->set_state(GLToolbarItem::HoverPressed); + + break; + } + case GLToolbarItem::HoverPressed: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLToolbarItem::Pressed); + + break; + } + default: + case GLToolbarItem::Disabled: + { + break; + } + } + + left += icon_stride; + } + } + + m_parent.set_tooltip(tooltip); +} + +void GLToolbar::_update_hover_state_vertical(const Pointf& mouse_pos) +{ + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = m_parent.get_canvas_size(); + Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + std::string tooltip = ""; + + for (GLToolbarItem* item : m_items) + { + if (item->is_separator()) + top -= separator_stride; + else + { + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + GLToolbarItem::EState state = item->get_state(); + bool inside = (left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top); + + switch (state) + { + case GLToolbarItem::Normal: + { + if (inside) + item->set_state(GLToolbarItem::Hover); + + break; + } + case GLToolbarItem::Hover: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLToolbarItem::Normal); + + break; + } + case GLToolbarItem::Pressed: + { + if (inside) + item->set_state(GLToolbarItem::HoverPressed); + + break; + } + case GLToolbarItem::HoverPressed: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLToolbarItem::Pressed); + + break; + } + default: + case GLToolbarItem::Disabled: + { + break; + } + } + + top -= icon_stride; + } + } + + m_parent.set_tooltip(tooltip); +} + +int GLToolbar::_contains_mouse_horizontal(const Pointf& mouse_pos) const +{ + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = m_parent.get_canvas_size(); + Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + int id = -1; + + for (GLToolbarItem* item : m_items) + { + ++id; + + if (item->is_separator()) + left += separator_stride; + else + { + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top)) + return id; + + left += icon_stride; + } + } + + return -1; +} + +int GLToolbar::_contains_mouse_vertical(const Pointf& mouse_pos) const +{ + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = m_parent.get_canvas_size(); + Pointf scaled_mouse_pos((mouse_pos.x - 0.5f * (float)cnv_size.get_width()) * inv_zoom, (0.5f * (float)cnv_size.get_height() - mouse_pos.y) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + int id = -1; + + for (GLToolbarItem* item : m_items) + { + ++id; + + if (item->is_separator()) + top -= separator_stride; + else + { + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + if ((left <= scaled_mouse_pos.x) && (scaled_mouse_pos.x <= right) && (bottom <= scaled_mouse_pos.y) && (scaled_mouse_pos.y <= top)) + return id; + + top -= icon_stride; + } + } + + return -1; +} + +void GLToolbar::_render_horizontal() const +{ + unsigned int tex_id = m_icons_texture.texture.get_id(); + int tex_size = m_icons_texture.texture.get_width(); + + if ((tex_id == 0) || (tex_size <= 0)) + return; + + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + // renders icons + for (const GLToolbarItem* item : m_items) + { + if (item->is_separator()) + left += separator_stride; + else + { + item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.items_icon_border_size, m_icons_texture.items_icon_size, m_icons_texture.items_icon_gap_size); + left += icon_stride; + } + } +} + +void GLToolbar::_render_vertical() const +{ + unsigned int tex_id = m_icons_texture.texture.get_id(); + int tex_size = m_icons_texture.texture.get_width(); + + if ((tex_id == 0) || (tex_size <= 0)) + return; + + float zoom = m_parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + float scaled_separator_size = m_layout.separator_size * inv_zoom; + float scaled_gap_size = m_layout.gap_size * inv_zoom; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top; + + // renders icons + for (const GLToolbarItem* item : m_items) + { + if (item->is_separator()) + top -= separator_stride; + else + { + item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.items_icon_border_size, m_icons_texture.items_icon_size, m_icons_texture.items_icon_gap_size); + top -= icon_stride; + } + } +} + +} // namespace GUI +} // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLToolbar.hpp b/xs/src/slic3r/GUI/GLToolbar.hpp new file mode 100644 index 0000000000..b6eb6b19c4 --- /dev/null +++ b/xs/src/slic3r/GUI/GLToolbar.hpp @@ -0,0 +1,177 @@ +#ifndef slic3r_GLToolbar_hpp_ +#define slic3r_GLToolbar_hpp_ + +#include "../../slic3r/GUI/GLTexture.hpp" +#include "../../libslic3r/Utils.hpp" + +#include +#include + +namespace Slic3r { + +class Pointf; + +namespace GUI { + +class GLCanvas3D; + +class GLToolbarItem +{ +public: + enum EType : unsigned char + { + Action, + Separator, + Num_Types + }; + + enum EState : unsigned char + { + Normal, + Pressed, + Disabled, + Hover, + HoverPressed, + Num_States + }; + + struct Data + { + std::string name; + std::string tooltip; + unsigned int sprite_id; + bool is_toggable; + PerlCallback* action_callback; + + Data(); + }; + +private: + EType m_type; + EState m_state; + Data m_data; + +public: + GLToolbarItem(EType type, const Data& data); + + EState get_state() const; + void set_state(EState state); + + const std::string& get_name() const; + const std::string& get_tooltip() const; + + void do_action(); + + bool is_enabled() const; + bool is_hovered() const; + bool is_pressed() const; + + bool is_toggable() const; + bool is_separator() const; + + void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const; + +private: + GLTexture::Quad_UVs _get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const; +}; + +class GLToolbar +{ +public: + // items icon textures are assumed to be square and all with the same size in pixels, no internal check is done + // icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState + // from left to right + struct ItemsIconsTexture + { + GLTexture texture; + // size of the square icons, in pixels + unsigned int items_icon_size; + // distance from the border, in pixels + unsigned int items_icon_border_size; + // distance between two adjacent icons (to avoid filtering artifacts), in pixels + unsigned int items_icon_gap_size; + + ItemsIconsTexture(); + }; + + struct Layout + { + enum Type : unsigned char + { + Horizontal, + Vertical, + Num_Types + }; + + Type type; + float top; + float left; + float separator_size; + float gap_size; + + Layout(); + }; + +private: + typedef std::vector ItemsList; + + GLCanvas3D& m_parent; + bool m_enabled; + ItemsIconsTexture m_icons_texture; + Layout m_layout; + + ItemsList m_items; + +public: + explicit GLToolbar(GLCanvas3D& parent); + + bool init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size); + + Layout::Type get_layout_type() const; + void set_layout_type(Layout::Type type); + + void set_position(float top, float left); + void set_separator_size(float size); + void set_gap_size(float size); + + bool is_enabled() const; + void set_enabled(bool enable); + + bool add_item(const GLToolbarItem::Data& data); + bool add_separator(); + + float get_width() const; + float get_height() const; + + void enable_item(const std::string& name); + void disable_item(const std::string& name); + + bool is_item_pressed(const std::string& name) const; + + void update_hover_state(const Pointf& mouse_pos); + + // returns the id of the item under the given mouse position or -1 if none + int contains_mouse(const Pointf& mouse_pos) const; + + void do_action(unsigned int item_id); + + void render() const; + +private: + float _get_width_horizontal() const; + float _get_width_vertical() const; + float _get_height_horizontal() const; + float _get_height_vertical() const; + float _get_main_size() const; + void _update_hover_state_horizontal(const Pointf& mouse_pos); + void _update_hover_state_vertical(const Pointf& mouse_pos); + int _contains_mouse_horizontal(const Pointf& mouse_pos) const; + int _contains_mouse_vertical(const Pointf& mouse_pos) const; + void _render_horizontal() const; + void _render_vertical() const; +}; + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLToolbar_hpp_ diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 1a0fc9b9f9..515675a311 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -422,6 +422,13 @@ enable_shader(canvas, enable) CODE: _3DScene::enable_shader((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); +void +enable_toolbar(canvas, enable) + SV *canvas; + bool enable; + CODE: + _3DScene::enable_toolbar((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); + void enable_force_zoom_to_bed(canvas, enable) SV *canvas; @@ -443,6 +450,23 @@ allow_multisample(canvas, allow) CODE: _3DScene::allow_multisample((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), allow); +void +enable_toolbar_item(canvas, item, enable) + SV *canvas; + std::string item; + bool enable; + CODE: + _3DScene::enable_toolbar_item((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), item, enable); + +bool +is_toolbar_item_pressed(canvas, item) + SV *canvas; + std::string item; + CODE: + RETVAL = _3DScene::is_toolbar_item_pressed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), item); + OUTPUT: + RETVAL + void zoom_to_bed(canvas) SV *canvas; @@ -629,7 +653,98 @@ register_on_update_geometry_info_callback(canvas, callback) SV *callback; CODE: _3DScene::register_on_update_geometry_info_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); - + +void +register_action_add_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_add_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_delete_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_delete_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_deleteall_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_deleteall_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_arrange_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_arrange_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_more_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_more_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_fewer_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_fewer_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_ccw45_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_ccw45_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_cw45_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_cw45_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_scale_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_scale_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_split_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_split_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_cut_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_cut_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_settings_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_settings_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + +void +register_action_layersediting_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_action_layersediting_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + void reset_legend_texture() CODE: