source: orange/source/orangeqt/point.cpp @ 10917:2508f9895423

Revision 10917:2508f9895423, 10.9 KB checked in by mstajdohar, 22 months ago (diff)

Fixed NULL pointer bug.

Line 
1/*
2    This file is part of the plot module for Orange
3    Copyright (C) 2011  Miha Čančula <miha@noughmad.eu>
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program 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
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "point.h"
20#include "curve.h"
21
22#include <QtGui/QPainter>
23#include <QtCore/QDebug>
24#include <QtCore/qmath.h>
25#include <QtGui/QStyleOptionGraphicsItem>
26
27QHash<PointData, QPixmap> Point::pixmap_cache;
28
29uint qHash(const PointData& data)
30{
31    // uint has 32 bits:
32    uint ret = data.size;
33    // size only goes up to 20, so 5 bits is enough
34    ret |= data.symbol << 5;
35    // symbol is less than 16, so 4 bits will do
36    ret |= data.state << 9;
37    // state is currently only two bits
38    ret |= data.transparent << 11;
39    // QRgb takes the full uins, so we just XOR by it
40    ret ^= data.color.rgba();
41    return ret;
42}
43
44bool operator==(const PointData& one, const PointData& other)
45{
46    return one.symbol == other.symbol && one.size == other.size && one.state == other.state && one.color == other.color;
47}
48
49QDebug& operator<<(QDebug& stream, const DataPoint& point)
50{
51    return stream.maybeSpace() << "DataPoint(" << point.x << ','<< point.y << ')';
52}
53
54bool operator==(const DataPoint& one, const DataPoint& other)
55{
56    return one.x == other.x && one.y == other.y;
57}
58
59DataPoint::operator QPointF() const
60{
61    return QPointF(x, y);
62}
63
64LabelItem::LabelItem(QGraphicsItem* parent): QGraphicsTextItem(parent)
65{
66}
67
68LabelItem::LabelItem(const QString &text, QGraphicsItem *parent): QGraphicsTextItem(text, parent)
69{
70}
71
72LabelItem::~LabelItem()
73{
74}
75
76void LabelItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
77{
78    /*
79    Q_UNUSED(widget);
80    if (dd->control) {
81        painter->save();
82        QRectF r = option->exposedRect;
83        painter->translate(-dd->controlOffset());
84        r.translate(dd->controlOffset());
85
86        QTextDocument *doc = dd->control->document();
87        QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
88
89        // the layout might need to expand the root frame to
90        // the viewport if NoWrap is set
91        if (layout)
92            layout->setViewport(dd->boundingRect);
93
94        dd->control->drawContents(painter, r);
95
96        if (layout)
97            layout->setViewport(QRect());
98
99        painter->restore();
100    }
101
102    if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
103        qt_graphicsItem_highlightSelected(this, painter, option);
104    */
105    QGraphicsTextItem::paint(painter, option, widget);
106}
107
108Point::Point(int symbol, QColor color, int size, QGraphicsItem* parent): QGraphicsObject(parent),
109 m_symbol(symbol),
110 m_color(color),
111 m_size(size)
112{
113    m_display_mode = DisplayPath;
114    m_transparent = true;
115    setFlag(ItemIgnoresTransformations);
116    label = NULL;
117}
118
119Point::Point(QGraphicsItem* parent): QGraphicsObject(parent)
120{
121    m_symbol = Ellipse;
122    m_color = Qt::black;
123    m_size = 5;
124    m_display_mode = DisplayPath;
125    m_transparent = true;
126    setFlag(ItemIgnoresTransformations);
127    label = NULL;
128}
129 
130void Point::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
131{
132    Q_UNUSED(option)
133    Q_UNUSED(widget)
134   
135    const PointData key(m_size, m_symbol, m_color, m_state, m_transparent);
136    // We make the pixmap slighly larger because the point outline has non-zero width
137    const int ps = m_size + 4;
138    if (!pixmap_cache.contains(key))
139    {
140        if (m_display_mode == DisplayPath)
141        {
142            QBrush brush(m_color);
143            QPixmap pixmap(ps, ps);
144            pixmap.fill(Qt::transparent);
145            QPainter p;
146           
147            QPen pen(m_color);
148            pen.setWidth(qMin(2, m_size/6));
149           
150            p.begin(&pixmap);
151            p.setRenderHints(painter->renderHints() | QPainter::Antialiasing);
152            if (m_state & Selected)
153            {
154                brush.setColor(m_color);
155                //pen.setStyle(Qt::NoPen);
156            }
157            else if (m_state & Marked)
158            {
159                /*
160                QRadialGradient g(0.5*ps, 0.5*ps, 0.5*m_size);
161                g.setColorAt(0, m_color);
162                g.setColorAt(0.5, Qt::transparent);
163                g.setColorAt(1, m_color);
164                brush = QBrush(g);
165                pen.setStyle(Qt::NoPen);
166                */
167                //QColor c = Qt::darkGray;
168                //c.setAlpha(150);
169                QColor c = brush.color();
170                //c.setAlpha(m_color.alpha()/6);
171                brush.setColor(c);
172                pen.setColor(Qt::black);
173                pen.setWidth(qMin(3, m_size/3));
174
175            }
176            else
177            {
178                QColor c = brush.color();
179                c.setAlpha(m_color.alpha()/6);
180                brush.setColor(c);
181            }
182            const QPainterPath path = path_for_symbol(m_symbol, m_size).translated(0.5*ps, 0.5*ps);
183
184            if (!m_transparent)
185            {
186                p.setBrush(Qt::white);
187                p.drawPath(path);
188            }
189
190            p.setBrush(brush);
191            p.setPen(pen);
192            p.drawPath(path);
193            pixmap_cache.insert(key, pixmap);
194        } 
195        else if (m_display_mode == DisplayPixmap)
196        {
197            pixmap_cache.insert(key, pixmap_for_symbol(m_symbol, m_color, m_size));
198        }
199    }
200    painter->drawPixmap(QPointF(-0.5*ps, -0.5*ps), pixmap_cache.value(key));
201    /*
202    if (!m_label.isEmpty())
203    {       
204        QFontMetrics metrics = option->fontMetrics;
205        int th = metrics.height();
206        int tw = metrics.width(m_label);
207        QRect r(-tw/2, 0, tw, th);
208        //painter->fillRect(r, QBrush(Qt::white));
209        painter->drawText(r, Qt::AlignHCenter, m_label);
210    }
211    */
212}
213
214QRectF Point::boundingRect() const
215{
216    return rect_for_size(m_size);
217}
218
219Point::~Point()
220{
221}
222
223QColor Point::color() const
224{
225    return m_color;
226}
227
228void Point::set_color(const QColor& color)
229{
230    m_color = color;
231    update();
232}
233
234Point::DisplayMode Point::display_mode() const
235{
236    return m_display_mode;
237}
238
239void Point::set_display_mode(Point::DisplayMode mode)
240{
241    m_display_mode = mode;
242    update();
243}
244
245int Point::size() const
246{
247    return m_size;
248}
249
250void Point::set_size(int size)
251{
252    m_size = size;
253    update();
254}
255
256int Point::symbol() const
257{
258    return m_symbol;
259}
260
261void Point::set_symbol(int symbol)
262{
263    m_symbol = symbol;
264    update();
265}
266
267QPainterPath Point::path_for_symbol(int symbol, int size)
268{
269  QPainterPath path;
270  qreal d = 0.5 * size;
271  switch (symbol)
272  {
273    case NoSymbol:
274      break;
275     
276    case Ellipse:
277      path.addEllipse(-d,-d,2*d,2*d);
278      break;
279     
280    case Rect:
281      path.addRect(-d,-d,2*d,2*d);
282      break;
283     
284    case Diamond:
285      path.addRect(-d,-d,2*d,2*d);
286      path = QTransform().rotate(45).map(path);
287      break;
288     
289    case Triangle:
290    case UTriangle:
291      path = trianglePath(d, 0);
292      break;
293     
294    case DTriangle:
295      path = trianglePath(d, 180);
296      break;
297     
298    case LTriangle:
299      path = trianglePath(d, -90);
300      break;
301   
302    case RTriangle:
303      path = trianglePath(d, 90);
304      break;
305
306    case Cross:
307      path = crossPath(d, 0);
308      break;
309   
310    case XCross:
311      path = crossPath(d, 45);
312      break;
313     
314    case HLine:
315      path.moveTo(-d,0);
316      path.lineTo(d,0);
317      break;
318     
319    case VLine:
320      path.moveTo(0,-d);
321      path.lineTo(0,d);
322      break;
323     
324    case Star1:
325      path.addPath(crossPath(d,0));
326      path.addPath(crossPath(d,45));
327      break;
328     
329    case Star2:
330      path = hexPath(d, true);
331      break;
332     
333    case Hexagon:
334      path = hexPath(d, false);
335      break;
336     
337    default:
338     // qWarning() << "Unsupported symbol" << symbol;
339        break;
340  }
341  return path;
342}
343
344
345QPainterPath Point::trianglePath(double d, double rot) {
346    QPainterPath path;
347    path.moveTo(-d, d*sqrt(3.0)/3);
348    path.lineTo(d, d*sqrt(3.0)/3);
349    path.lineTo(0, -2*d*sqrt(3.0)/3);
350    path.closeSubpath();
351    return QTransform().rotate(rot).map(path);
352}
353
354QPainterPath Point::crossPath(double d, double rot)
355{
356    QPainterPath path;
357    path.lineTo(0,d);
358    path.moveTo(0,0);
359    path.lineTo(0,-d);
360    path.moveTo(0,0); 
361    path.lineTo(d,0);
362    path.moveTo(0,0);
363    path.lineTo(-d,0);
364    return QTransform().rotate(rot).map(path);
365}
366
367QPainterPath Point::hexPath(double d, bool star) {
368    QPainterPath path;
369    if (!star)
370    {
371        path.moveTo(d,0);
372    }
373    for (int i = 0; i < 6; ++i)
374    {
375        path.lineTo( d * cos(M_PI/3*i), d*sin(M_PI/3*i) );
376        if (star)
377        {
378            path.lineTo(0,0);
379        }
380    }
381    path.closeSubpath();
382    return path;
383}
384
385QPixmap Point::pixmap_for_symbol(int symbol, QColor color, int size)
386{
387    // Indexed8 is the only format with a color table, which means we can replace entire colors
388    // and not only indididual pixels
389    QPixmap image(QSize(size, size));
390   
391    // TODO: Create fils with actual images, preferably SVG so they are scalable
392    // image.load(filename);
393    return image;
394}
395
396QRectF Point::rect_for_size(double size)
397{
398    return QRectF(-size/2, -size/2, size, size);
399}
400
401void Point::set_state(Point::State state) 
402{
403    m_state = state;
404}
405
406Point::State Point::state() const 
407{
408    return m_state;
409}
410
411void Point::set_state_flag(Point::StateFlag flag, bool on) 
412{
413    if (on)
414    {
415        m_state |= flag;
416    }
417    else
418    {
419        m_state &= ~flag;
420    }
421
422    if ((flag == Selected || flag == Marked) && label && ((Curve *)parentObject())->labels_on_marked())
423    {
424        if (is_selected() || is_marked())
425        {
426            label->show();
427        }
428        else
429        {
430            label->hide();
431        }
432    }
433
434    update();
435}
436
437bool Point::state_flag(Point::StateFlag flag) const 
438{
439    return m_state & flag;
440}
441
442void Point::set_selected(bool selected)
443{
444    set_state_flag(Selected, selected);
445}
446
447bool Point::is_selected() const
448{
449    return state_flag(Selected);
450}
451
452void Point::set_marked(bool marked)
453{
454    set_state_flag(Marked, marked);
455}
456
457bool Point::is_marked() const
458{
459    return state_flag(Marked);
460}
461
462bool Point::is_transparent()
463{
464    return m_transparent;
465}
466void Point::set_transparent(bool transparent)
467{
468    m_transparent = transparent;
469}
470
471DataPoint Point::coordinates() const
472{
473    return m_coordinates;
474}
475
476void Point::set_coordinates(const DataPoint& data_point)
477{
478    m_coordinates = data_point;
479}
480
481void Point::clear_cache()
482{
483    pixmap_cache.clear();
484}
485
486/*
487void Point::set_label(const QString& label)
488{
489    m_label = label;
490}
491*/
492
493QString Point::text() const
494{
495    if (label == NULL)
496    {
497        return "";
498    }
499    else
500    {
501        return label->toPlainText();
502    }
503}
504
505#include "point.moc"
Note: See TracBrowser for help on using the repository browser.