diff --git a/DSView/main.cpp b/DSView/main.cpp index 1278f99c..748a59d9 100644 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -237,9 +237,9 @@ bool bHighScale = true; { pv::MainFrame w; control->Start(); - w.show(); - w.readSettings(); - w.show_doc(); //to show the dailog for open help document + w.ShowFormInit(); + w.ShowHelpDocAsync(); //to show the dailog for open help document + ret = a.exec(); //Run the application control->Stop(); diff --git a/DSView/pv/dialogs/dsdialog.cpp b/DSView/pv/dialogs/dsdialog.cpp index 4a410e3e..433c0393 100644 --- a/DSView/pv/dialogs/dsdialog.cpp +++ b/DSView/pv/dialogs/dsdialog.cpp @@ -1,196 +1,196 @@ -/* - * This file is part of the DSView project. - * DSView is based on PulseView. - * - * Copyright (C) 2016 DreamSourceLab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include "dsdialog.h" -#include "shadow.h" - -#include -#include -#include -#include -#include -#include "../dsvdef.h" -#include "../config/appconfig.h" -#include "../ui/fn.h" - -namespace pv { -namespace dialogs { - -DSDialog::DSDialog() : - DSDialog(NULL, false, false) -{ -} - -DSDialog::DSDialog(QWidget *parent): - DSDialog(parent, false, false) -{ -} - -DSDialog::DSDialog(QWidget *parent, bool hasClose): - DSDialog(parent, hasClose, false) -{ -} - -DSDialog::DSDialog(QWidget *parent, bool hasClose, bool bBaseButton) : - QDialog(parent), - m_bBaseButton(bBaseButton) -{ - (void)parent; - - _base_layout = NULL; - _main_layout = NULL; - _main_widget = NULL; - _titlebar = NULL; - _shadow = NULL; - _base_button = NULL; - _titleSpaceLine = NULL; - - m_callback = NULL; - _clickYes = false; - - setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); - setAttribute(Qt::WA_TranslucentBackground); - - build_base(hasClose); -} - -DSDialog::~DSDialog() -{ - DESTROY_QT_OBJECT(_base_layout); - DESTROY_QT_OBJECT(_main_layout); - DESTROY_QT_OBJECT(_main_widget); - DESTROY_QT_OBJECT(_titlebar); - DESTROY_QT_OBJECT(_shadow); - DESTROY_QT_OBJECT(_base_button); -} - -void DSDialog::accept() -{ - _clickYes = true; - if (m_callback){ - m_callback->OnDlgResult(true); - } - - - QDialog::accept(); -} - -void DSDialog::reject() -{ - _clickYes = false; - - if (m_callback){ - m_callback->OnDlgResult(false); - } - - QDialog::reject(); -} - -void DSDialog::setTitle(QString title) -{ - if (_titlebar){ - _titlebar->setTitle(title); - } -} - -void DSDialog::reload() -{ - show(); -} - -int DSDialog::exec() -{ - //ok,cancel - if (m_bBaseButton){ - _base_button = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,Qt::Horizontal, this); - _main_layout->addWidget(_base_button);//, 5, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom); - //_main_layout->addWidget(_base_button,0, Qt::AlignHCenter | Qt::AlignBottom); - connect(_base_button, SIGNAL(rejected()), this, SLOT(reject())); - connect(_base_button, SIGNAL(accepted()), this, SLOT(accept())); - } - - update_font(); - - return QDialog::exec(); -} - - void DSDialog::SetTitleSpace(int h) - { - if (_titleSpaceLine != NULL){ - if (h > 0){ - _titleSpaceLine->setFixedHeight(h); - _titleSpaceLine->setVisible(true); - } - else{ - _titleSpaceLine->setVisible(false); - } - } - } - -void DSDialog::build_base(bool hasClose) -{ - _main_widget = new QWidget(this); - _main_layout = new QVBoxLayout(_main_widget); - _main_widget->setLayout(_main_layout); - - _shadow = new Shadow(this); - _shadow->setBlurRadius(10.0); - _shadow->setDistance(3.0); - _shadow->setColor(QColor(0, 0, 0, 80)); - _main_widget->setAutoFillBackground(true); - this->setGraphicsEffect(_shadow); - - _titlebar = new toolbars::TitleBar(false, this, hasClose); - _main_layout->addWidget(_titlebar); - - _titleSpaceLine = new QWidget(this); - _titleSpaceLine->setFixedHeight(15); - _main_layout->addWidget(_titleSpaceLine); - - _base_layout = new QVBoxLayout(this); - _base_layout->addWidget(_main_widget); - setLayout(_base_layout); - - _main_layout->setAlignment(Qt::AlignCenter | Qt::AlignTop); - _main_layout->setContentsMargins(10,5,10,10); -} - -void DSDialog::update_font() -{ - QFont font = this->font(); - font.setPointSizeF(AppConfig::Instance().appOptions.fontSize); - ui::set_form_font(this, font); - - if (_titlebar != NULL){ - _titlebar->update_font(); - } -} - -void DSDialog::show() -{ - update_font(); - - QWidget::show(); -} - -} // namespace dialogs -} // namespace pv +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "dsdialog.h" +#include "shadow.h" + +#include +#include +#include +#include +#include +#include "../dsvdef.h" +#include "../config/appconfig.h" +#include "../ui/fn.h" + +namespace pv { +namespace dialogs { + +DSDialog::DSDialog() : + DSDialog(NULL, false, false) +{ +} + +DSDialog::DSDialog(QWidget *parent): + DSDialog(parent, false, false) +{ +} + +DSDialog::DSDialog(QWidget *parent, bool hasClose): + DSDialog(parent, hasClose, false) +{ +} + +DSDialog::DSDialog(QWidget *parent, bool hasClose, bool bBaseButton) : + QDialog(parent), + m_bBaseButton(bBaseButton) +{ + (void)parent; + + _base_layout = NULL; + _main_layout = NULL; + _main_widget = NULL; + _titlebar = NULL; + _shadow = NULL; + _base_button = NULL; + _titleSpaceLine = NULL; + + m_callback = NULL; + _clickYes = false; + + setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + setAttribute(Qt::WA_TranslucentBackground); + + build_base(hasClose); +} + +DSDialog::~DSDialog() +{ + DESTROY_QT_OBJECT(_base_layout); + DESTROY_QT_OBJECT(_main_layout); + DESTROY_QT_OBJECT(_main_widget); + DESTROY_QT_OBJECT(_titlebar); + DESTROY_QT_OBJECT(_shadow); + DESTROY_QT_OBJECT(_base_button); +} + +void DSDialog::accept() +{ + _clickYes = true; + if (m_callback){ + m_callback->OnDlgResult(true); + } + + + QDialog::accept(); +} + +void DSDialog::reject() +{ + _clickYes = false; + + if (m_callback){ + m_callback->OnDlgResult(false); + } + + QDialog::reject(); +} + +void DSDialog::setTitle(QString title) +{ + if (_titlebar){ + _titlebar->setTitle(title); + } +} + +void DSDialog::reload() +{ + show(); +} + +int DSDialog::exec() +{ + //ok,cancel + if (m_bBaseButton){ + _base_button = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,Qt::Horizontal, this); + _main_layout->addWidget(_base_button);//, 5, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom); + //_main_layout->addWidget(_base_button,0, Qt::AlignHCenter | Qt::AlignBottom); + connect(_base_button, SIGNAL(rejected()), this, SLOT(reject())); + connect(_base_button, SIGNAL(accepted()), this, SLOT(accept())); + } + + update_font(); + + return QDialog::exec(); +} + + void DSDialog::SetTitleSpace(int h) + { + if (_titleSpaceLine != NULL){ + if (h > 0){ + _titleSpaceLine->setFixedHeight(h); + _titleSpaceLine->setVisible(true); + } + else{ + _titleSpaceLine->setVisible(false); + } + } + } + +void DSDialog::build_base(bool hasClose) +{ + _main_widget = new QWidget(this); + _main_layout = new QVBoxLayout(_main_widget); + _main_widget->setLayout(_main_layout); + + _shadow = new Shadow(this); + _shadow->setBlurRadius(10.0); + _shadow->setDistance(3.0); + _shadow->setColor(QColor(0, 0, 0, 80)); + _main_widget->setAutoFillBackground(true); + this->setGraphicsEffect(_shadow); + + _titlebar = new toolbars::TitleBar(false, this, NULL,hasClose); + _main_layout->addWidget(_titlebar); + + _titleSpaceLine = new QWidget(this); + _titleSpaceLine->setFixedHeight(15); + _main_layout->addWidget(_titleSpaceLine); + + _base_layout = new QVBoxLayout(this); + _base_layout->addWidget(_main_widget); + setLayout(_base_layout); + + _main_layout->setAlignment(Qt::AlignCenter | Qt::AlignTop); + _main_layout->setContentsMargins(10,5,10,10); +} + +void DSDialog::update_font() +{ + QFont font = this->font(); + font.setPointSizeF(AppConfig::Instance().appOptions.fontSize); + ui::set_form_font(this, font); + + if (_titlebar != NULL){ + _titlebar->update_font(); + } +} + +void DSDialog::show() +{ + update_font(); + + QWidget::show(); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/dsmessagebox.cpp b/DSView/pv/dialogs/dsmessagebox.cpp index 05e0f3f9..2c436adb 100644 --- a/DSView/pv/dialogs/dsmessagebox.cpp +++ b/DSView/pv/dialogs/dsmessagebox.cpp @@ -1,145 +1,145 @@ -/* - * This file is part of the DSView project. - * DSView is based on PulseView. - * - * Copyright (C) 2016 DreamSourceLab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include "dsmessagebox.h" -#include "shadow.h" - -#include -#include -#include -#include -#include -#include "../dsvdef.h" -#include "../ui/langresource.h" -#include "../config/appconfig.h" -#include "../ui/fn.h" - -namespace pv { -namespace dialogs { - -DSMessageBox::DSMessageBox(QWidget *parent,const QString title) : - QDialog(parent) -{ - (void)parent; - _layout = NULL; - _main_widget = NULL; - _msg = NULL; - _titlebar = NULL; - _shadow = NULL; - _main_layout = NULL; - - _bClickYes = false; - - setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); - setAttribute(Qt::WA_TranslucentBackground); - - _main_widget = new QWidget(this); - _main_layout = new QVBoxLayout(_main_widget); - _main_widget->setLayout(_main_layout); - - _shadow = new Shadow(this); - _msg = new QMessageBox(this); - _titlebar = new toolbars::TitleBar(false, this); - _layout = new QVBoxLayout(this); - - _shadow->setBlurRadius(10.0); - _shadow->setDistance(3.0); - _shadow->setColor(QColor(0, 0, 0, 80)); - - _main_widget->setAutoFillBackground(true); - this->setGraphicsEffect(_shadow); - - _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); - - if (!title.isEmpty()){ - _titlebar->setTitle(title); - } - else{ - _titlebar->setTitle(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_MESSAGE), "Message")); - } - - _main_layout->addWidget(_titlebar); - _main_layout->addWidget(_msg); - _layout->addWidget(_main_widget); - - setLayout(_layout); - - connect(_msg, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_button(QAbstractButton*))); -} - - -DSMessageBox::~DSMessageBox() -{ - DESTROY_QT_OBJECT(_layout); - DESTROY_QT_OBJECT(_main_widget); - DESTROY_QT_OBJECT(_msg); - DESTROY_QT_OBJECT(_titlebar); - DESTROY_QT_OBJECT(_shadow); - DESTROY_QT_OBJECT(_main_layout); -} - -void DSMessageBox::accept() -{ - using namespace Qt; - - QDialog::accept(); -} - -void DSMessageBox::reject() -{ - using namespace Qt; - - QDialog::reject(); -} - -QMessageBox* DSMessageBox::mBox() -{ - return _msg; -} - -void DSMessageBox::on_button(QAbstractButton *btn) -{ - QMessageBox::ButtonRole role = _msg->buttonRole(btn); - - if (role == QMessageBox::AcceptRole || role == QMessageBox::YesRole){ - _bClickYes = true; - accept(); - } - else - reject(); -} - -int DSMessageBox::exec() -{ - QFont font = this->font(); - font.setPointSizeF(AppConfig::Instance().appOptions.fontSize); - ui::set_form_font(this, font); - - if (_titlebar != NULL){ - _titlebar->update_font(); - } - - return QDialog::exec(); -} - -} // namespace dialogs -} // namespace pv +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2016 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "dsmessagebox.h" +#include "shadow.h" + +#include +#include +#include +#include +#include +#include "../dsvdef.h" +#include "../ui/langresource.h" +#include "../config/appconfig.h" +#include "../ui/fn.h" + +namespace pv { +namespace dialogs { + +DSMessageBox::DSMessageBox(QWidget *parent,const QString title) : + QDialog(parent) +{ + (void)parent; + _layout = NULL; + _main_widget = NULL; + _msg = NULL; + _titlebar = NULL; + _shadow = NULL; + _main_layout = NULL; + + _bClickYes = false; + + setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + setAttribute(Qt::WA_TranslucentBackground); + + _main_widget = new QWidget(this); + _main_layout = new QVBoxLayout(_main_widget); + _main_widget->setLayout(_main_layout); + + _shadow = new Shadow(this); + _msg = new QMessageBox(this); + _titlebar = new toolbars::TitleBar(false, this, NULL, false); + _layout = new QVBoxLayout(this); + + _shadow->setBlurRadius(10.0); + _shadow->setDistance(3.0); + _shadow->setColor(QColor(0, 0, 0, 80)); + + _main_widget->setAutoFillBackground(true); + this->setGraphicsEffect(_shadow); + + _msg->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + + if (!title.isEmpty()){ + _titlebar->setTitle(title); + } + else{ + _titlebar->setTitle(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_MESSAGE), "Message")); + } + + _main_layout->addWidget(_titlebar); + _main_layout->addWidget(_msg); + _layout->addWidget(_main_widget); + + setLayout(_layout); + + connect(_msg, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_button(QAbstractButton*))); +} + + +DSMessageBox::~DSMessageBox() +{ + DESTROY_QT_OBJECT(_layout); + DESTROY_QT_OBJECT(_main_widget); + DESTROY_QT_OBJECT(_msg); + DESTROY_QT_OBJECT(_titlebar); + DESTROY_QT_OBJECT(_shadow); + DESTROY_QT_OBJECT(_main_layout); +} + +void DSMessageBox::accept() +{ + using namespace Qt; + + QDialog::accept(); +} + +void DSMessageBox::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +QMessageBox* DSMessageBox::mBox() +{ + return _msg; +} + +void DSMessageBox::on_button(QAbstractButton *btn) +{ + QMessageBox::ButtonRole role = _msg->buttonRole(btn); + + if (role == QMessageBox::AcceptRole || role == QMessageBox::YesRole){ + _bClickYes = true; + accept(); + } + else + reject(); +} + +int DSMessageBox::exec() +{ + QFont font = this->font(); + font.setPointSizeF(AppConfig::Instance().appOptions.fontSize); + ui::set_form_font(this, font); + + if (_titlebar != NULL){ + _titlebar->update_font(); + } + + return QDialog::exec(); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/mainframe.cpp b/DSView/pv/mainframe.cpp index 5e2e68b7..82555950 100644 --- a/DSView/pv/mainframe.cpp +++ b/DSView/pv/mainframe.cpp @@ -45,7 +45,6 @@ #include #include - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include #endif @@ -56,9 +55,12 @@ #include "appcontrol.h" #include "ui/langresource.h" #include "log.h" - #include +#ifdef _WIN32 +#include "winnativewidget.h" +#endif + namespace pv { MainFrame::MainFrame() @@ -70,52 +72,34 @@ MainFrame::MainFrame() _titleBar = NULL; _mainWindow = NULL; _is_native_title = false; - _is_resize_ready = false; - _move_event_count = false; - _is_resize_reset_timer = false; - _resize_event_count = 0; + _is_resize_ready = false; + _parentNativeWidget = NULL; + _mainWindow = NULL; + _is_max_status = false; AppControl::Instance()->SetTopWindow(this); + + // Make this a borderless window which can't + // be resized or moved via the window system +#ifdef _WIN32 + setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); + _is_native_title = true; + _taskBtn = NULL; +#else + setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + setAttribute(Qt::WA_TranslucentBackground); + _is_native_title = false; +#endif - bool is_win32 = false; - - #ifdef _WIN32 - _is_native_title = true; - is_win32 = true; - #else - _is_native_title = false; - #endif - - //_is_native_title = true; - - setMinimumWidth(MainWindow::Min_Width); - setMinimumHeight(MainWindow::Min_Height); + // setMinimumWidth(MainWindow::Min_Width); + // setMinimumHeight(MainWindow::Min_Height); // Set the window icon QIcon icon; - - if (_is_native_title && is_win32){ - icon.addFile(QString::fromUtf8(":/icons/win_title_logo.svg"), QSize(), QIcon::Normal, QIcon::Off); - } - else{ - icon.addFile(QString::fromUtf8(":/icons/logo.svg"), QSize(), QIcon::Normal, QIcon::Off); - } - + icon.addFile(QString::fromUtf8(":/icons/logo.svg"), QSize(), QIcon::Normal, QIcon::Off); setWindowIcon(icon); - // Title - _titleBar = new toolbars::TitleBar(true, this); - - if (_is_native_title){ - _titleBar->setVisible(false); - _titleBar->set_native(); - } - else{ - setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); - setAttribute(Qt::WA_TranslucentBackground); - } - - // MainWindow + _titleBar = new toolbars::TitleBar(true, this, this, false); _mainWindow = new MainWindow(_titleBar, this); _mainWindow->setWindowFlags(Qt::Widget); @@ -129,10 +113,7 @@ MainFrame::MainFrame() _layout->setSpacing(0); _layout->setContentsMargins(0,0,0,0); - if (_is_native_title){ - _layout->addLayout(vbox, 0, 0); - } - else + if (true) { _top_left = new widgets::Border (TopLeft, this); _top_left->setFixedSize(Margin, Margin); @@ -179,11 +160,184 @@ MainFrame::MainFrame() connect(&_timer, SIGNAL(timeout()), this, SLOT(unfreezing())); - QTimer::singleShot(500, this, [this](){ + QTimer::singleShot(2000, this, [this](){ _is_resize_ready = true; }); installEventFilter(this); + + //PrintRegionProc(); +} + +void MainFrame::PrintRegionProc() +{ + PrintRegion(); + + QTimer::singleShot(4000, this, [this](){ + PrintRegionProc(); + }); +} + +void MainFrame::PrintRegion() +{ + QRect rc = geometry(); + + int x = rc.left(); + int y = rc.top(); + int w = rc.width(); + int h = rc.height(); + + dsv_info("print region, x:%d, y:%d, w:%d, h:%d", + x, y, w, h); +} + +void MainFrame::AttachNativeWindow() +{ +#ifdef _WIN32 + int k = QApplication::desktop()->screen()->devicePixelRatio(); + + QRect rc = geometry(); + + int x = rc.left() * k; + int y = rc.top() * k; + int w = rc.width() * k; + int h = rc.height() * k; + + if (_parentNativeWidget != NULL){ + _parentNativeWidget->SetChildWidget(NULL); + delete _parentNativeWidget; + } + + _parentNativeWidget = new WinNativeWidget(x, y, w, h); + _parentNativeWidget->setGeometry(x, y, w, h); + _parentNativeWidget->SetChildWidget(this); + + if (_parentNativeWidget->Handle()) + { + _parentNativeWidget->Show(true); + + setWindowFlags(Qt::FramelessWindowHint); + setProperty("_q_embedded_native_parent_handle", (WId)_parentNativeWidget->Handle()); + SetWindowLong((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + + SetParent((HWND)winId(), _parentNativeWidget->Handle()); + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(this, &e); + + QTimer::singleShot(10, this, [this](){ + move(0,0); + setVisible(true); + + if (_initWndInfo.isMaxSize){ + showMaximized(); + } + }); + } + +#endif +} + +void MainFrame::MoveWindow(int x, int y) +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + int k = window()->devicePixelRatio(); + _parentNativeWidget->Move(x * k, y * k); + return; + } +#endif + + move(x, y); +} + +QPoint MainFrame::GetParentPos() +{ +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + RECT rc; + int k = window()->devicePixelRatio(); + GetWindowRect(_parentNativeWidget->Handle(), &rc); + return QPoint(rc.left / k, rc.top / k); + } +#endif + + return pos(); +} + +bool MainFrame::ParentIsMaxsized() +{ + return _is_max_status; +} + +void MainFrame::MoveBegin() +{ + // dsv_info("Move begin."); + +#ifdef _WIN32 + if (_parentNativeWidget != NULL) + { + POINT p; + GetCursorPos(&p); + + HMONITOR hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY); + MONITORINFOEX inf; + inf.cbSize = sizeof(inf); + + if (GetMonitorInfo(hMonitor, &inf)) { + int x = inf.rcMonitor.left; + int y = inf.rcMonitor.top; + int w = inf.rcMonitor.right - inf.rcMonitor.left; + int h = inf.rcMonitor.bottom - inf.rcMonitor.top; + + _move_screen_region = QRect(x, y, w, h); + } + } + +#endif +} + +void MainFrame::MoveEnd() +{ + // dsv_info("Move end."); + +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + + POINT p; + GetCursorPos(&p); + + HMONITOR hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY); + MONITORINFOEX inf; + inf.cbSize = sizeof(inf); + + if (GetMonitorInfo(hMonitor, &inf)) { + int x = inf.rcMonitor.left; + int y = inf.rcMonitor.top; + int w = inf.rcMonitor.right - inf.rcMonitor.left; + int h = inf.rcMonitor.bottom - inf.rcMonitor.top; + + // End at the same screen. + if (x == _move_screen_region.left() && w == _move_screen_region.width()){ + dsv_info("Move to the same screen."); + return; + } + } + + dsv_info("Move to another screen."); + + QRect rc = GetFormRegion(); + + SetParent((HWND)winId(), NULL); + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(this, &e); + _parentNativeWidget->SetChildWidget(NULL); + + setGeometry(rc.left(), rc.top(), rc.width(), rc.height()); + + this->AttachNativeWindow(); + } + +#endif } void MainFrame::resizeEvent(QResizeEvent *event) @@ -194,28 +348,14 @@ void MainFrame::resizeEvent(QResizeEvent *event) return; } - if (isMaximized()) { + if (_is_max_status) { hide_border(); } else { show_border(); - - _resize_event_count++; - - if (_resize_event_count >= 2){ - saveNormalRegion(); - } - else if (!_is_resize_reset_timer){ - _is_resize_reset_timer = true; - - QTimer::singleShot(500, this, [this](){ - _is_resize_reset_timer = false; - _resize_event_count = 0; - }); - } } - _titleBar->setRestoreButton(isMaximized()); + _titleBar->setRestoreButton(_is_max_status); _layout->update(); } @@ -224,6 +364,14 @@ void MainFrame::closeEvent(QCloseEvent *event) writeSettings(); if (_mainWindow->able_to_close()){ + +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + _parentNativeWidget->SetChildWidget(NULL); + _parentNativeWidget->Show(false); + } +#endif + event->accept(); } else{ @@ -237,11 +385,7 @@ void MainFrame::unfreezing() } void MainFrame::hide_border() -{ - if (_is_native_title){ - return; - } - +{ _top_left->setVisible(false); _top_right->setVisible(false); _top->setVisible(false); @@ -253,11 +397,7 @@ void MainFrame::hide_border() } void MainFrame::show_border() -{ - if (_is_native_title){ - return; - } - +{ _top_left->setVisible(true); _top_right->setVisible(true); _top->setVisible(true); @@ -271,77 +411,99 @@ void MainFrame::show_border() void MainFrame::showNormal() { show_border(); + + dsv_info("Show as normal."); + + _is_max_status = false; + +#ifdef _WIN32 + if (_parentNativeWidget){ + _parentNativeWidget->ShowNormal(); + + return; + } +#endif + QFrame::showNormal(); } void MainFrame::showMaximized() -{ +{ hide_border(); + + dsv_info("Show as maxsize."); + + _is_max_status = true; + +#ifdef _WIN32 + if (_parentNativeWidget){ + _parentNativeWidget->ShowMax(); + return; + } +#endif + QFrame::showMaximized(); } void MainFrame::showMinimized() -{ +{ + dsv_info("Show as minsize."); + +#ifdef _WIN32 + if (_parentNativeWidget){ + _parentNativeWidget->ShowMin(); + return; + } +#endif + QFrame::showMinimized(); } void MainFrame::changeEvent(QEvent *event) { - if (event->type() == QEvent::WindowStateChange && _is_resize_ready) { + if (event->type() == QEvent::WindowStateChange && _is_resize_ready) { + //dsv_info("Window state changed."); QWindowStateChangeEvent *stateChangeEvent = static_cast(event); if (stateChangeEvent->oldState() & Qt::WindowMaximized && !(windowState() & Qt::WindowMaximized)) { - moveToNormal(); + } } QFrame::changeEvent(event); } -void MainFrame::moveToNormal() +void MainFrame::moveToWinNaitiveNormal() { - AppConfig &app = AppConfig::Instance(); - 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; - - if (_is_native_title && y != NO_POINT_VALUE){ - move(x, y); - } - else{ - move(left, top); - } +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + + int k = QApplication::desktop()->screen()->devicePixelRatio(); + + int x = _normalRegion.x * k; + int y = _normalRegion.y * k; + int w = _normalRegion.w * k; + int h = _normalRegion.h * k; - if (right - left > 0){ - resize(right - left, bottom - top); - } + _parentNativeWidget->setGeometry(x, y, w, h); + } +#endif } bool MainFrame::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::Move && _is_resize_ready){ - if (isMaximized() == false){ - _move_event_count++; - if (_move_event_count >= 2){ - saveNormalRegion(); - } + if (_is_max_status == false && _titleBar->IsMoving()){ + saveNormalRegion(); } return QFrame::eventFilter(object, event); - } - _move_event_count = 0; - - if (_is_native_title){ - return QFrame::eventFilter(object, event); - } + } const QEvent::Type type = event->type(); const QMouseEvent *const mouse_event = (QMouseEvent*)event; - int newWidth; - int newHeight; - int newLeft; - int newTop; + int newWidth = 0; + int newHeight = 0; + int newLeft = 0; + int newTop = 0; if (type != QEvent::MouseMove && type != QEvent::MouseButtonPress @@ -351,7 +513,7 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } //when window is maximized, or is moving, call return - if (isMaximized() || _titleBar->IsMoving()){ + if (_is_max_status || _titleBar->IsMoving()){ return QFrame::eventFilter(object, event); } @@ -389,103 +551,132 @@ bool MainFrame::eventFilter(QObject *object, QEvent *event) } if (type == QEvent::MouseMove) { + + QPoint pt; - #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - int x0 = (int)mouse_event->globalPosition().x(); - int y0 = (int)mouse_event->globalPosition().y(); - #else - int x0 = mouse_event->globalX(); - int y0 = mouse_event->globalY(); - #endif +#ifdef _WIN32 + POINT p; + GetCursorPos(&p); + pt.setX(p.x); + pt.setY(p.y); +#else + pt = mouse_event->globalPos(); +#endif + int datX = pt.x() - _clickPos.x(); + int datY = pt.y() - _clickPos.y(); + int l = _dragStartRegion.left(); + int t = _dragStartRegion.top(); + int r = _dragStartRegion.right(); + int b = _dragStartRegion.bottom(); if(mouse_event->buttons().testFlag(Qt::LeftButton)) { - if (!_freezing) { - switch (_hit_border) { + + // Do nothing this time. + if (_freezing){ + return QFrame::eventFilter(object, event); + } + + int minW = MainWindow::Min_Width; + int minH = MainWindow::Min_Height; + + switch (_hit_border) { case TopLeft: - newWidth = std::max(_dragStartGeometry.right() - x0, minimumWidth()); - newHeight = std::max(_dragStartGeometry.bottom() - y0, minimumHeight()); - newLeft = geometry().left(); - newTop = geometry().top(); - if (newWidth > minimumWidth()) - newLeft = x0; - if (newHeight > minimumHeight()) - newTop = y0; - setGeometry(newLeft, newTop, newWidth, newHeight); + l += datX; + t += datY; + if (r - l < minW) + l = r - minW; + if (b - t < minH) + t = b - minH; break; case BottomLeft: - newWidth = std::max(_dragStartGeometry.right() - x0, minimumWidth()); - newHeight = std::max(y0 - _dragStartGeometry.top(), minimumHeight()); - newLeft = geometry().left(); - if (newWidth > minimumWidth()) - newLeft = x0; - setGeometry(newLeft, _dragStartGeometry.top(), newWidth, newHeight); + l += datX; + b += datY; + if (r - l < minW) + l = r - minW; + if (b - t < minH) + b = t + minH; break; case TopRight: - newWidth = std::max(x0 - _dragStartGeometry.left(), minimumWidth()); - newHeight = std::max(_dragStartGeometry.bottom() - y0, minimumHeight()); - newTop = geometry().top(); - if (newHeight > minimumHeight()) - newTop = y0; - setGeometry(_dragStartGeometry.left(), newTop, newWidth, newHeight); + r += datX; + t += datY; + if (r - l < minW) + r = l + minW; + if (b - t < minH) + t = b - minH; break; case BottomRight: - newWidth = std::max(x0 - _dragStartGeometry.left(), minimumWidth()); - newHeight = std::max(y0 - _dragStartGeometry.top(), minimumHeight()); - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, newHeight); + r += datX; + b += datY; + if (r - l < minW) + r = l + minW; + if (b - t < minH) + b = t + minH; break; case Left: - newWidth = _dragStartGeometry.right() - x0; - if (newWidth > minimumWidth()){ - setGeometry(x0, _dragStartGeometry.top(), newWidth, height()); - } + l += datX; + if (r - l < minW) + l = r - minW; break; case Right: - newWidth = x0 - _dragStartGeometry.left(); - if (newWidth > minimumWidth()){ - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), newWidth, height()); - } + r += datX; + if (r - l < minW) + r = l + minW; break; - case Top: - newHeight = _dragStartGeometry.bottom() - y0; - if (newHeight > minimumHeight()){ - setGeometry(_dragStartGeometry.left(), y0,width(), newHeight); - } + case Top: + t += datY; + if (b - t < minH) + t = b - minH; break; - case Bottom: - newHeight = y0 - _dragStartGeometry.top(); - if (newHeight > minimumHeight()){ - setGeometry(_dragStartGeometry.left(), _dragStartGeometry.top(), width(), newHeight); - } + case Bottom: + b += datY; + if (b - t < minH) + b = t + minH; break; default: + r = l; break; - } - _freezing = true; - } + } + + if (r != l){ + SetFormRegion(l, t, r-l, b-t); + saveNormalRegion(); + } + return true; } } - else if (type == QEvent::MouseButtonPress) { + else if (type == QEvent::MouseButtonPress) { if (mouse_event->button() == Qt::LeftButton) if (_hit_border != None) _bDraging = true; - _timer.start(50); - _dragStartGeometry = geometry(); + _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) { if (mouse_event->button() == Qt::LeftButton) { _bDraging = false; - _timer.stop(); + _timer.stop(); } - } else if (!_bDraging && type == QEvent::Leave) { + } + else if (!_bDraging && type == QEvent::Leave) { _hit_border = None; setCursor(Qt::ArrowCursor); } @@ -499,38 +690,153 @@ void MainFrame::saveNormalRegion() if (!_is_resize_ready){ return; } - if (isMaximized()){ + if (_is_max_status){ return; + } + + AppConfig &app = AppConfig::Instance(); + +#ifdef _WIN32 + if (_parentNativeWidget != NULL){ + RECT rc; + int k = QApplication::desktop()->screen()->devicePixelRatio(); + + GetWindowRect(_parentNativeWidget->Handle(), &rc); + app.frameOptions.left = rc.left / k; + app.frameOptions.top = rc.top / k; + app.frameOptions.right = rc.right / k; + app.frameOptions.bottom = rc.bottom / k; + app.frameOptions.x = rc.left / k; + app.frameOptions.y = rc.top / k; } +#endif - AppConfig &app = AppConfig::Instance(); - QRect rc = geometry(); - app.frameOptions.left = rc.left(); - app.frameOptions.top = rc.top(); - app.frameOptions.right = rc.right(); - app.frameOptions.bottom = rc.bottom(); - - QRect frc = frameGeometry(); - app.frameOptions.x = frc.x(); - app.frameOptions.y = frc.y(); + if (_parentNativeWidget == NULL){ + QRect rc = geometry(); + app.frameOptions.left = rc.left(); + app.frameOptions.top = rc.top(); + app.frameOptions.right = rc.right(); + app.frameOptions.bottom = rc.bottom(); + app.frameOptions.x = rc.left(); + app.frameOptions.y = rc.top(); + } } void MainFrame::writeSettings() { AppConfig &app = AppConfig::Instance(); - app.frameOptions.isMax = isMaximized(); + app.frameOptions.isMax = _is_max_status; - if (isMaximized() == false && isVisible()){ + if (_is_max_status == false && isVisible()){ saveNormalRegion(); } - app.SaveFrame(); + app.SaveFrame(); + + int x = app.frameOptions.x; + int y = app.frameOptions.y; + int w = app.frameOptions.right - app.frameOptions.left; + int h = app.frameOptions.bottom - app.frameOptions.top; + + dsv_info("Save form, x:%d, y:%d, w:%d, h:%d", x, y, w, h); } -void MainFrame::readSettings() -{ - if (_layout == NULL) - return; +void MainFrame::ShowFormInit() +{ + ReadSettings(); + int x = _initWndInfo.r.x; + int y = _initWndInfo.r.y; + int w = _initWndInfo.r.w; + int h = _initWndInfo.r.h; + + if (w % 2 == 0){ + w++; + } + if (h % 2 == 0){ + h++; + } + + bool isWin32 = false; + +#ifdef _WIN32 + isWin32 = true; +#endif + + if (_initWndInfo.isMaxSize) + { + if (isWin32 && _is_native_title){ + hide_border(); + move(_normalRegion.x, _normalRegion.y); + resize(_normalRegion.w, _normalRegion.h); + } + else{ + move(x, y); + showMaximized(); + } + } + else{ + move(x, y); + resize(w, h); + } + + QFrame::show(); + + dsv_info("Init form, x:%d, y:%d, w:%d, h:%d", x, y, w, h); + + if (_is_native_title){ + AttachNativeWindow(); + } +} + +void MainFrame::SetFormRegion(int x, int y, int w, int h) +{ + #ifdef _WIN32 + + if (_parentNativeWidget != NULL){ + int k = QApplication::desktop()->screen()->devicePixelRatio(); + + x *= k; + y *= k; + w *= k; + h *= k; + + _parentNativeWidget->setGeometry(x, y, w, h); + + return; + } + #endif + + setGeometry(x, y, w, h); +} + + QRect MainFrame::GetFormRegion() + { + QRect rc; + +#ifdef _WIN32 + + if (_parentNativeWidget != NULL){ + int k = QApplication::desktop()->screen()->devicePixelRatio(); + RECT r; + GetWindowRect(_parentNativeWidget->Handle(), &r); + int x = r.left; + int y = r.top; + int w = r.right-r.left; + int h = r.bottom-r.top; + rc = QRect(x/k, y/k, w/k, h/k); + } + else{ + rc = geometry(); + } +#else + rc = geometry(); +#endif + + return rc; + } + +void MainFrame::ReadSettings() +{ AppConfig &app = AppConfig::Instance(); if (app.frameOptions.language > 0){ @@ -542,22 +848,31 @@ void MainFrame::readSettings() int right = app.frameOptions.right; int bottom = app.frameOptions.bottom; int x = app.frameOptions.x; - int y = app.frameOptions.y; - int ox = app.frameOptions.ox; - int oy = app.frameOptions.oy; + int y = app.frameOptions.y; + + if (x == NO_POINT_VALUE){ + x = left; + y = top; + } + + dsv_info("Loaded region, x:%d, y:%d, w:%d, h:%d", + x, y, right-left, bottom-top); bool bReset = false; int scrIndex = -1; - QRect winRc = {left, top, right-left, bottom-top}; + QRect winRc = {x, y, right-left, bottom-top}; for (int i=0; iavailableGeometry(); QRect inrc = rc.intersected(winRc); + 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 (inrc.width() > 10 || inrc.height() > 10){ + if (scrIndex == -1 && (inrc.width() > 10 || inrc.height() > 10)){ scrIndex = i; - break; } } @@ -567,10 +882,16 @@ void MainFrame::readSettings() else{ QRect rc = QGuiApplication::screens().at(scrIndex)->availableGeometry(); QRect inrc = rc.intersected(winRc); - if (inrc.width() < 70 || inrc.height() < 70){ + if (inrc.width() < 70 || inrc.height() < 70 || winRc.width() < 300){ bReset = true; } - } + } + + _initWndInfo.r.x = 0; + _initWndInfo.r.y = 0; + _initWndInfo.r.w = 0; + _initWndInfo.r.h = 0; + _initWndInfo.isMaxSize = false; if (app.frameOptions.isMax) { @@ -586,10 +907,25 @@ void MainFrame::readSettings() scrName = QGuiApplication::screens().at(scrIndex)->name(); } - move(rc.left(), rc.top()); + _initWndInfo.r.x = rc.left(); + _initWndInfo.r.y = rc.top(); + _initWndInfo.r.w = rc.width(); + _initWndInfo.r.h = rc.height(); + _initWndInfo.isMaxSize = true; - showMaximized(); // show max by system api - dsv_info("show as max, screen:%s", scrName.toStdString().c_str()); + _normalRegion.x = x; + _normalRegion.y = y; + _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; + } + + 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()); } else if (bReset) { @@ -610,31 +946,43 @@ void MainFrame::readSettings() const int x0 = rc.left() + (rc.width() - w) / 2; const int y0 = rc.top() + (rc.height() - h) / 2; - move(x0, y0); - resize(w, h); + _initWndInfo.r.x = x0; + _initWndInfo.r.y = y0; + _initWndInfo.r.w = w; + _initWndInfo.r.h = h; + _normalRegion = _initWndInfo.r; - dsv_info("reset, screen:%s", scrName.toStdString().c_str()); + 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()); } else { #ifdef _WIN32 if (y != NO_POINT_VALUE){ - move(x, y); + _initWndInfo.r.x = x; + _initWndInfo.r.y = y; } else{ - move(left, top); + _initWndInfo.r.x = left; + _initWndInfo.r.y = top; } #else - move(left, top); -#endif - - if (right - left > 0){ - resize(right - left, bottom - top); - } + _initWndInfo.r.x = left; + _initWndInfo.r.y = top; +#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(); - dsv_info("restore, screen:%s", QGuiApplication::screens().at(scrIndex)->name().toStdString().c_str()); + 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()); } + dsv_info("Normal region, x:%d, y:%d, w:%d, h:%d", + _normalRegion.x, _normalRegion.y, _normalRegion.w, _normalRegion.h); + // restore dockwidgets _mainWindow->restore_dock(); _titleBar->setRestoreButton(app.frameOptions.isMax); @@ -644,7 +992,7 @@ void MainFrame::readSettings() void MainFrame::showEvent(QShowEvent *event) { // Taskbar Progress Effert for Win7 and Above - if (_taskBtn->window() == NULL) { + if (_taskBtn && _taskBtn->window() == NULL) { _taskBtn->setWindow(windowHandle()); _taskPrg = _taskBtn->progress(); } @@ -666,6 +1014,13 @@ void MainFrame::setTaskbarProgress(int progress) #endif } +void MainFrame::ShowHelpDocAsync() +{ + QTimer::singleShot(300, this, [this](){ + show_doc(); + }); +} + void MainFrame::show_doc() { AppConfig &app = AppConfig::Instance(); diff --git a/DSView/pv/mainframe.h b/DSView/pv/mainframe.h index 781ac585..ea31f52f 100644 --- a/DSView/pv/mainframe.h +++ b/DSView/pv/mainframe.h @@ -28,25 +28,45 @@ #include #include #include +#include + #ifdef _WIN32 #include #include #endif +#include "toolbars/titlebar.h" + namespace pv { class MainWindow; - -namespace toolbars { -class TitleBar; -} +class WinNativeWidget; namespace dialogs { class DSMessageBox; class DSDialog; } + +struct Point +{ + int x; + int y; +}; -class MainFrame : public QFrame +struct FormRegion{ + int x; + int y; + int w; + int h; +}; + +struct FormInitInfo +{ + FormRegion r; + bool isMaxSize; +}; + +class MainFrame : public QFrame, public ITitleParent { Q_OBJECT @@ -67,16 +87,20 @@ public: public: MainFrame(); - - void readSettings(); + + void ShowFormInit(); + void ShowHelpDocAsync(); + + void PrintRegionProc(); + void PrintRegion(); protected: void resizeEvent(QResizeEvent *event); void closeEvent(QCloseEvent *event); bool eventFilter(QObject *object, QEvent *event); - #ifdef _WIN32 +#ifdef _WIN32 void showEvent(QShowEvent *event); - #endif +#endif void changeEvent(QEvent *event) override; @@ -88,7 +112,7 @@ public slots: void showNormal(); void showMaximized(); void showMinimized(); - void moveToNormal(); + void moveToWinNaitiveNormal(); private: void hide_border(); @@ -96,6 +120,19 @@ private: void writeSettings(); void saveNormalRegion(); + void ReadSettings(); + void AttachNativeWindow(); + + //ITitleParent + void MoveWindow(int x, int y) override; + QPoint GetParentPos() override; + bool ParentIsMaxsized() override; + void MoveBegin() override; + void MoveEnd() override; + + void SetFormRegion(int x, int y, int w, int h); + QRect GetFormRegion(); + private: toolbars::TitleBar *_titleBar; MainWindow *_mainWindow; @@ -110,8 +147,7 @@ private: widgets::Border *_bottom_left; widgets::Border *_bottom_right; - bool _bDraging; - QRect _dragStartGeometry; + bool _bDraging; int _hit_border; QTimer _timer; bool _freezing; @@ -122,10 +158,15 @@ private: #endif bool _is_native_title; - bool _is_resize_ready; - int _move_event_count; - int _resize_event_count; - bool _is_resize_reset_timer; + bool _is_resize_ready; + + WinNativeWidget *_parentNativeWidget; + FormInitInfo _initWndInfo; + FormRegion _normalRegion; + bool _is_max_status; + QPoint _clickPos; + QRect _dragStartRegion; + QRect _move_screen_region; }; } // namespace pv diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 36b5a33b..c28b5ea8 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -186,6 +186,7 @@ namespace pv _view = new pv::view::View(_session, _sampling_bar, this); _vertical_layout->addWidget(_view); + setIconSize(QSize(40, 40)); addToolBar(_sampling_bar); addToolBar(_trig_bar); @@ -255,6 +256,7 @@ namespace pv _sampling_bar->set_view(_view); + // Add the font form AppControl::Instance()->add_font_form(_protocol_widget); AppControl::Instance()->add_font_form(_dso_trigger_widget); @@ -1425,10 +1427,7 @@ namespace pv qss.open(QFile::ReadOnly | QFile::Text); qApp->setStyleSheet(qss.readAll()); qss.close(); - -#ifdef _WIN32 - setDark_Titlebar(reinterpret_cast(_frame->winId()), style == THEME_STYLE_DARK); -#endif + data_updated(); } @@ -2195,29 +2194,5 @@ namespace pv _view->update_all_trace_postion(); } - -#ifdef _WIN32 - void MainWindow::setDark_Titlebar(HWND hwnd, bool isDarkStyle) - { - HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - HMODULE hUser32 = GetModuleHandleW(L"user32.dll"); - fnAllowDarkModeForWindow AllowDarkModeForWindow - = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133))); - fnSetPreferredAppMode SetPreferredAppMode - = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135))); - fnSetWindowCompositionAttribute SetWindowCompositionAttribute - = reinterpret_cast(GetProcAddress(hUser32, "SetWindowCompositionAttribute")); - - SetPreferredAppMode(AllowDark); - BOOL dark = isDarkStyle; - AllowDarkModeForWindow(hwnd, dark); - WINDOWCOMPOSITIONATTRIBDATA data = { - WCA_USEDARKMODECOLORS, - &dark, - sizeof(dark) - }; - SetWindowCompositionAttribute(hwnd, &data); - } -#endif - + } // namespace pv diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index a7d01e46..15b98572 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -34,61 +34,6 @@ #include #include "dstimer.h" -#ifdef _WIN32 -#include -#include -#pragma comment (lib, "Dwmapi.lib") - -enum PreferredAppMode { - Default, - AllowDark, - ForceDark, - ForceLight, - Max -}; - -enum WINDOWCOMPOSITIONATTRIB { - WCA_UNDEFINED = 0, - WCA_NCRENDERING_ENABLED = 1, - WCA_NCRENDERING_POLICY = 2, - WCA_TRANSITIONS_FORCEDISABLED = 3, - WCA_ALLOW_NCPAINT = 4, - WCA_CAPTION_BUTTON_BOUNDS = 5, - WCA_NONCLIENT_RTL_LAYOUT = 6, - WCA_FORCE_ICONIC_REPRESENTATION = 7, - WCA_EXTENDED_FRAME_BOUNDS = 8, - WCA_HAS_ICONIC_BITMAP = 9, - WCA_THEME_ATTRIBUTES = 10, - WCA_NCRENDERING_EXILED = 11, - WCA_NCADORNMENTINFO = 12, - WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, - WCA_VIDEO_OVERLAY_ACTIVE = 14, - WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, - WCA_DISALLOW_PEEK = 16, - WCA_CLOAK = 17, - WCA_CLOAKED = 18, - WCA_ACCENT_POLICY = 19, - WCA_FREEZE_REPRESENTATION = 20, - WCA_EVER_UNCLOAKED = 21, - WCA_VISUAL_OWNER = 22, - WCA_HOLOGRAPHIC = 23, - WCA_EXCLUDED_FROM_DDA = 24, - WCA_PASSIVEUPDATEMODE = 25, - WCA_USEDARKMODECOLORS = 26, - WCA_LAST = 27 -}; - -struct WINDOWCOMPOSITIONATTRIBDATA { - WINDOWCOMPOSITIONATTRIB Attrib; - PVOID pvData; - SIZE_T cbData; -}; - -using fnAllowDarkModeForWindow = BOOL (WINAPI *)(HWND hWnd, BOOL allow); -using fnSetPreferredAppMode = PreferredAppMode (WINAPI *)(PreferredAppMode appMode); -using fnSetWindowCompositionAttribute = BOOL (WINAPI *)(HWND hwnd, WINDOWCOMPOSITIONATTRIBDATA *); -#endif - class QAction; class QMenuBar; class QMenu; @@ -213,10 +158,7 @@ private: void check_config_file_version(); void load_demo_decoder_config(QString optname); -#ifdef _WIN32 - static void setDark_Titlebar(HWND hwnd, bool isDarkStyle); -#endif - + private: //ISessionCallback void session_error() override; diff --git a/DSView/pv/toolbars/titlebar.cpp b/DSView/pv/toolbars/titlebar.cpp index bbd22258..13b0644b 100644 --- a/DSView/pv/toolbars/titlebar.cpp +++ b/DSView/pv/toolbars/titlebar.cpp @@ -20,7 +20,6 @@ */ #include "titlebar.h" - #include #include #include @@ -31,6 +30,12 @@ #include #include #include +#include + +#ifdef _WIN32 +#include +#endif + #include "../config/appconfig.h" #include "../appcontrol.h" #include "../dsvdef.h" @@ -39,18 +44,21 @@ namespace pv { namespace toolbars { -TitleBar::TitleBar(bool top, QWidget *parent, bool hasClose) : +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); @@ -114,7 +122,7 @@ void TitleBar::reStyle() if (_isTop) { _minimizeButton->setIcon(QIcon(iconPath+"/minimize.svg")); - if (parentWidget()->isMaximized()) + if (ParentIsMaxsized()) _maximizeButton->setIcon(QIcon(iconPath+"/restore.svg")); else _maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg")); @@ -123,6 +131,16 @@ void TitleBar::reStyle() _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 @@ -182,7 +200,7 @@ QString TitleBar::title() void TitleBar::showMaxRestore() { QString iconPath = GetIconPath(); - if (parentWidget()->isMaximized()) { + if (ParentIsMaxsized()) { _maximizeButton->setIcon(QIcon(iconPath+"/maximize.svg")); normalShow(); } else { @@ -203,7 +221,9 @@ void TitleBar::setRestoreButton(bool max) void TitleBar::mousePressEvent(QMouseEvent* event) { - if(event->button() == Qt::LeftButton && !parentWidget()->isMaximized()) + bool ableMove = !ParentIsMaxsized(); + + if(event->button() == Qt::LeftButton && ableMove) { int x = event->pos().x(); int y = event->pos().y(); @@ -212,9 +232,25 @@ void TitleBar::mousePressEvent(QMouseEvent* event) bool bClick = (x >= 6 && y >= 5 && x <= width() - 6); //top window need resize hit check if (!bTopWidow || bClick ){ - _moving = true; + _is_draging = true; + +#ifdef _WIN32 + POINT p; + GetCursorPos(&p); + _clickPos.setX(p.x); + _clickPos.setY(p.y); +#else _clickPos = event->globalPos(); - _oldPos = _parent->pos(); +#endif + if (_titleParent != NULL){ + _oldPos = _titleParent->GetParentPos(); + } + else{ + _oldPos = _parent->pos(); + } + + _is_done_moved = false; + event->accept(); return; } @@ -224,28 +260,74 @@ void TitleBar::mousePressEvent(QMouseEvent* event) void TitleBar::mouseMoveEvent(QMouseEvent *event) { - if(_moving){ - int x = _oldPos.x() + (event->globalPos().x() - _clickPos.x()); - int y = _oldPos.y() + (event->globalPos().y() - _clickPos.y()); - _parent->move(x, y); - event->accept(); - return; + 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) -{ - if (_isTop){ - showMaxRestore(); - } - QWidget::mouseDoubleClickEvent(event); +{ + QWidget::mouseDoubleClickEvent(event); + + if (_isTop){ + + QTimer::singleShot(200, this, [this](){ + showMaxRestore(); + }); + } } void TitleBar::update_font() diff --git a/DSView/pv/toolbars/titlebar.h b/DSView/pv/toolbars/titlebar.h index 8855063c..73bb1b77 100644 --- a/DSView/pv/toolbars/titlebar.h +++ b/DSView/pv/toolbars/titlebar.h @@ -30,6 +30,17 @@ 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 @@ -37,7 +48,7 @@ class TitleBar : public QWidget, public IFontForm Q_OBJECT public: - TitleBar(bool top, QWidget *parent, bool hasClose = false); + TitleBar(bool top, QWidget *parent, ITitleParent *titleParent, bool hasClose); ~TitleBar(); void setTitle(QString title); @@ -54,6 +65,8 @@ private: void changeEvent(QEvent *event); void reStyle(); + bool ParentIsMaxsized(); + signals: void normalShow(); void maximizedShow(); @@ -77,12 +90,15 @@ protected: 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 diff --git a/DSView/pv/winnativewidget.cpp b/DSView/pv/winnativewidget.cpp new file mode 100644 index 00000000..c879d290 --- /dev/null +++ b/DSView/pv/winnativewidget.cpp @@ -0,0 +1,232 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2024 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "winnativewidget.h" +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "../config.h" + +#define NAI_WIN_CREATE_STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN + +namespace pv { + +WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, const int height) +{ + _childWindow = nullptr; + childWidget = nullptr; + _hWnd = NULL; + + HBRUSH windowBackground = CreateSolidBrush(RGB(255, 255, 255)); + HINSTANCE hInstance = GetModuleHandle(nullptr); + WNDCLASSEX wcx = { 0 }; + + wcx.cbSize = sizeof(WNDCLASSEX); + wcx.style = CS_HREDRAW | CS_VREDRAW; + wcx.hInstance = hInstance; + wcx.lpfnWndProc = WndProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.lpszClassName = L"WindowClass"; + wcx.hbrBackground = windowBackground; + wcx.hCursor = LoadCursor(hInstance, IDC_ARROW); + + + RegisterClassEx(&wcx); + if (FAILED(RegisterClassEx(&wcx))) + { + dsv_info("ERROR: can't register window class"); + assert(false); + } + + QString title = QApplication::applicationName() + " v" + QApplication::applicationVersion(); + wchar_t title_string_buffer[50]; + int title_len = title.toWCharArray(title_string_buffer); + title_string_buffer[title_len] = 0; + + _hWnd = CreateWindow(L"WindowClass", title_string_buffer, + NAI_WIN_CREATE_STYLE, x, y, + width, height, 0, 0, hInstance, nullptr); + + if (!_hWnd) + { + dsv_info("ERROR: can't create naitive window"); + assert(false); + } + + SetWindowLongPtr(_hWnd, GWLP_USERDATA, reinterpret_cast(this)); + SetWindowPos(_hWnd, NULL, x, y, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); +} + +WinNativeWidget::~WinNativeWidget() +{ + if (_hWnd){ + Show(false); + DestroyWindow(_hWnd); + } +} + +void WinNativeWidget::SetChildWidget(QWidget *w) +{ + childWidget = w; + _childWindow = NULL; + + if (w != NULL){ + _childWindow = (HWND)w->winId(); + } +} + +LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WinNativeWidget *self = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + + if (self == NULL) + { + return DefWindowProc(hWnd, message, wParam, lParam); + } + + switch (message) + { + case WM_SYSCOMMAND: + { + if (wParam == SC_KEYMENU) + { + RECT winrect; + GetWindowRect(hWnd, &winrect); + TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN, winrect.left + 5, winrect.top + 5, 0, hWnd, NULL); + break; + } + else + { + return DefWindowProc(hWnd, message, wParam, lParam); + } + } + case WM_NCCALCSIZE: + { + return 0; + } + case WM_CLOSE: + { + if (self->childWidget != NULL) + { + self->childWidget->close(); + return 0; + } + break; + } + case WM_DESTROY: + { + // PostQuitMessage(0); + break; + } + case WM_SIZE: + { + if (self->_childWindow != NULL){ + self->ResizeChild(false); + } + + break; + } + } + + return DefWindowProc(hWnd, message, wParam, lParam); +} + +void WinNativeWidget::ResizeChild(bool bManual) +{ + if (_childWindow != NULL){ + + RECT rc; + GetClientRect(_hWnd, &rc); + + int k = QApplication::desktop()->screen()->devicePixelRatio(); + + k = childWidget->window()->devicePixelRatio(); + + int w = rc.right; + int h = rc.bottom; + + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(_hWnd, &wp); + + if (wp.showCmd == SW_MAXIMIZE) { + w -= 8; + h -= 8; + } + + childWidget->adjustSize(); + MoveWindow(_childWindow, 0, 0, w , h , 1 ); + + // dsv_info("resize child, w:%d, h:%d, k1:%d, k2:%d", w / k, h / k, k1, k2); + } +} + +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); + } +} + + void WinNativeWidget::Move(int x, int y) + { + RECT rc; + GetClientRect(_hWnd, &rc); + MoveWindow(_hWnd, x, y, rc.right, rc.bottom, 0); + } + +void WinNativeWidget::ShowNormal() +{ + if (_hWnd){ + SendMessage(_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0); + } +} + +void WinNativeWidget::ShowMax() +{ + if (_hWnd){ + SendMessage(_hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); + } +} + +void WinNativeWidget::ShowMin() +{ + if (_hWnd){ + SendMessage(_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); + } +} + +} diff --git a/DSView/pv/winnativewidget.h b/DSView/pv/winnativewidget.h new file mode 100644 index 00000000..4f1f3404 --- /dev/null +++ b/DSView/pv/winnativewidget.h @@ -0,0 +1,69 @@ + +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2024 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef WINNATIVEWINDOW_H +#define WINNATIVEWINDOW_H + + +#include +#include +#include + +namespace pv { + +class WinNativeWidget +{ +public: + + WinNativeWidget(const int x, const int y, const int width, const int height); + ~WinNativeWidget(); + + static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + + void SetChildWidget(QWidget *w); + + void setGeometry(const int x, const int y, const int width, const int height); + + inline HWND Handle(){ + return _hWnd; + } + + void Show(bool bShow); + void Move(int x, int y); + + void ShowNormal(); + void ShowMax(); + void ShowMin(); + + void ResizeChild(bool bManul); + +private: + QWidget* childWidget; + HWND _childWindow; + HWND _hWnd; +}; + +} + + +#endif // WINNATIVEWINDOW_H