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  start_button = std::max(static_cast<int>(m_buttonList.size()) / 2, 0);
846  start_button = (start_button / std::max(m_columns, 1)) * m_columns;
847 
848  if (start_button < m_itemCount / 2 &&
849  m_itemCount - m_selPosition - 1 < m_buttonList.size() / 2)
850  start_button += m_columns;
851 
852  first_button = last_button = start_button;
853 
854  // Now do initial row layout again with our new knowledge
855  selected_column = selected_row = -1;
856 
857  if (!DistributeRow(first_button, last_button,
858  first_item, last_item, selected_column,
859  skip_cols, grow_left, true, &col_widths,
860  height, 0, 0, col_cnt, wrapped))
861  {
862  delete[] col_widths;
863  return false;
864  }
865  }
866 
867  if (selected_column != -1)
868  selected_row = 0;
869 
870  row_heights.push_back(height);
871 
873  top_height = bottom_height = (height / 2);
874  else
875  bottom_height = height;
876 
877  if (m_layout == LayoutHorizontal)
878  break;
879 
880  // As as many columns as will fit.
881  if (DistributeCols(first_button, last_button,
882  first_item, last_item,
883  selected_column, selected_row,
884  skip_cols, &col_widths, row_heights,
885  top_height, bottom_height, wrapped))
886  break; // Buttons fit on each row, so done
887 
888  delete[] col_widths;
889  col_widths = nullptr;
890 
891  --m_columns;
892  start_item = m_selPosition;
893  }
894 
895  m_rows = row_heights.size();
896 
897  LOG(VB_GUI, LOG_DEBUG,
898  QString("%1 rows, %2 columns fit inside parent area %3x%4")
899  .arg(m_rows).arg(m_columns).arg(m_contentsRect.width())
900  .arg(m_contentsRect.height()));
901 
902  if (col_widths == nullptr)
903  return false;
904 
905  int total = 0;
906  int left_spacing = 0;
907  int right_spacing = 0;
908  int top_spacing = 0;
909  int bottom_spacing = 0;
910  MythRect min_rect;
911  QString status_msg;
912 
913  /*
914  * Calculate heights of buttons on each side of selected button
915  */
916  top_height = bottom_height = m_topRows = m_bottomRows = 0;
917 
918  status_msg = "Row heights: ";
919 
920  for (int row = 0; row < m_rows; ++row)
921  {
922  if (row != 0)
923  status_msg += ", ";
924 
925  if (row == selected_row)
926  {
927  status_msg += '[';
928  top_height += (row_heights[row] / 2);
929  bottom_height += ((row_heights[row] / 2) + (row_heights[row] % 2));
930  }
931  else
932  {
933  if (bottom_height)
934  {
935  bottom_height += m_itemVertSpacing + row_heights[row];
936  ++m_bottomRows;
937  }
938  else
939  {
940  top_height += row_heights[row] + m_itemVertSpacing;
941  ++m_topRows;
942  }
943  }
944 
945  status_msg += QString("%1").arg(row_heights[row]);
946 
947  if (row == selected_row)
948  status_msg += ']';
949  }
950 
951  /*
952  * How much extra space should there be between buttons?
953  */
955  {
956  // None
957  top_spacing = bottom_spacing = 0;
958  }
959  else
960  {
961  if (m_rows < 2)
962  {
963  // Equal space on both sides of single row
964  top_spacing = bottom_spacing =
965  (m_contentsRect.height() - top_height) / 2;
966  }
967  else
968  {
970  {
971  // Selected button needs to end up in the middle of area
972  top_spacing = m_topRows ? (m_contentsRect.height() / 2 -
973  top_height) / m_topRows : 0;
974  bottom_spacing = m_bottomRows ? (m_contentsRect.height() / 2 -
975  bottom_height) / m_bottomRows : 0;
976 
977  if (m_arrange == ArrangeSpread)
978  {
979  // Use same spacing on both sides of selected button
980  if (!m_topRows || top_spacing > bottom_spacing)
981  top_spacing = bottom_spacing;
982  else
983  bottom_spacing = top_spacing;
984  }
985  }
986  else
987  {
988  // Buttons will be evenly spread out to fill entire area
989  top_spacing = bottom_spacing = (m_contentsRect.height() -
990  (top_height + bottom_height)) /
992  }
993  }
994 
995  // Add in intra-button space size
996  top_height += (top_spacing * m_topRows);
997  bottom_height += (bottom_spacing * m_bottomRows);
998  }
999 
1000  /*
1001  * Calculate top margin
1002  */
1003  int y = m_contentsRect.y();
1004 
1005  if ((m_alignment & Qt::AlignVCenter) && m_arrange != ArrangeFill)
1006  {
1007  if (m_scrollStyle == ScrollCenter)
1008  {
1009  // Adjust to compensate for top height less than bottom height
1010  y += std::max(bottom_height - top_height, 0);
1011  total = std::max(top_height, bottom_height) * 2;
1012  }
1013  else
1014  total = top_height + bottom_height;
1015 
1016  // Adjust top margin so selected button ends up in the middle
1017  y += (std::max(m_contentsRect.height() - total, 2) / 2);
1018  }
1019  else if ((m_alignment & Qt::AlignBottom) && m_arrange == ArrangeStack)
1020  {
1021  // Adjust top margin so buttons are bottom justified
1022  y += std::max(m_contentsRect.height() -
1023  (top_height + bottom_height), 0);
1024  }
1025  min_rect.setY(y);
1026 
1027  status_msg += QString(" spacing top %1 bottom %2 fixed %3 offset %4")
1028  .arg(top_spacing).arg(bottom_spacing)
1029  .arg(m_itemVertSpacing).arg(y);
1030 
1031  LOG(VB_GUI, LOG_DEBUG, status_msg);
1032 
1033  /*
1034  * Calculate width of buttons on each side of selected button
1035  */
1036  int left_width = 0;
1037  int right_width = 0;
1039 
1040  status_msg = "Col widths: ";
1041 
1042  for (int col = 0; col < m_columns; ++col)
1043  {
1044  if (col != 0)
1045  status_msg += ", ";
1046 
1047  if (col == selected_column)
1048  {
1049  status_msg += '[';
1050  left_width += (col_widths[col] / 2);
1051  right_width += ((col_widths[col] / 2) + (col_widths[col] % 2));
1052  }
1053  else
1054  {
1055  if (right_width)
1056  {
1057  right_width += m_itemHorizSpacing + col_widths[col];
1058  ++m_rightColumns;
1059  }
1060  else
1061  {
1062  left_width += col_widths[col] + m_itemHorizSpacing;
1063  ++m_leftColumns;
1064  }
1065  }
1066 
1067  status_msg += QString("%1").arg(col_widths[col]);
1068 
1069  if (col == selected_column)
1070  status_msg += ']';
1071  }
1072 
1073  /*
1074  * How much extra space should there be between buttons?
1075  */
1077  {
1078  // None
1079  left_spacing = right_spacing = 0;
1080  }
1081  else
1082  {
1083  if (m_columns < 2)
1084  {
1085  // Equal space on both sides of single column
1086  left_spacing = right_spacing =
1087  (m_contentsRect.width() - left_width) / 2;
1088  }
1089  else
1090  {
1091  if (m_scrollStyle == ScrollCenter)
1092  {
1093  // Selected button needs to end up in the middle
1094  left_spacing = m_leftColumns ? (m_contentsRect.width() / 2 -
1095  left_width) / m_leftColumns : 0;
1096  right_spacing = m_rightColumns ? (m_contentsRect.width() / 2 -
1097  right_width) / m_rightColumns : 0;
1098 
1099  if (m_arrange == ArrangeSpread)
1100  {
1101  // Use same spacing on both sides of selected button
1102  if (!m_leftColumns || left_spacing > right_spacing)
1103  left_spacing = right_spacing;
1104  else
1105  right_spacing = left_spacing;
1106  }
1107  }
1108  else
1109  {
1110  // Buttons will be evenly spread out to fill entire area
1111  left_spacing = right_spacing = (m_contentsRect.width() -
1112  (left_width + right_width)) /
1114  }
1115  }
1116 
1117  // Add in intra-button space size
1118  left_width += (left_spacing * m_leftColumns);
1119  right_width += (right_spacing * m_rightColumns);
1120  }
1121 
1122  /*
1123  * Calculate left margin
1124  */
1125  int x_init = m_contentsRect.x();
1126 
1127  if ((m_alignment & Qt::AlignHCenter) && m_arrange != ArrangeFill)
1128  {
1129  if (m_scrollStyle == ScrollCenter)
1130  {
1131  // Compensate for left being smaller than right
1132  x_init += std::max(right_width - left_width, 0);
1133  total = std::max(left_width, right_width) * 2;
1134  }
1135  else
1136  total = left_width + right_width;
1137 
1138  // Adjust left margin so selected button ends up in the middle
1139  x_init += (std::max(m_contentsRect.width() - total, 2) / 2);
1140  }
1141  else if ((m_alignment & Qt::AlignRight) && m_arrange == ArrangeStack)
1142  {
1143  // Adjust left margin, so buttons are right justified
1144  x_init += std::max(m_contentsRect.width() -
1145  (left_width + right_width), 0);
1146  }
1147  min_rect.setX(x_init);
1148 
1149  status_msg += QString(" spacing left %1 right %2 fixed %3 offset %4")
1150  .arg(left_spacing).arg(right_spacing)
1151  .arg(m_itemHorizSpacing).arg(x_init);
1152  LOG(VB_GUI, LOG_DEBUG, status_msg);
1153 
1154  top_spacing += m_itemVertSpacing;
1155  bottom_spacing += m_itemVertSpacing;
1156  left_spacing += m_itemHorizSpacing;
1157  right_spacing += m_itemHorizSpacing;
1158 
1159  // Calculate position of each button
1160  int buttonIdx = first_button - skip_cols;
1161  int x = 0;
1162  int x_adj = 0;
1163  int y_adj = 0;
1164 
1165  int vertical_spacing = top_spacing;
1166 
1167  for (int row = 0; row < m_rows; ++row)
1168  {
1169  x = x_init;
1170  int horizontal_spacing = left_spacing;
1171 
1172  for (int col = 0; col < m_columns && buttonIdx <= last_button; ++col)
1173  {
1174  if (buttonIdx >= first_button)
1175  {
1176  MythUIStateType *realButton = m_buttonList[buttonIdx];
1177  auto *buttonstate = dynamic_cast<MythUIGroup *>
1178  (realButton->GetCurrentState());
1179  if (!buttonstate)
1180  break; // Not continue
1181 
1182  MythRect area = buttonstate->GetArea();
1183 
1184  // Center button within width of column
1185  if (m_alignment & Qt::AlignHCenter)
1186  x_adj = (col_widths[col] - minButtonWidth(area)) / 2;
1187  else if (m_alignment & Qt::AlignRight)
1188  x_adj = (col_widths[col] - minButtonWidth(area));
1189  else
1190  x_adj = 0;
1191  if (m_layout == LayoutHorizontal)
1192  x_adj -= area.x(); // Negate button's own offset
1193 
1194  // Center button within height of row.
1195  if (m_alignment & Qt::AlignVCenter)
1196  y_adj = (row_heights[row] - minButtonHeight(area)) / 2;
1197  else if (m_alignment & Qt::AlignBottom)
1198  y_adj = (row_heights[row] - minButtonHeight(area));
1199  else
1200  y_adj = 0;
1201  if (m_layout == LayoutVertical)
1202  y_adj -= area.y(); // Negate button's own offset
1203 
1204  // Set position of button
1205  realButton->SetPosition(x + x_adj, y + y_adj);
1206  realButton->SetVisible(true);
1207 
1208  if (col == selected_column)
1209  {
1210  horizontal_spacing = right_spacing;
1211  if (row == selected_row)
1212  realButton->MoveToTop();
1213  }
1214  }
1215  x += col_widths[col] + horizontal_spacing;
1216  ++buttonIdx;
1217  }
1218 
1219  if (row == selected_row)
1220  vertical_spacing = bottom_spacing;
1221 
1222  y += row_heights[row] + vertical_spacing;
1223  }
1224  min_rect.setWidth(x - min_rect.x());
1225  min_rect.setHeight(y - min_rect.y());
1226 
1228 
1229  // Hide buttons before first active button
1230  for (buttonIdx = 0; buttonIdx < first_button; ++buttonIdx)
1231  m_buttonList[buttonIdx]->SetVisible(false);
1232 
1233  // Hide buttons after last active buttons.
1234  for (buttonIdx = m_maxVisible - 1; buttonIdx > last_button; --buttonIdx)
1235  m_buttonList[buttonIdx]->SetVisible(false);
1236 
1237  // Set m_topPosition so arrows are displayed correctly.
1239  m_topPosition = static_cast<int>(m_itemsVisible < m_itemCount);
1240  else
1241  m_topPosition = first_item;
1242 
1244  if (m_minSize.isValid())
1245  {
1246  // Record the minimal area needed for the button list
1247  SetMinArea(min_rect);
1248  }
1249 
1250  delete[] col_widths;
1251  return true;
1252 }
1253 
1255 {
1256  if (m_buttonList.empty())
1257  return;
1258 
1259  int button = 0;
1260 
1261  switch (m_scrollStyle)
1262  {
1263  case ScrollCenter:
1264  case ScrollGroupCenter:
1265  m_topPosition = std::max(m_selPosition -
1266  (int)((float)m_itemsVisible / 2), 0);
1267  break;
1268  case ScrollFree:
1269  {
1270  int adjust = 0;
1271 
1272  if (m_topPosition == -1 || m_keepSelAtBottom)
1273  {
1274  if (m_topPosition == -1)
1275  m_topPosition = 0;
1276 
1277  if (m_layout == LayoutHorizontal)
1278  adjust = 1 - m_itemsVisible;
1279  else
1280  adjust = m_columns - m_itemsVisible;
1281 
1282  m_keepSelAtBottom = false;
1283  }
1284 
1285  if (m_selPosition < m_topPosition ||
1287  {
1288  if (m_layout == LayoutHorizontal)
1289  m_topPosition = m_selPosition + adjust;
1290  else
1291  m_topPosition = (m_selPosition + adjust) /
1292  m_columns * m_columns;
1293  }
1294 
1295  // Adjusted if last item is deleted
1296  if (((m_itemList.count() - m_topPosition) < m_itemsVisible) &&
1298  m_columns == 1)
1300 
1301  m_topPosition = std::max(m_topPosition, 0);
1302  break;
1303  }
1304  }
1305 
1306  QList<MythUIButtonListItem *>::iterator it = m_itemList.begin() +
1307  m_topPosition;
1308 
1310  {
1311  if (m_selPosition <= m_itemsVisible / 2)
1312  {
1313  button = (m_itemsVisible / 2) - m_selPosition;
1314 
1315  if (m_wrapStyle == WrapItems && button > 0 &&
1317  {
1318  it = m_itemList.end() - button;
1319  button = 0;
1320  }
1321  }
1322  else if ((m_itemCount - m_selPosition) < (m_itemsVisible / 2))
1323  {
1324  it = m_itemList.begin() + m_selPosition - (m_itemsVisible / 2);
1325  }
1326  }
1328  button = m_itemsVisible - m_itemCount;
1329 
1330  for (int i = 0; i < button; ++i)
1331  m_buttonList[i]->SetVisible(false);
1332 
1333  bool seenSelected = false;
1334 
1335  MythUIStateType *realButton = nullptr;
1336  MythUIButtonListItem *buttonItem = nullptr;
1337 
1338  if (it < m_itemList.begin())
1339  it = m_itemList.begin();
1340 
1341  int curItem = it < m_itemList.end() ? GetItemPos(*it) : 0;
1342 
1343  while (it < m_itemList.end() && button < m_itemsVisible)
1344  {
1345  realButton = m_buttonList[button];
1346  buttonItem = *it;
1347 
1348  if (!realButton || !buttonItem)
1349  break;
1350 
1351  bool selected = false;
1352 
1353  if (!seenSelected && (curItem == m_selPosition))
1354  {
1355  seenSelected = true;
1356  selected = true;
1357  }
1358 
1359  m_buttonToItem[button] = buttonItem;
1360  buttonItem->SetToRealButton(realButton, selected);
1361  realButton->SetVisible(true);
1362 
1363  if (m_wrapStyle == WrapItems && it == (m_itemList.end() - 1) &&
1365  {
1366  it = m_itemList.begin();
1367  curItem = 0;
1368  }
1369  else
1370  {
1371  ++it;
1372  ++curItem;
1373  }
1374 
1375  ++button;
1376  }
1377 
1378  for (; button < m_itemsVisible; ++button)
1379  m_buttonList[button]->SetVisible(false);
1380 }
1381 
1383 {
1384  if (m_selPosition < 0)
1385  m_selPosition = (m_wrapStyle > WrapNone) ? m_itemList.size() - 1 : 0;
1386  else if (m_selPosition >= m_itemList.size())
1387  m_selPosition = (m_wrapStyle > WrapNone) ? 0 : m_itemList.size() - 1;
1388 }
1389 
1391 {
1392  if (!m_initialized)
1393  Init();
1394 
1395  if (!m_initialized)
1396  return;
1397 
1398  if (m_clearing)
1399  return;
1400 
1401  m_needsUpdate = false;
1402 
1403  // mark the visible buttons as invisible
1404  QMap<int, MythUIButtonListItem*>::const_iterator i = m_buttonToItem.constBegin();
1405  while (i != m_buttonToItem.constEnd())
1406  {
1407  if (i.value())
1408  i.value()->setVisible(false);
1409  ++i;
1410  }
1411 
1412  // set topitem, top position
1413  SanitizePosition();
1414  m_buttonToItem.clear();
1415 
1416  if (m_arrange == ArrangeFixed)
1418  else
1420 
1421  updateLCD();
1422 
1423  m_needsUpdate = false;
1424 
1425  if (!m_downArrow || !m_upArrow)
1426  return;
1427 
1428  if (m_itemCount == 0)
1429  {
1432  }
1433  else
1434  {
1435  if (m_topPosition != 0)
1437  else
1439 
1442  else
1444 
1445  m_upArrow->MoveToTop();
1447  }
1448 }
1449 
1451 {
1452  if (item)
1453  emit itemVisible(item);
1454 }
1455 
1457 {
1458  bool wasEmpty = m_itemList.isEmpty();
1459 
1460  if (listPosition >= 0 && listPosition <= m_itemList.count())
1461  {
1462  m_itemList.insert(listPosition, item);
1463 
1464  if (listPosition <= m_selPosition)
1465  ++m_selPosition;
1466 
1467  if (listPosition <= m_topPosition)
1468  ++m_topPosition;
1469  }
1470  else
1471  m_itemList.append(item);
1472 
1473  ++m_itemCount;
1474 
1475  if (wasEmpty)
1476  {
1478  emit itemSelected(item);
1479  emit DependChanged(false);
1480  }
1481 
1482  Update();
1483 }
1484 
1486 {
1487  if (m_clearing)
1488  return;
1489 
1490  int curIndex = m_itemList.indexOf(item);
1491 
1492  if (curIndex == -1)
1493  return;
1494 
1495  QMap<int, MythUIButtonListItem*>::iterator it = m_buttonToItem.begin();
1496  while (it != m_buttonToItem.end())
1497  {
1498  if (it.value() == item)
1499  {
1500  m_buttonToItem.erase(it);
1501  break;
1502  }
1503  ++it;
1504  }
1505 
1506  if (curIndex < m_topPosition &&
1507  m_topPosition > 0)
1508  {
1509  // The removed item is before the visible part, move
1510  // everything up 1. The visible part shouldn't appear to
1511  // change.
1512  --m_topPosition;
1513  --m_selPosition;
1514  }
1515  else if (curIndex < m_selPosition ||
1516  (m_selPosition == m_itemCount - 1 &&
1517  m_selPosition > 0))
1518  {
1519  // The removed item is visible and before the selected item or
1520  // the selected item is the last item but not the only item,
1521  // move the selected item up 1.
1522  --m_selPosition;
1523  }
1524 
1525  m_itemList.removeAt(curIndex);
1526  --m_itemCount;
1527 
1528  Update();
1529 
1530  if (m_selPosition < m_itemCount)
1532  else
1533  emit itemSelected(nullptr);
1534 
1535  if (IsEmpty())
1536  emit DependChanged(true);
1537 }
1538 
1539 void MythUIButtonList::SetValueByData(const QVariant& data)
1540 {
1541  if (!m_initialized)
1542  Init();
1543 
1544  for (auto *item : qAsConst(m_itemList))
1545  {
1546  if (item->GetData() == data)
1547  {
1548  SetItemCurrent(item);
1549  return;
1550  }
1551  }
1552 }
1553 
1555 {
1556  int newIndex = m_itemList.indexOf(item);
1557  SetItemCurrent(newIndex);
1558 }
1559 
1560 void MythUIButtonList::SetItemCurrent(int current, int topPosition)
1561 {
1562  if (!m_initialized)
1563  Init();
1564 
1565  if (current == -1 || current >= m_itemList.size())
1566  return;
1567 
1568  if (!m_itemList.at(current)->isEnabled())
1569  return;
1570 
1571  if (current == m_selPosition &&
1572  (topPosition == -1 || topPosition == m_topPosition))
1573  return;
1574 
1575  m_topPosition = topPosition;
1576 
1577  if (topPosition > 0 && m_layout == LayoutGrid)
1578  m_topPosition -= (topPosition % m_columns);
1579 
1581 
1582  Update();
1583 
1584  emit itemSelected(GetItemCurrent());
1585 }
1586 
1588 {
1589  if (m_itemList.isEmpty() || m_selPosition >= m_itemList.size() ||
1590  m_selPosition < 0)
1591  return nullptr;
1592 
1593  return m_itemList.at(m_selPosition);
1594 }
1595 
1597 {
1599 
1600  if (item)
1601  return item->GetText().toInt();
1602 
1603  return 0;
1604 }
1605 
1607 {
1609 
1610  if (item)
1611  return item->GetText();
1612 
1613  return {};
1614 }
1615 
1617 {
1619 
1620  if (item)
1621  return item->GetData();
1622 
1623  return {};
1624 }
1625 
1627 {
1628  if (m_contentsRect.isValid())
1629  return m_contentsRect;
1630  return m_area;
1631 }
1632 
1634 {
1635  if (!m_itemList.empty())
1636  return m_itemList[0];
1637 
1638  return nullptr;
1639 }
1640 
1642 const
1643 {
1644  QListIterator<MythUIButtonListItem *> it(m_itemList);
1645 
1646  if (!it.findNext(item))
1647  return nullptr;
1648 
1649  return it.previous();
1650 }
1651 
1653 {
1654  return m_itemCount;
1655 }
1656 
1658 {
1659  if (m_needsUpdate)
1660  {
1663  }
1664 
1665  return m_itemsVisible;
1666 }
1667 
1669 {
1670  return m_itemCount <= 0;
1671 }
1672 
1674 {
1675  if (pos < 0 || pos >= m_itemList.size())
1676  return nullptr;
1677 
1678  return m_itemList.at(pos);
1679 }
1680 
1682 {
1683  if (!m_initialized)
1684  Init();
1685 
1686  for (auto *item : qAsConst(m_itemList))
1687  {
1688  if (item->GetData() == data)
1689  return item;
1690  }
1691 
1692  return nullptr;
1693 }
1694 
1696 {
1697  if (!item)
1698  return -1;
1699 
1700  return m_itemList.indexOf(item);
1701 }
1702 
1703 void MythUIButtonList::InitButton(int itemIdx, MythUIStateType* & realButton,
1704  MythUIButtonListItem* & buttonItem)
1705 {
1706  buttonItem = m_itemList[itemIdx];
1707 
1708  if (m_maxVisible == 0)
1709  {
1710  QString name("buttonlist button 0");
1711  auto *button = new MythUIStateType(this, name);
1712  button->CopyFrom(m_buttontemplate);
1713  button->ConnectDependants(true);
1714  m_buttonList.append(button);
1715  ++m_maxVisible;
1716  }
1717 
1718  realButton = m_buttonList[0];
1719  m_buttonToItem[0] = buttonItem;
1720 }
1721 
1722 /*
1723  * PageUp and PageDown are helpers when Dynamic layout is being used.
1724  *
1725  * When buttons are layed out dynamically, the number of buttons on the next
1726  * page, may not equal the number of buttons on the current page. Dynamic
1727  * layout is always center-weighted, so attempt to figure out which button
1728  * is near the middle on the next page.
1729  */
1730 
1732 {
1733  int pos = m_selPosition;
1734  int total = 0;
1735 
1736  /*
1737  * /On the new page/
1738  * If the number of buttons before the selected button does not equal
1739  * the number of buttons after the selected button, this logic can
1740  * undershoot the new selected button. That is better than overshooting
1741  * though.
1742  *
1743  * To fix this would require laying out the new page and then figuring
1744  * out which button should be selected, but this is already complex enough.
1745  */
1746 
1747  if (m_layout == LayoutHorizontal)
1748  {
1749  pos -= (m_leftColumns + 1);
1750 
1751  int max_width = m_contentsRect.width() / 2;
1752 
1753  for (; pos >= 0; --pos)
1754  {
1755  MythUIStateType *realButton = nullptr;
1756  MythUIButtonListItem *buttonItem = nullptr;
1757  InitButton(pos, realButton, buttonItem);
1758  buttonItem->SetToRealButton(realButton, true);
1759  auto *buttonstate = dynamic_cast<MythUIGroup *>
1760  (realButton->GetCurrentState());
1761 
1762  if (buttonstate == nullptr)
1763  {
1764  LOG(VB_GENERAL, LOG_ERR,
1765  "PageUp: Failed to query buttonlist state");
1766  return pos;
1767  }
1768 
1769  if (total + m_itemHorizSpacing +
1770  buttonstate->GetArea().width() / 2 >= max_width)
1771  return pos + 1;
1772 
1773  buttonItem->SetToRealButton(realButton, false);
1774  buttonstate = dynamic_cast<MythUIGroup *>
1775  (realButton->GetCurrentState());
1776  if (buttonstate)
1777  total += m_itemHorizSpacing + buttonstate->GetArea().width();
1778  }
1779 
1780  return 0;
1781  }
1782 
1783  // Grid or Vertical
1784  int dec = 1;
1785 
1786  if (m_layout == LayoutGrid)
1787  {
1788  /*
1789  * Adjusting using bottomRow:TopRow only works if new page
1790  * has the same ratio as the previous page, but that is common
1791  * with the grid layout, so go for it. If themers start doing
1792  * grids where this is not true, then this will need to be modified.
1793  */
1794  pos -= (m_columns * (m_topRows + 2 +
1795  std::max(m_bottomRows - m_topRows, 0)));
1796  dec = m_columns;
1797  }
1798  else
1799  {
1800  pos -= (m_topRows + 1);
1801  dec = 1;
1802  }
1803 
1804  int max_height = m_contentsRect.height() / 2;
1805 
1806  for (; pos >= 0; pos -= dec)
1807  {
1808  MythUIStateType *realButton = nullptr;
1809  MythUIButtonListItem *buttonItem = nullptr;
1810  InitButton(pos, realButton, buttonItem);
1811  buttonItem->SetToRealButton(realButton, true);
1812  auto *buttonstate = dynamic_cast<MythUIGroup *>
1813  (realButton->GetCurrentState());
1814 
1815  if (buttonstate == nullptr)
1816  {
1817  LOG(VB_GENERAL, LOG_ERR,
1818  "PageUp: Failed to query buttonlist state");
1819  return pos;
1820  }
1821 
1822  if (total + m_itemHorizSpacing +
1823  buttonstate->GetArea().height() / 2 >= max_height)
1824  return pos + dec;
1825 
1826  buttonItem->SetToRealButton(realButton, false);
1827  buttonstate = dynamic_cast<MythUIGroup *>
1828  (realButton->GetCurrentState());
1829  if (buttonstate)
1830  total += m_itemHorizSpacing + buttonstate->GetArea().height();
1831  }
1832 
1833  return 0;
1834 }
1835 
1837 {
1838  int pos = m_selPosition;
1839  int num_items = m_itemList.size();
1840  int total = 0;
1841 
1842  /*
1843  * /On the new page/
1844  * If the number of buttons before the selected button does not equal
1845  * the number of buttons after the selected button, this logic can
1846  * undershoot the new selected button. That is better than overshooting
1847  * though.
1848  *
1849  * To fix this would require laying out the new page and then figuring
1850  * out which button should be selected, but this is already complex enough.
1851  */
1852 
1853  if (m_layout == LayoutHorizontal)
1854  {
1855  pos += (m_rightColumns + 1);
1856 
1857  int max_width = m_contentsRect.width() / 2;
1858 
1859  for (; pos < num_items; ++pos)
1860  {
1861  MythUIStateType *realButton = nullptr;
1862  MythUIButtonListItem *buttonItem = nullptr;
1863  InitButton(pos, realButton, buttonItem);
1864  buttonItem->SetToRealButton(realButton, true);
1865  auto *buttonstate = dynamic_cast<MythUIGroup *>
1866  (realButton->GetCurrentState());
1867 
1868  if (buttonstate == nullptr)
1869  {
1870  LOG(VB_GENERAL, LOG_ERR,
1871  "PageDown: Failed to query buttonlist state");
1872  return pos;
1873  }
1874 
1875  if (total + m_itemHorizSpacing +
1876  buttonstate->GetArea().width() / 2 >= max_width)
1877  return pos - 1;
1878 
1879  buttonItem->SetToRealButton(realButton, false);
1880  buttonstate = dynamic_cast<MythUIGroup *>
1881  (realButton->GetCurrentState());
1882  if (buttonstate)
1883  total += m_itemHorizSpacing + buttonstate->GetArea().width();
1884  }
1885 
1886  return num_items - 1;
1887  }
1888 
1889  // Grid or Vertical
1890  int inc = 1;
1891 
1892  if (m_layout == LayoutGrid)
1893  {
1894  /*
1895  * Adjusting using bottomRow:TopRow only works if new page
1896  * has the same ratio as the previous page, but that is common
1897  * with the grid layout, so go for it. If themers start doing
1898  * grids where this is not true, then this will need to be modified.
1899  */
1900  pos += (m_columns * (m_bottomRows + 2 +
1901  std::max(m_topRows - m_bottomRows, 0)));
1902  inc = m_columns;
1903  }
1904  else
1905  {
1906  pos += (m_bottomRows + 1);
1907  inc = 1;
1908  }
1909 
1910  int max_height = m_contentsRect.height() / 2;
1911 
1912  for (; pos < num_items; pos += inc)
1913  {
1914  MythUIStateType *realButton = nullptr;
1915  MythUIButtonListItem *buttonItem = nullptr;
1916  InitButton(pos, realButton, buttonItem);
1917  buttonItem->SetToRealButton(realButton, true);
1918  auto *buttonstate = dynamic_cast<MythUIGroup *>
1919  (realButton->GetCurrentState());
1920 
1921  if (!buttonstate)
1922  {
1923  LOG(VB_GENERAL, LOG_ERR,
1924  "PageDown: Failed to query buttonlist state");
1925  return pos;
1926  }
1927 
1928  if (total + m_itemHorizSpacing +
1929  buttonstate->GetArea().height() / 2 >= max_height)
1930  return pos - inc;
1931 
1932  buttonItem->SetToRealButton(realButton, false);
1933  buttonstate = dynamic_cast<MythUIGroup *>
1934  (realButton->GetCurrentState());
1935  if (buttonstate)
1936  total += m_itemHorizSpacing + buttonstate->GetArea().height();
1937  }
1938 
1939  return num_items - 1;
1940 }
1941 
1943 {
1944  int pos = m_selPosition;
1945 
1946  if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
1947  return false;
1948 
1949  switch (unit)
1950  {
1951  case MoveItem:
1952  if (m_selPosition > 0)
1953  --m_selPosition;
1954  else if (m_wrapStyle > WrapNone)
1955  m_selPosition = m_itemList.size() - 1;
1956  else if (m_wrapStyle == WrapCaptive)
1957  return true;
1958 
1959  FindEnabledUp(unit);
1960 
1961  break;
1962 
1963  case MoveColumn:
1964  if (pos % m_columns > 0)
1965  {
1966  --m_selPosition;
1967  }
1968  else if (m_wrapStyle == WrapFlowing)
1969  {
1970  if (m_selPosition == 0)
1971  --m_selPosition = m_itemList.size() - 1;
1972  else
1973  --m_selPosition;
1974  }
1975  else if (m_wrapStyle > WrapNone)
1976  {
1977  m_selPosition = pos + (m_columns - 1);
1978  }
1979  else if (m_wrapStyle == WrapCaptive)
1980  {
1981  return true;
1982  }
1983 
1984  FindEnabledUp(unit);
1985 
1986  break;
1987 
1988  case MoveRow:
1989  if (m_scrollStyle != ScrollFree)
1990  {
1992  if (m_selPosition < 0)
1993  m_selPosition += m_itemList.size();
1994  else
1995  m_selPosition %= m_itemList.size();
1996  }
1997  else if ((pos - m_columns) >= 0)
1999  else if (m_wrapStyle > WrapNone)
2000  {
2001  m_selPosition = ((m_itemList.size() - 1) / m_columns) *
2002  m_columns + pos;
2003 
2004  if ((m_selPosition / m_columns)
2005  < ((m_itemList.size() - 1) / m_columns))
2006  m_selPosition = m_itemList.size() - 1;
2007 
2008  if (m_layout == LayoutVertical)
2009  m_topPosition = std::max(0, m_selPosition - m_itemsVisible + 1);
2010  }
2011  else if (m_wrapStyle == WrapCaptive)
2012  return true;
2013 
2014  FindEnabledUp(unit);
2015 
2016  break;
2017 
2018  case MovePage:
2019  if (m_arrange == ArrangeFixed)
2020  m_selPosition = std::max(0, m_selPosition - m_itemsVisible);
2021  else
2022  m_selPosition = PageUp();
2023 
2024  FindEnabledUp(unit);
2025 
2026  break;
2027 
2028  case MoveMid:
2029  m_selPosition = m_itemList.size() / 2;
2030  FindEnabledUp(unit);
2031  break;
2032 
2033  case MoveMax:
2034  m_selPosition = 0;
2035  FindEnabledUp(unit);
2036  break;
2037 
2038  case MoveByAmount:
2039  for (uint i = 0; i < amount; ++i)
2040  {
2041  if (m_selPosition > 0)
2042  --m_selPosition;
2043  else if (m_wrapStyle > WrapNone)
2044  m_selPosition = m_itemList.size() - 1;
2045  }
2046 
2047  FindEnabledUp(unit);
2048 
2049  break;
2050  }
2051 
2052  SanitizePosition();
2053 
2054  if (pos != m_selPosition)
2055  {
2056  Update();
2057  emit itemSelected(GetItemCurrent());
2058  }
2059  else
2060  return false;
2061 
2062  return true;
2063 }
2064 
2065 
2070 {
2071  if (m_selPosition < 0 || m_selPosition >= m_itemList.size() ||
2072  m_itemList.at(m_selPosition)->isEnabled())
2073  return;
2074 
2075  int step = (unit == MoveRow) ? m_columns : 1;
2076  if (unit == MoveRow && m_wrapStyle == WrapFlowing)
2077  unit = MoveItem;
2078  if (unit == MoveColumn)
2079  {
2080  while (m_selPosition < m_itemList.size() &&
2081  (m_selPosition + 1) % m_columns > 0 &&
2082  !m_itemList.at(m_selPosition)->isEnabled())
2083  ++m_selPosition;
2084 
2085  if (m_itemList.at(m_selPosition)->isEnabled())
2086  return;
2087 
2088  if (m_wrapStyle > WrapNone)
2089  {
2091  while ((m_selPosition + 1) % m_columns > 0 &&
2092  !m_itemList.at(m_selPosition)->isEnabled())
2093  ++m_selPosition;
2094  }
2095  }
2096  else
2097  {
2098  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2099  (m_selPosition < m_itemList.size() - step))
2100  m_selPosition += step;
2101 
2102  if (!m_itemList.at(m_selPosition)->isEnabled() &&
2104  {
2105  m_selPosition = (m_selPosition + step) % m_itemList.size();
2106 
2107  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2108  (m_selPosition < m_itemList.size() - step))
2109  m_selPosition += step;
2110  }
2111  }
2112 }
2113 
2115 {
2116  if (m_selPosition < 0 || m_selPosition >= m_itemList.size() ||
2117  m_itemList.at(m_selPosition)->isEnabled())
2118  return;
2119 
2120  int step = (unit == MoveRow) ? m_columns : 1;
2121  if (unit == MoveRow && m_wrapStyle == WrapFlowing)
2122  unit = MoveItem;
2123  if (unit == MoveColumn)
2124  {
2125  while (m_selPosition > 0 && (m_selPosition - 1) % m_columns > 0 &&
2126  !m_itemList.at(m_selPosition)->isEnabled())
2127  --m_selPosition;
2128 
2129  if (m_itemList.at(m_selPosition)->isEnabled())
2130  return;
2131 
2132  if (m_wrapStyle > WrapNone)
2133  {
2135  while ((m_selPosition - 1) % m_columns > 0 &&
2136  !m_itemList.at(m_selPosition)->isEnabled())
2137  --m_selPosition;
2138  }
2139  }
2140  else
2141  {
2142  while (!m_itemList.at(m_selPosition)->isEnabled() &&
2143  (m_selPosition - step >= 0))
2144  m_selPosition -= step;
2145 
2146  if (!m_itemList.at(m_selPosition)->isEnabled() &&
2148  {
2149  m_selPosition = m_itemList.size() - 1;
2150 
2151  while (m_selPosition > 0 &&
2152  !m_itemList.at(m_selPosition)->isEnabled() &&
2153  (m_selPosition - step >= 0))
2154  m_selPosition -= step;
2155  }
2156  }
2157 }
2158 
2159 
2161 {
2162  int pos = m_selPosition;
2163 
2164  if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
2165  return false;
2166 
2167  switch (unit)
2168  {
2169  case MoveItem:
2170  if (m_selPosition < m_itemList.size() - 1)
2171  ++m_selPosition;
2172  else if (m_wrapStyle > WrapNone)
2173  m_selPosition = 0;
2174  else if (m_wrapStyle == WrapCaptive)
2175  return true;
2176 
2177  FindEnabledDown(unit);
2178 
2179  break;
2180 
2181  case MoveColumn:
2182  if ((pos + 1) % m_columns > 0)
2183  {
2184  ++m_selPosition;
2185  }
2186  else if (m_wrapStyle == WrapFlowing)
2187  {
2188  if (m_selPosition < m_itemList.size() - 1)
2189  ++m_selPosition;
2190  else
2191  m_selPosition = 0;
2192  }
2193  else if (m_wrapStyle > WrapNone)
2194  {
2195  m_selPosition = pos - (m_columns - 1);
2196  }
2197  else if (m_wrapStyle == WrapCaptive)
2198  {
2199  return true;
2200  }
2201 
2202  FindEnabledDown(unit);
2203 
2204  break;
2205 
2206  case MoveRow:
2207  if (m_itemList.empty() || m_columns < 1)
2208  return true;
2209  if (m_scrollStyle != ScrollFree)
2210  {
2212  m_selPosition %= m_itemList.size();
2213  }
2214  else if (((m_itemList.size() - 1) / std::max(m_columns, 0))
2215  > (pos / m_columns))
2216  {
2218  if (m_selPosition >= m_itemList.size())
2219  m_selPosition = m_itemList.size() - 1;
2220  }
2221  else if (m_wrapStyle > WrapNone)
2222  m_selPosition = (pos % m_columns);
2223  else if (m_wrapStyle == WrapCaptive)
2224  return true;
2225 
2226  FindEnabledDown(unit);
2227 
2228  break;
2229 
2230  case MovePage:
2231  if (m_arrange == ArrangeFixed)
2232  {
2233  m_selPosition = std::min(m_itemCount - 1,
2235  }
2236  else
2237  {
2238  m_selPosition = PageDown();
2239  }
2240 
2241  FindEnabledDown(unit);
2242 
2243  break;
2244 
2245  case MoveMax:
2246  m_selPosition = m_itemCount - 1;
2247  FindEnabledDown(unit);
2248  break;
2249 
2250  case MoveByAmount:
2251  for (uint i = 0; i < amount; ++i)
2252  {
2253  if (m_selPosition < m_itemList.size() - 1)
2254  ++m_selPosition;
2255  else if (m_wrapStyle > WrapNone)
2256  m_selPosition = 0;
2257  }
2258  FindEnabledDown(unit);
2259  break;
2260 
2261  case MoveMid:
2262  break;
2263  }
2264 
2265  SanitizePosition();
2266 
2267  if (pos != m_selPosition)
2268  {
2269  m_keepSelAtBottom = true;
2270  Update();
2271  emit itemSelected(GetItemCurrent());
2272  }
2273  else
2274  return false;
2275 
2276  return true;
2277 }
2278 
2279 bool MythUIButtonList::MoveToNamedPosition(const QString &position_name)
2280 {
2281  if (!m_initialized)
2282  Init();
2283 
2284  if (m_selPosition < 0 || m_itemList.isEmpty() || !m_initialized)
2285  return false;
2286 
2287  bool found_it = false;
2288  int selectedPosition = 0;
2289  QList<MythUIButtonListItem *>::iterator it = m_itemList.begin();
2290 
2291  while (it != m_itemList.end())
2292  {
2293  if ((*it)->GetText() == position_name)
2294  {
2295  found_it = true;
2296  break;
2297  }
2298 
2299  ++it;
2300  ++selectedPosition;
2301  }
2302 
2303  if (!found_it || m_selPosition == selectedPosition)
2304  return false;
2305 
2306  SetItemCurrent(selectedPosition);
2307  return true;
2308 }
2309 
2311 {
2312  if (GetItemCurrent() != item)
2313  return false;
2314 
2315  if (item == m_itemList.first() && up)
2316  return false;
2317 
2318  if (item == m_itemList.last() && !up)
2319  return false;
2320 
2321  int oldpos = m_selPosition;
2322  int insertat = 0;
2323  bool dolast = false;
2324 
2325  if (up)
2326  {
2327  insertat = m_selPosition - 1;
2328 
2329  if (item == m_itemList.last())
2330  dolast = true;
2331  else
2332  ++m_selPosition;
2333 
2334  if (item == m_itemList.at(m_topPosition))
2335  ++m_topPosition;
2336  }
2337  else
2338  insertat = m_selPosition + 1;
2339 
2340  m_itemList.removeAt(oldpos);
2341  m_itemList.insert(insertat, item);
2342 
2343  if (up)
2344  {
2345  MoveUp();
2346 
2347  if (!dolast)
2348  MoveUp();
2349  }
2350  else
2351  MoveDown();
2352 
2353  return true;
2354 }
2355 
2357 {
2358  QMutableListIterator<MythUIButtonListItem *> it(m_itemList);
2359 
2360  while (it.hasNext())
2361  it.next()->setChecked(state);
2362 }
2363 
2365 {
2366  if (m_initialized)
2367  return;
2368 
2369  m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
2370  m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
2371  m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
2372 
2373  if (m_upArrow)
2374  m_upArrow->SetVisible(true);
2375 
2376  if (m_downArrow)
2377  m_downArrow->SetVisible(true);
2378 
2379  if (m_scrollBar)
2381 
2383 
2384  m_buttontemplate = dynamic_cast<MythUIStateType *>(GetChild("buttonitem"));
2385 
2386  if (!m_buttontemplate)
2387  {
2388  LOG(VB_GENERAL, LOG_ERR, QString("(%1) Statetype buttonitem is "
2389  "required in mythuibuttonlist: %2")
2390  .arg(GetXMLLocation(), objectName()));
2391  return;
2392  }
2393 
2394  m_buttontemplate->SetVisible(false);
2395 
2396  MythRect buttonItemArea;
2397 
2398  MythUIGroup *buttonActiveState = dynamic_cast<MythUIGroup *>
2399  (m_buttontemplate->GetState("active"));
2400 
2401  if (buttonActiveState)
2402  buttonItemArea = buttonActiveState->GetArea();
2403  else
2404  buttonItemArea = m_buttontemplate->GetArea();
2405 
2406  buttonItemArea.CalculateArea(m_contentsRect);
2407 
2408  m_itemHeight = buttonItemArea.height();
2409  m_itemWidth = buttonItemArea.width();
2410 
2411  /*
2412  * If fixed spacing is defined, then use the "active" state size
2413  * to predictively determine the position of each button.
2414  */
2415  if (m_arrange == ArrangeFixed)
2416  {
2417 
2419 
2420  int col = 1;
2421  int row = 1;
2422 
2423  for (int i = 0; i < m_itemsVisible; ++i)
2424  {
2425  QString name = QString("buttonlist button %1").arg(i);
2426  auto *button = new MythUIStateType(this, name);
2427  button->CopyFrom(m_buttontemplate);
2428  button->ConnectDependants(true);
2429 
2430  if (col > m_columns)
2431  {
2432  col = 1;
2433  ++row;
2434  }
2435 
2436  button->SetPosition(GetButtonPosition(col, row));
2437  ++col;
2438 
2439  m_buttonList.push_back(button);
2440  }
2441  }
2442 
2443  // The following is pretty much a hack for the benefit of MythGallery
2444  // it scales images based on the button size and we need to give it the
2445  // largest button state so that the images are not too small
2446  // This can be removed once the disk based image caching is added to
2447  // mythui, since the mythgallery thumbnail generator can be ditched.
2448  MythUIGroup *buttonSelectedState = dynamic_cast<MythUIGroup *>
2449  (m_buttontemplate->GetState("selected"));
2450 
2451  if (buttonSelectedState)
2452  {
2453  MythRect itemArea = buttonSelectedState->GetArea();
2454  itemArea.CalculateArea(m_contentsRect);
2455 
2456  if (m_itemHeight < itemArea.height())
2457  m_itemHeight = itemArea.height();
2458 
2459  if (m_itemWidth < itemArea.width())
2460  m_itemWidth = itemArea.width();
2461  }
2462 
2463  // End Hack
2464 
2465  m_initialized = true;
2466 }
2467 
2469 {
2470  if (!m_initialized)
2471  Init();
2472 
2473  return static_cast<uint>(m_itemWidth);
2474 }
2475 
2477 {
2478  if (!m_initialized)
2479  Init();
2480 
2481  return static_cast<uint>(m_itemHeight);
2482 }
2483 
2487 bool MythUIButtonList::keyPressEvent(QKeyEvent *event)
2488 {
2489  QStringList actions;
2490  bool handled = false;
2491  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
2492 
2493  // Handle action remappings
2494  for (const QString& action : qAsConst(actions))
2495  {
2496  if (!m_actionRemap.contains(action))
2497  continue;
2498 
2499  QString key = m_actionRemap[action];
2500  if (key.isEmpty())
2501  return true;
2502 
2503  QKeySequence a(key);
2504  if (a.isEmpty())
2505  continue;
2506 
2507 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2508  int keyCode = a[0];
2509  Qt::KeyboardModifiers modifiers = Qt::NoModifier;
2510  QStringList parts = key.split('+');
2511  for (int j = 0; j < parts.count(); ++j)
2512  {
2513  if (parts[j].toUpper() == "CTRL")
2514  modifiers |= Qt::ControlModifier;
2515  if (parts[j].toUpper() == "SHIFT")
2516  modifiers |= Qt::ShiftModifier;
2517  if (parts[j].toUpper() == "ALT")
2518  modifiers |= Qt::AltModifier;
2519  if (parts[j].toUpper() == "META")
2520  modifiers |= Qt::MetaModifier;
2521  }
2522 #else
2523  int keyCode = a[0].key();
2524  Qt::KeyboardModifiers modifiers = a[0].keyboardModifiers();
2525 #endif
2526 
2527  QCoreApplication::postEvent(
2529  new QKeyEvent(QEvent::KeyPress, keyCode, modifiers, key));
2530  QCoreApplication::postEvent(
2532  new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers, key));
2533 
2534  return true;
2535  }
2536 
2537  // handle actions for this container
2538  for (int i = 0; i < actions.size() && !handled; ++i)
2539  {
2540  QString action = actions[i];
2541  handled = true;
2542 
2543  if (action == "UP")
2544  {
2545  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2546  handled = MoveUp(MoveRow);
2547  else
2548  handled = false;
2549  }
2550  else if (action == "DOWN")
2551  {
2552  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2553  handled = MoveDown(MoveRow);
2554  else
2555  handled = false;
2556  }
2557  else if (action == "RIGHT")
2558  {
2559  if (m_layout == LayoutHorizontal)
2560  handled = MoveDown(MoveItem);
2561  else if (m_layout == LayoutGrid)
2562  {
2563  if (m_scrollStyle == ScrollFree)
2564  handled = MoveDown(MoveColumn);
2565  else
2566  handled = MoveDown(MoveItem);
2567  }
2568  else
2569  handled = false;
2570  }
2571  else if (action == "LEFT")
2572  {
2573  if (m_layout == LayoutHorizontal)
2574  handled = MoveUp(MoveItem);
2575  else if (m_layout == LayoutGrid)
2576  {
2577  if (m_scrollStyle == ScrollFree)
2578  handled = MoveUp(MoveColumn);
2579  else
2580  handled = MoveUp(MoveItem);
2581  }
2582  else
2583  handled = false;
2584  }
2585  else if (action == "PAGEUP")
2586  {
2587  MoveUp(MovePage);
2588  }
2589  else if (action == "PAGEDOWN")
2590  {
2591  MoveDown(MovePage);
2592  }
2593  else if (action == "PAGETOP")
2594  {
2595  MoveUp(MoveMax);
2596  }
2597  else if (action == "PAGEMIDDLE")
2598  {
2599  MoveUp(MoveMid);
2600  }
2601  else if (action == "PAGEBOTTOM")
2602  {
2603  MoveDown(MoveMax);
2604  }
2605  else if (action == "SELECT")
2606  {
2608 
2609  if (item && item->isEnabled())
2610  emit itemClicked(item);
2611  }
2612  else if (action == "SEARCH")
2613  {
2614  ShowSearchDialog();
2615  }
2616  else
2617  handled = false;
2618  }
2619 
2620  return handled;
2621 }
2622 
2627 {
2628  bool handled = false;
2629 
2630  switch (event->GetGesture())
2631  {
2633  {
2634  // We want the relative position of the click
2635  QPoint position = event->GetPosition() -
2636  m_parent->GetArea().topLeft();
2637 
2638  MythUIType *type = GetChildAt(position, false, false);
2639 
2640  if (!type)
2641  return false;
2642 
2643  auto *object = dynamic_cast<MythUIStateType *>(type);
2644  if (object)
2645  {
2646  handled = true;
2647  QString name = object->objectName();
2648 
2649  if (name == "upscrollarrow")
2650  {
2651  MoveUp(MovePage);
2652  }
2653  else if (name == "downscrollarrow")
2654  {
2655  MoveDown(MovePage);
2656  }
2657  else if (name.startsWith("buttonlist button"))
2658  {
2659  int pos = name.section(' ', 2, 2).toInt();
2660  MythUIButtonListItem *item = m_buttonToItem.value(pos);
2661 
2662  if (item)
2663  {
2664  if (item == GetItemCurrent())
2665  emit itemClicked(item);
2666  else
2667  SetItemCurrent(item);
2668  }
2669  }
2670  else
2671  handled = false;
2672  }
2673  }
2674  break;
2675 
2676  case MythGestureEvent::Up:
2679  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2680  handled = MoveUp(MoveRow);
2681  break;
2682 
2686  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2687  handled = MoveDown(MoveRow);
2688  break;
2689 
2691  if (m_layout == LayoutHorizontal)
2692  handled = MoveDown(MoveItem);
2693  else if (m_layout == LayoutGrid)
2694  {
2695  if (m_scrollStyle == ScrollFree)
2696  handled = MoveDown(MoveColumn);
2697  else
2698  handled = MoveDown(MoveItem);
2699  }
2700  break;
2701 
2703  if (m_layout == LayoutHorizontal)
2704  handled = MoveUp(MoveItem);
2705  else if (m_layout == LayoutGrid)
2706  {
2707  if (m_scrollStyle == ScrollFree)
2708  handled = MoveUp(MoveColumn);
2709  else
2710  handled = MoveUp(MoveItem);
2711  }
2712  break;
2713 
2714  default:
2715  break;
2716  }
2717 
2718  return handled;
2719 }
2720 
2721 class NextButtonListPageEvent : public QEvent
2722 {
2723  public:
2724  NextButtonListPageEvent(int start, int pageSize) :
2725  QEvent(kEventType), m_start(start), m_pageSize(pageSize) {}
2726  const int m_start;
2727  const int m_pageSize;
2728  static const Type kEventType;
2729 };
2730 
2731 const QEvent::Type NextButtonListPageEvent::kEventType =
2732  (QEvent::Type) QEvent::registerEventType();
2733 
2735 {
2736  if (event->type() == NextButtonListPageEvent::kEventType)
2737  {
2738  if (auto *npe = dynamic_cast<NextButtonListPageEvent*>(event); npe)
2739  {
2740  int cur = npe->m_start;
2741  for (; cur < npe->m_start + npe->m_pageSize && cur < GetCount(); ++cur)
2742  {
2743  const int loginterval = (cur < 1000 ? 100 : 500);
2744  if (cur > 200 && cur % loginterval == 0)
2745  LOG(VB_GUI, LOG_INFO,
2746  QString("Build background buttonlist item %1").arg(cur));
2747  emit itemLoaded(GetItemAt(cur));
2748  }
2749  m_nextItemLoaded = cur;
2750  if (cur < GetCount())
2751  LoadInBackground(cur, npe->m_pageSize);
2752  }
2753  }
2754 }
2755 
2756 void MythUIButtonList::LoadInBackground(int start, int pageSize)
2757 {
2758  m_nextItemLoaded = start;
2759  QCoreApplication::
2760  postEvent(this, new NextButtonListPageEvent(start, pageSize));
2761 }
2762 
2764 {
2765  QCoreApplication::
2766  removePostedEvents(this, NextButtonListPageEvent::kEventType);
2767  return m_nextItemLoaded;
2768 }
2769 
2770 QPoint MythUIButtonList::GetButtonPosition(int column, int row) const
2771 {
2772  int x = m_contentsRect.x() +
2773  ((column - 1) * (m_itemWidth + m_itemHorizSpacing));
2774  int y = m_contentsRect.y() +
2775  ((row - 1) * (m_itemHeight + m_itemVertSpacing));
2776 
2777  return {x, y};
2778 }
2779 
2781 {
2782  m_itemsVisible = 0;
2783  m_rows = 0;
2784  m_columns = 0;
2785 
2786  if ((m_layout == LayoutHorizontal) || (m_layout == LayoutGrid))
2787  {
2788  int x = 0;
2789 
2790  while (x <= m_contentsRect.width() - m_itemWidth)
2791  {
2793  ++m_columns;
2794  }
2795  }
2796 
2797  if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
2798  {
2799  int y = 0;
2800 
2801  while (y <= m_contentsRect.height() - m_itemHeight)
2802  {
2804  ++m_rows;
2805  }
2806  }
2807 
2808  if (m_rows <= 0)
2809  m_rows = 1;
2810 
2811  if (m_columns <= 0)
2812  m_columns = 1;
2813 
2815 }
2816 
2818 {
2819  if (rect == m_contentsRect)
2820  return;
2821 
2822  m_contentsRect = rect;
2823 
2824  if (m_area.isValid())
2826  else if (m_parent)
2828  else
2829  m_contentsRect.CalculateArea(GetMythMainWindow()->GetUIScreenRect());
2830 }
2831 
2836  const QString &filename, QDomElement &element, bool showWarnings)
2837 {
2838  if (element.tagName() == "buttonarea")
2839  SetButtonArea(parseRect(element));
2840  else if (element.tagName() == "layout")
2841  {
2842  QString layout = getFirstText(element).toLower();
2843 
2844  if (layout == "grid")
2845  m_layout = LayoutGrid;
2846  else if (layout == "horizontal")
2848  else
2850  }
2851  else if (element.tagName() == "arrange")
2852  {
2853  QString arrange = getFirstText(element).toLower();
2854 
2855  if (arrange == "fill")
2857  else if (arrange == "spread")
2859  else if (arrange == "stack")
2861  else
2863 
2864  }
2865  else if (element.tagName() == "align")
2866  {
2867  QString align = getFirstText(element).toLower();
2868  m_alignment = parseAlignment(align);
2869  }
2870  else if (element.tagName() == "scrollstyle")
2871  {
2872  QString layout = getFirstText(element).toLower();
2873 
2874  if (layout == "center")
2876  else if (layout == "groupcenter")
2878  else if (layout == "free")
2880  }
2881  else if (element.tagName() == "wrapstyle")
2882  {
2883  QString wrapstyle = getFirstText(element).toLower();
2884 
2885  if (wrapstyle == "captive")
2887  else if (wrapstyle == "none")
2889  else if (wrapstyle == "selection")
2891  else if (wrapstyle == "flowing")
2893  else if (wrapstyle == "items")
2895  }
2896  else if (element.tagName() == "showarrow")
2897  m_showArrow = parseBool(element);
2898  else if (element.tagName() == "showscrollbar")
2899  m_showScrollBar = parseBool(element);
2900  else if (element.tagName() == "spacing")
2901  {
2902  m_itemHorizSpacing = NormX(getFirstText(element).toInt());
2903  m_itemVertSpacing = NormY(getFirstText(element).toInt());
2904  }
2905  else if (element.tagName() == "drawfrombottom")
2906  {
2907  m_drawFromBottom = parseBool(element);
2908 
2909  if (m_drawFromBottom)
2910  m_alignment |= Qt::AlignBottom;
2911  }
2912  else if (element.tagName() == "searchposition")
2913  {
2914  m_searchPosition = parsePoint(element);
2915  }
2916  else if (element.tagName() == "triggerevent")
2917  {
2918  QString trigger = getFirstText(element);
2919  if (!trigger.isEmpty())
2920  {
2921  QString action = element.attribute("action", "");
2922  if (action.isEmpty())
2923  {
2924  m_actionRemap[trigger] = "";
2925  }
2926  else
2927  {
2928  QString context = element.attribute("context", "");
2929  QString keylist = MythMainWindow::GetKey(context, action);
2930 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2931  QStringList keys = keylist.split(',', QString::SkipEmptyParts);
2932 #else
2933  QStringList keys = keylist.split(',', Qt::SkipEmptyParts);
2934 #endif
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 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
3388  QStringList fields = fieldList.split(',', QString::SkipEmptyParts);
3389 #else
3390  QStringList fields = fieldList.split(',', Qt::SkipEmptyParts);
3391 #endif
3392 
3393  for (int x = 0; x < fields.count(); ++x)
3394  {
3395  if (m_strings.contains(fields.at(x).trimmed()))
3396  {
3397  if (startsWith)
3398  {
3399  if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
3400  return true;
3401  }
3402  else
3403  {
3404  if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
3405  return true;
3406  }
3407  }
3408  }
3409  }
3410 
3411  return false;
3412 }
3413 
3414 void MythUIButtonListItem::SetFontState(const QString &state,
3415  const QString &name)
3416 {
3417  if (!name.isEmpty())
3418  {
3419  if (m_strings.contains(name))
3420  m_strings[name].state = state;
3421  }
3422  else
3423  m_fontState = state;
3424 
3425  if (m_parent && m_isVisible)
3426  m_parent->Update();
3427 }
3428 
3429 void MythUIButtonListItem::SetImage(MythImage *image, const QString &name)
3430 {
3431  if (image)
3432  image->IncrRef();
3433 
3434  if (!name.isEmpty())
3435  {
3436  QMap<QString, MythImage*>::iterator it = m_images.find(name);
3437  if (it != m_images.end())
3438  {
3439  (*it)->DecrRef();
3440  if (image)
3441  *it = image;
3442  else
3443  m_images.erase(it);
3444  }
3445  else if (image)
3446  {
3447  m_images[name] = image;
3448  }
3449  }
3450  else
3451  {
3452  if (m_image)
3453  m_image->DecrRef();
3454  m_image = image;
3455  }
3456 
3457  if (m_parent && m_isVisible)
3458  m_parent->Update();
3459 }
3460 
3462 {
3463  m_imageFilenames.clear();
3464  m_imageFilenames = imageMap;
3465 }
3466 
3468 {
3469  m_imageCb.fn = fn;
3470  m_imageCb.data = data;
3471 }
3472 
3474 {
3475  if (!name.isEmpty())
3476  {
3477  QMap<QString, MythImage*>::iterator it = m_images.find(name);
3478  if (it != m_images.end())
3479  {
3480  (*it)->IncrRef();
3481  return (*it);
3482  }
3483  }
3484  else if (m_image)
3485  {
3486  m_image->IncrRef();
3487  return m_image;
3488  }
3489 
3490  return nullptr;
3491 }
3492 
3494  const QString &filename, const QString &name, bool force_reload)
3495 {
3496  bool do_update = force_reload;
3497 
3498  if (!name.isEmpty())
3499  {
3500  InfoMap::iterator it = m_imageFilenames.find(name);
3501 
3502  if (it == m_imageFilenames.end())
3503  {
3504  m_imageFilenames.insert(name, filename);
3505  do_update = true;
3506  }
3507  else if (*it != filename)
3508  {
3509  *it = filename;
3510  do_update = true;
3511  }
3512  }
3513  else if (m_imageFilename != filename)
3514  {
3516  do_update = true;
3517  }
3518 
3519  if (m_parent && do_update && m_isVisible)
3520  m_parent->Update();
3521 }
3522 
3523 QString MythUIButtonListItem::GetImageFilename(const QString &name) const
3524 {
3525  if (name.isEmpty())
3526  return m_imageFilename;
3527 
3528  if (m_imageCb.fn != nullptr)
3529  {
3530  QString result = m_imageCb.fn(name, m_imageCb.data);
3531  if (!result.isEmpty())
3532  return result;
3533  }
3534 
3535  InfoMap::const_iterator it = m_imageFilenames.find(name);
3536 
3537  if (it != m_imageFilenames.end())
3538  return *it;
3539 
3540  return {};
3541 }
3542 
3543 void MythUIButtonListItem::SetProgress1(int start, int total, int used)
3544 {
3545  m_progress1.used = used;
3546  m_progress1.start = start;
3547  m_progress1.total = total;
3548 
3549  if (m_parent && m_isVisible)
3550  m_parent->Update();
3551 }
3552 
3553 void MythUIButtonListItem::SetProgress2(int start, int total, int used)
3554 {
3555  m_progress2.used = used;
3556  m_progress2.start = start;
3557  m_progress2.total = total;
3558 
3559  if (m_parent && m_isVisible)
3560  m_parent->Update();
3561 }
3562 
3563 void MythUIButtonListItem::DisplayState(const QString &state,
3564  const QString &name)
3565 {
3566  if (name.isEmpty())
3567  return;
3568 
3569  bool do_update = false;
3570  InfoMap::iterator it = m_states.find(name);
3571 
3572  if (it == m_states.end())
3573  {
3574  m_states.insert(name, state);
3575  do_update = true;
3576  }
3577  else if (*it != state)
3578  {
3579  *it = state;
3580  do_update = true;
3581  }
3582 
3583  if (m_parent && do_update && m_isVisible)
3584  m_parent->Update();
3585 }
3586 
3588 {
3589  m_states.clear();
3590  m_states = stateMap;
3591 }
3592 
3594 {
3595  m_stateCb.fn = fn;
3596  m_stateCb.data = data;
3597 }
3598 
3599 QString MythUIButtonListItem::GetState(const QString &name)
3600 {
3601  if (name.isEmpty())
3602  return {};
3603  if (m_stateCb.fn != nullptr)
3604  {
3605  QString result = m_stateCb.fn(name, m_textCb.data);
3606  if (!result.isEmpty())
3607  return result;
3608  }
3609  if (m_states.contains(name))
3610  return m_states[name];
3611  return {};
3612 }
3613 
3615 {
3616  return m_checkable;
3617 }
3618 
3620 {
3621  return m_state;
3622 }
3623 
3625 {
3626  return m_parent;
3627 }
3628 
3630 {
3631  if (!m_checkable || m_state == state)
3632  return;
3633 
3634  m_state = state;
3635 
3636  if (m_parent && m_isVisible)
3637  m_parent->Update();
3638 }
3639 
3641 {
3642  m_checkable = flag;
3643 }
3644 
3646 {
3647  m_showArrow = flag;
3648 }
3649 
3651 {
3652  return m_enabled;
3653 }
3654 
3656 {
3657  m_enabled = flag;
3658 }
3659 
3661 {
3662  m_data = std::move(data);
3663 }
3664 
3666 {
3667  return m_data;
3668 }
3669 
3671 {
3672  if (m_parent)
3673  return m_parent->MoveItemUpDown(this, flag);
3674  return false;
3675 }
3676 
3678 {
3679  if (!buttontext)
3680  return;
3681 
3682  buttontext->SetText(m_text);
3683  buttontext->SetFontState(m_fontState);
3684 }
3685 
3687 {
3688  if (!buttonimage)
3689  return;
3690 
3691  if (!m_imageFilename.isEmpty())
3692  {
3693  buttonimage->SetFilename(m_imageFilename);
3694  buttonimage->Load();
3695  }
3696  else if (m_image)
3697  buttonimage->SetImage(m_image);
3698 }
3699 
3701 {
3702  if (!buttonarrow)
3703  return;
3704  buttonarrow->SetVisible(m_showArrow);
3705 }
3706 
3708 {
3709  if (!buttoncheck)
3710  return;
3711 
3712  buttoncheck->SetVisible(m_checkable);
3713 
3714  if (!m_checkable)
3715  return;
3716 
3717  if (m_state == NotChecked)
3718  buttoncheck->DisplayState(MythUIStateType::Off);
3719  else if (m_state == HalfChecked)
3720  buttoncheck->DisplayState(MythUIStateType::Half);
3721  else
3722  buttoncheck->DisplayState(MythUIStateType::Full);
3723 }
3724 
3726 {
3727  if (!buttonprogress)
3728  return;
3729 
3730  buttonprogress->Set(m_progress1.start, m_progress1.total, m_progress1.used);
3731 }
3732 
3734 {
3735  if (!buttonprogress)
3736  return;
3737 
3738  buttonprogress->Set(m_progress2.start, m_progress2.total, m_progress2.used);
3739 }
3740 
3742  const TextProperties& textprop)
3743 {
3744  if (!text)
3745  return;
3746 
3747  QString newText = text->GetTemplateText();
3748 
3749  static const QRegularExpression re {R"(%(([^\|%]+)?\||\|(.))?([\w#]+)(\|(.+?))?%)",
3750  QRegularExpression::DotMatchesEverythingOption};
3751 
3752  if (!newText.isEmpty() && newText.contains(re))
3753  {
3754  QString tempString = newText;
3755 
3756  QRegularExpressionMatchIterator i = re.globalMatch(newText);
3757  while (i.hasNext()) {
3758  QRegularExpressionMatch match = i.next();
3759  QString key = match.captured(4).toLower().trimmed();
3760  QString replacement;
3761  QString value = GetText(key);
3762 
3763  if (!value.isEmpty())
3764  {
3765  replacement = QString("%1%2%3%4")
3766  .arg(match.captured(2),
3767  match.captured(3),
3768  value,
3769  match.captured(6));
3770  }
3771 
3772  tempString.replace(match.captured(0), replacement);
3773  }
3774 
3775  newText = tempString;
3776  }
3777  else
3778  newText = textprop.text;
3779 
3780  if (newText.isEmpty())
3781  text->Reset();
3782  else
3783  text->SetText(newText);
3784 
3785  text->SetFontState(textprop.state.isEmpty() ? m_fontState : textprop.state);
3786 }
3787 
3789 {
3790  if (!image)
3791  return;
3792 
3793  if (!filename.isEmpty())
3794  {
3795  image->SetFilename(filename);
3796  image->Load();
3797  }
3798  else
3799  image->Reset();
3800 }
3801 
3803 {
3804  if (!uiimage)
3805  return;
3806 
3807  if (image)
3808  uiimage->SetImage(image);
3809  else
3810  uiimage->Reset();
3811 }
3812 
3813 void MythUIButtonListItem::DoButtonLookupState (MythUIStateType *statetype, const QString& name)
3814 {
3815  if (!statetype)
3816  return;
3817 
3818  if (!statetype->DisplayState(name))
3819  statetype->Reset();
3820 }
3821 
3823 {
3824  if (!m_parent)
3825  return;
3826 
3827  m_parent->ItemVisible(this);
3828  m_isVisible = true;
3829 
3830  QString state;
3831 
3832  if (!m_parent->IsEnabled())
3833  state = "disabled";
3834  else if (!m_enabled)
3835  {
3836  state = m_parent->m_active ? "disabledactive" : "disabledinactive";
3837  }
3838  else if (selected)
3839  {
3840  button->MoveToTop();
3841  state = m_parent->m_active ? "selectedactive" : "selectedinactive";
3842  }
3843  else
3844  state = m_parent->m_active ? "active" : "inactive";
3845 
3846  // Begin compatibility code
3847  // Attempt to fallback if the theme is missing certain states
3848  if (state == "disabled" && !button->GetState(state))
3849  {
3850  LOG(VB_GUI, LOG_WARNING, "Theme Error: Missing buttonlist state: disabled");
3851  state = "inactive";
3852  }
3853 
3854  if (state == "inactive" && !button->GetState(state))
3855  {
3856  LOG(VB_GUI, LOG_WARNING, "Theme Error: Missing buttonlist state: inactive");
3857  state = "active";
3858  }
3859  // End compatibility code
3860 
3861  auto *buttonstate = dynamic_cast<MythUIGroup *>(button->GetState(state));
3862  if (!buttonstate)
3863  {
3864  LOG(VB_GENERAL, LOG_CRIT, QString("Theme Error: Missing buttonlist state: %1")
3865  .arg(state));
3866  return;
3867  }
3868 
3869  buttonstate->Reset();
3870 
3871  QList<MythUIType *> descendants = buttonstate->GetAllDescendants();
3872  for (MythUIType *obj : descendants)
3873  {
3874  QString name = obj->objectName();
3875  if (name == "buttontext")
3876  DoButtonText(dynamic_cast<MythUIText *>(obj));
3877  else if (name == "buttonimage")
3878  DoButtonImage(dynamic_cast<MythUIImage *>(obj));
3879  else if (name == "buttonarrow")
3880  DoButtonArrow(dynamic_cast<MythUIImage *>(obj));
3881  else if (name == "buttoncheck")
3882  DoButtonCheck(dynamic_cast<MythUIStateType *>(obj));
3883  else if (name == "buttonprogress1")
3884  DoButtonProgress1(dynamic_cast<MythUIProgressBar *>(obj));
3885  else if (name == "buttonprogress2")
3886  DoButtonProgress2(dynamic_cast<MythUIProgressBar *>(obj));
3887 
3888  TextProperties textprop = GetTextProp(name);
3889  if (!textprop.text.isEmpty())
3890  DoButtonLookupText(dynamic_cast<MythUIText *>(obj), textprop);
3891 
3892  QString filename = GetImageFilename(name);
3893  if (!filename.isEmpty())
3894  DoButtonLookupFilename (dynamic_cast<MythUIImage *>(obj), filename);
3895 
3896  if (m_images.contains(name))
3897  DoButtonLookupImage(dynamic_cast<MythUIImage *>(obj), m_images[name]);
3898 
3899  QString luState = GetState(name);
3900  if (!luState.isEmpty())
3901  DoButtonLookupState(dynamic_cast<MythUIStateType *>(obj), luState);
3902  }
3903 
3904  // There is no need to check the return value here, since we already
3905  // checked that the state exists with GetState() earlier
3906  button->DisplayState(state);
3907 }
3908 
3909 //---------------------------------------------------------
3910 // SearchButtonListDialog
3911 //---------------------------------------------------------
3913 {
3914  if (!CopyWindowFromBase("MythSearchListDialog", this))
3915  return false;
3916 
3917  bool err = false;
3918  UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
3919  UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
3920  UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
3921  UIUtilW::Assign(this, m_searchState, "searchstate");
3922 
3923  if (err)
3924  {
3925  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'MythSearchListDialog'");
3926  return false;
3927  }
3928 
3930 
3934 
3935  BuildFocusList();
3936 
3937  return true;
3938 }
3939 
3941 {
3942  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
3943  return true;
3944 
3945  QStringList actions;
3946  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions, false);
3947 
3948  for (int i = 0; i < actions.size() && !handled; ++i)
3949  {
3950  QString action = actions[i];
3951  handled = true;
3952 
3953  if (action == "0")
3954  {
3956  searchChanged();
3957  }
3958  else
3959  handled = false;
3960  }
3961 
3962  if (!handled && MythScreenType::keyPressEvent(event))
3963  handled = true;
3964 
3965  return handled;
3966 }
3967 
3969 {
3970  bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);
3971 
3972  if (m_searchState)
3973  m_searchState->DisplayState(found ? "found" : "notfound");
3974 }
3975 
3977 {
3978  bool found = m_parentList->FindNext();
3979 
3980  if (m_searchState)
3981  m_searchState->DisplayState(found ? "found" : "notfound");
3982 }
3983 
3985 {
3986  bool found = m_parentList->FindPrev();
3987 
3988  if (m_searchState)
3989  m_searchState->DisplayState(found ? "found" : "notfound");
3990 }
3991 
3993 {
3995  return;
3996 
3997  int maximum = (m_itemCount <= m_itemsVisible) ? 0 : m_itemCount;
3998  m_scrollBar->SetMaximum(maximum);
4002 }
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:1673
MythUIType::m_area
MythRect m_area
Definition: mythuitype.h:274
MythUIButtonList::StopLoad
int StopLoad(void)
Definition: mythuibuttonlist.cpp:2763
MythUIButtonListItem::DoButtonArrow
void DoButtonArrow(MythUIImage *buttonarrow) const
Definition: mythuibuttonlist.cpp:3700
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:1587
MythUIButtonList::m_itemList
QList< MythUIButtonListItem * > m_itemList
Definition: mythuibuttonlist.h:387
LCD::getLCDHeight
int getLCDHeight(void) const
Definition: lcddevice.h:296
MythUIButtonListItem::HalfChecked
@ HalfChecked
Definition: mythuibuttonlist.h:47
MythUIButtonList::SetValueByData
void SetValueByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1539
mythuitext.h
mythuiprogressbar.h
XMLParseBase::parseAlignment
static int parseAlignment(const QString &text)
Definition: xmlparsebase.cpp:161
MythUIButtonList::Const
void Const()
Definition: mythuibuttonlist.cpp:58
SearchButtonListDialog::nextClicked
void nextClicked(void)
Definition: mythuibuttonlist.cpp:3976
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:148
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:1641
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:2770
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:3563
MythUIType::GetChildAt
MythUIType * GetChildAt(QPoint p, bool recursive=true, bool focusable=true) const
Return the first MythUIType at the given coordinates.
Definition: mythuitype.cpp:236
MythUIButtonListItem::m_strings
QMap< QString, TextProperties > m_strings
Definition: mythuibuttonlist.h:170
NextButtonListPageEvent::NextButtonListPageEvent
NextButtonListPageEvent(int start, int pageSize)
Definition: mythuibuttonlist.cpp:2724
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:2727
MythUIType::GetFullArea
virtual MythRect GetFullArea(void) const
Definition: mythuitype.cpp:892
MythUIButtonListItem::DoButtonLookupFilename
static void DoButtonLookupFilename(MythUIImage *image, const QString &filename)
Definition: mythuibuttonlist.cpp:3788
MythUIButtonListItem::SetImageFromMap
void SetImageFromMap(const InfoMap &imageMap)
Definition: mythuibuttonlist.cpp:3461
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:2160
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:2626
MythUIButtonListItem::DoButtonLookupState
static void DoButtonLookupState(MythUIStateType *statetype, const QString &name)
Definition: mythuibuttonlist.cpp:3813
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:133
MythUIButtonList::m_showArrow
bool m_showArrow
Definition: mythuibuttonlist.h:365
MythUIButtonList::RemoveItem
void RemoveItem(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1485
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:3733
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:2114
MythUIButtonList::ArrangeStack
@ ArrangeStack
Definition: mythuibuttonlist.h:276
NextButtonListPageEvent::kEventType
static const Type kEventType
Definition: mythuibuttonlist.cpp:2728
MythUIButtonListItem::SetStatesFromMap
void SetStatesFromMap(const InfoMap &stateMap)
Definition: mythuibuttonlist.cpp:3587
MythUIType::SetCanTakeFocus
void SetCanTakeFocus(bool set=true)
Set whether this widget can take focus.
Definition: mythuitype.cpp:357
MythUIButtonListItem::m_fontState
QString m_fontState
Definition: mythuibuttonlist.h:157
mythuiscrollbar.h
MythUIButtonListItem::parent
MythUIButtonList * parent() const
Definition: mythuibuttonlist.cpp:3624
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:2817
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:2726
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:21
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:2835
SearchButtonListDialog
Definition: mythuibuttonlist.h:399
MythUIButtonListItem::DoButtonProgress1
void DoButtonProgress1(MythUIProgressBar *buttonprogress) const
Definition: mythuibuttonlist.cpp:3725
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:1382
LCD::Get
static LCD * Get(void)
Definition: lcddevice.cpp:69
mythuiimage.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1652
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:1681
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:884
MythUIButtonList::customEvent
void customEvent(QEvent *event) override
Definition: mythuibuttonlist.cpp:2734
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:2476
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:1695
MythUIButtonList::m_itemVertSpacing
int m_itemVertSpacing
Definition: mythuibuttonlist.h:354
MythMainWindow::GetKey
static QString GetKey(const QString &Context, const QString &Action)
Definition: mythmainwindow.cpp:1318
MythUIButtonList::ItemVisible
void ItemVisible(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1450
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:1668
MythUIButtonList::PageDown
int PageDown(void)
Definition: mythuibuttonlist.cpp:1836
MythUIButtonList::~MythUIButtonList
~MythUIButtonList() override
Definition: mythuibuttonlist.cpp:67
MythUIButtonList::MoveItemUpDown
bool MoveItemUpDown(MythUIButtonListItem *item, bool up)
Definition: mythuibuttonlist.cpp:2310
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:3640
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1111
MythUIButtonList::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:3650
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:819
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:532
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:2487
MythUIButtonList::LoadInBackground
void LoadInBackground(int start=0, int pageSize=20)
Definition: mythuibuttonlist.cpp:2756
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:3473
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:920
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:1166
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:1456
TextProperties::state
QString state
Definition: mythuibuttonlist.h:25
MythUIButtonList::InitButton
void InitButton(int itemIdx, MythUIStateType *&realButton, MythUIButtonListItem *&buttonItem)
Definition: mythuibuttonlist.cpp:1703
MythUIButtonList::GetDataValue
QVariant GetDataValue() const
Definition: mythuibuttonlist.cpp:1616
MythUIButtonList::m_clearing
bool m_clearing
Definition: mythuibuttonlist.h:380
SearchButtonListDialog::searchChanged
void searchChanged(void)
Definition: mythuibuttonlist.cpp:3968
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:3614
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:2356
MythUIType::CopyFrom
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
Definition: mythuitype.cpp:1174
MythUIButtonList::ScrollFree
@ ScrollFree
Definition: mythuibuttonlist.h:275
MythUIButtonList::MoveUp
virtual bool MoveUp(MovementUnit unit=MoveItem, uint amount=0)
Definition: mythuibuttonlist.cpp:1942
MythUIButtonList::SetLCDTitles
void SetLCDTitles(const QString &title, const QString &columnList="")
Definition: mythuibuttonlist.cpp:3034
MythUIButtonList::CalculateButtonPositions
void CalculateButtonPositions(void)
Definition: mythuibuttonlist.cpp:1254
MythUIButtonListItem::SetTextCb
void SetTextCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3309
MythUIButtonList::GetIntValue
virtual int GetIntValue() const
Definition: mythuibuttonlist.cpp:1596
MythUIButtonList::m_searchStr
QString m_searchStr
Definition: mythuibuttonlist.h:348
SearchButtonListDialog::Create
bool Create(void) override
Definition: mythuibuttonlist.cpp:3912
MythUIStateType::Full
@ Full
Definition: mythuistatetype.h:25
MythUIButtonList::SetScrollBarPosition
void SetScrollBarPosition(void)
Definition: mythuibuttonlist.cpp:3992
XMLParseBase::parseRect
static MythRect parseRect(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:136
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:2364
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3665
MythUIButtonListItem::DoButtonLookupText
void DoButtonLookupText(MythUIText *text, const TextProperties &textprop)
Definition: mythuibuttonlist.cpp:3741
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:1657
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:1377
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:3822
MythUIButtonListItem::SetProgress2
void SetProgress2(int start, int total, int used)
Definition: mythuibuttonlist.cpp:3553
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:3686
mythuigroup.h
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:85
NextButtonListPageEvent
Definition: mythuibuttonlist.cpp:2721
MythUIButtonListItem::SetTextFromMap
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
Definition: mythuibuttonlist.cpp:3285
LCDMenuItem
Definition: lcddevice.h:25
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:3802
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:3414
MythUIButtonList::PageUp
int PageUp(void)
Definition: mythuibuttonlist.cpp:1731
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:3677
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:21
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:3429
MythUIButtonList::CalculateVisibleItems
virtual void CalculateVisibleItems(void)
Definition: mythuibuttonlist.cpp:2780
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:21
MythUIButtonList::m_selPosition
int m_selPosition
Definition: mythuibuttonlist.h:382
MythUIButtonListItem::setEnabled
void setEnabled(bool flag)
Definition: mythuibuttonlist.cpp:3655
MythUIButtonListItem::m_data
QVariant m_data
Definition: mythuibuttonlist.h:162
std
Definition: mythchrono.h:23
MythUIButtonList::CalculateArrowStates
void CalculateArrowStates(void)
Definition: mythuibuttonlist.cpp:1390
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:1606
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:132
MythUIButtonListItem::state
CheckState state() const
Definition: mythuibuttonlist.cpp:3619
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1108
SearchButtonListDialog::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythuibuttonlist.cpp:3940
MythUIButtonList::GetButtonArea
MythRect GetButtonArea(void) const
Definition: mythuibuttonlist.cpp:1626
MythUIButtonListItem::SetImageCb
void SetImageCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3467
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:2279
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1554
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:3645
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:3984
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:3523
MythUIButtonList::LayoutGrid
@ LayoutGrid
Definition: mythuibuttonlist.h:207
MythUIButtonListItem::m_image
MythImage * m_image
Definition: mythuibuttonlist.h:158
CHECKED
@ CHECKED
Definition: lcddevice.h:21
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:2468
MythUIType::NormX
static int NormX(int width)
Definition: mythuitype.cpp:1161
MythUIButtonList::FindEnabledDown
void FindEnabledDown(MovementUnit unit)
If the current item is not enabled, find the next enabled one.
Definition: mythuibuttonlist.cpp:2069
MythUIButtonListItem::SetStateCb
void SetStateCb(muibCbFn fn, void *data)
Definition: mythuibuttonlist.cpp:3593
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:1240
MythUIButtonList::m_downArrow
MythUIStateType * m_downArrow
Definition: mythuibuttonlist.h:370
MythUIButtonList::GetItemFirst
MythUIButtonListItem * GetItemFirst() const
Definition: mythuibuttonlist.cpp:1633
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:3629
MythUIButtonListItem::SetData
void SetData(QVariant data)
Definition: mythuibuttonlist.cpp:3660
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:308
XMLParseBase::parseBool
static bool parseBool(const QString &text)
Definition: xmlparsebase.cpp:64
MythUIButtonListItem::MoveUpDown
bool MoveUpDown(bool flag)
Definition: mythuibuttonlist.cpp:3670
MythUIButtonListItem::GetState
QString GetState(const QString &name)
Definition: mythuibuttonlist.cpp:3599
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:173
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:594
MythUIType::Finalize
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
Definition: mythuitype.cpp:1316
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:3543
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:3707