source: thomson/elec/CrO2/software/gui.cpp@ 45825a3

main
Last change on this file since 45825a3 was 45825a3, checked in by Adrien Destugues <pulkomandy@…>, 11 years ago

Add some safety checks

git-svn-id: svn://localhost/thomson@31 85ae3b6b-dc8f-4344-a89d-598714f2e4e5

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/* CrO2 datassette emulator
2 * Copyright 2012, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
3 *
4 * Distributed under the terms of the MIT licence.
5 */
6
7#include "gui.h"
8
9#include "device.h"
10#include "k5.h"
11
12#include <stdint.h>
13#include <string.h>
14#include <sstream>
15#include <ios>
16
17#include <iupcontrols.h>
18
19 // Start status poller "thread"
20int pollStatus(Ihandle* ih)
21{
22 uint8_t status;
23 try {
24 Device& dev = Device::getDevice();
25 status = dev.getStatus();
26 } catch(const char* ex) {
27 // Silently ignore exception if device is not available - not a good
28 // idea to handle it from a timer...
29 // Keep the timer running so it starts working when the device is
30 // plugged
31 return IUP_DEFAULT;
32 }
33
34 Ihandle* motoron = (Ihandle*)IupGetAttribute(ih, "target");
35 if (status & 8)
36 IupSetAttribute(motoron, "VALUE", "0"); // motor OFF
37 else
38 IupSetAttribute(motoron, "VALUE", "1"); // motor ON
39 return IUP_DEFAULT;
40}
41
42
43void startPolling(Ihandle* target) {
44 Ihandle* timer = IupTimer();
45
46 IupSetAttribute(timer, "target", (const char*)target);
47
48 IupSetAttribute(timer, "TIME", "300");
49 IupSetCallback(timer, "ACTION_CB", pollStatus);
50 IupSetAttribute(timer, "RUN", "YES");
51}
52
53/* UI */
54
55Gui::Gui(int* argc, char*** argv)
56{
57 file = NULL;
58
59 IupOpen(argc, argv);
60 IupControlsOpen();
61 IupImageLibOpen();
62
63 Ihandle* menu_open = IupItem("Open", NULL);
64 Ihandle* menu_exit = IupItem("Exit", NULL);
65 Callback<Gui>::create(menu_open, "ACTION", this, &Gui::menu_open);
66 Callback<Gui>::create(menu_exit, "ACTION", this, &Gui::menu_exit);
67
68 Ihandle* menu = IupMenu(
69 IupSubmenu("File",
70 IupMenu(
71 menu_open,
72 menu_exit,
73 NULL
74 )
75 ),
76 NULL
77 );
78
79 // CONTROL
80 Ihandle* motoron = IupProgressBar();
81 IupSetAttribute(motoron, "RASTERSIZE", "16x16");
82
83 playToggle = IupToggle("play", NULL);
84 IupSetAttribute(playToggle, "ACTIVE", "NO");
85 IupSetAttribute(playToggle, "IMAGE", "IUP_MediaPlay");
86 Callback<Gui, int, int>::create(playToggle, "ACTION", this,
87 &Gui::setPlaying);
88
89 Ihandle* recToggle = IupToggle("rec", NULL);
90 IupSetAttribute(recToggle, "ACTIVE", "NO");
91 IupSetAttribute(recToggle, "IMAGE", "IUP_MediaRecord");
92
93 // EXPLORE
94 Ihandle* platformlist = IupList(NULL);
95 IupSetAttribute(platformlist, "EXPAND", "HORIZONTAL");
96 IupSetAttribute(platformlist, "DROPDOWN", "YES");
97 IupSetAttribute(platformlist, "1", "MO5");
98 IupSetAttribute(platformlist, "VALUE", "1");
99
100 blocklist = IupTree();
101 IupSetAttribute(blocklist, "EXPAND", "VERTICAL");
102 IupSetAttribute(blocklist, "ADDEXPANDED", "NO");
103 IupSetAttribute(blocklist, "ADDROOT", "NO");
104 IupSetAttribute(blocklist, "IMAGELEAF", "IMGBLANK");
105 IupSetAttribute(blocklist, "RASTERSIZE", "140x200");
106 Callback<Gui, int, int, int>::create(blocklist, "SELECTION_CB", this, &Gui::selectBlock);
107
108 hexEd = IupMatrix(NULL);
109
110 // Setup title cells
111 IupSetAttribute(hexEd, "FONT", "Courier, 10");
112 IupSetAttribute(hexEd, "FONT*:17", "Courier, 10");
113 IupSetAttribute(hexEd, "NUMCOL", "17");
114 IupSetAttribute(hexEd, "WIDTHDEF", "10");
115 IupSetAttribute(hexEd, "WIDTH17", "105");
116 IupSetAttribute(hexEd, "WIDTH0", "12");
117 IupSetAttribute(hexEd, "HEIGHT0", "8");
118 IupSetAttribute(hexEd, "SIZE", "400x230");
119 IupSetAttribute(hexEd, "EXPAND", "YES");
120 IupSetAttribute(hexEd, "ALIGNMENT", "ALEFT");
121 Callback<Gui, const char*, int, int>::create(hexEd, "VALUE_CB", this, &Gui::matVal);
122 Callback<Gui, int, int, int, const char*>::create(hexEd, "VALUE_EDIT_CB", this, &Gui::setMatVal);
123
124 // WINDOW LAYOUT
125 Ihandle* tabs = IupTabs(
126 IupVbox(
127 IupHbox(
128 IupLabel("Motor"),
129 motoron,
130 NULL
131 ),
132 IupHbox(
133 playToggle,
134 recToggle,
135 NULL
136 ),
137 NULL
138 ),
139 IupVbox(
140 IupHbox(
141 IupLabel("Format:"),
142 platformlist,
143 NULL
144 ),
145 IupHbox(
146 blocklist,
147 IupVbox(
148 hexEd,
149 IupLabel("Checksum:"),
150 NULL
151 ),
152 NULL
153 )
154 ),
155 NULL
156 );
157
158 IupSetAttribute(tabs,"TABTITLE0", "Control");
159 IupSetAttribute(tabs,"TABTITLE1", "Explore");
160
161 Ihandle* dialog = IupDialog(tabs);
162 IupSetAttribute(dialog, "TITLE", "CrO2 tape emulator");
163 IupSetAttributeHandle(dialog, "MENU", menu);
164 IupShow(dialog);
165
166 // Run the timer
167 startPolling(motoron);
168
169 // TODO the IUP main loop is blocking - it may be wise to move it out of
170 // the constructor...
171 IupMainLoop();
172}
173
174
175Gui::~Gui()
176{
177 delete file;
178
179 IupControlsClose();
180 IupClose();
181}
182
183
184int Gui::menu_open()
185{
186 char name[65536];
187 name[0] = 0;
188 if (IupGetFile(name) == 0)
189 {
190 // Load file
191 try {
192 file = Tape::load(name);
193 } catch (const char* error) {
194 // FIXME popup an error dialog
195 puts(error);
196 return IUP_DEFAULT;
197 }
198
199 // Fill in EXPLORE tab
200 int count = file->getBlockCount();
201 int lastfile = -1;
202
203 IupSetAttribute(blocklist, "DELNODE", "ALL");
204
205 for (int i = 0; i < count; ++i)
206 {
207 const Tape::Block& blk = file->getBlock(i);
208 if (blk.isFile())
209 {
210 IupSetAttributeId(blocklist, "INSERTBRANCH", lastfile, blk.getName().c_str());
211 lastfile = i;
212 } else {
213 IupSetAttributeId(blocklist, "ADDLEAF", i-1, blk.getName().c_str());
214 if (blk.isControl())
215 IupSetAttributeId(blocklist, "IMAGE", i, "IMGLEAF");
216 }
217 }
218
219 // Enable play button
220 IupSetAttribute(playToggle, "ACTIVE", "YES");
221 }
222 return IUP_DEFAULT;
223}
224
225int Gui::menu_exit()
226{
227 return IUP_CLOSE;
228}
229
230int Gui::selectBlock(int id, int what)
231{
232 if (what)
233 {
234 selblock = id;
235 std::ostringstream att;
236 att << (file->getBlock(id).length / 16);
237 IupSetAttribute(hexEd, "NUMLIN", att.str().c_str());
238
239 IupSetAttribute(hexEd, IUP_REDRAW, "ALL");
240 } else if (selblock == id) {
241 selblock = -1;
242 }
243
244 return IUP_DEFAULT;
245}
246
247
248int Gui::setMatVal(int x, int y, const char* val)
249{
250 int pos = (y-1) * 16 + (x-1);
251
252 if (file == NULL || selblock < 0 || selblock >= file->getBlockCount())
253 return 0;
254
255 const Tape::Block& block = file->getBlock(selblock);
256 block.data[pos] = 0; // TODO parse hex val to int
257
258 return 0;
259}
260
261
262const char* Gui::matVal(int y, int x)
263{
264 if (y == 0)
265 {
266 switch(x)
267 {
268 case 0:
269 return "0x";
270 case 17:
271 return "ASCII";
272 default:
273 {
274 std::ostringstream name;
275 name << std::hex;
276 name << (x-1);
277 return name.str().c_str();
278 }
279 }
280 }
281
282 if (x == 0)
283 {
284 std::ostringstream name;
285 name << std::hex;
286 name << (y-1)*16;
287 return name.str().c_str();
288 }
289
290 if (file == NULL || selblock < 0 || selblock >= file->getBlockCount())
291 return "";
292 const Tape::Block& block = file->getBlock(selblock);
293
294 if (x == 17)
295 {
296 int off = (y-1)*16;
297 std::ostringstream txt;
298 for(int j = 0; j < 16; j++)
299 {
300 if (off + j >= block.length)
301 break;
302 char c = block.data[off+j];
303 if (isprint(c))
304 txt << c;
305 else
306 txt << '.';
307 }
308 return txt.str().c_str();
309 } else {
310
311 int pos = (y-1) * 16 + (x-1);
312 if (pos >= block.length)
313 return "";
314
315 return toHex(block.data[pos]);
316 }
317}
318
319int Gui::setPlaying(int state)
320{
321 if (state == 0)
322 {
323 // pause
324 } else try {
325 // play
326 Device::getDevice().write(*file);
327 } catch (const char* ex) {
328 IupMessage("CrO2 error", ex);
329 }
330
331 return IUP_DEFAULT;
332}
333
334const char* Gui::toHex(int val)
335{
336 std::ostringstream str;
337 str.flags(std::ios_base::hex | std::ios_base::uppercase);
338 str.width(2);
339 str.fill('0');
340 str << val;
341 return str.str().c_str();
342}
Note: See TracBrowser for help on using the repository browser.