]> Shamusworld >> Repos - wozmaker/blob - src/nibblewidget.cpp
Flesh out the disk settings dialog.
[wozmaker] / src / nibblewidget.cpp
1 //
2 // nibblewidget.cpp: Track waveform nibble display widget
3 //
4 // Part of the WOZ Maker project
5 // by James Hammons
6 // (C) 2018 Underground Software
7 //
8
9 #include "nibblewidget.h"
10 #include "fileio.h"
11 #include "global.h"
12
13
14 NibbleWidget::NibbleWidget(QWidget * parent/*= 0*/): QWidget(parent)
15 {
16         // Is this even needed?
17         setGeometry(QRect(0, 0, 20, 20));
18 }
19
20
21 NibbleWidget::~NibbleWidget(void)
22 {
23 }
24
25
26 void NibbleWidget::Update(void)
27 {
28         DecodeWaveform();
29         DecodeBitstream();
30
31         setMinimumWidth(52 * fWidth);
32 //      setMaximumWidth(52 * fWidth);
33         setMinimumHeight(((Global::nibbleCount + 51) / 52) * fHeight);
34         setMaximumHeight(((Global::nibbleCount + 51) / 52) * fHeight);
35         update();
36 }
37
38
39 void NibbleWidget::DecodeWaveform(void)
40 {
41         // Sanity check
42         if (Global::streamNum >= Global::numStreams)
43                 return;
44
45         uint8_t * data = Global::bitStream;
46         uint32_t dataSize = Uint32LE(Global::stream[Global::streamNum]->dataLength);
47         uint8_t * sdata = Global::stream[Global::streamNum]->data;
48         uint32_t & bits = Global::bitStreamLength;
49         bits = 0;
50
51         // Prime the pump
52         data[bits++] = 1;
53
54         for(uint32_t i=1; i<dataSize; i++)
55         {
56                 uint32_t timeToNext = sdata[i];
57
58                 if (sdata[i] == 0xFF)
59                 {
60                         while (sdata[i++] == 0xFF)
61                                 timeToNext += sdata[i];
62                 }
63
64                 if ((sdata[i] > 24))
65                 {
66                         if ((timeToNext >= 24) && (timeToNext <= 49))
67                         {
68                                 data[bits++] = 1;
69                         }
70                         else if ((timeToNext >= 50) && (timeToNext <= 80))
71                         {
72                                 data[bits++] = 0;
73                                 data[bits++] = 1;
74                         }
75                         else if ((timeToNext >= 81) && (timeToNext <= 112))
76                         {
77                                 data[bits++] = 0;
78                                 data[bits++] = 0;
79                                 data[bits++] = 1;
80                         }
81                         else if ((timeToNext >= 113) && (timeToNext <= 137))
82                         {
83                                 data[bits++] = 0;
84                                 data[bits++] = 0;
85                                 data[bits++] = 0;
86                                 data[bits++] = 1;
87                         }
88                         else
89                         {
90                                 // Handle zeros here...
91                                 while (timeToNext > 32)
92                                 {
93                                         data[bits++] = 0;
94                                         timeToNext -= 32;
95                                 }
96
97                                 data[bits++] = 1;
98                         }
99                 }
100         }
101 }
102
103
104 void NibbleWidget::DecodeBitstream(void)
105 {
106         uint8_t zeroBits3[6] = { 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07 };
107         uint8_t * data = Global::bitStream;
108
109         // Sanity check
110         if (data == NULL)
111                 return;
112
113         uint32_t dataSize = Global::bitStreamLength;
114         uint32_t pos = 0;
115         uint8_t byte = 0;
116         Global::nibbleCount = 0;
117         memset(nibble, 0, sizeof(uint16_t) * 10000);
118
119         while (pos < dataSize)
120         {
121                 uint8_t bit = data[pos];
122
123                 if (byte & 0x80)
124                 {
125                         if (!bit)
126                                 nibble[Global::nibbleCount]++;
127                         else
128                         {
129                                 // Check to see if there are illegal bit patterns in the
130                                 // decoded byte
131                                 for(uint8_t i=0; i<6; i++)
132                                 {
133                                         if ((byte & zeroBits3[i]) == 0)
134                                         {
135                                                 nibble[Global::nibbleCount] |= 0x0080;
136                                                 break;
137                                         }
138                                 }
139
140                                 nibble[Global::nibbleCount++] |= byte << 8;
141                                 byte = 1;
142                         }
143                 }
144                 else
145                         byte = (byte << 1) | (bit ? 1 : 0);
146
147                 pos++;
148         }
149 }
150
151
152 void NibbleWidget::paintEvent(QPaintEvent * /*event*/)
153 {
154         QPainter painter(this);
155         painter.setRenderHint(QPainter::Antialiasing);
156
157 //      QFont font("Monospace"); // ugly
158 //      QFont font("DejaVu Sans Mono"); // ugly
159         QFont font("Hack");
160         font.setPixelSize(14.5);
161         font.setWeight(QFont::Black);
162         font.setHintingPreference(QFont::PreferFullHinting);
163         font.setStyleHint(QFont::Monospace);
164         painter.setFont(font);
165
166         for(uint32_t y=0; y<(Global::nibbleCount+51)/52; y++)
167         {
168                 for(uint32_t x=0; x<52; x++)
169                 {
170                         if (((y * 52) + x) >= Global::nibbleCount)
171                                 break;
172
173                         QRectF r(x * fWidth, y * fHeight, fWidth, fHeight);
174                         uint8_t trailingZeroes = nibble[(y * 52) + x] & 0x7F;
175                         uint8_t badBitPattern = nibble[(y * 52) + x] & 0x80;
176
177                         if (trailingZeroes)
178                                 painter.fillRect(r, QColor(0xBF, 0xE3, 0xEF, 0xFF));
179                         else
180                                 painter.fillRect(r, Qt::white);
181
182                         if (badBitPattern)
183                                 painter.setPen(Qt::red);
184
185                         painter.drawText(r.translated(0.0, 2.0), Qt::AlignCenter, QString("%1").arg((ushort)(nibble[(y * 52) + x] >> 8), 2, 16, QChar('0')).toUpper());
186                         painter.setPen(Qt::black);
187
188                         if (trailingZeroes == 1)
189                         {
190                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f), r.y() + 5.0f), 2.0f, 2.0f);
191                         }
192                         else if (trailingZeroes == 2)
193                         {
194                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) - 4.0f, r.y() + 5.0f), 2.0f, 2.0f);
195                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) + 4.0f, r.y() + 5.0f), 2.0f, 2.0f);
196                         }
197                         else if (trailingZeroes >= 3)
198                         {
199                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f), r.y() + 5.0f), 2.0f, 2.0f);
200                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) - 6.0f, r.y() + 5.0f), 2.0f, 2.0f);
201                                 painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) + 6.0f, r.y() + 5.0f), 2.0f, 2.0f);
202                         }
203                 }
204         }
205 }
206
207
208 void NibbleWidget::mousePressEvent(QMouseEvent * event)
209 {
210         if (event->button() == Qt::LeftButton)
211         {
212                 event->accept();
213         }
214 }
215
216
217 void NibbleWidget::mouseMoveEvent(QMouseEvent * event)
218 {
219         if (event->buttons() & Qt::LeftButton)
220         {
221                 event->accept();
222         }
223 }
224
225
226 void NibbleWidget::mouseReleaseEvent(QMouseEvent * event)
227 {
228         if (event->button() == Qt::LeftButton)
229         {
230                 event->accept();
231         }
232 }
233
234
235 void NibbleWidget::mouseDoubleClickEvent(QMouseEvent * event)
236 {
237         if (event->button() == Qt::LeftButton)
238         {
239                 event->accept();
240         }
241 }
242
243
244 void NibbleWidget::keyPressEvent(QKeyEvent * event)
245 {
246         int key = event->key();
247
248         if (key == Qt::Key_Up)
249         {
250         }
251         else if (key == Qt::Key_Down)
252         {
253         }
254         else if (key == Qt::Key_Left)
255         {
256         }
257         else if (key == Qt::Key_Right)
258         {
259         }
260         else
261                 return;
262
263         // Only update if a key we recognize has been pressed!
264         update();
265 }
266
267
268 void NibbleWidget::keyReleaseEvent(QKeyEvent * /*event*/)
269 {
270 }
271
272
273 void NibbleWidget::resizeEvent(QResizeEvent * /*event*/)
274 {
275 //      ResizeGrid();
276 }
277