MythTV  master
mythuibuttonlist.cpp
Go to the documentation of this file.
1 #include "mythuibuttonlist.h"
2 
3 #include <cmath>
4 #include <algorithm>
5 #include <utility>
6 
7 // QT headers
8 #include <QCoreApplication>
9 #include <QDomDocument>
10 #include <QKeyEvent>
11 #include <QRegularExpression>
12 
13 // libmythbase headers
14 #include "libmythbase/lcddevice.h"
16 
17 // mythui headers
18 #include "mythmainwindow.h"
19 #include "mythuiscrollbar.h"
20 #include "mythuistatetype.h"
21 #include "mythuibutton.h"
22 #include "mythuitext.h"
23 #include "mythuitextedit.h"
24 #include "mythuigroup.h"
25 #include "mythuiimage.h"
26 #include "mythgesture.h"
27 #include "mythuiprogressbar.h"
28 
29 #define LOC QString("MythUIButtonList(%1): ").arg(objectName())
30 
31 MythUIButtonList::MythUIButtonList(MythUIType *parent, const QString &name)
32  : MythUIType(parent, name)
33 {
34  // Parent members
37 
38  Const();
39 }
40 
41 MythUIButtonList::MythUIButtonList(MythUIType *parent, const QString &name,
42  const QRect area, bool showArrow,
43  bool showScrollBar)
44  : MythUIType(parent, name),
45  m_showArrow(showArrow), m_showScrollBar(showScrollBar)
46 {
47  // Parent members
48  m_area = area;
49  m_initiator = true;
50  m_enableInitiator = true;
51 
54 
55  Const();
56 }
57 
59 {
60 
61  SetCanTakeFocus(true);
62 
63  connect(this, &MythUIType::TakingFocus, this, &MythUIButtonList::Select);
65 }
66 
68 {
69  m_buttonToItem.clear();
70  m_clearing = true;
71 
72  while (!m_itemList.isEmpty())
73  delete m_itemList.takeFirst();
74 }
75 
77 {
79 
80  if (item)
81  emit itemSelected(item);
82 
83  SetActive(true);
84 }
85 
87 {
88  SetActive(false);
89 }
90 
92 {
93  if (m_initialized)
94  Update();
95 }
96 
98 {
99  m_drawFromBottom = draw;
100 }
101 
103 {
104  if (m_active == active)
105  return;
106 
107  m_active = active;
108 
109  if (m_initialized)
110  Update();
111 }
112 
117 {
118  m_buttonToItem.clear();
119 
120  if (m_itemList.isEmpty())
121  return;
122 
123  m_clearing = true;
124 
125  while (!m_itemList.isEmpty())
126  delete m_itemList.takeFirst();
127 
128  m_clearing = false;
129 
130  m_selPosition = 0;
131  m_topPosition = 0;
132  m_itemCount = 0;
133 
134  StopLoad();
135  Update();
137 
138  emit DependChanged(true);
139 }
140 
142 {
143  m_needsUpdate = true;
144  SetRedraw();
145 }
146 
147 /*
148  * The "width" of a button determines it relative position when using
149  * Dynamic-Layout.
150  *
151  * If a button has a negative offset, that offset needs accounted for
152  * to position the button in proper releation to the surrounding buttons.
153  */
155 {
156  int width = area.width();
157 
158  if (area.x() < 0)
159  {
160  /*
161  * Assume if an overlap is allowed on the left, the same overlap
162  * is on the right
163  */
164  width += (area.x() * 2 - 1); // x is negative
165 
166  while (width < 0)
167  width -= area.x(); // Oops
168  }
169  else if (m_layout == LayoutHorizontal)
170  {
171  width -= area.x(); // Get rid of any "space" betwen the buttons
172  }
173 
174  return width;
175 }
176 
177 /*
178  * The "height" of a button determines it relative position when using
179  * Dynamic-Layout.
180  *
181  * If a button has a negative offset, that offset needs accounted for
182  * to position the button in proper releation to the surrounding buttons.
183  */
185 {
186  int height = area.height();
187 
188  if (area.y() < 0)
189  {
190  /*
191  * Assume if an overlap is allowed on the top, the same overlap
192  * is on the bottom
193  */
194  height += (area.y() * 2 - 1);
195 
196  while (height < 0)
197  height -= area.y(); // Oops
198  }
199  else if (m_layout == LayoutVertical)
200  {
201  height -= area.y(); // Get rid of any "space" betwen the buttons
202  }
203 
204  return height;
205 }
206 
207 /*
208  * For Dynamic-Layout, buttons are allocated as needed. If the list is
209  * being redrawn, re-use any previously allocated buttons.
210  */
211 MythUIGroup *MythUIButtonList::PrepareButton(int buttonIdx, int itemIdx,
212  int &selectedIdx,
213  int &button_shift)
214 {
215  MythUIButtonListItem *buttonItem = m_itemList[itemIdx];
216 
217  buttonIdx += button_shift;
218 
219  if (buttonIdx < 0 || buttonIdx + 1 > m_maxVisible)
220  {
221  QString name = QString("buttonlist button %1").arg(m_maxVisible);
222  auto *button = new MythUIStateType(this, name);
223  button->CopyFrom(m_buttontemplate);
224  button->ConnectDependants(true);
225 
226  if (buttonIdx < 0)
227  {
228  /*
229  * If a new button is needed in the front of the list, previously
230  * existing buttons need shifted to the right.
231  */
232  m_buttonList.prepend(button);
233  buttonIdx = 0;
234  ++button_shift;
235 
236  if (selectedIdx >= 0)
237  ++selectedIdx;
238  }
239  else
240  {
241  m_buttonList.append(button);
242  }
243 
244  ++m_maxVisible;
245  }
246 
247  MythUIStateType *realButton = m_buttonList[buttonIdx];
248  m_buttonToItem[buttonIdx] = buttonItem;
249  buttonItem->SetToRealButton(realButton, itemIdx == m_selPosition);
250  auto *buttonstate =
251  dynamic_cast<MythUIGroup *>(realButton->GetCurrentState());
252 
253  if (itemIdx == m_selPosition)
254  selectedIdx = buttonIdx;
255 
256  return buttonstate;
257 }
258 
259 /*
260  * Dynamically layout the buttons on a row.
261  */
262 bool MythUIButtonList::DistributeRow(int &first_button, int &last_button,
263  int &first_item, int &last_item,
264  int &selected_column, int &skip_cols,
265  bool grow_left, bool grow_right,
266  int **col_widths, int &row_height,
267  int total_height, int split_height,
268  int &col_cnt, bool &wrapped)
269 {
270  MythUIGroup *buttonstate = nullptr;
271  int left_width = 0;
272  int right_width = 0;
273  int begin = 0;
274  int end = 0;
275  bool underflow = false;
276 
277  int selectedIdx = -1;
278  int button_shift = 0;
279  col_cnt = 1;
280  skip_cols = 0;
281 
282  if (last_item + 1 > m_itemCount || last_item < 0 || first_item < 0)
283  return false;
284 
285  /*
286  * Allocate a button on the row. With a vertical layout, there is
287  * only one button per row, and this would be it.
288  */
289  if (grow_right)
290  {
291  buttonstate = PrepareButton(last_button, last_item,
292  selectedIdx, button_shift);
293  }
294  else
295  {
296  buttonstate = PrepareButton(first_button, first_item,
297  selectedIdx, button_shift);
298  }
299 
300  if (buttonstate == nullptr)
301  {
302  LOG(VB_GENERAL, LOG_ERR, QString("Failed to query buttonlist state: %1")
303  .arg(last_button));
304  return false;
305  }
306 
307  // Note size of initial button.
308  int max_width = m_contentsRect.width();
309  int max_height = m_contentsRect.height();
310  row_height = minButtonHeight(buttonstate->GetArea());
311  int width = minButtonWidth(buttonstate->GetArea());
312 
313  /*
314  * If the selected button should be centered, don't allow new buttons
315  * to take up more than half the allowed area.
316  */
317  bool vsplit = (m_scrollStyle == ScrollCenter);
318  bool hsplit = vsplit && grow_left && grow_right;
319 
320  if (hsplit)
321  {
322  max_width /= 2;
323  left_width = right_width = (width / 2);
324  }
325  else
326  {
327  if (grow_right)
328  {
329  left_width = 0;
330  right_width = width;
331  }
332  else
333  {
334  left_width = width;
335  right_width = 0;
336  }
337  }
338 
339  if (vsplit)
340  max_height /= 2;
341 
342  /*
343  * If total_height == 0, then this is the first row, so allow any height.
344  * Otherwise, If adding a button to a column would exceed the
345  * parent height, abort
346  */
347  if (total_height > 0 &&
348  ((vsplit ? split_height : total_height) +
349  m_itemVertSpacing + row_height > max_height))
350  {
351  LOG(VB_GUI, LOG_DEBUG,
352  QString("%1 Height exceeded %2 + (%3) + %4 = %5 which is > %6")
353  .arg(vsplit ? "Centering" : "Total")
354  .arg(split_height).arg(m_itemVertSpacing).arg(row_height)
355  .arg(split_height + m_itemVertSpacing + row_height)
356  .arg(max_height));
357  first_button += button_shift;
358  last_button += button_shift;
359  return false;
360  }
361 
362  LOG(VB_GUI, LOG_DEBUG, QString("Added button item %1 width %2 height %3")
363  .arg(grow_right ? last_item : first_item)
364  .arg(width).arg(row_height));
365 
366  int initial_first_button = first_button;
367  int initial_last_button = last_button;
368  int initial_first_item = first_item;
369  int initial_last_item = last_item;
370 
371  /*
372  * if col_widths is not nullptr, then grow_left & grow_right
373  * are mutually exclusive. So, col_idx can be anchored from
374  * the left or right.
375  */
376  int col_idx = 0;
377  if (!grow_right)
378  col_idx = m_columns - 1;
379 
380  // Add butons until no more fit.
381  bool added = (m_layout != LayoutVertical);
382 
383  while (added)
384  {
385  added = false;
386 
387  // If a grid, maintain same number of columns on each row.
388  if (grow_right && col_cnt < m_columns)
389  {
390  if (wrapped)
391  end = first_item;
392  else
393  {
394  // Are we allowed to wrap when we run out of items?
395  if (m_wrapStyle == WrapItems &&
396  (hsplit || m_scrollStyle != ScrollFree) &&
397  last_item + 1 == m_itemCount)
398  {
399  last_item = -1;
400  wrapped = true;
401  end = first_item;
402  }
403  else
404  {
405  end = m_itemCount;
406  }
407  }
408 
409  if (last_item + 1 < end)
410  {
411  // Allocate next button to the right.
412  buttonstate = PrepareButton(last_button + 1, last_item + 1,
413  selectedIdx, button_shift);
414 
415  if (buttonstate == nullptr)
416  continue;
417 
418  width = minButtonWidth(buttonstate->GetArea());
419 
420  // For grids, use the widest button in a column
421  if (*col_widths && width < (*col_widths)[col_idx])
422  width = (*col_widths)[col_idx];
423 
424  // Does the button fit?
425  if ((hsplit ? right_width : left_width + right_width) +
426  m_itemHorizSpacing + width > max_width)
427  {
428  int total = hsplit ? right_width : left_width + right_width;
429  LOG(VB_GUI, LOG_DEBUG,
430  QString("button on right would exceed width: "
431  "%1+(%2)+%3 == %4 which is > %5")
432  .arg(total).arg(m_itemHorizSpacing).arg(width)
433  .arg(total + m_itemHorizSpacing + width)
434  .arg(max_width));
435  }
436  else
437  {
438  added = true;
439  ++col_cnt;
440  ++last_button;
441  ++last_item;
442  ++col_idx;
443  right_width += m_itemHorizSpacing + width;
444  int height = minButtonHeight(buttonstate->GetArea());
445 
446  row_height = std::max(row_height, height);
447 
448  LOG(VB_GUI, LOG_DEBUG,
449  QString("Added button item %1 "
450  "R.width %2 height %3 total width %4+%5"
451  " (max %6)")
452  .arg(last_item).arg(width).arg(height)
453  .arg(left_width).arg(right_width).arg(max_width));
454  }
455  }
456  else
457  {
458  underflow = true;
459  }
460  }
461 
462  // If a grid, maintain same number of columns on each row.
463  if (grow_left && col_cnt < m_columns)
464  {
465  if (wrapped)
466  end = last_item + 1;
467  else
468  {
469  // Are we allowed to wrap when we run out of items?
470  if (m_wrapStyle == WrapItems &&
471  (hsplit || m_scrollStyle != ScrollFree) &&
472  first_item == 0)
473  {
474  first_item = m_itemCount;
475  wrapped = true;
476  end = last_item + 1;
477  }
478  else
479  {
480  end = 0;
481  }
482  }
483 
484  if (first_item > end)
485  {
486  buttonstate = PrepareButton(first_button - 1, first_item - 1,
487  selectedIdx, button_shift);
488 
489  if (buttonstate == nullptr)
490  continue;
491 
492  width = minButtonWidth(buttonstate->GetArea());
493 
494  // For grids, use the widest button in a column
495  if (*col_widths && width < (*col_widths)[col_idx])
496  width = (*col_widths)[col_idx];
497 
498  // Does the button fit?
499  if ((hsplit ? left_width : left_width + right_width) +
500  m_itemHorizSpacing + width > max_width)
501  {
502  int total = hsplit ? left_width : left_width + right_width;
503  LOG(VB_GUI, LOG_DEBUG,
504  QString("button on left would exceed width: "
505  "%1+(%2)+%3 == %4 which is > %5")
506  .arg(total).arg(m_itemHorizSpacing).arg(width)
507  .arg(total + m_itemHorizSpacing + width)
508  .arg(max_width));
509  }
510  else
511  {
512  added = true;
513  --first_button;
514  --first_item;
515  --col_idx;
516  ++col_cnt;
517  left_width += m_itemHorizSpacing + width;
518  int height = minButtonHeight(buttonstate->GetArea());
519 
520  row_height = std::max(row_height, height);
521 
522  LOG(VB_GUI, LOG_DEBUG,
523  QString("Added button item %1 "
524  "L.width %2 height %3 total width %4+%5"
525  " (max %6)")
526  .arg(first_item).arg(width).arg(height)
527  .arg(left_width).arg(right_width).arg(max_width));
528  }
529  }
530  else
531  {
532  underflow = true;
533  if (m_layout == LayoutGrid)
534  skip_cols = m_columns - col_cnt;
535  }
536  }
537  }
538 
539  /*
540  * If total_height == 0, then this is the first row, so allow any height.
541  * Otherwise, If adding a button to a column would exceed the
542  * parent height, abort
543  */
544  if (total_height > 0 &&
545  ((vsplit ? split_height : total_height) +
546  m_itemVertSpacing + row_height > max_height))
547  {
548  LOG(VB_GUI, LOG_DEBUG,
549  QString("%1 Height exceeded %2 + (%3) + %4 = %5 which is > %6")
550  .arg(vsplit ? "Centering" : "Total")
551  .arg(split_height).arg(m_itemVertSpacing).arg(row_height)
552  .arg(split_height + m_itemVertSpacing + row_height)
553  .arg(max_height));
554  first_button = initial_first_button + button_shift;
555  last_button = initial_last_button + button_shift;
556  first_item = initial_first_item;
557  last_item = initial_last_item;
558  return false;
559  }
560 
561  if (*col_widths == nullptr)
562  {
563  /*
564  * Allocate array to hold columns widths, now that we know
565  * how many columns there are.
566  */
567  *col_widths = new int[static_cast<size_t>(col_cnt)];
568 
569  for (col_idx = 0; col_idx < col_cnt; ++col_idx)
570  (*col_widths)[col_idx] = 0;
571 
572  }
573 
574  // Adjust for insertions on the front.
575  first_button += button_shift;
576  last_button += button_shift;
577 
578  // It fits, so so note max column widths
579  MythUIStateType *realButton = nullptr;
580  int buttonIdx = 0;
581 
582  if (grow_left)
583  {
584  begin = first_button;
585  end = first_button + col_cnt;
586  }
587  else
588  {
589  end = last_button + 1;
590  begin = end - col_cnt;
591  }
592 
593  for (buttonIdx = begin, col_idx = 0;
594  buttonIdx < end; ++buttonIdx, ++col_idx)
595  {
596  realButton = m_buttonList[buttonIdx];
597  buttonstate = dynamic_cast<MythUIGroup *>
598  (realButton->GetCurrentState());
599  if (!buttonstate)
600  break;
601  width = minButtonWidth(buttonstate->GetArea());
602 
603  (*col_widths)[col_idx] = std::max((*col_widths)[col_idx], width);
604 
605  // Make note of which column has the selected button
606  if (selectedIdx == buttonIdx)
607  selected_column = col_idx;
608  }
609 
610  /*
611  An underflow indicates we ran out of items, not that the
612  buttons did not fit on the row.
613  */
614  if (total_height && underflow && col_cnt < m_columns)
615  col_cnt = m_columns;
616 
617  return true;
618 }
619 
620 /*
621  * Dynamically layout columns
622  */
623 bool MythUIButtonList::DistributeCols(int &first_button, int &last_button,
624  int &first_item, int &last_item,
625  int &selected_column, int &selected_row,
626  int &skip_cols, int **col_widths,
627  QList<int> & row_heights,
628  int &top_height, int &bottom_height,
629  bool &wrapped)
630 {
631  int col_cnt = 0;
632  int height = 0;
633  int end = 0;
634  bool added = false;
635 
636  do
637  {
638  added = false;
639 
640  if (wrapped)
641  end = first_item;
642  else
643  {
644  // Are we allowed to wrap when we run out of items?
645  if (m_wrapStyle == WrapItems &&
648  last_item + 1 == m_itemCount)
649  {
650  last_item = -1;
651  wrapped = true;
652  end = first_item;
653  }
654  else
655  {
656  end = m_itemCount;
657  }
658  }
659 
660  if (last_item + 1 < end)
661  {
662  // Does another row fit?
663  if (DistributeRow(first_button, ++last_button,
664  first_item, ++last_item, selected_column,
665  skip_cols, false, true, col_widths, height,
666  top_height + bottom_height, bottom_height,
667  col_cnt, wrapped))
668  {
669  if (col_cnt < m_columns)
670  return false; // Need to try again with fewer cols
671 
672  if (selected_row == -1 && selected_column != -1)
673  selected_row = row_heights.size();
674 
675  row_heights.push_back(height);
676  bottom_height += (height + m_itemVertSpacing);
677  added = true;
678  }
679  else
680  {
681  --last_button;
682  --last_item;
683  }
684  }
685 
686  if (wrapped)
687  end = last_item + 1;
688  else
689  {
690  // Are we allowed to wrap when we run out of items?
691  if (m_wrapStyle == WrapItems &&
694  first_item == 0)
695  {
696  first_item = m_itemCount;
697  wrapped = true;
698  end = last_item + 1;
699  }
700  else
701  {
702  end = 0;
703  }
704  }
705 
706  if (first_item > end)
707  {
708  // Can we insert another row?
709  if (DistributeRow(--first_button, last_button,
710  --first_item, last_item, selected_column,
711  skip_cols, true, false, col_widths, height,
712  top_height + bottom_height, top_height,
713  col_cnt, wrapped))
714  {
715  if (col_cnt < m_columns)
716  return false; // Need to try again with fewer cols
717 
718  if (selected_row == -1 && selected_column != -1)
719  selected_row = row_heights.size();
720  else if (selected_row != -1)
721  ++selected_row;
722 
723  row_heights.push_front(height);
724  top_height += (height + m_itemVertSpacing);
725  added = true;
726  }
727  else
728  {
729  ++first_button;
730  ++first_item;
731  }
732  }
733  }
734  while (added);
735 
736  return true;
737 }
738 
739 /*
740  * Dynamically layout as many buttons as will fit in the area.
741  */
743 {
744  int first_button = 0;
745  int last_button = 0;
746  int start_button = 0;
747  int start_item = m_selPosition;
748  int first_item = 0;
749  int last_item = 0;
750  int skip_cols = 0;
751  int *col_widths = nullptr;
752  int col_cnt = 0;
753  int selected_column = -1;
754  int selected_row = -1;
755  bool wrapped = false;
756  bool grow_left = true;
757  int height = 0;
758  int top_height = 0;
759  int bottom_height = 0;
760 
761  QList<int> row_heights;
762 
763  LOG(VB_GUI, LOG_DEBUG, QString("DistributeButtons: "
764  "selected item %1 total items %2")
765  .arg(start_item).arg(m_itemCount));
766 
767  // if there are no items to show make sure all the buttons are made invisible
768  if (m_itemCount == 0)
769  {
770  for (int i = 0; i < m_buttonList.count(); ++i)
771  {
772  if (m_buttonList[i])
773  m_buttonList[i]->SetVisible(false);
774  }
775 
776  return false;
777  }
778 
779  /*
780  * Try fewer and fewer columns until each row can fit the same
781  * number of columns.
782  */
783  for (m_columns = m_itemCount; m_columns > 0;)
784  {
785  first_item = last_item = start_item;
786 
787  /*
788  * Drawing starts at start_button, and radiates from there.
789  * Attempt to pick a start_button which will minimize the need for new
790  * button allocations.
791  */
792  switch (m_scrollStyle)
793  {
794  case ScrollCenter:
795  case ScrollGroupCenter:
796  start_button = std::max((m_maxVisible / 2) - 1, 0);
797  break;
798  case ScrollFree:
799 
800  if (m_layout == LayoutGrid)
801  {
802  start_button = 0;
803  first_item = last_item = 0;
804  grow_left = false;
805  }
806  else if (!m_buttonList.empty())
807  {
808  if (m_itemCount - m_selPosition - 1 <
809  (m_buttonList.size() / 2))
810  {
811  start_button = m_buttonList.size() -
812  (m_itemCount - m_selPosition) + 1;
813  }
814  else if (m_selPosition >
815  (m_buttonList.size() / 2))
816  {
817  start_button = (m_buttonList.size() / 2);
818  }
819  else
820  {
821  start_button = m_selPosition;
822  }
823  }
824  else
825  {
826  start_button = 0;
827  }
828 
829  break;
830  }
831 
832  first_button = last_button = start_button;
833  row_heights.clear();
834 
835  // Process row with selected button, and set starting val for m_columns.
836  if (!DistributeRow(first_button, last_button,
837  first_item, last_item, selected_column,
838  skip_cols, grow_left, true, &col_widths,
839  height, 0, 0, col_cnt, wrapped))
840  {
841  delete[] col_widths;
842  return false;
843  }
844 
845  m_columns = col_cnt;
846 
848  {
849  /*
850  * Now that we know how many columns there are, we can start
851  * the grid layout for real.
852  */
853  start_item = (m_selPosition / m_columns) * m_columns;
854  first_item = last_item = start_item;
855 
856  /*
857  * Attempt to pick a start_button which will minimize the need
858  * for new button allocations.
859  */
860 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
861  start_button = std::max(m_buttonList.size() / 2, 0);
862 #else
863  start_button = std::max(m_buttonList.size() / 2, 0LL);
864 #endif
865  start_button = (start_button / std::max(m_columns, 1)) * m_columns;
866 
867  if (start_button < m_itemCount / 2 &&
868  m_itemCount - m_selPosition - 1 < m_buttonList.size() / 2)
869  start_button += m_columns;
870 
871  first_button = last_button = start_button;
872 
873  // Now do initial row layout again with our new knowledge
874  selected_column = selected_row = -1;
875 
876  if (!DistributeRow(first_button, last_button,
877  first_item, last_item, selected_column,
878  skip_cols, grow_left, true, &col_widths,
879  height, 0, 0, col_cnt, wrapped))
880  {
881  delete[] col_widths;
882  return false;
883  }
884  }
885 
886  if (selected_column != -1)
887  selected_row = 0;
888 
889  row_heights.push_back(height);
890 
892  top_height = bottom_height = (height / 2);
893  else
894  bottom_height = height;
895 
896  if (m_layout == LayoutHorizontal)
897  break;
898 
899  // As as many columns as will fit.
900  if (DistributeCols(first_button, last_button,
901  first_item, last_item,
902  selected_column, selected_row,
903  skip_cols, &col_widths, row_heights,
904  top_height, bottom_height, wrapped))
905  break; // Buttons fit on each row, so done
906 
907  delete[] col_widths;
908  col_widths = nullptr;
909 
910  --m_columns;
911  start_item = m_selPosition;
912  }
913 
914  m_rows = row_heights.size();
915 
916  LOG(VB_GUI, LOG_DEBUG,
917  QString("%1 rows, %2 columns fit inside parent area %3x%4")
918  .arg(m_rows).arg(m_columns).arg(m_contentsRect.width())
919  .arg(m_contentsRect.height()));
920 
921  if (col_widths == nullptr)
922  return false;
923 
924  int total = 0;
925  int left_spacing = 0;
926  int right_spacing = 0;
927  int top_spacing = 0;
928  int bottom_spacing = 0;
929  MythRect min_rect;
930  QString status_msg;
931 
932  /*
933  * Calculate heights of buttons on each side of selected button
934  */
935  top_height = bottom_height = m_topRows = m_bottomRows = 0;
936 
937  status_msg = "Row heights: ";
938 
939  for (int row = 0; row < m_rows; ++row)
940  {
941  if (row != 0)
942  status_msg += ", ";
943 
944  if (row == selected_row)
945  {
946  status_msg += '[';
947  top_height += (row_heights[row] / 2);
948  bottom_height += ((row_heights[row] / 2) + (row_heights[row] % 2));
949  }
950  else
951  {
952  if (bottom_height)
953  {
954  bottom_height += m_itemVertSpacing + row_heights[row];
955  ++m_bottomRows;
956  }
957  else
958  {
959  top_height += row_heights[row] + m_itemVertSpacing;
960  ++m_topRows;
961  }
962  }
963 
964  status_msg += QString("%1").arg(row_heights[row]);
965 
966  if (row == selected_row)
967  status_msg += ']';
968  }
969 
970  /*
971  * How much extra space should there be between buttons?
972  */
974  {
975  // None
976  top_spacing = bottom_spacing = 0;
977  }
978  else
979  {
980  if (m_rows < 2)
981  {
982  // Equal space on both sides of single row
983  top_spacing = bottom_spacing =
984  (m_contentsRect.height() - top_height) / 2;
985  }
986  else
987  {
989  {
990  // Selected button needs to end up in the middle of area
991  top_spacing = m_topRows ? (m_contentsRect.height() / 2 -
992  top_height) / m_topRows : 0;
993  bottom_spacing = m_bottomRows ? (m_contentsRect.height() / 2 -
994  bottom_height) / m_bottomRows : 0;
995 
996  if (m_arrange == ArrangeSpread)
997  {
998  // Use same spacing on both sides of selected button
999  if (!m_topRows || top_spacing > bottom_spacing)
1000  top_spacing = bottom_spacing;
1001  else
1002  bottom_spacing = top_spacing;
1003  }
1004  }
1005  else
1006  {
1007  // Buttons will be evenly spread out to fill entire area
1008  top_spacing = bottom_spacing = (m_contentsRect.height() -
1009  (top_height + bottom_height)) /
1010  (m_topRows + m_bottomRows);
1011  }
1012  }
1013 
1014  // Add in intra-button space size
1015  top_height += (top_spacing * m_topRows);
1016  bottom_height += (bottom_spacing * m_bottomRows);
1017  }
1018 
1019  /*
1020  * Calculate top margin
1021  */
1022  int y = m_contentsRect.y();
1023 
1024  if ((m_alignment & Qt::AlignVCenter) && m_arrange != ArrangeFill)
1025  {
1026  if (m_scrollStyle == ScrollCenter)
1027  {
1028  // Adjust to compensate for top height less than bottom height
1029  y += std::max(bottom_height - top_height, 0);
1030  total = std::max(top_height, bottom_height) * 2;
1031  }
1032  else
1033  {
1034  total = top_height + bottom_height;
1035  }
1036 
1037  // Adjust top margin so selected button ends up in the middle
1038  y += (std::max(m_contentsRect.height() - total, 2) / 2);
1039  }
1040  else if ((m_alignment & Qt::AlignBottom) && m_arrange == ArrangeStack)
1041  {
1042  // Adjust top margin so buttons are bottom justified
1043  y += std::max(m_contentsRect.height() -
1044  (top_height + bottom_height), 0);
1045  }
1046  min_rect.setY(y);
1047 
1048  status_msg += QString(" spacing top %1 bottom %2 fixed %3 offset %4")
1049  .arg(top_spacing).arg(bottom_spacing)
1050  .arg(m_itemVertSpacing).arg(y);
1051 
1052  LOG(VB_GUI, LOG_DEBUG, status_msg);
1053 
1054  /*
1055  * Calculate width of buttons on each side of selected button
1056  */
1057  int left_width = 0;
1058  int right_width = 0;
1060 
1061  status_msg = "Col widths: ";
1062 
1063  for (int col = 0; col < m_columns; ++col)
1064  {
1065  if (col != 0)
1066  status_msg += ", ";
1067 
1068  if (col == selected_column)
1069  {
1070  status_msg += '[';
1071  left_width += (col_widths[col] / 2);
1072  right_width += ((col_widths[col] / 2) + (col_widths[col] % 2));
1073  }
1074  else
1075  {
1076  if (right_width)
1077  {
1078  right_width += m_itemHorizSpacing + col_widths[col];
1079  ++m_rightColumns;
1080  }
1081  else
1082  {
1083  left_width += col_widths[col] + m_itemHorizSpacing;
1084  ++m_leftColumns;
1085  }
1086  }
1087 
1088  status_msg += QString("%1").arg(col_widths[col]);
1089 
1090  if (col == selected_column)
1091  status_msg += ']';
1092  }
1093 
1094  /*
1095  * How much extra space should there be between buttons?
1096  */
1098  {
1099  // None
1100  left_spacing = right_spacing = 0;
1101  }
1102  else
1103  {
1104  if (m_columns < 2)
1105  {
1106  // Equal space on both sides of single column
1107  left_spacing = right_spacing =
1108  (m_contentsRect.width() - left_width) / 2;
1109  }
1110  else
1111  {
1112  if (m_scrollStyle == ScrollCenter)
1113  {
1114  // Selected button needs to end up in the middle
1115  left_spacing = m_leftColumns ? (m_contentsRect.width() / 2 -
1116  left_width) / m_leftColumns : 0;
1117  right_spacing = m_rightColumns ? (m_contentsRect.width() / 2 -
1118  right_width) / m_rightColumns : 0;
1119 
1120  if (m_arrange == ArrangeSpread)
1121  {
1122  // Use same spacing on both sides of selected button
1123  if (!m_leftColumns || left_spacing > right_spacing)
1124  left_spacing = right_spacing;
1125  else
1126  right_spacing = left_spacing;
1127  }
1128  }
1129  else
1130  {
1131  // Buttons will be evenly spread out to fill entire area
1132  left_spacing = right_spacing = (m_contentsRect.width() -
1133  (left_width + right_width)) /
1135  }
1136  }
1137 
1138  // Add in intra-button space size
1139  left_width += (left_spacing * m_leftColumns);
1140  right_width += (right_spacing * m_rightColumns);
1141  }
1142 
1143  /*
1144  * Calculate left margin
1145  */
1146  int x_init = m_contentsRect.x();
1147 
1148  if ((m_alignment & Qt::AlignHCenter) && m_arrange != ArrangeFill)
1149  {
1150  if (m_scrollStyle == ScrollCenter)
1151  {
1152  // Compensate for left being smaller than right
1153  x_init += std::max(right_width - left_width, 0);
1154  total = std::max(left_width, right_width) * 2;
1155  }
1156  else
1157  {
1158  total = left_width + right_width;
1159  }
1160 
1161  // Adjust left margin so selected button ends up in the middle
1162  x_init += (std::max(m_contentsRect.width() - total, 2) / 2);
1163  }
1164  else if ((m_alignment & Qt::AlignRight) && m_arrange == ArrangeStack)
1165  {
1166  // Adjust left margin, so buttons are right justified
1167  x_init += std::max(m_contentsRect.width() -
1168  (left_width + right_width), 0);
1169  }
1170  min_rect.setX(x_init);
1171 
1172  status_msg += QString(" spacing left %1 right %2 fixed %3 offset %4")
1173  .arg(left_spacing).arg(right_spacing)
1174  .arg(m_itemHorizSpacing).arg(x_init);
1175  LOG(VB_GUI, LOG_DEBUG, status_msg);
1176 
1177  top_spacing += m_itemVertSpacing;
1178  bottom_spacing += m_itemVertSpacing;
1179  left_spacing += m_itemHorizSpacing;
1180  right_spacing += m_itemHorizSpacing;
1181 
1182  // Calculate position of each button
1183  int buttonIdx = first_button - skip_cols;
1184  int x = 0;
1185  int x_adj = 0;
1186  int y_adj = 0;
1187 
1188  int vertical_spacing = top_spacing;
1189 
1190  for (int row = 0; row < m_rows; ++row)
1191  {
1192  x = x_init;
1193  int horizontal_spacing = left_spacing;
1194 
1195  for (int col = 0; col < m_columns && buttonIdx <= last_button; ++col)
1196  {
1197  if (buttonIdx >= first_button)
1198  {
1199  MythUIStateType *realButton = m_buttonList[buttonIdx];
1200  auto *buttonstate = dynamic_cast<MythUIGroup *>
1201  (realButton->GetCurrentState());
1202  if (!buttonstate)
1203  break; // Not continue
1204 
1205  MythRect area = buttonstate->GetArea();
1206 
1207  // Center button within width of column
1208  if (m_alignment & Qt::AlignHCenter)
1209  x_adj = (col_widths[col] - minButtonWidth(area)) / 2;
1210  else if (m_alignment & Qt::AlignRight)
1211  x_adj = (col_widths[col] - minButtonWidth(area));
1212  else
1213  x_adj = 0;
1214  if (m_layout == LayoutHorizontal)
1215  x_adj -= area.x(); // Negate button's own offset
1216 
1217  // Center button within height of row.
1218  if (m_alignment & Qt::AlignVCenter)
1219  y_adj = (row_heights[row] - minButtonHeight(area)) / 2;
1220  else if (m_alignment & Qt::AlignBottom)
1221  y_adj = (row_heights[row] - minButtonHeight(area));
1222  else
1223  y_adj = 0;
1224  if (m_layout == LayoutVertical)
1225  y_adj -= area.y(); // Negate button's own offset
1226 
1227  // Set position of button
1228  realButton->SetPosition(x + x_adj, y + y_adj);
1229  realButton->SetVisible(true);
1230 
1231  if (col == selected_column)
1232  {
1233  horizontal_spacing = right_spacing;
1234  if (row == selected_row)
1235  realButton->MoveToTop();
1236  }
1237  }
1238  x += col_widths[col] + horizontal_spacing;
1239  ++buttonIdx;
1240  }
1241 
1242  if (row == selected_row)
1243  vertical_spacing = bottom_spacing;
1244 
1245  y += row_heights[row] + vertical_spacing;
1246  }
1247  min_rect.setWidth(x - min_rect.x());
1248  min_rect.setHeight(y - min_rect.y());
1249 
1251 
1252  // Hide buttons before first active button
1253  for (buttonIdx = 0; buttonIdx < first_button; ++buttonIdx)
1254  m_buttonList[buttonIdx]->SetVisible(false);
1255 
1256  // Hide buttons after last active buttons.
1257  for (buttonIdx = m_maxVisible - 1; buttonIdx > last_button; --buttonIdx)
1258  m_buttonList[buttonIdx]->SetVisible(false);
1259 
1260  // Set m_topPosition so arrows are displayed correctly.
1262  m_topPosition = static_cast<int>(m_itemsVisible < m_itemCount);
1263  else
1264  m_topPosition = first_item;
1265 
1267  if (m_minSize.isValid())
1268  {
1269  // Record the minimal area needed for the button list
1270  SetMinArea(min_rect);
1271  }
1272 
1273  delete[] col_widths;
1274  return true;
1275 }
1276 
1278 {
1279  if (m_buttonList.empty())
1280  return;
1281 
1282  int button = 0;
1283 
1284  switch (m_scrollStyle)
1285  {
1286  case ScrollCenter:
1287  case ScrollGroupCenter:
1288  m_topPosition = std::max(m_selPosition -
1289  (int)((float)m_itemsVisible / 2), 0);
1290  break;
1291  case ScrollFree:
1292  {
1293  int adjust = 0;
1294 
1295  if (m_topPosition == -1 || m_keepSelAtBottom)
1296  {
1297  if (m_topPosition == -1)
1298  m_topPosition = 0;
1299 
1300  if (m_layout == LayoutHorizontal)
1301  adjust = 1 - m_itemsVisible;
1302  else
1303  adjust = m_columns - m_itemsVisible;
1304 
1305  m_keepSelAtBottom = false;
1306  }
1307 
1308  if (m_selPosition < m_topPosition ||
1310  {
1311  if (m_layout == LayoutHorizontal)
1312  m_topPosition = m_selPosition + adjust;
1313  else
1314  m_topPosition = (m_selPosition + adjust) /
1315  m_columns * m_columns;
1316  }
1317 
1318  // Adjusted if last item is deleted
1319  if (((m_itemList.count() - m_topPosition) < m_itemsVisible) &&
1321  m_columns == 1)
1323 
1324  m_topPosition = std::max(m_topPosition, 0);
1325  break;
1326  }
1327  }
1328 
1329  QList<MythUIButtonListItem *>::iterator it = m_itemList.begin() +
1330  m_topPosition;
1331 
1333  {
1334  if (m_selPosition <= m_itemsVisible / 2)
1335  {
1336  button = (m_itemsVisible / 2) - m_selPosition;
1337 
1338  if (m_wrapStyle == WrapItems && button > 0 &&
1340  {
1341  it = m_itemList.end() - button;
1342  button = 0;
1343  }
1344  }
1345  else if ((m_itemCount - m_selPosition) < (m_itemsVisible / 2))
1346  {
1347  it = m_itemList.begin() + m_selPosition - (m_itemsVisible / 2);
1348  }
1349  }
1351  {
1352  button = m_itemsVisible - m_itemCount;
1353  }
1354 
1355  for (int i = 0; i < button; ++i)
1356  m_buttonList[i]->SetVisible(false);
1357 
1358  bool seenSelected = false;
1359 
1360  MythUIStateType *realButton = nullptr;
1361  MythUIButtonListItem *buttonItem = nullptr;
1362 
1363  if (it < m_itemList.begin())
1364  it = m_itemList.begin();
1365 
1366  int curItem = it < m_itemList.end() ? GetItemPos(*it) : 0;
1367 
1368  while (it < m_itemList.end() && button < m_itemsVisible)
1369  {
1370  realButton = m_buttonList[button];
1371  buttonItem = *it;
1372 
1373  if (!realButton || !buttonItem)
1374  break;
1375 
1376  bool selected = false;
1377 
1378  if (!seenSelected && (curItem == m_selPosition))
1379  {
1380  seenSelected = true;
1381  selected = true;
1382  }
1383 
1384  m_buttonToItem[button] = buttonItem;
1385  buttonItem->SetToRealButton(realButton, selected);
1386  realButton->SetVisible(true);
1387 
1388  if (m_wrapStyle == WrapItems && it == (m_itemList.end() - 1) &&
1390  {
1391  it = m_itemList.begin();
1392  curItem = 0;
1393  }
1394  else
1395  {
1396  ++it;
1397  ++curItem;
1398  }
1399 
1400  ++button;
1401  }
1402 
1403  for (; button < m_itemsVisible; ++button)
1404  m_buttonList[button]->SetVisible(false);
1405 }
1406 
1408 {
1409  if (m_selPosition < 0)
1410  m_selPosition = (m_wrapStyle > WrapNone) ? m_itemList.size() - 1 : 0;
1411  else if (m_selPosition >= m_itemList.size())
1412  m_selPosition = (m_wrapStyle > WrapNone) ? 0 : m_itemList.size() - 1;
1413 }
1414 
1416 {
1417  if (!m_initialized)
1418  Init();
1419 
1420  if (!m_initialized)
1421  return;
1422 
1423  if (m_clearing)
1424  return;
1425 
1426  m_needsUpdate = false;
1427 
1428  // mark the visible buttons as invisible
1429  QMap<int, MythUIButtonListItem*>::const_iterator i = m_buttonToItem.constBegin();
1430  while (i != m_buttonToItem.constEnd())
1431  {
1432  if (i.value())
1433  i.value()->setVisible(false);
1434  ++i;
1435  }
1436 
1437  // set topitem, top position
1438  SanitizePosition();
1439  m_buttonToItem.clear();
1440 
1441  if (m_arrange == ArrangeFixed)
1443  else
1445 
1446  updateLCD();
1447 
1448  m_needsUpdate = false;
1449 
1450  if (!m_downArrow || !m_upArrow)
1451  return;
1452 
1453  if (m_itemCount == 0)
1454  {
1457  }
1458  else
1459  {
1460  if (m_topPosition != 0)
1462  else
1464 
1467  else
1469 
1470  m_upArrow->MoveToTop();
1472  }
1473 }
1474 
1476 {
1477  if (item)
1478  emit itemVisible(item);
1479 }
1480 
1482 {
1483  bool wasEmpty = m_itemList.isEmpty();
1484 
1485  if (listPosition >= 0 && listPosition <= m_itemList.count())
1486  {
1487  m_itemList.insert(listPosition, item);
1488 
1489  if (listPosition <= m_selPosition)
1490  ++m_selPosition;
1491 
1492  if (listPosition <= m_topPosition)
1493  ++m_topPosition;
1494  }
1495  else
1496  {
1497  m_itemList.append(item);
1498  }
1499 
1500  ++m_itemCount;
1501 
1502  if (wasEmpty)
1503  {
1505  emit itemSelected(item);
1506  emit DependChanged(false);
1507  }
1508 
1509  Update();
1510 }
1511 
1513 {
1514  if (m_clearing)
1515  return;
1516 
1517  int curIndex = m_itemList.indexOf(item);
1518 
1519  if (curIndex == -1)
1520  return;
1521 
1522  QMap<int, MythUIButtonListItem*>::iterator it = m_buttonToItem.begin();
1523  while (it != m_buttonToItem.end())
1524  {
1525  if (it.value() == item)
1526  {
1527  m_buttonToItem.erase(it);
1528  break;
1529  }
1530  ++it;
1531  }
1532 
1533  if (curIndex < m_topPosition &&
1534  m_topPosition > 0)
1535  {
1536  // The removed item is before the visible part, move
1537  // everything up 1. The visible part shouldn't appear to
1538  // change.
1539  --m_topPosition;
1540  --m_selPosition;
1541  }
1542  else if (curIndex < m_selPosition ||
1543  (m_selPosition == m_itemCount - 1 &&
1544  m_selPosition > 0))
1545  {
1546  // The removed item is visible and before the selected item or
1547  // the selected item is the last item but not the only item,
1548  // move the selected item up 1.
1549  --m_selPosition;
1550  }
1551 
1552  m_itemList.removeAt(curIndex);
1553  --m_itemCount;
1554 
1555  Update();
1556 
1557  if (m_selPosition < m_itemCount)
1559  else
1560  emit itemSelected(nullptr);
1561 
1562  if (IsEmpty())
1563  emit DependChanged(true);
1564 }
1565 
1566 void MythUIButtonList::SetValueByData(const QVariant& data)
1567 {
1568  if (!m_initialized)
1569  Init();
1570 
1571  for (auto *item : std::as_const(m_itemList))
1572  {
1573  if (item->GetData() == data)
1574  {
1575  SetItemCurrent(item);
1576  return;
1577  }
1578  }
1579 }
1580 
1582 {
1583  int newIndex = m_itemList.indexOf(item);
1584  SetItemCurrent(newIndex);
1585 }
1586 
1587 void MythUIButtonList::SetItemCurrent(int current, int topPosition)
1588 {
1589  if (!m_initialized)
1590  Init();
1591 
1592  if (current == -1 || current >= m_itemList.size())
1593  return;
1594 
1595  if (!m_itemList.at(current)->isEnabled())
1596  return;
1597 
1598  if (current == m_selPosition &&
1599  (topPosition == -1 || topPosition == m_topPosition))
1600  return;
1601 
1602  m_topPosition = topPosition;
1603 
1604  if (topPosition > 0 && m_layout == LayoutGrid)
1605  m_topPosition -= (topPosition % m_columns);
1606 
1608 
1609  Update();
1610 
1611  emit itemSelected(GetItemCurrent());
1612 }
1613 
1615 {
1616  if (m_itemList.isEmpty() || m_selPosition >= m_itemList.size() ||
1617  m_selPosition < 0)
1618  return nullptr;
1619 
1620  return m_itemList.at(m_selPosition);
1621 }
1622 
1624 {
1626 
1627  if (item)
1628  return item->GetText().toInt();
1629 
1630  return 0;
1631 }
1632 
1634 {
1636 
1637  if (item)
1638  return item->GetText();
1639 
1640  return {};
1641 }
1642 
1644 {
1646 
1647  if (item)
1648  return item->GetData();
1649 
1650  return {};
1651 }
1652 
1654 {
1655  if (m_contentsRect.isValid())
1656  return m_contentsRect;
1657  return m_area;
1658 }
1659 
1661 {
1662  if (!m_itemList.empty())
1663  return m_itemList[0];
1664 
1665  return nullptr;
1666 }
1667 
1669 const
1670 {
1671  QListIterator<MythUIButtonListItem *> it(m_itemList);
1672 
1673  if (!it.findNext(item))
1674  return nullptr;
1675 
1676  return it.previous();
1677 }
1678 
1680 {
1681  return m_itemCount;
1682 }
1683 
1685 {
1686  if (m_needsUpdate)
1687  {
1690  }
1691 
1692  return m_itemsVisible;
1693 }
1694 
1696 {
1697  return m_itemCount <= 0;
1698 }
1699 
1701 {
1702  if (pos < 0 || pos >= m_itemList.size())
1703  return nullptr;
1704 
1705  return m_itemList.at(pos);
1706 }
1707 
1709 {
1710  if (!m_initialized)
1711  Init();
1712 
1713  for (auto *item : std::as_const(m_itemList))
1714  {
1715  if (item->GetData() == data)
1716  return item;
1717  }
1718 
1719  return nullptr;
1720 }
1721 
1723 {
1724  if (!item)
1725  return -1;
1726 
1727  return m_itemList.indexOf(item);
1728 }
1729 
1730 void MythUIButtonList::InitButton(int itemIdx, MythUIStateType* & realButton,
1731  MythUIButtonListItem* & buttonItem)
1732 {
1733  buttonItem = m_itemList[itemIdx];
1734 
1735  if (m_maxVisible == 0)
1736  {
1737  QString name("buttonlist button 0");
1738  auto *button = new MythUIStateType(this, name);
1739  button->CopyFrom(m_buttontemplate);
1740  button->ConnectDependants(true);
1741  m_buttonList.append(button);
1742  ++m_maxVisible;
1743  }
1744 
1745  realButton = m_buttonList[0];
1746  m_buttonToItem[0] = buttonItem;
1747 }
1748 
1749 /*
1750  * PageUp and PageDown are helpers when Dynamic layout is being used.
1751  *
1752  * When buttons are layed out dynamically, the number of buttons on the next
1753  * page, may not equal the number of buttons on the current page. Dynamic
1754  * layout is always center-weighted, so attempt to figure out which button
1755  * is near the middle on the next page.
1756  */
1757 
1759 {
1760  int pos = m_selPosition;
1761  int total = 0;
1762 
1763  /*
1764  * /On the new page/
1765  * If the number of buttons before the selected button does not equal
1766  * the number of buttons after the selected button, this logic can
1767  * undershoot the new selected button. That is better than overshooting
1768  * though.
1769  *
1770  * To fix this would require laying out the new page and then figuring
1771  * out which button should be selected, but this is already complex enough.
1772  */
1773 
1774  if (m_layout == LayoutHorizontal)
1775  {
1776  pos -= (m_leftColumns + 1);
1777 
1778  int max_width = m_contentsRect.width() / 2;
1779 
1780  for (; pos >= 0; --pos)
1781  {
1782  MythUIStateType *realButton = nullptr;
1783  MythUIButtonListItem *buttonItem = nullptr;
1784  InitButton(pos, realButton, buttonItem);
1785  buttonItem->SetToRealButton(realButton, true);
1786  auto *buttonstate = dynamic_cast<MythUIGroup *>
1787  (realButton->GetCurrentState());
1788 
1789  if (buttonstate == nullptr)
1790  {
1791  LOG(VB_GENERAL, LOG_ERR,
1792  "PageUp: Failed to query buttonlist state");
1793  return pos;
1794  }
1795 
1796  if (total + m_itemHorizSpacing +
1797  buttonstate->GetArea().width() / 2 >= max_width)
1798  return pos + 1;
1799 
1800  buttonItem->SetToRealButton(realButton, false);
1801  buttonstate = dynamic_cast<MythUIGroup *>
1802  (realButton->GetCurrentState());
1803  if (buttonstate)
1804  total += m_itemHorizSpacing + buttonstate->GetArea().width();
1805  }
1806 
1807  return 0;
1808  }
1809 
1810  // Grid or Vertical
1811  int dec = 1;
1812 
1813  if (m_layout == LayoutGrid)
1814  {
1815  /*
1816  * Adjusting using bottomRow:TopRow only works if new page
1817  * has the same ratio as the previous page, but that is common
1818  * with the grid layout, so go for it. If themers start doing
1819  * grids where this is not true, then this will need to be modified.
1820  */
1821  pos -= (m_columns * (m_topRows + 2 +
1822  std::max(m_bottomRows - m_topRows, 0)));
1823  dec = m_columns;
1824  }
1825  else
1826  {
1827  pos -= (m_topRows + 1);
1828  dec = 1;
1829  }
1830 
1831  int max_height = m_contentsRect.height() / 2;
1832 
1833  for (; pos >= 0; pos -= dec)
1834  {
1835  MythUIStateType *realButton = nullptr;
1836  MythUIButtonListItem *buttonItem = nullptr;
1837  InitButton(pos, realButton, buttonItem);
1838  buttonItem->SetToRealButton(realButton, true);
1839  auto *buttonstate = dynamic_cast<MythUIGroup *>
1840  (realButton->GetCurrentState());
1841 
1842  if (buttonstate == nullptr)
1843  {
1844  LOG(VB_GENERAL, LOG_ERR,
1845  "PageUp: Failed to query buttonlist state");
1846  return pos;
1847  }
1848 
1849  if (total + m_itemHorizSpacing +
1850  buttonstate->GetArea().height() / 2 >= max_height)
1851  return pos + dec;
1852 
1853  buttonItem->SetToRealButton(realButton, false);
1854  buttonstate = dynamic_cast<MythUIGroup *>
1855  (realButton->GetCurrentState());
1856  if (buttonstate)
1857  total += m_itemHorizSpacing + buttonstate->GetArea().height();
1858  }
1859 
1860  return 0;
1861 }
1862 
1864 {
1865  int pos = m_selPosition;
1866  int num_items = m_itemList.size();
1867  int total = 0;
1868 
1869  /*
1870  * /On the new page/
1871  * If the number of buttons before the selected button does not equal
1872  * the number of buttons after the selected button, this logic can
1873  * undershoot the new selected button. That is better than overshooting
1874  * though.
1875  *
1876  * To fix this would require laying out the new page and then figuring
1877  * out which button should be selected, but this is already complex enough.
1878  */
1879 
1880  if (m_layout == LayoutHorizontal)
1881  {
1882  pos += (m_rightColumns + 1);
1883 
1884  int max_width = m_contentsRect.width() / 2;
1885 
1886  for (; pos < num_items; ++pos)
1887  {
1888  MythUIStateType *realButton = nullptr;
1889  MythUIButtonListItem *buttonItem = nullptr;
1890  InitButton(pos, realButton, buttonItem);
1891  buttonItem->SetToRealButton(realButton, true);
1892  auto *buttonstate = dynamic_cast<MythUIGroup *>
1893  (realButton->GetCurrentState());
1894 
1895  if (buttonstate == nullptr)
1896  {
1897  LOG(VB_GENERAL, LOG_ERR,
1898  "PageDown: Failed to query buttonlist state");
1899  return pos;
1900  }
1901 
1902  if (total + m_itemHorizSpacing +
1903  buttonstate->GetArea().width() / 2 >= max_width)
1904  return pos - 1;
1905 
1906  buttonItem->SetToRealButton(realButton, false);
1907  buttonstate = dynamic_cast<MythUIGroup *>
1908  (realButton->GetCurrentState());
1909  if (buttonstate)
1910  total += m_itemHorizSpacing + buttonstate->GetArea().width();
1911  }
1912 
1913  return num_items - 1;
1914  }
1915 
1916  // Grid or Vertical
1917  int inc = 1;
1918 
1919  if (m_layout == LayoutGrid)
1920  {
1921  /*
1922  * Adjusting using bottomRow:TopRow only works if new page
1923  * has the same ratio as the previous page, but that is common
1924  * with the grid layout, so go for it. If themers start doing
1925  * grids where this is not true, then this will need to be modified.
1926  */
1927  pos += (m_columns * (m_bottomRows + 2 +
1928  std::max(m_topRows - m_bottomRows, 0)));
1929  inc = m_columns;
1930  }
1931  else
1932  {
1933  pos += (m_bottomRows + 1);
1934  inc = 1;
1935  }
1936 
1937  int max_height = m_contentsRect.height() / 2;
1938 
1939  for (; pos < num_items; pos += inc)
1940  {
1941  MythUIStateType *realButton = nullptr;
1942  MythUIButtonListItem *buttonItem = nullptr;
1943  InitButton(pos, realButton, buttonItem);
1944  buttonItem->SetToRealButton(realButton, true);
1945  auto *buttonstate = dynamic_cast<MythUIGroup *>
1946  (realButton->GetCurrentState());
1947 
1948  if (!buttonstate)
1949  {
1950  LOG(VB_GENERAL, LOG_ERR,
1951  "PageDown: Failed to query buttonlist state");
1952  return pos;
1953  }
1954 
1955  if (total + m_itemHorizSpacing +
1956  buttonstate->GetArea().height() / 2 >= max_height)
1957  return pos - inc;
1958 
1959  buttonItem->SetToRealButton(realButton, false);
1960  buttonstate = dynamic_cast<MythUIGroup *>
1961  (realButton->GetCurrentState());
1962  if (buttonstate)
1963  total += m_itemHorizSpacing + buttonstate->GetArea().height();
1964  }
1965 
1966  return num_items - 1;
1967 }
1968 
1970 {
1971  int pos = m_selPosition;
1972 
1973  if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
1974  return false;
1975 
1976  switch (unit)
1977  {
1978  case MoveItem:
1979  if (m_selPosition > 0)
1980  --m_selPosition;
1981  else if (m_wrapStyle > WrapNone)
1982  m_selPosition = m_itemList.size() - 1;
1983  else if (m_wrapStyle == WrapCaptive)
1984  return true;
1985 
1986  FindEnabledUp(unit);
1987 
1988  break;
1989 
1990  case MoveColumn:
1991  if (pos % m_columns > 0)
1992  {
1993  --m_selPosition;
1994  }
1995  else if (m_wrapStyle == WrapFlowing)
1996  {
1997  if (m_selPosition == 0)
1998  --m_selPosition = m_itemList.size() - 1;
1999  else
2000  --m_selPosition;
2001  }
2002  else if (m_wrapStyle > WrapNone)
2003  {
2004  m_selPosition = pos + (m_columns - 1);
2005  }
2006  else if (m_wrapStyle == WrapCaptive)
2007  {
2008  return true;
2009  }
2010 
2011  FindEnabledUp(unit);
2012 
2013  break;
2014 
2015  case MoveRow:
2016  if (m_scrollStyle != ScrollFree)
2017  {
2019  if (m_selPosition < 0)
2020  m_selPosition += m_itemList.size();
2021  else
2022  m_selPosition %= m_itemList.size();
2023  }
2024  else if ((pos - m_columns) >= 0)
2025  {
2027  }
2028  else if (m_wrapStyle > WrapNone)
2029  {
2030  m_selPosition = ((m_itemList.size() - 1) / m_columns) *
2031  m_columns + pos;
2032 
2033  if ((m_selPosition / m_columns)
2034  < ((m_itemList.size() - 1) / m_columns))
2035  m_selPosition = m_itemList.size() - 1;
2036 
2037  if (m_layout == LayoutVertical)
2038  m_topPosition = std::max(0, m_selPosition - m_itemsVisible + 1);
2039  }
2040  else if (m_wrapStyle == WrapCaptive)
2041  {
2042  return true;
2043  }
2044 
2045  FindEnabledUp(unit);
2046 
2047  break;
2048 
2049  case MovePage:
2050  if (m_arrange == ArrangeFixed)
2051  m_selPosition = std::max(0, m_selPosition - m_itemsVisible);
2052  else
2053  m_selPosition = PageUp();
2054 
2055  FindEnabledUp(unit);
2056 
2057  break;
2058 
2059  case MoveMid:
2060  m_selPosition = m_itemList.size() / 2;
2061  FindEnabledUp(unit);
2062  break;
2063 
2064  case MoveMax:
2065  m_selPosition = 0;
2066  FindEnabledUp(unit);
2067  break;
2068 
2069  case MoveByAmount:
2070  for (uint i = 0; i < amount; ++i)
2071  {
2072  if (m_selPosition > 0)
2073  --m_selPosition;
2074  else if (m_wrapStyle > WrapNone)
2075  m_selPosition = m_itemList.size() - 1;
2076  }
2077 
2078  FindEnabledUp(unit);
2079 
2080  break;
2081  }
2082 
2083  SanitizePosition();
2084 
2085  if (pos != m_selPosition)
2086  {
2087  Update();
2088  emit itemSelected(GetItemCurrent());
2089  }
2090  else
2091  {
2092  return false;
2093  }
2094 
2095  return true;
2096 }
2097 
2098 
2103 {
2104  if (m_selPosition < 0 || m_selPosition >= m_itemList.size() ||
2105  m_itemList.at(m_selPosition)->isEnabled())
2106  return;
2107 
2108  int step = (unit == MoveRow) ? m_columns : 1;
2109  if (unit == MoveRow && m_wrapStyle == WrapFlowing)
2110  unit = MoveItem;
2111  if (unit == MoveColumn)
2112  {
2113  while (m_selPosition < m_itemList.size() &&
2114  (m_selPosition + 1) % m_columns > 0 &&
2115  !m_itemList.at(m_selPosition)->isEnabled())
2116  ++m_selPosition;
2117 
2118  if (m_itemList.at(m_selPosition)->isEnabled())
2119  return;
2120 
2121  if (m_wrapStyle > WrapNone)
2122  {
2124  while ((m_selPosition + 1) % m_columns > 0 &&
2125  !m_itemList.at(m_selPosition)->isEnabled())
2126  ++m_selPosition;
2127  }
2128  }
2129  else
2130  {
2131  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2132  (m_selPosition < m_itemList.size() - step))
2133  m_selPosition += step;
2134 
2135  if (!m_itemList.at(m_selPosition)->isEnabled() &&
2137  {
2138  m_selPosition = (m_selPosition + step) % m_itemList.size();
2139 
2140  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2141  (m_selPosition < m_itemList.size() - step))
2142  m_selPosition += step;
2143  }
2144  }
2145 }
2146 
2148 {
2149  if (m_selPosition < 0 || m_selPosition >= m_itemList.size() ||
2150  m_itemList.at(m_selPosition)->isEnabled())
2151  return;
2152 
2153  int step = (unit == MoveRow) ? m_columns : 1;
2154  if (unit == MoveRow && m_wrapStyle == WrapFlowing)
2155  unit = MoveItem;
2156  if (unit == MoveColumn)
2157  {
2158  while (m_selPosition > 0 && (m_selPosition - 1) % m_columns > 0 &&
2159  !m_itemList.at(m_selPosition)->isEnabled())
2160  --m_selPosition;
2161 
2162  if (m_itemList.at(m_selPosition)->isEnabled())
2163  return;
2164 
2165  if (m_wrapStyle > WrapNone)
2166  {
2168  while ((m_selPosition - 1) % m_columns > 0 &&
2169  !m_itemList.at(m_selPosition)->isEnabled())
2170  --m_selPosition;
2171  }
2172  }
2173  else
2174  {
2175  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2176  (m_selPosition - step >= 0))
2177  m_selPosition -= step;
2178 
2179  if (!m_itemList.at(m_selPosition)->isEnabled() &&
2181  {
2182  m_selPosition = m_itemList.size() - 1;
2183 
2184  while (m_selPosition > 0 &&
2185  !m_itemList.at(m_selPosition)->isEnabled() &&
2186  (m_selPosition - step >= 0))
2187  m_selPosition -= step;
2188  }
2189  }
2190 }
2191 
2192 
2194 {
2195  int pos = m_selPosition;
2196 
2197  if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
2198  return false;
2199 
2200  switch (unit)
2201  {
2202  case MoveItem:
2203  if (m_selPosition < m_itemList.size() - 1)
2204  ++m_selPosition;
2205  else if (m_wrapStyle > WrapNone)
2206  m_selPosition = 0;
2207  else if (m_wrapStyle == WrapCaptive)
2208  return true;
2209 
2210  FindEnabledDown(unit);
2211 
2212  break;
2213 
2214  case MoveColumn:
2215  if ((pos + 1) % m_columns > 0)
2216  {
2217  ++m_selPosition;
2218  }
2219  else if (m_wrapStyle == WrapFlowing)
2220  {
2221  if (m_selPosition < m_itemList.size() - 1)
2222  ++m_selPosition;
2223  else
2224  m_selPosition = 0;
2225  }
2226  else if (m_wrapStyle > WrapNone)
2227  {
2228  m_selPosition = pos - (m_columns - 1);
2229  }
2230  else if (m_wrapStyle == WrapCaptive)
2231  {
2232  return true;
2233  }
2234 
2235  FindEnabledDown(unit);
2236 
2237  break;
2238 
2239  case MoveRow:
2240  if (m_itemList.empty() || m_columns < 1)
2241  return true;
2242  if (m_scrollStyle != ScrollFree)
2243  {
2245  m_selPosition %= m_itemList.size();
2246  }
2247  else if (((m_itemList.size() - 1) / std::max(m_columns, 0))
2248  > (pos / m_columns))
2249  {
2251  if (m_selPosition >= m_itemList.size())
2252  m_selPosition = m_itemList.size() - 1;
2253  }
2254  else if (m_wrapStyle > WrapNone)
2255  {
2256  m_selPosition = (pos % m_columns);
2257  }
2258  else if (m_wrapStyle == WrapCaptive)
2259  {
2260  return true;
2261  }
2262 
2263  FindEnabledDown(unit);
2264 
2265  break;
2266 
2267  case MovePage:
2268  if (m_arrange == ArrangeFixed)
2269  {
2270  m_selPosition = std::min(m_itemCount - 1,
2272  }
2273  else
2274  {
2275  m_selPosition = PageDown();
2276  }
2277 
2278  FindEnabledDown(unit);
2279 
2280  break;
2281 
2282  case MoveMax:
2283  m_selPosition = m_itemCount - 1;
2284  FindEnabledDown(unit);
2285  break;
2286 
2287  case MoveByAmount:
2288  for (uint i = 0; i < amount; ++i)
2289  {
2290  if (m_selPosition < m_itemList.size() - 1)
2291  ++m_selPosition;
2292  else if (m_wrapStyle > WrapNone)
2293  m_selPosition = 0;
2294  }
2295  FindEnabledDown(unit);
2296  break;
2297 
2298  case MoveMid:
2299  break;
2300  }
2301 
2302  SanitizePosition();
2303 
2304  if (pos != m_selPosition)
2305  {
2306  m_keepSelAtBottom = true;
2307  Update();
2308  emit itemSelected(GetItemCurrent());
2309  }
2310  else
2311  {
2312  return false;
2313  }
2314 
2315  return true;
2316 }
2317 
2318 bool MythUIButtonList::MoveToNamedPosition(const QString &position_name)
2319 {
2320  if (!m_initialized)
2321  Init();
2322 
2323  if (m_selPosition < 0 || m_itemList.isEmpty() || !m_initialized)
2324  return false;
2325 
2326  bool found_it = false;
2327  int selectedPosition = 0;
2328  QList<MythUIButtonListItem *>::iterator it = m_itemList.begin();
2329 
2330  while (it != m_itemList.end())
2331  {
2332  if ((*it)->GetText() == position_name)
2333  {
2334  found_it = true;
2335  break;
2336  }
2337 
2338  ++it;
2339  ++selectedPosition;
2340  }
2341 
2342  if (!found_it || m_selPosition == selectedPosition)
2343  return false;
2344 
2345  SetItemCurrent(selectedPosition);
2346  return true;
2347 }
2348 
2350 {
2351  if (GetItemCurrent() != item)
2352  return false;
2353 
2354  if (item == m_itemList.first() && up)
2355  return false;
2356 
2357  if (item == m_itemList.last() && !up)
2358  return false;
2359 
2360  int oldpos = m_selPosition;
2361  int insertat = 0;
2362  bool dolast = false;
2363 
2364  if (up)
2365  {
2366  insertat = m_selPosition - 1;
2367 
2368  if (item == m_itemList.last())
2369  dolast = true;
2370  else
2371  ++m_selPosition;
2372 
2373  if (item == m_itemList.at(m_topPosition))
2374  ++m_topPosition;
2375  }
2376  else
2377  {
2378  insertat = m_selPosition + 1;
2379  }
2380 
2381  m_itemList.removeAt(oldpos);
2382  m_itemList.insert(insertat, item);
2383 
2384  if (up)
2385  {
2386  MoveUp();
2387 
2388  if (!dolast)
2389  MoveUp();
2390  }
2391  else
2392  {
2393  MoveDown();
2394  }
2395 
2396  return true;
2397 }
2398 
2400 {
2401  QMutableListIterator<MythUIButtonListItem *> it(m_itemList);
2402 
2403  while (it.hasNext())
2404  it.next()->setChecked(state);
2405 }
2406 
2408 {
2409  if (m_initialized)
2410  return;
2411 
2412  m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
2413  m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
2414  m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
2415 
2416  if (m_upArrow)
2417  m_upArrow->SetVisible(true);
2418 
2419  if (m_downArrow)
2420  m_downArrow->SetVisible(true);
2421 
2422  if (m_scrollBar)
2424 
2426 
2427  m_buttontemplate = dynamic_cast<MythUIStateType *>(GetChild("buttonitem"));
2428 
2429  if (!m_buttontemplate)
2430  {
2431  LOG(VB_GENERAL, LOG_ERR, QString("(%1) Statetype buttonitem is "
2432  "required in mythuibuttonlist: %2")
2433  .arg(GetXMLLocation(), objectName()));
2434  return;
2435  }
2436 
2437  m_buttontemplate->SetVisible(false);
2438 
2439  MythRect buttonItemArea;
2440 
2441  MythUIGroup *buttonActiveState = dynamic_cast<MythUIGroup *>
2442  (m_buttontemplate->GetState("active"));
2443 
2444  if (buttonActiveState)
2445  buttonItemArea = buttonActiveState->GetArea();
2446  else
2447  buttonItemArea = m_buttontemplate->GetArea();
2448 
2449  buttonItemArea.CalculateArea(m_contentsRect);
2450 
2451  m_itemHeight = buttonItemArea.height();
2452  m_itemWidth = buttonItemArea.width();
2453 
2454  /*
2455  * If fixed spacing is defined, then use the "active" state size
2456  * to predictively determine the position of each button.
2457  */
2458  if (m_arrange == ArrangeFixed)
2459  {
2460 
2462 
2463  int col = 1;
2464  int row = 1;
2465 
2466  for (int i = 0; i < m_itemsVisible; ++i)
2467  {
2468  QString name = QString("buttonlist button %1").arg(i);
2469  auto *button = new MythUIStateType(this, name);
2470  button->CopyFrom(m_buttontemplate);
2471  button->ConnectDependants(true);
2472 
2473  if (col > m_columns)
2474  {
2475  col = 1;
2476  ++row;
2477  }
2478 
2479  button->SetPosition(GetButtonPosition(col, row));
2480  ++col;
2481 
2482  m_buttonList.push_back(button);
2483  }
2484  }
2485 
2486  // The following is pretty much a hack for the benefit of MythGallery
2487  // it scales images based on the button size and we need to give it the
2488  // largest button state so that the images are not too small
2489  // This can be removed once the disk based image caching is added to
2490  // mythui, since the mythgallery thumbnail generator can be ditched.
2491  MythUIGroup *buttonSelectedState = dynamic_cast<MythUIGroup *>
2492  (m_buttontemplate->GetState("selected"));
2493 
2494  if (buttonSelectedState)
2495  {
2496  MythRect itemArea = buttonSelectedState->GetArea();
2497  itemArea.CalculateArea(m_contentsRect);
2498 
2499  m_itemHeight = std::max(m_itemHeight, itemArea.height());
2500 
2501  m_itemWidth = std::max(m_itemWidth, itemArea.width());
2502  }
2503 
2504  // End Hack
2505 
2506  m_initialized = true;
2507 }
2508 
2510 {
2511  if (!m_initialized)
2512  Init();
2513 
2514  return static_cast<uint>(m_itemWidth);
2515 }
2516 
2518 {
2519  if (!m_initialized)
2520  Init();
2521 
2522  return static_cast<uint>(m_itemHeight);
2523 }
2524 
2528 bool MythUIButtonList::keyPressEvent(QKeyEvent *event)
2529 {
2530  QStringList actions;
2531  bool handled = false;
2532  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
2533 
2534  // Handle action remappings
2535  for (const QString& action : std::as_const(actions))
2536  {
2537  if (!m_actionRemap.contains(action))
2538  continue;
2539 
2540  QString key = m_actionRemap[action];
2541  if (key.isEmpty())
2542  return true;
2543 
2544  QKeySequence a(key);
2545  if (a.isEmpty())
2546  continue;
2547 
2548 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2549  int keyCode = a[0];
2550  Qt::KeyboardModifiers modifiers = Qt::NoModifier;
2551  QStringList parts = key.split('+');
2552  for (int j = 0; j < parts.count(); ++j)
2553  {
2554  if (parts[j].toUpper() == "CTRL")
2555  modifiers |= Qt::ControlModifier;
2556  if (parts[j].toUpper() == "SHIFT")
2557  modifiers |= Qt::ShiftModifier;
2558  if (parts[j].toUpper() == "ALT")
2559  modifiers |= Qt::AltModifier;
2560  if (parts[j].toUpper() == "META")
2561  modifiers |= Qt::MetaModifier;
2562  }
2563 #else
2564  int keyCode = a[0].key();
2565  Qt::KeyboardModifiers modifiers = a[0].keyboardModifiers();
2566 #endif
2567 
2568  QCoreApplication::postEvent(
2570  new QKeyEvent(QEvent::KeyPress, keyCode, modifiers, key));
2571  QCoreApplication::postEvent(
2573  new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers, key));
2574 
2575  return true;
2576  }
2577 
2578  // handle actions for this container
2579  for (int i = 0; i < actions.size() && !handled; ++i)
2580  {
2581  const QString& action = actions[i];
2582  handled = true;
2583 
2584  if (action == "UP")
2585  {
2586  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2587  handled = MoveUp(MoveRow);
2588  else
2589  handled = false;
2590  }
2591  else if (action == "DOWN")
2592  {
2593  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2594  handled = MoveDown(MoveRow);
2595  else
2596  handled = false;
2597  }
2598  else if (action == "RIGHT")
2599  {
2600  if (m_layout == LayoutHorizontal)
2601  handled = MoveDown(MoveItem);
2602  else if (m_layout == LayoutGrid)
2603  {
2604  if (m_scrollStyle == ScrollFree)
2605  handled = MoveDown(MoveColumn);
2606  else
2607  handled = MoveDown(MoveItem);
2608  }
2609  else
2610  {
2611  handled = false;
2612  }
2613  }
2614  else if (action == "LEFT")
2615  {
2616  if (m_layout == LayoutHorizontal)
2617  handled = MoveUp(MoveItem);
2618  else if (m_layout == LayoutGrid)
2619  {
2620  if (m_scrollStyle == ScrollFree)
2621  handled = MoveUp(MoveColumn);
2622  else
2623  handled = MoveUp(MoveItem);
2624  }
2625  else
2626  {
2627  handled = false;
2628  }
2629  }
2630  else if (action == "PAGEUP")
2631  {
2632  MoveUp(MovePage);
2633  }
2634  else if (action == "PAGEDOWN")
2635  {
2636  MoveDown(MovePage);
2637  }
2638  else if (action == "PAGETOP")
2639  {
2640  MoveUp(MoveMax);
2641  }
2642  else if (action == "PAGEMIDDLE")
2643  {
2644  MoveUp(MoveMid);
2645  }
2646  else if (action == "PAGEBOTTOM")
2647  {
2648  MoveDown(MoveMax);
2649  }
2650  else if (action == "SELECT")
2651  {
2653 
2654  if (item && item->isEnabled())
2655  emit itemClicked(item);
2656  }
2657  else if (action == "SEARCH")
2658  {
2659  ShowSearchDialog();
2660  }
2661  else
2662  {
2663  handled = false;
2664  }
2665  }
2666 
2667  return handled;
2668 }
2669 
2674 {
2675  bool handled = false;
2676 
2677  switch (event->GetGesture())
2678  {
2680  {
2681  // We want the relative position of the click
2682  QPoint position = event->GetPosition() -
2683  m_parent->GetArea().topLeft();
2684 
2685  MythUIType *type = GetChildAt(position, false, false);
2686 
2687  if (!type)
2688  return false;
2689 
2690  auto *object = dynamic_cast<MythUIStateType *>(type);
2691  if (object)
2692  {
2693  handled = true;
2694  QString name = object->objectName();
2695 
2696  if (name == "upscrollarrow")
2697  {
2698  MoveUp(MovePage);
2699  }
2700  else if (name == "downscrollarrow")
2701  {
2702  MoveDown(MovePage);
2703  }
2704  else if (name.startsWith("buttonlist button"))
2705  {
2706  int pos = name.section(' ', 2, 2).toInt();
2707  MythUIButtonListItem *item = m_buttonToItem.value(pos);
2708 
2709  if (item)
2710  {
2711  if (item == GetItemCurrent())
2712  emit itemClicked(item);
2713  else
2714  SetItemCurrent(item);
2715  }
2716  }
2717  else
2718  {
2719  handled = false;
2720  }
2721  }
2722  }
2723  break;
2724 
2725  case MythGestureEvent::Up:
2728  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2729  handled = MoveUp(MoveRow);
2730  break;
2731 
2735  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2736  handled = MoveDown(MoveRow);
2737  break;
2738 
2740  if (m_layout == LayoutHorizontal)
2741  handled = MoveDown(MoveItem);
2742  else if (m_layout == LayoutGrid)
2743  {
2744  if (m_scrollStyle == ScrollFree)
2745  handled = MoveDown(MoveColumn);
2746  else
2747  handled = MoveDown(MoveItem);
2748  }
2749  break;
2750 
2752  if (m_layout == LayoutHorizontal)
2753  handled = MoveUp(MoveItem);
2754  else if (m_layout == LayoutGrid)
2755  {
2756  if (m_scrollStyle == ScrollFree)
2757  handled = MoveUp(MoveColumn);
2758  else
2759  handled = MoveUp(MoveItem);
2760  }
2761  break;
2762 
2763  default:
2764  break;
2765  }
2766 
2767  return handled;
2768 }
2769 
2770 class NextButtonListPageEvent : public QEvent
2771 {
2772  public:
2773  NextButtonListPageEvent(int start, int pageSize) :
2774  QEvent(kEventType), m_start(start), m_pageSize(pageSize) {}
2775  const int m_start;
2776  const int m_pageSize;
2777  static const Type kEventType;
2778 };
2779 
2780 const QEvent::Type NextButtonListPageEvent::kEventType =
2781  (QEvent::Type) QEvent::registerEventType();
2782 
2784 {
2785  if (event->type() == NextButtonListPageEvent::kEventType)
2786  {
2787  if (auto *npe = dynamic_cast<NextButtonListPageEvent*>(event); npe)
2788  {
2789  int cur = npe->m_start;
2790  for (; cur < npe->m_start + npe->m_pageSize && cur < GetCount(); ++cur)
2791  {
2792  const int loginterval = (cur < 1000 ? 100 : 500);
2793  if (cur > 200 && cur % loginterval == 0)
2794  LOG(VB_GUI, LOG_INFO,
2795  QString("Build background buttonlist item %1").arg(cur));
2796  emit itemLoaded(GetItemAt(cur));
2797  }
2798  m_nextItemLoaded = cur;
2799  if (cur < GetCount())
2800  LoadInBackground(cur, npe->m_pageSize);
2801  }
2802  }
2803 }
2804 
2805 void MythUIButtonList::LoadInBackground(int start, int pageSize)
2806 {
2807  m_nextItemLoaded = start;
2808  QCoreApplication::
2809  postEvent(this, new NextButtonListPageEvent(start, pageSize));
2810 }
2811 
2813 {
2814  QCoreApplication::
2815  removePostedEvents(this, NextButtonListPageEvent::kEventType);
2816  return m_nextItemLoaded;
2817 }
2818 
2819 QPoint MythUIButtonList::GetButtonPosition(int column, int row) const
2820 {
2821  int x = m_contentsRect.x() +
2822  ((column - 1) * (m_itemWidth + m_itemHorizSpacing));
2823  int y = m_contentsRect.y() +
2824  ((row - 1) * (m_itemHeight + m_itemVertSpacing));
2825 
2826  return {x, y};
2827 }
2828 
2830 {
2831  m_itemsVisible = 0;
2832  m_rows = 0;
2833  m_columns = 0;
2834 
2835  if ((m_layout == LayoutHorizontal) || (m_layout == LayoutGrid))
2836  {
2837  int x = 0;
2838 
2839  while (x <= m_contentsRect.width() - m_itemWidth)
2840  {
2842  ++m_columns;
2843  }
2844  }
2845 
2846  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2847  {
2848  int y = 0;
2849 
2850  while (y <= m_contentsRect.height() - m_itemHeight)
2851  {
2853  ++m_rows;
2854  }
2855  }
2856 
2857  if (m_rows <= 0)
2858  m_rows = 1;
2859 
2860  if (m_columns <= 0)
2861  m_columns = 1;
2862 
2864 }
2865 
2867 {
2868  if (rect == m_contentsRect)
2869  return;
2870 
2871  m_contentsRect = rect;
2872 
2873  if (m_area.isValid())
2875  else if (m_parent)
2877  else
2878  m_contentsRect.CalculateArea(GetMythMainWindow()->GetUIScreenRect());
2879 }
2880 
2885  const QString &filename, QDomElement &element, bool showWarnings)
2886 {
2887  if (element.tagName() == "buttonarea")
2888  SetButtonArea(parseRect(element));
2889  else if (element.tagName() == "layout")
2890  {
2891  QString layout = getFirstText(element).toLower();
2892 
2893  if (layout == "grid")
2894  m_layout = LayoutGrid;
2895  else if (layout == "horizontal")
2897  else
2899  }
2900  else if (element.tagName() == "arrange")
2901  {
2902  QString arrange = getFirstText(element).toLower();
2903 
2904  if (arrange == "fill")
2906  else if (arrange == "spread")
2908  else if (arrange == "stack")
2910  else
2912 
2913  }
2914  else if (element.tagName() == "align")
2915  {
2916  QString align = getFirstText(element).toLower();
2917  m_alignment = parseAlignment(align);
2918  }
2919  else if (element.tagName() == "scrollstyle")
2920  {
2921  QString layout = getFirstText(element).toLower();
2922 
2923  if (layout == "center")
2925  else if (layout == "groupcenter")
2927  else if (layout == "free")
2929  }
2930  else if (element.tagName() == "wrapstyle")
2931  {
2932  QString wrapstyle = getFirstText(element).toLower();
2933 
2934  if (wrapstyle == "captive")
2936  else if (wrapstyle == "none")
2938  else if (wrapstyle == "selection")
2940  else if (wrapstyle == "flowing")
2942  else if (wrapstyle == "items")
2944  }
2945  else if (element.tagName() == "showarrow")
2946  {
2947  m_showArrow = parseBool(element);
2948  }
2949  else if (element.tagName() == "showscrollbar")
2950  {
2951  m_showScrollBar = parseBool(element);
2952  }
2953  else if (element.tagName() == "spacing")
2954  {
2955  m_itemHorizSpacing = NormX(getFirstText(element).toInt());
2956  m_itemVertSpacing = NormY(getFirstText(element).toInt());
2957  }
2958  else if (element.tagName() == "drawfrombottom")
2959  {
2960  m_drawFromBottom = parseBool(element);
2961 
2962  if (m_drawFromBottom)
2963  m_alignment |= Qt::AlignBottom;
2964  }
2965  else if (element.tagName() == "searchposition")
2966  {
2967  m_searchPosition = parsePoint(element);
2968  }
2969  else if (element.tagName() == "triggerevent")
2970  {
2971  QString trigger = getFirstText(element);
2972  if (!trigger.isEmpty())
2973  {
2974  QString action = element.attribute("action", "");
2975  if (action.isEmpty())
2976  {
2977  m_actionRemap[trigger] = "";
2978  }
2979  else
2980  {
2981  QString context = element.attribute("context", "");
2982  QString keylist = MythMainWindow::GetKey(context, action);
2983  QStringList keys = keylist.split(',', Qt::SkipEmptyParts);
2984  if (!keys.empty())
2985  m_actionRemap[trigger] = keys[0];
2986  }
2987  }
2988  }
2989  else
2990  {
2991  return MythUIType::ParseElement(filename, element, showWarnings);
2992  }
2993 
2994  return true;
2995 }
2996 
3000 void MythUIButtonList::DrawSelf(MythPainter * /*p*/, int /*xoffset*/, int /*yoffset*/,
3001  int /*alphaMod*/, QRect /*clipRect*/)
3002 {
3003  if (m_needsUpdate)
3004  {
3007  }
3008 }
3009 
3014 {
3015  auto *lb = new MythUIButtonList(parent, objectName());
3016  lb->CopyFrom(this);
3017 }
3018 
3023 {
3024  auto *lb = dynamic_cast<MythUIButtonList *>(base);
3025  if (!lb)
3026  return;
3027 
3028  m_layout = lb->m_layout;
3029  m_arrange = lb->m_arrange;
3030  m_alignment = lb->m_alignment;
3031 
3032  m_contentsRect = lb->m_contentsRect;
3033 
3034  m_itemHeight = lb->m_itemHeight;
3035  m_itemWidth = lb->m_itemWidth;
3036  m_itemHorizSpacing = lb->m_itemHorizSpacing;
3037  m_itemVertSpacing = lb->m_itemVertSpacing;
3038  m_itemsVisible = lb->m_itemsVisible;
3039  m_maxVisible = lb->m_maxVisible;
3040 
3041  m_active = lb->m_active;
3042  m_showArrow = lb->m_showArrow;
3043  m_showScrollBar = lb->m_showScrollBar;
3044 
3045  m_drawFromBottom = lb->m_drawFromBottom;
3046 
3047  m_scrollStyle = lb->m_scrollStyle;
3048  m_wrapStyle = lb->m_wrapStyle;
3049 
3050  m_clearing = false;
3052 
3053  m_searchPosition = lb->m_searchPosition;
3054  m_searchFields = lb->m_searchFields;
3055 
3056  MythUIType::CopyFrom(base);
3057 
3058  m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
3059  m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
3060  m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
3061 
3062  for (int i = 0; i < m_itemsVisible; ++i)
3063  {
3064  QString name = QString("buttonlist button %1").arg(i);
3065  DeleteChild(name);
3066  }
3067 
3068  m_buttonList.clear();
3069 
3070  m_actionRemap = lb->m_actionRemap;
3071 
3072  m_initialized = false;
3073 }
3074 
3079 {
3081 }
3082 
3083 void MythUIButtonList::SetLCDTitles(const QString &title, const QString &columnList)
3084 {
3085  m_lcdTitle = title;
3086  m_lcdColumns = columnList.split('|');
3087 }
3088 
3090 {
3091  if (!m_hasFocus)
3092  return;
3093 
3094  LCD *lcddev = LCD::Get();
3095 
3096  if (lcddev == nullptr)
3097  return;
3098 
3099  // Build a list of the menu items
3100  QList<LCDMenuItem> menuItems;
3101 
3102  auto start = std::max(0, m_selPosition - lcddev->getLCDHeight());
3103  auto end = std::min(m_itemCount, start + (lcddev->getLCDHeight() * 2));
3104 
3105  for (int r = start; r < end; ++r)
3106  {
3107  bool selected = r == GetCurrentPos();
3108 
3109  MythUIButtonListItem *item = GetItemAt(r);
3110  CHECKED_STATE state = NOTCHECKABLE;
3111 
3112  if (item->checkable())
3113  state = (item->state() == MythUIButtonListItem::NotChecked) ? UNCHECKED : CHECKED;
3114 
3115  QString text;
3116 
3117  for (int x = 0; x < m_lcdColumns.count(); ++x)
3118  {
3119  if (!m_lcdColumns[x].isEmpty() && item->m_strings.contains(m_lcdColumns[x]))
3120  {
3121  // named text column
3122  TextProperties props = item->m_strings[m_lcdColumns[x]];
3123 
3124  if (text.isEmpty())
3125  text = props.text;
3126  else
3127  text += " ~ " + props.text;
3128  }
3129  else
3130  {
3131  // default text column
3132  if (text.isEmpty())
3133  text = item->GetText();
3134  else
3135  text += " ~ " + item->GetText();
3136  }
3137  }
3138 
3139  if (!text.isEmpty())
3140  menuItems.append(LCDMenuItem(selected, state, text));
3141  else
3142  menuItems.append(LCDMenuItem(selected, state, item->GetText()));
3143  }
3144 
3145  if (!menuItems.isEmpty())
3146  lcddev->switchToMenu(menuItems, m_lcdTitle);
3147 }
3148 
3150 {
3151  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
3152 
3153  auto *dlg = new SearchButtonListDialog(popupStack, "MythSearchListDialog", this, "");
3154 
3155  if (dlg->Create())
3156  {
3157  if (m_searchPosition.x() != -2 || m_searchPosition.y() != -2)
3158  {
3159  int x = m_searchPosition.x();
3160  int y = m_searchPosition.y();
3161  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
3162  QRect dialogArea = dlg->GetArea();
3163 
3164  if (x == -1)
3165  x = (screenArea.width() - dialogArea.width()) / 2;
3166 
3167  if (y == -1)
3168  y = (screenArea.height() - dialogArea.height()) / 2;
3169 
3170  dlg->SetPosition(x, y);
3171  }
3172 
3173  popupStack->AddScreen(dlg);
3174  }
3175  else
3176  {
3177  delete dlg;
3178  }
3179 }
3180 
3181 bool MythUIButtonList::Find(const QString &searchStr, bool startsWith)
3182 {
3183  m_searchStr = searchStr;
3184  m_searchStartsWith = startsWith;
3185  return DoFind(false, true);
3186 }
3187 
3189 {
3190  return DoFind(true, true);
3191 }
3192 
3194 {
3195  return DoFind(true, false);
3196 }
3197 
3198 bool MythUIButtonList::DoFind(bool doMove, bool searchForward)
3199 {
3200  if (m_searchStr.isEmpty())
3201  return true;
3202 
3203  if (GetCount() == 0)
3204  return false;
3205 
3206  int startPos = GetCurrentPos();
3207  int currPos = startPos;
3208  bool found = false;
3209 
3210  if (doMove)
3211  {
3212  if (searchForward)
3213  {
3214  ++currPos;
3215 
3216  if (currPos >= GetCount())
3217  currPos = 0;
3218  }
3219  else
3220  {
3221  --currPos;
3222 
3223  if (currPos < 0)
3224  currPos = GetCount() - 1;
3225  }
3226  }
3227 
3228  while (true)
3229  {
3231 
3232  if (found)
3233  {
3234  SetItemCurrent(currPos);
3235  return true;
3236  }
3237 
3238  if (searchForward)
3239  {
3240  ++currPos;
3241 
3242  if (currPos >= GetCount())
3243  currPos = 0;
3244  }
3245  else
3246  {
3247  --currPos;
3248 
3249  if (currPos < 0)
3250  currPos = GetCount() - 1;
3251  }
3252 
3253  if (startPos == currPos)
3254  break;
3255  }
3256 
3257  return false;
3258 }
3259 
3261 
3263  QString text, QString image,
3264  bool checkable, CheckState state,
3265  bool showArrow, int listPosition)
3266  : m_parent(lbtype), m_text(std::move(text)), m_imageFilename(std::move(image)),
3267  m_checkable(checkable), m_state(state), m_showArrow(showArrow)
3268 {
3269  if (!lbtype)
3270  LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
3271 
3272  if (state >= NotChecked)
3273  m_checkable = true;
3274 
3275  if (m_parent)
3276  m_parent->InsertItem(this, listPosition);
3277 }
3278 
3280  const QString &text,
3281  QVariant data, int listPosition)
3282 {
3283  if (!lbtype)
3284  LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
3285 
3286  m_parent = lbtype;
3287  m_text = text;
3288  m_data = std::move(data);
3289 
3290  m_image = nullptr;
3291 
3292  m_checkable = false;
3293  m_state = CantCheck;
3294  m_showArrow = false;
3295  m_isVisible = false;
3296  m_enabled = true;
3297 
3298  if (m_parent)
3299  m_parent->InsertItem(this, listPosition);
3300 }
3301 
3303 {
3304  if (m_parent)
3305  m_parent->RemoveItem(this);
3306 
3307  if (m_image)
3308  m_image->DecrRef();
3309 
3310  QMap<QString, MythImage*>::iterator it;
3311  for (it = m_images.begin(); it != m_images.end(); ++it)
3312  {
3313  if (*it)
3314  (*it)->DecrRef();
3315  }
3316  m_images.clear();
3317 }
3318 
3319 void MythUIButtonListItem::SetText(const QString &text, const QString &name,
3320  const QString &state)
3321 {
3322  if (!name.isEmpty())
3323  {
3324  TextProperties textprop;
3325  textprop.text = text;
3326  textprop.state = state;
3327  m_strings.insert(name, textprop);
3328  }
3329  else
3330  {
3331  m_text = text;
3332  }
3333 
3334  if (m_parent && m_isVisible)
3335  m_parent->Update();
3336 }
3337 
3339  const QString &state)
3340 {
3341  InfoMap::const_iterator map_it = infoMap.begin();
3342 
3343  while (map_it != infoMap.end())
3344  {
3345  TextProperties textprop;
3346  textprop.text = (*map_it);
3347  textprop.state = state;
3348  m_strings[map_it.key()] = textprop;
3349  ++map_it;
3350  }
3351 
3352  if (m_parent && m_isVisible)
3353  m_parent->Update();
3354 }
3355 
3356 void MythUIButtonListItem::SetTextFromMap(const QMap<QString, TextProperties> &stringMap)
3357 {
3358  m_strings.clear();
3359  m_strings = stringMap;
3360 }
3361 
3363 {
3364  m_textCb.fn = fn;
3365  m_textCb.data = data;
3366 }
3367 
3368 QString MythUIButtonListItem::GetText(const QString &name) const
3369 {
3370  if (name.isEmpty())
3371  return m_text;
3372  if (m_textCb.fn != nullptr)
3373  {
3374  QString result = m_textCb.fn(name, m_textCb.data);
3375  if (!result.isEmpty())
3376  return result;
3377  }
3378  if (m_strings.contains(name))
3379  return m_strings[name].text;
3380  return {};
3381 }
3382 
3384 {
3385  if (name.isEmpty())
3386  return {m_text, ""};
3387  if (m_textCb.fn != nullptr)
3388  {
3389  QString result = m_textCb.fn(name, m_textCb.data);
3390  if (!result.isEmpty())
3391  return {result, ""};
3392  }
3393  if (m_strings.contains(name))
3394  return m_strings[name];
3395  return {};
3396 }
3397 
3398 bool MythUIButtonListItem::FindText(const QString &searchStr, const QString &fieldList,
3399  bool startsWith) const
3400 {
3401  if (fieldList.isEmpty())
3402  {
3403  if (startsWith)
3404  return m_text.startsWith(searchStr, Qt::CaseInsensitive);
3405  return m_text.contains(searchStr, Qt::CaseInsensitive);
3406  }
3407  if (fieldList == "**ALL**")
3408  {
3409  if (startsWith)
3410  {
3411  if (m_text.startsWith(searchStr, Qt::CaseInsensitive))
3412  return true;
3413  }
3414  else
3415  {
3416  if (m_text.contains(searchStr, Qt::CaseInsensitive))
3417  return true;
3418  }
3419 
3420  QMap<QString, TextProperties>::const_iterator i = m_strings.constBegin();
3421 
3422  while (i != m_strings.constEnd())
3423  {
3424  if (startsWith)
3425  {
3426  if (i.value().text.startsWith(searchStr, Qt::CaseInsensitive))
3427  return true;
3428  }
3429  else
3430  {
3431  if (i.value().text.contains(searchStr, Qt::CaseInsensitive))
3432  return true;
3433  }
3434 
3435  ++i;
3436  }
3437  }
3438  else
3439  {
3440  QStringList fields = fieldList.split(',', Qt::SkipEmptyParts);
3441  for (int x = 0; x < fields.count(); ++x)
3442  {
3443  if (m_strings.contains(fields.at(x).trimmed()))
3444  {
3445  if (startsWith)
3446  {
3447  if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
3448  return true;
3449  }
3450  else
3451  {
3452  if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
3453  return true;
3454  }
3455  }
3456  }
3457  }
3458 
3459  return false;
3460 }
3461 
3462 void MythUIButtonListItem::SetFontState(const QString &state,
3463  const QString &name)
3464 {
3465  if (!name.isEmpty())
3466  {
3467  if (m_strings.contains(name))
3468  m_strings[name].state = state;
3469  }
3470  else
3471  {
3472  m_fontState = state;
3473  }
3474 
3475  if (m_parent && m_isVisible)
3476  m_parent->Update();
3477 }
3478 
3479 void MythUIButtonListItem::SetImage(MythImage *image, const QString &name)
3480 {
3481  if (image)
3482  image->IncrRef();
3483 
3484  if (!name.isEmpty())
3485  {
3486  QMap<QString, MythImage*>::iterator it = m_images.find(name);
3487  if (it != m_images.end())
3488  {
3489  (*it)->DecrRef();
3490  if (image)
3491  *it = image;
3492  else
3493  m_images.erase(it);
3494  }
3495  else if (image)
3496  {
3497  m_images[name] = image;
3498  }
3499  }
3500  else
3501  {
3502  if (m_image)
3503  m_image->DecrRef();
3504  m_image = image;
3505  }
3506 
3507  if (m_parent && m_isVisible)
3508  m_parent->Update();
3509 }
3510 
3512 {
3513  m_imageFilenames.clear();
3514  m_imageFilenames = imageMap;
3515 }
3516 
3518 {
3519  m_imageCb.fn = fn;
3520  m_imageCb.data = data;
3521 }
3522 
3524 {
3525  if (!name.isEmpty())
3526  {
3527  QMap<QString, MythImage*>::iterator it = m_images.find(name);
3528  if (it != m_images.end())
3529  {
3530  (*it)->IncrRef();
3531  return (*it);
3532  }
3533  }
3534  else if (m_image)
3535  {
3536  m_image->IncrRef();
3537  return m_image;
3538  }
3539 
3540  return nullptr;
3541 }
3542 
3544  const QString &filename, const QString &name, bool force_reload)
3545 {
3546  bool do_update = force_reload;
3547 
3548  if (!name.isEmpty())
3549  {
3550  InfoMap::iterator it = m_imageFilenames.find(name);
3551 
3552  if (it == m_imageFilenames.end())
3553  {
3554  m_imageFilenames.insert(name, filename);
3555  do_update = true;
3556  }
3557  else if (*it != filename)
3558  {
3559  *it = filename;
3560  do_update = true;
3561  }
3562  }
3563  else if (m_imageFilename != filename)
3564  {
3566  do_update = true;
3567  }
3568 
3569  if (m_parent && do_update && m_isVisible)
3570  m_parent->Update();
3571 }
3572 
3573 QString MythUIButtonListItem::GetImageFilename(const QString &name) const
3574 {
3575  if (name.isEmpty())
3576  return m_imageFilename;
3577 
3578  if (m_imageCb.fn != nullptr)
3579  {
3580  QString result = m_imageCb.fn(name, m_imageCb.data);
3581  if (!result.isEmpty())
3582  return result;
3583  }
3584 
3585  InfoMap::const_iterator it = m_imageFilenames.find(name);
3586 
3587  if (it != m_imageFilenames.end())
3588  return *it;
3589 
3590  return {};
3591 }
3592 
3593 void MythUIButtonListItem::SetProgress1(int start, int total, int used)
3594 {
3595  m_progress1.used = used;
3596  m_progress1.start = start;
3597  m_progress1.total = total;
3598 
3599  if (m_parent && m_isVisible)
3600  m_parent->Update();
3601 }
3602 
3603 void MythUIButtonListItem::SetProgress2(int start, int total, int used)
3604 {
3605  m_progress2.used = used;
3606  m_progress2.start = start;
3607  m_progress2.total = total;
3608 
3609  if (m_parent && m_isVisible)
3610  m_parent->Update();
3611 }
3612 
3613 void MythUIButtonListItem::DisplayState(const QString &state,
3614  const QString &name)
3615 {
3616  if (name.isEmpty())
3617  return;
3618 
3619  bool do_update = false;
3620  InfoMap::iterator it = m_states.find(name);
3621 
3622  if (it == m_states.end())
3623  {
3624  m_states.insert(name, state);
3625  do_update = true;
3626  }
3627  else if (*it != state)
3628  {
3629  *it = state;
3630  do_update = true;
3631  }
3632 
3633  if (m_parent && do_update && m_isVisible)
3634  m_parent->Update();
3635 }
3636 
3638 {
3639  m_states.clear();
3640  m_states = stateMap;
3641 }
3642 
3644 {
3645  m_stateCb.fn = fn;
3646  m_stateCb.data = data;
3647 }
3648 
3649 QString MythUIButtonListItem::GetState(const QString &name)
3650 {
3651  if (name.isEmpty())
3652  return {};
3653  if (m_stateCb.fn != nullptr)
3654  {
3655  QString result = m_stateCb.fn(name, m_textCb.data);
3656  if (!result.isEmpty())
3657  return result;
3658  }
3659  if (m_states.contains(name))
3660  return m_states[name];
3661  return {};
3662 }
3663 
3665 {
3666  return m_checkable;
3667 }
3668 
3670 {
3671  return m_state;
3672 }
3673 
3675 {
3676  return m_parent;
3677 }
3678 
3680 {
3681  if (!m_checkable || m_state == state)
3682  return;
3683 
3684  m_state = state;
3685 
3686  if (m_parent && m_isVisible)
3687  m_parent->Update();
3688 }
3689 
3691 {
3692  m_checkable = flag;
3693 }
3694 
3696 {
3697  m_showArrow = flag;
3698 }
3699 
3701 {
3702  return m_enabled;
3703 }
3704 
3706 {
3707  m_enabled = flag;
3708 }
3709 
3711 {
3712  m_data = std::move(data);
3713 }
3714 
3716 {
3717  return m_data;
3718 }
3719 
3721 {
3722  if (m_parent)
3723  return m_parent->MoveItemUpDown(this, flag);
3724  return false;
3725 }
3726 
3728 {
3729  if (!buttontext)
3730  return;
3731 
3732  buttontext->SetText(m_text);
3733  buttontext->SetFontState(m_fontState);
3734 }
3735 
3737 {
3738  if (!buttonimage)
3739  return;
3740 
3741  if (!m_imageFilename.isEmpty())
3742  {
3743  buttonimage->SetFilename(m_imageFilename);
3744  buttonimage->Load();
3745  }
3746  else if (m_image)
3747  {
3748  buttonimage->SetImage(m_image);
3749  }
3750 }
3751 
3753 {
3754  if (!buttonarrow)
3755  return;
3756  buttonarrow->SetVisible(m_showArrow);
3757 }
3758 
3760 {
3761  if (!buttoncheck)
3762  return;
3763 
3764  buttoncheck->SetVisible(m_checkable);
3765 
3766  if (!m_checkable)
3767  return;
3768 
3769  if (m_state == NotChecked)
3770  buttoncheck->DisplayState(MythUIStateType::Off);
3771  else if (m_state == HalfChecked)
3772  buttoncheck->DisplayState(MythUIStateType::Half);
3773  else
3774  buttoncheck->DisplayState(MythUIStateType::Full);
3775 }
3776 
3778 {
3779  if (!buttonprogress)
3780  return;
3781 
3782  buttonprogress->Set(m_progress1.start, m_progress1.total, m_progress1.used);
3783 }
3784 
3786 {
3787  if (!buttonprogress)
3788  return;
3789 
3790  buttonprogress->Set(m_progress2.start, m_progress2.total, m_progress2.used);
3791 }
3792 
3794  const TextProperties& textprop)
3795 {
3796  if (!text)
3797  return;
3798 
3799  QString newText = text->GetTemplateText();
3800 
3801  static const QRegularExpression re {R"(%(([^\|%]+)?\||\|(.))?([\w#]+)(\|(.+?))?%)",
3802  QRegularExpression::DotMatchesEverythingOption};
3803 
3804  if (!newText.isEmpty() && newText.contains(re))
3805  {
3806  QString tempString = newText;
3807 
3808  QRegularExpressionMatchIterator i = re.globalMatch(newText);
3809  while (i.hasNext()) {
3810  QRegularExpressionMatch match = i.next();
3811  QString key = match.captured(4).toLower().trimmed();
3812  QString replacement;
3813  QString value = GetText(key);
3814 
3815  if (!value.isEmpty())
3816  {
3817  replacement = QString("%1%2%3%4")
3818  .arg(match.captured(2),
3819  match.captured(3),
3820  value,
3821  match.captured(6));
3822  }
3823 
3824  tempString.replace(match.captured(0), replacement);
3825  }
3826 
3827  newText = tempString;
3828  }
3829  else
3830  {
3831  newText = textprop.text;
3832  }
3833 
3834  if (newText.isEmpty())
3835  text->Reset();
3836  else
3837  text->SetText(newText);
3838 
3839  text->SetFontState(textprop.state.isEmpty() ? m_fontState : textprop.state);
3840 }
3841 
3843 {
3844  if (!image)
3845  return;
3846 
3847  if (!filename.isEmpty())
3848  {
3849  image->SetFilename(filename);
3850  image->Load();
3851  }
3852  else
3853  {
3854  image->Reset();
3855  }
3856 }
3857 
3859 {
3860  if (!uiimage)
3861  return;
3862 
3863  if (image)
3864  uiimage->SetImage(image);
3865  else
3866  uiimage->Reset();
3867 }
3868 
3869 void MythUIButtonListItem::DoButtonLookupState (MythUIStateType *statetype, const QString& name)
3870 {
3871  if (!statetype)
3872  return;
3873 
3874  if (!statetype->DisplayState(name))
3875  statetype->Reset();
3876 }
3877 
3879 {
3880  if (!m_parent)
3881  return;
3882 
3883  m_parent->ItemVisible(this);
3884  m_isVisible = true;
3885 
3886  QString state;
3887 
3888  if (!m_parent->IsEnabled())
3889  state = "disabled";
3890  else if (!m_enabled)
3891  {
3892  state = m_parent->m_active ? "disabledactive" : "disabledinactive";
3893  }
3894  else if (selected)
3895  {
3896  button->MoveToTop();
3897  state = m_parent->m_active ? "selectedactive" : "selectedinactive";
3898  }
3899  else
3900  {
3901  state = m_parent->m_active ? "active" : "inactive";
3902  }
3903 
3904  // Begin compatibility code
3905  // Attempt to fallback if the theme is missing certain states
3906  if (state == "disabled" && !button->GetState(state))
3907  {
3908  LOG(VB_GUI, LOG_WARNING, "Theme Error: Missing buttonlist state: disabled");
3909  state = "inactive";
3910  }
3911 
3912  if (state == "inactive" && !button->GetState(state))
3913  {
3914  LOG(VB_GUI, LOG_WARNING, "Theme Error: Missing buttonlist state: inactive");
3915  state = "active";
3916  }
3917  // End compatibility code
3918 
3919  auto *buttonstate = dynamic_cast<MythUIGroup *>(button->GetState(state));
3920  if (!buttonstate)
3921  {
3922  LOG(VB_GENERAL, LOG_CRIT, QString("Theme Error: Missing buttonlist state: %1")
3923  .arg(state));
3924  return;
3925  }
3926 
3927  buttonstate->Reset();
3928 
3929  QList<MythUIType *> descendants = buttonstate->GetAllDescendants();
3930  for (MythUIType *obj : std::as_const(descendants))
3931  {
3932  QString name = obj->objectName();
3933  if (name == "buttontext")
3934  DoButtonText(dynamic_cast<MythUIText *>(obj));
3935  else if (name == "buttonimage")
3936  DoButtonImage(dynamic_cast<MythUIImage *>(obj));
3937  else if (name == "buttonarrow")
3938  DoButtonArrow(dynamic_cast<MythUIImage *>(obj));
3939  else if (name == "buttoncheck")
3940  DoButtonCheck(dynamic_cast<MythUIStateType *>(obj));
3941  else if (name == "buttonprogress1")
3942  DoButtonProgress1(dynamic_cast<MythUIProgressBar *>(obj));
3943  else if (name == "buttonprogress2")
3944  DoButtonProgress2(dynamic_cast<MythUIProgressBar *>(obj));
3945 
3946  TextProperties textprop = GetTextProp(name);
3947  if (!textprop.text.isEmpty())
3948  DoButtonLookupText(dynamic_cast<MythUIText *>(obj), textprop);
3949 
3950  QString filename = GetImageFilename(name);
3951  if (!filename.isEmpty())
3952  DoButtonLookupFilename (dynamic_cast<MythUIImage *>(obj), filename);
3953 
3954  if (m_images.contains(name))
3955  DoButtonLookupImage(dynamic_cast<MythUIImage *>(obj), m_images[name]);
3956 
3957  QString luState = GetState(name);
3958  if (!luState.isEmpty())
3959  DoButtonLookupState(dynamic_cast<MythUIStateType *>(obj), luState);
3960  }
3961 
3962  // There is no need to check the return value here, since we already
3963  // checked that the state exists with GetState() earlier
3964  button->DisplayState(state);
3965 }
3966 
3967 //---------------------------------------------------------
3968 // SearchButtonListDialog
3969 //---------------------------------------------------------
3971 {
3972  if (!CopyWindowFromBase("MythSearchListDialog", this))
3973  return false;
3974 
3975  bool err = false;
3976  UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
3977  UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
3978  UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
3979  UIUtilW::Assign(this, m_searchState, "searchstate");
3980 
3981  if (err)
3982  {
3983  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'MythSearchListDialog'");
3984  return false;
3985  }
3986 
3988 
3992 
3993  BuildFocusList();
3994 
3995  return true;
3996 }
3997 
3999 {
4000  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
4001  return true;
4002 
4003  QStringList actions;
4004  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions, false);
4005 
4006  for (int i = 0; i < actions.size() && !handled; ++i)
4007  {
4008  const QString& action = actions[i];
4009  handled = true;
4010 
4011  if (action == "0")
4012  {
4014  searchChanged();
4015  }
4016  else
4017  {
4018  handled = false;
4019  }
4020  }
4021 
4022  if (!handled && MythScreenType::keyPressEvent(event))
4023  handled = true;
4024 
4025  return handled;
4026 }
4027 
4029 {
4030  bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);
4031 
4032  if (m_searchState)
4033  m_searchState->DisplayState(found ? "found" : "notfound");
4034 }
4035 
4037 {
4038  bool found = m_parentList->FindNext();
4039 
4040  if (m_searchState)
4041  m_searchState->DisplayState(found ? "found" : "notfound");
4042 }
4043 
4045 {
4046  bool found = m_parentList->FindPrev();
4047 
4048  if (m_searchState)
4049  m_searchState->DisplayState(found ? "found" : "notfound");
4050 }
4051 
4053 {
4055  return;
4056 
4057  int maximum = (m_itemCount <= m_itemsVisible) ? 0 : m_itemCount;
4058  m_scrollBar->SetMaximum(maximum);
4062 }
MythUIButtonList::WrapFlowing
@ WrapFlowing
Definition: mythuibuttonlist.h:283
MythUIButton::Clicked
void Clicked()
MythUIText::SetFontState
void SetFontState(const QString &state)
Definition: mythuitext.cpp:202
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1700
MythUIType::m_area
MythRect m_area
Definition: mythuitype.h:274
MythUIButtonList::StopLoad
int StopLoad(void)
Definition: mythuibuttonlist.cpp:2812
MythUIButtonListItem::DoButtonArrow
void DoButtonArrow(MythUIImage *buttonarrow) const
Definition: mythuibuttonlist.cpp:3752
MythUIButtonList::MoveMid
@ MoveMid
Definition: mythuibuttonlist.h:207
MythUIButtonList::ArrangeSpread
@ ArrangeSpread
Definition: mythuibuttonlist.h:280
MythUIButtonList::m_upArrow
MythUIStateType * m_upArrow
Definition: mythuibuttonlist.h:374
MythGestureEvent::Click
@ Click
Definition: mythgesture.h:77
ProgressInfo::start
int8_t start
Definition: mythuibuttonlist.h:29
MythUIButtonList::SetDrawFromBottom
void SetDrawFromBottom(bool draw)
Definition: mythuibuttonlist.cpp:97
MythUIButtonList::m_topPosition
int m_topPosition
Definition: mythuibuttonlist.h:388
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
MythUIButtonList::m_itemList
QList< MythUIButtonListItem * > m_itemList
Definition: mythuibuttonlist.h:392
LCD::getLCDHeight
int getLCDHeight(void) const
Definition: lcddevice.h:292
MythUIButtonList::SetValueByData
void SetValueByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1566
mythuitext.h
mythuiprogressbar.h
XMLParseBase::parseAlignment
static int parseAlignment(const QString &text)
Definition: xmlparsebase.cpp:153
MythUIButtonList::Const
void Const()
Definition: mythuibuttonlist.cpp:58
SearchButtonListDialog::nextClicked
void nextClicked(void)
Definition: mythuibuttonlist.cpp:4036
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
MythUIButtonList::MoveByAmount
@ MoveByAmount
Definition: mythuibuttonlist.h:207
XMLParseBase::parsePoint
static MythPoint parsePoint(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:75
MythUIType::DeleteChild
void DeleteChild(const QString &name)
Delete a named child of this UIType.
Definition: mythuitype.cpp:153
MythUIText::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:65
MythUIButtonList::GetItemNext
MythUIButtonListItem * GetItemNext(MythUIButtonListItem *item) const
Definition: mythuibuttonlist.cpp:1668
MythUIScreenBounds::GetUIScreenRect
QRect GetUIScreenRect()
Definition: mythuiscreenbounds.cpp:198
MythUIButtonList::m_scrollStyle
ScrollStyle m_scrollStyle
Definition: mythuibuttonlist.h:345
MythUIButtonList::DrawSelf
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override
Definition: mythuibuttonlist.cpp:3000
MythUIButtonList::GetButtonPosition
virtual QPoint GetButtonPosition(int column, int row) const
Definition: mythuibuttonlist.cpp:2819
muibCbFn
QString(*)(const QString &name, void *data) muibCbFn
Definition: mythuibuttonlist.h:34
MythUIButtonList::m_itemHeight
int m_itemHeight
Definition: mythuibuttonlist.h:357
MythUIButtonList::Find
bool Find(const QString &searchStr, bool startsWith=false)
Definition: mythuibuttonlist.cpp:3181
MythGestureEvent::GetGesture
Gesture GetGesture() const
Definition: mythgesture.h:85
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
MythUIType::GetChildAt
MythUIType * GetChildAt(QPoint p, bool recursive=true, bool focusable=true) const
Return the first MythUIType at the given coordinates.
Definition: mythuitype.cpp:241
MythUIButtonListItem::m_strings
QMap< QString, TextProperties > m_strings
Definition: mythuibuttonlist.h:170
NextButtonListPageEvent::NextButtonListPageEvent
NextButtonListPageEvent(int start, int pageSize)
Definition: mythuibuttonlist.cpp:2773
MythUIButtonListItem::m_stateCb
muibCbInfo m_stateCb
Definition: mythuibuttonlist.h:176
NextButtonListPageEvent::m_pageSize
const int m_pageSize
Definition: mythuibuttonlist.cpp:2776
MythUIButtonList::MovementUnit
MovementUnit
Definition: mythuibuttonlist.h:205
MythUIType::GetFullArea
virtual MythRect GetFullArea(void) const
Definition: mythuitype.cpp:893
UNCHECKED
@ UNCHECKED
Definition: lcddevice.h:17
MythUIButtonListItem::DoButtonLookupFilename
static void DoButtonLookupFilename(MythUIImage *image, const QString &filename)
Definition: mythuibuttonlist.cpp:3842
MythUIButtonList::ScrollCenter
@ ScrollCenter
Definition: mythuibuttonlist.h:278
MythUIButtonListItem::SetImageFromMap
void SetImageFromMap(const InfoMap &imageMap)
Definition: mythuibuttonlist.cpp:3511
MythUIType::Enabling
void Enabling()
MythUIStateType::GetState
MythUIType * GetState(const QString &name)
Definition: mythuistatetype.cpp:147
MythUIButtonList::m_itemCount
int m_itemCount
Definition: mythuibuttonlist.h:389
MythUIButtonList::MoveDown
virtual bool MoveDown(MovementUnit unit=MoveItem, uint amount=0)
Definition: mythuibuttonlist.cpp:2193
MythUIButtonList::m_needsUpdate
bool m_needsUpdate
Definition: mythuibuttonlist.h:384
MythUIButtonList::gestureEvent
bool gestureEvent(MythGestureEvent *event) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
Definition: mythuibuttonlist.cpp:2673
MythUIButtonList::WrapItems
@ WrapItems
Definition: mythuibuttonlist.h:283
MythUIButtonListItem::DoButtonLookupState
static void DoButtonLookupState(MythUIStateType *statetype, const QString &name)
Definition: mythuibuttonlist.cpp:3869
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
MythUIButtonList::m_showArrow
bool m_showArrow
Definition: mythuibuttonlist.h:370
MythUIButtonList::RemoveItem
void RemoveItem(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1512
MythGestureEvent::Down
@ Down
Definition: mythgesture.h:50
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:971
MythUIButtonList::m_layout
LayoutType m_layout
Definition: mythuibuttonlist.h:343
MythUIButtonList::m_buttontemplate
MythUIStateType * m_buttontemplate
Definition: mythuibuttonlist.h:377
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
MythUIButtonList::Finalize
void Finalize(void) override
Perform any post-xml parsing initialisation tasks.
Definition: mythuibuttonlist.cpp:3078
MythUIButtonList::WrapSelect
@ WrapSelect
Definition: mythuibuttonlist.h:282
MythGestureEvent::Left
@ Left
Definition: mythgesture.h:51
MythUIButtonListItem::DoButtonProgress2
void DoButtonProgress2(MythUIProgressBar *buttonprogress) const
Definition: mythuibuttonlist.cpp:3785
MythUIButtonListItem::m_imageFilenames
InfoMap m_imageFilenames
Definition: mythuibuttonlist.h:172
MythUIStateType::GetCurrentState
MythUIType * GetCurrentState()
Definition: mythuistatetype.h:43
MythScreenStack
Definition: mythscreenstack.h:16
MythUIButtonList::FindEnabledUp
void FindEnabledUp(MovementUnit unit)
Definition: mythuibuttonlist.cpp:2147
MythUIButtonList::LayoutHorizontal
@ LayoutHorizontal
Definition: mythuibuttonlist.h:209
NextButtonListPageEvent::kEventType
static const Type kEventType
Definition: mythuibuttonlist.cpp:2777
MythUIButtonListItem::SetStatesFromMap
void SetStatesFromMap(const InfoMap &stateMap)
Definition: mythuibuttonlist.cpp:3637
MythUIType::SetCanTakeFocus
void SetCanTakeFocus(bool set=true)
Set whether this widget can take focus.
Definition: mythuitype.cpp:362
MythUIButtonListItem::m_fontState
QString m_fontState
Definition: mythuibuttonlist.h:157
MythUIButtonList::ArrangeStack
@ ArrangeStack
Definition: mythuibuttonlist.h:280
mythuiscrollbar.h
MythUIButtonListItem::parent
MythUIButtonList * parent() const
Definition: mythuibuttonlist.cpp:3674
MythUIButtonListItem::FindText
bool FindText(const QString &searchStr, const QString &fieldList="**ALL**", bool startsWith=false) const
Definition: mythuibuttonlist.cpp:3398
MythUIButtonList::minButtonWidth
int minButtonWidth(const MythRect &area)
Definition: mythuibuttonlist.cpp:154
MythUIButtonList::SetButtonArea
void SetButtonArea(const MythRect &rect)
Definition: mythuibuttonlist.cpp:2866
ProgressInfo::total
int8_t total
Definition: mythuibuttonlist.h:30
MythUIButtonListItem::CheckState
CheckState
Definition: mythuibuttonlist.h:44
SearchButtonListDialog::m_searchText
QString m_searchText
Definition: mythuibuttonlist.h:426
MythUIGroup
Create a group of widgets.
Definition: mythuigroup.h:11
NextButtonListPageEvent::m_start
const int m_start
Definition: mythuibuttonlist.cpp:2775
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
mythuistatetype.h
MythUIButtonList::m_showScrollBar
bool m_showScrollBar
Definition: mythuibuttonlist.h:371
MythUIButtonList::m_alignment
int m_alignment
Definition: mythuibuttonlist.h:347
MythUIButtonListItem::m_imageFilename
QString m_imageFilename
Definition: mythuibuttonlist.h:159
MythUIStateType::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuistatetype.cpp:197
MythUIButtonListItem::m_textCb
muibCbInfo m_textCb
Definition: mythuibuttonlist.h:174
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:50
MythUIImage::Reset
void Reset(void) override
Reset the image back to the default defined in the theme.
Definition: mythuiimage.cpp:644
MythUIButtonList::MoveItem
@ MoveItem
Definition: mythuibuttonlist.h:206
CHECKED
@ CHECKED
Definition: lcddevice.h:17
MythUIButtonList::DoFind
bool DoFind(bool doMove, bool searchForward)
Definition: mythuibuttonlist.cpp:3198
MythUIButtonList::ParseElement
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
Definition: mythuibuttonlist.cpp:2884
SearchButtonListDialog
Definition: mythuibuttonlist.h:404
MythUIButtonListItem::DoButtonProgress1
void DoButtonProgress1(MythUIProgressBar *buttonprogress) const
Definition: mythuibuttonlist.cpp:3777
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
MythUIButtonList::m_nextItemLoaded
int m_nextItemLoaded
Definition: mythuibuttonlist.h:393
MythUIButtonList::MovePage
@ MovePage
Definition: mythuibuttonlist.h:206
SearchButtonListDialog::m_startsWith
bool m_startsWith
Definition: mythuibuttonlist.h:423
MythUIButtonListItem::~MythUIButtonListItem
virtual ~MythUIButtonListItem()
Definition: mythuibuttonlist.cpp:3302
mythuibuttonlist.h
MythUIButtonList::SanitizePosition
void SanitizePosition(void)
Definition: mythuibuttonlist.cpp:1407
LCD::Get
static LCD * Get(void)
Definition: lcddevice.cpp:69
mythuiimage.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1679
MythUIButtonList::m_buttonToItem
QMap< int, MythUIButtonListItem * > m_buttonToItem
Definition: mythuibuttonlist.h:380
MythUIButtonList::MoveMax
@ MoveMax
Definition: mythuibuttonlist.h:206
MythUIButtonList::m_bottomRows
int m_bottomRows
Definition: mythuibuttonlist.h:367
MythUIButtonList::m_drawFromBottom
bool m_drawFromBottom
Definition: mythuibuttonlist.h:395
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
MythUIButtonListItem::m_imageCb
muibCbInfo m_imageCb
Definition: mythuibuttonlist.h:175
MythUIButtonList::DistributeButtons
bool DistributeButtons(void)
Definition: mythuibuttonlist.cpp:742
MythUIButtonList::GetItemByData
MythUIButtonListItem * GetItemByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1708
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:110
MythUIType::TakingFocus
void TakingFocus()
MythUIType::GetArea
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:885
MythUIButtonList::customEvent
void customEvent(QEvent *event) override
Definition: mythuibuttonlist.cpp:2783
SearchButtonListDialog::m_parentList
MythUIButtonList * m_parentList
Definition: mythuibuttonlist.h:425
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythUIButtonList::ItemHeight
uint ItemHeight(void)
Definition: mythuibuttonlist.cpp:2517
MythUIButtonListItem::SetText
void SetText(const QString &text, const QString &name="", const QString &state="")
Definition: mythuibuttonlist.cpp:3319
MythUIText::GetTemplateText
QString GetTemplateText(void) const
Definition: mythuitext.h:49
MythUIButtonListItem::GetTextProp
TextProperties GetTextProp(const QString &name="") const
Definition: mythuibuttonlist.cpp:3383
MythUIButtonList::m_scrollBar
MythUIScrollBar * m_scrollBar
Definition: mythuibuttonlist.h:373
MythUIButtonList::GetItemPos
int GetItemPos(MythUIButtonListItem *item) const
Definition: mythuibuttonlist.cpp:1722
MythUIButtonList::m_itemVertSpacing
int m_itemVertSpacing
Definition: mythuibuttonlist.h:359
MythMainWindow::GetKey
static QString GetKey(const QString &Context, const QString &Action)
Definition: mythmainwindow.cpp:1318
MythUIButtonList::ItemVisible
void ItemVisible(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1475
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
MythUITextEdit::SetText
void SetText(const QString &text, bool moveCursor=true)
Definition: mythuitextedit.cpp:198
MythUIButtonList::IsEmpty
bool IsEmpty() const
Definition: mythuibuttonlist.cpp:1695
MythUIButtonList::PageDown
int PageDown(void)
Definition: mythuibuttonlist.cpp:1863
MythUIButtonList::~MythUIButtonList
~MythUIButtonList() override
Definition: mythuibuttonlist.cpp:67
MythUIButtonList::MoveItemUpDown
bool MoveItemUpDown(MythUIButtonListItem *item, bool up)
Definition: mythuibuttonlist.cpp:2349
MythUIButtonList::m_contentsRect
MythRect m_contentsRect
Definition: mythuibuttonlist.h:349
MythUIType::m_hasFocus
bool m_hasFocus
Definition: mythuitype.h:262
MythUIButtonList::ArrangeFill
@ ArrangeFill
Definition: mythuibuttonlist.h:280
MythUIButtonList::itemLoaded
void itemLoaded(MythUIButtonListItem *item)
mythlogging.h
MythUIButtonList::m_lcdColumns
QStringList m_lcdColumns
Definition: mythuibuttonlist.h:398
MythUIButtonList::m_rows
int m_rows
Definition: mythuibuttonlist.h:362
MythUIButtonListItem::setCheckable
void setCheckable(bool flag)
Definition: mythuibuttonlist.cpp:3690
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1111
MythUIButtonList::Deselect
void Deselect()
Definition: mythuibuttonlist.cpp:86
MythGestureEvent::DownRight
@ DownRight
Definition: mythgesture.h:58
MythUIType::GetXMLLocation
QString GetXMLLocation(void) const
Definition: mythuitype.h:180
MythUIButtonListItem::isEnabled
bool isEnabled() const
Definition: mythuibuttonlist.cpp:3700
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:240
MythUIType::SetMinArea
virtual void SetMinArea(const MythRect &rect)
Set the minimum area based on the given size.
Definition: mythuitype.cpp:820
MythUIProgressBar::Set
void Set(int start, int total, int used)
Definition: mythuiprogressbar.cpp:56
MythUIType::DependChanged
void DependChanged(bool isDefault)
MythUIButtonListItem::m_progress2
ProgressInfo m_progress2
Definition: mythuibuttonlist.h:168
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
MythUIType::SetPosition
void SetPosition(int x, int y)
Convenience method, calls SetPosition(const MythPoint&) Override that instead to change functionality...
Definition: mythuitype.cpp:533
MythUIButtonListItem::m_states
InfoMap m_states
Definition: mythuibuttonlist.h:173
MythUIType::IsEnabled
bool IsEnabled(void) const
Definition: mythuitype.h:117
MythUIType::Disabling
void Disabling()
MythUIButtonList::m_itemsVisible
int m_itemsVisible
Definition: mythuibuttonlist.h:360
MythUIButtonList::m_searchPosition
MythPoint m_searchPosition
Definition: mythuibuttonlist.h:351
MythUIButtonList::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythuibuttonlist.cpp:2528
MythUIButtonList::ArrangeFixed
@ ArrangeFixed
Definition: mythuibuttonlist.h:280
MythUIButtonList::LoadInBackground
void LoadInBackground(int start=0, int pageSize=20)
Definition: mythuibuttonlist.cpp:2805
MythUIStateType::Half
@ Half
Definition: mythuistatetype.h:27
MythUIButtonList::Update
void Update()
Definition: mythuibuttonlist.cpp:141
MythUIButtonListItem::GetImage
MythImage * GetImage(const QString &name="")
Gets a MythImage which has been assigned to this button item, as with SetImage() it should only be us...
Definition: mythuibuttonlist.cpp:3523
MythUIScrollBar::SetSliderPosition
void SetSliderPosition(int value)
Definition: mythuiscrollbar.cpp:73
MythUIButtonList::minButtonHeight
int minButtonHeight(const MythRect &area)
Definition: mythuibuttonlist.cpp:184
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:203
XMLParseBase::CopyWindowFromBase
static bool CopyWindowFromBase(const QString &windowname, MythScreenType *win)
Definition: xmlparsebase.cpp:941
MythUIButtonList::m_itemHorizSpacing
int m_itemHorizSpacing
Definition: mythuibuttonlist.h:358
CHECKED_STATE
CHECKED_STATE
Definition: lcddevice.h:17
XMLParseBase::getFirstText
static QString getFirstText(QDomElement &element)
Definition: xmlparsebase.cpp:52
MythUIButtonList::m_topRows
int m_topRows
Definition: mythuibuttonlist.h:366
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:52
MythRect::setHeight
void setHeight(const QString &sHeight)
Definition: mythrect.cpp:277
MythUIType::m_parent
MythUIType * m_parent
Definition: mythuitype.h:294
TextProperties
Definition: mythuibuttonlist.h:23
MythUIType::NormY
static int NormY(int height)
Definition: mythuitype.cpp:1163
MythRect::CalculateArea
void CalculateArea(QRect parentArea)
Definition: mythrect.cpp:64
MythUIButtonList::MythUIButtonList
MythUIButtonList(MythUIType *parent, const QString &name)
Definition: mythuibuttonlist.cpp:31
MythUIButtonList::InsertItem
void InsertItem(MythUIButtonListItem *item, int listPosition=-1)
Definition: mythuibuttonlist.cpp:1481
TextProperties::state
QString state
Definition: mythuibuttonlist.h:25
MythUIStateType::Off
@ Off
Definition: mythuistatetype.h:27
MythUIButtonList::InitButton
void InitButton(int itemIdx, MythUIStateType *&realButton, MythUIButtonListItem *&buttonItem)
Definition: mythuibuttonlist.cpp:1730
MythUIButtonList::GetDataValue
QVariant GetDataValue() const
Definition: mythuibuttonlist.cpp:1643
MythUIButtonList::m_clearing
bool m_clearing
Definition: mythuibuttonlist.h:385
SearchButtonListDialog::searchChanged
void searchChanged(void)
Definition: mythuibuttonlist.cpp:4028
SearchButtonListDialog::m_prevButton
MythUIButton * m_prevButton
Definition: mythuibuttonlist.h:429
MythUIButtonListItem::checkable
bool checkable() const
Definition: mythuibuttonlist.cpp:3664
MythUIButtonList::m_initialized
bool m_initialized
Definition: mythuibuttonlist.h:383
MythGestureEvent::UpRight
@ UpRight
Definition: mythgesture.h:56
MythUIButtonList::MoveRow
@ MoveRow
Definition: mythuibuttonlist.h:206
MythUIButtonList::SetAllChecked
void SetAllChecked(MythUIButtonListItem::CheckState state)
Definition: mythuibuttonlist.cpp:2399
MythUIType::CopyFrom
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
Definition: mythuitype.cpp:1171
MythUIButtonList::MoveUp
virtual bool MoveUp(MovementUnit unit=MoveItem, uint amount=0)
Definition: mythuibuttonlist.cpp:1969
MythUIButtonList::SetLCDTitles
void SetLCDTitles(const QString &title, const QString &columnList="")
Definition: mythuibuttonlist.cpp:3083
MythUIButtonList::CalculateButtonPositions
void CalculateButtonPositions(void)
Definition: mythuibuttonlist.cpp:1277
MythUIButtonListItem::SetTextCb
void SetTextCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3362
MythUIButtonList::GetIntValue
virtual int GetIntValue() const
Definition: mythuibuttonlist.cpp:1623
MythUIButtonList::m_searchStr
QString m_searchStr
Definition: mythuibuttonlist.h:353
SearchButtonListDialog::Create
bool Create(void) override
Definition: mythuibuttonlist.cpp:3970
MythUIButtonList::SetScrollBarPosition
void SetScrollBarPosition(void)
Definition: mythuibuttonlist.cpp:4052
MythGestureEvent::Right
@ Right
Definition: mythgesture.h:52
XMLParseBase::parseRect
static MythRect parseRect(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:132
MythUIButtonList::DistributeCols
bool DistributeCols(int &first_button, int &last_button, int &first_item, int &last_item, int &selected_column, int &selected_row, int &skip_cols, int **col_widths, QList< int > &row_heights, int &top_height, int &bottom_height, bool &wrapped)
Definition: mythuibuttonlist.cpp:623
MythUIButtonList::Init
virtual void Init()
Definition: mythuibuttonlist.cpp:2407
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
MythUIButtonList::ScrollGroupCenter
@ ScrollGroupCenter
Definition: mythuibuttonlist.h:278
MythUIButtonListItem::DoButtonLookupText
void DoButtonLookupText(MythUIText *text, const TextProperties &textprop)
Definition: mythuibuttonlist.cpp:3793
MythUIScrollBar
Scroll bar widget.
Definition: mythuiscrollbar.h:15
MythUIButtonList::FindNext
bool FindNext(void)
Definition: mythuibuttonlist.cpp:3188
MythUIButtonList::GetVisibleCount
int GetVisibleCount()
Definition: mythuibuttonlist.cpp:1684
MythUIButtonList::ScrollFree
@ ScrollFree
Definition: mythuibuttonlist.h:278
MythGestureEvent::Up
@ Up
Definition: mythgesture.h:49
NOTCHECKABLE
@ NOTCHECKABLE
Definition: lcddevice.h:17
MythUIButtonList::LayoutVertical
@ LayoutVertical
Definition: mythuibuttonlist.h:209
MythUIButtonList::m_maxVisible
int m_maxVisible
Definition: mythuibuttonlist.h:361
MythUIButtonList::m_searchStartsWith
bool m_searchStartsWith
Definition: mythuibuttonlist.h:354
MythUIType::MoveToTop
bool MoveToTop(void)
Definition: mythuitype.cpp:1373
muibCbInfo::fn
muibCbFn fn
Definition: mythuibuttonlist.h:37
MythUIButtonList::itemVisible
void itemVisible(MythUIButtonListItem *item)
mythgesture.h
A C++ ripoff of the stroke library for MythTV.
MythUIButtonListItem::SetToRealButton
virtual void SetToRealButton(MythUIStateType *button, bool selected)
Definition: mythuibuttonlist.cpp:3878
MythUIButtonListItem::SetProgress2
void SetProgress2(int start, int total, int used)
Definition: mythuibuttonlist.cpp:3603
MythUIType::Reset
virtual void Reset(void)
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitype.cpp:73
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
MythUIButtonListItem::DoButtonImage
void DoButtonImage(MythUIImage *buttonimage)
Definition: mythuibuttonlist.cpp:3736
MythGestureEvent::UpLeft
@ UpLeft
Definition: mythgesture.h:55
MythUIButtonList::LayoutGrid
@ LayoutGrid
Definition: mythuibuttonlist.h:209
mythuigroup.h
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:85
NextButtonListPageEvent
Definition: mythuibuttonlist.cpp:2770
MythUIButtonListItem::SetTextFromMap
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
Definition: mythuibuttonlist.cpp:3338
LCDMenuItem
Definition: lcddevice.h:21
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:46
MythUIButtonListItem::m_images
QMap< QString, MythImage * > m_images
Definition: mythuibuttonlist.h:171
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3368
MythUIButtonListItem::DoButtonLookupImage
static void DoButtonLookupImage(MythUIImage *uiimage, MythImage *image)
Definition: mythuibuttonlist.cpp:3858
MythImage::IncrRef
int IncrRef(void) override
Increments reference count.
Definition: mythimage.cpp:44
MythUIScrollBar::SetPageStep
void SetPageStep(int value)
Definition: mythuiscrollbar.cpp:50
SearchButtonListDialog::m_searchEdit
MythUITextEdit * m_searchEdit
Definition: mythuibuttonlist.h:428
MythUIButtonListItem::SetFontState
void SetFontState(const QString &state, const QString &name="")
Definition: mythuibuttonlist.cpp:3462
MythUIButtonList::PageUp
int PageUp(void)
Definition: mythuibuttonlist.cpp:1758
MythUIButtonList::m_actionRemap
QHash< QString, QString > m_actionRemap
Definition: mythuibuttonlist.h:381
MythUIType::m_initiator
bool m_initiator
Definition: mythuitype.h:266
MythUIButtonListItem::m_state
CheckState m_state
Definition: mythuibuttonlist.h:161
MythUIButtonList::ToggleEnabled
void ToggleEnabled()
Definition: mythuibuttonlist.cpp:91
MythUIButtonListItem::DoButtonText
void DoButtonText(MythUIText *buttontext)
Definition: mythuibuttonlist.cpp:3727
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:401
MythUIButtonListItem::m_text
QString m_text
Definition: mythuibuttonlist.h:156
MythUIButtonList::m_lcdTitle
QString m_lcdTitle
Definition: mythuibuttonlist.h:397
MythPoint::isValid
bool isValid(void) const
Definition: mythrect.h:102
MythUIButtonList::WrapNone
@ WrapNone
Definition: mythuibuttonlist.h:282
MythRect::topLeft
MythPoint topLeft(void) const
Definition: mythrect.cpp:288
MythUIButtonListItem::m_parent
MythUIButtonList * m_parent
Definition: mythuibuttonlist.h:155
MythRect::setWidth
void setWidth(const QString &sWidth)
Definition: mythrect.cpp:266
MythUIButtonListItem::m_checkable
bool m_checkable
Definition: mythuibuttonlist.h:160
MythUIButtonList::DistributeRow
bool DistributeRow(int &first_button, int &last_button, int &first_item, int &last_item, int &selected_column, int &skip_cols, bool grow_left, bool grow_right, int **col_widths, int &row_height, int total_height, int split_height, int &col_cnt, bool &wrapped)
Definition: mythuibuttonlist.cpp:262
mythuitextedit.h
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3479
MythUIButtonList::CalculateVisibleItems
virtual void CalculateVisibleItems(void)
Definition: mythuibuttonlist.cpp:2829
MythPainter
Definition: mythpainter.h:34
MythImage
Definition: mythimage.h:36
MythGestureEvent::DownLeft
@ DownLeft
Definition: mythgesture.h:57
MythUIButtonList::m_columns
int m_columns
Definition: mythuibuttonlist.h:363
MythUIScrollBar::SetMaximum
void SetMaximum(int value)
Definition: mythuiscrollbar.cpp:62
MythUIButtonList::m_selPosition
int m_selPosition
Definition: mythuibuttonlist.h:387
MythUIButtonListItem::setEnabled
void setEnabled(bool flag)
Definition: mythuibuttonlist.cpp:3705
MythUIButtonListItem::m_data
QVariant m_data
Definition: mythuibuttonlist.h:162
MythUIButtonList::CalculateArrowStates
void CalculateArrowStates(void)
Definition: mythuibuttonlist.cpp:1415
MythRect::setY
void setY(const QString &sY)
Definition: mythrect.cpp:256
MythUIType::m_minSize
MythPoint m_minSize
Definition: mythuitype.h:276
MythUIButtonList::GetValue
virtual QString GetValue() const
Definition: mythuibuttonlist.cpp:1633
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
MythUIButtonListItem::state
CheckState state() const
Definition: mythuibuttonlist.cpp:3669
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1105
SearchButtonListDialog::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythuibuttonlist.cpp:3998
MythUIButtonList::GetButtonArea
MythRect GetButtonArea(void) const
Definition: mythuibuttonlist.cpp:1653
MythUIButtonList::WrapCaptive
@ WrapCaptive
Definition: mythuibuttonlist.h:282
MythUIButtonListItem::SetImageCb
void SetImageCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3517
MythUIButtonListItem::m_progress1
ProgressInfo m_progress1
Definition: mythuibuttonlist.h:167
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:116
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MythUIButtonList::MoveToNamedPosition
bool MoveToNamedPosition(const QString &position_name)
Definition: mythuibuttonlist.cpp:2318
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1581
build_compdb.action
action
Definition: build_compdb.py:9
MythUIButtonList::m_arrange
ArrangeType m_arrange
Definition: mythuibuttonlist.h:344
MythUIButtonListItem::CantCheck
@ CantCheck
Definition: mythuibuttonlist.h:45
MythUIButtonList::m_leftColumns
int m_leftColumns
Definition: mythuibuttonlist.h:364
MythUIButtonListItem::setDrawArrow
void setDrawArrow(bool flag)
Definition: mythuibuttonlist.cpp:3695
MythUIImage::SetImage
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:749
MythUIButtonList::m_rightColumns
int m_rightColumns
Definition: mythuibuttonlist.h:365
mythuibutton.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
MythUIButtonList::m_active
bool m_active
Definition: mythuibuttonlist.h:369
SearchButtonListDialog::prevClicked
void prevClicked(void)
Definition: mythuibuttonlist.cpp:4044
MythUIButtonList::PrepareButton
MythUIGroup * PrepareButton(int buttonIdx, int itemIdx, int &selectedIdx, int &button_shift)
Definition: mythuibuttonlist.cpp:211
MythUITextEdit::valueChanged
void valueChanged()
MythUIButtonList::m_searchFields
QString m_searchFields
Definition: mythuibuttonlist.h:352
MythUIButtonListItem::m_isVisible
bool m_isVisible
Definition: mythuibuttonlist.h:164
MythUIButtonList::m_itemWidth
int m_itemWidth
Definition: mythuibuttonlist.h:356
MythUIButtonListItem::HalfChecked
@ HalfChecked
Definition: mythuibuttonlist.h:47
SearchButtonListDialog::m_searchState
MythUIStateType * m_searchState
Definition: mythuibuttonlist.h:431
MythUIButtonList::FindPrev
bool FindPrev(void)
Definition: mythuibuttonlist.cpp:3193
MythUIStateType::Full
@ Full
Definition: mythuistatetype.h:27
MythGestureEvent
A custom event that represents a mouse gesture.
Definition: mythgesture.h:39
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3573
MythUIButtonListItem::m_image
MythImage * m_image
Definition: mythuibuttonlist.h:158
MythUIButtonList::MoveColumn
@ MoveColumn
Definition: mythuibuttonlist.h:206
MythUIButtonList::m_buttonList
QVector< MythUIStateType * > m_buttonList
Definition: mythuibuttonlist.h:379
MythUIButtonList::ItemWidth
uint ItemWidth(void)
Definition: mythuibuttonlist.cpp:2509
MythUIType::NormX
static int NormX(int width)
Definition: mythuitype.cpp:1158
MythUIButtonList::FindEnabledDown
void FindEnabledDown(MovementUnit unit)
If the current item is not enabled, find the next enabled one.
Definition: mythuibuttonlist.cpp:2102
MythUIButtonListItem::SetStateCb
void SetStateCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3643
MythUIButtonListItem::m_showArrow
bool m_showArrow
Definition: mythuibuttonlist.h:163
MythUIButtonList::CreateCopy
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
Definition: mythuibuttonlist.cpp:3013
MythUIButtonList::m_keepSelAtBottom
bool m_keepSelAtBottom
Definition: mythuibuttonlist.h:390
MythUIButtonListItem::MythUIButtonListItem
MythUIButtonListItem(MythUIButtonList *lbtype, QString text, QString image="", bool checkable=false, CheckState state=CantCheck, bool showArrow=false, int listPosition=-1)
Definition: mythuibuttonlist.cpp:3262
lcddevice.h
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:677
MythUIButtonList::ShowSearchDialog
void ShowSearchDialog(void)
Definition: mythuibuttonlist.cpp:3149
MythUIType::LosingFocus
void LosingFocus()
MythUIType::ParseElement
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
Definition: mythuitype.cpp:1237
MythUIButtonList::m_downArrow
MythUIStateType * m_downArrow
Definition: mythuibuttonlist.h:375
MythUIButtonList::GetItemFirst
MythUIButtonListItem * GetItemFirst() const
Definition: mythuibuttonlist.cpp:1660
MythUIButtonList::Select
void Select()
Definition: mythuibuttonlist.cpp:76
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
build_compdb.filename
filename
Definition: build_compdb.py:21
TextProperties::text
QString text
Definition: mythuibuttonlist.h:24
mythmainwindow.h
SearchButtonListDialog::m_nextButton
MythUIButton * m_nextButton
Definition: mythuibuttonlist.h:430
MythUIButtonListItem::m_enabled
bool m_enabled
Definition: mythuibuttonlist.h:165
MythUIButtonListItem::setChecked
void setChecked(CheckState state)
Definition: mythuibuttonlist.cpp:3679
MythUIButtonListItem::SetData
void SetData(QVariant data)
Definition: mythuibuttonlist.cpp:3710
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:313
XMLParseBase::parseBool
static bool parseBool(const QString &text)
Definition: xmlparsebase.cpp:64
MythUIButtonListItem::MoveUpDown
bool MoveUpDown(bool flag)
Definition: mythuibuttonlist.cpp:3720
MythUIButtonListItem::GetState
QString GetState(const QString &name)
Definition: mythuibuttonlist.cpp:3649
MythUIButtonList::updateLCD
void updateLCD(void)
Definition: mythuibuttonlist.cpp:3089
MythUIType::m_enableInitiator
bool m_enableInitiator
Definition: mythuitype.h:265
muibCbInfo::data
void * data
Definition: mythuibuttonlist.h:38
LCD
Definition: lcddevice.h:169
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:22
MythRect::setX
void setX(const QString &sX)
Definition: mythrect.cpp:246
LCD::switchToMenu
void switchToMenu(QList< LCDMenuItem > &menuItems, const QString &app_name="", bool popMenu=true)
Definition: lcddevice.cpp:597
MythUIType::Finalize
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
Definition: mythuitype.cpp:1312
MythUIStateType::DisplayState
bool DisplayState(const QString &name)
Definition: mythuistatetype.cpp:84
ProgressInfo::used
int8_t used
Definition: mythuibuttonlist.h:31
MythUIButtonListItem::SetProgress1
void SetProgress1(int start, int total, int used)
Definition: mythuibuttonlist.cpp:3593
MythUIButtonList::m_wrapStyle
WrapStyle m_wrapStyle
Definition: mythuibuttonlist.h:346
uint
unsigned int uint
Definition: freesurround.h:24
MythUIButtonList::SetActive
void SetActive(bool active)
Definition: mythuibuttonlist.cpp:102
MythUIButtonList::CopyFrom
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
Definition: mythuibuttonlist.cpp:3022
MythUIButtonListItem::DoButtonCheck
void DoButtonCheck(MythUIStateType *buttoncheck)
Definition: mythuibuttonlist.cpp:3759