1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
25 #include "nel/3d/u_driver.h"
26 #include "nel/3d/u_text_context.h"
28 #include "chat_control.h"
29 #include "interfaces_manager.h"
31 #include <stdlib.h> // for rand()
39 using namespace NLMISC
;
46 extern UDriver
*Driver
;
47 extern UTextContext
*TextContext
;
53 CChatControl::CChatControl(uint id
)
59 //-----------------------------------------------
62 //-----------------------------------------------
63 CChatControl::CChatControl(uint id
, float x
, float y
, float x_pixel
, float y_pixel
, float w
, float h
, float w_pixel
, float h_pixel
, uint leftFunc
, uint rightFunc
, const CPen
&pen
)
64 : CMultiList(id
, x
, y
, x_pixel
, y_pixel
, w
, h
, w_pixel
, h_pixel
, pen
, 2)
66 init(leftFunc
, rightFunc
);
70 //-----------------------------------------------
73 //-----------------------------------------------
74 CChatControl::CChatControl(uint id
, float x
, float y
, float x_pixel
, float y_pixel
, float w
, float h
, float w_pixel
, float h_pixel
, uint leftFunc
, uint rightFunc
, uint32 fontSize
, CRGBA color
, bool shadow
)
75 : CMultiList(id
, x
, y
, x_pixel
, y_pixel
, w
, h
, w_pixel
, h_pixel
, fontSize
, color
, shadow
, 2)
77 init(leftFunc
, rightFunc
);
81 //-----------------------------------------------
83 //-----------------------------------------------
84 void CChatControl::init(uint left
, uint right
)
86 _LeftClickFunction
= left
;
87 _RightClickFunction
= right
;
89 _HistorySize
= 200; // memorize the last 200 lines
92 const float size
= static_cast<float> (1.0/_NbCol
);
94 _ColSize
[1] = static_cast<float> (size
* 1.5);
96 _LastStringHeight
= 0;
100 _MutedColor
= NLMISC::CRGBA(100,100,100);
101 _MutedHighlightColor
= NLMISC::CRGBA(100,200,200);
102 _HighlightColor
= NLMISC::CRGBA(255,255,255);
103 _SysTextColor
= NLMISC::CRGBA(255,255,255);
105 _UsedColors
.insert(_MutedColor
);
106 _UsedColors
.insert(_MutedHighlightColor
);
107 _UsedColors
.insert(_HighlightColor
);
108 _UsedColors
.insert(_SysTextColor
);
110 _SystemDisplayText
= ucstring("");
111 _CommandSid
= CEntityId(); // \todo GUIGUI : REMOVE SID.
113 _SelectedPlayer
= NULL
;
114 _SelectedPlayerSid
= NULL
;
116 /* Seed the random-number generator with current time so that
117 * the numbers will be different every time we run.
119 srand( (unsigned)time( NULL
) );
121 // map the command dummy NLMISC::CEntityId with the display color
122 _PlayersColor
.insert( std::make_pair( _CommandSid
, &_SysTextColor
) );
127 //-----------------------------------------------
129 //-----------------------------------------------
130 void CChatControl::clear()
134 _EndingIterator
= _ItemsList
.rbegin();
135 _EndingSidIterator
= _PlayersSid
.rbegin();
140 //-----------------------------------------------
142 // DEPRECATED, do not use this function
143 //-----------------------------------------------
144 void CChatControl::add(const std::list
<ucstring
> &strList
)
149 //-----------------------------------------------
151 // add text from player
152 //-----------------------------------------------
153 void CChatControl::add( const NLMISC::CEntityId
&sid
, const ucstring
&name
, const ucstring
&text
)
155 /// \toto Malkav: ensure the name is different from system messages displayed text (_SystemDisplayText)
158 // if the player is muted, ignore this phrase
159 if ( _MutedPlayers
.find( sid
) != _MutedPlayers
.end() )
162 // make a list with the name and text
163 static std::list
<ucstring
> ls
;
165 ls
.push_back( name
);
166 ls
.push_back( text
);
168 // add the NLMISC::CEntityId to the list of NLMISC::CEntityId
169 _PlayersSid
.push_back( sid
);
171 // if the max number of line isn't reached
172 if ( ( _HistorySize
> _ItemsList
.size() ) || ( _HistorySize
== 0) )
174 // add the new string
175 _ItemsList
.push_back( ls
);
177 // if this is the first string, init the ending point
178 if ( _ItemsList
.size() == 1)
180 _EndingIterator
= _ItemsList
.rbegin();
181 _EndingSidIterator
= _PlayersSid
.rbegin();
184 // max number reached, delete the oldest line and insert the new one
187 // remove the oldest string
188 _ItemsList
.pop_front();
189 // remove the oldest NLMISC::CEntityId
190 _PlayersSid
.pop_front();
193 _ItemsList
.push_back( ls
);
195 if ( (_AutoScroll
) || (_ItemsList
.size() == 1) )
197 _EndingIterator
= _ItemsList
.rbegin();
198 _EndingSidIterator
= _PlayersSid
.rbegin();
202 // if this a an unknown player:
203 if ( _PlayersColor
.find( sid
) == _PlayersColor
.end() )
205 // get a new display color for that player
207 color
= getNewColor();
209 // add the color to the set of existing color
210 std::pair
<TSetColors::iterator
, bool> ret
= _UsedColors
.insert( color
);
211 //nlassert(ret.second == true);
212 if (ret
.second
!= true)
214 nlwarning("<CChatControl::add> failed to insert color in _UsedColors !");
217 // map the NLMISC::CEntityId with the display color
218 _PlayersColor
.insert( std::make_pair( sid
, &(*(ret
.first
)) ) );
223 //-----------------------------------------------
226 //-----------------------------------------------
227 void CChatControl::add(const ucstring
&text
)
230 // make a list with the name and text
231 static std::list
<ucstring
> ls
;
233 ls
.push_back( _SystemDisplayText
);
234 ls
.push_back( text
);
236 // add the dummy NLMISC::CEntityId to the list of NLMISC::CEntityId
237 _PlayersSid
.push_back( _CommandSid
);
239 // if the max number of line isn't reached
240 if ( ( _HistorySize
> _ItemsList
.size() ) || ( _HistorySize
== 0) )
242 // add the new string
243 _ItemsList
.push_back( ls
);
245 // if this is the first string, init the ending point
246 if ( _ItemsList
.size() == 1)
248 _EndingIterator
= _ItemsList
.rbegin();
249 _EndingSidIterator
= _PlayersSid
.rbegin();
252 // max number reached, delete the oldest line and insert the new one
255 // remove the oldest string
256 _ItemsList
.pop_front();
257 // remove the oldest NLMISC::CEntityId
258 _PlayersSid
.pop_front();
261 _ItemsList
.push_back( ls
);
263 if ( (_AutoScroll
) || (_ItemsList
.size() == 1) )
265 _EndingIterator
= _ItemsList
.rbegin();
266 _EndingSidIterator
= _PlayersSid
.rbegin();
271 //-----------------------------------------------
273 // Display the control.
274 //-----------------------------------------------
275 void CChatControl::display()
277 // \todo GUIGUI : remove this damn thing after the UBI demo.
278 const CRGBA playerColors
[10] =
280 CRGBA(250,250, 10), // 0 : Jaune
281 CRGBA( 50,200, 50), // 1 : Vert
282 CRGBA( 0, 0,255), // 2 : Bleu
283 CRGBA(255,100, 0), // 3 : Orange
284 CRGBA( 64, 0,128), // 4 : Violet
285 CRGBA(128,128, 0), // 5 : Verdatre
286 CRGBA(128, 0, 64), // 6 : Pourpre
287 CRGBA(255,128,192), // 7 : Rose
288 CRGBA( 0,255,255), // 8 : Bleu ciel
289 CRGBA(100,100,100) // 9 : Gris
295 // If the control is hide -> return
299 /// \todo GUIGUI : if the scissor is corrected -> draw the bitmap after the scissor.
300 // calculate the real display size ( clip if scroll bar is visible )
301 float wDisplay
, yDisplay
, hDisplay
;
303 if (_VScroll
->show() )
304 wDisplay
= _W_Display
- _VScroll
->size();
306 wDisplay
= _W_Display
;
308 if (_HScroll
->show() )
310 hDisplay
= _H_Display
- _HScroll
->size();
311 yDisplay
= _Y_Display
+ _HScroll
->size();
315 hDisplay
= _H_Display
;
316 yDisplay
= _Y_Display
;
319 // Draw each Background
320 /* float w = 0 , x_display = _X_Display;
322 for (uint j = 0 ; j < _NbCol ; ++j)
324 w = _ColSize[j] * wDisplay;
325 Driver->drawBitmap(x_display , yDisplay, w, hDisplay, *CInterfMngr::getTexture(_BackgroundTexture), true, _BackgroundColor);
330 /// \todo GUIGUI : initialize the scissor with oldScissor and remove tmp variables.
331 // Backup scissor and create the new scissor to clip the list correctly.
332 CScissor oldScissor
= Driver
->getScissor();
335 float scisX
, scisY
, scisWidth
, scisHeight
;
336 scisX
= oldScissor
.X
;
337 scisY
= oldScissor
.Y
;
338 scisWidth
= oldScissor
.Width
;
339 scisHeight
= oldScissor
.Height
;
341 float xtmp
= _X_Display
+ _ColSize
[0] * wDisplay
;
342 float ytmp
= _Y_Display
+ _H_Display
;
343 float xscistmp
= scisX
+ scisWidth
;
344 float yscistmp
= scisY
+ scisHeight
;
350 scisWidth
= xtmp
-scisX
;
352 scisWidth
= xscistmp
-scisX
;
354 scisHeight
= ytmp
-scisY
;
356 scisHeight
= yscistmp
-scisY
;
357 scissor
.init(scisX
, scisY
, scisWidth
, scisHeight
);
358 Driver
->setScissor(scissor
);
361 // Display the text of the list.
362 TextContext
->setShaded(_Shadow
);
363 TextContext
->setFontSize(_FontSize
);
364 TextContext
->setHotSpot(UTextContext::BottomLeft
);
367 UTextContext::CStringInfo info
;
369 // if the ending item is the last item (so the first item in reverse order), hide/disable scrollbar
370 // if (_EndingIterator == _ItemsList.rbegin() )
373 static std::list
<ucstring
>::const_iterator itText
;
374 static NLMISC::CEntityId
* sid
= NULL
;
376 TItemList::reverse_iterator ritList
;
377 TSidList::reverse_iterator ritSidList
= _EndingSidIterator
;
379 const TItemList::reverse_iterator ritEndList
= _ItemsList
.rend();
380 const TMapSidToColor::iterator itColorEnd
= _PlayersColor
.end();
383 float y
= _Y_Display
+ _LastStringHeight
/3.0f
; // start a bit upper to have room to print a line
384 float x
= _X_Display
;
385 const float yLimit
= yDisplay
+ hDisplay
;
386 const float xLimit
= _X_Display
+ wDisplay
;
388 for( ritList
= _EndingIterator
; ritList
!= ritEndList
; ++ritList
)
393 itText
= (*ritList
).begin();
394 sid
= const_cast<NLMISC::CEntityId
*> (&(*ritSidList
));
396 // Test mouse position.
397 if ( (_MouseY
>= y
) && (_MouseY
<= y
+ _LastStringHeight
) && (_MouseX
>= x
) && (_MouseX
<= xLimit
))
399 // if player is muted
400 if ( (!_MutedPlayers
.empty() ) && ( _MutedPlayers
.find( *sid
) != _MutedPlayers
.end() ) )
402 TextContext
->setColor( _MutedHighlightColor
);
405 TextContext
->setColor( _HighlightColor
);
409 // if player is muted
410 if ( (!_MutedPlayers
.empty() ) && ( _MutedPlayers
.find( *sid
) != _MutedPlayers
.end() ) )
412 TextContext
->setColor( _MutedColor
);
416 // \todo GUIGUI : remove those thing after UBI demo.
417 // Get display color for that player.
418 TMapSidToColor::iterator itColor
= _PlayersColor
.find( *sid
);
419 if(itColor
!= itColorEnd
)
420 TextContext
->setColor(playerColors
[((*sid
).Id
/ 10)%10]);
422 nlwarning("CChatControl::display : Player does not exist.");
423 // TextContext->setColor( *(*itColor).second );
427 // display player name
428 // if this is a command line, then, use SysColor;
429 if ( (*sid
) == _CommandSid
)
430 TextContext
->setColor( _SysTextColor
);
432 index
= TextContext
->textPush( *itText
);
433 info
= TextContext
->getStringInfo(index
);
434 info
.convertTo01Size(Driver
);
435 if (maxH
< info
.StringHeight
)
436 maxH
= info
.StringHeight
;
438 TextContext
->printAt(x
, y
, index
);
439 TextContext
->erase(index
);
440 x
+= _ColSize
[0] * wDisplay
;
442 // insert player names and NLMISC::CEntityId coordinates in the _NamesYPos map (only if it's not a system message)
443 if ( (*sid
) != _CommandSid
)
444 _NamesYPos
.push_back( std::make_pair( std::make_pair(y
, y
+info
.StringHeight
), std::make_pair( &(*itText
), sid
) ) );
448 // set the new scissor
449 scisX
= oldScissor
.X
;
450 scisWidth
= oldScissor
.Width
;
452 xtmp
= _X_Display
+ _W_Display
;
453 xscistmp
= scisX
+ scisWidth
;
456 scisWidth
= xtmp
-scisX
;
458 scisWidth
= xscistmp
-scisX
;
460 scissor
.init(scisX
, scisY
, scisWidth
, scisHeight
);
461 Driver
->setScissor(scissor
);
464 index
= TextContext
->textPush( *itText
);
465 info
= TextContext
->getStringInfo(index
);
466 info
.convertTo01Size(Driver
);
467 if (maxH
< info
.StringHeight
)
468 maxH
= info
.StringHeight
;
470 TextContext
->printAt(x
, y
, index
);
471 TextContext
->erase(index
);
472 x
+= _ColSize
[1] * wDisplay
;
474 _LastStringHeight
= info
.StringHeight
;
476 // if display boundaries are reached, enable scroll bar and stop displaying
488 Driver
->setScissor(oldScissor
);
497 //-----------------------------------------------
499 // Manage the click of the mouse for the Button.
500 //-----------------------------------------------
501 void CChatControl::click(float x
, float y
, bool &taken
)
503 if (_VScroll
!= NULL
)
504 _VScroll
->click(x
,y
,taken
);
506 // if click still not caught by a control
509 // if user has clicked on a player ID, mute/unmute that player
511 if ( (x
>= _X_Display
) && ( x
<= (_X_Display
+ _W_Display
* _ColSize
[0]) ) )
513 // find the name with the y coordinate
514 bool found
= searchPlayerAtPos( y
,_SelectedPlayerSid
, _SelectedPlayer
) ;
516 // if a player was found
519 CInterfMngr::runFuncCtrl(_LeftClickFunction
, id());
525 _SelectedPlayer
= NULL
;
526 _SelectedPlayerSid
= NULL
;
531 //-----------------------------------------------
533 // Manage the click of the mouse for the Button.
534 //-----------------------------------------------
535 void CChatControl::clickRight(float x
, float y
, bool &taken
)
540 // if user has right clicked on a player, open the good pop-up menu
541 // if user has clicked on a player ID, mute/unmute that player
543 if ( (x
>= _X_Display
) && ( x
<= (_X_Display
+ _W_Display
* _ColSize
[0]) ) )
545 // find the name with the y coordinate
546 bool found
= searchPlayerAtPos( y
,_SelectedPlayerSid
, _SelectedPlayer
) ;
548 // if a player was found
551 CInterfMngr::runFuncCtrl(_RightClickFunction
, id());
557 _SelectedPlayer
= NULL
;
558 _SelectedPlayerSid
= NULL
;
563 //-----------------------------------------------
565 //-----------------------------------------------
566 void CChatControl::mouseMove( float x
, float y
)
574 //-----------------------------------------------
576 //-----------------------------------------------
577 bool CChatControl::searchPlayerAtPos(float y
, NLMISC::CEntityId
*&sid
, ucstring
*&name
) const
579 // allready test if y is within display limits
580 if ( (y
< _Y_Display
) || (y
>_Y_Display
+ _H_Display
) )
584 const TPairPFloatPStrSid::const_iterator itB
= _NamesYPos
.begin();
585 const TPairPFloatPStrSid::const_iterator itEnd
= _NamesYPos
.end();
586 TPairPFloatPStrSid::const_iterator it
= itB
;
588 const uint32 size
= _NamesYPos
.size();
590 if (size
== 0) return NULL
;
592 // we know the first name is at _Y_Display and the last one at _Y_Display+_H_Display (approx.)
593 // so we make an interpolation of name position in the list according to the y coordinate and the limits coordinates
594 for ( uint32 start
= static_cast<uint32
> ( (y
- _Y_Display
)/(_H_Display
) * size
) ; start
> 0 ; --start
)
605 float yMin
= (*it
).first
.first
, yMax
= (*it
).first
.second
;
614 yMin
= (*it
).first
.first
;
623 yMax
= (*it
).first
.second
;
626 if ( y
<= yMax
&& y
>= yMin
)
628 name
= const_cast<ucstring
*> ( (*it
).second
.first
);
629 sid
= const_cast<NLMISC::CEntityId
*> ( (*it
).second
.second
);
635 }// searchNameAtPos //
638 //-----------------------------------------------
640 //-----------------------------------------------
641 CRGBA
CChatControl::getNewColor() const
643 static CRGBA
color(255,0,0);
645 const TSetColors::const_iterator itColorsEnd
= _UsedColors
.end();
649 while( (_UsedColors
.find( color
) != itColorsEnd
)&& (max
<180) )
651 // generate a new color
652 // randomly add a number beetween 10 and 200 (in absolute) to each composant (rgb)
654 sint8 val
= static_cast<sint8
> ( (rand() - RAND_MAX
/2) % 190 );
661 val
= static_cast<sint8
> ( (rand() - RAND_MAX
/2) % 190 );
669 val
= static_cast<sint8
> ( (rand() - RAND_MAX
/2) % 190 );
683 //-----------------------------------------------
685 //-----------------------------------------------
686 void CChatControl::scrollV(sint32 scroll
)
688 // scrolling downward
691 const TItemList::reverse_iterator itB
= _ItemsList
.rbegin();
693 while ( ( _EndingIterator
!= itB
) && (scroll
!= 0) )
696 --_EndingSidIterator
;
703 const TItemList::reverse_iterator itE
= --_ItemsList
.rend();
705 while ( ( _EndingIterator
!= itE
) && (scroll
!= 0) )
708 ++_EndingSidIterator
;