1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23
24 #include "ultima/nuvie/core/nuvie_defs.h"
25 #include "ultima/nuvie/gui/gui.h"
26 #include "ultima/nuvie/gui/gui_types.h"
27 #include "ultima/nuvie/gui/gui_button.h"
28 #include "ultima/nuvie/gui/gui_text.h"
29 #include "ultima/nuvie/gui/gui_text_toggle_button.h"
30 #include "ultima/nuvie/gui/gui_callback.h"
31 #include "ultima/nuvie/gui/gui_area.h"
32 #include "ultima/nuvie/misc/u6_misc.h"
33 #include "ultima/nuvie/screen/dither.h"
34 #include "ultima/nuvie/screen/scale.h"
35 #include "ultima/nuvie/screen/screen.h"
36 #include "ultima/nuvie/gui/widgets/map_window.h"
37 #include "ultima/nuvie/gui/gui_dialog.h"
38 #include "ultima/nuvie/menus/video_dialog.h"
39 #include "ultima/nuvie/conf/configuration.h"
40 #include "ultima/nuvie/views/view_manager.h"
41 #include "ultima/nuvie/views/inventory_view.h"
42 #include "ultima/nuvie/keybinding/keys.h"
43
44 namespace Ultima {
45 namespace Nuvie {
46
47 #define VD_WIDTH 311
48 #define VD_HEIGHT 171 // add or subtract 13 if you add/remove a row
49
VideoDialog(GUI_CallBack * callback)50 VideoDialog::VideoDialog(GUI_CallBack *callback)
51 : GUI_Dialog(Game::get_game()->get_game_x_offset() + (Game::get_game()->get_game_width() - VD_WIDTH) / 2,
52 Game::get_game()->get_game_y_offset() + (Game::get_game()->get_game_height() - VD_HEIGHT) / 2,
53 VD_WIDTH, VD_HEIGHT, 244, 216, 131, GUI_DIALOG_UNMOVABLE) {
54 callback_object = callback;
55 non_square_pixels_button = NULL;
56 init();
57 grab_focus();
58 }
59
init()60 bool VideoDialog::init() {
61 int colX[] = { 9, 29, 63, 232, 270};
62 int height = 12;
63 int yesno_width = 32;
64 int buttonY = 9;
65 uint8 textY = 11;
66 uint8 row_h = 13;
67 last_index = 0;
68 b_index_num = -1;
69 bool no_fullscreen = false; // no compatible fullscreen setting found
70 GUI_Widget *widget;
71 GUI *gui = GUI::get_gui();
72 GUI_Font *font = gui->get_font();
73 Game *game = Game::get_game();
74 Screen *scr = game->get_screen();
75 const char *const yesno_text[] = { "no", "yes" };
76 #define SCALER_AND_SCALE_CANNOT_BE_CHANGED 1 // FIXME need to be able to change these in game -- they also haven't been updated for keyboard controls and the size of the gump isn't right
77 #if SCALER_AND_SCALE_CANNOT_BE_CHANGED
78 only2x_button = NULL;
79 scale_button = scaler_button = scale_win_button = scaler_win_button = NULL;
80
81 no_fullscreen = false;
82
83 #else
84 uint16 scrWidth = scr->get_width();
85 uint16 scrHeight = scr->get_height();
86 uint16 bpp = scr->get_bpp();
87
88 int textY[] = { 11, 24, 37, 50, 63 , 76, 89, 102, 115, 128, 141 };
89 int buttonY[] = { 9, 22, 35, 48, 61, 74, 87, 100, 113, 126, 139, 152 };
90 // scaler
91 int num_scalers = scr->get_scaler_reg()->GetNumScalers();
92 const char *scaler_text[num_scalers];
93 for (int i = 0; i <= num_scalers; i++)
94 scaler_text[i] = scr->get_scaler_reg()->GetNameForIndex(i);
95
96 widget = (GUI_Widget *) new GUI_Text(colX[0], textY[0], 0, 0, 0, "Scaler:", font);
97 AddWidget(widget);
98 // scaler(fullscreen)
99 int num_scalers_fullscreen, fullscreen_scaler_selection;
100 bool no_only2x_scalers = !SDL_VideoModeOK(scrWidth * 2, scrHeight * 2, bpp, SDL_FULLSCREEN);
101 if (no_only2x_scalers) {
102 num_scalers_fullscreen = 2;
103 fullscreen_scaler_selection = (scr->get_scaler_index() == 1) ? 1 : 0;
104 } else {
105 num_scalers_fullscreen = num_scalers;
106 fullscreen_scaler_selection = scr->get_scaler_index();
107 }
108 scaler_button = new GUI_TextToggleButton(this, colX[2], buttonY[0], 208, height, scaler_text, num_scalers_fullscreen, fullscreen_scaler_selection, font, BUTTON_TEXTALIGN_CENTER, this, 0);
109 AddWidget(scaler_button);
110 // scaler (windowed)
111 scaler_win_button = new GUI_TextToggleButton(this, colX[2], buttonY[0], 208, height, scaler_text, num_scalers, scr->get_scaler_index(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
112 AddWidget(scaler_win_button);
113 // scale
114 widget = (GUI_Widget *) new GUI_Text(colX[0], textY[1], 0, 0, 0, "Scale:", gui->get_font());
115 AddWidget(widget);
116 const char *scale_win_text[10];
117 scale_win_text[0] = "1";
118 scale_win_text[1] = "2";
119 scale_win_text[2] = "3";
120 scale_win_text[3] = "4";
121 scale_win_text[4] = "5";
122 scale_win_text[5] = "6";
123 scale_win_text[6] = "7";
124 scale_win_text[7] = "8";
125 int scale = scr->get_scale_factor();
126 char buff [4];
127 itoa(scale, buff, 10); // write current scale to buff
128 // scale (fullscreen)
129 const char *scale_text[10];
130 int num_scale = 0;
131 int scale_selection = 9;
132
133 for (int i = 1; i < 9; i++) {
134 if (SDL_VideoModeOK(scrWidth * i, scrHeight * i, bpp, SDL_FULLSCREEN)) {
135 scale_text[num_scale] = scale_win_text[i - 1];
136 if (i == scale)
137 scale_selection = num_scale;
138 num_scale++;
139 }
140 }
141 if (scale_selection == 9) { // current scale is greater than 8 (or wasn't returned as okay)
142 if (scr->is_fullscreen() || (scale > 8 && SDL_VideoModeOK(scrWidth * scale, scrHeight * scale, bpp, SDL_FULLSCREEN))) {
143 scale_selection = num_scale;
144 scaler_text[num_scale] = buff; // current scale
145 num_scale++;
146 } else if (num_scale > 0) {
147 scale_selection = 0;
148 } else {
149 no_fullscreen = true;
150 }
151 }
152 if (no_fullscreen) {
153 scale_button = NULL;
154 scaler_button->Delete();
155 scaler_button = NULL;
156 } else {
157 scale_button = new GUI_TextToggleButton(this, colX[4], buttonY[1], yesno_width, height, scale_text, num_scale, scale_selection, font, BUTTON_TEXTALIGN_CENTER, this, 0);
158 AddWidget(scale_button);
159 }
160 // scale (windowed)
161 int num_win_scale, scale_win_selection;
162 if (scale < 9) {
163 num_win_scale = 8;
164 scale_win_selection = scale - 1;
165 } else {
166 num_win_scale = 9;
167 scale_win_selection = 8;
168 scale_win_text[8] = buff;
169 }
170 scale_win_button = new GUI_TextToggleButton(this, colX[4], buttonY[1], yesno_width, height, scale_win_text, num_win_scale, scale_win_selection, font, BUTTON_TEXTALIGN_CENTER, this, 0);
171 AddWidget(scale_win_button);
172 // scale (only2x scale button for scalers that aren't point or interlaced)
173 only2x_button = new GUI_Button(this, colX[3], buttonY[1], 70, height, "2x only", font, BUTTON_TEXTALIGN_CENTER, 0, this, 0);
174 AddWidget(only2x_button);
175 // fullscreen_toggle
176 fullscreen_button = new GUI_TextToggleButton(this, colX[4], buttonY[2], yesno_width, height, yesno_text, 2, scr->is_fullscreen(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
177 AddWidget(fullscreen_button);
178
179 if (no_fullscreen && !scr->is_fullscreen()) {
180 fullscreen_button->Hide();
181 } else {
182 widget = (GUI_Widget *) new GUI_Text(colX[0], textY[2], 0, 0, 0, "Fullscreen:", gui->get_font());
183 AddWidget(widget);
184 }
185 #endif /* !SCALER_AND_SCALE_CANNOT_BE_CHANGED */
186
187 bool first_index = true;
188 #if SCALER_AND_SCALE_CANNOT_BE_CHANGED
189 // fullscreen_toggle
190 if (!no_fullscreen || scr->is_fullscreen()) {
191 widget = (GUI_Widget *) new GUI_Text(colX[0], textY, 0, 0, 0, "Fullscreen:", gui->get_font());
192 AddWidget(widget);
193
194 fullscreen_button = new GUI_TextToggleButton(this, colX[4], buttonY, yesno_width, height, yesno_text, 2, scr->is_fullscreen(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
195 AddWidget(fullscreen_button);
196 button_index[last_index] = fullscreen_button;
197
198 widget = (GUI_Widget *) new GUI_Text(colX[0], textY += row_h, 0, 0, 0, "Non-square pixels:", gui->get_font());
199 AddWidget(widget);
200 non_square_pixels_button = new GUI_TextToggleButton(this, colX[4], buttonY += row_h, yesno_width, height, yesno_text, 2, scr->is_non_square_pixels(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
201 AddWidget(non_square_pixels_button);
202 button_index[last_index += 1] = non_square_pixels_button;
203
204 first_index = false;
205 } else
206 fullscreen_button = NULL;
207 #endif
208
209 Configuration *config = Game::get_game()->get_config();
210
211 // show roofs
212 widget = (GUI_Widget *) new GUI_Text(colX[0], textY += first_index ? 0 : row_h, 0, 0, 0, "Show roofs:", gui->get_font());
213 AddWidget(widget);
214 roof_button = new GUI_TextToggleButton(this, colX[4], buttonY += first_index ? 0 : row_h, yesno_width, height, yesno_text, 2, game->is_roof_mode(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
215 AddWidget(roof_button);
216 button_index[(last_index += first_index ? 0 : 1)] = roof_button;
217 // use_new_dolls
218 if (game->is_new_style()) {
219 doll_button = NULL;
220 old_use_new_dolls = true;
221 } else {
222 widget = (GUI_Widget *) new GUI_Text(colX[0], textY += row_h, 0, 0, 0, "Use new actor dolls:", gui->get_font());
223 AddWidget(widget);
224 bool use_new_dolls;
225 config->value(config_get_game_key(config) + "/use_new_dolls", use_new_dolls, false);
226 old_use_new_dolls = use_new_dolls;
227 doll_button = new GUI_TextToggleButton(this, colX[4], buttonY += row_h, yesno_width, height, yesno_text, 2, use_new_dolls, font, BUTTON_TEXTALIGN_CENTER, this, 0);
228 AddWidget(doll_button);
229 button_index[last_index += 1] = doll_button;
230 }
231 // tile_lighting_b
232 widget = (GUI_Widget *) new GUI_Text(colX[0], textY += row_h, 0, 0, 0, "Use lighting data from map tiles:", gui->get_font());
233 AddWidget(widget);
234 old_use_tile_lighting = game->get_map_window()->using_map_tile_lighting;
235 tile_lighting_b = new GUI_TextToggleButton(this, colX[4], buttonY += row_h, yesno_width, height, yesno_text, 2, old_use_tile_lighting, font, BUTTON_TEXTALIGN_CENTER, this, 0);
236 AddWidget(tile_lighting_b);
237 button_index[last_index += 1] = tile_lighting_b;
238 // needs restart text
239 widget = (GUI_Widget *) new GUI_Text(colX[0], textY += row_h * 2, 0, 0, 0, "The following require a restart:", gui->get_font());
240 AddWidget(widget);
241 // lighting (needs reset)
242 widget = (GUI_Widget *) new GUI_Text(colX[1], textY += row_h, 0, 0, 0, "Lighting mode:", gui->get_font());
243 AddWidget(widget);
244 const char *const lighting_text[] = { "none", "smooth", "original" };
245 lighting_button = new GUI_TextToggleButton(this, colX[3], buttonY += row_h * 3, 70, height, lighting_text, 3, scr->get_old_lighting_style(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
246 AddWidget(lighting_button);
247 button_index[last_index += 1] = lighting_button;
248 // sprites (needs reset)
249 widget = (GUI_Widget *) new GUI_Text(colX[1], textY += row_h, 0, 0, 0, "Use custom actor tiles:", gui->get_font());
250 AddWidget(widget);
251 const char *const sprite_text[] = { "no", "yes", "default" };
252 Std::string custom_tile_str;
253 int custom_tiles;
254 config->value(config_get_game_key(config) + "/custom_actor_tiles", custom_tile_str, "default");
255 if (custom_tile_str == "default")
256 custom_tiles = 2;
257 else
258 custom_tiles = custom_tile_str == "yes" ? 1 : 0;
259 sprites_b = new GUI_TextToggleButton(this, colX[3], buttonY += row_h, 70, height, sprite_text, 3, custom_tiles, font, BUTTON_TEXTALIGN_CENTER, this, 0);
260 AddWidget(sprites_b);
261 button_index[last_index += 1] = sprites_b;
262 // game_style (needs reset)
263 const char *game_style_text[4];
264 game_style_text[0] = "original style";
265 game_style_text[1] = "new style";
266 game_style_text[2] = "original+";
267 game_style_text[3] = "original+ full map";
268 widget = (GUI_Widget *) new GUI_Text(colX[1], textY += row_h, 0, 0, 0, "Game style:", gui->get_font());
269 AddWidget(widget);
270 game_style_button = new GUI_TextToggleButton(this, colX[3] - 84, buttonY += row_h, 154, height, game_style_text, 4, game->get_game_style(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
271 AddWidget(game_style_button);
272 button_index[last_index += 1] = game_style_button;
273 // dithering (needs reset)
274 widget = (GUI_Widget *) new GUI_Text(colX[1], textY += row_h, 0, 0, 0, "Old video graphics:", gui->get_font());
275 AddWidget(widget);
276 const char *const dither_text[] = { "no", "CGA", "EGA" };
277 dither_button = new GUI_TextToggleButton(this, colX[4], buttonY += row_h, yesno_width, height, dither_text, 3, game->get_dither()->get_mode(), font, BUTTON_TEXTALIGN_CENTER, this, 0);
278 AddWidget(dither_button);
279 button_index[last_index += 1] = dither_button;
280 // cancel/save buttons
281 cancel_button = new GUI_Button(this, 95, VD_HEIGHT - 20, 54, height, "Cancel", font, BUTTON_TEXTALIGN_CENTER, 0, this, 0);
282 AddWidget(cancel_button);
283 button_index[last_index += 1] = cancel_button;
284 save_button = new GUI_Button(this, 170, VD_HEIGHT - 20, 40, height, "Save", font, BUTTON_TEXTALIGN_CENTER, 0, this, 0);
285 AddWidget(save_button);
286 button_index[last_index += 1] = save_button;
287
288 rebuild_buttons(true);
289 return true;
290 }
291
~VideoDialog()292 VideoDialog::~VideoDialog() {
293 }
294
rebuild_buttons(bool init)295 void VideoDialog::rebuild_buttons(bool init) {
296 #if SCALER_AND_SCALE_CANNOT_BE_CHANGED
297 return;
298 #endif
299 int scaler;
300 bool fullscreen;
301 Screen *scr = Game::get_game()->get_screen();
302
303 if (init) {
304 scaler = scr->get_scaler_index();
305 fullscreen = scr->is_fullscreen();
306 } else {
307 fullscreen = fullscreen_button->GetSelection();
308 if (fullscreen)
309 scaler = scaler_button->GetSelection();
310 else
311 scaler = scaler_win_button->GetSelection();
312 }
313 // scaler buttons
314 if (fullscreen) {
315 if (scaler_button)
316 scaler_button->Show();
317 scaler_win_button->Hide();
318 } else {
319 if (scaler_button)
320 scaler_button->Hide();
321 scaler_win_button->Show();
322 }
323 // scale buttons
324 if (scaler > 1) {
325 if (scale_button)
326 scale_button->Hide();
327 scale_win_button->Hide();
328 only2x_button->Show();
329 } else {
330 only2x_button->Hide();
331 if (fullscreen) {
332 if (scale_button)
333 scale_button->Show();
334 scale_win_button->Hide();
335 } else {
336 if (scale_button)
337 scale_button->Hide();
338 scale_win_button->Show();
339 }
340 }
341 }
342
close_dialog()343 GUI_status VideoDialog::close_dialog() {
344 Delete(); // mark dialog as deleted. it will be freed by the GUI object
345 callback_object->callback(0, this, this);
346 return GUI_YUM;
347 }
348
KeyDown(const Common::KeyState & key)349 GUI_status VideoDialog::KeyDown(const Common::KeyState &key) {
350 KeyBinder *keybinder = Game::get_game()->get_keybinder();
351 ActionType a = keybinder->get_ActionType(key);
352
353 switch (keybinder->GetActionKeyType(a)) {
354 case NORTH_KEY:
355 case WEST_KEY:
356 if (b_index_num != -1)
357 button_index[b_index_num]->set_highlighted(false);
358
359 if (b_index_num <= 0)
360 b_index_num = last_index;
361 else
362 b_index_num = b_index_num - 1;
363 button_index[b_index_num]->set_highlighted(true);
364 break;
365 case SOUTH_KEY:
366 case EAST_KEY:
367 if (b_index_num != -1)
368 button_index[b_index_num]->set_highlighted(false);
369
370 if (b_index_num == last_index)
371 b_index_num = 0;
372 else
373 b_index_num += 1;
374 button_index[b_index_num]->set_highlighted(true);
375 break;
376 case DO_ACTION_KEY:
377 if (b_index_num != -1) return button_index[b_index_num]->Activate_button();
378 break;
379 case CANCEL_ACTION_KEY:
380 return close_dialog();
381 default:
382 keybinder->handle_always_available_keys(a);
383 break;
384 }
385 return GUI_YUM;
386 }
387
callback(uint16 msg,GUI_CallBack * caller,void * data)388 GUI_status VideoDialog::callback(uint16 msg, GUI_CallBack *caller, void *data) {
389 if (caller == cancel_button) {
390 return close_dialog();
391 } else if (fullscreen_button && caller == fullscreen_button) {
392 rebuild_buttons(false);
393 #ifndef SCALER_AND_SCALE_CANNOT_BE_CHANGED
394 } else if (caller == scaler_button) {
395 if (scaler_button->GetSelection() > 1) {
396 scale_button->Hide();
397 only2x_button->Show();
398 } else {
399 scale_button->Show();
400 only2x_button->Hide();
401 }
402 } else if (caller == scaler_win_button) {
403 if (scaler_win_button->GetSelection() > 1) {
404 scale_win_button->Hide();
405 only2x_button->Show();
406 } else {
407 scale_win_button->Show();
408 only2x_button->Hide();
409 }
410 #endif /* !SCALER_AND_SCALE_CANNOT_BE_CHANGED */
411 } else if (caller == save_button) {
412 Game *game = Game::get_game();
413 Screen *scr = Game::get_game()->get_screen();
414 Configuration *config = Game::get_game()->get_config();
415 bool fullscreen = fullscreen_button ? fullscreen_button->GetSelection() : scr->is_fullscreen();
416 #if SCALER_AND_SCALE_CANNOT_BE_CHANGED
417 if (fullscreen != scr->is_fullscreen())
418 scr->toggle_fullscreen();
419 bool non_square_pixels = non_square_pixels_button ? (bool)non_square_pixels_button->GetSelection() : false;
420 scr->set_non_square_pixels(non_square_pixels);
421 #else
422 // scaler
423 int scaler;
424 if (fullscreen)
425 scaler = scaler_button->GetSelection();
426 else
427 scaler = scaler_win_button->GetSelection();
428 config->set("config/video/scale_method", scr->get_scaler_reg()->GetNameForIndex(scaler));
429 // scale
430 int scale;
431 if (fullscreen)
432 scale = scale_button->GetSelection() + 1;
433 else
434 scale = scale_win_button->GetSelection() + 1;
435 config->set("config/video/scale_factor", scale);
436 #endif
437 // fullscreen
438 config->set("config/fullscreen", fullscreen ? "yes" : "no");
439 game->get_screen()->set_fullscreen(fullscreen);
440
441 // non-square pixels
442 config->set("config/video/non_square_pixels", non_square_pixels ? "yes" : "no");
443 // roof mode
444 bool roof_mode = roof_button->GetSelection();
445 game->set_roof_mode(roof_mode);
446 game->get_map_window()->set_roof_mode(roof_mode);
447 game->get_game_map()->set_roof_mode(roof_mode);
448 config->set(config_get_game_key(config) + "/roof_mode", roof_mode ? "yes" : "no");
449 // use_new_dolls
450 if (doll_button && old_use_new_dolls != (doll_button->GetSelection() ? 1 : 0)) {
451 config->set(config_get_game_key(config) + "/use_new_dolls", doll_button->GetSelection() ? "yes" : "no");
452 ViewManager *vm = game->get_view_manager();
453 InventoryView *iv = vm->get_inventory_view();
454 if (vm->get_current_view() == iv) // showing a doll so need to reset
455 iv->set_party_member(iv->get_party_member_num());
456 }
457 // tile_lighting_b
458 if (old_use_tile_lighting != (bool)tile_lighting_b->GetSelection()) {
459 config->set(config_get_game_key(config) + "/map_tile_lighting", tile_lighting_b->GetSelection() ? "yes" : "no");
460 game->get_map_window()->using_map_tile_lighting = tile_lighting_b->GetSelection() == 1;
461 game->get_map_window()->updateAmbience();
462 }
463 // lighting
464 const char *lighting_char;
465 int lighting = lighting_button->GetSelection();
466 if (lighting == 0)
467 lighting_char = "none";
468 else if (lighting == 1)
469 lighting_char = "smooth";
470 else
471 lighting_char = "original";
472 config->set("config/general/lighting", lighting_char);
473 // sprites
474 const char *sprite_char;
475 if (sprites_b->GetSelection() == 2)
476 sprite_char = "default";
477 else
478 sprite_char = sprites_b->GetSelection() ? "yes" : "no";
479 config->set(config_get_game_key(config) + "/custom_actor_tiles", sprite_char);
480 // game_style
481 const char *game_style_text[4];
482 game_style_text[0] = "original";
483 game_style_text[1] = "new";
484 game_style_text[2] = "original+";
485 game_style_text[3] = "original+_full_map";
486 config->set("config/video/game_style", game_style_text[game_style_button->GetSelection()]);
487 // dither
488 const char *dither_char;
489 uint8 dither = dither_button->GetSelection();
490 if (dither == 0)
491 dither_char = "none";
492 else if (dither == 1)
493 dither_char = "cga";
494 else
495 dither_char = "ega";
496 config->set("config/general/dither_mode", dither_char);
497
498 config->write();
499 close_dialog();
500 return GUI_YUM;
501 }
502
503 return GUI_PASS;
504 }
505
506 } // End of namespace Nuvie
507 } // End of namespace Ultima
508