Files
OrcaSlicer/src/slic3r/GUI/BBLTopbar.cpp
T
HanifKoh 4895bc03b4 Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced (#16099)
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced

Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.

clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.

* Remove Unused Project Includes From Files With Platform-Specific Code

A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.

* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass

The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.

* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call

* Include Headers That Files Reached Through Ones the Cleanup Removed

* Drop Includes Duplicated by the Cleanup or by Main's Own Additions

* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
2026-10-05 16:47:17 +08:00

824 lines
26 KiB
C++

#include "BBLTopbar.hpp"
#include "wx/artprov.h"
#include "wx/aui/framemanager.h"
#include "wx/display.h"
#include <wx/gdicmn.h>
#include <wx/event.h>
#include <wx/dcbuffer.h>
#include <wx/dc.h>
#include <wx/aui/auibar.h>
#include "slic3r/GUI/Widgets/StateColor.hpp"
#include <wx/settings.h>
#include "slic3r/GUI/Widgets/Label.hpp"
#include <wx/image.h>
#include <wx/string.h>
#include <cstddef>
#include <wx/utils.h>
#include <wx/window.h>
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "wxExtensions.hpp"
#include "Plater.hpp"
#include "MainFrame.hpp"
#include "WebViewDialog.hpp"
#include "PartPlate.hpp"
#include <boost/log/trivial.hpp>
#include "libslic3r/AppConfig.hpp"
#ifdef __WXGTK__
#include <gtk/gtk.h>
#endif
#define TOPBAR_ICON_SIZE 18
#define TOPBAR_TITLE_WIDTH 300
using namespace Slic3r;
enum CUSTOM_ID
{
ID_TOP_MENU_TOOL = 3100,
ID_LOGO,
ID_TOP_FILE_MENU,
ID_TOP_DROPDOWN_MENU,
ID_TITLE,
ID_MODEL_STORE,
ID_CALIB,
ID_TOOL_BAR = 3200,
ID_AMS_NOTEBOOK,
};
CenteredTitle::CenteredTitle(wxWindow* parent)
: wxControl()
{
SetBackgroundStyle(wxBG_STYLE_PAINT);
Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
wxBufferedPaintDC dc(this);
dc.SetBackground(wxBrush(wxColour(38, 46, 48)));
dc.Clear();
dc.SetTextForeground(*wxWHITE);
wxFontMetrics fm = dc.GetFontMetrics();
int textHeight = fm.ascent + fm.descent;
wxRect rect = GetClientRect();
wxString ellipsized = wxControl::Ellipsize(m_title, dc, wxELLIPSIZE_END, wxMax(0, rect.GetWidth() - FromDIP(8)));
int y = rect.y + (rect.height - textHeight) / 2 + 1;
int x = rect.x + ((ellipsized != m_title) // is ellipsized
? FromDIP(4) // align to left when clipped
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2); // centered when has available space
dc.DrawText(ellipsized, x, y);
});
// repaint for Ellipsize
Bind(wxEVT_SIZE, [this](wxSizeEvent& e) {
Refresh();
e.Skip();
});
auto forwardMouseEvent = [this](wxMouseEvent& e) {
if (e.LeftDown() && e.GetClickCount() > 1) return; // prevent duplicate event
e.SetPosition(GetParent()->ScreenToClient(ClientToScreen(e.GetPosition())));
GetParent()->GetEventHandler()->ProcessEvent(e);
};
Bind(wxEVT_LEFT_DOWN, forwardMouseEvent);
Bind(wxEVT_LEFT_DCLICK, forwardMouseEvent);
}
void CenteredTitle::SetTitle(const wxString& title) {
m_title = title;
Refresh();
}
// required for proper height
wxSize CenteredTitle::DoGetBestSize() const
{
return wxSize(10, FromDIP(30));
}
class BBLTopbarArt : public wxAuiDefaultToolBarArt
{
public:
virtual void DrawBackground(wxDC& dc, wxWindow* wnd, const wxRect& rect) wxOVERRIDE;
virtual void DrawButton(wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& item, const wxRect& rect) wxOVERRIDE;
};
void BBLTopbarArt::DrawBackground(wxDC& dc, wxWindow* wnd, const wxRect& rect)
{
dc.SetBrush(wxBrush(wxColour(38, 46, 48)));
wxRect clipRect = rect;
clipRect.y -= 8;
clipRect.height += 8;
dc.SetClippingRegion(clipRect);
dc.DrawRectangle(rect);
dc.DestroyClippingRegion();
}
void BBLTopbarArt::DrawButton(wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& item, const wxRect& rect)
{
int textWidth = 0, textHeight = 0;
wxFontMetrics fm;
if (m_flags & wxAUI_TB_TEXT)
{
dc.SetFont(m_font);
fm = dc.GetFontMetrics();
textHeight = fm.ascent + fm.descent;
dc.GetTextExtent(item.GetLabel(), &textWidth, nullptr);
}
int bmpX = 0, bmpY = 0;
int textX = 0, textY = 0;
// ORCA resolves the toolbar item bitmap using the actual window DPI context used for painting.
// GetBitmap() / GetDisabledBitmap() was using internal window pointer (m_window), not the paint-time wnd
// m_window was created before final DPI context was known so items not scales properly
const wxBitmap bmp = item.GetCurrentBitmapFor(wnd);
const wxSize bmpSize = bmp.IsOk() ? bmp.GetScaledSize() : wxSize(0, 0);
if (m_textOrientation == wxAUI_TBTOOL_TEXT_BOTTOM)
{
bmpX = rect.x +
(rect.width / 2) -
(bmpSize.x / 2);
bmpY = rect.y +
((rect.height - textHeight) / 2) -
(bmpSize.y / 2);
textX = rect.x + (rect.width / 2) - (textWidth / 2) + 1;
textY = rect.y + rect.height - textHeight - 1;
}
else if (m_textOrientation == wxAUI_TBTOOL_TEXT_RIGHT)
{
bmpX = rect.x + wnd->FromDIP(3);
bmpY = rect.y +
(rect.height / 2) -
(bmpSize.y / 2);
textX = bmpX + wnd->FromDIP(3) + bmpSize.x;
textY = bmpY + bmpSize.y / 2 - textHeight / 2 - fm.externalLeading + 1;
}
if (!(item.GetState() & wxAUI_BUTTON_STATE_DISABLED))
{
if (item.GetState() & wxAUI_BUTTON_STATE_PRESSED)
{
dc.SetPen(wxPen(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.SetBrush(wxBrush(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.DrawRectangle(rect);
}
else if ((item.GetState() & wxAUI_BUTTON_STATE_HOVER) || item.IsSticky())
{
dc.SetPen(wxPen(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.SetBrush(wxBrush(StateColor::darkModeColorFor("#009688"))); // ORCA
// draw an even lighter background for checked item hovers (since
// the hover background is the same color as the check background)
if (item.GetState() & wxAUI_BUTTON_STATE_CHECKED)
dc.SetBrush(wxBrush(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.DrawRectangle(rect);
}
else if (item.GetState() & wxAUI_BUTTON_STATE_CHECKED)
{
// it's important to put this code in an else statement after the
// hover, otherwise hovers won't draw properly for checked items
dc.SetPen(wxPen(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.SetBrush(wxBrush(StateColor::darkModeColorFor("#009688"))); // ORCA
dc.DrawRectangle(rect);
}
}
if (bmp.IsOk())
dc.DrawBitmap(bmp, bmpX, bmpY, true);
// set the item's text color based on if it is disabled
#ifdef __WINDOWS__
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
#else
dc.SetTextForeground(*wxWHITE);
#endif
if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED)
{
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
}
if ((m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty())
{
dc.DrawText(item.GetLabel(), textX, textY);
}
}
BBLTopbar::BBLTopbar(wxFrame* parent)
: wxAuiToolBar(parent, ID_TOOL_BAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_TEXT | wxAUI_TB_HORZ_TEXT)
{
Init(parent);
}
BBLTopbar::BBLTopbar(wxWindow* pwin, wxFrame* parent)
: wxAuiToolBar(pwin, ID_TOOL_BAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_TEXT | wxAUI_TB_HORZ_TEXT)
{
Init(parent);
}
void BBLTopbar::Init(wxFrame* parent)
{
auto* art = new BBLTopbarArt();
art->SetFont(Label::Body_12);
SetArtProvider(art);
m_frame = parent;
m_skip_popup_file_menu = false;
m_skip_popup_dropdown_menu = false;
m_skip_popup_calib_menu = false;
wxInitAllImageHandlers();
bool window_btns_on_left = false;
#ifdef __linux__
window_btns_on_left = wxGetApp().app_config->get("window_buttons_on_left") == "true";
if(window_btns_on_left){
wxBitmap close_bitmap = create_scaled_bitmap("topbar_close", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* close_btn = this->AddTool(wxID_CLOSE_FRAME, "", close_bitmap);
this->AddSpacer(FromDIP(4));
maximize_bitmap = create_scaled_bitmap("topbar_max", nullptr, TOPBAR_ICON_SIZE);
window_bitmap = create_scaled_bitmap("topbar_win", nullptr, TOPBAR_ICON_SIZE);
if (m_frame->IsMaximized()) {
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", window_bitmap);
}
else {
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", maximize_bitmap);
}
this->AddSpacer(FromDIP(4));
wxBitmap iconize_bitmap = create_scaled_bitmap("topbar_min", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* iconize_btn = this->AddTool(wxID_ICONIZE_FRAME, "", iconize_bitmap);
this->AddSpacer(15);
}
#endif
if(!window_btns_on_left)
this->AddSpacer(5);
/*wxBitmap logo_bitmap = create_scaled_bitmap("topbar_logo", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* logo_item = this->AddTool(ID_LOGO, "", logo_bitmap);
logo_item->SetHoverBitmap(logo_bitmap);
logo_item->SetActive(false);*/
wxBitmap file_bitmap = create_scaled_bitmap("topbar_file", nullptr, TOPBAR_ICON_SIZE);
m_file_menu_item = this->AddTool(ID_TOP_FILE_MENU, _L("File"), file_bitmap, wxEmptyString, wxITEM_NORMAL);
this->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
this->AddSpacer(FromDIP(5));
wxBitmap dropdown_bitmap = create_scaled_bitmap("topbar_dropdown", nullptr, TOPBAR_ICON_SIZE);
m_dropdown_menu_item = this->AddTool(ID_TOP_DROPDOWN_MENU, "",
dropdown_bitmap, wxEmptyString);
this->AddSpacer(FromDIP(5));
this->AddSeparator();
this->AddSpacer(FromDIP(5));
//wxBitmap open_bitmap = create_scaled_bitmap("topbar_open", nullptr, TOPBAR_ICON_SIZE);
//wxAuiToolBarItem* tool_item = this->AddTool(wxID_OPEN, "", open_bitmap);
this->AddSpacer(FromDIP(10));
wxBitmap save_bitmap = create_scaled_bitmap("topbar_save", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* save_btn = this->AddTool(wxID_SAVE, "", save_bitmap);
this->AddSpacer(FromDIP(10));
wxBitmap undo_bitmap = create_scaled_bitmap("topbar_undo", nullptr, TOPBAR_ICON_SIZE);
m_undo_item = this->AddTool(wxID_UNDO, "", undo_bitmap);
wxBitmap undo_inactive_bitmap = create_scaled_bitmap("topbar_undo_inactive", nullptr, TOPBAR_ICON_SIZE);
m_undo_item->SetDisabledBitmap(undo_inactive_bitmap);
this->AddSpacer(FromDIP(10));
wxBitmap redo_bitmap = create_scaled_bitmap("topbar_redo", nullptr, TOPBAR_ICON_SIZE);
m_redo_item = this->AddTool(wxID_REDO, "", redo_bitmap);
wxBitmap redo_inactive_bitmap = create_scaled_bitmap("topbar_redo_inactive", nullptr, TOPBAR_ICON_SIZE);
m_redo_item->SetDisabledBitmap(redo_inactive_bitmap);
this->AddSpacer(FromDIP(10));
wxBitmap calib_bitmap = create_scaled_bitmap("calib_sf", nullptr, TOPBAR_ICON_SIZE);
wxBitmap calib_bitmap_inactive = create_scaled_bitmap("calib_sf_inactive", nullptr, TOPBAR_ICON_SIZE);
m_calib_item = this->AddTool(ID_CALIB, _L("Calibration"), calib_bitmap);
m_calib_item->SetDisabledBitmap(calib_bitmap_inactive);
this->AddSpacer(FromDIP(25));
//this->AddStretchSpacer(1);
m_title_ctrl = new CenteredTitle(this);
m_title_ctrl->SetFont(Label::Body_12);
wxAuiToolBarItem* title_item = this->AddControl(m_title_ctrl, "");
title_item->SetProportion(1);
this->AddSpacer(FromDIP(25));
//this->AddStretchSpacer(1);
//this->EnableTool(m_publish_item->GetId(), false);
//this->AddSpacer(FromDIP(4));
/*wxBitmap model_store_bitmap = create_scaled_bitmap("topbar_store", nullptr, TOPBAR_ICON_SIZE);
m_model_store_item = this->AddTool(ID_MODEL_STORE, "", model_store_bitmap);
this->AddSpacer(12);
*/
//this->AddSeparator();
//this->AddSpacer(FromDIP(4));
if(!window_btns_on_left){
wxBitmap iconize_bitmap = create_scaled_bitmap("topbar_min", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* iconize_btn = this->AddTool(wxID_ICONIZE_FRAME, "", iconize_bitmap);
this->AddSpacer(FromDIP(4));
maximize_bitmap = create_scaled_bitmap("topbar_max", nullptr, TOPBAR_ICON_SIZE);
window_bitmap = create_scaled_bitmap("topbar_win", nullptr, TOPBAR_ICON_SIZE);
if (m_frame->IsMaximized()) {
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", window_bitmap);
}
else {
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", maximize_bitmap);
}
this->AddSpacer(FromDIP(4));
wxBitmap close_bitmap = create_scaled_bitmap("topbar_close", nullptr, TOPBAR_ICON_SIZE);
wxAuiToolBarItem* close_btn = this->AddTool(wxID_CLOSE_FRAME, "", close_bitmap);
}
Realize();
// m_toolbar_h = this->GetSize().GetHeight();
m_toolbar_h = FromDIP(30);
int client_w = parent->GetClientSize().GetWidth();
this->SetSize(client_w, m_toolbar_h);
this->Bind(wxEVT_MOTION, &BBLTopbar::OnMouseMotion, this);
this->Bind(wxEVT_MOUSE_CAPTURE_LOST, &BBLTopbar::OnMouseCaptureLost, this);
this->Bind(wxEVT_MENU_CLOSE, &BBLTopbar::OnMenuClose, this);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnFileToolItem, this, ID_TOP_FILE_MENU);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnDropdownToolItem, this, ID_TOP_DROPDOWN_MENU);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnCalibToolItem, this, ID_CALIB);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnIconize, this, wxID_ICONIZE_FRAME);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnFullScreen, this, wxID_MAXIMIZE_FRAME);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnCloseFrame, this, wxID_CLOSE_FRAME);
this->Bind(wxEVT_LEFT_DCLICK, &BBLTopbar::OnMouseLeftDClock, this);
this->Bind(wxEVT_LEFT_DOWN, &BBLTopbar::OnMouseLeftDown, this);
this->Bind(wxEVT_LEFT_UP, &BBLTopbar::OnMouseLeftUp, this);
this->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) {
m_last_mouse_position = wxDefaultPosition;
event.Skip();
});
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnOpenProject, this, wxID_OPEN);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnSaveProject, this, wxID_SAVE);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnRedo, this, wxID_REDO);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnUndo, this, wxID_UNDO);
//this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnModelStoreClicked, this, ID_MODEL_STORE);
}
BBLTopbar::~BBLTopbar()
{
m_file_menu_item = nullptr;
m_dropdown_menu_item = nullptr;
m_file_menu = nullptr;
}
void BBLTopbar::OnOpenProject(wxAuiToolBarEvent& event)
{
MainFrame* main_frame = dynamic_cast<MainFrame*>(m_frame);
Plater* plater = main_frame->plater();
plater->load_project();
}
void BBLTopbar::OnSaveProject(wxAuiToolBarEvent& event)
{
MainFrame* main_frame = dynamic_cast<MainFrame*>(m_frame);
Plater* plater = main_frame->plater();
plater->save_project();
}
void BBLTopbar::OnUndo(wxAuiToolBarEvent& event)
{
MainFrame* main_frame = dynamic_cast<MainFrame*>(m_frame);
Plater* plater = main_frame->plater();
plater->undo();
}
void BBLTopbar::OnRedo(wxAuiToolBarEvent& event)
{
MainFrame* main_frame = dynamic_cast<MainFrame*>(m_frame);
Plater* plater = main_frame->plater();
plater->redo();
}
void BBLTopbar::EnableUndoRedoItems()
{
this->EnableTool(m_undo_item->GetId(), true);
this->EnableTool(m_redo_item->GetId(), true);
this->EnableTool(m_calib_item->GetId(), true);
Refresh();
}
void BBLTopbar::DisableUndoRedoItems()
{
this->EnableTool(m_undo_item->GetId(), false);
this->EnableTool(m_redo_item->GetId(), false);
this->EnableTool(m_calib_item->GetId(), false);
Refresh();
}
void BBLTopbar::SaveNormalRect()
{
m_normalRect = m_frame->GetRect();
}
void BBLTopbar::ShowCalibrationButton(bool show)
{
m_calib_item->GetSizerItem()->Show(show);
m_sizer->Layout();
if (!show)
m_calib_item->GetSizerItem()->SetDimension({-1000, 0}, {0, 0});
Refresh();
}
void BBLTopbar::OnModelStoreClicked(wxAuiToolBarEvent& event)
{
//GUI::wxGetApp().load_url(wxString(wxGetApp().app_config->get_web_host_url() + MODEL_STORE_URL));
}
void BBLTopbar::SetFileMenu(wxMenu* file_menu)
{
m_file_menu = file_menu;
}
void BBLTopbar::AddDropDownSubMenu(wxMenu* sub_menu, const wxString& title)
{
m_top_menu.AppendSubMenu(sub_menu, title);
}
void BBLTopbar::AddDropDownMenuItem(wxMenuItem* menu_item)
{
m_top_menu.Append(menu_item);
}
wxMenu* BBLTopbar::GetTopMenu()
{
return &m_top_menu;
}
wxMenu* BBLTopbar::GetCalibMenu()
{
return &m_calib_menu;
}
void BBLTopbar::SetTitle(wxString title)
{
m_titleText = title;
if (m_title_ctrl)
m_title_ctrl->SetTitle(title);
}
void BBLTopbar::SetMaximizedSize()
{
maximize_btn->SetBitmap(maximize_bitmap);
}
void BBLTopbar::SetWindowSize()
{
maximize_btn->SetBitmap(window_bitmap);
}
void BBLTopbar::UpdateToolbarWidth(int width)
{
this->SetSize(width, m_toolbar_h);
}
void BBLTopbar::Rescale() {
int em = em_unit(this);
wxAuiToolBarItem* item;
/*item = this->FindTool(ID_LOGO);
item->SetBitmap(create_scaled_bitmap("topbar_logo", nullptr, TOPBAR_ICON_SIZE));*/
item = this->FindTool(ID_TOP_FILE_MENU);
item->SetBitmap(create_scaled_bitmap("topbar_file", this, TOPBAR_ICON_SIZE));
item = this->FindTool(ID_TOP_DROPDOWN_MENU);
item->SetBitmap(create_scaled_bitmap("topbar_dropdown", this, TOPBAR_ICON_SIZE));
//item = this->FindTool(wxID_OPEN);
//item->SetBitmap(create_scaled_bitmap("topbar_open", nullptr, TOPBAR_ICON_SIZE));
item = this->FindTool(wxID_SAVE);
item->SetBitmap(create_scaled_bitmap("topbar_save", this, TOPBAR_ICON_SIZE));
item = this->FindTool(wxID_UNDO);
item->SetBitmap(create_scaled_bitmap("topbar_undo", this, TOPBAR_ICON_SIZE));
item->SetDisabledBitmap(create_scaled_bitmap("topbar_undo_inactive", this, TOPBAR_ICON_SIZE));
item = this->FindTool(wxID_REDO);
item->SetBitmap(create_scaled_bitmap("topbar_redo", this, TOPBAR_ICON_SIZE));
item->SetDisabledBitmap(create_scaled_bitmap("topbar_redo_inactive", this, TOPBAR_ICON_SIZE));
item = this->FindTool(ID_CALIB);
item->SetBitmap(create_scaled_bitmap("calib_sf", this, TOPBAR_ICON_SIZE));
item->SetDisabledBitmap(create_scaled_bitmap("calib_sf_inactive", this, TOPBAR_ICON_SIZE));
if (m_title_ctrl)
m_title_ctrl->SetTitle(m_titleText);
/*item = this->FindTool(ID_MODEL_STORE);
item->SetBitmap(create_scaled_bitmap("topbar_store", this, TOPBAR_ICON_SIZE));
*/
item = this->FindTool(wxID_ICONIZE_FRAME);
item->SetBitmap(create_scaled_bitmap("topbar_min", this, TOPBAR_ICON_SIZE));
item = this->FindTool(wxID_MAXIMIZE_FRAME);
maximize_bitmap = create_scaled_bitmap("topbar_max", this, TOPBAR_ICON_SIZE);
window_bitmap = create_scaled_bitmap("topbar_win", this, TOPBAR_ICON_SIZE);
if (m_frame->IsMaximized()) {
item->SetBitmap(window_bitmap);
}
else {
item->SetBitmap(maximize_bitmap);
}
item = this->FindTool(wxID_CLOSE_FRAME);
item->SetBitmap(create_scaled_bitmap("topbar_close", this, TOPBAR_ICON_SIZE));
Realize();
}
void BBLTopbar::OnIconize(wxAuiToolBarEvent& event)
{
m_frame->Iconize();
}
void BBLTopbar::OnFullScreen(wxAuiToolBarEvent& event)
{
#ifdef __WXGTK__
GtkWindow* gtk_window = GTK_WINDOW(m_frame->m_widget);
if (gtk_window_is_maximized(gtk_window)) {
gtk_window_unmaximize(gtk_window);
}
else {
m_normalRect = m_frame->GetRect();
gtk_window_maximize(gtk_window);
}
return;
#endif
if (m_frame->IsMaximized()) {
m_frame->Restore();
}
else {
m_normalRect = m_frame->GetRect();
m_frame->Maximize();
}
}
void BBLTopbar::OnCloseFrame(wxAuiToolBarEvent& event)
{
m_frame->Close();
}
void BBLTopbar::OnMouseLeftDClock(wxMouseEvent& mouse)
{
m_last_mouse_position = mouse.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(mouse.GetPosition());
wxAuiToolBarItem* item = this->FindToolByPosition(mouse.GetX(), mouse.GetY());
// check whether mouse is not on any tool item
if (item != NULL && item->GetWindow() != m_title_ctrl) {
mouse.Skip();
return;
}
#ifdef __W1XMSW__
::PostMessage((HWND) m_frame->GetHandle(), WM_NCLBUTTONDBLCLK, HTCAPTION, MAKELPARAM(mouse_pos.x, mouse_pos.y));
return;
#endif // __WXMSW__
wxAuiToolBarEvent evt;
OnFullScreen(evt);
}
void BBLTopbar::OnFileToolItem(wxAuiToolBarEvent& evt)
{
wxAuiToolBar* tb = static_cast<wxAuiToolBar*>(evt.GetEventObject());
tb->SetToolSticky(evt.GetId(), true);
if (!m_skip_popup_file_menu) {
auto rec = this->GetToolRect(ID_TOP_FILE_MENU);
GetParent()->PopupMenu(m_file_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2));
}
else {
m_skip_popup_file_menu = false;
}
// make sure the button is "un-stuck"
tb->SetToolSticky(evt.GetId(), false);
}
void BBLTopbar::OnDropdownToolItem(wxAuiToolBarEvent& evt)
{
wxAuiToolBar* tb = static_cast<wxAuiToolBar*>(evt.GetEventObject());
tb->SetToolSticky(evt.GetId(), true);
if (!m_skip_popup_dropdown_menu) {
auto rec = this->GetToolRect(ID_TOP_DROPDOWN_MENU);
GetParent()->PopupMenu(&m_top_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2));
}
else {
m_skip_popup_dropdown_menu = false;
}
// make sure the button is "un-stuck"
tb->SetToolSticky(evt.GetId(), false);
}
void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt)
{
wxAuiToolBar *tb = static_cast<wxAuiToolBar *>(evt.GetEventObject());
tb->SetToolSticky(evt.GetId(), true);
if (!m_skip_popup_calib_menu) {
auto rec = this->GetToolRect(ID_CALIB);
GetParent()->PopupMenu(&m_calib_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2));
} else {
m_skip_popup_calib_menu = false;
}
// make sure the button is "un-stuck"
tb->SetToolSticky(evt.GetId(), false);
}
void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
{
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
wxPoint frame_pos = m_frame->GetScreenPosition();
wxAuiToolBarItem* item = this->FindToolByPosition(event.GetX(), event.GetY());
m_delta = mouse_pos - frame_pos;
if (item == NULL || item->GetWindow() == m_title_ctrl)
{
#ifdef __WXMSW__
CaptureMouse();
ReleaseMouse();
::PostMessage((HWND) m_frame->GetHandle(), WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(mouse_pos.x, mouse_pos.y));
return;
#elif defined(__WXGTK__)
// Use WM-integrated drag for smoother window movement on Linux.
gtk_window_begin_move_drag(
GTK_WINDOW(m_frame->m_widget),
1, // left mouse button
mouse_pos.x, mouse_pos.y,
gtk_get_current_event_time());
return;
#else
CaptureMouse();
#endif
}
event.Skip();
}
void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
{
m_last_mouse_position = event.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (HasCapture())
{
ReleaseMouse();
}
event.Skip();
}
void BBLTopbar::OnMouseMotion(wxMouseEvent& event)
{
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (!HasCapture()) {
//m_frame->OnMouseMotion(event);
event.Skip();
return;
}
if (event.Dragging() && event.LeftIsDown())
{
// leave max state and adjust position
if (m_frame->IsMaximized()) {
wxRect rect = m_frame->GetRect();
// Filter unexcept mouse move
if (m_delta + rect.GetLeftTop() != mouse_pos) {
m_delta = mouse_pos - rect.GetLeftTop();
m_delta.x = m_delta.x * m_normalRect.width / rect.width;
m_delta.y = m_delta.y * m_normalRect.height / rect.height;
m_frame->Restore();
}
}
m_frame->Move(mouse_pos - m_delta);
}
event.Skip();
}
void BBLTopbar::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
{
}
void BBLTopbar::OnMenuClose(wxMenuEvent& event)
{
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
if (item == m_file_menu_item) {
m_skip_popup_file_menu = true;
}
else if (item == m_dropdown_menu_item) {
m_skip_popup_dropdown_menu = true;
}
}
wxAuiToolBarItem* BBLTopbar::FindToolByCurrentPosition()
{
if (m_last_mouse_position != wxDefaultPosition && GetClientRect().Contains(m_last_mouse_position))
return this->FindToolByPosition(m_last_mouse_position.x, m_last_mouse_position.y);
#ifdef __WXGTK__
if (Slic3r::GUI::is_running_on_wayland())
return nullptr;
#endif
wxPoint mouse_pos = ::wxGetMousePosition();
wxPoint client_pos = this->ScreenToClient(mouse_pos);
return this->FindToolByPosition(client_pos.x, client_pos.y);
}
#ifdef __WXMSW__
#include <windowsx.h>
WXLRESULT CenteredTitle::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
switch (nMsg) {
case WM_NCHITTEST: {
// Pass all mouse event to parent
return HTTRANSPARENT;
}
}
return wxControl::MSWWindowProc(nMsg, wParam, lParam);
}
WXLRESULT BBLTopbar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
switch (nMsg) {
case WM_NCHITTEST: {
m_last_mouse_position = ScreenToClient({GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)});
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
if (item != NULL && item->GetWindow() != m_title_ctrl) {
break;
}
// Pass the event to main window if mouse is on the top bar and not on any of the buttons
return HTTRANSPARENT;
}
}
return wxAuiToolBar::MSWWindowProc(nMsg, wParam, lParam);
}
#endif