diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d0693a..2a938ca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). + + +## [1.11.0 / 5.66.0] - 2023-08-?? + +### Changed +- Don't close submenus on mouse-leave [#2963](https://github.com/sandboxie-plus/Sandboxie/issues/2963) + + + + + + ## [1.10.4 / 5.65.4] - 2023-08-11 ### Fixed diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 40be46f8..3248035d 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -21,8 +21,8 @@ #ifndef _MY_VERSION_H #define _MY_VERSION_H -#define MY_VERSION_BINARY 5,65,4 -#define MY_VERSION_STRING "5.65.4" +#define MY_VERSION_BINARY 5,66,0 +#define MY_VERSION_STRING "5.66.0" #define MY_ABI_VERSION 0x56500 // These #defines are used by either Resource Compiler or NSIS installer diff --git a/SandboxiePlus/SandMan/CustomStyles.h b/SandboxiePlus/SandMan/CustomStyles.h new file mode 100644 index 00000000..35960752 --- /dev/null +++ b/SandboxiePlus/SandMan/CustomStyles.h @@ -0,0 +1,167 @@ +#pragma once +#include +#include "SandMan.h" + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Implements properly oriented side tabs +// + +class CustomTabStyle : public QProxyStyle { +public: + CustomTabStyle(QStyle* style = 0) : QProxyStyle(style) {} + + QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const { + QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); + if (type == QStyle::CT_TabBarTab) { + const QTabWidget* pTabWidget = qobject_cast(widget->parentWidget()); + if (pTabWidget && pTabWidget->tabPosition() == QTabWidget::West) { + s.transpose(); + QString baseName = baseStyle()->metaObject()->className(); + if (baseName == "QFusionStyle") + s.setHeight(s.height() * 125 / 100); + else + s.setHeight(s.height() * 15 / 10); + s.setWidth(s.width() * 11 / 10); // for the the icon + } + } + return s; + } + + void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { + if (element == CE_TabBarTabLabel) { + const QTabWidget* pTabWidget = qobject_cast(widget->parentWidget()); + if (pTabWidget && pTabWidget->tabPosition() == QTabWidget::West) { + if (const QStyleOptionTab* tab = qstyleoption_cast(option)) { + QStyleOptionTab opt(*tab); + opt.shape = QTabBar::RoundedNorth; + //opt.iconSize = QSize(32, 32); + opt.iconSize = QSize(24, 24); + QProxyStyle::drawControl(element, &opt, painter, widget); + return; + } + } + } + QProxyStyle::drawControl(element, option, painter, widget); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Keeps submenus visible when the mosue leaves +// + +class KeepSubMenusVisibleStyle : public QProxyStyle { +public: + KeepSubMenusVisibleStyle(QStyle* style = 0) : QProxyStyle(style) {} + + int styleHint(StyleHint styleHint, const QStyleOption* opt = nullptr, + const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override + { + if (styleHint == SH_Menu_SubMenuDontStartSloppyOnLeave) + return 1; + return QProxyStyle::styleHint(styleHint, opt, widget, returnData); + } +}; + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Implements nice flat buttons +// + +class MyButtonStyle : public QProxyStyle +{ +public: + MyButtonStyle(QStyle* pStyle) : QProxyStyle(pStyle) {} + + virtual QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const + { + QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); + if (type == CE_PushButton && widget->property("leftButton").toBool()) + { + if (const QStyleOptionButton* button = qstyleoption_cast(option)) + { + if (!button->icon.isNull()) { + s.setWidth(s.width() + 20 + button->iconSize.width()); + } + } + } + return s; + } + + virtual void drawControl(ControlElement element, const QStyleOption* opt, QPainter* p, const QWidget* widget) const + { + if (element == CE_PushButtonLabel && widget->property("leftButton").toBool()) + { + if (const QStyleOptionButton* button = qstyleoption_cast(opt)) + { + QRect textRect = button->rect; + uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic; + if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget)) + tf |= Qt::TextHideMnemonic; + + if (!button->icon.isNull()) { + QRect iconRect; + QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + if (mode == QIcon::Normal && button->state & State_HasFocus) + mode = QIcon::Active; + QIcon::State state = QIcon::Off; + if (button->state & State_On) + state = QIcon::On; + + QPixmap pixmap = button->icon.pixmap(widget ? widget->window()->windowHandle() : 0, button->iconSize, mode, state); + + int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); + int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); + int labelWidth = pixmapWidth; + int labelHeight = pixmapHeight; + int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint() + int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); + if (!button->text.isEmpty()) + labelWidth += (textWidth + iconSpacing); + + textRect.setLeft(textRect.left() + 20 + button->iconSize.width()); + + /*************************************************************/ + // Make the icon rectangle always be 10px in from the left edge + /*************************************************************/ + iconRect = QRect(10, + textRect.y() + (textRect.height() - labelHeight) / 2, + pixmapWidth, pixmapHeight); + + iconRect = visualRect(button->direction, textRect, iconRect); + + /***********************************/ + // Always horizontal align the text + /***********************************/ + tf |= Qt::AlignLeft; + + + if (button->state & (State_On | State_Sunken)) + iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); + p->drawPixmap(iconRect, pixmap); + } + else { + tf |= Qt::AlignHCenter; + } + if (button->state & (State_On | State_Sunken)) + textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); + + if (button->features & QStyleOptionButton::HasMenu) { + int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget); + if (button->direction == Qt::LeftToRight) + textRect = textRect.adjusted(0, 0, -indicatorSize, 0); + else + textRect = textRect.adjusted(indicatorSize, 0, 0, 0); + } + proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled), + button->text, QPalette::ButtonText); + } + return; + } + + + // For all other controls, draw the default + QProxyStyle::drawControl(element, opt, p, widget); + } +}; \ No newline at end of file diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index 759bb446..b2a5a5c0 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -41,6 +41,7 @@ #include "Engine/ScriptManager.h" #include "AddonManager.h" #include "Windows/PopUpWindow.h" +#include "CustomStyles.h" CSbiePlusAPI* theAPI = NULL; @@ -126,7 +127,6 @@ CSandMan::CSandMan(QWidget *parent) theGUI = this; m_DarkTheme = false; - m_FusionTheme = false; QDesktopServices::setUrlHandler("http", this, "OpenUrl"); QDesktopServices::setUrlHandler("https", this, "OpenUrl"); @@ -3623,7 +3623,7 @@ void CSandMan::SetUITheme() int iViewMode = theConf->GetInt("Options/ViewMode", 1); QApplication::setStyle(QStyleFactory::create((bDark || iViewMode == 2) ? "Windows" : m_DefaultStyle)); } - m_FusionTheme = bFusion; + QApplication::setStyle(new KeepSubMenusVisibleStyle(new CustomTabStyle(QApplication::style()))); CTreeItemModel::SetDarkMode(bDark); diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h index 2e31c7a3..fcd87b94 100644 --- a/SandboxiePlus/SandMan/SandMan.h +++ b/SandboxiePlus/SandMan/SandMan.h @@ -477,7 +477,6 @@ public: QString m_Language; quint32 m_LanguageId; bool m_DarkTheme; - bool m_FusionTheme; }; diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index 9cc74b17..6872f03b 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -44,6 +44,7 @@ HEADERS += ./stdafx.h \ ./Engine/V4ScriptDebuggerApi.h \ ./Engine/JSEngineExt.h \ ./Engine/WizardObject.h \ + ./CustomStyles.h \ ./AddonManager.h SOURCES += ./main.cpp \ diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp index 0d6d6094..a98ff8af 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp @@ -181,9 +181,6 @@ COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QStri this->setWindowTitle(tr("Sandboxie Plus - '%1' Options").arg(QString(Name).replace("_", " "))); ui.tabs->setTabPosition(QTabWidget::West); - ui.tabs->tabBar()->setStyle(new CustomTabStyle(ui.tabs->tabBar()->style())); - ui.tabs->tabBar()->setProperty("isSidebar", true); - ui.tabs->setCurrentIndex(0); ui.tabs->setTabIcon(0, CSandMan::GetIcon("Config")); diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index 4559577e..d6a4e650 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -21,33 +21,6 @@ #include #include -QSize CustomTabStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const { - QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); - if (type == QStyle::CT_TabBarTab && widget->property("isSidebar").toBool()) { - s.transpose(); - if(theGUI->m_FusionTheme) - s.setHeight(s.height() * 13 / 10); - else - s.setHeight(s.height() * 15 / 10); - s.setWidth(s.width() * 11 / 10); // for the the icon - } - return s; -} - -void CustomTabStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { - if (element == CE_TabBarTabLabel && widget->property("isSidebar").toBool()) { - if (const QStyleOptionTab* tab = qstyleoption_cast(option)) { - QStyleOptionTab opt(*tab); - opt.shape = QTabBar::RoundedNorth; - //opt.iconSize = QSize(32, 32); - opt.iconSize = QSize(24, 24); - QProxyStyle::drawControl(element, &opt, painter, widget); - return; - } - } - QProxyStyle::drawControl(element, option, painter, widget); -} - void FixTriStateBoxPallete(QWidget* pWidget) { @@ -143,8 +116,6 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) FixTriStateBoxPallete(this); ui.tabs->setTabPosition(QTabWidget::West); - ui.tabs->tabBar()->setStyle(new CustomTabStyle(ui.tabs->tabBar()->style())); - ui.tabs->tabBar()->setProperty("isSidebar", true); ui.tabs->setCurrentIndex(0); ui.tabs->setTabIcon(0, CSandMan::GetIcon("Config")); diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.h b/SandboxiePlus/SandMan/Windows/SettingsWindow.h index 9c3a6274..98399df4 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.h +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.h @@ -2,17 +2,8 @@ #include #include "ui_SettingsWindow.h" -#include #include "../../MiscHelpers/Common/SettingsWidgets.h" -class CustomTabStyle : public QProxyStyle { -public: - CustomTabStyle(QStyle* style = 0) : QProxyStyle(style) {} - - QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const; - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const; -}; - void FixTriStateBoxPallete(QWidget* pWidget); class CSecretCheckBox : public QCheckBox diff --git a/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp b/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp index 60e1b75a..b66cdd65 100644 --- a/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp +++ b/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp @@ -21,6 +21,7 @@ #include "../Views/TraceView.h" #include "../AddonManager.h" +#include "../CustomStyles.h" CBoxAssistant::CBoxAssistant(QWidget *parent) : QWizard(parent) diff --git a/SandboxiePlus/SandMan/Wizards/BoxAssistant.h b/SandboxiePlus/SandMan/Wizards/BoxAssistant.h index b6f8227d..5d17c849 100644 --- a/SandboxiePlus/SandMan/Wizards/BoxAssistant.h +++ b/SandboxiePlus/SandMan/Wizards/BoxAssistant.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include "SbiePlusAPI.h" QT_BEGIN_NAMESPACE @@ -15,105 +14,6 @@ QT_END_NAMESPACE class CWizardEngine; -class MyButtonStyle : public QProxyStyle -{ -public: - MyButtonStyle(QStyle* pStyle) : QProxyStyle(pStyle) {} - - virtual QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const - { - QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); - if (type == CE_PushButton && widget->property("leftButton").toBool()) - { - if (const QStyleOptionButton* button = qstyleoption_cast(option)) - { - if (!button->icon.isNull()) { - s.setWidth(s.width() + 20 + button->iconSize.width()); - } - } - } - return s; - } - - virtual void drawControl(ControlElement element, const QStyleOption* opt, QPainter* p, const QWidget* widget) const - { - if (element == CE_PushButtonLabel && widget->property("leftButton").toBool()) - { - if (const QStyleOptionButton* button = qstyleoption_cast(opt)) - { - QRect textRect = button->rect; - uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic; - if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget)) - tf |= Qt::TextHideMnemonic; - - if (!button->icon.isNull()) { - QRect iconRect; - QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; - if (mode == QIcon::Normal && button->state & State_HasFocus) - mode = QIcon::Active; - QIcon::State state = QIcon::Off; - if (button->state & State_On) - state = QIcon::On; - - QPixmap pixmap = button->icon.pixmap(widget ? widget->window()->windowHandle() : 0, button->iconSize, mode, state); - - int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); - int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); - int labelWidth = pixmapWidth; - int labelHeight = pixmapHeight; - int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint() - int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); - if (!button->text.isEmpty()) - labelWidth += (textWidth + iconSpacing); - - textRect.setLeft(textRect.left() + 20 + button->iconSize.width()); - - /*************************************************************/ - // Make the icon rectangle always be 10px in from the left edge - /*************************************************************/ - iconRect = QRect(10, - textRect.y() + (textRect.height() - labelHeight) / 2, - pixmapWidth, pixmapHeight); - - iconRect = visualRect(button->direction, textRect, iconRect); - - /***********************************/ - // Always horizontal align the text - /***********************************/ - tf |= Qt::AlignLeft; - - - if (button->state & (State_On | State_Sunken)) - iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), - proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); - p->drawPixmap(iconRect, pixmap); - } - else { - tf |= Qt::AlignHCenter; - } - if (button->state & (State_On | State_Sunken)) - textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), - proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); - - if (button->features & QStyleOptionButton::HasMenu) { - int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget); - if (button->direction == Qt::LeftToRight) - textRect = textRect.adjusted(0, 0, -indicatorSize, 0); - else - textRect = textRect.adjusted(indicatorSize, 0, 0, 0); - } - proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled), - button->text, QPalette::ButtonText); - } - return; - } - - - // For all other controls, draw the default - QProxyStyle::drawControl(element, opt, p, widget); - } -}; - class CBoxAssistant : public QWizard { diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 127a3d09..849c283b 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -1,8 +1,8 @@ #pragma once #define VERSION_MJR 1 -#define VERSION_MIN 10 -#define VERSION_REV 4 +#define VERSION_MIN 11 +#define VERSION_REV 0 #define VERSION_UPD 0 #ifndef STR