/xbmc/guilib/GUIButtonControl.cpp

http://github.com/xbmc/xbmc · C++ · 370 lines · 306 code · 50 blank · 14 comment · 52 complexity · ea31ef65a2a7144e69fe25fb7f42e54e MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2018 Team Kodi
  3. * This file is part of Kodi - https://kodi.tv
  4. *
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * See LICENSES/README.md for more information.
  7. */
  8. #include "GUIButtonControl.h"
  9. #include "GUIFontManager.h"
  10. #include "input/Key.h"
  11. CGUIButtonControl::CGUIButtonControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus, const CLabelInfo& labelInfo, bool wrapMultiline)
  12. : CGUIControl(parentID, controlID, posX, posY, width, height)
  13. , m_imgFocus(posX, posY, width, height, textureFocus)
  14. , m_imgNoFocus(posX, posY, width, height, textureNoFocus)
  15. , m_label(posX, posY, width, height, labelInfo, wrapMultiline ? CGUILabel::OVER_FLOW_WRAP : CGUILabel::OVER_FLOW_TRUNCATE)
  16. , m_label2(posX, posY, width, height, labelInfo)
  17. {
  18. m_bSelected = false;
  19. m_alpha = 255;
  20. m_focusCounter = 0;
  21. m_minWidth = 0;
  22. m_maxWidth = width;
  23. ControlType = GUICONTROL_BUTTON;
  24. }
  25. CGUIButtonControl::~CGUIButtonControl(void) = default;
  26. void CGUIButtonControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
  27. {
  28. ProcessText(currentTime);
  29. if (m_bInvalidated)
  30. {
  31. m_imgFocus.SetWidth(GetWidth());
  32. m_imgFocus.SetHeight(m_height);
  33. m_imgNoFocus.SetWidth(GetWidth());
  34. m_imgNoFocus.SetHeight(m_height);
  35. }
  36. if (HasFocus())
  37. {
  38. unsigned int alphaChannel = m_alpha;
  39. if (m_pulseOnSelect)
  40. {
  41. unsigned int alphaCounter = m_focusCounter + 2;
  42. if ((alphaCounter % 128) >= 64)
  43. alphaChannel = alphaCounter % 64;
  44. else
  45. alphaChannel = 63 - (alphaCounter % 64);
  46. alphaChannel += 192;
  47. alphaChannel = (unsigned int)((float)m_alpha * (float)alphaChannel / 255.0f);
  48. }
  49. if (m_imgFocus.SetAlpha((unsigned char)alphaChannel))
  50. MarkDirtyRegion();
  51. m_imgFocus.SetVisible(true);
  52. m_imgNoFocus.SetVisible(false);
  53. m_focusCounter++;
  54. }
  55. else
  56. {
  57. m_imgFocus.SetVisible(false);
  58. m_imgNoFocus.SetVisible(true);
  59. }
  60. m_imgFocus.Process(currentTime);
  61. m_imgNoFocus.Process(currentTime);
  62. CGUIControl::Process(currentTime, dirtyregions);
  63. }
  64. void CGUIButtonControl::Render()
  65. {
  66. m_imgFocus.Render();
  67. m_imgNoFocus.Render();
  68. RenderText();
  69. CGUIControl::Render();
  70. }
  71. void CGUIButtonControl::RenderText()
  72. {
  73. m_label.Render();
  74. m_label2.Render();
  75. }
  76. CGUILabel::COLOR CGUIButtonControl::GetTextColor() const
  77. {
  78. if (IsDisabled())
  79. return CGUILabel::COLOR_DISABLED;
  80. if (HasFocus())
  81. return CGUILabel::COLOR_FOCUSED;
  82. return CGUILabel::COLOR_TEXT;
  83. }
  84. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  85. float CGUIButtonControl::GetWidth() const
  86. {
  87. if (m_minWidth && m_minWidth != m_width)
  88. {
  89. float txtWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
  90. if (m_label2.GetTextWidth())
  91. {
  92. static const float min_space = 10;
  93. txtWidth += m_label2.GetTextWidth() + 2 * m_label2.GetLabelInfo().offsetX + min_space;
  94. }
  95. float maxWidth = m_maxWidth ? m_maxWidth : txtWidth;
  96. return CLAMP(txtWidth, m_minWidth, maxWidth);
  97. }
  98. return m_width;
  99. }
  100. void CGUIButtonControl::SetMinWidth(float minWidth)
  101. {
  102. if (m_minWidth != minWidth)
  103. MarkDirtyRegion();
  104. m_minWidth = minWidth;
  105. }
  106. void CGUIButtonControl::ProcessText(unsigned int currentTime)
  107. {
  108. CRect labelRenderRect = m_label.GetRenderRect();
  109. CRect label2RenderRect = m_label2.GetRenderRect();
  110. float renderWidth = GetWidth();
  111. bool changed = m_label.SetMaxRect(m_posX, m_posY, renderWidth, m_height);
  112. changed |= m_label.SetText(m_info.GetLabel(m_parentID));
  113. changed |= m_label.SetScrolling(HasFocus());
  114. changed |= m_label2.SetMaxRect(m_posX, m_posY, renderWidth, m_height);
  115. changed |= m_label2.SetText(m_info2.GetLabel(m_parentID));
  116. // text changed - images need resizing
  117. if (m_minWidth && (m_label.GetRenderRect() != labelRenderRect))
  118. SetInvalid();
  119. // auto-width - adjust hitrect
  120. if (m_minWidth && m_width != renderWidth)
  121. {
  122. CRect rect(m_posX, m_posY, renderWidth, m_height);
  123. SetHitRect(rect, m_hitColor);
  124. }
  125. // render the second label if it exists
  126. if (!m_info2.GetLabel(m_parentID).empty())
  127. {
  128. changed |= m_label2.SetAlign(XBFONT_RIGHT | (m_label.GetLabelInfo().align & XBFONT_CENTER_Y) | XBFONT_TRUNCATED);
  129. changed |= m_label2.SetScrolling(HasFocus());
  130. // If overlapping was corrected - compare render rects to determine
  131. // if they changed since last frame.
  132. if (CGUILabel::CheckAndCorrectOverlap(m_label, m_label2))
  133. changed |= (m_label.GetRenderRect() != labelRenderRect ||
  134. m_label2.GetRenderRect() != label2RenderRect);
  135. changed |= m_label2.SetColor(GetTextColor());
  136. changed |= m_label2.Process(currentTime);
  137. }
  138. changed |= m_label.SetColor(GetTextColor());
  139. changed |= m_label.Process(currentTime);
  140. if (changed)
  141. MarkDirtyRegion();
  142. }
  143. bool CGUIButtonControl::OnAction(const CAction &action)
  144. {
  145. if (action.GetID() == ACTION_SELECT_ITEM)
  146. {
  147. OnClick();
  148. return true;
  149. }
  150. return CGUIControl::OnAction(action);
  151. }
  152. bool CGUIButtonControl::OnMessage(CGUIMessage& message)
  153. {
  154. if (message.GetControlId() == GetID())
  155. {
  156. if (message.GetMessage() == GUI_MSG_LABEL_SET)
  157. {
  158. SetLabel(message.GetLabel());
  159. return true;
  160. }
  161. if (message.GetMessage() == GUI_MSG_LABEL2_SET)
  162. {
  163. SetLabel2(message.GetLabel());
  164. return true;
  165. }
  166. if (message.GetMessage() == GUI_MSG_IS_SELECTED)
  167. {
  168. message.SetParam1(m_bSelected ? 1 : 0);
  169. return true;
  170. }
  171. if (message.GetMessage() == GUI_MSG_SET_SELECTED)
  172. {
  173. if (!m_bSelected)
  174. SetInvalid();
  175. m_bSelected = true;
  176. return true;
  177. }
  178. if (message.GetMessage() == GUI_MSG_SET_DESELECTED)
  179. {
  180. if (m_bSelected)
  181. SetInvalid();
  182. m_bSelected = false;
  183. return true;
  184. }
  185. }
  186. return CGUIControl::OnMessage(message);
  187. }
  188. void CGUIButtonControl::AllocResources()
  189. {
  190. CGUIControl::AllocResources();
  191. m_focusCounter = 0;
  192. m_imgFocus.AllocResources();
  193. m_imgNoFocus.AllocResources();
  194. if (!m_width)
  195. m_width = m_imgFocus.GetWidth();
  196. if (!m_height)
  197. m_height = m_imgFocus.GetHeight();
  198. }
  199. void CGUIButtonControl::FreeResources(bool immediately)
  200. {
  201. CGUIControl::FreeResources(immediately);
  202. m_imgFocus.FreeResources(immediately);
  203. m_imgNoFocus.FreeResources(immediately);
  204. }
  205. void CGUIButtonControl::DynamicResourceAlloc(bool bOnOff)
  206. {
  207. CGUIControl::DynamicResourceAlloc(bOnOff);
  208. m_imgFocus.DynamicResourceAlloc(bOnOff);
  209. m_imgNoFocus.DynamicResourceAlloc(bOnOff);
  210. }
  211. void CGUIButtonControl::SetInvalid()
  212. {
  213. CGUIControl::SetInvalid();
  214. m_label.SetInvalid();
  215. m_label2.SetInvalid();
  216. m_imgFocus.SetInvalid();
  217. m_imgNoFocus.SetInvalid();
  218. }
  219. void CGUIButtonControl::SetLabel(const std::string &label)
  220. { // NOTE: No fallback for buttons at this point
  221. if (m_info.GetLabel(GetParentID(), false) != label)
  222. {
  223. m_info.SetLabel(label, "", GetParentID());
  224. SetInvalid();
  225. }
  226. }
  227. void CGUIButtonControl::SetLabel2(const std::string &label2)
  228. { // NOTE: No fallback for buttons at this point
  229. if (m_info2.GetLabel(GetParentID(), false) != label2)
  230. {
  231. m_info2.SetLabel(label2, "", GetParentID());
  232. SetInvalid();
  233. }
  234. }
  235. void CGUIButtonControl::SetPosition(float posX, float posY)
  236. {
  237. CGUIControl::SetPosition(posX, posY);
  238. m_imgFocus.SetPosition(posX, posY);
  239. m_imgNoFocus.SetPosition(posX, posY);
  240. }
  241. void CGUIButtonControl::SetAlpha(unsigned char alpha)
  242. {
  243. if (m_alpha != alpha)
  244. MarkDirtyRegion();
  245. m_alpha = alpha;
  246. }
  247. bool CGUIButtonControl::UpdateColors()
  248. {
  249. bool changed = CGUIControl::UpdateColors();
  250. changed |= m_label.UpdateColors();
  251. changed |= m_label2.UpdateColors();
  252. changed |= m_imgFocus.SetDiffuseColor(m_diffuseColor);
  253. changed |= m_imgNoFocus.SetDiffuseColor(m_diffuseColor);
  254. return changed;
  255. }
  256. CRect CGUIButtonControl::CalcRenderRegion() const
  257. {
  258. CRect buttonRect = CGUIControl::CalcRenderRegion();
  259. CRect textRect = m_label.GetRenderRect();
  260. buttonRect.Union(textRect);
  261. return buttonRect;
  262. }
  263. EVENT_RESULT CGUIButtonControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
  264. {
  265. if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
  266. {
  267. OnAction(CAction(ACTION_SELECT_ITEM));
  268. return EVENT_RESULT_HANDLED;
  269. }
  270. return EVENT_RESULT_UNHANDLED;
  271. }
  272. std::string CGUIButtonControl::GetDescription() const
  273. {
  274. std::string strLabel(m_info.GetLabel(m_parentID));
  275. return strLabel;
  276. }
  277. std::string CGUIButtonControl::GetLabel2() const
  278. {
  279. std::string strLabel(m_info2.GetLabel(m_parentID));
  280. return strLabel;
  281. }
  282. void CGUIButtonControl::PythonSetLabel(const std::string &strFont, const std::string &strText, UTILS::Color textColor, UTILS::Color shadowColor, UTILS::Color focusedColor)
  283. {
  284. m_label.GetLabelInfo().font = g_fontManager.GetFont(strFont);
  285. m_label.GetLabelInfo().textColor = textColor;
  286. m_label.GetLabelInfo().focusedColor = focusedColor;
  287. m_label.GetLabelInfo().shadowColor = shadowColor;
  288. SetLabel(strText);
  289. }
  290. void CGUIButtonControl::PythonSetDisabledColor(UTILS::Color disabledColor)
  291. {
  292. m_label.GetLabelInfo().disabledColor = disabledColor;
  293. }
  294. void CGUIButtonControl::OnClick()
  295. {
  296. // Save values, as the click message may deactivate the window
  297. int controlID = GetID();
  298. int parentID = GetParentID();
  299. CGUIAction clickActions = m_clickActions;
  300. // button selected, send a message
  301. CGUIMessage msg(GUI_MSG_CLICKED, controlID, parentID, 0);
  302. SendWindowMessage(msg);
  303. clickActions.ExecuteActions(controlID, parentID);
  304. }
  305. void CGUIButtonControl::OnFocus()
  306. {
  307. m_focusActions.ExecuteActions(GetID(), GetParentID());
  308. }
  309. void CGUIButtonControl::OnUnFocus()
  310. {
  311. m_unfocusActions.ExecuteActions(GetID(), GetParentID());
  312. }
  313. void CGUIButtonControl::SetSelected(bool bSelected)
  314. {
  315. if (m_bSelected != bSelected)
  316. {
  317. m_bSelected = bSelected;
  318. SetInvalid();
  319. }
  320. }