Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / gui / ctrl_scroll.cpp
blob28d7f2fede6920586c6817400aeaf4f7fb96b3ef
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;
875 if (event.getType() == NLGUI::CEventDescriptor::mouse)
877 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
878 if ((CWidgetManager::getInstance()->getCapturePointerLeft() != this) &&
879 (!((eventDesc.getX() >= _XReal) &&
880 (eventDesc.getX() < (_XReal + _WReal))&&
881 (eventDesc.getY() > _YReal) &&
882 (eventDesc.getY() <= (_YReal+ _HReal)))))
883 return false;
885 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
887 _MouseDown = true;
888 _InitialValue = getValue();
889 if (!_Target)
890 _TrackPos = _TrackDispPos;
891 _MouseDownOffsetX = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos));
892 _MouseDownOffsetY = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0));
894 // if target is a menu, hidde its sub menus
895 if(_Target && _Target->getParent())
897 CGroupSubMenuBase *menu = dynamic_cast<CGroupSubMenuBase*>(_Target->getParent());
898 if(menu)
899 menu->hideSubMenus();
901 return true;
903 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
905 _MouseDown = false;
906 runAH(_AHOnScrollEnd, _AHOnScrollEndParams.empty() ? _AHOnScrollParams : _AHOnScrollEndParams); // backward compatibility
907 return true;
909 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown && _MouseDown && _Cancelable)
911 _MouseDown = false;
912 setValue(_InitialValue);
913 runAH(_AHOnScrollCancel, _AHOnScrollCancelParams); // backward compatibility
914 return true;
916 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
918 if (_MouseDown)
920 sint32 dx = eventDesc.getX() - (getXReal() + (_Vertical ? 0 : _TrackPos) + _MouseDownOffsetX);
921 sint32 dy = eventDesc.getY() - (getYReal() + (_Vertical ? _TrackPos : 0 ) + _MouseDownOffsetY);
922 if (dx != 0) moveTrackX (dx);
923 if (dy != 0) moveTrackY (dy);
925 return true;
927 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousewheel && _Vertical)
929 moveTargetY (-(eventDesc.getWheel() * 12));
930 return true;
933 else if (event.getType() == NLGUI::CEventDescriptor::key)
935 const NLGUI::CEventDescriptorKey &eventDesc = (const NLGUI::CEventDescriptorKey &)event;
937 if (eventDesc.getKeyEventType() == NLGUI::CEventDescriptorKey::keydown)
939 if (_Keyboard)
941 sint32 i = 0;
942 // direction
943 if (eventDesc.getKey() == KeyNEXT) i++;
944 else if (eventDesc.getKey() == KeyPRIOR) i--;
945 else
946 return false;
948 if (_Vertical)
949 moveTrackY(-(i * _TargetStepY));
950 else
951 moveTrackX(-(i * _TargetStepX));
953 return true;
957 return false;
960 // ------------------------------------------------------------------------------------------------
961 void CCtrlScroll::setTarget (CInterfaceGroup *pIG)
963 _Target = pIG;
965 if (_Vertical)
967 if (_Target->getPosRef()&Hotspot_Tx)
968 _Aligned = 0;
969 else
970 _Aligned = 1;
972 if (_Target->getPosRef()&Hotspot_Tx)
973 _Inverted = true;
974 else
975 _Inverted = true;
977 else
979 if (_Target->getPosRef()&Hotspot_xL)
980 _Aligned = 2;
981 else
982 _Aligned = 3;
984 if (_Target->getPosRef()&Hotspot_xL)
985 _Inverted = true;
986 else
987 _Inverted = true;
990 // ------------------------------------------------------------------------------------------------
991 sint32 CCtrlScroll::moveTrackX (sint32 dx)
993 if (_Vertical)
994 return 0;
995 if ((getWReal()-_TrackSize) <= 0)
996 return 0;
998 float newtpos;
999 float tpos = _TrackPos;
1000 sint32 tsize = _TrackSize;
1002 // Limit the scroller to the defined area
1003 newtpos = tpos + dx;
1004 if (newtpos < 0) newtpos = 0;
1005 if (newtpos > (getWReal()-tsize)) newtpos = (getWReal()-tsize);
1006 dx = newtpos - tpos;
1008 if (_Target)
1010 _TrackPos = newtpos;
1012 computeTargetOfsFromPos();
1014 else // This is a number scroller
1016 float factor = (float)(_Max - _Min);
1018 if (_Aligned == 2) // LEFT
1019 factor = -factor * newtpos / (float)(getWReal()-tsize) - _Min;
1020 else // RIGHT
1021 factor = factor * (1.0f-(newtpos / (float)(getWReal()-tsize))) + _Min;
1023 _TrackPos = newtpos;
1025 if (_Aligned == 2) // LEFT
1026 _Value = (sint32) (_Inverted ? factor : -factor);
1027 else // RIGHT
1028 _Value = (sint32) (_Inverted ? factor : -factor);
1030 // step and clamp value
1031 normalizeValue(_Value);
1034 float factor;
1035 if (_Aligned == 2) // LEFT
1036 factor = ((float)_Value-_Min) / (_Max-_Min);
1037 else // RIGHT
1038 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
1039 factor *= (this->getWReal() - _TrackSize);
1041 _TrackDispPos = (sint32)factor;
1044 if (_IsDBLink)
1046 _ObserverOn = false;
1047 _DBLink.setSInt32 (_Value);
1048 _ObserverOn = true;
1052 // Launch the scroller event if any
1053 runAH(_AHOnScroll, _AHOnScrollParams);
1055 return dx;
1058 // ------------------------------------------------------------------------------------------------
1059 sint32 CCtrlScroll::moveTrackY (sint32 dy)
1061 if (!_Vertical)
1062 return 0;
1063 if ((getHReal()-_TrackSize) <= 0)
1064 return 0;
1066 float newtpos;
1067 float tpos = _TrackPos;
1068 sint32 tsize = _TrackSize;
1070 // Limit the scroller to the defined area
1071 newtpos = tpos + dy;
1072 if (newtpos < 0) newtpos = 0;
1073 if (newtpos > (getHReal()-tsize)) newtpos = (getHReal()-tsize);
1074 dy = newtpos - tpos;
1076 if (_Target)
1078 _TrackPos = newtpos;
1080 computeTargetOfsFromPos();
1082 else // This is a number scroller
1084 float factor = (float)(_Max - _Min);
1086 if (_Aligned == 1) // BOTTOM
1087 factor = -factor * newtpos / (float)(getHReal()-tsize) - _Min;
1088 else // TOP
1089 factor = factor * (1.0f-(newtpos / (float)(getHReal()-tsize))) + _Min;
1091 _TrackPos = newtpos;
1093 if (_Aligned == 1) // BOTTOM
1094 _Value = (sint32) (_Inverted ? factor : -factor);
1095 else // TOP
1096 _Value = (sint32) (_Inverted ? factor : -factor);
1098 // step and clamp value
1099 normalizeValue(_Value);
1102 float factor;
1103 if (_Aligned == 1) // BOTTOM
1104 factor = ((float)_Value-_Min) / (_Max-_Min);
1105 else // TOP
1106 factor = 1.0f - ((float)_Value-_Min) / (_Max-_Min);
1107 factor *= (this->getHReal() - _TrackSize);
1109 _TrackDispPos = (sint32)factor;
1112 if (_IsDBLink)
1114 _ObserverOn = false;
1115 _DBLink.setSInt32 (_Value);
1116 _ObserverOn = true;
1120 // Launch the scroller event if any
1121 runAH(_AHOnScroll, _AHOnScrollParams);
1123 return dy;
1126 // ------------------------------------------------------------------------------------------------
1127 void CCtrlScroll::setTextureBottomOrLeft (const std::string &txName)
1129 CViewRenderer &rVR = *CViewRenderer::getInstance();
1130 _TxIdB = rVR.getTextureIdFromName(txName);
1133 // ------------------------------------------------------------------------------------------------
1134 void CCtrlScroll::setTextureMiddle (const std::string &txName)
1136 CViewRenderer &rVR = *CViewRenderer::getInstance();
1137 _TxIdM = rVR.getTextureIdFromName(txName);
1140 // ------------------------------------------------------------------------------------------------
1141 void CCtrlScroll::setTextureTopOrRight (const std::string &txName)
1143 CViewRenderer &rVR = *CViewRenderer::getInstance();
1144 _TxIdT = rVR.getTextureIdFromName(txName);
1147 std::string CCtrlScroll::getTextureBottomOrLeft() const
1149 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdB );
1152 std::string CCtrlScroll::getTextureMiddle() const
1154 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdM );
1157 std::string CCtrlScroll::getTextureTopOrRight() const
1159 return CViewRenderer::getInstance()->getTextureNameFromId( _TxIdT );
1162 // ------------------------------------------------------------------------------------------------
1163 void CCtrlScroll::setValue(sint32 value)
1165 normalizeValue(value);
1167 if (_IsDBLink)
1169 _ObserverOn = false;
1170 _DBLink.setSInt32(value);
1171 _ObserverOn = true;
1173 else
1175 _Value = value;
1177 invalidateCoords();
1180 // ------------------------------------------------------------------------------------------------
1181 void CCtrlScroll::setTrackPos(sint32 pos)
1183 if (_Vertical)
1185 moveTrackY(pos - _TrackPos);
1187 else
1189 moveTrackX(pos - _TrackPos);
1191 invalidateCoords();
1194 // ------------------------------------------------------------------------------------------------
1195 void CCtrlScroll::computeTargetOfsFromPos()
1197 if(_Vertical)
1199 float factor = ((float)_Target->getHReal() - (float)_Target->getMaxHReal());
1201 if (_Aligned == 1) // BOTTOM
1202 factor = -factor * _TrackPos / favoid0((float)(getHReal()-_TrackSize));
1203 else // TOP
1204 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getHReal()-_TrackSize))));
1206 // Compute Steped target
1207 sint32 nexOfsY= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1208 if(_TargetStepY>1)
1209 nexOfsY= ((nexOfsY+_TargetStepY/2)/_TargetStepY) * _TargetStepY;
1210 _Target->setOfsY (nexOfsY);
1211 _LastTargetOfsY = nexOfsY;
1213 // invalidate only XReal/YReal, doing only 1 pass
1214 _Target->invalidateCoords(1);
1216 else
1218 float factor = ((float)_Target->getWReal() - (float)_Target->getMaxWReal());
1220 if (_Aligned == 2) // LEFT
1221 factor = -factor * _TrackPos / favoid0((float)(getWReal()-_TrackSize));
1222 else // RIGHT
1223 factor = factor * (1.0f-(_TrackPos / favoid0((float)(getWReal()-_TrackSize))));
1225 // Compute Steped target
1226 sint32 nexOfsX= (sint32) floorf(0.5+(_Inverted ? factor : -factor));
1227 if(_TargetStepX>1)
1228 nexOfsX= ((nexOfsX+_TargetStepX/2)/_TargetStepX) * _TargetStepX;
1229 _Target->setOfsX (nexOfsX);
1230 _LastTargetOfsX = nexOfsX;
1232 // invalidate only XReal/YReal, doing only 1 pass
1233 _Target->invalidateCoords(1);
1237 // ------------------------------------------------------------------------------------------------
1238 void CCtrlScroll::update(ICDBNode * /* node */)
1240 if (!_ObserverOn) return;
1241 _Value = _DBLink.getSInt32();
1242 // the value in the db changed
1243 invalidateCoords(1);
1244 if (_Target) _Target->invalidateCoords(1);
1248 // ***************************************************************************
1249 void CCtrlScroll::moveTargetX (sint32 dx)
1251 if(!_Target)
1252 return;
1253 sint32 maxWReal= _Target->getMaxWReal();
1254 sint32 wReal= _Target->getWReal();
1255 if(wReal <= maxWReal)
1256 return;
1258 // compute the new ofsX.
1259 sint32 ofsX= _Target->getOfsX();
1260 ofsX+= dx;
1261 clamp(ofsX, 0, wReal-maxWReal);
1262 _Target->setOfsX(ofsX);
1264 // compute new trackPos.
1265 if (_Aligned == 2) // LEFT
1267 float factor = (float)(wReal-maxWReal);
1268 factor = -(float)ofsX / factor;
1269 clamp(factor, 0.f, 1.f);
1270 _TrackPos = factor * (getWReal()-_TrackSize);
1272 else // RIGHT
1274 float factor = (float)(wReal-maxWReal);
1275 factor = (float)ofsX / factor;
1276 clamp(factor, 0.f, 1.f);
1277 _TrackPos = (1.0f-factor) * (getWReal() - _TrackSize);
1280 // invalidate only position. 1 pass is sufficient
1281 invalidateCoords(1);
1284 // ***************************************************************************
1285 void CCtrlScroll::moveTargetY (sint32 dy)
1287 if(!_Target)
1288 return;
1289 sint32 maxHReal= _Target->getMaxHReal();
1290 sint32 hReal= _Target->getHReal();
1291 if(hReal <= maxHReal)
1292 return;
1294 if (_TargetStepY > 1)
1296 sint sign = (0 < dy) - (dy < 0);
1297 dy = sign * max(1, (dy / _TargetStepY)) * _TargetStepY;
1300 // compute the new ofsY.
1301 sint32 ofsY= _Target->getOfsY();
1302 ofsY+= dy;
1304 // compute new trackPos.
1305 if (_Aligned == 1) // BOTTOM
1307 clamp(ofsY, maxHReal - hReal, 0);
1308 _Target->setOfsY(ofsY);
1309 float factor = (float)(hReal-maxHReal);
1310 factor = -(float)ofsY / factor;
1311 clamp(factor, 0.f, 1.f);
1312 _TrackPos = factor * (getHReal()-_TrackSize);
1314 else // TOP
1316 clamp(ofsY, 0, hReal-maxHReal);
1317 _Target->setOfsY(ofsY);
1318 float factor = (float)(hReal-maxHReal);
1319 factor = (float)ofsY / factor;
1320 clamp(factor, 0.f, 1.f);
1321 _TrackPos = (1.0f-factor) * (getHReal() - _TrackSize);
1324 // invalidate only position. 1 pass is sufficient
1325 invalidateCoords(1);
1328 // ***************************************************************************
1329 void CCtrlScroll::normalizeValue(sint32 &value)
1331 // if, 0 no step
1332 if(_StepValue==0 || _StepValue==1)
1333 return;
1334 // if interval is null, force min!
1335 if(_Max==_Min)
1337 value= _Min;
1338 return;
1341 // get range of possible position
1342 // sint32 size= _Max - _Min;
1344 // step (round)
1345 sint32 val= (value + (_StepValue/2) -_Min) / _StepValue;
1346 val= _Min + val * _StepValue;
1347 clamp(val, _Min, _Max);
1348 value= val;
1351 // ***************************************************************************
1352 void CCtrlScroll::setFrozen (bool state)
1354 _Frozen = state;
1355 if (_Frozen)
1357 _Value = 0;
1362 // ------------------------------------------------------------------------------------------------
1363 int CCtrlScroll::luaEnsureVisible(CLuaState &ls)
1365 const char *funcName = "ensureVisible";
1366 CLuaIHM::checkArgCount(ls, funcName, 3);
1367 CLuaIHM::checkArgTypeUIElement(ls, funcName, 1);
1368 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
1369 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING);
1370 THotSpot hs[2];
1371 std::string hsStr[] = { ls.toString(2), ls.toString(3) };
1373 for (uint hsIndex = 0; hsIndex < 2; ++ hsIndex)
1375 if (_Vertical)
1377 if (NLMISC::nlstricmp(hsStr[hsIndex], "T") == 0)
1379 hs[hsIndex] = Hotspot_Tx;
1381 else
1382 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1384 hs[hsIndex] = Hotspot_Mx;
1386 else
1387 if (NLMISC::nlstricmp(hsStr[hsIndex], "B") == 0)
1389 hs[hsIndex] = Hotspot_Bx;
1391 else
1393 hs[hsIndex] = Hotspot_Bx;
1394 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for vertical scrollbar", funcName);
1397 else
1399 if (NLMISC::nlstricmp(hsStr[hsIndex], "L") == 0)
1401 hs[hsIndex] = Hotspot_xL;
1403 else
1404 if (NLMISC::nlstricmp(hsStr[hsIndex], "M") == 0)
1406 hs[hsIndex] = Hotspot_xM;
1408 else
1409 if (NLMISC::nlstricmp(hsStr[hsIndex], "R") == 0)
1411 hs[hsIndex] = Hotspot_xR;
1413 else
1415 hs[hsIndex] = Hotspot_xL;
1416 CLuaIHM::fails(ls, "%s : couldn't parse hotspot for horizontal scrollbar", funcName);
1420 ensureVisible(CLuaIHM::getUIOnStack(ls, 1), hs[0], hs[1]);
1421 return 0;
1425 // ------------------------------------------------------------------------------------------------
1426 void CCtrlScroll::ensureVisible(CInterfaceElement *childElement, THotSpot childHotSpot, THotSpot parentHotSpot)
1428 if (!_Target) return; // not connected to a target yet
1429 if (!childElement) return;
1430 // compute corners of interest for enclosed element & enclosing group
1431 sint32 childX, childY;
1432 childElement->getCorner(childX, childY, childHotSpot);
1433 if (_Vertical)
1435 sint32 maxHReal= _Target->getMaxHReal();
1436 sint32 hReal= _Target->getHReal();
1437 if(hReal > maxHReal)
1439 sint enclosingDY;
1440 switch (parentHotSpot)
1442 case Hotspot_Bx:
1443 enclosingDY = maxHReal;
1444 break;
1445 case Hotspot_Mx:
1446 enclosingDY = maxHReal / 2;
1447 break;
1448 case Hotspot_Tx:
1449 enclosingDY = 0;
1450 break;
1451 default:
1452 nlassert(0);
1453 break;
1455 if (_Aligned == 0)
1457 // Top aligned case
1458 sint32 offsetY = (_Target->getYReal() + _Target->getHReal() - childY) - enclosingDY;
1459 NLMISC::clamp(offsetY, 0, hReal - maxHReal);
1460 _Target->setOfsY(offsetY);
1461 _Target->invalidateCoords();
1463 else if (_Aligned == 1)
1465 // Bottom aligned case
1466 sint32 offsetY = (maxHReal - enclosingDY) - (childY - _Target->getYReal());
1467 NLMISC::clamp(offsetY, maxHReal - hReal, 0);
1468 _Target->setOfsY(offsetY);
1469 _Target->invalidateCoords();
1472 // else, ... fully visible (not occluded by parent group)
1474 else
1476 sint32 maxWReal= _Target->getMaxWReal();
1477 sint32 wReal= _Target->getWReal();
1478 if(wReal > maxWReal)
1480 sint enclosingDX;
1481 switch (parentHotSpot)
1483 case Hotspot_xL:
1484 enclosingDX = maxWReal;
1485 break;
1486 case Hotspot_xM:
1487 enclosingDX = maxWReal / 2;
1488 break;
1489 case Hotspot_xR:
1490 enclosingDX = 0;
1491 break;
1492 default:
1493 nlassert(0);
1494 break;
1496 if (_Aligned == 3)
1498 // right aligned case
1499 sint32 offsetX = (_Target->getXReal() + _Target->getWReal() - childX) - enclosingDX;
1500 NLMISC::clamp(offsetX, 0, wReal - maxWReal);
1501 _Target->setOfsX(offsetX);
1502 _Target->invalidateCoords();
1504 else if (_Aligned == 2)
1506 // Left aligned case
1507 sint32 offsetX = (maxWReal - enclosingDX) - (childX - _Target->getXReal());
1508 NLMISC::clamp(offsetX, maxWReal - wReal, 0);
1509 _Target->setOfsX(offsetX);
1510 _Target->invalidateCoords();
1513 // else, ... fully visible (not occluded by parent group)