]>
Commit | Line | Data |
---|---|---|
0c0e1888 JH |
1 | /**************************************************************************** |
2 | ** | |
3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | |
4 | ** Contact: http://www.qt-project.org/legal | |
5 | ** | |
6 | ** This file is part of the QtGui module of the Qt Toolkit. | |
7 | ** | |
8 | ** $QT_BEGIN_LICENSE:LGPL$ | |
9 | ** Commercial License Usage | |
10 | ** Licensees holding valid commercial Qt licenses may use this file in | |
11 | ** accordance with the commercial license agreement provided with the | |
12 | ** Software or, alternatively, in accordance with the terms contained in | |
13 | ** a written agreement between you and Digia. For licensing terms and | |
14 | ** conditions see http://qt.digia.com/licensing. For further information | |
15 | ** use the contact form at http://qt.digia.com/contact-us. | |
16 | ** | |
17 | ** GNU Lesser General Public License Usage | |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | |
19 | ** General Public License version 2.1 as published by the Free Software | |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | |
21 | ** packaging of this file. Please review the following information to | |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
24 | ** | |
25 | ** In addition, as a special exception, Digia gives you certain additional | |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception | |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
28 | ** | |
29 | ** GNU General Public License Usage | |
30 | ** Alternatively, this file may be used under the terms of the GNU | |
31 | ** General Public License version 3.0 as published by the Free Software | |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the | |
33 | ** packaging of this file. Please review the following information to | |
34 | ** ensure the GNU General Public License version 3.0 requirements will be | |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. | |
36 | ** | |
37 | ** | |
38 | ** $QT_END_LICENSE$ | |
39 | ** | |
40 | ****************************************************************************/ | |
41 | ||
42 | #define QT_NO_MENU | |
43 | ||
44 | #include <QPainter> | |
45 | #include <QPaintEvent> | |
46 | #include <QStyle> | |
47 | #include <QStyleOptionFrame> | |
48 | ||
49 | #include "wellarray.h" | |
50 | ||
51 | void QWellArray::paintEvent(QPaintEvent *e) | |
52 | { | |
53 | QRect r = e->rect(); | |
54 | int cx = r.x(); | |
55 | int cy = r.y(); | |
56 | int ch = r.height(); | |
57 | int cw = r.width(); | |
58 | int colfirst = columnAt(cx); | |
59 | int collast = columnAt(cx + cw); | |
60 | int rowfirst = rowAt(cy); | |
61 | int rowlast = rowAt(cy + ch); | |
62 | ||
63 | if (isRightToLeft()) { | |
64 | int t = colfirst; | |
65 | colfirst = collast; | |
66 | collast = t; | |
67 | } | |
68 | ||
69 | QPainter painter(this); | |
70 | QPainter *p = &painter; | |
71 | QRect rect(0, 0, cellWidth(), cellHeight()); | |
72 | ||
73 | ||
74 | if (collast < 0 || collast >= ncols) | |
75 | collast = ncols-1; | |
76 | if (rowlast < 0 || rowlast >= nrows) | |
77 | rowlast = nrows-1; | |
78 | ||
79 | // Go through the rows | |
80 | for (int r = rowfirst; r <= rowlast; ++r) { | |
81 | // get row position and height | |
82 | int rowp = rowY(r); | |
83 | ||
84 | // Go through the columns in the row r | |
85 | // if we know from where to where, go through [colfirst, collast], | |
86 | // else go through all of them | |
87 | for (int c = colfirst; c <= collast; ++c) { | |
88 | // get position and width of column c | |
89 | int colp = columnX(c); | |
90 | // Translate painter and draw the cell | |
91 | rect.translate(colp, rowp); | |
92 | paintCell(p, r, c, rect); | |
93 | rect.translate(-colp, -rowp); | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | struct QWellArrayData { | |
99 | QBrush *brush; | |
100 | }; | |
101 | ||
102 | QWellArray::QWellArray(int rows, int cols, QWidget *parent) | |
103 | : QWidget(parent) | |
104 | ,nrows(rows), ncols(cols) | |
105 | { | |
106 | d = 0; | |
107 | setFocusPolicy(Qt::StrongFocus); | |
108 | cellw = 28; | |
109 | cellh = 24; | |
110 | curCol = 0; | |
111 | curRow = 0; | |
112 | selCol = -1; | |
113 | selRow = -1; | |
114 | } | |
115 | ||
116 | QSize QWellArray::sizeHint() const | |
117 | { | |
118 | ensurePolished(); | |
119 | return gridSize().boundedTo(QSize(640, 480)); | |
120 | } | |
121 | ||
122 | ||
123 | void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect) | |
124 | { | |
125 | int b = 3; //margin | |
126 | ||
127 | const QPalette & g = palette(); | |
128 | QStyleOptionFrame opt; | |
129 | int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); | |
130 | opt.lineWidth = dfw; | |
131 | opt.midLineWidth = 1; | |
132 | opt.rect = rect.adjusted(b, b, -b, -b); | |
133 | opt.palette = g; | |
134 | opt.state = QStyle::State_Enabled | QStyle::State_Sunken; | |
135 | style()->drawPrimitive(QStyle::PE_Frame, &opt, p, this); | |
136 | b += dfw; | |
137 | ||
138 | if ((row == curRow) && (col == curCol)) { | |
139 | if (hasFocus()) { | |
140 | QStyleOptionFocusRect opt; | |
141 | opt.palette = g; | |
142 | opt.rect = rect; | |
143 | opt.state = QStyle::State_None | QStyle::State_KeyboardFocusChange; | |
144 | style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this); | |
145 | } | |
146 | } | |
147 | paintCellContents(p, row, col, opt.rect.adjusted(dfw, dfw, -dfw, -dfw)); | |
148 | } | |
149 | ||
150 | /*! | |
151 | Reimplement this function to change the contents of the well array. | |
152 | */ | |
153 | void QWellArray::paintCellContents(QPainter *p, int row, int col, const QRect &r) | |
154 | { | |
155 | if (d) { | |
156 | p->fillRect(r, d->brush[row*numCols()+col]); | |
157 | } else { | |
158 | p->fillRect(r, Qt::white); | |
159 | p->setPen(Qt::black); | |
160 | p->drawLine(r.topLeft(), r.bottomRight()); | |
161 | p->drawLine(r.topRight(), r.bottomLeft()); | |
162 | } | |
163 | } | |
164 | ||
165 | void QWellArray::mousePressEvent(QMouseEvent *e) | |
166 | { | |
167 | // The current cell marker is set to the cell the mouse is pressed in | |
168 | QPoint pos = e->pos(); | |
169 | setCurrent(rowAt(pos.y()), columnAt(pos.x())); | |
170 | } | |
171 | ||
172 | void QWellArray::mouseReleaseEvent(QMouseEvent * /* event */) | |
173 | { | |
174 | // The current cell marker is set to the cell the mouse is clicked in | |
175 | setSelected(curRow, curCol); | |
176 | } | |
177 | ||
178 | ||
179 | /* | |
180 | Sets the cell currently having the focus. This is not necessarily | |
181 | the same as the currently selected cell. | |
182 | */ | |
183 | ||
184 | void QWellArray::setCurrent(int row, int col) | |
185 | { | |
186 | if ((curRow == row) && (curCol == col)) | |
187 | return; | |
188 | ||
189 | if (row < 0 || col < 0) | |
190 | row = col = -1; | |
191 | ||
192 | int oldRow = curRow; | |
193 | int oldCol = curCol; | |
194 | ||
195 | curRow = row; | |
196 | curCol = col; | |
197 | ||
198 | updateCell(oldRow, oldCol); | |
199 | updateCell(curRow, curCol); | |
200 | } | |
201 | ||
202 | /* | |
203 | Sets the currently selected cell to \a row, \a column. If \a row or | |
204 | \a column are less than zero, the current cell is unselected. | |
205 | ||
206 | Does not set the position of the focus indicator. | |
207 | */ | |
208 | void QWellArray::setSelected(int row, int col) | |
209 | { | |
210 | int oldRow = selRow; | |
211 | int oldCol = selCol; | |
212 | ||
213 | if (row < 0 || col < 0) | |
214 | row = col = -1; | |
215 | ||
216 | selCol = col; | |
217 | selRow = row; | |
218 | ||
219 | updateCell(oldRow, oldCol); | |
220 | updateCell(selRow, selCol); | |
221 | if (row >= 0) | |
222 | emit selected(row, col); | |
223 | ||
224 | #ifndef QT_NO_MENU | |
225 | if (isVisible() && qobject_cast<QMenu*>(parentWidget())) | |
226 | parentWidget()->close(); | |
227 | #endif | |
228 | } | |
229 | ||
230 | void QWellArray::focusInEvent(QFocusEvent*) | |
231 | { | |
232 | updateCell(curRow, curCol); | |
233 | } | |
234 | ||
235 | void QWellArray::setCellBrush(int row, int col, const QBrush &b) | |
236 | { | |
237 | if (!d) { | |
238 | d = new QWellArrayData; | |
239 | int i = numRows()*numCols(); | |
240 | d->brush = new QBrush[i]; | |
241 | } | |
242 | if (row >= 0 && row < numRows() && col >= 0 && col < numCols()) | |
243 | d->brush[row*numCols()+col] = b; | |
244 | } | |
245 | ||
246 | /* | |
247 | Returns the brush set for the cell at \a row, \a column. If no brush is | |
248 | set, Qt::NoBrush is returned. | |
249 | */ | |
250 | ||
251 | QBrush QWellArray::cellBrush(int row, int col) | |
252 | { | |
253 | if (d && row >= 0 && row < numRows() && col >= 0 && col < numCols()) | |
254 | return d->brush[row*numCols()+col]; | |
255 | return Qt::NoBrush; | |
256 | } | |
257 | ||
258 | ||
259 | ||
260 | /*!\reimp | |
261 | */ | |
262 | ||
263 | void QWellArray::focusOutEvent(QFocusEvent*) | |
264 | { | |
265 | updateCell(curRow, curCol); | |
266 | } | |
267 | ||
268 | /*\reimp | |
269 | */ | |
270 | void QWellArray::keyPressEvent(QKeyEvent* e) | |
271 | { | |
272 | switch(e->key()) { // Look at the key code | |
273 | case Qt::Key_Left: // If 'left arrow'-key, | |
274 | if(curCol > 0) // and cr't not in leftmost col | |
275 | setCurrent(curRow, curCol - 1); // set cr't to next left column | |
276 | break; | |
277 | case Qt::Key_Right: // Correspondingly... | |
278 | if(curCol < numCols()-1) | |
279 | setCurrent(curRow, curCol + 1); | |
280 | break; | |
281 | case Qt::Key_Up: | |
282 | if(curRow > 0) | |
283 | setCurrent(curRow - 1, curCol); | |
284 | break; | |
285 | case Qt::Key_Down: | |
286 | if(curRow < numRows()-1) | |
287 | setCurrent(curRow + 1, curCol); | |
288 | break; | |
289 | #if 0 | |
290 | // bad idea that shouldn't have been implemented; very counterintuitive | |
291 | case Qt::Key_Return: | |
292 | case Qt::Key_Enter: | |
293 | /* | |
294 | ignore the key, so that the dialog get it, but still select | |
295 | the current row/col | |
296 | */ | |
297 | e->ignore(); | |
298 | // fallthrough intended | |
299 | #endif | |
300 | case Qt::Key_Space: | |
301 | setSelected(curRow, curCol); | |
302 | break; | |
303 | default: // If not an interesting key, | |
304 | e->ignore(); // we don't accept the event | |
305 | return; | |
306 | } | |
307 | ||
308 | } |