include only used headers
[colorflood] / colorflood / src / field.cpp
1 /*
2   Copyright 2010 Serge Ziryukin <ftrvxmtrx@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; version 2 of the License.
7
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   GNU General Public License for more details.
12 */
13
14 #include <QMetaType>
15 #include <QDataStream>
16 #include <QSettings>
17 #include <QTime>
18 #include <QPainter>
19 #include <QPaintEvent>
20 #include "field.hpp"
21 #include "colorscheme.hpp"
22
23 static const int fieldWidth = 420;
24
25 const int Field::rects[Field::NUM_SIZES] = { 14, 21, 28 };
26 const int Field::turns[Field::NUM_SIZES] = { 25, 35, 50 };
27
28 // we declare out QVector<FieldRect> metatype
29 // and stream operators to save whole field to settings
30 Q_DECLARE_METATYPE(Field::RectVector);
31
32 static QDataStream &operator<< (QDataStream &out, const Field::RectVector &rv)
33 {
34     for (QVector<Field::FieldRect>::const_iterator rect = rv.begin();
35          rect != rv.end();
36          rect++)
37     {
38         out << (*rect).brush;
39         out << (*rect).flood;
40     }
41
42     return out;
43 }
44
45 static QDataStream &operator>> (QDataStream &in, Field::RectVector &rv)
46 {
47     Field::FieldRect r;
48
49     rv.clear();
50
51     for (; !in.atEnd() ;)
52     {
53         in >> r.brush >> r.flood;
54         rv << r;
55     }
56
57     rv.pop_back();
58
59     return in;
60 }
61
62 Field::Field (QWidget *parent)
63     : QWidget (parent)
64 {
65     setFixedSize(fieldWidth, fieldWidth);
66
67     // restore field size and field itself from settings
68
69     qRegisterMetaType<RectVector>("Field::RectVector");
70     qRegisterMetaTypeStreamOperators<RectVector>("Field::RectVector");
71
72     QSettings settings;
73
74     int size = settings.value("field/fieldSize", SIZE_SMALL).toInt();
75
76     if (size < SIZE_SMALL || size >= NUM_SIZES)
77         size = SIZE_SMALL;
78
79     this->size = (FieldSize)size;
80
81     if (settings.contains("field/data"))
82         data = settings.value("field/data").value<RectVector>();
83
84     if (data.size() != rects[size] * rects[size])
85         randomize();
86 }
87
88 Field::~Field ()
89 {
90     QSettings settings;
91
92     settings.setValue("field/size", size);
93
94     QVariant v;
95     v.setValue(data);
96     settings.setValue("field/data", v);
97 }
98
99 Field::FieldSize Field::getSize () const
100 {
101     return size;
102 }
103
104 void Field::randomize ()
105 {
106     FieldRect rect;
107     rect.flood = false;
108
109     data.clear();
110     data = RectVector(rects[size] * rects[size], rect);
111
112     qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
113
114     int numBrushes = ColorScheme::instance().getScheme().size();
115
116     for (QVector<FieldRect>::iterator rect = data.begin();
117          rect != data.end();
118          rect++)
119     {
120         (*rect).brush = qrand() % numBrushes;
121     }
122
123     update();
124 }
125
126 int Field::getNumRectsOfSize (FieldSize size)
127 {
128     return rects[size];
129 }
130
131 int Field::getNumTurnsOfSize (FieldSize size)
132 {
133     return turns[size];
134 }
135
136 int Field::getRectSize (FieldSize size)
137 {
138     return fieldWidth / rects[size];
139 }
140
141 void Field::paintEvent (QPaintEvent *event)
142 {
143     QPainter painter;
144     painter.begin(this);
145
146     QRect rect = QRect(0, 0, getRectSize(size), getRectSize(size));
147
148     const QVector<QBrush> &scheme = ColorScheme::instance().getScheme();
149
150     for (int y = 0; y < rects[size] ;y++)
151     {
152         int n = y * rects[size];
153
154         for (int x = 0; x < rects[size] ;x++, n++)
155         {
156             rect.moveTo(x * rect.width(), y * rect.height());
157
158             if (rect.intersects(event->rect()))
159                 painter.fillRect(rect, scheme.at(data[n].brush));
160         }
161     }
162
163     painter.end();
164 }