1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the documentation of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of The Qt Company Ltd nor the names of its
21 ** contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 /*!
42 view.cpp
43
44 Provides a view to represent a one-dimensional sequence of integers
45 obtained from a list model as a series of rows.
46 */
47
48 #include <QAbstractItemModel>
49 #include <QBrush>
50 #include <QItemSelection>
51 #include <QPainter>
52 #include <QPaintEvent>
53 #include <QPen>
54 #include <QPoint>
55 #include <QResizeEvent>
56 #include <QScrollBar>
57 #include <QSizePolicy>
58
59 #include "view.h"
60
LinearView(QWidget * parent)61 LinearView::LinearView(QWidget *parent)
62 : QAbstractItemView(parent)
63 {
64 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
65 }
66
67 /*!
68 Returns the position of the item in viewport coordinates.
69 */
70
itemViewportRect(const QModelIndex & index) const71 QRect LinearView::itemViewportRect(const QModelIndex &index) const
72 {
73 QRect rect = itemRect(index);
74 QRect result(rect.left() - horizontalScrollBar()->value(),
75 rect.top() - verticalScrollBar()->value(),
76 rect.width(), viewport()->height());
77
78 return result;
79 }
80
81 /*!
82 Returns the rectangle of the item at position \a index in the
83 model. The rectangle is in contents coordinates.
84 */
85
itemRect(const QModelIndex & index) const86 QRect LinearView::itemRect(const QModelIndex &index) const
87 {
88 if (!index.isValid())
89 return QRect();
90 else
91 return QRect(index.row(), 0, 1, 1);
92 }
93
94
ensureVisible(const QModelIndex & index)95 void LinearView::ensureVisible(const QModelIndex &index)
96 {
97 QRect area = viewport()->rect();
98 QRect rect = itemViewportRect(index);
99
100 if (rect.left() < area.left())
101 horizontalScrollBar()->setValue(
102 horizontalScrollBar()->value() - rect.left());
103 else if (rect.right() > area.right())
104 horizontalScrollBar()->setValue(
105 horizontalScrollBar()->value() + rect.left() - area.width());
106 }
107
108 /*!
109 Returns the item that covers the coordinate given in the view.
110 */
111
itemAt(int x,int) const112 QModelIndex LinearView::itemAt(int x, int /* y */) const
113 {
114 int row = x + horizontalScrollBar()->value();
115
116 return model()->index(row, 0, QModelIndex());
117 }
118
119 //void LinearView::dataChanged(const QModelIndex &/* topLeft */,
120 // const QModelIndex &/* bottomRight */)
121 //{
122 // updateGeometries();
123 // if (isVisible())
124 // repaint();
125 //}
126
rowsInserted(const QModelIndex &,int,int)127 void LinearView::rowsInserted(const QModelIndex &/* parent */, int /* start */,
128 int /* end */)
129 {
130 updateGeometries();
131 if (isVisible())
132 repaint();
133 }
134
rowsRemoved(const QModelIndex &,int,int)135 void LinearView::rowsRemoved(const QModelIndex &/* parent */, int /* start */,
136 int /* end */)
137 {
138 updateGeometries();
139 if (isVisible())
140 repaint();
141 }
142 /*
143 void LinearView::verticalScrollbarAction(int action)
144 {
145 }
146
147 void LinearView::horizontalScrollbarAction(int action)
148 {
149 }
150 */
151
152 /*!
153 Select the items in the model that lie within the rectangle specified by
154 \a rect, using the selection \a command.
155 */
156
setSelection(const QRect & rect,QItemSelectionModel::SelectionFlags command)157 void LinearView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
158 {
159 QModelIndex leftIndex = itemAt(rect.left(), 0);
160 QModelIndex rightIndex = itemAt(rect.right(), 0);
161
162 QItemSelection selection(leftIndex, rightIndex);
163
164 selectionModel()->select(selection, command);
165 }
166
moveCursor(QAbstractItemView::CursorAction cursorAction,Qt::KeyboardModifiers)167 QModelIndex LinearView::moveCursor(QAbstractItemView::CursorAction cursorAction,
168 Qt::KeyboardModifiers)
169 {
170 QModelIndex current = currentIndex();
171
172 switch (cursorAction) {
173 case MoveLeft:{
174 if (current.row() > 0)
175 return model()->index(current.row() - 1, 0, QModelIndex());
176 else
177 return model()->index(0, 0, QModelIndex());
178 break;}
179 case MoveRight:{
180 if (current.row() < rows(current) - 1)
181 return model()->index(current.row() + 1, 0, QModelIndex());
182 else
183 return model()->index(rows(current) - 1, 0,QModelIndex());
184 break;}
185 case MoveUp:
186 return current;
187 case MoveDown:
188 return current;
189 case MovePageUp:
190 return current;
191 case MovePageDown:
192 return current;
193 case MoveHome:
194 return model()->index(0, 0, QModelIndex());
195 case MoveEnd:
196 return model()->index(rows(current) - 1, 0, QModelIndex());
197 default:
198 return current;
199 }
200 }
201
horizontalOffset() const202 int LinearView::horizontalOffset() const
203 {
204 return horizontalScrollBar()->value();
205 }
206
verticalOffset() const207 int LinearView::verticalOffset() const
208 {
209 return verticalScrollBar()->value();
210 }
211
212 /*!
213 Returns a rectangle corresponding to the selection in viewport cooridinates.
214 */
215
selectionViewportRect(const QItemSelection & selection) const216 QRect LinearView::selectionViewportRect(const QItemSelection &selection) const
217 {
218 int ranges = selection.count();
219
220 if (ranges == 0)
221 return QRect();
222
223 // Note that we use the top and bottom functions of the selection range
224 // since the data is stored in rows.
225
226 int firstRow = selection.at(0).top();
227 int lastRow = selection.at(0).top();
228
229 for (int i = 0; i < ranges; ++i) {
230 firstRow = qMin(firstRow, selection.at(i).top());
231 lastRow = qMax(lastRow, selection.at(i).bottom());
232 }
233
234 QModelIndex firstItem = model()->index(qMin(firstRow, lastRow), 0,
235 QModelIndex());
236 QModelIndex lastItem = model()->index(qMax(firstRow, lastRow), 0,
237 QModelIndex());
238
239 QRect firstRect = itemViewportRect(firstItem);
240 QRect lastRect = itemViewportRect(lastItem);
241
242 return QRect(firstRect.left(), firstRect.top(),
243 lastRect.right() - firstRect.left(), firstRect.height());
244 }
245
paintEvent(QPaintEvent * event)246 void LinearView::paintEvent(QPaintEvent *event)
247 {
248 QPainter painter(viewport());
249
250 QRect updateRect = event->rect();
251 QBrush background(Qt::black);
252 QPen foreground(Qt::white);
253
254 painter.fillRect(updateRect, background);
255 painter.setPen(foreground);
256
257 QModelIndex firstItem = itemAt(updateRect.left(), updateRect.top());
258 if (!firstItem.isValid())
259 firstItem = model()->index(0, 0, QModelIndex());
260
261 QModelIndex lastItem = itemAt(updateRect.right(), updateRect.bottom());
262 if (!lastItem.isValid())
263 lastItem = model()->index(rows() - 1, 0, QModelIndex());
264
265 int x = updateRect.left();
266 //int top = updateRect.top();
267 //int bottom = updateRect.bottom();
268
269 int row = firstItem.row();
270 QModelIndex index = model()->index(row, 0, QModelIndex());
271 int value = model()->data(index, Qt::DisplayRole).toInt();
272 int midPoint = viewport()->height()/2;
273 int y2 = midPoint - int(value * midPoint/255.0);
274
275 while (row <= lastItem.row()) {
276
277 QModelIndex index = model()->index(row, 0, QModelIndex());
278 int value = model()->data(index, Qt::DisplayRole).toInt();
279
280 int y1 = y2;
281 y2 = midPoint - int(value * midPoint/255.0);
282
283 painter.drawLine(x-1, y1, x, y2);
284 ++row; ++x;
285 }
286 }
287
resizeEvent(QResizeEvent *)288 void LinearView::resizeEvent(QResizeEvent * /* event */)
289 {
290 updateGeometries();
291 }
292
updateGeometries()293 void LinearView::updateGeometries()
294 {
295 if (viewport()->width() < rows()) {
296 horizontalScrollBar()->setPageStep(viewport()->width());
297 horizontalScrollBar()->setRange(0, rows() - viewport()->width() - 1);
298 }
299 }
300
sizeHint() const301 QSize LinearView::sizeHint() const
302 {
303 return QSize(rows(), 200);
304 }
305
rows(const QModelIndex & index) const306 int LinearView::rows(const QModelIndex &index) const
307 {
308 return model()->rowCount(model()->parent(index));
309 }
310
isIndexHidden(const QModelIndex & index) const311 bool LinearView::isIndexHidden(const QModelIndex &index) const
312 {
313 return false;
314 }
315