source: thomson/elec/CrO2/software/gui.cpp@ 6bd7144

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

More work on Haiku port

git-svn-id: svn://localhost/thomson@29 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 puts(error);
195 return IUP_DEFAULT;
196 }
197
198 // Fill in EXPLORE tab
199 int count = file->getBlockCount();
200 int lastfile = -1;
201
202 IupSetAttribute(blocklist, "DELNODE", "ALL");
203
204 for (int i = 0; i < count; ++i)
205 {
206 const Tape::Block& blk = file->getBlock(i);
207 if (blk.isFile())
208 {
209 IupSetAttributeId(blocklist, "INSERTBRANCH", lastfile, blk.getName().c_str());
210 lastfile = i;
211 } else {
212 IupSetAttributeId(blocklist, "ADDLEAF", i-1, blk.getName().c_str());
213 if (blk.isControl())
214 IupSetAttributeId(blocklist, "IMAGE", i, "IMGLEAF");
215 }
216 }
217
218 // Enable play button
219 IupSetAttribute(playToggle, "ACTIVE", "YES");
220 }
221 return IUP_DEFAULT;
222}
223
224int Gui::menu_exit()
225{
226 return IUP_CLOSE;
227}
228
229int Gui::selectBlock(int id, int what)
230{
231 if (what)
232 {
233 selblock = id;
234 std::ostringstream att;
235 att << (file->getBlock(id).length / 16);
236 IupSetAttribute(hexEd, "NUMLIN", att.str().c_str());
237
238 IupSetAttribute(hexEd, IUP_REDRAW, "ALL");
239 } else if (selblock == id) {
240 selblock = -1;
241 }
242
243 return IUP_DEFAULT;
244}
245
246
247int Gui::setMatVal(int x, int y, const char* val)
248{
249 int pos = (y-1) * 16 + (x-1);
250
251 if (file == NULL || selblock < 0 || selblock >= file->getBlockCount())
252 return 0;
253
254 const Tape::Block& block = file->getBlock(selblock);
255 block.data[pos] = 0; // TODO parse hex val to int
256
257 return 0;
258}
259
260
261const char* Gui::matVal(int y, int x)
262{
263 if (y == 0)
264 {
265 switch(x)
266 {
267 case 0:
268 return "0x";
269 case 17:
270 return "ASCII";
271 default:
272 {
273 std::ostringstream name;
274 name << std::hex;
275 name << (x-1);
276 return name.str().c_str();
277 }
278 }
279 }
280
281 if (x == 0)
282 {
283 std::ostringstream name;
284 name << std::hex;
285 name << (y-1)*16;
286 return name.str().c_str();
287 }
288
289 if (file == NULL || selblock < 0 || selblock >= file->getBlockCount())
290 return "";
291 const Tape::Block& block = file->getBlock(selblock);
292
293 if (x == 17)
294 {
295 int off = (y-1)*16;
296 std::ostringstream txt;
297 for(int j = 0; j < 16; j++)
298 {
299 if (off + j >= block.length)
300 break;
301 char c = block.data[off+j];
302 if (isprint(c))
303 txt << c;
304 else
305 txt << '.';
306 }
307 return txt.str().c_str();
308 } else {
309
310 int pos = (y-1) * 16 + (x-1);
311 if (pos >= block.length)
312 return "";
313
314 return toHex(block.data[pos]);
315 }
316}
317
318int Gui::setPlaying(int state)
319{
320 if (state == 0)
321 {
322 // pause
323 } else try {
324 // play
325 Device::getDevice().write(*file);
326 } catch (const char* ex) {
327 IupMessage("CrO2 error", ex);
328 }
329
330 return IUP_DEFAULT;
331}
332
333const char* Gui::toHex(int val)
334{
335 std::ostringstream str;
336 str.flags(std::ios_base::hex | std::ios_base::uppercase);
337 str.width(2);
338 str.fill('0');
339 str << val;
340 return str.str().c_str();
341}
Note: See TracBrowser for help on using the repository browser.