// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // ------------------------------------------------------------------------------------------------ #include "stdpch.h" #include "interface_manager.h" #include "interface_expr.h" #include "group_menu.h" #include "game_share/xml_auto_ptr.h" #include "view_bitmap.h" #include "action_handler.h" // Just for getAllParams #include "lua_ihm.h" #include "nel/misc/i18n.h" using namespace NLMISC; using namespace std; static const std::string ID_MENU_CHECKBOX = "menu_cb"; static const std::string ID_MENU_SEPARATOR = "menu_separator"; static const std::string ID_MENU_SUBMENU = "menu_sb"; static const uint MENU_WIDGET_X = 2; static const uint LEFT_MENU_WIDGET_X = 4; // ------------------------------------------------------------------------------------------------ // CGroupSubMenu // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ bool CViewTextMenu::getGrayed() const { return _Grayed; } // ------------------------------------------------------------------------------------------------ void CViewTextMenu::setGrayed (bool g) { _Grayed = g; } // ------------------------------------------------------------------------------------------------ void CViewTextMenu::setCheckable(bool c) { if (!c) { _Checkable = false; _CheckBox = NULL; } else { _Checkable = true; } } // ------------------------------------------------------------------------------------------------ void CViewTextMenu::setChecked(bool c) { if (_CheckBox) { CInterfaceOptions *pIO = CInterfaceManager::getInstance()->getOptions("menu_checkbox"); if (!pIO) return; _CheckBox->setTexture(pIO->getValStr(c ? "checked_bitmap" : "unchecked_bitmap")); } _Checked = c; } // ------------------------------------------------------------------------------------------------ sint32 CViewTextMenu::getAlpha() const { if (_Grayed) { return OldColorGrayed.A; } else { if (Over) return OldColorOver.A; else return OldColor.A; } } // ------------------------------------------------------------------------------------------------ void CViewTextMenu::setAlpha (sint32 a) { OldShadowColor.A = OldColor.A = (uint8)a; OldShadowColorOver.A = OldColorOver.A = (uint8)a; OldShadowColorGrayed.A = OldShadowColorGrayed.A = (uint8)a; } // ------------------------------------------------------------------------------------------------ // CGroupSubMenu // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ CGroupSubMenu::CGroupSubMenu(const TCtorParam ¶m) : CGroupFrame(param) { _SelectionView = NULL; _GroupList = NULL; _GroupMenu = NULL; _Selected = -1; _MaxVisibleLine = -1; _ScrollBar = NULL; } // ------------------------------------------------------------------------------------------------ CGroupSubMenu::~CGroupSubMenu() { removeAllUserGroups(); } // ------------------------------------------------------------------------------------------------ sint CGroupSubMenu::getLineFromId(const std::string &id) { for (uint k = 0; k < _Lines.size(); ++k) { if (_Lines[k].Id == id) { return (sint) k; } } return -1; } // ------------------------------------------------------------------------------------------------ CGroupSubMenu *CGroupSubMenu::getSubMenu(uint index) const { if (index >= _SubMenus.size()) { nlassert("bad index"); return NULL; } return _SubMenus[index]; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setSubMenu(uint index, CGroupSubMenu *sub) { nlassert(sub != NULL); nlassert(index < _SubMenus.size()); if (_SubMenus[index] != NULL) { // must delete from the group menu (if not found, just delete) if( !_GroupMenu || !_GroupMenu->delGroup(_SubMenus[index]) ) delete _SubMenus[index]; _SubMenus[index] = NULL; delView(_Lines[index].RightArrow); } if (_Lines[index].CheckBox) _Lines[index].RightArrow = createRightArrow(_Lines[index].CheckBox, true); else _Lines[index].RightArrow = createRightArrow(_GroupList, false); sub->_GroupMenu = _GroupMenu; sub->initOptions(this); _GroupMenu->addGroup (sub); sub->_DispType = _GroupMenu->_DispType; _SubMenus[index] = sub; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::initOptions(CInterfaceGroup *parent) { // Initialization // me _Parent = _GroupMenu; if (parent == NULL) { setParentPos (_GroupMenu); setParentPosRef (Hotspot_TL); setPosRef (Hotspot_TL); } else { setParentPos (parent); setParentPosRef (Hotspot_BR); setPosRef (Hotspot_BL); } _DisplayFrame = true; _ResizeFromChildH = true; _ResizeFromChildW = true; _ResizeFromChildHMargin = 8; _ResizeFromChildWMargin = 8; _ModulateGlobalColor = _GroupMenu->_ModulateGlobalColor; // the selection if (_SelectionView == NULL) { _SelectionView = new CViewBitmap(CViewBase::TCtorParam()); // CInterfaceManager *pIM = CInterfaceManager::getInstance(); // CViewRenderer &rVR = pIM->getViewRenderer(); _SelectionView->setParent (this); _SelectionView->setActive (false); _SelectionView->setTexture ("blank.tga"); _SelectionView->setScale (true); _SelectionView->setX (4); _SelectionView->setSizeRef(1); // sizeref on W _SelectionView->setW (-8); addView (_SelectionView, 0); } // the group list if (_GroupList == NULL) { _GroupList = new CGroupList(CViewBase::TCtorParam()); _GroupList->setParent (this); _GroupList->setParentPos (this); _GroupList->setX (4); _GroupList->setY (4); _GroupList->setSpace (_GroupMenu->_Space); addGroup (_GroupList); } } // ------------------------------------------------------------------------------------------------ bool CGroupSubMenu::parse (xmlNodePtr cur, CInterfaceGroup *parent) { initOptions(parent); CInterfaceManager *im = CInterfaceManager::getInstance(); // the children while (cur) { CViewTextMenu *pV = NULL; CXMLAutoPtr id((const char*) xmlGetProp (cur, (xmlChar*)"id")); if (stricmp((char*)cur->name, "separator") == 0) { if (id) { addSeparator((const char *) id); } else { addSeparator(); } } else if (stricmp((char*)cur->name, "action") == 0) { string strId, strAh, strParams, strCond, strTexture=""; ucstring ucstrName; if (id) strId = (const char*)id; CXMLAutoPtr name((const char*) xmlGetProp (cur, (xmlChar*)"name")); if (name) { const char *ptrName = (const char*)name; ucstrName = ucstring(ptrName); if ((strlen(ptrName)>2) && (ptrName[0] == 'u') && (ptrName[1] == 'i')) ucstrName = CI18N::get (ptrName); } CXMLAutoPtr ah((const char*) xmlGetProp (cur, (xmlChar*)"handler")); if (ah) strAh = (const char*)ah; CXMLAutoPtr cond((const char*) xmlGetProp (cur, (xmlChar*)"cond")); if (cond) strCond = (const char*)cond; CXMLAutoPtr params((const char*) xmlGetProp (cur, (xmlChar*)"params")); if (params) strParams = (const char*)params; CXMLAutoPtr strCheckable((const char*) xmlGetProp (cur, (xmlChar*)"checkable")); bool bCheckable = false; if (strCheckable) bCheckable = convertBool (strCheckable); CXMLAutoPtr strChecked((const char*) xmlGetProp (cur, (xmlChar*)"checked")); bool bChecked = false; if (strChecked) bChecked = convertBool (strChecked); bool bFormatted = false; CXMLAutoPtr strFormatted((const char*) xmlGetProp (cur, (xmlChar*)"formatted")); if (strFormatted) bFormatted = convertBool (strFormatted); pV = addLine (ucstrName, strAh, strParams, strId, strCond, strTexture, bCheckable, bChecked, bFormatted); CXMLAutoPtr strSelectable((const char*) xmlGetProp (cur, (xmlChar*)"selectable")); bool bSelectable = true; if (strSelectable) bSelectable = convertBool (strSelectable); _Lines.back().Selectable = bSelectable; CXMLAutoPtr grayed((const char*) xmlGetProp (cur, (xmlChar*)"grayed")); bool bGrayed = false; if (grayed) bGrayed = convertBool (grayed); pV->setGrayed(bGrayed); // Is this line has a sub menu ? xmlNodePtr child = cur->children; if (child != NULL) { if (_Lines.back().CheckBox) { _Lines.back().RightArrow = createRightArrow(_Lines.back().CheckBox, true); } else { _Lines.back().RightArrow = createRightArrow(_GroupList, false); } // and create the sub menu CGroupSubMenu *childMenu = new CGroupSubMenu(CViewText::TCtorParam()); childMenu->_GroupMenu = _GroupMenu; childMenu->parse (child, this); CXMLAutoPtr MVL((const char*) xmlGetProp(cur, (xmlChar*)"max_visible_line")); if (MVL) { sint32 maxVisibleLine; fromString((const char*)MVL, maxVisibleLine); childMenu->setMaxVisibleLine(maxVisibleLine); } _SubMenus.back() = childMenu; } // Add user groups // Left CXMLAutoPtr usergroup((const char*) xmlGetProp (cur, (xmlChar*)"usergroup_l")); if (usergroup) { vector< pair > vparams; CXMLAutoPtr ugparams((const char*) xmlGetProp (cur, (xmlChar*)"usergroup_params_l")); if (ugparams) { IActionHandler::getAllParams((const char*)ugparams, vparams); } string completeId = _Parent->getId() + ":" + _Lines[_Lines.size()-1].Id; CInterfaceGroup *pUGLeft = im->createGroupInstance((const char*)usergroup, completeId, vparams); if (pUGLeft) setUserGroupLeft((uint)_Lines.size()-1, pUGLeft, true); } usergroup = (char*) xmlGetProp (cur, (xmlChar*)"usergroup_r"); if (usergroup) { vector< pair > vparams; CXMLAutoPtr ugparams((const char*) xmlGetProp (cur, (xmlChar*)"usergroup_params_r")); if (ugparams) { IActionHandler::getAllParams((const char*)ugparams, vparams); } string completeId = _Parent->getId() + ":" + _Lines[_Lines.size()-1].Id; CInterfaceGroup *pUG = im->createGroupInstance((const char*)usergroup, completeId, vparams); if (pUG) setUserGroupRight((uint)_Lines.size()-1, pUG, true); } } cur = cur->next; } _GroupMenu->addGroup (this); this->_DispType = _GroupMenu->_DispType; return true; } // ------------------------------------------------------------------------------------------------ CViewBitmap *CGroupSubMenu::createCheckBox(bool checked) { // Put the left arrow to the line CViewBitmap *pVB = new CViewBitmap(CViewBase::TCtorParam()); pVB->setParent (this); pVB->setParentPos (_GroupList); pVB->setParentPosRef (Hotspot_BR); pVB->setPosRef (Hotspot_BL); CInterfaceOptions *pIO = CInterfaceManager::getInstance()->getOptions("menu_checkbox"); if (pIO) { pVB->setTexture(pIO->getValStr(checked ? "checked_bitmap" : "unchecked_bitmap")); } pVB->setX (MENU_WIDGET_X); pVB->setId (ID_MENU_CHECKBOX); // always rescale to parent in update coords addView (pVB); return pVB; } // ------------------------------------------------------------------------------------------------ CViewBitmap *CGroupSubMenu::createRightArrow(CInterfaceElement *parentPos, bool center) { // Put the left arrow to the line CViewBitmap *pVB = new CViewBitmap(CViewBase::TCtorParam()); pVB->setParent (this); pVB->setParentPos (parentPos); if (!center) { pVB->setParentPosRef (Hotspot_BR); pVB->setPosRef (Hotspot_BL); } else { pVB->setParentPosRef (Hotspot_MR); pVB->setPosRef (Hotspot_ML); } pVB->setTexture("w_arrow_right_3.tga"); pVB->setX (MENU_WIDGET_X); pVB->setId (ID_MENU_SUBMENU); // rescale to parent in update coords if asked (not needed if there's already on the left a checkbox) addView (pVB); return pVB; } // ------------------------------------------------------------------------------------------------ #define GET_REF_ELM(__index__) \ CInterfaceElement *refElm; \ sint32 refElmYReal= 0; \ sint32 refElmHReal= 0; \ refElm = _Lines[__index__].ViewText; \ if(refElm) \ { \ refElmYReal= refElm->getYReal() - _Lines[__index__].TextDY; \ refElmHReal= _Lines[__index__].HReal; \ } void CGroupSubMenu::updateCoords () { if (_ParentPos == _GroupMenu) { // Root Menu setX(_GroupMenu->SpawnMouseX); setY(_GroupMenu->SpawnMouseY); CGroupFrame::updateCoords(); CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer(); uint32 screenW, screenH; rVR.getScreenSize(screenW, screenH); if ((_XReal+_WReal) > (sint32)screenW) setX(screenW-_WReal); if (_YReal < 0) setY(_HReal); } else // The sub menu may go outside the screen in Y. => clamp it as possible { /* X/Y coords have normally been updated before by "parent" sub menus Why? because setSubMenu() is typically called in "parent first" order (or it is exactly what is done in ::parse()) => Parent CGroupSubMenu::updateCoords() are called before their sons in CGroupMenu::updateCoords() !!! => No Need to call _SubMenus[RALineNb]->updateCoords() below ! (else would call too much time because of recursion!!) */ // must udpate correct Real coords CGroupFrame::updateCoords(); // get screen size CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer(); uint32 screenW, screenH; rVR.getScreenSize(screenW, screenH); sint32 hReal= getHReal(); // If the H is too big, abort.. can't do anything if(hReal<=(sint32)screenH) { sint32 yReal= getYReal(); // compute the shift to apply to the Y of the sub menu, to respect (as possible) the screen sint32 dyClamp= 0; if(yReal<0) dyClamp= - yReal; if(yReal+hReal>(sint32)screenH) dyClamp= screenH - (yReal+hReal); // change then the Y if(dyClamp!=0) { setY(getY()+dyClamp); CGroupFrame::updateCoords(); } } } // not yet setuped? if (!_GroupList) return; // get text dy position sint32 textDYPos= 0; textDYPos= -(1+_GroupList->getSpace())/2; // Set the arrows at the right positions (in _Views we have selection and the right arrows) sint32 CBLineNb = 0; // check box sint32 RALineNb = 0; // right arrow uint32 i; sint32 maxUserGroupWidth = 0; // compute max width of user groups, & adapt max height for each line uint k; // update all left user groups to get their width sint32 maxLeftUGWidth = 0; for(k = 0; k < _Lines.size(); ++k) { if (_Lines[k].UserGroupLeft) { _Lines[k].UserGroupLeft->updateCoords(); maxLeftUGWidth = std::max(_Lines[k].UserGroupLeft->getWReal(), maxLeftUGWidth); } } _GroupList->setX(LEFT_MENU_WIDGET_X + maxLeftUGWidth); // active separators when needed bool activeLineSeen = false; for (i = 0; i < _Lines.size(); ++i) { if (_Lines[i].Separator != NULL) { if (i == _Lines.size() - 1) { _Lines[i].Separator->setActive(false); break; } _Lines[i].Separator->setActive(activeLineSeen); activeLineSeen = false; } else { if (_Lines[i].ViewText && _Lines[i].ViewText->getActive()) activeLineSeen = true; } } CGroupFrame::updateCoords(); bool mustUpdate = false; if (_MaxVisibleLine > 0 && sint32(_Lines.size())>_MaxVisibleLine) { for(k = 0; k < _Lines.size(); ++k) if (_Lines[k].ViewText) { // compute max height of widgets on the left of text sint32 widgetMaxH = 0; if (_Lines[k].UserGroupRight) widgetMaxH = _Lines[k].UserGroupRight->getHReal(); if (_Lines[k].UserGroupLeft) widgetMaxH = std::max(widgetMaxH, _Lines[k].UserGroupLeft->getHReal()); if (_Lines[k].CheckBox) widgetMaxH = std::max(widgetMaxH, _Lines[k].CheckBox->getHReal()); if (_Lines[k].RightArrow) widgetMaxH = std::max(widgetMaxH, _Lines[k].RightArrow->getHReal()); widgetMaxH = std::max(widgetMaxH, _Lines[k].ViewText->getHReal()); _GroupList->setMaxH(widgetMaxH*_MaxVisibleLine+_GroupList->getSpace()*(_MaxVisibleLine-1)); if (_ScrollBar == NULL) { _ScrollBar = new CCtrlScroll(CViewBase::TCtorParam()); _ScrollBar->setParent (this); _ScrollBar->setParentPos (_GroupList); _ScrollBar->setPosRef (Hotspot_BL); _ScrollBar->setParentPosRef (Hotspot_BR); _ScrollBar->setX (4); _ScrollBar->setY (0); _ScrollBar->setW (8); _ScrollBar->setTextureBottomOrLeft ("w_scroll_l123_b.tga"); _ScrollBar->setTextureMiddle ("w_scroll_l123_m.tga"); _ScrollBar->setTextureTopOrRight ("w_scroll_l123_t.tga"); _ScrollBar->setTarget(_GroupList); _SelectionView->setW (-8-8-2); addCtrl(_ScrollBar); mustUpdate = true; } break; } } else { _SelectionView->setW(-8); } // *** Setup Text for(k = 0; k < _Lines.size(); ++k) { CInterfaceGroup *ig = _Lines[k].UserGroupRight; if (ig) { ig->updateCoords(); maxUserGroupWidth = std::max(maxUserGroupWidth, ig->getWReal()); } if (_Lines[k].ViewText) { // compute max height of widgets on the left of text sint32 widgetMaxH = 0; if (_Lines[k].UserGroupRight) widgetMaxH = _Lines[k].UserGroupRight->getHReal(); if (_Lines[k].UserGroupLeft) widgetMaxH = std::max(widgetMaxH, _Lines[k].UserGroupLeft->getHReal()); if (_Lines[k].CheckBox) widgetMaxH = std::max(widgetMaxH, _Lines[k].CheckBox->getHReal()); if (_Lines[k].RightArrow) widgetMaxH = std::max(widgetMaxH, _Lines[k].RightArrow->getHReal()); sint32 textHReal= _Lines[k].ViewText->getHReal(); _Lines[k].HReal= max(widgetMaxH, textHReal); _Lines[k].TextDY= textDYPos; if(widgetMaxH>textHReal) _Lines[k].TextDY+= (widgetMaxH-textHReal) / 2; } } // *** Update Text Positions // sint32 currX = 0; for(k = 0; k < _Lines.size(); ++k) { if (_Lines[k].ViewText) { // Setup Y _Lines[k].ViewText->setY(_Lines[k].TextDY); } } if (mustUpdate) { CGroupFrame::updateCoords(); } // *** Setup SubMenus and CheckBoxes Positions sint32 maxViewW = 0; for (i = 1; i < _Views.size(); ++i) { CViewBitmap *pVB = dynamic_cast(_Views[i]); if (pVB == NULL) continue; if (pVB->getId() == ID_MENU_SUBMENU) { // Look for the next line of the menu that contains a sub menu for(;;) { nlassert (RALineNb < (sint32)_SubMenus.size()); if (_SubMenus[RALineNb] != NULL) // has a check box or an arrow to indicate submenu ? { break; } ++RALineNb; } // get refElm and refElmYReal GET_REF_ELM(RALineNb) // if there is a check box, y is 0 if (_Lines[RALineNb].CheckBox || _Lines[RALineNb].UserGroupRight) { pVB->setY(0); pVB->setX(MENU_WIDGET_X); } else { sint32 limY = refElmYReal + refElmHReal/2 - _GroupList->getYReal(); // Setup the arrow at the right pos if(_GroupList->getMaxH()>=limY && limY>=0) { pVB->setY(refElmYReal + (refElmHReal - pVB->getHReal()) / 2 - _GroupList->getYReal()); pVB->setColor(_Lines[RALineNb].ViewText->getColor()); pVB->setActive(_Lines[RALineNb].ViewText->getActive()); pVB->setX(maxUserGroupWidth + MENU_WIDGET_X); } else { pVB->setY(0); pVB->setActive(false); } } if (_GroupMenu->SpawnOnMousePos) { _SubMenus[RALineNb]->setParentPos (this); // According to mouse position, set the sub menu on the left or right, begin at top or bottom CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer(); uint32 screenW, screenH; rVR.getScreenSize(screenW, screenH); if ((_GroupMenu->SpawnMouseX <= ((sint32)screenW/2)) && (_GroupMenu->SpawnMouseY <= ((sint32)screenH/2))) { _SubMenus[RALineNb]->setParentPosRef(Hotspot_BR); _SubMenus[RALineNb]->setPosRef(Hotspot_BL); _SubMenus[RALineNb]->setY (refElmYReal - _GroupList->getYReal()); } if ((_GroupMenu->SpawnMouseX <= ((sint32)screenW/2)) && (_GroupMenu->SpawnMouseY > ((sint32)screenH/2))) { _SubMenus[RALineNb]->setParentPosRef(Hotspot_TR); _SubMenus[RALineNb]->setPosRef(Hotspot_TL); _SubMenus[RALineNb]->setY (refElmHReal+(refElmYReal - _GroupList->getYReal()) - _GroupList->getHReal()); } if ((_GroupMenu->SpawnMouseX > ((sint32)screenW/2)) && (_GroupMenu->SpawnMouseY <= ((sint32)screenH/2))) { _SubMenus[RALineNb]->setParentPosRef(Hotspot_BL); _SubMenus[RALineNb]->setPosRef(Hotspot_BR); _SubMenus[RALineNb]->setY (refElmYReal - _GroupList->getYReal()); } if ((_GroupMenu->SpawnMouseX > ((sint32)screenW/2)) && (_GroupMenu->SpawnMouseY > ((sint32)screenH/2))) { _SubMenus[RALineNb]->setParentPosRef(Hotspot_TL); _SubMenus[RALineNb]->setPosRef(Hotspot_TR); _SubMenus[RALineNb]->setY (refElmHReal+(refElmYReal - _GroupList->getYReal()) - _GroupList->getHReal()); } _SubMenus[RALineNb]->setX(0); } else { // Setup sub menu _SubMenus[RALineNb]->setParentPos (this); _SubMenus[RALineNb]->setParentPosRef (Hotspot_BR); _SubMenus[RALineNb]->setPosRef (Hotspot_BL); _SubMenus[RALineNb]->setY (16+refElmYReal - _GroupList->getYReal() - _SubMenus[RALineNb]->getHReal()); } ++RALineNb; } else if (pVB->getId() == ID_MENU_CHECKBOX) { for(;;) { nlassert (CBLineNb < (sint32)_SubMenus.size()); if (_Lines[CBLineNb].CheckBox != NULL) // has a check box or an arrow to indicate submenu ? { break; } ++CBLineNb; } // Setup the arrow at the right pos if (!_Lines[CBLineNb].UserGroupRight) { // get refElm and refElmYReal GET_REF_ELM(CBLineNb) pVB->setX(maxUserGroupWidth + 2 * MENU_WIDGET_X); sint32 limY = refElmYReal + refElmHReal/2 - _GroupList->getYReal(); // Setup the arrow at the right pos if(_GroupList->getMaxH()>=limY && limY>=0){ pVB->setY(refElmYReal + (refElmHReal - pVB->getHReal()) / 2 - _GroupList->getYReal()); pVB->setActive(_Lines[CBLineNb].ViewText->getActive()); } else { pVB->setY(0); pVB->setActive(false); } } else { pVB->setY(0); pVB->setX(MENU_WIDGET_X); } pVB->setColor (_Lines[CBLineNb].ViewText->getColor()); // ++CBLineNb; } if (maxViewW<(pVB->getWReal()+pVB->getX())) maxViewW = pVB->getWReal()+pVB->getX(); } // setup scrollbar position in function of views width if(maxViewW>0 && _ScrollBar) _ScrollBar->setX(4 + maxViewW); // *** Setup user groups positions for(k = 0; k < _Lines.size(); ++k) { CInterfaceGroup *igr = _Lines[k].UserGroupRight; CInterfaceGroup *igl = _Lines[k].UserGroupLeft; if (igr || igl) { // get refElm and refElmYReal GET_REF_ELM(k) if (refElm) { if (igr) { igr->setX(MENU_WIDGET_X + maxUserGroupWidth - igr->getWReal()); sint32 limY = refElmYReal + refElmHReal/2 - _GroupList->getYReal(); if(_GroupList->getMaxH()>=limY && limY>=0) { igr->setY(refElmYReal + (refElmHReal - igr->getHReal()) / 2 - _GroupList->getYReal()); igr->setActive (refElm->getActive()); } else { igr->setY(0); igr->setActive(false); } } if (igl) { sint32 limY = refElmYReal + refElmHReal/2 - _GroupList->getYReal(); if(_GroupList->getMaxH()>=limY && limY>=0) { igl->setY(refElmYReal + (refElmHReal - igl->getHReal()) / 2 - this->getYReal()); igl->setActive(refElm->getActive()); } else { igl->setY(0); igl->setActive(false); } } } } } sint32 SepLineNb = 0; // set separator at the right position for (i = 0; i < _ChildrenGroups.size(); ++i) { CInterfaceGroup *pIG = dynamic_cast(_ChildrenGroups[i]); if (pIG == NULL) continue; if (pIG->getId() != ID_MENU_SEPARATOR) continue; // is it a separator ? // set good width /*sint32 sw = getW() - _LeftBorder - _RightBorder; sw = std::max(sw, (sint32) 0); pIG->setW(sw);*/ // Look for the next line of the menu that contains a separator CInterfaceGroup *sep = NULL; do { nlassert (SepLineNb < (sint32)_Lines.size()); sep = _Lines[SepLineNb].Separator; ++SepLineNb; } while (sep == NULL); // Setup the arrow at the right pos pIG->setY (sep->getYReal() - getYReal()); pIG->setActive(sep->getActive()); } CGroupFrame::updateCoords(); //_SelectionView->setW (this->getW()); _SelectionView->setH (8); _SelectionView->setY (4); if (_Selected != -1 && _Lines[_Selected].ViewText != NULL) { CRGBA col= _GroupMenu->_HighLightOver; _SelectionView->setColor (col); _SelectionView->setModulateGlobalColor(getModulateGlobalColor()); // get refElm and refElmYReal GET_REF_ELM(_Selected) _SelectionView->setH (refElmHReal); _SelectionView->setY (refElmYReal - this->getYReal()); } } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::checkCoords() { if (!_Active) return; if (_GroupMenu == NULL) return; // if the mouse goes out the window, unselect all (because handleEvent may not be called) CInterfaceManager *pIM = CInterfaceManager::getInstance(); sint xMouse= pIM->getPointer()->getX(); sint yMouse= pIM->getPointer()->getY(); if (!((xMouse >= _XReal) && (xMouse < (_XReal + _WReal))&& (yMouse > _YReal) && (yMouse <= (_YReal+ _HReal)))) _Selected= -1; // CViewRenderer &rVR = pIM->getViewRenderer(); // Highlight (background under the selection) if (_Selected != -1) { // display hightlight if(_GroupMenu->_HighLightOver.A > 0) { _SelectionView->setActive (true); _SelectionView->invalidateCoords(); } else { _SelectionView->setActive (false); } } else // no selection { _SelectionView->setActive (false); } // Text color if grayed or not for (sint32 i = 0; i < (sint32)_Lines.size(); ++i) { if (_Lines[i].ViewText) { if (_Lines[i].ViewText->getGrayed()) // Colors when the text is grayed { _Lines[i].ViewText->setColor (_Lines[i].ViewText->OldColorGrayed); _Lines[i].ViewText->setShadowColor (_Lines[i].ViewText->OldShadowColorGrayed); } else { if (i == _Selected) // Colors when the text is selected { _Lines[i].ViewText->Over = true; _Lines[i].ViewText->setColor (_Lines[i].ViewText->OldColorOver); _Lines[i].ViewText->setShadowColor (_Lines[i].ViewText->OldShadowColorOver); } else // Or finally normal colors { _Lines[i].ViewText->Over = false; _Lines[i].ViewText->setColor (_Lines[i].ViewText->OldColor); _Lines[i].ViewText->setShadowColor (_Lines[i].ViewText->OldShadowColor); } } } } } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::draw() { if (!_Active) return; if (_GroupMenu == NULL) return; CGroupFrame::draw(); } // ------------------------------------------------------------------------------------------------ bool CGroupSubMenu::handleEvent (const CEventDescriptor &event) { if (!_Active) return false; sint32 textDYPos= 0; if(_GroupList) textDYPos= -(1+_GroupList->getSpace())/2; if (event.getType() == CEventDescriptor::mouse) { const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event; _Selected = -1; // TODO First check sub menus that can be not in the area of this menu if (!((eventDesc.getX() >= _XReal) && (eventDesc.getX() < (_XReal + _WReal))&& (eventDesc.getY() > _YReal) && (eventDesc.getY() <= (_YReal+ _HReal)))) return false; uint32 i = 0; for (i = 0; i < _Lines.size(); ++i) { if (_Lines[i].Selectable) { // get refElm and refElmYReal GET_REF_ELM(i) if (refElm) { if (refElm->getActive() == true) if ((eventDesc.getY() > refElmYReal) && (eventDesc.getY() <= (refElmYReal + refElmHReal + _GroupList->getSpace()))) { _Selected = i; break; } } } } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) { // If a line is selected and the line is not grayed if ((_Selected != -1) && (!_Lines[i].ViewText->getGrayed())) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->runActionHandler ( _Lines[_Selected].AHName, pIM->getCtrlLaunchingModal(), _Lines[_Selected].AHParams ); if (_SubMenus[_Selected] != NULL) { openSubMenu (_Selected); } else { // if the menu hasn't triggered a new modal window, disable it if (pIM->getModalWindow() == _GroupMenu) { if(_GroupMenu && _GroupMenu->getCloseSubMenuUsingPopModal()) pIM->popModalWindow(); else pIM->disableModalWindow (); } } } } if (event.getType() == CEventDescriptor::mouse) { const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event; // if (_GroupList && _ScrollBar) { if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousewheel) { if (isIn(eventDesc.getX(), eventDesc.getY())) { sint32 h = 0; for (uint32 k = 0; k < _Lines.size(); ++k) if (_Lines[k].ViewText) { // compute max height of widgets on the left of text sint32 widgetMaxH = 0; if (_Lines[k].UserGroupRight) widgetMaxH = _Lines[k].UserGroupRight->getHReal(); if (_Lines[k].UserGroupLeft) widgetMaxH = std::max(widgetMaxH, _Lines[k].UserGroupLeft->getHReal()); if (_Lines[k].CheckBox) widgetMaxH = std::max(widgetMaxH, _Lines[k].CheckBox->getHReal()); if (_Lines[k].RightArrow) widgetMaxH = std::max(widgetMaxH, _Lines[k].RightArrow->getHReal()); widgetMaxH = std::max(widgetMaxH, _Lines[k].ViewText->getHReal()); h = widgetMaxH+_GroupList->getSpace(); } if (h == 0) h = 1; _ScrollBar->moveTargetY(- eventDesc.getWheel() * h); hideSubMenus(); return true; } } } } return true; } return false; } // ------------------------------------------------------------------------------------------------ CInterfaceElement* CGroupSubMenu::getElement (const std::string &id) { string sTmp = id.substr(0, _GroupMenu->getId().size()); if (sTmp != _GroupMenu->getId()) return NULL; string sRest = id.substr(_GroupMenu->getId().size()+1, id.size()); // Iterate through the tree to see if sRest is present CGroupSubMenu *pCurGSM = this; while (!sRest.empty()) { // Get the first element of the sRest string::size_type posid = sRest.find (":"); if (posid == string::npos) // Is there just one token to test ? { for (uint32 i = 0; i < pCurGSM->_Lines.size(); ++i) if (sRest == pCurGSM->_Lines[i].Id) return pCurGSM->_Lines[i].ViewText; sRest = ""; } else // no a lot of token left { string sTok = sRest.substr (0, posid); uint32 i = 0; for (i = 0; i < pCurGSM->_Lines.size(); ++i) if (sTok == pCurGSM->_Lines[i].Id) break; if (i == pCurGSM->_Lines.size()) return NULL; // No sub-menus if (pCurGSM->_SubMenus[i] == NULL) { // Get next token sRest = sRest.substr (posid+1); posid = sRest.find (":"); if (posid == string::npos) sTok = sRest; else sTok = sRest.substr (0, posid); // Do we want left or right user group ? if (pCurGSM->_Lines[i].UserGroupRight) { string sUGid = pCurGSM->_Lines[i].UserGroupRight->getId(); sUGid = sUGid.substr(sUGid.rfind(':')+1,sUGid.size()); if (sUGid == sTok) { CInterfaceElement *pIE = pCurGSM->_Lines[i].UserGroupRight->getElement(id); return pIE; } } if (pCurGSM->_Lines[i].UserGroupLeft) { string sUGid = pCurGSM->_Lines[i].UserGroupLeft->getId(); sUGid = sUGid.substr(sUGid.rfind(':')+1,sUGid.size()); if (sUGid == sTok) { CInterfaceElement *pIE = pCurGSM->_Lines[i].UserGroupLeft->getElement(id); return pIE; } } return NULL; } else { pCurGSM = pCurGSM->_SubMenus[i]; } } sRest = sRest.substr (posid+1); } return NULL; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::addSeparator(const std::string &id) { addSeparatorAtIndex((uint)_Lines.size(), id); } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::addSeparatorAtIndex(uint index, const std::string &id) { if (index > _Lines.size()) { nlwarning("Bad index"); return; } CInterfaceManager *im = CInterfaceManager::getInstance(); // create the real separator. It may be larger than the group list, this is why we create a separate group CInterfaceGroup *separator = im->createGroupInstance("menu_separator", "", NULL, 0); if (!separator) return; separator->setId(ID_MENU_SEPARATOR); addGroup(separator); separator->setParent(this); // create place holder group CInterfaceGroup *ph = im->createGroupInstance("menu_separator_empty", "", NULL, 0); if (!ph) { delGroup(separator); return; } _GroupList->addChildAtIndex(ph, index); SSubMenuEntry tmp; tmp.Id = id; tmp.Separator = ph; tmp.ViewText = NULL; tmp.CheckBox = NULL; tmp.RightArrow = NULL; _Lines.insert(_Lines.begin() + index, tmp); _SubMenus.insert(_SubMenus.begin() + index, NULL); _GroupMenu->invalidateCoords(); } // ------------------------------------------------------------------------------------------------ CViewTextMenu* CGroupSubMenu::addLine (const ucstring &name, const std::string &ah, const std::string ¶ms, const std::string &id, const std::string &cond, const std::string &texture, bool checkable /*= false*/, bool checked /*= false*/, bool formatted /*= false */ ) { SSubMenuEntry tmp; CViewTextMenu *pV = new CViewTextMenu(CViewBase::TCtorParam()); pV->setCaseMode(_GroupMenu->getCaseMode()); if (formatted) { pV->setMultiLine (true); pV->setMultiLineMaxWOnly (true); pV->setTextFormatTaged (name); } else { pV->setText (name); } pV->setColor (_GroupMenu->_Color); pV->setFontSize (_GroupMenu->_FontSize); pV->setShadow (_GroupMenu->_Shadow); pV->setCheckable(checkable); pV->setChecked(checked); pV->setModulateGlobalColor(_GroupMenu->_ModulateGlobalColor); pV->OldColor = _GroupMenu->_Color; pV->OldShadowColor = _GroupMenu->_ShadowColor; pV->OldColorOver = _GroupMenu->_ColorOver; pV->OldShadowColorOver = _GroupMenu->_ShadowColorOver; pV->OldColorGrayed = _GroupMenu->_ColorGrayed; pV->OldShadowColorGrayed = _GroupMenu->_ShadowColorGrayed; _GroupList->addChild (pV); CViewBitmap *checkBox = NULL; if (checkable) { checkBox = createCheckBox(checked); checkBox->setTexture(texture); pV->setCheckBox(checkBox); } tmp.ViewText = pV; tmp.Separator = NULL; tmp.AHName = ah; tmp.AHParams = params; tmp.Cond = cond; tmp.CheckBox = checkBox; tmp.RightArrow = NULL; if (id.empty()) tmp.Id = NLMISC::toString (_Lines.size()); else tmp.Id = id; pV->setId(_GroupMenu->getId()+":"+tmp.Id); _Lines.push_back (tmp); // Add an empty sub menu by default _SubMenus.push_back (NULL); _GroupMenu->invalidateCoords(); return pV; } CViewTextMenu* CGroupSubMenu::addLineAtIndex(uint index, const ucstring &name, const std::string &ah, const std::string ¶ms, const std::string &id /*=""*/, const std::string &cond /*=std::string()*/, const std::string &texture, bool checkable /*= false*/, bool checked /*= false*/, bool formatted /*= false */ ) { if (index > _Lines.size()) { nlwarning("Bad index"); return NULL; } SSubMenuEntry tmp; CViewTextMenu *pV = new CViewTextMenu(CViewBase::TCtorParam()); pV->setCaseMode(_GroupMenu->getCaseMode()); if (formatted) { pV->setMultiLine (true); pV->setMultiLineMaxWOnly (true); pV->setTextFormatTaged (name); } else { pV->setText (name); } pV->setColor (_GroupMenu->_Color); pV->setFontSize (_GroupMenu->_FontSize); pV->setShadow (_GroupMenu->_Shadow); pV->setCheckable(checkable); pV->setChecked(checked); pV->setModulateGlobalColor(_GroupMenu->_ModulateGlobalColor); pV->OldColor = _GroupMenu->_Color; pV->OldShadowColor = _GroupMenu->_ShadowColor; pV->OldColorOver = _GroupMenu->_ColorOver; pV->OldShadowColorOver = _GroupMenu->_ShadowColorOver; pV->OldColorGrayed = _GroupMenu->_ColorGrayed; pV->OldShadowColorGrayed = _GroupMenu->_ShadowColorGrayed; _GroupList->addChildAtIndex(pV, index); CViewBitmap *checkBox = NULL; if (checkable) { checkBox = createCheckBox(checked); checkBox->setTexture(texture); pV->setCheckBox(checkBox); } tmp.ViewText = pV; tmp.Separator = NULL; tmp.AHName = ah; tmp.AHParams = params; tmp.Cond = cond; tmp.CheckBox = checkBox; tmp.RightArrow = NULL; if (id.empty()) tmp.Id = NLMISC::toString (_Lines.size()); else tmp.Id = id; pV->setId(getId()+":"+tmp.Id); _Lines.insert(_Lines.begin() + index, tmp); // Add an empty sub menu by default _SubMenus.insert(_SubMenus.begin() + index, NULL); _GroupMenu->invalidateCoords(); return pV; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::removeLine(uint index) { if (index >= _Lines.size()) { nlwarning("Bad index"); return; } setUserGroupRight(index, NULL, false); // remove user group setUserGroupLeft(index, NULL, false); // remove user group // remove view (right arrow & checkbox) if (_Lines[index].RightArrow) delView(_Lines[index].RightArrow); if (_Lines[index].CheckBox) delView(_Lines[index].CheckBox); if (_Lines[index].Separator) { // remove one separator group for(uint k = 0; k < _ChildrenGroups.size(); ++k) { if (_ChildrenGroups[k]->getId() == ID_MENU_SEPARATOR) { delGroup(_ChildrenGroups[k]); break; } } } // _GroupList->setDelOnRemove(index, true); _GroupList->delChild(index); _Lines.erase(_Lines.begin() + index); //invalidate selection _Selected = -1; if(_SubMenus[index]) { // reset it and his sons (recurs) _SubMenus[index]->reset(); // then delete it _GroupMenu->delGroup(_SubMenus[index]); } _SubMenus.erase(_SubMenus.begin() + index); _GroupMenu->invalidateCoords(); } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::openSubMenu (sint32 nb) { hideSubMenus (); _SubMenus[nb]->setActive (true); } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::hideSubMenus () { for (uint32 i = 0; i < _SubMenus.size(); ++i) if (_SubMenus[i] != NULL) { _SubMenus[i]->setActive (false); _SubMenus[i]->hideSubMenus (); } } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::reset() { uint lineCount = (uint)_Lines.size(); for(sint k = lineCount - 1; k >= 0; --k) { removeLine(k); } } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::removeAllUserGroups() { for(uint k = 0; k < _Lines.size(); ++k) { setUserGroupRight(k, NULL, false); setUserGroupLeft(k, NULL, false); } } // ------------------------------------------------------------------------------------------------ CInterfaceGroup *CGroupSubMenu::getUserGroupRight(uint line) const { if (line >= _Lines.size()) { nlwarning("bad index"); return NULL; } return _Lines[line].UserGroupRight; } // ------------------------------------------------------------------------------------------------ CInterfaceGroup *CGroupSubMenu::getUserGroupLeft(uint line) const { if (line >= _Lines.size()) { nlwarning("bad index"); return NULL; } return _Lines[line].UserGroupLeft; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setUserGroupRight(uint line, CInterfaceGroup *group, bool ownership) { if (line >= _Lines.size()) { nlwarning("bad index"); return; } if (group && isChildGroup(group)) { nlwarning("Group inserted twice"); return; } if (_Lines[line].UserGroupRight) { delGroup(_Lines[line].UserGroupRight, !_Lines[line].UserGroupRightOwnership); } _Lines[line].UserGroupRight = group; _Lines[line].UserGroupRightOwnership = ownership; if (group) { CViewBase *prevElem = _Lines[line].CheckBox ? _Lines[line].CheckBox : _Lines[line].RightArrow; if (prevElem) { prevElem->setParentPosRef (Hotspot_MR); prevElem->setPosRef (Hotspot_ML); prevElem->setParentPos(group); prevElem->setX(MENU_WIDGET_X); prevElem->setY(0); } sint insertionOrder; if (prevElem) { insertionOrder = getInsertionOrder(prevElem); } else { insertionOrder = -1; } addGroup(group, insertionOrder); group->setParent(this); group->setParentPos(_GroupList); group->setParentPosRef (Hotspot_BR); group->setPosRef (Hotspot_BL); } else { // restore all posref.. CViewBase *prevElem = _Lines[line].CheckBox ? _Lines[line].CheckBox : _Lines[line].RightArrow; if (prevElem) { prevElem->setParent (this); prevElem->setParentPos (_GroupList); prevElem->setParentPosRef (Hotspot_BR); prevElem->setPosRef (Hotspot_BL); prevElem->setX (MENU_WIDGET_X); } } _GroupMenu->invalidateCoords(); } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setUserGroupLeft(uint line, CInterfaceGroup *group, bool ownership) { if (line >= _Lines.size()) { nlwarning("bad index"); return; } if (group && isChildGroup(group)) { nlwarning("Group inserted twice"); return; } if (_Lines[line].UserGroupLeft) { delGroup(_Lines[line].UserGroupLeft, !_Lines[line].UserGroupLeftOwnership); } _Lines[line].UserGroupLeft = group; _Lines[line].UserGroupLeftOwnership = ownership; if (group) { addGroup(group); group->setParent(this); group->setParentPos(this); group->setParentPosRef (Hotspot_BL); group->setPosRef (Hotspot_BL); group->setX(LEFT_MENU_WIDGET_X); } _GroupMenu->invalidateCoords(); } // ------------------------------------------------------------------------------------------------ CGroupSubMenu *CGroupSubMenu::cloneMenu(CGroupSubMenu *appendToMenu, CGroupMenu *newFather, CInterfaceGroup *initGroup /* = NULL */) const { CGroupSubMenu *copyMenu = appendToMenu ? appendToMenu : new CGroupSubMenu(CViewText::TCtorParam()); uint startSize = (uint)copyMenu->_Lines.size(); copyMenu->_GroupMenu = newFather; copyMenu->initOptions(initGroup); copyMenu->_Lines.reserve(_Lines.size() + startSize); copyMenu->_SubMenus.reserve(_SubMenus.size() + startSize); // copy childrens for(uint k = 0; k < _Lines.size(); ++k) { if (_Lines[k].Separator) { copyMenu->addSeparator(_Lines[k].Id); } else { std::string texture = std::string(); if(_Lines[k].ViewText->getCheckBox()) { texture = _Lines[k].ViewText->getCheckBox()->getTexture(); } CViewTextMenu *pV = NULL; pV = copyMenu->addLine (_Lines[k].ViewText->getText(), _Lines[k].AHName, _Lines[k].AHParams, _Lines[k].Id, _Lines[k].Cond, texture, _Lines[k].ViewText->getCheckable(), _Lines[k].ViewText->getChecked(), _Lines[k].ViewText->getFormatted ()); copyMenu->_Lines[k].Selectable = _Lines[k].Selectable; pV->setGrayed(_Lines[k].ViewText->getGrayed()); } // sub menu copy if there's one if (_SubMenus[k] != NULL) { if (copyMenu->_Lines.back().CheckBox) { copyMenu->_Lines.back().RightArrow = copyMenu->createRightArrow(copyMenu->_Lines.back().CheckBox, true); } else { copyMenu->_Lines.back().RightArrow = copyMenu->createRightArrow(copyMenu->_GroupList, false); } // and create the sub menu copyMenu->_SubMenus[k + startSize] = _SubMenus[k]->cloneMenu(NULL, newFather, copyMenu); } } if (!appendToMenu) { newFather->addGroup(copyMenu); } return copyMenu; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setActive(bool state) { // check conditions for(uint k = 0; k < _Lines.size(); ++k) { if (!_Lines[k].Cond.empty()) { CInterfaceExprValue result; if (CInterfaceExpr::eval(_Lines[k].Cond, result)) { if (result.toBool()) { _Lines[k].ViewText->setGrayed(!result.getBool()); } } } } if(_ScrollBar && _GroupList) _ScrollBar->setTrackPos(_GroupList->getHReal()); CGroupFrame::setActive(state); } // ------------------------------------------------------------------------------------------------ const std::string CGroupSubMenu::getActionHandler(uint lineIndex) const { if (lineIndex > _Lines.size()) { nlwarning("Bad index"); return 0; } return _Lines[lineIndex].AHName; } // ------------------------------------------------------------------------------------------------ const std::string CGroupSubMenu::getActionHandlerParam(uint lineIndex) const { if (lineIndex > _Lines.size()) { nlwarning("Bad index"); return 0; } return _Lines[lineIndex].AHParams; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setSelectable(uint lineIndex, bool selectable) { if (lineIndex > _Lines.size()) { nlwarning("Bad index"); return; } _Lines[lineIndex].Selectable = selectable; } // ------------------------------------------------------------------------------------------------ bool CGroupSubMenu::getSelectable(uint lineIndex) const { if (lineIndex > _Lines.size()) { nlwarning("Bad index"); return 0; } return _Lines[lineIndex].Selectable; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setMaxVisibleLine(sint32 mvl) { _MaxVisibleLine = mvl; } // ------------------------------------------------------------------------------------------------ const std::string &CGroupSubMenu::getLineId(uint index) { if(index>=_Lines.size()) { static string nullString; return nullString; } else return _Lines[index].Id; } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setGrayedLine(uint line, bool g) { if(line<_Lines.size()) { if (_Lines[line].ViewText) { _Lines[line].ViewText->setGrayed(g); } } } // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setHiddenLine(uint line, bool h) { if(line<_Lines.size()) { if (_Lines[line].ViewText) { _Lines[line].ViewText->setActive(!h); } } } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetNumLine(CLuaState &ls) { CLuaIHM::checkArgCount(ls, "getNumLine", 0); ls.push((double) getNumLine()); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetSubMenu(CLuaState &ls) { const char *funcName = "getSubMenu"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); CLuaIHM::pushUIOnStack(ls, getSubMenu((uint) ls.toNumber(1))); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaAddSubMenu(CLuaState &ls) { const char *funcName = "addSubMenu"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); setSubMenu((uint) ls.toNumber(1), new CGroupSubMenu(CViewText::TCtorParam())); CLuaIHM::pushUIOnStack(ls, getSubMenu((uint) ls.toNumber(1))); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetLineId(CLuaState &ls) { const char *funcName = "getLineId"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); std::string id = getLineId((uint) ls.toNumber(1)); CLuaIHM::push(ls, id); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetLineFromId(CLuaState &ls) { const char *funcName = "getLineFromId"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING); ls.push((double) getLineFromId(ls.toString(1))); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaIsSeparator(CLuaState &ls) { const char *funcName = "isSeparator"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); ls.push(isSeparator((uint) ls.toNumber(1))); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaAddLine(CLuaState &ls) { const char *funcName = "addLine"; CLuaIHM::checkArgCount(ls, funcName, 4); CLuaIHM::checkArgTypeUCString(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING); CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING); CLuaIHM::checkArgType(ls, funcName, 4, LUA_TSTRING); ucstring arg1; nlverify(CLuaIHM::getUCStringOnStack(ls, 1, arg1)); addLine(arg1, ls.toString(2), ls.toString(3), ls.toString(4)); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaAddLineAtIndex(CLuaState &ls) { const char *funcName = "addLineAtIndex"; CLuaIHM::checkArgCount(ls, funcName, 5); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); CLuaIHM::checkArgTypeUCString(ls, funcName, 2); CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING); CLuaIHM::checkArgType(ls, funcName, 4, LUA_TSTRING); CLuaIHM::checkArgType(ls, funcName, 5, LUA_TSTRING); ucstring arg2; nlverify(CLuaIHM::getUCStringOnStack(ls, 2, arg2)); addLineAtIndex((uint) ls.toNumber(1), arg2, ls.toString(3), ls.toString(4), ls.toString(5)); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaAddSeparator(CLuaState &ls) { CLuaIHM::checkArgCount(ls, "addSeparator", 0); addSeparator(); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaAddSeparatorAtIndex(CLuaState &ls) { const char *funcName = "addSeparatorAtIndex"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); addSeparatorAtIndex((uint) ls.toNumber(1)); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaRemoveLine(CLuaState &ls) { const char *funcName = "removeLine"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); removeLine((uint) ls.toNumber(1)); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaSetUserGroupRight(CLuaState &ls) { const char *funcName = "setUserGroupRight"; CLuaIHM::checkArgCount(ls, funcName, 2); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); if (!(CLuaIHM::isUIOnStack(ls, 2) || ls.isNil(2))) { CLuaIHM::fails(ls, toString("%s : Group required as argument 2", funcName)); } CInterfaceElement *el = CLuaIHM::getUIOnStack(ls, 2); CInterfaceGroup *group = dynamic_cast(el); if (el && !group) { CLuaIHM::fails(ls, "%s : Group required as argument 2", funcName); } setUserGroupRight((uint) ls.toNumber(1), group, true); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaSetUserGroupLeft(CLuaState &ls) { const char *funcName = "setUserGroupLeft"; CLuaIHM::checkArgCount(ls, funcName, 2); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); if (!(CLuaIHM::isUIOnStack(ls, 2) || ls.isNil(2))) { CLuaIHM::fails(ls, "%s : Group required as argument 2", funcName); } CInterfaceElement *el = CLuaIHM::getUIOnStack(ls, 2); CInterfaceGroup *group = dynamic_cast(el); if (el && !group) { CLuaIHM::fails(ls, "%s : Group required as argument 2", funcName); } setUserGroupLeft((uint) ls.toNumber(1), group, true); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetUserGroupRight(CLuaState &ls) { const char *funcName = "getUserGroupRight"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); CLuaIHM::pushUIOnStack(ls, getUserGroupRight((uint) ls.toNumber(1))); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaGetUserGroupLeft(CLuaState &ls) { const char *funcName = "getUserGroupLeft"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); CInterfaceElement *pIE = getUserGroupLeft((uint) ls.toNumber(1)); if (pIE) { CLuaIHM::pushUIOnStack(ls, pIE); return 1; } else return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaSetMaxVisibleLine(CLuaState &ls) { const char *funcName = "setMaxVisibleLine"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); setMaxVisibleLine((uint) ls.toNumber(1)); return 0; } // ------------------------------------------------------------------------------------------------ int CGroupSubMenu::luaReset(CLuaState &ls) { const char *funcName = "reset"; CLuaIHM::checkArgCount(ls, funcName, 0); reset(); return 0; } // ------------------------------------------------------------------------------------------------ // CGroupMenu // ------------------------------------------------------------------------------------------------ NLMISC_REGISTER_OBJECT(CViewBase, CGroupMenu, std::string, "menu"); // ------------------------------------------------------------------------------------------------ CGroupMenu::CGroupMenu(const TCtorParam ¶m) :CGroupModal(param) { _Active = false; _Color = CRGBA::White; _ColorOver = CRGBA::White; _ColorGrayed = CRGBA(128, 128, 128, 255); _ShadowColor = CRGBA::Black; _ShadowColorOver = CRGBA::Black; _ShadowColorGrayed = CRGBA::Black; _HighLightOver.set(128, 0, 0, 255); _FontSize = 12; _Shadow = false; _ResizeFromChildH = _ResizeFromChildW = true; _DisplayFrame = false; _RootMenu = NULL; _Space = 3; _CaseMode = CaseUpper; _Formatted = false; } // ------------------------------------------------------------------------------------------------ CGroupMenu::~CGroupMenu() { } // ------------------------------------------------------------------------------------------------ bool CGroupMenu::parse (xmlNodePtr in, CInterfaceGroup *parentGroup) { CXMLAutoPtr prop; _FontSize = 12; // override source menu options (if there's one) if (!CGroupModal::parse(in, parentGroup)) return false; // see if this menu extends another menu prop= (char*) xmlGetProp( in, (xmlChar*)"extends" ); CGroupSubMenu *gmExtended = NULL; if (prop) { CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMenu *gm = dynamic_cast(im->getElementFromId(prop)); if (!gm) { gm = dynamic_cast(im->getElementFromId("ui:interface:" + std::string((const char*)prop))); } if (gm) { gmExtended = gm->_RootMenu; // copy group frame parameters CGroupFrame::copyOptionFrom(*gm); // copy basic datas _Color = gm->_Color; _ShadowColor = gm->_ShadowColor; _Shadow = gm->_Shadow; _FontSize = gm->_FontSize; _ColorOver = gm->_ColorOver; _ShadowColorOver = gm->_ShadowColorOver; _HighLightOver = gm->_HighLightOver; _ColorGrayed = gm->_ColorGrayed; _ShadowColorGrayed = gm->_ShadowColorGrayed; _Priority = gm->_Priority; _ModulateGlobalColor = gm->_ModulateGlobalColor; _Space = gm->_Space; _CaseMode = gm->_CaseMode; } else { nlwarning("Can't get menu %s or bad type", (const char *) prop); } } // Override the modal behaviour because of sub menus ExitClickOut = true; ExitClickL = false; ExitClickR = false; ExitKeyPushed = true; _ResizeFromChildH = _ResizeFromChildW = true; _DisplayFrame = false; _Active = false; _Formatted = false; // text colors prop= (char*) xmlGetProp( in, (xmlChar*)"color" ); if (prop) _Color = convertColor(prop); prop = (char*) xmlGetProp( in, (xmlChar*)"case_mode" ); if (prop) { sint32 caseMode; fromString((const char*)prop, caseMode); _CaseMode = (TCaseMode)caseMode; } prop= (char*) xmlGetProp( in, (xmlChar*)"shadow_color" ); if (prop) _ShadowColor = convertColor(prop); prop= (char*) xmlGetProp( in, (xmlChar*)"color_over" ); if (prop) _ColorOver = convertColor(prop); prop= (char*) xmlGetProp( in, (xmlChar*)"shadow_color_over" ); if (prop) _ShadowColorOver = convertColor(prop); prop= (char*) xmlGetProp( in, (xmlChar*)"highlight_over" ); if (prop) _HighLightOver = convertColor(prop); prop= (char*) xmlGetProp( in, (xmlChar*)"color_grayed" ); if (prop) _ColorGrayed = convertColor(prop); prop= (char*) xmlGetProp( in, (xmlChar*)"shadow_color_grayed" ); if (prop) _ShadowColorGrayed = convertColor(prop); prop = (char*) xmlGetProp (in, (xmlChar*)"space"); if (prop) fromString((const char*)prop, _Space); // Text props prop = (char*) xmlGetProp( in, (xmlChar*)"fontsize" ); if (prop) fromString((const char*)prop, _FontSize); prop = (char*) xmlGetProp( in, (xmlChar*)"shadow" ); if (prop) _Shadow = convertBool(prop); prop = (char*) xmlGetProp( in, (xmlChar*)"formatted" ); if (prop) _Formatted = convertBool(prop); // Read sons xmlNodePtr cur; cur = in->children; if (_RootMenu != NULL) delete _RootMenu; _RootMenu = new CGroupSubMenu(CViewText::TCtorParam()); _RootMenu->_GroupMenu = this; _RootMenu->parse (cur); prop = (char*) xmlGetProp( in, (xmlChar*)"max_visible_line" ); if (prop) { sint32 maxVisibleLine; fromString((const char*)prop, maxVisibleLine); _RootMenu->setMaxVisibleLine(maxVisibleLine); } if (gmExtended) { gmExtended->cloneMenu(_RootMenu, this); } return true; } // ------------------------------------------------------------------------------------------------ void CGroupMenu::recurseDraw(CGroupSubMenu *pSubMenu) { pSubMenu->draw(); // const vector &rGroups = pSubMenu->getGroups(); for (uint32 i = 0; i < pSubMenu->getNumLines(); i++) { CGroupSubMenu *pGSM = pSubMenu->getSubMenu(i); if (pGSM != NULL) { recurseDraw(pGSM); CInterfaceManager::getInstance()->getViewRenderer().flush(); } } } // ------------------------------------------------------------------------------------------------ void CGroupMenu::draw () { if (!_Active) return; // TEMP TEMP //CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer(); //rVR.drawRotFlipBitmap _RenderLayer, (_XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(255, 0, 0, 255) ); _RootMenu->_Active = true; if (SpawnOnMousePos) recurseDraw(_RootMenu); else CGroupModal::draw(); } // ------------------------------------------------------------------------------------------------ bool CGroupMenu::handleEvent (const CEventDescriptor &event) { if (!_Active) return false; return CGroupModal::handleEvent (event); } // ------------------------------------------------------------------------------------------------ CInterfaceElement* CGroupMenu::getElement (const std::string &id) { if (id == getId()) return this; CInterfaceElement *pIE = _RootMenu->getElement(id); if (pIE != NULL) return pIE; return CGroupModal::getElement(id); } // ------------------------------------------------------------------------------------------------ void CGroupMenu::setActive (bool state) { if (SpawnOnMousePos) { CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer(); uint32 w,h; rVR.getScreenSize(w,h); setW(w); setH(h); setX(0); setY(0); _ResizeFromChildH = _ResizeFromChildW = false; _RootMenu->_PosRef = Hotspot_TL; _RootMenu->_ParentPosRef = Hotspot_BL; } CGroupFrame::setActive (state); // must recompute now the pos of the menu uint32 i; for (i = 0; i < _ChildrenGroups.size(); ++i) { _ChildrenGroups[i]->setActive (true); } CGroupModal::updateCoords(); // hide sub menus _RootMenu->hideSubMenus(); } // ------------------------------------------------------------------------------------------------ bool CGroupSubMenu::isSeparator(uint i) const { if (i >= _SubMenus.size()) { nlassert("bad index"); return false; } return _Lines[i].Separator != NULL; } // ------------------------------------------------------------------------------------------------ bool CGroupMenu::isWindowUnder (sint32 x, sint32 y) { for (uint32 i = 0; i < _ChildrenGroups.size(); ++i) if (_ChildrenGroups[i]->getActive ()) if (_ChildrenGroups[i]->isWindowUnder(x, y)) return true; return false; } // ------------------------------------------------------------------------------------------------ void CGroupMenu::addLine (const string &name, const string &ah, const string ¶ms, const std::string &id/*=std::string()*/, const std::string &cond /*= std::string()*/, const std::string &texture, bool checkable /*= false*/, bool checked /*= false*/ ) { if (_RootMenu == NULL) { _RootMenu = new CGroupSubMenu(CViewText::TCtorParam()); _RootMenu->_GroupMenu = this; addGroup (_RootMenu); } _RootMenu->addLine (name, ah, params, id, cond, texture, checkable, checked, _Formatted); } // ------------------------------------------------------------------------------------------------ void CGroupMenu::addLine(const ucstring &name, const std::string &ah, const std::string ¶ms, const std::string &id /* = std::string()*/, const std::string &cond /*= std::string()*/, const std::string &texture, bool checkable /*= false*/, bool checked /*= false*/ ) { if (_RootMenu == NULL) { _RootMenu = new CGroupSubMenu(CViewText::TCtorParam()); _RootMenu->_GroupMenu = this; addGroup (_RootMenu); } _RootMenu->addLine (name, ah, params, id, cond, texture, checkable, checked, _Formatted); } // ------------------------------------------------------------------------------------------------ void CGroupMenu::addLineAtIndex(uint index, const ucstring &name, const std::string &ah, const std::string ¶ms, const std::string &id /*=std::string()*/, const std::string &cond /*=std::string()*/, const std::string &texture, bool checkable /*=false*/, bool checked /*=false*/) { if (_RootMenu == NULL) { _RootMenu = new CGroupSubMenu(CViewText::TCtorParam()); _RootMenu->_GroupMenu = this; addGroup (_RootMenu); } _RootMenu->addLineAtIndex(index, name, ah, params, id, cond, texture, checkable, checked, _Formatted); } // ------------------------------------------------------------------------------------------------ void CGroupMenu::reset () { if ( _RootMenu ) { _RootMenu->reset(); invalidateCoords(); } } // ------------------------------------------------------------------------------------------------ void CGroupMenu::setMinW(sint32 minW) { if ( _RootMenu ) { _RootMenu->_GroupList->setMinW(minW-_RootMenu->getResizeFromChildWMargin()); _RootMenu->_GroupList->setW(minW-_RootMenu->getResizeFromChildWMargin()); _RootMenu->setW(minW-_RootMenu->getResizeFromChildWMargin()); } } // ------------------------------------------------------------------------------------------------ void CGroupMenu::setGrayedLine(uint line, bool g) { if ( _RootMenu ) { _RootMenu->setGrayedLine(line, g); } } // ------------------------------------------------------------------------------------------------ uint CGroupMenu::getNumLine() const { return _RootMenu ? _RootMenu->getNumLine() : 0; } // ------------------------------------------------------------------------------------------------ void CGroupMenu::deleteLine(uint index) { if (index > getNumLine()) { nlwarning("bad index"); return; } _RootMenu->removeLine(index); } // ------------------------------------------------------------------------------------------------ const std::string CGroupMenu::getActionHandler(uint lineIndex) const { return _RootMenu ? _RootMenu->getActionHandler(lineIndex) : ""; } // ------------------------------------------------------------------------------------------------ const std::string CGroupMenu::getActionHandlerParam(uint lineIndex) const { return _RootMenu ? _RootMenu->getActionHandlerParam(lineIndex) : ""; } // ------------------------------------------------------------------------------------------------ void CGroupMenu::setUserGroupRight(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/) { if (_RootMenu) { _RootMenu->setUserGroupRight(line, gr, ownerShip); } } // ------------------------------------------------------------------------------------------------ void CGroupMenu::setUserGroupLeft(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/) { if (_RootMenu) { _RootMenu->setUserGroupLeft(line, gr, ownerShip); } } // ------------------------------------------------------------------------------------------------ int CGroupMenu::luaGetRootMenu(CLuaState &ls) { CLuaIHM::checkArgCount(ls, "getRootMenu", 0); CLuaIHM::pushUIOnStack(ls, getRootMenu()); return 1; } // ------------------------------------------------------------------------------------------------ int CGroupMenu::luaSetMinW(CLuaState &ls) { const char *funcName = "setMinW"; CLuaIHM::checkArgCount(ls, funcName, 1); CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); setMinW((sint32) ls.toNumber(1)); return 0; }