/xbmc/guilib/GUISelectButtonControl.cpp

http://github.com/xbmc/xbmc · C++ · 446 lines · 337 code · 50 blank · 59 comment · 65 complexity · 3fa0a16d798a88bada5d9c391eef3b1c MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2013 Team XBMC
  3. * http://xbmc.org
  4. *
  5. * This Program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * This Program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with XBMC; see the file COPYING. If not, see
  17. * <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "GUISelectButtonControl.h"
  21. #include "GUIWindowManager.h"
  22. #include "utils/TimeUtils.h"
  23. #include "Key.h"
  24. CGUISelectButtonControl::CGUISelectButtonControl(int parentID, int controlID,
  25. float posX, float posY,
  26. float width, float height,
  27. const CTextureInfo& buttonFocus,
  28. const CTextureInfo& button,
  29. const CLabelInfo& labelInfo,
  30. const CTextureInfo& selectBackground,
  31. const CTextureInfo& selectArrowLeft,
  32. const CTextureInfo& selectArrowLeftFocus,
  33. const CTextureInfo& selectArrowRight,
  34. const CTextureInfo& selectArrowRightFocus
  35. )
  36. : CGUIButtonControl(parentID, controlID, posX, posY, width, height, buttonFocus, button, labelInfo)
  37. , m_imgBackground(posX, posY, width, height, selectBackground)
  38. , m_imgLeft(posX, posY, 16, 16, selectArrowLeft)
  39. , m_imgLeftFocus(posX, posY, 16, 16, selectArrowLeftFocus)
  40. , m_imgRight(posX, posY, 16, 16, selectArrowRight)
  41. , m_imgRightFocus(posX, posY, 16, 16, selectArrowRightFocus)
  42. {
  43. m_bShowSelect = false;
  44. m_iCurrentItem = -1;
  45. m_iDefaultItem = -1;
  46. m_iStartFrame = 0;
  47. m_bLeftSelected = false;
  48. m_bRightSelected = false;
  49. m_bMovedLeft = false;
  50. m_bMovedRight = false;
  51. m_ticks = 0;
  52. m_label.SetAlign(m_label.GetLabelInfo().align | XBFONT_CENTER_X);
  53. ControlType = GUICONTROL_SELECTBUTTON;
  54. }
  55. CGUISelectButtonControl::~CGUISelectButtonControl(void)
  56. {}
  57. void CGUISelectButtonControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
  58. {
  59. if (m_bInvalidated)
  60. {
  61. m_imgBackground.SetWidth(m_width);
  62. m_imgBackground.SetHeight(m_height);
  63. }
  64. // Are we in selection mode
  65. if (m_bShowSelect)
  66. {
  67. // render background, left and right arrow
  68. if (m_imgBackground.Process(currentTime))
  69. MarkDirtyRegion();
  70. CGUILabel::COLOR color = CGUILabel::COLOR_TEXT;
  71. // User has moved left...
  72. if (m_bMovedLeft)
  73. {
  74. m_iStartFrame++;
  75. if (m_iStartFrame >= 10)
  76. {
  77. m_iStartFrame = 0;
  78. m_bMovedLeft = false;
  79. MarkDirtyRegion();
  80. }
  81. // If we are moving left
  82. // render item text as disabled
  83. color = CGUILabel::COLOR_DISABLED;
  84. }
  85. // Update arrow
  86. m_imgLeftFocus.Process(currentTime);
  87. m_imgLeft.Process(currentTime);
  88. // User has moved right...
  89. if (m_bMovedRight)
  90. {
  91. m_iStartFrame++;
  92. if (m_iStartFrame >= 10)
  93. {
  94. m_iStartFrame = 0;
  95. m_bMovedRight = false;
  96. MarkDirtyRegion();
  97. }
  98. // If we are moving right
  99. // render item text as disabled
  100. color = CGUILabel::COLOR_DISABLED;
  101. }
  102. // Update arrow
  103. m_imgRightFocus.Process(currentTime);
  104. m_imgRight.Process(currentTime);
  105. // Render text if a current item is available
  106. if (m_iCurrentItem >= 0 && (unsigned)m_iCurrentItem < m_vecItems.size())
  107. {
  108. bool changed = m_label.SetMaxRect(m_posX, m_posY, m_width, m_height);
  109. changed |= m_label.SetText(m_vecItems[m_iCurrentItem]);
  110. changed |= m_label.SetColor(color);
  111. changed |= m_label.Process(currentTime);
  112. if (changed)
  113. MarkDirtyRegion();
  114. }
  115. // Select current item, if user doesn't
  116. // move left or right for 1.5 sec.
  117. unsigned int ticksSpan = currentTime - m_ticks;
  118. if (ticksSpan > 1500)
  119. {
  120. // User hasn't moved disable selection mode...
  121. m_bShowSelect = false;
  122. MarkDirtyRegion();
  123. // ...and send a thread message.
  124. // (Sending a message with SendMessage
  125. // can result in a GPF.)
  126. CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
  127. g_windowManager.SendThreadMessage(message);
  128. }
  129. CGUIControl::Process(currentTime, dirtyregions);
  130. } // if (m_bShowSelect)
  131. else
  132. CGUIButtonControl::Process(currentTime, dirtyregions);
  133. }
  134. void CGUISelectButtonControl::Render()
  135. {
  136. if (m_bShowSelect)
  137. {
  138. // render background, left and right arrow
  139. m_imgBackground.Render();
  140. // Render arrows
  141. if (m_bLeftSelected || m_bMovedLeft)
  142. m_imgLeftFocus.Render();
  143. else
  144. m_imgLeft.Render();
  145. if (m_bRightSelected || m_bMovedRight)
  146. m_imgRightFocus.Render();
  147. else
  148. m_imgRight.Render();
  149. // Render text if a current item is available
  150. if (m_iCurrentItem >= 0 && (unsigned)m_iCurrentItem < m_vecItems.size())
  151. m_label.Render();
  152. CGUIControl::Render();
  153. } // if (m_bShowSelect)
  154. else
  155. {
  156. // No, render a normal button
  157. CGUIButtonControl::Render();
  158. }
  159. }
  160. bool CGUISelectButtonControl::OnMessage(CGUIMessage& message)
  161. {
  162. if ( message.GetControlId() == GetID() )
  163. {
  164. if (message.GetMessage() == GUI_MSG_LABEL_ADD)
  165. {
  166. if (m_vecItems.size() <= 0)
  167. {
  168. m_iCurrentItem = 0;
  169. m_iDefaultItem = 0;
  170. }
  171. m_vecItems.push_back(message.GetLabel());
  172. return true;
  173. }
  174. else if (message.GetMessage() == GUI_MSG_LABEL_RESET)
  175. {
  176. m_vecItems.erase(m_vecItems.begin(), m_vecItems.end());
  177. m_iCurrentItem = -1;
  178. m_iDefaultItem = -1;
  179. return true;
  180. }
  181. else if (message.GetMessage() == GUI_MSG_ITEM_SELECTED)
  182. {
  183. message.SetParam1(m_iCurrentItem);
  184. if (m_iCurrentItem >= 0 && m_iCurrentItem < (int)m_vecItems.size())
  185. message.SetLabel(m_vecItems[m_iCurrentItem]);
  186. return true;
  187. }
  188. else if (message.GetMessage() == GUI_MSG_ITEM_SELECT)
  189. {
  190. m_iDefaultItem = m_iCurrentItem = message.GetParam1();
  191. return true;
  192. }
  193. }
  194. return CGUIButtonControl::OnMessage(message);
  195. }
  196. bool CGUISelectButtonControl::OnAction(const CAction &action)
  197. {
  198. if (!m_bShowSelect)
  199. {
  200. if (action.GetID() == ACTION_SELECT_ITEM)
  201. {
  202. // Enter selection mode
  203. m_bShowSelect = true;
  204. SetInvalid();
  205. // Start timer, if user doesn't select an item
  206. // or moves left/right. The control will
  207. // automatically select the current item.
  208. m_ticks = CTimeUtils::GetFrameTime();
  209. return true;
  210. }
  211. else
  212. return CGUIButtonControl::OnAction(action);
  213. }
  214. else
  215. {
  216. if (action.GetID() == ACTION_SELECT_ITEM)
  217. {
  218. // User has selected an item, disable selection mode...
  219. m_bShowSelect = false;
  220. SetInvalid();
  221. // ...and send a message.
  222. CGUIMessage message(GUI_MSG_CLICKED, GetID(), GetParentID() );
  223. SendWindowMessage(message);
  224. return true;
  225. }
  226. if (action.GetID() == ACTION_MOVE_UP || action.GetID() == ACTION_MOVE_DOWN )
  227. {
  228. // Disable selection mode when moving up or down
  229. m_bShowSelect = false;
  230. m_iCurrentItem = m_iDefaultItem;
  231. SetInvalid();
  232. }
  233. // call the base class
  234. return CGUIButtonControl::OnAction(action);
  235. }
  236. }
  237. void CGUISelectButtonControl::FreeResources(bool immediately)
  238. {
  239. CGUIButtonControl::FreeResources(immediately);
  240. m_imgBackground.FreeResources(immediately);
  241. m_imgLeft.FreeResources(immediately);
  242. m_imgLeftFocus.FreeResources(immediately);
  243. m_imgRight.FreeResources(immediately);
  244. m_imgRightFocus.FreeResources(immediately);
  245. m_bShowSelect = false;
  246. }
  247. void CGUISelectButtonControl::DynamicResourceAlloc(bool bOnOff)
  248. {
  249. CGUIControl::DynamicResourceAlloc(bOnOff);
  250. m_imgBackground.DynamicResourceAlloc(bOnOff);
  251. m_imgLeft.DynamicResourceAlloc(bOnOff);
  252. m_imgLeftFocus.DynamicResourceAlloc(bOnOff);
  253. m_imgRight.DynamicResourceAlloc(bOnOff);
  254. m_imgRightFocus.DynamicResourceAlloc(bOnOff);
  255. }
  256. void CGUISelectButtonControl::AllocResources()
  257. {
  258. CGUIButtonControl::AllocResources();
  259. m_imgBackground.AllocResources();
  260. m_imgLeft.AllocResources();
  261. m_imgLeftFocus.AllocResources();
  262. m_imgRight.AllocResources();
  263. m_imgRightFocus.AllocResources();
  264. // Position right arrow
  265. float posX = (m_posX + m_width - 8) - 16;
  266. float posY = m_posY + (m_height - 16) / 2;
  267. m_imgRight.SetPosition(posX, posY);
  268. m_imgRightFocus.SetPosition(posX, posY);
  269. // Position left arrow
  270. posX = m_posX + 8;
  271. m_imgLeft.SetPosition(posX, posY);
  272. m_imgLeftFocus.SetPosition(posX, posY);
  273. }
  274. void CGUISelectButtonControl::SetInvalid()
  275. {
  276. CGUIButtonControl::SetInvalid();
  277. m_imgBackground.SetInvalid();
  278. m_imgLeft.SetInvalid();
  279. m_imgLeftFocus.SetInvalid();
  280. m_imgRight.SetInvalid();
  281. m_imgRightFocus.SetInvalid();
  282. }
  283. void CGUISelectButtonControl::OnLeft()
  284. {
  285. if (m_bShowSelect)
  286. {
  287. // Set for visual feedback
  288. m_bMovedLeft = true;
  289. m_iStartFrame = 0;
  290. SetInvalid();
  291. // Reset timer for automatically selecting
  292. // the current item.
  293. m_ticks = CTimeUtils::GetFrameTime();
  294. // Switch to previous item
  295. if (m_vecItems.size() > 0)
  296. {
  297. m_iCurrentItem--;
  298. if (m_iCurrentItem < 0)
  299. m_iCurrentItem = (int)m_vecItems.size() - 1;
  300. }
  301. }
  302. else
  303. { // use the base class
  304. CGUIButtonControl::OnLeft();
  305. }
  306. }
  307. void CGUISelectButtonControl::OnRight()
  308. {
  309. if (m_bShowSelect)
  310. {
  311. // Set for visual feedback
  312. m_bMovedRight = true;
  313. m_iStartFrame = 0;
  314. SetInvalid();
  315. // Reset timer for automatically selecting
  316. // the current item.
  317. m_ticks = CTimeUtils::GetFrameTime();
  318. // Switch to next item
  319. if (m_vecItems.size() > 0)
  320. {
  321. m_iCurrentItem++;
  322. if (m_iCurrentItem >= (int)m_vecItems.size())
  323. m_iCurrentItem = 0;
  324. }
  325. }
  326. else
  327. { // use the base class
  328. CGUIButtonControl::OnRight();
  329. }
  330. }
  331. bool CGUISelectButtonControl::OnMouseOver(const CPoint &point)
  332. {
  333. bool ret = CGUIControl::OnMouseOver(point);
  334. m_bLeftSelected = false;
  335. m_bRightSelected = false;
  336. if (m_imgLeft.HitTest(point))
  337. { // highlight the left control, but don't start moving until we have clicked
  338. m_bLeftSelected = true;
  339. }
  340. if (m_imgRight.HitTest(point))
  341. { // highlight the right control, but don't start moving until we have clicked
  342. m_bRightSelected = true;
  343. }
  344. // reset ticks
  345. m_ticks = CTimeUtils::GetFrameTime();
  346. return ret;
  347. }
  348. EVENT_RESULT CGUISelectButtonControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
  349. {
  350. if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
  351. {
  352. if (m_bShowSelect && m_imgLeft.HitTest(point))
  353. OnLeft();
  354. else if (m_bShowSelect && m_imgRight.HitTest(point))
  355. OnRight();
  356. else // normal select
  357. CGUIButtonControl::OnMouseEvent(point, event);
  358. return EVENT_RESULT_HANDLED;
  359. }
  360. else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
  361. {
  362. OnLeft();
  363. return EVENT_RESULT_HANDLED;
  364. }
  365. else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
  366. {
  367. OnRight();
  368. return EVENT_RESULT_HANDLED;
  369. }
  370. return EVENT_RESULT_UNHANDLED;
  371. }
  372. void CGUISelectButtonControl::SetPosition(float posX, float posY)
  373. {
  374. float leftOffX = m_imgLeft.GetXPosition() - m_posX;
  375. float leftOffY = m_imgLeft.GetYPosition() - m_posY;
  376. float rightOffX = m_imgRight.GetXPosition() - m_posX;
  377. float rightOffY = m_imgRight.GetYPosition() - m_posY;
  378. float backOffX = m_imgBackground.GetXPosition() - m_posX;
  379. float backOffY = m_imgBackground.GetYPosition() - m_posY;
  380. CGUIButtonControl::SetPosition(posX, posY);
  381. m_imgLeft.SetPosition(posX + leftOffX, posY + leftOffY);
  382. m_imgLeftFocus.SetPosition(posX + leftOffX, posY + leftOffY);
  383. m_imgRight.SetPosition(posX + rightOffX, posY + rightOffY);
  384. m_imgRightFocus.SetPosition(posX + rightOffX, posY + rightOffY);
  385. m_imgBackground.SetPosition(posX + backOffX, posY + backOffY);
  386. }
  387. bool CGUISelectButtonControl::UpdateColors()
  388. {
  389. bool changed = CGUIButtonControl::UpdateColors();
  390. changed |= m_imgLeft.SetDiffuseColor(m_diffuseColor);
  391. changed |= m_imgLeftFocus.SetDiffuseColor(m_diffuseColor);
  392. changed |= m_imgRight.SetDiffuseColor(m_diffuseColor);
  393. changed |= m_imgRightFocus.SetDiffuseColor(m_diffuseColor);
  394. changed |= m_imgBackground.SetDiffuseColor(m_diffuseColor);
  395. return changed;
  396. }