summaryrefslogtreecommitdiffstats
path: root/apps/plugins/frotz/dumb_output.c
blob: eb61419195f9379e33ded0732bac0bafaa4b8235 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/* dumb-output.c
 * $Id: dumb-output.c,v 1.2 2002/03/26 22:52:31 feedle Exp $
 *
 * Copyright 1997,1998 Alfresco Petrofsky <alfresco@petrofsky.berkeley.edu>.
 * Any use permitted provided this notice stays intact.
 *
 * Changes for Rockbox copyright 2009 Torne Wuff
 *
 * Rockbox is not really a dumb terminal (it supports printing text wherever
 * you like) but it doesn't implement a terminal type buffer, so this is
 * close enough to be a good starting point. Keeping a copy of the graphical
 * framebuffer would be too expensive, text+attributes is much smaller.
 */

#include "dumb_frotz.h"

/* The in-memory state of the screen.  */
/* Each cell contains a style in the upper byte and a char in the lower. */
typedef unsigned short cell;
static cell screen_data[(LCD_WIDTH/SYSFONT_WIDTH) * (LCD_HEIGHT/SYSFONT_HEIGHT)];

static cell make_cell(int style, char c) {return (style << 8) | (0xff & c);}
static char cell_char(cell c) {return c & 0xff;}
static int cell_style(cell c) {return c >> 8;}

static int current_style = 0;
static int cursor_row = 0, cursor_col = 0;

static cell *dumb_row(int r) {return screen_data + r * h_screen_cols;}

int os_char_width (zchar z)
{
  (void)z;
  return 1;
}

int os_string_width (const zchar *s)
{
  int width = 0;
  zchar c;

  while ((c = *s++) != 0)
    if (c == ZC_NEW_STYLE || c == ZC_NEW_FONT)
      s++;
    else
      width += os_char_width(c);

  return width;
}

void os_set_cursor(int row, int col)
{
  cursor_row = row - 1; cursor_col = col - 1;
  if (cursor_row >= h_screen_rows)
    cursor_row = h_screen_rows - 1;
}

/* Set a cell */
static void dumb_set_cell(int row, int col, cell c)
{
  dumb_row(row)[col] = c;
}

void os_set_text_style(int x)
{
  current_style = x & REVERSE_STYLE;
}

static void dumb_display_cell(int row, int col)
{
  cell cel = dumb_row(row)[col];
  char c = cell_char(cel);
  if (!c)
      c = ' ';
  char style = cell_style(cel);
  char s[5];
  char *end = rb->utf8encode(c, s);
  *end = 0;
  if (style & REVERSE_STYLE)
    rb->lcd_set_drawmode(DRMODE_INVERSEVID);
  rb->lcd_putsxy(col * SYSFONT_WIDTH, row * SYSFONT_HEIGHT, s);
  rb->lcd_set_drawmode(DRMODE_SOLID);
}

/* put a character in the cell at the cursor and advance the cursor.  */
static void dumb_display_char(char c)
{
  dumb_set_cell(cursor_row, cursor_col, make_cell(current_style, c));
  if (++cursor_col == h_screen_cols) {
    if (cursor_row == h_screen_rows - 1)
      cursor_col--;
    else {
      cursor_row++;
      cursor_col = 0;
    }
  }
}

void os_display_char (zchar c)
{
  if (c >= ZC_LATIN1_MIN /*&& c <= ZC_LATIN1_MAX*/) {
    dumb_display_char(c);
  } else if (c >= 32 && c <= 126) {
    dumb_display_char(c);
  } else if (c == ZC_GAP) {
    dumb_display_char(' '); dumb_display_char(' ');
  } else if (c == ZC_INDENT) {
    dumb_display_char(' '); dumb_display_char(' '); dumb_display_char(' ');
  }
  return;
}


/* Haxor your boxor? */
void os_display_string (const zchar *s)
{
  zchar c;

  while ((c = *s++) != 0)
    if (c == ZC_NEW_FONT)
      s++;
    else if (c == ZC_NEW_STYLE)
      os_set_text_style(*s++);
    else {
     os_display_char (c); 
     }
}

void os_erase_area (int top, int left, int bottom, int right)
{
  int row;
  top--; left--; bottom--; right--;
  if (left == 0 && right == h_screen_cols - 1)
    rb->memset(dumb_row(top), 0, (bottom - top + 1) * h_screen_cols * sizeof(cell));
  else
    for (row = top; row <= bottom; row++)
      rb->memset(dumb_row(row) + left, 0, (right - left + 1) * sizeof(cell));
}

void os_scroll_area (int top, int left, int bottom, int right, int units)
{
  int row;
  top--; left--; bottom--; right--;
  if (units > 0) {
    for (row = top; row <= bottom - units; row++)
      rb->memcpy(dumb_row(row) + left,
              dumb_row(row + units) + left,
              (right - left + 1) * sizeof(cell));
    os_erase_area(bottom - units + 2, left + 1, bottom + 1, right + 1);
  } else if (units < 0) {
    for (row = bottom; row >= top - units; row--)
      rb->memcpy(dumb_row(row) + left,
              dumb_row(row + units) + left,
              (right - left + 1) * sizeof(cell));
    os_erase_area(top + 1, left + 1, top - units, right + 1);
  }
}

int os_font_data(int font, int *height, int *width)
{
    if (font == TEXT_FONT) {
      *height = 1; *width = 1; return 1;
    }
    return 0;
}

void os_set_colour (int x, int y) { (void)x; (void)y; }
void os_set_font (int x) { (void)x; }

/* Unconditionally show whole screen. */
void dumb_dump_screen(void)
{
  int r, c;
  rb->lcd_clear_display();
  for (r = 0; r < h_screen_height; r++)
    for (c = 0; c < h_screen_width; c++)
      dumb_display_cell(r, c);
  rb->lcd_update();
}

/* Show the current screen contents. */
void dumb_show_screen(bool show_cursor)
{
  (void)show_cursor;
  dumb_dump_screen();
}

void os_more_prompt(void)
{
  int old_row = cursor_row;
  int old_col = cursor_col;
  int old_style = current_style;
  
  current_style = REVERSE_STYLE;
  os_display_string("[MORE]");
  wait_for_key();

  cursor_row = old_row;
  cursor_col = old_col;
  current_style = old_style;
  os_erase_area(cursor_row+1, cursor_col+1, cursor_row+1, cursor_col+7);
}

void os_reset_screen(void)
{
  current_style = REVERSE_STYLE;
  os_display_string("[Press key to exit]");
  wait_for_key();
}


/* To make the common code happy */

void os_prepare_sample (int a) { (void)a; }
void os_finish_with_sample (int a) { (void)a; }
void os_start_sample (int a, int b, int c, zword d)
{
    (void)a; (void)b; (void)c; (void)d;
}
void os_stop_sample (int a) { (void)a; }

void dumb_init_output(void)
{
  if (h_version == V3) {
    h_config |= CONFIG_SPLITSCREEN;
    h_flags &= ~OLD_SOUND_FLAG;
  }

  if (h_version >= V5) {
    h_flags &= ~SOUND_FLAG;
  }

  h_screen_height = h_screen_rows;
  h_screen_width = h_screen_cols;

  h_font_width = 1; h_font_height = 1;

  os_erase_area(1, 1, h_screen_rows, h_screen_cols);
}

bool os_picture_data(int num, int *height, int *width)
{
  (void)num;
  *height = 0;
  *width = 0;
  return FALSE;
}

void os_draw_picture (int num, int row, int col)
{
  (void)num;
  (void)row;
  (void)col;
}

int os_peek_colour (void) {return BLACK_COLOUR; }