From 3e8e7c78070db97ea88e5d84072b9a70d8da2771 Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Fri, 15 Mar 2024 15:12:01 +0800 Subject: [PATCH] Add the shadow layer on windows --- DSView/pv/interface/icallbacks.h | 2 +- DSView/pv/mainframe.cpp | 383 ++++++++++++++++----------- DSView/pv/mainframe.h | 32 +-- DSView/pv/mainwindow.h | 4 +- DSView/pv/winnativewidget.cpp | 293 ++++++++++++++++++--- DSView/pv/winnativewidget.h | 27 +- DSView/pv/winshadow.cpp | 426 +++++++++++++++++++++++++++++++ DSView/pv/winshadow.h | 114 +++++++++ 8 files changed, 1069 insertions(+), 212 deletions(-) create mode 100644 DSView/pv/winshadow.cpp create mode 100644 DSView/pv/winshadow.h diff --git a/DSView/pv/interface/icallbacks.h b/DSView/pv/interface/icallbacks.h index f8a9b6e5..aa523d24 100644 --- a/DSView/pv/interface/icallbacks.h +++ b/DSView/pv/interface/icallbacks.h @@ -116,7 +116,7 @@ public: }; enum ParentNativeEvent{ - EV_SCREEN_DPI_CHANGED = 0, + PARENT_EVENT_DISPLAY_CHANGED = 0, }; class IParentNativeEventCallback diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index ce45ca56..94c05535 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include @@ -77,29 +78,41 @@ MainFrame::MainFrame() _is_native_title = false; _is_resize_ready = false; _parentNativeWidget = NULL; - _mainWindow = NULL; - _is_max_status = false; - _move_start_screen = NULL; + _mainWindow = NULL; + _move_start_screen = NULL; + + _left = NULL; + _right = NULL; + _top = NULL; + _bottom = NULL; + _top_left = NULL; + _top_right = NULL; + _bottom_left = NULL; + _bottom_right = NULL; AppControl::Instance()->SetTopWindow(this); - // Make this a borderless window which can't - // be resized or moved via the window system + bool isWin32 = false; + #ifdef _WIN32 setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); _is_native_title = true; _taskBtn = NULL; + isWin32 = true; #else setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); setAttribute(Qt::WA_TranslucentBackground); _is_native_title = false; #endif - - // setMinimumWidth(MainWindow::Min_Width); - // setMinimumHeight(MainWindow::Min_Height); - setMinimumWidth(300); - setMinimumHeight(400); +#ifdef _WIN32 + if (!_is_native_title){ + setAttribute(Qt::WA_TranslucentBackground); + } +#endif + + setMinimumWidth(MainWindow::Min_Width); + setMinimumHeight(MainWindow::Min_Height); // Set the window icon QIcon icon; @@ -119,8 +132,9 @@ MainFrame::MainFrame() _layout = new QGridLayout(this); _layout->setSpacing(0); _layout->setContentsMargins(0,0,0,0); + - if (true) + if (!isWin32 || !_is_native_title) { _top_left = new widgets::Border (TopLeft, this); _top_left->setFixedSize(Margin, Margin); @@ -159,6 +173,9 @@ MainFrame::MainFrame() _layout->addWidget(_bottom, 2, 1); _layout->addWidget(_bottom_right, 2, 2); } + else{ + _layout->addLayout(vbox, 0, 0); + } #ifdef _WIN32 _taskBtn = new QWinTaskbarButton(this); @@ -175,82 +192,9 @@ MainFrame::MainFrame() connect(this, SIGNAL(sig_ParentNativeEvent(int)), this, SLOT(OnParentNaitveWindowEvent(int))); - //PrintRegionProc(); + } - -void MainFrame::PrintRegionProc() -{ - PrintRegion(); - - QTimer::singleShot(4000, this, [this](){ - PrintRegionProc(); - }); -} - -void MainFrame::PrintRegion() -{ - QRect rc = geometry(); - - int x = rc.left(); - int y = rc.top(); - int w = rc.width(); - int h = rc.height(); - - dsv_info("print region, x:%d, y:%d, w:%d, h:%d", - x, y, w, h); -} - -void MainFrame::AttachNativeWindow() -{ -#ifdef _WIN32 - int k = QApplication::desktop()->screen()->devicePixelRatio(); - - int x = _initWndInfo.r.x; - int y = _initWndInfo.r.y; - int w = _initWndInfo.r.w; - int h = _initWndInfo.r.h; - - x *= k; - y *= k; - w *= k; - h *= k; - - if (_parentNativeWidget != NULL){ - _parentNativeWidget->SetChildWidget(NULL); - delete _parentNativeWidget; - } - - _parentNativeWidget = new WinNativeWidget(x, y, w, h); - _parentNativeWidget->setGeometry(x, y, w, h); - _parentNativeWidget->SetChildWidget(this); - _parentNativeWidget->SetNativeEventCallback(this); - - if (_parentNativeWidget->Handle()) - { - _parentNativeWidget->Show(true); - - setWindowFlags(Qt::FramelessWindowHint); - setProperty("_q_embedded_native_parent_handle", (WId)_parentNativeWidget->Handle()); - SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); - - SetParent((HWND)winId(), _parentNativeWidget->Handle()); - QEvent e(QEvent::EmbeddingControl); - QApplication::sendEvent(this, &e); - - QTimer::singleShot(10, this, [this](){ - move(0,0); - setVisible(true); - - if (_initWndInfo.isMaxSize){ - showMaximized(); - } - _parentNativeWidget->ResizeChild(); - }); - } - -#endif -} - + void MainFrame::MoveWindow(int x, int y) { #ifdef _WIN32 @@ -280,7 +224,7 @@ QPoint MainFrame::GetParentPos() bool MainFrame::ParentIsMaxsized() { - return _is_max_status; + return IsMaxsized(); } void MainFrame::MoveBegin() @@ -308,11 +252,13 @@ void MainFrame::MoveEnd() #ifdef _WIN32 if (_parentNativeWidget != NULL){ auto scr = _parentNativeWidget->GetPointScreen(); - if (scr != _move_start_screen){ - _parentNativeWidget->UpdateChildDpi(); + if (scr != _move_start_screen){ + _parentNativeWidget->UpdateChildDpi(); + _parentNativeWidget->ResizeSelf(); } - + _parentNativeWidget->ResizeChild(); + _parentNativeWidget->MoveShadow(); _parentNativeWidget->SetMovingFlag(false); } #endif @@ -327,17 +273,24 @@ void MainFrame::OnParentNaitveWindowEvent(int msg) { #ifdef _WIN32 if (_parentNativeWidget != NULL){ - if (msg == EV_SCREEN_DPI_CHANGED){ + if (msg == PARENT_EVENT_DISPLAY_CHANGED){ QTimer::singleShot(100, this, [this](){ - _parentNativeWidget->UpdateChildDpi(); - _parentNativeWidget->ResizeChild(); - PopupDlgList::TryCloseAllByScreenChanged(); + _parentNativeWidget->OnDisplayChanged(); }); } } #endif } + +void MainFrame::OnMoveWinShadow() +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + _parentNativeWidget->MoveShadow(); + } +#endif +} void MainFrame::resizeEvent(QResizeEvent *event) { @@ -347,14 +300,14 @@ void MainFrame::resizeEvent(QResizeEvent *event) return; } - if (_is_max_status) { + if (IsMaxsized()) { hide_border(); } - else { + else if(IsNormalsized()) { show_border(); } - _titleBar->setRestoreButton(_is_max_status); + _titleBar->setRestoreButton(IsMaxsized()); _layout->update(); } @@ -385,6 +338,9 @@ void MainFrame::unfreezing() void MainFrame::hide_border() { + if (_top_left == NULL) + return; + _top_left->setVisible(false); _top_right->setVisible(false); _top->setVisible(false); @@ -397,6 +353,9 @@ void MainFrame::hide_border() void MainFrame::show_border() { + if (_top_left == NULL) + return; + _top_left->setVisible(true); _top_right->setVisible(true); _top->setVisible(true); @@ -409,16 +368,11 @@ void MainFrame::show_border() void MainFrame::showNormal() { - show_border(); - - dsv_info("Show as normal."); - - _is_max_status = false; + show_border(); #ifdef _WIN32 if (_parentNativeWidget){ - _parentNativeWidget->ShowNormal(); - + _parentNativeWidget->ShowNormal(); return; } #endif @@ -429,11 +383,7 @@ void MainFrame::showNormal() void MainFrame::showMaximized() { hide_border(); - - dsv_info("Show as maxsize."); - - _is_max_status = true; - + #ifdef _WIN32 if (_parentNativeWidget){ _parentNativeWidget->ShowMax(); @@ -445,9 +395,7 @@ void MainFrame::showMaximized() } void MainFrame::showMinimized() -{ - dsv_info("Show as minsize."); - +{ #ifdef _WIN32 if (_parentNativeWidget){ _parentNativeWidget->ShowMin(); @@ -471,23 +419,6 @@ void MainFrame::changeEvent(QEvent *event) QFrame::changeEvent(event); } -void MainFrame::moveToWinNaitiveNormal() -{ -#ifdef _WIN32 - if (_parentNativeWidget != NULL){ - - int k = QApplication::desktop()->screen()->devicePixelRatio(); - - int x = _normalRegion.x * k; - int y = _normalRegion.y * k; - int w = _normalRegion.w * k; - int h = _normalRegion.h * k; - - _parentNativeWidget->setGeometry(x, y, w, h); - } -#endif -} - bool MainFrame::eventFilter(QObject *object, QEvent *event) { const QEvent::Type type = event->type(); @@ -505,7 +436,7 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } //when window is maximized, or is moving, call return - if (_is_max_status || _titleBar->IsMoving()){ + if (IsMaxsized() || IsMoving()){ return QFrame::eventFilter(object, event); } @@ -545,17 +476,27 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) if (type == QEvent::MouseMove) { QPoint pt; + int k = 1; #ifdef _WIN32 POINT p; GetCursorPos(&p); pt.setX(p.x); pt.setY(p.y); + + if (_parentNativeWidget != NULL){ + auto scr = _parentNativeWidget->GetPointScreen(); + assert(scr); + k = scr->devicePixelRatio(); + } #else pt = mouse_event->globalPos(); #endif int datX = pt.x() - _clickPos.x(); int datY = pt.y() - _clickPos.y(); + datX /= k; + datY /= k; + int l = _dragStartRegion.left(); int t = _dragStartRegion.top(); int r = _dragStartRegion.right(); @@ -673,7 +614,6 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) setCursor(Qt::ArrowCursor); } - return QFrame::eventFilter(object, event); } @@ -682,7 +622,7 @@ void MainFrame::saveNormalRegion() if (!_is_resize_ready){ return; } - if (_is_max_status){ + if (!IsNormalsized()){ return; } @@ -691,7 +631,9 @@ void MainFrame::saveNormalRegion() #ifdef _WIN32 if (_parentNativeWidget != NULL){ RECT rc; - int k = QApplication::desktop()->screen()->devicePixelRatio(); + auto scr = _parentNativeWidget->GetPointScreen(); + assert(scr); + int k = scr->devicePixelRatio(); GetWindowRect(_parentNativeWidget->Handle(), &rc); app.frameOptions.left = rc.left / k; @@ -717,9 +659,9 @@ void MainFrame::saveNormalRegion() void MainFrame::writeSettings() { AppConfig &app = AppConfig::Instance(); - app.frameOptions.isMax = _is_max_status; + app.frameOptions.isMax = IsMaxsized(); - if (_is_max_status == false && isVisible()){ + if (IsNormalsized() && isVisible()){ saveNormalRegion(); } app.SaveFrame(); @@ -752,23 +694,18 @@ void MainFrame::ShowFormInit() h++; } + dsv_info("Init form, x:%d, y:%d, w:%d, h:%d, k:%d", + x, y, w, h, _initWndInfo.k); + bool isWin32 = false; #ifdef _WIN32 isWin32 = true; #endif - if (_initWndInfo.isMaxSize) - { - if (isWin32 && _is_native_title){ - hide_border(); - move(_normalRegion.x, _normalRegion.y); - resize(_normalRegion.w, _normalRegion.h); - } - else{ - move(x, y); - showMaximized(); - } + if (_initWndInfo.isMaxSize){ + move(x, y); + showMaximized(); } else{ move(x, y); @@ -776,12 +713,96 @@ void MainFrame::ShowFormInit() } QFrame::show(); - - dsv_info("Init form, x:%d, y:%d, w:%d, h:%d", x, y, w, h); - + + #ifdef _WIN32 if (_is_native_title){ AttachNativeWindow(); - } + } +#endif +} + +void MainFrame::AttachNativeWindow() +{ +#ifdef _WIN32 + + assert(_parentNativeWidget == NULL); + + int k = _initWndInfo.k; + + int x = _normalRegion.x; + int y = _normalRegion.y; + int w = _normalRegion.w; + int h = _normalRegion.h; + + x *= k; + y *= k; + w *= k; + h *= k; + + WinNativeWidget *nativeWindow = new WinNativeWidget(x, y, w, h); + nativeWindow->setGeometry(x, y, w, h); + + if (nativeWindow->Handle() == NULL){ + dsv_info("ERROR: native window is invalid."); + return; + } + + //check the normal region + QScreen *scr = nativeWindow->GetPointScreen(); + if (scr != NULL){ + QRect full_rc = scr->availableGeometry(); + + if (full_rc.width() - _normalRegion.w < 100 && !_initWndInfo.isMaxSize) + { + int w1 = full_rc.width() / 1.5; + int h1 = full_rc.height() / 1.5; + int x1 = full_rc.left() + (full_rc.width() - w1) / 2; + int y1 = full_rc.top() + (full_rc.height() - h1) / 2; + nativeWindow->setGeometry(x1 * k, y1 * k, w1 * k, h1 *k); + + dsv_info("%s:Reset the normal region, x:%d, y:%d, w:%d, h:%d", + scr->name().toStdString().c_str(), + x1, y1, w1, h1); + } + } + else{ + dsv_info("ERROR: get point screen error."); + } + + setWindowFlags(Qt::FramelessWindowHint); + setProperty("_q_embedded_native_parent_handle", (WId)nativeWindow->Handle()); + SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + SetParent((HWND)winId(), nativeWindow->Handle()); + + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(this, &e); + + if (_initWndInfo.isMaxSize){ + nativeWindow->ShowMax(); + } + else{ + nativeWindow->Show(true); + } + + nativeWindow->SetChildWidget(this); + nativeWindow->SetNativeEventCallback(this); + _parentNativeWidget = nativeWindow; + + auto shandow = _parentNativeWidget->Shadow(); + if (shandow){ + shandow->SetFrame(this); + connect(shandow, SIGNAL(showSignal()), this, SLOT(OnMoveWinShadow())); + } + + QTimer::singleShot(50, this, [this](){ + move(0,0); + setVisible(true); + _parentNativeWidget->UpdateChildDpi(); + _parentNativeWidget->ResizeChild(); + _parentNativeWidget->BeginShowShadow(); + }); + +#endif } void MainFrame::SetFormRegion(int x, int y, int w, int h) @@ -789,7 +810,9 @@ void MainFrame::SetFormRegion(int x, int y, int w, int h) #ifdef _WIN32 if (_parentNativeWidget != NULL){ - int k = QApplication::desktop()->screen()->devicePixelRatio(); + auto scr = _parentNativeWidget->GetPointScreen(); + assert(scr); + int k = scr->devicePixelRatio(); x *= k; y *= k; @@ -812,7 +835,9 @@ QRect MainFrame::GetFormRegion() #ifdef _WIN32 if (_parentNativeWidget != NULL){ - int k = QApplication::desktop()->screen()->devicePixelRatio(); + auto scr = _parentNativeWidget->GetPointScreen(); + assert(scr); + int k = scr->devicePixelRatio(); RECT r; GetWindowRect(_parentNativeWidget->Handle(), &r); int x = r.left; @@ -831,6 +856,49 @@ QRect MainFrame::GetFormRegion() return rc; } +bool MainFrame::IsMaxsized() +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + return _parentNativeWidget->IsMaxsized(); + } +#endif + + return QFrame::isMaximized(); +} + +bool MainFrame::IsNormalsized() +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + return _parentNativeWidget->IsNormalsized(); + } +#endif + + if (!QFrame::isMaximized() && !QFrame::isMinimized()){ + return true; + } + return false; +} + +bool MainFrame::IsMoving() +{ + return _titleBar->IsMoving(); +} + +int MainFrame::GetDevicePixelRatio() +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + auto scr = _parentNativeWidget->GetPointScreen(); + assert(scr); + return scr->devicePixelRatio(); + } +#endif + + return windowHandle()->devicePixelRatio(); +} + void MainFrame::ReadSettings() { AppConfig &app = AppConfig::Instance(); @@ -851,8 +919,8 @@ void MainFrame::ReadSettings() y = top; } - dsv_info("Loaded region, x:%d, y:%d, w:%d, h:%d", - x, y, right-left, bottom-top); + dsv_info("Read region info, x:%d, y:%d, w:%d, h:%d, isMax:%d", + x, y, right-left, bottom-top, app.frameOptions.isMax); bool bReset = false; int scrIndex = -1; @@ -888,6 +956,7 @@ void MainFrame::ReadSettings() _initWndInfo.r.w = 0; _initWndInfo.r.h = 0; _initWndInfo.isMaxSize = false; + int k = 1; if (app.frameOptions.isMax) { @@ -897,10 +966,12 @@ void MainFrame::ReadSettings() if (scrIndex == -1){ rc = QGuiApplication::primaryScreen()->availableGeometry(); scrName = QGuiApplication::primaryScreen()->name(); + k = QGuiApplication::primaryScreen()->devicePixelRatio(); } else{ rc = QGuiApplication::screens().at(scrIndex)->availableGeometry(); scrName = QGuiApplication::screens().at(scrIndex)->name(); + k = QGuiApplication::screens().at(scrIndex)->devicePixelRatio(); } _initWndInfo.r.x = rc.left(); @@ -931,10 +1002,12 @@ void MainFrame::ReadSettings() if (scrIndex == -1){ rc = QGuiApplication::primaryScreen()->availableGeometry(); scrName = QGuiApplication::primaryScreen()->name(); + k = QGuiApplication::primaryScreen()->devicePixelRatio(); } else{ rc = QGuiApplication::screens().at(scrIndex)->availableGeometry(); scrName = QGuiApplication::screens().at(scrIndex)->name(); + k = QGuiApplication::screens().at(scrIndex)->devicePixelRatio(); } int w = rc.width() / 1.5; @@ -971,6 +1044,7 @@ void MainFrame::ReadSettings() _normalRegion = _initWndInfo.r; QString scrName = QGuiApplication::screens().at(scrIndex)->name(); QRect rc = QGuiApplication::screens().at(scrIndex)->availableGeometry(); + k = QGuiApplication::screens().at(scrIndex)->devicePixelRatio(); dsv_info("Restore, screen:%s, x:%d, y:%d, w:%d, h:%d", scrName.toStdString().c_str() ,rc.left(), rc.top(), rc.width(), rc.height()); @@ -982,6 +1056,7 @@ void MainFrame::ReadSettings() // restore dockwidgets _mainWindow->restore_dock(); _titleBar->setRestoreButton(app.frameOptions.isMax); + _initWndInfo.k = k; } #ifdef _WIN32 diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index 67aa0b02..726cafbe 100644 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -64,6 +64,7 @@ struct FormInitInfo { FormRegion r; bool isMaxSize; + int k; }; class MainFrame : @@ -93,20 +94,25 @@ public: void ShowFormInit(); void ShowHelpDocAsync(); - - void PrintRegionProc(); - void PrintRegion(); + + bool IsMaxsized(); + bool IsNormalsized(); + bool IsMoving(); + int GetDevicePixelRatio(); + void SetFormRegion(int x, int y, int w, int h); + QRect GetFormRegion(); + void saveNormalRegion(); protected: void resizeEvent(QResizeEvent *event); void closeEvent(QCloseEvent *event); - bool eventFilter(QObject *object, QEvent *event); + bool eventFilter(QObject *object, QEvent *event) override; #ifdef _WIN32 void showEvent(QShowEvent *event); #endif void changeEvent(QEvent *event) override; - + signals: void sig_ParentNativeEvent(int msg); @@ -117,15 +123,14 @@ public slots: void showNormal(); void showMaximized(); - void showMinimized(); - void moveToWinNaitiveNormal(); + void showMinimized(); void OnParentNaitveWindowEvent(int msg); + void OnMoveWinShadow(); private: void hide_border(); void show_border(); void writeSettings(); - void saveNormalRegion(); void ReadSettings(); void AttachNativeWindow(); @@ -139,10 +144,8 @@ private: //IParentNativeEventCallback void OnParentNativeEvent(ParentNativeEvent msg) override; - - void SetFormRegion(int x, int y, int w, int h); - QRect GetFormRegion(); - + + private: toolbars::TitleBar *_titleBar; MainWindow *_mainWindow; @@ -168,12 +171,11 @@ private: #endif bool _is_native_title; - bool _is_resize_ready; + bool _is_resize_ready; WinNativeWidget *_parentNativeWidget; FormInitInfo _initWndInfo; - FormRegion _normalRegion; - bool _is_max_status; + FormRegion _normalRegion; QPoint _clickPos; QRect _dragStartRegion; QScreen *_move_start_screen; diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 15b98572..f5e82d74 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -84,8 +84,8 @@ class MainWindow : Q_OBJECT public: - static const int Min_Width = 800; - static const int Min_Height = 520; + static const int Min_Width = 350; + static const int Min_Height = 300; static const int Base_Height = 150; static const int Per_Chan_Height = 35; diff --git a/DSView/pv/winnativewidget.cpp b/DSView/pv/winnativewidget.cpp index b4591adc..099d9154 100644 --- a/DSView/pv/winnativewidget.cpp +++ b/DSView/pv/winnativewidget.cpp @@ -30,13 +30,21 @@ #include #include #include +#include +#include +#include +#include + #include "log.h" #include "../config.h" -#define NAI_WIN_CREATE_STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN +#define FIXED_WIDTH(widget) (widget->minimumWidth() >= widget->maximumWidth()) +#define FIXED_HEIGHT(widget) (widget->minimumHeight() >= widget->maximumHeight()) +#define FIXED_SIZE(widget) (FIXED_WIDTH(widget) && FIXED_HEIGHT(widget)) namespace pv { - + +//-----------------------------WinNativeWidget WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, const int height) { _childWindow = nullptr; @@ -44,6 +52,8 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons _hWnd = NULL; _event_callback = NULL; _is_moving = false; + _shadow = NULL; + _cur_screen = NULL; HBRUSH windowBackground = CreateSolidBrush(RGB(0, 0, 0)); HINSTANCE hInstance = GetModuleHandle(nullptr); @@ -55,7 +65,7 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons wcx.lpfnWndProc = WndProc; wcx.cbClsExtra = 0; wcx.cbWndExtra = 0; - wcx.lpszClassName = L"WindowClass"; + wcx.lpszClassName = L"DSViewWindowClass"; wcx.hbrBackground = windowBackground; wcx.hCursor = LoadCursor(hInstance, IDC_ARROW); @@ -66,15 +76,12 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons dsv_info("ERROR: can't register window class"); assert(false); } - - QString title = QApplication::applicationName() + " v" + QApplication::applicationVersion(); - wchar_t title_string_buffer[50]; - int title_len = title.toWCharArray(title_string_buffer); - title_string_buffer[title_len] = 0; - _hWnd = CreateWindow(L"WindowClass", title_string_buffer, - NAI_WIN_CREATE_STYLE, x, y, - width, height, 0, 0, hInstance, nullptr); + _hWnd = CreateWindow(L"DSViewWindowClass", L"DSView", + // WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + x, y, width, height, + NULL, NULL, hInstance, NULL); if (!_hWnd) { @@ -89,6 +96,11 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons WinNativeWidget::~WinNativeWidget() { if (_hWnd){ + if (_shadow){ + _shadow->hide(); + delete _shadow; + _shadow = NULL; + } Show(false); DestroyWindow(_hWnd); } @@ -101,6 +113,8 @@ void WinNativeWidget::SetChildWidget(QWidget *w) if (w != NULL){ _childWindow = (HWND)w->winId(); + _shadow = new WinShadow(_hWnd, w); + _shadow->createWinId(); } } @@ -115,6 +129,22 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam switch (message) { + case WM_ACTIVATE: + { + switch (wParam) + { + case WA_ACTIVE: + case WA_CLICKACTIVE: + { + self->BeginShowShadow(); + break; + } + case WA_INACTIVE: + { + break; + } + } + } case WM_SYSCOMMAND: { if (wParam == SC_KEYMENU) @@ -122,12 +152,12 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam RECT winrect; GetWindowRect(hWnd, &winrect); TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN, winrect.left + 5, winrect.top + 5, 0, hWnd, NULL); - break; } else { return DefWindowProc(hWnd, message, wParam, lParam); } + break;; } case WM_NCCALCSIZE: { @@ -150,24 +180,76 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam case WM_SIZE: { if (self->_childWindow != NULL){ - self->ResizeChild(); + self->ResizeChild(); + + if (self->_shadow){ + if (self->IsNormalsized()){ + self->_shadow->tryToShow(); + } + else{ + self->_shadow->hide(); + } + } + + self->MoveShadow(); } break; } - case WM_DPICHANGED: - if (self->_is_moving == false){ - if (self->_event_callback != NULL){ - self->_event_callback->OnParentNativeEvent(EV_SCREEN_DPI_CHANGED); - } - else{ - self->UpdateChildDpi(); - self->ResizeChild(); - } + case WM_GETMINMAXINFO: + { + if (self->childWidget) + { + auto gw = self->childWidget; + int k = gw->windowHandle()->devicePixelRatio(); + MINMAXINFO *mmi = reinterpret_cast(lParam); - dsv_info("Dpi was changed."); + int border_width = 0; + QSize minimum = gw->minimumSize(); + QSize sizeHint = gw->minimumSizeHint(); + + mmi->ptMinTrackSize.x = qFloor(qMax(minimum.width(), sizeHint.width()) * + k) + border_width * 2; + mmi->ptMinTrackSize.y = qFloor(qMax(minimum.height(), sizeHint.height()) * + k) + border_width; + + QSize maximum = gw->maximumSize(); + + mmi->ptMaxTrackSize.x = qFloor(maximum.width() * k) + border_width * 2; + mmi->ptMaxTrackSize.y = qFloor(maximum.height() * k) + border_width; } break; + } + case WM_DISPLAYCHANGE: + { + dsv_info("Display changed."); + + if (self->_event_callback != NULL){ + self->_event_callback->OnParentNativeEvent(PARENT_EVENT_DISPLAY_CHANGED); + } + + break; + } + case WM_WINDOWPOSCHANGING: + { + int st = 3; + if (self->IsMaxsized()) + st = 1; + else if (self->IsNormalsized()) + st = 2; + + if (self->childWidget != NULL && self->_shadow){ + if (st == 2){ + if (self->childWidget->isVisible() && !self->_is_moving){ + self->_shadow->showLater(); + } + } + else { + self->_shadow->hide(); + } + } + break; + } } return DefWindowProc(hWnd, message, wParam, lParam); @@ -177,27 +259,95 @@ void WinNativeWidget::ResizeChild() { if (_childWindow != NULL){ RECT rc; - GetClientRect(_hWnd, &rc); + GetWindowRect(_hWnd, &rc); - int w = rc.right; - int h = rc.bottom; - - WINDOWPLACEMENT wp; - wp.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(_hWnd, &wp); - - if (wp.showCmd == SW_MAXIMIZE) { + int sp = 0; + int x = sp; + int y = sp; + int w = rc.right - rc.left - sp * 2; + int h = rc.bottom - rc.top - sp * 2; + + if (IsMaxsized()) { w -= 8; h -= 8; } - - //childWidget->adjustSize(); - MoveWindow(_childWindow, 0, 0, w - 1 , h - 1 , 1); - MoveWindow(_childWindow, 0, 0, w , h , 1); - childWidget->updateGeometry(); + + MoveWindow(_childWindow, x, y, w - 1 , h - 1 , 1); + MoveWindow(_childWindow, x, y, w , h , 1); + childWidget->updateGeometry(); } } +void WinNativeWidget::ResizeSelf() +{ + if (_hWnd) + { + RECT rc; + GetWindowRect(_hWnd, &rc); + + int x = rc.left; + int y = rc.top; + int w = rc.right - rc.left; + int h = rc.bottom - rc.top; + + static int times = 0; + times++; + + if (times % 2 == 0){ + w += 2; + h += 2; + } + else{ + w -= 2; + h -= 2; + } + + MoveWindow(_hWnd, x, y, w , h , 1); + } +} + +void WinNativeWidget::MoveShadow() +{ + if (!_shadow || !childWidget){ + return; + } + + if (IsNormalsized()) + { + + RECT rc; + GetWindowRect(_hWnd, &rc); + + int bw = SHADOW_BORDER_WIDTH; + + // bw = 20; + + int x = rc.left; + int y = rc.top; + int w = rc.right - rc.left; + int h = rc.bottom - rc.top; + + x -= bw; + y -= bw; + w += bw * 2; + h += bw * 2; + + MoveWindow((HWND)_shadow->winId(), x, y, w , h , 1); + _shadow->setActive(isActiveWindow()); + } + else{ + _shadow->hide(); + _shadow->setActive(false); + _shadow->update(); + } +} + +bool WinNativeWidget::isActiveWindow() +{ + const HWND active_window = GetActiveWindow(); + return ((active_window == _hWnd) || IsChild(_hWnd, active_window)); +} + void WinNativeWidget::setGeometry(const int x, const int y, const int width, const int height) { // dsv_info("set parent window, x:%d, y:%d, w:%d, h:%d", x, y, width, height); @@ -210,6 +360,10 @@ void WinNativeWidget::Show(bool bShow) { if (_hWnd){ ShowWindow(_hWnd, bShow ? SW_SHOW : SW_HIDE); + + if (!bShow && _shadow){ + _shadow->hide(); + } } } @@ -217,7 +371,20 @@ void WinNativeWidget::Show(bool bShow) { RECT rc; GetClientRect(_hWnd, &rc); - MoveWindow(_hWnd, x, y, rc.right, rc.bottom, 0); + int w = rc.right; + int h = rc.bottom; + MoveWindow(_hWnd, x, y, w, h, 1); + + if (_shadow != NULL){ + auto scr = GetPointScreen(); + + if (_cur_screen && scr && scr != _cur_screen){ + _shadow->windowHandle()->setScreen(scr); + } + _cur_screen = scr; + + MoveShadow(); + } } void WinNativeWidget::ShowNormal() @@ -246,6 +413,12 @@ void WinNativeWidget::UpdateChildDpi() QScreen *scr = screenFromWindow(_hWnd); if (scr != NULL && childWidget != NULL){ childWidget->windowHandle()->setScreen(scr); + if (_shadow){ + _shadow->windowHandle()->setScreen(scr); + } + } + else{ + dsv_info("ERROR: failed to update child's screen."); } } @@ -282,4 +455,48 @@ QScreen* WinNativeWidget::GetPointScreen() return screenFromWindow(_hWnd); } +void WinNativeWidget::OnDisplayChanged() +{ + UpdateChildDpi(); + ResizeChild(); + + RECT rc; + GetWindowRect(_hWnd, &rc); + int w = rc.right - rc.left; + int h = rc.bottom - rc.top; + MoveWindow(_hWnd, rc.left, rc.top, w + 1, h + 1, 1); +} + +bool WinNativeWidget::IsMaxsized() +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(_hWnd, &wp); + return wp.showCmd == SW_MAXIMIZE; +} + +bool WinNativeWidget::IsMinsized() +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(_hWnd, &wp); + return wp.showCmd == SW_MINIMIZE; +} + +bool WinNativeWidget::IsNormalsized() +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(_hWnd, &wp); + return wp.showCmd == SW_SHOWNORMAL; +} + +void WinNativeWidget::BeginShowShadow() +{ + if (_shadow){ + _shadow->show(); + _shadow->showLater(); + } +} + } diff --git a/DSView/pv/winnativewidget.h b/DSView/pv/winnativewidget.h index 595e8c08..692b9c11 100644 --- a/DSView/pv/winnativewidget.h +++ b/DSView/pv/winnativewidget.h @@ -28,19 +28,23 @@ #include #include #include +#include + #include "interface/icallbacks.h" +#include "winshadow.h" #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 #endif namespace pv { + class WinNativeWidget { public: - WinNativeWidget(const int x, const int y, const int width, const int height); + WinNativeWidget(const int x, const int y, const int width, const int heigh); ~WinNativeWidget(); static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -62,9 +66,11 @@ public: void UpdateChildDpi(); void ResizeChild(); + void ResizeSelf(); inline void SetMovingFlag(bool bMoving){ _is_moving = bMoving; + _cur_screen = NULL; } QScreen* GetPointScreen(); @@ -73,15 +79,32 @@ public: _event_callback = callback; } + void OnDisplayChanged(); + bool IsMaxsized(); + bool IsMinsized(); + bool IsNormalsized(); + + void MoveShadow(); + + inline WinShadow* Shadow(){ + return _shadow; + } + + bool isActiveWindow(); + + void BeginShowShadow(); + private: QScreen* screenFromWindow(HWND hwnd); - + private: QWidget* childWidget; HWND _childWindow; HWND _hWnd; IParentNativeEventCallback *_event_callback; bool _is_moving; + WinShadow *_shadow; + QScreen *_cur_screen; }; } diff --git a/DSView/pv/winshadow.cpp b/DSView/pv/winshadow.cpp new file mode 100644 index 00000000..c8487e28 --- /dev/null +++ b/DSView/pv/winshadow.cpp @@ -0,0 +1,426 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2024 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "winshadow.h" +#include "log.h" +#include "config/appconfig.h" +#include "mainframe.h" +#include "mainwindow.h" + + +namespace pv { + +namespace + { + const QColor dark_border0 = QColor(80, 80, 80, 255); + const QColor dark_border1 = QColor(48, 47, 47, 200); + const QColor dark_border2 = QColor(48, 47, 47, 150); + const QColor dark_border3 = QColor(48, 47, 47, 100); + const QColor dark_border4 = QColor(48, 47, 47, 10); + + const QColor light_border0 = QColor(100, 100, 100, 255); + const QColor light_border1 = QColor(150, 150, 150, 150); + const QColor light_border2 = QColor(150, 150, 150, 100); + const QColor light_border3 = QColor(150, 150, 150, 50); + const QColor light_border4 = QColor(150, 150, 150, 0); + + const int Margin = 4; + } + +WinShadow::WinShadow(HWND hwnd, QWidget *parent) : QWidget(parent) +{ + m_hwnd = HWND(hwnd); + m_active = true; + m_timer = NULL; + m_bClean = false; + _frame = NULL; + _hit_border = None; + _bDraging = false; + _freezing = false; + + setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_TranslucentBackground); + + m_timer = new QTimer(this); + connect(m_timer, &QTimer::timeout, this, &WinShadow::show); + + m_timer->setInterval(500); + m_timer->setSingleShot(true); + + _layout = new QGridLayout(this); + _layout->setSpacing(0); + _layout->setContentsMargins(0,0,0,0); + + setLayout(_layout); + + if (true) + { + _top_left = new widgets::Border (TopLeft, this); + _top_left->setFixedSize(Margin, Margin); + _top_left->installEventFilter(this); + _top = new widgets::Border (Top, this); + _top->setFixedHeight(Margin); + _top->installEventFilter(this); + _top_right = new widgets::Border (TopRight, this); + _top_right->setFixedSize(Margin, Margin); + _top_right->installEventFilter(this); + + _left = new widgets::Border (Left, this); + _left->setFixedWidth(Margin); + _left->installEventFilter(this); + _right = new widgets::Border (Right, this); + _right->setFixedWidth(Margin); + _right->installEventFilter(this); + + _bottom_left = new widgets::Border (BottomLeft, this); + _bottom_left->setFixedSize(Margin, Margin); + _bottom_left->installEventFilter(this); + _bottom = new widgets::Border (Bottom, this); + _bottom->setFixedHeight(Margin); + _bottom->installEventFilter(this); + _bottom_right = new widgets::Border (BottomRight, this); + _bottom_right->setFixedSize(Margin, Margin); + _bottom_right->installEventFilter(this); + + _layout->addWidget(_top_left, 0, 0); + _layout->addWidget(_top, 0, 1); + _layout->addWidget(_top_right, 0, 2); + _layout->addWidget(_left, 1, 0); + + _layout->addWidget(_right, 1, 2); + _layout->addWidget(_bottom_left, 2, 0); + _layout->addWidget(_bottom, 2, 1); + _layout->addWidget(_bottom_right, 2, 2); + } +} + +int WinShadow::shadowWidth() +{ + return SHADOW_BORDER_WIDTH; +} + +void WinShadow::showLater() +{ + m_timer->stop(); + m_timer->start(); +} + +void WinShadow::show() +{ + m_bClean = false; + + if (m_timer->isActive()) + return; + + if (!IsWindowEnabled(m_hwnd)) + return; + + if (GetForegroundWindow() != m_hwnd) + return; + + Q_EMIT showSignal(); + + QWidget::show(); + QWidget::raise(); + + SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + +} + +bool WinShadow::tryToShow() +{ + if (!isVisible()){ + show(); + + if (!m_timer->isActive()){ + showLater(); + } + return true; + } + return false; +} + +void WinShadow::SetClean(bool bClean) +{ + m_bClean = bClean; + if (isVisible()){ + repaint(); + } +} + +void WinShadow::hide() +{ + SetClean(true); + m_timer->stop(); + + if (!isVisible()) + return; + + QWidget::hide(); +} + +void WinShadow::setActive(bool active) +{ + m_active = active; + repaint(); +} + +bool WinShadow::nativeEvent(const QByteArray &eventType, void *message, long *result) +{ + MSG *msg = static_cast(message); + + switch (msg->message) + { + case WM_ACTIVATE: + { + switch (msg->wParam) + { + case WA_ACTIVE: + case WA_CLICKACTIVE: + { + SetForegroundWindow(m_hwnd); + break; + } + default: + break; + } + + break; + } + case WM_MOUSEACTIVATE: + { + SetForegroundWindow(m_hwnd); + *result = MA_NOACTIVATE; + return true; + } + /* + case WM_NCMOUSEMOVE: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCHITTEST: + { + *result = long(SendMessageW(m_hwnd, msg->message, msg->wParam, msg->lParam)); + return true; + } + */ + default: + break; + } + + return QWidget::nativeEvent(eventType, message, result); +} + +bool WinShadow::eventFilter(QObject *object, QEvent *event) +{ + const QEvent::Type type = event->type(); + const QMouseEvent *const mouse_event = (QMouseEvent*)event; + int newWidth = 0; + int newHeight = 0; + int newLeft = 0; + int newTop = 0; + + if (_frame == NULL){ + return QWidget::eventFilter(object, event); + } + + if (type != QEvent::MouseMove + && type != QEvent::MouseButtonPress + && type != QEvent::MouseButtonRelease + && type != QEvent::Leave){ + return QWidget::eventFilter(object, event); + } + + //when window is maximized, or is moving, call return + if (_frame->IsMaxsized() || _frame->IsMoving()){ + return QWidget::eventFilter(object, event); + } + + if (!_bDraging && type == QEvent::MouseMove && (!(mouse_event->buttons() | Qt::NoButton))){ + if (object == _top_left) { + _hit_border = TopLeft; + setCursor(Qt::SizeFDiagCursor); + } else if (object == _bottom_right) { + _hit_border = BottomRight; + setCursor(Qt::SizeFDiagCursor); + } else if (object == _top_right) { + _hit_border = TopRight; + setCursor(Qt::SizeBDiagCursor); + } else if (object == _bottom_left) { + _hit_border = BottomLeft; + setCursor(Qt::SizeBDiagCursor); + } else if (object == _left) { + _hit_border = Left; + setCursor(Qt::SizeHorCursor); + } else if (object == _right) { + _hit_border = Right; + setCursor(Qt::SizeHorCursor); + } else if (object == _bottom) { + _hit_border = Bottom; + setCursor(Qt::SizeVerCursor); + } else if (object == _top) { + _hit_border = Top; + setCursor(Qt::SizeVerCursor); + } else { + _hit_border = None; + setCursor(Qt::ArrowCursor); + } + + return QWidget::eventFilter(object, event); + } + + if (type == QEvent::MouseMove) { + + QPoint pt; + int k = _frame->GetDevicePixelRatio(); + + POINT p; + GetCursorPos(&p); + pt.setX(p.x); + pt.setY(p.y); + + + int datX = pt.x() - _clickPos.x(); + int datY = pt.y() - _clickPos.y(); + datX /= k; + datY /= k; + + int l = _dragStartRegion.left(); + int t = _dragStartRegion.top(); + int r = _dragStartRegion.right(); + int b = _dragStartRegion.bottom(); + + if(mouse_event->buttons().testFlag(Qt::LeftButton)) { + + // Do nothing this time. + if (_freezing){ + return QWidget::eventFilter(object, event); + } + + int minW = MainWindow::Min_Width; + int minH = MainWindow::Min_Height; + + switch (_hit_border) { + case TopLeft: + l += datX; + t += datY; + if (r - l < minW) + l = r - minW; + if (b - t < minH) + t = b - minH; + break; + + case BottomLeft: + l += datX; + b += datY; + if (r - l < minW) + l = r - minW; + if (b - t < minH) + b = t + minH; + break; + + case TopRight: + r += datX; + t += datY; + if (r - l < minW) + r = l + minW; + if (b - t < minH) + t = b - minH; + break; + + case BottomRight: + r += datX; + b += datY; + if (r - l < minW) + r = l + minW; + if (b - t < minH) + b = t + minH; + break; + + case Left: + l += datX; + if (r - l < minW) + l = r - minW; + break; + + case Right: + r += datX; + if (r - l < minW) + r = l + minW; + break; + + case Top: + t += datY; + if (b - t < minH) + t = b - minH; + break; + + case Bottom: + b += datY; + if (b - t < minH) + b = t + minH; + break; + + default: + r = l; + break; + } + + if (r != l){ + _frame->SetFormRegion(l, t, r-l, b-t); + _frame->saveNormalRegion(); + } + + return true; + } + } + else if (type == QEvent::MouseButtonPress) { + if (mouse_event->button() == Qt::LeftButton) + if (_hit_border != None) + _bDraging = true; + _timer.start(50); + + + POINT p; + GetCursorPos(&p); + _clickPos.setX(p.x); + _clickPos.setY(p.y); + + + _dragStartRegion = _frame->GetFormRegion(); + } + else if (type == QEvent::MouseButtonRelease) { + if (mouse_event->button() == Qt::LeftButton) { + _bDraging = false; + _timer.stop(); + } + } + else if (!_bDraging && type == QEvent::Leave) { + _hit_border = None; + setCursor(Qt::ArrowCursor); + } + + return QWidget::eventFilter(object, event); +} + +} diff --git a/DSView/pv/winshadow.h b/DSView/pv/winshadow.h new file mode 100644 index 00000000..f04b58fb --- /dev/null +++ b/DSView/pv/winshadow.h @@ -0,0 +1,114 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2024 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef WINSHADOW_H +#define WINSHADOW_H + +#include +#include +#include +#include +#include + +#include "widgets/border.h" + + +#define SHADOW_BORDER_WIDTH 4 + +namespace pv { + +class MainFrame; + +class WinShadow : public QWidget +{ + Q_OBJECT + + enum borderTypes{ + None, + TopLeft, + Left, + BottomLeft, + Bottom, + BottomRight, + Right, + TopRight, + Top + }borderTypes; + +public: + explicit WinShadow(HWND hwnd, QWidget *parent); + + bool tryToShow(); + + void SetClean(bool bClean); + + inline void SetFrame(MainFrame *frame){ + _frame = frame; + } + +Q_SIGNALS: + void showSignal(); + +public Q_SLOTS: + void showLater(); + void show(); + void hide(); + void setActive(bool active); + int shadowWidth(); + +private: + //Functions + bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; + + bool eventFilter(QObject *object, QEvent *event) override; + + +private: + + QTimer *m_timer; + HWND m_hwnd; + bool m_active; + bool m_bClean; + + QGridLayout *_layout; + widgets::Border *_left; + widgets::Border *_right; + widgets::Border *_top; + widgets::Border *_bottom; + widgets::Border *_top_left; + widgets::Border *_top_right; + widgets::Border *_bottom_left; + widgets::Border *_bottom_right; + + MainFrame *_frame; + + int _hit_border; + bool _bDraging; + QTimer _timer; + bool _freezing; + QPoint _clickPos; + QRect _dragStartRegion; + +}; + +} + +#endif // SHADOW_H