Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1440 lines
38 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #include <stdarg.h>
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #ifdef _PS3
  12. #include <wctype.h>
  13. #endif
  14. #include <vgui/IInput.h>
  15. #include <vgui/ILocalize.h>
  16. #include <vgui/IPanel.h>
  17. #include <vgui/ISurface.h>
  18. #include <vgui/IScheme.h>
  19. #include <keyvalues.h>
  20. #include <vgui_controls/Label.h>
  21. #include <vgui_controls/Image.h>
  22. #include <vgui_controls/TextImage.h>
  23. #include <vgui_controls/Controls.h>
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include <tier0/memdbgon.h>
  26. using namespace vgui;
  27. #ifndef max
  28. #define max(a,b) (((a) > (b)) ? (a) : (b))
  29. #endif
  30. // DMX serializer fields.
  31. BEGIN_DMXELEMENT_UNPACK_NAMESPACE_SIMPLE( vgui, Label )
  32. END_DMXELEMENT_UNPACK_NAMESPACE( vgui, Label, s_pUnpackParams )
  33. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( Label, Label );
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Constructor
  36. //-----------------------------------------------------------------------------
  37. Label::Label(Panel *parent, const char *panelName, const char *text) : BaseClass(parent, panelName)
  38. {
  39. Init();
  40. _textImage = new TextImage(text);
  41. _textImage->SetColor(Color(0, 0, 0, 0));
  42. SetText(text);
  43. _textImageIndex = AddImage(_textImage, 0);
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Constructor
  47. //-----------------------------------------------------------------------------
  48. Label::Label(Panel *parent, const char *panelName, const wchar_t *wszText) : BaseClass(parent, panelName)
  49. {
  50. Init();
  51. _textImage = new TextImage(wszText);
  52. _textImage->SetColor(Color(0, 0, 0, 0));
  53. SetText(wszText);
  54. _textImageIndex = AddImage(_textImage, 0);
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose: Destructor
  58. //-----------------------------------------------------------------------------
  59. Label::~Label()
  60. {
  61. delete _textImage;
  62. delete [] _associateName;
  63. delete [] _fontOverrideName;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose: Construct the label
  67. //-----------------------------------------------------------------------------
  68. void Label::Init()
  69. {
  70. _contentAlignment = a_west;
  71. _textColorState = CS_NORMAL;
  72. _textInset[0] = 0;
  73. _textInset[1] = 0;
  74. _hotkey = 0;
  75. _associate = NULL;
  76. _associateName = NULL;
  77. _fontOverrideName = NULL;
  78. m_bNoShortcutSyntax = false;
  79. m_bWrap = false;
  80. m_bCenterWrap = false;
  81. m_bAutoWideToContents = false;
  82. m_bUseProportionalInsets = false;
  83. m_bAutoWideDirty = false;
  84. m_bAutoTallToContents = false;
  85. m_bAutoTallDirty = false;
  86. // SetPaintBackgroundEnabled(false);
  87. REGISTER_COLOR_AS_OVERRIDABLE( _disabledFgColor1, "disabledFgColor1_override" );
  88. REGISTER_COLOR_AS_OVERRIDABLE( _disabledFgColor2, "disabledFgColor2_override" );
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Set whether the text is displayed bright or dull
  92. //-----------------------------------------------------------------------------
  93. void Label::SetTextColorState(EColorState state)
  94. {
  95. if (_textColorState != state)
  96. {
  97. _textColorState = state;
  98. InvalidateLayout();
  99. }
  100. }
  101. void Label::GetSizerMinimumSize(int &wide, int &tall)
  102. {
  103. GetContentSize(wide,tall);
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Return the full size of the contained content
  107. //-----------------------------------------------------------------------------
  108. void Label::GetContentSize(int &wide, int &tall)
  109. {
  110. if( GetFont() == INVALID_FONT ) // we haven't loaded our font yet, so load it now
  111. {
  112. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  113. if ( pScheme )
  114. {
  115. SetFont( pScheme->GetFont( "Default", IsProportional() ) );
  116. }
  117. }
  118. int tx0, ty0, tx1, ty1;
  119. ComputeAlignment(tx0, ty0, tx1, ty1);
  120. // the +8 is padding to the content size
  121. // the code which uses it should really set that itself;
  122. // however a lot of existing code relies on this
  123. wide = (tx1 - tx0) + _textInset[0];
  124. // get the size of the text image and remove it
  125. int iWide, iTall;
  126. _textImage->GetSize(iWide, iTall);
  127. wide -= iWide;
  128. // get the full, untruncated (no elipsis) size of the text image.
  129. _textImage->GetContentSize(iWide, iTall);
  130. wide += iWide;
  131. // addin the image offsets as well
  132. for (int i=0; i < _imageDar.Count(); i++)
  133. wide += _imageDar[i].offset;
  134. tall = max((ty1 - ty0) + _textInset[1], iTall);
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose: Calculate the keyboard key that is a hotkey
  138. //-----------------------------------------------------------------------------
  139. wchar_t Label::CalculateHotkey(const char *text)
  140. {
  141. for (const char *ch = text; *ch != 0; ch++)
  142. {
  143. if (*ch == '&')
  144. {
  145. // get the next character
  146. ch++;
  147. if (*ch == '&')
  148. {
  149. // just an &
  150. continue;
  151. }
  152. else if (*ch == 0)
  153. {
  154. break;
  155. }
  156. else if (V_isalnum(*ch))
  157. {
  158. // found the hotkey
  159. return (wchar_t)tolower(*ch);
  160. }
  161. }
  162. }
  163. return '\0';
  164. }
  165. wchar_t Label::CalculateHotkey(const wchar_t *text)
  166. {
  167. if( text )
  168. {
  169. for (const wchar_t *ch = text; *ch != 0; ch++)
  170. {
  171. if (*ch == '&')
  172. {
  173. // get the next character
  174. ch++;
  175. if (*ch == '&')
  176. {
  177. // just an &
  178. continue;
  179. }
  180. else if (*ch == 0)
  181. {
  182. break;
  183. }
  184. else if (iswalnum(*ch))
  185. {
  186. // found the hotkey
  187. return (wchar_t)towlower(*ch);
  188. }
  189. }
  190. }
  191. }
  192. return '\0';
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: Check if this label has a hotkey that is the key passed in.
  196. //-----------------------------------------------------------------------------
  197. Panel *Label::HasHotkey(wchar_t key)
  198. {
  199. #ifdef VGUI_HOTKEYS_ENABLED
  200. if ( iswalnum( key ) )
  201. key = towlower( key );
  202. if (_hotkey == key)
  203. return this;
  204. #endif
  205. return NULL;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Set the hotkey for this label
  209. //-----------------------------------------------------------------------------
  210. void Label::SetHotkey(wchar_t ch)
  211. {
  212. _hotkey = ch;
  213. }
  214. wchar_t Label::GetHotKey()
  215. {
  216. return _hotkey;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Handle a hotkey by passing on focus to associate
  220. //-----------------------------------------------------------------------------
  221. void Label::OnHotkeyPressed()
  222. {
  223. // we can't accept focus, but if we are associated to a control give it to that
  224. if (_associate.Get() && !IsBuildModeActive())
  225. {
  226. _associate->RequestFocus();
  227. }
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose: Redirect mouse pressed to giving focus to associate
  231. //-----------------------------------------------------------------------------
  232. void Label::OnMousePressed(MouseCode code)
  233. {
  234. if (_associate.Get() && !IsBuildModeActive())
  235. {
  236. _associate->RequestFocus();
  237. }
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Return the text in the label
  241. //-----------------------------------------------------------------------------
  242. void Label::GetText(char *textOut, int bufferLen)
  243. {
  244. _textImage->GetText(textOut, bufferLen);
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: Return the text in the label
  248. //-----------------------------------------------------------------------------
  249. void Label::GetText(wchar_t *textOut, int bufLenInBytes)
  250. {
  251. _textImage->GetText(textOut, bufLenInBytes);
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose: Take the string and looks it up in the localization file
  255. // to convert it to unicode
  256. // Setting the text will not set the size of the label.
  257. // Set the size explicitly or use setToContent()
  258. //-----------------------------------------------------------------------------
  259. void Label::SetText(const char *text)
  260. {
  261. // if set to null, just make blank
  262. if (!text)
  263. {
  264. text = "";
  265. }
  266. // let the text image do the translation itself
  267. _textImage->SetText(text);
  268. if( text[0] == '#' )
  269. {
  270. SetHotkey(CalculateHotkey(g_pVGuiLocalize->Find(text)));
  271. }
  272. else
  273. {
  274. SetHotkey(CalculateHotkey(text));
  275. }
  276. m_bAutoWideDirty = m_bAutoWideToContents;
  277. m_bAutoTallDirty = m_bAutoTallToContents;
  278. HandleAutoSizing();
  279. InvalidateLayout();
  280. Repaint();
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Set unicode text directly
  284. //-----------------------------------------------------------------------------
  285. void Label::SetText(const wchar_t *unicodeString, bool bClearUnlocalizedSymbol)
  286. {
  287. m_bAutoWideDirty = m_bAutoWideToContents;
  288. m_bAutoTallDirty = m_bAutoTallToContents;
  289. if ( unicodeString && _textImage->GetUText() && !Q_wcscmp(unicodeString,_textImage->GetUText()) )
  290. return;
  291. _textImage->SetText(unicodeString, bClearUnlocalizedSymbol);
  292. //!! need to calculate hotkey from translated string
  293. SetHotkey(CalculateHotkey(unicodeString));
  294. InvalidateLayout(); // possible that the textimage needs to expand
  295. Repaint();
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: updates localized text
  299. //-----------------------------------------------------------------------------
  300. void Label::OnDialogVariablesChanged(KeyValues *dialogVariables )
  301. {
  302. StringIndex_t index = _textImage->GetUnlocalizedTextSymbol();
  303. if (index != INVALID_STRING_INDEX)
  304. {
  305. // reconstruct the string from the variables
  306. wchar_t buf[2048];
  307. g_pVGuiLocalize->ConstructString(buf, sizeof(buf), index, dialogVariables);
  308. SetText(buf);
  309. }
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose: Additional offset at the Start of the text (from whichever side it is aligned)
  313. //-----------------------------------------------------------------------------
  314. void Label::SetTextInset(int xInset, int yInset)
  315. {
  316. _textInset[0] = xInset;
  317. _textInset[1] = yInset;
  318. int wide, tall;
  319. GetSize( wide, tall);
  320. _textImage->SetDrawWidth(wide - _textInset[0]);
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose:
  324. //-----------------------------------------------------------------------------
  325. void Label::GetTextInset(int *xInset, int *yInset )
  326. {
  327. *xInset = _textInset[0];
  328. *yInset = _textInset[1];
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose: Set the enabled state
  332. //-----------------------------------------------------------------------------
  333. void Label::SetEnabled(bool state)
  334. {
  335. Panel::SetEnabled(state);
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Purpose: Calculates where in the panel the content resides
  339. // Input : &tx0 - [out] position of the content
  340. // &ty0 -
  341. // &tx1 -
  342. // &ty1 -
  343. // Note: horizontal alignment is west if the image dar has
  344. // more than one image in it, this is because we use image sizes
  345. // to determine layout in classes for example, Menu.
  346. //-----------------------------------------------------------------------------
  347. void Label::ComputeAlignment(int &tx0, int &ty0, int &tx1, int &ty1)
  348. {
  349. int wide, tall;
  350. GetPaintSize(wide, tall);
  351. int tWide,tTall;
  352. // text bounding box
  353. tx0 = 0;
  354. ty0 = 0;
  355. // loop through all the images and calculate the complete bounds
  356. int maxX = 0, maxY = 0;
  357. int actualXAlignment = _contentAlignment;
  358. for (int i = 0; i < _imageDar.Count(); i++)
  359. {
  360. TImageInfo &imageInfo = _imageDar[i];
  361. IImage *image = imageInfo.image;
  362. if (!image)
  363. continue; // skip over null images
  364. // add up the bounds
  365. int iWide, iTall;
  366. image->GetSize(iWide, iTall);
  367. if (iWide > wide) // if the image is larger than the label just do a west alignment
  368. actualXAlignment = Label::a_west;
  369. // get the max height
  370. maxY = max(maxY, iTall);
  371. maxX += iWide;
  372. // add the offset to x
  373. maxX += imageInfo.offset;
  374. }
  375. tWide = maxX;
  376. tTall = maxY;
  377. // x align text
  378. switch (actualXAlignment)
  379. {
  380. // left
  381. case Label::a_northwest:
  382. case Label::a_west:
  383. case Label::a_southwest:
  384. {
  385. tx0 = 0;
  386. break;
  387. }
  388. // center
  389. case Label::a_north:
  390. case Label::a_center:
  391. case Label::a_south:
  392. {
  393. tx0 = (wide - tWide) / 2;
  394. break;
  395. }
  396. // right
  397. case Label::a_northeast:
  398. case Label::a_east:
  399. case Label::a_southeast:
  400. {
  401. tx0 = wide - tWide;
  402. break;
  403. }
  404. }
  405. // y align text
  406. switch (_contentAlignment)
  407. {
  408. //top
  409. case Label::a_northwest:
  410. case Label::a_north:
  411. case Label::a_northeast:
  412. {
  413. ty0 = 0;
  414. break;
  415. }
  416. // center
  417. case Label::a_west:
  418. case Label::a_center:
  419. case Label::a_east:
  420. {
  421. ty0 = (tall - tTall) / 2;
  422. break;
  423. }
  424. // south
  425. case Label::a_southwest:
  426. case Label::a_south:
  427. case Label::a_southeast:
  428. {
  429. ty0 = tall - tTall;
  430. break;
  431. }
  432. }
  433. tx1 = tx0 + tWide;
  434. ty1 = ty0 + tTall;
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Purpose: overridden main drawing function for the panel
  438. //-----------------------------------------------------------------------------
  439. void Label::Paint()
  440. {
  441. int tx0, ty0, tx1, ty1;
  442. ComputeAlignment(tx0, ty0, tx1, ty1);
  443. // calculate who our associate is if we haven't already
  444. if (_associateName)
  445. {
  446. SetAssociatedControl(FindSiblingByName(_associateName));
  447. delete [] _associateName;
  448. _associateName = NULL;
  449. }
  450. int labelWide, labelTall;
  451. GetSize(labelWide, labelTall);
  452. int x = tx0, y = _textInset[1] + ty0;
  453. int imageYPos = 0; // a place to save the y offset for when we draw the disable version of the image
  454. // draw the set of images
  455. for (int i = 0; i < _imageDar.Count(); i++)
  456. {
  457. TImageInfo &imageInfo = _imageDar[i];
  458. IImage *image = imageInfo.image;
  459. if (!image)
  460. continue; // skip over null images
  461. // add the offset to x
  462. x += imageInfo.offset;
  463. // if this is the text image then add its inset to the left or from the right
  464. if (i == _textImageIndex)
  465. {
  466. switch ( _contentAlignment )
  467. {
  468. // left
  469. case Label::a_northwest:
  470. case Label::a_west:
  471. case Label::a_southwest:
  472. {
  473. x += _textInset[0];
  474. break;
  475. }
  476. // right
  477. case Label::a_northeast:
  478. case Label::a_east:
  479. case Label::a_southeast:
  480. {
  481. x -= _textInset[0];
  482. break;
  483. }
  484. }
  485. }
  486. // see if the image is in a fixed position
  487. if (imageInfo.xpos >= 0)
  488. {
  489. x = imageInfo.xpos;
  490. }
  491. // draw
  492. imageYPos = y;
  493. image->SetPos(x, y);
  494. // fix up y for center-aligned text
  495. if (_contentAlignment == Label::a_west || _contentAlignment == Label::a_center || _contentAlignment == Label::a_east)
  496. {
  497. int iw, it;
  498. image->GetSize(iw, it);
  499. if (it < (ty1 - ty0))
  500. {
  501. imageYPos = ((ty1 - ty0) - it) / 2 + y;
  502. image->SetPos(x, ((ty1 - ty0) - it) / 2 + y);
  503. }
  504. }
  505. // don't resize the image unless its too big
  506. if (imageInfo.width >= 0)
  507. {
  508. int w, t;
  509. image->GetSize(w, t);
  510. if (w > imageInfo.width)
  511. {
  512. image->SetSize(imageInfo.width, t);
  513. }
  514. }
  515. // if it's the basic text image then draw specially
  516. if (image == _textImage)
  517. {
  518. int savex = x;
  519. int saveYPos = imageYPos;
  520. // Allow override of x position of text
  521. RepositionTextImage( x, imageYPos, _textImage );
  522. if (IsEnabled())
  523. {
  524. _textImage->SetPos( x, imageYPos );
  525. if (_associate.Get() && ipanel()->HasParent(input()->GetFocus(), _associate->GetVPanel()))
  526. {
  527. _textImage->SetColor(_associateColor);
  528. }
  529. else
  530. {
  531. _textImage->SetColor(GetFgColor());
  532. }
  533. _textImage->Paint();
  534. }
  535. else
  536. {
  537. // draw disabled version, with embossed look
  538. _textImage->SetPos(x + 1, imageYPos + 1);
  539. _textImage->SetColor(_disabledFgColor1);
  540. _textImage->Paint();
  541. surface()->DrawFlushText();
  542. // overlayed image
  543. _textImage->SetPos(x, imageYPos);
  544. _textImage->SetColor(_disabledFgColor2);
  545. _textImage->Paint();
  546. }
  547. x = savex;
  548. imageYPos = saveYPos;
  549. }
  550. else
  551. {
  552. image->Paint();
  553. }
  554. // add the image size to x
  555. int wide, tall;
  556. image->GetSize(wide, tall);
  557. x += wide;
  558. }
  559. }
  560. //-----------------------------------------------------------------------------
  561. // Purpose: Helper function, draws a simple line with dashing parameters
  562. //-----------------------------------------------------------------------------
  563. void Label::DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen)
  564. {
  565. // work out which way the line goes
  566. if ((x1 - x0) > (y1 - y0))
  567. {
  568. // x direction line
  569. while (1)
  570. {
  571. if (x0 + dashLen > x1)
  572. {
  573. // draw partial
  574. surface()->DrawFilledRect(x0, y0, x1, y1);
  575. }
  576. else
  577. {
  578. surface()->DrawFilledRect(x0, y0, x0 + dashLen, y1);
  579. }
  580. x0 += dashLen;
  581. if (x0 + gapLen > x1)
  582. break;
  583. x0 += gapLen;
  584. }
  585. }
  586. else
  587. {
  588. // y direction
  589. while (1)
  590. {
  591. if (y0 + dashLen > y1)
  592. {
  593. // draw partial
  594. surface()->DrawFilledRect(x0, y0, x1, y1);
  595. }
  596. else
  597. {
  598. surface()->DrawFilledRect(x0, y0, x1, y0 + dashLen);
  599. }
  600. y0 += dashLen;
  601. if (y0 + gapLen > y1)
  602. break;
  603. y0 += gapLen;
  604. }
  605. }
  606. }
  607. void Label::SetContentAlignment(Alignment alignment)
  608. {
  609. _contentAlignment=alignment;
  610. Repaint();
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Purpose: Size the width of the label to its contents - only works from in ApplySchemeSettings or PerformLayout()
  614. //-----------------------------------------------------------------------------
  615. void Label::SizeToContents()
  616. {
  617. int wide, tall;
  618. GetContentSize(wide, tall);
  619. SetSize(wide, tall);
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Purpose: Set the font the text is drawn in
  623. //-----------------------------------------------------------------------------
  624. void Label::SetFont(HFont font)
  625. {
  626. _textImage->SetFont(font);
  627. Repaint();
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose: Resond to resizing of the panel
  631. //-----------------------------------------------------------------------------
  632. void Label::OnSizeChanged(int wide, int tall)
  633. {
  634. InvalidateLayout();
  635. Panel::OnSizeChanged(wide, tall);
  636. }
  637. //-----------------------------------------------------------------------------
  638. // Purpose: Get the font the textImage is drawn in.
  639. //-----------------------------------------------------------------------------
  640. HFont Label::GetFont()
  641. {
  642. return _textImage->GetFont();
  643. }
  644. //-----------------------------------------------------------------------------
  645. // Purpose: Set the foreground color of the Label
  646. //-----------------------------------------------------------------------------
  647. void Label::SetFgColor(Color color)
  648. {
  649. if (!(GetFgColor() == color))
  650. {
  651. BaseClass::SetFgColor(color);
  652. _textImage->SetColor(color);
  653. Repaint();
  654. }
  655. }
  656. //-----------------------------------------------------------------------------
  657. // Purpose: Get the foreground color of the Label
  658. //-----------------------------------------------------------------------------
  659. Color Label::GetFgColor()
  660. {
  661. Color clr = Panel::GetFgColor();
  662. return clr;
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Purpose: Set the foreground color 1 color of the Label
  666. //-----------------------------------------------------------------------------
  667. void Label::SetDisabledFgColor1(Color color)
  668. {
  669. _disabledFgColor1 = color;
  670. }
  671. //-----------------------------------------------------------------------------
  672. // Purpose:
  673. //-----------------------------------------------------------------------------
  674. void Label::SetDisabledFgColor2(Color color)
  675. {
  676. _disabledFgColor2 = color;
  677. }
  678. //-----------------------------------------------------------------------------
  679. // Purpose:
  680. //-----------------------------------------------------------------------------
  681. Color Label::GetDisabledFgColor1()
  682. {
  683. return _disabledFgColor1;
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Purpose:
  687. //-----------------------------------------------------------------------------
  688. Color Label::GetDisabledFgColor2()
  689. {
  690. return _disabledFgColor2;
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose:
  694. //-----------------------------------------------------------------------------
  695. TextImage *Label::GetTextImage()
  696. {
  697. return _textImage;
  698. }
  699. //-----------------------------------------------------------------------------
  700. // Purpose:
  701. //-----------------------------------------------------------------------------
  702. bool Label::RequestInfo(KeyValues *outputData)
  703. {
  704. if (!stricmp(outputData->GetName(), "GetText"))
  705. {
  706. wchar_t wbuf[256];
  707. _textImage->GetText(wbuf, 255);
  708. outputData->SetWString("text", wbuf);
  709. return true;
  710. }
  711. return Panel::RequestInfo(outputData);
  712. }
  713. //-----------------------------------------------------------------------------
  714. // Purpose: Sets the text from the message
  715. //-----------------------------------------------------------------------------
  716. void Label::OnSetText(KeyValues *params)
  717. {
  718. KeyValues *pkvText = params->FindKey("text", false);
  719. if (!pkvText)
  720. return;
  721. if (pkvText->GetDataType() == KeyValues::TYPE_STRING)
  722. {
  723. SetText(pkvText->GetString());
  724. }
  725. else if (pkvText->GetDataType() == KeyValues::TYPE_WSTRING)
  726. {
  727. SetText(pkvText->GetWString());
  728. }
  729. }
  730. //-----------------------------------------------------------------------------
  731. // Purpose: Add an image to the list
  732. // returns the index the image was placed in
  733. //-----------------------------------------------------------------------------
  734. int Label::AddImage(IImage *image, int offset)
  735. {
  736. int newImage = _imageDar.AddToTail();
  737. _imageDar[newImage].image = image;
  738. _imageDar[newImage].offset = (short)offset;
  739. _imageDar[newImage].xpos = -1;
  740. _imageDar[newImage].width = -1;
  741. InvalidateLayout();
  742. return newImage;
  743. }
  744. // Clears all images and sets the only remaining image to the passed in image
  745. void Label::SetImage(IImage *image, int preOffset )
  746. {
  747. ClearImages();
  748. AddImage( image, preOffset );
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Purpose: removes all images from the list
  752. // user is responsible for the memory
  753. //-----------------------------------------------------------------------------
  754. void Label::ClearImages()
  755. {
  756. _imageDar.RemoveAll();
  757. _textImageIndex = -1;
  758. }
  759. void Label::ResetToSimpleTextImage()
  760. {
  761. ClearImages();
  762. _textImageIndex = AddImage(_textImage, 0);
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Purpose: Multiple image handling
  766. // Images are drawn from left to right across the label, ordered by index
  767. // By default there is a TextImage in position 0
  768. // Set the contents of an IImage in the IImage array.
  769. //-----------------------------------------------------------------------------
  770. void Label::SetImageAtIndex(int index, IImage *image, int offset)
  771. {
  772. EnsureImageCapacity(index);
  773. // Assert( image );
  774. if ( _imageDar[index].image != image || _imageDar[index].offset != offset)
  775. {
  776. _imageDar[index].image = image;
  777. _imageDar[index].offset = (short)offset;
  778. InvalidateLayout();
  779. }
  780. }
  781. //-----------------------------------------------------------------------------
  782. // Purpose: Get an IImage in the IImage array.
  783. //-----------------------------------------------------------------------------
  784. IImage *Label::GetImageAtIndex(int index)
  785. {
  786. if ( _imageDar.IsValidIndex( index ) )
  787. return _imageDar[index].image;
  788. return NULL;
  789. }
  790. //-----------------------------------------------------------------------------
  791. // Purpose: Get the number of images in the array.
  792. //-----------------------------------------------------------------------------
  793. int Label::GetImageCount()
  794. {
  795. return _imageDar.Count();
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Purpose: Move where the default text image is within the image array
  799. // (it starts in position 0)
  800. // Input : newIndex -
  801. // Output : int - the index the default text image was previously in
  802. //-----------------------------------------------------------------------------
  803. int Label::SetTextImageIndex(int newIndex)
  804. {
  805. if (newIndex == _textImageIndex)
  806. return _textImageIndex;
  807. EnsureImageCapacity(newIndex);
  808. int oldIndex = _textImageIndex;
  809. if ( _textImageIndex >= 0 )
  810. {
  811. _imageDar[_textImageIndex].image = NULL;
  812. }
  813. if (newIndex > -1)
  814. {
  815. _imageDar[newIndex].image = _textImage;
  816. }
  817. _textImageIndex = newIndex;
  818. return oldIndex;
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Purpose: Ensure that the maxIndex will be a valid index
  822. //-----------------------------------------------------------------------------
  823. void Label::EnsureImageCapacity(int maxIndex)
  824. {
  825. while (_imageDar.Count() <= maxIndex)
  826. {
  827. AddImage(NULL, 0);
  828. }
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose: Set the offset in pixels before the image
  832. //-----------------------------------------------------------------------------
  833. void Label::SetImagePreOffset(int index, int preOffset)
  834. {
  835. if (_imageDar.IsValidIndex(index) && _imageDar[index].offset != preOffset)
  836. {
  837. _imageDar[index].offset = (short)preOffset;
  838. InvalidateLayout();
  839. }
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose: fixes the layout bounds of the image within the label
  843. //-----------------------------------------------------------------------------
  844. void Label::SetImageBounds(int index, int x, int width)
  845. {
  846. _imageDar[index].xpos = (short)x;
  847. _imageDar[index].width = (short)width;
  848. }
  849. //-----------------------------------------------------------------------------
  850. // Purpose: Labels can be associated with controls, and alter behaviour based on the associates behaviour
  851. // If the associate is disabled, so are we
  852. // If the associate has focus, we may alter how we draw
  853. // If we get a hotkey press or focus message, we forward the focus to the associate
  854. //-----------------------------------------------------------------------------
  855. void Label::SetAssociatedControl(Panel *control)
  856. {
  857. if (control != this)
  858. {
  859. _associate = control;
  860. }
  861. else
  862. {
  863. // don't let the associate ever be set to be ourself
  864. _associate = NULL;
  865. }
  866. }
  867. //-----------------------------------------------------------------------------
  868. // Purpose: Called after a panel requests focus to fix up the whole chain
  869. //-----------------------------------------------------------------------------
  870. void Label::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel)
  871. {
  872. if (_associate.Get() && subFocus == GetVPanel() && !IsBuildModeActive())
  873. {
  874. // we've received focus; pass the focus onto the associate instead
  875. _associate->RequestFocus();
  876. }
  877. else
  878. {
  879. BaseClass::OnRequestFocus(subFocus, defaultPanel);
  880. }
  881. }
  882. //-----------------------------------------------------------------------------
  883. // Purpose: sets custom settings from the scheme file
  884. //-----------------------------------------------------------------------------
  885. void Label::ApplySchemeSettings(IScheme *pScheme)
  886. {
  887. BaseClass::ApplySchemeSettings(pScheme);
  888. if (_fontOverrideName)
  889. {
  890. // use the custom specified font since we have one set
  891. SetFont(pScheme->GetFont(_fontOverrideName, IsProportional()));
  892. }
  893. if ( GetFont() == INVALID_FONT )
  894. {
  895. SetFont( pScheme->GetFont( "Default", IsProportional() ) );
  896. }
  897. if ( m_bWrap || m_bCenterWrap )
  898. {
  899. //tell it how big it is
  900. int wide, tall;
  901. Panel::GetSize(wide, tall);
  902. wide -= _textInset[0]; // take inset into account
  903. _textImage->SetSize(wide, tall);
  904. _textImage->RecalculateNewLinePositions();
  905. }
  906. else
  907. {
  908. // if you don't set the size of the image, many, many buttons will break - we might want to look into fixing this all over the place later
  909. int wide, tall;
  910. _textImage->GetContentSize(wide, tall);
  911. _textImage->SetSize(wide, tall);
  912. }
  913. m_bAutoWideDirty = m_bAutoWideToContents;
  914. m_bAutoTallDirty = m_bAutoTallToContents;
  915. HandleAutoSizing();
  916. // clear out any the images, since they will have been invalidated
  917. for (int i = 0; i < _imageDar.Count(); i++)
  918. {
  919. IImage *image = _imageDar[i].image;
  920. if (!image)
  921. continue; // skip over null images
  922. if (i == _textImageIndex)
  923. continue;
  924. _imageDar[i].image = NULL;
  925. }
  926. SetDisabledFgColor1(GetSchemeColor("Label.DisabledFgColor1", pScheme));
  927. SetDisabledFgColor2(GetSchemeColor("Label.DisabledFgColor2", pScheme));
  928. SetBgColor(GetSchemeColor("Label.BgColor", pScheme));
  929. switch (_textColorState)
  930. {
  931. case CS_DULL:
  932. SetFgColor(GetSchemeColor("Label.TextDullColor", pScheme));
  933. break;
  934. case CS_BRIGHT:
  935. SetFgColor(GetSchemeColor("Label.TextBrightColor", pScheme));
  936. break;
  937. case CS_NORMAL:
  938. default:
  939. SetFgColor(GetSchemeColor("Label.TextColor", pScheme));
  940. break;
  941. }
  942. _associateColor = GetSchemeColor("Label.SelectedTextColor", pScheme);
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Purpose:
  946. //-----------------------------------------------------------------------------
  947. void Label::GetSettings( KeyValues *outResourceData )
  948. {
  949. // panel settings
  950. Panel::GetSettings( outResourceData );
  951. // label settings
  952. char buf[256];
  953. _textImage->GetUnlocalizedText( buf, 255 );
  954. if (!strnicmp(buf, "#var_", 5))
  955. {
  956. // strip off the variable prepender on save
  957. outResourceData->SetString( "labelText", buf + 5 );
  958. }
  959. else
  960. {
  961. outResourceData->SetString( "labelText", buf );
  962. }
  963. const char *alignmentString = "";
  964. switch ( _contentAlignment )
  965. {
  966. case a_northwest: alignmentString = "north-west"; break;
  967. case a_north: alignmentString = "north"; break;
  968. case a_northeast: alignmentString = "north-east"; break;
  969. case a_center: alignmentString = "center"; break;
  970. case a_east: alignmentString = "east"; break;
  971. case a_southwest: alignmentString = "south-west"; break;
  972. case a_south: alignmentString = "south"; break;
  973. case a_southeast: alignmentString = "south-east"; break;
  974. case a_west:
  975. default: alignmentString = "west"; break;
  976. }
  977. outResourceData->SetString( "textAlignment", alignmentString );
  978. if (_associate)
  979. {
  980. outResourceData->SetString("associate", _associate->GetName());
  981. }
  982. outResourceData->SetInt("dulltext", (int)(_textColorState == CS_DULL));
  983. outResourceData->SetInt("brighttext", (int)(_textColorState == CS_BRIGHT));
  984. if (_fontOverrideName)
  985. {
  986. outResourceData->SetString("font", _fontOverrideName);
  987. }
  988. outResourceData->SetBool("wrap", m_bWrap );
  989. outResourceData->SetBool("centerwrap", m_bCenterWrap );
  990. if ( m_bUseProportionalInsets )
  991. {
  992. outResourceData->SetInt("textinsetx", scheme()->GetProportionalNormalizedValueEx( GetScheme(), _textInset[0] ) );
  993. outResourceData->SetInt("textinsety", _textInset[1]);
  994. }
  995. else
  996. {
  997. outResourceData->SetInt("textinsetx", _textInset[0]);
  998. outResourceData->SetInt("textinsety", _textInset[1]);
  999. }
  1000. outResourceData->SetBool("noshortcutsyntax", m_bNoShortcutSyntax );
  1001. outResourceData->SetBool("auto_tall_tocontents", m_bAutoTallToContents );
  1002. outResourceData->SetBool("auto_wide_tocontents", m_bAutoWideToContents );
  1003. outResourceData->SetBool("use_proportional_insets", m_bUseProportionalInsets );
  1004. }
  1005. //-----------------------------------------------------------------------------
  1006. // Purpose:
  1007. //-----------------------------------------------------------------------------
  1008. void Label::ApplySettings( KeyValues *inResourceData )
  1009. {
  1010. BaseClass::ApplySettings( inResourceData );
  1011. // label settings
  1012. const char *labelText = inResourceData->GetString( "labelText", NULL );
  1013. if ( labelText )
  1014. {
  1015. if (labelText[0] == '%' && labelText[strlen(labelText) - 1] == '%')
  1016. {
  1017. // it's a variable, set it to be a special variable localized string
  1018. wchar_t unicodeVar[256];
  1019. g_pVGuiLocalize->ConvertANSIToUnicode(labelText, unicodeVar, sizeof(unicodeVar));
  1020. char var[256];
  1021. _snprintf(var, sizeof(var), "#var_%s", labelText);
  1022. g_pVGuiLocalize->AddString(var + 1, unicodeVar, "");
  1023. SetText(var);
  1024. }
  1025. else
  1026. {
  1027. SetText(labelText);
  1028. }
  1029. }
  1030. // text alignment
  1031. const char *alignmentString = inResourceData->GetString( "textAlignment", "" );
  1032. int align = -1;
  1033. if ( !stricmp(alignmentString, "north-west") )
  1034. {
  1035. align = a_northwest;
  1036. }
  1037. else if ( !stricmp(alignmentString, "north") )
  1038. {
  1039. align = a_north;
  1040. }
  1041. else if ( !stricmp(alignmentString, "north-east") )
  1042. {
  1043. align = a_northeast;
  1044. }
  1045. else if ( !stricmp(alignmentString, "west") )
  1046. {
  1047. align = a_west;
  1048. }
  1049. else if ( !stricmp(alignmentString, "center") )
  1050. {
  1051. align = a_center;
  1052. }
  1053. else if ( !stricmp(alignmentString, "east") )
  1054. {
  1055. align = a_east;
  1056. }
  1057. else if ( !stricmp(alignmentString, "south-west") )
  1058. {
  1059. align = a_southwest;
  1060. }
  1061. else if ( !stricmp(alignmentString, "south") )
  1062. {
  1063. align = a_south;
  1064. }
  1065. else if ( !stricmp(alignmentString, "south-east") )
  1066. {
  1067. align = a_southeast;
  1068. }
  1069. if ( align != -1 )
  1070. {
  1071. SetContentAlignment( (Alignment)align );
  1072. }
  1073. // the control we are to be associated with may not have been created yet,
  1074. // so keep a pointer to it's name and calculate it when we can
  1075. const char *associateName = inResourceData->GetString("associate", "");
  1076. if (associateName[0] != 0)
  1077. {
  1078. int len = Q_strlen(associateName) + 1;
  1079. _associateName = new char[ len ];
  1080. Q_strncpy( _associateName, associateName, len );
  1081. }
  1082. if (inResourceData->GetInt("dulltext", 0) == 1)
  1083. {
  1084. SetTextColorState(CS_DULL);
  1085. }
  1086. else if (inResourceData->GetInt("brighttext", 0) == 1)
  1087. {
  1088. SetTextColorState(CS_BRIGHT);
  1089. }
  1090. else
  1091. {
  1092. SetTextColorState(CS_NORMAL);
  1093. }
  1094. // font settings
  1095. const char *overrideFont = inResourceData->GetString("font", "");
  1096. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  1097. if (*overrideFont)
  1098. {
  1099. delete [] _fontOverrideName;
  1100. int len = Q_strlen(overrideFont) + 1;
  1101. _fontOverrideName = new char[ len ];
  1102. Q_strncpy(_fontOverrideName, overrideFont, len );
  1103. SetFont(pScheme->GetFont(_fontOverrideName, IsProportional()));
  1104. }
  1105. else if (_fontOverrideName)
  1106. {
  1107. delete [] _fontOverrideName;
  1108. _fontOverrideName = NULL;
  1109. SetFont(pScheme->GetFont("Default", IsProportional()));
  1110. }
  1111. bool bWrapText = inResourceData->GetInt("centerwrap", 0) > 0;
  1112. SetCenterWrap( bWrapText );
  1113. m_bAutoWideToContents = inResourceData->GetInt("auto_wide_tocontents", 0) > 0;
  1114. m_bAutoTallToContents = inResourceData->GetInt("auto_tall_tocontents", 0) > 0;
  1115. bWrapText = inResourceData->GetInt("wrap", 0) > 0;
  1116. SetWrap( bWrapText );
  1117. bool bNoShortcutSyntax = inResourceData->GetInt("noshortcutsyntax", 0) > 0;
  1118. SetNoShortcutSyntax( bNoShortcutSyntax );
  1119. int inset_x = inResourceData->GetInt("textinsetx", _textInset[0]);
  1120. int inset_y = inResourceData->GetInt("textinsety", _textInset[1]);
  1121. // Had to play it safe and add a new key for backwards compatibility
  1122. m_bUseProportionalInsets = inResourceData->GetInt("use_proportional_insets", 0) > 0;
  1123. if ( m_bUseProportionalInsets )
  1124. {
  1125. inset_x = scheme()->GetProportionalScaledValueEx( GetScheme(), inset_x );
  1126. }
  1127. SetTextInset( inset_x, inset_y );
  1128. bool bAllCaps = inResourceData->GetInt("allcaps", 0) > 0;
  1129. SetAllCaps( bAllCaps );
  1130. InvalidateLayout(true);
  1131. }
  1132. //-----------------------------------------------------------------------------
  1133. // Purpose: Returns a description of the label string
  1134. //-----------------------------------------------------------------------------
  1135. const char *Label::GetDescription( void )
  1136. {
  1137. static char buf[1024];
  1138. Q_snprintf(buf, sizeof(buf), "%s, string labelText, string associate, alignment textAlignment, int wrap, int dulltext, int brighttext, string font", BaseClass::GetDescription());
  1139. return buf;
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Purpose: If a label has images in _imageDar, the size
  1143. // must take those into account as well as the textImage part
  1144. // Textimage part will shrink ONLY if there is not enough room.
  1145. //-----------------------------------------------------------------------------
  1146. void Label::PerformLayout()
  1147. {
  1148. int wide, tall;
  1149. Panel::GetSize(wide, tall);
  1150. wide -= _textInset[0]; // take inset into account
  1151. // if we just have a textImage, this is trivial.
  1152. if (_imageDar.Count() == 1 && _textImageIndex == 0)
  1153. {
  1154. if ( m_bWrap || m_bCenterWrap )
  1155. {
  1156. int twide, ttall;
  1157. _textImage->GetContentSize(twide, ttall);
  1158. _textImage->SetSize(wide, ttall);
  1159. }
  1160. else
  1161. {
  1162. int twide, ttall;
  1163. _textImage->GetContentSize(twide, ttall);
  1164. // tell the textImage how much space we have to draw in
  1165. if ( wide < twide)
  1166. _textImage->SetSize(wide, ttall);
  1167. else
  1168. _textImage->SetSize(twide, ttall);
  1169. }
  1170. HandleAutoSizing();
  1171. return;
  1172. }
  1173. // assume the images in the dar cannot be resized, and if
  1174. // the images + the textimage are too wide we shring the textimage part
  1175. if (_textImageIndex < 0)
  1176. return;
  1177. // get the size of the images
  1178. int widthOfImages = 0;
  1179. for (int i = 0; i < _imageDar.Count(); i++)
  1180. {
  1181. TImageInfo &imageInfo = _imageDar[i];
  1182. IImage *image = imageInfo.image;
  1183. if (!image)
  1184. continue; // skip over null images
  1185. if (i == _textImageIndex)
  1186. continue;
  1187. // add up the bounds
  1188. int iWide, iTall;
  1189. image->GetSize(iWide, iTall);
  1190. widthOfImages += iWide;
  1191. }
  1192. // so this is how much room we have to draw the textimage part
  1193. int spaceAvail = wide - widthOfImages;
  1194. // if we have no space at all just leave everything as is.
  1195. if (spaceAvail < 0)
  1196. return;
  1197. int twide, ttall;
  1198. _textImage->GetSize (twide, ttall);
  1199. // tell the textImage how much space we have to draw in
  1200. _textImage->SetSize(spaceAvail, ttall);
  1201. HandleAutoSizing();
  1202. }
  1203. void Label::SetWrap( bool bWrap )
  1204. {
  1205. m_bWrap = bWrap;
  1206. _textImage->SetWrap( m_bWrap );
  1207. InvalidateLayout();
  1208. }
  1209. void Label::SetCenterWrap( bool bWrap )
  1210. {
  1211. m_bCenterWrap = bWrap;
  1212. _textImage->SetCenterWrap( m_bCenterWrap );
  1213. InvalidateLayout();
  1214. }
  1215. void Label::SetNoShortcutSyntax( bool bNoShortcutSyntax )
  1216. {
  1217. m_bNoShortcutSyntax = bNoShortcutSyntax;
  1218. _textImage->SetNoShortcutSyntax( bNoShortcutSyntax );
  1219. InvalidateLayout();
  1220. }
  1221. void Label::SetAllCaps( bool bAllCaps )
  1222. {
  1223. m_bAllCaps = bAllCaps;
  1224. _textImage->SetAllCaps( m_bAllCaps );
  1225. InvalidateLayout();
  1226. }
  1227. void Label::HandleAutoSizing( void )
  1228. {
  1229. if ( m_bAutoWideDirty )
  1230. {
  1231. m_bAutoWideDirty = false;
  1232. // Only change our width to match our content
  1233. int wide, tall;
  1234. GetContentSize(wide, tall);
  1235. SetSize(wide, GetTall());
  1236. }
  1237. if ( m_bAutoTallDirty )
  1238. {
  1239. m_bAutoTallDirty = false;
  1240. // Only change our width to match our content
  1241. int wide, tall;
  1242. GetContentSize( wide, tall );
  1243. SetSize( GetWide(), tall );
  1244. }
  1245. }