// 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 "nel/gui/view_bitmap_combo.h" #include "nel/misc/xml_auto_ptr.h" #include "nel/gui/db_manager.h" #include "nel/gui/view_renderer.h" #include "nel/gui/widget_manager.h" #include "nel/gui/view_pointer_base.h" #include "nel/gui/interface_group.h" using namespace NLMISC; namespace NLGUI { //======================================================================================= bool CComboBoxDesc::parse(xmlNodePtr cur, CInterfaceElement*owner) { nlassert(owner); const std::string &ownerId = owner->getId(); CXMLAutoPtr prop; // prop = xmlGetProp(cur, (const xmlChar *) "selected"); if (!prop) { nlwarning((ownerId + " : Couldn't read 'selected' field").c_str()); return false; } owner->relativeSInt64Read(CurrSelected, "selected", prop, "0"); // prop = xmlGetProp(cur, (const xmlChar *) "num_row"); owner->relativeSInt64Read(NumRow, "num_row", prop, "1"); // prop = xmlGetProp(cur, (const xmlChar *) "num_col"); owner->relativeSInt64Read(NumCol, "num_col", prop, "1"); // prop = xmlGetProp(cur, (const xmlChar *) "itemw"); owner->relativeSInt64Read(ItemWidth, "itemw", prop, "32"); // prop = xmlGetProp(cur, (const xmlChar *) "itemh"); owner->relativeSInt64Read(ItemHeight, "itemh", prop, "32"); // prop = xmlGetProp(cur, (const xmlChar *) "unrolled"); owner->relativeBoolRead(Unrolled, "unrolled", prop, "false"); // prop = xmlGetProp(cur, (xmlChar *) "wgap"); owner->relativeSInt64Read(WGap, "wgap", prop, "0"); // prop = xmlGetProp(cur, (xmlChar *) "hgap"); owner->relativeSInt64Read(HGap, "hgap", prop, "0"); // prop = xmlGetProp(cur, (xmlChar *) "wgap_selected"); owner->relativeSInt64Read(WGapSelected, "wgap_selected", prop, "0"); // prop = xmlGetProp(cur, (xmlChar *) "hgap_selected"); owner->relativeSInt64Read(HGapSelected, "hgap_selected", prop, "0"); // // prop = xmlGetProp(cur, (xmlChar *) "num_sel"); owner->relativeSInt64Read(NumSel, "num_sel", prop, "1"); // prop = (char*) xmlGetProp (cur, (xmlChar*)"align"); Align.readSInt32 ("0", ownerId + ":align"); if (prop) { const char *seekPtr = prop.getDatas(); while (*seekPtr != 0) { if ((*seekPtr=='l')||(*seekPtr=='L')) { Align.setSInt32 (Align.getSInt32()&(~1)); } if ((*seekPtr=='r')||(*seekPtr=='R')) { Align.setSInt32 (Align.getSInt32()|1); } if ((*seekPtr=='b')||(*seekPtr=='B')) { Align.setSInt32 (Align.getSInt32()&(~2)); } if ((*seekPtr=='t')||(*seekPtr=='T')) { Align.setSInt32 (Align.getSInt32()|2); } ++seekPtr; } } // return true; } //========================================================================================= void CComboBoxDesc::addObserver(ICDBNode::IPropertyObserver *obs) { // Add observers on dimensions if (NumRow.getNodePtr()) { ICDBNode::CTextId textId; NumRow.getNodePtr()->addObserver(obs, textId); } if (NumCol.getNodePtr()) { ICDBNode::CTextId textId; NumCol.getNodePtr()->addObserver(obs, textId); } if (ItemWidth.getNodePtr()) { ICDBNode::CTextId textId; ItemWidth.getNodePtr()->addObserver(obs, textId); } if (ItemHeight.getNodePtr()) { ICDBNode::CTextId textId; ItemHeight.getNodePtr()->addObserver(obs, textId); } if (Unrolled.getNodePtr()) { ICDBNode::CTextId textId; Unrolled.getNodePtr()->addObserver(obs, textId); } } //======================================================================================= void CComboBoxDesc::getGridSize(uint &numRow, uint &numCol) const { numRow = NumRow.getSInt32(); numCol = NumCol.getSInt32(); if (numRow == 0 || numCol == 0) return; if (!Unrolled.getBool()) { numRow = numCol = 1; } } //======================================================================================= void CComboBoxDesc::getDimensions(uint &w, uint &h) const { uint numRow, numCol; getGridSize(numRow, numCol); w = numCol * (ItemWidth.getSInt32() + WGap.getSInt32()); h = numRow * (ItemHeight.getSInt32() + HGap.getSInt32()); // if (numCol == 1) w -= WGap.getSInt32(); else w += WGapSelected.getSInt32() - WGap.getSInt32(); // if (numRow == 1) h -= HGap.getSInt32(); else h += HGapSelected.getSInt32() - HGap.getSInt32(); } //======================================================================================= NLMISC_REGISTER_OBJECT(CViewBase, CViewBitmapCombo, std::string, "bitmap_combo"); CViewBitmapCombo::CViewBitmapCombo(const TCtorParam ¶m) : CViewBase(param) { } //======================================================================================= bool CViewBitmapCombo::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup) { if (! CViewBase::parse(cur, parentGroup) ) { parseError(parentGroup); return false; } CXMLAutoPtr prop; std::string texs; prop = xmlGetProp(cur, (xmlChar *)"tx_normal"); if (prop) texs = (const char*)prop; std::string texsOver; prop = xmlGetProp(cur, (xmlChar *)"tx_over"); if (prop) texsOver = (const char*)prop; std::string texsPushed; prop = xmlGetProp(cur, (xmlChar *)"tx_pushed"); if (prop) texsPushed = (const char*)prop; // // for colors, an empty strings means all colors are white // std::string col; prop = xmlGetProp(cur, (xmlChar *)"col_normal"); if (prop) col = (const char*)prop; std::string colOver; prop = xmlGetProp(cur, (xmlChar *)"col_over"); if (prop) colOver = (const char*)prop; std::string colPushed; prop = xmlGetProp(cur, (xmlChar *)"col_pushed"); if (prop) colPushed = (const char*)prop; /* if (texs.empty() || texsOver.empty() || texsPushed.empty()) { parseError(parentGroup, "Cannot read tx_normal, tx_over, or tx_pushed"); return false; }*/ parseTexList(texs, _Texs); parseTexList(texsOver, _TexsOver); parseTexList(texsPushed, _TexsPushed); parseColList(col, _Col); parseColList(colOver, _ColOver); parseColList(colPushed, _ColPushed); // /* if (_Texs.size() != _TexsOver.size() || _TexsOver.size() != _TexsPushed.size()) { parseError(parentGroup, "Texture names arrays do not have the same size"); return false; } // uint numCols = NLMISC::maxof(_Col.size(), _ColOver.size(), _ColPushed.size()); if (! ( (_Col.empty() || _Col.size() == numCols) && (_ColOver.empty() || _ColOver.size() == numCols) && (_ColPushed.empty() || _ColPushed.size() == numCols) ) ) { parseError(parentGroup, "Color names arrays do not have the same size (note an empty array is valid, means all color are 255 255 255"); return false; }*/ // if (!_CD.parse(cur, this)) { return false; } // setupSize(); // _CD.addObserver(this); return true; } //======================================================================================= NLMISC::CRGBA CViewBitmapCombo::getCol(const CViewBitmapCombo::TColorArray &array,uint index) { if (array.empty()) return CRGBA::White; return array[index % array.size()]; } //======================================================================================= const std::string *CViewBitmapCombo::getTex(const TStringArray &array,uint index) { if (array.empty()) return NULL; return &array[index % array.size()]; } //======================================================================================= sint32 CViewBitmapCombo::getTexId(const TIdArray &array, uint index) { if (array.empty()) return -1; return array[index % array.size()]; } //======================================================================================= void CViewBitmapCombo::draw() { if (_Texs.empty()) return; uint numRow, numCol; _CD.getGridSize(numRow, numCol); if (numRow == 0 || numCol == 0) return; sint32 mx = 0, my = 0; CViewRenderer &rVR = *CViewRenderer::getInstance(); const std::vector &rVB = CWidgetManager::getInstance()->getViewsUnderPointer(); if (!CWidgetManager::getInstance()->getPointer()) return; CWidgetManager::getInstance()->getPointer()->getPointerDispPos(mx, my); bool over = false; uint32 i; for (i = 0; i < rVB.size(); ++i) { if (rVB[i] == this) { over = true; break; } } if (_TexsId.size() == 0) { for (i = 0; i < _Texs.size(); ++i) _TexsId.push_back(rVR.getTextureIdFromName(_Texs[i])); for (i = 0; i < _TexsOver.size(); ++i) _TexsOverId.push_back(rVR.getTextureIdFromName(_TexsOver[i])); for (i = 0; i < _TexsPushed.size(); ++i) _TexsPushedId.push_back(rVR.getTextureIdFromName(_TexsPushed[i])); } sint32 textId; CRGBA color; uint selectedTexIndex = _CD.CurrSelected.getSInt32(); uint itemw = _CD.ItemWidth.getSInt32() + _CD.WGap.getSInt32(); uint itemh = _CD.ItemHeight.getSInt32() + _CD.HGap.getSInt32(); uint counter = 0; bool overItem = false; for(uint x = 0; x < numCol; ++x) { for(uint y = 0; y < numRow; ++y) { uint texIndex = counter; if (counter != 0) { if (counter == selectedTexIndex) { texIndex = 0; } sint px; sint py; // get the right position depending on alignment if (_CD.Align.getSInt32() & 1) // right align ? { px = _XReal + _WReal - (x + 1) * itemw; } else { px = _XReal + x * itemw; } // top align ? if (_CD.Align.getSInt32() & 2) { py = _YReal + _HReal - (y + 1) * itemh; } else { py = _YReal + y * itemh; } if (x != 0) { if (_CD.Align.getSInt32() & 1) px -= _CD.WGapSelected.getSInt32() - _CD.WGap.getSInt32(); else px += _CD.WGapSelected.getSInt32() - _CD.WGap.getSInt32(); } if (y != 0) { if (_CD.Align.getSInt32() & 2) py -= _CD.HGapSelected.getSInt32() - _CD.HGap.getSInt32(); else py += _CD.HGapSelected.getSInt32() - _CD.HGap.getSInt32(); } // is the mouse on current item ? if (over && mx >= px && my >= py && mx < px + (sint32) itemw && my < py + (sint32) itemh) { overItem = true; if ( CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton) { textId = getTexId(_TexsPushedId, texIndex); color = getCol(_ColPushed, texIndex); } else { textId = getTexId(_TexsOverId, texIndex); color = getCol(_ColOver, texIndex); } } else { textId = getTexId(_TexsId, texIndex); color = getCol(_Col, texIndex); } CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer, px, py, itemw, itemh, 0, false, textId, color); } ++counter; if ((sint32) counter == _CD.NumSel.getSInt32()) break; } } if ((sint32) selectedTexIndex >= _CD.NumSel.getSInt32()) { return; } // draw current selection sint32 px; sint32 py; // if (_CD.Align.getSInt32() & 1) { px = _XReal + _WReal - itemw; } else { px = _XReal; } // if (_CD.Align.getSInt32() & 2) { py = _YReal + _HReal - itemh; } else { py = _YReal; } // if (_CD.Unrolled.getBool()) { if (overItem && CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton) { textId = getTexId(_TexsId, selectedTexIndex); color = getCol(_Col, selectedTexIndex); } else { textId = getTexId(_TexsPushedId, selectedTexIndex); color = getCol(_ColPushed, selectedTexIndex); } } else { if (over && mx >= px && my >= py && mx < px + (sint32) itemw && my < py + (sint32) itemh ) { if ( CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton) { textId = getTexId(_TexsPushedId, selectedTexIndex); color = getCol(_ColPushed, selectedTexIndex); } else { textId = getTexId(_TexsOverId, selectedTexIndex); color = getCol(_ColOver, selectedTexIndex); } } else { textId = getTexId(_TexsId, selectedTexIndex); color = getCol(_Col, selectedTexIndex); } } CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer, px, py, itemw, itemh, 0, false, textId, color); } //======================================================================================= void CViewBitmapCombo::parseTexList(const std::string &names, TStringArray &dest) { static const char sep[] = " ,\t"; std::string::size_type pos = 0, nextPos; dest.clear(); do { nextPos = names.find_first_of(sep, pos); if (pos != nextPos) { dest.push_back(names.substr(pos, nextPos - pos)); } pos = names.find_first_not_of(sep, nextPos); } while (pos != std::string::npos); } //======================================================================================= void CViewBitmapCombo::parseColList(const std::string &names,TColorArray &dest) { static const char sep[] = ",\t"; std::string::size_type pos = 0, nextPos; dest.clear(); std::string col; do { nextPos = names.find_first_of(sep, pos); if (pos != nextPos) { col = names.substr(pos, nextPos - pos); int r = 0, g = 0, b = 0, a = 255; sscanf (col.c_str(), "%d %d %d %d", &r, &g, &b, &a); NLMISC::clamp (r, 0, 255); NLMISC::clamp (g, 0, 255); NLMISC::clamp (b, 0, 255); NLMISC::clamp (a, 0, 255); dest.push_back(NLMISC::CRGBA((uint8) r, (uint8) g, (uint8) b, (uint8) a)); } pos = names.find_first_not_of(sep, nextPos); } while (pos != std::string::npos); } //======================================================================================= void CViewBitmapCombo::setupSize() { uint w, h; _CD.getDimensions(w, h); setW(w); setH(h); invalidateCoords(); } //======================================================================================= void CViewBitmapCombo::update(ICDBNode * /* leaf */) { setupSize(); } //======================================================================================= /** copy an array of char * into an array of strings */ static void copyStrArrayFromChar(CViewBitmapCombo::TStringArray &dest, const char * const src[], uint numColor) { dest.resize(numColor); for(uint k = 0; k < numColor; ++k) { dest[k] = src[k]; } } static void copyRGBAVectorFromRGBAArray(CViewBitmapCombo::TColorArray &dest, const NLMISC::CRGBA src[], uint numColor) { dest.resize(numColor); std::copy(src, src + numColor, dest.begin()); } //======================================================================================= void CViewBitmapCombo::setTexs(const char * const tex[], uint numTex) { copyStrArrayFromChar(_Texs, tex, numTex); } //======================================================================================= void CViewBitmapCombo::setTexsOver(const char * const tex[], uint numTex) { copyStrArrayFromChar(_TexsOver, tex, numTex); } //======================================================================================= void CViewBitmapCombo::setTexsPushed(const char * const tex[], uint numTex) { copyStrArrayFromChar(_TexsPushed, tex, numTex); } //======================================================================================= void CViewBitmapCombo::setColors(const NLMISC::CRGBA colors[], uint numColors) { copyRGBAVectorFromRGBAArray(_Col, colors, numColors); } //======================================================================================= void CViewBitmapCombo::setColorsOver(const NLMISC::CRGBA colors[], uint numColors) { copyRGBAVectorFromRGBAArray(_ColOver, colors, numColors); } //======================================================================================= void CViewBitmapCombo::setColorsPushed(const NLMISC::CRGBA colors[], uint numColors) { copyRGBAVectorFromRGBAArray(_ColPushed, colors, numColors); } }