1 /* This file is part of the KDE project
2 * Copyright (C) 2007 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "KoPositionSelector.h"
22
23 #include <QRadioButton>
24 #include <QGridLayout>
25 #include <QButtonGroup>
26 #include <QPainter>
27 #include <WidgetsDebug.h>
28 #include <QStyleOption>
29
30 #define GAP 0
31
32 class Q_DECL_HIDDEN KoPositionSelector::Private
33 {
34 public:
Private()35 Private()
36 : position(KoFlake::TopLeftCorner)
37 {
38 topLeft = createButton(KoFlake::TopLeftCorner);
39 topLeft->setChecked(true);
40 topRight = createButton(KoFlake::TopRightCorner);
41 center = createButton(KoFlake::CenteredPosition);
42 bottomRight = createButton(KoFlake::BottomRightCorner);
43 bottomLeft = createButton(KoFlake::BottomLeftCorner);
44 }
45
createButton(int id)46 QRadioButton *createButton(int id) {
47 QRadioButton *b = new QRadioButton();
48 buttonGroup.addButton(b, id);
49 return b;
50 }
51
52 QRadioButton *topLeft, *topRight, *center, *bottomRight, *bottomLeft;
53 QButtonGroup buttonGroup;
54 KoFlake::Position position;
55 };
56
57 class RadioLayout : public QLayout {
58 Q_OBJECT
59 public:
RadioLayout(QWidget * parent)60 RadioLayout(QWidget *parent)
61 : QLayout(parent)
62 {
63 }
64
~RadioLayout()65 ~RadioLayout() override
66 {
67 foreach( const Item & item, items )
68 delete item.child;
69 items.clear();
70 }
71
setGeometry(const QRect & geom)72 void setGeometry (const QRect &geom) override {
73 QSize prefSize = calcSizes();
74
75 qreal columnWidth, rowHeight;
76 if (geom.width() <= minimum.width())
77 columnWidth = geom.width() / (qreal) maxCol;
78 else
79 columnWidth = prefSize.width() + GAP;
80 if (geom.height() <= minimum.height())
81 rowHeight = geom.height() / (qreal) maxRow;
82 else
83 rowHeight = prefSize.height() + GAP;
84 // padding inside row and column so that radio button is centered
85 QPoint padding( qRound(0.5 * (columnWidth - prefSize.width())), qRound(0.5 * (rowHeight - prefSize.height())));
86 // offset so that all the radio button are centered within the widget
87 qreal offsetX = 0.5 * (geom.width()- static_cast<qreal>(maxCol) * columnWidth);
88 qreal offsetY = 0.5 * (geom.height() - static_cast<qreal>(maxRow) * rowHeight);
89 QPoint offset( qRound(offsetX), qRound(offsetY));
90 foreach(const Item & item, items) {
91 QPoint point( qRound(item.column * columnWidth), qRound(item.row * rowHeight) );
92 QRect rect(point + offset + padding + geom.topLeft(), prefSize);
93 item.child->setGeometry(rect);
94 }
95 }
96
calcSizes()97 QSize calcSizes() {
98 QSize prefSize;
99 maxRow = 0;
100 maxCol = 0;
101 foreach(const Item & item, items) {
102 if(prefSize.isEmpty()) {
103 QAbstractButton *but = dynamic_cast<QAbstractButton*> (item.child->widget());
104 Q_ASSERT(but);
105 QStyleOptionButton opt;
106 opt.initFrom(but);
107 prefSize = QSize(but->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, &opt, but),
108 but->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight, &opt, but));
109 }
110 maxRow = qMax(maxRow, item.row);
111 maxCol = qMax(maxCol, item.column);
112 }
113 maxCol++; maxRow++; // due to being zero-based.
114 preferred = QSize(maxCol * prefSize.width() + (maxCol-1) * GAP, maxRow * prefSize.height() + (maxRow-1) * GAP);
115 minimum = QSize(maxCol * prefSize.width(), maxRow * prefSize.height());
116 return prefSize;
117 }
118
itemAt(int index) const119 QLayoutItem *itemAt (int index) const override {
120 if( index < count() )
121 return items.at(index).child;
122 else
123 return 0;
124 }
125
takeAt(int index)126 QLayoutItem *takeAt (int index) override {
127 Q_ASSERT(index < count());
128 Item item = items.takeAt(index);
129 return item.child;
130 }
131
count() const132 int count () const override {
133 return items.count();
134 }
135
addItem(QLayoutItem *)136 void addItem(QLayoutItem *) override {
137 Q_ASSERT(0);
138 }
139
sizeHint() const140 QSize sizeHint() const override {
141 if(preferred.isEmpty())
142 const_cast<RadioLayout*> (this)->calcSizes();
143 return preferred;
144 }
145
minimumSize() const146 QSize minimumSize() const override {
147 if(minimum.isEmpty())
148 const_cast<RadioLayout*> (this)->calcSizes();
149 return minimum;
150 }
151
addWidget(QRadioButton * widget,int row,int column)152 void addWidget(QRadioButton *widget, int row, int column) {
153 addChildWidget(widget);
154 Item newItem;
155 newItem.child = new QWidgetItem(widget);
156 newItem.row = row;
157 newItem.column = column;
158 items.append(newItem);
159 }
160
161 private:
162 struct Item {
163 QLayoutItem *child;
164 int column;
165 int row;
166 };
167 QList<Item> items;
168 QSize preferred, minimum;
169 int maxCol, maxRow;
170 };
171
KoPositionSelector(QWidget * parent)172 KoPositionSelector::KoPositionSelector(QWidget *parent)
173 : QWidget(parent),
174 d(new Private())
175 {
176 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
177 RadioLayout *lay = new RadioLayout(this);
178 lay->addWidget(d->topLeft, 0, 0);
179 lay->addWidget(d->topRight, 0, 2);
180 lay->addWidget(d->center, 1, 1);
181 lay->addWidget(d->bottomRight, 2, 2);
182 lay->addWidget(d->bottomLeft, 2, 0);
183 setLayout(lay);
184
185 connect(&d->buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(positionChanged(int)));
186 }
187
~KoPositionSelector()188 KoPositionSelector::~KoPositionSelector() {
189 delete d;
190 }
191
position() const192 KoFlake::Position KoPositionSelector::position() const {
193 return d->position;
194 }
195
setPosition(KoFlake::Position position)196 void KoPositionSelector::setPosition(KoFlake::Position position) {
197 d->position = position;
198 switch(d->position) {
199 case KoFlake::TopLeftCorner:
200 d->topLeft->setChecked(true);
201 break;
202 case KoFlake::TopRightCorner:
203 d->topRight->setChecked(true);
204 break;
205 case KoFlake::CenteredPosition:
206 d->center->setChecked(true);
207 break;
208 case KoFlake::BottomLeftCorner:
209 d->bottomLeft->setChecked(true);
210 break;
211 case KoFlake::BottomRightCorner:
212 d->bottomRight->setChecked(true);
213 break;
214 }
215 }
216
positionChanged(int position)217 void KoPositionSelector::positionChanged(int position) {
218 d->position = static_cast<KoFlake::Position> (position);
219 emit positionSelected(d->position);
220 }
221
paintEvent(QPaintEvent *)222 void KoPositionSelector::paintEvent (QPaintEvent *) {
223 QPainter painter( this );
224 QPen pen(Qt::black);
225 int width;
226 if (d->topLeft->width() %2 == 0)
227 width = 2;
228 else
229 width = 3;
230 pen.setWidth(width);
231 painter.setPen(pen);
232 painter.drawRect( QRect( d->topLeft->geometry().center(), d->bottomRight->geometry().center() ) );
233 painter.end();
234 }
235 #include "KoPositionSelector.moc"
236