source: thomson/elec/CrO2/software/gui.cpp@ 53c4be3

main
Last change on this file since 53c4be3 was 53c4be3, checked in by Adrien Destugues <pulkomandy@…>, 12 years ago
  • Support for ZX spectrup TAP files.

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

  • Property mode set to 100644
File size: 6.4 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
111 // WINDOW LAYOUT
112 Ihandle* tabs = IupTabs(
113 IupVbox(
114 IupHbox(
115 IupLabel("Motor"),
116 motoron,
117 NULL
118 ),
119 IupHbox(
120 playToggle,
121 IupToggle("REC",NULL),
122 NULL
123 ),
124 NULL
125 ),
126 IupVbox(
127 IupHbox(
128 IupLabel("Format:"),
129 platformlist,
130 NULL
131 ),
132 IupHbox(
133 blocklist,
134 IupVbox(
135 hexEd,
136 IupLabel("Checksum:"),
137 NULL
138 ),
139 NULL
140 )
141 ),
142 NULL
143 );
144
145 IupSetAttribute(tabs,"TABTITLE0", "Control");
146 IupSetAttribute(tabs,"TABTITLE1", "Explore");
147
148 Ihandle* dialog = IupDialog(tabs);
149 IupSetAttribute(dialog, "TITLE", "CrO2 tape emulator");
150 IupSetAttributeHandle(dialog, "MENU", menu);
151 IupShow(dialog);
152
153 // Run the timer
154 startPolling(motoron);
155
156 // TODO the IUP main loop is blocking - it may be wise to move it out of
157 // the constructor...
158 IupMainLoop();
159}
160
161
162Gui::~Gui()
163{
164 delete file;
165
166 IupControlsClose();
167 IupClose();
168}
169
170
171int Gui::menu_open()
172{
173 char name[65536];
174 name[0] = 0;
175 if (IupGetFile(name) == 0)
176 {
177 // Load file
178 try {
179 file = Tape::load(name);
180 } catch (const char* error) {
181 puts(error);
182 return IUP_DEFAULT;
183 }
184
185 // Fill in EXPLORE tab
186 int count = file->getBlockCount();
187 int lastfile = -1;
188
189 IupSetAttribute(blocklist, "DELNODE", "ALL");
190
191 for (int i = 0; i < count; ++i)
192 {
193 const Tape::Block& blk = file->getBlock(i);
194 if (blk.isFile())
195 {
196 IupSetAttributeId(blocklist, "INSERTBRANCH", lastfile, blk.getName().c_str());
197 lastfile = i;
198 } else {
199 IupSetAttributeId(blocklist, "ADDLEAF", i-1, blk.getName().c_str());
200 if (blk.isControl())
201 IupSetAttributeId(blocklist, "IMAGE", i, "IMGLEAF");
202 }
203 }
204 }
205 return IUP_DEFAULT;
206}
207
208int Gui::menu_exit()
209{
210 return IUP_CLOSE;
211}
212
213int Gui::selectBlock(int id, int what)
214{
215 if (what)
216 {
217 selblock = id;
218 std::ostringstream att;
219 att << (file->getBlock(id).length / 16);
220 IupSetAttribute(hexEd, "NUMLIN", att.str().c_str());
221
222 IupSetAttribute(hexEd, IUP_REDRAW, "ALL");
223 } else if (selblock == id) {
224 selblock = -1;
225 }
226
227 return IUP_DEFAULT;
228}
229
230const char* Gui::matVal(int y, int x)
231{
232 if (y == 0)
233 {
234 switch(x)
235 {
236 case 0:
237 return "0x";
238 case 17:
239 return "ASCII";
240 default:
241 {
242 std::ostringstream name;
243 name << std::hex;
244 name << (x-1);
245 return name.str().c_str();
246 }
247 }
248 }
249
250 if (x == 0)
251 {
252 std::ostringstream name;
253 name << std::hex;
254 name << (y-1)*16;
255 return name.str().c_str();
256 }
257
258 if (file == NULL || selblock < 0 || selblock >= file->getBlockCount())
259 return "";
260 const Tape::Block& block = file->getBlock(selblock);
261
262 if (x == 17)
263 {
264 int off = (y-1)*16;
265 std::ostringstream txt;
266 for(int j = 0; j < 16; j++)
267 {
268 if (off + j >= block.length)
269 break;
270 char c = block.data[off+j];
271 if (isprint(c))
272 txt << c;
273 else
274 txt << '.';
275 }
276 return txt.str().c_str();
277 } else {
278
279 int pos = (y-1) * 16 + (x-1);
280 if (pos >= block.length)
281 return "";
282
283 return toHex(block.data[pos]);
284 }
285}
286
287int Gui::setPlaying(int state)
288{
289 if (state == 0)
290 {
291 // pause
292 } else {
293 // play
294 Device::getDevice().write(*file);
295 }
296
297 return IUP_DEFAULT;
298}
299
300const char* Gui::toHex(int val)
301{
302 std::ostringstream str;
303 str.flags(std::ios_base::hex | std::ios_base::uppercase);
304 str.width(2);
305 str.fill('0');
306 str << val;
307 return str.str().c_str();
308}
Note: See TracBrowser for help on using the repository browser.