/**
 * KStyle for KDE4
 * Copyright (C) 2004-2005 Maksim Orlovich <maksim@kde.org>
 * Copyright (C) 2005,2006 Sandro Giessl <giessl@kde.org>
 *
 * Based in part on the following software:
 *  KStyle for KDE3
 *      Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
 *      Portions  (C) 1998-2000 TrollTech AS
 *  Keramik for KDE3,
 *      Copyright (C) 2002      Malte Starostik   <malte@kde.org>
 *                (C) 2002-2003 Maksim Orlovich  <maksim@kde.org>
 *      Portions  (C) 2001-2002 Karol Szwed     <gallium@kde.org>
 *                (C) 2001-2002 Fredrik Höglund <fredrik@kde.org>
 *                (C) 2000 Daniel M. Duley       <mosfet@kde.org>
 *                (C) 2000 Dirk Mueller         <mueller@kde.org>
 *                (C) 2001 Martijn Klingens    <klingens@kde.org>
 *                (C) 2003 Sandro Giessl      <sandro@giessl.com>
 *  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.
 *
 * Many thanks to Bradley T. Hughes for the 3 button scrollbar code.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License version 2 as published by the Free Software Foundation.
 *
 * 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.
 */

#include "k4style.h"

#include <qalgorithms.h>
#include <QCache>
#include <QEvent>
#include <QVariant>
#include <QAbstractItemView>
#include <QApplication>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QIcon>
#include <QLabel>
#include <QKeyEvent>
#include <QPainter>
#include <QScrollBar>
#include <QStyleOption>

#include <kconfiggroup.h>
#include <QDebug>
#include <kiconloader.h>
#include <kcolorscheme.h>

//### FIXME: Who to credit these to?
static const qint32 u_arrow[] = { -1, -3, 0, -3, -2, -2, 1, -2, -3, -1, 2, -1, -4, 0, 3, 0, -4, 1, 3, 1};
static const qint32 d_arrow[] = { -4, -2, 3, -2, -4, -1, 3, -1, -3, 0, 2, 0, -2, 1, 1, 1, -1, 2, 0, 2};
static const qint32 l_arrow[] = { -3, -1, -3, 0, -2, -2, -2, 1, -1, -3, -1, 2, 0, -4, 0, 3, 1, -4, 1, 3};
static const qint32 r_arrow[] = { -2, -4, -2, 3, -1, -4, -1, 3, 0, -3, 0, 2, 1, -2, 1, 1, 2, -1, 2, 0};
#define QCOORDARRLEN(x) sizeof(x)/(sizeof(qint32)*2)

/**
 TODO: lots of missing widgets, SH_ settings, etc.

 Minor stuff:
    ProgressBar::Precision handling
*/

// ----------------------------------------------------------------------------

// For item view selections
struct SelectionTiles {
    QPixmap left, center, right;
};

// ----------------------------------------------------------------------------

static const QStyle::StyleHint SH_KCustomStyleElement = (QStyle::StyleHint)0xff000001;
static const int X_KdeBase = 0xff000000;

class K4StylePrivate
{
public:
    K4StylePrivate();
    QCache<quint64, SelectionTiles> selectionCache;

    QHash<QString, int> styleElements;
    int hintCounter, controlCounter, subElementCounter;
};

K4StylePrivate::K4StylePrivate()
{
    selectionCache.setMaxCost(10);
    controlCounter = subElementCounter = X_KdeBase;
    hintCounter = X_KdeBase + 1; //sic! X_KdeBase is covered by SH_KCustomStyleElement
}

// ----------------------------------------------------------------------------

K4Style::K4Style() : clickedLabel(nullptr), d(new K4StylePrivate)
{
    //Set up some default metrics...
    setWidgetLayoutProp(WT_Generic, Generic::DefaultFrameWidth, 2);
    setWidgetLayoutProp(WT_Generic, Generic::DefaultLayoutSpacing, 6);
    setWidgetLayoutProp(WT_Generic, Generic::DefaultLayoutMargin, 9);

    setWidgetLayoutProp(WT_PushButton, PushButton::ContentsMargin, 5);
    setWidgetLayoutProp(WT_PushButton, PushButton::FocusMargin,    3);
    setWidgetLayoutProp(WT_PushButton, PushButton::PressedShiftHorizontal, 2);
    setWidgetLayoutProp(WT_PushButton, PushButton::PressedShiftVertical,   2);
    setWidgetLayoutProp(WT_PushButton, PushButton::MenuIndicatorSize,      8);
    setWidgetLayoutProp(WT_PushButton, PushButton::TextToIconSpace,        6);

    setWidgetLayoutProp(WT_Splitter, Splitter::Width, 6); //As KStyle in KDE3

    setWidgetLayoutProp(WT_CheckBox, CheckBox::Size, 16);
    setWidgetLayoutProp(WT_CheckBox, CheckBox::BoxTextSpace, 6);
    setWidgetLayoutProp(WT_CheckBox, CheckBox::NoLabelFocusMargin, 1);

    setWidgetLayoutProp(WT_RadioButton, RadioButton::Size, 16);
    setWidgetLayoutProp(WT_RadioButton, RadioButton::BoxTextSpace, 6);

    setWidgetLayoutProp(WT_DockWidget, DockWidget::TitleTextColor,
                        ColorMode(QPalette::HighlightedText));
    setWidgetLayoutProp(WT_DockWidget, DockWidget::TitleMargin, 2);
    setWidgetLayoutProp(WT_DockWidget, DockWidget::FrameWidth, 3);
    setWidgetLayoutProp(WT_DockWidget, DockWidget::SeparatorExtent, 6);

    setWidgetLayoutProp(WT_ProgressBar, ProgressBar::GrooveMargin,  2);
    setWidgetLayoutProp(WT_ProgressBar, ProgressBar::SideTextSpace, 3); //(Matches QCommonStyle)
    setWidgetLayoutProp(WT_ProgressBar, ProgressBar::MaxBusyIndicatorSize, 10000);
    setWidgetLayoutProp(WT_ProgressBar, ProgressBar::BusyIndicatorSize,    10);
    setWidgetLayoutProp(WT_ProgressBar, ProgressBar::Precision,            1);

    setWidgetLayoutProp(WT_MenuBar, MenuBar::ItemSpacing,   14);
    setWidgetLayoutProp(WT_MenuBar, MenuBar::Margin,        2);
    setWidgetLayoutProp(WT_MenuBar, MenuBar::Margin + Left,  4);
    setWidgetLayoutProp(WT_MenuBar, MenuBar::Margin + Right, 4);

    setWidgetLayoutProp(WT_MenuBarItem, MenuBarItem::Margin, 1);

    setWidgetLayoutProp(WT_Menu, Menu::FrameWidth, 1);
    setWidgetLayoutProp(WT_Menu, Menu::Margin,     3);
    setWidgetLayoutProp(WT_Menu, Menu::ScrollerHeight, 10);
    setWidgetLayoutProp(WT_Menu, Menu::TearOffHeight, 10);

    setWidgetLayoutProp(WT_MenuItem, MenuItem::CheckWidth, 12);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::CheckSpace, 3);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::IconWidth, 12);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::IconSpace, 3);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::ArrowWidth, 11);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::ArrowSpace, 3);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::Margin,     2);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::SeparatorHeight, 0); //the margins give enough rooms
    setWidgetLayoutProp(WT_MenuItem, MenuItem::MinHeight,  16);
    setWidgetLayoutProp(WT_MenuItem, MenuItem::TextColor, ColorMode(QPalette::Text));
    setWidgetLayoutProp(WT_MenuItem, MenuItem::ActiveTextColor, ColorMode(QPalette::HighlightedText));
    setWidgetLayoutProp(WT_MenuItem, MenuItem::DisabledTextColor,       ColorMode(QPalette::Text));
    setWidgetLayoutProp(WT_MenuItem, MenuItem::ActiveDisabledTextColor, ColorMode(QPalette::Text));
    setWidgetLayoutProp(WT_MenuItem, MenuItem::AccelSpace, 16);

    //KDE default is single top button, double bottom one
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleTopButton, 0);
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleBotButton, 1);
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::SingleButtonHeight, 16);
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleButtonHeight, 32);
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::BarWidth, 16);
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor,
                        ColorMode(ColorMode::BWAutoContrastMode, QPalette::Button));
    setWidgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor,
                        ColorMode(ColorMode::BWAutoContrastMode, QPalette::ButtonText));

    setWidgetLayoutProp(WT_TabBar, TabBar::TabContentsMargin, 6);
    setWidgetLayoutProp(WT_TabBar, TabBar::TabFocusMargin, 3);
    setWidgetLayoutProp(WT_TabBar, TabBar::TabOverlap, 0);
    setWidgetLayoutProp(WT_TabBar, TabBar::BaseHeight, 2);
    setWidgetLayoutProp(WT_TabBar, TabBar::BaseOverlap, 2);
    setWidgetLayoutProp(WT_TabBar, TabBar::ScrollButtonWidth, 10);
    setWidgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, 6);

    setWidgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin, 2);

    setWidgetLayoutProp(WT_Tree, Tree::MaxExpanderSize, 9);

    setWidgetLayoutProp(WT_Slider, Slider::HandleThickness, 20);
    setWidgetLayoutProp(WT_Slider, Slider::HandleLength, 16);

    setWidgetLayoutProp(WT_SpinBox, SpinBox::FrameWidth, 1);
    setWidgetLayoutProp(WT_SpinBox, SpinBox::ButtonWidth, 16);
    setWidgetLayoutProp(WT_SpinBox, SpinBox::ButtonSpacing, 1);
    setWidgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Right, 1);
    setWidgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Top, 1);
    setWidgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Bot, 1);

    setWidgetLayoutProp(WT_ComboBox, ComboBox::FrameWidth, 1);
    setWidgetLayoutProp(WT_ComboBox, ComboBox::ButtonWidth, 16);
    setWidgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Right, 1);
    setWidgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Top, 1);
    setWidgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Bot, 1);
    setWidgetLayoutProp(WT_ComboBox, ComboBox::FocusMargin, 1);

    setWidgetLayoutProp(WT_Header, Header::ContentsMargin, 3);
    setWidgetLayoutProp(WT_Header, Header::TextToIconSpace, 3);
    setWidgetLayoutProp(WT_Header, Header::MarkSize, 9);

    setWidgetLayoutProp(WT_GroupBox, GroupBox::FrameWidth, 2);
    setWidgetLayoutProp(WT_GroupBox, GroupBox::TextAlignTop, false);
    setWidgetLayoutProp(WT_GroupBox, GroupBox::TitleTextColor, ColorMode(QPalette::Text));

    setWidgetLayoutProp(WT_ToolBar, ToolBar::HandleExtent, 6);
    setWidgetLayoutProp(WT_ToolBar, ToolBar::SeparatorExtent, 6);
    setWidgetLayoutProp(WT_ToolBar, ToolBar::ExtensionExtent, 10);
    setWidgetLayoutProp(WT_ToolBar, ToolBar::FrameWidth, 2);
    setWidgetLayoutProp(WT_ToolBar, ToolBar::ItemSpacing, 3);
    setWidgetLayoutProp(WT_ToolBar, ToolBar::ItemMargin, 1);

    setWidgetLayoutProp(WT_ToolButton, ToolButton::ContentsMargin, 5);
    setWidgetLayoutProp(WT_ToolButton, ToolButton::FocusMargin,    3);
    setWidgetLayoutProp(WT_ToolButton, ToolButton::MenuIndicatorSize, 11);

    setWidgetLayoutProp(WT_ToolBoxTab, ToolBoxTab::Margin, 0);

    setWidgetLayoutProp(WT_Window, Window::TitleTextColor, ColorMode(QPalette::HighlightedText));
    setWidgetLayoutProp(WT_Window, Window::TitleHeight, 20);
    setWidgetLayoutProp(WT_Window, Window::TitleMargin, 2);
    setWidgetLayoutProp(WT_Window, Window::NoTitleFrame, 0);
    setWidgetLayoutProp(WT_Window, Window::ButtonWidth, 16);
    setWidgetLayoutProp(WT_Window, Window::ButtonSpace, 2);
    setWidgetLayoutProp(WT_Window, Window::ButtonToTextSpace, 3);
}

K4Style::~K4Style()
{
    // this is just for stupid msvc compiler to force the creation of
    // DoubleButtonOption::defaultOption() inside kstyle lib
    // hope the optimizer won't throw it away
    const DoubleButtonOption *bOpt = extractOption<const DoubleButtonOption *>(nullptr);
    Q_UNUSED(bOpt)
#ifdef __GNUC__
#warning "mem leak: need to delete bOpt"
#endif
    delete d;
}

/*
    Custom Style Element runtime extension:
    We reserve one StyleHint to let the effective style inform widgets whether it supports certain
    string based style elements.
    As this could lead to number conflicts (i.e. an app utilizing one of the hints itself for other
    purposes) there're various safety mechanisms to rule out such interference.

    1) It's most unlikely that a widget in some 3rd party app will accidentally call a general
    QStyle/K4Style styleHint() or draw*() and (unconditionally) expect a valid return, however:
    a. The StyleHint is not directly above Qt's custom base, assuming most 3rd party apps would
    - in case - make use of such
    b. In order to be accepted, the StyleHint query must pass a widget with a perfectly matching
    name, containing the typical element prefix ("CE_", etc.) and being supported by the current style
    c. Instead using Qt's fragile qstyleoption_cast on the QStyleOption provided to the StyleHint
    query, try to dump out a string and hope for the best, we now manipulate the widgets objectName().
    Plain Qt dependent widgets can do that themselves and if a widget uses K4Style's convenience access
    functions, it won't notice this at all

    2) The key problem is that a common KDE widget will run into an apps custom style which will then
    falsely respond to the styleHint() call with an invalid value.
    To prevent this, supporting styles *must* set a Q_CLASSINFO "X-KDE-CustomElements".

    3) If any of the above traps snaps, the returned id is 0 - the QStyle default, indicating
    that this element is not supported by the current style.

    Obviously, this contains the "diminished clean" action to (temporarily) manipulate the
    objectName() of a const QWidget* - but this happens completely inside K4Style or the widget, if
    it does not make use of K4Styles static convenience functions.
    My biggest worry here would be, that in a multithreaded environment a thread (usually not being
    owner of the widget) does something crucially relying on the widgets name property...
    This however would also have to happen during the widget construction or stylechanges, when
    the functions in doubt will typically be called.
    So this is imho unlikely causing any trouble, ever.
*/

/*
    The functions called by the real style implementation to add support for a certain element.
    Checks for well-formed string (containing the element prefix) and returns 0 otherwise.
    Checks whether the element is already supported or inserts it otherwise; Returns the proper id
    NOTICE: We could check for "X-KDE-CustomElements", but this would bloat style start up times
    (if they e.g. register 100 elements or so)
*/

static inline int newStyleElement(const QString &element, const char *check, int &counter, QHash<QString, int> *elements)
{
    if (!element.contains(check)) {
        return 0;
    }
    int id = elements->value(element, 0);
    if (!id) {
        ++counter;
        id = counter;
        elements->insert(element, id);
    }
    return id;
}

QStyle::StyleHint K4Style::newStyleHint(const QString &element)
{
    return (StyleHint)newStyleElement(element, "SH_", d->hintCounter, &d->styleElements);
}

QStyle::ControlElement K4Style::newControlElement(const QString &element)
{
    return (ControlElement)newStyleElement(element, "CE_", d->controlCounter, &d->styleElements);
}

K4Style::SubElement K4Style::newSubElement(const QString &element)
{
    return (SubElement)newStyleElement(element, "SE_", d->subElementCounter, &d->styleElements);
}

QString K4Style::defaultStyle()
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
    return QString("breeze");
#else
    return QString(); // native style
#endif
}

/*
    The functions called by widgets that request custom element support, passed to the effective style.
    Collected in a static inline function due to similarity.
*/

static inline int customStyleElement(QStyle::StyleHint type, const QString &element, QWidget *widget)
{
    if (!widget || widget->style()->metaObject()->indexOfClassInfo("X-KDE-CustomElements") < 0) {
        return 0;
    }

    const QString originalName = widget->objectName();
    widget->setObjectName(element);
    const int id = widget->style()->styleHint(type, nullptr, widget);
    widget->setObjectName(originalName);
    return id;
}

QStyle::StyleHint K4Style::customStyleHint(const QString &element, const QWidget *widget)
{
    return (StyleHint) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
}

QStyle::ControlElement K4Style::customControlElement(const QString &element, const QWidget *widget)
{
    return (ControlElement) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
}

QStyle::SubElement K4Style::customSubElement(const QString &element, const QWidget *widget)
{
    return (SubElement) customStyleElement(SH_KCustomStyleElement, element, const_cast<QWidget *>(widget));
}

void K4Style::polish(QWidget *w)
{
    if (qobject_cast<QLabel *>(w)) {
        w->installEventFilter(this);
    }

    // Enable hover effects in all itemviews
    if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(w)) {
        itemView->viewport()->setAttribute(Qt::WA_Hover);
    }

    QCommonStyle::polish(w);
}
void K4Style::unpolish(QWidget *w)
{
    if (qobject_cast<QLabel *>(w)) {
        w->removeEventFilter(this);
    }

    QCommonStyle::unpolish(w);
}
void K4Style::polish(QApplication *a)
{
    QCommonStyle::polish(a);
}
void K4Style::unpolish(QApplication *a)
{
    QCommonStyle::unpolish(a);
}
void K4Style::polish(QPalette &pal)
{
    QCommonStyle::polish(pal);
}
QRect K4Style::itemTextRect(const QFontMetrics &fm, const QRect &r,
                            int flags, bool enabled,
                            const QString &text) const
{
    return QCommonStyle::itemTextRect(fm, r, flags, enabled, text);
}
QRect K4Style::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const
{
    return QCommonStyle::itemPixmapRect(r, flags, pixmap);
}
void K4Style::drawItemText(QPainter *painter, const QRect &rect,
                           int flags, const QPalette &pal, bool enabled,
                           const QString &text, QPalette::ColorRole textRole) const
{
    QCommonStyle::drawItemText(painter, rect, flags, pal, enabled,
                               text, textRole);
}
void K4Style::drawItemPixmap(QPainter *painter, const QRect &rect,
                             int alignment, const QPixmap &pixmap) const
{
    QCommonStyle::drawItemPixmap(painter, rect, alignment, pixmap);
}
QPalette K4Style::standardPalette() const
{
    return KColorScheme::createApplicationPalette(KSharedConfig::openConfig());
}

QIcon K4Style::standardIcon(StandardPixmap standardIcon, const QStyleOption */*option*/,
                            const QWidget */*widget*/) const
{
    switch (standardIcon) {
    case QStyle::SP_DesktopIcon:
        return QIcon::fromTheme("user-desktop");
    case QStyle::SP_TrashIcon:
        return QIcon::fromTheme("user-trash");
    case QStyle::SP_ComputerIcon:
        return QIcon::fromTheme("computer");
    case QStyle::SP_DriveFDIcon:
        return QIcon::fromTheme("media-floppy");
    case QStyle::SP_DriveHDIcon:
        return QIcon::fromTheme("drive-harddisk");
    case QStyle::SP_DriveCDIcon:
    case QStyle::SP_DriveDVDIcon:
        return QIcon::fromTheme("drive-optical");
    case QStyle::SP_DriveNetIcon:
        return QIcon::fromTheme("folder-remote");
    case QStyle::SP_DirHomeIcon:
        return QIcon::fromTheme("user-home");
    case QStyle::SP_DirOpenIcon:
        return QIcon::fromTheme("document-open-folder");
    case QStyle::SP_DirClosedIcon:
        return QIcon::fromTheme("folder");
    case QStyle::SP_DirIcon:
        return QIcon::fromTheme("folder");
    case QStyle::SP_DirLinkIcon:
        return QIcon::fromTheme("folder"); //TODO: generate (!?) folder with link emblem
    case QStyle::SP_FileIcon:
        return QIcon::fromTheme("text-plain"); //TODO: look for a better icon
    case QStyle::SP_FileLinkIcon:
        return QIcon::fromTheme("text-plain"); //TODO: generate (!?) file with link emblem
    case QStyle::SP_FileDialogStart:
        return QIcon::fromTheme("media-playback-start"); //TODO: find correct icon
    case QStyle::SP_FileDialogEnd:
        return QIcon::fromTheme("media-playback-stop"); //TODO: find correct icon
    case QStyle::SP_FileDialogToParent:
        return QIcon::fromTheme("go-up");
    case QStyle::SP_FileDialogNewFolder:
        return QIcon::fromTheme("folder-new");
    case QStyle::SP_FileDialogDetailedView:
        return QIcon::fromTheme("view-list-details");
    case QStyle::SP_FileDialogInfoView:
        return QIcon::fromTheme("document-properties");
    case QStyle::SP_FileDialogContentsView:
        return QIcon::fromTheme("view-list-icons");
    case QStyle::SP_FileDialogListView:
        return QIcon::fromTheme("view-list-text");
    case QStyle::SP_FileDialogBack:
        return QIcon::fromTheme("go-previous");
    case QStyle::SP_MessageBoxInformation:
        return QIcon::fromTheme("dialog-information");
    case QStyle::SP_MessageBoxWarning:
        return QIcon::fromTheme("dialog-warning");
    case QStyle::SP_MessageBoxCritical:
        return QIcon::fromTheme("dialog-error");
    case QStyle::SP_MessageBoxQuestion:
        return QIcon::fromTheme("dialog-information");
    case QStyle::SP_DialogOkButton:
        return QIcon::fromTheme("dialog-ok");
    case QStyle::SP_DialogCancelButton:
        return QIcon::fromTheme("dialog-cancel");
    case QStyle::SP_DialogHelpButton:
        return QIcon::fromTheme("help-contents");
    case QStyle::SP_DialogOpenButton:
        return QIcon::fromTheme("document-open");
    case QStyle::SP_DialogSaveButton:
        return QIcon::fromTheme("document-save");
    case QStyle::SP_DialogCloseButton:
        return QIcon::fromTheme("dialog-close");
    case QStyle::SP_DialogApplyButton:
        return QIcon::fromTheme("dialog-ok-apply");
    case QStyle::SP_DialogResetButton:
        return QIcon::fromTheme("document-revert");
    case QStyle::SP_DialogDiscardButton:
        return QIcon::fromTheme("dialog-cancel");
    case QStyle::SP_DialogYesButton:
        return QIcon::fromTheme("dialog-ok-apply");
    case QStyle::SP_DialogNoButton:
        return QIcon::fromTheme("dialog-cancel");
    case QStyle::SP_ArrowUp:
        return QIcon::fromTheme("go-up");
    case QStyle::SP_ArrowDown:
        return QIcon::fromTheme("go-down");
    case QStyle::SP_ArrowLeft:
        return QIcon::fromTheme("go-previous-view");
    case QStyle::SP_ArrowRight:
        return QIcon::fromTheme("go-next-view");
    case QStyle::SP_ArrowBack:
        return QIcon::fromTheme("go-previous");
    case QStyle::SP_ArrowForward:
        return QIcon::fromTheme("go-next");
    case QStyle::SP_BrowserReload:
        return QIcon::fromTheme("view-refresh");
    case QStyle::SP_BrowserStop:
        return QIcon::fromTheme("process-stop");
    case QStyle::SP_MediaPlay:
        return QIcon::fromTheme("media-playback-start");
    case QStyle::SP_MediaStop:
        return QIcon::fromTheme("media-playback-stop");
    case QStyle::SP_MediaPause:
        return QIcon::fromTheme("media-playback-pause");
    case QStyle::SP_MediaSkipForward:
        return QIcon::fromTheme("media-skip-forward");
    case QStyle::SP_MediaSkipBackward:
        return QIcon::fromTheme("media-skip-backward");
    case QStyle::SP_MediaSeekForward:
        return QIcon::fromTheme("media-seek-forward");
    case QStyle::SP_MediaSeekBackward:
        return QIcon::fromTheme("media-seek-backward");
    case QStyle::SP_MediaVolume:
        return QIcon::fromTheme("audio-volume-medium");
    case QStyle::SP_MediaVolumeMuted:
        return QIcon::fromTheme("audio-volume-muted");

    default:
        return QIcon();
    }
}

QPixmap K4Style::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
                                const QWidget *widget) const
{
    return QCommonStyle::standardPixmap(standardPixmap, opt, widget);
}
QPixmap K4Style::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
                                     const QStyleOption *opt) const
{
    return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
}

void K4Style::drawInsideRect(QPainter *p, const QRect &r) const
{
    p->drawRect(r.x(), r.y(), r.width() - 1, r.height() - 1);
}

QRect K4Style::centerRect(const QRect &in, int w, int h) const
{
    return QRect(in.x() + (in.width() - w) / 2, in.y() + (in.height() - h) / 2, w, h);
}

QRect K4Style::centerRect(const QRect &in, const QSize &size) const
{
    return centerRect(in, size.width(), size.height());
}

void K4Style::drawKStylePrimitive(WidgetType widgetType, int primitive,
                                  const QStyleOption *opt,
                                  const QRect &r, const QPalette &pal,
                                  State flags, QPainter *p,
                                  const QWidget *widget,
                                  K4Style::Option *kOpt) const
{
    switch (widgetType) {
    case WT_Tree: {
        switch (primitive) {
        case Tree::VerticalBranch:
        case Tree::HorizontalBranch:
            //### FIXME: set sane color.
            p->fillRect(r, QBrush(Qt::Dense4Pattern));
            return;
        case Tree::ExpanderOpen:
        case Tree::ExpanderClosed: {
            p->setPen(pal.text().color());
            drawInsideRect(p, r); //the border.
            int signLineSize = r.width() / 4;
            p->drawLine(r.center().x() - signLineSize, r.center().y(),
                        r.center().x() + signLineSize, r.center().y()); //-
            if (primitive == Tree::ExpanderClosed) //vertical line of +
                p->drawLine(r.center().x(), r.center().y() - signLineSize,
                            r.center().x(), r.center().y() + signLineSize);
            return;
        }
        default:
            break;
        }

        break;
    }

    case WT_SpinBox: {
        switch (primitive) {
        case SpinBox::PlusSymbol:
        case SpinBox::MinusSymbol: {
            p->setPen(pal.buttonText().color());

            int l = qMin(r.width() - 2, r.height() - 2);
            QPoint c = r.center();

            p->drawLine(c.x() - l / 2, c.y(), c.x() + l / 2, c.y());
            if (primitive == SpinBox::PlusSymbol) {
                p->drawLine(c.x(), c.y() - l / 2, c.x(), c.y() + l / 2);
            }

            return;
        }
        default:
            break;
        }

        break;
    }

    case WT_GroupBox: {
        if (primitive == GroupBox::FlatFrame) {
            QPen oldPen = p->pen();
            p->setPen(pal.color(QPalette::WindowText));
            p->drawLine(r.topLeft(), r.topRight());
            p->setPen(oldPen);
        }

        break;
    }

    case WT_ToolBoxTab: {
        if (primitive == ToolBoxTab::Panel) {
            drawKStylePrimitive(WT_ToolButton, ToolButton::Panel, opt, r, pal, flags, p, widget);
        }

        break;
    }

    case WT_DockWidget: {
        switch (primitive) {
        case DockWidget::TitlePanel:
            p->fillRect(r, pal.color(QPalette::Highlight));
            return;

        case DockWidget::SeparatorHandle:
            return;

        default:
            break;
        }

        break;
    }

    case WT_Window: {
        switch (primitive) {
        case Window::TitlePanel:
            p->fillRect(r, pal.color(QPalette::Highlight));
            return;

        case Window::ButtonMenu: {
            K4Style::TitleButtonOption *tbkOpts =
                extractOption<K4Style::TitleButtonOption *>(kOpt);
            if (!tbkOpts->icon.isNull()) {
                tbkOpts->icon.paint(p, r);
            } else {
                QStyleOption tool(0);
                tool.palette = pal;
                // TODO: give it a nice KDE logo.
                QPixmap pm = standardPixmap(SP_TitleBarMenuButton, &tool, widget);
                tool.rect = r;
                p->save();
                drawItemPixmap(p, r, Qt::AlignCenter, pm);
                p->restore();
            }
            return;
        }

        case Window::ButtonMin:
        case Window::ButtonMax:
        case Window::ButtonRestore:
        case Window::ButtonClose:
        case Window::ButtonShade:
        case Window::ButtonUnshade:
        case Window::ButtonHelp: {
            K4Style::TitleButtonOption *tbkOpts =
                extractOption<K4Style::TitleButtonOption *>(kOpt);
            State bflags = flags;
            bflags &= ~State_Sunken;
            if (tbkOpts->active) {
                bflags |= State_Sunken;
            }
            drawKStylePrimitive(WT_ToolButton, ToolButton::Panel, opt, r, pal, bflags, p, widget);
            return;
        }
        }

        break;
    }

    case WT_TabBar: {
        // For vertical text fallback, provide the generic text implementation
        // a transformed rotated painter, with rect swizzled appropriately
        if (primitive == TabBar::EastText || primitive == TabBar::WestText) {
            QTransform tr;

            if (primitive == TabBar::WestText) {
                tr.translate(r.x(), r.height() + r.y());
                tr.rotate(-90);
            } else {
                tr.translate(r.width() + r.x(), r.y());
                tr.rotate(90);
            }

            p->save();
            p->setTransform(tr, true);
            drawKStylePrimitive(WT_TabBar, Generic::Text, opt,
                                QRect(0, 0, r.height(), r.width()), pal, flags, p, widget, kOpt);
            p->restore();
        }
        break;
    }

    default:
        break;
    }

    if (primitive == Generic::Text) {
        K4Style::TextOption *textOpts = extractOption<K4Style::TextOption *>(kOpt);

        //### debug
        //p->setPen(Qt::green);
        //drawInsideRect(p, r);

        QColor col = textOpts->color.color(pal);
        QPen   old = p->pen();
        p->setPen(col);
        drawItemText(p, r, Qt::AlignVCenter | Qt::TextShowMnemonic | textOpts->hAlign, pal, flags & State_Enabled,
                     textOpts->text);
        p->setPen(old);
    } else if (primitive == Generic::Icon) {
        K4Style::IconOption *iconOpts = extractOption<K4Style::IconOption *>(kOpt);
        QIcon::Mode mode;
        QIcon::State iconState;

        // Select the correct icon from the iconset
        if (flags & State_Enabled)
            if (iconOpts->active) {
                mode = QIcon::Active;
            } else {
                mode = QIcon::Normal;
            }
        else {
            mode = QIcon::Disabled;
        }

        if ((flags & State_On) || (flags & State_Sunken)) {
            iconState = QIcon::On;
        } else {
            iconState = QIcon::Off;
        }

        QSize size = iconOpts->size;
        if (!size.isValid()) {
            size = QSize(pixelMetric(PM_SmallIconSize), pixelMetric(PM_SmallIconSize));
        }
        QPixmap icon = iconOpts->icon.pixmap(size, mode, iconState);
        p->drawPixmap(centerRect(r, icon.size()), icon);
    } else if (primitive == Generic::FocusIndicator) {
        QPen pen;
        pen.setWidth(0);
        pen.setStyle(Qt::DotLine);
        p->setPen(pen);
        drawInsideRect(p, r);
    } else if (primitive >= Generic::ArrowUp && primitive <= Generic::ArrowLeft) {
        //### FIXME: Helper for these sorts of things, as Keramik has virtually
        //identical code!
        K4Style::ColorOption *colorOpt   = extractOption<K4Style::ColorOption *>(kOpt);
        QColor               arrowColor = colorOpt->color.color(pal);

        QPolygon poly;

        switch (primitive) {
        case Generic::ArrowUp:
            poly.setPoints(QCOORDARRLEN(u_arrow), u_arrow);
            break;

        case Generic::ArrowDown:
            poly.setPoints(QCOORDARRLEN(d_arrow), d_arrow);
            break;

        case Generic::ArrowLeft:
            poly.setPoints(QCOORDARRLEN(l_arrow), l_arrow);
            break;

        default:
            poly.setPoints(QCOORDARRLEN(r_arrow), r_arrow);
        }

        if (flags & State_Enabled) {
            //CHECKME: Why is the -1 needed?
            poly.translate(r.x() + r.width() / 2 - 1, r.y() + r.height() / 2);

            p->setPen(arrowColor);
            p->drawPolygon(poly);
        } else {
            //Disabled ones ignore color parameter
            poly.translate(r.x() + r.width() / 2, r.y() + r.height() / 2 + 1);
            p->setPen(pal.color(QPalette::Light));
            p->drawPolygon(poly);
            poly.translate(-1, -1);
            p->setPen(pal.mid().color());
            p->drawPolygon(poly);
        }

    }
#if 0 //Reenable if you need a debug aid
    else {
        p->setPen(Qt::red);
        drawInsideRect(p, r);
    }
#endif
}

void K4Style::setWidgetLayoutProp(WidgetType widget, int metric, int value)
{
    if (metrics.size() <= widget) {
        metrics.resize(widget + 1);
    }

    QVector<int> &widgetMetrics = metrics[widget];
    if (widgetMetrics.size() <= metric) {
        widgetMetrics.resize(metric + 1);
    }

    widgetMetrics[metric] = value;
}

int K4Style::widgetLayoutProp(WidgetType widget, int metric,
                              const QStyleOption *opt,
                              const QWidget *w) const
{
    Q_UNUSED(opt)
    Q_UNUSED(w)

    if (metrics.size() <= widget) {
        return 0;
    }

    const QVector<int> &widgetMetrics = metrics[widget];
    if (widgetMetrics.size() <= metric) {
        return 0;
    }

    return widgetMetrics[metric];
}

QSize K4Style::expandDim(const QSize &orig, WidgetType wt, int baseMarginMetric,
                         const QStyleOption *opt, const QWidget *w, bool rotated) const
{
    int addWidth =  2 * widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w) +
                    widgetLayoutProp(wt, baseMarginMetric + Left, opt, w) +
                    widgetLayoutProp(wt, baseMarginMetric + Right, opt, w);

    int addHeight = 2 * widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w) +
                    widgetLayoutProp(wt, baseMarginMetric + Top, opt, w) +
                    widgetLayoutProp(wt, baseMarginMetric + Bot, opt, w);

    return QSize(orig.width() + (rotated ? addHeight : addWidth),
                 orig.height() + (rotated ? addWidth : addHeight));
}

QRect K4Style::insideMargin(const QRect &orig, WidgetType wt,
                            int baseMarginMetric,
                            const QStyleOption *opt, const QWidget *w) const
{
    int x1 = orig.topLeft().x();
    int y1 = orig.topLeft().y();
    int x2 = orig.bottomRight().x();
    int y2 = orig.bottomRight().y();

    x1 += widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w);
    x1 += widgetLayoutProp(wt, baseMarginMetric + Left, opt, w);

    y1 += widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w);
    y1 += widgetLayoutProp(wt, baseMarginMetric + Top, opt, w);

    x2 -= widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w);
    x2 -= widgetLayoutProp(wt, baseMarginMetric + Right, opt, w);

    y2 -= widgetLayoutProp(wt, baseMarginMetric + MainMargin, opt, w);
    y2 -= widgetLayoutProp(wt, baseMarginMetric + Bot, opt, w);

    return QRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
}

QRect K4Style::handleRTL(const QStyleOption *opt, const QRect &subRect) const
{
    return visualRect(opt->direction, opt->rect, subRect);
}

QPoint K4Style::handleRTL(const QStyleOption *opt, const QPoint &pos) const
{
    return visualPos(opt->direction, opt->rect, pos);
}

void K4Style::drawPrimitive(PrimitiveElement elem, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    //Extract the stuff we need out of the option
    State flags = option->state;
    QRect      r     = option->rect;
    QPalette   pal   = option->palette;

    switch (elem) {
    case PE_FrameFocusRect:
        drawKStylePrimitive(WT_Generic, Generic::FocusIndicator, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorArrowUp:
        drawKStylePrimitive(WT_Generic, Generic::ArrowUp, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorArrowDown:
        drawKStylePrimitive(WT_Generic, Generic::ArrowDown, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorArrowLeft:
        drawKStylePrimitive(WT_Generic, Generic::ArrowLeft, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorArrowRight:
        drawKStylePrimitive(WT_Generic, Generic::ArrowRight, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorMenuCheckMark:
        //### check flags
        drawKStylePrimitive(WT_MenuItem, MenuItem::CheckOn, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorCheckBox:
        if (flags & State_NoChange) {
            drawKStylePrimitive(WT_CheckBox, CheckBox::CheckTriState, option, r, pal, flags, painter, widget);
        } else if (flags & State_On) {
            drawKStylePrimitive(WT_CheckBox, CheckBox::CheckOn, option, r, pal, flags, painter, widget);
        } else {
            drawKStylePrimitive(WT_CheckBox, CheckBox::CheckOff, option, r, pal, flags, painter, widget);
        }
        return;
    case PE_IndicatorRadioButton:
        if (flags & State_On) {
            drawKStylePrimitive(WT_RadioButton, RadioButton::RadioOn, option, r, pal, flags, painter, widget);
        } else {
            drawKStylePrimitive(WT_RadioButton, RadioButton::RadioOff, option, r, pal, flags, painter, widget);
        }
        return;
    case PE_IndicatorBranch: {
        int centerX = r.x() + r.width() / 2;
        int centerY = r.y() + r.height() / 2;

        int expanderAdjust = 0;
        //First, determine whether we need to draw an expander.
        if (flags & State_Children) {
            //How large should we make it?
            int sizeLimit = qMin(qMin(r.width(), r.height()),
                                 widgetLayoutProp(WT_Tree, Tree::MaxExpanderSize, option, widget));
            if ((sizeLimit & 1) == 0) {
                --sizeLimit;
            }

            expanderAdjust = sizeLimit / 2 + 1;

            QRect expanderRect = QRect(centerX - sizeLimit / 2, centerY - sizeLimit / 2,
                                       sizeLimit, sizeLimit);

            drawKStylePrimitive(WT_Tree, flags & State_Open ? Tree::ExpanderOpen : Tree::ExpanderClosed,
                                option, expanderRect, pal, flags, painter, widget);
        }

        //Now, draw the branches. The top line gets drawn unless we're completely
        //w/o any indication of a neightbor
        if (flags & (State_Item | State_Children | State_Sibling)) {
            QRect topLine = QRect(QPoint(centerX, r.y()), QPoint(centerX, centerY - expanderAdjust));
            drawKStylePrimitive(WT_Tree, Tree::VerticalBranch, option, topLine, pal, flags, painter, widget);
        }

        //The right/left (depending on dir) line gets drawn if we have an item
        if (flags & State_Item) {
            QRect horLine;
            if (option->direction == Qt::LeftToRight)
                horLine = QRect(QPoint(centerX + expanderAdjust, centerY),
                                QPoint(r.right(), centerY));
            else
                horLine = QRect(QPoint(r.left(), centerY),
                                QPoint(centerX - expanderAdjust, centerY));
            drawKStylePrimitive(WT_Tree, Tree::HorizontalBranch, option, horLine, pal, flags, painter, widget);
        }

        //The bottom if we have a sibling
        if (flags & State_Sibling) {
            QRect botLine = QRect(QPoint(centerX, centerY + expanderAdjust),
                                  QPoint(centerX, r.bottom()));
            drawKStylePrimitive(WT_Tree, Tree::VerticalBranch, option, botLine, pal, flags, painter, widget);
        }
        return;
    }
    case PE_FrameMenu:
        drawKStylePrimitive(WT_Menu, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    case PE_IndicatorHeaderArrow: {
        const QStyleOptionHeader *hOpt = qstyleoption_cast<const QStyleOptionHeader *>(option);
        int primitive = 0;
        if (flags & State_UpArrow || (hOpt && hOpt->sortIndicator == QStyleOptionHeader::SortUp)) {
            primitive = Generic::ArrowUp;
        } else if (flags & State_DownArrow || (hOpt && hOpt->sortIndicator == QStyleOptionHeader::SortDown)) {
            primitive = Generic::ArrowDown;
        }
        if (primitive != 0) {
            drawKStylePrimitive(WT_Header, primitive, option, r, pal, flags, painter, widget);
        }
        return;
    }
    case PE_FrameTabBarBase: {
        drawKStylePrimitive(WT_TabBar, TabBar::BaseFrame, option, r, pal, flags, painter, widget);
        return;
    }
    case PE_IndicatorTabTear: {
        drawKStylePrimitive(WT_TabBar, TabBar::IndicatorTear, option, r, pal, flags, painter, widget);
        return;
    }
    case PE_FrameTabWidget: {
        drawKStylePrimitive(WT_TabWidget, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_PanelLineEdit: {
        drawKStylePrimitive(WT_LineEdit, LineEdit::Panel, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_FrameLineEdit: {
        drawKStylePrimitive(WT_LineEdit, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_FrameGroupBox: {
        if (const QStyleOptionFrame *fOpt =
                    qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            QStyleOptionFrame fOpt2(*fOpt);

            if (fOpt2.features & QStyleOptionFrame::Flat) {
                drawKStylePrimitive(WT_GroupBox, GroupBox::FlatFrame, option, r, pal, flags, painter, widget);
            } else {
                drawKStylePrimitive(WT_GroupBox, Generic::Frame, option, r, pal, flags, painter, widget);
            }
        }
        return;
    }

    case PE_FrameStatusBar: {
        drawKStylePrimitive(WT_StatusBar, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_FrameDockWidget: {
        drawKStylePrimitive(WT_DockWidget, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_IndicatorDockWidgetResizeHandle: {
        drawKStylePrimitive(WT_DockWidget, DockWidget::SeparatorHandle, option, r, pal, flags,
                            painter, widget);
        return;
    }

    case PE_FrameWindow: {
        drawKStylePrimitive(WT_Window, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_Frame: {
        drawKStylePrimitive(WT_Generic, Generic::Frame, option, r, pal, flags, painter, widget);
        return;
    }

    case PE_IndicatorToolBarHandle: {
        if (flags & State_Horizontal)
            drawKStylePrimitive(WT_ToolBar, ToolBar::HandleHor,
                                option, r, pal, flags, painter, widget);
        else
            drawKStylePrimitive(WT_ToolBar, ToolBar::HandleVert,
                                option, r, pal, flags, painter, widget);
        return;
    }

    case PE_IndicatorToolBarSeparator:
        drawKStylePrimitive(WT_ToolBar, ToolBar::Separator, option, r, pal, flags, painter, widget);
        return;

    case PE_PanelButtonCommand:
        //case PE_PanelButtonBevel: // ### CHECKME
        drawKStylePrimitive(WT_PushButton, PushButton::Panel, option, r, pal, flags, painter, widget);
        return;
    case PE_FrameDefaultButton:
        drawKStylePrimitive(WT_PushButton, PushButton::DefaultButtonFrame, option, r, pal, flags, painter, widget);
        return;

    case PE_PanelButtonTool:
        drawKStylePrimitive(WT_ToolButton, ToolButton::Panel, option, r, pal, flags, painter, widget);
        return;

    case PE_IndicatorButtonDropDown:
        drawKStylePrimitive(WT_ToolButton, Generic::ArrowDown, option, r, pal, flags, painter, widget);
        return;

    case PE_PanelItemViewItem: {

        const QStyleOptionViewItem *opt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
        const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
        bool hover = (option->state & State_MouseOver) && (!view ||
                     view->selectionMode() != QAbstractItemView::NoSelection);

        bool hasCustomBackground = opt->backgroundBrush.style() != Qt::NoBrush &&
                                   !(option->state & State_Selected);
        bool hasSolidBackground = !hasCustomBackground || opt->backgroundBrush.style() == Qt::SolidPattern;

        const qreal rounding = 2.5;

        if (!hover && !(option->state & State_Selected) && !hasCustomBackground &&
                !(opt->features & QStyleOptionViewItem::Alternate)) {
            return;
        }

        QPalette::ColorGroup cg;
        if (option->state & State_Enabled) {
            cg = (option->state & State_Active) ? QPalette::Normal : QPalette::Inactive;
        } else {
            cg = QPalette::Disabled;
        }

        QColor color;

        if (hasCustomBackground && hasSolidBackground) {
            color = opt->backgroundBrush.color();
        } else {
            color = option->palette.color(cg, QPalette::Highlight);
        }

        if (hover && !hasCustomBackground) {
            if (!(option->state & State_Selected)) {
                color.setAlphaF(.20);
            } else {
                color = color.lighter(110);
            }
        }

        if (opt && (opt->features & QStyleOptionViewItem::Alternate)) {
            painter->fillRect(option->rect, option->palette.brush(cg, QPalette::AlternateBase));
        }

        if (!hover && !(option->state & State_Selected) && !hasCustomBackground) {
            return;
        }

        quint64 key = quint64(option->rect.height()) << 32 | color.rgba();
        SelectionTiles tiles;
        SelectionTiles *tilesPtr = d->selectionCache.object(key);
        if (tilesPtr) {
            // We can't use tilesPtr directly since obj lifetime is different
            // if we QCache::insert() vs. use ret value from QCache::object().
            tiles = *tilesPtr;
        }
        if (!tilesPtr && hasSolidBackground) {
            QImage image(32 + 16, option->rect.height(), QImage::Format_ARGB32_Premultiplied);
            image.fill(0);

            QRect r = image.rect().adjusted(0, 0, -1, -1);

            QPainterPath path1, path2;
            path1.addRoundedRect(r, rounding, rounding);
            path2.addRoundedRect(r.adjusted(1, 1, -1, -1), rounding - 1, rounding - 1);

            // items with custom background brushes always have their background drawn
            // regardless of whether they are hovered or selected or neither so
            // the gradient effect needs to be more subtle
            int lightenAmount = hasCustomBackground ? 110 : 130;
            QLinearGradient gradient(0, 0, 0, r.bottom());
            gradient.setColorAt(0, color.lighter(lightenAmount));
            gradient.setColorAt(1, color);

            QPainter p(&image);
            p.setRenderHint(QPainter::Antialiasing);
            p.translate(.5, .5);
            p.setPen(QPen(color, 1));
            p.setBrush(gradient);
            p.drawPath(path1);
            p.strokePath(path2, QPen(QColor(255, 255, 255, 64), 1));
            p.end();

            QPixmap pixmap = QPixmap::fromImage(image);

            tiles.left   = pixmap.copy(0, 0, 8, image.height());
            tiles.center = pixmap.copy(8, 0, 32, image.height());
            tiles.right  = pixmap.copy(40, 0, 8, image.height());

            d->selectionCache.insert(key, new SelectionTiles(tiles));
        } else if (hasCustomBackground && !hasSolidBackground) {
            const QPointF oldBrushOrigin = painter->brushOrigin();
            painter->setBrushOrigin(opt->rect.topLeft());
            painter->setBrush(opt->backgroundBrush);
            painter->setPen(Qt::NoPen);
            painter->drawRect(opt->rect);
            painter->setBrushOrigin(oldBrushOrigin);
            return;
        }

        bool roundedLeft  = false;
        bool roundedRight = false;
        if (opt) {
            roundedLeft  = (opt->viewItemPosition == QStyleOptionViewItem::Beginning);
            roundedRight = (opt->viewItemPosition == QStyleOptionViewItem::End);
            if (opt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
                    opt->viewItemPosition == QStyleOptionViewItem::Invalid ||
                    (view && view->selectionBehavior() != QAbstractItemView::SelectRows)) {
                roundedLeft  = true;
                roundedRight = true;
            }
        }

        QRect r = option->rect;
        bool reverseLayout = option->direction == Qt::RightToLeft;

        if (!reverseLayout ? roundedLeft : roundedRight) {
            painter->drawPixmap(r.topLeft(), tiles.left);
            r.adjust(8, 0, 0, 0);
        }
        if (!reverseLayout ? roundedRight : roundedLeft) {
            painter->drawPixmap(r.right() - 8 + 1, r.top(), tiles.right);
            r.adjust(0, 0, -8, 0);
        }
        if (r.isValid()) {
            painter->drawTiledPixmap(r, tiles.center);
        }

        return;
    }

    default:
        break;
    }

    QCommonStyle::drawPrimitive(elem, option, painter, widget);
}

void K4Style::drawControl(ControlElement element, const QStyleOption *option, QPainter *p, const QWidget *widget) const
{
    //Extract the stuff we need out of the option
    State flags = option->state;
    QRect      r     = option->rect;
    QPalette   pal   = option->palette;

    switch (element) {
    case CE_PushButton: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        //Draw the bevel outside
        drawControl(CE_PushButtonBevel, option, p, widget);

        //Now, draw the label...
        QRect labelRect = r;

        //Move inside of default indicator margin if need be
        if ((bOpt->features & QStyleOptionButton::DefaultButton) || (bOpt->features & QStyleOptionButton::AutoDefaultButton)) {
            labelRect = insideMargin(labelRect, WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
        }

        //now get the contents area
        labelRect = insideMargin(labelRect, WT_PushButton, PushButton::ContentsMargin, option, widget);

        //### do we do anything for RTL here?

        QStyleOptionButton bOptTmp = *bOpt;
        bOptTmp.rect = labelRect;
        drawControl(CE_PushButtonLabel, &bOptTmp, p, widget);

        //Finally, renderer the focus indicator if need be
        if (flags & State_HasFocus) {
            QRect focusRect = insideMargin(r, WT_PushButton, PushButton::FocusMargin, option, widget);

            QStyleOptionFocusRect foOpts;
            foOpts.palette         = pal;
            foOpts.rect            = focusRect;
            foOpts.state           = flags;

            drawKStylePrimitive(WT_PushButton, Generic::FocusIndicator, &foOpts, focusRect, pal, flags, p, widget);
        }

        return;
    }

    case CE_PushButtonBevel: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        //Check whether we should draw default indicator.
        if (bOpt->features & QStyleOptionButton::DefaultButton) {
            drawPrimitive(PE_FrameDefaultButton, option, p, widget);
        }

        QRect bevelRect = r;
        //Exclude the margin if default or auto-default
        if ((bOpt->features & QStyleOptionButton::DefaultButton) || (bOpt->features & QStyleOptionButton::AutoDefaultButton)) {
            bevelRect = insideMargin(r, WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
        }

        //Now draw the bevel itself.
        QStyleOptionButton bOptTmp = *bOpt;
        bOptTmp.rect = bevelRect;
        drawPrimitive(PE_PanelButtonCommand, &bOptTmp, p, widget);

        return;
    }

    case CE_PushButtonLabel: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        //Extract out coordinates for easier manipulation
        //(OK, OK, for easier stealing of code from Keramik)
        int x, y, w, h;
        r.getRect(&x, &y, &w, &h);

        //Are we active? If so, shift contents
        bool active = (flags & State_On) || (flags & State_Sunken);
        if (active) {
            x += widgetLayoutProp(WT_PushButton, PushButton::PressedShiftHorizontal, option, widget);
            y += widgetLayoutProp(WT_PushButton, PushButton::PressedShiftVertical, option, widget);
        }

        //Layout the stuff.
        if (bOpt->features & QStyleOptionButton::HasMenu) {
            int indicatorWidth = widgetLayoutProp(WT_PushButton, PushButton::MenuIndicatorSize, option, widget);
            int indicatorSpacing = widgetLayoutProp(WT_PushButton, PushButton::TextToIconSpace, option, widget);
            w -= indicatorWidth + indicatorSpacing;

            //Draw the arrow...
            drawKStylePrimitive(WT_PushButton, Generic::ArrowDown, option,
                                handleRTL(bOpt, QRect(x + w + indicatorSpacing, y, indicatorWidth, h)),
                                pal, flags, p, widget);
        }

        // Draw the icon if there is one
        if (!bOpt->icon.isNull()) {
            IconOption icoOpt;
            icoOpt.icon   = bOpt->icon;
            icoOpt.size   = bOpt->iconSize;
            icoOpt.active = flags & State_HasFocus;

            if (!bOpt->text.isEmpty()) {
                int margin = widgetLayoutProp(WT_PushButton, PushButton::TextToIconSpace, option, widget);
                //Center text + icon w/margin in between..

                //Calculate length of both.
                int length = bOpt->iconSize.width() + margin
                             + p->fontMetrics().size(Qt::TextShowMnemonic, bOpt->text).width();

                //Calculate offset.
                int offset = (w - length) / 2;

                //draw icon
                QRect rect = QRect(QPoint(x + offset, y + h / 2 - bOpt->iconSize.height() / 2), bOpt->iconSize);
                drawKStylePrimitive(WT_PushButton, Generic::Icon, option,
                                    handleRTL(bOpt, rect),
                                    pal, flags, p, widget, &icoOpt);

                //new bounding rect for the text
                x += offset + bOpt->iconSize.width() + margin;
                w =  length - bOpt->iconSize.width() - margin;
            } else {
                //Icon only. Center it. (Thankfully, they killed the icon + pixmap insanity in Qt4. Whee!
                //(no need to do anything for RTL here, it's symmetric)
                drawKStylePrimitive(WT_PushButton, Generic::Icon, option,
                                    QRect(x, y, w, h),
                                    pal, flags, p, widget, &icoOpt);
            }
        } else {
            //Center the text
            int textW = p->fontMetrics().size(Qt::TextShowMnemonic, bOpt->text).width();
            x += (w - textW) / 2;
            w =  textW;
        }

        TextOption lbOpt(bOpt->text);
        drawKStylePrimitive(WT_PushButton, Generic::Text, option, handleRTL(bOpt, QRect(x, y, w, h)),
                            pal, flags, p, widget, &lbOpt);

        return;
    }

    case CE_DockWidgetTitle: {
        const QStyleOptionDockWidget *dwOpt = ::qstyleoption_cast<const QStyleOptionDockWidget *>(option);
        if (!dwOpt) {
            return;
        }

        QRect textRect = insideMargin(r, WT_DockWidget, DockWidget::TitleMargin, option, widget);
        drawKStylePrimitive(WT_DockWidget, DockWidget::TitlePanel, option, r, pal, flags, p, widget);

        TextOption lbOpt(dwOpt->title);
        lbOpt.color = widgetLayoutProp(WT_DockWidget, DockWidget::TitleTextColor,
                                       option, widget);
        drawKStylePrimitive(WT_DockWidget, Generic::Text, option, textRect, pal, flags, p, widget, &lbOpt);
        return;
    }

    case CE_ToolBoxTabShape: {
        drawKStylePrimitive(WT_ToolBoxTab, ToolBoxTab::Panel, option, r, pal, flags, p, widget);
        return;
    }
    /*
            case CE_ToolBoxTabLabel:
            {
                drawKStylePrimitive(WT_ToolBoxTab, Generic::Text, option, r, pal, flags, p, widget);
                return;
            }
    */
    case CE_CheckBox: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        //Draw the checkbox
        QRect checkBox = subElementRect(SE_CheckBoxIndicator, option, widget);
        QStyleOptionButton bOptTmp = *bOpt;
        bOptTmp.rect = checkBox;
        drawPrimitive(PE_IndicatorCheckBox, &bOptTmp, p, widget);

        // pixmap and text label...
        bOptTmp.rect = subElementRect(SE_CheckBoxContents, option, widget);
        drawControl(CE_CheckBoxLabel, &bOptTmp, p, widget);

        //Draw the focus rect...
        if (flags & State_HasFocus) {
            QRect focusRect = subElementRect(SE_CheckBoxFocusRect, option, widget);
            drawKStylePrimitive(WT_CheckBox, Generic::FocusIndicator, option, focusRect,
                                pal, flags, p, widget);
        }
        return;
    }

    case CE_CheckBoxLabel: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        int textShift = 0; // shift text in case there is a label pixmap
        // draw the pixmap, if there is one
        if (!bOpt->icon.isNull()) {
            IconOption icoOpt;
            icoOpt.icon   = bOpt->icon;
            icoOpt.size   = bOpt->iconSize;
            icoOpt.active = flags & State_HasFocus;

            QRect iconRect(r.x(), r.y() + (r.height() - bOpt->iconSize.height()) / 2,
                           bOpt->iconSize.width(), bOpt->iconSize.height());
            drawKStylePrimitive(WT_CheckBox, Generic::Icon, option,
                                handleRTL(bOpt, iconRect),
                                pal, flags, p, widget, &icoOpt);

            textShift = bOpt->iconSize.width() +
                        widgetLayoutProp(WT_RadioButton, RadioButton::BoxTextSpace, option, widget);
        }

        if (!bOpt->text.isEmpty()) {
            TextOption lbOpt(bOpt->text);
            drawKStylePrimitive(WT_CheckBox, Generic::Text, option,
                                handleRTL(bOpt, r.adjusted(textShift, 0, 0, 0)),
                                pal, flags, p, widget, &lbOpt);
        }

        return;
    }

    case CE_RadioButton: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        //Draw the indicator
        QRect indicator = subElementRect(SE_RadioButtonIndicator, option, widget);
        QStyleOptionButton bOptTmp = *bOpt;
        bOptTmp.rect = indicator;
        drawPrimitive(PE_IndicatorRadioButton, &bOptTmp, p, widget);

        // pixmap and text label...
        bOptTmp.rect = subElementRect(SE_RadioButtonContents, option, widget);
        drawControl(CE_RadioButtonLabel, &bOptTmp, p, widget);

        //Draw the focus rect...
        if (flags & State_HasFocus) {
            QRect focusRect = subElementRect(SE_RadioButtonFocusRect, option, widget);
            drawKStylePrimitive(WT_RadioButton, Generic::FocusIndicator, option, focusRect,
                                pal, flags, p, widget);
        }
        return;
    }

    case CE_RadioButtonLabel: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return;
        }

        int textShift = 0; // shift text in case there is a label pixmap
        // draw the pixmap, if there is one
        if (!bOpt->icon.isNull()) {
            IconOption icoOpt;
            icoOpt.icon   = bOpt->icon;
            icoOpt.active = flags & State_HasFocus;
            icoOpt.size   = bOpt->iconSize;

            QRect iconRect(r.x(), r.y() + (r.height() - bOpt->iconSize.height()) / 2,
                           bOpt->iconSize.width(), bOpt->iconSize.height());
            drawKStylePrimitive(WT_RadioButton, Generic::Icon, option,
                                handleRTL(bOpt, iconRect),
                                pal, flags, p, widget, &icoOpt);

            textShift = bOpt->iconSize.width() +
                        widgetLayoutProp(WT_RadioButton, RadioButton::BoxTextSpace, option, widget);
        }

        TextOption lbOpt(bOpt->text);
        drawKStylePrimitive(WT_RadioButton, Generic::Text, option,
                            handleRTL(bOpt, r.adjusted(textShift, 0, 0, 0)),
                            pal, flags, p, widget, &lbOpt);
        return;
    }

    //The CE_ProgressBar implementation inside QCommonStyle is acceptible.
    //We just implement the subElementRect's it uses

    case CE_ProgressBarGroove: {
        drawKStylePrimitive(WT_ProgressBar, ProgressBar::Groove,  option, r,
                            pal, flags, p, widget);
        return;
    }

    case CE_ProgressBarContents: {
        const QStyleOptionProgressBar *pbOpt = qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        const QStyleOptionProgressBar *pbOpt2 = qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        if (!pbOpt) {
            return;
        }

        //We layout as if LTR, relying on visualRect to fix it up
        double progress    = pbOpt->progress - pbOpt->minimum;
        int steps          = qMax(pbOpt->maximum  - pbOpt->minimum, 1);
        bool busyIndicator = (pbOpt->minimum == 0 && pbOpt->maximum == 0);
        bool horizontal    = !pbOpt2 || pbOpt2->orientation == Qt::Horizontal;

        //Do we have to draw anything?
        if (!progress && ! busyIndicator) {
            return;
        }

        //Calculate width fraction
        double widthFrac;
        if (busyIndicator) {
            widthFrac = widgetLayoutProp(WT_ProgressBar, ProgressBar::BusyIndicatorSize, option, widget) / 100.0;
        } else {
            widthFrac = progress / steps;
        }

        //And now the pixel width
        int width = qMin(r.width(), (int)(widthFrac * double(r.width())));
        int height = qMin(r.height(), (int)(widthFrac * r.height()));

        if (busyIndicator) {
            int size = width;
            if (!horizontal) {
                size = height;
            }
            //Clamp to upper width limit
            if (size > widgetLayoutProp(WT_ProgressBar, ProgressBar::MaxBusyIndicatorSize, option, widget)) {
                size = widgetLayoutProp(WT_ProgressBar, ProgressBar::MaxBusyIndicatorSize, option, widget);
            }

            //A busy indicator with width 0 is kind of useless
            if (size < 1) {
                size = 1;
            }

            int remSize = (horizontal ? r.width() : r.height()) - size; //The space around which we move around...
            if (remSize <= 0) {
                remSize = 1;    //Do something non-crashy when too small...
            }

            int pstep =  int(progress) % (2 * remSize);

            if (pstep > remSize) {
                //Bounce about.. We're remWidth + some delta, we want to be remWidth - delta...
                // - ( (remWidth + some delta) - 2* remWidth )  = - (some deleta - remWidth) = remWidth - some delta..
                pstep = -(pstep - 2 * remSize);
            }

            QRect indicatorRect;
            if (horizontal) {
                indicatorRect = QRect(r.x() + pstep, r.y(), size, r.height());
            } else {
                indicatorRect = QRect(r.x(), r.y() + pstep, r.width(), size);
            }
            drawKStylePrimitive(WT_ProgressBar, ProgressBar::BusyIndicator, option, handleRTL(option, indicatorRect),
                                pal, flags, p, widget);
        } else {
            QRect indicatorRect;
            if (horizontal) {
                indicatorRect = QRect(r.x(), r.y(), width, r.height());
            } else {
                indicatorRect = QRect(r.x(), r.bottom() - height + 1, r.width(), height);
            }
            drawKStylePrimitive(WT_ProgressBar, ProgressBar::Indicator, option, handleRTL(option, indicatorRect),
                                pal, flags, p, widget);
        }
        return;
    }

    case CE_ProgressBarLabel: {
        const QStyleOptionProgressBar *pbOpt = qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        const QStyleOptionProgressBar *pbOpt2 = qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        if (pbOpt) {
            TextOption lbOpt(pbOpt->text);
            bool horizontal = !pbOpt2 || pbOpt2->orientation == Qt::Horizontal;
            bool reverseLayout = option->direction == Qt::RightToLeft;

            p->save();

            // rotate label for vertical layout
            if (!horizontal && !reverseLayout) {
                p->translate(r.topRight());
                p->rotate(90.0);
            } else if (!horizontal) {
                p->translate(r.bottomLeft());
                p->rotate(-90.0);
            }

            if (useSideText(pbOpt)) {
                lbOpt.color = QPalette::ButtonText;

                //### or other way around?
                if (option->direction == Qt::LeftToRight) {
                    lbOpt.hAlign = Qt::AlignRight;
                } else {
                    lbOpt.hAlign = Qt::AlignLeft;
                }

                //Handle side margin.
                int marWidth = widgetLayoutProp(WT_ProgressBar, ProgressBar::SideTextSpace, option, widget);

                drawKStylePrimitive(WT_ProgressBar, Generic::Text, option,
                                    horizontal ? r.adjusted(0, marWidth, 0, -marWidth) : QRect(0, marWidth, r.height(), r.width() - marWidth),
                                    pal, flags, p, widget, &lbOpt);
            } else {
                if (pbOpt->textAlignment == Qt::AlignLeft) { //TODO: Check BIDI?
                    lbOpt.hAlign = Qt::AlignHCenter;
                } else {
                    lbOpt.hAlign = pbOpt->textAlignment;
                }

                //Now, we need to figure out the geometry of the indicator.
                QRect progressRect;
                double progress    = pbOpt->progress - pbOpt->minimum;
                int steps          = qMax(pbOpt->maximum  - pbOpt->minimum, 1);
                bool busyIndicator = (steps <= 1);

                int width;
                int height;
                if (busyIndicator) {
                    //how did this happen? handle as 0%
                    width = 0;
                    height = 0;
                } else {
                    double widthFrac = progress / steps;;
                    width = qMin(r.width(), (int)(widthFrac * r.width()));
                    height = qMin(r.height(), (int)(widthFrac * r.height()));
                }

                //If there is any indicator, we do two paths, with different
                //clipping rects, for the two colors.
                if (width || height) {
                    if (horizontal) {
                        p->setClipRect(handleRTL(option, QRect(r.x(), r.y(), width, r.height())));
                    } else if (!reverseLayout) {
                        p->setClipRect(QRect(r.height() - height, 0, r.height(), r.width()));
                    } else {
                        p->setClipRect(QRect(0, 0, height, r.width()));
                    }
                    lbOpt.color = QPalette::HighlightedText;
                    drawKStylePrimitive(WT_ProgressBar, Generic::Text, option,
                                        horizontal ? r : QRect(0, 0, r.height(), r.width()),
                                        pal, flags, p, widget, &lbOpt);

                    if (horizontal) {
                        p->setClipRect(handleRTL(option, QRect(r.x() + width, r.y(), r.width() - width, r.height())));
                    } else if (!reverseLayout) {
                        p->setClipRect(QRect(0, 0, r.height() - height, r.width()));
                    } else {
                        p->setClipRect(QRect(height, 0, r.height() - height, r.width()));
                    }
                    lbOpt.color = QPalette::ButtonText;
                    drawKStylePrimitive(WT_ProgressBar, Generic::Text, option,
                                        horizontal ? r : QRect(0, 0, r.height(), r.width()),
                                        pal, flags, p, widget, &lbOpt);
                    p->setClipping(false);
                } else {
                    lbOpt.color = QPalette::ButtonText;
                    drawKStylePrimitive(WT_ProgressBar, Generic::Text, option,
                                        horizontal ? r : QRect(0, 0, r.height(), r.width()),
                                        pal, flags, p, widget, &lbOpt);
                }
            }
            p->restore();
        }
        return;
    }

    case CE_MenuBarItem: {
        const QStyleOptionMenuItem *mOpt = ::qstyleoption_cast<const QStyleOptionMenuItem *>(option);
        if (!mOpt) {
            return;
        }

        //Bevel...
        drawKStylePrimitive(WT_MenuBarItem, MenuBarItem::Panel, option, r,
                            pal, flags, p, widget);

        //Text...
        QRect textRect = insideMargin(r, WT_MenuBarItem, MenuBarItem::Margin, option, widget);

        TextOption lbOpt(mOpt->text);
        drawKStylePrimitive(WT_MenuBarItem, Generic::Text, option, textRect,
                            pal, flags, p, widget, &lbOpt);

        return;
    }

    case CE_MenuBarEmptyArea: {
        drawKStylePrimitive(WT_MenuBar, MenuBar::EmptyArea,  option, r,
                            pal, flags, p, widget);
        return;
    }

    case CE_MenuEmptyArea:
    case CE_MenuVMargin:
    case CE_MenuHMargin: {
        drawKStylePrimitive(WT_Menu, Menu::Background,  option, r,
                            pal, flags, p, widget);
        return;
    }

    case CE_MenuItem: {

        //First of all,render the background.
        drawKStylePrimitive(WT_Menu, Menu::Background, option, r,
                            pal, flags, p, widget);

        const QStyleOptionMenuItem *miOpt = ::qstyleoption_cast<const QStyleOptionMenuItem *>(option);
        if (!miOpt || miOpt->menuItemType == QStyleOptionMenuItem::EmptyArea) {
            return;
        }

        //Remove the margin (for everything but the column background)
        QRect ir = insideMargin(r, WT_MenuItem, MenuItem::Margin, option, widget);

        //First, figure out the left column width. When CheckAlongsideIcon is disabled it's just
        // the icon column width. Otherwise it consists of CheckWidth+CheckSpace+icon column width.
        int iconColW = miOpt->maxIconWidth;
        iconColW     = qMax(iconColW, widgetLayoutProp(WT_MenuItem, MenuItem::IconWidth, option, widget));
        int checkColW = widgetLayoutProp(WT_MenuItem, MenuItem::CheckWidth, option, widget);
        int checkSpace = widgetLayoutProp(WT_MenuItem, MenuItem::CheckSpace, option, widget);

        int leftColW = iconColW;
        // only use the additional check row if the menu has checkable menuItems.
        bool checkAlongsideIcon = (miOpt->menuHasCheckableItems &&
                                   widgetLayoutProp(WT_MenuItem, MenuItem::CheckAlongsideIcon, option, widget));
        if (checkAlongsideIcon) {
            leftColW = checkColW + checkSpace + iconColW;
        }

        //And the right arrow column...
        int rightColW = widgetLayoutProp(WT_MenuItem, MenuItem::ArrowSpace, option, widget) +
                        widgetLayoutProp(WT_MenuItem, MenuItem::ArrowWidth, option, widget);

        //Render left column background. This is a bit tricky, since we don't use the V margin.
        QRect leftColRect(ir.x(), r.y(), leftColW, r.height());
        drawKStylePrimitive(WT_MenuItem, MenuItem::CheckColumn, option, handleRTL(option, leftColRect),
                            pal, flags, p, widget);

        //Separators: done with the bg, can paint them and bail them out.
        if (miOpt->menuItemType == QStyleOptionMenuItem::Separator) {
            drawKStylePrimitive(WT_MenuItem, MenuItem::Separator, option, ir, pal, flags, p, widget);
            return;
        }

        //Now paint the active indicator --- other stuff goes on top of it
        bool active = (flags & State_Selected);

        //Active indicator...
        if (active) {
            drawKStylePrimitive(WT_MenuItem, MenuItem::ItemIndicator, option, handleRTL(option, r), pal, flags, p, widget);
        }

        ColorMode textColor = (flags & State_Enabled) ? (widgetLayoutProp(WT_MenuItem, active ?
                              MenuItem::ActiveTextColor :
                              MenuItem::TextColor, option, widget))
                              : (widgetLayoutProp(WT_MenuItem, active ?
                                      MenuItem::ActiveDisabledTextColor :
                                      MenuItem::DisabledTextColor, option, widget));

        //Readjust the column rectangle back to proper height
        leftColRect = QRect(ir.x(), ir.y(), leftColW, ir.height());
        // Paint checkbox, etc.
        if (!checkAlongsideIcon && !miOpt->icon.isNull()) {
            // there is an icon and the item is checked, so paint a CheckIcon
            if (miOpt->checked) {
                drawKStylePrimitive(WT_MenuItem, MenuItem::CheckIcon,
                                    option, handleRTL(option, leftColRect), pal, flags,
                                    p, widget);
            }
        } else {
            // paint a normal check- resp. radiomark.
            QRect checkColRect;
            if (checkAlongsideIcon) {
                checkColRect = QRect(leftColRect.x(), leftColRect.y(),
                                     checkColW, leftColRect.height());
            } else {
                checkColRect = leftColRect;
            }

            bool checked = miOpt->checked;
            if (miOpt->checkType == QStyleOptionMenuItem::NonExclusive) {
                drawKStylePrimitive(WT_MenuItem, checked ? MenuItem::CheckOn : MenuItem::CheckOff,
                                    option, handleRTL(option, checkColRect), pal, flags,
                                    p, widget);
            } else if (miOpt->checkType == QStyleOptionMenuItem::Exclusive) {
                drawKStylePrimitive(WT_MenuItem, checked ? MenuItem::RadioOn : MenuItem::RadioOff,
                                    option, handleRTL(option, checkColRect), pal, flags,
                                    p, widget);
            }
        }
        // Paint the menu icon.
        if (!miOpt->icon.isNull()) {
            int iconSize = pixelMetric(PM_SmallIconSize);

            QRect iconColRect;
            if (checkAlongsideIcon) {
                iconColRect = QRect(leftColRect.x() + checkColW + checkSpace, leftColRect.y(),
                                    leftColRect.width() - (checkColW + checkSpace), leftColRect.height());
            } else {
                iconColRect = leftColRect;
            }
            IconOption icoOpt;
            icoOpt.icon   = miOpt->icon;
            icoOpt.active = flags & State_Selected;
            drawKStylePrimitive(WT_MenuItem, Generic::Icon, option,
                                handleRTL(option, centerRect(iconColRect, iconSize, iconSize)),
                                pal, flags, p, widget, &icoOpt);
        }

        //Now include the spacing when calculating the next columns
        leftColW += widgetLayoutProp(WT_MenuItem, MenuItem::IconSpace, option, widget);

        //Render the text, including any accel.
        QString text = miOpt->text;
        QRect   textRect = QRect(ir.x() + leftColW, ir.y(), ir.width() - leftColW - rightColW, ir.height());
        QFont   font = miOpt->font;
        const QFont oldFont = p->font();

        p->setFont(font);
        int tabPos = miOpt->text.indexOf(QLatin1Char('\t'));
        if (tabPos != -1) {
            text = miOpt->text.left(tabPos);
            QString accl = miOpt->text.mid(tabPos + 1);

            //Draw the accel.
            TextOption lbOpt(accl);
            lbOpt.color  = textColor;
            lbOpt.hAlign = Qt::AlignRight;
            drawKStylePrimitive(WT_MenuItem, Generic::Text, option, handleRTL(option, textRect),
                                pal, flags, p, widget, &lbOpt);
        }

        //Draw the text.
        TextOption lbOpt(text);
        lbOpt.color = textColor;
        drawKStylePrimitive(WT_MenuItem, Generic::Text, option, handleRTL(option, textRect),
                            pal, flags, p, widget, &lbOpt);

        p->setFont(oldFont);

        //Render arrow, if need be.
        if (miOpt->menuItemType == QStyleOptionMenuItem::SubMenu) {
            ColorOption arrowColor;
            arrowColor.color = textColor;

            int aw = widgetLayoutProp(WT_MenuItem, MenuItem::ArrowWidth, option, widget);

            QRect arrowRect(ir.x() + ir.width() - aw, ir.y(), aw, ir.height());
            drawKStylePrimitive(WT_MenuItem, option->direction == Qt::LeftToRight ?
                                Generic::ArrowRight : Generic::ArrowLeft,
                                option, handleRTL(option, arrowRect), pal, flags, p, widget, &arrowColor);
        }

        return;
    }

    case CE_ScrollBarAddLine:
    case CE_ScrollBarSubLine: {
        const QStyleOptionSlider *slOpt = ::qstyleoption_cast<const QStyleOptionSlider *>(option);
        if (!slOpt) {
            return;
        }

        //Fix up the rectangle to be what we want
        r = internalSubControlRect(CC_ScrollBar, slOpt,
                                   element == CE_ScrollBarAddLine ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget);
        const_cast<QStyleOption *>(option)->rect = r;

        bool doubleButton = false;

        //See whether we're a double-button...
        if (element == CE_ScrollBarAddLine && widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleBotButton, option, widget)) {
            doubleButton = true;
        }
        if (element == CE_ScrollBarSubLine && widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleTopButton, option, widget)) {
            doubleButton = true;
        }

        if (doubleButton) {
            if (flags & State_Horizontal) {
                DoubleButtonOption::ActiveButton ab = DoubleButtonOption::None;

                //Depending on RTL direction, the one on the left is either up or down.
                bool leftAdds, rightAdds;
                if (slOpt->direction == Qt::LeftToRight) {
                    leftAdds  = false;
                    rightAdds = true;
                } else {
                    leftAdds  = true;
                    rightAdds = false;
                }

                //Determine whether any of the buttons is active
                if (flags & State_Sunken) {
                    if (((slOpt->activeSubControls & SC_ScrollBarAddLine) && leftAdds) ||
                            ((slOpt->activeSubControls & SC_ScrollBarSubLine) && !leftAdds)) {
                        ab = DoubleButtonOption::Left;
                    }

                    if (((slOpt->activeSubControls & SC_ScrollBarAddLine) && rightAdds) ||
                            ((slOpt->activeSubControls & SC_ScrollBarSubLine) && !rightAdds)) {
                        ab = DoubleButtonOption::Right;
                    }
                }

                DoubleButtonOption bOpt(ab);
                drawKStylePrimitive(WT_ScrollBar, ScrollBar::DoubleButtonHor,
                                    option, r, pal, flags, p, widget, &bOpt);

                //Draw the left arrow..
                QRect leftSubButton = QRect(r.x(), r.y(), r.width() / 2, r.height());

                ColorOption colOpt;
                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);
                if (ab == DoubleButtonOption::Left) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                drawKStylePrimitive(WT_ScrollBar, Generic::ArrowLeft, option, leftSubButton, pal,
                                    flags, p, widget, &colOpt);

                //Right half..
                QRect rightSubButton;
                rightSubButton.setBottomRight(r.bottomRight());
                rightSubButton.setLeft(leftSubButton.right() + 1);
                rightSubButton.setTop(r.top());

                //Chose proper color
                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);
                if (ab == DoubleButtonOption::Right) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                drawKStylePrimitive(WT_ScrollBar, Generic::ArrowRight, option, rightSubButton, pal,
                                    flags, p, widget, &colOpt);
            } else {
                DoubleButtonOption::ActiveButton ab = DoubleButtonOption::None;

                //Determine whether any of the buttons is active
                //Qt sets both sunken and activeSubControls for active,
                //just activeSubControls for hover.
                if (flags & State_Sunken) {
                    if (slOpt->activeSubControls & SC_ScrollBarSubLine) {
                        ab = DoubleButtonOption::Top;
                    }

                    if (slOpt->activeSubControls & SC_ScrollBarAddLine) {
                        ab = DoubleButtonOption::Bottom;
                    }
                }

                //Paint the bevel
                DoubleButtonOption bOpt(ab);
                drawKStylePrimitive(WT_ScrollBar, ScrollBar::DoubleButtonVert,
                                    option, r, pal, flags, p, widget, &bOpt);

                //Paint top button.
                ColorOption colOpt;
                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);

                if (ab == DoubleButtonOption::Top) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                QRect topSubButton = QRect(r.x(), r.y(), r.width(), r.height() / 2);
                drawKStylePrimitive(WT_ScrollBar, Generic::ArrowUp, option, topSubButton, pal,
                                    flags, p, widget, &colOpt);

                //Paint bot button
                QRect botSubButton;
                botSubButton.setBottomRight(r.bottomRight());
                botSubButton.setLeft(r.left());
                botSubButton.setTop(topSubButton.bottom() + 1);

                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);

                if (ab == DoubleButtonOption::Bottom) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                drawKStylePrimitive(WT_ScrollBar, Generic::ArrowDown, option, botSubButton, pal,
                                    flags, p, widget, &colOpt);
            }
        } else {
            // Single button
            if (flags & State_Horizontal) {
                drawKStylePrimitive(WT_ScrollBar, ScrollBar::SingleButtonHor,
                                    option, r, pal, flags, p, widget);

                int  primitive;
                bool active   = false;

                if (element == CE_ScrollBarAddLine) {
                    if (slOpt->direction == Qt::LeftToRight) {
                        primitive = Generic::ArrowRight;
                    } else {
                        primitive = Generic::ArrowLeft;
                    }

                    if ((slOpt->activeSubControls & SC_ScrollBarAddLine) && (flags & State_Sunken)) {
                        active = true;
                    }
                } else {
                    if (slOpt->direction == Qt::LeftToRight) {
                        primitive = Generic::ArrowLeft;
                    } else {
                        primitive = Generic::ArrowRight;
                    }

                    if ((slOpt->activeSubControls & SC_ScrollBarSubLine) && (flags & State_Sunken)) {
                        active = true;
                    }
                }

                ColorOption colOpt;
                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);
                if (active) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                drawKStylePrimitive(WT_ScrollBar, primitive, option, r, pal,
                                    flags, p, widget, &colOpt);
            } else {
                drawKStylePrimitive(WT_ScrollBar, ScrollBar::SingleButtonVert,
                                    option, r, pal, flags, p, widget);

                int  primitive;
                bool active   = false;

                if (element == CE_ScrollBarAddLine) {
                    primitive = Generic::ArrowDown;
                    if ((slOpt->activeSubControls & SC_ScrollBarAddLine) && (flags & State_Sunken)) {
                        active = true;
                    }
                } else {
                    primitive = Generic::ArrowUp;
                    if ((slOpt->activeSubControls & SC_ScrollBarSubLine) && (flags & State_Sunken)) {
                        active = true;
                    }
                }

                ColorOption colOpt;
                colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ArrowColor, option, widget);
                if (active) {
                    colOpt.color = widgetLayoutProp(WT_ScrollBar, ScrollBar::ActiveArrowColor, option, widget);
                }

                drawKStylePrimitive(WT_ScrollBar, primitive, option, r, pal,
                                    flags, p, widget, &colOpt);
            }
        }
        return;
    }

// TODO: what about CE_ScrollBarFirst, CE_ScrollBarLast...?
//         case CE_ScrollBarFirst:
//         case CE_ScrollBarLast:

    case CE_ScrollBarSlider: {
        drawKStylePrimitive(WT_ScrollBar,
                            (flags & State_Horizontal) ? ScrollBar::SliderHor  :
                            ScrollBar::SliderVert,
                            option, r, pal, flags, p, widget);
        return;
    }

    case CE_ScrollBarAddPage: {
        const QStyleOptionSlider *slOpt = ::qstyleoption_cast<const QStyleOptionSlider *>(option);
        if (!slOpt) {
            return;
        }

        if (flags & State_Horizontal)
            drawKStylePrimitive(WT_ScrollBar,
                                (slOpt->direction == Qt::LeftToRight) ? ScrollBar::GrooveAreaHorRight :
                                ScrollBar::GrooveAreaHorLeft,
                                option, r, pal, flags, p, widget);
        else
            drawKStylePrimitive(WT_ScrollBar, ScrollBar::GrooveAreaVertBottom,
                                option, r, pal, flags, p, widget);
        return;
    }

    case CE_ScrollBarSubPage: {
        const QStyleOptionSlider *slOpt = ::qstyleoption_cast<const QStyleOptionSlider *>(option);
        if (!slOpt) {
            return;
        }

        if (flags & State_Horizontal)
            drawKStylePrimitive(WT_ScrollBar,
                                (slOpt->direction == Qt::LeftToRight) ? ScrollBar::GrooveAreaHorLeft :
                                ScrollBar::GrooveAreaHorRight,
                                option, r, pal, flags, p, widget);
        else
            drawKStylePrimitive(WT_ScrollBar, ScrollBar::GrooveAreaVertTop,
                                option, r, pal, flags, p, widget);
        return;
    }

    //QCS's CE_TabBarTab is perfectly fine, so we just handle the subbits

    case CE_TabBarTabShape: {
        const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option);
        if (!tabOpt) {
            return;
        }

        // TabOverlap handling
        int tabOverlap = pixelMetric(PM_TabBarTabOverlap, option, widget);
        bool beginning = tabOpt->position == QStyleOptionTab::Beginning;
        bool onlyOne = tabOpt->position == QStyleOptionTab::OnlyOneTab;
        if (!beginning && !onlyOne) {
            switch (tabSide(tabOpt)) {
            case North:
            case South:
                if (option->direction == Qt::LeftToRight) {
                    r.adjust(-tabOverlap, 0, 0, 0);
                } else {
                    r.adjust(0, 0, tabOverlap, 0);
                }
                break;
            case East:
            case West:
                r.adjust(0, -tabOverlap, 0, 0);
            default:
                break;
            }
        }

        int prim;
        switch (tabSide(tabOpt)) {
        case North:
            prim = TabBar::NorthTab; break;
        case South:
            prim = TabBar::SouthTab; break;
        case East:
            prim = TabBar::EastTab; break;
        default:
            prim = TabBar::WestTab; break;
        }

        drawKStylePrimitive(WT_TabBar, prim, option, r, pal, flags, p, widget);

        return;
    }

    case CE_TabBarTabLabel: {
        const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option);
        if (!tabOpt) {
            return;
        }

        //First, we get our content region.
        QRect labelRect = subElementRect(SE_TabBarTabText, option, widget);

        Side tabSd = tabSide(tabOpt);

        //Now, what we do, depends on rotation, LTR vs. RTL, and text/icon combinations.
        //First, figure out if we have to deal with icons, and place them if need be.
        if (!tabOpt->icon.isNull()) {
            QStyleOptionTab tabV3(*tabOpt);
            QSize iconSize = tabV3.iconSize;
            if (!iconSize.isValid()) {
                int iconExtent = pixelMetric(PM_SmallIconSize);
                iconSize = QSize(iconExtent, iconExtent);
            }

            IconOption icoOpt;
            icoOpt.icon   = tabOpt->icon;
            icoOpt.active = flags & State_Selected;
            icoOpt.size = iconSize;

            if (tabOpt->text.isNull()) {
                //Icon only. Easy.
                drawKStylePrimitive(WT_TabBar, Generic::Icon, option, labelRect,
                                    pal, flags, p, widget, &icoOpt);
                return;
            }

            //OK, we have to stuff both icon and text. So we figure out where to stick the icon.
            QRect iconRect;

            if (tabSd == North || tabSd == South) {
                //OK, this is simple affair, we just pick a side for the icon
                //based on layout direction. (Actually, I guess text
                //would be more accurate, but I am -so- not doing BIDI here)
                if (tabOpt->direction == Qt::LeftToRight) {
                    //We place icon on the left.
                    iconRect = QRect(labelRect.x(), labelRect.y() + (labelRect.height() - iconSize.height() + 1) / 2,
                                     iconSize.width(), iconSize.height());

                    //Adjust the text rect.
                    labelRect.setLeft(labelRect.x() + iconSize.width() +
                                      widgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, option, widget));
                } else {
                    //We place icon on the right
                    iconRect = QRect(labelRect.x() + labelRect.width() - iconSize.width(),
                                     labelRect.y() + (labelRect.height() - iconSize.height() + 1) / 2, iconSize.width(), iconSize.height());
                    //Adjust the text rect
                    labelRect.setWidth(labelRect.width() - iconSize.width() -
                                       widgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, option, widget));
                }
            } else {
                bool aboveIcon = false;
                if (tabSd == West && tabOpt->direction == Qt::RightToLeft) {
                    aboveIcon = true;
                }
                if (tabSd == East && tabOpt->direction == Qt::LeftToRight) {
                    aboveIcon = true;
                }

                if (aboveIcon) {
                    iconRect = QRect(labelRect.x() + (labelRect.width() - iconSize.width() + 1) / 2, labelRect.y(),
                                     iconSize.width(), iconSize.height());
                    labelRect.setTop(labelRect.y() + iconSize.height() +
                                     widgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, option, widget));
                } else {
                    iconRect = QRect(labelRect.x() + (labelRect.width() - iconSize.width() + 1) / 2,
                                     labelRect.y() + labelRect.height() - iconSize.height(),
                                     iconSize.width(), iconSize.height());
                    labelRect.setHeight(labelRect.height() - iconSize.height() -
                                        widgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, option, widget));
                }
            }

            //Draw the thing
            drawKStylePrimitive(WT_TabBar, Generic::Icon, option, iconRect,
                                pal, flags, p, widget, &icoOpt);
        } //if have icon.

        //Draw text
        if (!tabOpt->text.isNull()) {
            TextOption lbOpt(tabOpt->text);
            if (widget) {
                lbOpt.color = widget->foregroundRole();
            }

            int primitive = Generic::Text; // For horizontal tabs

            if (tabSd == East) {
                primitive = TabBar::EastText;
            } else if (tabSd == West) {
                primitive = TabBar::WestText;
            }

            drawKStylePrimitive(WT_TabBar, primitive, option, labelRect,
                                pal, flags, p, widget, &lbOpt);
        }

        //If need be, draw focus rect
        if (tabOpt->state & State_HasFocus) {
            QRect focusRect = marginAdjustedTab(tabOpt, TabBar::TabFocusMargin);
            drawKStylePrimitive(WT_TabBar, Generic::FocusIndicator, option, focusRect,
                                pal, flags, p, widget);
        }
        return;
    }

    case CE_ToolBar: {
        if (flags & State_Horizontal) {
            drawKStylePrimitive(WT_ToolBar, ToolBar::PanelHor, option, r, pal, flags, p, widget);
        } else {
            drawKStylePrimitive(WT_ToolBar, ToolBar::PanelVert, option, r, pal, flags, p, widget);
        }

        return;
    }

    case CE_HeaderSection: {
        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            drawKStylePrimitive(WT_Header, (header->orientation == Qt::Horizontal) ? Header::SectionHor : Header::SectionVert,
                                option, r, pal, flags, p, widget);
            return;
        }
    }

    case CE_HeaderLabel: {
        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            QRect textRect = r;
            if (!header->icon.isNull()) {
                bool enabled = flags & State_Enabled;
                QPixmap pm = header->icon.pixmap(pixelMetric(PM_SmallIconSize), enabled ? QIcon::Normal : QIcon::Disabled);

                // TODO: respect header->iconAlignment.
                bool reverseLayout = header->direction == Qt::RightToLeft;
                int iy = r.top() + (r.height() - pm.height()) / 2;
                int ix = reverseLayout ? r.right() - pm.width() : r.left();
                QRect iconRect = QRect(ix, iy, pm.width(), pm.height());

                IconOption iconOpt;
                iconOpt.icon = pm;
                drawKStylePrimitive(WT_Header, Generic::Icon, option, iconRect, pal, flags, p, widget, &iconOpt);

                // adjust the rect for the text...
                int spacing = widgetLayoutProp(WT_Header, Header::TextToIconSpace, option, widget);
                if (reverseLayout) {
                    textRect.setRight(r.right() - iconRect.width() - spacing);
                } else {
                    textRect.setLeft(r.x() + iconRect.width() + spacing);
                }
            }

            TextOption lbOpt(header->text);
            lbOpt.hAlign = header->textAlignment;
            drawKStylePrimitive(WT_Header, Generic::Text, option, textRect, pal, flags, p, widget, &lbOpt);
        }
        return;
    }

    case CE_Splitter: {
        if (flags & State_Horizontal) {
            drawKStylePrimitive(WT_Splitter, Splitter::HandleHor, option, r, pal, flags, p, widget);
        } else {
            drawKStylePrimitive(WT_Splitter, Splitter::HandleVert, option, r, pal, flags, p, widget);
        }
        return;
    }

    default:
        break;
    }

    QCommonStyle::drawControl(element, option, p, widget);
}

int K4Style::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
{
    switch (hint) {
    case SH_ComboBox_ListMouseTracking:
        return true;

    case SH_MenuBar_MouseTracking:
    case SH_Menu_MouseTracking:
        return true;

    case SH_Menu_SubMenuPopupDelay:
        return 96; // Motif-like delay...

    case SH_TitleBar_NoBorder:
        return widgetLayoutProp(WT_Window, Window::NoTitleFrame, option, widget);

    case SH_GroupBox_TextLabelVerticalAlignment:
        if (widgetLayoutProp(WT_GroupBox, GroupBox::TextAlignTop, option, widget)) {
            return Qt::AlignTop;
        } else {
            return Qt::AlignVCenter;
        }

    case SH_GroupBox_TextLabelColor: {
        ColorMode cm(widgetLayoutProp(WT_GroupBox, GroupBox::TitleTextColor,
                                      option, widget));
        return cm.color(option ? option->palette : qApp->palette()).rgba();
    }

    case SH_DialogButtonLayout:
        return QDialogButtonBox::KdeLayout;

    case SH_ScrollBar_MiddleClickAbsolutePosition:
        return true;

    // Don't draw the branch as selected in tree views
    case SH_ItemView_ShowDecorationSelected:
        return false;

    case SH_ItemView_ActivateItemOnSingleClick:
        return KSharedConfig::openConfig()->group("KDE").readEntry("SingleClick", true);
    case SH_KCustomStyleElement:
        if (!widget) {
            return 0;
        }
        return d->styleElements.value(widget->objectName(), 0);

    // per HIG, align the contents in a form layout to the left
    case SH_FormLayoutFormAlignment:
        return Qt::AlignLeft | Qt::AlignTop;

    // per HIG, align the labels in a form layout to the right
    case SH_FormLayoutLabelAlignment:
        return Qt::AlignRight;

    case SH_FormLayoutFieldGrowthPolicy:
        return QFormLayout::ExpandingFieldsGrow;

    case SH_FormLayoutWrapPolicy:
        return QFormLayout::DontWrapRows;

    case SH_MessageBox_TextInteractionFlags:
        return true;

    case SH_DialogButtonBox_ButtonsHaveIcons: {
        // was KGlobalSettings::showIconsOnPushButtons() :
        KConfigGroup g(KSharedConfig::openConfig(), "KDE");
        return g.readEntry("ShowIconsOnPushButtons", true);
    }
    case SH_ItemView_ArrowKeysNavigateIntoChildren:
        return true;
    case SH_Widget_Animate: {
        KConfigGroup g(KSharedConfig::openConfig(), "KDE-Global GUI Settings");
        return g.readEntry("GraphicEffectsLevel", 0);
    }
    default:
        break;
    };

    return QCommonStyle::styleHint(hint, option, widget, returnData);
}

int K4Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    switch (metric) {
    case PM_SmallIconSize:
    case PM_ButtonIconSize:
        return KIconLoader::global()->currentSize(KIconLoader::Small);
    case PM_ToolBarIconSize:
        return KIconLoader::global()->currentSize(KIconLoader::Toolbar);
    case PM_LargeIconSize:
        return KIconLoader::global()->currentSize(KIconLoader::Dialog);
    case PM_MessageBoxIconSize:
        // TODO return KIconLoader::global()->currentSize(KIconLoader::MessageBox);
        return KIconLoader::SizeHuge;

    case PM_DefaultFrameWidth:
        if (qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
            return widgetLayoutProp(WT_GroupBox, GroupBox::FrameWidth, option, widget);
        } else {
            return widgetLayoutProp(WT_Generic, Generic::DefaultFrameWidth, option, widget);
        }

    case PM_DefaultChildMargin:
    case PM_DefaultTopLevelMargin:
        return widgetLayoutProp(WT_Generic, Generic::DefaultLayoutMargin, option, widget);

    case PM_LayoutHorizontalSpacing:
    case PM_LayoutVerticalSpacing:
        // use layoutSpacingImplementation
        return -1;

    case PM_DefaultLayoutSpacing:
        return widgetLayoutProp(WT_Generic, Generic::DefaultLayoutSpacing, option, widget);

    case PM_LayoutLeftMargin:
    case PM_LayoutTopMargin:
    case PM_LayoutRightMargin:
    case PM_LayoutBottomMargin: {
        PixelMetric marginMetric;
        if ((option && (option->state & QStyle::State_Window))
                || (widget && widget->isWindow())) {
            marginMetric = PM_DefaultTopLevelMargin;
        } else {
            marginMetric = PM_DefaultChildMargin;
        }
        return pixelMetric(marginMetric, option, widget);
    }

    case PM_ButtonMargin:
        return 0; //Better not return anything here since we already
    //incorporated this into SE_PushButtonContents
    case PM_ButtonDefaultIndicator:
        // PushButton::DefaultIndicatorMargin is used throughout KStyle button
        // implementation code, so this probably is not necessary.
        // return it in case Apps rely on this metric, though.
        return widgetLayoutProp(WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
    case PM_ButtonShiftHorizontal:
        return widgetLayoutProp(WT_PushButton, PushButton::PressedShiftHorizontal, option, widget);
    case PM_ButtonShiftVertical:
        return widgetLayoutProp(WT_PushButton, PushButton::PressedShiftVertical, option, widget);
    case PM_MenuButtonIndicator:
        if (qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            return widgetLayoutProp(WT_ToolButton, ToolButton::MenuIndicatorSize, option, widget);
        } else {
            return widgetLayoutProp(WT_PushButton, PushButton::MenuIndicatorSize, option, widget);
        }

    case PM_SplitterWidth:
        return widgetLayoutProp(WT_Splitter, Splitter::Width, option, widget);

    case PM_IndicatorWidth:
    case PM_IndicatorHeight:
        return widgetLayoutProp(WT_CheckBox, CheckBox::Size, option, widget);

    case PM_ExclusiveIndicatorWidth:
    case PM_ExclusiveIndicatorHeight:
        return widgetLayoutProp(WT_RadioButton, RadioButton::Size, option, widget);

    case PM_DockWidgetFrameWidth:
        return widgetLayoutProp(WT_DockWidget, DockWidget::FrameWidth, option, widget);

    case PM_DockWidgetSeparatorExtent:
        return widgetLayoutProp(WT_DockWidget, DockWidget::SeparatorExtent, option, widget);

    // handle extent only used somewhere in Qt3support, don't care.
    // case PM_DockWidgetHandleExtent:

    case PM_DockWidgetTitleMargin:
        return widgetLayoutProp(WT_DockWidget, DockWidget::TitleMargin, option, widget);

    case PM_ProgressBarChunkWidth:
        return widgetLayoutProp(WT_ProgressBar, ProgressBar::Precision, option, widget);

    case PM_MenuBarPanelWidth:
        return 0; //Simplification: just one primitive is used and it includes the border

    case PM_MenuBarHMargin: {
        //Calculate how much extra space we need besides the frame size. We use the left margin
        //here, and adjust the total rect by the difference between it and the right margin
        int spaceL = widgetLayoutProp(WT_MenuBar, MenuBar::Margin, option, widget) + widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Left, option, widget);

        return spaceL;
    }

    case PM_MenuBarVMargin: {
        //As above, we return the top one, and fudge the total size for the bottom.
        int spaceT = widgetLayoutProp(WT_MenuBar, MenuBar::Margin, option, widget) + widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Top, option, widget);
        return spaceT;
    }

    case PM_MenuBarItemSpacing:
        return widgetLayoutProp(WT_MenuBar, MenuBar::ItemSpacing, option, widget);

    case PM_MenuDesktopFrameWidth:
        return 0; //### CHECKME

    case PM_MenuPanelWidth:
        return widgetLayoutProp(WT_Menu, Menu::FrameWidth, option, widget);

    /* ### seems to trigger Qt bug. So we loose the margins for now
    case PM_MenuHMargin:
    {
    //Calculate how much extra space we need besides the frame size. We use the left margin
    //here, and adjust the total rect by the difference between it and the right margin
    int spaceL = widgetLayoutProp(WT_Menu, Menu::Margin, option, widget) + widgetLayoutProp(WT_Menu, Menu::Margin + Left, option, widget) -
            widgetLayoutProp(WT_Menu, Menu::FrameWidth, option, widget);

    return spaceL;
    }

    case PM_MenuVMargin:
    {
    //As above, we return the top one, and fudge the total size for the bottom.
    int spaceT = widgetLayoutProp(WT_Menu, Menu::Margin, option, widget) + widgetLayoutProp(WT_Menu, Menu::Margin + Top, option, widget) -
        widgetLayoutProp(WT_Menu, Menu::FrameWidth, option, widget);
    return spaceT;
    }     */

    case PM_MenuScrollerHeight:
        return widgetLayoutProp(WT_Menu, Menu::ScrollerHeight, option, widget);

    case PM_MenuTearoffHeight:
        return widgetLayoutProp(WT_Menu, Menu::TearOffHeight, option, widget);

    case PM_TabBarTabHSpace: {
        const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option);
        if (tabOpt) {
            //Perhaps we can avoid the extra margin...
            if (tabOpt->text.isNull() && !tabOpt->icon.isNull()) {
                return 0;
            }
            if (tabOpt->icon.isNull() && !tabOpt->text.isNull()) {
                return 0;
            }
        }

        return widgetLayoutProp(WT_TabBar, TabBar::TabTextToIconSpace, option, widget);
    }

    case PM_TabBarTabVSpace:
        return 0;

    case PM_TabBarBaseHeight:
        return widgetLayoutProp(WT_TabBar, TabBar::BaseHeight, option, widget);

    case PM_TabBarBaseOverlap:
        return widgetLayoutProp(WT_TabBar, TabBar::BaseOverlap, option, widget);

    case PM_TabBarTabOverlap:
        return widgetLayoutProp(WT_TabBar, TabBar::TabOverlap, option, widget);

    case PM_TabBarScrollButtonWidth:
        return widgetLayoutProp(WT_TabBar, TabBar::ScrollButtonWidth, option, widget);

    case PM_TabBarTabShiftVertical:
        return 1;

    case PM_TabBarTabShiftHorizontal:
        return 0;

    case PM_SliderControlThickness:
        return widgetLayoutProp(WT_Slider, Slider::HandleThickness, option, widget);

    case PM_SliderLength:
        return widgetLayoutProp(WT_Slider, Slider::HandleLength, option, widget);

    case PM_SliderThickness: {
        // not sure what the difference to PM_SliderControlThickness actually is
        return widgetLayoutProp(WT_Slider, Slider::HandleThickness, option, widget);
    }

    case PM_SpinBoxFrameWidth:
        return widgetLayoutProp(WT_SpinBox, SpinBox::FrameWidth, option, widget);

    case PM_ComboBoxFrameWidth:
        return widgetLayoutProp(WT_ComboBox, ComboBox::FrameWidth, option, widget);

    case PM_HeaderMarkSize:
        return widgetLayoutProp(WT_Header, Header::MarkSize, option, widget);

    case PM_HeaderMargin:
        return widgetLayoutProp(WT_Header, Header::TextToIconSpace, option, widget);

    case PM_ToolBarFrameWidth:
        return widgetLayoutProp(WT_ToolBar, ToolBar::FrameWidth, option, widget);

    case PM_ToolBarHandleExtent:
        return widgetLayoutProp(WT_ToolBar, ToolBar::HandleExtent, option, widget);

    case PM_ToolBarSeparatorExtent:
        return widgetLayoutProp(WT_ToolBar, ToolBar::SeparatorExtent, option, widget);

    case PM_ToolBarExtensionExtent:
        return widgetLayoutProp(WT_ToolBar, ToolBar::ExtensionExtent, option, widget);

    case PM_ToolBarItemMargin:
        return widgetLayoutProp(WT_ToolBar, ToolBar::ItemMargin, option, widget);

    case PM_ToolBarItemSpacing:
        return widgetLayoutProp(WT_ToolBar, ToolBar::ItemSpacing, option, widget);

    case PM_ScrollBarExtent:
        return widgetLayoutProp(WT_ScrollBar, ScrollBar::BarWidth, option, widget);

    case PM_TitleBarHeight:
        return widgetLayoutProp(WT_Window, Window::TitleHeight, option, widget);

    default:
        break;
    }

    return QCommonStyle::pixelMetric(metric, option, widget);
}

int K4Style::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget) const
{
    Q_UNUSED(control1); Q_UNUSED(control2); Q_UNUSED(orientation);

    return pixelMetric(PM_DefaultLayoutSpacing, option, widget);
}

bool K4Style::isVerticalTab(const QStyleOptionTab *tbOpt) const
{
    switch (tbOpt->shape) {
    case QTabBar::RoundedWest:
    case QTabBar::RoundedEast:
    case QTabBar::TriangularWest:
    case QTabBar::TriangularEast:
        return true;
    default:
        return false;
    }
}

bool K4Style::isReflectedTab(const QStyleOptionTab *tbOpt) const
{
    switch (tbOpt->shape) {
    case QTabBar::RoundedEast:
    case QTabBar::TriangularEast:
    case QTabBar::RoundedSouth:
    case QTabBar::TriangularSouth:
        return true;
    default:
        return false;
    }
}

K4Style::Side K4Style::tabSide(const QStyleOptionTab *tbOpt) const
{
    switch (tbOpt->shape) {
    case QTabBar::RoundedEast:
    case QTabBar::TriangularEast:
        return East;
    case QTabBar::RoundedWest:
    case QTabBar::TriangularWest:
        return West;
    case QTabBar::RoundedNorth:
    case QTabBar::TriangularNorth:
        return North;
    default:
        return South;
    }
}

QRect K4Style::marginAdjustedTab(const QStyleOptionTab *tabOpt, int property) const
{
    QRect r = tabOpt->rect;

    //For region, we first figure out the geometry if it was normal, and adjust.
    //this takes some rotating
    bool vertical = isVerticalTab(tabOpt);
    bool flip     = isReflectedTab(tabOpt);

    QRect idializedGeometry = vertical ? QRect(0, 0, r.height(), r.width())
                              : QRect(0, 0, r.width(),  r.height());

    QRect contentArea = insideMargin(idializedGeometry, WT_TabBar, property, tabOpt, nullptr);

    int leftMargin  = contentArea.x();
    int rightMargin = idializedGeometry.width() - 1 - contentArea.right();
    int topMargin   = contentArea.y();
    int botMargin   = idializedGeometry.height() - 1 - contentArea.bottom();

    if (vertical) {
        int t       = rightMargin;
        rightMargin = topMargin;
        topMargin   = leftMargin;
        leftMargin  = botMargin;
        botMargin   = t;

        if (!flip) {
            qSwap(leftMargin, rightMargin);
        }
    } else if (flip) {
        qSwap(topMargin, botMargin);
        //For horizontal tabs, we also want to reverse stuff for RTL!
        if (tabOpt->direction == Qt::RightToLeft) {
            qSwap(leftMargin, rightMargin);
        }
    }

    QRect geom =
        QRect(QPoint(leftMargin, topMargin),
              QPoint(r.width()  - 1 - rightMargin,
                     r.height() - 1 - botMargin));
    geom.translate(r.topLeft());
    return geom;
}

bool K4Style::useSideText(const QStyleOptionProgressBar *pbOpt) const
{
    if (widgetLayoutProp(WT_ProgressBar, ProgressBar::SideText) == 0) {
        return false;
    }

    if (!pbOpt) {
        return false;    //Paranoia
    }

    if (!pbOpt->textVisible) {
        return false;    //Don't allocate side margin if text display is off...
    }

    if (pbOpt->textAlignment & Qt::AlignHCenter) {
        return false;    //### do we want this? we don't
    }
    //force indicator to the side outside
    //the main otherwise.

    if (pbOpt->minimum == pbOpt->maximum) {
        return false;
    }

    int widthAlloc = pbOpt->fontMetrics.width(QLatin1String("100%"));

    if (pbOpt->fontMetrics.width(pbOpt->text) > widthAlloc) {
        return false;    //Doesn't fit!
    }

    return true;
}

int K4Style::sideTextWidth(const QStyleOptionProgressBar *pbOpt) const
{
    return pbOpt->fontMetrics.width(QLatin1String("100%")) +
           2 * widgetLayoutProp(WT_ProgressBar, ProgressBar::SideTextSpace);
}

QRect K4Style::subElementRect(SubElement sr, const QStyleOption *option, const QWidget *widget) const
{
    QRect r = option->rect;

    switch (sr) {
    case SE_PushButtonContents: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return r;
        }

        if ((bOpt->features & QStyleOptionButton::DefaultButton) || (bOpt->features & QStyleOptionButton::AutoDefaultButton)) {
            r = insideMargin(r, WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
        }

        return insideMargin(r, WT_PushButton, PushButton::ContentsMargin, option, widget);
    }

    case SE_PushButtonFocusRect: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return r;
        }

        if ((bOpt->features & QStyleOptionButton::DefaultButton) || (bOpt->features & QStyleOptionButton::AutoDefaultButton)) {
            r = insideMargin(r, WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
        }

        return insideMargin(r, WT_PushButton, PushButton::FocusMargin, option, widget);
    }

    case SE_ToolBoxTabContents: {
        return insideMargin(r, WT_ToolBoxTab, ToolBoxTab::Margin, option, widget);
    }

    case SE_CheckBoxContents: {
        r.setX(r.x() + widgetLayoutProp(WT_CheckBox, CheckBox::Size, option, widget) +
               widgetLayoutProp(WT_CheckBox, CheckBox::BoxTextSpace, option, widget));
        return handleRTL(option, r);
    }

    case SE_RadioButtonContents: {
        r.setX(r.x() + widgetLayoutProp(WT_RadioButton, RadioButton::Size, option, widget) +
               widgetLayoutProp(WT_RadioButton, RadioButton::BoxTextSpace, option, widget));
        return handleRTL(option, r);
    }

    case SE_CheckBoxFocusRect: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return r;
        }

        QRect ret;

        if (bOpt->text.isEmpty()) {
            // first convert, so we can deal with logical coords
            QRect checkRect =
                handleRTL(option, subElementRect(SE_CheckBoxIndicator, option, widget));
            ret = insideMargin(checkRect, WT_CheckBox, CheckBox::NoLabelFocusMargin, option, widget);
        } else {
            // first convert, so we can deal with logical coords
            QRect contentsRect =
                handleRTL(option, subElementRect(SE_CheckBoxContents, option, widget));
            ret = insideMargin(contentsRect, WT_CheckBox, CheckBox::FocusMargin, option, widget);
        }
        // convert back to screen coords
        return handleRTL(option, ret);
    }

    case SE_RadioButtonFocusRect: {
        // first convert it back to logical coords
        QRect contentsRect =
            handleRTL(option, subElementRect(SE_RadioButtonContents, option, widget));

        // modify the rect and convert back to screen coords
        return handleRTL(option,
                         insideMargin(contentsRect, WT_RadioButton,
                                      RadioButton::FocusMargin, option, widget));
    }

    case SE_ProgressBarGroove: {
        const QStyleOptionProgressBar *pbOpt = ::qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        if (useSideText(pbOpt)) {
            r.setWidth(r.width() - sideTextWidth(pbOpt));
            return r;
        }

        //Centering mode --- could be forced or side... so the groove area is everything
        return r;
    }

    case SE_ProgressBarContents: {
        QRect grooveRect = subElementRect(SE_ProgressBarGroove, option, widget);
        return insideMargin(grooveRect, WT_ProgressBar, ProgressBar::GrooveMargin, option, widget);
    }

    case SE_ProgressBarLabel: {
        const QStyleOptionProgressBar *pbOpt = ::qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        if (useSideText(pbOpt)) {
            int width = sideTextWidth(pbOpt);
            return QRect(r.x() + r.width() - width, r.y(), width, r.height());
        }

        //The same as the contents area..
        return subElementRect(SE_PushButtonContents, option, widget);
    }

    // SE_TabWidgetTabPane implementation in QCommonStyle is perfectly fine.
    case SE_TabWidgetTabContents: {
        const QStyleOptionTabWidgetFrame *tabOpt = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
        if (!tabOpt) {
            break;
        }

        // Don't apply the custom margin when documentMode is enabled.
        if (tabOpt->lineWidth == 0) {
            break;
        }

        // use QCommonStyle's SE_TabWidgetTabPane, and adjust the result
        // according to the custom frame width.
        QRect pane = QCommonStyle::subElementRect(SE_TabWidgetTabPane, option, widget);
        int m   = widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin, option, widget);
        int top = m + widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Top,
                                       option, widget);
        int bot = m + widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Bot,
                                       option, widget);
        int left = m + widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Left,
                                        option, widget);
        int right = m + widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Right,
                                         option, widget);

        switch (tabOpt->shape) {
        case QTabBar::RoundedNorth:
        case QTabBar::TriangularNorth:
            return pane.adjusted(left, top, -right, -bot);
        case QTabBar::RoundedEast:
        case QTabBar::TriangularEast:
            return pane.adjusted(bot, left, -top, -right);
        case QTabBar::RoundedSouth:
        case QTabBar::TriangularSouth:
            return pane.adjusted(right, bot, -left, -top);
        case QTabBar::RoundedWest:
        case QTabBar::TriangularWest:
            return pane.adjusted(top, right, -bot, -left);
        }
    }

    case SE_TabBarTabText: {
        const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option);
        if (!tabOpt) {
            return QRect();
        }

        QRect r = marginAdjustedTab(tabOpt, TabBar::TabContentsMargin);
        QStyleOptionTab tov3(*tabOpt);

        switch (tov3.shape) {
        case QTabBar::RoundedNorth:
        case QTabBar::TriangularNorth:
        case QTabBar::RoundedSouth:
        case QTabBar::TriangularSouth:
            if (tov3.direction == Qt::LeftToRight) {
                r.adjust(tov3.leftButtonSize.width(), 0, -tov3.rightButtonSize.width(), 0);
            } else {
                r.adjust(tov3.rightButtonSize.width(), 0, -tov3.leftButtonSize.width(), 0);
            }
            break;
        case QTabBar::RoundedEast:
        case QTabBar::TriangularEast:
            r.adjust(0, tov3.leftButtonSize.width(), 0, -tov3.rightButtonSize.width());
            break;
        case QTabBar::RoundedWest:
        case QTabBar::TriangularWest:
            r.adjust(0, tov3.rightButtonSize.width(), 0, -tov3.leftButtonSize.width());
            break;
        }

        return r;
    }

    default:
        break;
    }

    return QCommonStyle::subElementRect(sr, option, widget);
}

void  K4Style::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
                                  QPainter *p,      const QWidget *w) const
{
    //Extract the stuff we need out of the option
    State flags = opt->state;
    QRect      r     = opt->rect;
    QPalette   pal   = opt->palette;

    switch (cc) {
    case CC_ScrollBar: {
        QStyleOptionComplex *mutableOpt = const_cast<QStyleOptionComplex *>(opt);
        if ((mutableOpt->subControls & SC_ScrollBarSubLine) || (mutableOpt->subControls & SC_ScrollBarAddLine)) {
            //If we paint one of the buttons, must paint both!
            mutableOpt->subControls |= SC_ScrollBarSubPage | SC_ScrollBarAddLine;
        }
        //Note: we falldown to the base intentionally
    }
    break;

    case CC_Slider: {
        if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
            QRect groove = subControlRect(CC_Slider, slider, SC_SliderGroove, w);
            QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, w);
            bool hor = slider->orientation == Qt::Horizontal;

            if (slider->subControls & SC_SliderTickmarks) {
                // TODO: make tickmarks customizable with Slider::Tickmark-primitives?
                QStyleOptionSlider tmpSlider = *slider;
                tmpSlider.subControls = SC_SliderTickmarks;
                QCommonStyle::drawComplexControl(cc, &tmpSlider, p, w);
            }

            if ((slider->subControls & SC_SliderGroove) && groove.isValid()) {
                drawKStylePrimitive(WT_Slider, hor ? Slider::GrooveHor : Slider::GrooveVert, opt, groove, pal, flags, p, w);
            }

            if (slider->subControls & SC_SliderHandle) {
                drawKStylePrimitive(WT_Slider, hor ? Slider::HandleHor : Slider::HandleVert, opt, handle, pal, flags, p, w);

                if (slider->state & State_HasFocus) {
                    QRect focus = subElementRect(SE_SliderFocusRect, slider, w);
                    drawKStylePrimitive(WT_Slider, Generic::FocusIndicator, opt, focus, pal, flags, p, w, nullptr);
                }
            }
        } //option OK
        return;
    } //CC_Slider

    case CC_SpinBox: {
        if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
            bool activeSbUp = sb->activeSubControls & SC_SpinBoxUp && (flags & State_Sunken);
            bool activeSbDown = sb->activeSubControls & SC_SpinBoxDown && (flags & State_Sunken);

            if (sb->subControls & SC_SpinBoxFrame) {
                drawKStylePrimitive(WT_SpinBox, Generic::Frame, opt, r, pal, flags, p, w);
            }

            if (sb->subControls & SC_SpinBoxEditField) {
                QRect editField = subControlRect(CC_SpinBox, opt, SC_SpinBoxEditField, w);
                drawKStylePrimitive(WT_SpinBox, SpinBox::EditField, opt, editField, pal, flags, p, w);
            }

            QRect upRect, downRect;
            if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
                upRect   = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp,   w);
                downRect = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
                QRect buttonAreaRect = upRect | downRect;
                drawKStylePrimitive(WT_SpinBox, SpinBox::ButtonArea, opt, buttonAreaRect, pal, flags, p, w);
            }

            if (sb->subControls & SC_SpinBoxUp) {
                // adjust the sunken state flag...
                State upFlags = flags;
                if (activeSbUp) {
                    upFlags |= State_Sunken;
                } else {
                    upFlags &= ~State_Sunken;
                }

                drawKStylePrimitive(WT_SpinBox, SpinBox::UpButton, opt, upRect, pal, upFlags, p, w);

                // draw symbol...
                int primitive;
                if (sb->buttonSymbols == QAbstractSpinBox::PlusMinus) {
                    primitive = SpinBox::PlusSymbol;
                } else {
                    primitive = Generic::ArrowUp;
                }
                drawKStylePrimitive(WT_SpinBox, primitive, opt, upRect, pal, upFlags, p, w);
            }

            if (sb->subControls & SC_SpinBoxDown) {
                // adjust the sunken state flag...
                State downFlags = flags;
                if (activeSbDown) {
                    downFlags |= State_Sunken;
                } else {
                    downFlags &= ~State_Sunken;
                }

                drawKStylePrimitive(WT_SpinBox, SpinBox::DownButton, opt, downRect, pal, downFlags, p, w);

                // draw symbol...
                int primitive;
                if (sb->buttonSymbols == QAbstractSpinBox::PlusMinus) {
                    primitive = SpinBox::MinusSymbol;
                } else {
                    primitive = Generic::ArrowDown;
                }
                drawKStylePrimitive(WT_SpinBox, primitive, opt, downRect, pal, downFlags, p, w);
            }

            return;
        } //option OK
    } //CC_SpinBox

    case CC_ComboBox: {
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
            if (cb->subControls & SC_ComboBoxFrame) {
                drawKStylePrimitive(WT_ComboBox, Generic::Frame, opt, r, pal, flags, p, w);

                // focus indicator
                if (cb->state & State_HasFocus) {
                    QRect editField = subControlRect(CC_ComboBox, opt, SC_ComboBoxEditField, w);
                    QRect focusRect = insideMargin(editField, WT_ComboBox, ComboBox::FocusMargin, opt, w);
                    drawKStylePrimitive(WT_ComboBox, Generic::FocusIndicator, opt, focusRect, pal, flags, p, w, nullptr);
                }
            }

            if (cb->subControls & SC_ComboBoxEditField) {
                QRect editField = subControlRect(CC_ComboBox, opt, SC_ComboBoxEditField, w);
                drawKStylePrimitive(WT_ComboBox, ComboBox::EditField, opt, editField, pal, flags, p, w);
            }

            if (cb->subControls & SC_ComboBoxArrow) {
                QRect buttonRect = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
                drawKStylePrimitive(WT_ComboBox, ComboBox::Button, opt, buttonRect, pal, flags, p, w);

                // draw symbol...
                drawKStylePrimitive(WT_ComboBox, Generic::ArrowDown, opt, buttonRect, pal, flags, p, w);
            }

            return;
        } //option OK
        break;
    } //CC_Combo

    case CC_ToolButton: {
        if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
            QRect buttonRect = subControlRect(cc, tool, SC_ToolButton, w);
            QRect menuRect = subControlRect(cc, tool, SC_ToolButtonMenu, w);

            // State_AutoRaise: only draw button when State_MouseOver
            State bflags = tool->state;
            if (bflags & State_AutoRaise) {
                if (!(bflags & State_MouseOver)) {
                    bflags &= ~State_Raised;
                }
            }
            State mflags = bflags;

            QStyleOption tOpt(0);
            tOpt.palette = pal;

            if (tool->subControls & SC_ToolButton) {
                if (bflags & (State_Sunken | State_On | State_Raised)) {
                    tOpt.rect = buttonRect;
                    tOpt.state = bflags;
                    drawPrimitive(PE_PanelButtonTool, &tOpt, p, w);
                }
            }

            if (tool->subControls & SC_ToolButtonMenu) {
                tOpt.rect = menuRect;
                tOpt.state = mflags;
                drawPrimitive(PE_IndicatorButtonDropDown, &tOpt, p, w);
            } else if (tool->features & QStyleOptionToolButton::HasMenu) {
                // This is requesting KDE3-style arrow indicator, per Qt 4.4 behavior. Qt 4.3 prefers to hide
                // the fact of the menu's existence. Whee! Since we don't know how to paint this right,
                // though, we have to have some metrics set for it to look nice.
                int size = widgetLayoutProp(WT_ToolButton, ToolButton::InlineMenuIndicatorSize, opt, w);

                if (size) {
                    int xOff = widgetLayoutProp(WT_ToolButton, ToolButton::InlineMenuIndicatorXOff, opt, w);
                    int yOff = widgetLayoutProp(WT_ToolButton, ToolButton::InlineMenuIndicatorYOff, opt, w);

                    QRect r = QRect(buttonRect.right() + xOff, buttonRect.bottom() + yOff, size, size);
                    tOpt.rect  = r;
                    tOpt.state = bflags;
                    drawPrimitive(PE_IndicatorButtonDropDown, &tOpt, p, w);
                }
            }

            if (flags & State_HasFocus) {
                QRect focusRect = insideMargin(r, WT_ToolButton, ToolButton::FocusMargin, opt, w);
                tOpt.rect = focusRect;
                tOpt.state = bflags;
                drawKStylePrimitive(WT_ToolButton, Generic::FocusIndicator, &tOpt, focusRect, pal, bflags, p, w);
            }

            // CE_ToolButtonLabel expects a readjusted rect, for the button area proper
            QStyleOptionToolButton labelOpt = *tool;
            labelOpt.rect = buttonRect;
            drawControl(CE_ToolButtonLabel, &labelOpt, p, w);

            return;
        }
        break;
    } //CC_ToolButton

    case CC_TitleBar: {
        const QStyleOptionTitleBar *tb =
            qstyleoption_cast<const QStyleOptionTitleBar *>(opt);
        if (!tb) {
            break;
        }

        // title bar
        drawKStylePrimitive(WT_Window, Window::TitlePanel, opt, r, pal, flags, p, w);

        // TODO: different color depending on Active/inactive state
        // draw title text
        QRect textRect = subControlRect(CC_TitleBar, tb, SC_TitleBarLabel, w);
        TextOption textOpt(tb->text);
        textOpt.color = widgetLayoutProp(WT_Window, Window::TitleTextColor, opt, w);
        drawKStylePrimitive(WT_Window, Generic::Text, opt, textRect,
                            pal, flags, p, w, &textOpt);

        TitleButtonOption buttonKOpt;
        buttonKOpt.icon = tb->icon;

        if ((tb->subControls & SC_TitleBarSysMenu) &&
                (tb->titleBarFlags & Qt::WindowSystemMenuHint)) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarSysMenu)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarSysMenu, w);
            drawKStylePrimitive(WT_Window, Window::ButtonMenu, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if ((tb->subControls & SC_TitleBarMinButton) &&
                (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarMinButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarMinButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonMin, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if ((tb->subControls & SC_TitleBarMaxButton) &&
                (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarMaxButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarMaxButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonMax, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if ((tb->subControls & SC_TitleBarCloseButton) &&
                (tb->titleBarFlags & Qt::WindowSystemMenuHint)) {
//                 bool hover = (tb->activeSubControls & SC_TitleBarCloseButton)
//                         && (tb->state & State_MouseOver);
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarCloseButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarCloseButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonClose, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if ((tb->subControls & SC_TitleBarNormalButton) &&
                (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
                  (tb->titleBarState & Qt::WindowMinimized)) ||
                 ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
                  (tb->titleBarState & Qt::WindowMaximized)))) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarNormalButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarNormalButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonRestore, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if (tb->subControls & SC_TitleBarShadeButton) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarShadeButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarShadeButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonShade, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if (tb->subControls & SC_TitleBarUnshadeButton) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarUnshadeButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarUnshadeButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonUnshade, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        if ((tb->subControls & SC_TitleBarContextHelpButton)
                && (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)) {
            buttonKOpt.active = (tb->activeSubControls & SC_TitleBarContextHelpButton)
                                && (tb->state & State_Sunken);
            QRect br = subControlRect(CC_TitleBar, tb, SC_TitleBarContextHelpButton, w);
            drawKStylePrimitive(WT_Window, Window::ButtonHelp, opt, br, pal, flags, p, w,
                                &buttonKOpt);
        }

        return;
    } // CC_TitleBar

    default:
        break;
    } //switch

    QCommonStyle::drawComplexControl(cc, opt, p, w);
}

QRect K4Style::internalSubControlRect(ComplexControl control, const QStyleOptionComplex *option,
                                      SubControl subControl, const QWidget *widget) const
{
    QRect r = option->rect;

    if (control == CC_ScrollBar) {
        switch (subControl) {
        //The "top" arrow
        case SC_ScrollBarSubLine: {
            int majorSize;
            if (widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleTopButton, option, widget)) {
                majorSize = widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleButtonHeight, option, widget);
            } else {
                majorSize = widgetLayoutProp(WT_ScrollBar, ScrollBar::SingleButtonHeight, option, widget);
            }

            if (option->state & State_Horizontal) {
                return handleRTL(option, QRect(r.x(), r.y(), majorSize, r.height()));
            } else {
                return handleRTL(option, QRect(r.x(), r.y(), r.width(), majorSize));
            }

        }

        //The "bottom" arrow
        case SC_ScrollBarAddLine: {
            int majorSize;
            if (widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleBotButton, option, widget)) {
                majorSize = widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleButtonHeight, option, widget);
            } else {
                majorSize = widgetLayoutProp(WT_ScrollBar, ScrollBar::SingleButtonHeight, option, widget);
            }

            if (option->state & State_Horizontal) {
                return handleRTL(option, QRect(r.right() - majorSize + 1, r.y(), majorSize, r.height()));
            } else {
                return handleRTL(option, QRect(r.x(), r.bottom() - majorSize + 1, r.width(), majorSize));
            }
        }

        default:
            break;
        }
    }

    return QRect();
}

QRect K4Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
                              SubControl subControl, const QWidget *widget) const
{
    QRect r = option->rect;

    switch (control) {
    case CC_ScrollBar: {
        switch (subControl) {
        //For both arrows, we return -everything-,
        //to get stuff to repaint right. See internalSubControlRect
        //for the real thing
        case SC_ScrollBarSubLine:
        case SC_ScrollBarAddLine:
            return r;

        //The main groove area. This is used to compute the others...
        case SC_ScrollBarGroove: {
            QRect top = handleRTL(option, internalSubControlRect(control, option, SC_ScrollBarSubLine, widget));
            QRect bot = handleRTL(option, internalSubControlRect(control, option, SC_ScrollBarAddLine, widget));

            QPoint topLeftCorner, botRightCorner;
            if (option->state & State_Horizontal) {
                topLeftCorner  = QPoint(top.right() + 1, top.top());
                botRightCorner = QPoint(bot.left()  - 1, top.bottom());
            } else {
                topLeftCorner  = QPoint(top.left(),  top.bottom() + 1);
                botRightCorner = QPoint(top.right(), bot.top()    - 1);
            }

            return handleRTL(option, QRect(topLeftCorner, botRightCorner));
        }

        case SC_ScrollBarFirst:
        case SC_ScrollBarLast:
            return QRect();

        case SC_ScrollBarSlider: {
            const QStyleOptionSlider *slOpt = ::qstyleoption_cast<const QStyleOptionSlider *>(option);

            //We do handleRTL here to unreflect things if need be
            QRect groove = handleRTL(option, subControlRect(control, option, SC_ScrollBarGroove, widget));
            Q_ASSERT(slOpt);

            if (slOpt->minimum == slOpt->maximum) {
                return groove;
            }

            //Figure out how much room we have..
            int space;
            if (option->state & State_Horizontal) {
                space = groove.width();
            } else {
                space = groove.height();
            }

            //Calculate the portion of this space that the slider should take up.
            int sliderSize = int(space * float(slOpt->pageStep) /
                                 (slOpt->maximum - slOpt->minimum + slOpt->pageStep));

            if (sliderSize < widgetLayoutProp(WT_ScrollBar, ScrollBar::MinimumSliderHeight, option, widget)) {
                sliderSize = widgetLayoutProp(WT_ScrollBar, ScrollBar::MinimumSliderHeight, option, widget);
            }

            if (sliderSize > space) {
                sliderSize = space;
            }

            //What do we have remaining?
            space = space - sliderSize;

            //uhm, yeah, nothing much
            if (space <= 0) {
                return groove;
            }

            int pos = qRound(float(slOpt->sliderPosition - slOpt->minimum) /
                             (slOpt->maximum - slOpt->minimum) * space);
            if (option->state & State_Horizontal) {
                return handleRTL(option, QRect(groove.x() + pos, groove.y(), sliderSize, groove.height()));
            } else {
                return handleRTL(option, QRect(groove.x(), groove.y() + pos, groove.width(), sliderSize));
            }
        }

        case SC_ScrollBarSubPage: {
            //We do handleRTL here to unreflect things if need be
            QRect slider = handleRTL(option, subControlRect(control, option, SC_ScrollBarSlider, widget));
            QRect groove = handleRTL(option, subControlRect(control, option, SC_ScrollBarGroove, widget));

            //We're above the slider in the groove.
            if (option->state & State_Horizontal) {
                return handleRTL(option, QRect(groove.x(), groove.y(), slider.x() - groove.x(), groove.height()));
            } else {
                return handleRTL(option, QRect(groove.x(), groove.y(), groove.width(), slider.y() - groove.y()));
            }
        }

        case SC_ScrollBarAddPage: {
            //We do handleRTL here to unreflect things if need be
            QRect slider = handleRTL(option, subControlRect(control, option, SC_ScrollBarSlider, widget));
            QRect groove = handleRTL(option, subControlRect(control, option, SC_ScrollBarGroove, widget));

            //We're below the slider in the groove.
            if (option->state & State_Horizontal)
                return handleRTL(option,
                                 QRect(slider.right() + 1, groove.y(), groove.right() - slider.right(), groove.height()));
            else
                return handleRTL(option,
                                 QRect(groove.x(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom()));
        }

        default:
            break;
        }
    } //CC_ScrollBar

    case CC_SpinBox: {
        if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {

            int fw = widgetLayoutProp(WT_SpinBox, SpinBox::FrameWidth, option, widget);
            int bw = widgetLayoutProp(WT_SpinBox, SpinBox::ButtonWidth, option, widget);
            int bm = widgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin, option, widget);
            int bml = bm + widgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Left, option, widget);
            int bmr = bm + widgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Right, option, widget);
            int bmt = bm + widgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Top, option, widget);
            int bmb = bm + widgetLayoutProp(WT_SpinBox, SpinBox::ButtonMargin + Bot, option, widget);
            int bs = widgetLayoutProp(WT_SpinBox, SpinBox::ButtonSpacing, option, widget);
            bool symmButtons = widgetLayoutProp(WT_SpinBox, SpinBox::SymmetricButtons, option, widget);
            bool supportFrameless = widgetLayoutProp(WT_SpinBox, SpinBox::SupportFrameless, option, widget);

            // SpinBox without a frame, set the corresponding layout values to 0, reduce button width.
            if (supportFrameless && !sb->frame) {
                bw = bw - bmr; // reduce button with as the right button margin will be ignored.
                fw = 0;
                bmt = bmb = bmr = 0;
            }

            const int buttonsWidth = bw - bml - bmr;
            const int buttonsLeft = r.right() - bw + bml + 1;

            // compute the height of each button...
            int availableButtonHeight = r.height() - bmt - bmb - bs;
            if (symmButtons) {
                // make sure the availableButtonHeight is even by reducing the
                // button spacing by 1 if necessary. Results in both buttons
                // of the same height...
                if (availableButtonHeight % 2 != 0) {
                    --bs;

                    // recalculate...
                    availableButtonHeight = r.height() - bmt - bmb - bs;
                }
            }
            int heightUp = availableButtonHeight / 2;
            int heightDown = availableButtonHeight - heightUp;

            switch (subControl) {
            case SC_SpinBoxUp:
                return handleRTL(option,
                                 QRect(buttonsLeft, r.top() + bmt, buttonsWidth, heightUp));
            case SC_SpinBoxDown:
                return handleRTL(option,
                                 QRect(buttonsLeft, r.bottom() - bmb - heightDown + 1, buttonsWidth, heightDown));
            case SC_SpinBoxEditField: {
                QRect labelRect(r.left() + fw, r.top() + fw, r.width() - fw - bw, r.height() - 2 * fw);
                labelRect = insideMargin(labelRect, WT_SpinBox, SpinBox::ContentsMargin, option, widget);
                return handleRTL(option, labelRect);
            }
            case SC_SpinBoxFrame:
                return (sb->frame || !supportFrameless) ? r : QRect();
            default:
                break;
            }
        } //option ok
    } //CC_SpinBox

    case CC_ComboBox: {
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {

            int fw = widgetLayoutProp(WT_ComboBox, ComboBox::FrameWidth, option, widget);
            int bw = widgetLayoutProp(WT_ComboBox, ComboBox::ButtonWidth, option, widget);
            int bm = widgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin, option, widget);
            int bml = bm + widgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Left, option, widget);
            int bmr = bm + widgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Right, option, widget);
            int bmt = bm + widgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Top, option, widget);
            int bmb = bm + widgetLayoutProp(WT_ComboBox, ComboBox::ButtonMargin + Bot, option, widget);
            bool supportFrameless = widgetLayoutProp(WT_ComboBox, ComboBox::SupportFrameless, option, widget);

            // ComboBox without a frame, set the corresponding layout values to 0, reduce button width.
            if (supportFrameless && !cb->frame) {
                bw = bw - bmr; // reduce button with as the right button margin will be ignored.
                fw = 0;
                bmt = bmb = bmr = 0;
            }

            switch (subControl) {
            case SC_ComboBoxFrame:
                return (cb->frame || !supportFrameless) ? r : QRect();
            case SC_ComboBoxArrow:
                return handleRTL(option,
                                 QRect(r.right() - bw + bml + 1, r.top() + bmt, bw - bml - bmr, r.height() - bmt - bmb));
            case SC_ComboBoxEditField: {
                QRect labelRect(r.left() + fw, r.top() + fw, r.width() - fw - bw, r.height() - 2 * fw);
                labelRect = insideMargin(labelRect, WT_ComboBox, ComboBox::ContentsMargin, option, widget);
                return handleRTL(option, labelRect);
            }
            case SC_ComboBoxListBoxPopup:
                // TODO: need to add layoutProps to control the popup rect?
//                         return cb->popupRect;
                // popupRect seems to be empty, so use QStyleOption::rect as Qt's styles do
                return r;
            default:
                break;
            }
        } //option ok
    } //CC_ComboBox

    case CC_TitleBar: {
        const QStyleOptionTitleBar *tbOpt =
            qstyleoption_cast<const QStyleOptionTitleBar *>(option);
        if (!tbOpt) {
            break;
        }

        QRect ret = insideMargin(r, WT_Window, Window::TitleMargin, option, widget);

        const int btnHeight = ret.height();
        const int btnWidth = widgetLayoutProp(WT_Window, Window::ButtonWidth, option, widget);
        const int btnSpace = widgetLayoutProp(WT_Window, Window::ButtonSpace, option, widget);
        const int titleSpace = widgetLayoutProp(WT_Window, Window::ButtonToTextSpace, option, widget);

        bool isMinimized = tbOpt->titleBarState & Qt::WindowMinimized;
        bool isMaximized = tbOpt->titleBarState & Qt::WindowMaximized;

        // button layout:  menu -title- help,shade,min,max,close

        bool menuCloseBtn = tbOpt->titleBarFlags & Qt::WindowSystemMenuHint;
        bool minBtn = !isMinimized &&
                      (tbOpt->titleBarFlags & Qt::WindowMinimizeButtonHint);
        bool maxBtn = !isMaximized &&
                      (tbOpt->titleBarFlags & Qt::WindowMaximizeButtonHint);
        bool restoreBtn =
            (isMinimized && (tbOpt->titleBarFlags & Qt::WindowMinimizeButtonHint)) ||
            (isMaximized && (tbOpt->titleBarFlags & Qt::WindowMaximizeButtonHint));
        bool shadeBtn = tbOpt->titleBarFlags & Qt::WindowShadeButtonHint;
        bool helpBtn = tbOpt->titleBarFlags & Qt::WindowContextHelpButtonHint;

        int btnOffsetCount = 0; // for button rects; count the position in the button bar

        switch (subControl) {
        case SC_TitleBarLabel: {
            if (tbOpt->titleBarFlags & Qt::WindowTitleHint) {
                int cLeft = 0; // count buttons in the button bar
                int cRight = 0;

                if (menuCloseBtn) {
                    // menu and close button
                    ++cLeft;
                    ++cRight;
                }
                if (minBtn) {
                    ++cRight;
                }
                if (restoreBtn) {
                    ++cRight;
                }
                if (maxBtn) {
                    ++cRight;
                }
                if (shadeBtn) {
                    ++cRight;
                }
                if (helpBtn) {
                    ++cRight;
                }

                ret.adjust(cLeft * btnWidth + (cLeft - 1)*btnSpace + titleSpace, 0,
                           -(titleSpace + cRight * btnWidth + (cRight - 1)*btnSpace), 0);
            }
            break;
        }

        case SC_TitleBarSysMenu: {
            if (tbOpt->titleBarFlags & Qt::WindowSystemMenuHint) {
                ret.setRect(ret.left(), ret.top(), btnWidth, btnHeight);
            }
            break;
        }

        case SC_TitleBarContextHelpButton:
            if (helpBtn) {
                ++btnOffsetCount;
            }
        case SC_TitleBarMinButton:
            if (minBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarMinButton) {
                return QRect();
            }
        case SC_TitleBarNormalButton:
            if (restoreBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarNormalButton) {
                return QRect();
            }
        case SC_TitleBarMaxButton:
            if (maxBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarMaxButton) {
                return QRect();
            }
        case SC_TitleBarShadeButton:
            if (!isMinimized && shadeBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarShadeButton) {
                return QRect();
            }
        case SC_TitleBarUnshadeButton:
            if (isMinimized && shadeBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarUnshadeButton) {
                return QRect();
            }
        case SC_TitleBarCloseButton: {
            if (menuCloseBtn) {
                ++btnOffsetCount;
            } else if (subControl == SC_TitleBarCloseButton) {
                return QRect();
            }
            // set the rect for all buttons that fell through:
            ret.setRect(ret.right() - btnOffsetCount * btnWidth - (btnOffsetCount - 1)*btnSpace,
                        ret.top(), btnWidth, btnHeight);
            break;
        }

        default:
            return QRect();
        }

        return visualRect(tbOpt->direction, tbOpt->rect, ret);

    } // CC_TitleBar

    default:
        break;
    }

    return QCommonStyle::subControlRect(control, option, subControl, widget);
}

/*
 Checks whether the point is before the bound rect for
 bound of given orientation
*/
static bool preceeds(const QPoint &pt, const QRect &bound,
                     const QStyleOption *opt)
{
    if (opt->state & QStyle::State_Horizontal) {
        //What's earlier depends on RTL or not
        if (opt->direction == Qt::LeftToRight) {
            return pt.x() < bound.right();
        } else {
            return pt.x() > bound.x();
        }
    } else {
        return pt.y() < bound.y();
    }
}

static QStyle::SubControl buttonPortion(const QRect &totalRect,
                                        const QPoint &pt,
                                        const QStyleOption *opt)
{
    if (opt->state & QStyle::State_Horizontal) {
        //What's earlier depends on RTL or not
        if (opt->direction == Qt::LeftToRight) {
            return pt.x() < totalRect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine;
        } else {
            return pt.x() > totalRect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine;
        }
    } else {
        return pt.y() < totalRect.center().y() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine;
    }
}

QStyle::SubControl K4Style::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
        const QPoint &pt, const QWidget *w) const
{
    if (cc == CC_ScrollBar) {
        //First, check whether we're inside the groove or not...
        QRect groove = subControlRect(CC_ScrollBar, opt, SC_ScrollBarGroove, w);

        if (groove.contains(pt)) {
            //Must be either page up/page down, or just click on the slider.
            //Grab the slider to compare
            QRect slider = subControlRect(CC_ScrollBar, opt, SC_ScrollBarSlider, w);

            if (slider.contains(pt)) {
                return SC_ScrollBarSlider;
            } else if (preceeds(pt, slider, opt)) {
                return SC_ScrollBarSubPage;
            } else {
                return SC_ScrollBarAddPage;
            }
        } else {
            //This is one of the up/down buttons. First, decide which one it is.
            if (preceeds(pt, groove, opt)) {
                //"Upper" button
                if (widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleTopButton, nullptr, w)) {
                    QRect buttonRect = internalSubControlRect(CC_ScrollBar, opt, SC_ScrollBarSubLine, w);
                    return buttonPortion(buttonRect, pt, opt);
                } else {
                    return SC_ScrollBarSubLine;    //Easy one!
                }
            } else {
                //"Bottom" button
                if (widgetLayoutProp(WT_ScrollBar, ScrollBar::DoubleBotButton, nullptr, w)) {
                    QRect buttonRect = internalSubControlRect(CC_ScrollBar, opt, SC_ScrollBarAddLine, w);
                    return buttonPortion(buttonRect, pt, opt);
                } else {
                    return SC_ScrollBarAddLine;    //Easy one!
                }
            }
        }
    }

    return QCommonStyle::hitTestComplexControl(cc, opt, pt, w);
}

QSize K4Style::sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const
{
    switch (type) {
    case CT_PushButton: {
        const QStyleOptionButton *bOpt = qstyleoption_cast<const QStyleOptionButton *>(option);
        if (!bOpt) {
            return contentsSize;
        }

        QSize size = contentsSize;

        if ((bOpt->features & QStyleOptionButton::DefaultButton) || (bOpt->features & QStyleOptionButton::AutoDefaultButton)) {
            size = expandDim(size, WT_PushButton, PushButton::DefaultIndicatorMargin, option, widget);
        }

        //### TODO: Handle minimum size limits, extra spacing as in current styles ??
        size = expandDim(size, WT_PushButton, PushButton::ContentsMargin, option, widget);

        if (bOpt->features & QStyleOptionButton::HasMenu) {
            size.setWidth(size.width() + widgetLayoutProp(WT_PushButton, PushButton::TextToIconSpace, option, widget));
        }

        if (!bOpt->text.isEmpty() && !bOpt->icon.isNull()) {
            // Incorporate the spacing between the icon and text. Qt sticks 4 there,
            // but we use PushButton::TextToIconSpace.
            size.setWidth(size.width() - 4 + widgetLayoutProp(WT_PushButton, PushButton::TextToIconSpace, option, widget));
        }
        return size;
    }

    case CT_ToolButton: {
        // We want to avoid super-skiny buttons, for things like "up" when icons + text
        // For this, we would like to make width >= height.
        // However, once we get here, QToolButton may have already put in the menu area
        // (PM_MenuButtonIndicator) into the width. So we may have to take it out, fix things
        // up, and add it back in. So much for class-independent rendering...
        QSize size = contentsSize;
        int   menuAreaWidth = 0;
        if (const QStyleOptionToolButton *tbOpt = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            if (tbOpt->features & QStyleOptionToolButton::MenuButtonPopup) {
                menuAreaWidth = pixelMetric(QStyle::PM_MenuButtonIndicator, option, widget);
            } else if (tbOpt->features & QStyleOptionToolButton::HasMenu) {
                size.setWidth(size.width() + widgetLayoutProp(WT_ToolButton, ToolButton::InlineMenuIndicatorSize, tbOpt, widget));
            }
        }

        size.setWidth(size.width() - menuAreaWidth);
        if (size.width() < size.height()) {
            size.setWidth(size.height());
        }
        size.setWidth(size.width() + menuAreaWidth);

        return expandDim(size, WT_ToolButton, ToolButton::ContentsMargin, option, widget);
    }

    case CT_CheckBox: {
        //Add size for indicator ### handle empty case differently?
        int indicator = widgetLayoutProp(WT_CheckBox, CheckBox::Size, option, widget);
        int spacer    = widgetLayoutProp(WT_CheckBox, CheckBox::BoxTextSpace, option, widget);

        //Make sure we include space for the focus rect margin
        QSize size = expandDim(contentsSize, WT_CheckBox, CheckBox::FocusMargin, option, widget);

        //Make sure we can fit the indicator (### an extra margin around that?)
        size.setHeight(qMax(size.height(), indicator));

        //Add space for the indicator and the icon
        size.setWidth(size.width() + indicator + spacer);

        return size;
    }

    case CT_RadioButton: {
        //Add size for indicator
        int indicator = widgetLayoutProp(WT_RadioButton, RadioButton::Size, option, widget);
        int spacer    = widgetLayoutProp(WT_RadioButton, RadioButton::BoxTextSpace, option, widget);

        //Make sure we include space for the focus rect margin
        QSize size = expandDim(contentsSize, WT_RadioButton, RadioButton::FocusMargin, option, widget);

        //Make sure we can fit the indicator (### an extra margin around that?)
        size.setHeight(qMax(size.height(), indicator));

        //Add space for the indicator and the icon
        size.setWidth(size.width() + indicator + spacer);

        return size;
    }

    case CT_ProgressBar: {
        QSize size = contentsSize;

        const QStyleOptionProgressBar *pbOpt = ::qstyleoption_cast<const QStyleOptionProgressBar *>(option);
        if (useSideText(pbOpt)) {
            //Allocate extra room for side text
            size.setWidth(size.width() + sideTextWidth(pbOpt));
        }

        return size;
    }

    case CT_MenuBar: {
        int extraW = widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Right, option, widget) -
                     widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Left, option, widget);

        int extraH = widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Bot, option, widget) -
                     widgetLayoutProp(WT_MenuBar, MenuBar::Margin + Top, option, widget);

        return QSize(contentsSize.width() + extraW, contentsSize.height() + extraH);
    }

    case CT_Menu: {
        int extraW = widgetLayoutProp(WT_Menu, Menu::Margin + Right, option, widget) -
                     widgetLayoutProp(WT_Menu, Menu::Margin + Left, option, widget);

        int extraH = widgetLayoutProp(WT_Menu, Menu::Margin + Bot, option, widget) -
                     widgetLayoutProp(WT_Menu, Menu::Margin + Top, option, widget);

        return QSize(contentsSize.width() + extraW, contentsSize.height() + extraH);
    }

    case CT_MenuItem: {
        const QStyleOptionMenuItem *miOpt = ::qstyleoption_cast<const QStyleOptionMenuItem *>(option);
        if (!miOpt) {
            return contentsSize;    //Someone is asking for trouble..
        }

        //First, we calculate the intrinsic size of the item..
        QSize insideSize;

        switch (miOpt->menuItemType) {
        case QStyleOptionMenuItem::Normal:
        case QStyleOptionMenuItem::DefaultItem: //huh?
        case QStyleOptionMenuItem::SubMenu: {
            int iconColW = miOpt->maxIconWidth;
            iconColW     = qMax(iconColW, widgetLayoutProp(WT_MenuItem, MenuItem::IconWidth, option, widget));

            int leftColW = iconColW;
            if (miOpt->menuHasCheckableItems &&
                    widgetLayoutProp(WT_MenuItem, MenuItem::CheckAlongsideIcon, option, widget)) {
                leftColW = widgetLayoutProp(WT_MenuItem, MenuItem::CheckWidth, option, widget) +
                           widgetLayoutProp(WT_MenuItem, MenuItem::CheckSpace, option, widget) +
                           iconColW;
            }

            leftColW     += widgetLayoutProp(WT_MenuItem, MenuItem::IconSpace, option, widget);

            int rightColW = widgetLayoutProp(WT_MenuItem, MenuItem::ArrowSpace, option, widget) +
                            widgetLayoutProp(WT_MenuItem, MenuItem::ArrowWidth, option, widget);

            QFontMetrics fm(miOpt->font);

            int textW;
            int tabPos = miOpt->text.indexOf(QLatin1Char('\t'));
            if (tabPos == -1) {
                //No accel..
                textW = contentsSize.width();
            } else {
                // The width of the accelerator is not included here since
                // Qt will add that on separately after obtaining the
                // sizeFromContents() for each menu item in the menu to be shown
                // ( see QMenuPrivate::calcActionRects() )
                textW = contentsSize.width() +
                        widgetLayoutProp(WT_MenuItem, MenuItem::AccelSpace, option, widget);
            }

            int h = qMax(contentsSize.height(), widgetLayoutProp(WT_MenuItem, MenuItem::MinHeight, option, widget));
            insideSize = QSize(leftColW + textW + rightColW, h);
            break;
        }

        case QStyleOptionMenuItem::Separator: {
            insideSize = QSize(10, widgetLayoutProp(WT_MenuItem, MenuItem::SeparatorHeight, option, widget));
        }
        break;

        //Double huh if we get those.
        case QStyleOptionMenuItem::Scroller:
        case QStyleOptionMenuItem::TearOff:
        case QStyleOptionMenuItem::Margin:
        case QStyleOptionMenuItem::EmptyArea:
            return contentsSize;
        }

        //...now apply the outermost margin.
        return expandDim(insideSize, WT_MenuItem, MenuItem::Margin, option, widget);
    }

    case CT_MenuBarItem:
        return expandDim(contentsSize, WT_MenuBarItem, MenuBarItem::Margin, option, widget);

    case CT_TabBarTab: {
        //With our PM_TabBarTabHSpace/VSpace, Qt should give us what we want for
        //contentsSize, so we just expand that. Qt also takes care of
        //the vertical thing.

        bool rotated = false; // indicates whether the tab is rotated by 90 degrees
        if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option)) {
            rotated = isVerticalTab(tabOpt);
        }

        return expandDim(contentsSize, WT_TabBar, TabBar::TabContentsMargin, option, widget, rotated);
    }

    case CT_TabWidget: {
        const QStyleOptionTabWidgetFrame *tabOpt = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
        if (!tabOpt) {
            break;
        }

        int m = widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin, option, widget);
        int vert = 2 * m +
                   widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Top, option, widget) +
                   widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Bot, option, widget);
        int hor = 2 * m +
                  widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Left, option, widget) +
                  widgetLayoutProp(WT_TabWidget, TabWidget::ContentsMargin + Right, option, widget);

        switch (tabOpt->shape) {
        case QTabBar::RoundedNorth:
        case QTabBar::TriangularNorth:
        case QTabBar::RoundedWest:
        case QTabBar::TriangularWest:
            return contentsSize + QSize(hor, vert);
        case QTabBar::RoundedSouth:
        case QTabBar::TriangularSouth:
        case QTabBar::RoundedEast:
        case QTabBar::TriangularEast:
            return contentsSize + QSize(vert, hor);
        }
    }

    case CT_HeaderSection: {
        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            QSize iconSize = header->icon.isNull() ? QSize(0, 0) : QSize(22, 22);
            QSize textSize = header->fontMetrics.size(0, header->text);
            int iconSpacing = widgetLayoutProp(WT_Header, Header::TextToIconSpace, option, widget);
            int w = iconSize.width() + iconSpacing + textSize.width();
            int h = qMax(iconSize.height(), textSize.height());

            return expandDim(QSize(w, h), WT_Header, Header::ContentsMargin, option, widget);
        }
    }

    case CT_ComboBox: {
        // TODO: Figure out what to do with the button margins
        QSize size = contentsSize;

        // Add the contents margin
        size = expandDim(size, WT_ComboBox, ComboBox::ContentsMargin, option, widget);

        // Add the button width
        size.rwidth() += widgetLayoutProp(WT_ComboBox, ComboBox::ButtonWidth, option, widget);

        // Add the frame width
        size.rwidth()  += widgetLayoutProp(WT_ComboBox, ComboBox::FrameWidth, option, widget) * 2;
        size.rheight() += widgetLayoutProp(WT_ComboBox, ComboBox::FrameWidth, option, widget) * 2;

        return size;
    }

    default:
        break;
    }

    return QCommonStyle::sizeFromContents(type, option, contentsSize, widget);
}

bool K4Style::eventFilter(QObject *obj, QEvent *ev)
{
    if (QCommonStyle::eventFilter(obj, ev)) {
        return true;
    }

    if (QLabel *lbl = qobject_cast<QLabel *>(obj)) {
        QWidget *buddy = lbl->buddy();
        if (buddy) {
            switch (ev->type()) {
            case QEvent::MouseButtonPress: {
                QMouseEvent *mev = dynamic_cast<QMouseEvent *>(ev);
                if (!mev) {
                    break;
                }

                if (lbl->rect().contains(mev->pos())) {
                    clickedLabel = obj;
                    lbl->repaint();
                }
                break;
            }
            case QEvent::MouseButtonRelease: {
                QMouseEvent *mev = dynamic_cast<QMouseEvent *>(ev);
                if (!mev) {
                    break;
                }

                if (clickedLabel) {
                    clickedLabel = nullptr;
                    lbl->update();
                }

                // set focus to the buddy...
                if (lbl->rect().contains(mev->pos())) {
                    buddy->setFocus(Qt::ShortcutFocusReason);
                }
                break;
            }
            case QEvent::Paint:
                if (obj == clickedLabel && buddy->isEnabled()) {
                    // paint focus rect
                    QPainter p(lbl);
                    QStyleOptionFocusRect foOpts;
                    QRect foRect(0, 0, lbl->width(), lbl->height());
                    foOpts.palette = lbl->palette();
                    foOpts.rect    = foRect;
                    drawKStylePrimitive(WT_Generic, Generic::FocusIndicator, &foOpts,
                                        foRect, lbl->palette(), nullptr, &p, lbl);
                }
                break;

            default:
                break;
            }
        }
    }

    return false;
}

K4Style::ColorMode::ColorMode(QPalette::ColorRole _role):
    mode(PaletteEntryMode),
    role(_role)
{}

K4Style::ColorMode::ColorMode(Mode _mode, QPalette::ColorRole _role):
    mode(_mode),
    role(_role)
{}

K4Style::ColorMode::operator int() const
{
    return int(role) | int(mode);
}

K4Style::ColorMode::ColorMode(int encoded)
{
    mode = (encoded & BWAutoContrastMode) ? BWAutoContrastMode : PaletteEntryMode;
    role = QPalette::ColorRole(encoded & (~BWAutoContrastMode));
}

QColor K4Style::ColorMode::color(const QPalette &palette)
{
    QColor palColor = palette.color(role);

    if (mode == BWAutoContrastMode) {
        if (qGray(palColor.rgb()) > 128) { //### CHECKME
            palColor = Qt::black;
        } else {
            palColor = Qt::white;
        }
    }
    return palColor;
}

K4Style::TextOption::TextOption()
{
    init();
}

K4Style::TextOption::TextOption(const QString &_text):
    text(_text)
{
    init();
}

void K4Style::TextOption::init()
{
    hAlign = Qt::AlignLeft; //NOTE: Check BIDI?
}

