mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-25 00:58:35 -07:00
ENH: Flash filament dialog on outside click to prompt focus
Brief flicker reminds users to act on the dialog before proceeding elsewhere. jira: STUDIO-13492 Change-Id: I3daaa567f4aa738094fc01effcd9b9245aea9d2c (cherry picked from commit 3decd7a5e4f5a13b7fd1dbb0fc39e0b3849ed6d1)
This commit is contained in:
parent
44c13f3967
commit
723ce9d431
2 changed files with 174 additions and 9 deletions
|
|
@ -13,6 +13,10 @@
|
|||
#include <wx/stattext.h>
|
||||
#include <wx/button.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define COLOR_DEMO_SIZE wxSize(FromDIP(50), FromDIP(50))
|
||||
#define COLOR_BTN_BITMAP_SIZE wxSize(FromDIP(24), FromDIP(24))
|
||||
#define COLOR_BTN_SIZE wxSize(FromDIP(30), FromDIP(30))
|
||||
|
|
@ -37,6 +41,21 @@ void FilamentPickerDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||
Layout();
|
||||
}
|
||||
|
||||
// Flash effect implementation
|
||||
void FilamentPickerDialog::StartFlashing()
|
||||
{
|
||||
// Stop any existing flash timer
|
||||
if (m_flash_timer) {
|
||||
m_flash_timer->Stop();
|
||||
delete m_flash_timer;
|
||||
}
|
||||
|
||||
m_flash_timer = new wxTimer(this, wxID_ANY + 1);
|
||||
Bind(wxEVT_TIMER, &FilamentPickerDialog::OnFlashTimer, this, m_flash_timer->GetId());
|
||||
m_flash_step = 0;
|
||||
m_flash_timer->Start(50);
|
||||
}
|
||||
|
||||
FilamentPickerDialog::FilamentPickerDialog(wxWindow *parent, const wxString& fila_id, const FilamentColor& fila_color, const std::string& fila_type)
|
||||
: DPIDialog(parent ? parent : wxGetApp().mainframe,
|
||||
wxID_ANY,
|
||||
|
|
@ -118,10 +137,16 @@ FilamentPickerDialog::FilamentPickerDialog(wxWindow *parent, const wxString& fil
|
|||
// Set window transparency
|
||||
SetTransparent(255);
|
||||
BindEvents();
|
||||
|
||||
// Start click detection timer for outside click detection
|
||||
StartClickDetection();
|
||||
}
|
||||
|
||||
FilamentPickerDialog::~FilamentPickerDialog()
|
||||
{
|
||||
// Clean up all timers
|
||||
CleanupTimers();
|
||||
|
||||
delete m_color_query;
|
||||
m_color_query = nullptr;
|
||||
|
||||
|
|
@ -584,19 +609,12 @@ wxColourData FilamentPickerDialog::GetSingleColorData()
|
|||
|
||||
void FilamentPickerDialog::BindEvents()
|
||||
{
|
||||
// Bind mouse events
|
||||
// Bind mouse events for window dragging
|
||||
Bind(wxEVT_LEFT_DOWN, &FilamentPickerDialog::OnMouseLeftDown, this);
|
||||
Bind(wxEVT_MOTION, &FilamentPickerDialog::OnMouseMove, this);
|
||||
Bind(wxEVT_LEFT_UP, &FilamentPickerDialog::OnMouseLeftUp, this);
|
||||
|
||||
// Add safety event handlers to ensure mouse capture is released
|
||||
Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& event) {
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
}
|
||||
event.Skip();
|
||||
});
|
||||
|
||||
// Essential window events
|
||||
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) {
|
||||
if (HasCapture()) {
|
||||
ReleaseMouse();
|
||||
|
|
@ -728,5 +746,132 @@ void FilamentPickerDialog::OnButtonPaint(wxPaintEvent& event)
|
|||
dc.DrawRectangle(1, 1, COLOR_BTN_SIZE.GetWidth() - 1, COLOR_BTN_SIZE.GetHeight() - 1);
|
||||
}
|
||||
|
||||
bool FilamentPickerDialog::IsClickOnTopMostWindow(const wxPoint& mouse_pos)
|
||||
{
|
||||
wxWindow* main_window = wxGetApp().mainframe;
|
||||
if (!main_window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wxRect main_rect = main_window->GetScreenRect();
|
||||
bool in_main_app = main_rect.Contains(mouse_pos);
|
||||
|
||||
if (!in_main_app) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows: Use WindowFromPoint to check actual topmost window
|
||||
POINT pt = {mouse_pos.x, mouse_pos.y};
|
||||
HWND hwnd_at_point = WindowFromPoint(pt);
|
||||
HWND main_hwnd = (HWND)main_window->GetHandle();
|
||||
|
||||
// Check if clicked window belongs to our main window hierarchy
|
||||
HWND parent_hwnd = hwnd_at_point;
|
||||
while (parent_hwnd != NULL) {
|
||||
if (parent_hwnd == main_hwnd) {
|
||||
return true;
|
||||
}
|
||||
parent_hwnd = ::GetParent(parent_hwnd);
|
||||
}
|
||||
return false;
|
||||
|
||||
#elif defined(__WXOSX__)
|
||||
// macOS: Use focus and active window check
|
||||
return (wxGetActiveWindow() == main_window) || main_window->HasFocus();
|
||||
|
||||
#else
|
||||
// Linux: Use focus check (similar to macOS)
|
||||
return (wxGetActiveWindow() == main_window) || main_window->HasFocus();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::StartClickDetection()
|
||||
{
|
||||
if (m_click_timer) {
|
||||
StopClickDetection();
|
||||
}
|
||||
|
||||
m_click_timer = new wxTimer(this, wxID_ANY);
|
||||
Bind(wxEVT_TIMER, &FilamentPickerDialog::OnTimerCheck, this, m_click_timer->GetId());
|
||||
m_click_timer->Start(50);
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::StopClickDetection()
|
||||
{
|
||||
if (m_click_timer) {
|
||||
m_click_timer->Stop();
|
||||
delete m_click_timer;
|
||||
m_click_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::CleanupTimers()
|
||||
{
|
||||
StopClickDetection();
|
||||
|
||||
if (m_flash_timer) {
|
||||
m_flash_timer->Stop();
|
||||
delete m_flash_timer;
|
||||
m_flash_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Only perform complex detection when the mouse state actually changes
|
||||
void FilamentPickerDialog::OnTimerCheck(wxTimerEvent& event)
|
||||
{
|
||||
static wxPoint last_mouse_pos(-1, -1);
|
||||
wxPoint current_pos = wxGetMousePosition();
|
||||
|
||||
// If the mouse position and button state haven't changed, skip the detection
|
||||
if (current_pos == last_mouse_pos &&
|
||||
wxGetMouseState().LeftIsDown() == m_last_mouse_down) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_mouse_pos = current_pos;
|
||||
|
||||
wxPoint mouse_pos = wxGetMousePosition();
|
||||
wxRect window_rect = GetScreenRect();
|
||||
|
||||
// Check if mouse button state changed
|
||||
bool mouse_down = wxGetMouseState().LeftIsDown();
|
||||
|
||||
if (mouse_down != m_last_mouse_down) {
|
||||
if (mouse_down) {
|
||||
bool in_dialog = window_rect.Contains(mouse_pos);
|
||||
bool is_valid_click = IsClickOnTopMostWindow(mouse_pos);
|
||||
|
||||
if (is_valid_click && !in_dialog) {
|
||||
StartFlashing();
|
||||
}
|
||||
}
|
||||
|
||||
m_last_mouse_down = mouse_down;
|
||||
}
|
||||
}
|
||||
|
||||
void FilamentPickerDialog::OnFlashTimer(wxTimerEvent& event)
|
||||
{
|
||||
// 5 flashes = 10 steps (semi-transparent -> opaque for each flash)
|
||||
if (m_flash_step < 10) {
|
||||
if (m_flash_step % 2 == 0) {
|
||||
// Even steps: semi-transparent
|
||||
SetTransparent(120);
|
||||
} else {
|
||||
// Odd steps: opaque
|
||||
SetTransparent(255);
|
||||
}
|
||||
|
||||
m_flash_step++;
|
||||
} else {
|
||||
// Complete flash sequence
|
||||
SetTransparent(255);
|
||||
m_flash_timer->Stop();
|
||||
delete m_flash_timer;
|
||||
m_flash_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <wx/scrolwin.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/region.h>
|
||||
#include <wx/timer.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -39,6 +40,14 @@ protected:
|
|||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseLeftUp(wxMouseEvent& event);
|
||||
void OnButtonPaint(wxPaintEvent& event);
|
||||
void OnTimerCheck(wxTimerEvent& event);
|
||||
void OnFlashTimer(wxTimerEvent& event);
|
||||
|
||||
// Platform-independent window detection
|
||||
bool IsClickOnTopMostWindow(const wxPoint& mouse_pos);
|
||||
void StartClickDetection();
|
||||
void StopClickDetection();
|
||||
void CleanupTimers();
|
||||
|
||||
private:
|
||||
// UI creation methods
|
||||
|
|
@ -67,6 +76,9 @@ private:
|
|||
bool LoadFilamentData(const wxString& fila_id);
|
||||
wxColourData GetSingleColorData();
|
||||
|
||||
// Flash effect
|
||||
void StartFlashing();
|
||||
|
||||
// UI elements
|
||||
wxStaticBitmap* m_color_demo{nullptr};
|
||||
wxStaticText* m_label_preview_color{nullptr};
|
||||
|
|
@ -90,6 +102,14 @@ private:
|
|||
|
||||
// Mouse drag members
|
||||
wxPoint m_drag_delta;
|
||||
|
||||
// Click detection timers
|
||||
wxTimer* m_click_timer{nullptr};
|
||||
bool m_last_mouse_down{false};
|
||||
|
||||
// Flash effect timer
|
||||
wxTimer* m_flash_timer{nullptr};
|
||||
int m_flash_step{0};
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue