emu: remember page editor cursor position in memview
[zymosis.git] / src / ZXEmuT / memview.c
blobc17dff81b38fb7e2662461848dd802ed3e069203
1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2022 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #define MV_FAST_RECODE
22 #include "../libzymosis/zymosis.h"
23 #include "libvideo/video.h"
24 #include "memview.h"
25 #include "emucommon.h"
26 #include "emuvars.h"
27 #include "emuutils.h"
28 #include "console.h"
31 // ////////////////////////////////////////////////////////////////////////// //
32 #ifdef MV_FAST_RECODE
33 static const uint8_t cp1251to866[256] = {
34 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
35 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
36 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
37 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
38 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
39 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
40 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
41 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
42 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
43 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
44 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
45 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
46 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
47 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
48 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
49 0xa8,0xb8,0xaa,0xba,0xaf,0xbf,0xa1,0xa2,0xb0,0x00,0xb7,0x00,0xb9,0xa4,0x00,0xa0,
52 #else
54 static const uint16_t charMap1251[128] = {
55 0x0402,0x0403,0x201A,0x0453,0x201E,0x2026,0x2020,0x2021,0x20AC,0x2030,0x0409,0x2039,0x040A,0x040C,0x040B,0x040F,
56 0x0452,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014,0x003F,0x2122,0x0459,0x203A,0x045A,0x045C,0x045B,0x045F,
57 0x00A0,0x040E,0x045E,0x0408,0x00A4,0x0490,0x00A6,0x00A7,0x0401,0x00A9,0x0404,0x00AB,0x00AC,0x00AD,0x00AE,0x0407,
58 0x00B0,0x00B1,0x0406,0x0456,0x0491,0x00B5,0x00B6,0x00B7,0x0451,0x2116,0x0454,0x00BB,0x0458,0x0405,0x0455,0x0457,
59 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,0x041F,
60 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,0x042F,
61 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,0x043E,0x043F,
62 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,0x044E,0x044F,
65 static const uint16_t charMap866[128] = {
66 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,0x041F,
67 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,0x042F,
68 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,0x043E,0x043F,
69 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510,
70 0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567,
71 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580,
72 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,0x044E,0x044F,
73 0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040E,0x045E,0x00B0,0x2219,0x00B7,0x221A,0x2116,0x00A4,0x25A0,0x00A0,
77 static uint8_t table1251to866[65536];
78 static int tableRCInited = 0;
81 //==========================================================================
83 // initTableRC
85 //==========================================================================
86 static void initTableRC (void) {
87 tableRCInited = 1;
88 memset(table1251to866, '.', sizeof(table1251to866));
89 for (uint16_t f = 0; f < 128; ++f) table1251to866[f] = (uint8_t)f;
90 for (uint16_t f = 0; f < 128; ++f) {
91 const uint16_t code = charMap1251[f];
92 for (uint16_t c = 0; c < 128; ++c) {
93 if (charMap866[c] == code) {
94 table1251to866[f+128U] = (uint8_t)(c+128U);
99 #endif
102 // ////////////////////////////////////////////////////////////////////////// //
103 int memviewActive = 0;
104 uint8_t mv_pagemap[256];
106 // >0xffff: pages
107 uint32_t mv_staddr = 0x5B00;
108 int mv_encoding = MV_ENC_7BIT;
109 int mv_viewmode = MV_MODE_HEX;
110 int mv_textwidth = 64;
111 uint8_t mv_textcolor = 7; // paper is ignored
113 static int inaddrpos = -1;
114 static int mmeditpos = 0;
115 static int mmeditactive = 0;
117 static vt_simple_menu *current_menu = NULL;
118 static void (*menu_sel_cb) (uint32_t sel) = NULL;
119 static vt_simple_menu wkmenu;
121 static int evtCtrlKeyDown = 0;
122 static int evtAltKeyDown = 0;
123 static int evtShiftKeyDown = 0;
126 //==========================================================================
128 // recodeByte
130 //==========================================================================
131 static inline uint16_t recodeByte (uint16_t b) {
132 if (mv_encoding == MV_ENC_1251) {
133 #ifdef MV_FAST_RECODE
134 b = cp1251to866[b];
135 #else
136 if (!tableRCInited) initTableRC();
137 b = table1251to866[b];
138 #endif
140 if (mv_encoding == MV_ENC_7BIT) b &= 0x7f;
141 if (b < 32 || b == 127) b = '.'|0x8000;
142 else if (b == 32 && mv_viewmode == MV_MODE_HEX) b = '.'|0x4000;
143 return b;
147 //==========================================================================
149 // isAddrEditActive
151 //==========================================================================
152 static __attribute__((always_inline)) inline int isAddrEditActive (void) {
153 return (inaddrpos >= 0);
157 //==========================================================================
159 // isMemEditActive
161 //==========================================================================
162 static __attribute__((always_inline)) inline int isMMEditActive (void) {
163 return mmeditactive;
167 //==========================================================================
169 // getByte
171 //==========================================================================
172 static __attribute__((always_inline)) inline uint8_t getByte (uint32_t addr) {
173 return
174 addr <= 0xffffU ?
175 z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER) :
176 zxMemoryBanks[mv_pagemap[((addr>>14)-4)%(unsigned)zxMaxMemoryBank]][addr&0x3fffU];
180 //==========================================================================
182 // memviewResetMMap
184 //==========================================================================
185 static void memviewResetMMap (int inorder) {
186 for (uint32_t f = 0; f < 256; ++f) mv_pagemap[f] = f;
187 if (!inorder) {
188 mv_pagemap[1] = 5;
189 mv_pagemap[5] = 1;
194 //==========================================================================
196 // memviewInit
198 //==========================================================================
199 void memviewInit (void) {
200 memviewResetMMap(1);
204 //==========================================================================
206 // memviewSetActive
208 //==========================================================================
209 void memviewSetActive (int st) {
210 memviewActive = !!st;
214 //==========================================================================
216 // drawAllChars
218 //==========================================================================
219 static __attribute__((unused)) void drawAllChars (void) {
220 for (int y = 0; y < 16; ++y) {
221 for (int x = 0; x < 16; ++x) {
222 vt_writechar(x, y, y*16+x, 0x0f);
225 for (int x = 0; x < 16; ++x) {
226 vt_writechar(x, VID_TEXT_HEIGHT-1, '*', (x<<4)|(x < 8 ? 15 : 0));
231 //==========================================================================
233 // drawMMap
235 //==========================================================================
236 static void drawMMap (void) {
237 int xofs = 26;
238 int yofs = 10;
240 vt_draw_frame_ex(xofs-2, yofs-1, 3*8+3, 10, 0x50,
241 VID_FRAME_DOUBLE|VID_FRAME_OVERWRITE|VID_FRAME_FILL,
242 " Page Map ");
244 for (int y = 0; y < 8; ++y) {
245 for (int x = 0; x < 8; ++x) {
246 uint8_t attr;
247 if (y*8+x == mmeditpos/2) {
248 attr = 0x1F;
249 } else {
250 attr = (zxMemBanksDirty[mv_pagemap[y*8+x]] ? 0x50 : 0x51);
252 vt_writef(xofs+x*3, yofs+y, attr, "%02X", mv_pagemap[y*8+x]);
256 const int cx = mmeditpos%16;
257 const int cy = mmeditpos/16;
258 vt_writeattr(xofs+(cx/2)*3+(cx%2), yofs+cy, emuGetCursorColor(0xF0, 0x70));
262 //==========================================================================
264 // writeAddrAt
266 //==========================================================================
267 static void writeAddrAt (int x, int y, uint32_t addr) {
268 uint8_t dirty;
269 char buf[16];
270 if (addr <= 0xffffU) {
271 snprintf(buf, sizeof(buf), ".. %04X", addr);
272 dirty = zxMemBanksDirty[zxMemoryBankNum[addr>>14]];
273 } else {
274 snprintf(buf, sizeof(buf), "%02X %04X", ((addr>>14)-4)%zxMaxMemoryBank, addr&0x3fffU);
275 dirty = zxMemBanksDirty[mv_pagemap[((addr>>14)-4)%(unsigned)zxMaxMemoryBank]];
277 vt_writestrcnt(x, y, buf, 7, 0x05);
278 if (!dirty) vt_writeattrs(x, y, 2, 0x03);
282 //==========================================================================
284 // drawHexView
286 //==========================================================================
287 static void drawHexView (void) {
288 char buf[256];
289 const int mhgt = VID_TEXT_HEIGHT-2;
290 uint32_t addr = mv_staddr;
291 vt_draw_frame(1, 0, 78, mhgt+2, 15, VID_FRAME_SINGLE);
292 const int xofs = 2;
293 const int yofs = 1;
294 for (int dy = 0; dy < mhgt; ++dy) {
295 writeAddrAt(xofs, dy+yofs, addr);
297 for (int dx = 0; dx < 16; ++dx) {
298 if (addr <= 0xffffU && addr+(unsigned)dx > 0xffffU) break;
299 uint8_t b = getByte(addr+(unsigned)dx);
300 snprintf(buf, sizeof(buf), "%02X", b);
301 vt_writestrz(xofs+8+dx*3+(dx >= 8), dy+yofs, buf, 7);
304 for (int dx = 0; dx < 16; ++dx) {
305 if (addr <= 0xffffU && addr+(unsigned)dx > 0xffffU) break;
306 uint16_t b = recodeByte(getByte(addr+(unsigned)dx));
307 vt_writechar(xofs+8+16*3+2+dx+(dx >= 8), dy+yofs, (char)b,
308 (b <= 0xff ? mv_textcolor : (b&0x8000 ? 5 : mv_textcolor)+(b&0x4000 ? 0x10 : 0)));
311 addr += 16;
316 //==========================================================================
318 // goLineUp
320 //==========================================================================
321 static uint32_t goLineUp (uint32_t addr) {
322 if (!addr) return 0;
323 uint8_t b = getByte(addr-1U);
324 const int skiptsp = (b == 10 || b == 13);
325 if (b == 10) {
326 --addr;
327 if (addr && getByte(addr-1U) == 13) --addr;
328 if (!addr) return 0;
329 } else if (b == 13) {
330 --addr;
331 if (!addr) return 0;
333 int zerostate = -1; // <0:haven't seen; 0:non-zero seen; 1:only zero seen
334 // skip trailing spaces
335 if (skiptsp) {
336 while (addr && getByte(addr-1U) == 32) {
337 --addr;
338 zerostate = 0;
341 const uint32_t orgaddr = addr;
342 int count = mv_textwidth;
343 while (addr && count--) {
344 b = getByte(addr-1U);
345 if (b == 13 || b == 10) return addr;
346 if (b == 0) {
347 if (zerostate == 0) return addr; // seen non-zero
348 zerostate = 1; // only zero seen
349 } else {
350 if (zerostate == 1) return addr;
351 zerostate = 0; // seen non-zero
353 --addr;
355 return (addr ? orgaddr-mv_textwidth : 0);
359 //==========================================================================
361 // goLineDown
363 //==========================================================================
364 static uint32_t goLineDown (uint32_t addr) {
365 const uint32_t orgaddr = addr;
366 int count = mv_textwidth;
367 int zerostate = -1; // <0:haven't seen; 0:non-zero seen; 1:only zero seen
368 uint8_t b;
369 while (addr && count--) {
370 b = getByte(addr++);
371 if (b == 13 || b == 10) {
372 if (b == 13 && getByte(addr) == 10) ++addr;
373 return addr;
375 if (b == 0) {
376 if (zerostate == 0) return addr-1; // seen non-zero
377 zerostate = 1; // only zero seen
378 } else {
379 if (zerostate == 1) return addr-1;
380 zerostate = 0; // seen non-zero
383 addr = orgaddr+mv_textwidth;
384 // check for trailing spaces
385 while (getByte(addr) == 32) ++addr;
386 b = getByte(addr);
387 if (b == 13) b = getByte(++addr);
388 if (b == 10) ++addr;
389 return addr;
393 //==========================================================================
395 // drawTextView
397 //==========================================================================
398 static void drawTextView (void) {
399 const int xofs = 2;
400 const int yofs = 1;
401 uint32_t addr = mv_staddr;
402 vt_draw_frame(1, 0, 78, VID_TEXT_HEIGHT, 15, VID_FRAME_SINGLE);
403 for (int y = 0; y < VID_TEXT_HEIGHT-2; ++y) {
404 writeAddrAt(xofs, y+yofs, addr);
405 uint32_t eaddr = goLineDown(addr);
406 if (eaddr > addr && getByte(eaddr-1) == 10) --eaddr;
407 if (eaddr > addr && getByte(eaddr-1) == 13) --eaddr;
408 const uint32_t naddr = eaddr;
409 if (eaddr-addr > mv_textwidth) eaddr = addr+mv_textwidth;
410 int xxofs = (MV_MAX_TEXT_WIDTH-mv_textwidth)/2;
411 const uint32_t len = eaddr-addr;
412 for (uint32_t x = 0; x < len; ++x) {
413 uint16_t b = recodeByte(getByte(addr++));
414 vt_writechar(xofs+8+xxofs+x, y+yofs, (char)b,
415 (b <= 0xff ? mv_textcolor : (b&0x8000 ? 5 : mv_textcolor)+(b&0x4000 ? 0x10 : 0)));
417 // check for trailing spaces
418 addr = naddr;
419 while (getByte(addr) == 32) ++addr;
420 if (getByte(addr) == 13) ++addr;
421 if (getByte(addr) == 10) ++addr;
423 vt_writef(7, 0, 0x05, "[wdt:%d]", mv_textwidth);
427 //==========================================================================
429 // memviewDraw
431 //==========================================================================
432 void memviewDraw (void) {
433 //vt_cls(0xb0, 0x01);
434 vt_cls(32, 0x07);
436 if (mv_viewmode == MV_MODE_HEX) drawHexView(); else drawTextView();
438 switch (mv_encoding) {
439 case MV_ENC_7BIT: vt_writestrz(2+70, 0, "[7bit]", 4); break;
440 case MV_ENC_1251: vt_writestrz(2+68, 0, "[cp1251]", 4); break;
441 case MV_ENC_866: vt_writestrz(2+69, 0, "[cp866]", 4); break;
444 // draw physical page
446 uint8_t pg;
447 if (mv_staddr <= 0xffffU) {
448 pg = zxMemoryBankNum[mv_staddr>>14];
449 } else {
450 pg = mv_pagemap[((mv_staddr>>14)-4)%(unsigned)zxMaxMemoryBank];
452 uint8_t attr = (zxMemBanksDirty[pg] ? 0x04 : 0x03);
453 vt_writef(2, 0, attr, "[%02X]", pg);
456 if (isAddrEditActive()) {
457 vt_writeattr(2+inaddrpos+(inaddrpos >= 2), 1, emuGetCursorColor(0xF0, 0x70));
458 } else if (isMMEditActive()) {
459 drawMMap();
462 if (current_menu) vt_smm_draw(current_menu);
464 #if 0
465 drawAllChars();
466 #endif
470 //==========================================================================
472 // doLeft
474 //==========================================================================
475 static void doLeft (void) {
476 if (isAddrEditActive()) {
477 if (inaddrpos) --inaddrpos;
478 return;
480 if (isMMEditActive()) {
481 if (mmeditpos > 0) --mmeditpos;
482 return;
484 if (mv_staddr) --mv_staddr;
488 //==========================================================================
490 // doRight
492 //==========================================================================
493 static void doRight (void) {
494 if (isAddrEditActive()) {
495 if (inaddrpos < 5) ++inaddrpos;
496 return;
498 if (isMMEditActive()) {
499 if (mmeditpos < 64*2-1) ++mmeditpos;
500 return;
502 ++mv_staddr;
506 //==========================================================================
508 // doUp
510 //==========================================================================
511 static void doUp (void) {
512 if (isAddrEditActive()) {
513 if (inaddrpos >= 2) inaddrpos = 0;
514 return;
516 if (isMMEditActive()) {
517 if (mmeditpos >= 8*2) mmeditpos -= 8*2;
518 return;
520 if (mv_viewmode == MV_MODE_TEXT) {
521 uint32_t nn = goLineUp(mv_staddr);
522 if (mv_staddr > 0xffffU && nn <= 0xffffU) nn = 0x010000U;
523 mv_staddr = nn;
524 return;
526 if (mv_staddr <= 0xffffU) {
527 if (mv_staddr < 16) mv_staddr = 0; else mv_staddr -= 16;
528 } else {
529 mv_staddr -= 16;
534 //==========================================================================
536 // doDown
538 //==========================================================================
539 static void doDown (void) {
540 if (isAddrEditActive()) {
541 if (inaddrpos < 2) inaddrpos = 2;
542 return;
544 if (isMMEditActive()) {
545 if (mmeditpos+8*2 < 64*2) mmeditpos += 8*2;
546 return;
548 if (mv_viewmode == MV_MODE_TEXT) {
549 mv_staddr = goLineDown(mv_staddr);
550 return;
552 mv_staddr += 16;
556 //==========================================================================
558 // doPageUp
560 //==========================================================================
561 static void doPageUp (void) {
562 if (isAddrEditActive()) {
563 if (mv_staddr > 0xffffU) {
564 uint32_t pg = (mv_staddr>>14)-4;
565 if (pg > 0) --pg;
566 mv_staddr = (pg+4)<<14;
568 return;
570 if (isMMEditActive()) return;
571 if (mv_viewmode == MV_MODE_TEXT) {
572 for (int f = 0; f < VID_TEXT_HEIGHT-3; ++f) {
573 uint32_t nn = goLineUp(mv_staddr);
574 if (mv_staddr > 0xffffU && nn <= 0xffffU) nn = 0x010000U;
575 mv_staddr = nn;
577 return;
579 if (mv_staddr <= 0xffffU) {
580 if (mv_staddr < 16*(VID_TEXT_HEIGHT-2)) mv_staddr = 0; else mv_staddr -= 16*(VID_TEXT_HEIGHT-2);
581 } else {
582 mv_staddr -= 16*(VID_TEXT_HEIGHT-2);
587 //==========================================================================
589 // doPageDown
591 //==========================================================================
592 static void doPageDown (void) {
593 if (isAddrEditActive()) {
594 if (mv_staddr <= 0xffffU) {
595 mv_staddr = 0x010000U;
596 } else {
597 uint32_t pg = (mv_staddr>>14)-4;
598 if (pg+1 < (uint32_t)zxMaxMemoryBank) mv_staddr = (pg+5)<<14;
600 return;
602 if (isMMEditActive()) return;
603 if (mv_viewmode == MV_MODE_TEXT) {
604 for (int f = 0; f < VID_TEXT_HEIGHT-3; ++f) {
605 mv_staddr = goLineDown(mv_staddr);
607 return;
609 if (mv_staddr <= 0xffffU) {
610 if (mv_staddr+16*(VID_TEXT_HEIGHT-2) > 0xffffU) mv_staddr = 0x10000U-16; else mv_staddr += 16*(VID_TEXT_HEIGHT-2);
611 } else {
612 mv_staddr += 16*(VID_TEXT_HEIGHT-2);
617 //==========================================================================
619 // menu_set_encoding
621 //==========================================================================
622 static void menu_set_encoding (uint32_t sel) {
623 mv_encoding = (int)sel;
627 //==========================================================================
629 // menu_set_text_width
631 //==========================================================================
632 static void menu_set_text_width (uint32_t sel) {
633 const int wdts[5] = {32, 42, 51, 64, MV_MAX_TEXT_WIDTH};
634 mv_textwidth = wdts[sel];
638 //==========================================================================
640 // menu_set_text_bright
642 //==========================================================================
643 static void menu_set_text_bright (uint32_t sel) {
644 mv_textcolor &= 0x07;
645 mv_textcolor |= (sel ? 0x08 : 0x00);
649 //==========================================================================
651 // menu_set_text_color
653 //==========================================================================
654 static void menu_set_text_color (uint32_t sel) {
655 mv_textcolor = (mv_textcolor&0x08)|(sel+1);
659 //==========================================================================
661 // menu_set_view_mode
663 //==========================================================================
664 static void menu_set_view_mode (uint32_t sel) {
665 mv_viewmode = (int)sel;
669 //==========================================================================
671 // memviewKeyEvent
673 //==========================================================================
674 int memviewKeyEvent (SDL_KeyboardEvent *key) {
675 if (current_menu) {
676 int mrs = vt_smm_process_key(current_menu, key);
677 switch (mrs) {
678 case VID_SMM_ESCAPE:
679 vt_smm_deinit(current_menu);
680 current_menu = NULL;
681 return 1;
682 case VID_SMM_NOTMINE:
683 break;
684 case VID_SMM_EATEN:
685 return 1;
686 case VID_SMM_SELECTED:
687 if (menu_sel_cb) {
688 const uint32_t cy = current_menu->cursor_y;
689 vt_smm_deinit(current_menu);
690 current_menu = NULL;
691 menu_sel_cb(cy);
692 } else {
693 vt_smm_deinit(current_menu);
694 current_menu = NULL;
696 return 1;
698 return 1;
701 if (key->type != SDL_KEYDOWN) return 1;
703 evtCtrlKeyDown = !!(key->keysym.mod&KMOD_CTRL);
704 evtAltKeyDown = !!(key->keysym.mod&KMOD_ALT);
705 evtShiftKeyDown = !!(key->keysym.mod&KMOD_SHIFT);
707 if (isAddrEditActive() && key->keysym.unicode > 32 && key->keysym.unicode < 127) {
708 int d = digitInBase((char)key->keysym.unicode, 16);
709 if (d >= 0) {
710 if (inaddrpos < 2) {
711 uint32_t pg = (mv_staddr > 0xffffU ? (mv_staddr>>14)-4 : 0);
712 pg &= (inaddrpos ? 0xf0U : 0x0fU);
713 pg |= ((unsigned)d)<<((1-inaddrpos)*4);
714 mv_staddr = (mv_staddr&0x3fffU)|((pg+4)<<14);
715 } else {
716 if (mv_staddr > 0xffffU && inaddrpos == 2 && d > 3) return 1;
717 if (mv_staddr > 0xffffU) {
718 uint32_t pg = (mv_staddr>>14);
719 mv_staddr &= ~(0x000fU<<((5-inaddrpos)*4));
720 mv_staddr |= ((unsigned)d)<<((5-inaddrpos)*4);
721 mv_staddr |= pg<<14;
722 } else {
723 mv_staddr &= ~(0x000fU<<((5-inaddrpos)*4));
724 mv_staddr |= ((unsigned)d)<<((5-inaddrpos)*4);
727 if (inaddrpos < 5) ++inaddrpos;
728 return 1;
732 if (isMMEditActive() && key->keysym.unicode > 32 && key->keysym.unicode < 127) {
733 int d = digitInBase((char)key->keysym.unicode, 16);
734 if (d >= 0) {
735 const int mmindex = mmeditpos/2;
736 uint8_t v = mv_pagemap[mmindex];
737 if (mmeditpos%2 == 0) {
738 v &= 0x0F;
739 v |= d<<4;
740 } else {
741 v &= 0xF0;
742 v |= d;
744 // swap
745 if (mv_pagemap[mmindex] != v) {
746 int swidx = 0;
747 while (swidx < 64 && mv_pagemap[swidx] != v) ++swidx;
748 if (swidx < 64) {
749 uint8_t vtmp = mv_pagemap[swidx];
750 mv_pagemap[swidx] = mv_pagemap[mmindex];
751 mv_pagemap[mmindex] = vtmp;
752 } else {
753 mv_pagemap[mmindex] = v;
756 ++mmeditpos;
757 if (mmeditpos >= 64*2) mmeditpos = 64*2-1;
758 return 1;
762 switch (key->keysym.sym) {
763 case SDLK_ESCAPE:
764 case SDLK_q:
765 case SDLK_x:
766 if (isAddrEditActive()) inaddrpos = -1;
767 else if (isMMEditActive()) mmeditactive = 0;
768 else memviewSetActive(0);
769 return 1;
771 case SDLK_RETURN:
772 if (isMMEditActive()) {
773 // go to the selected physical page
774 mv_staddr = (((mmeditpos/2)+4)<<14);
776 inaddrpos = -1;
777 mmeditactive = 0;
778 return 1;
780 case SDLK_DELETE: case SDLK_KP_PERIOD:
781 if (isAddrEditActive()) {
782 if (inaddrpos < 2) mv_staddr &= 0xffffU;
783 } else if (isMMEditActive()) {
784 if (evtShiftKeyDown) memviewResetMMap(0);
785 else if (evtCtrlKeyDown) memviewResetMMap(1);
786 else if (evtAltKeyDown) {
787 memviewResetMMap(1);
788 mv_pagemap[0] = 2;
789 mv_pagemap[1] = 0;
790 mv_pagemap[2] = 1;
791 } else if (!evtShiftKeyDown && !evtCtrlKeyDown && !evtAltKeyDown) {
792 const int mmindex = mmeditpos/2;
793 uint8_t v = (uint8_t)mmindex;
794 if (mv_pagemap[mmindex] != v) {
795 int swidx = 0;
796 while (swidx < 64 && mv_pagemap[swidx] != v) ++swidx;
797 if (swidx < 64) {
798 uint8_t vtmp = mv_pagemap[swidx];
799 mv_pagemap[swidx] = mv_pagemap[mmindex];
800 mv_pagemap[mmindex] = vtmp;
801 } else {
802 mv_pagemap[mmindex] = v;
807 return 1;
809 case SDLK_F6:
810 mv_viewmode = !mv_viewmode; // we have only two for now
811 return 1;
813 case SDLK_LEFT: case SDLK_KP4: doLeft(); return 1;
814 case SDLK_RIGHT: case SDLK_KP6: doRight(); return 1;
815 case SDLK_UP: case SDLK_KP8: doUp(); return 1;
816 case SDLK_DOWN: case SDLK_KP2: doDown(); return 1;
817 case SDLK_PAGEUP: case SDLK_KP9: case SDLK_o: doPageUp(); return 1;
818 case SDLK_PAGEDOWN: case SDLK_KP3: case SDLK_p: doPageDown(); return 1;
819 case SDLK_BACKSPACE: if (isAddrEditActive()) doLeft(); return 1;
821 case SDLK_SPACE:
822 if (isAddrEditActive()) return 1;
823 if (mv_viewmode == MV_MODE_TEXT) {
824 if ((key->keysym.mod&KMOD_SHIFT) != 0) doPageUp(); else doPageDown();
826 return 1;
828 case SDLK_1:
829 if (isAddrEditActive()) return 1;
830 if (mv_viewmode == MV_MODE_TEXT) mv_textwidth = 32;
831 return 1;
832 case SDLK_2:
833 if (isAddrEditActive()) return 1;
834 if (mv_viewmode == MV_MODE_TEXT) mv_textwidth = 42;
835 return 1;
836 case SDLK_3:
837 if (isAddrEditActive()) return 1;
838 if (mv_viewmode == MV_MODE_TEXT) mv_textwidth = 51;
839 return 1;
840 case SDLK_4:
841 if (isAddrEditActive()) return 1;
842 if (mv_viewmode == MV_MODE_TEXT) mv_textwidth = 64;
843 return 1;
844 case SDLK_0:
845 if (isAddrEditActive()) return 1;
846 if (mv_viewmode == MV_MODE_TEXT) mv_textwidth = MV_MAX_TEXT_WIDTH;
847 return 1;
849 case SDLK_HOME: case SDLK_KP7:
850 if (isAddrEditActive()) inaddrpos = (inaddrpos > 2 ? 2 : 0);
851 return 1;
852 case SDLK_END: case SDLK_KP1:
853 if (isAddrEditActive()) inaddrpos = (inaddrpos < 2 ? 2 : 5);
854 return 1;
856 case SDLK_b:
857 if (!isAddrEditActive()) {
858 if ((key->keysym.mod&KMOD_ALT) != 0) {
859 vt_smm_init(&wkmenu, "Text brightness", (const char *[]){"off", "on", NULL});
860 menu_sel_cb = &menu_set_text_bright;
861 wkmenu.cursor_y = (mv_textcolor >= 0x08 ? 1 : 0);
862 current_menu = &wkmenu;
863 } else {
864 mv_textcolor ^= 0x08;
867 return 1;
869 case SDLK_c:
870 if (!isAddrEditActive()) {
871 if ((key->keysym.mod&KMOD_ALT) != 0) {
872 vt_smm_init(&wkmenu, "Text color", (const char *[]){
873 "blue", "red", "magenta", "green", "cyan", "yellow", "white",
874 NULL});
875 menu_sel_cb = &menu_set_text_color;
876 wkmenu.cursor_y = (mv_textcolor&0x07)-1;
877 current_menu = &wkmenu;
878 } else {
879 mv_textcolor = ((mv_textcolor+1)&0x07)|(mv_textcolor&0x08);
880 if (!mv_textcolor) mv_textcolor = 1;
881 else if (mv_textcolor == 8) mv_textcolor = 9;
884 return 1;
886 case SDLK_e:
887 if ((key->keysym.mod&KMOD_ALT) != 0) {
888 vt_smm_init(&wkmenu, "Encoding", (const char *[]){"7 bit", "CP 866", "CP 1251", NULL});
889 menu_sel_cb = &menu_set_encoding;
890 wkmenu.cursor_y = (uint32_t)mv_encoding;
891 current_menu = &wkmenu;
892 } else {
893 if (!isAddrEditActive()) memviewSetActive(0);
895 return 1;
897 case SDLK_g:
898 if (!isAddrEditActive()) inaddrpos = 2;
899 return 1;
901 case SDLK_m:
902 if ((key->keysym.mod&KMOD_ALT) != 0) {
903 vt_smm_init(&wkmenu, "View mode", (const char *[]){"hex", "text", NULL});
904 menu_sel_cb = &menu_set_view_mode;
905 wkmenu.cursor_y = (uint32_t)mv_viewmode;
906 current_menu = &wkmenu;
908 return 1;
910 case SDLK_w:
911 if ((key->keysym.mod&KMOD_ALT) != 0 && mv_viewmode == MV_MODE_TEXT) {
912 vt_smm_init(&wkmenu, "Text width", (const char *[]){"32", "42", "51", "64", "max", NULL});
913 menu_sel_cb = &menu_set_text_width;
914 if (mv_textwidth <= 32) wkmenu.cursor_y = 0;
915 else if (mv_textwidth <= 42) wkmenu.cursor_y = 1;
916 else if (mv_textwidth <= 51) wkmenu.cursor_y = 2;
917 else if (mv_textwidth <= 64) wkmenu.cursor_y = 3;
918 else wkmenu.cursor_y = 4;
919 current_menu = &wkmenu;
921 return 1;
923 case SDLK_F7:
924 if (isAddrEditActive()) return 1;
925 if (!isMMEditActive()) mmeditactive = 1;
926 return 1;
928 case SDLK_F9:
929 if ((key->keysym.mod&(KMOD_ALT|KMOD_SHIFT)) == 0) {
930 int v = optMaxSpeed;
931 emuSetMaxSpeed(!v);
933 return 1;
935 case SDLK_F1:
936 if (!isAddrEditActive() && !isMMEditActive()) {
937 if ((key->keysym.mod&(KMOD_ALT|KMOD_SHIFT)) == 0) {
938 int v = ((optPaused&PAUSE_PERMANENT_MASK) == 0);
939 emuSetPaused(v ? PAUSE_PERMANENT_SET : PAUSE_PERMANENT_RESET);
940 return 1;
943 /* fallthrough */
944 case SDLK_h:
945 /*if ((key->keysym.mod&KMOD_ALT) != 0)*/ {
946 if (isAddrEditActive()) {
947 vt_smm_init_textview(&wkmenu, "Small help (MM)",
948 (const char *[]){
949 "dunno, cursor keys. pgup/pgdn moves by pages.",
950 "del on page number clears page index.",
951 NULL
953 } else if (isMMEditActive()) {
954 vt_smm_init_textview(&wkmenu, "Small help (AE)",
955 (const char *[]){
956 "\x01""C-Del", " restore pages in order",
957 "\x01""S-Del", " restore pages in 502 order",
958 "\x01""M-Del", " restore pages in 201 order",
959 "\x01""Del", " make current page ordered",
960 NULL
962 } else {
963 vt_smm_init_textview(&wkmenu, "Small help",
964 (const char *[]){
965 "\x01""F6", " switch view mode",
966 //"\x01""F8", " switch encoding",
967 "\x01""G", " input address",
968 "\x01""C", " cycle text colors",
969 "\x01""B", " toggle text brightness",
970 "\x01""0-4", " set text width",
971 "\x01""M-E", " select encoding",
972 "\x01""M-W", " select text width",
973 "\x01""M-M", " select view mode",
974 NULL
977 menu_sel_cb = NULL;
978 current_menu = &wkmenu;
980 return 1;
982 default: break;
985 return 1;