00001 #include "glwx.h"
00002
00003 GUIPanel::GUIPanel(const std::string &cbs) : GUIRectangle(cbs), GUIClippedRectangle()
00004 {
00005 setInterval(4, 4);
00006 widgetType = WT_PANEL;
00007 layout = PL_FREE_LAYOUT;
00008 }
00009
00010 bool GUIPanel::loadXMLSettings(const char *stackPath)
00011 {
00012 std::string xmlFile = MediaPathManager::lookUpMediaPath(stackPath);
00013 bool result = false;
00014
00015 if(!xmlFile.size())
00016 return Logger::writeErrorLog("Failed to locate the XML GUI file");
00017
00018 TiXmlDocument cfgStack(xmlFile);
00019
00020 if(!cfgStack.LoadFile())
00021 return Logger::writeErrorLog("Invalid XML GUI description file");
00022
00023 result = loadXMLSettings(cfgStack.FirstChildElement());
00024 forceUpdate(true);
00025 return result;
00026 }
00027
00028 bool GUIPanel::loadXMLSettings(const TiXmlElement *element)
00029 {
00030 if(!XMLArbiter::inspectElementInfo(element, "Panel"))
00031 return Logger::writeErrorLog("Need a Panel node in the xml file");
00032
00033 const char *description = element->Attribute("description");
00034 std::string type = element->Attribute("layout") ? element->Attribute("layout") : "UNKNOWN";
00035
00036 if(description)
00037 return loadXMLSettings(description);
00038
00039 layout = (type == "CEN_YAXIS") ? PL_YAXIS_CEN_LAYOUT :
00040 (type == "YAXIS" ) ? PL_YAXIS_LAYOUT :
00041 (type == "XAXIS" ) ? PL_XAXIS_LAYOUT :
00042 (type == "GRID" ) ? PL_GRID_LAYOUT : PL_FREE_LAYOUT;
00043
00044 for(const TiXmlElement *child = element->FirstChildElement();
00045 child;
00046 child = child->NextSiblingElement() )
00047 {
00048 std::string childName = child->Value();
00049
00050 if(!childName.size())
00051 continue;
00052
00053 if(childName == "CheckBox")
00054 {
00055 GUICheckBox *newCheckBox = new GUICheckBox();
00056 if(!newCheckBox->loadXMLSettings(child) || !addWidget(newCheckBox))
00057 deleteObject(newCheckBox);
00058 continue;
00059 }
00060
00061 if(childName == "TabbedPanel")
00062 {
00063 GUITabbedPanel *newTabbedPanel = new GUITabbedPanel();
00064 if(!newTabbedPanel->loadXMLSettings(child) || !addWidget(newTabbedPanel))
00065 deleteObject(newTabbedPanel);
00066 continue;
00067 }
00068
00069 if(childName == "RadioButton")
00070 {
00071 GUIRadioButton *newRadioButton = new GUIRadioButton();
00072 if(!newRadioButton->loadXMLSettings(child) || !addWidget(newRadioButton))
00073 {
00074 deleteObject(newRadioButton);
00075 }
00076 else
00077 {
00078 if(newRadioButton->isChecked())
00079 notify(newRadioButton);
00080 }
00081 continue;
00082 }
00083
00084 if(childName == "ComboBox")
00085 {
00086 GUIComboBox *newComboBox = new GUIComboBox();
00087 if(!newComboBox->loadXMLSettings(child) || !addWidget(newComboBox))
00088 deleteObject(newComboBox);
00089 continue;
00090 }
00091
00092 if(childName == "TextBox")
00093 {
00094 GUITextBox *newTextBox = new GUITextBox();
00095 if(!newTextBox->loadXMLSettings(child) || !addWidget(newTextBox))
00096 deleteObject(newTextBox);
00097 continue;
00098 }
00099
00100 if(childName == "Slider")
00101 {
00102 GUISlider *newSlider = new GUISlider();
00103 if(!newSlider->loadXMLSettings(child) || !addWidget(newSlider))
00104 deleteObject(newSlider);
00105 continue;
00106 }
00107
00108 if(childName == "Separator")
00109 {
00110 GUISeparator *newSeparator = new GUISeparator();
00111 if((layout != PL_YAXIS_LAYOUT &&
00112 layout != PL_XAXIS_LAYOUT &&
00113 layout != PL_YAXIS_CEN_LAYOUT) ||
00114 (!newSeparator->loadXMLSettings(child)))
00115 {
00116 deleteObject(newSeparator);
00117 }
00118 else
00119 {
00120 newSeparator->setParent(this);
00121 newSeparator->setOrientation((layout != PL_YAXIS_LAYOUT && layout != PL_YAXIS_CEN_LAYOUT));
00122 elements.push_back(newSeparator);
00123 }
00124 continue;
00125 }
00126
00127 if(childName == "Button")
00128 {
00129 GUIButton *newButton = new GUIButton();
00130 if(!newButton->loadXMLSettings(child) || !addWidget(newButton))
00131 deleteObject(newButton);
00132 continue;
00133 }
00134
00135 if(childName == "Label")
00136 {
00137 GUILabel *newLabel = new GUILabel();
00138 if(!newLabel->loadXMLSettings(child) || !addWidget(newLabel))
00139 deleteObject(newLabel);
00140 continue;
00141 }
00142
00143
00144 if(childName == "Interval")
00145 setInterval(XMLArbiter::fillComponents2i(child, interval));
00146
00147 if(childName == "Panel")
00148 {
00149 GUIPanel *panel = new GUIPanel();
00150 if(!panel->loadXMLSettings(child) || !addWidget(panel))
00151 deleteObject(panel);
00152 continue;
00153 }
00154 }
00155
00156 return GUIRectangle::loadXMLSettings(element) &&
00157 GUIClippedRectangle::loadXMLClippedRectangleInfo(element);
00158 }
00159
00160 GUIRectangle *GUIPanel::getWidgetByCallbackString(const std::string &callbackString)
00161 {
00162 if(!callbackString.size())
00163 return NULL;
00164
00165 GUIRectangle *element = NULL,
00166 *tPanel = NULL;
00167
00168 size_t t = 0;
00169
00170 for(t = 0; t < elements.size(); t++)
00171 {
00172 if(elements[t]->getCallbackString() == callbackString)
00173 return elements[t];
00174 }
00175
00176 for(t = 0; t < elements.size(); t++)
00177 {
00178 if(elements[t]->getWidgetType() == WT_PANEL)
00179 if(element = ((GUIPanel*)elements[t])->getWidgetByCallbackString(callbackString))
00180 break;
00181
00182 if(elements[t]->getWidgetType() == WT_TABBED_PANEL)
00183 if(element = ((GUITabbedPanel*)elements[t])->getLowerPanel()->getWidgetByCallbackString(callbackString))
00184 break;
00185 }
00186 return element;
00187 }
00188
00189 void GUIPanel::checkMouseEvents(MouseEvent &evt, int extraInfo, bool infoBits)
00190 {
00191 if(visible && active)
00192 {
00193 GUIRectangle::checkMouseEvents(evt, extraInfo, infoBits);
00194 for(size_t t = 0; t < elements.size(); t++)
00195 {
00196 if(elements[t]->isActive())
00197 elements[t]->checkMouseEvents(evt, extraInfo, infoBits);
00198 }
00199 }
00200 }
00201 void GUIPanel::checkKeyboardEvents(KeyEvent &evt, int extraInfo)
00202 {
00203 if(visible && active)
00204 {
00205 GUIRectangle::checkKeyboardEvents(evt, extraInfo);
00206 for(size_t t = 0; t < elements.size(); t++)
00207 if(elements[t]->isActive())
00208 elements[t]->checkKeyboardEvents(evt, extraInfo);
00209 }
00210 }
00211
00212 void GUIPanel::render(float tick)
00213 {
00214 if(!isAttached() || !parent)
00215 return;
00216
00217 Widgets comboBoxes;
00218 GUIComboBox *cbPTR;
00219
00220 if(visible)
00221 {
00222 renderClippedBounds();
00223 for(size_t t = 0; t < elements.size(); t++)
00224 if(elements[t]->getWidgetType() != WT_COMBO_BOX)
00225 elements[t]->render(tick);
00226 else
00227 {
00228 cbPTR = (GUIComboBox*)elements[t];
00229 if(!cbPTR->isDeployed())
00230 cbPTR->render(tick);
00231 else
00232 comboBoxes.push_back(elements[t]);
00233 }
00234
00235 for(size_t t = 0; t < comboBoxes.size(); t++)
00236 comboBoxes[t]->render(tick);
00237 }
00238 }
00239
00240 void GUIPanel::collectZWidgets(ZWidgets &container)
00241 {
00242 if(visible)
00243 {
00244 for(size_t t = 0; t < elements.size(); t++)
00245 if(elements[t]->getWidgetType() != WT_PANEL)
00246 {
00247 ZWidget zWidget(elements[t]);
00248 zWidget.setDistance(float(elements[t]->getZCoordinate()));
00249 container.push_back(zWidget);
00250 }
00251 else
00252 {
00253 ((GUIPanel*)elements[t])->collectZWidgets(container);
00254 }
00255
00256 ZWidget zWidget(this);
00257 zWidget.setDistance(float(getZCoordinate()));
00258
00259 container.push_back(zWidget);
00260 }
00261 }
00262
00263 void GUIPanel::pack()
00264 {
00265 if(!update)
00266 return;
00267
00268 size_t t = 0;
00269
00270 for(t = 0; t < elements.size(); t++)
00271 elements[t]->forceUpdate(update);
00272
00273 if(!t)
00274 {
00275 correctPosition();
00276 return;
00277 }
00278
00279 switch(layout)
00280 {
00281 case PL_YAXIS_LAYOUT:
00282 case PL_YAXIS_CEN_LAYOUT:
00283 packYAxisLayout();
00284 break;
00285 case PL_XAXIS_LAYOUT:
00286 packXAxisLayout();
00287 break;
00288 default: packFreeLayout();
00289 }
00290
00291 for(t = 0; t < elements.size(); t++)
00292 elements[t]->forceUpdate(update);
00293 }
00294
00295 void GUIPanel::forceUpdate(bool updateArg)
00296 {
00297 update = updateArg;
00298 pack();
00299 }
00300
00301 void GUIPanel::packYAxisLayout()
00302 {
00303 computeWindowBounds();
00304
00305 std::vector<int> childrenHeights,
00306 childrenWidths;
00307
00308 size_t t = 0;
00309 int height = 0,
00310 xOffset = 0,
00311 panelWidth = getWidth();
00312
00313 for(t = 0; t < elements.size(); t++)
00314 {
00315 const Tuple4i &childBounds = elements[t]->getWindowBounds();
00316 childrenHeights.push_back(childBounds.w - childBounds.y + interval.y);
00317 childrenWidths.push_back(childBounds.z - childBounds.x);
00318 height += childrenHeights[t];
00319 panelWidth = childrenWidths[t] > panelWidth ? childrenWidths[t] : panelWidth;
00320 }
00321
00322 dimensions.set(float(panelWidth), float(height));
00323 GUIRectangle::computeWindowBounds();
00324
00325 windowBounds.z += interval.x*2;
00326 windowBounds.w += interval.y;
00327
00328 update = false;
00329 height = interval.y;
00330
00331 correctPosition();
00332 computeClippedBounds(windowBounds);
00333
00334 for(t = 0; t < elements.size(); t++)
00335 {
00336 xOffset = (layout == PL_YAXIS_CEN_LAYOUT) * (panelWidth - childrenWidths[t])/2;
00337
00338 elements[t]->setAnchorPoint(AT_CORNERLU);
00339 elements[t]->setPosition(float(interval.x + xOffset), float(height));
00340 elements[t]->computeWindowBounds();
00341 height += childrenHeights[t];
00342 }
00343 }
00344
00345 void GUIPanel::packXAxisLayout()
00346 {
00347 computeWindowBounds();
00348
00349 std::vector<int> childrenWidths,
00350 childrenHeights;
00351 float offset = 0;
00352 size_t t = 0;
00353 int height = 0,
00354 width = 0,
00355 panelHeight = windowBounds.w - windowBounds.y;
00356
00357 for(t = 0; t < elements.size(); t++)
00358 {
00359 const Tuple4i &childBounds = elements[t]->getWindowBounds();
00360 childrenHeights.push_back(childBounds.w - childBounds.y);
00361 childrenWidths.push_back (childBounds.z - childBounds.x + interval.x);
00362
00363 width += childrenWidths[t];
00364 height = childBounds.w - childBounds.y;
00365 panelHeight = height > panelHeight ? height : panelHeight;
00366 }
00367
00368 dimensions.set(float(width), float(panelHeight));
00369 GUIRectangle::computeWindowBounds();
00370
00371 windowBounds.z += interval.x;
00372 windowBounds.w += interval.y*2;
00373
00374 update = false;
00375 width = interval.x;
00376
00377 correctPosition();
00378 computeClippedBounds(windowBounds);
00379
00380 for(t = 0; t < elements.size(); t++)
00381 {
00382 offset = clamp(float(panelHeight - childrenHeights[t])/2.0f + interval.y, 0.0f, 1000.0f);
00383 elements[t]->setAnchorPoint(AT_CORNERLU);
00384 elements[t]->setPosition(float(width), offset);
00385 elements[t]->computeWindowBounds();
00386 width += childrenWidths[t];
00387 }
00388 }
00389
00390 void GUIPanel::packFreeLayout()
00391 {
00392 if(!update || !parent)
00393 return;
00394
00395 Tuple4i newBounds = getWindowBounds();
00396 size_t t = 0;
00397 int temp1 = 0,
00398 temp2 = 0;
00399
00400 for(t = 0; t < elements.size(); t++)
00401 {
00402 elements[t]->forceUpdate(update);
00403 const Tuple4i &childBounds = elements[t]->getWindowBounds();
00404
00405 newBounds.x = (childBounds.x - clipSize) < newBounds.x ?
00406 childBounds.x - clipSize : newBounds.x;
00407 newBounds.y = (childBounds.y - clipSize) < newBounds.y ?
00408 childBounds.y - clipSize : newBounds.y;
00409 newBounds.z = (childBounds.z + clipSize) > newBounds.z ?
00410 childBounds.z + clipSize: newBounds.z;
00411 newBounds.w = (childBounds.w + clipSize) > newBounds.w ?
00412 childBounds.w + clipSize : newBounds.w;
00413 }
00414
00415 windowBounds = newBounds;
00416 update = false;
00417
00418 correctPosition();
00419 computeClippedBounds(windowBounds);
00420
00421 for(t = 0; t < elements.size(); t++)
00422 elements[t]->computeWindowBounds();
00423 }
00424
00425 void GUIPanel::correctPosition()
00426 {
00427 if(!parent)
00428 return;
00429
00430 const Tuple4i& parentBounds = parent->getWindowBounds();
00431 bool update = false;
00432 int temp = windowBounds.z - windowBounds.x;
00433
00434 if(position.x < 0)
00435 if(parentBounds.z - windowBounds.z < abs(position.x))
00436 {
00437 windowBounds.z = parentBounds.z + int(position.x);
00438 windowBounds.x = windowBounds.z - temp;
00439 update = true;
00440 }
00441
00442 if(position.x > 1)
00443 if(windowBounds.x < position.x + parentBounds.x)
00444 {
00445 windowBounds.x = parentBounds.x + int(position.x);
00446 windowBounds.z = windowBounds.x + temp;
00447 update = true;
00448 }
00449
00450 if(position.y < 0)
00451 if(parentBounds.w - windowBounds.w < abs(position.y))
00452 {
00453 temp = windowBounds.w - windowBounds.y;
00454 windowBounds.w = parentBounds.w + int(position.y);
00455 windowBounds.y = windowBounds.w - temp;
00456 update = true;
00457 }
00458
00459 if(update)
00460 for(size_t t = 0; t < elements.size(); t++)
00461 {
00462 elements[t]->forceUpdate(true);
00463 elements[t]->computeWindowBounds();
00464 }
00465 }
00466
00467 bool GUIPanel::addWidget(GUIRectangle *element)
00468 {
00469 if(element)
00470 {
00471 for(size_t t = 0; t < elements.size(); t++)
00472 if(elements[t]->getCallbackString() == element->getCallbackString())
00473 return Logger::writeErrorLog(std::string("Panel already has a child with CBS -> ")
00474 + element->getCallbackString());
00475 elements.push_back(element);
00476 element->setParent(this);
00477 return true;
00478 }
00479 return false;
00480 }
00481
00482 void GUIPanel::clear()
00483 {
00484 parent = NULL;
00485
00486 for(size_t t = 0; t < elements.size(); t++)
00487 deleteObject(elements[t]);
00488
00489 elements.clear();
00490 }
00491
00492 void GUIPanel::notify(GUIRectangle *element)
00493 {
00494 if(!element)
00495 return;
00496
00497 switch(element->getWidgetType())
00498 {
00499 case WT_RADIO_BUTTON:
00500 for(size_t t = 0; t < elements.size(); t++)
00501 if(elements[t]->getWidgetType() == WT_RADIO_BUTTON &&
00502 elements[t]!= element)
00503 {
00504 GUIRadioButton *rButton = (GUIRadioButton*)elements[t];
00505 rButton->setChecked(false);
00506 }
00507 break;
00508 }
00509 }
00510
00511 int GUIPanel::getWidgetCountByType(int type)
00512 {
00513 int counter = 0;
00514
00515 for(size_t t = 0; t < elements.size(); t++)
00516 if(elements[t]->getWidgetType() == type)
00517 counter++;
00518
00519 return counter;
00520 }
00521
00522 int GUIPanel::getTreeHeight()
00523 {
00524 int height = 1;
00525
00526 for(size_t t = 0; t < elements.size(); t++)
00527 if(elements[t]->getWidgetType() == WT_PANEL)
00528 height += ((GUIPanel*)elements[t])->getTreeHeight();
00529 return height;
00530 }
00531
00532 void GUIPanel::setInterval(const Tuple2i &dimensions)
00533 {
00534 setInterval(dimensions.x, dimensions.y);
00535 }
00536
00537 void GUIPanel::setInterval(int width, int height)
00538 {
00539 interval.set(clamp(width , 0, 2500),
00540 clamp(height, 0, 2500));
00541 }
00542
00543 const Tuple2i &GUIPanel::getInterval()
00544 {
00545 return interval;
00546 }
00547
00548 void GUIPanel::setLayout(int layoutArg)
00549 {
00550 switch(layoutArg)
00551 {
00552 case PL_GRID_LAYOUT:
00553 case PL_YAXIS_CEN_LAYOUT:
00554 case PL_YAXIS_LAYOUT:
00555 case PL_XAXIS_LAYOUT:
00556 layout = layoutArg;
00557 break;
00558 default: layout = PL_FREE_LAYOUT;
00559 }
00560 }
00561
00562 int GUIPanel::getLayout()
00563 {
00564 return layout;
00565 }
00566
00567 Widgets &GUIPanel::getWidgets()
00568 {
00569 return elements;
00570 }
00571
00572 GUIPanel::~GUIPanel()
00573 {
00574 clear();
00575 }
00576