Root/
| 1 | /* |
| 2 | * gui.c - Graphical output for ubb-la |
| 3 | * |
| 4 | * Written 2013 by Werner Almesberger |
| 5 | * Copyright 2013 Werner Almesberger |
| 6 | * |
| 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; either version 2 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | */ |
| 12 | |
| 13 | #include <stdarg.h> |
| 14 | #include <stdint.h> |
| 15 | #include <stdlib.h> |
| 16 | #include <alloca.h> |
| 17 | |
| 18 | #include "SDL.h" |
| 19 | #include "SDL_gfxPrimitives.h" |
| 20 | #include "SDL_gfxPrimitives_font.h" |
| 21 | |
| 22 | #include "gui.h" |
| 23 | |
| 24 | |
| 25 | #if 0 |
| 26 | #define DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) |
| 27 | #else |
| 28 | #define DEBUG(fmt, ...) |
| 29 | #endif |
| 30 | |
| 31 | |
| 32 | #define XRES 320 /* canvas width */ |
| 33 | #define YRES 240 /* canvas height */ |
| 34 | |
| 35 | |
| 36 | /* ----- Colors ------------------------------------------------------------ */ |
| 37 | |
| 38 | |
| 39 | #define TEXT_RGBA 0xffffffff /* general text */ |
| 40 | #define UNIT_RGBA 0xb0e0ffff /* units */ |
| 41 | #define MAP_BUF_RGBA 0x808080ff /* buffer in the map */ |
| 42 | #define MAP_VIEW_RGBA 0xffffffff /* current view in the map */ |
| 43 | #define CENTER_RGBA 0x5080ffff /* center marker */ |
| 44 | #define USER_REF_RGBA 0x00ff40ff /* user reference marker */ |
| 45 | #define LEVEL_RGBA 0xffff00ff /* constant level or single change */ |
| 46 | #define BOUNCE_RGBA 0xff8080ff /* bouncing signal */ |
| 47 | #define LABEL_RGBA 0xffffffff /* channel label */ |
| 48 | #define DIV_RGBA 0x808080ff /* divisions */ |
| 49 | |
| 50 | |
| 51 | /* ----- Layout ------------------------------------------------------------ */ |
| 52 | |
| 53 | |
| 54 | #define XCENTER ((XRES+CH_XOFF)/2) |
| 55 | #define XWIDTH (XRES-CH_XOFF) |
| 56 | |
| 57 | #define MAP_BUF_Y0 2 |
| 58 | #define MAP_BUF_Y1 8 |
| 59 | #define MAP_VIEW_Y0 0 |
| 60 | #define MAP_VIEW_Y1 10 |
| 61 | |
| 62 | #define CENTER_W 8 |
| 63 | #define CENTER_Y0 20 |
| 64 | #define CENTER_Y1 (CENTER_Y0+4) |
| 65 | |
| 66 | #define USER_REF_W 8 |
| 67 | #define USER_REF_Y0 92 |
| 68 | #define USER_REF_Y1 (USER_REF_Y0+4) |
| 69 | |
| 70 | #define CH_XOFF 30 |
| 71 | #define CH_YOFF 30 |
| 72 | #define CH_SKIP 16 |
| 73 | #define CH_HEIGHT 8 |
| 74 | |
| 75 | #define DIV_X 32 |
| 76 | #define DIV_Y 6 |
| 77 | |
| 78 | #define MAX_ZOOM 3 |
| 79 | |
| 80 | #define UNIT_GAP 2 /* space between number and unit */ |
| 81 | |
| 82 | #define POS_T_X 182 |
| 83 | #define POS_SAMP_X 270 |
| 84 | #define POS_Y (MEAS_DIV_Y-8-3) |
| 85 | |
| 86 | #define MEAS_DIV_Y (FREQ_Y-3-1) |
| 87 | |
| 88 | #define FREQ_X 0 |
| 89 | #define FREQ_Y 222 |
| 90 | #define INTERVAL_X 0 |
| 91 | #define INTERVAL_Y (FREQ_Y+8+2) |
| 92 | #define DIV_SAMP_X (DIV_INT_X-8) |
| 93 | #define DIV_SAMP_Y FREQ_Y |
| 94 | #define DIV_INT_X 80 |
| 95 | #define DIV_INT_Y INTERVAL_Y |
| 96 | |
| 97 | #define USER_T_X POS_T_X |
| 98 | #define USER_T_Y FREQ_Y |
| 99 | #define USER_SAMP_X POS_SAMP_X |
| 100 | #define USER_SAMP_Y USER_T_Y |
| 101 | #define USER_FREQ_X POS_T_X |
| 102 | #define USER_FREQ_Y (USER_T_Y+8+2) |
| 103 | |
| 104 | |
| 105 | /* ----- Miscellaneous definitions ----------------------------------------- */ |
| 106 | |
| 107 | |
| 108 | #define REPEAT_DELAY_MS 300 |
| 109 | #define REPEAT_INTERVAL_MS 30 |
| 110 | |
| 111 | static SDL_Surface *surf; |
| 112 | static int user_ref = -1; |
| 113 | |
| 114 | |
| 115 | /* ----- Helper functions -------------------------------------------------- */ |
| 116 | |
| 117 | |
| 118 | static inline uint8_t get_sample(const uint8_t *buf, unsigned i) |
| 119 | { |
| 120 | return (buf[i >> 1] >> 4*(~i & 1)) & 0xf; |
| 121 | } |
| 122 | |
| 123 | |
| 124 | /* ----- SDL initialization and screen-wide functions ---------------------- */ |
| 125 | |
| 126 | |
| 127 | void gui_init(void) |
| 128 | { |
| 129 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { |
| 130 | fprintf(stderr, "SDL_init: %s\n", SDL_GetError()); |
| 131 | exit(1); |
| 132 | } |
| 133 | atexit(SDL_Quit); |
| 134 | |
| 135 | surf = SDL_SetVideoMode(XRES, YRES, 0, SDL_SWSURFACE); |
| 136 | if (!surf) { |
| 137 | fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError()); |
| 138 | exit(1); |
| 139 | } |
| 140 | |
| 141 | SDL_EnableKeyRepeat(REPEAT_DELAY_MS, REPEAT_INTERVAL_MS); |
| 142 | |
| 143 | #ifdef BEN |
| 144 | SDL_ShowCursor(SDL_DISABLE); |
| 145 | #endif |
| 146 | } |
| 147 | |
| 148 | |
| 149 | static void clear(void) |
| 150 | { |
| 151 | SDL_LockSurface(surf); |
| 152 | SDL_FillRect(surf, NULL, SDL_MapRGB(surf->format, 0, 0, 0)); |
| 153 | } |
| 154 | |
| 155 | |
| 156 | static void update(void) |
| 157 | { |
| 158 | SDL_UnlockSurface(surf); |
| 159 | SDL_UpdateRect(surf, 0, 0, 0, 0); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | /* ----- Text output ------------------------------------------------------- */ |
| 164 | |
| 165 | |
| 166 | /* |
| 167 | * stringColor from SDL_gfx fails for some reason. SDL_ttf is just too much |
| 168 | * compatibility trouble. So we do our own. |
| 169 | */ |
| 170 | |
| 171 | static void textf(int x, int y, uint32_t color, const char *fmt, ...) |
| 172 | { |
| 173 | va_list ap; |
| 174 | char *tmp, *s; |
| 175 | uint8_t *p; |
| 176 | int n, ix, iy; |
| 177 | |
| 178 | va_start(ap, fmt); |
| 179 | n = vsnprintf(NULL, 0, fmt, ap); |
| 180 | va_end(ap); |
| 181 | tmp = alloca(n+1); |
| 182 | va_start(ap, fmt); |
| 183 | vsnprintf(tmp, n+1, fmt, ap); |
| 184 | va_end(ap); |
| 185 | |
| 186 | for (s = tmp; *s; s++) { |
| 187 | p = gfxPrimitivesFontdata+(*s << 3); |
| 188 | for (iy = 0; iy != 8; iy++) { |
| 189 | for (ix = 0; ix != 8; ix++) |
| 190 | if ((*p << ix) & 0x80) |
| 191 | pixelColor(surf, x+ix, y+iy, color); |
| 192 | p++; |
| 193 | } |
| 194 | x += 8; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | |
| 199 | /* ----- Map of buffer and view -------------------------------------------- */ |
| 200 | |
| 201 | |
| 202 | static void show_map(int skip, int nibbles, int s0, int s1) |
| 203 | { |
| 204 | int w = nibbles-skip; |
| 205 | int m = (nibbles-skip) >> 1; |
| 206 | int scale = 0; |
| 207 | int x0, x1; |
| 208 | |
| 209 | while (w >= XWIDTH/2) { |
| 210 | w >>= 1; |
| 211 | scale++; |
| 212 | } |
| 213 | boxColor(surf, XCENTER-(w >> 1), MAP_BUF_Y0, |
| 214 | XCENTER+(w >> 1), MAP_BUF_Y1, MAP_BUF_RGBA); |
| 215 | x0 = (s0-m+(XCENTER << scale)) >> scale; |
| 216 | x1 = x0+((s1-s0) >> scale); |
| 217 | rectangleColor(surf, x0, MAP_VIEW_Y0, x1, MAP_VIEW_Y1, MAP_VIEW_RGBA); |
| 218 | } |
| 219 | |
| 220 | |
| 221 | /* ----- Waveform elements ------------------------------------------------- */ |
| 222 | |
| 223 | |
| 224 | static inline int ch_y(int ch, int v) |
| 225 | { |
| 226 | return CH_YOFF+CH_SKIP*ch+(v ? 0 : CH_HEIGHT); |
| 227 | } |
| 228 | |
| 229 | |
| 230 | static void bounce(int x, int ch) |
| 231 | { |
| 232 | vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), BOUNCE_RGBA); |
| 233 | } |
| 234 | |
| 235 | |
| 236 | static void change(int x, int ch) |
| 237 | { |
| 238 | vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), LEVEL_RGBA); |
| 239 | } |
| 240 | |
| 241 | |
| 242 | static void level(int x0, int x1, int ch, int v) |
| 243 | { |
| 244 | if (x0 == x1) |
| 245 | pixelColor(surf, x0, ch_y(ch, v), LEVEL_RGBA); |
| 246 | else |
| 247 | hlineColor(surf, x0, x1, ch_y(ch, v), LEVEL_RGBA); |
| 248 | } |
| 249 | |
| 250 | |
| 251 | /* ----- Show (part of) a buffer ------------------------------------------- */ |
| 252 | |
| 253 | |
| 254 | static void show_buffer_zoom_in(const uint8_t *buf, int skip, int nibbles, |
| 255 | int x0, int x1) |
| 256 | { |
| 257 | int f = (x1-x0)/(nibbles-skip); |
| 258 | int x, i, j; |
| 259 | int last[4] = { -1, -1, -1, -1}; |
| 260 | uint8_t v, bit; |
| 261 | |
| 262 | DEBUG("in: %d-%d (%d) Sa; %d-%d (%d) pix; %d f (%d)\n", |
| 263 | skip, nibbles, nibbles-skip, x0, x1, x1-x0, f, f*(nibbles-skip)); |
| 264 | x = x0; |
| 265 | for (i = skip; i != nibbles; i++) { |
| 266 | v = get_sample(buf, i); |
| 267 | for (j = 0; j != 4; j++) { |
| 268 | bit = (v >> j) & 1; |
| 269 | if (bit == last[j] || last[j] == -1) { |
| 270 | level(x, x+f-1, j, bit); |
| 271 | } else { |
| 272 | change(x, j); |
| 273 | level(x+1, x+f-1, j, bit); |
| 274 | } |
| 275 | last[j] = bit; |
| 276 | } |
| 277 | x += f; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | |
| 282 | static void show_buffer_zoom_out(const uint8_t *buf, int skip, int nibbles, |
| 283 | int x0, int x1) |
| 284 | { |
| 285 | int f = (nibbles-skip)/(x1-x0); |
| 286 | int x; |
| 287 | int i = skip, n, j; |
| 288 | int changes[4], last[4] = { -1, -1, -1, -1}, next[4]; |
| 289 | uint8_t v, bit; |
| 290 | |
| 291 | DEBUG("out: %d-%d (%d) Sa; %d-%d (%d) pix; %d f (%d)\n", |
| 292 | skip, nibbles, nibbles-skip, x0, x1, x1-x0, f, f*(x1-x0)); |
| 293 | for (x = x0; x != x1; x++) { |
| 294 | n = i+f; |
| 295 | for (j = 0; j != 4; j++) { |
| 296 | next[j] = last[j]; |
| 297 | changes[j] = 0; |
| 298 | } |
| 299 | while (i != n) { |
| 300 | v = get_sample(buf, i); |
| 301 | for (j = 0; j != 4; j++) { |
| 302 | bit = (v >> j) & 1; |
| 303 | if (bit != next[j]) { |
| 304 | changes[j]++; |
| 305 | next[j] = bit; |
| 306 | } |
| 307 | } |
| 308 | i++; |
| 309 | } |
| 310 | for (j = 0; j != 4; j++) { |
| 311 | if (changes[j] > 1) |
| 312 | bounce(x, j); |
| 313 | else if (!changes[j] || last[j] == -1) |
| 314 | level(x, x, j, next[j]); |
| 315 | else |
| 316 | change(x, j); |
| 317 | last[j] = next[j]; |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | |
| 323 | static void user_ref_marker(int x0, int x1, int x) |
| 324 | { |
| 325 | if (x < 0 || x > x1-x0) |
| 326 | return; |
| 327 | filledTrigonColor(surf, x0+x, USER_REF_Y0, |
| 328 | x0+x-USER_REF_W/2, USER_REF_Y1, |
| 329 | x0+x+USER_REF_W/2, USER_REF_Y1, USER_REF_RGBA); |
| 330 | } |
| 331 | |
| 332 | |
| 333 | static void show_buffer(const uint8_t *buf, int skip, int nibbles, |
| 334 | int x0, int x1, int zoom, int pos) |
| 335 | { |
| 336 | int xm, w, s, p0, p1; |
| 337 | int d, dp, ref; |
| 338 | |
| 339 | xm = (x0+x1) >> 1; |
| 340 | dp = pos-((nibbles-skip) >> 1); |
| 341 | ref = user_ref+skip; |
| 342 | DEBUG("show: %d-%d Sa; %d-%d pix; pos %d dp %d; xm %d xcenter %d\n", |
| 343 | skip, nibbles, x0, x1, pos, dp, xm, XCENTER); |
| 344 | if (zoom < 0) { |
| 345 | s = (x1-x0) << -zoom; |
| 346 | show_map(skip, nibbles, pos-s/2, pos+s/2); |
| 347 | w = (nibbles-skip) >> -zoom; |
| 348 | p0 = xm-(w >> 1)-(dp >> -zoom); |
| 349 | p1 = xm+((w+1) >> 1)-(dp >> -zoom); |
| 350 | if (p0 < x0) { |
| 351 | skip += (x0-p0) << -zoom; |
| 352 | p0 = x0; |
| 353 | } |
| 354 | if (p1 > x1) { |
| 355 | nibbles -= (p1-x1) << -zoom; |
| 356 | p1 = x1; |
| 357 | } |
| 358 | show_buffer_zoom_out(buf, skip, nibbles, p0, p1); |
| 359 | if (user_ref != -1) |
| 360 | user_ref_marker(p0, p1, (ref-skip) >> -zoom); |
| 361 | } else { |
| 362 | s = (x1-x0) >> zoom; |
| 363 | show_map(skip, nibbles, pos-s/2, pos+s/2); |
| 364 | w = (nibbles-skip) << zoom; |
| 365 | p0 = xm-(w >> 1)-(dp << zoom); |
| 366 | p1 = xm+((w+1) >> 1)-(dp << zoom); |
| 367 | if (p0 < x0) { |
| 368 | d = ((x0-p0)+(1 << zoom)-1) >> zoom; |
| 369 | skip += d; |
| 370 | p0 += d << zoom; |
| 371 | } |
| 372 | if (p1 > x1) { |
| 373 | d = ((p1-x1)+(1 << zoom)-1) >> zoom; |
| 374 | nibbles -= d; |
| 375 | p1 -= d << zoom; |
| 376 | } |
| 377 | show_buffer_zoom_in(buf, skip, nibbles, p0, p1); |
| 378 | if (user_ref != -1) |
| 379 | user_ref_marker(p0, p1, (ref-skip) << zoom); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | |
| 384 | /* ----- Display various settings ------------------------------------------ */ |
| 385 | |
| 386 | |
| 387 | static void si_text(int x, int y, double v, const char *unit, int digits) |
| 388 | { |
| 389 | const char *pfx; |
| 390 | |
| 391 | if (v >= 1e6) { |
| 392 | v /= 1e6; |
| 393 | pfx = "M"; |
| 394 | } else if (v >= 1e3) { |
| 395 | v /= 1e3; |
| 396 | pfx = "k"; |
| 397 | } else if (v >= 1) { |
| 398 | pfx = " "; |
| 399 | } else if (v >= 1e-3) { |
| 400 | v *= 1e3; |
| 401 | pfx = "m"; |
| 402 | } else if (v >= 1e-6) { |
| 403 | v *= 1e6; |
| 404 | pfx = "u"; |
| 405 | } else { |
| 406 | v *= 1e9; |
| 407 | pfx = "n"; |
| 408 | } |
| 409 | if (v >= 10 && digits == 3) |
| 410 | textf(x, y, TEXT_RGBA, "%3d", (int) (v+0.5)); |
| 411 | else if (v >= 100 && digits == 4) |
| 412 | textf(x, y, TEXT_RGBA, "%4d", (int) (v+0.5)); |
| 413 | else if (digits == 7) |
| 414 | textf(x, y, TEXT_RGBA, "%*.*f", digits, 3, v); |
| 415 | else if (v >= 100) |
| 416 | textf(x, y, TEXT_RGBA, "%*.*f", digits, digits-4, v); |
| 417 | else if (v >= 10) |
| 418 | textf(x, y, TEXT_RGBA, "%*.*f", digits, digits-3, v); |
| 419 | else |
| 420 | textf(x, y, TEXT_RGBA, "%*.*f", digits, digits-2, v); |
| 421 | textf(x+digits*8+UNIT_GAP, y, UNIT_RGBA, "%s%s", pfx, unit); |
| 422 | } |
| 423 | |
| 424 | |
| 425 | static void show_freq(double freq, int zoom) |
| 426 | { |
| 427 | int div; |
| 428 | |
| 429 | si_text(FREQ_X, FREQ_Y, freq, "Sa/s", 3); |
| 430 | si_text(INTERVAL_X, INTERVAL_Y, 1/freq, "s/Sa", 3); |
| 431 | div = (DIV_X >> MAX_ZOOM) << (MAX_ZOOM-zoom); |
| 432 | textf(DIV_SAMP_X, DIV_SAMP_Y, TEXT_RGBA, "%4d", div); |
| 433 | textf(DIV_SAMP_X+4*8+UNIT_GAP, DIV_SAMP_Y, UNIT_RGBA, "Sa/div", div); |
| 434 | si_text(DIV_INT_X, DIV_INT_Y, div/freq, "s/div", 3); |
| 435 | } |
| 436 | |
| 437 | |
| 438 | static void show_position(double freq, int pos) |
| 439 | { |
| 440 | si_text(POS_T_X, POS_Y, pos/freq, "s", 7); |
| 441 | hlineColor(surf, 0, XRES-1, MEAS_DIV_Y, DIV_RGBA); |
| 442 | si_text(POS_T_X, POS_Y, pos/freq, "s", 7); |
| 443 | hlineColor(surf, 0, XRES-1, MEAS_DIV_Y, DIV_RGBA); |
| 444 | |
| 445 | textf(POS_SAMP_X, POS_Y, TEXT_RGBA, "%4d", pos); |
| 446 | textf(POS_SAMP_X+4*8+UNIT_GAP, POS_Y, UNIT_RGBA, "Sa", div); |
| 447 | } |
| 448 | |
| 449 | |
| 450 | static void show_user_ref(double freq, int pos, int user_ref) |
| 451 | { |
| 452 | si_text(USER_T_X, USER_T_Y, fabs(user_ref-pos)/freq, "s", 7); |
| 453 | |
| 454 | textf(USER_SAMP_X,USER_SAMP_Y, TEXT_RGBA, "%4d", |
| 455 | pos > user_ref ? pos-user_ref : user_ref-pos); |
| 456 | textf(USER_SAMP_X+4*8+UNIT_GAP, USER_SAMP_Y, UNIT_RGBA, "Sa", div); |
| 457 | |
| 458 | if (pos != user_ref) |
| 459 | si_text(USER_FREQ_X, USER_FREQ_Y, |
| 460 | freq/fabs(user_ref-pos), "Hz", 7); |
| 461 | } |
| 462 | |
| 463 | |
| 464 | /* ----- Show divisions ---------------------------------------------------- */ |
| 465 | |
| 466 | |
| 467 | static void show_divisions(void) |
| 468 | { |
| 469 | int n = XWIDTH/2/DIV_X; |
| 470 | int i; |
| 471 | |
| 472 | for (i = -n; i <= n; i++) |
| 473 | vlineColor(surf, XCENTER+i*DIV_X, |
| 474 | ch_y(0, 1)-DIV_Y, ch_y(3, 0)+DIV_Y, |
| 475 | i ? DIV_RGBA : CENTER_RGBA); |
| 476 | } |
| 477 | |
| 478 | |
| 479 | /* ----- Main event loop --------------------------------------------------- */ |
| 480 | |
| 481 | |
| 482 | static int pos_step(int zoom) |
| 483 | { |
| 484 | return zoom == MAX_ZOOM ? 1 : 1 << (MAX_ZOOM-zoom+1); |
| 485 | } |
| 486 | |
| 487 | |
| 488 | static int smart_pos(const uint8_t *buf, int skip, int nibbles, |
| 489 | int pos, int dir) |
| 490 | { |
| 491 | uint8_t ref; |
| 492 | |
| 493 | if (dir < 0) { |
| 494 | if (!pos) |
| 495 | return pos; |
| 496 | ref = get_sample(buf, skip+pos-1); |
| 497 | } else { |
| 498 | ref = get_sample(buf, skip+pos); |
| 499 | } |
| 500 | do { |
| 501 | pos += dir; |
| 502 | if (pos < 0 || pos == nibbles-skip) |
| 503 | return pos-dir; |
| 504 | } while (get_sample(buf, skip+pos) == ref); |
| 505 | if (dir < 0) |
| 506 | pos++; |
| 507 | return pos; |
| 508 | } |
| 509 | |
| 510 | |
| 511 | void gui(const uint8_t *buf, int skip, int nibbles, double freq) |
| 512 | { |
| 513 | SDL_Event event; |
| 514 | int pos = (skip+nibbles) >> 1; |
| 515 | int zoom; /* < 0: zoom out; 0: 1 pixel = 1 sample; > 1: zoom in */ |
| 516 | int min_zoom = 0; |
| 517 | int i, shift; |
| 518 | |
| 519 | while (XWIDTH < (nibbles-skip) >> -min_zoom) |
| 520 | min_zoom--; |
| 521 | zoom = min_zoom; |
| 522 | while (1) { |
| 523 | clear(); |
| 524 | for (i = 0; i != 4; i++) |
| 525 | textf(0, ch_y(i, 1), LABEL_RGBA, "CH%d", i); |
| 526 | show_divisions(); |
| 527 | filledTrigonColor(surf, XCENTER, CENTER_Y1, |
| 528 | XCENTER-CENTER_W/2, CENTER_Y0, |
| 529 | XCENTER+CENTER_W/2, CENTER_Y0, CENTER_RGBA); |
| 530 | show_buffer(buf, skip, nibbles, CH_XOFF, XRES, zoom, pos); |
| 531 | show_freq(freq, zoom); |
| 532 | show_position(freq, pos); |
| 533 | if (user_ref != -1) |
| 534 | show_user_ref(freq, pos, user_ref); |
| 535 | update(); |
| 536 | |
| 537 | while (1) { |
| 538 | SDL_WaitEvent(&event); |
| 539 | switch (event.type) { |
| 540 | case SDL_KEYDOWN: |
| 541 | shift = event.key.keysym.mod & KMOD_SHIFT; |
| 542 | switch (event.key.keysym.sym) { |
| 543 | case SDLK_UP: |
| 544 | if (zoom < MAX_ZOOM) |
| 545 | zoom++; |
| 546 | break; |
| 547 | case SDLK_DOWN: |
| 548 | if (zoom > min_zoom) |
| 549 | zoom--; |
| 550 | break; |
| 551 | case SDLK_LEFT: |
| 552 | if (shift) { |
| 553 | pos = smart_pos(buf, |
| 554 | skip, nibbles, pos, -1); |
| 555 | } else { |
| 556 | pos -= pos_step(zoom); |
| 557 | if (pos < 0) |
| 558 | pos = 0; |
| 559 | } |
| 560 | break; |
| 561 | case SDLK_RIGHT: |
| 562 | if (shift) { |
| 563 | pos = smart_pos(buf, |
| 564 | skip, nibbles, pos, 1); |
| 565 | } else { |
| 566 | pos += pos_step(zoom); |
| 567 | if (pos > nibbles-skip-1) |
| 568 | pos = nibbles-skip-1; |
| 569 | } |
| 570 | break; |
| 571 | case SDLK_SPACE: |
| 572 | if (pos == user_ref) |
| 573 | user_ref = -1; |
| 574 | else |
| 575 | user_ref = pos; |
| 576 | break; |
| 577 | case SDLK_RETURN: |
| 578 | case SDLK_q: |
| 579 | return; |
| 580 | case SDLK_LSHIFT: |
| 581 | case SDLK_RSHIFT: |
| 582 | continue; |
| 583 | default: |
| 584 | printf("%x\n", event.key.keysym.sym); |
| 585 | continue; |
| 586 | } |
| 587 | break; |
| 588 | case SDL_QUIT: |
| 589 | return; |
| 590 | default: |
| 591 | continue; |
| 592 | } |
| 593 | break; |
| 594 | } |
| 595 | } |
| 596 | } |
| 597 |
Branches:
master
