diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 9d0c5ad..b4e9fe0 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -180,6 +180,7 @@ void DockAreaWidgetPrivate::createTabBar() TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width()); TabsMenuButton->setMenu(new QMenu(TabsMenuButton)); TopLayout->addWidget(TabsMenuButton, 0); + TabsMenuButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), SLOT(onTabsMenuActionTriggered(QAction*))); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index db3ecc5..1d8eaad 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -993,7 +993,6 @@ bool CDockContainerWidget::restoreState(QXmlStreamReader& s, bool Testing) QByteArray GeometryString = s.readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toLocal8Bit(); QByteArray Geometry = QByteArray::fromHex(GeometryString); - std::cout << "Geometry: " << Geometry.toHex(' ').toStdString() << std::endl; if (Geometry.isEmpty()) { return false; diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 6c476d0..27d436c 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -312,7 +312,6 @@ QByteArray CDockManager::saveState(int version) const s.writeEndElement(); s.writeEndDocument(); - std::cout << xmldata.toStdString() << std::endl; return xmldata; } @@ -408,14 +407,12 @@ QStringList CDockManager::perspectiveNames() const //============================================================================ void CDockManager::openPerspective(const QString& PerspectiveName) { - std::cout << "CDockManager::openPerspective " << PerspectiveName.toStdString() << std::endl; const auto Iterator = d->Perspectives.find(PerspectiveName); if (d->Perspectives.end() == Iterator) { return; } - std::cout << "CDockManager::openPerspective - restoring state" << std::endl; restoreState(Iterator.value()); } diff --git a/src/DockOverlay.cpp b/src/DockOverlay.cpp index b88529f..deaf374 100644 --- a/src/DockOverlay.cpp +++ b/src/DockOverlay.cpp @@ -33,160 +33,14 @@ #include #include #include +#include #include "DockAreaWidget.h" +#include + namespace ads { -//============================================================================ -static QPixmap createDropIndicatorPixmap(const QPalette& pal, const QSizeF& size, DockWidgetArea DockWidgetArea, - CDockOverlay::eMode Mode) -{ - QColor borderColor = pal.color(QPalette::Active, QPalette::Highlight); - QColor backgroundColor = pal.color(QPalette::Active, QPalette::Base); - - QPixmap pm(size.width(), size.height()); - pm.fill(QColor(0, 0, 0, 0)); - - QPainter p(&pm); - QPen pen = p.pen(); - QRectF ShadowRect(pm.rect()); - QRectF baseRect; - baseRect.setSize(ShadowRect.size() * 0.7); - baseRect.moveCenter(ShadowRect.center()); - - // Fill - p.fillRect(ShadowRect, QColor(0, 0, 0, 64)); - - // Drop area rect. - p.save(); - QRectF areaRect; - QLineF areaLine; - QRectF nonAreaRect; - switch (DockWidgetArea) - { - case TopDockWidgetArea: - areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f); - nonAreaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f); - areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight()); - break; - case RightDockWidgetArea: - areaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height()); - nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height()); - areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft()); - break; - case BottomDockWidgetArea: - areaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f); - nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f); - areaLine = QLineF(areaRect.topLeft(), areaRect.topRight()); - break; - case LeftDockWidgetArea: - areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height()); - nonAreaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height()); - areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight()); - break; - default: - break; - } - - QSizeF baseSize = baseRect.size(); - if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea) - { - baseRect = areaRect; - } - - p.fillRect(baseRect, backgroundColor); - if (areaRect.isValid()) - { - pen = p.pen(); - pen.setColor(borderColor); - QColor Color = borderColor; - Color.setAlpha(64); - p.setBrush(Color); - p.setPen(Qt::NoPen); - p.drawRect(areaRect); - - pen = p.pen(); - pen.setColor(borderColor); - pen.setStyle(Qt::DashLine); - p.setPen(pen); - p.drawLine(areaLine); - } - p.restore(); - - p.save(); - // Draw outer border - pen = p.pen(); - pen.setColor(borderColor); - pen.setWidth(1); - p.setBrush(Qt::NoBrush); - p.setPen(pen); - p.drawRect(baseRect); - - // draw window title bar - p.setBrush(borderColor); - QRectF FrameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10)); - p.drawRect(FrameRect); - p.restore(); - - // Draw arrow for outer container drop indicators - if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea) - { - QRectF ArrowRect; - ArrowRect.setSize(baseSize); - ArrowRect.setWidth(ArrowRect.width() / 4.6); - ArrowRect.setHeight(ArrowRect.height() / 2); - ArrowRect.moveCenter(QPointF(0, 0)); - QPolygonF Arrow; - Arrow << ArrowRect.topLeft() - << QPointF( ArrowRect.right(), ArrowRect.center().y()) - << ArrowRect.bottomLeft(); - p.setPen(Qt::NoPen); - p.setBrush(backgroundColor); - p.setRenderHint(QPainter::Antialiasing, true); - p.translate(nonAreaRect.center().x(), nonAreaRect.center().y()); - - switch (DockWidgetArea) - { - case TopDockWidgetArea: - p.rotate(-90); - break; - case RightDockWidgetArea: - break; - case BottomDockWidgetArea: - p.rotate(90); - break; - case LeftDockWidgetArea: - p.rotate(180); - break; - default: - break; - } - - p.drawPolygon(Arrow); - } - - return pm; -} - - -//============================================================================ -QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea, - CDockOverlay::eMode Mode) -{ - QLabel* l = new QLabel(); - l->setObjectName("DockWidgetAreaLabel"); - - const qreal metric = static_cast(l->fontMetrics().height()) * 3.f; - const QSizeF size(metric, metric); - - l->setPixmap(createDropIndicatorPixmap(l->palette(), size, DockWidgetArea, - Mode)); - l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); - l->setAttribute(Qt::WA_TranslucentBackground); - return l; -} - /** * Private data class of CDockOverlay @@ -219,6 +73,8 @@ struct DockOverlayCrossPrivate CDockOverlay* DockOverlay; QHash DropIndicatorWidgets; QGridLayout* GridLayout; + QColor IconColors[5]; + bool UpdateRequired = false; /** * Private data constructor @@ -231,6 +87,206 @@ struct DockOverlayCrossPrivate * @return */ QPoint areaGridPosition(const DockWidgetArea area); + + + /** + * Palette based default icon colors + */ + QColor defaultIconColor(CDockOverlayCross::eIconColor ColorIndex) + { + QPalette pal = _this->palette(); + switch (ColorIndex) + { + case CDockOverlayCross::FrameColor: return pal.color(QPalette::Active, QPalette::Highlight); + case CDockOverlayCross::WindowBackgroundColor: return pal.color(QPalette::Active, QPalette::Base); + case CDockOverlayCross::OverlayColor: + { + QColor Color = pal.color(QPalette::Active, QPalette::Highlight); + Color.setAlpha(64); + return Color; + } + break; + + case CDockOverlayCross::ArrowColor: return pal.color(QPalette::Active, QPalette::Base); + case CDockOverlayCross::ShadowColor: return QColor(0, 0, 0, 64); + default: + return QColor(); + } + + return QColor(); + } + + /** + * Stylehseet based icon colors + */ + QColor iconColor(CDockOverlayCross::eIconColor ColorIndex) + { + QColor Color = IconColors[ColorIndex]; + if (!Color.isValid()) + { + Color = defaultIconColor(ColorIndex); + IconColors[ColorIndex] = Color; + } + return Color; + } + + + //============================================================================ + QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea, + CDockOverlay::eMode Mode) + { + QLabel* l = new QLabel(); + l->setObjectName("DockWidgetAreaLabel"); + + const qreal metric = static_cast(l->fontMetrics().height()) * 3.f; + const QSizeF size(metric, metric); + + l->setPixmap(createDropIndicatorPixmap(size, DockWidgetArea, Mode)); + l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + l->setAttribute(Qt::WA_TranslucentBackground); + return l; + } + + + //============================================================================ + QPixmap createDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea, + CDockOverlay::eMode Mode) + { + QColor borderColor = iconColor(CDockOverlayCross::FrameColor); + QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor); + + QPixmap pm(size.width(), size.height()); + pm.fill(QColor(0, 0, 0, 0)); + + QPainter p(&pm); + QPen pen = p.pen(); + QRectF ShadowRect(pm.rect()); + QRectF baseRect; + baseRect.setSize(ShadowRect.size() * 0.7); + baseRect.moveCenter(ShadowRect.center()); + + // Fill + QColor ShadowColor = iconColor(CDockOverlayCross::ShadowColor); + if (ShadowColor.alpha() == 255) + { + ShadowColor.setAlpha(64); + } + p.fillRect(ShadowRect, ShadowColor); + + // Drop area rect. + p.save(); + QRectF areaRect; + QLineF areaLine; + QRectF nonAreaRect; + switch (DockWidgetArea) + { + case TopDockWidgetArea: + areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f); + nonAreaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f); + areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight()); + break; + case RightDockWidgetArea: + areaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height()); + nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height()); + areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft()); + break; + case BottomDockWidgetArea: + areaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f); + nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f); + areaLine = QLineF(areaRect.topLeft(), areaRect.topRight()); + break; + case LeftDockWidgetArea: + areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height()); + nonAreaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height()); + areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight()); + break; + default: + break; + } + + QSizeF baseSize = baseRect.size(); + if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea) + { + baseRect = areaRect; + } + + p.fillRect(baseRect, backgroundColor); + if (areaRect.isValid()) + { + pen = p.pen(); + pen.setColor(borderColor); + QColor Color = iconColor(CDockOverlayCross::OverlayColor); + if (Color.alpha() == 255) + { + Color.setAlpha(64); + } + p.setBrush(Color); + p.setPen(Qt::NoPen); + p.drawRect(areaRect); + + pen = p.pen(); + pen.setColor(borderColor); + pen.setStyle(Qt::DashLine); + p.setPen(pen); + p.drawLine(areaLine); + } + p.restore(); + + p.save(); + // Draw outer border + pen = p.pen(); + pen.setColor(borderColor); + pen.setWidth(1); + p.setBrush(Qt::NoBrush); + p.setPen(pen); + p.drawRect(baseRect); + + // draw window title bar + p.setBrush(borderColor); + QRectF FrameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10)); + p.drawRect(FrameRect); + p.restore(); + + // Draw arrow for outer container drop indicators + if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea) + { + QRectF ArrowRect; + ArrowRect.setSize(baseSize); + ArrowRect.setWidth(ArrowRect.width() / 4.6); + ArrowRect.setHeight(ArrowRect.height() / 2); + ArrowRect.moveCenter(QPointF(0, 0)); + QPolygonF Arrow; + Arrow << ArrowRect.topLeft() + << QPointF( ArrowRect.right(), ArrowRect.center().y()) + << ArrowRect.bottomLeft(); + p.setPen(Qt::NoPen); + p.setBrush(iconColor(CDockOverlayCross::ArrowColor)); + p.setRenderHint(QPainter::Antialiasing, true); + p.translate(nonAreaRect.center().x(), nonAreaRect.center().y()); + + switch (DockWidgetArea) + { + case TopDockWidgetArea: + p.rotate(-90); + break; + case RightDockWidgetArea: + break; + case BottomDockWidgetArea: + p.rotate(90); + break; + case LeftDockWidgetArea: + p.rotate(180); + break; + default: + break; + } + + p.drawPolygon(Arrow); + } + + return pm; + } + }; @@ -247,7 +303,6 @@ CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) : setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); - d->Cross->setupOverlayCross(Mode); d->Cross->setVisible(false); setVisible(false); } @@ -405,6 +460,18 @@ void CDockOverlay::hideEvent(QHideEvent* e) } +//============================================================================ +bool CDockOverlay::event(QEvent *e) +{ + bool Result = Super::event(e); + if (e->type() == QEvent::Polish) + { + d->Cross->setupOverlayCross(d->Mode); + } + return Result; +} + + //============================================================================ static int areaAlignment(const DockWidgetArea area) { @@ -480,13 +547,29 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode) d->Mode = Mode; QHash areaWidgets; - areaWidgets.insert(TopDockWidgetArea, createDropIndicatorWidget(TopDockWidgetArea, Mode)); - areaWidgets.insert(RightDockWidgetArea, createDropIndicatorWidget(RightDockWidgetArea, Mode)); - areaWidgets.insert(BottomDockWidgetArea, createDropIndicatorWidget(BottomDockWidgetArea, Mode)); - areaWidgets.insert(LeftDockWidgetArea, createDropIndicatorWidget(LeftDockWidgetArea, Mode)); - areaWidgets.insert(CenterDockWidgetArea, createDropIndicatorWidget(CenterDockWidgetArea, Mode)); + areaWidgets.insert(TopDockWidgetArea, d->createDropIndicatorWidget(TopDockWidgetArea, Mode)); + areaWidgets.insert(RightDockWidgetArea, d->createDropIndicatorWidget(RightDockWidgetArea, Mode)); + areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode)); + areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode)); + areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode)); setAreaWidgets(areaWidgets); + d->UpdateRequired = false; +} + + +//============================================================================ +void CDockOverlayCross::setIconColor(eIconColor ColorIndex, const QColor& Color) +{ + d->IconColors[ColorIndex] = Color; + d->UpdateRequired = true; +} + + +//============================================================================ +QColor CDockOverlayCross::iconColor(eIconColor ColorIndex) const +{ + return d->IconColors[ColorIndex]; } @@ -573,6 +656,10 @@ DockWidgetArea CDockOverlayCross::cursorLocation() const //============================================================================ void CDockOverlayCross::showEvent(QShowEvent*) { + if (d->UpdateRequired) + { + setupOverlayCross(d->Mode); + } this->updatePosition(); } @@ -611,6 +698,38 @@ void CDockOverlayCross::reset() } +//============================================================================ +void CDockOverlayCross::setIconColors(const QString& Colors) +{ + static const QMap ColorCompenentStringMap{ + {"Frame", CDockOverlayCross::FrameColor}, + {"Background", CDockOverlayCross::WindowBackgroundColor}, + {"Overlay", CDockOverlayCross::OverlayColor}, + {"Arrow", CDockOverlayCross::ArrowColor}, + {"Shadow", CDockOverlayCross::ShadowColor}}; + + auto ColorList = Colors.split(' ', QString::SkipEmptyParts); + for (const auto& ColorListEntry : ColorList) + { + auto ComponentColor = ColorListEntry.split('=', QString::SkipEmptyParts); + int Component = ColorCompenentStringMap.value(ComponentColor[0], -1); + if (Component < 0) + { + continue; + } + d->IconColors[Component] = QColor(ComponentColor[1]); + } + + d->UpdateRequired = true; +} + +//============================================================================ +QString CDockOverlayCross::iconColors() const +{ + return QString(); +} + + } // namespace ads //---------------------------------------------------------------------------- diff --git a/src/DockOverlay.h b/src/DockOverlay.h index 4b19d48..e09d4d4 100644 --- a/src/DockOverlay.h +++ b/src/DockOverlay.h @@ -48,6 +48,8 @@ private: friend class DockOverlayCross; public: + using Super = QFrame; + enum eMode { ModeDockAreaOverlay, @@ -100,6 +102,11 @@ public: */ QRect dropOverlayRect() const; + /** + * Handle polish events + */ + virtual bool event(QEvent *e) override; + protected: virtual void paintEvent(QPaintEvent *e) override; virtual void showEvent(QShowEvent* e) override; @@ -112,18 +119,71 @@ struct DockOverlayCrossPrivate; * DockOverlayCross shows a cross with 5 different drop area possibilities. * I could have handled everything inside DockOverlay, but because of some * styling issues it's better to have a separate class for the cross. + * You can style the cross icon using the property system. + * \code + * ads--CDockOverlayCross + { + qproperty-iconFrameColor: palette(highlight); + qproperty-iconBackgroundColor: palette(base); + qproperty-iconOverlayColor: palette(highlight); + qproperty-iconArrowColor: rgb(227, 227, 227); + qproperty-iconShadowColor: rgb(0, 0, 0); + } + * \endcode + * Or you can use the iconColors property to pass in AARRGGBB values as + * hex string like shown in the example below. + * \code + * ads--CDockOverlayCross + * { + * qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747"; + * } + * \endcode */ class CDockOverlayCross : public QWidget { Q_OBJECT + Q_PROPERTY(QString iconColors READ iconColors WRITE setIconColors) + Q_PROPERTY(QColor iconFrameColor READ iconColor WRITE setIconFrameColor) + Q_PROPERTY(QColor iconBackgroundColor READ iconColor WRITE setIconBackgroundColor) + Q_PROPERTY(QColor iconOverlayColor READ iconColor WRITE setIconOverlayColor) + Q_PROPERTY(QColor iconArrowColor READ iconColor WRITE setIconArrowColor) + Q_PROPERTY(QColor iconShadowColor READ iconColor WRITE setIconShadowColor) + +public: + enum eIconColor + { + FrameColor,///< the color of the frame of the small window icon + WindowBackgroundColor,///< the background color of the small window in the icon + OverlayColor,///< the color that shows the overlay (the dock side) in the icon + ArrowColor,///< the arrow that points into the direction + ShadowColor///< the color of the shadow rectangle that is painted below the icons + }; + private: DockOverlayCrossPrivate* d; friend struct DockOverlayCrossPrivate; friend class CDockOverlay; +protected: + /** + * This function returns an empty string and is only here to silence + * moc + */ + QString iconColors() const; + + /** + * This is a dummy function for the property system + */ + QColor iconColor() const {return QColor();} + void setIconFrameColor(const QColor& Color) {setIconColor(FrameColor, Color);} + void setIconBackgroundColor(const QColor& Color) {setIconColor(WindowBackgroundColor, Color);} + void setIconOverlayColor(const QColor& Color) {setIconColor(OverlayColor, Color);} + void setIconArrowColor(const QColor& Color) {setIconColor(ArrowColor, Color);} + void setIconShadowColor(const QColor& Color) {setIconColor(ShadowColor, Color);} + public: /** - * Creates an overlay corss for the given overlay + * Creates an overlay cross for the given overlay */ CDockOverlayCross(CDockOverlay* overlay); @@ -132,6 +192,16 @@ public: */ virtual ~CDockOverlayCross(); + /** + * Sets a certain icon color + */ + void setIconColor(eIconColor ColorIndex, const QColor& Color); + + /** + * Returns the icon color given by ColorIndex + */ + QColor iconColor(eIconColor ColorIndex) const; + /** * Returns the dock widget area depending on the current cursor location. * The function checks, if the mouse cursor is inside of any drop indicator @@ -154,6 +224,19 @@ public: */ void updatePosition(); + /** + * A string with all icon colors to set. + * You can use this property to style the overly icon via CSS stylesheet + * file. The colors are set via a color identifier and a hex AARRGGBB value like + * in the example below. + * \code + * ads--CDockOverlayCross + * { + * qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747"; + * } + */ + void setIconColors(const QString& Colors); + protected: virtual void showEvent(QShowEvent* e) override; void setAreaWidgets(const QHash& widgets); diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 6c2f5a9..51eed38 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -367,8 +367,16 @@ bool CFloatingDockContainer::event(QEvent *e) else if (d->NonClientAreaMouseButtonPress && (e->type() == QEvent::Resize)) { // If user resizes the floating widget, we do not want to show any - // drop overlays or drop overlay icons - d->setDraggingActive(false); + // drop overlays or drop overlay icons. If the window is maximized, + // then dragging the window via title bar will cause the widget to + // leave the maximized state. This in turn will trigger a resize event. + // To know, if the resize event was triggered by user via moving a + // corner of the window frame or if it was caused by a windows state + // change, we check, if we are not in maximized state. + if (!isMaximized()) + { + d->setDraggingActive(false); + } } return QWidget::event(e);