]> sigrok.org Git - pulseview.git/blob - pv/widgets/wellarray.cpp
6776e34f6b110dc7c2f457b528f6573cd08e387d
[pulseview.git] / pv / widgets / wellarray.cpp
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 }