Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / view_bitmap_combo.cpp
blobcb89d50428f519bc4649829258add6ec566d1eec
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
21 #include "nel/gui/view_bitmap_combo.h"
22 #include "nel/misc/xml_auto_ptr.h"
23 #include "nel/gui/db_manager.h"
24 #include "nel/gui/view_renderer.h"
25 #include "nel/gui/widget_manager.h"
26 #include "nel/gui/view_pointer_base.h"
27 #include "nel/gui/interface_group.h"
29 using namespace NLMISC;
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 namespace NLGUI
38 //=======================================================================================
39 bool CComboBoxDesc::parse(xmlNodePtr cur, CInterfaceElement*owner)
41 nlassert(owner);
42 const std::string &ownerId = owner->getId();
43 CXMLAutoPtr prop;
45 prop = xmlGetProp(cur, (const xmlChar *) "selected");
46 if (!prop)
48 nlwarning((ownerId + " : Couldn't read 'selected' field").c_str());
49 return false;
51 owner->relativeSInt64Read(CurrSelected, "selected", prop, "0");
53 prop = xmlGetProp(cur, (const xmlChar *) "num_row");
54 owner->relativeSInt64Read(NumRow, "num_row", prop, "1");
56 prop = xmlGetProp(cur, (const xmlChar *) "num_col");
57 owner->relativeSInt64Read(NumCol, "num_col", prop, "1");
59 prop = xmlGetProp(cur, (const xmlChar *) "itemw");
60 owner->relativeSInt64Read(ItemWidth, "itemw", prop, "32");
62 prop = xmlGetProp(cur, (const xmlChar *) "itemh");
63 owner->relativeSInt64Read(ItemHeight, "itemh", prop, "32");
65 prop = xmlGetProp(cur, (const xmlChar *) "unrolled");
66 owner->relativeBoolRead(Unrolled, "unrolled", prop, "false");
68 prop = xmlGetProp(cur, (xmlChar *) "wgap");
69 owner->relativeSInt64Read(WGap, "wgap", prop, "0");
71 prop = xmlGetProp(cur, (xmlChar *) "hgap");
72 owner->relativeSInt64Read(HGap, "hgap", prop, "0");
74 prop = xmlGetProp(cur, (xmlChar *) "wgap_selected");
75 owner->relativeSInt64Read(WGapSelected, "wgap_selected", prop, "0");
77 prop = xmlGetProp(cur, (xmlChar *) "hgap_selected");
78 owner->relativeSInt64Read(HGapSelected, "hgap_selected", prop, "0");
81 prop = xmlGetProp(cur, (xmlChar *) "num_sel");
82 owner->relativeSInt64Read(NumSel, "num_sel", prop, "1");
84 prop = (char*) xmlGetProp (cur, (xmlChar*)"align");
85 Align.readSInt32 ("0", ownerId + ":align");
86 if (prop)
88 const char *seekPtr = prop.getDatas();
89 while (*seekPtr != 0)
91 if ((*seekPtr=='l')||(*seekPtr=='L'))
93 Align.setSInt32 (Align.getSInt32()&(~1));
95 if ((*seekPtr=='r')||(*seekPtr=='R'))
97 Align.setSInt32 (Align.getSInt32()|1);
99 if ((*seekPtr=='b')||(*seekPtr=='B'))
101 Align.setSInt32 (Align.getSInt32()&(~2));
103 if ((*seekPtr=='t')||(*seekPtr=='T'))
105 Align.setSInt32 (Align.getSInt32()|2);
107 ++seekPtr;
111 return true;
115 //=========================================================================================
116 void CComboBoxDesc::addObserver(ICDBNode::IPropertyObserver *obs)
118 // Add observers on dimensions
119 if (NumRow.getNodePtr())
121 ICDBNode::CTextId textId;
122 NumRow.getNodePtr()->addObserver(obs, textId);
124 if (NumCol.getNodePtr())
126 ICDBNode::CTextId textId;
127 NumCol.getNodePtr()->addObserver(obs, textId);
129 if (ItemWidth.getNodePtr())
131 ICDBNode::CTextId textId;
132 ItemWidth.getNodePtr()->addObserver(obs, textId);
134 if (ItemHeight.getNodePtr())
136 ICDBNode::CTextId textId;
137 ItemHeight.getNodePtr()->addObserver(obs, textId);
139 if (Unrolled.getNodePtr())
141 ICDBNode::CTextId textId;
142 Unrolled.getNodePtr()->addObserver(obs, textId);
146 //=======================================================================================
147 void CComboBoxDesc::getGridSize(uint &numRow, uint &numCol) const
149 numRow = NumRow.getSInt32();
150 numCol = NumCol.getSInt32();
151 if (numRow == 0 || numCol == 0) return;
152 if (!Unrolled.getBool())
154 numRow = numCol = 1;
158 //=======================================================================================
159 void CComboBoxDesc::getDimensions(uint &w, uint &h) const
161 uint numRow, numCol;
162 getGridSize(numRow, numCol);
163 w = numCol * (ItemWidth.getSInt32() + WGap.getSInt32());
164 h = numRow * (ItemHeight.getSInt32() + HGap.getSInt32());
166 if (numCol == 1) w -= WGap.getSInt32();
167 else w += WGapSelected.getSInt32() - WGap.getSInt32();
169 if (numRow == 1) h -= HGap.getSInt32();
170 else h += HGapSelected.getSInt32() - HGap.getSInt32();
173 //=======================================================================================
174 NLMISC_REGISTER_OBJECT(CViewBase, CViewBitmapCombo, std::string, "bitmap_combo");
176 CViewBitmapCombo::CViewBitmapCombo(const TCtorParam &param) : CViewBase(param)
180 std::string CViewBitmapCombo::getProperty( const std::string &name ) const
182 if( name == "tx_normal" )
184 std::string normal;
185 getTexList( _Texs, normal );
186 return normal;
188 else
189 if( name == "tx_over" )
191 std::string over;
192 getTexList( _TexsOver, over );
193 return over;
195 else
196 if( name == "tx_pushed" )
198 std::string pushed;
199 getTexList( _TexsPushed, pushed );
200 return pushed;
202 else
203 if( name == "col_normal" )
205 std::string normal;
206 getColList( _Col, normal );
207 return normal;
209 else
210 if( name == "col_over" )
212 std::string over;
213 getColList( _ColOver, over );
214 return over;
216 else
217 if( name == "col_pushed" )
219 std::string pushed;
220 getColList( _ColPushed, pushed );
221 return pushed;
223 else
224 return CViewBase::getProperty( name );
227 void CViewBitmapCombo::setProperty( const std::string &name, const std::string &value )
229 if( name == "tx_normal" )
231 parseTexList( value, _Texs );
232 return;
234 else
235 if( name == "tx_over" )
237 parseTexList( value, _TexsOver );
238 return;
240 else
241 if( name == "tx_pushed" )
243 parseTexList( value, _TexsPushed );
244 return;
246 else
247 if( name == "col_normal" )
249 parseColList( value, _Col );
250 return;
252 else
253 if( name == "col_over" )
255 parseColList( value, _ColOver );
256 return;
258 else
259 if( name == "col_pushed" )
261 parseColList( value, _ColPushed );
262 return;
264 else
265 CViewBase::setProperty( name, value );
268 xmlNodePtr CViewBitmapCombo::serialize( xmlNodePtr parentNode, const char *type ) const
270 xmlNodePtr node = CViewBase::serialize( parentNode, type );
271 if( node == NULL )
272 return NULL;
274 xmlSetProp( node, BAD_CAST "type", BAD_CAST "bitmap_combo" );
276 std::string normal;
277 std::string over;
278 std::string pushed;
280 getTexList( _Texs, normal );
281 getTexList( _TexsOver, over );
282 getTexList( _TexsPushed, pushed );
283 xmlSetProp( node, BAD_CAST "tx_normal", BAD_CAST normal.c_str() );
284 xmlSetProp( node, BAD_CAST "tx_over", BAD_CAST over.c_str() );
285 xmlSetProp( node, BAD_CAST "tx_pushed", BAD_CAST pushed.c_str() );
287 getColList( _Col, normal );
288 getColList( _ColOver, over );
289 getColList( _ColPushed, pushed );
290 xmlSetProp( node, BAD_CAST "col_normal", BAD_CAST normal.c_str() );
291 xmlSetProp( node, BAD_CAST "col_over", BAD_CAST over.c_str() );
292 xmlSetProp( node, BAD_CAST "col_pushed", BAD_CAST pushed.c_str() );
295 return node;
298 //=======================================================================================
299 bool CViewBitmapCombo::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
301 if (! CViewBase::parse(cur, parentGroup) )
303 parseError(parentGroup);
304 return false;
307 CXMLAutoPtr prop;
309 std::string texs;
310 prop = xmlGetProp(cur, (xmlChar *)"tx_normal");
311 if (prop) texs = (const char*)prop;
312 std::string texsOver;
313 prop = xmlGetProp(cur, (xmlChar *)"tx_over");
314 if (prop) texsOver = (const char*)prop;
315 std::string texsPushed;
316 prop = xmlGetProp(cur, (xmlChar *)"tx_pushed");
317 if (prop) texsPushed = (const char*)prop;
319 // for colors, an empty strings means all colors are white
321 std::string col;
322 prop = xmlGetProp(cur, (xmlChar *)"col_normal");
323 if (prop) col = (const char*)prop;
324 std::string colOver;
325 prop = xmlGetProp(cur, (xmlChar *)"col_over");
326 if (prop) colOver = (const char*)prop;
327 std::string colPushed;
328 prop = xmlGetProp(cur, (xmlChar *)"col_pushed");
329 if (prop) colPushed = (const char*)prop;
331 /* if (texs.empty() || texsOver.empty() || texsPushed.empty())
333 parseError(parentGroup, "Cannot read tx_normal, tx_over, or tx_pushed");
334 return false;
337 parseTexList(texs, _Texs);
338 parseTexList(texsOver, _TexsOver);
339 parseTexList(texsPushed, _TexsPushed);
341 parseColList(col, _Col);
342 parseColList(colOver, _ColOver);
343 parseColList(colPushed, _ColPushed);
345 /* if (_Texs.size() != _TexsOver.size() || _TexsOver.size() != _TexsPushed.size())
347 parseError(parentGroup, "Texture names arrays do not have the same size");
348 return false;
351 uint numCols = NLMISC::maxof(_Col.size(), _ColOver.size(), _ColPushed.size());
352 if (!
354 (_Col.empty() || _Col.size() == numCols)
355 && (_ColOver.empty() || _ColOver.size() == numCols)
356 && (_ColPushed.empty() || _ColPushed.size() == numCols)
360 parseError(parentGroup, "Color names arrays do not have the same size (note an empty array is valid, means all color are 255 255 255");
361 return false;
364 if (!_CD.parse(cur, this))
366 return false;
369 setupSize();
371 _CD.addObserver(this);
373 return true;
376 //=======================================================================================
377 NLMISC::CRGBA CViewBitmapCombo::getCol(const CViewBitmapCombo::TColorArray &array,uint index)
379 if (array.empty()) return CRGBA::White;
380 return array[index % array.size()];
383 //=======================================================================================
384 const std::string *CViewBitmapCombo::getTex(const TStringArray &array,uint index)
386 if (array.empty()) return NULL;
387 return &array[index % array.size()];
390 //=======================================================================================
391 sint32 CViewBitmapCombo::getTexId(const TIdArray &array, uint index)
393 if (array.empty()) return -1;
394 return array[index % array.size()];
397 //=======================================================================================
398 void CViewBitmapCombo::draw()
400 if (_Texs.empty()) return;
401 uint numRow, numCol;
402 _CD.getGridSize(numRow, numCol);
403 if (numRow == 0 || numCol == 0) return;
405 sint32 mx = 0, my = 0;
406 CViewRenderer &rVR = *CViewRenderer::getInstance();
407 const std::vector<CViewBase *> &rVB = CWidgetManager::getInstance()->getViewsUnderPointer();
408 if (!CWidgetManager::getInstance()->getPointer()) return;
409 CWidgetManager::getInstance()->getPointer()->getPointerDispPos(mx, my);
410 bool over = false;
411 uint32 i;
412 for (i = 0; i < rVB.size(); ++i)
414 if (rVB[i] == this)
416 over = true;
417 break;
421 if (_TexsId.empty())
423 for (i = 0; i < _Texs.size(); ++i)
424 _TexsId.push_back(rVR.getTextureIdFromName(_Texs[i]));
425 for (i = 0; i < _TexsOver.size(); ++i)
426 _TexsOverId.push_back(rVR.getTextureIdFromName(_TexsOver[i]));
427 for (i = 0; i < _TexsPushed.size(); ++i)
428 _TexsPushedId.push_back(rVR.getTextureIdFromName(_TexsPushed[i]));
431 sint32 textId;
432 CRGBA color;
433 uint selectedTexIndex = _CD.CurrSelected.getSInt32();
434 uint itemw = _CD.ItemWidth.getSInt32() + _CD.WGap.getSInt32();
435 uint itemh = _CD.ItemHeight.getSInt32() + _CD.HGap.getSInt32();
436 uint counter = 0;
438 bool overItem = false;
439 for(uint x = 0; x < numCol; ++x)
441 for(uint y = 0; y < numRow; ++y)
443 uint texIndex = counter;
444 if (counter != 0)
446 if (counter == selectedTexIndex)
448 texIndex = 0;
450 sint px;
451 sint py;
452 // get the right position depending on alignment
453 if (_CD.Align.getSInt32() & 1) // right align ?
455 px = _XReal + _WReal - (x + 1) * itemw;
457 else
459 px = _XReal + x * itemw;
461 // top align ?
462 if (_CD.Align.getSInt32() & 2)
464 py = _YReal + _HReal - (y + 1) * itemh;
466 else
468 py = _YReal + y * itemh;
471 if (x != 0)
473 if (_CD.Align.getSInt32() & 1)
474 px -= _CD.WGapSelected.getSInt32() - _CD.WGap.getSInt32();
475 else px += _CD.WGapSelected.getSInt32() - _CD.WGap.getSInt32();
477 if (y != 0)
479 if (_CD.Align.getSInt32() & 2)
480 py -= _CD.HGapSelected.getSInt32() - _CD.HGap.getSInt32();
481 else py += _CD.HGapSelected.getSInt32() - _CD.HGap.getSInt32();
483 // is the mouse on current item ?
484 if (over
485 && mx >= px
486 && my >= py
487 && mx < px + (sint32) itemw
488 && my < py + (sint32) itemh)
490 overItem = true;
491 if ( CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton)
493 textId = getTexId(_TexsPushedId, texIndex);
494 color = getCol(_ColPushed, texIndex);
496 else
498 textId = getTexId(_TexsOverId, texIndex);
499 color = getCol(_ColOver, texIndex);
502 else
504 textId = getTexId(_TexsId, texIndex);
505 color = getCol(_Col, texIndex);
507 CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer, px, py, itemw, itemh, 0, false,
508 textId,
509 color);
511 ++counter;
512 if ((sint32) counter == _CD.NumSel.getSInt32())
513 break;
517 if ((sint32) selectedTexIndex >= _CD.NumSel.getSInt32())
519 return;
522 // draw current selection
523 sint32 px;
524 sint32 py;
526 if (_CD.Align.getSInt32() & 1)
528 px = _XReal + _WReal - itemw;
530 else
532 px = _XReal;
535 if (_CD.Align.getSInt32() & 2)
537 py = _YReal + _HReal - itemh;
539 else
541 py = _YReal;
544 if (_CD.Unrolled.getBool())
546 if (overItem && CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton)
548 textId = getTexId(_TexsId, selectedTexIndex);
549 color = getCol(_Col, selectedTexIndex);
551 else
553 textId = getTexId(_TexsPushedId, selectedTexIndex);
554 color = getCol(_ColPushed, selectedTexIndex);
557 else
559 if (over
560 && mx >= px
561 && my >= py
562 && mx < px + (sint32) itemw
563 && my < py + (sint32) itemh
566 if ( CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton)
568 textId = getTexId(_TexsPushedId, selectedTexIndex);
569 color = getCol(_ColPushed, selectedTexIndex);
571 else
573 textId = getTexId(_TexsOverId, selectedTexIndex);
574 color = getCol(_ColOver, selectedTexIndex);
577 else
579 textId = getTexId(_TexsId, selectedTexIndex);
580 color = getCol(_Col, selectedTexIndex);
584 CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer, px, py, itemw, itemh, 0, false,
585 textId,
586 color);
589 //=======================================================================================
590 void CViewBitmapCombo::parseTexList(const std::string &names, TStringArray &dest)
592 static const char sep[] = " ,\t";
593 std::string::size_type pos = 0, nextPos;
594 dest.clear();
597 nextPos = names.find_first_of(sep, pos);
598 if (pos != nextPos)
600 dest.push_back(names.substr(pos, nextPos - pos));
602 pos = names.find_first_not_of(sep, nextPos);
604 while (pos != std::string::npos);
607 //=======================================================================================
608 void CViewBitmapCombo::parseColList(const std::string &names,TColorArray &dest)
610 static const char sep[] = ",\t";
611 std::string::size_type pos = 0, nextPos;
612 dest.clear();
613 std::string col;
616 nextPos = names.find_first_of(sep, pos);
617 if (pos != nextPos)
619 col = names.substr(pos, nextPos - pos);
620 int r = 0, g = 0, b = 0, a = 255;
621 sscanf (col.c_str(), "%d %d %d %d", &r, &g, &b, &a);
622 NLMISC::clamp (r, 0, 255);
623 NLMISC::clamp (g, 0, 255);
624 NLMISC::clamp (b, 0, 255);
625 NLMISC::clamp (a, 0, 255);
626 dest.push_back(NLMISC::CRGBA((uint8) r, (uint8) g, (uint8) b, (uint8) a));
628 pos = names.find_first_not_of(sep, nextPos);
630 while (pos != std::string::npos);
633 void CViewBitmapCombo::getTexList( const TStringArray &arr, std::string &dest ) const
635 dest.clear();
636 TStringArray::const_iterator itr;
637 for( itr = arr.begin(); itr != arr.end(); ++itr )
639 dest += *itr;
640 dest += " ";
644 void CViewBitmapCombo::getColList( const TColorArray &arr, std::string &dest ) const
646 dest.clear();
647 TColorArray::const_iterator itr;
648 for( itr = arr.begin(); itr != arr.end(); ++itr )
650 dest += toString( *itr );
651 dest += " ";
655 //=======================================================================================
656 void CViewBitmapCombo::setupSize()
658 uint w, h;
659 _CD.getDimensions(w, h);
660 setW(w);
661 setH(h);
662 invalidateCoords();
665 //=======================================================================================
666 void CViewBitmapCombo::update(ICDBNode * /* leaf */)
668 setupSize();
672 //=======================================================================================
673 /** copy an array of char * into an array of strings
675 static void copyStrArrayFromChar(CViewBitmapCombo::TStringArray &dest, const char * const src[], uint numColor)
677 dest.resize(numColor);
678 for(uint k = 0; k < numColor; ++k)
680 dest[k] = src[k];
685 static void copyRGBAVectorFromRGBAArray(CViewBitmapCombo::TColorArray &dest, const NLMISC::CRGBA src[], uint numColor)
687 dest.resize(numColor);
688 std::copy(src, src + numColor, dest.begin());
692 //=======================================================================================
693 void CViewBitmapCombo::setTexs(const char * const tex[], uint numTex)
695 copyStrArrayFromChar(_Texs, tex, numTex);
698 //=======================================================================================
699 void CViewBitmapCombo::setTexsOver(const char * const tex[], uint numTex)
701 copyStrArrayFromChar(_TexsOver, tex, numTex);
705 //=======================================================================================
706 void CViewBitmapCombo::setTexsPushed(const char * const tex[], uint numTex)
708 copyStrArrayFromChar(_TexsPushed, tex, numTex);
711 //=======================================================================================
712 void CViewBitmapCombo::setColors(const NLMISC::CRGBA colors[], uint numColors)
714 copyRGBAVectorFromRGBAArray(_Col, colors, numColors);
718 //=======================================================================================
719 void CViewBitmapCombo::setColorsOver(const NLMISC::CRGBA colors[], uint numColors)
721 copyRGBAVectorFromRGBAArray(_ColOver, colors, numColors);
725 //=======================================================================================
726 void CViewBitmapCombo::setColorsPushed(const NLMISC::CRGBA colors[], uint numColors)
728 copyRGBAVectorFromRGBAArray(_ColPushed, colors, numColors);