option.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00010 #include <sstream>
00011 
00012 #include "utils.h"
00013 
00014 #include "option.h"
00015 #include "video.h"
00016 
00017 using namespace std;
00018 
00019 using namespace hoa_utils;
00020 using namespace hoa_video::private_video;
00021 
00022 namespace hoa_video {
00023 
00024 OptionBox::OptionBox() {
00025   _option_xalign = VIDEO_X_LEFT;
00026   _option_yalign = VIDEO_Y_TOP;
00027   _selection_mode = VIDEO_SELECT_SINGLE;
00028   _switching = false;
00029   _horizontal_wrap_mode = VIDEO_WRAP_MODE_NONE;
00030   _vertical_wrap_mode = VIDEO_WRAP_MODE_NONE;
00031   _cursor_state = VIDEO_CURSOR_STATE_VISIBLE;
00032   _event = 0;
00033   _selection = -1;
00034   _first_selection = -1;
00035   _number_options = 0;
00036   _scrolling = 0;
00037   _scroll_offset = 0;
00038   _blink_time = 0;
00039   _scroll_time = 0;
00040   _blink = false;
00041   _cursor_xoffset = 0.0f;
00042   _cursor_yoffset = 0.0f;
00043   _horizontal_spacing = _vertical_spacing = 0.0f;
00044   _number_rows = _number_columns = 0;
00045   _initialized = IsInitialized(_initialization_errors);
00046   _TEMP_overide_scissorring = false;
00047 }
00048 
00049 
00050 
00051 OptionBox::~OptionBox() {
00052   ClearOptions();
00053 }
00054 
00055 
00056 
00057 void OptionBox::Update(uint32 frame_time) {
00058   _event = 0; // Clear all events
00059 
00060   _blink = ((_blink_time / VIDEO_CURSOR_BLINK_RATE) % 2) == 1;
00061   _blink_time += frame_time;
00062 
00063   if (_scrolling) {
00064     _scroll_time += frame_time;
00065 
00066     if (_scroll_time > VIDEO_OPTION_SCROLL_TIME) {
00067       _scroll_time = 0;
00068       _scrolling = false;
00069     }
00070   }
00071 }
00072 
00073 
00074 
00075 void OptionBox::Draw() {
00076   // Do nothing if the option box is not properly initialized
00077   if (_initialized == false) {
00078     return;
00079   }
00080 
00081   VideoManager->_PushContext();
00082   VideoManager->SetDrawFlags(_xalign, _yalign, VIDEO_BLEND, 0);
00083 
00084   // (1) Determine the edge dimensions of the option box
00085   float left, right, bottom, top;
00086   left = 0.0f;
00087   right = _number_columns * _horizontal_spacing;
00088   bottom = 0.0f;
00089   top = _number_rows * _vertical_spacing;
00090 
00091   CalculateAlignedRect(left, right, bottom, top);
00092 
00093   int32 x, y, w, h;
00094 
00095   x = static_cast<int32>(left < right ? left : right);
00096   y = static_cast<int32>(top < bottom ? top : bottom);
00097   w = static_cast<int32>(right - left);
00098   if (w < 0)
00099     w = -w;
00100   h = static_cast<int32>(top - bottom);
00101   if (h < 0)
00102     h = -h;
00103 
00104   ScreenRect rect(x, y, w, h);
00105 
00106   int32 cursor_margin = static_cast<int32>(VideoManager->GetDefaultCursor()->GetWidth() + 1 - _cursor_xoffset);
00107   rect.left -= cursor_margin;
00108   rect.width += cursor_margin;
00109 
00110 
00111   // TEMP: Code to make the inventory look good for now until scissoring can be fixed correctly
00112   // Used to set the scissoring back to what it was before
00113   bool scissoring_rollback = VideoManager->IsScissoringEnabled();
00114   if (_TEMP_overide_scissorring) {
00115     rect.top += 71;
00116     rect.height += 10;
00117     rect.Intersect(VideoManager->GetScissorRect());
00118     VideoManager->EnableScissoring(true);
00119     VideoManager->SetScissorRect(rect);
00120   }
00121   else {
00122     if (_owner && VideoManager->IsScissoringEnabled() ) {
00123       rect.Intersect(_owner->GetScissorRect());
00124       rect.Intersect(VideoManager->GetScissorRect());
00125       VideoManager->EnableScissoring(true);
00126       VideoManager->SetScissorRect(rect);
00127     }
00128   }
00129 
00130   CoordSys &cs = VideoManager->_coord_sys;
00131   VideoManager->SetFont(_font);
00132   VideoManager->SetDrawFlags(_option_xalign, _option_yalign, VIDEO_X_NOFLIP, VIDEO_Y_NOFLIP, VIDEO_BLEND, 0);
00133 
00134   int32 row_min, row_max;
00135   float cell_offset = 0.0f;
00136 
00137   if (!_scrolling) {
00138     row_min = _scroll_offset;
00139     row_max = _scroll_offset + _number_rows;
00140   }
00141   else if (_scroll_direction == -1) { // Scrolling up
00142     row_min = _scroll_offset;
00143     row_max = _scroll_offset + _number_rows + 1;
00144 
00145     cell_offset = cs.GetVerticalDirection() * (1.0f - (_scroll_time / (VIDEO_OPTION_SCROLL_TIME))) * _vertical_spacing;
00146   }
00147   else { // Scrolling down
00148     row_min = _scroll_offset - 1;
00149     row_max = _scroll_offset + _number_rows;
00150     cell_offset = cs.GetVerticalDirection() * ((_scroll_time / (VIDEO_OPTION_SCROLL_TIME))) * _vertical_spacing;
00151   }
00152 
00153   OptionCellBounds bounds;
00154   bounds.y_top = top + cell_offset;
00155   bounds.y_center = bounds.y_top - 0.5f * _vertical_spacing * cs.GetVerticalDirection();
00156   bounds.y_bottom = (bounds.y_center * 2.0f) - bounds.y_top;
00157 
00158   float yoff = -_vertical_spacing * cs.GetVerticalDirection();
00159   float xoff = _horizontal_spacing * cs.GetHorizontalDirection();
00160   bool finished = false;
00161 
00162   // Iterate through all the visible option cells and draw them
00163   for (int32 row = row_min; row < row_max; row++) {
00164     bounds.x_left = left;
00165     bounds.x_center = bounds.x_left + (0.5f * _horizontal_spacing * cs.GetHorizontalDirection());
00166     bounds.x_right = (bounds.x_center * 2.0f) - bounds.x_left;
00167 
00168     // Draw the columns of options
00169     for (int32 col = 0; col < _number_columns; ++col) {
00170       int32 index = row * _number_columns + col;
00171 
00172       if (index >= _number_options || index < 0) {
00173         finished = true;
00174         break;
00175       }
00176 
00177       float left_edge = 999999.0f; // The x offset to where the text actually begins
00178       float x, y;
00179 
00180       int32 xalign = _option_xalign;
00181       int32 yalign = _option_yalign;
00182       _SetupAlignment(xalign, yalign, bounds, x, y);
00183 
00184       Option &op = _options.at(index);
00185       if (op.disabled)
00186         VideoManager->SetTextColor(Color::gray);
00187       else
00188         VideoManager->SetTextColor(Color::white);
00189 
00190       // Iterate through all option elements in the current option
00191       for (int32 element = 0; element < static_cast<int32>(op.elements.size()); element++) {
00192         switch (op.elements[element].type) {
00193           case VIDEO_OPTION_ELEMENT_LEFT_ALIGN:
00194           {
00195             xalign = VIDEO_X_LEFT;
00196             _SetupAlignment(xalign, _option_yalign, bounds, x, y);
00197             break;
00198           }
00199           case VIDEO_OPTION_ELEMENT_CENTER_ALIGN:
00200           {
00201             xalign = VIDEO_X_CENTER;
00202             _SetupAlignment(xalign, _option_yalign, bounds, x, y);
00203             break;
00204           }
00205           case VIDEO_OPTION_ELEMENT_RIGHT_ALIGN:
00206           {
00207             xalign = VIDEO_X_RIGHT;
00208             _SetupAlignment(xalign, _option_yalign, bounds, x, y);
00209             break;
00210           }
00211           case VIDEO_OPTION_ELEMENT_IMAGE:
00212           {
00213             int32 image_index = op.elements[element].value;
00214 
00215             if (image_index >= 0 && image_index < static_cast<int32>(op.images.size())) {
00216               if (op.disabled)
00217                 VideoManager->DrawImage(op.images[image_index], Color::gray);
00218               else
00219                 VideoManager->DrawImage(op.images[image_index], Color::white);
00220 
00221               float width = op.images[image_index].GetWidth();
00222               float edge = x - bounds.x_left; // edge value for VIDEO_X_LEFT
00223               if (xalign == VIDEO_X_CENTER)
00224                 edge -= width * 0.5f * cs.GetHorizontalDirection();
00225               else if (xalign == VIDEO_X_RIGHT)
00226                 edge -= width * cs.GetHorizontalDirection();
00227 
00228               if (edge < left_edge)
00229                 left_edge = edge;
00230 
00231             }
00232             break;
00233           }
00234           case VIDEO_OPTION_ELEMENT_POSITION:
00235           {
00236             x = bounds.x_left + op.elements[element].value * cs.GetHorizontalDirection();
00237             VideoManager->Move(x, y);
00238             break;
00239           }
00240           case VIDEO_OPTION_ELEMENT_TEXT:
00241           {
00242             int32 text_index = op.elements[element].value;
00243 
00244             if (text_index >= 0 && text_index < static_cast<int32>(op.text.size())) {
00245               const ustring& text = op.text[text_index];
00246               float width = static_cast<float>(VideoManager->CalculateTextWidth(_font, text));
00247               float edge = x - bounds.x_left; // edge value for VIDEO_X_LEFT
00248 
00249               if (xalign == VIDEO_X_CENTER)
00250                 edge -= width * 0.5f * cs.GetHorizontalDirection();
00251               else if (xalign == VIDEO_X_RIGHT)
00252                 edge -= width * cs.GetHorizontalDirection();
00253 
00254               if (edge < left_edge)
00255                 left_edge = edge;
00256 
00257               VideoManager->DrawText(text);
00258             }
00259 
00260             break;
00261           }
00262           case VIDEO_OPTION_ELEMENT_INVALID:
00263           case VIDEO_OPTION_ELEMENT_TOTAL:
00264           default:
00265           {
00266             cerr << "VIDEO WARNING: In OptionBox::Draw(), invalid option element type was present" << endl;
00267             break;
00268           }
00269         } // switch (op.elements[element].type)
00270       } // for (int32 element = 0; element < static_cast<int32>(op.elements.size()); element++)
00271 
00272       float cursor_offset = 0;
00273       if (_scrolling) {
00274         if (_scroll_direction == -1)// Scrolling up
00275           cursor_offset = -cell_offset;
00276         else // Scrolling down
00277           cursor_offset = -cell_offset + cs.GetVerticalDirection() * _vertical_spacing;
00278       }
00279 
00280       // Check if this is the index where we should draw the cursor icon for switching elements
00281       if (index == _first_selection && _blink == false && _cursor_state != VIDEO_CURSOR_STATE_HIDDEN) {
00282         _SetupAlignment(VIDEO_X_LEFT, _option_yalign, bounds, x, y);
00283         VideoManager->SetDrawFlags(VIDEO_BLEND, 0);
00284         VideoManager->MoveRelative(_cursor_xoffset + left_edge + _cursor_xoffset, cursor_offset + _cursor_yoffset + _cursor_yoffset);
00285         StillImage *default_cursor = VideoManager->GetDefaultCursor();
00286 
00287         if (default_cursor)
00288           VideoManager->DrawImage(*default_cursor, Color::white);
00289       }
00290 
00291       // Check if this is the index where we should draw the selection cursor icon, if it is visible
00292       if (index == _selection && (_blink && _cursor_state == VIDEO_CURSOR_STATE_BLINKING) == false && _cursor_state != VIDEO_CURSOR_STATE_HIDDEN) {
00293         _SetupAlignment(VIDEO_X_LEFT, _option_yalign, bounds, x, y);
00294         VideoManager->SetDrawFlags(VIDEO_BLEND, 0);
00295         VideoManager->MoveRelative(_cursor_xoffset + left_edge, cursor_offset + _cursor_yoffset);
00296         StillImage *default_cursor = VideoManager->GetDefaultCursor();
00297 
00298         if (default_cursor)
00299           VideoManager->DrawImage(*default_cursor, Color::white);
00300       }
00301 
00302       bounds.x_left += xoff;
00303       bounds.x_center += xoff;
00304       bounds.x_right += xoff;
00305     } // for (int32 col = 0; col < _number_columns; ++col)
00306 
00307     if (finished)
00308       break;
00309 
00310     bounds.y_top += yoff;
00311     bounds.y_center += yoff;
00312     bounds.y_bottom += yoff;
00313   } // for (int32 row = row_min; row < row_max; row++)
00314 
00315   VideoManager->EnableScissoring(scissoring_rollback);
00316   VideoManager->_PopContext();
00317 } // void OptionBox::Draw()
00318 
00319 
00320 
00321 void OptionBox::ClearOptions() {
00322   // Before deleting the options, deallocate any images that are stored by them
00323   for(int32 j = 0; j < static_cast<int32>(_options.size()); ++j) {
00324     for(int32 i = 0; i < static_cast<int32>(_options[j].images.size()); ++i) {
00325       VideoManager->DeleteImage(_options[j].images[i]);
00326     }
00327   }
00328 
00329   _options.clear();
00330 }
00331 
00332 
00333 
00334 bool OptionBox::SetOptions(const vector<ustring>& format_text) {
00335   _options.clear();
00336   _number_options = 0;
00337 
00338   vector<ustring>::const_iterator i = format_text.begin();
00339   while (i != format_text.end()) {
00340     const ustring &str = *i;
00341 
00342     Option option;
00343 
00344     if (_ConstructOption(str, option) == false) {
00345       _options.clear();
00346       _number_options = 0;
00347       if (VIDEO_DEBUG)
00348         cerr << "VIDEO ERROR: OptionBox::SetOptions() failed due to an invalid format string: "
00349           << MakeStandardString(*i) << endl;
00350       return false;
00351     }
00352 
00353     _options.push_back(option);
00354 
00355     _number_options++;
00356     i++;
00357   }
00358 
00359   return true;
00360 }
00361 
00362 
00363 
00364 bool OptionBox::AddOption(const hoa_utils::ustring &text) {
00365   Option option;
00366 
00367   // Construct the option 
00368   if (_ConstructOption(text, option) == false) {
00369     return false;
00370   }
00371 
00372   _options.push_back(option);
00373   _number_options++;
00374   return true;
00375 }
00376 
00377 
00378 
00379 bool OptionBox::SetOptionText(int32 index, const hoa_utils::ustring &text) {
00380   if (index < 0 || index >= _number_options) {
00381     if (VIDEO_DEBUG)
00382       cerr << "VIDEO WARNING: OptionBox::SetOptionText() failed because it was given an invalid index: " << index << endl;
00383     return false;
00384   }
00385 
00386   _ConstructOption(text, _options[index]);
00387   return true;
00388 }
00389 
00390 
00391 
00392 void OptionBox::SetSelection(int32 index) {
00393   if (index < 0 || index >= _number_options) {
00394     if (VIDEO_DEBUG)
00395       cerr << "VIDEO WARNING: OptionBox::SetSelection() failed because it was passed an invalid index: "
00396         << index << endl;
00397     return;
00398   }
00399   _selection = index;
00400 
00401   int32 select_row = _selection / _number_columns;
00402 
00403   // If the new selection isn't currently being displayed, instantly scroll to it
00404   if (select_row < _scroll_offset || select_row > _scroll_offset + _number_rows - 1) {
00405     _scroll_offset = select_row - _number_rows + 1;
00406 
00407     int32 total_num_rows = (_number_options + _number_columns - 1) / _number_columns;
00408 
00409     if (_scroll_offset + _number_rows >= total_num_rows) {
00410       _scroll_offset = total_num_rows - _number_rows;
00411     }
00412   }
00413 }
00414 
00415 
00416 
00417 void OptionBox::EnableOption(int32 index, bool enable) {
00418   if (index < 0 || index >= _number_options) {
00419     if (VIDEO_DEBUG)
00420       cerr << "VIDEO WARNING: OptionBox::EnableOption() failed because an invalid "
00421         << "option index was specified: " << index << endl;
00422     return;
00423   }
00424 
00425   _options[index].disabled = !enable;
00426 }
00427 
00428 
00429 
00430 bool OptionBox::IsInitialized(string& error_messages) {
00431   ostringstream s;
00432   error_messages.clear();
00433 
00434   if (_number_rows <= 0)
00435     s << "* Invalid number of rows (" << _number_rows << ")" << endl;
00436 
00437   if (_number_columns <= 0)
00438     s << "* Invalid number of columns (" << _number_columns << ")" << endl;
00439 
00440   if (_horizontal_spacing <= 0.0f && _number_columns > 1)
00441     s << "* Invalid horizontal spacing (" << _horizontal_spacing << ")" << endl;
00442 
00443   if (_vertical_spacing <= 0.0f && _number_rows > 1)
00444     s << "* Invalid vertical spacing (" << _vertical_spacing << ")" << endl;
00445 
00446   if (_option_xalign < VIDEO_X_LEFT || _option_xalign > VIDEO_X_RIGHT)
00447     s << "* Invalid x align (" << _option_xalign << ")" << endl;
00448 
00449   if (_option_yalign < VIDEO_Y_TOP || _option_yalign > VIDEO_Y_BOTTOM)
00450     s << "* Invalid y align (" << _option_yalign << ")" << endl;
00451 
00452   if (_font.empty())
00453     s << "* Invalid font (none has been set)" << endl;
00454 
00455   if (_selection_mode <= VIDEO_SELECT_INVALID || _selection_mode >= VIDEO_SELECT_TOTAL)
00456     s << "* Invalid selection mode (" << _selection_mode << ")" << endl;
00457 
00458   error_messages = s.str();
00459 
00460   if (error_messages.empty())
00461     _initialized = true;
00462   else
00463     _initialized = false;
00464 
00465   return _initialized;
00466 }
00467 
00468 // -----------------------------------------------------------------------------
00469 // Input Handling Methods
00470 // -----------------------------------------------------------------------------
00471 
00472 void OptionBox::HandleUpKey() {
00473   // Ignore input while scrolling, or if an event has already been logged
00474   if (_scrolling || _event)
00475     return;
00476 
00477   if (_ChangeSelection(-1, false) == false)
00478     _event = VIDEO_OPTION_BOUNDS_UP;
00479 }
00480 
00481 
00482 
00483 void OptionBox::HandleDownKey() {
00484   // Ignore input while scrolling, or if an event has already been logged
00485   if (_scrolling || _event)
00486     return;
00487 
00488   if(_ChangeSelection(1, false) == false)
00489     _event = VIDEO_OPTION_BOUNDS_DOWN;
00490 }
00491 
00492 
00493 
00494 void OptionBox::HandleLeftKey() {
00495   // Ignore input while scrolling, or if an event has already been logged
00496   if (_scrolling || _event)
00497     return;
00498 
00499   if (_ChangeSelection(-1, true) == false)
00500     _event = VIDEO_OPTION_BOUNDS_LEFT;
00501 }
00502 
00503 
00504 
00505 void OptionBox::HandleRightKey() {
00506   // Ignore input while scrolling, or if an event has already been logged
00507   if (_scrolling || _event)
00508     return;
00509 
00510 
00511   if (_ChangeSelection(1, true) == false)
00512     _event = VIDEO_OPTION_BOUNDS_RIGHT;
00513 }
00514 
00515 
00516 
00517 void OptionBox::HandleConfirmKey() {
00518   // Ignore input while scrolling, or if an event has already been logged
00519   if (_scrolling || _event)
00520     return;
00521 
00522   // Abort if an invalid option is selected
00523   if (_selection < 0 || _selection >= _number_options) {
00524     if (VIDEO_DEBUG)
00525       cerr << "VIDEO WARNING: In OptionBox::HandleConfirmKey(), an invalid (out of bounds) option "
00526         << "was selected: " << _selection << endl;
00527     return;
00528   }
00529 
00530   // Case #1: switch the position of two different options
00531   if (_switching && _first_selection >= 0 && _selection != _first_selection) {
00532     // Switch the location of the two selected options
00533     Option temp = _options[_selection];
00534     _options[_selection] = _options[_first_selection];
00535     _options[_first_selection] = temp;
00536     // Set _first_selection to -1, so that we know we're not in switching mode any more
00537     _first_selection = -1;
00538 
00539     _event = VIDEO_OPTION_SWITCH;
00540   }
00541 
00542   // Case #2: partial confirm (confirming the first element in a double confirm)
00543   else if (_selection_mode == VIDEO_SELECT_DOUBLE && _first_selection == -1) {
00544     // mark the item that is getting switched
00545     _first_selection = _selection;
00546   }
00547 
00548   // Case #3: confirm
00549   else {
00550     if (_options[_selection].disabled) {
00551       // TODO: do something to tell player they confirmed on a disabled option
00552       return;
00553     }
00554 
00555     _event = VIDEO_OPTION_CONFIRM;
00556 
00557     // Get out of switch mode
00558     _first_selection = -1;
00559   }
00560 }
00561 
00562 
00563 
00564 void OptionBox::HandleCancelKey() {
00565   // Ignore input while scrolling, or if an event has already been logged
00566   if (_scrolling || _event)
00567     return;
00568 
00569   // If we're in switch mode and the cancel key is hit, get out of switch mode.
00570   if (_first_selection >= 0)
00571     _first_selection = -1;
00572   else
00573     _event = VIDEO_OPTION_CANCEL;
00574 }
00575 
00576 // -----------------------------------------------------------------------------
00577 // Member Access Functions
00578 // -----------------------------------------------------------------------------
00579 
00580 void OptionBox::SetFont(const std::string& font_name) {
00581   if (VideoManager->GetFontProperties(font_name) == NULL) {
00582     if(VIDEO_DEBUG)
00583       cerr << "VIDEO WARNING: OptionBox::SetFont() failed because GameVideo::GetFontProperties() returned false for font: " << font_name << endl;
00584     return;
00585   }
00586 
00587   _font = font_name;
00588   _initialized = IsInitialized(_initialization_errors);
00589 }
00590 
00591 
00592 
00593 void OptionBox::SetCursorState(CursorState state) {
00594   if (state <= VIDEO_CURSOR_STATE_INVALID || state >= VIDEO_CURSOR_STATE_TOTAL) {
00595     if (VIDEO_DEBUG)
00596       cerr << "VIDEO WARNING: OptionBox::SetCursorState() failed because the argument passed was invalid: "
00597         << state << endl;
00598     return;
00599   }
00600 
00601   _cursor_state = state;
00602 }
00603 
00604 // -----------------------------------------------------------------------------
00605 // Private Methods
00606 // -----------------------------------------------------------------------------
00607 
00608 bool OptionBox::_ConstructOption(const ustring& format_string, Option& op) {
00609   // Options are enabled by default
00610   op.disabled = false;
00611 
00612   // Clear all vectors, to make certain that the Option passed in is empty
00613   op.elements.clear();
00614   op.text.clear();
00615   op.images.clear();
00616 
00617   // This is a valid case. It simply means we add an option with no tags, text, or other data.
00618   if (format_string.empty()) {
00619     return true;
00620   }
00621 
00622   // Copy the format_string into a temporary string that we can manipulate
00623   ustring tmp = format_string;
00624 
00625   while (tmp.empty() == false) {
00626     OptionElement new_element;
00627 
00628     if (tmp[0] == OPEN_TAG) { // Process a new tag
00629       size_t length = tmp.length();
00630 
00631       if (length < 3) {
00632         // All formatting tags are at least 3 characters long because you need the opening (<)
00633         // and close (>) plus stuff in the middle. So anything less than 3 characters is a problem.
00634 
00635         if (VIDEO_DEBUG)
00636           cerr << "VIDEO ERROR: OptionBox::_ConstructOption() failed because a tag opening was detected "
00637             << "with an inadequate number of remaining characters to construct a full tag: "
00638             << MakeStandardString(format_string) << endl;
00639         return false;
00640       }
00641 
00642       size_t end_position = tmp.find(END_TAG);
00643 
00644       if (end_position == ustring::npos) { // Did not find the end of the tag
00645         if (VIDEO_DEBUG)
00646           cerr << "VIDEO ERROR: OptionBox::_ConstructOption() failed because a matching end tag could not "
00647             << "be found for an open tag: " << MakeStandardString(format_string) << endl;
00648         return false;
00649       }
00650 
00651       if (tmp[2] == END_TAG) { // First check if the tag is a 1-character alignment tag
00652         if (tmp[1] == CENTER_TAG1 || tmp[1] == CENTER_TAG2) {
00653           new_element.type = VIDEO_OPTION_ELEMENT_CENTER_ALIGN;
00654         }
00655         else if (tmp[1] == RIGHT_TAG1 || tmp[1] == RIGHT_TAG2) {
00656           new_element.type = VIDEO_OPTION_ELEMENT_RIGHT_ALIGN;
00657         }
00658         else if (tmp[1] == LEFT_TAG1 || tmp[1] == LEFT_TAG2) {
00659           new_element.type = VIDEO_OPTION_ELEMENT_LEFT_ALIGN;
00660         }
00661       }
00662       else { // The tag contains more than 1-character
00663         // Extract the tag string 
00664         string tag_text = MakeStandardString(tmp.substr(1, end_position - 1));
00665         
00666         if (IsStringNumeric(tag_text)) { // Then this must be a positioning tag
00667           new_element.type  = VIDEO_OPTION_ELEMENT_POSITION;
00668           new_element.value = atoi(tag_text.c_str());
00669         }
00670         else { // Then this must be an image tag
00671           StillImage imd;
00672           imd.SetFilename(tag_text);
00673 
00674           if (VideoManager->LoadImage(imd) == false) {
00675             if (VIDEO_DEBUG)
00676               cerr << "VIDEO ERROR: OptionBox::_ConstructOption failed because of an invalid image tag: "
00677                 << MakeStandardString(format_string) << endl;
00678             return false;
00679           }
00680           new_element.type  = VIDEO_OPTION_ELEMENT_IMAGE;
00681           new_element.value = static_cast<int32> (op.images.size());
00682           op.images.push_back(imd);
00683         }
00684       }
00685 
00686       // Finished processing the tag so update the tmp string
00687       if (end_position == length - 1) { // End of string
00688         tmp.clear();
00689       }
00690       else {
00691         tmp = tmp.substr(end_position + 1, length - end_position - 1);
00692       }
00693     } // if (tmp[0] == OPEN_TAG)
00694 
00695     else { // If this isn't a tag, then it is raw text that should be added to the option
00696       new_element.type = VIDEO_OPTION_ELEMENT_TEXT;
00697       new_element.value = static_cast<int32>(op.text.size());
00698 
00699       // find the distance until the next tag
00700       size_t tag_begin = tmp.find(OPEN_TAG);
00701 
00702       if (tag_begin == ustring::npos) { // There are no more tags remaining, so extract the entire string
00703         op.text.push_back(tmp);
00704         tmp.clear();
00705       }
00706       else { // Another tag remains to be processed, so extract the text substring
00707         op.text.push_back(tmp.substr(0, tag_begin));
00708         tmp = tmp.substr(tag_begin, tmp.length() - tag_begin);
00709       }
00710     }
00711 
00712     op.elements.push_back(new_element);
00713   } // while (tmp.empty() == false)
00714 
00715   return true;
00716 } // bool _ConstructOption(const ustring& format_string, Option& option)
00717 
00718 
00719 
00720 bool OptionBox::_ChangeSelection(int32 offset, bool horizontal) {
00721   // Do nothing if the movement is horizontal and there is only one column with no horizontal wrap shifting
00722   if (horizontal == true && _number_columns == 1 && _horizontal_wrap_mode != VIDEO_WRAP_MODE_SHIFTED)
00723     return false;
00724   // Do nothing if the movement is vertical and there is only one row with no vertical wrap shifting
00725   if (horizontal == false && _number_rows == 1 && _vertical_wrap_mode != VIDEO_WRAP_MODE_SHIFTED)
00726     return false;
00727 
00728   // Get the row, column coordinates for the current selection
00729   int32 row = _selection / _number_columns;
00730   int32 col = _selection % _number_columns;
00731   bool bounds_exceeded = false;
00732 
00733   // Determine if the movement selection will exceed a column or row bondary
00734   if ((horizontal == true && ((col + offset < 0) || (col + offset >= _number_columns))) ||
00735     (horizontal == false && ((row + offset < 0) || (row + offset >= _number_rows))))
00736   {
00737     bounds_exceeded = true;
00738   }
00739 
00740   // Case #1: movement selection is within bounds
00741   if (bounds_exceeded == false) {
00742     if (horizontal)
00743       _selection += offset;
00744     else
00745       _selection += (offset * _number_columns);
00746   }
00747 
00748   // Case #2: movement exceeds bounds, no wrapping enabled
00749   else if ((horizontal == true && _horizontal_wrap_mode == VIDEO_WRAP_MODE_NONE) ||
00750     (horizontal == false && _vertical_wrap_mode == VIDEO_WRAP_MODE_NONE))
00751   {
00752     return false;
00753   }
00754 
00755   // Case #3: horizontal movement with wrapping enabled
00756   else if (horizontal == true) {
00757     if (col + offset < 0) { // The left boundary was exceeded
00758       if (_horizontal_wrap_mode == VIDEO_WRAP_MODE_STRAIGHT)
00759         offset += _number_columns;
00760       else if (_horizontal_wrap_mode == VIDEO_WRAP_MODE_SHIFTED) {
00761         if (_vertical_wrap_mode != VIDEO_WRAP_MODE_NONE) // Make sure vertical wrapping is accepted
00762           offset += _number_options;
00763         else
00764           return false;
00765       }
00766     }
00767     else { // The right boundary was exceeded
00768       if (_horizontal_wrap_mode == VIDEO_WRAP_MODE_STRAIGHT)
00769         offset -= _number_columns;
00770       else if (_horizontal_wrap_mode == VIDEO_WRAP_MODE_SHIFTED) {
00771         if (_vertical_wrap_mode != VIDEO_WRAP_MODE_NONE) // Make sure vertical wrapping is accepted
00772           offset -= _number_options;
00773         else
00774           return false;
00775       }
00776     }
00777     _selection = (_selection + offset) % _number_options;
00778   }
00779   
00780   // Case #4: vertical movement with wrapping enabled
00781   else {
00782     if (row + offset < 0) { // The top boundary was exceeded
00783       if (_vertical_wrap_mode == VIDEO_WRAP_MODE_STRAIGHT)
00784         offset += _number_options;
00785       else if (_vertical_wrap_mode == VIDEO_WRAP_MODE_SHIFTED) {
00786         if (_horizontal_wrap_mode != VIDEO_WRAP_MODE_NONE) // Make sure horizontal wrapping is accepted
00787           offset += (_number_columns - 1);
00788         else
00789           return false;
00790       }
00791     }
00792     else  { // The bottom boundary was exceeded
00793       if (_vertical_wrap_mode == VIDEO_WRAP_MODE_STRAIGHT)
00794         offset -= _number_options;
00795       else if (_vertical_wrap_mode == VIDEO_WRAP_MODE_SHIFTED) {
00796         if (_horizontal_wrap_mode != VIDEO_WRAP_MODE_NONE) // Make sure horizontal wrapping is accepted
00797           offset -= (_number_columns - 1);
00798         else
00799           return false;
00800       }
00801     }
00802     _selection = (_selection + (offset * _number_columns)) % _number_options;
00803   }
00804 
00805   // If the new selection isn't currently being displayed, scroll it into view
00806   row = _selection / _number_columns;
00807   if (row < _scroll_offset || row > _scroll_offset + _number_rows - 1) {
00808     _scrolling = true;
00809     _scroll_time = 0;
00810 
00811     if (row < _scroll_offset)
00812       _scroll_direction = -1; // scroll up
00813     else
00814       _scroll_direction = 1; // scroll down
00815 
00816     _scroll_offset += _scroll_direction;
00817   }
00818 
00819   _event = VIDEO_OPTION_SELECTION_CHANGE;
00820 
00821   return true;
00822 } // bool OptionBox::_ChangeSelection(int32 offset, bool horizontal)
00823 
00824 
00825 
00826 void OptionBox::_SetupAlignment(int32 xalign, int32 yalign, const OptionCellBounds& bounds, float& x, float& y) {
00827   VideoManager->SetDrawFlags(xalign, yalign, 0);
00828 
00829   switch (xalign) {
00830     case VIDEO_X_LEFT:
00831       x = bounds.x_left;
00832       break;
00833     case VIDEO_X_CENTER:
00834       x = bounds.x_center;
00835       break;
00836     default:
00837       x = bounds.x_right;
00838       break;
00839   }
00840 
00841   switch(yalign) {
00842     case VIDEO_Y_TOP:
00843       y = bounds.y_top;
00844       break;
00845     case VIDEO_Y_CENTER:
00846       y = bounds.y_center;
00847       break;
00848     default:
00849       y = bounds.y_bottom;
00850       break;
00851   }
00852 
00853   VideoManager->Move(x, y);
00854 } // void OptionBox::_SetupAlignment(int32 xalign, int32 yalign, const OptionCellBounds& bounds, float& x, float& y)
00855 
00856 } // namespace hoa_video

Generated on Fri Jul 6 23:11:20 2007 for Hero of Allacrost by  doxygen 1.5.1