VirtualBox

Changeset 52053 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Jul 16, 2014 2:41:46 PM (10 years ago)
Author:
vboxsync
Message:

FE/Qt: 3646: Status-bar Editor: Initial implementation, enabled on Win host only for now.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r51992 r52053  
    482482        src/runtime/UIMachine.cpp \
    483483        src/runtime/UIMachineMenuBar.cpp \
     484        src/runtime/normal/UIMachineWindowNormal.cpp \
    484485        src/selector/UIActionPoolSelector.cpp \
    485486        src/selector/UIVMDesktop.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp

    r52014 r52053  
    2424#include <QContextMenuEvent>
    2525#include <QResizeEvent>
     26
     27#include <QStylePainter>
     28#include <QStyleOption>
     29#include <QPaintEvent>
     30#include <QPainter>
     31#include <QDrag>
    2632
    2733/* GUI includes: */
     
    4349#endif /* Q_WS_MAC */
    4450
     51#include "QIWithRetranslateUI.h"
     52#include "QIToolButton.h"
     53#include "UIIconPool.h"
     54#include "UIConverter.h"
     55#include "UIAnimationFramework.h"
     56
    4557/* COM includes: */
    4658#include "CConsole.h"
     
    4860#include "CUSBController.h"
    4961#include "CUSBDeviceFilters.h"
     62
     63
     64/** QWidget extension
     65  * used as status-bar editor button. */
     66class UIStatusBarEditorButton : public QIWithRetranslateUI<QWidget>
     67{
     68    Q_OBJECT;
     69
     70signals:
     71
     72    /** Notifies about click. */
     73    void sigClick();
     74
     75    /** Notifies about drag-object destruction. */
     76    void sigDragObjectDestroy();
     77
     78public:
     79
     80    /** Holds the mime-type for the D&D system. */
     81    static const QString MimeType;
     82
     83    /** Constructor for the button of passed @a type. */
     84    UIStatusBarEditorButton(IndicatorType type);
     85
     86    /** Returns button type. */
     87    IndicatorType type() const { return m_type; }
     88
     89    /** Returns button size-hint. */
     90    QSize sizeHint() const { return m_size; }
     91
     92    /** Defines whether button is @a fChecked. */
     93    void setChecked(bool fChecked);
     94
     95private:
     96
     97    /** Retranslation routine. */
     98    virtual void retranslateUi();
     99
     100    /** Paint-event handler. */
     101    virtual void paintEvent(QPaintEvent *pEvent);
     102
     103    /** Mouse-press event handler. */
     104    virtual void mousePressEvent(QMouseEvent *pEvent);
     105    /** Mouse-release event handler. */
     106    virtual void mouseReleaseEvent(QMouseEvent *pEvent);
     107    /** Mouse-enter event handler. */
     108    virtual void enterEvent(QEvent *pEvent);
     109    /** Mouse-leave event handler. */
     110    virtual void leaveEvent(QEvent *pEvent);
     111    /** Mouse-move event handler. */
     112    virtual void mouseMoveEvent(QMouseEvent *pEvent);
     113
     114    /** Holds the button type. */
     115    IndicatorType m_type;
     116    /** Holds the button size. */
     117    QSize m_size;
     118    /** Holds the button pixmap. */
     119    QPixmap m_pixmap;
     120    /** Holds whether button is checked. */
     121    bool m_fChecked;
     122    /** Holds whether button is hovered. */
     123    bool m_fHovered;
     124    /** Holds the last mouse-press position. */
     125    QPoint m_mousePressPosition;
     126};
     127
     128/* static */
     129const QString UIStatusBarEditorButton::MimeType = QString("application/virtualbox;value=IndicatorType");
     130
     131UIStatusBarEditorButton::UIStatusBarEditorButton(IndicatorType type)
     132    : m_type(type)
     133    , m_fChecked(false)
     134    , m_fHovered(false)
     135{
     136    /* Track mouse events: */
     137    setMouseTracking(true);
     138
     139    /* Prepare icon for assigned type: */
     140    const QIcon icon = gpConverter->toIcon(m_type);
     141    /* Cache button size-hint: */
     142    m_size = icon.availableSizes().first();
     143    /* Cache pixmap of same size: */
     144    m_pixmap = icon.pixmap(m_size);
     145
     146    /* Translate finally: */
     147    retranslateUi();
     148}
     149
     150void UIStatusBarEditorButton::setChecked(bool fChecked)
     151{
     152    /* Update 'checked' state: */
     153    m_fChecked = fChecked;
     154    /* Update: */
     155    update();
     156}
     157
     158void UIStatusBarEditorButton::retranslateUi()
     159{
     160    /* Translate tool-tip: */
     161    setToolTip(tr("<nobr><b>Click</b> to toggle indicator presence.</nobr><br>"
     162                  "<nobr><b>Drag&Drop</b> to change indicator position.</nobr>"));
     163}
     164
     165void UIStatusBarEditorButton::paintEvent(QPaintEvent*)
     166{
     167    /* Create style-painter: */
     168    QStylePainter painter(this);
     169    QStyleOption option;
     170    option.initFrom(this);
     171    option.rect = QRect(0, 0, width(), height());
     172    /* Remember checked-state: */
     173    if (m_fChecked)
     174        option.state |= QStyle::State_On;
     175    /* Draw check-box for hovered-state: */
     176    if (m_fHovered)
     177        painter.drawPrimitive(QStyle::PE_IndicatorCheckBox, option);
     178    /* Draw pixmap for unhovered-state: */
     179    else
     180        painter.drawItemPixmap(option.rect, Qt::AlignCenter, m_pixmap);
     181}
     182
     183void UIStatusBarEditorButton::mousePressEvent(QMouseEvent *pEvent)
     184{
     185    /* We are interested in left button only: */
     186    if (pEvent->button() != Qt::LeftButton)
     187        return;
     188
     189    /* Remember mouse-press position: */
     190    m_mousePressPosition = pEvent->globalPos();
     191}
     192
     193void UIStatusBarEditorButton::mouseReleaseEvent(QMouseEvent *pEvent)
     194{
     195    /* We are interested in left button only: */
     196    if (pEvent->button() != Qt::LeftButton)
     197        return;
     198
     199    /* Forget mouse-press position: */
     200    m_mousePressPosition = QPoint();
     201
     202    /* Notify about click: */
     203    emit sigClick();
     204}
     205
     206void UIStatusBarEditorButton::enterEvent(QEvent*)
     207{
     208    /* Make sure button isn't hovered: */
     209    if (m_fHovered)
     210        return;
     211
     212    /* Invert hovered state: */
     213    m_fHovered = true;
     214    /* Update: */
     215    update();
     216}
     217
     218void UIStatusBarEditorButton::leaveEvent(QEvent*)
     219{
     220    /* Make sure button is hovered: */
     221    if (!m_fHovered)
     222        return;
     223
     224    /* Invert hovered state: */
     225    m_fHovered = false;
     226    /* Update: */
     227    update();
     228}
     229
     230void UIStatusBarEditorButton::mouseMoveEvent(QMouseEvent *pEvent)
     231{
     232    /* Make sure item isn't already dragged: */
     233    if (m_mousePressPosition.isNull())
     234        return QWidget::mouseMoveEvent(pEvent);
     235
     236    /* Make sure item is really dragged: */
     237    if (QLineF(pEvent->globalPos(), m_mousePressPosition).length() <
     238        QApplication::startDragDistance())
     239        return QWidget::mouseMoveEvent(pEvent);
     240
     241    /* Initialize dragging: */
     242    m_mousePressPosition = QPoint();
     243    QDrag *pDrag = new QDrag(this);
     244    connect(pDrag, SIGNAL(destroyed(QObject*)), this, SIGNAL(sigDragObjectDestroy()));
     245    QMimeData *pMimeData = new QMimeData;
     246    pMimeData->setData(MimeType, gpConverter->toInternalString(m_type).toLatin1());
     247    pDrag->setMimeData(pMimeData);
     248    pDrag->setPixmap(m_pixmap);
     249    pDrag->exec();
     250}
     251
     252
     253/** QWidget reimplementation
     254  * providing user with possibility to edit status-bar layout. */
     255class UIStatusBarEditorWindow : public QIWithRetranslateUI2<QWidget>
     256{
     257    Q_OBJECT;
     258    Q_PROPERTY(QRect startGeometry READ startGeometry);
     259    Q_PROPERTY(QRect finalGeometry READ finalGeometry);
     260
     261signals:
     262
     263    /** Notifies about window shown. */
     264    void sigShown();
     265    /** Commands window to expand. */
     266    void sigExpand();
     267    /** Commands window to collapse. */
     268    void sigCollapse();
     269
     270public:
     271
     272    /** Constructor, passes @a pParent to the QIRichToolButton constructor.
     273      * @param rect is used to define initial cached parent geometry.
     274      * @param statusBarRect is used to define initial cached status-bar geometry. */
     275    UIStatusBarEditorWindow(QWidget *pParent, const QRect &rect, const QRect &statusBarRect);
     276
     277private slots:
     278
     279    /** Mark window as expanded. */
     280    void sltMarkAsExpanded() { m_fExpanded = true; }
     281    /** Mark window as collapsed. */
     282    void sltMarkAsCollapsed() { close(); m_fExpanded = false; }
     283
     284    /** Handles parent geometry change. */
     285    void sltParentGeometryChanged(const QRect &rect);
     286
     287    /** Handles configuration change. */
     288    void sltHandleConfigurationChange();
     289
     290    /** Handles button click. */
     291    void sltHandleButtonClick();
     292
     293    /** Handles drag object destroy. */
     294    void sltHandleDragObjectDestroy();
     295
     296private:
     297
     298    /** Prepare routine. */
     299    void prepare();
     300    /** Prepare status buttons routine. */
     301    void prepareStatusButtons();
     302    /** Prepare status button routine. */
     303    void prepareStatusButton(IndicatorType type);
     304    /** Prepare animation routine. */
     305    void prepareAnimation();
     306
     307    /** Updates status buttons. */
     308    void updateStatusButtons();
     309    /** Updates animation. */
     310    void updateAnimation();
     311    /** Update geometry. */
     312    void adjustGeometry();
     313
     314    /** Retranslation routine. */
     315    virtual void retranslateUi();
     316
     317    /** Show event handler. */
     318    virtual void showEvent(QShowEvent *pEvent);
     319    /** Close event handler. */
     320    virtual void closeEvent(QCloseEvent *pEvent);
     321
     322    /** Paint event handler. */
     323    virtual void paintEvent(QPaintEvent *pEvent);
     324
     325    /** Drag-enter event handler. */
     326    virtual void dragEnterEvent(QDragEnterEvent *pEvent);
     327    /** Drag-move event handler. */
     328    virtual void dragMoveEvent(QDragMoveEvent *pEvent);
     329    /** Drag-leave event handler. */
     330    virtual void dragLeaveEvent(QDragLeaveEvent *pEvent);
     331    /** Drop event handler. */
     332    virtual void dropEvent(QDropEvent *pEvent);
     333
     334    /** Returns position for passed @a type. */
     335    int position(IndicatorType type) const;
     336
     337    /** Returns cached start-geometry. */
     338    QRect startGeometry() const { return m_startGeometry; }
     339    /** Returns cached final-geometry. */
     340    QRect finalGeometry() const { return m_finalGeometry; }
     341
     342    /** @name Geometry
     343      * @{ */
     344        /** Holds the cached parent geometry. */
     345        QRect m_rect;
     346        /** Holds the cached status-bar geometry. */
     347        QRect m_statusBarRect;
     348    /** @} */
     349
     350    /** @name Geometry: Animation
     351      * @{ */
     352        /** Holds the expand/collapse animation instance. */
     353        UIAnimation *m_pAnimation;
     354        /** Holds whether window is expanded. */
     355        bool m_fExpanded;
     356        /** Holds the cached start-geometry. */
     357        QRect m_startGeometry;
     358        /** Holds the cached final-geometry. */
     359        QRect m_finalGeometry;
     360    /** @} */
     361
     362    /** @name Contents
     363      * @{ */
     364        /** Holds the main-layout instance. */
     365        QHBoxLayout *m_pMainLayout;
     366        /** Holds the button-layout instance. */
     367        QHBoxLayout *m_pButtonLayout;
     368        /** Holds the close-button instance. */
     369        QIToolButton *m_pButtonClose;
     370        /** Holds status-bar buttons. */
     371        QMap<IndicatorType, UIStatusBarEditorButton*> m_buttons;
     372    /** @} */
     373
     374    /** @name Contents: Restrictions
     375      * @{ */
     376        /** Holds the cached status-bar button restrictions. */
     377        QList<IndicatorType> m_restrictions;
     378    /** @} */
     379
     380    /** @name Contents: Order
     381      * @{ */
     382        /** Holds the cached status-bar button order. */
     383        QList<IndicatorType> m_order;
     384        /** Holds the token-button to drop dragged-button nearby. */
     385        UIStatusBarEditorButton *m_pButtonDropToken;
     386        /** Holds whether dragged-button should be dropped <b>after</b> the token-button. */
     387        bool m_fDropAfterTokenButton;
     388    /** @} */
     389};
     390
     391UIStatusBarEditorWindow::UIStatusBarEditorWindow(QWidget *pParent, const QRect &rect, const QRect &statusBarRect)
     392    : QIWithRetranslateUI2<QWidget>(pParent, Qt::Tool | Qt::FramelessWindowHint)
     393    , m_rect(rect), m_statusBarRect(statusBarRect)
     394    , m_pAnimation(0), m_fExpanded(false)
     395    , m_pMainLayout(0), m_pButtonLayout(0)
     396    , m_pButtonClose(0)
     397    , m_pButtonDropToken(0)
     398    , m_fDropAfterTokenButton(true)
     399{
     400    /* Prepare: */
     401    prepare();
     402}
     403
     404void UIStatusBarEditorWindow::sltParentGeometryChanged(const QRect &rect)
     405{
     406    /* Update rectangle: */
     407    m_rect = rect;
     408    /* Update animation: */
     409    updateAnimation();
     410    /* Adjust geometry: */
     411    adjustGeometry();
     412}
     413
     414void UIStatusBarEditorWindow::sltHandleConfigurationChange()
     415{
     416    /* Update status buttons: */
     417    updateStatusButtons();
     418}
     419
     420void UIStatusBarEditorWindow::sltHandleButtonClick()
     421{
     422    /* Make sure sender is valid: */
     423    UIStatusBarEditorButton *pButton = qobject_cast<UIStatusBarEditorButton*>(sender());
     424    AssertPtrReturnVoid(pButton);
     425
     426    /* Get sender type: */
     427    const IndicatorType type = pButton->type();
     428
     429    /* Load current status-bar indicator restrictions: */
     430    QList<IndicatorType> restrictions =
     431        gEDataManager->restrictedStatusBarIndicators(vboxGlobal().managedVMUuid());
     432
     433    /* Invert restriction for sender type: */
     434    if (restrictions.contains(type))
     435        restrictions.removeAll(type);
     436    else
     437        restrictions.append(type);
     438
     439    /* Save updated status-bar indicator restrictions: */
     440    gEDataManager->setRestrictedStatusBarIndicators(restrictions, vboxGlobal().managedVMUuid());
     441}
     442
     443void UIStatusBarEditorWindow::sltHandleDragObjectDestroy()
     444{
     445    /* Reset token: */
     446    m_pButtonDropToken = 0;
     447    m_fDropAfterTokenButton = true;
     448    /* Update: */
     449    update();
     450}
     451
     452void UIStatusBarEditorWindow::prepare()
     453{
     454    /* Do not count that window as important for application,
     455     * it will NOT be taken into account when other top-level windows will be closed: */
     456    setAttribute(Qt::WA_QuitOnClose, false);
     457    /* Delete window when closed: */
     458    setAttribute(Qt::WA_DeleteOnClose);
     459    /* Make window background translucent: */
     460    setAttribute(Qt::WA_TranslucentBackground);
     461    /* Track D&D events: */
     462    setAcceptDrops(true);
     463
     464    /* Create main-layout: */
     465    m_pMainLayout = new QHBoxLayout(this);
     466    AssertPtrReturnVoid(m_pMainLayout);
     467    {
     468        /* Configure main-layout: */
     469        int iLeft, iTop, iRight, iBottom;
     470        m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
     471        if (iBottom >= 5)
     472            iBottom -= 5;
     473        m_pMainLayout->setContentsMargins(iLeft, iTop, iRight, iBottom);
     474        m_pMainLayout->setSpacing(0);
     475        /* Create close-button: */
     476        m_pButtonClose = new QIToolButton;
     477        AssertPtrReturnVoid(m_pButtonClose);
     478        {
     479            /* Configure close-button: */
     480            m_pButtonClose->setMinimumSize(QSize(1, 1));
     481            m_pButtonClose->setShortcut(Qt::Key_Escape);
     482            m_pButtonClose->setIcon(UIIconPool::iconSet(":/ok_16px.png"));
     483            connect(m_pButtonClose, SIGNAL(clicked(bool)), this, SLOT(close()));
     484            /* Add close-button into main-layout: */
     485            m_pMainLayout->addWidget(m_pButtonClose);
     486        }
     487        /* Insert stretch: */
     488        m_pMainLayout->addStretch();
     489        /* Create button-layout: */
     490        m_pButtonLayout = new QHBoxLayout;
     491        AssertPtrReturnVoid(m_pButtonLayout);
     492        {
     493            /* Configure button-layout: */
     494            m_pButtonLayout->setContentsMargins(0, 0, 0, 0);
     495            m_pButtonLayout->setSpacing(5);
     496            /* Add button-layout into main-layout: */
     497            m_pMainLayout->addLayout(m_pButtonLayout);
     498        }
     499        /* Prepare status buttons: */
     500        prepareStatusButtons();
     501    }
     502
     503    /* Translate contents: */
     504    retranslateUi();
     505
     506    /* Prepare animation: */
     507    prepareAnimation();
     508
     509    /* Activate window: */
     510    activateWindow();
     511}
     512
     513void UIStatusBarEditorWindow::prepareStatusButtons()
     514{
     515    /* Create status buttons: */
     516    for (int i = IndicatorType_Invalid; i < IndicatorType_Max; ++i)
     517    {
     518        /* Get current type: */
     519        const IndicatorType type = (IndicatorType)i;
     520        /* Skip inappropriate types: */
     521        if (type == IndicatorType_Invalid || type == IndicatorType_KeyboardExtension)
     522            continue;
     523        /* Create status button: */
     524        prepareStatusButton(type);
     525    }
     526
     527    /* Listen for the status-bar configuration changes: */
     528    connect(gEDataManager, SIGNAL(sigStatusBarConfigurationChange()),
     529            this, SLOT(sltHandleConfigurationChange()));
     530    /* Update status buttons: */
     531    updateStatusButtons();
     532}
     533
     534void UIStatusBarEditorWindow::prepareStatusButton(IndicatorType type)
     535{
     536    /* Create status button: */
     537    UIStatusBarEditorButton *pButton = new UIStatusBarEditorButton(type);
     538    AssertPtrReturnVoid(pButton);
     539    {
     540        /* Configure status button: */
     541        connect(pButton, SIGNAL(sigClick()), this, SLOT(sltHandleButtonClick()));
     542        connect(pButton, SIGNAL(sigDragObjectDestroy()), this, SLOT(sltHandleDragObjectDestroy()));
     543        /* Add status button into button-layout: */
     544        m_pButtonLayout->addWidget(pButton);
     545        /* Insert status button into map: */
     546        m_buttons.insert(type, pButton);
     547    }
     548}
     549
     550void UIStatusBarEditorWindow::prepareAnimation()
     551{
     552    /* Prepare geometry animation itself: */
     553    connect(this, SIGNAL(sigShown()), this, SIGNAL(sigExpand()), Qt::QueuedConnection);
     554    m_pAnimation = UIAnimation::installPropertyAnimation(this, "geometry", "startGeometry", "finalGeometry",
     555                                                         SIGNAL(sigExpand()), SIGNAL(sigCollapse()));
     556    connect(m_pAnimation, SIGNAL(sigStateEnteredStart()), this, SLOT(sltMarkAsCollapsed()));
     557    connect(m_pAnimation, SIGNAL(sigStateEnteredFinal()), this, SLOT(sltMarkAsExpanded()));
     558    /* Update animation: */
     559    updateAnimation();
     560}
     561
     562void UIStatusBarEditorWindow::updateStatusButtons()
     563{
     564    /* Recache status-bar configuration: */
     565    m_restrictions = gEDataManager->restrictedStatusBarIndicators(vboxGlobal().managedVMUuid());
     566    m_order = gEDataManager->statusBarIndicatorOrder(vboxGlobal().managedVMUuid());
     567    for (int iType = IndicatorType_Invalid; iType < IndicatorType_Max; ++iType)
     568        if (iType != IndicatorType_Invalid && iType != IndicatorType_KeyboardExtension &&
     569            !m_order.contains((IndicatorType)iType))
     570            m_order << (IndicatorType)iType;
     571
     572    /* Update configuration for all the status buttons: */
     573    foreach (const IndicatorType &type, m_order)
     574    {
     575        /* Get button: */
     576        UIStatusBarEditorButton *pButton = m_buttons.value(type);
     577        /* Update button 'checked' state: */
     578        pButton->setChecked(!m_restrictions.contains(type));
     579        /* Make sure it have valid position: */
     580        const int iWantedIndex = position(type);
     581        const int iActualIndex = m_pButtonLayout->indexOf(pButton);
     582        if (iActualIndex != iWantedIndex)
     583        {
     584            /* Re-inject button into main-layout at proper position: */
     585            m_pButtonLayout->removeWidget(pButton);
     586            m_pButtonLayout->insertWidget(iWantedIndex, pButton);
     587        }
     588    }
     589}
     590
     591void UIStatusBarEditorWindow::updateAnimation()
     592{
     593    /* Calculate geometry animation boundaries
     594     * based on size-hint and minimum size-hint: */
     595    const QSize sh = sizeHint();
     596    const QSize msh = minimumSizeHint();
     597    m_startGeometry = QRect(m_rect.x(), m_rect.y() + m_rect.height() - m_statusBarRect.height() - msh.height(),
     598                            qMax(m_rect.width(), msh.width()), msh.height());
     599    m_finalGeometry = QRect(m_rect.x(), m_rect.y() + m_rect.height() - m_statusBarRect.height() - sh.height(),
     600                            qMax(m_rect.width(), sh.width()), sh.height());
     601    m_pAnimation->update();
     602}
     603
     604void UIStatusBarEditorWindow::adjustGeometry()
     605{
     606    /* Adjust geometry based on size-hint: */
     607    const QSize sh = sizeHint();
     608    setGeometry(m_rect.x(), m_rect.y() + m_rect.height() - m_statusBarRect.height() - sh.height(),
     609                qMax(m_rect.width(), sh.width()), sh.height());
     610    raise();
     611}
     612
     613void UIStatusBarEditorWindow::retranslateUi()
     614{
     615    /* Translate close-button: */
     616    m_pButtonClose->setToolTip(tr("Close"));
     617}
     618
     619void UIStatusBarEditorWindow::showEvent(QShowEvent*)
     620{
     621    /* If window isn't expanded: */
     622    if (!m_fExpanded)
     623    {
     624        /* Start expand animation: */
     625        emit sigShown();
     626    }
     627}
     628
     629void UIStatusBarEditorWindow::closeEvent(QCloseEvent *pEvent)
     630{
     631    /* If window isn't expanded: */
     632    if (!m_fExpanded)
     633    {
     634        /* Ignore close-event: */
     635        pEvent->ignore();
     636        return;
     637    }
     638
     639    /* If animation state is Final: */
     640    const QString strAnimationState = property("AnimationState").toString();
     641    bool fAnimationComplete = strAnimationState == "Final";
     642    if (fAnimationComplete)
     643    {
     644        /* Ignore close-event: */
     645        pEvent->ignore();
     646        /* And start collapse animation: */
     647        emit sigCollapse();
     648    }
     649}
     650
     651void UIStatusBarEditorWindow::paintEvent(QPaintEvent*)
     652{
     653    /* Prepare painter: */
     654    QPainter painter(this);
     655
     656    /* Prepare palette colors: */
     657    const QPalette pal = palette();
     658    QColor color0 = pal.color(QPalette::Window);
     659    QColor color1 = pal.color(QPalette::Window).lighter(110);
     660    color1.setAlpha(0);
     661    QColor color2 = pal.color(QPalette::Window).darker(200);
     662    QColor color3 = pal.color(QPalette::Window).darker(120);
     663
     664    /* Left corner: */
     665    QRadialGradient grad1(QPointF(5, 5), 5);
     666    {
     667        grad1.setColorAt(0, color2);
     668        grad1.setColorAt(1, color1);
     669    }
     670    /* Right corner: */
     671    QRadialGradient grad2(QPointF(width() - 5, 5), 5);
     672    {
     673        grad2.setColorAt(0, color2);
     674        grad2.setColorAt(1, color1);
     675    }
     676    /* Top line: */
     677    QLinearGradient grad3(QPointF(5, 0), QPointF(5, 5));
     678    {
     679        grad3.setColorAt(0, color1);
     680        grad3.setColorAt(1, color2);
     681    }
     682    /* Left line: */
     683    QLinearGradient grad4(QPointF(0, 5), QPointF(5, 5));
     684    {
     685        grad4.setColorAt(0, color1);
     686        grad4.setColorAt(1, color2);
     687    }
     688    /* Right line: */
     689    QLinearGradient grad5(QPointF(width(), 5), QPointF(width() - 5, 5));
     690    {
     691        grad5.setColorAt(0, color1);
     692        grad5.setColorAt(1, color2);
     693    }
     694
     695    /* Paint frames: */
     696    painter.fillRect(QRect(5, 5, width() - 5 * 2, height() - 5), color0);
     697    painter.fillRect(QRect(0, 0, 5, 5), grad1);
     698    painter.fillRect(QRect(width() - 5, 0, 5, 5), grad2);
     699    painter.fillRect(QRect(5, 0, width() - 5 * 2, 5), grad3);
     700    painter.fillRect(QRect(0, 5, 5, height() - 5), grad4);
     701    painter.fillRect(QRect(width() - 5, 5, 5, height() - 5), grad5);
     702    painter.save();
     703    painter.setPen(color3);
     704    painter.drawLine(QLine(QPoint(5 + 1, 5 + 1),                      QPoint(width() - 1 - 5 - 1, 5 + 1)));
     705    painter.drawLine(QLine(QPoint(width() - 1 - 5 - 1, 5 + 1),        QPoint(width() - 1 - 5 - 1, height() - 1)));
     706    painter.drawLine(QLine(QPoint(width() - 1 - 5 - 1, height() - 1), QPoint(5 + 1, height() - 1)));
     707    painter.drawLine(QLine(QPoint(5 + 1, height() - 1),               QPoint(5 + 1, 5 + 1)));
     708    painter.restore();
     709
     710    /* Paint drop token: */
     711    if (m_pButtonDropToken)
     712    {
     713        QStyleOption option;
     714        option.state |= QStyle::State_Horizontal;
     715        const QRect geo = m_pButtonDropToken->geometry();
     716        option.rect = !m_fDropAfterTokenButton ?
     717                      QRect(geo.topLeft() - QPoint(5, 5),
     718                            geo.bottomLeft() + QPoint(0, 5)) :
     719                      QRect(geo.topRight() - QPoint(0, 5),
     720                            geo.bottomRight() + QPoint(5, 5));
     721        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator,
     722                                             &option, &painter);
     723    }
     724}
     725
     726void UIStatusBarEditorWindow::dragEnterEvent(QDragEnterEvent *pEvent)
     727{
     728    /* Make sure event is valid: */
     729    AssertPtrReturnVoid(pEvent);
     730    /* And mime-data is set: */
     731    const QMimeData *pMimeData = pEvent->mimeData();
     732    AssertPtrReturnVoid(pMimeData);
     733    /* Make sure mime-data format is valid: */
     734    if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
     735        return;
     736
     737    /* Accept drag-enter event: */
     738    pEvent->acceptProposedAction();
     739}
     740
     741void UIStatusBarEditorWindow::dragMoveEvent(QDragMoveEvent *pEvent)
     742{
     743    /* Make sure event is valid: */
     744    AssertPtrReturnVoid(pEvent);
     745    /* And mime-data is set: */
     746    const QMimeData *pMimeData = pEvent->mimeData();
     747    AssertPtrReturnVoid(pMimeData);
     748    /* Make sure mime-data format is valid: */
     749    if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
     750        return;
     751
     752    /* Reset token: */
     753    m_pButtonDropToken = 0;
     754    m_fDropAfterTokenButton = true;
     755
     756    /* Get event position: */
     757    const QPoint pos = pEvent->pos();
     758    /* Search for most suitable button: */
     759    foreach (const IndicatorType &type, m_order)
     760    {
     761        m_pButtonDropToken = m_buttons.value(type);
     762        const QRect geo = m_pButtonDropToken->geometry();
     763        if (pos.x() < geo.center().x())
     764        {
     765            m_fDropAfterTokenButton = false;
     766            break;
     767        }
     768    }
     769    /* Update: */
     770    update();
     771}
     772
     773void UIStatusBarEditorWindow::dragLeaveEvent(QDragLeaveEvent*)
     774{
     775    /* Reset token: */
     776    m_pButtonDropToken = 0;
     777    m_fDropAfterTokenButton = true;
     778    /* Update: */
     779    update();
     780}
     781
     782void UIStatusBarEditorWindow::dropEvent(QDropEvent *pEvent)
     783{
     784    /* Make sure event is valid: */
     785    AssertPtrReturnVoid(pEvent);
     786    /* And mime-data is set: */
     787    const QMimeData *pMimeData = pEvent->mimeData();
     788    AssertPtrReturnVoid(pMimeData);
     789    /* Make sure mime-data format is valid: */
     790    if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
     791        return;
     792
     793    /* Make sure token-button set: */
     794    if (!m_pButtonDropToken)
     795        return;
     796
     797    /* Determine type of token-button: */
     798    const IndicatorType tokenType = m_pButtonDropToken->type();
     799    /* Determine type of dropped-button: */
     800    const QString strDroppedType =
     801        QString::fromLatin1(pMimeData->data(UIStatusBarEditorButton::MimeType));
     802    const IndicatorType droppedType =
     803        gpConverter->fromInternalString<IndicatorType>(strDroppedType);
     804
     805    /* Make sure these types are different: */
     806    if (droppedType == tokenType)
     807        return;
     808
     809    /* Load current status-bar indicator order and make sure it's complete: */
     810    QList<IndicatorType> order =
     811        gEDataManager->statusBarIndicatorOrder(vboxGlobal().managedVMUuid());
     812    for (int iType = IndicatorType_Invalid; iType < IndicatorType_Max; ++iType)
     813        if (iType != IndicatorType_Invalid && iType != IndicatorType_KeyboardExtension &&
     814            !order.contains((IndicatorType)iType))
     815            order << (IndicatorType)iType;
     816
     817    /* Remove type of dropped-button: */
     818    order.removeAll(droppedType);
     819    /* Insert type of dropped-button into position of token-button: */
     820    int iPosition = order.indexOf(tokenType);
     821    if (m_fDropAfterTokenButton)
     822        ++iPosition;
     823    order.insert(iPosition, droppedType);
     824
     825    /* Save updated status-bar indicator order: */
     826    gEDataManager->setStatusBarIndicatorOrder(order, vboxGlobal().managedVMUuid());
     827}
     828
     829int UIStatusBarEditorWindow::position(IndicatorType type) const
     830{
     831    int iPosition = 0;
     832    foreach (const IndicatorType &iteratedType, m_order)
     833        if (iteratedType == type)
     834            return iPosition;
     835        else
     836            ++iPosition;
     837    return iPosition;
     838}
     839
    50840
    51841UIMachineWindowNormal::UIMachineWindowNormal(UIMachineLogic *pMachineLogic, ulong uScreenId)
     
    110900    /* Update virtualization stuff: */
    111901    updateAppearanceOf(UIVisualElement_FeaturesStuff);
     902}
     903
     904void UIMachineWindowNormal::sltShowStatusBarContextMenu(const QPoint &position)
     905{
     906    /* Prepare context-menu: */
     907    QMenu menu;
     908    /* Having just one action to configure status-bar: */
     909    QAction *pAction = menu.addAction(UIIconPool::iconSet(":/vm_settings_16px.png"),
     910                                      tr("Configure status-bar..."),
     911                                      this, SLOT(sltOpenStatusBarEditorWindow()));
     912    pAction->setEnabled(!uisession()->property("StatusBarEditorOpened").toBool());
     913    /* Execute context-menu: */
     914    menu.exec(statusBar()->mapToGlobal(position));
     915}
     916
     917void UIMachineWindowNormal::sltOpenStatusBarEditorWindow()
     918{
     919    /* Prevent user from opening another one editor: */
     920    uisession()->setProperty("StatusBarEditorOpened", true);
     921    /* Create status-bar editor: */
     922    UIStatusBarEditorWindow *pStatusBarEditor =
     923        new UIStatusBarEditorWindow(this, m_normalGeometry, statusBar()->geometry());
     924    AssertPtrReturnVoid(pStatusBarEditor);
     925    {
     926        /* Configure status-bar editor: */
     927        connect(this, SIGNAL(sigGeometryChange(const QRect&)),
     928                pStatusBarEditor, SLOT(sltParentGeometryChanged(const QRect&)));
     929        connect(pStatusBarEditor, SIGNAL(destroyed(QObject*)),
     930                this, SLOT(sltStatusBarEditorWindowClosed()));
     931        /* Show window: */
     932        pStatusBarEditor->show();
     933    }
     934}
     935
     936void UIMachineWindowNormal::sltStatusBarEditorWindowClosed()
     937{
     938    /* Allow user to open editor again: */
     939    uisession()->setProperty("StatusBarEditorOpened", QVariant());
    112940}
    113941
     
    1901018    AssertPtrReturnVoid(statusBar());
    1911019    {
     1020#ifdef Q_WS_WIN
     1021        /* Configure status-bar: */
     1022        statusBar()->setContextMenuPolicy(Qt::CustomContextMenu);
     1023        connect(statusBar(), SIGNAL(customContextMenuRequested(const QPoint&)),
     1024                this, SLOT(sltShowStatusBarContextMenu(const QPoint&)));
     1025#endif /* Q_WS_WIN */
    1921026        /* Create indicator-pool: */
    1931027        m_pIndicatorsPool = new UIIndicatorsPool(machineLogic()->uisession());
     
    3291163            {
    3301164                m_normalGeometry.setSize(pResizeEvent->size());
     1165                emit sigGeometryChange(m_normalGeometry);
    3311166#ifdef VBOX_WITH_DEBUGGER_GUI
    3321167                /* Update debugger window position: */
     
    3411176            {
    3421177                m_normalGeometry.moveTo(geometry().x(), geometry().y());
     1178                emit sigGeometryChange(m_normalGeometry);
    3431179#ifdef VBOX_WITH_DEBUGGER_GUI
    3441180                /* Update debugger window position: */
     
    3481184            break;
    3491185        }
     1186        case QEvent::WindowActivate:
     1187            emit sigGeometryChange(m_normalGeometry);
     1188            break;
    3501189        default:
    3511190            break;
     
    4651304}
    4661305
    467 
     1306#include "UIMachineWindowNormal.moc"
     1307
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.h

    r52014 r52053  
    3232    Q_OBJECT;
    3333
     34signals:
     35
     36    /** Notifies about geometry change. */
     37    void sigGeometryChange(const QRect &rect);
     38
    3439protected:
    3540
     
    5358    void sltVideoCaptureChange();
    5459    void sltCPUExecutionCapChange();
     60
     61    /** Handles status-bar context-menu-request: */
     62    void sltShowStatusBarContextMenu(const QPoint &position);
     63    /** Handles status-bar editor opening. */
     64    void sltOpenStatusBarEditorWindow();
     65    /** Handles status-bar editor closing. */
     66    void sltStatusBarEditorWindowClosed();
    5567
    5668    /** Handles indicator context-menu-request: */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette