diff --git a/data/themes/default/close.png b/data/themes/default/close.png new file mode 100644 index 00000000000..0dc87670dbb Binary files /dev/null and b/data/themes/default/close.png differ diff --git a/data/themes/default/maximize.png b/data/themes/default/maximize.png new file mode 100644 index 00000000000..1cb4186241a Binary files /dev/null and b/data/themes/default/maximize.png differ diff --git a/data/themes/default/minimize.png b/data/themes/default/minimize.png new file mode 100644 index 00000000000..33bb26378ea Binary files /dev/null and b/data/themes/default/minimize.png differ diff --git a/data/themes/default/restore.png b/data/themes/default/restore.png new file mode 100644 index 00000000000..4492e17a643 Binary files /dev/null and b/data/themes/default/restore.png differ diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 49ba6dd4d15..a66f7799590 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -576,6 +576,40 @@ BBTCOView { background-color: rgb( 128, 182, 175 ); /* default colour for bb-tracks */ } +/* Subwindows in MDI-Area */ +SubWindow { + color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #4b525c, stop: 1.0 #31363d); + qproperty-activeColor: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #33383e, stop: 1.0 #1a1c20); + qproperty-textShadowColor: rgb( 0, 0, 0 ); + qproperty-borderColor: rgb( 0, 0, 0 ); +} + +/* Subwindow title text */ +SubWindow > QLabel { + color: rgb( 255, 255, 255 ); + font-size: 12px; + font-style: normal; +} + +/* SubWindow titlebar button */ +SubWindow > QPushButton { + background-color: rgba( 255, 255, 255, 0% ); + border-width: 0px; + border-color: none; + border-style: none; +} + +SubWindow > QPushButton:hover{ + background-color: rgba( 255, 255, 255, 15% ); + border-width: 1px; + border-color: rgba( 0, 0, 0, 20% ); + border-style: solid; + border-radius: 2px; +} + + /* Plugins */ TripleOscillatorView Knob { diff --git a/include/SubWindow.h b/include/SubWindow.h index 821e0a76201..9e43e334530 100644 --- a/include/SubWindow.h +++ b/include/SubWindow.h @@ -23,18 +23,19 @@ * Boston, MA 02110-1301 USA. * */ - - #ifndef SUBWINDOW_H #define SUBWINDOW_H - +#include +#include #include -#include +#include +#include +#include +#include #include "export.h" - class QMoveEvent; class QResizeEvent; class QWidget; @@ -43,16 +44,43 @@ class QWidget; class EXPORT SubWindow : public QMdiSubWindow { Q_OBJECT + Q_PROPERTY( QBrush activeColor READ activeColor WRITE setActiveColor ) + Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor ) + Q_PROPERTY( QColor borderColor READ borderColor WRITE setBorderColor ) + public: - SubWindow(QWidget *parent=NULL, Qt::WindowFlags windowFlags=0); + SubWindow( QWidget *parent = NULL, Qt::WindowFlags windowFlags = 0 ); // same as QWidet::normalGeometry, but works properly under X11 (see https://bugreports.qt.io/browse/QTBUG-256) QRect getTrueNormalGeometry() const; + QBrush activeColor() const; + QColor textShadowColor() const; + QColor borderColor() const; + void setActiveColor( const QBrush & b ); + void setTextShadowColor( const QColor &c ); + void setBorderColor( const QColor &c ); + protected: // hook the QWidget move/resize events to update the tracked geometry - virtual void moveEvent(QMoveEvent * event); - virtual void resizeEvent(QResizeEvent * event); + virtual void moveEvent( QMoveEvent * event ); + virtual void resizeEvent( QResizeEvent * event ); + virtual void paintEvent( QPaintEvent * pe ); + private: + const QSize m_buttonSize; + const int m_titleBarHeight; + QPushButton * m_closeBtn; + QPushButton * m_minimizeBtn; + QPushButton * m_maximizeBtn; + QPushButton * m_restoreBtn; + QBrush m_activeColor; + QColor m_textShadowColor; + QColor m_borderColor; + QPoint m_position; QRect m_trackedNormalGeom; + QLabel * m_windowTitle; + QGraphicsDropShadowEffect * m_shadow; + + static void elideText( QLabel *label, QString text ); }; -#endif \ No newline at end of file +#endif diff --git a/src/gui/SubWindow.cpp b/src/gui/SubWindow.cpp index cc29962534b..fb01a10ae76 100644 --- a/src/gui/SubWindow.cpp +++ b/src/gui/SubWindow.cpp @@ -1,4 +1,4 @@ -/* +/* * SubWindow.cpp - Implementation of QMdiSubWindow that correctly tracks * the geometry that windows should be restored to. * Workaround for https://bugreports.qt.io/browse/QTBUG-256 @@ -26,42 +26,255 @@ #include "SubWindow.h" +#include #include #include -#include +#include "embed.h" -SubWindow::SubWindow(QWidget *parent, Qt::WindowFlags windowFlags) - : QMdiSubWindow(parent, windowFlags) + +SubWindow::SubWindow( QWidget *parent, Qt::WindowFlags windowFlags ) : + QMdiSubWindow( parent, windowFlags ), + m_buttonSize( 17, 17 ), + m_titleBarHeight( 24 ) { // initialize the tracked geometry to whatever Qt thinks the normal geometry currently is. // this should always work, since QMdiSubWindows will not start as maximized m_trackedNormalGeom = normalGeometry(); + + // inits the colors + m_activeColor = Qt::SolidPattern; + m_textShadowColor = Qt::black; + m_borderColor = Qt::black; + + // close, minimize, maximize and restore (after minimizing) buttons + m_closeBtn = new QPushButton( embed::getIconPixmap( "close" ), QString::null, this ); + m_closeBtn->resize( m_buttonSize ); + m_closeBtn->setFocusPolicy( Qt::NoFocus ); + m_closeBtn->setToolTip( tr( "Close" ) ); + connect( m_closeBtn, SIGNAL( clicked( bool ) ), this, SLOT( close() ) ); + + m_maximizeBtn = new QPushButton( embed::getIconPixmap( "maximize" ), QString::null, this ); + m_maximizeBtn->resize( m_buttonSize ); + m_maximizeBtn->setFocusPolicy( Qt::NoFocus ); + m_maximizeBtn->setToolTip( tr( "Maximize" ) ); + connect( m_maximizeBtn, SIGNAL( clicked( bool ) ), this, SLOT( showMaximized() ) ); + + m_minimizeBtn = new QPushButton( embed::getIconPixmap( "minimize" ), QString::null, this ); + m_minimizeBtn->resize( m_buttonSize ); + m_minimizeBtn->setFocusPolicy( Qt::NoFocus ); + m_minimizeBtn->setToolTip( tr( "Minimize" ) ); + connect( m_minimizeBtn, SIGNAL( clicked( bool ) ), this, SLOT( showMinimized() ) ); + + m_restoreBtn = new QPushButton( embed::getIconPixmap( "restore" ), QString::null, this ); + m_restoreBtn->resize( m_buttonSize ); + m_restoreBtn->setFocusPolicy( Qt::NoFocus ); + m_restoreBtn->setToolTip( tr( "Restore" ) ); + connect( m_restoreBtn, SIGNAL( clicked( bool ) ), this, SLOT( showNormal() ) ); + + // QLabel for the window title and the shadow effect + m_shadow = new QGraphicsDropShadowEffect(); + m_shadow->setColor( m_textShadowColor ); + m_shadow->setXOffset( 1 ); + m_shadow->setYOffset( 1 ); + + m_windowTitle = new QLabel( this ); + m_windowTitle->setFocusPolicy( Qt::NoFocus ); + m_windowTitle->setGraphicsEffect( m_shadow ); +} + + + + +void SubWindow::paintEvent( QPaintEvent * ) +{ + QPainter p( this ); + QRect rect( 0, 0, width(), m_titleBarHeight ); + bool isActive = SubWindow::mdiArea()->activeSubWindow() == this; + + p.fillRect( rect, isActive ? activeColor() : p.pen().brush() ); + + // window border + p.setPen( borderColor() ); + + // bottom, left, and right lines + p.drawLine( 0, height() - 1, width(), height() - 1 ); + p.drawLine( 0, m_titleBarHeight, 0, height() - 1 ); + p.drawLine( width() - 1, m_titleBarHeight, width() - 1, height() - 1 ); + + // window icon + QPixmap winicon( widget()->windowIcon().pixmap( m_buttonSize ) ); + p.drawPixmap( 3, 3, m_buttonSize.width(), m_buttonSize.height(), winicon ); +} + + + + +void SubWindow::elideText( QLabel *label, QString text ) +{ + QFontMetrics metrix( label->font() ); + int width = label->width() - 2; + QString clippedText = metrix.elidedText( text, Qt::ElideRight, width ); + label->setText( clippedText ); } + + + QRect SubWindow::getTrueNormalGeometry() const { return m_trackedNormalGeom; } -void SubWindow::moveEvent(QMoveEvent * event) + + + +QBrush SubWindow::activeColor() const +{ + return m_activeColor; +} + + + + +QColor SubWindow::textShadowColor() const { - QMdiSubWindow::moveEvent(event); + return m_textShadowColor; +} + + + + +QColor SubWindow::borderColor() const +{ + return m_borderColor; +} + + + + +void SubWindow::setActiveColor( const QBrush & b ) +{ + m_activeColor = b; +} + + + + +void SubWindow::setTextShadowColor( const QColor & c ) +{ + m_textShadowColor = c; +} + + + + +void SubWindow::setBorderColor( const QColor &c ) +{ + m_borderColor = c; +} + + + + +void SubWindow::moveEvent( QMoveEvent * event ) +{ + QMdiSubWindow::moveEvent( event ); // if the window was moved and ISN'T minimized/maximized/fullscreen, - // then save the current position - if (!isMaximized() && !isMinimized() && !isFullScreen()) + // then save the current position + if( !isMaximized() && !isMinimized() && !isFullScreen() ) { - m_trackedNormalGeom.moveTopLeft(event->pos()); + m_trackedNormalGeom.moveTopLeft( event->pos() ); } } -void SubWindow::resizeEvent(QResizeEvent * event) + + + +void SubWindow::resizeEvent( QResizeEvent * event ) { - QMdiSubWindow::resizeEvent(event); + // button adjustments + m_minimizeBtn->hide(); + m_maximizeBtn->hide(); + m_restoreBtn->hide(); + + const int rightSpace = 3; + const int buttonGap = 1; + const int menuButtonSpace = 24; + + QPoint rightButtonPos( width() - rightSpace - m_buttonSize.width() , 3 ); + QPoint middleButtonPos( width() - rightSpace - ( 2 * m_buttonSize.width() ) - buttonGap, 3 ); + QPoint leftButtonPos( width() - rightSpace - ( 3 * m_buttonSize.width() ) - ( 2 * buttonGap ), 3 ); + + // the buttonBarWidth depends on the number of buttons. + // we need it to calculate the width of window title label + int buttonBarWidth = rightSpace + m_buttonSize.width(); + + // set the buttons on their positions. + // the close button is always needed and on the rightButtonPos + m_closeBtn->move( rightButtonPos ); + + // here we ask: is the Subwindow maximizable and/or minimizable + // then we set the buttons and show them if needed + if( windowFlags() & Qt::WindowMaximizeButtonHint ) + { + buttonBarWidth = buttonBarWidth + m_buttonSize.width() + buttonGap; + m_maximizeBtn->move( middleButtonPos ); + m_maximizeBtn->show(); + } + + if( windowFlags() & Qt::WindowMinimizeButtonHint ) + { + buttonBarWidth = buttonBarWidth + m_buttonSize.width() + buttonGap; + if( m_maximizeBtn->isHidden() ) + { + m_minimizeBtn->move( middleButtonPos ); + } + else + { + m_minimizeBtn->move( leftButtonPos ); + } + m_minimizeBtn->show(); + m_restoreBtn->hide(); + if( isMinimized() ) + { + if( m_maximizeBtn->isHidden() ) + { + m_restoreBtn->move( middleButtonPos ); + } + else + { + m_restoreBtn->move( leftButtonPos ); + } + m_restoreBtn->show(); + m_minimizeBtn->hide(); + } + } + + // title QLabel adjustments + m_windowTitle->setAlignment( Qt::AlignHCenter ); + m_windowTitle->setFixedWidth( widget()->width() - ( menuButtonSpace + buttonBarWidth ) ); + m_windowTitle->move( menuButtonSpace, + ( m_titleBarHeight / 2 ) - ( m_windowTitle->sizeHint().height() / 2 ) - 1 ); + + // if minimized we can't use widget()->width(). We have to hard code the width, + // as the width of all minimized windows is the same. + if( isMinimized() ) + { + m_windowTitle->setFixedWidth( 120 ); + } + + // truncate the label string if the window is to small. Adds "..." + elideText( m_windowTitle, widget()->windowTitle() ); + m_windowTitle->setTextInteractionFlags( Qt::NoTextInteraction ); + m_windowTitle->adjustSize(); + + QMdiSubWindow::resizeEvent( event ); + // if the window was resized and ISN'T minimized/maximized/fullscreen, - // then save the current size - if (!isMaximized() && !isMinimized() && !isFullScreen()) + // then save the current size + if( !isMaximized() && !isMinimized() && !isFullScreen() ) { - m_trackedNormalGeom.setSize(event->size()); + m_trackedNormalGeom.setSize( event->size() ); } -} \ No newline at end of file +}