Fixed: Use target_stepy to calculate dy for scrolling
[ryzomcore.git] / code / nel / src / gui / ctrl_scroll.cpp
blobacdaa15f5693149d6c91b7ae9bfd4c5acbb355e2
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stdpch.h"
19 #include "nel/gui/widget_manager.h"
20 #include "nel/gui/action_handler.h"
21 #include "nel/gui/interface_group.h"
22 #include "nel/gui/view_renderer.h"
23 #include "nel/gui/ctrl_scroll.h"
24 #include "nel/misc/xml_auto_ptr.h"
25 #include "nel/gui/group_submenu_base.h"
26 #include "nel/gui/lua_ihm.h"
28 using namespace NLMISC;
29 using namespace std;
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 NLMISC_REGISTER_OBJECT(CViewBase, CCtrlScroll, std::string, "scroll");
37 namespace NLGUI
40 // ------------------------------------------------------------------------------------------------
41 CCtrlScroll::CCtrlScroll(const TCtorParam &param)
42 : CCtrlScrollBase(param)
44 _Vertical = true;
45 _Aligned = 1;
46 _TrackPos = 0;
47 _TrackDispPos = 0;
48 _TrackSize = _TrackSizeMin = 16;
49 _Min = 0;
50 _Max = 100;
51 _Value = 0;
52 _InitialValue = 0;
53 _MouseDown = false;
54 _CallingAH = false;
55 _Cancelable = false;
56 _Target = NULL;
57 _Inverted = false;
58 _IsDBLink = false;
59 _LastTargetHReal = 0;
60 _LastTargetMaxHReal = 0;
61 _LastTargetWReal = 0;
62 _LastTargetMaxWReal = 0;
63 _LastTargetOfsX = 0;
64 _LastTargetOfsY = 0;
65 _ObserverOn = true;
66 _TargetStepX = 1;
67 _TargetStepY = 1;
68 _StepValue = 0;
69 _TileM = false;
70 _Frozen = false;
73 // ------------------------------------------------------------------------------------------------
74 void CCtrlScroll::runAH(const std::string &name, const std::string &params)
76 if (name.empty()) return;
77 if (_CallingAH) return; // avoid infinite loop
78 _CallingAH = true;
79 CAHManager::getInstance()->runActionHandler(name, this, params);
80 _CallingAH = false;
83 // ------------------------------------------------------------------------------------------------
84 CCtrlScroll::~CCtrlScroll()
86 if (_IsDBLink)
88 ICDBNode::CTextId textId;
89 _DBLink.getNodePtr()->removeObserver(this, textId);
93 std::string CCtrlScroll::getProperty( const std::string &name ) const
96 if( name == "tx_bottomleft" )
98 return getTextureBottomOrLeft();
100 else
101 if( name == "tx_middle" )
103 return getTextureMiddle();
105 else
106 if( name == "tx_topright" )
108 return getTextureTopOrRight();
110 else
111 if( name == "vertical" )
113 return toString( _Vertical );
115 else
116 if( name == "align" )
118 switch( _Aligned )
120 case 0:
121 return "T";
122 break;
123 case 1:
124 return "B";
125 break;
126 case 2:
127 return "L";
128 break;
129 case 3:
130 return "R";
131 break;
134 return "";
136 else
137 if( name == "min" )
139 return toString( _Min );
141 else
142 if( name == "max" )
144 return toString( _Max );
146 else
147 if( name == "value" )
149 if( _IsDBLink )
150 return _DBLink.getNodePtr()->getFullName();
151 else
152 return toString( _Value );
154 else
155 if( name == "tracksize" )
157 return toString( _TrackSize );
159 else
160 if( name == "onscroll" )
162 return _AHOnScroll;
164 else
165 if( name == "params" )
167 return _AHOnScrollParams;
169 else
170 if( name == "onscrollend" )
172 return _AHOnScrollEnd;
174 else
175 if( name == "end_params" )
177 return _AHOnScrollEndParams;
179 else
180 if( name == "onscrollcancel" )
182 return _AHOnScrollCancel;
184 else
185 if( name == "cancel_params" )
187 return _AHOnScrollCancelParams;
189 else
190 if( name == "target" )
192 if( _Target != NULL )
193 return _Target->getId();
194 else
195 return "";
197 else
198 if( name == "target_stepx" )
200 return toString( _TargetStepX );
202 else
203 if( name == "target_stepy" )
205 return toString( _TargetStepY );
207 else
208 if( name == "step_value" )
210 return toString( _StepValue );
212 else
213 if( name == "cancelable" )
215 return toString( _Cancelable );
217 else
218 if( name == "frozen" )
220 return toString( _Frozen );
222 else
223 return CCtrlBase::getProperty( name );
227 void CCtrlScroll::setProperty( const std::string &name, const std::string &value )
229 if( name == "tx_bottomleft" )
231 setTextureBottomOrLeft( value );
232 return;
234 else
235 if( name == "tx_middle" )
237 setTextureMiddle( value );
238 return;
240 else
241 if( name == "tx_topright" )
243 setTextureTopOrRight( value );
244 return;
246 else
247 if( name == "vertical" )
249 bool b;
250 if( fromString( value, b ) )
251 _Vertical = b;
252 return;
254 else
255 if( name == "align" )
257 if( value == "T" )
258 _Aligned = 0;
259 else
260 if( value == "B" )
261 _Aligned = 1;
262 else
263 if( value == "L" )
264 _Aligned = 2;
265 else
266 if( value == "R" )
267 _Aligned = 3;
269 return;
271 else
272 if( name == "min" )
274 sint32 i;
275 if( fromString( value, i ) )
276 _Min = i;
277 return;
279 else
280 if( name == "max" )
282 sint32 i;
283 if( fromString( value, i ) )
284 _Max = i;
285 return;
287 else
288 if( name == "value" )
290 sint32 i;
291 if( fromString( value, i ) )
293 _IsDBLink = false;
294 _Value = i;
296 else
298 _IsDBLink = true;
299 _DBLink.link( value.c_str() );
300 ICDBNode::CTextId dummy;
301 _DBLink.getNodePtr()->addObserver( this, dummy );
303 return;
305 else
306 if( name == "tracksize" )
308 sint32 i;
309 if( fromString( value, i ) )
310 _TrackSize = i;
311 return;
313 else
314 if( name == "onscroll" )
316 _AHOnScroll = value;
317 return;
319 else
320 if( name == "params" )
322 _AHOnScrollParams = value;
323 return;
325 else
326 if( name == "onscrollend" )
328 _AHOnScrollEnd = value;
329 return;
331 else
332 if( name == "end_params" )
334 _AHOnScrollEndParams = value;
335 return;
337 else
338 if( name == "onscrollcancel" )
340 _AHOnScrollCancel = value;
341 return;
343 else
344 if( name == "cancel_params" )
346 _AHOnScrollCancelParams = value;
347 return;
349 else
350 if( name == "target" )
352 _Target = dynamic_cast< CInterfaceGroup* >(
353 CWidgetManager::getInstance()->getElementFromId( value )
355 return;
357 else
358 if( name == "target_stepx" )
360 sint32 i;
361 if( fromString( value, i ) )
362 _TargetStepX = i;
363 return;
365 else
366 if( name == "target_stepy" )
368 sint32 i;
369 if( fromString( value, i ) )
370 _TargetStepY = i;
371 return;
373 else
374 if( name == "step_value" )
376 uint32 i;
377 if( fromString( value, i ) )
378 _StepValue = i;
379 return;
381 else
382 if( name == "cancelable" )
384 bool b;
385 if( fromString( value, b ) )
386 _Cancelable = b;
387 return;
389 else
390 if( name == "frozen" )
392 bool b;
393 if( fromString( value, b ) )
394 _Frozen = b;
395 return;
397 else
398 CCtrlBase::setProperty( name, value );
401 xmlNodePtr CCtrlScroll::serialize( xmlNodePtr parentNode, const char *type ) const
403 xmlNodePtr node = CCtrlBase::serialize( parentNode, type );
404 if( node == NULL )
405 return NULL;
407 xmlSetProp( node, BAD_CAST "type", BAD_CAST "scroll" );
408 xmlSetProp( node, BAD_CAST "tx_bottomleft", BAD_CAST getTextureBottomOrLeft().c_str() );
409 xmlSetProp( node, BAD_CAST "tx_middle", BAD_CAST getTextureMiddle().c_str() );
410 xmlSetProp( node, BAD_CAST "tx_topright", BAD_CAST getTextureTopOrRight().c_str() );
411 xmlSetProp( node, BAD_CAST "vertical", BAD_CAST toString( _Vertical ).c_str() );
413 std::string align;
415 switch( _Aligned )
417 case 0:
418 align = "T";
419 break;
421 case 1:
422 align = "B";
423 break;
425 case 2:
426 align = "L";
427 break;
429 case 3:
430 align = "R";
431 break;
433 xmlSetProp( node, BAD_CAST "align", BAD_CAST align.c_str() );
435 xmlSetProp( node, BAD_CAST "min", BAD_CAST toString( _Min ).c_str() );
436 xmlSetProp( node, BAD_CAST "max", BAD_CAST toString( _Max ).c_str() );
438 if( _IsDBLink )
439 xmlSetProp( node, BAD_CAST "value", BAD_CAST _DBLink.getNodePtr()->getFullName().c_str() );
441 xmlSetProp( node, BAD_CAST "tracksize", BAD_CAST toString( _TrackSize ).c_str() );
442 xmlSetProp( node, BAD_CAST "onscroll", BAD_CAST _AHOnScroll.c_str() );
443 xmlSetProp( node, BAD_CAST "params", BAD_CAST _AHOnScrollParams.c_str() );
444 xmlSetProp( node, BAD_CAST "onscrollend", BAD_CAST _AHOnScrollEnd.c_str() );
445 xmlSetProp( node, BAD_CAST "end_params", BAD_CAST _AHOnScrollEndParams.c_str() );
446 xmlSetProp( node, BAD_CAST "onscrollcancel", BAD_CAST _AHOnScrollCancel.c_str() );
447 xmlSetProp( node, BAD_CAST "cancel_params", BAD_CAST _AHOnScrollCancelParams.c_str() );
449 if( _Target != NULL )
450 xmlSetProp( node, BAD_CAST "target", BAD_CAST _Target->getId().c_str() );
451 else
452 xmlSetProp( node, BAD_CAST "target", BAD_CAST "" );
454 xmlSetProp( node, BAD_CAST "target_stepx", BAD_CAST toString( _TargetStepX ).c_str() );
455 xmlSetProp( node, BAD_CAST "target_stepy", BAD_CAST toString( _TargetStepY ).c_str() );
456 xmlSetProp( node, BAD_CAST "step_value", BAD_CAST toString( _StepValue ).c_str() );
457 xmlSetProp( node, BAD_CAST "cancelable", BAD_CAST toString( _Cancelable ).c_str() );
458 xmlSetProp( node, BAD_CAST "frozen", BAD_CAST toString( _Frozen ).c_str() );
460 return node;
463 // ------------------------------------------------------------------------------------------------
464 bool CCtrlScroll::parse(xmlNodePtr node, CInterfaceGroup * parentGroup)
466 if (!CCtrlBase::parse(node, parentGroup))
467 return false;
469 CXMLAutoPtr prop;
470 // Read textures
471 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_bottomleft" );
472 if(prop) setTextureBottomOrLeft(string((const char*)prop));
473 else setTextureBottomOrLeft ("w_scroll_l0_b.tga");
475 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_middle" );
476 if(prop) setTextureMiddle(string((const char*)prop));
477 else setTextureMiddle ("w_scroll_l0_m.tga");
479 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_topright" );
480 if(prop) setTextureTopOrRight(string((const char*)prop));
481 else setTextureTopOrRight ("w_scroll_l0_t.tga");
483 // Read properties
484 prop = (char*) xmlGetProp( node, (xmlChar*)"vertical" );
485 if (prop) _Vertical = convertBool((const char*)prop);
487 prop = (char*) xmlGetProp (node, (xmlChar*)"align");
488 _Aligned = 1;
489 if (prop)
491 if (stricmp(prop, "T") == 0) _Aligned = 0;
492 else if (stricmp(prop, "B") == 0) _Aligned = 1;
493 else if (stricmp(prop, "L") == 0) _Aligned = 2;
494 else if (stricmp(prop, "R") == 0) _Aligned = 3;
497 prop = (char*) xmlGetProp( node, (xmlChar*)"min" );
498 if (prop) fromString((const char*)prop, _Min);
500 prop = (char*) xmlGetProp( node, (xmlChar*)"max" );
501 if (prop) fromString((const char*)prop, _Max);
503 prop = (char*) xmlGetProp( node, (xmlChar*)"value" );
504 if (prop)
506 if ( isdigit(*prop) || *prop=='-')
508 _IsDBLink = false;
509 fromString((const char*)prop, _Value);
511 else
513 _IsDBLink = true;
514 _DBLink.link(prop);
515 ICDBNode::CTextId textId;
516 _DBLink.getNodePtr()->addObserver(this, textId);
521 prop = (char*) xmlGetProp( node, (xmlChar*)"tracksize" );
522 if (prop) fromString((const char*)prop, _TrackSize);
524 // Read Action handlers
525 prop = (char*) xmlGetProp( node, (xmlChar*)"onscroll" );
526 if (prop) _AHOnScroll = NLMISC::toLower(prop.str());
527 prop = (char*) xmlGetProp( node, (xmlChar*)"params" );
528 if (prop) _AHOnScrollParams = string((const char*)prop);
530 prop = (char*) xmlGetProp( node, (xmlChar*)"onscrollend" );
531 if (prop) _AHOnScrollEnd = NLMISC::toLower(prop.str());
532 prop = (char*) xmlGetProp( node, (xmlChar*)"end_params" );
533 if (prop) _AHOnScrollEndParams = string((const char*)prop);
535 prop = (char*) xmlGetProp( node, (xmlChar*)"onscrollcancel" );
536 if (prop) _AHOnScrollCancel = NLMISC::toLower(prop.str());
537 prop = (char*) xmlGetProp( node, (xmlChar*)"cancel_params" );
538 if (prop) _AHOnScrollCancelParams = string((const char*)prop);
541 // auto-target
542 prop = (char*) xmlGetProp( node, (xmlChar*)"target" );
543 if (prop)
545 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(prop.str()));
546 if(group == NULL)
547 group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(this->getId(), prop.str()));
549 if(group != NULL)
550 setTarget (group);
554 // auto-step
555 prop = (char*) xmlGetProp( node, (xmlChar*)"target_stepx" );
556 if(prop) fromString((const char*)prop, _TargetStepX);
557 prop = (char*) xmlGetProp( node, (xmlChar*)"target_stepy" );
558 if(prop) fromString((const char*)prop, _TargetStepY);
559 _TargetStepX= max((sint32)1, _TargetStepX);
560 _TargetStepY= max((sint32)1, _TargetStepY);
562 // Scroll Step
563 prop = (char*) xmlGetProp( node, (xmlChar*)"step_value" );
564 if(prop) fromString((const char*)prop, _StepValue);
566 prop = (char*) xmlGetProp( node, (xmlChar*)"cancelable" );
567 if (prop) _Cancelable = convertBool(prop);
569 prop= (char*) xmlGetProp (node, (xmlChar*)"frozen");
570 _Frozen = false;
571 if (prop)
572 _Frozen = convertBool(prop);
575 return true;
578 // ------------------------------------------------------------------------------------------------
580 int CCtrlScroll::luaSetTarget(CLuaState &ls)
582 const char *funcName = "setTarget";
583 CLuaIHM::checkArgCount(ls, funcName, 1);
584 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
585 std::string targetId = ls.toString(1);
587 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(targetId));
588 if(group != NULL)
590 setTarget (group);
593 return 0;
596 void CCtrlScroll::updateCoords()
598 if (_Target)
600 // update only if visible
601 if (_Target->getActive())
603 CViewRenderer &rVR = *CViewRenderer::getInstance();
604 sint32 w, h;
605 rVR.getTextureSizeFromId (_TxIdB, w, h);
607 if (_Vertical)
609 _W = w;
610 _H = _Target->getMaxHReal();
612 else
614 _W = _Target->getMaxWReal();
615 _H = h;
618 CCtrlBase::updateCoords ();
619 if (_Vertical)
621 if(_Target->getHReal()!=_LastTargetHReal || _Target->getMaxHReal()!=_LastTargetMaxHReal ||
622 _Target->getOfsY() != _LastTargetOfsY
625 _LastTargetHReal= _Target->getHReal();
626 _LastTargetMaxHReal= _Target->getMaxHReal();
627 _LastTargetOfsY = _Target->getOfsY();
629 // Activate only if needed
630 setActive(_Target->getHReal() > _Target->getMaxHReal());
631 CCtrlBase::updateCoords();
633 // Calculate size of the track button
634 if ((_Target->getHReal() <= _Target->getMaxHReal()) || (_Target->getHReal() == 0))
636 _TrackSize = _Target->getMaxHReal();
638 else
640 float factor = (float)_Target->getMaxHReal() / (float)_Target->getHReal();
641 factor = _TrackSizeMin + factor * (this->getHReal() - _TrackSizeMin);
642 _TrackSize = (sint32)factor;
644 // Calculate pos of the track button
645 if (_Target->getHReal() <= _Target->getMaxHReal())
647 if (_Aligned == 1) // BOTTOM
648 _TrackPos = 0;
649 else // TOP
650 _TrackPos = getHReal()-_TrackSize;
652 else
654 if (_Aligned == 1) // BOTTOM
656 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
657 factor = -(float)_Target->getOfsY() / factor;
658 if (factor < 0.0f) factor = 0.0f;
659 if (factor > 1.0f) factor = 1.0f;
660 _TrackPos = factor * (getHReal()-_TrackSize);
662 else // TOP
664 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
665 factor = (float)_Target->getOfsY() / factor;
666 if (factor < 0.0f) factor = 0.0f;
667 if (factor > 1.0f) factor = 1.0f;
668 sint32 hreal = getHReal();
669 _TrackPos = (1.0f-factor) * (hreal - _TrackSize);
673 // invalidate coords.
674 computeTargetOfsFromPos();
677 else // Horizontal Tracker
679 if(_Target->getWReal()!=_LastTargetWReal || _Target->getMaxWReal()!=_LastTargetMaxWReal ||
680 _Target->getOfsX() != _LastTargetOfsX)
682 _LastTargetWReal= _Target->getWReal();
683 _LastTargetMaxWReal= _Target->getMaxWReal();
684 _LastTargetOfsX = _Target->getOfsX();
686 // Activate only if needed
687 setActive(_Target->getWReal() > _Target->getMaxWReal());
688 CCtrlBase::updateCoords();
690 // Calculate size of the track button
691 if ((_Target->getWReal() <= _Target->getMaxWReal()) || (_Target->getWReal() == 0))
693 _TrackSize = _Target->getMaxWReal();
695 else
697 float factor = (float)_Target->getMaxWReal() / (float)_Target->getWReal();
698 factor = _TrackSizeMin + factor * (this->getWReal() - _TrackSizeMin);
699 _TrackSize = (sint32)factor;
701 // Calculate pos of the track button
702 if (_Target->getWReal() <= _Target->getMaxWReal())
704 if (_Aligned == 2) // LEFT
705 _TrackPos = 0;
706 else // RIGHT
707 _TrackPos = getWReal()-_TrackSize;
709 else
711 if (_Aligned == 2) // LEFT
713 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
714 factor = -(float)_Target->getOfsX() / factor;
715 if (factor < 0.0f) factor = 0.0f;
716 if (factor > 1.0f) factor = 1.0f;
717 _TrackPos = factor * (getWReal()-_TrackSize);
719 else // RIGHT
721 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
722 factor = (float)_Target->getOfsX() / factor;
723 if (factor < 0.0f) factor = 0.0f;
724 if (factor > 1.0f) factor = 1.0f;
725 sint32 hreal = getWReal();
726 _TrackPos = (1.0f-factor) * (hreal - _TrackSize);
730 // invalidate coords.
731 computeTargetOfsFromPos();
735 // reset cache
736 else
738 _LastTargetHReal= 0;
739 _LastTargetMaxHReal= 0;
740 _LastTargetWReal= 0;
741 _LastTargetMaxWReal= 0;
742 _LastTargetOfsX = 0;
743 _LastTargetOfsY = 0;
744 setActive(false);
747 else
749 CCtrlBase::updateCoords ();
750 if (_IsDBLink)
751 _Value = _DBLink.getSInt32();
752 if (_Vertical)
754 float factor;
755 if (_Aligned == 1) // BOTTOM
756 factor = ((float)_Value-_Min) / (_Max-_Min);
757 else // TOP
758 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
759 factor *= (this->getHReal() - _TrackSize);
761 _TrackDispPos = (sint32)factor;
763 else
765 float factor;
766 if (_Aligned == 2) // LEFT
767 factor = ((float)_Value-_Min) / (_Max-_Min);
768 else // RIGHT
769 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
770 factor *= (this->getWReal() - _TrackSize);
772 _TrackDispPos = (sint32)factor;
775 CCtrlBase::updateCoords ();
778 // ------------------------------------------------------------------------------------------------
779 void CCtrlScroll::draw()
781 CViewRenderer &rVR = *CViewRenderer::getInstance();
782 CRGBA col = CWidgetManager::getInstance()->getGlobalColorForContent();
784 if (_Target)
786 if (_Vertical)
788 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos, _WReal, 4, 0, false, _TxIdB, col );
789 if (_TileM == 0)
790 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, col );
791 else
792 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal, _YReal+_TrackPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, _TileM-1, col );
793 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos+_TrackSize-4, _WReal, 4, 0, false, _TxIdT, col );
795 else
797 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos, _YReal, 4, _HReal, 0, false, _TxIdB, col );
798 if (_TileM == 0)
799 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, col );
800 else
801 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal+_TrackPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, _TileM-1, col );
802 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos+_TrackSize-4, _YReal, 4, _HReal, 0, false, _TxIdT, col );
805 else
807 if (_Vertical)
809 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos, _WReal, 4, 0, false, _TxIdB, col );
810 if (_TileM == 0)
811 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, col );
812 else
813 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal, _YReal+_TrackDispPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, _TileM-1, col );
814 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos+_TrackSize-4, _WReal, 4, 0, false, _TxIdT, col );
816 else
818 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos, _YReal, 4, _HReal, 0, false, _TxIdB, col );
819 if (_TileM == 0)
820 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, col );
821 else
822 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal+_TrackDispPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, _TileM-1, col );
823 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos+_TrackSize-4, _YReal, 4, _HReal, 0, false, _TxIdT, col );
828 // ------------------------------------------------------------------------------------------------
829 bool CCtrlScroll::handleEvent (const NLGUI::CEventDescriptor &event)
831 if (CCtrlBase::handleEvent(event)) return true;
832 if (!_Active || _Frozen)
833 return false;
834 if (event.getType() == NLGUI::CEventDescriptor::mouse)
836 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
837 if ((CWidgetManager::getInstance()->getCapturePointerLeft() != this) &&
838 (!((eventDesc.getX() >= _XReal) &&
839 (eventDesc.getX() < (_XReal + _WReal))&&
840 (eventDesc.getY() > _YReal) &&
841 (eventDesc.getY() <= (_YReal+ _HReal)))))
842 return false;
844 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
846 _MouseDown = true;
847 _InitialValue = getValue();
848 if (!_Target)
849 _TrackPos = _TrackDispPos;
850 _MouseDownOffsetX = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos));
851 _MouseDownOffsetY = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0));
853 // if target is a menu, hidde its sub menus
854 if(_Target && _Target->getParent())
856 CGroupSubMenuBase *menu = dynamic_cast<CGroupSubMenuBase*>(_Target->getParent());
857 if(menu)
858 menu->hideSubMenus();
860 return true;
862 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
864 _MouseDown = false;
865 runAH(_AHOnScrollEnd, _AHOnScrollEndParams.empty() ? _AHOnScrollParams : _AHOnScrollEndParams); // backward compatibility
866 return true;
868 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown && _MouseDown && _Cancelable)
870 _MouseDown = false;
871 setValue(_InitialValue);
872 runAH(_AHOnScrollCancel, _AHOnScrollCancelParams); // backward compatibility
873 return true;
875 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
877 if (_MouseDown)
879 sint32 dx = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos) + _MouseDownOffsetX);
880 sint32 dy = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0 ) + _MouseDownOffsetY);
881 if (dx != 0) moveTrackX (dx);
882 if (dy != 0) moveTrackY (dy);
884 return true;
886 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousewheel && _Vertical)
888 moveTargetY (-(eventDesc.getWheel() * 12));
889 return true;
892 return false;
895 // ------------------------------------------------------------------------------------------------
896 void CCtrlScroll::setTarget (CInterfaceGroup *pIG)
898 _Target = pIG;
900 if (_Vertical)
902 if (_Target->getPosRef()&Hotspot_Tx)
903 _Aligned = 0;
904 else
905 _Aligned = 1;
907 if (_Target->getPosRef()&Hotspot_Tx)
908 _Inverted = true;
909 else
910 _Inverted = true;
912 else
914 if (_Target->getPosRef()&Hotspot_xL)
915 _Aligned = 2;
916 else
917 _Aligned = 3;
919 if (_Target->getPosRef()&Hotspot_xL)
920 _Inverted = true;
921 else
922 _Inverted = true;
925 // ------------------------------------------------------------------------------------------------
926 sint32 CCtrlScroll::moveTrackX (sint32 dx)
928 if (_Vertical)
929 return 0;
930 if ((getWReal()-_TrackSize) <= 0)
931 return 0;
933 float newtpos;
934 float tpos = _TrackPos;
935 sint32 tsize = _TrackSize;
937 // Limit the scroller to the defined area
938 newtpos = tpos + dx;
939 if (newtpos < 0) newtpos = 0;
940 if (newtpos > (getWReal()-tsize)) newtpos = (getWReal()-tsize);
941 dx = newtpos - tpos;
943 if (_Target)
945 _TrackPos = newtpos;
947 computeTargetOfsFromPos();
949 else // This is a number scroller
951 float factor = (float)(_Max - _Min);
953 if (_Aligned == 2) // LEFT
954 factor = -factor * newtpos / (float)(getWReal()-tsize) - _Min;
955 else // RIGHT
956 factor = factor * (1.0f-(newtpos / (float)(getWReal()-tsize))) + _Min;
958 _TrackPos = newtpos;
960 if (_Aligned == 2) // LEFT
961 _Value = (sint32) (_Inverted ? factor : -factor);
962 else // RIGHT
963 _Value = (sint32) (_Inverted ? factor : -factor);
965 // step and clamp value
966 normalizeValue(_Value);
969 float factor;
970 if (_Aligned == 2) // LEFT
971 factor = ((float)_Value-_Min) / (_Max-_Min);
972 else // RIGHT
973 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
974 factor *= (this->getWReal() - _TrackSize);
976 _TrackDispPos = (sint32)factor;
979 if (_IsDBLink)
981 _ObserverOn = false;
982 _DBLink.setSInt32 (_Value);
983 _ObserverOn = true;
987 // Launch the scroller event if any
988 runAH(_AHOnScroll, _AHOnScrollParams);
990 return dx;
993 // ------------------------------------------------------------------------------------------------
994 sint32 CCtrlScroll::moveTrackY (sint32 dy)
996 if (!_Vertical)
997 return 0;
998 if ((getHReal()-_TrackSize) <= 0)
999 return 0;
1001 float newtpos;
1002 float tpos = _TrackPos;
1003 sint32 tsize = _TrackSize;
1005 // Limit the scroller to the defined area
1006 newtpos = tpos + dy;
1007 if (newtpos < 0) newtpos = 0;
1008 if (newtpos > (getHReal()-tsize)) newtpos = (getHReal()-tsize);
1009 dy = newtpos - tpos;
1011 if (_Target)
1013 _TrackPos = newtpos;
1015 computeTargetOfsFromPos();
1017 else // This is a number scroller
1019 float factor = (float)(_Max - _Min);
1021 if (_Aligned == 1) // BOTTOM
1022 factor = -factor * newtpos / (float)(getHReal()-tsize) - _Min;
1023 else // TOP
1024 factor = factor * (1.0f-(newtpos / (float)(getHReal()-tsize))) + _Min;
1026 _TrackPos = newtpos;
1028 if (_Aligned == 1) // BOTTOM
1029 _Value = (sint32) (_Inverted ? factor : -factor);
1030 else // TOP
1031 _Value = (sint32) (_Inverted ? factor : -factor);
1033 // step and clamp value
1034 normalizeValue(_Value);
1037 float factor;
1038 if (_Aligned == 1) // BOTTOM
1039 factor = ((float)_Value-_Min) / (_Max-_Min);
1040 else // TOP
1041 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
1042 factor *= (this->getHReal() - _TrackSize);
1044 _TrackDispPos = (sint32)factor;
1047 if (_IsDBLink)
1049 _ObserverOn = false;
1050 _DBLink.setSInt32 (_Value);
1051 _ObserverOn = true;
1055 // Launch the scroller event if any
1056 runAH(_AHOnScroll, _AHOnScrollParams);
1058 return dy;
1061 // ------------------------------------------------------------------------------------------------
1062 void CCtrlScroll::setTextureBottomOrLeft (const std::string &txName)
1064 CViewRenderer &rVR = *CViewRenderer::getInstance();
1065 _TxIdB = rVR.getTextureIdFromName(txName);
1068 // ------------------------------------------------------------------------------------------------
1069 void CCtrlScroll::setTextureMiddle (const std::string &txName)
1071 CViewRenderer &rVR = *CViewRenderer::getInstance();
1072 _TxIdM = rVR.getTextureIdFromName(txName);
1075 // ------------------------------------------------------------------------------------------------
1076 void CCtrlScroll::setTextureTopOrRight (const std::string &txName)
1078 CViewRenderer &rVR = *CViewRenderer::getInstance();
1079 _TxIdT = rVR.getTextureIdFromName(txName);
1082 std::string CCtrlScroll::getTextureBottomOrLeft() const
1084 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdB );
1087 std::string CCtrlScroll::getTextureMiddle() const
1089 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdM );
1092 std::string CCtrlScroll::getTextureTopOrRight() const
1094 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdT );
1097 // ------------------------------------------------------------------------------------------------
1098 void CCtrlScroll::setValue(sint32 value)
1100 normalizeValue(value);
1102 if (_IsDBLink)
1104 _ObserverOn = false;
1105 _DBLink.setSInt32(value);
1106 _ObserverOn = true;
1108 else
1110 _Value = value;
1112 invalidateCoords();
1115 // ------------------------------------------------------------------------------------------------
1116 void CCtrlScroll::setTrackPos(sint32 pos)
1118 if (_Vertical)
1120 moveTrackY(pos - _TrackPos);
1122 else
1124 moveTrackX(pos - _TrackPos);
1126 invalidateCoords();
1129 // ------------------------------------------------------------------------------------------------
1130 void CCtrlScroll::computeTargetOfsFromPos()
1132 if(_Vertical)
1134 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
1136 if (_Aligned == 1) // BOTTOM
1137 factor = -factor * _TrackPos / favoid0((float)(getHReal()-_TrackSize));
1138 else // TOP
1139 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getHReal()-_TrackSize))));
1141 // Compute Steped target
1142 sint32 nexOfsY= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1143 if(_TargetStepY>1)
1144 nexOfsY= ((nexOfsY+_TargetStepY/2)/_TargetStepY) * _TargetStepY;
1145 _Target->setOfsY (nexOfsY);
1146 _LastTargetOfsY = nexOfsY;
1148 // invalidate only XReal/YReal, doing only 1 pass
1149 _Target->invalidateCoords(1);
1151 else
1153 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
1155 if (_Aligned == 2) // LEFT
1156 factor = -factor * _TrackPos / favoid0((float)(getWReal()-_TrackSize));
1157 else // RIGHT
1158 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getWReal()-_TrackSize))));
1160 // Compute Steped target
1161 sint32 nexOfsX= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1162 if(_TargetStepX>1)
1163 nexOfsX= ((nexOfsX+_TargetStepX/2)/_TargetStepX) * _TargetStepX;
1164 _Target->setOfsX (nexOfsX);
1165 _LastTargetOfsX = nexOfsX;
1167 // invalidate only XReal/YReal, doing only 1 pass
1168 _Target->invalidateCoords(1);
1172 // ------------------------------------------------------------------------------------------------
1173 void CCtrlScroll::update(ICDBNode * /* node */)
1175 if (!_ObserverOn) return;
1176 _Value = _DBLink.getSInt32();
1177 // the value in the db changed
1178 invalidateCoords(1);
1179 if (_Target) _Target->invalidateCoords(1);
1183 // ***************************************************************************
1184 void CCtrlScroll::moveTargetX (sint32 dx)
1186 if(!_Target)
1187 return;
1188 sint32 maxWReal= _Target->getMaxWReal();
1189 sint32 wReal= _Target->getWReal();
1190 if(wReal <= maxWReal)
1191 return;
1193 // compute the new ofsX.
1194 sint32 ofsX= _Target->getOfsX();
1195 ofsX+= dx;
1196 clamp(ofsX, 0, wReal-maxWReal);
1197 _Target->setOfsX(ofsX);
1199 // compute new trackPos.
1200 if (_Aligned == 2) // LEFT
1202 float factor = (float)(wReal-maxWReal);
1203 factor = -(float)ofsX / factor;
1204 clamp(factor, 0.f, 1.f);
1205 _TrackPos = factor * (getWReal()-_TrackSize);
1207 else // RIGHT
1209 float factor = (float)(wReal-maxWReal);
1210 factor = (float)ofsX / factor;
1211 clamp(factor, 0.f, 1.f);
1212 _TrackPos = (1.0f-factor) * (getWReal() - _TrackSize);
1215 // invalidate only position. 1 pass is sufficient
1216 invalidateCoords(1);
1219 // ***************************************************************************
1220 void CCtrlScroll::moveTargetY (sint32 dy)
1222 if(!_Target)
1223 return;
1224 sint32 maxHReal= _Target->getMaxHReal();
1225 sint32 hReal= _Target->getHReal();
1226 if(hReal <= maxHReal)
1227 return;
1229 if (_TargetStepY > 1)
1231 sint sign = (0 < dy) - (dy < 0);
1232 dy = sign * max(1, (dy / _TargetStepY)) * _TargetStepY;
1235 // compute the new ofsY.
1236 sint32 ofsY= _Target->getOfsY();
1237 ofsY+= dy;
1239 // compute new trackPos.
1240 if (_Aligned == 1) // BOTTOM
1242 clamp(ofsY, maxHReal - hReal, 0);
1243 _Target->setOfsY(ofsY);
1244 float factor = (float)(hReal-maxHReal);
1245 factor = -(float)ofsY / factor;
1246 clamp(factor, 0.f, 1.f);
1247 _TrackPos = factor * (getHReal()-_TrackSize);
1249 else // TOP
1251 clamp(ofsY, 0, hReal-maxHReal);
1252 _Target->setOfsY(ofsY);
1253 float factor = (float)(hReal-maxHReal);
1254 factor = (float)ofsY / factor;
1255 clamp(factor, 0.f, 1.f);
1256 _TrackPos = (1.0f-factor) * (getHReal() - _TrackSize);
1259 // invalidate only position. 1 pass is sufficient
1260 invalidateCoords(1);
1263 // ***************************************************************************
1264 void CCtrlScroll::normalizeValue(sint32 &value)
1266 // if, 0 no step
1267 if(_StepValue==0 || _StepValue==1)
1268 return;
1269 // if interval is null, force min!
1270 if(_Max==_Min)
1272 value= _Min;
1273 return;
1276 // get range of possible position
1277 // sint32 size= _Max - _Min;
1279 // step (round)
1280 sint32 val= (value + (_StepValue/2) -_Min) / _StepValue;
1281 val= _Min + val * _StepValue;
1282 clamp(val, _Min, _Max);
1283 value= val;
1286 // ***************************************************************************
1287 void CCtrlScroll::setFrozen (bool state)
1289 _Frozen = state;
1290 if (_Frozen)
1292 _Value = 0;
1297 // ------------------------------------------------------------------------------------------------
1298 int CCtrlScroll::luaEnsureVisible(CLuaState &ls)
1300 const char *funcName = "ensureVisible";
1301 CLuaIHM::checkArgCount(ls, funcName, 3);
1302 CLuaIHM::checkArgTypeUIElement(ls, funcName, 1);
1303 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
1304 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING);
1305 THotSpot hs[2];
1306 std::string hsStr[] = { ls.toString(2), ls.toString(3) };
1308 for (uint hsIndex = 0; hsIndex < 2; ++ hsIndex)
1310 if (_Vertical)
1312 if (NLMISC::nlstricmp(hsStr[hsIndex], "T") == 0)
1314 hs[hsIndex] = Hotspot_Tx;
1316 else
1317 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1319 hs[hsIndex] = Hotspot_Mx;
1321 else
1322 if (NLMISC::nlstricmp(hsStr[hsIndex], "B") == 0)
1324 hs[hsIndex] = Hotspot_Bx;
1326 else
1328 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for vertical scrollbar", funcName);
1331 else
1333 if (NLMISC::nlstricmp(hsStr[hsIndex], "L") == 0)
1335 hs[hsIndex] = Hotspot_xL;
1337 else
1338 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1340 hs[hsIndex] = Hotspot_xM;
1342 else
1343 if (NLMISC::nlstricmp(hsStr[hsIndex], "R") == 0)
1345 hs[hsIndex] = Hotspot_xR;
1347 else
1349 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for horizontal scrollbar", funcName);
1353 ensureVisible(CLuaIHM::getUIOnStack(ls, 1), hs[0], hs[1]);
1354 return 0;
1358 // ------------------------------------------------------------------------------------------------
1359 void CCtrlScroll::ensureVisible(CInterfaceElement *childElement, THotSpot childHotSpot, THotSpot parentHotSpot)
1361 if (!_Target) return; // not connected to a target yet
1362 if (!childElement) return;
1363 // compute corners of interest for enclosed element & enclosing group
1364 sint32 childX, childY;
1365 childElement->getCorner(childX, childY, childHotSpot);
1366 if (_Vertical)
1368 sint32 maxHReal= _Target->getMaxHReal();
1369 sint32 hReal= _Target->getHReal();
1370 if(hReal > maxHReal)
1372 sint enclosingDY;
1373 switch (parentHotSpot)
1375 case Hotspot_Bx:
1376 enclosingDY = maxHReal;
1377 break;
1378 case Hotspot_Mx:
1379 enclosingDY = maxHReal / 2;
1380 break;
1381 case Hotspot_Tx:
1382 enclosingDY = 0;
1383 break;
1384 default:
1385 nlassert(0);
1386 break;
1388 if (_Aligned == 0)
1390 // Top aligned case
1391 sint32 offsetY = (_Target->getYReal() + _Target->getHReal() - childY) - enclosingDY;
1392 NLMISC::clamp(offsetY, 0, hReal - maxHReal);
1393 _Target->setOfsY(offsetY);
1394 _Target->invalidateCoords();
1396 else if (_Aligned == 1)
1398 // Bottom aligned case
1399 sint32 offsetY = (maxHReal - enclosingDY) - (childY - _Target->getYReal());
1400 NLMISC::clamp(offsetY, maxHReal - hReal, 0);
1401 _Target->setOfsY(offsetY);
1402 _Target->invalidateCoords();
1405 // else, ... fully visible (not occluded by parent group)
1407 else
1409 sint32 maxWReal= _Target->getMaxWReal();
1410 sint32 wReal= _Target->getWReal();
1411 if(wReal > maxWReal)
1413 sint enclosingDX;
1414 switch (parentHotSpot)
1416 case Hotspot_xL:
1417 enclosingDX = maxWReal;
1418 break;
1419 case Hotspot_xM:
1420 enclosingDX = maxWReal / 2;
1421 break;
1422 case Hotspot_xR:
1423 enclosingDX = 0;
1424 break;
1425 default:
1426 nlassert(0);
1427 break;
1429 if (_Aligned == 3)
1431 // right aligned case
1432 sint32 offsetX = (_Target->getXReal() + _Target->getWReal() - childX) - enclosingDX;
1433 NLMISC::clamp(offsetX, 0, wReal - maxWReal);
1434 _Target->setOfsX(offsetX);
1435 _Target->invalidateCoords();
1437 else if (_Aligned == 2)
1439 // Left aligned case
1440 sint32 offsetX = (maxWReal - enclosingDX) - (childX - _Target->getXReal());
1441 NLMISC::clamp(offsetX, maxWReal - wReal, 0);
1442 _Target->setOfsX(offsetX);
1443 _Target->invalidateCoords();
1446 // else, ... fully visible (not occluded by parent group)