[vlc-commits] [Git][videolan/vlc][master] 7 commits: qt: use negative margin for extending frame

François Cartegnie (@fcartegnie) gitlab at videolan.org
Fri Dec 23 15:14:58 UTC 2022



François Cartegnie pushed to branch master at VideoLAN / VLC


Commits:
57a7bf51 by Prince Gupta at 2022-12-23T14:59:14+00:00
qt: use negative margin for extending frame

- - - - -
99ee50c5 by Prince Gupta at 2022-12-23T14:59:14+00:00
qt: implement CSDButtonModel

- - - - -
68a57d6f by Prince Gupta at 2022-12-23T14:59:14+00:00
qml: refactor CSDButtonSets to use CSDButtonModel

- - - - -
682158f3 by Prince Gupta at 2022-12-23T14:59:14+00:00
qml: add option to show CSD buttons hovered externally

- - - - -
dac28e76 by Prince Gupta at 2022-12-23T14:59:14+00:00
qml: handle CSDButton.showHovered in Window Button set

- - - - -
92588cdc by Prince Gupta at 2022-12-23T14:59:14+00:00
qml: send rect changes for window csd button set

- - - - -
a0e968bb by Prince Gupta at 2022-12-23T14:59:14+00:00
qt: show snap layouts menu on windows 11 with CSD

- - - - -


10 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/maininterface/mainctx.hpp
- modules/gui/qt/maininterface/mainctx_win32.cpp
- modules/gui/qt/maininterface/mainui.cpp
- + modules/gui/qt/util/csdbuttonmodel.cpp
- + modules/gui/qt/util/csdbuttonmodel.hpp
- modules/gui/qt/widgets/qml/CSDThemeButtonSet.qml
- modules/gui/qt/widgets/qml/CSDWindowButton.qml
- modules/gui/qt/widgets/qml/CSDWindowButtonSet.qml


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -277,6 +277,7 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/util/covergenerator.cpp \
 	gui/qt/util/covergenerator.hpp \
 	gui/qt/util/imageluminanceextractor.cpp gui/qt/util/imageluminanceextractor.hpp \
+	gui/qt/util/csdbuttonmodel.cpp gui/qt/util/csdbuttonmodel.hpp \
 	gui/qt/util/imagehelper.cpp gui/qt/util/imagehelper.hpp \
 	gui/qt/util/i18n.cpp gui/qt/util/i18n.hpp \
 	gui/qt/util/keyhelper.cpp gui/qt/util/keyhelper.hpp \
@@ -477,6 +478,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/util/color_scheme_model.moc.cpp \
 	gui/qt/util/color_svg_image_provider.moc.cpp \
 	gui/qt/util/imageluminanceextractor.moc.cpp \
+	gui/qt/util/csdbuttonmodel.moc.cpp \
 	gui/qt/util/i18n.moc.cpp \
 	gui/qt/util/keyhelper.moc.cpp \
 	gui/qt/util/navigation_history.moc.cpp \


=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -31,6 +31,7 @@
 #include "maininterface/mainctx.hpp"
 #include "compositor.hpp"
 #include "util/renderer_manager.hpp"
+#include "util/csdbuttonmodel.hpp"
 
 #include "widgets/native/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
 #include "util/qt_dirs.hpp"                     // toNativeSeparators
@@ -47,6 +48,7 @@
 
 #include "dialogs/toolbar/controlbar_profile_model.hpp"
 
+
 #include <QKeyEvent>
 
 #include <QUrl>
@@ -104,6 +106,7 @@ bool loadVLCOption<bool>(vlc_object_t *obj, const char *name)
 
 MainCtx::MainCtx(qt_intf_t *_p_intf)
     : p_intf(_p_intf)
+    , m_csdButtonModel {std::make_unique<CSDButtonModel>(this, this)}
 {
     /**
      *  Configuration and settings


=====================================
modules/gui/qt/maininterface/mainctx.hpp
=====================================
@@ -42,6 +42,7 @@
 
 #include <atomic>
 
+class CSDButtonModel;
 class QSettings;
 class QCloseEvent;
 class QKeyEvent;
@@ -142,6 +143,7 @@ public:
 
 };
 
+
 class MainCtx : public QObject
 {
     Q_OBJECT
@@ -176,6 +178,8 @@ class MainCtx : public QObject
     Q_PROPERTY(bool useGlobalShortcuts READ getUseGlobalShortcuts WRITE setUseGlobalShortcuts NOTIFY useGlobalShortcutsChanged FINAL)
     Q_PROPERTY(int maxVolume READ maxVolume NOTIFY maxVolumeChanged FINAL)
 
+    Q_PROPERTY(CSDButtonModel *csdButtonModel READ csdButtonModel CONSTANT FINAL)
+
     // This Property only works if hasAcrylicSurface is set
     Q_PROPERTY(bool acrylicActive READ acrylicActive WRITE setAcrylicActive NOTIFY acrylicActiveChanged FINAL)
 
@@ -290,6 +294,8 @@ public:
 
     Q_INVOKABLE static void setAttachedToolTip(QObject* toolTip);
 
+    CSDButtonModel *csdButtonModel() { return m_csdButtonModel.get(); }
+
 protected:
     /* Systray */
     void createSystray();
@@ -360,6 +366,8 @@ protected:
 
     int m_maxVolume = 125;
 
+    std::unique_ptr<CSDButtonModel> m_csdButtonModel;
+
 public slots:
     void toggleUpdateSystrayMenu();
     void showUpdateSystrayMenu();


=====================================
modules/gui/qt/maininterface/mainctx_win32.cpp
=====================================
@@ -32,6 +32,7 @@
 #include "playlist/playlist_controller.hpp"
 #include "dialogs/dialogs_provider.hpp"
 #include "widgets/native/interface_widgets.hpp"
+#include "util/csdbuttonmodel.hpp"
 
 #include <QBitmap>
 
@@ -83,6 +84,13 @@
 #define GET_FLAGS_LPARAM(lParam)      (LOWORD(lParam))
 #define GET_KEYSTATE_LPARAM(lParam)   GET_FLAGS_LPARAM(lParam)
 
+
+// XXX: Cygwin (at least) doesn't define these macros. Too bad...
+#ifndef GET_X_LPARAM
+    #define GET_X_LPARAM(a) ((int16_t)(a))
+    #define GET_Y_LPARAM(a) ((int16_t)((a)>>16))
+#endif
+
 using namespace vlc::playlist;
 
 #ifndef WM_NCUAHDRAWCAPTION
@@ -109,10 +117,11 @@ HWND WinId( QWindow *windowHandle )
 class CSDWin32EventHandler : public QObject, public QAbstractNativeEventFilter
 {
 public:
-    CSDWin32EventHandler(const bool useClientSideDecoration, const bool isWin7Compositor, QWindow *window, QObject *parent)
+    CSDWin32EventHandler(const bool useClientSideDecoration, const bool isWin7Compositor, QWindow *window, CSDButtonModel *buttonmodel, QObject *parent)
         : QObject {parent}
         , m_useClientSideDecoration {useClientSideDecoration}
         , m_window {window}
+        , m_buttonmodel {buttonmodel}
         , m_isWin7Compositor {isWin7Compositor}
     {
         QApplication::instance()->installNativeEventFilter(this);
@@ -194,6 +203,90 @@ public:
              return true;
         }
 
+        // send to determine on what part of UI is mouse ON
+        // handle it to relay if mouse is on the CSD buttons
+        // required for snap layouts menu (WINDOWS 11)
+        if ( msg->message == WM_NCHITTEST )
+        {
+            setAllUnhovered();
+
+            // Get the point in screen coordinates.
+            POINT point = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
+
+            // Map the point to client coordinates.
+            ::MapWindowPoints(nullptr, msg->hwnd, &point, 1);
+
+            const QPoint qtPoint {point.x, point.y};
+            auto button = overlappingButton(qtPoint);
+            if (!button)
+                return false;
+
+            switch (button->type())
+            {
+            case CSDButton::Close:
+                *result = HTCLOSE;
+                return true;
+            case CSDButton::Minimize:
+                *result = HTMINBUTTON;
+                return true;
+            case CSDButton::MaximizeRestore:
+                *result = HTMAXBUTTON;
+                return true;
+            default:
+                vlc_assert_unreachable();
+                return false;
+            }
+        }
+
+        if ( msg->message == WM_NCMOUSEMOVE )
+        {
+
+            // when we handle WM_NCHITTEST, that makes the OS to capture the mouse events
+            // and WM_NCMOUSEMOVE is sent in this case, manually handle them here and relay
+            // to UI to draw correct button state
+            switch ( msg->wParam )
+            {
+            case HTCLOSE:
+                setHovered(CSDButton::Close);
+                break;
+            case HTMINBUTTON:
+                setHovered(CSDButton::Minimize);
+                break;
+            case HTMAXBUTTON:
+                setHovered(CSDButton::MaximizeRestore);
+                break;
+            }
+
+            // If we haven't previously asked for mouse tracking, request mouse
+            // tracking. We need to do this so we can get the WM_NCMOUSELEAVE
+            // message when the mouse leave the titlebar. Otherwise, we won't always
+            // get that message (especially if the user moves the mouse _real
+            // fast_).
+            const bool onSystemButton = (msg->wParam == HTCLOSE || msg->wParam == HTMINBUTTON || msg->wParam == HTMAXBUTTON);
+            if (!m_trackingMouse && onSystemButton)
+            {
+                TRACKMOUSEEVENT ev{};
+                ev.cbSize = sizeof(TRACKMOUSEEVENT);
+                // TME_NONCLIENT is absolutely critical here. In my experimentation,
+                // we'd get WM_MOUSELEAVE messages after just a HOVER_DEFAULT
+                // timeout even though we're not requesting TME_HOVER, which kinda
+                // ruined the whole point of this.
+                ev.dwFlags = TME_LEAVE | TME_NONCLIENT;
+                ev.hwndTrack = msg->hwnd;
+                ev.dwHoverTime = HOVER_DEFAULT; // we don't _really_ care about this.
+                TrackMouseEvent(&ev); // TODO check return?
+                m_trackingMouse = true;
+            }
+        }
+
+        if ( msg->message == WM_NCMOUSELEAVE || msg->message == WM_MOUSELEAVE )
+        {
+            m_trackingMouse = false;
+
+            // release all buttons we may have captured
+            setAllUnhovered();
+        }
+
         return false;
     }
 
@@ -228,7 +321,9 @@ private:
         }
 
         // add back shadows
-        const MARGINS m {0, 0, (m_useClientSideDecoration ? 1 : 0) /* top margin */ , 0};
+        // with positive margins, snap layouts menu (windows 11) won't appear
+        const int margin = (m_useClientSideDecoration ? - 1 : 0);
+        const MARGINS m {margin, margin, margin, margin};
         DwmExtendFrameIntoClientArea(winId, &m);
 
         SetWindowPos(winId, NULL, 0, 0, 0, 0,
@@ -237,9 +332,41 @@ private:
             SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER);
     }
 
+    CSDButton *overlappingButton(const QPoint point)
+    {
+        for (auto button : m_buttonmodel->windowCSDButtons())
+        {
+            if (button->rect().contains(point))
+                return button;
+        }
+        return nullptr;
+    }
+
+    void setHovered(CSDButton::ButtonType type)
+    {
+        for (auto button : m_buttonmodel->windowCSDButtons()) {
+            if (button->type() == type) {
+                button->setShowHovered(true);
+                return ;
+            }
+        }
+
+        vlc_assert_unreachable();
+    }
+
+    void setAllUnhovered()
+    {
+        for (auto button : m_buttonmodel->windowCSDButtons())
+        {
+            button->setShowHovered(false);
+        }
+    }
+
     DWORD m_nonCSDGwlStyle = 0;
     bool m_useClientSideDecoration;
     QWindow *m_window;
+    CSDButtonModel *m_buttonmodel;
+    bool m_trackingMouse = false;
     const bool m_isWin7Compositor;
 };
 
@@ -511,7 +638,7 @@ InterfaceWindowHandlerWin32::InterfaceWindowHandlerWin32(qt_intf_t *_p_intf, Mai
 #if QT_CLIENT_SIDE_DECORATION_AVAILABLE
     , m_CSDWindowEventHandler(new CSDWin32EventHandler(mainCtx->useClientSideDecoration(),
                                                        _p_intf->p_compositor->type() == vlc::Compositor::Win7Compositor,
-                                                       window, window))
+                                                       window, mainCtx->csdButtonModel(), window))
 #endif
 
 {


=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -44,6 +44,7 @@
 #include "util/flickable_scroll_handler.hpp"
 #include "util/color_svg_image_provider.hpp"
 #include "util/effects_image_provider.hpp"
+#include "util/csdbuttonmodel.hpp"
 
 #include "dialogs/help/aboutmodel.hpp"
 #include "dialogs/dialogs_provider.hpp"
@@ -225,6 +226,7 @@ void MainUI::registerQMLTypes()
         const int versionMinor = 1;
 
         qmlRegisterSingletonType<MainCtx>(uri, versionMajor, versionMinor, "MainCtx", SingletonRegisterHelper<MainCtx>::callback);
+
         qmlRegisterSingletonType<NavigationHistory>(uri, versionMajor, versionMinor, "History", SingletonRegisterHelper<NavigationHistory>::callback);
         qmlRegisterSingletonType<PlayerController>(uri, versionMajor, versionMinor, "Player", SingletonRegisterHelper<PlayerController>::callback);
         qmlRegisterSingletonType<I18n>(uri, versionMajor, versionMinor, "I18n", SingletonRegisterHelper<I18n>::callback);
@@ -265,6 +267,9 @@ void MainUI::registerQMLTypes()
         qmlRegisterUncreatableType<ProgramListModel>(uri, versionMajor, versionMinor, "ProgramListModel", "available programs of a media" );
         qmlRegisterUncreatableType<VLCVarChoiceModel>(uri, versionMajor, versionMinor, "VLCVarChoiceModel", "generic variable with choice model" );
 
+        qmlRegisterUncreatableType<CSDButton>(uri, versionMajor, versionMinor, "CSDButton", "");
+        qmlRegisterUncreatableType<CSDButtonModel>(uri, versionMajor, versionMinor, "CSDButtonModel", "has CSD buttons and provides for communicating CSD events between UI and backend");
+
         qRegisterMetaType<PlaylistPtr>();
         qRegisterMetaType<PlaylistItem>();
         qmlRegisterUncreatableType<PlaylistItem>(uri, versionMajor, versionMinor, "PlaylistItem", "");


=====================================
modules/gui/qt/util/csdbuttonmodel.cpp
=====================================
@@ -0,0 +1,108 @@
+/*****************************************************************************
+ * Copyright (C) 2022 the VideoLAN team
+ *
+ * Authors: Prince Gupta <guptaprince8832 at gmail.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 Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#include "csdbuttonmodel.hpp"
+
+#include "maininterface/mainctx.hpp"
+
+#include <QWindow>
+
+CSDButton::CSDButton(ButtonType type, QObject *parent)
+    : QObject {parent}
+    , m_type {type}
+{
+}
+
+bool CSDButton::showHovered() const
+{
+    return m_showHovered;
+}
+
+void CSDButton::setShowHovered(bool newShowHovered)
+{
+    if (m_showHovered == newShowHovered)
+        return;
+    m_showHovered = newShowHovered;
+    emit showHoveredChanged();
+}
+
+CSDButton::ButtonType CSDButton::type() const
+{
+    return m_type;
+}
+
+const QRect &CSDButton::rect() const
+{
+    return m_rect;
+}
+
+void CSDButton::setRect(const QRect &newRect)
+{
+    if (m_rect == newRect)
+        return;
+    m_rect = newRect;
+    emit rectChanged();
+}
+
+void CSDButton::click()
+{
+    emit clicked();
+}
+
+CSDButtonModel::CSDButtonModel(MainCtx *mainCtx, QObject *parent)
+    : QObject {parent}
+    , m_mainCtx {mainCtx}
+{
+    auto newButton = [this](CSDButton::ButtonType type, void (CSDButtonModel::* onClick)())
+    {
+        auto button = new CSDButton(type, this);
+        connect(button, &CSDButton::clicked, this, onClick);
+        m_windowCSDButtons.append(button);
+    };
+
+    newButton(CSDButton::Minimize, &CSDButtonModel::minimizeButtonClicked);
+    newButton(CSDButton::MaximizeRestore, &CSDButtonModel::maximizeRestoreButtonClicked);
+    newButton(CSDButton::Close, &CSDButtonModel::closeButtonClicked);
+}
+
+QList<CSDButton *> CSDButtonModel::windowCSDButtons() const
+{
+    return m_windowCSDButtons;
+}
+
+void CSDButtonModel::minimizeButtonClicked()
+{
+    emit m_mainCtx->requestInterfaceMinimized();
+}
+
+void CSDButtonModel::maximizeRestoreButtonClicked()
+{
+    const auto visibility = m_mainCtx->intfMainWindow()->visibility();
+    if (visibility == QWindow::Maximized)
+        emit m_mainCtx->requestInterfaceNormal();
+    else
+        emit m_mainCtx->requestInterfaceMaximized();
+}
+
+void CSDButtonModel::closeButtonClicked()
+{
+    m_mainCtx->intfMainWindow()->close();
+}


=====================================
modules/gui/qt/util/csdbuttonmodel.hpp
=====================================
@@ -0,0 +1,103 @@
+/*****************************************************************************
+ * Copyright (C) 2022 the VideoLAN team
+ *
+ * Authors: Prince Gupta <guptaprince8832 at gmail.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 Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef CSDBUTTONCONTROLLER_HPP
+#define CSDBUTTONCONTROLLER_HPP
+
+#include <QObject>
+#include <QRect>
+
+class CSDButton : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(ButtonType type READ type CONSTANT)
+    Q_PROPERTY(bool showHovered READ showHovered WRITE setShowHovered NOTIFY showHoveredChanged)
+    Q_PROPERTY(QRect rect READ rect WRITE setRect NOTIFY rectChanged)
+
+public:
+    enum ButtonType
+    {
+        Minimize,
+        MaximizeRestore,
+        Close,
+
+        TypeCount
+    };
+
+    Q_ENUM(ButtonType);
+
+    CSDButton(ButtonType type, QObject *parent);
+
+    ButtonType type() const;
+
+    // 'showHovered' is hint for UI to the show this
+    // button as in 'hovered' state
+    // used by implmentation incase custom event handling is required for CSD
+    bool showHovered() const;
+    void setShowHovered(bool newShowHovered);
+
+    // 'rect' is location of the button in the UI
+    // may be used by implementation to relay the information
+    // to OS such as to show snaplay out menu on Windows 11
+    const QRect &rect() const;
+    void setRect(const QRect &newRect);
+
+public slots:
+    // signals to perfrom action associated with button
+    void click();
+
+signals:
+    void showHoveredChanged();
+    void rectChanged();
+    void clicked();
+
+private:
+    const ButtonType m_type;
+    bool m_showHovered = false;
+    QRect m_rect;
+};
+
+
+class MainCtx;
+
+class CSDButtonModel : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QList<CSDButton *> windowCSDButtons READ windowCSDButtons CONSTANT)
+
+public:
+    CSDButtonModel(MainCtx *mainCtx, QObject *parent = nullptr);
+
+    QList<CSDButton *> windowCSDButtons() const;
+
+private slots:
+    void minimizeButtonClicked();
+    void maximizeRestoreButtonClicked();
+    void closeButtonClicked();
+
+private:
+    MainCtx *m_mainCtx;
+    QList<CSDButton *> m_windowCSDButtons;
+};
+
+
+Q_DECLARE_METATYPE(CSDButton *)
+
+#endif // CSDBUTTONCONTROLLER_HPP


=====================================
modules/gui/qt/widgets/qml/CSDThemeButtonSet.qml
=====================================
@@ -46,47 +46,34 @@ Rectangle {
 
         spacing: root._interNavButtonSpacing
 
-        CSDThemeButton {
-            id: minimizeButton
+        Repeater {
+            model: MainCtx.csdButtonModel.windowCSDButtons
 
-            anchors.verticalCenter: parent.verticalCenter
+            CSDThemeButton {
 
-            bannerHeight: root.height
+                anchors.verticalCenter: parent.verticalCenter
 
-            buttonType: CSDThemeImage.MINIMIZE
+                bannerHeight: root.height
 
-            onClicked: MainCtx.requestInterfaceMinimized()
-        }
-
-        CSDThemeButton {
-            id: maximizeButton
-
-            anchors.verticalCenter: parent.verticalCenter
+                buttonType: {
+                    switch (modelData.type) {
+                    case CSDButton.Minimize:
+                        return CSDThemeImage.MINIMIZE
 
-            bannerHeight: root.height
+                    case CSDButton.MaximizeRestore:
+                        return (MainCtx.intfMainWindow.visibility === Window.Maximized)
+                                ? CSDThemeImage.RESTORE
+                                : CSDThemeImage.MAXIMIZE
 
-            buttonType: (MainCtx.intfMainWindow.visibility === Window.Maximized)  ? CSDThemeImage.RESTORE : CSDThemeImage.MAXIMIZE
+                    case CSDButton.Close:
+                        return CSDThemeButton.CLOSE
+                    }
 
-            onClicked: {
-                if (MainCtx.intfMainWindow.visibility === Window.Maximized) {
-                    MainCtx.requestInterfaceNormal()
-                } else {
-                    MainCtx.requestInterfaceMaximized()
+                    console.assert(false, "unreachable")
                 }
-            }
-        }
-
-        CSDThemeButton {
-            id: closeButton
 
-            anchors.verticalCenter: parent.verticalCenter
-
-            bannerHeight: root.height
-
-            buttonType: CSDThemeImage.CLOSE
-
-            onClicked: MainCtx.intfMainWindow.close()
+                onClicked: modelData.click()
+            }
         }
     }
-
 }


=====================================
modules/gui/qt/widgets/qml/CSDWindowButton.qml
=====================================
@@ -29,6 +29,9 @@ T.Button {
     property color color: VLCStyle.colors.text
     property color hoverColor: VLCStyle.colors.windowCSDButtonBg
     property string iconTxt: ""
+    property bool showHovered: false
+
+    readonly property bool _paintHovered: control.hovered || showHovered
 
     padding: 0
     width: VLCStyle.dp(40, VLCStyle.scale)
@@ -39,11 +42,16 @@ T.Button {
     background: Rectangle {
         height: control.height
         width: control.width
-        color: !control.hovered ? "transparent"
-               : control.pressed ? (VLCStyle.colors.isThemeDark ? Qt.lighter(control.hoverColor, 1.2)
-                                      : Qt.darker(control.hoverColor, 1.2)
-                                    )
-               : control.hoverColor
+        color: {
+            if (control._paintHovered)
+                return control.hoverColor
+
+            if (control.pressed)
+                return VLCStyle.colors.isThemeDark ? Qt.lighter(control.hoverColor, 1.2)
+                                                   : Qt.darker(control.hoverColor, 1.2)
+
+            return "transparent"
+        }
     }
 
     contentItem: Item {


=====================================
modules/gui/qt/widgets/qml/CSDWindowButtonSet.qml
=====================================
@@ -33,38 +33,69 @@ Row {
     property color color: VLCStyle.colors.text
     property color hoverColor: VLCStyle.colors.windowCSDButtonBg
 
-    property bool hovered: minimizeButton.hovered || maximizeButton.hovered || closeButton.hovered
-
-    CSDWindowButton {
-        id: minimizeButton
-        iconTxt: VLCIcons.window_minimize
-        onClicked: MainCtx.requestInterfaceMinimized()
-        height: windowButtonGroup.height
-        color: windowButtonGroup.color
-        hoverColor: windowButtonGroup.hoverColor
+    readonly property bool hovered: {
+        var h = false
+        for (var i = 0; i < repeater.count; ++i) {
+            var button = repeater.itemAt(i)
+            h = h || button.hovered || button.showHovered
+        }
+
+        return h
     }
 
-    CSDWindowButton {
-        id: maximizeButton
-        iconTxt: (MainCtx.intfMainWindow.visibility === Window.Maximized)  ? VLCIcons.window_restore :VLCIcons.window_maximize
-        onClicked: {
-            if (MainCtx.intfMainWindow.visibility === Window.Maximized) {
-                MainCtx.requestInterfaceNormal()
-            } else {
-                MainCtx.requestInterfaceMaximized()
+    Repeater {
+        id: repeater
+
+        model: MainCtx.csdButtonModel.windowCSDButtons
+
+        CSDWindowButton {
+            height: windowButtonGroup.height
+
+            showHovered: modelData.showHovered
+
+            color: (modelData.type === CSDButton.Close && (hovered || modelData.showHovered))
+                   ? "white"
+                   : windowButtonGroup.color
+
+            hoverColor: (modelData.type === CSDButton.Close) ? "red" : windowButtonGroup.hoverColor
+
+            iconTxt: {
+                switch (modelData.type) {
+                case CSDButton.Minimize:
+                    return VLCIcons.window_minimize
+
+                case CSDButton.MaximizeRestore:
+                    return (MainCtx.intfMainWindow.visibility === Window.Maximized)
+                            ? VLCIcons.window_restore
+                            : VLCIcons.window_maximize
+
+                case CSDButton.Close:
+                    return VLCIcons.window_close
+                }
+
+                console.assert(false, "unreachable")
             }
-        }
-        height: windowButtonGroup.height
-        color: windowButtonGroup.color
-        hoverColor: windowButtonGroup.hoverColor
-    }
 
-    CSDWindowButton {
-        id: closeButton
-        iconTxt: VLCIcons.window_close
-        onClicked: MainCtx.intfMainWindow.close()
-        height: windowButtonGroup.height
-        color: closeButton.hovered ? "white" : windowButtonGroup.color
-        hoverColor: "red"
+            onClicked: modelData.click()
+
+            // handles VLCStyle.scale changes
+            onWidthChanged: Qt.callLater(updateRect)
+            onHeightChanged: Qt.callLater(updateRect)
+
+            Connections {
+                target: VLCStyle.self
+
+                // handle window resize
+                onAppWidthChanged: Qt.callLater(updateRect)
+                onAppHeightChanged: Qt.callLater(updateRect)
+            }
+
+            function updateRect() {
+                var point = mapToItem(null, 0, 0)
+                var rect = Qt.rect(point.x, point.y, width, height)
+
+                modelData.rect = rect
+            }
+        }
     }
 }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/16e913456ee1075b2b819d7951892b1e3f3f980b...a0e968bb8918df985ed45ddfde84c58c1bd68a33

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/16e913456ee1075b2b819d7951892b1e3f3f980b...a0e968bb8918df985ed45ddfde84c58c1bd68a33
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list