source: thomson/elec/CrO2/software/gui.cpp@ e43c8d0

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

Some cleanup.

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

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