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