1 /*
2  * This file is part of TONG.              http://www.nongnu.org/tong
3  * Copyright 2004, 2006 Owen Swerkstrom
4  *
5  * TONG! is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * TONG! is distributed in the hope that it will be useful and fun,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with TONG!; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 #include "text.h"
21 
22 
Text()23 Text::Text() {
24 	LoadGraphics();
25 	x=0;
26 	y=0;
27 	text=NULL;
28 }
29 
~Text()30 Text::~Text() {
31 	delete[] text;
32 	SDL_FreeSurface(textbits);
33 }
34 
LoadGraphics()35 void Text::LoadGraphics() {
36 	SDL_Surface* ttemp;
37 	ttemp=IMG_Load("media/text.png");
38 	textbits=SDL_DisplayFormatAlpha(ttemp);
39 	SDL_FreeSurface(ttemp);
40 }
41 
Init(int xpos,int ypos,const char * msg)42 void Text::Init(int xpos, int ypos, const char* msg) {
43 	x=xpos;
44 	y=ypos;
45 	text=new char[(int)strlen(msg)+1];
46 	strcpy(text, msg);
47 	return;
48 }
49 
SetText(const char * msg)50 void Text::SetText(const char* msg) {
51 	delete[] text;
52 	text=new char[(int)strlen(msg)+1];
53 	strcpy(text, msg);
54 	return;
55 }
56 
SetX(int newx)57 void Text::SetX(int newx) {
58 	x=newx;
59 	return;
60 }
61 
SetY(int newy)62 void Text::SetY(int newy) {
63 	y=newy;
64 	return;
65 }
66 
GetLines()67 int Text::GetLines() {
68 	int i, lines=1;
69 	for(i=0; i<(int)strlen(text); i++) {
70 		if(text[i]=='\n') {
71 			lines++;
72 		}
73 	}
74 	return lines;
75 }
76 
Draw(SDL_Surface * surf)77 void Text::Draw(SDL_Surface* surf) {
78 	int i;
79 	int letterx = x;
80 	int lettery = y;
81 	SDL_Rect srcrect;
82 	srcrect.w = TEXTWIDTH;
83 	srcrect.h = TEXTHEIGHT;
84 	//draw each letter
85 	for(i = 0; text[i]; i++) {
86 		if(text[i] == '\n') {
87 			letterx = x;
88 			lettery += TEXTHEIGHT;
89 		} else {
90 			srcrect.x = ((int)text[i] % 32) * TEXTWIDTH;
91 			if(text[i] < '@') {
92 				srcrect.y = 0;
93 			} else if(text[i] < '`') {
94 				srcrect.y = TEXTHEIGHT;
95 			} else {
96 				srcrect.y = TEXTHEIGHT * 2;
97 			}
98 			destrect.x = letterx;
99 			destrect.y = lettery;
100 			if(SDL_BlitSurface(textbits, &srcrect, surf, &destrect)) {
101 				LoadGraphics();
102 				SDL_BlitSurface(textbits, &srcrect, surf, &destrect);
103 			}
104 			letterx += TEXTWIDTH;
105 		}
106 	}
107 	return;
108 }
109 
110 
Menu()111 Menu::Menu() {
112 	LoadGraphics();
113 	content=new char[0];
114 	x=y=0;
115 	boxesw=boxesh=0;
116 	choices=0;
117 	current=0;
118 	active=false;
119 	states=new int;
120 }
121 
~Menu()122 Menu::~Menu() {
123 	delete[] content;
124 	SDL_FreeSurface(textbits);
125 	delete[] states;
126 }
127 
LoadGraphics()128 void Menu::LoadGraphics() {
129 	SDL_Surface* ttemp;
130 	ttemp=IMG_Load("media/text.png");
131 	textbits=SDL_DisplayFormatAlpha(ttemp);
132 	SDL_FreeSurface(ttemp);
133 	ttemp=IMG_Load("media/textbox.png");
134 	menubits=SDL_DisplayFormatAlpha(ttemp);
135 	SDL_FreeSurface(ttemp);
136 }
137 
138 //set whether the menu is active (cursor'd) or not
SetActive(bool activate)139 void Menu::SetActive(bool activate) {
140 	active=activate;
141 	return;
142 }
143 
IsActive()144 bool Menu::IsActive() {
145 	return active;
146 }
147 
148 //add a choice labeled text to the menu
AddChoice(const char * text,int state)149 void Menu::AddChoice(const char* text, int state) {
150 	char* temp;
151 	int i;
152 	int* newstates=new int[choices+1];
153 
154 	for(i=0; i<(int)choices; i++) {
155 		newstates[i]=states[i];
156 	}
157 	newstates[choices]=state;
158 	delete[] states;
159 	states=newstates;
160 	choices++;
161 
162 	if(choices==1) {
163 		//easy to add the first one
164 		current=1;
165 		temp=new char[(int)strlen(text)+1];
166 		strcpy(temp, text);
167 	} else {
168 		//put newlines between choices, end with null
169 		temp=new char[(int)strlen(text)+(int)strlen(content)+2];
170 		strncpy(temp, content, strlen(content));
171 		temp[strlen(content)]='\n';
172 		temp[strlen(content)+1]='\0';
173 		strcat(temp, text);
174 	}
175 	//swap the completed temp in for the menu's content
176 	delete[] content;
177 	content=temp;
178 	CalcArea();
179 	return;
180 }
181 
182 //replace the menu's which'th choice with text
ModChoice(const char * text,unsigned int which)183 bool Menu::ModChoice(const char* text, unsigned int which) {
184 	char* temp;
185 	unsigned int newlines=0, keepchars=0;
186 	int i, startpos=0, endpos=0;
187 	bool success=false;
188 
189 	if(which>choices || which<1) {
190 		//    printf("out-of-range ModChoice\n");
191 	} else {
192 		//easy to replace just one
193 		if(choices==1) {
194 			current=1;
195 			temp=new char[(int)strlen(text)+1];
196 			if(temp==NULL) {
197 				printf("couldn't allocate %d!\n", (int)strlen(text)+1);
198 				return false;
199 			}
200 			strcpy(temp, text);
201 		} else {
202 			for(i=0; i<(int)strlen(content)-1; i++) {
203 				if(content[i]=='\n') {
204 					newlines++;
205 					//watch for position of newlines around which'th choice
206 					if(newlines+1==which) {
207 						startpos=i;
208 					} else if(newlines==which) {
209 						endpos=i;
210 					}
211 				}
212 			}
213 			keepchars=strlen(content)-(endpos-startpos);
214 			temp=new char[(int)strlen(text)+keepchars+2];
215 			if(temp==NULL) {
216 				printf("couldn't allocate %d!\n", (int)(keepchars+2+strlen(text)));
217 				return false;
218 			}
219 			if(endpos==0) {
220 				//last option changes
221 				strncpy(temp, content, startpos);
222 				temp[startpos]='\n';
223 				temp[startpos+1]='\0';
224 				strcat(temp, text);
225 			} else {
226 				if(startpos>0) {
227 					//some middle option changes
228 					strncpy(temp, content, startpos);
229 					temp[startpos]='\n';
230 					strncpy(temp+startpos+1, text, strlen(text)+1);
231 					startpos++; //?! not sure why this and the +1^ are needed
232 				} else {
233 					//first option changes
234 					strncpy(temp, text, strlen(text));
235 				}
236 				temp[startpos+strlen(text)]='\n';
237 				strcpy(temp+startpos+strlen(text)+1, content+endpos+1);
238 			}
239 			/*this better not be necessary... :^S
240 			  if(temp[strlen(temp)]!='\0') {
241 			  temp[strlen(temp)]='\0';
242 			  }
243 			*/
244 			//swap the completed temp in for the menu's content
245 			delete[] content;
246 			content=temp;
247 			CalcArea();
248 			success=true;
249 		}
250 	}
251 	return success;
252 }
253 
SetState(int which,int state)254 bool Menu::SetState(int which, int state) {
255 	bool success = false;
256 	int i = 0;
257 	if(which > (int)choices || which < 1) {
258 	} else {
259 		if(state == HIGHLIGHTED) {
260 			for(i = 0; i < (int)choices; i++) {
261 				if(states[i] == HIGHLIGHTED) {
262 					states[i] = NORMAL;
263 				}
264 			}
265 		}
266 		states[which - 1] = state;
267 		success = true;
268 	}
269 	return success;
270 }
271 
GetState(int which)272 int Menu::GetState(int which) {
273 	if(which > (int)choices || which < 1) {
274 		//printf("invalid choice GetState\n");
275 		return DISABLED;
276 	} else {
277 		return states[which - 1];
278 	}
279 }
280 
MoveCursor(int direction)281 bool Menu::MoveCursor(int direction) {
282 	int i;
283 	unsigned int oldcurrent = current;
284 	switch(direction) {
285 	case NORTH:
286 		for(i = current; i > 0; i--) {
287 			if(GetState(i - 1) != DISABLED) {
288 				current = i - 1;
289 				break;
290 			}
291 		}
292 		if(oldcurrent == current) {
293 			for(i = choices + 1; i > (int)oldcurrent; i--) {
294 				if(GetState(i - 1) != DISABLED) {
295 					current = i - 1;
296 					break;
297 				}
298 			}
299 		}
300 		break;
301 	case SOUTH:
302 		for(i = current; i <= (int)choices; i++) {
303 			if(GetState(i+1) != DISABLED) {
304 				current = i + 1;
305 				break;
306 			}
307 		}
308 		if(oldcurrent == current) {
309 			for(i = 0; i < (int)oldcurrent; i++) {
310 				if(GetState(i + 1) != DISABLED) {
311 					current = i + 1;
312 					break;
313 				}
314 			}
315 		}
316 		break;
317 	default:
318 		break;
319 	}
320 	return current != oldcurrent;
321 }
322 
GetChoice()323 int Menu::GetChoice() {
324 	return current;
325 }
326 
SetChoice(int newchoice)327 void Menu::SetChoice(int newchoice) {
328 	current = newchoice;
329 	return;
330 }
331 
NumChoices()332 int Menu::NumChoices() {
333 	return choices;
334 }
335 
SetPos(int newx,int newy)336 void Menu::SetPos(int newx, int newy) {
337 	x = newx;
338 	y = newy;
339 	return;
340 }
341 
CalcArea()342 void Menu::CalcArea() {
343 	int halves=0;
344 	int i;
345 
346 	boxesw=boxesh=0;
347 	for(i=0; i<(int)strlen(content); i++) {
348 		if(content[i]=='\n') {
349 			boxesh++;
350 			if(boxesw<(halves/2)) {
351 				boxesw=halves/2;
352 				if(halves%2==0) {
353 					boxesw--;
354 				}
355 			}
356 			halves=0;
357 		} else {
358 			halves++;
359 		}
360 	}
361 	if(boxesw<(halves/2)) {
362 		boxesw=halves/2;
363 		if(halves%2==0) {
364 			boxesw--;
365 		}
366 	}
367 	return;
368 }
369 
Draw(SDL_Surface * surf)370 void Menu::Draw(SDL_Surface* surf) {
371 	SDL_Rect srcrect;
372 	int i;
373 	int j;
374 	int mode;
375 	int line = 0;
376 	int letterx = x;
377 	int lettery = y;
378 	if(active) {
379 		mode = NORMAL;
380 	} else {
381 		mode = DISABLED;
382 	}
383 	if(strlen(content) > 0) {
384 		//draw the background
385 		srcrect.w = srcrect.h = MENUTILE;
386 		for(i = 0; i <= boxesw + 1; i++) {
387 			for(j = 0; j <= boxesh + 1; j++) {
388 				if(i == 0) {
389 					srcrect.x = 0;
390 				} else if(i == boxesw + 1) {
391 					srcrect.x = MENUTILE * 2;
392 				} else {
393 					srcrect.x = MENUTILE;
394 				}
395 				if(j == 0) {
396 					srcrect.y = 0;
397 				} else if(j == boxesh + 1) {
398 					srcrect.y = MENUTILE * 2;
399 				} else {
400 					srcrect.y = MENUTILE;
401 				}
402 				destrect.x = x - (MENUTILE / 2) + (i * MENUTILE);
403 				destrect.y = y - (MENUTILE / 2) + (j * MENUTILE);
404 				if(SDL_BlitSurface(menubits, &srcrect, surf, &destrect)) {
405 					LoadGraphics();
406 					SDL_BlitSurface(menubits, &srcrect, surf, &destrect);
407 				}
408 			}
409 		}
410 		//draw each letter
411 		mode = active ? states[0] : DISABLED;
412 		srcrect.w = TEXTWIDTH;
413 		srcrect.h = TEXTHEIGHT;
414 		for(i = 0; i < (int)strlen(content); i++) {
415 			if(content[i] == '\n') {
416 				letterx = x;
417 				lettery += TEXTHEIGHT;
418 				line++;
419 				if((int)choices > line) {
420 					mode = active ? states[line] : DISABLED;
421 				}
422 			} else {
423 				srcrect.x = ((int)content[i] % 32) * TEXTWIDTH;
424 				if(content[i] < '@') {
425 					srcrect.y = 0 + mode;
426 				} else if(content[i] < '`') {
427 					srcrect.y = TEXTHEIGHT + mode;
428 				} else {
429 					srcrect.y = (TEXTHEIGHT * 2) + mode;
430 				}
431 				destrect.x = letterx;
432 				destrect.y = lettery;
433 				if(SDL_BlitSurface(textbits, &srcrect, surf, &destrect)) {
434 					LoadGraphics();
435 					SDL_BlitSurface(textbits, &srcrect, surf, &destrect);
436 				}
437 				letterx += TEXTWIDTH;
438 			}
439 		}
440 		if(active) {
441 			//draw the pointer finger thingy
442 			srcrect.x = 0;
443 			srcrect.y = MENUTILE * 3;
444 			srcrect.w = MENUTILE;
445 			srcrect.h = MENUTILE / 2;
446 			destrect.x = x - MENUTILE;
447 			destrect.y = y + (MENUTILE * 2 / 5) + (TEXTHEIGHT * (current-1));
448 			if(SDL_BlitSurface(menubits, &srcrect, surf, &destrect)) {
449 				LoadGraphics();
450 				SDL_BlitSurface(menubits, &srcrect, surf, &destrect);
451 			}
452 		}
453 	} else {
454 		//draw a blank menu if the menu is, erm, blank.
455 		srcrect.x = srcrect.y = 0;
456 		srcrect.w = srcrect.h = MENUTILE * 3;
457 		destrect.x = x - (MENUTILE / 2);
458 		destrect.y = y - (MENUTILE / 2);
459 		if(SDL_BlitSurface(menubits, &srcrect, surf, &destrect)) {
460 			LoadGraphics();
461 			SDL_BlitSurface(menubits, &srcrect, surf, &destrect);
462 		}
463 	}
464 	return;
465 }
466