Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / ctrl_scroll.cpp
blob4d496de668b4a1f65e0e324f98497efba04053d7
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 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 // Copyright (C) 2015-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
23 #include "nel/gui/widget_manager.h"
24 #include "nel/gui/action_handler.h"
25 #include "nel/gui/interface_group.h"
26 #include "nel/gui/view_renderer.h"
27 #include "nel/gui/ctrl_scroll.h"
28 #include "nel/misc/xml_auto_ptr.h"
29 #include "nel/gui/group_submenu_base.h"
30 #include "nel/gui/lua_ihm.h"
32 using namespace NLMISC;
33 using namespace std;
35 #ifdef DEBUG_NEW
36 #define new DEBUG_NEW
37 #endif
39 NLMISC_REGISTER_OBJECT(CViewBase, CCtrlScroll, std::string, "scroll");
41 namespace NLGUI
44 // ------------------------------------------------------------------------------------------------
45 CCtrlScroll::CCtrlScroll(const TCtorParam &param)
46 : CCtrlScrollBase(param)
48 _Vertical = true;
49 _Aligned = 1;
50 _TrackPos = 0;
51 _TrackDispPos = 0;
52 _TrackSize = _TrackSizeMin = 8;
53 _Min = 0;
54 _Max = 100;
55 _Value = 0;
56 _InitialValue = 0;
57 _MouseDown = false;
58 _CallingAH = false;
59 _Cancelable = false;
60 _Keyboard = false;
61 _Target = NULL;
62 _Inverted = false;
63 _IsDBLink = false;
64 _LastTargetHReal = 0;
65 _LastTargetMaxHReal = 0;
66 _LastTargetWReal = 0;
67 _LastTargetMaxWReal = 0;
68 _LastTargetOfsX = 0;
69 _LastTargetOfsY = 0;
70 _ObserverOn = true;
71 _TargetStepX = 1;
72 _TargetStepY = 1;
73 _StepValue = 0;
74 _TileM = false;
75 _Frozen = false;
76 _Scale = false;
79 // ------------------------------------------------------------------------------------------------
80 void CCtrlScroll::runAH(const std::string &name, const std::string &params)
82 if (name.empty()) return;
83 if (_CallingAH) return; // avoid infinite loop
84 _CallingAH = true;
85 CAHManager::getInstance()->runActionHandler(name, this, params);
86 _CallingAH = false;
89 // ------------------------------------------------------------------------------------------------
90 CCtrlScroll::~CCtrlScroll()
92 if (_IsDBLink)
94 ICDBNode::CTextId textId;
95 _DBLink.getNodePtr()->removeObserver(this, textId);
99 std::string CCtrlScroll::getProperty( const std::string &name ) const
102 if( name == "tx_bottomleft" )
104 return getTextureBottomOrLeft();
106 else
107 if( name == "tx_middle" )
109 return getTextureMiddle();
111 else
112 if( name == "tx_topright" )
114 return getTextureTopOrRight();
116 else
117 if( name == "scale" )
119 return toString( _Scale );
121 else
122 if( name == "vertical" )
124 return toString( _Vertical );
126 else
127 if( name == "align" )
129 switch( _Aligned )
131 case 0:
132 return "T";
133 break;
134 case 1:
135 return "B";
136 break;
137 case 2:
138 return "L";
139 break;
140 case 3:
141 return "R";
142 break;
145 return "";
147 else
148 if( name == "min" )
150 return toString( _Min );
152 else
153 if( name == "max" )
155 return toString( _Max );
157 else
158 if( name == "value" )
160 if( _IsDBLink )
161 return _DBLink.getNodePtr()->getFullName();
162 else
163 return toString( _Value );
165 else
166 if( name == "tracksize" )
168 return toString( _TrackSize );
170 else
171 if( name == "onscroll" )
173 return _AHOnScroll;
175 else
176 if( name == "params" )
178 return _AHOnScrollParams;
180 else
181 if( name == "onscrollend" )
183 return _AHOnScrollEnd;
185 else
186 if( name == "end_params" )
188 return _AHOnScrollEndParams;
190 else
191 if( name == "onscrollcancel" )
193 return _AHOnScrollCancel;
195 else
196 if( name == "cancel_params" )
198 return _AHOnScrollCancelParams;
200 else
201 if( name == "target" )
203 if( _Target != NULL )
204 return _Target->getId();
205 else
206 return "";
208 else
209 if( name == "target_stepx" )
211 return toString( _TargetStepX );
213 else
214 if( name == "target_stepy" )
216 return toString( _TargetStepY );
218 else
219 if( name == "step_value" )
221 return toString( _StepValue );
223 else
224 if( name == "cancelable" )
226 return toString( _Cancelable );
228 else
229 if( name == "keyboard" )
231 return toString( _Keyboard );
233 else
234 if( name == "frozen" )
236 return toString( _Frozen );
238 else
239 return CCtrlBase::getProperty( name );
243 void CCtrlScroll::setProperty( const std::string &name, const std::string &value )
245 if( name == "tx_bottomleft" )
247 setTextureBottomOrLeft( value );
248 return;
250 else
251 if( name == "tx_middle" )
253 setTextureMiddle( value );
254 return;
256 else
257 if( name == "tx_topright" )
259 setTextureTopOrRight( value );
260 return;
262 else
263 if( name =="scale" )
265 bool b;
266 if (fromString( value, b ) )
267 _Scale = b;
268 return;
270 else
271 if( name == "vertical" )
273 bool b;
274 if( fromString( value, b ) )
275 _Vertical = b;
276 return;
278 else
279 if( name == "align" )
281 if( value == "T" )
282 _Aligned = 0;
283 else
284 if( value == "B" )
285 _Aligned = 1;
286 else
287 if( value == "L" )
288 _Aligned = 2;
289 else
290 if( value == "R" )
291 _Aligned = 3;
293 return;
295 else
296 if( name == "min" )
298 sint32 i;
299 if( fromString( value, i ) )
300 _Min = i;
301 return;
303 else
304 if( name == "max" )
306 sint32 i;
307 if( fromString( value, i ) )
308 _Max = i;
309 return;
311 else
312 if( name == "value" )
314 sint32 i;
315 if( fromString( value, i ) )
317 _IsDBLink = false;
318 _Value = i;
320 else
322 _IsDBLink = true;
323 _DBLink.link( value.c_str() );
324 ICDBNode::CTextId dummy;
325 _DBLink.getNodePtr()->addObserver( this, dummy );
327 return;
329 else
330 if( name == "tracksize" )
332 sint32 i;
333 if( fromString( value, i ) )
334 _TrackSize = i;
335 return;
337 else
338 if( name == "onscroll" )
340 _AHOnScroll = value;
341 return;
343 else
344 if( name == "params" )
346 _AHOnScrollParams = value;
347 return;
349 else
350 if( name == "onscrollend" )
352 _AHOnScrollEnd = value;
353 return;
355 else
356 if( name == "end_params" )
358 _AHOnScrollEndParams = value;
359 return;
361 else
362 if( name == "onscrollcancel" )
364 _AHOnScrollCancel = value;
365 return;
367 else
368 if( name == "cancel_params" )
370 _AHOnScrollCancelParams = value;
371 return;
373 else
374 if( name == "target" )
376 _Target = dynamic_cast< CInterfaceGroup* >(
377 CWidgetManager::getInstance()->getElementFromId( value )
379 return;
381 else
382 if( name == "target_stepx" )
384 sint32 i;
385 if( fromString( value, i ) )
386 _TargetStepX = i;
387 return;
389 else
390 if( name == "target_stepy" )
392 sint32 i;
393 if( fromString( value, i ) )
394 _TargetStepY = i;
395 return;
397 else
398 if( name == "step_value" )
400 uint32 i;
401 if( fromString( value, i ) )
402 _StepValue = i;
403 return;
405 else
406 if( name == "cancelable" )
408 bool b;
409 if( fromString( value, b ) )
410 _Cancelable = b;
411 return;
413 else
414 if( name == "keyboard" )
416 bool b;
417 if( fromString( value, b ) )
418 _Keyboard = b;
419 return;
421 else
422 if( name == "frozen" )
424 bool b;
425 if( fromString( value, b ) )
426 _Frozen = b;
427 return;
429 else
430 CCtrlBase::setProperty( name, value );
433 xmlNodePtr CCtrlScroll::serialize( xmlNodePtr parentNode, const char *type ) const
435 xmlNodePtr node = CCtrlBase::serialize( parentNode, type );
436 if( node == NULL )
437 return NULL;
439 xmlSetProp( node, BAD_CAST "type", BAD_CAST "scroll" );
440 xmlSetProp( node, BAD_CAST "tx_bottomleft", BAD_CAST getTextureBottomOrLeft().c_str() );
441 xmlSetProp( node, BAD_CAST "tx_middle", BAD_CAST getTextureMiddle().c_str() );
442 xmlSetProp( node, BAD_CAST "tx_topright", BAD_CAST getTextureTopOrRight().c_str() );
443 xmlSetProp( node, BAD_CAST "scale", BAD_CAST toString( _Scale ).c_str() );
444 xmlSetProp( node, BAD_CAST "vertical", BAD_CAST toString( _Vertical ).c_str() );
446 std::string align;
448 switch( _Aligned )
450 case 0:
451 align = "T";
452 break;
454 case 1:
455 align = "B";
456 break;
458 case 2:
459 align = "L";
460 break;
462 case 3:
463 align = "R";
464 break;
466 xmlSetProp( node, BAD_CAST "align", BAD_CAST align.c_str() );
468 xmlSetProp( node, BAD_CAST "min", BAD_CAST toString( _Min ).c_str() );
469 xmlSetProp( node, BAD_CAST "max", BAD_CAST toString( _Max ).c_str() );
471 if( _IsDBLink )
472 xmlSetProp( node, BAD_CAST "value", BAD_CAST _DBLink.getNodePtr()->getFullName().c_str() );
474 xmlSetProp( node, BAD_CAST "tracksize", BAD_CAST toString( _TrackSize ).c_str() );
475 xmlSetProp( node, BAD_CAST "onscroll", BAD_CAST _AHOnScroll.c_str() );
476 xmlSetProp( node, BAD_CAST "params", BAD_CAST _AHOnScrollParams.c_str() );
477 xmlSetProp( node, BAD_CAST "onscrollend", BAD_CAST _AHOnScrollEnd.c_str() );
478 xmlSetProp( node, BAD_CAST "end_params", BAD_CAST _AHOnScrollEndParams.c_str() );
479 xmlSetProp( node, BAD_CAST "onscrollcancel", BAD_CAST _AHOnScrollCancel.c_str() );
480 xmlSetProp( node, BAD_CAST "cancel_params", BAD_CAST _AHOnScrollCancelParams.c_str() );
482 if( _Target != NULL )
483 xmlSetProp( node, BAD_CAST "target", BAD_CAST _Target->getId().c_str() );
484 else
485 xmlSetProp( node, BAD_CAST "target", BAD_CAST "" );
487 xmlSetProp( node, BAD_CAST "target_stepx", BAD_CAST toString( _TargetStepX ).c_str() );
488 xmlSetProp( node, BAD_CAST "target_stepy", BAD_CAST toString( _TargetStepY ).c_str() );
489 xmlSetProp( node, BAD_CAST "step_value", BAD_CAST toString( _StepValue ).c_str() );
490 xmlSetProp( node, BAD_CAST "cancelable", BAD_CAST toString( _Cancelable ).c_str() );
491 xmlSetProp( node, BAD_CAST "keyboard", BAD_CAST toString( _Keyboard ).c_str() );
492 xmlSetProp( node, BAD_CAST "frozen", BAD_CAST toString( _Frozen ).c_str() );
494 return node;
497 // ------------------------------------------------------------------------------------------------
498 bool CCtrlScroll::parse(xmlNodePtr node, CInterfaceGroup * parentGroup)
500 if (!CCtrlBase::parse(node, parentGroup))
501 return false;
503 CXMLAutoPtr prop;
504 // Read textures
505 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_bottomleft" );
506 if(prop) setTextureBottomOrLeft(string((const char*)prop));
507 else setTextureBottomOrLeft ("w_scroll_l0_b.tga");
509 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_middle" );
510 if(prop) setTextureMiddle(string((const char*)prop));
511 else setTextureMiddle ("w_scroll_l0_m.tga");
513 prop = (char*) xmlGetProp( node, (xmlChar*)"tx_topright" );
514 if(prop) setTextureTopOrRight(string((const char*)prop));
515 else setTextureTopOrRight ("w_scroll_l0_t.tga");
517 // Override texture size (w for vertical, h for horizontal)
518 prop = (char*) xmlGetProp( node, (xmlChar*)"scale" );
519 if (prop) _Scale = convertBool((const char*)prop);
521 // Read properties
522 prop = (char*) xmlGetProp( node, (xmlChar*)"vertical" );
523 if (prop) _Vertical = convertBool((const char*)prop);
525 prop = (char*) xmlGetProp (node, (xmlChar*)"align");
526 _Aligned = 1;
527 if (prop)
529 if (stricmp(prop, "T") == 0) _Aligned = 0;
530 else if (stricmp(prop, "B") == 0) _Aligned = 1;
531 else if (stricmp(prop, "L") == 0) _Aligned = 2;
532 else if (stricmp(prop, "R") == 0) _Aligned = 3;
535 prop = (char*) xmlGetProp( node, (xmlChar*)"min" );
536 if (prop) fromString((const char*)prop, _Min);
538 prop = (char*) xmlGetProp( node, (xmlChar*)"max" );
539 if (prop) fromString((const char*)prop, _Max);
541 prop = (char*) xmlGetProp( node, (xmlChar*)"value" );
542 if (prop)
544 if ( isdigit(*prop) || *prop=='-')
546 _IsDBLink = false;
547 fromString((const char*)prop, _Value);
549 else
551 _IsDBLink = true;
552 _DBLink.link(prop);
553 ICDBNode::CTextId textId;
554 _DBLink.getNodePtr()->addObserver(this, textId);
559 prop = (char*) xmlGetProp( node, (xmlChar*)"tracksize" );
560 if (prop) fromString((const char*)prop, _TrackSize);
562 // Read Action handlers
563 prop = (char*) xmlGetProp( node, (xmlChar*)"onscroll" );
564 if (prop) _AHOnScroll = NLMISC::toLowerAscii(prop.str());
565 prop = (char*) xmlGetProp( node, (xmlChar*)"params" );
566 if (prop) _AHOnScrollParams = string((const char*)prop);
568 prop = (char*) xmlGetProp( node, (xmlChar*)"onscrollend" );
569 if (prop) _AHOnScrollEnd = NLMISC::toLowerAscii(prop.str());
570 prop = (char*) xmlGetProp( node, (xmlChar*)"end_params" );
571 if (prop) _AHOnScrollEndParams = string((const char*)prop);
573 prop = (char*) xmlGetProp( node, (xmlChar*)"onscrollcancel" );
574 if (prop) _AHOnScrollCancel = NLMISC::toLowerAscii(prop.str());
575 prop = (char*) xmlGetProp( node, (xmlChar*)"cancel_params" );
576 if (prop) _AHOnScrollCancelParams = string((const char*)prop);
579 // auto-target
580 prop = (char*) xmlGetProp( node, (xmlChar*)"target" );
581 if (prop)
583 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(prop.str()));
584 if(group == NULL)
585 group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(this->getId(), prop.str()));
587 if(group != NULL)
588 setTarget (group);
592 // auto-step
593 prop = (char*) xmlGetProp( node, (xmlChar*)"target_stepx" );
594 if(prop) fromString((const char*)prop, _TargetStepX);
595 prop = (char*) xmlGetProp( node, (xmlChar*)"target_stepy" );
596 if(prop) fromString((const char*)prop, _TargetStepY);
597 _TargetStepX= max((sint32)1, _TargetStepX);
598 _TargetStepY= max((sint32)1, _TargetStepY);
600 // Scroll Step
601 prop = (char*) xmlGetProp( node, (xmlChar*)"step_value" );
602 if(prop) fromString((const char*)prop, _StepValue);
604 prop = (char*) xmlGetProp( node, (xmlChar*)"cancelable" );
605 if (prop) _Cancelable = convertBool(prop);
607 prop = (char*) xmlGetProp( node, (xmlChar*)"keyboard" );
608 if (prop) _Keyboard = convertBool(prop);
610 prop= (char*) xmlGetProp (node, (xmlChar*)"frozen");
611 _Frozen = false;
612 if (prop)
613 _Frozen = convertBool(prop);
616 return true;
619 // ------------------------------------------------------------------------------------------------
621 int CCtrlScroll::luaSetTarget(CLuaState &ls)
623 const char *funcName = "setTarget";
624 CLuaIHM::checkArgCount(ls, funcName, 1);
625 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
626 std::string targetId = ls.toString(1);
628 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(targetId));
629 if(group != NULL)
631 setTarget (group);
634 return 0;
637 void CCtrlScroll::updateCoords()
639 if (_Target)
641 // update only if visible
642 if (_Target->getActive())
644 CViewRenderer &rVR = *CViewRenderer::getInstance();
645 sint32 w, h;
646 rVR.getTextureSizeFromId (_TxIdB, w, h);
648 if (_Vertical)
650 if (!_Scale) _W = w;
651 _H = _Target->getMaxHReal();
653 else
655 _W = _Target->getMaxWReal();
656 if (!_Scale) _H = h;
659 CCtrlBase::updateCoords ();
660 if (_Vertical)
662 if(_Target->getHReal()!=_LastTargetHReal || _Target->getMaxHReal()!=_LastTargetMaxHReal ||
663 _Target->getOfsY() != _LastTargetOfsY
666 _LastTargetHReal= _Target->getHReal();
667 _LastTargetMaxHReal= _Target->getMaxHReal();
668 _LastTargetOfsY = _Target->getOfsY();
670 // Activate only if needed
671 setActive(_Target->getHReal() > _Target->getMaxHReal());
672 CCtrlBase::updateCoords();
674 // Calculate size of the track button
675 if ((_Target->getHReal() <= _Target->getMaxHReal()) || (_Target->getHReal() == 0))
677 _TrackSize = _Target->getMaxHReal();
679 else
681 float factor = (float)_Target->getMaxHReal() / (float)_Target->getHReal();
682 factor = _TrackSizeMin + factor * (this->getHReal() - _TrackSizeMin);
683 _TrackSize = (sint32)factor;
685 // Calculate pos of the track button
686 if (_Target->getHReal() <= _Target->getMaxHReal())
688 if (_Aligned == 1) // BOTTOM
689 _TrackPos = 0;
690 else // TOP
691 _TrackPos = getHReal()-_TrackSize;
693 else
695 if (_Aligned == 1) // BOTTOM
697 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
698 factor = -(float)_Target->getOfsY() / factor;
699 if (factor < 0.0f) factor = 0.0f;
700 if (factor > 1.0f) factor = 1.0f;
701 _TrackPos = factor * (getHReal()-_TrackSize);
703 else // TOP
705 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
706 factor = (float)_Target->getOfsY() / factor;
707 if (factor < 0.0f) factor = 0.0f;
708 if (factor > 1.0f) factor = 1.0f;
709 sint32 hreal = getHReal();
710 _TrackPos = (1.0f-factor) * (hreal - _TrackSize);
714 // invalidate coords.
715 computeTargetOfsFromPos();
718 else // Horizontal Tracker
720 if(_Target->getWReal()!=_LastTargetWReal || _Target->getMaxWReal()!=_LastTargetMaxWReal ||
721 _Target->getOfsX() != _LastTargetOfsX)
723 _LastTargetWReal= _Target->getWReal();
724 _LastTargetMaxWReal= _Target->getMaxWReal();
725 _LastTargetOfsX = _Target->getOfsX();
727 // Activate only if needed
728 setActive(_Target->getWReal() > _Target->getMaxWReal());
729 CCtrlBase::updateCoords();
731 // Calculate size of the track button
732 if ((_Target->getWReal() <= _Target->getMaxWReal()) || (_Target->getWReal() == 0))
734 _TrackSize = _Target->getMaxWReal();
736 else
738 float factor = (float)_Target->getMaxWReal() / (float)_Target->getWReal();
739 factor = _TrackSizeMin + factor * (this->getWReal() - _TrackSizeMin);
740 _TrackSize = (sint32)factor;
742 // Calculate pos of the track button
743 if (_Target->getWReal() <= _Target->getMaxWReal())
745 if (_Aligned == 2) // LEFT
746 _TrackPos = 0;
747 else // RIGHT
748 _TrackPos = getWReal()-_TrackSize;
750 else
752 if (_Aligned == 2) // LEFT
754 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
755 factor = -(float)_Target->getOfsX() / factor;
756 if (factor < 0.0f) factor = 0.0f;
757 if (factor > 1.0f) factor = 1.0f;
758 _TrackPos = factor * (getWReal()-_TrackSize);
760 else // RIGHT
762 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
763 factor = (float)_Target->getOfsX() / factor;
764 if (factor < 0.0f) factor = 0.0f;
765 if (factor > 1.0f) factor = 1.0f;
766 sint32 hreal = getWReal();
767 _TrackPos = (1.0f-factor) * (hreal - _TrackSize);
771 // invalidate coords.
772 computeTargetOfsFromPos();
776 // reset cache
777 else
779 _LastTargetHReal= 0;
780 _LastTargetMaxHReal= 0;
781 _LastTargetWReal= 0;
782 _LastTargetMaxWReal= 0;
783 _LastTargetOfsX = 0;
784 _LastTargetOfsY = 0;
785 setActive(false);
788 else
790 CCtrlBase::updateCoords ();
791 if (_IsDBLink)
792 _Value = _DBLink.getSInt32();
793 if (_Vertical)
795 float factor;
796 if (_Aligned == 1) // BOTTOM
797 factor = ((float)_Value-_Min) / (_Max-_Min);
798 else // TOP
799 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
800 factor *= (this->getHReal() - _TrackSize);
802 _TrackDispPos = (sint32)factor;
804 else
806 float factor;
807 if (_Aligned == 2) // LEFT
808 factor = ((float)_Value-_Min) / (_Max-_Min);
809 else // RIGHT
810 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
811 factor *= (this->getWReal() - _TrackSize);
813 _TrackDispPos = (sint32)factor;
816 CCtrlBase::updateCoords ();
819 // ------------------------------------------------------------------------------------------------
820 void CCtrlScroll::draw()
822 CViewRenderer &rVR = *CViewRenderer::getInstance();
823 CRGBA col = CWidgetManager::getInstance()->getGlobalColorForContent();
825 if (_Target)
827 if (_Vertical)
829 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos, _WReal, 4, 0, false, _TxIdB, col );
830 if (_TileM == 0)
831 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, col );
832 else
833 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal, _YReal+_TrackPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, _TileM-1, col );
834 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackPos+_TrackSize-4, _WReal, 4, 0, false, _TxIdT, col );
836 else
838 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos, _YReal, 4, _HReal, 0, false, _TxIdB, col );
839 if (_TileM == 0)
840 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, col );
841 else
842 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal+_TrackPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, _TileM-1, col );
843 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackPos+_TrackSize-4, _YReal, 4, _HReal, 0, false, _TxIdT, col );
846 else
848 if (_Vertical)
850 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos, _WReal, 4, 0, false, _TxIdB, col );
851 if (_TileM == 0)
852 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, col );
853 else
854 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal, _YReal+_TrackDispPos+4, _WReal, _TrackSize-8, 0, false, _TxIdM, _TileM-1, col );
855 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_TrackDispPos+_TrackSize-4, _WReal, 4, 0, false, _TxIdT, col );
857 else
859 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos, _YReal, 4, _HReal, 0, false, _TxIdB, col );
860 if (_TileM == 0)
861 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, col );
862 else
863 rVR.drawRotFlipBitmapTiled (_RenderLayer, _XReal+_TrackDispPos+4, _YReal, _TrackSize-8, _HReal, 0, false, _TxIdM, _TileM-1, col );
864 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_TrackDispPos+_TrackSize-4, _YReal, 4, _HReal, 0, false, _TxIdT, col );
869 // ------------------------------------------------------------------------------------------------
870 bool CCtrlScroll::handleEvent (const NLGUI::CEventDescriptor &event)
872 if (CCtrlBase::handleEvent(event)) return true;
873 if (!_Active || _Frozen)
874 return false;
876 if (event.getType() == NLGUI::CEventDescriptor::mouse)
878 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
879 if ((CWidgetManager::getInstance()->getCapturePointerLeft() != this) &&
880 (!((eventDesc.getX() >= _XReal) &&
881 (eventDesc.getX() < (_XReal + _WReal))&&
882 (eventDesc.getY() > _YReal) &&
883 (eventDesc.getY() <= (_YReal+ _HReal)))))
884 return false;
886 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
888 _MouseDown = true;
889 _InitialValue = getValue();
890 if (!_Target)
891 _TrackPos = _TrackDispPos;
892 _MouseDownOffsetX = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos));
893 _MouseDownOffsetY = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0));
895 // if target is a menu, hidde its sub menus
896 if(_Target && _Target->getParent())
898 CGroupSubMenuBase *menu = dynamic_cast<CGroupSubMenuBase*>(_Target->getParent());
899 if(menu)
900 menu->hideSubMenus();
902 return true;
904 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
906 _MouseDown = false;
907 runAH(_AHOnScrollEnd, _AHOnScrollEndParams.empty() ? _AHOnScrollParams : _AHOnScrollEndParams); // backward compatibility
908 return true;
910 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown && _MouseDown && _Cancelable)
912 _MouseDown = false;
913 setValue(_InitialValue);
914 runAH(_AHOnScrollCancel, _AHOnScrollCancelParams); // backward compatibility
915 return true;
917 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
919 if (_MouseDown)
921 sint32 dx = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos) + _MouseDownOffsetX);
922 sint32 dy = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0 ) + _MouseDownOffsetY);
923 if (dx != 0) moveTrackX (dx);
924 if (dy != 0) moveTrackY (dy);
926 return true;
928 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousewheel && _Vertical)
930 moveTargetY (-(eventDesc.getWheel() * 12));
931 return true;
934 else if (event.getType() == NLGUI::CEventDescriptor::key)
936 const NLGUI::CEventDescriptorKey &eventDesc = (const NLGUI::CEventDescriptorKey &)event;
938 if (eventDesc.getKeyEventType() == NLGUI::CEventDescriptorKey::keydown)
940 if (_Keyboard)
942 sint32 i = 0;
943 // direction
944 if (eventDesc.getKey() == KeyNEXT) i++;
945 else if (eventDesc.getKey() == KeyPRIOR) i--;
946 else
947 return false;
949 if (_Vertical)
950 moveTrackY(-(i * _TargetStepY));
951 else
952 moveTrackX(-(i * _TargetStepX));
954 return true;
958 return false;
961 // ------------------------------------------------------------------------------------------------
962 void CCtrlScroll::setTarget (CInterfaceGroup *pIG)
964 _Target = pIG;
966 if (_Vertical)
968 if (_Target->getPosRef()&Hotspot_Tx)
969 _Aligned = 0;
970 else
971 _Aligned = 1;
973 if (_Target->getPosRef()&Hotspot_Tx)
974 _Inverted = true;
975 else
976 _Inverted = true;
978 else
980 if (_Target->getPosRef()&Hotspot_xL)
981 _Aligned = 2;
982 else
983 _Aligned = 3;
985 if (_Target->getPosRef()&Hotspot_xL)
986 _Inverted = true;
987 else
988 _Inverted = true;
991 // ------------------------------------------------------------------------------------------------
992 sint32 CCtrlScroll::moveTrackX (sint32 dx)
994 if (_Vertical)
995 return 0;
996 if ((getWReal()-_TrackSize) <= 0)
997 return 0;
999 float newtpos;
1000 float tpos = _TrackPos;
1001 sint32 tsize = _TrackSize;
1003 // Limit the scroller to the defined area
1004 newtpos = tpos + dx;
1005 if (newtpos < 0) newtpos = 0;
1006 if (newtpos > (getWReal()-tsize)) newtpos = (getWReal()-tsize);
1007 dx = newtpos - tpos;
1009 if (_Target)
1011 _TrackPos = newtpos;
1013 computeTargetOfsFromPos();
1015 else // This is a number scroller
1017 float factor = (float)(_Max - _Min);
1019 if (_Aligned == 2) // LEFT
1020 factor = -factor * newtpos / (float)(getWReal()-tsize) - _Min;
1021 else // RIGHT
1022 factor = factor * (1.0f-(newtpos / (float)(getWReal()-tsize))) + _Min;
1024 _TrackPos = newtpos;
1026 if (_Aligned == 2) // LEFT
1027 _Value = (sint32) (_Inverted ? factor : -factor);
1028 else // RIGHT
1029 _Value = (sint32) (_Inverted ? factor : -factor);
1031 // step and clamp value
1032 normalizeValue(_Value);
1035 float factor;
1036 if (_Aligned == 2) // LEFT
1037 factor = ((float)_Value-_Min) / (_Max-_Min);
1038 else // RIGHT
1039 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
1040 factor *= (this->getWReal() - _TrackSize);
1042 _TrackDispPos = (sint32)factor;
1045 if (_IsDBLink)
1047 _ObserverOn = false;
1048 _DBLink.setSInt32 (_Value);
1049 _ObserverOn = true;
1053 // Launch the scroller event if any
1054 runAH(_AHOnScroll, _AHOnScrollParams);
1056 return dx;
1059 // ------------------------------------------------------------------------------------------------
1060 sint32 CCtrlScroll::moveTrackY (sint32 dy)
1062 if (!_Vertical)
1063 return 0;
1064 if ((getHReal()-_TrackSize) <= 0)
1065 return 0;
1067 float newtpos;
1068 float tpos = _TrackPos;
1069 sint32 tsize = _TrackSize;
1071 // Limit the scroller to the defined area
1072 newtpos = tpos + dy;
1073 if (newtpos < 0) newtpos = 0;
1074 if (newtpos > (getHReal()-tsize)) newtpos = (getHReal()-tsize);
1075 dy = newtpos - tpos;
1077 if (_Target)
1079 _TrackPos = newtpos;
1081 computeTargetOfsFromPos();
1083 else // This is a number scroller
1085 float factor = (float)(_Max - _Min);
1087 if (_Aligned == 1) // BOTTOM
1088 factor = -factor * newtpos / (float)(getHReal()-tsize) - _Min;
1089 else // TOP
1090 factor = factor * (1.0f-(newtpos / (float)(getHReal()-tsize))) + _Min;
1092 _TrackPos = newtpos;
1094 if (_Aligned == 1) // BOTTOM
1095 _Value = (sint32) (_Inverted ? factor : -factor);
1096 else // TOP
1097 _Value = (sint32) (_Inverted ? factor : -factor);
1099 // step and clamp value
1100 normalizeValue(_Value);
1103 float factor;
1104 if (_Aligned == 1) // BOTTOM
1105 factor = ((float)_Value-_Min) / (_Max-_Min);
1106 else // TOP
1107 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
1108 factor *= (this->getHReal() - _TrackSize);
1110 _TrackDispPos = (sint32)factor;
1113 if (_IsDBLink)
1115 _ObserverOn = false;
1116 _DBLink.setSInt32 (_Value);
1117 _ObserverOn = true;
1121 // Launch the scroller event if any
1122 runAH(_AHOnScroll, _AHOnScrollParams);
1124 return dy;
1127 // ------------------------------------------------------------------------------------------------
1128 void CCtrlScroll::setTextureBottomOrLeft (const std::string &txName)
1130 CViewRenderer &rVR = *CViewRenderer::getInstance();
1131 _TxIdB = rVR.getTextureIdFromName(txName);
1134 // ------------------------------------------------------------------------------------------------
1135 void CCtrlScroll::setTextureMiddle (const std::string &txName)
1137 CViewRenderer &rVR = *CViewRenderer::getInstance();
1138 _TxIdM = rVR.getTextureIdFromName(txName);
1141 // ------------------------------------------------------------------------------------------------
1142 void CCtrlScroll::setTextureTopOrRight (const std::string &txName)
1144 CViewRenderer &rVR = *CViewRenderer::getInstance();
1145 _TxIdT = rVR.getTextureIdFromName(txName);
1148 std::string CCtrlScroll::getTextureBottomOrLeft() const
1150 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdB );
1153 std::string CCtrlScroll::getTextureMiddle() const
1155 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdM );
1158 std::string CCtrlScroll::getTextureTopOrRight() const
1160 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdT );
1163 // ------------------------------------------------------------------------------------------------
1164 void CCtrlScroll::setValue(sint32 value)
1166 normalizeValue(value);
1168 if (_IsDBLink)
1170 _ObserverOn = false;
1171 _DBLink.setSInt32(value);
1172 _ObserverOn = true;
1174 else
1176 _Value = value;
1178 invalidateCoords();
1181 // ------------------------------------------------------------------------------------------------
1182 void CCtrlScroll::setTrackPos(sint32 pos)
1184 if (_Vertical)
1186 moveTrackY(pos - _TrackPos);
1188 else
1190 moveTrackX(pos - _TrackPos);
1192 invalidateCoords();
1195 // ------------------------------------------------------------------------------------------------
1196 void CCtrlScroll::computeTargetOfsFromPos()
1198 if(_Vertical)
1200 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
1202 if (_Aligned == 1) // BOTTOM
1203 factor = -factor * _TrackPos / favoid0((float)(getHReal()-_TrackSize));
1204 else // TOP
1205 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getHReal()-_TrackSize))));
1207 // Compute Steped target
1208 sint32 nexOfsY= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1209 if(_TargetStepY>1)
1210 nexOfsY= ((nexOfsY+_TargetStepY/2)/_TargetStepY) * _TargetStepY;
1211 _Target->setOfsY (nexOfsY);
1212 _LastTargetOfsY = nexOfsY;
1214 // invalidate only XReal/YReal, doing only 1 pass
1215 _Target->invalidateCoords(1);
1217 else
1219 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
1221 if (_Aligned == 2) // LEFT
1222 factor = -factor * _TrackPos / favoid0((float)(getWReal()-_TrackSize));
1223 else // RIGHT
1224 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getWReal()-_TrackSize))));
1226 // Compute Steped target
1227 sint32 nexOfsX= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1228 if(_TargetStepX>1)
1229 nexOfsX= ((nexOfsX+_TargetStepX/2)/_TargetStepX) * _TargetStepX;
1230 _Target->setOfsX (nexOfsX);
1231 _LastTargetOfsX = nexOfsX;
1233 // invalidate only XReal/YReal, doing only 1 pass
1234 _Target->invalidateCoords(1);
1238 // ------------------------------------------------------------------------------------------------
1239 void CCtrlScroll::update(ICDBNode * /* node */)
1241 if (!_ObserverOn) return;
1242 _Value = _DBLink.getSInt32();
1243 // the value in the db changed
1244 invalidateCoords(1);
1245 if (_Target) _Target->invalidateCoords(1);
1249 // ***************************************************************************
1250 void CCtrlScroll::moveTargetX (sint32 dx)
1252 if(!_Target)
1253 return;
1254 sint32 maxWReal= _Target->getMaxWReal();
1255 sint32 wReal= _Target->getWReal();
1256 if(wReal <= maxWReal)
1257 return;
1260 // compute the new ofsX.
1261 sint32 ofsX= _Target->getOfsX();
1262 ofsX+= dx;
1263 clamp(ofsX, 0, wReal-maxWReal);
1264 _Target->setOfsX(ofsX);
1266 // compute new trackPos.
1267 if (_Aligned == 2) // LEFT
1269 float factor = (float)(wReal-maxWReal);
1270 factor = -(float)ofsX / factor;
1271 clamp(factor, 0.f, 1.f);
1272 _TrackPos = factor * (getWReal()-_TrackSize);
1274 else // RIGHT
1276 float factor = (float)(wReal-maxWReal);
1277 factor = (float)ofsX / factor;
1278 clamp(factor, 0.f, 1.f);
1279 _TrackPos = (1.0f-factor) * (getWReal() - _TrackSize);
1282 // invalidate only position. 1 pass is sufficient
1283 invalidateCoords(1);
1286 // ***************************************************************************
1287 void CCtrlScroll::moveTargetY (sint32 dy)
1289 if(!_Target)
1290 return;
1291 sint32 maxHReal= _Target->getMaxHReal();
1292 sint32 hReal= _Target->getHReal();
1293 if(hReal <= maxHReal)
1294 return;
1296 if (_TargetStepY > 1)
1298 sint sign = (0 < dy) - (dy < 0);
1299 dy = sign * max(1, (dy / _TargetStepY)) * _TargetStepY;
1302 // compute the new ofsY.
1303 sint32 ofsY= _Target->getOfsY();
1304 ofsY+= dy;
1306 // compute new trackPos.
1307 if (_Aligned == 1) // BOTTOM
1309 clamp(ofsY, maxHReal - hReal, 0);
1310 _Target->setOfsY(ofsY);
1311 float factor = (float)(hReal-maxHReal);
1312 factor = -(float)ofsY / factor;
1313 clamp(factor, 0.f, 1.f);
1314 _TrackPos = factor * (getHReal()-_TrackSize);
1316 else // TOP
1318 clamp(ofsY, 0, hReal-maxHReal);
1319 _Target->setOfsY(ofsY);
1320 float factor = (float)(hReal-maxHReal);
1321 factor = (float)ofsY / factor;
1322 clamp(factor, 0.f, 1.f);
1323 _TrackPos = (1.0f-factor) * (getHReal() - _TrackSize);
1326 // invalidate only position. 1 pass is sufficient
1327 invalidateCoords(1);
1330 // ***************************************************************************
1331 void CCtrlScroll::normalizeValue(sint32 &value)
1333 // if, 0 no step
1334 if(_StepValue==0 || _StepValue==1)
1335 return;
1336 // if interval is null, force min!
1337 if(_Max==_Min)
1339 value= _Min;
1340 return;
1343 // get range of possible position
1344 // sint32 size= _Max - _Min;
1346 // step (round)
1347 sint32 val= (value + (_StepValue/2) -_Min) / _StepValue;
1348 val= _Min + val * _StepValue;
1349 clamp(val, _Min, _Max);
1350 value= val;
1353 // ***************************************************************************
1354 void CCtrlScroll::setFrozen (bool state)
1356 _Frozen = state;
1357 if (_Frozen)
1359 _Value = 0;
1364 // ------------------------------------------------------------------------------------------------
1365 int CCtrlScroll::luaEnsureVisible(CLuaState &ls)
1367 const char *funcName = "ensureVisible";
1368 CLuaIHM::checkArgCount(ls, funcName, 3);
1369 CLuaIHM::checkArgTypeUIElement(ls, funcName, 1);
1370 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
1371 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING);
1372 THotSpot hs[2];
1373 std::string hsStr[] = { ls.toString(2), ls.toString(3) };
1375 for (uint hsIndex = 0; hsIndex < 2; ++ hsIndex)
1377 if (_Vertical)
1379 if (NLMISC::nlstricmp(hsStr[hsIndex], "T") == 0)
1381 hs[hsIndex] = Hotspot_Tx;
1383 else
1384 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1386 hs[hsIndex] = Hotspot_Mx;
1388 else
1389 if (NLMISC::nlstricmp(hsStr[hsIndex], "B") == 0)
1391 hs[hsIndex] = Hotspot_Bx;
1393 else
1395 hs[hsIndex] = Hotspot_Bx;
1396 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for vertical scrollbar", funcName);
1399 else
1401 if (NLMISC::nlstricmp(hsStr[hsIndex], "L") == 0)
1403 hs[hsIndex] = Hotspot_xL;
1405 else
1406 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1408 hs[hsIndex] = Hotspot_xM;
1410 else
1411 if (NLMISC::nlstricmp(hsStr[hsIndex], "R") == 0)
1413 hs[hsIndex] = Hotspot_xR;
1415 else
1417 hs[hsIndex] = Hotspot_xL;
1418 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for horizontal scrollbar", funcName);
1422 ensureVisible(CLuaIHM::getUIOnStack(ls, 1), hs[0], hs[1]);
1423 return 0;
1427 // ------------------------------------------------------------------------------------------------
1428 void CCtrlScroll::ensureVisible(CInterfaceElement *childElement, THotSpot childHotSpot, THotSpot parentHotSpot)
1430 if (!_Target) return; // not connected to a target yet
1431 if (!childElement) return;
1432 // compute corners of interest for enclosed element & enclosing group
1433 sint32 childX, childY;
1434 childElement->getCorner(childX, childY, childHotSpot);
1435 if (_Vertical)
1437 sint32 maxHReal= _Target->getMaxHReal();
1438 sint32 hReal= _Target->getHReal();
1439 if(hReal > maxHReal)
1441 sint enclosingDY;
1442 switch (parentHotSpot)
1444 case Hotspot_Bx:
1445 enclosingDY = maxHReal;
1446 break;
1447 case Hotspot_Mx:
1448 enclosingDY = maxHReal / 2;
1449 break;
1450 case Hotspot_Tx:
1451 enclosingDY = 0;
1452 break;
1453 default:
1454 nlassert(0);
1455 break;
1457 if (_Aligned == 0)
1459 // Top aligned case
1460 sint32 offsetY = (_Target->getYReal() + _Target->getHReal() - childY) - enclosingDY;
1461 NLMISC::clamp(offsetY, 0, hReal - maxHReal);
1462 _Target->setOfsY(offsetY);
1463 _Target->invalidateCoords();
1465 else if (_Aligned == 1)
1467 // Bottom aligned case
1468 sint32 offsetY = (maxHReal - enclosingDY) - (childY - _Target->getYReal());
1469 NLMISC::clamp(offsetY, maxHReal - hReal, 0);
1470 _Target->setOfsY(offsetY);
1471 _Target->invalidateCoords();
1474 // else, ... fully visible (not occluded by parent group)
1476 else
1478 sint32 maxWReal= _Target->getMaxWReal();
1479 sint32 wReal= _Target->getWReal();
1480 if(wReal > maxWReal)
1482 sint enclosingDX;
1483 switch (parentHotSpot)
1485 case Hotspot_xL:
1486 enclosingDX = maxWReal;
1487 break;
1488 case Hotspot_xM:
1489 enclosingDX = maxWReal / 2;
1490 break;
1491 case Hotspot_xR:
1492 enclosingDX = 0;
1493 break;
1494 default:
1495 nlassert(0);
1496 break;
1498 if (_Aligned == 3)
1500 // right aligned case
1501 sint32 offsetX = (_Target->getXReal() + _Target->getWReal() - childX) - enclosingDX;
1502 NLMISC::clamp(offsetX, 0, wReal - maxWReal);
1503 _Target->setOfsX(offsetX);
1504 _Target->invalidateCoords();
1506 else if (_Aligned == 2)
1508 // Left aligned case
1509 sint32 offsetX = (maxWReal - enclosingDX) - (childX - _Target->getXReal());
1510 NLMISC::clamp(offsetX, maxWReal - wReal, 0);
1511 _Target->setOfsX(offsetX);
1512 _Target->invalidateCoords();
1515 // else, ... fully visible (not occluded by parent group)