00001
00002
00003
00004
00005
00006
00007
00009
00010 #include <sstream>
00011
00012 #include "utils.h"
00013 #include "video.h"
00014 #include "gui.h"
00015 #include "menu_window.h"
00016
00017 using namespace std;
00018 using namespace hoa_utils;
00019 using namespace hoa_video;
00020 using namespace hoa_video::private_video;
00021
00022
00023 namespace hoa_video {
00024
00025 MenuWindow::MenuWindow() :
00026 _width(0),
00027 _height(0),
00028 _skin(NULL),
00029 _window_state(VIDEO_MENU_STATE_HIDDEN),
00030 _display_timer(0),
00031 _display_mode(VIDEO_MENU_INSTANT),
00032 _is_scissored(false)
00033 {
00034 _id = GUIManager->GetNextMenuWindowID();
00035 _initialized = IsInitialized(_initialization_errors);
00036 }
00037
00038
00039
00040 bool MenuWindow::Create(string skin_name, float w, float h, int32 visible_flags, int32 shared_flags) {
00041 _skin = GUIManager->GetMenuSkin(skin_name);
00042 if (_skin == NULL) {
00043 if (VIDEO_DEBUG)
00044 cerr << "VIDEO WARNING: MenuWindow::Create() failed because the requested menu skin was not found: "
00045 << skin_name << endl;
00046 return false;
00047 }
00048
00049 return Create(w, h, visible_flags, shared_flags);
00050 }
00051
00052
00053
00054 bool MenuWindow::Create(float w, float h, int32 visible_flags, int32 shared_flags) {
00055 if (w <= 0 || h <= 0) {
00056 if (VIDEO_DEBUG)
00057 cerr << "VIDEO WARNING: MenuWindow::Create() failed because an invalid width or height was passed in: "
00058 << "(width = " << w << ", height = " << h << ")" << endl;
00059 return false;
00060 }
00061
00062 _width = w;
00063 _height = h;
00064 _edge_visible_flags = visible_flags;
00065 _edge_shared_flags = shared_flags;
00066
00067 if (_skin == NULL) {
00068 _skin = GUIManager->GetDefaultMenuSkin();
00069 }
00070 if (_skin == NULL) {
00071 if (VIDEO_DEBUG)
00072 cerr << "VIDEO WARNING: MenuWindow::Create() failed because a default menu skin was unavailable "
00073 << "(no skins were loaded)" << endl;
00074 return false;
00075 }
00076
00077 if (_RecreateImage() == false) {
00078 if (VIDEO_DEBUG)
00079 cerr << "VIDEO WARNING: MenuWindow::Create() failed because the window could not be recreated" << endl;
00080 return false;
00081 }
00082
00083
00084 GUIManager->AddMenuWindow(this);
00085 _initialized = IsInitialized(_initialization_errors);
00086 return true;
00087 }
00088
00089
00090
00091 void MenuWindow::Destroy() {
00092 _skin = NULL;
00093 GUIManager->RemoveMenuWindow(this);
00094 VideoManager->DeleteImage(_menu_image);
00095 }
00096
00097
00098
00099 void MenuWindow::Update(uint32 frame_time) {
00100 _display_timer += frame_time;
00101
00102 if (_display_timer >= VIDEO_MENU_SCROLL_TIME) {
00103 if (_window_state == VIDEO_MENU_STATE_SHOWING)
00104 _window_state = VIDEO_MENU_STATE_SHOWN;
00105 else if (_window_state == VIDEO_MENU_STATE_HIDING)
00106 _window_state = VIDEO_MENU_STATE_HIDDEN;
00107 }
00108
00109 if (_window_state == VIDEO_MENU_STATE_HIDDEN || _window_state == VIDEO_MENU_STATE_SHOWN) {
00110
00111 float x_buffer = (_width - _inner_width) / 2;
00112 float y_buffer = (_height - _inner_height) / 2;
00113
00114 float left, right, bottom, top;
00115 left = 0.0f;
00116 right = _width;
00117 bottom = 0.0f;
00118 top = _height;
00119
00120 VideoManager->PushState();
00121 VideoManager->SetDrawFlags(_xalign, _yalign, 0);
00122 CalculateAlignedRect(left, right, bottom, top);
00123 VideoManager->PopState();
00124
00125 _scissor_rect = VideoManager->CalculateScreenRect(left, right, bottom, top);
00126
00127 _scissor_rect.left += static_cast<int32>(x_buffer);
00128 _scissor_rect.width -= static_cast<int32>(x_buffer * 2);
00129 _scissor_rect.top += static_cast<int32>(y_buffer);
00130 _scissor_rect.height -= static_cast<int32>(y_buffer * 2);
00131
00132
00133 _is_scissored = false;
00134 return;
00135 }
00136
00137 _is_scissored = true;
00138
00139
00140 float draw_percent = 1.0f;
00141
00142 if (_display_mode != VIDEO_MENU_INSTANT && _window_state != VIDEO_MENU_STATE_SHOWN) {
00143 float time = static_cast<float>(_display_timer) / static_cast<float>(VIDEO_MENU_SCROLL_TIME);
00144 if (time > 1.0f)
00145 time = 1.0f;
00146
00147 if (_window_state == VIDEO_MENU_STATE_HIDING)
00148 time = 1.0f - time;
00149
00150 draw_percent = time;
00151 }
00152
00153 if (draw_percent != 1.0f) {
00154 if (_display_mode == VIDEO_MENU_EXPAND_FROM_CENTER) {
00155 float left, right, bottom, top;
00156 left = 0.0f;
00157 right = _width;
00158 bottom = 0.0f;
00159 top = _height;
00160
00161 VideoManager->PushState();
00162 VideoManager->SetDrawFlags(_xalign, _yalign, 0);
00163 CalculateAlignedRect(left, right, bottom, top);
00164 VideoManager->PopState();
00165
00166 float center = (top + bottom) * 0.5f;
00167
00168 bottom = center * (1.0f - draw_percent) + bottom * draw_percent;
00169 top = center * (1.0f - draw_percent) + top * draw_percent;
00170
00171 _scissor_rect = VideoManager->CalculateScreenRect(left, right, bottom, top);
00172 }
00173 }
00174 }
00175
00176
00177
00178 void MenuWindow::Draw() {
00179 if (_initialized == false) {
00180 if (VIDEO_DEBUG)
00181 cerr << "VIDEO WARNING: MenuWindow::Draw() failed because the menu window was not initialized:\n" << _initialization_errors << endl;
00182 return;
00183 }
00184
00185 if (_window_state == VIDEO_MENU_STATE_HIDDEN)
00186 return;
00187
00188 VideoManager->_PushContext();
00189 VideoManager->SetDrawFlags(_xalign, _yalign, VIDEO_BLEND, 0);
00190
00191 if (_is_scissored) {
00192 ScreenRect rect = _scissor_rect;
00193 if (VideoManager->IsScissoringEnabled()) {
00194 rect.Intersect(VideoManager->GetScissorRect());
00195 }
00196 else {
00197 VideoManager->EnableScissoring(true);
00198 }
00199 VideoManager->SetScissorRect(rect);
00200 }
00201
00202 VideoManager->Move(_x_position, _y_position);
00203 VideoManager->DrawImage(_menu_image, Color::white);
00204
00205 VideoManager->_PopContext();
00206 return;
00207 }
00208
00209
00210
00211 void MenuWindow::Show() {
00212 if (_initialized == false) {
00213 if (VIDEO_DEBUG)
00214 cerr << "VIDEO WARNING: MenuWindow::Show() failed because the menu window was not initialized:\n" << _initialization_errors << endl;
00215 return;
00216 }
00217
00218 if (_window_state == VIDEO_MENU_STATE_SHOWING || _window_state == VIDEO_MENU_STATE_SHOWN) {
00219 return;
00220 }
00221
00222 _display_timer = 0;
00223
00224 if (_display_mode == VIDEO_MENU_INSTANT)
00225 _window_state = VIDEO_MENU_STATE_SHOWN;
00226 else
00227 _window_state = VIDEO_MENU_STATE_SHOWING;
00228 }
00229
00230
00231
00232 void MenuWindow::Hide() {
00233 if (_initialized == false) {
00234 if (VIDEO_DEBUG)
00235 cerr << "VIDEO WARNING: MenuWindow::Hide() failed because the menu window was not initialized:\n" << _initialization_errors << endl;
00236 return;
00237 }
00238
00239 if (_window_state == VIDEO_MENU_STATE_HIDING || _window_state == VIDEO_MENU_STATE_HIDDEN) {
00240 return;
00241 }
00242
00243 _display_timer = 0;
00244
00245 if (_display_mode == VIDEO_MENU_INSTANT)
00246 _window_state = VIDEO_MENU_STATE_HIDDEN;
00247 else
00248 _window_state = VIDEO_MENU_STATE_HIDING;
00249 }
00250
00251
00252
00253 bool MenuWindow::IsInitialized(string& errors) {
00254 errors.clear();
00255 ostringstream stream;
00256
00257
00258 if (_width <= 0.0f || _width > 1024.0f)
00259 stream << "* Invalid width (" << _width << ")" << endl;
00260
00261
00262 if (_height <= 0.0f || _height > 768.0f)
00263 stream << "* Invalid height (" << _height << ")" << endl;
00264
00265
00266 if (_display_mode <= VIDEO_MENU_INVALID || _display_mode >= VIDEO_MENU_TOTAL)
00267 stream << "* Invalid display mode (" << _display_mode << ")" << endl;
00268
00269
00270 if (_window_state <= VIDEO_MENU_STATE_INVALID || _window_state >= VIDEO_MENU_STATE_TOTAL)
00271 stream << "* Invalid state (" << _window_state << ")" << endl;
00272
00273
00274 if (_menu_image.GetWidth() == 0)
00275 stream << "* Menu image is not loaded" << endl;
00276
00277
00278 if (_skin == NULL)
00279 stream << "* No menu skin is assigned" << endl;
00280
00281 errors = stream.str();
00282
00283 if (errors.empty()) {
00284 _initialized = true;
00285 }
00286 else {
00287 _initialized = false;
00288 }
00289
00290 return _initialized;
00291 }
00292
00293
00294
00295 void MenuWindow::ChangeEdgeVisibleFlags(int32 flags) {
00296 _edge_visible_flags = flags;
00297 _RecreateImage();
00298 }
00299
00300
00301
00302 void MenuWindow::ChangeEdgeSharedFlags(int32 flags) {
00303 _edge_shared_flags = flags;
00304 _RecreateImage();
00305 }
00306
00307
00308
00309 void MenuWindow::ChangeMenuSkin(string& skin_name) {
00310 MenuSkin* new_skin = GUIManager->GetMenuSkin(skin_name);
00311 if (new_skin == NULL) {
00312 if (VIDEO_DEBUG)
00313 cerr << "VIDEO WARNING: MenuWindow::ChangeMenuSkin() failed because the skin_name \""
00314 << skin_name << "\" was invalid" << endl;
00315 return;
00316 }
00317 _skin = new_skin;
00318 _RecreateImage();
00319 }
00320
00321
00322
00323 void MenuWindow::SetDisplayMode(VIDEO_MENU_DISPLAY_MODE mode) {
00324 if (mode <= VIDEO_MENU_INVALID || mode >= VIDEO_MENU_TOTAL) {
00325 if (VIDEO_DEBUG)
00326 cerr << "VIDEO WARNING: MenuWindow::SetDisplayMode() failed because an invalid argument was given: " << mode << endl;
00327 return;
00328 }
00329
00330 _display_mode = mode;
00331 _initialized = IsInitialized(_initialization_errors);
00332 }
00333
00334
00335
00336 bool MenuWindow::_RecreateImage() {
00337 if (_skin == NULL) {
00338 if (VIDEO_DEBUG) {
00339 cerr << "VIDEO ERROR: In MenuWindow::_RecreateImage(), there was no menu skin set" << endl;
00340 }
00341 return false;
00342 }
00343
00344 VideoManager->DeleteImage(_menu_image);
00345 _menu_image.Clear();
00346
00347
00348 float left_border_size = _skin->borders[1][0].GetWidth();
00349 float right_border_size = _skin->borders[1][2].GetWidth();
00350 float top_border_size = _skin->borders[2][1].GetHeight();
00351 float bottom_border_size = _skin->borders[0][1].GetHeight();
00352
00353 float horizontal_border_size = left_border_size + right_border_size;
00354 float vertical_border_size = top_border_size + bottom_border_size;
00355
00356 float top_width = _skin->borders[2][1].GetWidth();
00357 float left_height = _skin->borders[1][0].GetHeight();
00358
00359
00360 _inner_width = _width - horizontal_border_size;
00361 _inner_height = _height - vertical_border_size;
00362
00363 if (_inner_width < 0.0f) {
00364 if (VIDEO_DEBUG) {
00365 cerr << "VIDEO ERROR: In MenuWindow::_RecreateImage(), _inner_width was negative" << endl;
00366 }
00367 return false;
00368 }
00369
00370 if (_inner_height < 0.0f) {
00371 if (VIDEO_DEBUG) {
00372 cerr << "VIDEO ERROR: In MenuWindow::_RecreateImage(), _inner_height was negative" << endl;
00373 }
00374 return false;
00375 }
00376
00377
00378 bool background_loaded = _skin->background.GetWidth();
00379
00380
00381 float num_x_tiles = _inner_width / top_width;
00382 float num_y_tiles = _inner_height / left_height;
00383
00384 int32 inum_x_tiles = static_cast<int32>(num_x_tiles);
00385 int32 inum_y_tiles = static_cast<int32>(num_y_tiles);
00386
00387
00388
00389
00390 float dnum_x_tiles = num_x_tiles - inum_x_tiles;
00391 float dnum_y_tiles = num_y_tiles - inum_y_tiles;
00392
00393 if (dnum_x_tiles > 0.001f) {
00394 float width_adjust = (1.0f - dnum_x_tiles) * top_width;
00395 _width += width_adjust;
00396 _inner_width += width_adjust;
00397 ++inum_x_tiles;
00398 }
00399
00400 if (dnum_y_tiles > 0.001f) {
00401 float height_adjust = (1.0f - dnum_y_tiles) * top_width;
00402 _height += height_adjust;
00403 _inner_height += height_adjust;
00404 ++inum_y_tiles;
00405 }
00406
00407
00408
00409 Color c[4];
00410 _skin->borders[1][1].GetVertexColor(c[0], 0);
00411 _skin->borders[1][1].GetVertexColor(c[1], 1);
00412 _skin->borders[1][1].GetVertexColor(c[2], 2);
00413 _skin->borders[1][1].GetVertexColor(c[3], 3);
00414
00415 VideoManager->DeleteImage(_skin->borders[1][1]);
00416 _skin->borders[1][1].SetDimensions(left_border_size, top_border_size);
00417 _skin->borders[1][1].SetVertexColors(c[0], c[1], c[2], c[3]);
00418 VideoManager->LoadImage(_skin->borders[1][1]);
00419
00420
00421
00422 if (background_loaded) {
00423 _skin->background.SetVertexColors(c[0], c[1], c[2], c[3]);
00424
00425 float width = _skin->background.GetWidth();
00426 float height = _skin->background.GetHeight();
00427
00428 float min_x = 0;
00429 float min_y = 0;
00430
00431 float max_x = _inner_width + horizontal_border_size;
00432 float max_y = _inner_height + vertical_border_size;
00433
00434 if (_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
00435 max_y -= (top_border_size / 2);
00436 if (_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
00437 min_y += (bottom_border_size / 2);
00438 if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
00439 min_x += (left_border_size / 2);
00440 if (_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
00441 max_x -= (right_border_size / 2);
00442
00443 for (float y = min_y ; y < max_y; y += height) {
00444 for (float x = min_x; x < max_x; x += width) {
00445 float u = 1.0, v = 1.0;
00446
00447 if (x + width > max_x)
00448 u = (max_x - x) / width;
00449 if (y + height > max_y)
00450 v = (max_y - y) / height;
00451
00452 _menu_image.AddImage(_skin->background, x, y, 0, 0, u, v);
00453 }
00454 }
00455 }
00456 else {
00457
00458 VideoManager->DeleteImage(_skin->borders[1][1]);
00459 _skin->borders[1][1].SetDimensions(_inner_width, _inner_height);
00460 _skin->borders[1][1].SetVertexColors(c[0], c[1], c[2], c[3]);
00461 VideoManager->LoadImage(_skin->borders[1][1]);
00462
00463 _menu_image.AddImage(_skin->borders[1][1], left_border_size, bottom_border_size);
00464 }
00465
00466
00467 float max_x = left_border_size + inum_x_tiles * top_width;
00468 float max_y = bottom_border_size + inum_y_tiles * left_height;
00469 float min_x = 0.0f;
00470 float min_y = 0.0f;
00471
00472
00473 if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT && _edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM) {
00474 if (_edge_shared_flags & VIDEO_MENU_EDGE_LEFT && _edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
00475 _menu_image.AddImage(_skin->connectors[4], min_x, min_y);
00476 else if (_edge_shared_flags & VIDEO_MENU_EDGE_LEFT)
00477 _menu_image.AddImage(_skin->connectors[1], min_x, min_y);
00478 else if (_edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
00479 _menu_image.AddImage(_skin->connectors[2], min_x, min_y);
00480 else
00481 _menu_image.AddImage(_skin->borders[2][0], min_x, min_y);
00482 }
00483 else if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
00484 _menu_image.AddImage(_skin->borders[1][0], min_x, min_y);
00485 else if (_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
00486 _menu_image.AddImage(_skin->borders[0][1], min_x, min_y);
00487 else if (!background_loaded)
00488 _menu_image.AddImage(_skin->borders[1][1], min_x, min_y);
00489
00490
00491 if (_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT && _edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM) {
00492 if (_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT && _edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
00493 _menu_image.AddImage(_skin->connectors[4], max_x, min_y);
00494 else if (_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT)
00495 _menu_image.AddImage(_skin->connectors[1], max_x, min_y);
00496 else if (_edge_shared_flags & VIDEO_MENU_EDGE_BOTTOM)
00497 _menu_image.AddImage(_skin->connectors[3], max_x, min_y);
00498 else
00499 _menu_image.AddImage(_skin->borders[2][2], max_x, min_y);
00500 }
00501 else if (_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
00502 _menu_image.AddImage(_skin->borders[1][2], max_x, min_y);
00503 else if (_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
00504 _menu_image.AddImage(_skin->borders[2][1], max_x, min_y);
00505 else if (!background_loaded)
00506 _menu_image.AddImage(_skin->borders[1][1], max_x, min_y);
00507
00508
00509 if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT && _edge_visible_flags & VIDEO_MENU_EDGE_TOP) {
00510 if (_edge_shared_flags & VIDEO_MENU_EDGE_LEFT && _edge_shared_flags & VIDEO_MENU_EDGE_TOP)
00511 _menu_image.AddImage(_skin->connectors[4], min_x, max_y);
00512 else if (_edge_shared_flags & VIDEO_MENU_EDGE_LEFT)
00513 _menu_image.AddImage(_skin->connectors[0], min_x, max_y);
00514 else if (_edge_shared_flags & VIDEO_MENU_EDGE_TOP)
00515 _menu_image.AddImage(_skin->connectors[2], min_x, max_y);
00516 else
00517 _menu_image.AddImage(_skin->borders[0][0], min_x, max_y);
00518 }
00519 else if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
00520 _menu_image.AddImage(_skin->borders[1][0], min_x, max_y);
00521 else if (_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
00522 _menu_image.AddImage(_skin->borders[0][1], min_x, max_y);
00523 else if (!background_loaded)
00524 _menu_image.AddImage(_skin->borders[1][1], min_x, max_y);
00525
00526
00527 if (_edge_visible_flags & VIDEO_MENU_EDGE_TOP && _edge_visible_flags & VIDEO_MENU_EDGE_RIGHT) {
00528 if (_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT && _edge_shared_flags & VIDEO_MENU_EDGE_TOP)
00529 _menu_image.AddImage(_skin->connectors[4], max_x, max_y);
00530 else if (_edge_shared_flags & VIDEO_MENU_EDGE_RIGHT)
00531 _menu_image.AddImage(_skin->connectors[0], max_x, max_y);
00532 else if (_edge_shared_flags & VIDEO_MENU_EDGE_TOP)
00533 _menu_image.AddImage(_skin->connectors[3], max_x, max_y);
00534 else
00535 _menu_image.AddImage(_skin->borders[0][2], max_x, max_y);
00536 }
00537 else if (_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
00538 _menu_image.AddImage(_skin->borders[0][1], max_x, max_y);
00539 else if (_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
00540 _menu_image.AddImage(_skin->borders[1][2], max_x, max_y);
00541 else if (!background_loaded)
00542 _menu_image.AddImage(_skin->borders[1][1], max_x, max_y);
00543
00544
00545 for (int32 tile_x = 0; tile_x < inum_x_tiles; ++tile_x) {
00546 if (_edge_visible_flags & VIDEO_MENU_EDGE_TOP)
00547 _menu_image.AddImage(_skin->borders[0][1], left_border_size + top_width * tile_x, max_y);
00548 else if (!background_loaded)
00549 _menu_image.AddImage(_skin->borders[1][1], left_border_size + top_width * tile_x, max_y);
00550
00551 if (_edge_visible_flags & VIDEO_MENU_EDGE_BOTTOM)
00552 _menu_image.AddImage(_skin->borders[2][1], left_border_size + top_width * tile_x, 0.0f);
00553 else if (!background_loaded)
00554 _menu_image.AddImage(_skin->borders[1][1], left_border_size + top_width * tile_x, 0.0f);
00555 }
00556
00557
00558 for (int32 tile_y = 0; tile_y < inum_y_tiles; ++tile_y) {
00559 if (_edge_visible_flags & VIDEO_MENU_EDGE_LEFT)
00560 _menu_image.AddImage(_skin->borders[1][0], 0.0f, bottom_border_size + left_height * tile_y);
00561 else if (!background_loaded)
00562 _menu_image.AddImage(_skin->borders[1][1], 0.0f, bottom_border_size + left_height * tile_y);
00563
00564 if (_edge_visible_flags & VIDEO_MENU_EDGE_RIGHT)
00565 _menu_image.AddImage(_skin->borders[1][2], max_x, bottom_border_size + left_height * tile_y);
00566 else if (!background_loaded)
00567 _menu_image.AddImage(_skin->borders[1][1], max_x, bottom_border_size + left_height * tile_y);
00568 }
00569
00570 return true;
00571 }
00572
00573 }