1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
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/>.
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
;
38 //=======================================================================================
39 bool CComboBoxDesc::parse(xmlNodePtr cur
, CInterfaceElement
*owner
)
42 const std::string
&ownerId
= owner
->getId();
45 prop
= xmlGetProp(cur
, (const xmlChar
*) "selected");
48 nlwarning((ownerId
+ " : Couldn't read 'selected' field").c_str());
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");
88 const char *seekPtr
= prop
.getDatas();
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);
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())
158 //=======================================================================================
159 void CComboBoxDesc::getDimensions(uint
&w
, uint
&h
) const
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
¶m
) : CViewBase(param
)
180 std::string
CViewBitmapCombo::getProperty( const std::string
&name
) const
182 if( name
== "tx_normal" )
185 getTexList( _Texs
, normal
);
189 if( name
== "tx_over" )
192 getTexList( _TexsOver
, over
);
196 if( name
== "tx_pushed" )
199 getTexList( _TexsPushed
, pushed
);
203 if( name
== "col_normal" )
206 getColList( _Col
, normal
);
210 if( name
== "col_over" )
213 getColList( _ColOver
, over
);
217 if( name
== "col_pushed" )
220 getColList( _ColPushed
, pushed
);
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
);
235 if( name
== "tx_over" )
237 parseTexList( value
, _TexsOver
);
241 if( name
== "tx_pushed" )
243 parseTexList( value
, _TexsPushed
);
247 if( name
== "col_normal" )
249 parseColList( value
, _Col
);
253 if( name
== "col_over" )
255 parseColList( value
, _ColOver
);
259 if( name
== "col_pushed" )
261 parseColList( value
, _ColPushed
);
265 CViewBase::setProperty( name
, value
);
268 xmlNodePtr
CViewBitmapCombo::serialize( xmlNodePtr parentNode
, const char *type
) const
270 xmlNodePtr node
= CViewBase::serialize( parentNode
, type
);
274 xmlSetProp( node
, BAD_CAST
"type", BAD_CAST
"bitmap_combo" );
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() );
298 //=======================================================================================
299 bool CViewBitmapCombo::parse(xmlNodePtr cur
, CInterfaceGroup
* parentGroup
)
301 if (! CViewBase::parse(cur
, parentGroup
) )
303 parseError(parentGroup
);
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
322 prop
= xmlGetProp(cur
, (xmlChar
*)"col_normal");
323 if (prop
) col
= (const char*)prop
;
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");
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");
351 uint numCols = NLMISC::maxof(_Col.size(), _ColOver.size(), _ColPushed.size());
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");
364 if (!_CD
.parse(cur
, this))
371 _CD
.addObserver(this);
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;
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
);
412 for (i
= 0; i
< rVB
.size(); ++i
)
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
]));
433 uint selectedTexIndex
= _CD
.CurrSelected
.getSInt32();
434 uint itemw
= _CD
.ItemWidth
.getSInt32() + _CD
.WGap
.getSInt32();
435 uint itemh
= _CD
.ItemHeight
.getSInt32() + _CD
.HGap
.getSInt32();
438 bool overItem
= false;
439 for(uint x
= 0; x
< numCol
; ++x
)
441 for(uint y
= 0; y
< numRow
; ++y
)
443 uint texIndex
= counter
;
446 if (counter
== selectedTexIndex
)
452 // get the right position depending on alignment
453 if (_CD
.Align
.getSInt32() & 1) // right align ?
455 px
= _XReal
+ _WReal
- (x
+ 1) * itemw
;
459 px
= _XReal
+ x
* itemw
;
462 if (_CD
.Align
.getSInt32() & 2)
464 py
= _YReal
+ _HReal
- (y
+ 1) * itemh
;
468 py
= _YReal
+ y
* itemh
;
473 if (_CD
.Align
.getSInt32() & 1)
474 px
-= _CD
.WGapSelected
.getSInt32() - _CD
.WGap
.getSInt32();
475 else px
+= _CD
.WGapSelected
.getSInt32() - _CD
.WGap
.getSInt32();
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 ?
487 && mx
< px
+ (sint32
) itemw
488 && my
< py
+ (sint32
) itemh
)
491 if ( CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton
)
493 textId
= getTexId(_TexsPushedId
, texIndex
);
494 color
= getCol(_ColPushed
, texIndex
);
498 textId
= getTexId(_TexsOverId
, texIndex
);
499 color
= getCol(_ColOver
, texIndex
);
504 textId
= getTexId(_TexsId
, texIndex
);
505 color
= getCol(_Col
, texIndex
);
507 CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer
, px
, py
, itemw
, itemh
, 0, false,
512 if ((sint32
) counter
== _CD
.NumSel
.getSInt32())
517 if ((sint32
) selectedTexIndex
>= _CD
.NumSel
.getSInt32())
522 // draw current selection
526 if (_CD
.Align
.getSInt32() & 1)
528 px
= _XReal
+ _WReal
- itemw
;
535 if (_CD
.Align
.getSInt32() & 2)
537 py
= _YReal
+ _HReal
- itemh
;
544 if (_CD
.Unrolled
.getBool())
546 if (overItem
&& CWidgetManager::getInstance()->getPointer()->getButtonState() & NLMISC::leftButton
)
548 textId
= getTexId(_TexsId
, selectedTexIndex
);
549 color
= getCol(_Col
, selectedTexIndex
);
553 textId
= getTexId(_TexsPushedId
, selectedTexIndex
);
554 color
= getCol(_ColPushed
, selectedTexIndex
);
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
);
573 textId
= getTexId(_TexsOverId
, selectedTexIndex
);
574 color
= getCol(_ColOver
, selectedTexIndex
);
579 textId
= getTexId(_TexsId
, selectedTexIndex
);
580 color
= getCol(_Col
, selectedTexIndex
);
584 CViewRenderer::getInstance()->drawRotFlipBitmap (_RenderLayer
, px
, py
, itemw
, itemh
, 0, false,
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
;
597 nextPos
= names
.find_first_of(sep
, pos
);
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
;
616 nextPos
= names
.find_first_of(sep
, pos
);
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
636 TStringArray::const_iterator itr
;
637 for( itr
= arr
.begin(); itr
!= arr
.end(); ++itr
)
644 void CViewBitmapCombo::getColList( const TColorArray
&arr
, std::string
&dest
) const
647 TColorArray::const_iterator itr
;
648 for( itr
= arr
.begin(); itr
!= arr
.end(); ++itr
)
650 dest
+= toString( *itr
);
655 //=======================================================================================
656 void CViewBitmapCombo::setupSize()
659 _CD
.getDimensions(w
, h
);
665 //=======================================================================================
666 void CViewBitmapCombo::update(ICDBNode
* /* leaf */)
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
)
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
);