Optimize the native window on window system

This commit is contained in:
dreamsourcelabTAI 2024-03-25 11:19:23 +08:00
parent 441e514922
commit c83cd3c453
15 changed files with 4611 additions and 4654 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,164 +1,165 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2021 DreamSourceLab <support@dreamsourcelab.com>
*
* 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
*/
#pragma once
#include <string>
#include <vector>
#include <QString>
#include <QByteArray>
#define LAN_CN 25
#define LAN_EN 31
#define THEME_STYLE_DARK "dark"
#define THEME_STYLE_LIGHT "light"
#define APP_NAME "DSView"
//--------------------api---
QString GetIconPath();
QString GetAppDataDir();
QString GetFirmwareDir();
QString GetUserDataDir();
QString GetDecodeScriptDir();
QString GetProfileDir();
//------------------class
class StringPair
{
public:
StringPair(const std::string &key, const std::string &value);
std::string m_key;
std::string m_value;
};
#define APP_CONFIG_VERSION 3
#define NO_POINT_VALUE -10000
struct AppOptions
{
int version;
bool quickScroll;
bool warnofMultiTrig;
bool originalData;
bool ableSaveLog;
bool appendLogMode;
int logLevel;
bool transDecoderDlg;
bool trigPosDisplayInMid;
bool displayProfileInBar;
bool swapBackBufferAlways;
bool autoScrollLatestData;
float fontSize;
std::vector<StringPair> m_protocolFormats;
};
// The dock pannel open status.
struct DockOptions
{
bool decodeDock;
bool triggerDock;
bool measureDock;
bool searchDock;
};
struct FrameOptions
{
QString style;
int language;
int left; //frame region
int top;
int right;
int bottom;
int x;
int y;
int ox;
int oy;
bool isMax;
QByteArray windowState;
DockOptions _logicDock;
DockOptions _analogDock;
DockOptions _dsoDock;
};
struct UserHistory
{
QString exportDir;
QString saveDir;
bool showDocuments;
QString screenShotPath;
QString sessionDir;
QString openDir;
QString protocolExportPath;
QString exportFormat;
};
struct FontParam
{
QString name;
float size;
};
struct FontOptions
{
FontParam toolbar;
FontParam channelLabel;
FontParam channelBody;
FontParam ruler;
FontParam title;
FontParam other;
};
class AppConfig
{
private:
AppConfig();
~AppConfig();
AppConfig(AppConfig &o);
public:
static AppConfig &Instance();
void LoadAll();
void SaveApp();
void SaveHistory();
void SaveFrame();
void SetProtocolFormat(const std::string &protocolName, const std::string &value);
std::string GetProtocolFormat(const std::string &protocolName);
inline bool IsLangCn()
{
return frameOptions.language == LAN_CN;
}
static void GetFontSizeRange(float *minSize, float *maxSize);
public:
AppOptions appOptions;
UserHistory userHistory;
FrameOptions frameOptions;
};
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2021 DreamSourceLab <support@dreamsourcelab.com>
*
* 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
*/
#pragma once
#include <string>
#include <vector>
#include <QString>
#include <QByteArray>
#define LAN_CN 25
#define LAN_EN 31
#define THEME_STYLE_DARK "dark"
#define THEME_STYLE_LIGHT "light"
#define APP_NAME "DSView"
//--------------------api---
QString GetIconPath();
QString GetAppDataDir();
QString GetFirmwareDir();
QString GetUserDataDir();
QString GetDecodeScriptDir();
QString GetProfileDir();
//------------------class
class StringPair
{
public:
StringPair(const std::string &key, const std::string &value);
std::string m_key;
std::string m_value;
};
#define APP_CONFIG_VERSION 3
#define NO_POINT_VALUE -10000
struct AppOptions
{
int version;
bool quickScroll;
bool warnofMultiTrig;
bool originalData;
bool ableSaveLog;
bool appendLogMode;
int logLevel;
bool transDecoderDlg;
bool trigPosDisplayInMid;
bool displayProfileInBar;
bool swapBackBufferAlways;
bool autoScrollLatestData;
float fontSize;
std::vector<StringPair> m_protocolFormats;
};
// The dock pannel open status.
struct DockOptions
{
bool decodeDock;
bool triggerDock;
bool measureDock;
bool searchDock;
};
struct FrameOptions
{
QString style;
int language;
int left; //frame region
int top;
int right;
int bottom;
int x;
int y;
int ox;
int oy;
bool isMax;
QString displayName;
QByteArray windowState;
DockOptions _logicDock;
DockOptions _analogDock;
DockOptions _dsoDock;
};
struct UserHistory
{
QString exportDir;
QString saveDir;
bool showDocuments;
QString screenShotPath;
QString sessionDir;
QString openDir;
QString protocolExportPath;
QString exportFormat;
};
struct FontParam
{
QString name;
float size;
};
struct FontOptions
{
FontParam toolbar;
FontParam channelLabel;
FontParam channelBody;
FontParam ruler;
FontParam title;
FontParam other;
};
class AppConfig
{
private:
AppConfig();
~AppConfig();
AppConfig(AppConfig &o);
public:
static AppConfig &Instance();
void LoadAll();
void SaveApp();
void SaveHistory();
void SaveFrame();
void SetProtocolFormat(const std::string &protocolName, const std::string &value);
std::string GetProtocolFormat(const std::string &protocolName);
inline bool IsLangCn()
{
return frameOptions.language == LAN_CN;
}
static void GetFontSizeRange(float *minSize, float *maxSize);
public:
AppOptions appOptions;
UserHistory userHistory;
FrameOptions frameOptions;
};

View File

@ -1,128 +1,128 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2021 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 _I_CALLBACKS_
#define _I_CALLBACKS_
class ISessionCallback
{
public:
virtual void session_error()=0;
virtual void session_save()=0;
virtual void data_updated()=0;
virtual void update_capture()=0;
virtual void cur_snap_samplerate_changed()=0;
virtual void signals_changed()=0;
virtual void receive_trigger(quint64 trigger_pos)=0;
virtual void frame_ended()=0;
virtual void frame_began()=0;
virtual void show_region(uint64_t start, uint64_t end, bool keep)=0;
virtual void show_wait_trigger()=0;
virtual void repeat_hold(int percent)=0;
virtual void decode_done()=0;
virtual void receive_data_len(quint64 len)=0;
virtual void receive_header()=0;
virtual void trigger_message(int msg)=0;
virtual void delay_prop_msg(QString strMsg)=0;
};
class ISessionDataGetter
{
public:
virtual bool genSessionData(std::string &str) = 0;
};
class IDlgCallback
{
public:
virtual void OnDlgResult(bool bYes)=0;
};
class IMainForm{
public:
virtual void switchLanguage(int language)=0;
};
#define DSV_MSG_START_COLLECT_WORK_PREV 5001
#define DSV_MSG_START_COLLECT_WORK 5002
#define DSV_MSG_COLLECT_START 5003
#define DSV_MSG_COLLECT_END 5004
#define DSV_MSG_END_COLLECT_WORK_PREV 5005
#define DSV_MSG_END_COLLECT_WORK 5006
#define DSV_MSG_REV_END_PACKET 5007
#define DSV_MSG_DEVICE_LIST_UPDATED 6000
#define DSV_MSG_BEGIN_DEVICE_OPTIONS 6001 //Begin show device options dialog.
#define DSV_MSG_END_DEVICE_OPTIONS 6002
#define DSV_MSG_DEVICE_OPTIONS_UPDATED 6003
#define DSV_MSG_DEVICE_DURATION_UPDATED 6004
#define DSV_MSG_DEVICE_MODE_CHANGED 6005
#define DSV_MSG_CURRENT_DEVICE_CHANGE_PREV 6006
#define DSV_MSG_CURRENT_DEVICE_CHANGED 6007
#define DSV_MSG_NEW_USB_DEVICE 6008
#define DSV_MSG_CURRENT_DEVICE_DETACHED 6009
#define DSV_MSG_DEVICE_CONFIG_UPDATED 6010
#define DSV_MSG_DEMO_OPERATION_MODE_CHNAGED 6011
#define DSV_MSG_COLLECT_MODE_CHANGED 6012
#define DSV_MSG_DATA_POOL_CHANGED 6013
#define DSV_MSG_TRIG_NEXT_COLLECT 7001
#define DSV_MSG_SAVE_COMPLETE 7002
#define DSV_MSG_STORE_CONF_PREV 7003
#define DSV_MSG_CLEAR_DECODE_DATA 8001
#define DSV_MSG_APP_OPTIONS_CHANGED 9001
#define DSV_MSG_FONT_OPTIONS_CHANGED 9002
class IMessageListener
{
public:
virtual void OnMessage(int msg)=0;
};
class IDecoderPannel
{
public:
virtual void update_deocder_item_name(void *trace_handel, const char *name)=0;
};
class IFontForm
{
public:
virtual void update_font()=0;
};
enum ParentNativeEvent{
PARENT_EVENT_DISPLAY_CHANGED = 0,
};
class IParentNativeEventCallback
{
public:
virtual void OnParentNativeEvent(ParentNativeEvent msg)=0;
};
#endif
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2021 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 _I_CALLBACKS_
#define _I_CALLBACKS_
class ISessionCallback
{
public:
virtual void session_error()=0;
virtual void session_save()=0;
virtual void data_updated()=0;
virtual void update_capture()=0;
virtual void cur_snap_samplerate_changed()=0;
virtual void signals_changed()=0;
virtual void receive_trigger(quint64 trigger_pos)=0;
virtual void frame_ended()=0;
virtual void frame_began()=0;
virtual void show_region(uint64_t start, uint64_t end, bool keep)=0;
virtual void show_wait_trigger()=0;
virtual void repeat_hold(int percent)=0;
virtual void decode_done()=0;
virtual void receive_data_len(quint64 len)=0;
virtual void receive_header()=0;
virtual void trigger_message(int msg)=0;
virtual void delay_prop_msg(QString strMsg)=0;
};
class ISessionDataGetter
{
public:
virtual bool genSessionData(std::string &str) = 0;
};
class IDlgCallback
{
public:
virtual void OnDlgResult(bool bYes)=0;
};
class IMainForm{
public:
virtual void switchLanguage(int language)=0;
};
#define DSV_MSG_START_COLLECT_WORK_PREV 5001
#define DSV_MSG_START_COLLECT_WORK 5002
#define DSV_MSG_COLLECT_START 5003
#define DSV_MSG_COLLECT_END 5004
#define DSV_MSG_END_COLLECT_WORK_PREV 5005
#define DSV_MSG_END_COLLECT_WORK 5006
#define DSV_MSG_REV_END_PACKET 5007
#define DSV_MSG_DEVICE_LIST_UPDATED 6000
#define DSV_MSG_BEGIN_DEVICE_OPTIONS 6001 //Begin show device options dialog.
#define DSV_MSG_END_DEVICE_OPTIONS 6002
#define DSV_MSG_DEVICE_OPTIONS_UPDATED 6003
#define DSV_MSG_DEVICE_DURATION_UPDATED 6004
#define DSV_MSG_DEVICE_MODE_CHANGED 6005
#define DSV_MSG_CURRENT_DEVICE_CHANGE_PREV 6006
#define DSV_MSG_CURRENT_DEVICE_CHANGED 6007
#define DSV_MSG_NEW_USB_DEVICE 6008
#define DSV_MSG_CURRENT_DEVICE_DETACHED 6009
#define DSV_MSG_DEVICE_CONFIG_UPDATED 6010
#define DSV_MSG_DEMO_OPERATION_MODE_CHNAGED 6011
#define DSV_MSG_COLLECT_MODE_CHANGED 6012
#define DSV_MSG_DATA_POOL_CHANGED 6013
#define DSV_MSG_TRIG_NEXT_COLLECT 7001
#define DSV_MSG_SAVE_COMPLETE 7002
#define DSV_MSG_STORE_CONF_PREV 7003
#define DSV_MSG_CLEAR_DECODE_DATA 8001
#define DSV_MSG_APP_OPTIONS_CHANGED 9001
#define DSV_MSG_FONT_OPTIONS_CHANGED 9002
class IMessageListener
{
public:
virtual void OnMessage(int msg)=0;
};
class IDecoderPannel
{
public:
virtual void update_deocder_item_name(void *trace_handel, const char *name)=0;
};
class IFontForm
{
public:
virtual void update_font()=0;
};
enum ParentNativeEvent{
PARENT_EVENT_DISPLAY_CHANGED = 0,
};
class IParentNativeEventCallback
{
public:
virtual void OnParentNativeEvent(ParentNativeEvent msg)=0;
};
#endif

View File

@ -75,7 +75,7 @@ MainFrame::MainFrame()
_freezing = false;
_titleBar = NULL;
_mainWindow = NULL;
_is_native_title = false;
_is_win32_parent_window = false;
_is_resize_ready = false;
_parentNativeWidget = NULL;
_mainWindow = NULL;
@ -95,18 +95,19 @@ MainFrame::MainFrame()
bool isWin32 = false;
#ifdef _WIN32
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
_is_native_title = true;
setWindowFlags(Qt::FramelessWindowHint);
_is_win32_parent_window = true;
_taskBtn = NULL;
isWin32 = true;
#else
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
setAttribute(Qt::WA_TranslucentBackground);
_is_native_title = false;
_is_win32_parent_window = false;
#endif
#ifdef _WIN32
if (!_is_native_title){
if (!_is_win32_parent_window){
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
setAttribute(Qt::WA_TranslucentBackground);
}
#endif
@ -134,7 +135,7 @@ MainFrame::MainFrame()
_layout->setContentsMargins(0,0,0,0);
if (!isWin32 || !_is_native_title)
if (!isWin32 || !_is_win32_parent_window)
{
_top_left = new widgets::Border (TopLeft, this);
_top_left->setFixedSize(Margin, Margin);
@ -230,8 +231,7 @@ bool MainFrame::ParentIsMaxsized()
void MainFrame::MoveBegin()
{
#ifdef _WIN32
if (_parentNativeWidget != NULL){
_parentNativeWidget->SetMovingFlag(true);
if (_parentNativeWidget != NULL){
_move_start_screen = _parentNativeWidget->GetPointScreen();
}
#endif
@ -247,19 +247,18 @@ void MainFrame::MoveEnd()
SetFormRegion(rc.x(), rc.y(), rc.width(), rc.height());
}
#ifndef _WIN32
saveNormalRegion();
#endif
#ifdef _WIN32
if (_parentNativeWidget != NULL){
auto scr = _parentNativeWidget->GetPointScreen();
if (scr != _move_start_screen){
_parentNativeWidget->UpdateChildDpi();
_parentNativeWidget->ResizeSelf();
_parentNativeWidget->UpdateChildDpi();
}
_parentNativeWidget->ResizeChild();
_parentNativeWidget->MoveShadow();
_parentNativeWidget->SetMovingFlag(false);
_parentNativeWidget->ResizeChild();
}
#endif
}
@ -272,22 +271,23 @@ void MainFrame::OnParentNativeEvent(ParentNativeEvent msg)
void MainFrame::OnParentNaitveWindowEvent(int msg)
{
#ifdef _WIN32
if (_parentNativeWidget != NULL){
if (msg == PARENT_EVENT_DISPLAY_CHANGED){
QTimer::singleShot(100, this, [this](){
PopupDlgList::TryCloseAllByScreenChanged();
_parentNativeWidget->OnDisplayChanged();
});
}
}
#endif
}
if (_parentNativeWidget != NULL
&& msg == PARENT_EVENT_DISPLAY_CHANGED){
void MainFrame::OnMoveWinShadow()
{
#ifdef _WIN32
if (_parentNativeWidget != NULL){
_parentNativeWidget->MoveShadow();
QTimer::singleShot(100, this, [this](){
auto scr = _parentNativeWidget->GetPointScreen();
if (scr == NULL){
dsv_info("ERROR: failed to get point screen, will to get the primary.");
scr = QGuiApplication::primaryScreen();
}
PopupDlgList::TryCloseAllByScreenChanged(scr);
PopupDlgList::SetCurrentScreen(scr);
_parentNativeWidget->UpdateChildDpi();
_parentNativeWidget->ResizeChild();
_parentNativeWidget->ReShowWindow();
});
}
#endif
}
@ -320,7 +320,8 @@ void MainFrame::closeEvent(QCloseEvent *event)
#ifdef _WIN32
if (_parentNativeWidget != NULL){
_parentNativeWidget->SetChildWidget(NULL);
_parentNativeWidget->Show(false);
setVisible(false);
_parentNativeWidget->Show(false);
}
#endif
@ -428,6 +429,12 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event)
int newLeft = 0;
int newTop = 0;
#ifdef _WIN32
if (_parentNativeWidget != NULL){
return QFrame::eventFilter(object, event);
}
#endif
if (type != QEvent::MouseMove
&& type != QEvent::MouseButtonPress
&& type != QEvent::MouseButtonRelease
@ -477,21 +484,8 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event)
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;
@ -580,7 +574,9 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event)
if (r != l){
SetFormRegion(l, t, r-l, b-t);
saveNormalRegion();
#ifndef _WIN32
saveNormalRegion();
#endif
}
return true;
@ -592,15 +588,7 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event)
_bDraging = true;
_timer.start(50);
#ifdef _WIN32
POINT p;
GetCursorPos(&p);
_clickPos.setX(p.x);
_clickPos.setY(p.y);
#else
_clickPos = mouse_event->globalPos();
#endif
_dragStartRegion = GetFormRegion();
}
else if (type == QEvent::MouseButtonRelease) {
@ -630,10 +618,8 @@ void MainFrame::saveNormalRegion()
#ifdef _WIN32
if (_parentNativeWidget != NULL){
RECT rc;
auto scr = _parentNativeWidget->GetPointScreen();
assert(scr);
int k = scr->devicePixelRatio();
RECT rc;
int k = _parentNativeWidget->GetDevicePixelRatio();
GetWindowRect(_parentNativeWidget->Handle(), &rc);
app.frameOptions.left = rc.left / k;
@ -661,6 +647,18 @@ void MainFrame::writeSettings()
AppConfig &app = AppConfig::Instance();
app.frameOptions.isMax = IsMaxsized();
#ifdef _WIN32
if (_parentNativeWidget != NULL){
auto scr = _parentNativeWidget->GetPointScreen();
app.frameOptions.displayName = scr->name();
}
else{
app.frameOptions.displayName = windowHandle()->screen()->name();
}
#else
app.frameOptions.displayName = windowHandle()->screen()->name();
#endif
if (IsNormalsized() && isVisible()){
saveNormalRegion();
}
@ -698,24 +696,31 @@ void MainFrame::ShowFormInit()
x, y, w, h, _initWndInfo.k);
bool isWin32 = false;
#ifdef _WIN32
isWin32 = true;
#endif
if (_initWndInfo.isMaxSize){
move(x, y);
showMaximized();
if (isWin32 &&_is_win32_parent_window){
resize(w, h);
}
else{
showMaximized();
}
}
else{
move(x, y);
resize(w, h);
}
QFrame::show();
#ifdef _WIN32
if (_is_native_title){
if (!_is_win32_parent_window){
QFrame::show();
return;
}
#ifdef _WIN32
if (_is_win32_parent_window){
AttachNativeWindow();
}
#endif
@ -727,19 +732,19 @@ void MainFrame::AttachNativeWindow()
assert(_parentNativeWidget == NULL);
int k = _initWndInfo.k;
int x = _normalRegion.x;
int y = _normalRegion.y;
int w = _normalRegion.w;
int h = _normalRegion.h;
int k = _initWndInfo.k;
int x = _normalRegion.x * k;
int y = _normalRegion.y * k;
int w = _normalRegion.w * k;
int h = _normalRegion.h * k;
x *= k;
y *= k;
w *= k;
h *= k;
bool isDrak = false;
if (AppConfig::Instance().frameOptions.style == THEME_STYLE_DARK){
isDrak = true;
}
WinNativeWidget *nativeWindow = new WinNativeWidget(x, y, w, h);
WinNativeWidget *nativeWindow = new WinNativeWidget(x, y, w, h, isDrak);
nativeWindow->setGeometry(x, y, w, h);
if (nativeWindow->Handle() == NULL){
@ -751,6 +756,7 @@ void MainFrame::AttachNativeWindow()
QScreen *scr = nativeWindow->GetPointScreen();
if (scr != NULL){
QRect full_rc = scr->availableGeometry();
PopupDlgList::SetCurrentScreen(scr);
if (full_rc.width() - _normalRegion.w < 100 && !_initWndInfo.isMaxSize)
{
@ -769,6 +775,12 @@ void MainFrame::AttachNativeWindow()
dsv_info("ERROR: get point screen error.");
}
nativeWindow->SetChildWidget(this);
nativeWindow->SetNativeEventCallback(this);
nativeWindow->UpdateChildDpi();
nativeWindow->SetTitleBarWidget(_titleBar);
_titleBar->EnableAbleDrag(false);
setWindowFlags(Qt::FramelessWindowHint);
setProperty("_q_embedded_native_parent_handle", (WId)nativeWindow->Handle());
SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
@ -776,6 +788,8 @@ void MainFrame::AttachNativeWindow()
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(this, &e);
setVisible(true);
if (_initWndInfo.isMaxSize){
nativeWindow->ShowMax();
@ -783,25 +797,10 @@ void MainFrame::AttachNativeWindow()
else{
nativeWindow->Show(true);
}
nativeWindow->SetChildWidget(this);
nativeWindow->SetNativeEventCallback(this);
nativeWindow->SetBorderColor(QColor(0x80, 0x80, 0x80));
_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
}
@ -810,9 +809,7 @@ void MainFrame::SetFormRegion(int x, int y, int w, int h)
#ifdef _WIN32
if (_parentNativeWidget != NULL){
auto scr = _parentNativeWidget->GetPointScreen();
assert(scr);
int k = scr->devicePixelRatio();
int k = _parentNativeWidget->GetDevicePixelRatio();
x *= k;
y *= k;
@ -835,9 +832,7 @@ QRect MainFrame::GetFormRegion()
#ifdef _WIN32
if (_parentNativeWidget != NULL){
auto scr = _parentNativeWidget->GetPointScreen();
assert(scr);
int k = scr->devicePixelRatio();
int k = _parentNativeWidget->GetDevicePixelRatio();
RECT r;
GetWindowRect(_parentNativeWidget->Handle(), &r);
int x = r.left;
@ -886,33 +881,22 @@ 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();
AppConfig &app = AppConfig::Instance();
if (app.frameOptions.language > 0){
_mainWindow->switchLanguage(app.frameOptions.language);
}
// The history scale region.
int left = app.frameOptions.left;
int top = app.frameOptions.top;
int right = app.frameOptions.right;
int bottom = app.frameOptions.bottom;
int x = app.frameOptions.x;
int y = app.frameOptions.y;
int y = app.frameOptions.y;
QString lstDisplayName = app.frameOptions.displayName;
if (x == NO_POINT_VALUE){
x = left;
@ -922,30 +906,52 @@ void MainFrame::ReadSettings()
dsv_info("Read region info, x:%d, y:%d, w:%d, h:%d, isMax:%d",
x, y, right-left, bottom-top, app.frameOptions.isMax);
if (lstDisplayName != ""){
dsv_info("Last display:%s", lstDisplayName.toStdString().c_str());
}
bool bReset = false;
int scrIndex = -1;
QRect winRc = {x, y, right-left, bottom-top};
int k = 1;
int zoomk = 1;
QString scrName = "";
QRect full_rect = QRect(0,0,0,0);
QScreen *screen = NULL;
for (int i=0; i<QGuiApplication::screens().size(); i++){
QRect rc = QGuiApplication::screens().at(i)->availableGeometry();
QRect inrc = rc.intersected(winRc);
QRect rc = QGuiApplication::screens().at(i)->availableGeometry();
QString name = QGuiApplication::screens().at(i)->name();
dsv_info("Screen name:%s, region, left:%d, top:%d, right:%d, bottom:%d",
name.toStdString().c_str(), rc.left(), rc.top(), rc.right(), rc.bottom() );
if (scrIndex == -1 && (inrc.width() > 10 || inrc.height() > 10)){
if (name == lstDisplayName){
scrIndex = i;
}
}
dsv_info("Screen name:%s, region, left:%d, top:%d, width:%d, height:%d",
name.toStdString().c_str(), rc.left(), rc.top(), rc.width(), rc.height() );
}
if (scrIndex == -1){
bReset = true;
screen = QGuiApplication::primaryScreen();
}
else{
QRect rc = QGuiApplication::screens().at(scrIndex)->availableGeometry();
QRect inrc = rc.intersected(winRc);
else{
screen = QGuiApplication::screens().at(scrIndex);
}
full_rect = screen->availableGeometry();
k = screen->devicePixelRatio();
scrName = screen->name();
#ifdef _WIN32
if (_is_win32_parent_window){
zoomk = k;
}
#endif
QRect winRc = {x * zoomk, y * zoomk, right-left, bottom-top};
if (!bReset){
QRect inrc = full_rect.intersected(winRc);
if (inrc.width() < 70 || inrc.height() < 70 || winRc.width() < 300){
bReset = true;
}
@ -956,28 +962,13 @@ void MainFrame::ReadSettings()
_initWndInfo.r.w = 0;
_initWndInfo.r.h = 0;
_initWndInfo.isMaxSize = false;
int k = 1;
if (app.frameOptions.isMax)
{
QRect rc;
QString scrName;
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();
_initWndInfo.r.y = rc.top();
_initWndInfo.r.w = rc.width();
_initWndInfo.r.h = rc.height();
_initWndInfo.r.x = full_rect.left();
_initWndInfo.r.y = full_rect.top();
_initWndInfo.r.w = full_rect.width();
_initWndInfo.r.h = full_rect.height();
_initWndInfo.isMaxSize = true;
_normalRegion.x = x;
@ -985,44 +976,37 @@ void MainFrame::ReadSettings()
_normalRegion.w = right-left;
_normalRegion.h = bottom-top;
QRect inrc = rc.intersected(winRc);
if (inrc.width() < 70 || inrc.height() < 70 || winRc.width() < 300){
_normalRegion.x = rc.left() + (rc.width() - _normalRegion.w) / 2;
_normalRegion.y = rc.top() + (rc.height() - _normalRegion.h) / 2;
QRect inrc = full_rect.intersected(winRc);
if (inrc.width() < 70 || inrc.height() < 70 || winRc.width() < 100){
_normalRegion.x = full_rect.left()
+ (full_rect.width() - _normalRegion.w) / 2 * zoomk;
_normalRegion.y = full_rect.top()
+ (full_rect.height() - _normalRegion.h) / 2 * zoomk;
_normalRegion.x /= zoomk;
_normalRegion.y /= zoomk;
}
dsv_info("Show as max, screen:%s, x:%d, y:%d, w:%d, h:%d",
scrName.toStdString().c_str(), rc.x(), rc.y(), rc.width(), rc.height());
scrName.toStdString().c_str(), full_rect.x(), full_rect.y(),
full_rect.width(), full_rect.height());
}
else if (bReset)
{
QRect rc;
QString scrName;
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;
int h = rc.height() / 1.5;
const int x0 = rc.left() + (rc.width() - w) / 2;
const int y0 = rc.top() + (rc.height() - h) / 2;
_initWndInfo.r.x = x0;
_initWndInfo.r.y = y0;
{
int w = full_rect.width() / 1.5;
int h = full_rect.height() / 1.5;
int x0 = full_rect.left() + (full_rect.width() - w) / 2 * zoomk;
int y0 = full_rect.top() + (full_rect.height() - h) / 2 * zoomk;
_initWndInfo.r.x = x0 / zoomk;
_initWndInfo.r.y = y0 / zoomk;
_initWndInfo.r.w = w;
_initWndInfo.r.h = h;
_normalRegion = _initWndInfo.r;
dsv_info("Reset, screen:%s, x:%d, y:%d, w:%d, h:%d",
scrName.toStdString().c_str(), rc.left(), rc.top(), rc.width(), rc.height());
scrName.toStdString().c_str(), full_rect.left(), full_rect.top(),
full_rect.width(), full_rect.height());
}
else
{
@ -1041,13 +1025,11 @@ void MainFrame::ReadSettings()
#endif
_initWndInfo.r.w = right - left;
_initWndInfo.r.h = bottom - top;
_normalRegion = _initWndInfo.r;
QString scrName = QGuiApplication::screens().at(scrIndex)->name();
QRect rc = QGuiApplication::screens().at(scrIndex)->availableGeometry();
k = QGuiApplication::screens().at(scrIndex)->devicePixelRatio();
_normalRegion = _initWndInfo.r;
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());
scrName.toStdString().c_str() ,full_rect.left(), full_rect.top(),
full_rect.width(), full_rect.height());
}
dsv_info("Normal region, x:%d, y:%d, w:%d, h:%d",
@ -1137,4 +1119,33 @@ void MainFrame::show_doc()
}
}
bool MainFrame::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
#ifdef _WIN32
if (_parentNativeWidget != NULL)
{
MSG *msg = static_cast<MSG*>(message);
HWND hwnd = _parentNativeWidget->Handle();
switch (msg->message)
{
case WM_NCMOUSEMOVE:
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONUP:
case WM_NCLBUTTONDBLCLK:
case WM_NCHITTEST:
{
*result = long(SendMessageW(hwnd,
msg->message, msg->wParam, msg->lParam));
return true;
}
}
}
#endif
return QWidget::nativeEvent(eventType, message, result);
}
} // namespace pv

View File

@ -98,7 +98,6 @@ public:
bool IsMaxsized();
bool IsNormalsized();
bool IsMoving();
int GetDevicePixelRatio();
void SetFormRegion(int x, int y, int w, int h);
QRect GetFormRegion();
void saveNormalRegion();
@ -112,6 +111,8 @@ protected:
#endif
void changeEvent(QEvent *event) override;
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
signals:
void sig_ParentNativeEvent(int msg);
@ -125,13 +126,11 @@ public slots:
void showMaximized();
void showMinimized();
void OnParentNaitveWindowEvent(int msg);
void OnMoveWinShadow();
private:
void hide_border();
void show_border();
void writeSettings();
void ReadSettings();
void AttachNativeWindow();
@ -170,9 +169,8 @@ private:
QWinTaskbarProgress *_taskPrg;
#endif
bool _is_native_title;
bool _is_resize_ready;
bool _is_win32_parent_window;
bool _is_resize_ready;
WinNativeWidget *_parentNativeWidget;
FormInitInfo _initWndInfo;
FormRegion _normalRegion;

File diff suppressed because it is too large Load Diff

View File

@ -1,248 +1,249 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
* Copyright (C) 2013 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 DSVIEW_PV_MAINWINDOW_H
#define DSVIEW_PV_MAINWINDOW_H
#include <list>
#include <QMainWindow>
#include <QTranslator>
#include "dialogs/dsmessagebox.h"
#include "interface/icallbacks.h"
#include "eventobject.h"
#include <QJsonDocument>
#include <chrono>
#include "dstimer.h"
class QAction;
class QMenuBar;
class QMenu;
class QVBoxLayout;
class QStatusBar;
class QToolBar;
class QWidget;
class QDockWidget;
class AppControl;
class DeviceAgent;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
namespace pv {
class SigSession;
namespace toolbars {
class SamplingBar;
class TrigBar;
class FileBar;
class LogoBar;
class TitleBar;
}
namespace dock{
class ProtocolDock;
class TriggerDock;
class DsoTriggerDock;
class MeasureDock;
class SearchDock;
}
namespace view {
class View;
}
//The mainwindow,referenced by MainFrame
//TODO: create graph view,toolbar,and show device list
class MainWindow :
public QMainWindow,
public ISessionCallback,
public IMainForm,
public ISessionDataGetter,
public IMessageListener
{
Q_OBJECT
public:
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;
public:
explicit MainWindow(toolbars::TitleBar *title_bar, QWidget *parent = 0);
void openDoc();
public slots:
void switchTheme(QString style);
void restore_dock();
private slots:
void on_load_file(QString file_name);
void on_open_doc();
void on_protocol(bool visible);
void on_trigger(bool visible);
void on_measure(bool visible);
void on_search(bool visible);
void on_screenShot();
void on_save();
void on_export();
bool on_load_session(QString name);
bool on_store_session(QString name);
void on_data_updated();
void on_session_error();
void on_signals_changed();
void on_receive_trigger(quint64 trigger_pos);
void on_frame_ended();
void on_frame_began();
void on_decode_done();
void on_receive_data_len(quint64 len);
void on_cur_snap_samplerate_changed();
void on_trigger_message(int msg);
void on_delay_prop_msg();
signals:
void prgRate(int progress);
public:
//IMainForm
void switchLanguage(int language) override;
bool able_to_close();
private:
void setup_ui();
void retranslateUi();
bool eventFilter(QObject *object, QEvent *event);
void check_usb_device_speed();
void reset_all_view();
bool confirm_to_store_data();
void update_toolbar_view_status();
void calc_min_height();
void update_title_bar_text();
//json operation
private:
QString gen_config_file_path(bool isNewFormat);
bool load_config_from_file(QString file);
bool load_config_from_json(QJsonDocument &doc, bool &haveDecoder);
void load_device_config();
bool gen_config_json(QJsonObject &sessionVar);
void save_config();
bool save_config_to_file(QString file);
void load_channel_view_indexs(QJsonDocument &doc);
QJsonDocument get_config_json_from_data_file(QString file, bool &bSucesss);
QJsonArray get_decoder_json_from_data_file(QString file, bool &bSucesss);
void check_config_file_version();
void load_demo_decoder_config(QString optname);
private:
//ISessionCallback
void session_error() override;
void session_save() override;
void data_updated() override;
void update_capture() override;
void cur_snap_samplerate_changed() override;
void signals_changed() override;
void receive_trigger(quint64 trigger_pos) override;
void frame_ended() override;
void frame_began() override;
void show_region(uint64_t start, uint64_t end, bool keep) override;
void show_wait_trigger() override;
void repeat_hold(int percent) override;
void decode_done() override;
void receive_data_len(quint64 len) override;
void receive_header() override;
void trigger_message(int msg) override;
void delay_prop_msg(QString strMsg) override;
//ISessionDataGetter
bool genSessionData(std::string &str) override;
//IMessageListener
void OnMessage(int msg) override;
private:
pv::view::View *_view;
dialogs::DSMessageBox *_msg;
QMenuBar *_menu_bar;
QMenu *_menu_file;
QAction *_action_open;
QAction *_action_connect;
QAction *_action_quit;
QMenu *_menu_view;
QAction *_action_view_zoom_in;
QAction *_action_view_zoom_out;
QAction *_action_view_show_cursors;
QMenu *_menu_help;
QAction *_action_about;
QWidget *_central_widget;
QVBoxLayout *_vertical_layout;
toolbars::SamplingBar *_sampling_bar;
toolbars::TrigBar *_trig_bar;
toolbars::FileBar *_file_bar;
toolbars::LogoBar *_logo_bar; //help button, on top right
toolbars::TitleBar *_title_bar;
QDockWidget *_protocol_dock;
dock::ProtocolDock *_protocol_widget;
QDockWidget *_trigger_dock;
QDockWidget *_dso_trigger_dock;
dock::TriggerDock *_trigger_widget;
dock::DsoTriggerDock *_dso_trigger_widget;
QDockWidget *_measure_dock;
dock::MeasureDock *_measure_widget;
QDockWidget *_search_dock;
dock::SearchDock *_search_widget;
QTranslator _qtTrans;
QTranslator _myTrans;
EventObject _event;
SigSession *_session;
DeviceAgent *_device_agent;
bool _is_auto_switch_device;
high_resolution_clock::time_point _last_key_press_time;
bool _is_save_confirm_msg;
QString _pattern_mode;
QWidget *_frame;
DsTimer _delay_prop_msg_timer;
QString _strMsg;
QString _lst_title_string;
QString _title_ext_string;
int _key_value;
bool _key_vaild;
};
} // namespace pv
#endif // DSVIEW_PV_MAINWINDOW_H
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
* Copyright (C) 2013 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 DSVIEW_PV_MAINWINDOW_H
#define DSVIEW_PV_MAINWINDOW_H
#include <list>
#include <QMainWindow>
#include <QTranslator>
#include "dialogs/dsmessagebox.h"
#include "interface/icallbacks.h"
#include "eventobject.h"
#include <QJsonDocument>
#include <chrono>
#include "dstimer.h"
class QAction;
class QMenuBar;
class QMenu;
class QVBoxLayout;
class QStatusBar;
class QToolBar;
class QWidget;
class QDockWidget;
class AppControl;
class DeviceAgent;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
namespace pv {
class SigSession;
namespace toolbars {
class SamplingBar;
class TrigBar;
class FileBar;
class LogoBar;
class TitleBar;
}
namespace dock{
class ProtocolDock;
class TriggerDock;
class DsoTriggerDock;
class MeasureDock;
class SearchDock;
}
namespace view {
class View;
}
//The mainwindow,referenced by MainFrame
//TODO: create graph view,toolbar,and show device list
class MainWindow :
public QMainWindow,
public ISessionCallback,
public IMainForm,
public ISessionDataGetter,
public IMessageListener
{
Q_OBJECT
public:
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;
public:
explicit MainWindow(toolbars::TitleBar *title_bar, QWidget *parent = 0);
void openDoc();
public slots:
void switchTheme(QString style);
void restore_dock();
private slots:
void on_load_file(QString file_name);
void on_open_doc();
void on_protocol(bool visible);
void on_trigger(bool visible);
void on_measure(bool visible);
void on_search(bool visible);
void on_screenShot();
void on_save();
void on_export();
bool on_load_session(QString name);
bool on_store_session(QString name);
void on_data_updated();
void on_session_error();
void on_signals_changed();
void on_receive_trigger(quint64 trigger_pos);
void on_frame_ended();
void on_frame_began();
void on_decode_done();
void on_receive_data_len(quint64 len);
void on_cur_snap_samplerate_changed();
void on_trigger_message(int msg);
void on_delay_prop_msg();
signals:
void prgRate(int progress);
public:
//IMainForm
void switchLanguage(int language) override;
bool able_to_close();
private:
void setup_ui();
void retranslateUi();
bool eventFilter(QObject *object, QEvent *event);
void check_usb_device_speed();
void reset_all_view();
bool confirm_to_store_data();
void update_toolbar_view_status();
void calc_min_height();
void update_title_bar_text();
//json operation
private:
QString gen_config_file_path(bool isNewFormat);
bool load_config_from_file(QString file);
bool load_config_from_json(QJsonDocument &doc, bool &haveDecoder);
void load_device_config();
bool gen_config_json(QJsonObject &sessionVar);
void save_config();
bool save_config_to_file(QString file);
void load_channel_view_indexs(QJsonDocument &doc);
QJsonDocument get_config_json_from_data_file(QString file, bool &bSucesss);
QJsonArray get_decoder_json_from_data_file(QString file, bool &bSucesss);
void check_config_file_version();
void load_demo_decoder_config(QString optname);
private:
//ISessionCallback
void session_error() override;
void session_save() override;
void data_updated() override;
void update_capture() override;
void cur_snap_samplerate_changed() override;
void signals_changed() override;
void receive_trigger(quint64 trigger_pos) override;
void frame_ended() override;
void frame_began() override;
void show_region(uint64_t start, uint64_t end, bool keep) override;
void show_wait_trigger() override;
void repeat_hold(int percent) override;
void decode_done() override;
void receive_data_len(quint64 len) override;
void receive_header() override;
void trigger_message(int msg) override;
void delay_prop_msg(QString strMsg) override;
//ISessionDataGetter
bool genSessionData(std::string &str) override;
//IMessageListener
void OnMessage(int msg) override;
private:
pv::view::View *_view;
dialogs::DSMessageBox *_msg;
QMenuBar *_menu_bar;
QMenu *_menu_file;
QAction *_action_open;
QAction *_action_connect;
QAction *_action_quit;
QMenu *_menu_view;
QAction *_action_view_zoom_in;
QAction *_action_view_zoom_out;
QAction *_action_view_show_cursors;
QMenu *_menu_help;
QAction *_action_about;
QWidget *_central_widget;
QVBoxLayout *_vertical_layout;
toolbars::SamplingBar *_sampling_bar;
toolbars::TrigBar *_trig_bar;
toolbars::FileBar *_file_bar;
toolbars::LogoBar *_logo_bar; //help button, on top right
toolbars::TitleBar *_title_bar;
QDockWidget *_protocol_dock;
dock::ProtocolDock *_protocol_widget;
QDockWidget *_trigger_dock;
QDockWidget *_dso_trigger_dock;
dock::TriggerDock *_trigger_widget;
dock::DsoTriggerDock *_dso_trigger_widget;
QDockWidget *_measure_dock;
dock::MeasureDock *_measure_widget;
QDockWidget *_search_dock;
dock::SearchDock *_search_widget;
QTranslator _qtTrans;
QTranslator _myTrans;
EventObject _event;
SigSession *_session;
DeviceAgent *_device_agent;
bool _is_auto_switch_device;
high_resolution_clock::time_point _last_key_press_time;
bool _is_save_confirm_msg;
QString _pattern_mode;
QWidget *_frame;
DsTimer _delay_prop_msg_timer;
QString _strMsg;
QString _lst_title_string;
QString _title_ext_string;
int _key_value;
bool _key_vaild;
};
} // namespace pv
#endif // DSVIEW_PV_MAINWINDOW_H

View File

@ -1,341 +1,330 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2016 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 "titlebar.h"
#include <QStyle>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QStyleOption>
#include <assert.h>
#include <QTimer>
#ifdef _WIN32
#include <windows.h>
#endif
#include "../config/appconfig.h"
#include "../appcontrol.h"
#include "../dsvdef.h"
#include "../ui/fn.h"
namespace pv {
namespace toolbars {
TitleBar::TitleBar(bool top, QWidget *parent, ITitleParent *titleParent, bool hasClose) :
QWidget(parent)
{
_minimizeButton = NULL;
_maximizeButton = NULL;
_closeButton = NULL;
_moving = false;
_is_draging = false;
_parent = parent;
_isTop = top;
_hasClose = hasClose;
_title = NULL;
_is_native = false;
_titleParent = titleParent;
_is_done_moved = false;
assert(parent);
setObjectName("TitleBar");
setContentsMargins(0,0,0,0);
setFixedHeight(32);
QHBoxLayout *lay1 = new QHBoxLayout(this);
_title = new QLabel(this);
lay1->addWidget(_title);
if (_isTop) {
_minimizeButton = new XToolButton(this);
_minimizeButton->setObjectName("MinimizeButton");
_maximizeButton = new XToolButton(this);
_maximizeButton->setObjectName("MaximizeButton");
lay1->addWidget(_minimizeButton);
lay1->addWidget(_maximizeButton);
connect(this, SIGNAL(normalShow()), parent, SLOT(showNormal()));
connect(this, SIGNAL( maximizedShow()), parent, SLOT(showMaximized()));
connect(_minimizeButton, SIGNAL( clicked()), parent, SLOT(showMinimized()));
connect(_maximizeButton, SIGNAL( clicked()), this, SLOT(showMaxRestore()));
}
if (_isTop || _hasClose) {
_closeButton= new XToolButton(this);
_closeButton->setObjectName("CloseButton");
lay1->addWidget(_closeButton);
connect(_closeButton, SIGNAL( clicked()), parent, SLOT(close()));
}
lay1->insertStretch(0, 500);
lay1->insertStretch(2, 500);
lay1->setContentsMargins(0,0,0,0);
lay1->setSpacing(0);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
update_font();
}
TitleBar::~TitleBar(){
DESTROY_QT_OBJECT(_minimizeButton);
DESTROY_QT_OBJECT(_maximizeButton);
DESTROY_QT_OBJECT(_closeButton);
}
void TitleBar::changeEvent(QEvent *event)
{
if (event->type() == QEvent::StyleChange)
reStyle();
QWidget::changeEvent(event);
}
void TitleBar::reStyle()
{
QString iconPath = GetIconPath();
if (_isTop) {
_minimizeButton->setIcon(QIcon(iconPath+"/minimize.svg"));
if (ParentIsMaxsized())
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
else
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
}
if (_isTop || _hasClose)
_closeButton->setIcon(QIcon(iconPath+"/close.svg"));
}
bool TitleBar::ParentIsMaxsized()
{
if (_titleParent != NULL){
return _titleParent->ParentIsMaxsized();
}
else{
return parentWidget()->isMaximized();
}
}
void TitleBar::paintEvent(QPaintEvent *event)
{
//draw logo icon
QStyleOption o;
o.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
p.setRenderHint(QPainter::Antialiasing, true);
const int xgap = 2;
const int xstart = 10;
p.setPen(QPen(QColor(213, 15, 37, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*0, height()*0.50, xstart + xgap*0, height()*0.66);
p.drawLine(xstart + xgap*18, height()*0.34, xstart + xgap*18, height()*0.50);
p.setPen(QPen(QColor(238, 178, 17, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*2, height()*0.50, xstart + xgap*2, height()*0.83);
p.drawLine(xstart + xgap*16, height()*0.17, xstart + xgap*16, height()*0.50);
p.setPen(QPen(QColor(17, 133, 209, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*4, height()*0.50, xstart + xgap*4, height()*1.00);
p.drawLine(xstart + xgap*14, height()*0.00, xstart + xgap*14, height()*0.50);
p.setPen(QPen(QColor(0, 153, 37, 200), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*6, height()*0.50, xstart + xgap*6, height()*0.83);
p.drawLine(xstart + xgap*12, height()*0.17, xstart + xgap*12, height()*0.50);
p.setPen(QPen(QColor(109, 50, 156, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*8, height()*0.50, xstart + xgap*8, height()*0.66);
p.drawLine(xstart + xgap*10, height()*0.34, xstart + xgap*10, height()*0.50);
QWidget::paintEvent(event);
}
void TitleBar::setTitle(QString title)
{
if (!_is_native){
_title->setText(title);
}
else if (_parent != NULL){
_parent->setWindowTitle(title);
}
}
QString TitleBar::title()
{
if (!_is_native){
return _title->text();
}
else if (_parent != NULL){
return _parent->windowTitle();
}
return "";
}
void TitleBar::showMaxRestore()
{
QString iconPath = GetIconPath();
if (ParentIsMaxsized()) {
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
normalShow();
} else {
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
maximizedShow();
}
}
void TitleBar::setRestoreButton(bool max)
{
QString iconPath = GetIconPath();
if (!max) {
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
} else {
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
}
}
void TitleBar::mousePressEvent(QMouseEvent* event)
{
bool ableMove = !ParentIsMaxsized();
if(event->button() == Qt::LeftButton && ableMove)
{
int x = event->pos().x();
int y = event->pos().y();
bool bTopWidow = AppControl::Instance()->GetTopWindow() == _parent;
bool bClick = (x >= 6 && y >= 5 && x <= width() - 6); //top window need resize hit check
if (!bTopWidow || bClick ){
_is_draging = true;
#ifdef _WIN32
POINT p;
GetCursorPos(&p);
_clickPos.setX(p.x);
_clickPos.setY(p.y);
#else
_clickPos = event->globalPos();
#endif
if (_titleParent != NULL){
_oldPos = _titleParent->GetParentPos();
}
else{
_oldPos = _parent->pos();
}
_is_done_moved = false;
event->accept();
return;
}
}
QWidget::mousePressEvent(event);
}
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
if(_is_draging){
int datX = 0;
int datY = 0;
#ifdef _WIN32
POINT p;
GetCursorPos(&p);
int k = window()->devicePixelRatio();
datX = (p.x - _clickPos.x()) / k;
datY = (p.y - _clickPos.y()) / k;
#else
datX = (event->globalPos().x() - _clickPos.x());
datY = (event->globalPos().y() - _clickPos.y());
#endif
int x = _oldPos.x() + datX;
int y = _oldPos.y() + datY;
if (!_moving){
if (ABS_VAL(datX) >= 2 || ABS_VAL(datY) >= 2){
_moving = true;
}
else{
return;
}
}
if (_titleParent != NULL){
if (!_is_done_moved){
_is_done_moved = true;
_titleParent->MoveBegin();
}
_titleParent->MoveWindow(x, y);
}
else{
_parent->move(x, y);
}
event->accept();
return;
}
QWidget::mouseMoveEvent(event);
}
void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
if (_moving && _titleParent != NULL){
_titleParent->MoveEnd();
}
_moving = false;
_is_draging = false;
QWidget::mouseReleaseEvent(event);
}
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
QWidget::mouseDoubleClickEvent(event);
if (_isTop){
QTimer::singleShot(200, this, [this](){
showMaxRestore();
});
}
}
void TitleBar::update_font()
{
QFont font = this->font();
font.setPointSizeF(AppConfig::Instance().appOptions.fontSize+1);
_title->setFont(font);
}
} // namespace toolbars
} // namespace pv
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2016 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 "titlebar.h"
#include <QStyle>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QStyleOption>
#include <assert.h>
#include <QTimer>
#include "../config/appconfig.h"
#include "../appcontrol.h"
#include "../dsvdef.h"
#include "../ui/fn.h"
namespace pv {
namespace toolbars {
namespace{
static bool _is_able_drag = true;
}
TitleBar::TitleBar(bool top, QWidget *parent, ITitleParent *titleParent, bool hasClose) :
QWidget(parent)
{
_minimizeButton = NULL;
_maximizeButton = NULL;
_closeButton = NULL;
_moving = false;
_is_draging = false;
_parent = parent;
_isTop = top;
_hasClose = hasClose;
_title = NULL;
_is_native = false;
_titleParent = titleParent;
_is_done_moved = false;
assert(parent);
setObjectName("TitleBar");
setContentsMargins(0,0,0,0);
setFixedHeight(32);
QHBoxLayout *lay1 = new QHBoxLayout(this);
_title = new QLabel(this);
lay1->addWidget(_title);
if (_isTop) {
_minimizeButton = new XToolButton(this);
_minimizeButton->setObjectName("MinimizeButton");
_maximizeButton = new XToolButton(this);
_maximizeButton->setObjectName("MaximizeButton");
lay1->addWidget(_minimizeButton);
lay1->addWidget(_maximizeButton);
connect(this, SIGNAL(normalShow()), parent, SLOT(showNormal()));
connect(this, SIGNAL( maximizedShow()), parent, SLOT(showMaximized()));
connect(_minimizeButton, SIGNAL( clicked()), parent, SLOT(showMinimized()));
connect(_maximizeButton, SIGNAL( clicked()), this, SLOT(showMaxRestore()));
}
if (_isTop || _hasClose) {
_closeButton= new XToolButton(this);
_closeButton->setObjectName("CloseButton");
lay1->addWidget(_closeButton);
connect(_closeButton, SIGNAL( clicked()), parent, SLOT(close()));
}
lay1->insertStretch(0, 500);
lay1->insertStretch(2, 500);
lay1->setContentsMargins(0,0,0,0);
lay1->setSpacing(0);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
update_font();
}
TitleBar::~TitleBar(){
DESTROY_QT_OBJECT(_minimizeButton);
DESTROY_QT_OBJECT(_maximizeButton);
DESTROY_QT_OBJECT(_closeButton);
}
void TitleBar::changeEvent(QEvent *event)
{
if (event->type() == QEvent::StyleChange)
reStyle();
QWidget::changeEvent(event);
}
void TitleBar::reStyle()
{
QString iconPath = GetIconPath();
if (_isTop) {
_minimizeButton->setIcon(QIcon(iconPath+"/minimize.svg"));
if (ParentIsMaxsized())
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
else
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
}
if (_isTop || _hasClose)
_closeButton->setIcon(QIcon(iconPath+"/close.svg"));
}
bool TitleBar::ParentIsMaxsized()
{
if (_titleParent != NULL){
return _titleParent->ParentIsMaxsized();
}
else{
return parentWidget()->isMaximized();
}
}
void TitleBar::paintEvent(QPaintEvent *event)
{
//draw logo icon
QStyleOption o;
o.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
p.setRenderHint(QPainter::Antialiasing, true);
const int xgap = 2;
const int xstart = 10;
p.setPen(QPen(QColor(213, 15, 37, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*0, height()*0.50, xstart + xgap*0, height()*0.66);
p.drawLine(xstart + xgap*18, height()*0.34, xstart + xgap*18, height()*0.50);
p.setPen(QPen(QColor(238, 178, 17, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*2, height()*0.50, xstart + xgap*2, height()*0.83);
p.drawLine(xstart + xgap*16, height()*0.17, xstart + xgap*16, height()*0.50);
p.setPen(QPen(QColor(17, 133, 209, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*4, height()*0.50, xstart + xgap*4, height()*1.00);
p.drawLine(xstart + xgap*14, height()*0.00, xstart + xgap*14, height()*0.50);
p.setPen(QPen(QColor(0, 153, 37, 200), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*6, height()*0.50, xstart + xgap*6, height()*0.83);
p.drawLine(xstart + xgap*12, height()*0.17, xstart + xgap*12, height()*0.50);
p.setPen(QPen(QColor(109, 50, 156, 255), 2, Qt::SolidLine));
p.drawLine(xstart + xgap*8, height()*0.50, xstart + xgap*8, height()*0.66);
p.drawLine(xstart + xgap*10, height()*0.34, xstart + xgap*10, height()*0.50);
QWidget::paintEvent(event);
}
void TitleBar::setTitle(QString title)
{
if (!_is_native){
_title->setText(title);
}
else if (_parent != NULL){
_parent->setWindowTitle(title);
}
}
QString TitleBar::title()
{
if (!_is_native){
return _title->text();
}
else if (_parent != NULL){
return _parent->windowTitle();
}
return "";
}
void TitleBar::showMaxRestore()
{
QString iconPath = GetIconPath();
if (ParentIsMaxsized()) {
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
normalShow();
} else {
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
maximizedShow();
}
}
void TitleBar::setRestoreButton(bool max)
{
QString iconPath = GetIconPath();
if (!max) {
_maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg"));
} else {
_maximizeButton->setIcon(QIcon(iconPath+"/restore.svg"));
}
}
void TitleBar::mousePressEvent(QMouseEvent* event)
{
bool ableMove = !ParentIsMaxsized();
if(event->button() == Qt::LeftButton && ableMove && _is_able_drag)
{
int x = event->pos().x();
int y = event->pos().y();
bool bTopWidow = AppControl::Instance()->GetTopWindow() == _parent;
bool bClick = (x >= 6 && y >= 5 && x <= width() - 6); //top window need resize hit check
if (!bTopWidow || bClick ){
_is_draging = true;
_clickPos = event->globalPos();
if (_titleParent != NULL){
_oldPos = _titleParent->GetParentPos();
}
else{
_oldPos = _parent->pos();
}
_is_done_moved = false;
event->accept();
return;
}
}
QWidget::mousePressEvent(event);
}
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
if(_is_draging){
int datX = 0;
int datY = 0;
datX = (event->globalPos().x() - _clickPos.x());
datY = (event->globalPos().y() - _clickPos.y());
int x = _oldPos.x() + datX;
int y = _oldPos.y() + datY;
if (!_moving){
if (ABS_VAL(datX) >= 2 || ABS_VAL(datY) >= 2){
_moving = true;
}
else{
return;
}
}
if (_titleParent != NULL){
if (!_is_done_moved){
_is_done_moved = true;
_titleParent->MoveBegin();
}
_titleParent->MoveWindow(x, y);
}
else{
_parent->move(x, y);
}
event->accept();
return;
}
QWidget::mouseMoveEvent(event);
}
void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
if (_moving && _titleParent != NULL){
_titleParent->MoveEnd();
}
_moving = false;
_is_draging = false;
QWidget::mouseReleaseEvent(event);
}
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
QWidget::mouseDoubleClickEvent(event);
if (_isTop){
QTimer::singleShot(200, this, [this](){
showMaxRestore();
});
}
}
void TitleBar::update_font()
{
QFont font = this->font();
font.setPointSizeF(AppConfig::Instance().appOptions.fontSize+1);
_title->setFont(font);
}
void TitleBar::EnableAbleDrag(bool bEnabled)
{
_is_able_drag = bEnabled;
}
} // namespace toolbars
} // namespace pv

View File

@ -1,108 +1,110 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2016 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 DSVIEW_PV_TOOLBARS_TITLEBAR_H
#define DSVIEW_PV_TOOLBARS_TITLEBAR_H
#include <QWidget>
#include "../interface/icallbacks.h"
#include "../ui/xtoolbutton.h"
class QHBoxLayout;
class QLabel;
namespace pv {
class ITitleParent
{
public:
virtual void MoveWindow(int x, int y)=0;
virtual QPoint GetParentPos()=0;
virtual bool ParentIsMaxsized()=0;
virtual void MoveBegin()=0;
virtual void MoveEnd()=0;
};
namespace toolbars {
class TitleBar : public QWidget, public IFontForm
{
Q_OBJECT
public:
TitleBar(bool top, QWidget *parent, ITitleParent *titleParent, bool hasClose);
~TitleBar();
void setTitle(QString title);
QString title();
//IFontForm
void update_font() override;
inline void set_native(){
_is_native = true;
}
private:
void changeEvent(QEvent *event);
void reStyle();
bool ParentIsMaxsized();
signals:
void normalShow();
void maximizedShow();
public slots:
void showMaxRestore();
void setRestoreButton(bool max);
inline bool IsMoving(){return _moving;}
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
XToolButton *_minimizeButton;
XToolButton *_maximizeButton;
XToolButton *_closeButton;
QLabel *_title;
bool _moving;
bool _is_draging;
bool _isTop;
bool _hasClose;
QPoint _clickPos;
QPoint _oldPos;
QWidget *_parent;
bool _is_native;
ITitleParent *_titleParent;
bool _is_done_moved;
};
} // namespace toolbars
} // namespace pv
#endif // DSVIEW_PV_TOOLBARS_TITLEBAR_H
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2016 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 DSVIEW_PV_TOOLBARS_TITLEBAR_H
#define DSVIEW_PV_TOOLBARS_TITLEBAR_H
#include <QWidget>
#include "../interface/icallbacks.h"
#include "../ui/xtoolbutton.h"
class QHBoxLayout;
class QLabel;
namespace pv {
class ITitleParent
{
public:
virtual void MoveWindow(int x, int y)=0;
virtual QPoint GetParentPos()=0;
virtual bool ParentIsMaxsized()=0;
virtual void MoveBegin()=0;
virtual void MoveEnd()=0;
};
namespace toolbars {
class TitleBar : public QWidget, public IFontForm
{
Q_OBJECT
public:
TitleBar(bool top, QWidget *parent, ITitleParent *titleParent, bool hasClose);
~TitleBar();
void setTitle(QString title);
QString title();
//IFontForm
void update_font() override;
inline void set_native(){
_is_native = true;
}
void EnableAbleDrag(bool bEnabled);
private:
void changeEvent(QEvent *event);
void reStyle();
bool ParentIsMaxsized();
signals:
void normalShow();
void maximizedShow();
public slots:
void showMaxRestore();
void setRestoreButton(bool max);
inline bool IsMoving(){return _moving;}
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
XToolButton *_minimizeButton;
XToolButton *_maximizeButton;
XToolButton *_closeButton;
QLabel *_title;
bool _moving;
bool _is_draging;
bool _isTop;
bool _hasClose;
QPoint _clickPos;
QPoint _oldPos;
QWidget *_parent;
bool _is_native;
ITitleParent *_titleParent;
bool _is_done_moved;
};
} // namespace toolbars
} // namespace pv
#endif // DSVIEW_PV_TOOLBARS_TITLEBAR_H

View File

@ -1,70 +1,81 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2024 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 "popupdlglist.h"
#include <QGuiApplication>
namespace{
std::vector<QWidget*> g_popup_dlg_list;
int g_screen_count = 1;
}
void PopupDlgList::AddDlgTolist(QWidget *w)
{
if (w != nullptr){
g_popup_dlg_list.push_back(w);
}
g_screen_count = QGuiApplication::screens().size();
}
void PopupDlgList::RemoveDlgFromList(QWidget *w)
{
if (w != nullptr){
for (auto it = g_popup_dlg_list.begin(); it != g_popup_dlg_list.end(); ++it)
{
if ((*it) == w){
g_popup_dlg_list.erase(it);
break;
}
}
}
}
void PopupDlgList::TryCloseAllByScreenChanged()
{
int screen_count = QGuiApplication::screens().size();
if (screen_count != g_screen_count)
{
int num = g_popup_dlg_list.size();
for (int i=0; i<num; i++)
{
auto it = g_popup_dlg_list.begin() + i;
if ((*it)->isVisible()){
(*it)->close(); //Close the dialog.
g_popup_dlg_list.erase(it);
--num;
--i;
}
}
}
}
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2024 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 "popupdlglist.h"
#include <QGuiApplication>
#include <QScreen>
#include <QWindow>
#include <QTimer>
#include "../log.h"
namespace{
std::vector<PopuDlgItem> g_popup_dlg_list;
QScreen *currentScreen = NULL;
}
void PopupDlgList::AddDlgTolist(QWidget *w)
{
if (w != nullptr){
PopuDlgItem item;
item.screen = currentScreen;
item.widget = w;
g_popup_dlg_list.push_back(item);
}
}
void PopupDlgList::RemoveDlgFromList(QWidget *w)
{
if (w != nullptr){
for (auto it = g_popup_dlg_list.begin(); it != g_popup_dlg_list.end(); ++it)
{
if ((*it).widget == w){
g_popup_dlg_list.erase(it);
break;
}
}
}
}
void PopupDlgList::TryCloseAllByScreenChanged(QScreen *windowScreen)
{
int num = g_popup_dlg_list.size();
for (int i=0; i<num; i++)
{
auto it = g_popup_dlg_list.begin() + i;
auto w = (*it).widget;
if (w->isVisible()){
if ((*it).screen != windowScreen){
w->close(); //Close the dialog.
g_popup_dlg_list.erase(it);
--num;
--i;
}
}
}
}
void PopupDlgList::SetCurrentScreen(QScreen *screen)
{
currentScreen = screen;
}

View File

@ -1,36 +1,45 @@
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2024 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 POPUP_DLG_LIST_H
#define POPUP_DLG_LIST_H
#include <vector>
#include <QWidget>
class PopupDlgList
{
public:
static void AddDlgTolist(QWidget *w);
static void RemoveDlgFromList(QWidget *w);
static void TryCloseAllByScreenChanged();
};
/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2024 DreamSourceLab <support@dreamsourcelab.com>
*
* 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 POPUP_DLG_LIST_H
#define POPUP_DLG_LIST_H
#include <vector>
#include <QWidget>
class QScreen;
struct PopuDlgItem
{
QScreen *screen;
QWidget *widget;
};
class PopupDlgList
{
public:
static void AddDlgTolist(QWidget *w);
static void RemoveDlgFromList(QWidget *w);
static void TryCloseAllByScreenChanged(QScreen *windowScreen);
static void SetCurrentScreen(QScreen *screen);
};
#endif

View File

@ -21,7 +21,7 @@
*/
#include "WinNativeWidget.h"
#include "winnativewidget.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
@ -34,9 +34,11 @@
#include <QtGui>
#include <QtWidgets>
#include <qmath.h>
#include <string.h>
#include "log.h"
#include "../config.h"
#include "winshadow.h"
#define FIXED_WIDTH(widget) (widget->minimumWidth() >= widget->maximumWidth())
#define FIXED_HEIGHT(widget) (widget->minimumHeight() >= widget->maximumHeight())
@ -45,19 +47,24 @@
namespace pv {
//-----------------------------WinNativeWidget
WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, const int height)
WinNativeWidget::WinNativeWidget(const int x, const int y, const int width,
const int height, bool isDark)
{
_childWindow = nullptr;
childWidget = nullptr;
_hWnd = NULL;
_event_callback = NULL;
_is_moving = false;
_shadow = NULL;
_cur_screen = NULL;
_titleBarWidget = NULL;
_is_native_border = IsWin11OrGreater();
_hCurrentMonitor = NULL;
_shadow = NULL;
_border_color = QColor(0x80,0x80,0x80);
HBRUSH windowBackground = CreateSolidBrush(RGB(0, 0, 0));
HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASSEX wcx = { 0 };
WNDCLASSEX wcx;
memset(&wcx, 0, sizeof(WNDCLASSEXW));
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
@ -66,10 +73,15 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.lpszClassName = L"DSViewWindowClass";
wcx.hbrBackground = windowBackground;
wcx.hCursor = LoadCursor(hInstance, IDC_ARROW);
if (isDark){
wcx.hbrBackground = CreateSolidBrush(RGB(38, 38, 38));
}
else{
wcx.hbrBackground = CreateSolidBrush(RGB(248, 248, 248));
}
RegisterClassEx(&wcx);
if (FAILED(RegisterClassEx(&wcx)))
{
@ -78,7 +90,7 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons
}
_hWnd = CreateWindow(L"DSViewWindowClass", L"DSView",
// WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN,
//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);
@ -88,19 +100,20 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, cons
dsv_info("ERROR: can't create naitive window");
assert(false);
}
SetWindowLongW(_hWnd, GWL_STYLE, GetWindowLongW(_hWnd, GWL_STYLE) & ~WS_CAPTION);
SetWindowLongPtr(_hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
SetWindowPos(_hWnd, NULL, x, y, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
if (!_is_native_border){
_shadow = new WinShadow(_hWnd, NULL);
_shadow->createWinId();
}
}
WinNativeWidget::~WinNativeWidget()
{
if (_hWnd){
if (_shadow){
_shadow->hide();
delete _shadow;
_shadow = NULL;
}
Show(false);
DestroyWindow(_hWnd);
}
@ -113,38 +126,34 @@ void WinNativeWidget::SetChildWidget(QWidget *w)
if (w != NULL){
_childWindow = (HWND)w->winId();
_shadow = new WinShadow(_hWnd, w);
_shadow->createWinId();
}
}
else if (_shadow != NULL){
_shadow->hideShadow();
_shadow->close(); //Set null, the applictoin will exit.
}
}
void WinNativeWidget::ReShowWindow()
{
if (IsMaxsized()){
ShowMax();
}
else{
ShowNormal();
}
Show(true);
}
LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WinNativeWidget *self = reinterpret_cast<WinNativeWidget*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (self == NULL)
{
if (self == NULL){
return DefWindowProc(hWnd, message, wParam, lParam);
}
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)
@ -153,101 +162,223 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam
GetWindowRect(hWnd, &winrect);
TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN, winrect.left + 5, winrect.top + 5, 0, hWnd, NULL);
}
else
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;;
}
}
case WM_NCCALCSIZE:
{
return 0;
}
if (!wParam || self->IsMaxsized()){
return 0;
}
if (!self->_is_native_border){
return 0;
}
int k = self->GetDevicePixelRatio();
NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
RECT* rect = &params->rgrc[0];
int borderSize = 1 * k;
rect->left += borderSize;
rect->top += 1;
rect->right -= borderSize;
rect->bottom -= borderSize;
return WVR_VALIDRECTS;
}
case WM_NCACTIVATE:
{
// Is activing.
if (wParam){
return 0;
}
HWND hForegWnd = GetForegroundWindow();
HWND hActiveWnd = GetActiveWindow();
// Is not the foreground window.
if (hForegWnd != hActiveWnd){
return 0;
}
//Is the foreground window, but is not actived, maybe opening a child dialog.
SetWindowRedraw(hWnd, FALSE);
LRESULT result = DefWindowProc(hWnd, message, wParam, lParam);
SetWindowRedraw(hWnd, TRUE);
return result;
}
case WM_CLOSE:
{
if (self->childWidget != NULL)
{
if (self->childWidget != NULL) {
self->childWidget->close();
return 0;
}
break;
}
case WM_DESTROY:
case WM_MOVE:
{
// PostQuitMessage(0);
if (IsIconic(hWnd) == FALSE) {
self->_hCurrentMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
self->ResizeChild();
}
break;
}
case WM_DPICHANGED:
case WM_DISPLAYCHANGE:
{
if (self->_event_callback != NULL){
self->_event_callback->OnParentNativeEvent(PARENT_EVENT_DISPLAY_CHANGED);
}
else{
self->UpdateChildDpi();
self->ResizeChild();
}
break;
}
case WM_SIZE:
{
if (self->_childWindow != NULL){
self->ResizeChild();
if (self->_shadow){
if (self->IsNormalsized()){
self->_shadow->tryToShow();
}
else{
self->_shadow->hide();
}
}
self->MoveShadow();
{
if (wParam != SIZE_MINIMIZED && self->_childWindow != NULL){
self->ResizeChild();
}
break;
}
case WM_GETMINMAXINFO:
{
if (self->childWidget)
{
auto gw = self->childWidget;
int k = gw->windowHandle()->devicePixelRatio();
MINMAXINFO *mmi = reinterpret_cast<MINMAXINFO*>(lParam);
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:
{
static int lst_state = -1;
int st = 3;
if (self->IsMaxsized())
st = 1;
else if (self->IsNormalsized())
st = 2;
if (self->childWidget != NULL && self->_shadow){
if (self->childWidget != NULL && self->_shadow && lst_state != st){
if (st == 2){
if (self->childWidget->isVisible() && !self->_is_moving){
if (self->childWidget->isVisible()){
self->_shadow->showLater();
self->showBorder();
}
}
else {
self->_shadow->hide();
self->_shadow->hide();
self->hideBorder();
}
lst_state = st;
}
break;
}
case WM_GETMINMAXINFO:
{
if (self->childWidget && self->_hCurrentMonitor)
{
int maxWidth = 0;
int maxHeight = 0;
bool bError = false;
if (!self->getMonitorWorkArea(self->_hCurrentMonitor, &maxWidth, &maxHeight))
{
HMONITOR hCurrentMonitor = MonitorFromWindow(self->_hWnd, MONITOR_DEFAULTTONEAREST);
if (!self->getMonitorWorkArea(hCurrentMonitor, &maxWidth, &maxHeight)){
dsv_info("ERROR: failed to get work area from window handle.");
bError = true;
}
}
if (!bError)
{
auto gw = self->childWidget;
int k = self->GetDevicePixelRatio();
QSize minimum = gw->minimumSize();
QSize sizeHint = gw->minimumSizeHint();
MINMAXINFO *mmi = reinterpret_cast<MINMAXINFO*>(lParam);
mmi->ptMinTrackSize.x = qFloor(qMax(minimum.width(), sizeHint.width()) * k);
mmi->ptMinTrackSize.y = qFloor(qMax(minimum.height(), sizeHint.height()) * k);
mmi->ptMaxTrackSize.x = maxWidth;
mmi->ptMaxTrackSize.y = maxHeight;
}
}
break;
}
case WM_NCHITTEST:
{
auto childWidget = self->childWidget;
if (childWidget == NULL)
break;
int k = self->GetDevicePixelRatio();
const LONG borderWidth = 8 * k;
RECT winrect;
GetWindowRect(hWnd, &winrect);
long x = GET_X_LPARAM(lParam);
long y = GET_Y_LPARAM(lParam);
// Check if the size can to resize.
if (!self->IsMaxsized())
{
//bottom left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
return HTBOTTOMLEFT;
}
//bottom right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
return HTBOTTOMRIGHT;
}
//top left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
return HTTOPLEFT;
}
//top right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
return HTTOPRIGHT;
}
//left border
if (x >= winrect.left && x < winrect.left + borderWidth)
{
return HTLEFT;
}
//right border
if (x < winrect.right && x >= winrect.right - borderWidth)
{
return HTRIGHT;
}
//bottom border
if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
return HTBOTTOM;
}
//top border
if (y >= winrect.top && y < winrect.top + borderWidth)
{
return HTTOP;
}
}
// Check unble move.
if (self->_titleBarWidget)
{
QRect titleRect = self->_titleBarWidget->geometry();
int titleWidth = titleRect.width() * k - 55 * k;
int titleHeight = titleRect.height() * k;
if (x > winrect.left + 2 * k && x < winrect.left + titleWidth)
{
if (y > winrect.top + 2 * k && y < winrect.top + titleHeight){
return HTCAPTION;
}
}
}
break;
}
}
@ -255,90 +386,66 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam
return DefWindowProc(hWnd, message, wParam, lParam);
}
bool WinNativeWidget::getMonitorWorkArea(HMONITOR hCurrentMonitor, int *outWidth, int *outHeight)
{
assert(outWidth);
assert(outHeight);
MONITORINFO monitorInfo;
memset(&monitorInfo, 0, sizeof(MONITORINFO));
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hCurrentMonitor, &monitorInfo);
int borderSizeX = GetSystemMetrics(SM_CXSIZEFRAME);
int borderSizeY = GetSystemMetrics(SM_CYSIZEFRAME);
int workAreaWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
int workAreaHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
int maxWidth = workAreaWidth + borderSizeX * 2;
int maxHeight = workAreaHeight + borderSizeY * 2;
if (workAreaWidth > 0){
*outWidth = maxWidth;
*outHeight = maxHeight;
return true;
}
return false;
}
void WinNativeWidget::ResizeChild()
{
if (_childWindow != NULL){
RECT rc;
GetWindowRect(_hWnd, &rc);
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;
int k = GetDevicePixelRatio();
if (_shadow != NULL){
_shadow->setScale(k);
_shadow->moveShadow();
}
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);
GetClientRect(_hWnd, &rc);
int x = rc.left;
int y = rc.top;
int x = 0;
int y = 0;
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;
if (IsMaxsized()){
w -= 4 * k;
h -= 4 * k;
}
else{
w -= 2;
h -= 2;
int border = 0 * k;
x += border;
y += border;
w -= border * 2;
h -= border * 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();
MoveWindow(_childWindow, x, y, w + 1 , h + 1 , 1);
MoveWindow(_childWindow, x, y, w , h , 1);
childWidget->updateGeometry();
}
}
@ -349,21 +456,16 @@ bool WinNativeWidget::isActiveWindow()
}
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);
{
if (_hWnd != NULL){
MoveWindow(_hWnd, x, y, width, height, 1);
}
}
}
void WinNativeWidget::Show(bool bShow)
{
if (_hWnd){
ShowWindow(_hWnd, bShow ? SW_SHOW : SW_HIDE);
if (!bShow && _shadow){
_shadow->hide();
}
ShowWindow(_hWnd, bShow ? SW_SHOW : SW_HIDE);
}
}
@ -373,18 +475,7 @@ void WinNativeWidget::Show(bool bShow)
GetClientRect(_hWnd, &rc);
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();
}
MoveWindow(_hWnd, x, y, w, h, 1);
}
void WinNativeWidget::ShowNormal()
@ -413,11 +504,11 @@ void WinNativeWidget::UpdateChildDpi()
QScreen *scr = screenFromWindow(_hWnd);
if (scr != NULL && childWidget != NULL){
childWidget->windowHandle()->setScreen(scr);
if (_shadow){
if (_shadow != NULL){
_shadow->windowHandle()->setScreen(scr);
}
}
else{
else{
dsv_info("ERROR: failed to update child's screen.");
}
}
@ -427,7 +518,11 @@ QScreen* WinNativeWidget::screenFromWindow(HWND hwnd)
if (hwnd == NULL)
return NULL;
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
HMONITOR monitor = _hCurrentMonitor;
if (monitor == NULL){
monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
}
MONITORINFO monitor_info;
memset(&monitor_info, 0, sizeof(MONITORINFO));
@ -455,18 +550,6 @@ 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;
@ -491,12 +574,101 @@ bool WinNativeWidget::IsNormalsized()
return wp.showCmd == SW_SHOWNORMAL;
}
void WinNativeWidget::BeginShowShadow()
void WinNativeWidget::SetBorderColor(QColor color)
{
if (_shadow){
_shadow->show();
_shadow->showLater();
_border_color = color;
if (_hWnd)
{
if (_is_native_border)
{
const DWORD DWMWINDOWATTRIBUTE_DWMWA_BORDER_COLOR = 34;
COLORREF COLOR = RGB(color.red(), color.green(), color.blue());
typedef HRESULT(WINAPI *tDwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
tDwmSetWindowAttribute pDwmSetWindowAttribute =
tDwmSetWindowAttribute(QLibrary::resolve("dwmapi", "DwmSetWindowAttribute"));
if (pDwmSetWindowAttribute){
pDwmSetWindowAttribute(_hWnd, DWMWINDOWATTRIBUTE_DWMWA_BORDER_COLOR, &COLOR, sizeof(COLOR));
}
}
else if (childWidget != NULL){
if (IsMaxsized()){
hideBorder();
}
else{
showBorder();
}
}
}
}
void WinNativeWidget::showBorder()
{
if (childWidget != NULL && !_is_native_border){
childWidget->setObjectName("DSViewFrame");
QString borderCss = "#DSViewFrame {border-radius:0px; border:1px solid %1;}";
QString borderStyle = borderCss.arg(_border_color.name());
childWidget->setStyleSheet(borderStyle);
}
}
void WinNativeWidget::hideBorder()
{
if (childWidget != NULL && !_is_native_border){
childWidget->setObjectName("DSViewFrame");
QString borderCss = "#DSViewFrame {border-radius:0px; border:0px solid %1;}";
QString borderStyle = borderCss.arg(_border_color.name());
childWidget->setStyleSheet(borderStyle);
}
}
bool WinNativeWidget::isWinXOrGreater(DWORD major_version, DWORD minor_version, DWORD build_number)
{
bool is_win_x_or_greater = false;
typedef NTSTATUS(WINAPI *tRtlGetVersion)(LPOSVERSIONINFOEXW);
tRtlGetVersion pRtlGetVersion = tRtlGetVersion(QLibrary::resolve("ntdll", "RtlGetVersion"));
if (pRtlGetVersion)
{
OSVERSIONINFOEXW os_info;
memset(&os_info, 0, sizeof(OSVERSIONINFOEXW));
os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
NTSTATUS status = pRtlGetVersion(&os_info);
if (status == 0)
{
is_win_x_or_greater = (os_info.dwMajorVersion >= major_version &&
os_info.dwMinorVersion >= minor_version &&
os_info.dwBuildNumber >= build_number);
}
}
return is_win_x_or_greater;
}
bool WinNativeWidget::IsWin11OrGreater()
{
return isWinXOrGreater(10, 0, 22000);
}
int WinNativeWidget::GetDevicePixelRatio()
{
auto scr = GetPointScreen();
if (scr != NULL){
return scr->devicePixelRatio();
}
else if (childWidget != NULL){
return childWidget->windowHandle()->devicePixelRatio();
}
return 1;
}
bool WinNativeWidget::IsVisible()
{
if (_hWnd){
return IsWindowVisible(_hWnd);
}
return false;
}
}

View File

@ -31,22 +31,27 @@
#include <QByteArray>
#include "interface/icallbacks.h"
#include "winshadow.h"
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
#ifndef SM_CXPADDEDBORDER
#define SM_CXPADDEDBORDER 105
#endif
namespace pv {
class WinShadow;
class WinNativeWidget
{
public:
WinNativeWidget(const int x, const int y, const int width, const int heigh);
WinNativeWidget(const int x, const int y, const int width, const int heigh, bool isDark);
~WinNativeWidget();
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void SetChildWidget(QWidget *w);
@ -65,46 +70,49 @@ public:
void ShowMin();
void UpdateChildDpi();
void ResizeChild();
void ResizeSelf();
inline void SetMovingFlag(bool bMoving){
_is_moving = bMoving;
_cur_screen = NULL;
}
void ResizeChild();
QScreen* GetPointScreen();
inline void SetNativeEventCallback(IParentNativeEventCallback *callback){
_event_callback = callback;
}
void OnDisplayChanged();
bool IsMaxsized();
bool IsMinsized();
bool IsNormalsized();
void MoveShadow();
inline WinShadow* Shadow(){
return _shadow;
}
bool IsNormalsized();
bool isActiveWindow();
void BeginShowShadow();
void SetBorderColor(QColor color);
bool IsWin11OrGreater();
inline void SetTitleBarWidget(QWidget *w){
_titleBarWidget = w;
}
int GetDevicePixelRatio();
bool IsVisible();
void ReShowWindow();
private:
QScreen* screenFromWindow(HWND hwnd);
bool isWinXOrGreater(DWORD major_version, DWORD minor_version, DWORD build_number);
void showBorder();
void hideBorder();
bool getMonitorWorkArea(HMONITOR hCurrentMonitor, int *outWidth, int *outHeight);
private:
QWidget* childWidget;
HWND _childWindow;
HWND _hWnd;
QWidget *_titleBarWidget;
IParentNativeEventCallback *_event_callback;
bool _is_moving;
bool _is_native_border;
HMONITOR _hCurrentMonitor;
WinShadow *_shadow;
QScreen *_cur_screen;
QColor _border_color;
};
}

View File

@ -18,117 +18,51 @@
* 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"
#define COLOR1 QColor(0, 0, 0, 75)
#define COLOR2 QColor(0, 0, 0, 30)
#define COLOR3 QColor(0, 0, 0, 1)
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)
{
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);
m_parent = parent;
m_scale = 1;
setWindowFlags(Qt::Window | Qt::FramelessWindowHint |
(!m_parent ? Qt::Tool : Qt::WindowFlags(0)));
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &WinShadow::show);
connect(m_timer, &QTimer::timeout, this, &WinShadow::showShadow);
connect(this, &WinShadow::showSignal, this, &WinShadow::onMoveSelf);
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);
}
m_timer->setSingleShot(true);
}
int WinShadow::shadowWidth()
{
return SHADOW_BORDER_WIDTH;
void WinShadow::onMoveSelf()
{
moveShadow();
}
void WinShadow::showLater()
{
m_timer->stop();
m_timer->start();
m_timer->start();
}
void WinShadow::show()
void WinShadow::showShadow()
{
m_bClean = false;
if (m_timer->isActive())
return;
@ -144,283 +78,145 @@ void WinShadow::show()
QWidget::raise();
SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
bool WinShadow::tryToShow()
void WinShadow::hideShadow()
{
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();
repaint();
}
bool WinShadow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
{
MSG *msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_ACTIVATE:
{
switch (msg->wParam)
case WM_ACTIVATE:
{
case WA_ACTIVE:
case WA_CLICKACTIVE:
switch (msg->wParam)
{
case WA_ACTIVE:
case WA_CLICKACTIVE:
{
SetForegroundWindow(m_hwnd);
break;
}
}
break;
}
case WM_MOUSEACTIVATE:
{
SetForegroundWindow(m_hwnd);
break;
SetForegroundWindow(m_hwnd);
*result = MA_NOACTIVATE;
return true;
}
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();
}
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;
}
}
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);
return QWidget::nativeEvent(eventType, message, result);
}
void WinShadow::moveShadow()
{
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(m_hwnd, &wp);
if (wp.showCmd == SW_SHOWNORMAL){
RECT rc;
GetWindowRect(m_hwnd, &rc);
int bw = (SHADOW_BORDER_WIDTH - 1) * m_scale;
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;
const HWND active_window = GetActiveWindow();
bool isActiveWindow = ((active_window == m_hwnd)
|| IsChild(m_hwnd, active_window));
MoveWindow((HWND)winId(), x, y, w , h , 1);
setActive(isActiveWindow);
}
}
void WinShadow::paintEvent(QPaintEvent *event)
{
const int shadow_width = SHADOW_BORDER_WIDTH;
QPainter painter(this);
painter.setCompositionMode(QPainter::CompositionMode_Source);
if (!m_active)
{
painter.fillRect(rect(), QColor(0, 0, 0, 1));
QRect rect1 = rect().adjusted(shadow_width, shadow_width, -shadow_width, -shadow_width);
painter.fillRect(rect1, Qt::transparent);
return;
}
QPixmap radial_gradient = QPixmap(shadow_width * 2, shadow_width * 2);
{
radial_gradient.fill(QColor(0, 0, 0, 1));
QPainter painter(&radial_gradient);
painter.setRenderHint(QPainter::Antialiasing);
painter.setCompositionMode(QPainter::CompositionMode_Source);
QRadialGradient gradient(shadow_width, shadow_width, shadow_width);
gradient.setColorAt(0.0, COLOR1);
gradient.setColorAt(0.2, COLOR2);
gradient.setColorAt(0.5, COLOR3);
QPen pen(Qt::transparent, 0);
painter.setPen(pen);
painter.setBrush(gradient);
painter.drawEllipse(0, 0, shadow_width * 2, shadow_width * 2);
}
QRect rect1 = rect().adjusted(shadow_width, shadow_width, -shadow_width, -shadow_width);
painter.drawPixmap(0, 0, shadow_width, shadow_width, radial_gradient, 0, 0, shadow_width, shadow_width);
painter.drawPixmap(rect().width() - shadow_width, 0, radial_gradient, shadow_width, 0, shadow_width, shadow_width); //Top-right corner
painter.drawPixmap(0, rect().height() - shadow_width, radial_gradient, 0, shadow_width, shadow_width, shadow_width); //Bottom-left corner
painter.drawPixmap(rect().width() - shadow_width, rect().height() - shadow_width, radial_gradient, shadow_width, shadow_width, shadow_width, shadow_width); //Bottom-right corner
painter.drawPixmap(shadow_width, 0, rect1.width(), shadow_width, radial_gradient, shadow_width, 0, 1, shadow_width); //Top
painter.drawPixmap(0, shadow_width, shadow_width, rect1.height(), radial_gradient, 0, shadow_width, shadow_width, 1); //Left
painter.drawPixmap(rect1.width() + shadow_width, shadow_width, shadow_width, rect1.height(), radial_gradient, shadow_width, shadow_width, shadow_width, 1); //Right
painter.drawPixmap(shadow_width, rect1.height() + shadow_width, rect1.width(), shadow_width, radial_gradient, shadow_width, shadow_width, 1, SHADOW_BORDER_WIDTH); //Bottom
}
}// namespace pv

View File

@ -19,96 +19,52 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WINSHADOW_H
#define WINSHADOW_H
#ifndef SHADOW_H
#define SHADOW_H
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QtWidgets>
#include <windows.h>
#include <QGridLayout>
#include "widgets/border.h"
#define SHADOW_BORDER_WIDTH 11
#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 moveShadow();
void SetClean(bool bClean);
inline void SetFrame(MainFrame *frame){
_frame = frame;
inline void setScale(int k){
m_scale = k;
}
void showLater();
void hideShadow();
Q_SIGNALS:
void showSignal();
public Q_SLOTS:
void showShadow();
void onMoveSelf();
public Q_SLOTS:
void showLater();
void show();
void hide();
private:
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
void paintEvent(QPaintEvent *event) override;
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:
QWidget *m_parent;
QTimer *m_timer;
HWND m_hwnd;
bool m_active;
bool m_bClean;
int m_scale;
};
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;
} // namespace pv
MainFrame *_frame;
int _hit_border;
bool _bDraging;
QTimer _timer;
bool _freezing;
QPoint _clickPos;
QRect _dragStartRegion;
};
}
#endif // SHADOW_H
#endif