1 /*
2  * This file Copyright (C) 2012-2015 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 #include <QApplication>
10 #include <QStyle>
11 #include <QStylePainter>
12 
13 #include "FilterBarComboBox.h"
14 #include "StyleHelper.h"
15 #include "Utils.h"
16 
17 namespace
18 {
19 
getHSpacing(QWidget const * w)20 int getHSpacing(QWidget const* w)
21 {
22     return qMax(3, w->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr, w));
23 }
24 
25 } // namespace
26 
FilterBarComboBox(QWidget * parent)27 FilterBarComboBox::FilterBarComboBox(QWidget* parent) :
28     QComboBox(parent)
29 {
30     setSizeAdjustPolicy(QComboBox::AdjustToContents);
31 }
32 
minimumSizeHint() const33 QSize FilterBarComboBox::minimumSizeHint() const
34 {
35     QFontMetrics fm(fontMetrics());
36     QSize const textSize = fm.boundingRect(itemText(0)).size();
37     QSize const countSize = fm.boundingRect(itemData(0, CountStringRole).toString()).size();
38     return calculateSize(textSize, countSize);
39 }
40 
sizeHint() const41 QSize FilterBarComboBox::sizeHint() const
42 {
43     QFontMetrics fm(fontMetrics());
44     QSize maxTextSize(0, 0);
45     QSize maxCountSize(0, 0);
46 
47     for (int i = 0, n = count(); i < n; ++i)
48     {
49         QSize const textSize = fm.boundingRect(itemText(i)).size();
50         maxTextSize.setHeight(qMax(maxTextSize.height(), textSize.height()));
51         maxTextSize.setWidth(qMax(maxTextSize.width(), textSize.width()));
52 
53         QSize const countSize = fm.boundingRect(itemData(i, CountStringRole).toString()).size();
54         maxCountSize.setHeight(qMax(maxCountSize.height(), countSize.height()));
55         maxCountSize.setWidth(qMax(maxCountSize.width(), countSize.width()));
56     }
57 
58     return calculateSize(maxTextSize, maxCountSize);
59 }
60 
calculateSize(QSize const & textSize,QSize const & countSize) const61 QSize FilterBarComboBox::calculateSize(QSize const& textSize, QSize const& countSize) const
62 {
63     int const hmargin = getHSpacing(this);
64 
65     QStyleOptionComboBox option;
66     initStyleOption(&option);
67 
68     QSize contentSize = iconSize() + QSize(4, 2);
69     contentSize.setHeight(qMax(contentSize.height(), textSize.height()));
70     contentSize.rwidth() += hmargin + textSize.width();
71     contentSize.rwidth() += hmargin + countSize.width();
72 
73     return style()->sizeFromContents(QStyle::CT_ComboBox, &option, contentSize, this).expandedTo(qApp->globalStrut());
74 }
75 
paintEvent(QPaintEvent * e)76 void FilterBarComboBox::paintEvent(QPaintEvent* e)
77 {
78     Q_UNUSED(e)
79 
80     QStylePainter painter(this);
81     painter.setPen(palette().color(QPalette::Text));
82 
83     // draw the combobox frame, focusrect and selected etc.
84     QStyleOptionComboBox opt;
85     initStyleOption(&opt);
86     painter.drawComplexControl(QStyle::CC_ComboBox, opt);
87 
88     // draw the icon and text
89     QModelIndex const modelIndex = model()->index(currentIndex(), 0, rootModelIndex());
90 
91     if (modelIndex.isValid())
92     {
93         QStyle* s = style();
94         int const hmargin = getHSpacing(this);
95 
96         QRect rect = s->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this);
97         rect.adjust(2, 1, -2, -1);
98 
99         // draw the icon
100         QIcon const icon = Utils::getIconFromIndex(modelIndex);
101 
102         if (!icon.isNull())
103         {
104             QRect const iconRect = QStyle::alignedRect(opt.direction, Qt::AlignLeft | Qt::AlignVCenter, opt.iconSize, rect);
105             icon.paint(&painter, iconRect, Qt::AlignCenter, StyleHelper::getIconMode(opt.state), QIcon::Off);
106             Utils::narrowRect(rect, iconRect.width() + hmargin, 0, opt.direction);
107         }
108 
109         // draw the count
110         QString text = modelIndex.data(CountStringRole).toString();
111 
112         if (!text.isEmpty())
113         {
114             QPen const pen = painter.pen();
115             painter.setPen(Utils::getFadedColor(pen.color()));
116             QRect const textRect = QStyle::alignedRect(opt.direction, Qt::AlignRight | Qt::AlignVCenter,
117                 QSize(opt.fontMetrics.width(text), rect.height()), rect);
118             painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, text);
119             Utils::narrowRect(rect, 0, textRect.width() + hmargin, opt.direction);
120             painter.setPen(pen);
121         }
122 
123         // draw the text
124         text = modelIndex.data(Qt::DisplayRole).toString();
125         text = painter.fontMetrics().elidedText(text, Qt::ElideRight, rect.width());
126         painter.drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, text);
127     }
128 }
129