1 /*
2     GUILIB:  An example GUI framework library for use with SDL
3 */
4 
5 /* A simple dumb terminal scrollable widget */
6 
7 #include <stdarg.h>
8 #include <string.h>
9 #include <ctype.h>
10 
11 #include "GUI_termwin.h"
12 #include "GUI_loadimage.h"
13 
14 #define KEYREPEAT_TIME	100		/* Repeat every 100 ms */
15 
GUI_TermWin(int x,int y,int w,int h,SDL_Surface * Font,void (* KeyProc)(SDLKey key,Uint16 unicode),int scrollback)16 GUI_TermWin:: GUI_TermWin(int x, int y, int w, int h, SDL_Surface *Font,
17 				void (*KeyProc)(SDLKey key, Uint16 unicode), int scrollback)
18  : GUI_Scrollable(NULL, x, y, w, h)
19 {
20 	/* The font surface should be a 16x16 character pixmap */
21 	if ( Font == NULL ) {
22 		font = GUI_DefaultFont();
23 	} else {
24 		font = Font;
25 	}
26 	charh = font->h/16;
27 	charw = font->w/16;
28 	rows = h/(charh-1);   /* Bottom row in font is not displayed */
29 	cols = w/charw;
30 	if ( scrollback == 0 ) {
31 		scrollback = rows;
32 	}
33 	total_rows = scrollback;
34 
35 	/* Allocate and clear the character buffer */
36 	vscreen = new Uint8[total_rows*cols];
37 	Clear();
38 
39 	/* Set the user-defined keyboard handler */
40 	keyproc = KeyProc;
41 	repeat_key = SDLK_UNKNOWN;
42 	repeat_unicode = 0;
43 
44 	/* Set key event translation on */
45 	translated = SDL_EnableUNICODE(1);
46 }
47 
~GUI_TermWin()48 GUI_TermWin:: ~GUI_TermWin()
49 {
50 	delete[] vscreen;
51 
52 	/* Reset key event translation */
53 	SDL_EnableUNICODE(translated);
54 }
55 
56 void
Display(void)57 GUI_TermWin:: Display(void)
58 {
59 	int row, i, j;
60 	Uint8 ch;
61 	SDL_Rect src;
62 	SDL_Rect dst;
63 
64 	row = first_row+scroll_row;
65 	if ( row < 0 ) {
66 		row = total_rows+row;
67 	}
68 	src.w = charw;
69 	src.h = charh-1;
70 	dst.w = charw;
71 	dst.h = charh-1;
72 	for ( i=0; i<rows; ++i ) {
73 		for ( j=0; j<cols; ++j ) {
74 			ch = vscreen[row*cols+j];
75 			src.x = (ch%16)*charw;
76 			src.y = (ch/16)*charh;
77 			dst.x = area.x+j*charw;
78 			dst.y = area.y+i*(charh-1);
79 			SDL_BlitSurface(font, &src, screen, &dst);
80 		}
81 		row = (row+1)%total_rows;
82 	}
83 	changed = 0;
84 }
85 
86 int
Scroll(int amount)87 GUI_TermWin:: Scroll(int amount)
88 {
89 	if ( amount ) {
90 		scroll_row += amount;
91 		if ( scroll_row < scroll_min ) {
92 			scroll_row = scroll_min;
93 		} else
94 		if ( scroll_row > scroll_max ) {
95 			scroll_row = scroll_max;
96 		}
97 		changed = 1;
98 	}
99 	return(scroll_row);
100 }
101 
102 void
Range(int & first,int & last)103 GUI_TermWin:: Range(int &first, int &last)
104 {
105 	first = scroll_min; last = scroll_max;
106 }
107 
108 GUI_status
KeyDown(SDL_keysym key)109 GUI_TermWin:: KeyDown(SDL_keysym key)
110 {
111 	GUI_status status;
112 
113 	status = GUI_PASS;
114 	if ( keyproc ) {
115 		keyproc(key.sym, key.unicode);
116 		repeat_key = key.sym;
117 		repeat_unicode = key.unicode;
118 		repeat_next = SDL_GetTicks()+5*KEYREPEAT_TIME;
119 		status = GUI_YUM;
120 	}
121 	return(status);
122 }
123 
124 GUI_status
KeyUp(SDL_keysym key)125 GUI_TermWin:: KeyUp(SDL_keysym key)
126 {
127 	repeat_key = SDLK_UNKNOWN;
128 	return(GUI_PASS);
129 }
130 
131 void
NewLine(void)132 GUI_TermWin:: NewLine(void)
133 {
134 	if ( cur_row == (rows-1) ) {
135 		int newrow;
136 
137 		first_row = (first_row+1)%total_rows;
138 		newrow = (first_row+rows-1)%total_rows;
139 		memset(&vscreen[newrow*cols], ' ', cols);
140 	} else {
141 		cur_row += 1;
142 	}
143 	cur_col = 0;
144 }
145 
146 void
AddText(const char * text,int len)147 GUI_TermWin:: AddText(const char *text, int len)
148 {
149 	int row;
150 
151 	while ( len-- ) {
152 		switch (*text) {
153 			case '\b': {
154 				/* Backspace */
155 				if ( cur_col > 0 ) {
156 					--cur_col;
157 					row = (first_row+cur_row)%total_rows;
158 					vscreen[row*cols+cur_col] = ' ';
159 				}
160 			}
161 			break;
162 
163 			case '\r':
164 				/* Skip '\n' in "\r\n" sequence */
165 				if ( (len > 0) && (*(text+1) == '\n') ) {
166 					--len; ++text;
167 				}
168 				/* Fall through to newline */
169 			case '\n': {
170 				NewLine();
171 			}
172 			break;
173 
174 			default: {  /* Put characters on screen */
175 				if ( cur_col == cols ) {
176 					NewLine();
177 				}
178 				row = (first_row+cur_row)%total_rows;
179 				vscreen[row*cols+cur_col] = *text;
180 				cur_col += 1;
181 			}
182 			break;
183 		}
184 		++text;
185 	}
186 	/* Reset any scrolling, and mark us for update on idle */
187 	scroll_row = 0;
188 	changed = 1;
189 }
190 
191 void
AddText(const char * fmt,...)192 GUI_TermWin:: AddText(const char *fmt, ...)
193 {
194 	char text[1024];		/* Caution!  Buffer overflow!! */
195 	va_list ap;
196 
197 	va_start(ap, fmt);
198 	vsprintf(text, fmt, ap);
199 	AddText(text, strlen(text));
200 	va_end(ap);
201 }
202 
203 void
Clear(void)204 GUI_TermWin:: Clear(void)
205 {
206 	/* Clear the virtual screen */
207 	memset(vscreen, ' ', total_rows*cols);
208 
209 	/* Set the first row in buffer, display row in buffer, and
210 	   current cursor offset.
211 	 */
212 	first_row = total_rows-rows;		/* Actual address */
213 	scroll_min = -(total_rows-rows);	/* Virtual address */
214 	scroll_row = 0;				/* Virtual address */
215 	scroll_max = 0;				/* Virtual address */
216 	cur_row = 0;				/* Virtual address */
217 	cur_col = 0;				/* Virtual address */
218 
219 	/* Mark the display for update */
220 	changed = 1;
221 }
222 
223 int
Changed(void)224 GUI_TermWin:: Changed(void)
225 {
226 	return(changed);
227 }
228 
229 GUI_status
Idle(void)230 GUI_TermWin:: Idle(void)
231 {
232 	GUI_status status;
233 
234 	status = GUI_PASS;
235 
236 	/* Perform any necessary key repeat */
237 	if ( repeat_key && keyproc ) {
238 		if ( repeat_next <= SDL_GetTicks() ) {
239 			keyproc(repeat_key, repeat_unicode);
240 			repeat_next = SDL_GetTicks()+KEYREPEAT_TIME;
241 		}
242 	}
243 
244 	/* Check to see if display contents have changed */
245 	if ( changed ) {
246 		status = GUI_REDRAW;
247 		changed = 0;
248 	}
249 	return(status);
250 }
251 
252 /* change FG/BG colors and transparency */
SetColoring(Uint8 fr,Uint8 fg,Uint8 fb,int bg_opaque,Uint8 br,Uint8 bg,Uint8 bb)253 void GUI_TermWin::SetColoring(Uint8 fr,Uint8 fg,Uint8 fb, int bg_opaque,
254 				Uint8 br, Uint8 bg, Uint8 bb)
255 {
256 	SDL_Color colors[3]={{br,bg,bb,0},{fr,fg,fb,0}};
257 	if (bg_opaque)
258 	{
259 	  SDL_SetColors(font,colors,0,2);
260 	  SDL_SetColorKey(font,0,0);
261 	}
262 	else
263 	{
264 	  SDL_SetColors(font,&colors[1],1,1);
265 	  SDL_SetColorKey(font,SDL_SRCCOLORKEY,0);
266 	}
267 }
268