PageRenderTime 27ms CodeModel.GetById 2ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/MenuLog.cpp

http://github.com/clintbellanger/flare
C++ | 293 lines | 175 code | 64 blank | 54 comment | 32 complexity | 863dc4bfe93841342e0288db9af62eb9 MD5 | raw file
  1/*
  2Copyright 2011 Clint Bellanger
  3
  4This file is part of FLARE.
  5
  6FLARE is free software: you can redistribute it and/or modify it under the terms
  7of the GNU General Public License as published by the Free Software Foundation,
  8either version 3 of the License, or (at your option) any later version.
  9
 10FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
 11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 12PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 13
 14You should have received a copy of the GNU General Public License along with
 15FLARE.  If not, see http://www.gnu.org/licenses/
 16*/
 17
 18/**
 19 * class MenuLog
 20 */
 21
 22#include "MenuLog.h"
 23#include "SharedResources.h"
 24#include "WidgetLabel.h"
 25
 26using namespace std;
 27
 28
 29MenuLog::MenuLog() {
 30
 31	visible = false;
 32	
 33	for (int i=0; i<LOG_TYPE_COUNT; i++) {
 34		log_count[i] = 0;
 35		for (int j=0; j<MAX_LOG_MESSAGES; j++) {
 36			msg_buffer[i][j] = NULL;
 37		}
 38	}
 39	active_log = 0;
 40
 41	tab_labels[LOG_TYPE_MESSAGES] = msg->get("Messages");
 42	tab_labels[LOG_TYPE_QUESTS] = msg->get("Quests");
 43	tab_labels[LOG_TYPE_STATISTICS] = msg->get("Statistics");
 44
 45	// TODO: allow menu size to be configurable
 46	menu_area.x = 0;
 47	menu_area.y = (VIEW_H - 416)/2;
 48	menu_area.w = 320;
 49	menu_area.h = 416;
 50	
 51	list_area.x = menu_area.x + 40;
 52	list_area.y = menu_area.y + 56;
 53	list_area.w = 224;
 54	list_area.h = 328;
 55	
 56	tabs_area.x = menu_area.x + 32;
 57	tabs_area.y = menu_area.y + 30;
 58	tabs_area.w = 240;
 59	tabs_area.h = 20;
 60
 61	tab_padding.y = 4;
 62	tab_padding.x = 6;
 63	paragraph_spacing = font->getLineHeight()/2;
 64	
 65	for (int i=0; i<LOG_TYPE_COUNT; i++) {
 66		tab_rect[i].y = tabs_area.y;
 67		tab_rect[i].h = tabs_area.h;
 68		
 69		if (i==0) tab_rect[i].x = tabs_area.x;
 70		else tab_rect[i].x = tab_rect[i-1].x + tab_rect[i-1].w;
 71		
 72		tab_rect[i].w = font->calc_width(tab_labels[i]) + tab_padding.x + tab_padding.x;
 73		
 74	}
 75	
 76	loadGraphics();
 77
 78	closeButton = new WidgetButton(mods->locate("images/menus/buttons/button_x.png"));
 79	closeButton->pos.x = 294;
 80	closeButton->pos.y = (VIEW_H - 480)/2 + 34;
 81	
 82}
 83
 84void MenuLog::loadGraphics() {
 85
 86	background = IMG_Load(mods->locate("images/menus/log.png").c_str());
 87	tab_active = IMG_Load(mods->locate("images/menus/tab_active.png").c_str());
 88	tab_inactive = IMG_Load(mods->locate("images/menus/tab_inactive.png").c_str());
 89	
 90	
 91	if(!background || !tab_active || !tab_inactive) {
 92		fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError());
 93		SDL_Quit();
 94	}
 95	
 96	// optimize
 97	SDL_Surface *cleanup = background;
 98	background = SDL_DisplayFormatAlpha(background);
 99	SDL_FreeSurface(cleanup);	
100
101	cleanup = tab_active;
102	tab_active = SDL_DisplayFormatAlpha(tab_active);
103	SDL_FreeSurface(cleanup);	
104
105	cleanup = tab_inactive;
106	tab_inactive = SDL_DisplayFormatAlpha(tab_inactive);
107	SDL_FreeSurface(cleanup);	
108}
109
110/**
111 * Perform one frame of logic
112 */
113void MenuLog::logic() {
114	if (!visible) return;
115	
116	if (closeButton->checkClick()) {
117		visible = false;
118	}
119}
120
121/**
122 * Render graphics for this frame when the menu is open
123 */
124void MenuLog::render() {
125
126	if (!visible) return;
127	
128	SDL_Rect src;
129	
130	// background
131	src.x = 0;
132	src.y = 0;
133	src.w = menu_area.w;
134	src.h = menu_area.h;
135	SDL_BlitSurface(background, &src, screen, &menu_area);
136	
137	// close button
138	closeButton->render();
139	
140	// text overlay
141	WidgetLabel label;
142	label.set(menu_area.x+160, menu_area.y+8, JUSTIFY_CENTER, VALIGN_TOP, msg->get("Log"), FONT_WHITE);
143	label.render();
144
145	// display tabs
146	for (int i=0; i<LOG_TYPE_COUNT; i++) {
147		renderTab(i);
148	}
149	
150	// display latest log messages
151	
152	int display_number = 0;
153	int total_size = 0;
154
155	// first calculate how many entire messages can fit in the log view
156	for (int i=log_count[active_log]-1; i>=0; i--) {
157		total_size += msg_buffer[active_log][i]->h + paragraph_spacing;
158		if (total_size < list_area.h) display_number++;
159		else break;
160	}
161	
162	// now display these messages
163	SDL_Rect dest;
164	dest.x = list_area.x;
165	dest.y = list_area.y;
166	
167	for (int i=log_count[active_log]-display_number; i<log_count[active_log]; i++) {
168
169		SDL_BlitSurface(msg_buffer[active_log][i], NULL, screen, &dest);
170		dest.y += msg_buffer[active_log][i]->h + paragraph_spacing;
171	}
172}
173
174/**
175 * Display the specified tab
176 * Render the font and tab background
177 * The active tab will look different
178 */
179void MenuLog::renderTab(int log_type) {
180	int i = log_type;
181	
182	// draw tab background
183	SDL_Rect src;
184	SDL_Rect dest;
185	src.x = src.y = 0;
186	dest.x = tab_rect[i].x;
187	dest.y = tab_rect[i].y;
188	src.w = tab_rect[i].w;
189	src.h = tab_rect[i].h;
190	
191	if (i == active_log)
192		SDL_BlitSurface(tab_active, &src, screen, &dest);	
193	else
194		SDL_BlitSurface(tab_inactive, &src, screen, &dest);	
195
196	// draw tab right edge
197	src.x = 128 - tab_padding.x;
198	src.w = tab_padding.x;
199	dest.x = tab_rect[i].x + tab_rect[i].w - tab_padding.x;
200	
201	if (i == active_log)
202		SDL_BlitSurface(tab_active, &src, screen, &dest);	
203	else
204		SDL_BlitSurface(tab_inactive, &src, screen, &dest);	
205	
206	
207	// set tab label text color
208	int tab_label_color;
209	if (i == active_log) tab_label_color = FONT_WHITE;
210	else tab_label_color = FONT_GREY;
211		
212	WidgetLabel label;
213	label.set(tab_rect[i].x + tab_padding.x, tab_rect[i].y + tab_padding.y, JUSTIFY_LEFT, VALIGN_TOP, tab_labels[i], tab_label_color);
214	label.render();
215}
216
217/**
218 * Add a new message to the log
219 */
220void MenuLog::add(const string& s, int log_type) {
221
222	if (log_count[log_type] == MAX_LOG_MESSAGES) {
223		remove(0, log_type);
224	}
225	
226	// add new message
227	log_msg[log_type][log_count[log_type]] = s;
228	
229	// render the log entry and store it in a buffer
230	Point size = font->calc_size(s, list_area.w);
231	msg_buffer[log_type][log_count[log_type]] = createSurface(size.x, size.y);
232	font->renderShadowed(s, 0, 0, JUSTIFY_LEFT, msg_buffer[log_type][log_count[log_type]], list_area.w, FONT_WHITE);
233
234	log_count[log_type]++;
235}
236
237/**
238 * Remove log message with the given id
239 */
240void MenuLog::remove(int msg_index, int log_type) {
241
242	SDL_FreeSurface(msg_buffer[log_type][msg_index]);
243	msg_buffer[log_type][msg_index] = NULL;
244		
245	for (int i=msg_index; i<MAX_LOG_MESSAGES-1; i++) {
246		log_msg[log_type][i] = log_msg[log_type][i+1];
247		msg_buffer[log_type][i] = msg_buffer[log_type][i+1];
248	}
249
250	log_count[log_type]--;
251}
252
253/**
254 * Called by MenuManager
255 * The tab area was clicked. Change the active tab
256 */
257void MenuLog::clickTab(Point mouse) {
258	for (int i=0; i<LOG_TYPE_COUNT; i++) {
259		if(isWithin(tab_rect[i], mouse)) {
260			active_log = i;
261			return;
262		}
263	}
264}
265
266void MenuLog::clear(int log_type) {
267	log_count[log_type] = 0;
268	for (int i=0; i<MAX_LOG_MESSAGES; i++) {
269		SDL_FreeSurface(msg_buffer[log_type][i]);
270		msg_buffer[log_type][i] = NULL;
271	}
272}
273
274void MenuLog::clear() {
275	for (int i=0; i<LOG_TYPE_COUNT; i++) {
276		clear(i);
277	}
278}
279
280MenuLog::~MenuLog() {
281
282	for (int i=0; i<LOG_TYPE_COUNT; i++) {
283		log_count[i] = 0;
284		for (int j=0; j<MAX_LOG_MESSAGES; j++) {
285			SDL_FreeSurface(msg_buffer[i][j]);
286		}
287	}
288
289	SDL_FreeSurface(background);
290	SDL_FreeSurface(tab_active);
291	SDL_FreeSurface(tab_inactive);
292	delete closeButton;
293}