/xbmc/guilib/GUISpinControl.cpp

http://github.com/xbmc/xbmc · C++ · 1025 lines · 892 code · 104 blank · 29 comment · 178 complexity · fdeaaa1f41963e62d1c2c3dd34cdb56d 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 "GUISpinControl.h"
  9. #include "GUIMessage.h"
  10. #include "input/Key.h"
  11. #include "utils/StringUtils.h"
  12. #include <stdio.h>
  13. #define SPIN_BUTTON_DOWN 1
  14. #define SPIN_BUTTON_UP 2
  15. CGUISpinControl::CGUISpinControl(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& textureUp, const CTextureInfo& textureDown, const CTextureInfo& textureUpFocus, const CTextureInfo& textureDownFocus, const CTextureInfo& textureUpDisabled, const CTextureInfo& textureDownDisabled, const CLabelInfo &labelInfo, int iType)
  16. : CGUIControl(parentID, controlID, posX, posY, width, height)
  17. , m_imgspinUp(posX, posY, width, height, textureUp)
  18. , m_imgspinDown(posX, posY, width, height, textureDown)
  19. , m_imgspinUpFocus(posX, posY, width, height, textureUpFocus)
  20. , m_imgspinDownFocus(posX, posY, width, height, textureDownFocus)
  21. , m_imgspinUpDisabled(posX, posY, width, height, textureUpDisabled)
  22. , m_imgspinDownDisabled(posX, posY, width, height, textureDownDisabled)
  23. , m_label(posX, posY, width, height, labelInfo)
  24. {
  25. m_bReverse = false;
  26. m_iStart = 0;
  27. m_iEnd = 100;
  28. m_fStart = 0.0f;
  29. m_fEnd = 1.0f;
  30. m_fInterval = 0.1f;
  31. m_iValue = 0;
  32. m_fValue = 0.0;
  33. m_iType = iType;
  34. m_iSelect = SPIN_BUTTON_DOWN;
  35. m_bShowRange = false;
  36. m_iTypedPos = 0;
  37. strcpy(m_szTyped, "");
  38. ControlType = GUICONTROL_SPIN;
  39. m_currentItem = 0;
  40. m_numItems = 10;
  41. m_itemsPerPage = 10;
  42. m_showOnePage = true;
  43. }
  44. CGUISpinControl::~CGUISpinControl(void) = default;
  45. bool CGUISpinControl::OnAction(const CAction &action)
  46. {
  47. switch (action.GetID())
  48. {
  49. case REMOTE_0:
  50. case REMOTE_1:
  51. case REMOTE_2:
  52. case REMOTE_3:
  53. case REMOTE_4:
  54. case REMOTE_5:
  55. case REMOTE_6:
  56. case REMOTE_7:
  57. case REMOTE_8:
  58. case REMOTE_9:
  59. {
  60. if (strlen(m_szTyped) >= 3)
  61. {
  62. m_iTypedPos = 0;
  63. strcpy(m_szTyped, "");
  64. }
  65. int iNumber = action.GetID() - REMOTE_0;
  66. m_szTyped[m_iTypedPos] = iNumber + '0';
  67. m_iTypedPos++;
  68. m_szTyped[m_iTypedPos] = 0;
  69. int iValue;
  70. sscanf(m_szTyped, "%i", &iValue);
  71. switch (m_iType)
  72. {
  73. case SPIN_CONTROL_TYPE_INT:
  74. {
  75. if (iValue < m_iStart || iValue > m_iEnd)
  76. {
  77. m_iTypedPos = 0;
  78. m_szTyped[m_iTypedPos] = iNumber + '0';
  79. m_iTypedPos++;
  80. m_szTyped[m_iTypedPos] = 0;
  81. sscanf(m_szTyped, "%i", &iValue);
  82. if (iValue < m_iStart || iValue > m_iEnd)
  83. {
  84. m_iTypedPos = 0;
  85. strcpy(m_szTyped, "");
  86. return true;
  87. }
  88. }
  89. m_iValue = iValue;
  90. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  91. SendWindowMessage(msg);
  92. }
  93. break;
  94. case SPIN_CONTROL_TYPE_TEXT:
  95. {
  96. if (iValue < 0 || iValue >= (int)m_vecLabels.size())
  97. {
  98. m_iTypedPos = 0;
  99. m_szTyped[m_iTypedPos] = iNumber + '0';
  100. m_iTypedPos++;
  101. m_szTyped[m_iTypedPos] = 0;
  102. sscanf(m_szTyped, "%i", &iValue);
  103. if (iValue < 0 || iValue >= (int)m_vecLabels.size())
  104. {
  105. m_iTypedPos = 0;
  106. strcpy(m_szTyped, "");
  107. return true;
  108. }
  109. }
  110. m_iValue = iValue;
  111. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  112. SendWindowMessage(msg);
  113. }
  114. break;
  115. }
  116. return true;
  117. }
  118. break;
  119. case ACTION_PAGE_UP:
  120. if (!m_bReverse)
  121. PageDown();
  122. else
  123. PageUp();
  124. return true;
  125. break;
  126. case ACTION_PAGE_DOWN:
  127. if (!m_bReverse)
  128. PageUp();
  129. else
  130. PageDown();
  131. return true;
  132. break;
  133. case ACTION_SELECT_ITEM:
  134. if (m_iSelect == SPIN_BUTTON_UP)
  135. {
  136. MoveUp();
  137. return true;
  138. }
  139. if (m_iSelect == SPIN_BUTTON_DOWN)
  140. {
  141. MoveDown();
  142. return true;
  143. }
  144. break;
  145. }
  146. /* static float m_fSmoothScrollOffset = 0.0f;
  147. if (action.GetID() == ACTION_SCROLL_UP)
  148. {
  149. m_fSmoothScrollOffset += action.GetAmount() * action.GetAmount();
  150. bool handled = false;
  151. while (m_fSmoothScrollOffset > 0.4)
  152. {
  153. handled = true;
  154. m_fSmoothScrollOffset -= 0.4f;
  155. MoveDown();
  156. }
  157. return handled;
  158. }*/
  159. return CGUIControl::OnAction(action);
  160. }
  161. void CGUISpinControl::OnLeft()
  162. {
  163. if (m_iSelect == SPIN_BUTTON_UP)
  164. {
  165. // select the down button
  166. m_iSelect = SPIN_BUTTON_DOWN;
  167. MarkDirtyRegion();
  168. }
  169. else
  170. { // base class
  171. CGUIControl::OnLeft();
  172. }
  173. }
  174. void CGUISpinControl::OnRight()
  175. {
  176. if (m_iSelect == SPIN_BUTTON_DOWN)
  177. {
  178. // select the up button
  179. m_iSelect = SPIN_BUTTON_UP;
  180. MarkDirtyRegion();
  181. }
  182. else
  183. { // base class
  184. CGUIControl::OnRight();
  185. }
  186. }
  187. void CGUISpinControl::Clear()
  188. {
  189. m_vecLabels.clear();
  190. m_vecValues.clear();
  191. m_vecStrValues.clear();
  192. SetValue(0);
  193. }
  194. bool CGUISpinControl::OnMessage(CGUIMessage& message)
  195. {
  196. if (CGUIControl::OnMessage(message) )
  197. return true;
  198. if (message.GetControlId() == GetID() )
  199. {
  200. switch (message.GetMessage())
  201. {
  202. case GUI_MSG_ITEM_SELECT:
  203. if (SPIN_CONTROL_TYPE_PAGE == m_iType)
  204. {
  205. m_currentItem = message.GetParam1();
  206. return true;
  207. }
  208. SetValue( message.GetParam1());
  209. if (message.GetParam2() == SPIN_BUTTON_DOWN || message.GetParam2() == SPIN_BUTTON_UP)
  210. m_iSelect = message.GetParam2();
  211. return true;
  212. break;
  213. case GUI_MSG_LABEL_RESET:
  214. if (SPIN_CONTROL_TYPE_PAGE == m_iType)
  215. {
  216. m_itemsPerPage = message.GetParam1();
  217. m_numItems = message.GetParam2();
  218. return true;
  219. }
  220. {
  221. Clear();
  222. return true;
  223. }
  224. break;
  225. case GUI_MSG_SHOWRANGE:
  226. if (message.GetParam1() )
  227. m_bShowRange = true;
  228. else
  229. m_bShowRange = false;
  230. break;
  231. case GUI_MSG_SET_LABELS:
  232. if (message.GetPointer())
  233. {
  234. auto labels =
  235. static_cast<const std::vector<std::pair<std::string, int>>*>(message.GetPointer());
  236. Clear();
  237. for (const auto& i : *labels)
  238. AddLabel(i.first, i.second);
  239. SetValue( message.GetParam1());
  240. }
  241. break;
  242. case GUI_MSG_LABEL_ADD:
  243. {
  244. AddLabel(message.GetLabel(), message.GetParam1());
  245. return true;
  246. }
  247. break;
  248. case GUI_MSG_ITEM_SELECTED:
  249. {
  250. message.SetParam1( GetValue() );
  251. message.SetParam2(m_iSelect);
  252. if (m_iType == SPIN_CONTROL_TYPE_TEXT)
  253. {
  254. if ( m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
  255. message.SetLabel( m_vecLabels[m_iValue]);
  256. }
  257. return true;
  258. }
  259. case GUI_MSG_PAGE_UP:
  260. if (CanMoveUp())
  261. MoveUp();
  262. return true;
  263. case GUI_MSG_PAGE_DOWN:
  264. if (CanMoveDown())
  265. MoveDown();
  266. return true;
  267. case GUI_MSG_MOVE_OFFSET:
  268. {
  269. int count = message.GetParam1();
  270. while (count < 0)
  271. {
  272. MoveUp();
  273. count++;
  274. }
  275. while (count > 0)
  276. {
  277. MoveDown();
  278. count--;
  279. }
  280. return true;
  281. }
  282. }
  283. }
  284. return false;
  285. }
  286. void CGUISpinControl::AllocResources()
  287. {
  288. CGUIControl::AllocResources();
  289. m_imgspinUp.AllocResources();
  290. m_imgspinUpFocus.AllocResources();
  291. m_imgspinDown.AllocResources();
  292. m_imgspinDownFocus.AllocResources();
  293. m_imgspinUpDisabled.AllocResources();
  294. m_imgspinDownDisabled.AllocResources();
  295. m_imgspinDownFocus.SetPosition(m_posX, m_posY);
  296. m_imgspinDown.SetPosition(m_posX, m_posY);
  297. m_imgspinDownDisabled.SetPosition(m_posX, m_posY);
  298. m_imgspinUp.SetPosition(m_posX + m_imgspinDown.GetWidth(), m_posY);
  299. m_imgspinUpFocus.SetPosition(m_posX + m_imgspinDownFocus.GetWidth(), m_posY);
  300. m_imgspinUpDisabled.SetPosition(m_posX + m_imgspinDownDisabled.GetWidth(), m_posY);
  301. }
  302. void CGUISpinControl::FreeResources(bool immediately)
  303. {
  304. CGUIControl::FreeResources(immediately);
  305. m_imgspinUp.FreeResources(immediately);
  306. m_imgspinUpFocus.FreeResources(immediately);
  307. m_imgspinDown.FreeResources(immediately);
  308. m_imgspinDownFocus.FreeResources(immediately);
  309. m_imgspinUpDisabled.FreeResources(immediately);
  310. m_imgspinDownDisabled.FreeResources(immediately);
  311. m_iTypedPos = 0;
  312. strcpy(m_szTyped, "");
  313. }
  314. void CGUISpinControl::DynamicResourceAlloc(bool bOnOff)
  315. {
  316. CGUIControl::DynamicResourceAlloc(bOnOff);
  317. m_imgspinUp.DynamicResourceAlloc(bOnOff);
  318. m_imgspinUpFocus.DynamicResourceAlloc(bOnOff);
  319. m_imgspinDown.DynamicResourceAlloc(bOnOff);
  320. m_imgspinDownFocus.DynamicResourceAlloc(bOnOff);
  321. m_imgspinUpDisabled.DynamicResourceAlloc(bOnOff);
  322. m_imgspinDownDisabled.DynamicResourceAlloc(bOnOff);
  323. }
  324. void CGUISpinControl::SetInvalid()
  325. {
  326. CGUIControl::SetInvalid();
  327. m_label.SetInvalid();
  328. m_imgspinUp.SetInvalid();
  329. m_imgspinUpFocus.SetInvalid();
  330. m_imgspinDown.SetInvalid();
  331. m_imgspinDownFocus.SetInvalid();
  332. m_imgspinUpDisabled.SetInvalid();
  333. m_imgspinDownDisabled.SetInvalid();
  334. }
  335. void CGUISpinControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
  336. {
  337. bool changed = false;
  338. if (!HasFocus())
  339. {
  340. m_iTypedPos = 0;
  341. strcpy(m_szTyped, "");
  342. }
  343. std::string text;
  344. if (m_iType == SPIN_CONTROL_TYPE_INT)
  345. {
  346. if (m_bShowRange)
  347. {
  348. text = StringUtils::Format("%i/%i", m_iValue, m_iEnd);
  349. }
  350. else
  351. {
  352. text = StringUtils::Format("%i", m_iValue);
  353. }
  354. }
  355. else if (m_iType == SPIN_CONTROL_TYPE_PAGE)
  356. {
  357. // work out number of pages and current page
  358. int numPages = (m_numItems + m_itemsPerPage - 1) / m_itemsPerPage;
  359. int currentPage = m_currentItem / m_itemsPerPage + 1;
  360. if (m_currentItem >= m_numItems - m_itemsPerPage)
  361. currentPage = numPages;
  362. text = StringUtils::Format("%i/%i", currentPage, numPages);
  363. }
  364. else if (m_iType == SPIN_CONTROL_TYPE_FLOAT)
  365. {
  366. if (m_bShowRange)
  367. {
  368. text = StringUtils::Format("%02.2f/%02.2f", m_fValue, m_fEnd);
  369. }
  370. else
  371. {
  372. text = StringUtils::Format("%02.2f", m_fValue);
  373. }
  374. }
  375. else
  376. {
  377. if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size() )
  378. {
  379. if (m_bShowRange)
  380. {
  381. text = StringUtils::Format("(%i/%i) %s", m_iValue + 1, (int)m_vecLabels.size(), m_vecLabels[m_iValue].c_str() );
  382. }
  383. else
  384. {
  385. text = StringUtils::Format("%s", m_vecLabels[m_iValue].c_str() );
  386. }
  387. }
  388. else text = StringUtils::Format("?%i?", m_iValue);
  389. }
  390. changed |= m_label.SetText(text);
  391. float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
  392. // Position the arrows
  393. bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
  394. if (!arrowsOnRight)
  395. {
  396. const float space = 5;
  397. changed |= m_imgspinDownFocus.SetPosition(m_posX + textWidth + space, m_posY);
  398. changed |= m_imgspinDown.SetPosition(m_posX + textWidth + space, m_posY);
  399. changed |= m_imgspinDownDisabled.SetPosition(m_posX + textWidth + space, m_posY);
  400. changed |= m_imgspinUpFocus.SetPosition(m_posX + textWidth + space + m_imgspinDown.GetWidth(), m_posY);
  401. changed |= m_imgspinUp.SetPosition(m_posX + textWidth + space + m_imgspinDown.GetWidth(), m_posY);
  402. changed |= m_imgspinUpDisabled.SetPosition(m_posX + textWidth + space + m_imgspinDownDisabled.GetWidth(), m_posY);
  403. }
  404. changed |= m_imgspinDownFocus.Process(currentTime);
  405. changed |= m_imgspinDown.Process(currentTime);
  406. changed |= m_imgspinUp.Process(currentTime);
  407. changed |= m_imgspinUpFocus.Process(currentTime);
  408. changed |= m_imgspinUpDisabled.Process(currentTime);
  409. changed |= m_imgspinDownDisabled.Process(currentTime);
  410. changed |= m_label.Process(currentTime);
  411. if (changed)
  412. MarkDirtyRegion();
  413. CGUIControl::Process(currentTime, dirtyregions);
  414. }
  415. void CGUISpinControl::Render()
  416. {
  417. if ( HasFocus() )
  418. {
  419. if (m_iSelect == SPIN_BUTTON_UP)
  420. m_imgspinUpFocus.Render();
  421. else
  422. m_imgspinUp.Render();
  423. if (m_iSelect == SPIN_BUTTON_DOWN)
  424. m_imgspinDownFocus.Render();
  425. else
  426. m_imgspinDown.Render();
  427. }
  428. else if ( !HasFocus() && !IsDisabled() )
  429. {
  430. m_imgspinUp.Render();
  431. m_imgspinDown.Render();
  432. }
  433. else
  434. {
  435. m_imgspinUpDisabled.Render();
  436. m_imgspinDownDisabled.Render();
  437. }
  438. if (m_label.GetLabelInfo().font)
  439. {
  440. const float space = 5;
  441. float textWidth = m_label.GetTextWidth() + 2 * m_label.GetLabelInfo().offsetX;
  442. // Position the arrows
  443. bool arrowsOnRight(0 != (m_label.GetLabelInfo().align & (XBFONT_RIGHT | XBFONT_CENTER_X)));
  444. if (arrowsOnRight)
  445. RenderText(m_posX - space - textWidth, m_posY, textWidth, m_height);
  446. else
  447. RenderText(m_posX + m_imgspinDown.GetWidth() + m_imgspinUp.GetWidth() + space, m_posY, textWidth, m_height);
  448. // set our hit rectangle for MouseOver events
  449. m_hitRect = m_label.GetRenderRect();
  450. }
  451. CGUIControl::Render();
  452. }
  453. void CGUISpinControl::RenderText(float posX, float posY, float width, float height)
  454. {
  455. m_label.SetMaxRect(posX, posY, width, height);
  456. m_label.SetColor(GetTextColor());
  457. m_label.Render();
  458. }
  459. CGUILabel::COLOR CGUISpinControl::GetTextColor() const
  460. {
  461. if (IsDisabled())
  462. return CGUILabel::COLOR_DISABLED;
  463. else if (HasFocus())
  464. return CGUILabel::COLOR_FOCUSED;
  465. return CGUILabel::COLOR_TEXT;
  466. }
  467. void CGUISpinControl::SetRange(int iStart, int iEnd)
  468. {
  469. m_iStart = iStart;
  470. m_iEnd = iEnd;
  471. }
  472. void CGUISpinControl::SetFloatRange(float fStart, float fEnd)
  473. {
  474. m_fStart = fStart;
  475. m_fEnd = fEnd;
  476. }
  477. void CGUISpinControl::SetValueFromLabel(const std::string &label)
  478. {
  479. if (m_iType == SPIN_CONTROL_TYPE_TEXT)
  480. {
  481. m_iValue = 0;
  482. for (unsigned int i = 0; i < m_vecLabels.size(); i++)
  483. if (label == m_vecLabels[i])
  484. m_iValue = i;
  485. }
  486. else
  487. m_iValue = atoi(label.c_str());
  488. MarkDirtyRegion();
  489. SetInvalid();
  490. }
  491. void CGUISpinControl::SetValue(int iValue)
  492. {
  493. if (m_iType == SPIN_CONTROL_TYPE_TEXT)
  494. {
  495. m_iValue = 0;
  496. for (unsigned int i = 0; i < m_vecValues.size(); i++)
  497. if (iValue == m_vecValues[i])
  498. m_iValue = i;
  499. }
  500. else
  501. m_iValue = iValue;
  502. MarkDirtyRegion();
  503. SetInvalid();
  504. }
  505. void CGUISpinControl::SetFloatValue(float fValue)
  506. {
  507. m_fValue = fValue;
  508. }
  509. void CGUISpinControl::SetStringValue(const std::string& strValue)
  510. {
  511. if (m_iType == SPIN_CONTROL_TYPE_TEXT)
  512. {
  513. m_iValue = 0;
  514. for (unsigned int i = 0; i < m_vecStrValues.size(); i++)
  515. if (strValue == m_vecStrValues[i])
  516. m_iValue = i;
  517. }
  518. SetInvalid();
  519. }
  520. int CGUISpinControl::GetValue() const
  521. {
  522. if (m_iType == SPIN_CONTROL_TYPE_TEXT)
  523. {
  524. if (m_iValue >= 0 && m_iValue < (int)m_vecValues.size())
  525. return m_vecValues[m_iValue];
  526. }
  527. return m_iValue;
  528. }
  529. float CGUISpinControl::GetFloatValue() const
  530. {
  531. return m_fValue;
  532. }
  533. std::string CGUISpinControl::GetStringValue() const
  534. {
  535. if (m_iType == SPIN_CONTROL_TYPE_TEXT && m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
  536. {
  537. if (m_iValue < (int)m_vecStrValues.size())
  538. return m_vecStrValues[m_iValue];
  539. return m_vecLabels[m_iValue];
  540. }
  541. return "";
  542. }
  543. void CGUISpinControl::AddLabel(const std::string& strLabel, int iValue)
  544. {
  545. m_vecLabels.push_back(strLabel);
  546. m_vecValues.push_back(iValue);
  547. }
  548. void CGUISpinControl::AddLabel(const std::string& strLabel, const std::string& strValue)
  549. {
  550. m_vecLabels.push_back(strLabel);
  551. m_vecStrValues.push_back(strValue);
  552. }
  553. const std::string CGUISpinControl::GetLabel() const
  554. {
  555. if (m_iValue >= 0 && m_iValue < (int)m_vecLabels.size())
  556. {
  557. return m_vecLabels[m_iValue];
  558. }
  559. return "";
  560. }
  561. void CGUISpinControl::SetPosition(float posX, float posY)
  562. {
  563. CGUIControl::SetPosition(posX, posY);
  564. m_imgspinDownFocus.SetPosition(posX, posY);
  565. m_imgspinDown.SetPosition(posX, posY);
  566. m_imgspinDownDisabled.SetPosition(posX, posY);
  567. m_imgspinUp.SetPosition(m_posX + m_imgspinDown.GetWidth(), m_posY);
  568. m_imgspinUpFocus.SetPosition(m_posX + m_imgspinDownFocus.GetWidth(), m_posY);
  569. m_imgspinUpDisabled.SetPosition(m_posX + m_imgspinDownDisabled.GetWidth(), m_posY);
  570. }
  571. float CGUISpinControl::GetWidth() const
  572. {
  573. return m_imgspinDown.GetWidth() * 2 ;
  574. }
  575. bool CGUISpinControl::CanMoveUp(bool bTestReverse)
  576. {
  577. // test for reverse...
  578. if (bTestReverse && m_bReverse) return CanMoveDown(false);
  579. switch (m_iType)
  580. {
  581. case SPIN_CONTROL_TYPE_PAGE:
  582. return m_currentItem > 0;
  583. case SPIN_CONTROL_TYPE_INT:
  584. {
  585. if (m_iValue - 1 >= m_iStart)
  586. return true;
  587. return false;
  588. }
  589. break;
  590. case SPIN_CONTROL_TYPE_FLOAT:
  591. {
  592. if (m_fValue - m_fInterval >= m_fStart)
  593. return true;
  594. return false;
  595. }
  596. break;
  597. case SPIN_CONTROL_TYPE_TEXT:
  598. {
  599. if (m_iValue - 1 >= 0)
  600. return true;
  601. return false;
  602. }
  603. break;
  604. }
  605. return false;
  606. }
  607. bool CGUISpinControl::CanMoveDown(bool bTestReverse)
  608. {
  609. // test for reverse...
  610. if (bTestReverse && m_bReverse) return CanMoveUp(false);
  611. switch (m_iType)
  612. {
  613. case SPIN_CONTROL_TYPE_PAGE:
  614. return m_currentItem < m_numItems;
  615. case SPIN_CONTROL_TYPE_INT:
  616. {
  617. if (m_iValue + 1 <= m_iEnd)
  618. return true;
  619. return false;
  620. }
  621. break;
  622. case SPIN_CONTROL_TYPE_FLOAT:
  623. {
  624. if (m_fValue + m_fInterval <= m_fEnd)
  625. return true;
  626. return false;
  627. }
  628. break;
  629. case SPIN_CONTROL_TYPE_TEXT:
  630. {
  631. if (m_iValue + 1 < (int)m_vecLabels.size())
  632. return true;
  633. return false;
  634. }
  635. break;
  636. }
  637. return false;
  638. }
  639. void CGUISpinControl::PageUp()
  640. {
  641. switch (m_iType)
  642. {
  643. case SPIN_CONTROL_TYPE_INT:
  644. {
  645. if (m_iValue - 10 >= m_iStart)
  646. m_iValue -= 10;
  647. else
  648. m_iValue = m_iStart;
  649. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  650. SendWindowMessage(msg);
  651. return ;
  652. }
  653. break;
  654. case SPIN_CONTROL_TYPE_PAGE:
  655. ChangePage(-10);
  656. break;
  657. case SPIN_CONTROL_TYPE_TEXT:
  658. {
  659. if (m_iValue - 10 >= 0)
  660. m_iValue -= 10;
  661. else
  662. m_iValue = 0;
  663. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  664. SendWindowMessage(msg);
  665. return ;
  666. }
  667. break;
  668. }
  669. }
  670. void CGUISpinControl::PageDown()
  671. {
  672. switch (m_iType)
  673. {
  674. case SPIN_CONTROL_TYPE_INT:
  675. {
  676. if (m_iValue + 10 <= m_iEnd)
  677. m_iValue += 10;
  678. else
  679. m_iValue = m_iEnd;
  680. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  681. SendWindowMessage(msg);
  682. return ;
  683. }
  684. break;
  685. case SPIN_CONTROL_TYPE_PAGE:
  686. ChangePage(10);
  687. break;
  688. case SPIN_CONTROL_TYPE_TEXT:
  689. {
  690. if (m_iValue + 10 < (int)m_vecLabels.size() )
  691. m_iValue += 10;
  692. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  693. SendWindowMessage(msg);
  694. }
  695. break;
  696. }
  697. }
  698. void CGUISpinControl::MoveUp(bool bTestReverse)
  699. {
  700. if (bTestReverse && m_bReverse)
  701. { // actually should move down.
  702. MoveDown(false);
  703. return ;
  704. }
  705. switch (m_iType)
  706. {
  707. case SPIN_CONTROL_TYPE_INT:
  708. {
  709. if (m_iValue - 1 >= m_iStart)
  710. m_iValue--;
  711. else if (m_iValue == m_iStart)
  712. m_iValue = m_iEnd;
  713. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  714. SendWindowMessage(msg);
  715. return ;
  716. }
  717. break;
  718. case SPIN_CONTROL_TYPE_PAGE:
  719. ChangePage(-1);
  720. break;
  721. case SPIN_CONTROL_TYPE_FLOAT:
  722. {
  723. if (m_fValue - m_fInterval >= m_fStart)
  724. m_fValue -= m_fInterval;
  725. else if (m_fValue - m_fInterval < m_fStart)
  726. m_fValue = m_fEnd;
  727. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  728. SendWindowMessage(msg);
  729. return ;
  730. }
  731. break;
  732. case SPIN_CONTROL_TYPE_TEXT:
  733. {
  734. if (m_iValue - 1 >= 0)
  735. m_iValue--;
  736. else if (m_iValue == 0)
  737. m_iValue = (int)m_vecLabels.size() - 1;
  738. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  739. SendWindowMessage(msg);
  740. return ;
  741. }
  742. break;
  743. }
  744. }
  745. void CGUISpinControl::MoveDown(bool bTestReverse)
  746. {
  747. if (bTestReverse && m_bReverse)
  748. { // actually should move up.
  749. MoveUp(false);
  750. return ;
  751. }
  752. switch (m_iType)
  753. {
  754. case SPIN_CONTROL_TYPE_INT:
  755. {
  756. if (m_iValue + 1 <= m_iEnd)
  757. m_iValue++;
  758. else if (m_iValue == m_iEnd)
  759. m_iValue = m_iStart;
  760. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  761. SendWindowMessage(msg);
  762. return ;
  763. }
  764. break;
  765. case SPIN_CONTROL_TYPE_PAGE:
  766. ChangePage(1);
  767. break;
  768. case SPIN_CONTROL_TYPE_FLOAT:
  769. {
  770. if (m_fValue + m_fInterval <= m_fEnd)
  771. m_fValue += m_fInterval;
  772. else if (m_fValue + m_fInterval > m_fEnd)
  773. m_fValue = m_fStart;
  774. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  775. SendWindowMessage(msg);
  776. return ;
  777. }
  778. break;
  779. case SPIN_CONTROL_TYPE_TEXT:
  780. {
  781. if (m_iValue + 1 < (int)m_vecLabels.size() )
  782. m_iValue++;
  783. else if (m_iValue == (int)m_vecLabels.size() - 1)
  784. m_iValue = 0;
  785. CGUIMessage msg(GUI_MSG_CLICKED, GetID(), GetParentID());
  786. SendWindowMessage(msg);
  787. return ;
  788. }
  789. break;
  790. }
  791. }
  792. void CGUISpinControl::SetReverse(bool bReverse)
  793. {
  794. m_bReverse = bReverse;
  795. }
  796. void CGUISpinControl::SetFloatInterval(float fInterval)
  797. {
  798. m_fInterval = fInterval;
  799. }
  800. void CGUISpinControl::SetShowRange(bool bOnoff)
  801. {
  802. m_bShowRange = bOnoff;
  803. }
  804. int CGUISpinControl::GetMinimum() const
  805. {
  806. switch (m_iType)
  807. {
  808. case SPIN_CONTROL_TYPE_PAGE:
  809. return 0;
  810. case SPIN_CONTROL_TYPE_INT:
  811. return m_iStart;
  812. break;
  813. case SPIN_CONTROL_TYPE_TEXT:
  814. return 1;
  815. break;
  816. case SPIN_CONTROL_TYPE_FLOAT:
  817. return (int)(m_fStart*10.0f);
  818. break;
  819. }
  820. return 0;
  821. }
  822. int CGUISpinControl::GetMaximum() const
  823. {
  824. switch (m_iType)
  825. {
  826. case SPIN_CONTROL_TYPE_PAGE:
  827. return m_numItems;
  828. case SPIN_CONTROL_TYPE_INT:
  829. return m_iEnd;
  830. break;
  831. case SPIN_CONTROL_TYPE_TEXT:
  832. return (int)m_vecLabels.size();
  833. break;
  834. case SPIN_CONTROL_TYPE_FLOAT:
  835. return (int)(m_fEnd*10.0f);
  836. break;
  837. }
  838. return 100;
  839. }
  840. bool CGUISpinControl::HitTest(const CPoint &point) const
  841. {
  842. if (m_imgspinUpFocus.HitTest(point) || m_imgspinDownFocus.HitTest(point))
  843. return true;
  844. return CGUIControl::HitTest(point);
  845. }
  846. bool CGUISpinControl::OnMouseOver(const CPoint &point)
  847. {
  848. int select = m_iSelect;
  849. if (m_imgspinDownFocus.HitTest(point))
  850. m_iSelect = SPIN_BUTTON_DOWN;
  851. else
  852. m_iSelect = SPIN_BUTTON_UP;
  853. if (select != m_iSelect)
  854. MarkDirtyRegion();
  855. return CGUIControl::OnMouseOver(point);
  856. }
  857. EVENT_RESULT CGUISpinControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
  858. {
  859. if (event.m_id == ACTION_MOUSE_LEFT_CLICK)
  860. {
  861. if (m_imgspinUpFocus.HitTest(point))
  862. MoveUp();
  863. else if (m_imgspinDownFocus.HitTest(point))
  864. MoveDown();
  865. return EVENT_RESULT_HANDLED;
  866. }
  867. else if (event.m_id == ACTION_MOUSE_WHEEL_UP)
  868. {
  869. if (m_imgspinUpFocus.HitTest(point) || m_imgspinDownFocus.HitTest(point))
  870. {
  871. MoveUp();
  872. return EVENT_RESULT_HANDLED;
  873. }
  874. }
  875. else if (event.m_id == ACTION_MOUSE_WHEEL_DOWN)
  876. {
  877. if (m_imgspinUpFocus.HitTest(point) || m_imgspinDownFocus.HitTest(point))
  878. {
  879. MoveDown();
  880. return EVENT_RESULT_HANDLED;
  881. }
  882. }
  883. return EVENT_RESULT_UNHANDLED;
  884. }
  885. std::string CGUISpinControl::GetDescription() const
  886. {
  887. return StringUtils::Format("%i/%i", 1 + GetValue(), GetMaximum());
  888. }
  889. bool CGUISpinControl::IsFocusedOnUp() const
  890. {
  891. return (m_iSelect == SPIN_BUTTON_UP);
  892. }
  893. void CGUISpinControl::ChangePage(int amount)
  894. {
  895. m_currentItem += amount * m_itemsPerPage;
  896. if (m_currentItem > m_numItems - m_itemsPerPage)
  897. m_currentItem = m_numItems - m_itemsPerPage;
  898. if (m_currentItem < 0)
  899. m_currentItem = 0;
  900. CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetParentID(), GetID(), GUI_MSG_PAGE_CHANGE, m_currentItem);
  901. SendWindowMessage(message);
  902. }
  903. bool CGUISpinControl::UpdateColors()
  904. {
  905. bool changed = CGUIControl::UpdateColors();
  906. changed |= m_label.UpdateColors();
  907. changed |= m_imgspinDownFocus.SetDiffuseColor(m_diffuseColor);
  908. changed |= m_imgspinDown.SetDiffuseColor(m_diffuseColor);
  909. changed |= m_imgspinUp.SetDiffuseColor(m_diffuseColor);
  910. changed |= m_imgspinUpFocus.SetDiffuseColor(m_diffuseColor);
  911. changed |= m_imgspinUpDisabled.SetDiffuseColor(m_diffuseColor);
  912. changed |= m_imgspinDownDisabled.SetDiffuseColor(m_diffuseColor);
  913. return changed;
  914. }
  915. bool CGUISpinControl::IsVisible() const
  916. {
  917. // page controls can be optionally disabled if the number of pages is 1
  918. if (m_iType == SPIN_CONTROL_TYPE_PAGE && m_numItems <= m_itemsPerPage && !m_showOnePage)
  919. return false;
  920. return CGUIControl::IsVisible();
  921. }