KoDockWidgetTitleBar.cpp 12.3 KB
Newer Older
1
/* This file is part of the KDE project
Marijn Kruisselbrink's avatar
Marijn Kruisselbrink committed
2
   Copyright (c) 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3
   Copyright (C) 2007 Thomas Zander <zander@kde.org>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/
20

21
#include "KoDockWidgetTitleBar.h"
22
#include "KoDockWidgetTitleBar_p.h"
23
#include "KoDockWidgetTitleBarButton.h"
24

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
25 26
#include <KoIcon.h>

27
#include <kdebug.h>
28
#include <klocale.h>
29 30 31 32 33

#include <QAbstractButton>
#include <QAction>
#include <QLabel>
#include <QLayout>
34
#include <QStyle>
35 36 37 38 39 40 41 42 43
#include <QStylePainter>
#include <QStyleOptionFrame>

static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
{
    return (dockwidget->features() & feature) == feature;
}

KoDockWidgetTitleBar::KoDockWidgetTitleBar(QDockWidget* dockWidget)
44 45
        : QWidget(dockWidget), d(new Private(this))
{
46 47
    QDockWidget *q = dockWidget;

48
    d->floatIcon = themedIcon("docker_float");
49
    d->floatButton = new KoDockWidgetTitleBarButton(this);
50
    d->floatButton->setIcon(d->floatIcon);
51 52
    connect(d->floatButton, SIGNAL(clicked()), SLOT(toggleFloating()));
    d->floatButton->setVisible(true);
53
    d->floatButton->setToolTip(i18nc("@info:tooltip", "Float Docker"));
54 55
    d->floatButton->setStyleSheet("border: 0");

56
    d->removeIcon = themedIcon("docker_close");
57
    d->closeButton = new KoDockWidgetTitleBarButton(this);
58
    d->closeButton->setIcon(d->removeIcon);
59 60
    connect(d->closeButton, SIGNAL(clicked()), q, SLOT(close()));
    d->closeButton->setVisible(true);
61 62 63
    d->closeButton->setToolTip(i18nc("@info:tooltip", "Close Docker"));   
    d->closeButton->setStyleSheet("border: 0"); // border makes the header busy looking (appears on some OSs)

64 65
    d->openIcon = themedIcon("docker_collapse_a");
    d->closeIcon = themedIcon("docker_collapsed_b");
66 67 68
    d->collapseButton = new KoDockWidgetTitleBarButton(this);
    d->collapseButton->setIcon(d->openIcon);
    connect(d->collapseButton, SIGNAL(clicked()), SLOT(toggleCollapsed()));
69 70
    d->collapseButton->setVisible(true);
    d->collapsable = true;
71
    d->collapseButton->setToolTip(i18nc("@info:tooltip", "Collapse Docker"));
72 73
    d->collapseButton->setStyleSheet("border: 0");

Timothée Giet's avatar
Timothée Giet committed
74
    d->lockIcon = themedIcon("docker_lock_b");
75
    d->lockButton = new KoDockWidgetTitleBarButton(this);
76
    d->lockButton->setCheckable(true);
77
    d->lockButton->setIcon(d->lockIcon);
78
    connect(d->lockButton, SIGNAL(toggled(bool)), SLOT(setLocked(bool)));
79
    d->lockButton->setVisible(true);
80
    d->lockable = true;
81
    d->lockButton->setToolTip(i18nc("@info:tooltip", "Lock Docker"));
82
    d->lockButton->setStyleSheet("border: 0");
83

84
    connect(dockWidget, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), SLOT(featuresChanged(QDockWidget::DockWidgetFeatures)));
85
    connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(topLevelChanged(bool)));
86

87
    d->featuresChanged(0);
88 89 90 91 92 93 94 95 96 97 98 99 100 101
}

KoDockWidgetTitleBar::~KoDockWidgetTitleBar()
{
    delete d;
}

QSize KoDockWidgetTitleBar::minimumSizeHint() const
{
    return sizeHint();
}

QSize KoDockWidgetTitleBar::sizeHint() const
{
102 103 104 105
    if (isHidden()) {
        return QSize(0, 0);
    }

106 107 108 109 110 111 112
    QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());

    int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
    int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);

    // get size of buttons...
    QSize closeSize(0, 0);
113
    if (d->closeButton && hasFeature(q, QDockWidget::DockWidgetClosable)) {
114 115
        closeSize = d->closeButton->sizeHint();
    }
116

117
    QSize floatSize(0, 0);
118
    if (d->floatButton && hasFeature(q, QDockWidget::DockWidgetFloatable)) {
119 120
        floatSize = d->floatButton->sizeHint();
    }
121

122
    QSize hideSize(0, 0);
123
    if (d->collapseButton && d->collapsable) {
124 125
        hideSize = d->collapseButton->sizeHint();
    }
126

127
    QSize lockSize(0, 0);
128 129
    if (d->lockButton && d->lockable) {
        lockSize = d->lockButton->sizeHint();
130
    }
131

132 133
    int buttonHeight = qMax(qMax(qMax(closeSize.height(), floatSize.height()), hideSize.height()), lockSize.height()) + 2;
    int buttonWidth = closeSize.width() + floatSize.width() + hideSize.width() + lockSize.width();
134

135
    int height = buttonHeight;
136
    if (d->textVisibilityMode == FullTextAlwaysVisible) {
137 138 139
        // get font size
        QFontMetrics titleFontMetrics = q->fontMetrics();
        int fontHeight = titleFontMetrics.lineSpacing() + 2 * mw;
140

141 142
        height = qMax(height, fontHeight);
    }
143 144

    /*
Boudewijn Rempt's avatar
Boudewijn Rempt committed
145
     * Calculate the width of title and add to the total width of the docker window when collapsed.
146
     */
147 148 149
    const int titleWidth =
        (d->textVisibilityMode == FullTextAlwaysVisible) ? (q->fontMetrics().width(q->windowTitle()) + 2*mw) :
                                                           0;
150

151 152 153 154
    if (d->preCollapsedWidth > 0) {
        return QSize(d->preCollapsedWidth, height);
    }
    else {
155 156 157 158
        if (d->textVisibilityMode == FullTextAlwaysVisible) {
            return QSize(buttonWidth /*+ height*/ + 2*mw + 2*fw + titleWidth, height);
        }
        else {
159 160 161 162 163 164
            if (q->widget()) {
                return QSize(qMin(q->widget()->sizeHint().width(), buttonWidth), height);
            }
            else {
                return QSize(buttonWidth, height);
            }
165
        }
166
    }
167 168 169 170 171 172 173 174 175 176 177
}

void KoDockWidgetTitleBar::paintEvent(QPaintEvent*)
{
    QStylePainter p(this);

    QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());

    int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0;
    int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);

178 179
    QStyleOptionDockWidgetV2 titleOpt;
    titleOpt.initFrom(q);
180

181
    QSize collapseButtonSize(0,0);
182
    if (d->collapsable) {
183
        collapseButtonSize = d->collapseButton->size();
184
    }
185

186
    QSize lockButtonSize(0,0);
187
    if (d->lockable) {
188 189 190 191 192
        lockButtonSize = d->lockButton->size();
    }

    titleOpt.rect = QRect(QPoint(fw + mw + collapseButtonSize.width() + lockButtonSize.width(), 0),
                          QSize(geometry().width() - (fw * 2) -  mw - collapseButtonSize.width() - lockButtonSize.width(), geometry().height()));
193 194 195 196
    titleOpt.title = q->windowTitle();
    titleOpt.closable = hasFeature(q, QDockWidget::DockWidgetClosable);
    titleOpt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable);
    p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
197 198 199 200 201
}

void KoDockWidgetTitleBar::resizeEvent(QResizeEvent*)
{
    QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
202

203
    int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0;
204

205 206 207 208 209 210
    QStyleOptionDockWidgetV2 opt;
    opt.initFrom(q);
    opt.rect = QRect(QPoint(fw, fw), QSize(geometry().width() - (fw * 2), geometry().height() - (fw * 2)));
    opt.title = q->windowTitle();
    opt.closable = hasFeature(q, QDockWidget::DockWidgetClosable);
    opt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable);
211

212 213 214
    QRect floatRect = q->style()->subElementRect(QStyle::SE_DockWidgetFloatButton, &opt, q);
    if (!floatRect.isNull())
        d->floatButton->setGeometry(floatRect);
215

216 217 218
    QRect closeRect = q->style()->subElementRect(QStyle::SE_DockWidgetCloseButton, &opt, q);
    if (!closeRect.isNull())
        d->closeButton->setGeometry(closeRect);
219

220
    int top = fw;
221 222 223 224
    if (!floatRect.isNull())
        top = floatRect.y();
    else if (!closeRect.isNull())
        top = closeRect.y();
225

226 227 228 229 230 231 232
    QSize size = d->collapseButton->size();
    if (!closeRect.isNull()) {
        size = d->closeButton->size();
    } else if (!floatRect.isNull()) {
        size = d->floatButton->size();
    }
    QRect collapseRect = QRect(QPoint(fw, top), size);
233
    d->collapseButton->setGeometry(collapseRect);
234 235

    size = d->lockButton->size();
236

237 238 239 240 241
    if (!closeRect.isNull()) {
        size = d->closeButton->size();
    } else if (!floatRect.isNull()) {
        size = d->floatButton->size();
    }
242

243
    int offset = 0;
244 245

    if (d->collapsable) {
246 247 248 249 250
        offset = collapseRect.width();
    }
    QRect lockRect = QRect(QPoint(fw + 2 + offset, top), size);
    d->lockButton->setGeometry(lockRect);

251
    if (width() < (closeRect.width() + lockRect.width()) + 50) {
252 253
        d->collapsable = false;
        d->collapseButton->setVisible(false);
254
        d->lockButton->setVisible(false);
255
        d->lockable = false;
256
    } else {
257 258
        d->collapsable = d->collapsableSet;
        d->collapseButton->setVisible(true);
259
        d->lockButton->setVisible(true);
260
        d->lockable = true;
261
    }
262 263
}

264 265 266
void KoDockWidgetTitleBar::setCollapsed(bool collapsed)
{
    QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
267
    if (q && q->widget() && q->widget()->isHidden() != collapsed)
268 269 270
        d->toggleCollapsed();
}

271 272 273 274
void KoDockWidgetTitleBar::setLocked(bool locked)
{
    QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    d->locked = locked;
    d->lockButton->blockSignals(true);
    d->lockButton->setChecked(locked);
    d->lockButton->blockSignals(false);

    //qDebug() << "setlocked" << q << d->locked << locked;

    if (locked) {
        d->features = q->features();
        q->setFeatures(QDockWidget::NoDockWidgetFeatures);
    }
    else {
        q->setFeatures(d->features);
    }

290 291 292 293 294
    q->toggleViewAction()->setEnabled(!locked);
    d->closeButton->setEnabled(!locked);
    d->floatButton->setEnabled(!locked);
    d->collapseButton->setEnabled(!locked);

295 296 297
    d->updateIcons();
    q->setProperty("Locked", locked);
    resizeEvent(0);
298 299 300
}


301 302
void KoDockWidgetTitleBar::setCollapsable(bool collapsable)
{
303
    d->collapsableSet = collapsable;
304
    d->collapsable = collapsable;
305 306 307
    d->collapseButton->setVisible(collapsable);
}

308 309 310 311 312
void KoDockWidgetTitleBar::setTextVisibilityMode(TextVisibilityMode textVisibilityMode)
{
    d->textVisibilityMode = textVisibilityMode;
}

313 314 315 316 317
void KoDockWidgetTitleBar::updateIcons()
{
    d->updateIcons();
}

318 319 320 321 322 323 324
void KoDockWidgetTitleBar::Private::toggleFloating()
{
    QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());

    q->setFloating(!q->isFloating());
}

325 326 327 328 329
void KoDockWidgetTitleBar::Private::topLevelChanged(bool topLevel)
{
    lockButton->setEnabled(!topLevel);
}

330 331 332
void KoDockWidgetTitleBar::Private::toggleCollapsed()
{
    QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
333 334
    if (q == 0) // there does not *have* to be anything on the dockwidget.
        return;
335 336

    preCollapsedWidth = q->widget()->isHidden() ? -1 : thePublic->width();
337
    q->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // will be overwritten again next
338 339
    if (q->widget()) {
        q->widget()->setVisible(q->widget()->isHidden());
340
        collapseButton->setIcon(q->widget()->isHidden() ? themedIcon("docker_collapse_b") : themedIcon("docker_collapse_a"));
341
    }
342 343 344 345
}

void KoDockWidgetTitleBar::Private::featuresChanged(QDockWidget::DockWidgetFeatures)
{
346
    QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
347

348 349
    closeButton->setVisible(hasFeature(q, QDockWidget::DockWidgetClosable));
    floatButton->setVisible(hasFeature(q, QDockWidget::DockWidgetFloatable));
350

351 352
    thePublic->resizeEvent(0);
}
353

354

355
void KoDockWidgetTitleBar::Private::updateIcons()
356
{    
357 358
    QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());

359
    lockIcon = (!locked) ? themedIcon("docker_lock_a", true) : themedIcon("docker_lock_b", true);
360
    lockButton->setIcon(lockIcon);
361 362

    // this method gets called when switching themes, so update all of the themed icons now
363 364
   floatButton->setIcon(themedIcon("docker_float", true));
   closeButton->setIcon(themedIcon("docker_close", true));
365

366 367 368
    if (q->widget()) {
        collapseButton->setIcon(q->widget()->isHidden() ? themedIcon("docker_collapse_b") : themedIcon("docker_collapse_a"));
    }
369
    thePublic->resizeEvent(0);
370

371 372 373
}


Thomas Zander's avatar
Thomas Zander committed
374
#include <KoDockWidgetTitleBar.moc>