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