00001 #include "mythuibuttonlist.h"
00002
00003 #include <math.h>
00004
00005
00006 #include <QCoreApplication>
00007 #include <QDomDocument>
00008 #include <QKeyEvent>
00009
00010
00011 #include "mythlogging.h"
00012
00013
00014 #include "mythmainwindow.h"
00015 #include "mythuiscrollbar.h"
00016 #include "mythuistatetype.h"
00017 #include "lcddevice.h"
00018 #include "mythuibutton.h"
00019 #include "mythuitext.h"
00020 #include "mythuitextedit.h"
00021
00022 #define LOC QString("MythUIButtonList(%1): ").arg(objectName())
00023
00024 MythUIButtonList::MythUIButtonList(MythUIType *parent, const QString &name)
00025 : MythUIType(parent, name)
00026 {
00027 m_showArrow = true;
00028 m_showScrollBar = true;
00029
00030 Const();
00031 }
00032
00033 MythUIButtonList::MythUIButtonList(MythUIType *parent, const QString &name,
00034 const QRect &area, bool showArrow,
00035 bool showScrollArrows, bool showScrollBar)
00036 : MythUIType(parent, name)
00037 {
00038 m_Area = area;
00039 m_showArrow = showArrow;
00040 m_showScrollBar = showScrollBar;
00041
00042 Const();
00043 }
00044
00045 void MythUIButtonList::Const(void)
00046 {
00047 m_contentsRect = MythRect(0, 0, 0, 0);
00048
00049 m_layout = LayoutVertical;
00050 m_arrange = ArrangeFixed;
00051 m_alignment = Qt::AlignLeft | Qt::AlignTop;
00052 m_scrollStyle = ScrollFree;
00053 m_wrapStyle = WrapNone;
00054
00055 m_active = false;
00056 m_drawFromBottom = false;
00057
00058 m_selPosition = 0;
00059 m_topPosition = 0;
00060 m_itemCount = 0;
00061 m_keepSelAtBottom = false;
00062
00063 m_initialized = false;
00064 m_needsUpdate = false;
00065 m_clearing = false;
00066 m_itemHorizSpacing = 0;
00067 m_itemVertSpacing = 0;
00068 m_itemHeight = 0;
00069 m_itemWidth = 0;
00070 m_itemsVisible = 0;
00071 m_maxVisible = 0;
00072 m_columns = 0;
00073 m_rows = 0;
00074 m_leftColumns = 0;
00075 m_rightColumns = 0;
00076 m_topRows = 0;
00077 m_bottomRows = 0;
00078 m_lcdTitle = "";
00079
00080 m_searchPosition = MythPoint(-2, -2);
00081 m_searchFields = "**ALL**";
00082 m_searchStartsWith = false;
00083
00084 m_upArrow = m_downArrow = NULL;
00085 m_scrollBar = NULL;
00086
00087 m_buttontemplate = NULL;
00088
00089 m_nextItemLoaded = 0;
00090
00091 SetCanTakeFocus(true);
00092
00093 connect(this, SIGNAL(TakingFocus()), this, SLOT(Select()));
00094 connect(this, SIGNAL(LosingFocus()), this, SLOT(Deselect()));
00095 }
00096
00097 MythUIButtonList::~MythUIButtonList()
00098 {
00099 m_ButtonToItem.clear();
00100 m_clearing = true;
00101
00102 while (!m_itemList.isEmpty())
00103 delete m_itemList.takeFirst();
00104 }
00105
00106 void MythUIButtonList::Select()
00107 {
00108 MythUIButtonListItem *item = GetItemCurrent();
00109
00110 if (item)
00111 emit itemSelected(item);
00112
00113 SetActive(true);
00114 }
00115
00116 void MythUIButtonList::Deselect()
00117 {
00118 SetActive(false);
00119 }
00120
00121 void MythUIButtonList::SetDrawFromBottom(bool draw)
00122 {
00123 m_drawFromBottom = draw;
00124 }
00125
00126 void MythUIButtonList::SetActive(bool active)
00127 {
00128 if (m_active == active)
00129 return;
00130
00131 m_active = active;
00132
00133 if (m_initialized)
00134 Update();
00135 }
00136
00140 void MythUIButtonList::Reset()
00141 {
00142 m_ButtonToItem.clear();
00143
00144 if (m_itemList.isEmpty())
00145 return;
00146
00147 m_clearing = true;
00148
00149 while (!m_itemList.isEmpty())
00150 delete m_itemList.takeFirst();
00151
00152 m_clearing = false;
00153
00154 m_selPosition = 0;
00155 m_topPosition = 0;
00156 m_itemCount = 0;
00157
00158 StopLoad();
00159 Update();
00160 MythUIType::Reset();
00161 }
00162
00163 void MythUIButtonList::Update()
00164 {
00165 m_needsUpdate = true;
00166 SetRedraw();
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176 int MythUIButtonList::minButtonWidth(const MythRect &area)
00177 {
00178 int width = area.width();
00179
00180 if (area.x() < 0)
00181 {
00182
00183
00184
00185
00186 width += (area.x() * 2 - 1);
00187
00188 while (width < 0)
00189 width -= area.x();
00190 }
00191 else if (m_layout == LayoutHorizontal)
00192 width -= area.x();
00193
00194 return width;
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204 int MythUIButtonList::minButtonHeight(const MythRect &area)
00205 {
00206 int height = area.height();
00207
00208 if (area.y() < 0)
00209 {
00210
00211
00212
00213
00214 height += (area.y() * 2 - 1);
00215
00216 while (height < 0)
00217 height -= area.y();
00218 }
00219 else if (m_layout == LayoutVertical)
00220 height -= area.y();
00221
00222 return height;
00223 }
00224
00225
00226
00227
00228
00229 MythUIGroup *MythUIButtonList::PrepareButton(int buttonIdx, int itemIdx,
00230 int &selectedIdx,
00231 int &button_shift)
00232 {
00233 MythUIStateType *realButton;
00234 MythUIGroup *buttonstate;
00235 MythUIButtonListItem *buttonItem = m_itemList[itemIdx];
00236
00237 buttonIdx += button_shift;
00238
00239 if (buttonIdx < 0 || buttonIdx + 1 > m_maxVisible)
00240 {
00241 QString name = QString("buttonlist button %1").arg(m_maxVisible);
00242 MythUIStateType *button = new MythUIStateType(this, name);
00243 button->CopyFrom(m_buttontemplate);
00244 button->ConnectDependants(true);
00245
00246 if (buttonIdx < 0)
00247 {
00248
00249
00250
00251
00252 m_ButtonList.prepend(button);
00253 buttonIdx = 0;
00254 ++button_shift;
00255
00256 if (selectedIdx >= 0)
00257 ++selectedIdx;
00258 }
00259 else
00260 m_ButtonList.append(button);
00261
00262 ++m_maxVisible;
00263 }
00264
00265 realButton = m_ButtonList[buttonIdx];
00266 m_ButtonToItem[buttonIdx] = buttonItem;
00267 buttonItem->SetToRealButton(realButton, itemIdx == m_selPosition);
00268 buttonstate = dynamic_cast<MythUIGroup *>(realButton->GetCurrentState());
00269
00270 if (itemIdx == m_selPosition)
00271 selectedIdx = buttonIdx;
00272
00273 return buttonstate;
00274 }
00275
00276
00277
00278
00279 bool MythUIButtonList::DistributeRow(int &first_button, int &last_button,
00280 int &first_item, int &last_item,
00281 int &selected_column, int &skip_cols,
00282 bool grow_left, bool grow_right,
00283 int **col_widths, int &row_height,
00284 int total_height, int split_height,
00285 int &col_cnt, bool &wrapped)
00286 {
00287 MythUIGroup *buttonstate;
00288 int initial_first_button, initial_last_button;
00289 int initial_first_item, initial_last_item;
00290 int col_idx, left_cnt = 0;
00291 int width, height;
00292 int max_width, max_height;
00293 int left_width, right_width;
00294 int begin, end;
00295 bool underflow = false;
00296 bool added;
00297 bool hsplit, vsplit;
00298 int selectedIdx;
00299 int button_shift;
00300
00301 selectedIdx = -1;
00302 button_shift = 0;
00303 col_cnt = 1;
00304 skip_cols = 0;
00305
00306 if (last_item + 1 > m_itemCount || last_item < 0 || first_item < 0)
00307 return false;
00308
00309
00310
00311
00312
00313 if (grow_right)
00314 buttonstate = PrepareButton(last_button, last_item,
00315 selectedIdx, button_shift);
00316 else
00317 buttonstate = PrepareButton(first_button, first_item,
00318 selectedIdx, button_shift);
00319
00320 if (buttonstate == NULL)
00321 {
00322 LOG(VB_GENERAL, LOG_ERR, QString("Failed to query buttonlist state: %1")
00323 .arg(last_button));
00324 return false;
00325 }
00326
00327
00328 max_width = m_contentsRect.width();
00329 max_height = m_contentsRect.height();
00330 row_height = minButtonHeight(buttonstate->GetArea());
00331 width = minButtonWidth(buttonstate->GetArea());
00332
00333
00334
00335
00336
00337 vsplit = (m_scrollStyle == ScrollCenter);
00338 hsplit = vsplit && grow_left && grow_right;
00339
00340 if (hsplit)
00341 {
00342 max_width /= 2;
00343 left_width = right_width = (width / 2);
00344 }
00345 else
00346 {
00347 if (grow_right)
00348 {
00349 left_width = 0;
00350 right_width = width;
00351 }
00352 else
00353 {
00354 left_width = width;
00355 right_width = 0;
00356 }
00357 }
00358
00359 if (vsplit)
00360 max_height /= 2;
00361
00362
00363
00364
00365
00366
00367 if (total_height > 0 &&
00368 ((vsplit ? split_height : total_height) +
00369 m_itemVertSpacing + row_height > max_height))
00370 {
00371 LOG(VB_GUI, LOG_DEBUG,
00372 QString("%1 Height exceeded %2 + (%3) + %4 = %5 which is > %6")
00373 .arg(vsplit ? "Centering" : "Total")
00374 .arg(split_height).arg(m_itemVertSpacing).arg(row_height)
00375 .arg(split_height + m_itemVertSpacing + row_height)
00376 .arg(max_height));
00377 first_button += button_shift;
00378 last_button += button_shift;
00379 return false;
00380 }
00381
00382 LOG(VB_GUI, LOG_DEBUG, QString("Added button item %1 width %2 height %3")
00383 .arg(grow_right ? last_item : first_item)
00384 .arg(width).arg(row_height));
00385
00386 initial_first_button = first_button;
00387 initial_last_button = last_button;
00388 initial_first_item = first_item;
00389 initial_last_item = last_item;
00390
00391
00392
00393
00394
00395
00396 if (grow_right)
00397 col_idx = 0;
00398 else
00399 col_idx = m_columns - 1;
00400
00401
00402 added = (m_layout != LayoutVertical);
00403
00404 while (added)
00405 {
00406 added = false;
00407
00408
00409 if (grow_right && col_cnt < m_columns)
00410 {
00411 if (wrapped)
00412 end = first_item;
00413 else
00414 {
00415
00416 if (m_wrapStyle == WrapItems &&
00417 (hsplit || m_scrollStyle != ScrollFree) &&
00418 last_item + 1 == m_itemCount)
00419 {
00420 last_item = -1;
00421 wrapped = true;
00422 end = first_item;
00423 }
00424 else
00425 end = m_itemCount;
00426 }
00427
00428 if (last_item + 1 < end)
00429 {
00430
00431 buttonstate = PrepareButton(last_button + 1, last_item + 1,
00432 selectedIdx, button_shift);
00433
00434 if (buttonstate == NULL)
00435 continue;
00436
00437 width = minButtonWidth(buttonstate->GetArea());
00438
00439
00440 if (*col_widths && width < (*col_widths)[col_idx])
00441 width = (*col_widths)[col_idx];
00442
00443
00444 if ((hsplit ? right_width : left_width + right_width) +
00445 m_itemHorizSpacing + width > max_width)
00446 {
00447 int total = hsplit ? right_width : left_width + right_width;
00448 LOG(VB_GUI, LOG_DEBUG,
00449 QString("button on right would exceed width: "
00450 "%1+(%2)+%3 == %4 which is > %5")
00451 .arg(total).arg(m_itemHorizSpacing).arg(width)
00452 .arg(total + m_itemHorizSpacing + width)
00453 .arg(max_width));
00454 }
00455 else
00456 {
00457 added = true;
00458 ++col_cnt;
00459 ++last_button;
00460 ++last_item;
00461 ++col_idx;
00462 right_width += m_itemHorizSpacing + width;
00463 height = minButtonHeight(buttonstate->GetArea());
00464
00465 if (row_height < height)
00466 row_height = height;
00467
00468 LOG(VB_GUI, LOG_DEBUG,
00469 QString("Added button item %1 "
00470 "R.width %2 height %3 total width %4+%5"
00471 " (max %6)")
00472 .arg(last_item).arg(width).arg(height)
00473 .arg(left_width).arg(right_width).arg(max_width));
00474 }
00475 }
00476 else
00477 underflow = true;
00478 }
00479
00480
00481 if (grow_left && col_cnt < m_columns)
00482 {
00483 if (wrapped)
00484 end = last_item + 1;
00485 else
00486 {
00487
00488 if (m_wrapStyle == WrapItems &&
00489 (hsplit || m_scrollStyle != ScrollFree) &&
00490 first_item == 0)
00491 {
00492 first_item = m_itemCount;
00493 wrapped = true;
00494 end = last_item + 1;
00495 }
00496 else
00497 end = 0;
00498 }
00499
00500 if (first_item > end)
00501 {
00502 buttonstate = PrepareButton(first_button - 1, first_item - 1,
00503 selectedIdx, button_shift);
00504
00505 if (buttonstate == NULL)
00506 continue;
00507
00508 width = minButtonWidth(buttonstate->GetArea());
00509
00510
00511 if (*col_widths && width < (*col_widths)[col_idx])
00512 width = (*col_widths)[col_idx];
00513
00514
00515 if ((hsplit ? left_width : left_width + right_width) +
00516 m_itemHorizSpacing + width > max_width)
00517 {
00518 int total = hsplit ? left_width : left_width + right_width;
00519 LOG(VB_GUI, LOG_DEBUG,
00520 QString("button on left would exceed width: "
00521 "%1+(%2)+%3 == %4 which is > %5")
00522 .arg(total).arg(m_itemHorizSpacing).arg(width)
00523 .arg(total + m_itemHorizSpacing + width)
00524 .arg(max_width));
00525 }
00526 else
00527 {
00528 added = true;
00529 --first_button;
00530 --first_item;
00531 --col_idx;
00532 ++col_cnt;
00533 ++left_cnt;
00534 left_width += m_itemHorizSpacing + width;
00535 height = minButtonHeight(buttonstate->GetArea());
00536
00537 if (row_height < height)
00538 row_height = height;
00539
00540 LOG(VB_GUI, LOG_DEBUG,
00541 QString("Added button item %1 "
00542 "L.width %2 height %3 total width %4+%5"
00543 " (max %6)")
00544 .arg(first_item).arg(width).arg(height)
00545 .arg(left_width).arg(right_width).arg(max_width));
00546 }
00547 }
00548 else
00549 {
00550 underflow = true;
00551 if (m_layout == LayoutGrid)
00552 skip_cols = m_columns - col_cnt;
00553 }
00554 }
00555 }
00556
00557
00558
00559
00560
00561
00562 if (total_height > 0 &&
00563 ((vsplit ? split_height : total_height) +
00564 m_itemVertSpacing + row_height > max_height))
00565 {
00566 LOG(VB_GUI, LOG_DEBUG,
00567 QString("%1 Height exceeded %2 + (%3) + %4 = %5 which is > %6")
00568 .arg(vsplit ? "Centering" : "Total")
00569 .arg(split_height).arg(m_itemVertSpacing).arg(row_height)
00570 .arg(split_height + m_itemVertSpacing + row_height)
00571 .arg(max_height));
00572 first_button = initial_first_button + button_shift;
00573 last_button = initial_last_button + button_shift;
00574 first_item = initial_first_item;
00575 last_item = initial_last_item;
00576 return false;
00577 }
00578
00579 if (*col_widths == 0)
00580 {
00581
00582
00583
00584
00585 *col_widths = new int[col_cnt];
00586
00587 for (col_idx = 0; col_idx < col_cnt; ++col_idx)
00588 (*col_widths)[col_idx] = 0;
00589
00590 }
00591
00592
00593 first_button += button_shift;
00594 last_button += button_shift;
00595
00596
00597 MythUIStateType *realButton;
00598 int buttonIdx;
00599
00600 if (grow_left)
00601 {
00602 begin = first_button;
00603 end = first_button + col_cnt;
00604 }
00605 else
00606 {
00607 end = last_button + 1;
00608 begin = end - col_cnt;
00609 }
00610
00611 for (buttonIdx = begin, col_idx = 0;
00612 buttonIdx < end; ++buttonIdx, ++col_idx)
00613 {
00614 realButton = m_ButtonList[buttonIdx];
00615 buttonstate = dynamic_cast<MythUIGroup *>
00616 (realButton->GetCurrentState());
00617 if (!buttonstate)
00618 break;
00619 width = minButtonWidth(buttonstate->GetArea());
00620
00621 if ((*col_widths)[col_idx] < width)
00622 (*col_widths)[col_idx] = width;
00623
00624
00625 if (selectedIdx == buttonIdx)
00626 selected_column = col_idx;
00627 }
00628
00629
00630
00631
00632
00633 if (total_height && underflow && col_cnt < m_columns)
00634 col_cnt = m_columns;
00635
00636 return true;
00637 }
00638
00639
00640
00641
00642 bool MythUIButtonList::DistributeCols(int &first_button, int &last_button,
00643 int &first_item, int &last_item,
00644 int &selected_column, int &selected_row,
00645 int &skip_cols, int **col_widths,
00646 QList<int> & row_heights,
00647 int &top_height, int &bottom_height,
00648 bool &wrapped)
00649 {
00650 int col_cnt;
00651 int height;
00652 int row_cnt = 1;
00653 int end;
00654 bool added;
00655
00656 do
00657 {
00658 added = false;
00659
00660 if (wrapped)
00661 end = first_item;
00662 else
00663 {
00664
00665 if (m_wrapStyle == WrapItems &&
00666 (m_scrollStyle == ScrollCenter ||
00667 m_scrollStyle == ScrollGroupCenter) &&
00668 last_item + 1 == m_itemCount)
00669 {
00670 last_item = -1;
00671 wrapped = true;
00672 end = first_item;
00673 }
00674 else
00675 end = m_itemCount;
00676 }
00677
00678 if (last_item + 1 < end)
00679 {
00680
00681 if (DistributeRow(first_button, ++last_button,
00682 first_item, ++last_item, selected_column,
00683 skip_cols, false, true, col_widths, height,
00684 top_height + bottom_height, bottom_height,
00685 col_cnt, wrapped))
00686 {
00687 if (col_cnt < m_columns)
00688 return false;
00689
00690 if (selected_row == -1 && selected_column != -1)
00691 selected_row = row_heights.size();
00692
00693 ++row_cnt;
00694 row_heights.push_back(height);
00695 bottom_height += (height + m_itemVertSpacing);
00696 added = true;
00697 }
00698 else
00699 {
00700 --last_button;
00701 --last_item;
00702 }
00703 }
00704
00705 if (wrapped)
00706 end = last_item + 1;
00707 else
00708 {
00709
00710 if (m_wrapStyle == WrapItems &&
00711 (m_scrollStyle == ScrollCenter ||
00712 m_scrollStyle == ScrollGroupCenter) &&
00713 first_item == 0)
00714 {
00715 first_item = m_itemCount;
00716 wrapped = true;
00717 end = last_item + 1;
00718 }
00719 else
00720 end = 0;
00721 }
00722
00723 if (first_item > end)
00724 {
00725
00726 if (DistributeRow(--first_button, last_button,
00727 --first_item, last_item, selected_column,
00728 skip_cols, true, false, col_widths, height,
00729 top_height + bottom_height, top_height,
00730 col_cnt, wrapped))
00731 {
00732 if (col_cnt < m_columns)
00733 return false;
00734
00735 if (selected_row == -1 && selected_column != -1)
00736 selected_row = row_heights.size();
00737 else if (selected_row != -1)
00738 ++selected_row;
00739
00740 ++row_cnt;
00741 row_heights.push_front(height);
00742 top_height += (height + m_itemVertSpacing);
00743 added = true;
00744 }
00745 else
00746 {
00747 ++first_button;
00748 ++first_item;
00749 }
00750 }
00751 }
00752 while (added);
00753
00754 return true;
00755 }
00756
00757
00758
00759
00760 bool MythUIButtonList::DistributeButtons(void)
00761 {
00762 int first_button, last_button, start_button, start_item;
00763 int first_item, last_item, skip_cols = 0;
00764 int *col_widths;
00765 int col_cnt;
00766 int selected_column, selected_row;
00767 bool wrapped = false;
00768 bool grow_left = true;
00769
00770 QList<int> row_heights;
00771 QList<int>::iterator Iheight;
00772 int height, top_height, bottom_height;
00773
00774 start_item = m_selPosition;
00775 selected_column = selected_row = -1;
00776 top_height = bottom_height = 0;
00777 col_widths = 0;
00778 first_button = last_button = start_button = 0;
00779
00780 LOG(VB_GUI, LOG_DEBUG, QString("DistributeButtons: "
00781 "selected item %1 total items %2")
00782 .arg(start_item).arg(m_itemCount));
00783
00784
00785
00786
00787
00788 for (m_columns = m_itemCount; m_columns > 0;)
00789 {
00790 first_item = last_item = start_item;
00791
00792
00793
00794
00795
00796
00797 switch (m_scrollStyle)
00798 {
00799 case ScrollCenter:
00800 case ScrollGroupCenter:
00801 start_button = qMax((m_maxVisible / 2) - 1, 0);
00802 break;
00803 case ScrollFree:
00804
00805 if (m_layout == LayoutGrid)
00806 {
00807 start_button = 0;
00808 first_item = last_item = 0;
00809 grow_left = false;
00810 }
00811 else if (!m_ButtonList.empty())
00812 {
00813 if (m_itemCount - m_selPosition - 1 <
00814 static_cast<int>(m_ButtonList.size()) / 2)
00815 start_button = m_ButtonList.size() -
00816 (m_itemCount - m_selPosition) + 1;
00817 else if (m_selPosition >
00818 static_cast<int>(m_ButtonList.size()) / 2)
00819 start_button = (m_ButtonList.size() / 2);
00820 else
00821 start_button = m_selPosition;
00822 }
00823 else
00824 start_button = 0;
00825
00826 break;
00827 }
00828
00829 first_button = last_button = start_button;
00830 row_heights.clear();
00831
00832
00833 if (!DistributeRow(first_button, last_button,
00834 first_item, last_item, selected_column,
00835 skip_cols, grow_left, true, &col_widths,
00836 height, 0, 0, col_cnt, wrapped))
00837 {
00838 delete[] col_widths;
00839 return false;
00840 }
00841
00842 m_columns = col_cnt;
00843
00844 if (m_layout == LayoutGrid && m_scrollStyle == ScrollFree)
00845 {
00846
00847
00848
00849
00850 start_item = (m_selPosition / m_columns) * m_columns;
00851 first_item = last_item = start_item;
00852
00853
00854
00855
00856
00857 start_button = qMax((int)m_ButtonList.size() / 2, 0);
00858 start_button = (start_button / qMax(m_columns, 1)) * m_columns;
00859
00860 if (start_button < m_itemCount / 2 &&
00861 m_itemCount - m_selPosition - 1 < (int)m_ButtonList.size() / 2)
00862 start_button += m_columns;
00863
00864 first_button = last_button = start_button;
00865
00866
00867 selected_column = selected_row = -1;
00868
00869 if (!DistributeRow(first_button, last_button,
00870 first_item, last_item, selected_column,
00871 skip_cols, grow_left, true, &col_widths,
00872 height, 0, 0, col_cnt, wrapped))
00873 {
00874 delete[] col_widths;
00875 return false;
00876 }
00877 }
00878
00879 if (selected_column != -1)
00880 selected_row = 0;
00881
00882 row_heights.push_back(height);
00883
00884 if (m_scrollStyle == ScrollCenter)
00885 top_height = bottom_height = (height / 2);
00886 else
00887 bottom_height = height;
00888
00889 if (m_layout == LayoutHorizontal)
00890 break;
00891
00892
00893 if (DistributeCols(first_button, last_button,
00894 first_item, last_item,
00895 selected_column, selected_row,
00896 skip_cols, &col_widths, row_heights,
00897 top_height, bottom_height, wrapped))
00898 break;
00899
00900 delete[] col_widths;
00901 col_widths = 0;
00902
00903 --m_columns;
00904 start_item = m_selPosition;
00905 }
00906
00907 m_rows = row_heights.size();
00908
00909 LOG(VB_GUI, LOG_DEBUG,
00910 QString("%1 rows, %2 columns fit inside parent area %3x%4")
00911 .arg(m_rows).arg(m_columns).arg(m_contentsRect.width())
00912 .arg(m_contentsRect.height()));
00913
00914 if (col_widths == 0)
00915 return false;
00916
00917 int total, row, col;
00918 int left_spacing, right_spacing, top_spacing, bottom_spacing;
00919 int x, y, x_init, x_adj, y_adj;
00920 QString status_msg;
00921
00922
00923
00924
00925 top_height = bottom_height = m_topRows = m_bottomRows = 0;
00926
00927 status_msg = "Row heights: ";
00928
00929 for (row = 0; row < m_rows; ++row)
00930 {
00931 if (row != 0)
00932 status_msg += ", ";
00933
00934 if (row == selected_row)
00935 {
00936 status_msg += '[';
00937 top_height += (row_heights[row] / 2);
00938 bottom_height += ((row_heights[row] / 2) + (row_heights[row] % 2));
00939 }
00940 else
00941 {
00942 if (bottom_height)
00943 {
00944 bottom_height += m_itemVertSpacing + row_heights[row];
00945 ++m_bottomRows;
00946 }
00947 else
00948 {
00949 top_height += row_heights[row] + m_itemVertSpacing;
00950 ++m_topRows;
00951 }
00952 }
00953
00954 status_msg += QString("%1").arg(row_heights[row]);
00955
00956 if (row == selected_row)
00957 status_msg += ']';
00958 }
00959
00960
00961
00962
00963 if (m_arrange == ArrangeStack || m_layout == LayoutHorizontal)
00964 {
00965
00966 top_spacing = bottom_spacing = 0;
00967 }
00968 else
00969 {
00970 if (m_rows < 2)
00971 {
00972
00973 top_spacing = bottom_spacing =
00974 (m_contentsRect.height() - top_height) / 2;
00975 }
00976 else
00977 {
00978 if (m_scrollStyle == ScrollCenter)
00979 {
00980
00981 top_spacing = m_topRows ? (m_contentsRect.height() / 2 -
00982 top_height) / m_topRows : 0;
00983 bottom_spacing = m_bottomRows ? (m_contentsRect.height() / 2 -
00984 bottom_height) / m_bottomRows : 0;
00985
00986 if (m_arrange == ArrangeSpread)
00987 {
00988
00989 if (!m_topRows || top_spacing > bottom_spacing)
00990 top_spacing = bottom_spacing;
00991 else
00992 bottom_spacing = top_spacing;
00993 }
00994 }
00995 else
00996 {
00997
00998 top_spacing = bottom_spacing = (m_contentsRect.height() -
00999 (top_height + bottom_height)) /
01000 (m_topRows + m_bottomRows);
01001 }
01002 }
01003
01004
01005 top_height += (top_spacing * m_topRows);
01006 bottom_height += (bottom_spacing * m_bottomRows);
01007 }
01008
01009
01010
01011
01012 y = m_contentsRect.y();
01013
01014 if ((m_alignment & Qt::AlignVCenter) && m_arrange != ArrangeFill)
01015 {
01016 if (m_scrollStyle == ScrollCenter)
01017 {
01018
01019 y += qMax(bottom_height - top_height, 0);
01020 total = qMax(top_height, bottom_height) * 2;
01021 }
01022 else
01023 total = top_height + bottom_height;
01024
01025
01026 y += (qMax(m_contentsRect.height() - total, 2) / 2);
01027 }
01028 else if ((m_alignment & Qt::AlignBottom) && m_arrange == ArrangeStack)
01029 {
01030
01031 y += qMax(m_contentsRect.height() -
01032 (top_height + bottom_height), 0);
01033 }
01034
01035 status_msg += QString(" spacing top %1 bottom %2 fixed %3 offset %4")
01036 .arg(top_spacing).arg(bottom_spacing)
01037 .arg(m_itemVertSpacing).arg(y);
01038
01039 LOG(VB_GUI, LOG_DEBUG, status_msg);
01040
01041
01042
01043
01044 int left_width, right_width;
01045
01046 left_width = right_width = m_leftColumns = m_rightColumns = 0;
01047
01048 status_msg = "Col widths: ";
01049
01050 for (col = 0; col < m_columns; ++col)
01051 {
01052 if (col != 0)
01053 status_msg += ", ";
01054
01055 if (col == selected_column)
01056 {
01057 status_msg += '[';
01058 left_width += (col_widths[col] / 2);
01059 right_width += ((col_widths[col] / 2) + (col_widths[col] % 2));
01060 }
01061 else
01062 {
01063 if (right_width)
01064 {
01065 right_width += m_itemHorizSpacing + col_widths[col];
01066 ++m_rightColumns;
01067 }
01068 else
01069 {
01070 left_width += col_widths[col] + m_itemHorizSpacing;
01071 ++m_leftColumns;
01072 }
01073 }
01074
01075 status_msg += QString("%1").arg(col_widths[col]);
01076
01077 if (col == selected_column)
01078 status_msg += ']';
01079 }
01080
01081
01082
01083
01084 if (m_arrange == ArrangeStack || m_layout == LayoutVertical)
01085 {
01086
01087 left_spacing = right_spacing = 0;
01088 }
01089 else
01090 {
01091 if (m_columns < 2)
01092 {
01093
01094 left_spacing = right_spacing =
01095 (m_contentsRect.width() - left_width) / 2;
01096 }
01097 else
01098 {
01099 if (m_scrollStyle == ScrollCenter)
01100 {
01101
01102 left_spacing = m_leftColumns ? (m_contentsRect.width() / 2 -
01103 left_width) / m_leftColumns : 0;
01104 right_spacing = m_rightColumns ? (m_contentsRect.width() / 2 -
01105 right_width) / m_rightColumns : 0;
01106
01107 if (m_arrange == ArrangeSpread)
01108 {
01109
01110 if (!m_leftColumns || left_spacing > right_spacing)
01111 left_spacing = right_spacing;
01112 else
01113 right_spacing = left_spacing;
01114 }
01115 }
01116 else
01117 {
01118
01119 left_spacing = right_spacing = (m_contentsRect.width() -
01120 (left_width + right_width)) /
01121 (m_leftColumns + m_rightColumns);
01122 }
01123 }
01124
01125
01126 left_width += (left_spacing * m_leftColumns);
01127 right_width += (right_spacing * m_rightColumns);
01128 }
01129
01130
01131
01132
01133 x_init = m_contentsRect.x();
01134
01135 if ((m_alignment & Qt::AlignHCenter) && m_arrange != ArrangeFill)
01136 {
01137 if (m_scrollStyle == ScrollCenter)
01138 {
01139
01140 x_init += qMax(right_width - left_width, 0);
01141 total = qMax(left_width, right_width) * 2;
01142 }
01143 else
01144 total = left_width + right_width;
01145
01146
01147 x_init += (qMax(m_contentsRect.width() - total, 2) / 2);
01148 }
01149 else if ((m_alignment & Qt::AlignRight) && m_arrange == ArrangeStack)
01150 {
01151
01152 x_init += qMax(m_contentsRect.width() -
01153 (left_width + right_width), 0);
01154 }
01155
01156 status_msg += QString(" spacing left %1 right %2 fixed %3 offset %4")
01157 .arg(left_spacing).arg(right_spacing)
01158 .arg(m_itemHorizSpacing).arg(x_init);
01159 LOG(VB_GUI, LOG_DEBUG, status_msg);
01160
01161 top_spacing += m_itemVertSpacing;
01162 bottom_spacing += m_itemVertSpacing;
01163 left_spacing += m_itemHorizSpacing;
01164 right_spacing += m_itemHorizSpacing;
01165
01166 MythUIStateType *realButton = NULL;
01167 MythUIGroup *buttonstate;
01168
01169
01170 int vertical_spacing, horizontal_spacing;
01171 int buttonIdx = first_button - skip_cols;
01172
01173 vertical_spacing = top_spacing;
01174
01175 for (row = 0; row < m_rows; ++row)
01176 {
01177 x = x_init;
01178 horizontal_spacing = left_spacing;
01179
01180 for (col = 0; col < m_columns && buttonIdx <= last_button; ++col)
01181 {
01182 if (buttonIdx >= first_button)
01183 {
01184 realButton = m_ButtonList[buttonIdx];
01185 buttonstate = dynamic_cast<MythUIGroup *>
01186 (realButton->GetCurrentState());
01187 if (!buttonstate)
01188 break;
01189
01190 MythRect area = buttonstate->GetArea();
01191
01192
01193 if (m_alignment & Qt::AlignHCenter)
01194 x_adj = (col_widths[col] - minButtonWidth(area)) / 2;
01195 else if (m_alignment & Qt::AlignRight)
01196 x_adj = (col_widths[col] - minButtonWidth(area));
01197 else
01198 x_adj = 0;
01199 if (m_layout == LayoutHorizontal)
01200 x_adj -= area.x();
01201
01202
01203 if (m_alignment & Qt::AlignVCenter)
01204 y_adj = (row_heights[row] - minButtonHeight(area)) / 2;
01205 else if (m_alignment & Qt::AlignBottom)
01206 y_adj = (row_heights[row] - minButtonHeight(area));
01207 else
01208 y_adj = 0;
01209 if (m_layout == LayoutVertical)
01210 y_adj -= area.y();
01211
01212
01213 realButton->SetPosition(x + x_adj, y + y_adj);
01214 realButton->SetVisible(true);
01215
01216 if (col == selected_column)
01217 {
01218 horizontal_spacing = right_spacing;
01219 if (row == selected_row)
01220 realButton->MoveToTop();
01221 }
01222 }
01223 x += col_widths[col] + horizontal_spacing;
01224 ++buttonIdx;
01225 }
01226
01227 if (row == selected_row)
01228 vertical_spacing = bottom_spacing;
01229
01230 y += row_heights[row] + vertical_spacing;
01231 }
01232
01233 m_itemsVisible = m_columns * m_rows;
01234
01235
01236 for (buttonIdx = 0; buttonIdx < first_button; ++buttonIdx)
01237 m_ButtonList[buttonIdx]->SetVisible(false);
01238
01239
01240 for (buttonIdx = m_maxVisible - 1; buttonIdx > last_button; --buttonIdx)
01241 m_ButtonList[buttonIdx]->SetVisible(false);
01242
01243
01244 if (m_scrollStyle == ScrollCenter || m_scrollStyle == ScrollGroupCenter)
01245 m_topPosition = static_cast<int>(m_itemsVisible) < m_itemCount;
01246 else
01247 m_topPosition = first_item;
01248
01249 delete[] col_widths;
01250 return true;
01251 }
01252
01253 void MythUIButtonList::SetPosition(void)
01254 {
01255 if (m_ButtonList.size() == 0)
01256 return;
01257
01258 int button = 0;
01259
01260 switch (m_scrollStyle)
01261 {
01262 case ScrollCenter:
01263 case ScrollGroupCenter:
01264 m_topPosition = qMax(m_selPosition -
01265 (int)((float)m_itemsVisible / 2), 0);
01266 break;
01267 case ScrollFree:
01268 {
01269 int adjust = 0;
01270
01271 if (m_topPosition == -1 || m_keepSelAtBottom)
01272 {
01273 if (m_topPosition == -1)
01274 m_topPosition = 0;
01275
01276 if (m_layout == LayoutHorizontal)
01277 adjust = 1 - m_itemsVisible;
01278 else
01279 adjust = m_columns - m_itemsVisible;
01280
01281 m_keepSelAtBottom = false;
01282 }
01283
01284 if (m_selPosition < m_topPosition ||
01285 m_topPosition + (int)m_itemsVisible <= m_selPosition)
01286 {
01287 if (m_layout == LayoutHorizontal)
01288 m_topPosition = m_selPosition + adjust;
01289 else
01290 m_topPosition = (m_selPosition + adjust) /
01291 m_columns * m_columns;
01292 }
01293
01294 m_topPosition = qMax(m_topPosition, 0);
01295 break;
01296 }
01297 }
01298
01299 QList<MythUIButtonListItem *>::iterator it = m_itemList.begin() + m_topPosition;
01300
01301 if (m_scrollStyle == ScrollCenter || m_scrollStyle == ScrollGroupCenter)
01302 {
01303 if (m_selPosition <= (int)(m_itemsVisible / 2))
01304 {
01305 button = (m_itemsVisible / 2) - m_selPosition;
01306
01307 if (m_wrapStyle == WrapItems && button > 0 &&
01308 m_itemCount >= (int)m_itemsVisible)
01309 {
01310 it = m_itemList.end() - button;
01311 button = 0;
01312 }
01313 }
01314 else if ((m_itemCount - m_selPosition) < (int)(m_itemsVisible / 2))
01315 {
01316 it = m_itemList.begin() + m_selPosition - (m_itemsVisible / 2);
01317 }
01318 }
01319 else if (m_drawFromBottom && m_itemCount < (int)m_itemsVisible)
01320 button = m_itemsVisible - m_itemCount;
01321
01322 for (int i = 0; i < button; i++)
01323 m_ButtonList[i]->SetVisible(false);
01324
01325 bool seenSelected = false;
01326
01327 MythUIStateType *realButton = NULL;
01328 MythUIButtonListItem *buttonItem = NULL;
01329
01330 if (it < m_itemList.begin())
01331 it = m_itemList.begin();
01332
01333 int curItem = GetItemPos(*it);
01334
01335 while (it < m_itemList.end() && button < (int)m_itemsVisible)
01336 {
01337 realButton = m_ButtonList[button];
01338 buttonItem = *it;
01339
01340 if (!realButton || !buttonItem)
01341 break;
01342
01343 bool selected = false;
01344
01345 if (!seenSelected && (curItem == m_selPosition))
01346 {
01347 seenSelected = true;
01348 selected = true;
01349 }
01350
01351 m_ButtonToItem[button] = buttonItem;
01352 buttonItem->SetToRealButton(realButton, selected);
01353 realButton->SetVisible(true);
01354
01355 if (m_wrapStyle == WrapItems && it == (m_itemList.end() - 1) &&
01356 m_itemCount >= (int)m_itemsVisible)
01357 {
01358 it = m_itemList.begin();
01359 curItem = 0;
01360 }
01361 else
01362 {
01363 ++it;
01364 ++curItem;
01365 }
01366
01367 button++;
01368 }
01369
01370 for (; button < (int)m_itemsVisible; button++)
01371 m_ButtonList[button]->SetVisible(false);
01372
01373 }
01374
01375 void MythUIButtonList::SanitizePosition(void)
01376 {
01377 if (m_selPosition < 0)
01378 m_selPosition = (m_wrapStyle > WrapNone) ? m_itemList.size() - 1 : 0;
01379 else if (m_selPosition >= m_itemList.size())
01380 m_selPosition = (m_wrapStyle > WrapNone) ? 0 : m_itemList.size() - 1;
01381 }
01382
01383 void MythUIButtonList::SetPositionArrowStates()
01384 {
01385 if (!m_initialized)
01386 Init();
01387
01388 if (!m_initialized)
01389 return;
01390
01391 if (m_clearing)
01392 return;
01393
01394 m_needsUpdate = false;
01395
01396
01397 SanitizePosition();
01398 m_ButtonToItem.clear();
01399
01400 if (m_arrange == ArrangeFixed)
01401 SetPosition();
01402 else
01403 DistributeButtons();
01404
01405 updateLCD();
01406
01407 m_needsUpdate = false;
01408
01409 if (!m_downArrow || !m_upArrow)
01410 return;
01411
01412 if (m_itemCount == 0)
01413 {
01414 m_downArrow->DisplayState(MythUIStateType::Off);
01415 m_upArrow->DisplayState(MythUIStateType::Off);
01416 }
01417 else
01418 {
01419 if (m_topPosition != 0)
01420 m_upArrow->DisplayState(MythUIStateType::Full);
01421 else
01422 m_upArrow->DisplayState(MythUIStateType::Off);
01423
01424 if (m_topPosition + (int)m_itemsVisible < m_itemCount)
01425 m_downArrow->DisplayState(MythUIStateType::Full);
01426 else
01427 m_downArrow->DisplayState(MythUIStateType::Off);
01428
01429 m_upArrow->MoveToTop();
01430 m_downArrow->MoveToTop();
01431 }
01432 }
01433
01434 void MythUIButtonList::ItemVisible(MythUIButtonListItem *item)
01435 {
01436 if (item)
01437 emit itemVisible(item);
01438 }
01439
01440 void MythUIButtonList::InsertItem(MythUIButtonListItem *item, int listPosition)
01441 {
01442 bool wasEmpty = m_itemList.isEmpty();
01443
01444 if (listPosition >= 0 && listPosition <= m_itemList.count())
01445 {
01446 m_itemList.insert(listPosition, item);
01447
01448 if (listPosition <= m_selPosition)
01449 m_selPosition++;
01450
01451 if (listPosition <= m_topPosition)
01452 m_topPosition++;
01453 }
01454 else
01455 m_itemList.append(item);
01456
01457 m_itemCount++;
01458
01459 if (wasEmpty)
01460 {
01461 m_selPosition = m_topPosition = 0;
01462 emit itemSelected(item);
01463 }
01464
01465 Update();
01466 }
01467
01468 void MythUIButtonList::RemoveItem(MythUIButtonListItem *item)
01469 {
01470 if (m_clearing)
01471 return;
01472
01473 int curIndex = m_itemList.indexOf(item);
01474
01475 if (curIndex == -1)
01476 return;
01477
01478 if (curIndex == m_topPosition &&
01479 m_topPosition > 0 &&
01480 m_topPosition == m_itemCount - 1)
01481 {
01482 m_topPosition--;
01483 }
01484
01485 if (curIndex == m_selPosition &&
01486 m_selPosition > 0 &&
01487 m_selPosition == m_itemCount - 1)
01488 {
01489 m_selPosition--;
01490 }
01491
01492 m_itemList.removeAt(curIndex);
01493 m_itemCount--;
01494
01495 Update();
01496
01497 if (m_selPosition < m_itemCount)
01498 emit itemSelected(m_itemList.at(m_selPosition));
01499 else
01500 emit itemSelected(NULL);
01501 }
01502
01503 void MythUIButtonList::SetValueByData(QVariant data)
01504 {
01505 if (!m_initialized)
01506 Init();
01507
01508 for (int i = 0; i < m_itemList.size(); ++i)
01509 {
01510 MythUIButtonListItem *item = m_itemList.at(i);
01511
01512 if (item->GetData() == data)
01513 {
01514 SetItemCurrent(item);
01515 return;
01516 }
01517 }
01518 }
01519
01520 void MythUIButtonList::SetItemCurrent(MythUIButtonListItem *item)
01521 {
01522 int newIndex = m_itemList.indexOf(item);
01523 SetItemCurrent(newIndex);
01524 }
01525
01526 void MythUIButtonList::SetItemCurrent(int current, int topPosition)
01527 {
01528 if (!m_initialized)
01529 Init();
01530
01531 if (current == -1 || current >= m_itemList.size())
01532 return;
01533
01534 if (current == m_selPosition &&
01535 (topPosition == -1 || topPosition == m_topPosition))
01536 return;
01537
01538 m_topPosition = topPosition;
01539
01540 if (topPosition > 0 && m_layout == LayoutGrid)
01541 m_topPosition -= (topPosition % m_columns);
01542
01543 m_selPosition = current;
01544
01545 Update();
01546
01547 emit itemSelected(GetItemCurrent());
01548 }
01549
01550 MythUIButtonListItem *MythUIButtonList::GetItemCurrent() const
01551 {
01552 if (m_itemList.isEmpty() || m_selPosition > m_itemList.size() ||
01553 m_selPosition < 0)
01554 return NULL;
01555
01556 return m_itemList.at(m_selPosition);
01557 }
01558
01559 int MythUIButtonList::GetIntValue() const
01560 {
01561 MythUIButtonListItem *item = GetItemCurrent();
01562
01563 if (item)
01564 return item->GetText().toInt();
01565
01566 return 0;
01567 }
01568
01569 QString MythUIButtonList::GetValue() const
01570 {
01571 MythUIButtonListItem *item = GetItemCurrent();
01572
01573 if (item)
01574 return item->GetText();
01575
01576 return QString();
01577 }
01578
01579 QVariant MythUIButtonList::GetDataValue() const
01580 {
01581 MythUIButtonListItem *item = GetItemCurrent();
01582
01583 if (item)
01584 return item->GetData();
01585
01586 return QVariant();
01587 }
01588
01589 MythRect MythUIButtonList::GetButtonArea(void) const
01590 {
01591 if (m_contentsRect.isValid())
01592 return m_contentsRect;
01593 return m_Area;
01594 }
01595
01596 MythUIButtonListItem *MythUIButtonList::GetItemFirst() const
01597 {
01598 if (!m_itemList.empty())
01599 return m_itemList[0];
01600
01601 return NULL;
01602 }
01603
01604 MythUIButtonListItem *MythUIButtonList::GetItemNext(MythUIButtonListItem *item)
01605 const
01606 {
01607 QListIterator<MythUIButtonListItem *> it(m_itemList);
01608
01609 if (!it.findNext(item))
01610 return 0;
01611
01612 return it.previous();
01613 }
01614
01615 int MythUIButtonList::GetCount() const
01616 {
01617 return m_itemCount;
01618 }
01619
01620 uint MythUIButtonList::GetVisibleCount()
01621 {
01622 if (m_needsUpdate)
01623 {
01624 SetPositionArrowStates();
01625 SetScrollBarPosition();
01626 }
01627
01628 return m_itemsVisible;
01629 }
01630
01631 bool MythUIButtonList::IsEmpty() const
01632 {
01633 if (m_itemCount > 0)
01634 return false;
01635 else
01636 return true;
01637 }
01638
01639 MythUIButtonListItem *MythUIButtonList::GetItemAt(int pos) const
01640 {
01641 if (pos < 0 || pos >= m_itemList.size())
01642 return NULL;
01643
01644 return m_itemList.at(pos);
01645 }
01646
01647 MythUIButtonListItem *MythUIButtonList::GetItemByData(QVariant data)
01648 {
01649 if (!m_initialized)
01650 Init();
01651
01652 for (int i = 0; i < m_itemList.size(); ++i)
01653 {
01654 MythUIButtonListItem *item = m_itemList.at(i);
01655
01656 if (item->GetData() == data)
01657 return item;
01658 }
01659
01660 return NULL;
01661 }
01662
01663 int MythUIButtonList::GetItemPos(MythUIButtonListItem *item) const
01664 {
01665 if (!item)
01666 return -1;
01667
01668 return m_itemList.indexOf(item);
01669 }
01670
01671 void MythUIButtonList::InitButton(int itemIdx, MythUIStateType* & realButton,
01672 MythUIButtonListItem* & buttonItem)
01673 {
01674 buttonItem = m_itemList[itemIdx];
01675
01676 if (m_maxVisible == 0)
01677 {
01678 QString name("buttonlist button 0");
01679 MythUIStateType *button = new MythUIStateType(this, name);
01680 button->CopyFrom(m_buttontemplate);
01681 button->ConnectDependants(true);
01682 m_ButtonList.append(button);
01683 ++m_maxVisible;
01684 }
01685
01686 realButton = m_ButtonList[0];
01687 m_ButtonToItem[0] = buttonItem;
01688 }
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699 int MythUIButtonList::PageUp(void)
01700 {
01701 int pos = m_selPosition;
01702 int total = 0;
01703 MythUIGroup *buttonstate;
01704 MythUIStateType *realButton;
01705 MythUIButtonListItem *buttonItem;
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718 if (m_layout == LayoutHorizontal)
01719 {
01720 pos -= (m_leftColumns + 1);
01721
01722 int max_width = m_contentsRect.width() / 2;
01723
01724 for (; pos >= 0; --pos)
01725 {
01726 InitButton(pos, realButton, buttonItem);
01727 buttonItem->SetToRealButton(realButton, true);
01728 buttonstate = dynamic_cast<MythUIGroup *>
01729 (realButton->GetCurrentState());
01730
01731 if (buttonstate == NULL)
01732 {
01733 LOG(VB_GENERAL, LOG_ERR,
01734 "PageUp: Failed to query buttonlist state");
01735 return pos;
01736 }
01737
01738 if (total + m_itemHorizSpacing +
01739 buttonstate->GetArea().width() / 2 >= max_width)
01740 return pos + 1;
01741
01742 buttonItem->SetToRealButton(realButton, false);
01743 buttonstate = dynamic_cast<MythUIGroup *>
01744 (realButton->GetCurrentState());
01745 total += m_itemHorizSpacing + buttonstate->GetArea().width();
01746 }
01747
01748 return 0;
01749 }
01750
01751
01752 int dec;
01753
01754 if (m_layout == LayoutGrid)
01755 {
01756
01757
01758
01759
01760
01761
01762 pos -= (m_columns * (m_topRows + 2 +
01763 qMax(m_bottomRows - m_topRows, 0)));
01764 dec = m_columns;
01765 }
01766 else
01767 {
01768 pos -= (m_topRows + 1);
01769 dec = 1;
01770 }
01771
01772 int max_height = m_contentsRect.height() / 2;
01773
01774 for (; pos >= 0; pos -= dec)
01775 {
01776 InitButton(pos, realButton, buttonItem);
01777 buttonItem->SetToRealButton(realButton, true);
01778 buttonstate = dynamic_cast<MythUIGroup *>
01779 (realButton->GetCurrentState());
01780
01781 if (buttonstate == NULL)
01782 {
01783 LOG(VB_GENERAL, LOG_ERR,
01784 "PageUp: Failed to query buttonlist state");
01785 return pos;
01786 }
01787
01788 if (total + m_itemHorizSpacing +
01789 buttonstate->GetArea().height() / 2 >= max_height)
01790 return pos + dec;
01791
01792 buttonItem->SetToRealButton(realButton, false);
01793 buttonstate = dynamic_cast<MythUIGroup *>
01794 (realButton->GetCurrentState());
01795 total += m_itemHorizSpacing + buttonstate->GetArea().height();
01796 }
01797
01798 return 0;
01799 }
01800
01801 int MythUIButtonList::PageDown(void)
01802 {
01803 int pos = m_selPosition;
01804 int num_items = m_itemList.size();
01805 int total = 0;
01806 MythUIGroup *buttonstate;
01807 MythUIStateType *realButton;
01808 MythUIButtonListItem *buttonItem;
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821 if (m_layout == LayoutHorizontal)
01822 {
01823 pos += (m_rightColumns + 1);
01824
01825 int max_width = m_contentsRect.width() / 2;
01826
01827 for (; pos < num_items; ++pos)
01828 {
01829 InitButton(pos, realButton, buttonItem);
01830 buttonItem->SetToRealButton(realButton, true);
01831 buttonstate = dynamic_cast<MythUIGroup *>
01832 (realButton->GetCurrentState());
01833
01834 if (buttonstate == NULL)
01835 {
01836 LOG(VB_GENERAL, LOG_ERR,
01837 "PageDown: Failed to query buttonlist state");
01838 return pos;
01839 }
01840
01841 if (total + m_itemHorizSpacing +
01842 buttonstate->GetArea().width() / 2 >= max_width)
01843 return pos - 1;
01844
01845 buttonItem->SetToRealButton(realButton, false);
01846 buttonstate = dynamic_cast<MythUIGroup *>
01847 (realButton->GetCurrentState());
01848 total += m_itemHorizSpacing + buttonstate->GetArea().width();
01849 }
01850
01851 return num_items - 1;
01852 }
01853
01854
01855 int inc;
01856
01857 if (m_layout == LayoutGrid)
01858 {
01859
01860
01861
01862
01863
01864
01865 pos += (m_columns * (m_bottomRows + 2 +
01866 qMax(m_topRows - m_bottomRows, 0)));
01867 inc = m_columns;
01868 }
01869 else
01870 {
01871 pos += (m_bottomRows + 1);
01872 inc = 1;
01873 }
01874
01875 int max_height = m_contentsRect.height() / 2;
01876
01877 for (; pos < num_items; pos += inc)
01878 {
01879 InitButton(pos, realButton, buttonItem);
01880 buttonItem->SetToRealButton(realButton, true);
01881 buttonstate = dynamic_cast<MythUIGroup *>
01882 (realButton->GetCurrentState());
01883
01884 if (!buttonstate)
01885 {
01886 LOG(VB_GENERAL, LOG_ERR,
01887 "PageDown: Failed to query buttonlist state");
01888 return pos;
01889 }
01890
01891 if (total + m_itemHorizSpacing +
01892 buttonstate->GetArea().height() / 2 >= max_height)
01893 return pos - inc;
01894
01895 buttonItem->SetToRealButton(realButton, false);
01896 buttonstate = dynamic_cast<MythUIGroup *>
01897 (realButton->GetCurrentState());
01898 if (buttonstate)
01899 total += m_itemHorizSpacing + buttonstate->GetArea().height();
01900 }
01901
01902 return num_items - 1;
01903 }
01904
01905 bool MythUIButtonList::MoveUp(MovementUnit unit, uint amount)
01906 {
01907 int pos = m_selPosition;
01908
01909 if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
01910 return false;
01911
01912 switch (unit)
01913 {
01914 case MoveItem:
01915 if (m_selPosition > 0)
01916 --m_selPosition;
01917 else if (m_wrapStyle > WrapNone)
01918 m_selPosition = m_itemList.size() - 1;
01919 else if (m_wrapStyle == WrapCaptive)
01920 return true;
01921
01922 break;
01923
01924 case MoveColumn:
01925 if (pos % m_columns > 0)
01926 --m_selPosition;
01927 else if (m_wrapStyle == WrapFlowing)
01928 if (m_selPosition == 0)
01929 --m_selPosition = m_itemList.size() - 1;
01930 else
01931 --m_selPosition;
01932 else if (m_wrapStyle > WrapNone)
01933 m_selPosition = pos + (m_columns - 1);
01934 else if (m_wrapStyle == WrapCaptive)
01935 return true;
01936
01937 break;
01938
01939 case MoveRow:
01940 if (m_scrollStyle != ScrollFree)
01941 {
01942 m_selPosition -= m_columns;
01943 if (m_selPosition < 0)
01944 m_selPosition += m_itemList.size();
01945 else
01946 m_selPosition %= m_itemList.size();
01947 }
01948 else if ((pos - m_columns) >= 0)
01949 m_selPosition -= m_columns;
01950 else if (m_wrapStyle > WrapNone)
01951 {
01952 m_selPosition = ((m_itemList.size() - 1) / m_columns) *
01953 m_columns + pos;
01954
01955 if ((m_selPosition / m_columns)
01956 < ((m_itemList.size() - 1) / m_columns))
01957 m_selPosition = m_itemList.size() - 1;
01958
01959 if (m_layout == LayoutVertical)
01960 m_topPosition = qMax(0, m_selPosition - (int)m_itemsVisible + 1);
01961 }
01962 else if (m_wrapStyle == WrapCaptive)
01963 return true;
01964
01965 break;
01966
01967 case MovePage:
01968 if (m_arrange == ArrangeFixed)
01969 m_selPosition = qMax(0, m_selPosition - (int)m_itemsVisible);
01970 else
01971 m_selPosition = PageUp();
01972
01973 break;
01974
01975 case MoveMid:
01976 m_selPosition = (int)(m_itemList.size() / 2);
01977 break;
01978
01979 case MoveMax:
01980 m_selPosition = 0;
01981 break;
01982
01983 case MoveByAmount:
01984 for (uint i = 0; i < amount; ++i)
01985 {
01986 if (m_selPosition > 0)
01987 --m_selPosition;
01988 else if (m_wrapStyle > WrapNone)
01989 m_selPosition = m_itemList.size() - 1;
01990 }
01991
01992 break;
01993 }
01994
01995 SanitizePosition();
01996
01997 if (pos != m_selPosition)
01998 {
01999 Update();
02000 emit itemSelected(GetItemCurrent());
02001 }
02002 else
02003 return false;
02004
02005 return true;
02006 }
02007
02008 bool MythUIButtonList::MoveDown(MovementUnit unit, uint amount)
02009 {
02010 int pos = m_selPosition;
02011
02012 if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
02013 return false;
02014
02015 switch (unit)
02016 {
02017 case MoveItem:
02018 if (m_selPosition < m_itemList.size() - 1)
02019 ++m_selPosition;
02020 else if (m_wrapStyle > WrapNone)
02021 m_selPosition = 0;
02022 else if (m_wrapStyle == WrapCaptive)
02023 return true;
02024
02025 break;
02026
02027 case MoveColumn:
02028 if ((pos + 1) % m_columns > 0)
02029 ++m_selPosition;
02030 else if (m_wrapStyle == WrapFlowing)
02031 if (m_selPosition < m_itemList.size() - 1)
02032 ++m_selPosition;
02033 else
02034 m_selPosition = 0;
02035 else if (m_wrapStyle > WrapNone)
02036 m_selPosition = pos - (m_columns - 1);
02037 else if (m_wrapStyle == WrapCaptive)
02038 return true;
02039
02040 break;
02041
02042 case MoveRow:
02043 if (m_scrollStyle != ScrollFree)
02044 {
02045 m_selPosition += m_columns;
02046 m_selPosition %= m_itemList.size();
02047 }
02048 else if (((m_itemList.size() - 1) / qMax(m_columns, 0))
02049 > (pos / m_columns))
02050 {
02051 m_selPosition += m_columns;
02052 if (m_selPosition > m_itemList.size() - 1)
02053 m_selPosition = m_itemList.size() - 1;
02054 }
02055 else if (m_wrapStyle > WrapNone)
02056 m_selPosition = (pos % m_columns);
02057 else if (m_wrapStyle == WrapCaptive)
02058 return true;
02059
02060 break;
02061
02062 case MovePage:
02063 if (m_arrange == ArrangeFixed)
02064 m_selPosition = qMin(m_itemCount - 1,
02065 m_selPosition + (int)m_itemsVisible);
02066 else
02067 m_selPosition = PageDown();
02068
02069 break;
02070
02071 case MoveMax:
02072 m_selPosition = m_itemCount - 1;
02073 break;
02074
02075 case MoveByAmount:
02076 for (uint i = 0; i < amount; ++i)
02077 {
02078 if (m_selPosition < m_itemList.size() - 1)
02079 ++m_selPosition;
02080 else if (m_wrapStyle > WrapNone)
02081 m_selPosition = 0;
02082 }
02083
02084 break;
02085 }
02086
02087 SanitizePosition();
02088
02089 if (pos != m_selPosition)
02090 {
02091 m_keepSelAtBottom = true;
02092 Update();
02093 emit itemSelected(GetItemCurrent());
02094 }
02095 else
02096 return false;
02097
02098 return true;
02099 }
02100
02101 bool MythUIButtonList::MoveToNamedPosition(const QString &position_name)
02102 {
02103 if (!m_initialized)
02104 Init();
02105
02106 if (m_selPosition < 0 || m_itemList.isEmpty() || !m_initialized)
02107 return false;
02108
02109 bool found_it = false;
02110 int selectedPosition = 0;
02111 QList<MythUIButtonListItem *>::iterator it = m_itemList.begin();
02112
02113 while (it != m_itemList.end())
02114 {
02115 if ((*it)->GetText() == position_name)
02116 {
02117 found_it = true;
02118 break;
02119 }
02120
02121 ++it;
02122 ++selectedPosition;
02123 }
02124
02125 if (!found_it || m_selPosition == selectedPosition)
02126 return false;
02127
02128 SetItemCurrent(selectedPosition);
02129 return true;
02130 }
02131
02132 bool MythUIButtonList::MoveItemUpDown(MythUIButtonListItem *item, bool up)
02133 {
02134 if (GetItemCurrent() != item)
02135 return false;
02136
02137 if (item == m_itemList.first() && up)
02138 return false;
02139
02140 if (item == m_itemList.last() && !up)
02141 return false;
02142
02143 int oldpos = m_selPosition;
02144 int insertat = 0;
02145 bool dolast = false;
02146
02147 if (up)
02148 {
02149 insertat = m_selPosition - 1;
02150
02151 if (item == m_itemList.last())
02152 dolast = true;
02153 else
02154 ++m_selPosition;
02155
02156 if (item == m_itemList.at(m_topPosition))
02157 ++m_topPosition;
02158 }
02159 else
02160 insertat = m_selPosition + 1;
02161
02162 m_itemList.removeAt(oldpos);
02163 m_itemList.insert(insertat, item);
02164
02165 if (up)
02166 {
02167 MoveUp();
02168
02169 if (!dolast)
02170 MoveUp();
02171 }
02172 else
02173 MoveDown();
02174
02175 return true;
02176 }
02177
02178 void MythUIButtonList::SetAllChecked(MythUIButtonListItem::CheckState state)
02179 {
02180 QMutableListIterator<MythUIButtonListItem *> it(m_itemList);
02181
02182 while (it.hasNext())
02183 it.next()->setChecked(state);
02184 }
02185
02186 void MythUIButtonList::Init()
02187 {
02188 if (m_initialized)
02189 return;
02190
02191 m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
02192 m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
02193 m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
02194
02195 if (m_upArrow)
02196 m_upArrow->SetVisible(true);
02197
02198 if (m_downArrow)
02199 m_downArrow->SetVisible(true);
02200
02201 if (m_scrollBar)
02202 m_scrollBar->SetVisible(m_showScrollBar);
02203
02204 m_contentsRect.CalculateArea(m_Area);
02205
02206 m_buttontemplate = dynamic_cast<MythUIStateType *>(GetChild("buttonitem"));
02207
02208 if (!m_buttontemplate)
02209 {
02210 LOG(VB_GENERAL, LOG_ERR, QString("(%1) Statetype buttonitem is "
02211 "required in mythuibuttonlist: %2")
02212 .arg(GetXMLLocation()).arg(objectName()));
02213 return;
02214 }
02215
02216 m_buttontemplate->SetVisible(false);
02217
02218 MythRect buttonItemArea;
02219
02220 MythUIGroup *buttonActiveState = dynamic_cast<MythUIGroup *>
02221 (m_buttontemplate->GetState("active"));
02222
02223 if (buttonActiveState)
02224 buttonItemArea = buttonActiveState->GetArea();
02225 else
02226 buttonItemArea = m_buttontemplate->GetArea();
02227
02228 buttonItemArea.CalculateArea(m_contentsRect);
02229
02230 m_itemHeight = buttonItemArea.height();
02231 m_itemWidth = buttonItemArea.width();
02232
02233
02234
02235
02236
02237 if (m_arrange == ArrangeFixed)
02238 {
02239
02240 CalculateVisibleItems();
02241
02242 int col = 1;
02243 int row = 1;
02244
02245 for (int i = 0; i < (int)m_itemsVisible; i++)
02246 {
02247 QString name = QString("buttonlist button %1").arg(i);
02248 MythUIStateType *button = new MythUIStateType(this, name);
02249 button->CopyFrom(m_buttontemplate);
02250 button->ConnectDependants(true);
02251
02252 if (col > m_columns)
02253 {
02254 col = 1;
02255 row++;
02256 }
02257
02258 button->SetPosition(GetButtonPosition(col, row));
02259 col++;
02260
02261 m_ButtonList.push_back(button);
02262 }
02263 }
02264
02265
02266
02267
02268
02269
02270 MythUIGroup *buttonSelectedState = dynamic_cast<MythUIGroup *>
02271 (m_buttontemplate->GetState("selected"));
02272
02273 if (buttonSelectedState)
02274 {
02275 MythRect itemArea = buttonSelectedState->GetArea();
02276 itemArea.CalculateArea(m_contentsRect);
02277
02278 if (m_itemHeight < itemArea.height())
02279 m_itemHeight = itemArea.height();
02280
02281 if (m_itemWidth < itemArea.width())
02282 m_itemWidth = itemArea.width();
02283 }
02284
02285
02286
02287 m_initialized = true;
02288 }
02289
02290 uint MythUIButtonList::ItemWidth(void)
02291 {
02292 if (!m_initialized)
02293 Init();
02294
02295 return m_itemWidth;
02296 }
02297
02298 uint MythUIButtonList::ItemHeight(void)
02299 {
02300 if (!m_initialized)
02301 Init();
02302
02303 return m_itemHeight;
02304 }
02305
02309 bool MythUIButtonList::keyPressEvent(QKeyEvent *e)
02310 {
02311 QStringList actions;
02312 bool handled = false;
02313 handled = GetMythMainWindow()->TranslateKeyPress("Global", e, actions);
02314
02315
02316 for (int i = 0; i < actions.size(); i++)
02317 {
02318 if (!m_actionRemap.contains(actions[i]))
02319 continue;
02320
02321 QString key = m_actionRemap[actions[i]];
02322 if (key.isEmpty())
02323 return true;
02324
02325 QKeySequence a(key);
02326 if (a.isEmpty())
02327 continue;
02328
02329 int keyCode = a[0];
02330 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
02331 QStringList parts = key.split('+');
02332 for (int j = 0; j < parts.count(); j++)
02333 {
02334 if (parts[j].toUpper() == "CTRL")
02335 modifiers |= Qt::ControlModifier;
02336 if (parts[j].toUpper() == "SHIFT")
02337 modifiers |= Qt::ShiftModifier;
02338 if (parts[j].toUpper() == "ALT")
02339 modifiers |= Qt::AltModifier;
02340 if (parts[j].toUpper() == "META")
02341 modifiers |= Qt::MetaModifier;
02342 }
02343
02344 QCoreApplication::postEvent(
02345 GetMythMainWindow(),
02346 new QKeyEvent(QEvent::KeyPress, keyCode, modifiers, key));
02347 QCoreApplication::postEvent(
02348 GetMythMainWindow(),
02349 new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers, key));
02350
02351 return true;
02352 }
02353
02354
02355 for (int i = 0; i < actions.size() && !handled; i++)
02356 {
02357 QString action = actions[i];
02358 handled = true;
02359
02360 if (action == "UP")
02361 {
02362 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02363 handled = MoveUp(MoveRow);
02364 else
02365 handled = false;
02366 }
02367 else if (action == "DOWN")
02368 {
02369 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02370 handled = MoveDown(MoveRow);
02371 else
02372 handled = false;
02373 }
02374 else if (action == "RIGHT")
02375 {
02376 if (m_layout == LayoutHorizontal)
02377 handled = MoveDown(MoveItem);
02378 else if (m_layout == LayoutGrid)
02379 {
02380 if (m_scrollStyle == ScrollFree)
02381 handled = MoveDown(MoveColumn);
02382 else
02383 handled = MoveDown(MoveItem);
02384 }
02385 else
02386 handled = false;
02387 }
02388 else if (action == "LEFT")
02389 {
02390 if (m_layout == LayoutHorizontal)
02391 handled = MoveUp(MoveItem);
02392 else if (m_layout == LayoutGrid)
02393 {
02394 if (m_scrollStyle == ScrollFree)
02395 handled = MoveUp(MoveColumn);
02396 else
02397 handled = MoveUp(MoveItem);
02398 }
02399 else
02400 handled = false;
02401 }
02402 else if (action == "PAGEUP")
02403 {
02404 MoveUp(MovePage);
02405 }
02406 else if (action == "PAGEDOWN")
02407 {
02408 MoveDown(MovePage);
02409 }
02410 else if (action == "PAGETOP")
02411 {
02412 MoveUp(MoveMax);
02413 }
02414 else if (action == "PAGEMIDDLE")
02415 {
02416 MoveUp(MoveMid);
02417 }
02418 else if (action == "PAGEBOTTOM")
02419 {
02420 MoveDown(MoveMax);
02421 }
02422 else if (action == "SELECT")
02423 {
02424 MythUIButtonListItem *item = GetItemCurrent();
02425
02426 if (item)
02427 emit itemClicked(item);
02428 }
02429 else if (action == "SEARCH")
02430 {
02431 ShowSearchDialog();
02432 }
02433 else
02434 handled = false;
02435 }
02436
02437 return handled;
02438 }
02439
02443 bool MythUIButtonList::gestureEvent(MythGestureEvent *event)
02444 {
02445 bool handled = false;
02446
02447 if (event->gesture() == MythGestureEvent::Click)
02448 {
02449
02450 QPoint position = event->GetPosition() -
02451 m_Parent->GetArea().topLeft();
02452
02453 MythUIType *type = GetChildAt(position, false, false);
02454
02455 if (!type)
02456 return false;
02457
02458 MythUIStateType *object = dynamic_cast<MythUIStateType *>(type);
02459
02460 if (object)
02461 {
02462 handled = true;
02463 QString name = object->objectName();
02464
02465 if (name == "upscrollarrow")
02466 {
02467 MoveUp(MovePage);
02468 }
02469 else if (name == "downscrollarrow")
02470 {
02471 MoveDown(MovePage);
02472 }
02473 else if (name.startsWith("buttonlist button"))
02474 {
02475 int pos = name.section(' ', 2, 2).toInt();
02476 MythUIButtonListItem *item = m_ButtonToItem[pos];
02477
02478 if (item)
02479 {
02480 if (item == GetItemCurrent())
02481 emit itemClicked(item);
02482 else
02483 SetItemCurrent(item);
02484 }
02485 }
02486 else
02487 handled = false;
02488 }
02489 }
02490
02491 return handled;
02492 }
02493
02494 class NextButtonListPageEvent : public QEvent
02495 {
02496 public:
02497 NextButtonListPageEvent(int start, int pageSize) :
02498 QEvent(kEventType), m_start(start), m_pageSize(pageSize) {}
02499 const int m_start;
02500 const int m_pageSize;
02501 static Type kEventType;
02502 };
02503
02504 QEvent::Type NextButtonListPageEvent::kEventType =
02505 (QEvent::Type) QEvent::registerEventType();
02506
02507 void MythUIButtonList::customEvent(QEvent *event)
02508 {
02509 if (event->type() == NextButtonListPageEvent::kEventType)
02510 {
02511 NextButtonListPageEvent *npe =
02512 static_cast<NextButtonListPageEvent*>(event);
02513 int cur = npe->m_start;
02514 for (; cur < npe->m_start + npe->m_pageSize && cur < GetCount(); ++cur)
02515 {
02516 const int loginterval = (cur < 1000 ? 100 : 500);
02517 if (cur % loginterval == 0)
02518 LOG(VB_GENERAL, LOG_INFO,
02519 QString("Build background buttonlist item %1").arg(cur));
02520 emit itemLoaded(GetItemAt(cur));
02521 }
02522 m_nextItemLoaded = cur;
02523 if (cur < GetCount())
02524 LoadInBackground(cur, npe->m_pageSize);
02525 }
02526 }
02527
02528 void MythUIButtonList::LoadInBackground(int start, int pageSize)
02529 {
02530 m_nextItemLoaded = start;
02531 QCoreApplication::
02532 postEvent(this, new NextButtonListPageEvent(start, pageSize));
02533 }
02534
02535 int MythUIButtonList::StopLoad(void)
02536 {
02537 QCoreApplication::
02538 removePostedEvents(this, NextButtonListPageEvent::kEventType);
02539 return m_nextItemLoaded;
02540 }
02541
02542 QPoint MythUIButtonList::GetButtonPosition(int column, int row) const
02543 {
02544 int x = m_contentsRect.x() +
02545 ((column - 1) * (m_itemWidth + m_itemHorizSpacing));
02546 int y = m_contentsRect.y() +
02547 ((row - 1) * (m_itemHeight + m_itemVertSpacing));
02548
02549 return QPoint(x, y);
02550 }
02551
02552 void MythUIButtonList::CalculateVisibleItems(void)
02553 {
02554 m_itemsVisible = 0;
02555 m_rows = 0;
02556 m_columns = 0;
02557
02558 if ((m_layout == LayoutHorizontal) || (m_layout == LayoutGrid))
02559 {
02560 int x = 0;
02561
02562 while (x <= m_contentsRect.width() - m_itemWidth)
02563 {
02564 x += m_itemWidth + m_itemHorizSpacing;
02565 m_columns++;
02566 }
02567 }
02568
02569 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02570 {
02571 int y = 0;
02572
02573 while (y <= m_contentsRect.height() - m_itemHeight)
02574 {
02575 y += m_itemHeight + m_itemVertSpacing;
02576 m_rows++;
02577 }
02578 }
02579
02580 if (m_rows <= 0)
02581 m_rows = 1;
02582
02583 if (m_columns <= 0)
02584 m_columns = 1;
02585
02586 m_itemsVisible = m_columns * m_rows;
02587 }
02588
02589 void MythUIButtonList::SetButtonArea(const MythRect &rect)
02590 {
02591 if (rect == m_contentsRect)
02592 return;
02593
02594 m_contentsRect = rect;
02595
02596 if (m_Area.isValid())
02597 m_contentsRect.CalculateArea(m_Area);
02598 else if (m_Parent)
02599 m_contentsRect.CalculateArea(m_Parent->GetFullArea());
02600 else
02601 m_contentsRect.CalculateArea(GetMythMainWindow()->GetUIScreenRect());
02602 }
02603
02607 bool MythUIButtonList::ParseElement(
02608 const QString &filename, QDomElement &element, bool showWarnings)
02609 {
02610 if (element.tagName() == "buttonarea")
02611 SetButtonArea(parseRect(element));
02612 else if (element.tagName() == "layout")
02613 {
02614 QString layout = getFirstText(element).toLower();
02615
02616 if (layout == "grid")
02617 m_layout = LayoutGrid;
02618 else if (layout == "horizontal")
02619 m_layout = LayoutHorizontal;
02620 else
02621 m_layout = LayoutVertical;
02622 }
02623 else if (element.tagName() == "arrange")
02624 {
02625 QString arrange = getFirstText(element).toLower();
02626
02627 if (arrange == "fill")
02628 m_arrange = ArrangeFill;
02629 else if (arrange == "spread")
02630 m_arrange = ArrangeSpread;
02631 else if (arrange == "stack")
02632 m_arrange = ArrangeStack;
02633 else
02634 m_arrange = ArrangeFixed;
02635
02636 }
02637 else if (element.tagName() == "align")
02638 {
02639 QString align = getFirstText(element).toLower();
02640 m_alignment = parseAlignment(align);
02641 }
02642 else if (element.tagName() == "scrollstyle")
02643 {
02644 QString layout = getFirstText(element).toLower();
02645
02646 if (layout == "center")
02647 m_scrollStyle = ScrollCenter;
02648 else if (layout == "groupcenter")
02649 m_scrollStyle = ScrollGroupCenter;
02650 else if (layout == "free")
02651 m_scrollStyle = ScrollFree;
02652 }
02653 else if (element.tagName() == "wrapstyle")
02654 {
02655 QString wrapstyle = getFirstText(element).toLower();
02656
02657 if (wrapstyle == "captive")
02658 m_wrapStyle = WrapCaptive;
02659 else if (wrapstyle == "none")
02660 m_wrapStyle = WrapNone;
02661 else if (wrapstyle == "selection")
02662 m_wrapStyle = WrapSelect;
02663 else if (wrapstyle == "flowing")
02664 m_wrapStyle = WrapFlowing;
02665 else if (wrapstyle == "items")
02666 m_wrapStyle = WrapItems;
02667 }
02668 else if (element.tagName() == "showarrow")
02669 m_showArrow = parseBool(element);
02670 else if (element.tagName() == "showscrollbar")
02671 m_showScrollBar = parseBool(element);
02672 else if (element.tagName() == "spacing")
02673 {
02674 m_itemHorizSpacing = NormX(getFirstText(element).toInt());
02675 m_itemVertSpacing = NormY(getFirstText(element).toInt());
02676 }
02677 else if (element.tagName() == "drawfrombottom")
02678 {
02679 m_drawFromBottom = parseBool(element);
02680
02681 if (m_drawFromBottom)
02682 m_alignment |= Qt::AlignBottom;
02683 }
02684 else if (element.tagName() == "searchposition")
02685 {
02686 m_searchPosition = parsePoint(element);
02687 }
02688 else if (element.tagName() == "triggerevent")
02689 {
02690 QString trigger = getFirstText(element);
02691 if (!trigger.isEmpty())
02692 {
02693 QString action = element.attribute("action", "");
02694 if (action.isEmpty())
02695 {
02696 m_actionRemap[trigger] = "";
02697 }
02698 else
02699 {
02700 QString context = element.attribute("context", "");
02701 QString keylist = GetMythMainWindow()->GetKey(context, action);
02702 QStringList keys = keylist.split(',', QString::SkipEmptyParts);
02703 if (!keys.empty())
02704 m_actionRemap[trigger] = keys[0];
02705 }
02706 }
02707 }
02708 else
02709 {
02710 return MythUIType::ParseElement(filename, element, showWarnings);
02711 }
02712
02713 return true;
02714 }
02715
02719 void MythUIButtonList::DrawSelf(MythPainter *, int, int, int, QRect)
02720 {
02721 if (m_needsUpdate)
02722 {
02723 SetPositionArrowStates();
02724 SetScrollBarPosition();
02725 }
02726 }
02727
02731 void MythUIButtonList::CreateCopy(MythUIType *parent)
02732 {
02733 MythUIButtonList *lb = new MythUIButtonList(parent, objectName());
02734 lb->CopyFrom(this);
02735 }
02736
02740 void MythUIButtonList::CopyFrom(MythUIType *base)
02741 {
02742 MythUIButtonList *lb = dynamic_cast<MythUIButtonList *>(base);
02743
02744 if (!lb)
02745 return;
02746
02747 m_layout = lb->m_layout;
02748 m_arrange = lb->m_arrange;
02749 m_alignment = lb->m_alignment;
02750
02751 m_contentsRect = lb->m_contentsRect;
02752
02753 m_itemHeight = lb->m_itemHeight;
02754 m_itemWidth = lb->m_itemWidth;
02755 m_itemHorizSpacing = lb->m_itemHorizSpacing;
02756 m_itemVertSpacing = lb->m_itemVertSpacing;
02757 m_itemsVisible = lb->m_itemsVisible;
02758 m_maxVisible = lb->m_maxVisible;
02759
02760 m_active = lb->m_active;
02761 m_showArrow = lb->m_showArrow;
02762 m_showScrollBar = lb->m_showScrollBar;
02763
02764 m_drawFromBottom = lb->m_drawFromBottom;
02765
02766 m_scrollStyle = lb->m_scrollStyle;
02767 m_wrapStyle = lb->m_wrapStyle;
02768
02769 m_clearing = false;
02770 m_selPosition = m_topPosition = m_itemCount = 0;
02771
02772 m_searchPosition = lb->m_searchPosition;
02773 m_searchFields = lb->m_searchFields;
02774
02775 MythUIType::CopyFrom(base);
02776
02777 m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
02778 m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
02779 m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
02780
02781 for (int i = 0; i < (int)m_itemsVisible; i++)
02782 {
02783 MythUIType *deltype;
02784 QString name = QString("buttonlist button %1").arg(i);
02785 deltype = GetChild(name);
02786 delete deltype;
02787 }
02788
02789 m_ButtonList.clear();
02790
02791 m_actionRemap = lb->m_actionRemap;
02792
02793 m_initialized = false;
02794 }
02795
02799 void MythUIButtonList::Finalize(void)
02800 {
02801 MythUIType::Finalize();
02802 }
02803
02804 void MythUIButtonList::SetLCDTitles(const QString &title, const QString &columnList)
02805 {
02806 m_lcdTitle = title;
02807 m_lcdColumns = columnList.split('|');
02808 }
02809
02810 void MythUIButtonList::updateLCD(void)
02811 {
02812 if (!m_HasFocus)
02813 return;
02814
02815 LCD *lcddev = LCD::Get();
02816
02817 if (lcddev == NULL)
02818 return;
02819
02820
02821 QList<LCDMenuItem> menuItems;
02822 bool selected;
02823
02824 int start = std::max(0, (int)(m_selPosition - lcddev->getLCDHeight()));
02825 int end = std::min(m_itemCount, (int)(start + (lcddev->getLCDHeight() * 2)));
02826
02827 for (int r = start; r < end; r++)
02828 {
02829 if (r == GetCurrentPos())
02830 selected = true;
02831 else
02832 selected = false;
02833
02834 MythUIButtonListItem *item = GetItemAt(r);
02835 CHECKED_STATE state = NOTCHECKABLE;
02836
02837 if (item->checkable())
02838 state = (item->state() == MythUIButtonListItem::NotChecked) ? UNCHECKED : CHECKED;
02839
02840 QString text;
02841
02842 for (int x = 0; x < m_lcdColumns.count(); x++)
02843 {
02844 if (!m_lcdColumns[x].isEmpty() && item->m_strings.contains(m_lcdColumns[x]))
02845 {
02846
02847 TextProperties props = item->m_strings[m_lcdColumns[x]];
02848
02849 if (text.isEmpty())
02850 text = props.text;
02851 else
02852 text += " ~ " + props.text;
02853 }
02854 else
02855 {
02856
02857 if (text.isEmpty())
02858 text = item->GetText();
02859 else
02860 text += " ~ " + item->GetText();
02861 }
02862 }
02863
02864 if (!text.isEmpty())
02865 menuItems.append(LCDMenuItem(selected, state, text));
02866 else
02867 menuItems.append(LCDMenuItem(selected, state, item->GetText()));
02868 }
02869
02870 if (!menuItems.isEmpty())
02871 lcddev->switchToMenu(menuItems, m_lcdTitle);
02872 }
02873
02874 void MythUIButtonList::ShowSearchDialog(void)
02875 {
02876 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
02877
02878 SearchButtonListDialog *dlg = new SearchButtonListDialog(popupStack, "MythSearchListDialog", this, "");
02879
02880 if (dlg->Create())
02881 {
02882 if (m_searchPosition.x() != -2 || m_searchPosition.y() != -2)
02883 {
02884 int x = m_searchPosition.x();
02885 int y = m_searchPosition.y();
02886 QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
02887 QRect dialogArea = dlg->GetArea();
02888
02889 if (x == -1)
02890 x = (screenArea.width() - dialogArea.width()) / 2;
02891
02892 if (y == -1)
02893 y = (screenArea.height() - dialogArea.height()) / 2;
02894
02895 dlg->SetPosition(x, y);
02896 }
02897
02898 popupStack->AddScreen(dlg);
02899 }
02900 else
02901 delete dlg;
02902 }
02903
02904 bool MythUIButtonList::Find(const QString &searchStr, bool startsWith)
02905 {
02906 m_searchStr = searchStr;
02907 m_searchStartsWith = startsWith;
02908 return DoFind(false, true);
02909 }
02910
02911 bool MythUIButtonList::FindNext(void)
02912 {
02913 return DoFind(true, true);
02914 }
02915
02916 bool MythUIButtonList::FindPrev(void)
02917 {
02918 return DoFind(true, false);
02919 }
02920
02921 bool MythUIButtonList::DoFind(bool doMove, bool searchForward)
02922 {
02923 if (m_searchStr.isEmpty())
02924 return true;
02925
02926 if (GetCount() == 0)
02927 return false;
02928
02929 int startPos = GetCurrentPos();
02930 int currPos = startPos;
02931 bool found = false;
02932
02933 if (doMove)
02934 {
02935 if (searchForward)
02936 {
02937 currPos++;
02938
02939 if (currPos >= GetCount())
02940 currPos = 0;
02941 }
02942 else
02943 {
02944 currPos--;
02945
02946 if (currPos < 0)
02947 currPos = GetCount() - 1;
02948 }
02949 }
02950
02951 while (true)
02952 {
02953 found = GetItemAt(currPos)->FindText(m_searchStr, m_searchFields, m_searchStartsWith);
02954
02955 if (found)
02956 {
02957 SetItemCurrent(currPos);
02958 return true;
02959 }
02960
02961 if (searchForward)
02962 {
02963 currPos++;
02964
02965 if (currPos >= GetCount())
02966 currPos = 0;
02967 }
02968 else
02969 {
02970 currPos--;
02971
02972 if (currPos < 0)
02973 currPos = GetCount() - 1;
02974 }
02975
02976 if (startPos == currPos)
02977 break;
02978 }
02979
02980 return false;
02981 }
02982
02984
02985 MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList *lbtype,
02986 const QString &text, const QString &image,
02987 bool checkable, CheckState state,
02988 bool showArrow, int listPosition)
02989 {
02990 if (!lbtype)
02991 LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
02992
02993 m_parent = lbtype;
02994 m_text = text;
02995 m_image = NULL;
02996 m_imageFilename = image;
02997 m_checkable = checkable;
02998 m_state = state;
02999 m_showArrow = showArrow;
03000 m_data = 0;
03001
03002 if (state >= NotChecked)
03003 m_checkable = true;
03004
03005 if (m_parent)
03006 m_parent->InsertItem(this, listPosition);
03007 }
03008
03009 MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList *lbtype,
03010 const QString &text,
03011 QVariant data, int listPosition)
03012 {
03013 if (!lbtype)
03014 LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
03015
03016 m_parent = lbtype;
03017 m_text = text;
03018 m_data = data;
03019
03020 m_image = NULL;
03021
03022 m_checkable = false;
03023 m_state = CantCheck;
03024 m_showArrow = false;
03025
03026 if (m_parent)
03027 m_parent->InsertItem(this, listPosition);
03028 }
03029
03030 MythUIButtonListItem::~MythUIButtonListItem()
03031 {
03032 if (m_parent)
03033 m_parent->RemoveItem(this);
03034
03035 if (m_image)
03036 m_image->DownRef();
03037
03038 QMapIterator<QString, MythImage *> it(m_images);
03039
03040 while (it.hasNext())
03041 {
03042 it.next();
03043 it.value()->DownRef();
03044 }
03045 }
03046
03047 void MythUIButtonListItem::SetText(const QString &text, const QString &name,
03048 const QString &state)
03049 {
03050 if (!name.isEmpty())
03051 {
03052 TextProperties textprop;
03053 textprop.text = text;
03054 textprop.state = state;
03055 m_strings.insert(name, textprop);
03056 }
03057 else
03058 m_text = text;
03059
03060 if (m_parent)
03061 m_parent->Update();
03062 }
03063
03064 void MythUIButtonListItem::SetTextFromMap(InfoMap &infoMap,
03065 const QString &state)
03066 {
03067 QHash<QString, QString>::iterator map_it = infoMap.begin();
03068
03069 while (map_it != infoMap.end())
03070 {
03071 TextProperties textprop;
03072 textprop.text = (*map_it);
03073 textprop.state = state;
03074 m_strings[map_it.key()] = textprop;
03075 ++map_it;
03076 }
03077
03078 if (m_parent)
03079 m_parent->Update();
03080 }
03081
03082 void MythUIButtonListItem::SetTextFromMap(QMap<QString, TextProperties> &stringMap)
03083 {
03084 m_strings.clear();
03085 m_strings = stringMap;
03086 }
03087
03088 QString MythUIButtonListItem::GetText(const QString &name) const
03089 {
03090 if (name.isEmpty())
03091 return m_text;
03092 else if (m_strings.contains(name))
03093 return m_strings[name].text;
03094 else
03095 return QString();
03096 }
03097
03098 bool MythUIButtonListItem::FindText(const QString &searchStr, const QString &fieldList,
03099 bool startsWith) const
03100 {
03101 if (fieldList.isEmpty())
03102 {
03103 if (startsWith)
03104 return m_text.startsWith(searchStr, Qt::CaseInsensitive);
03105 else
03106 return m_text.contains(searchStr, Qt::CaseInsensitive);
03107 }
03108 else if (fieldList == "**ALL**")
03109 {
03110 if (startsWith)
03111 {
03112 if (m_text.startsWith(searchStr, Qt::CaseInsensitive))
03113 return true;
03114 }
03115 else
03116 {
03117 if (m_text.contains(searchStr, Qt::CaseInsensitive))
03118 return true;
03119 }
03120
03121 QMap<QString, TextProperties>::const_iterator i = m_strings.constBegin();
03122
03123 while (i != m_strings.constEnd())
03124 {
03125 if (startsWith)
03126 {
03127 if (i.value().text.startsWith(searchStr, Qt::CaseInsensitive))
03128 return true;
03129 }
03130 else
03131 {
03132 if (i.value().text.contains(searchStr, Qt::CaseInsensitive))
03133 return true;
03134 }
03135
03136 ++i;
03137 }
03138 }
03139 else
03140 {
03141 QStringList fields = fieldList.split(',', QString::SkipEmptyParts);
03142
03143 for (int x = 0; x < fields.count(); x++)
03144 {
03145 if (m_strings.contains(fields.at(x).trimmed()))
03146 {
03147 if (startsWith)
03148 {
03149 if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
03150 return true;
03151 }
03152 else
03153 {
03154 if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
03155 return true;
03156 }
03157 }
03158 }
03159 }
03160
03161 return false;
03162 }
03163
03164 void MythUIButtonListItem::SetFontState(const QString &state,
03165 const QString &name)
03166 {
03167 if (!name.isEmpty())
03168 {
03169 if (m_strings.contains(name))
03170 m_strings[name].state = state;
03171 }
03172 else
03173 m_fontState = state;
03174
03175 if (m_parent)
03176 m_parent->Update();
03177 }
03178
03179 void MythUIButtonListItem::setImage(MythImage *image, const QString &name)
03180 {
03181 if (!name.isEmpty())
03182 {
03183 if (m_images.contains(name))
03184 {
03185 if (m_images.value(name))
03186 m_images.value(name)->DownRef();
03187 }
03188
03189 if (image)
03190 {
03191 m_images.insert(name, image);
03192 image->UpRef();
03193 }
03194 else
03195 m_images.remove(name);
03196 }
03197 else
03198 {
03199 if (image == m_image)
03200 return;
03201
03202 if (m_image)
03203 m_image->DownRef();
03204
03205 m_image = image;
03206
03207 if (image)
03208 image->UpRef();
03209 }
03210
03211 if (m_parent)
03212 m_parent->Update();
03213 }
03214
03215 void MythUIButtonListItem::SetImageFromMap(const InfoMap &imageMap)
03216 {
03217 m_imageFilenames.clear();
03218 m_imageFilenames = imageMap;
03219 }
03220
03221 MythImage *MythUIButtonListItem::getImage(const QString &name)
03222 {
03223 if (!name.isEmpty())
03224 {
03225 if (m_images.contains(name))
03226 return m_images.value(name);
03227 }
03228 else
03229 {
03230 return m_image;
03231 }
03232
03233 return NULL;
03234 }
03235
03236 void MythUIButtonListItem::SetImage(
03237 const QString &filename, const QString &name, bool force_reload)
03238 {
03239 bool do_update = force_reload;
03240
03241 if (!name.isEmpty())
03242 {
03243 InfoMap::iterator it = m_imageFilenames.find(name);
03244
03245 if (it == m_imageFilenames.end())
03246 {
03247 m_imageFilenames.insert(name, filename);
03248 do_update = true;
03249 }
03250 else if (*it != filename)
03251 {
03252 *it = filename;
03253 do_update = true;
03254 }
03255 }
03256 else if (m_imageFilename != filename)
03257 {
03258 m_imageFilename = filename;
03259 do_update = true;
03260 }
03261
03262 if (m_parent && do_update)
03263 m_parent->Update();
03264 }
03265
03266 QString MythUIButtonListItem::GetImage(const QString &name) const
03267 {
03268 if (name.isEmpty())
03269 return m_imageFilename;
03270
03271 InfoMap::const_iterator it = m_imageFilenames.find(name);
03272
03273 if (it != m_imageFilenames.end())
03274 return *it;
03275
03276 return QString();
03277 }
03278
03279 void MythUIButtonListItem::DisplayState(const QString &state,
03280 const QString &name)
03281 {
03282 if (name.isEmpty())
03283 return;
03284
03285 bool do_update = false;
03286 InfoMap::iterator it = m_states.find(name);
03287
03288 if (it == m_states.end())
03289 {
03290 m_states.insert(name, state);
03291 do_update = true;
03292 }
03293 else if (*it != state)
03294 {
03295 *it = state;
03296 do_update = true;
03297 }
03298
03299 if (m_parent && do_update)
03300 m_parent->Update();
03301 }
03302
03303 void MythUIButtonListItem::SetStatesFromMap(const InfoMap &stateMap)
03304 {
03305 m_states.clear();
03306 m_states = stateMap;
03307 }
03308
03309 bool MythUIButtonListItem::checkable() const
03310 {
03311 return m_checkable;
03312 }
03313
03314 MythUIButtonListItem::CheckState MythUIButtonListItem::state() const
03315 {
03316 return m_state;
03317 }
03318
03319 MythUIButtonList *MythUIButtonListItem::parent() const
03320 {
03321 return m_parent;
03322 }
03323
03324 void MythUIButtonListItem::setChecked(MythUIButtonListItem::CheckState state)
03325 {
03326 if (!m_checkable || m_state == state)
03327 return;
03328
03329 m_state = state;
03330
03331 if (m_parent)
03332 m_parent->Update();
03333 }
03334
03335 void MythUIButtonListItem::setCheckable(bool flag)
03336 {
03337 m_checkable = flag;
03338 }
03339
03340 void MythUIButtonListItem::setDrawArrow(bool flag)
03341 {
03342 m_showArrow = flag;
03343 }
03344
03345 void MythUIButtonListItem::SetData(QVariant data)
03346 {
03347 m_data = data;
03348 }
03349
03350 QVariant MythUIButtonListItem::GetData()
03351 {
03352 return m_data;
03353 }
03354
03355 bool MythUIButtonListItem::MoveUpDown(bool flag)
03356 {
03357 if (m_parent)
03358 return m_parent->MoveItemUpDown(this, flag);
03359 else
03360 return false;
03361 }
03362
03363 void MythUIButtonListItem::SetToRealButton(MythUIStateType *button, bool selected)
03364 {
03365 if (!m_parent)
03366 return;
03367
03368 m_parent->ItemVisible(this);
03369
03370 QString state;
03371
03372 if (selected)
03373 {
03374 button->MoveToTop();
03375 state = m_parent->m_active ? "selectedactive" : "selectedinactive";
03376 }
03377 else
03378 state = m_parent->m_active ? "active" : "inactive";
03379
03380 if (!button->DisplayState(state) && state == "inactive")
03381 {
03382 state = "active";
03383 button->DisplayState(state);
03384 }
03385
03386 MythUIGroup *buttonstate = dynamic_cast<MythUIGroup *>
03387 (button->GetCurrentState());
03388
03389 if (!buttonstate)
03390 {
03391 LOG(VB_GENERAL, LOG_ERR, QString("Failed to query buttonlist state: %1")
03392 .arg(state));
03393 return;
03394 }
03395
03396 buttonstate->SetVisible(true);
03397 buttonstate->Reset();
03398
03399 MythUIText *buttontext = dynamic_cast<MythUIText *>
03400 (buttonstate->GetChild("buttontext"));
03401
03402 if (buttontext)
03403 {
03404 buttontext->SetText(m_text);
03405 buttontext->SetFontState(m_fontState);
03406 }
03407
03408 MythUIImage *buttonimage = dynamic_cast<MythUIImage *>
03409 (buttonstate->GetChild("buttonimage"));
03410
03411 if (buttonimage)
03412 {
03413 if (!m_imageFilename.isEmpty())
03414 {
03415 buttonimage->SetFilename(m_imageFilename);
03416 buttonimage->Load();
03417 }
03418 else if (m_image)
03419 buttonimage->SetImage(m_image);
03420 }
03421
03422 MythUIImage *buttonarrow = dynamic_cast<MythUIImage *>
03423 (buttonstate->GetChild("buttonarrow"));
03424
03425 if (buttonarrow)
03426 buttonarrow->SetVisible(m_showArrow);
03427
03428 MythUIStateType *buttoncheck = dynamic_cast<MythUIStateType *>
03429 (buttonstate->GetChild("buttoncheck"));
03430
03431 if (buttoncheck)
03432 {
03433 buttoncheck->SetVisible(m_checkable);
03434
03435 if (m_checkable)
03436 {
03437 if (m_state == NotChecked)
03438 buttoncheck->DisplayState(MythUIStateType::Off);
03439 else if (m_state == HalfChecked)
03440 buttoncheck->DisplayState(MythUIStateType::Half);
03441 else
03442 buttoncheck->DisplayState(MythUIStateType::Full);
03443 }
03444 }
03445
03446 MythUIText *text;
03447 QMap<QString, TextProperties>::iterator string_it = m_strings.begin();
03448
03449 while (string_it != m_strings.end())
03450 {
03451 text = dynamic_cast<MythUIText *>
03452 (buttonstate->GetChild(string_it.key()));
03453
03454 if (text)
03455 {
03456 TextProperties textprop = string_it.value();
03457
03458 QString newText = text->GetTemplateText();
03459
03460 QRegExp regexp("%(([^\\|%]+)?\\||\\|(.))?(\\w+)(\\|(.+))?%");
03461 regexp.setMinimal(true);
03462
03463 if (!newText.isEmpty() && newText.contains(regexp))
03464 {
03465 int pos = 0;
03466 QString tempString = newText;
03467
03468 while ((pos = regexp.indexIn(newText, pos)) != -1)
03469 {
03470 QString key = regexp.cap(4).toLower().trimmed();
03471 QString replacement;
03472 QString value = m_strings.value(key).text;
03473
03474 if (!value.isEmpty())
03475 {
03476 replacement = QString("%1%2%3%4")
03477 .arg(regexp.cap(2))
03478 .arg(regexp.cap(3))
03479 .arg(m_strings.value(key).text)
03480 .arg(regexp.cap(6));
03481 }
03482
03483 tempString.replace(regexp.cap(0), replacement);
03484 pos += regexp.matchedLength();
03485 }
03486
03487 newText = tempString;
03488 }
03489 else
03490 newText = textprop.text;
03491
03492 if (newText.isEmpty())
03493 text->Reset();
03494 else
03495 text->SetText(newText);
03496
03497 text->SetFontState(textprop.state.isEmpty() ? m_fontState : textprop.state);
03498 }
03499
03500 ++string_it;
03501 }
03502
03503 MythUIImage *image;
03504 InfoMap::iterator imagefile_it = m_imageFilenames.begin();
03505
03506 while (imagefile_it != m_imageFilenames.end())
03507 {
03508 image = dynamic_cast<MythUIImage *>
03509 (buttonstate->GetChild(imagefile_it.key()));
03510
03511 if (image)
03512 {
03513 if (!imagefile_it.value().isEmpty())
03514 {
03515 image->SetFilename(imagefile_it.value());
03516 image->Load();
03517 }
03518 else
03519 image->Reset();
03520 }
03521
03522 ++imagefile_it;
03523 }
03524
03525 QMap<QString, MythImage *>::iterator image_it = m_images.begin();
03526
03527 while (image_it != m_images.end())
03528 {
03529 image = dynamic_cast<MythUIImage *>
03530 (buttonstate->GetChild(image_it.key()));
03531
03532 if (image)
03533 {
03534 if (image_it.value())
03535 image->SetImage(image_it.value());
03536 else
03537 image->Reset();
03538 }
03539
03540 ++image_it;
03541 }
03542
03543 MythUIStateType *statetype;
03544 InfoMap::iterator state_it = m_states.begin();
03545
03546 while (state_it != m_states.end())
03547 {
03548 statetype = dynamic_cast<MythUIStateType *>
03549 (buttonstate->GetChild(state_it.key()));
03550
03551 if (statetype)
03552 {
03553 if (!statetype->DisplayState(state_it.value()))
03554 statetype->Reset();
03555 }
03556
03557 ++state_it;
03558 }
03559 }
03560
03561
03562
03563
03564 SearchButtonListDialog::SearchButtonListDialog(MythScreenStack *parent, const char *name,
03565 MythUIButtonList *parentList, QString searchText)
03566 : MythScreenType(parent, name, false),
03567 m_startsWith(false), m_parentList(parentList),
03568 m_searchText(searchText), m_searchEdit(NULL),
03569 m_prevButton(NULL), m_nextButton(NULL),
03570 m_searchState(NULL)
03571 {
03572 }
03573
03574 SearchButtonListDialog::~SearchButtonListDialog(void)
03575 {
03576 }
03577
03578 bool SearchButtonListDialog::Create(void)
03579 {
03580 if (!CopyWindowFromBase("MythSearchListDialog", this))
03581 return false;
03582
03583 bool err = false;
03584 UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
03585 UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
03586 UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
03587 UIUtilW::Assign(this, m_searchState, "searchstate");
03588
03589 if (err)
03590 {
03591 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'MythSearchListDialog'");
03592 return false;
03593 }
03594
03595 m_searchEdit->SetText(m_searchText);
03596
03597 connect(m_searchEdit, SIGNAL(valueChanged()), SLOT(searchChanged()));
03598 connect(m_prevButton, SIGNAL(Clicked()), SLOT(prevClicked()));
03599 connect(m_nextButton, SIGNAL(Clicked()), SLOT(nextClicked()));
03600
03601 BuildFocusList();
03602
03603 return true;
03604 }
03605
03606 bool SearchButtonListDialog::keyPressEvent(QKeyEvent *event)
03607 {
03608 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
03609 return true;
03610
03611 QStringList actions;
03612 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions, false);
03613
03614 for (int i = 0; i < actions.size() && !handled; i++)
03615 {
03616 QString action = actions[i];
03617 handled = true;
03618
03619 if (action == "0")
03620 {
03621 m_startsWith = !m_startsWith;
03622 searchChanged();
03623 }
03624 else
03625 handled = false;
03626 }
03627
03628 if (!handled && MythScreenType::keyPressEvent(event))
03629 handled = true;
03630
03631 return handled;
03632 }
03633
03634 void SearchButtonListDialog::searchChanged(void)
03635 {
03636 bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);
03637
03638 if (m_searchState)
03639 m_searchState->DisplayState(found ? "found" : "notfound");
03640 }
03641
03642 void SearchButtonListDialog::nextClicked(void)
03643 {
03644 bool found = m_parentList->FindNext();
03645
03646 if (m_searchState)
03647 m_searchState->DisplayState(found ? "found" : "notfound");
03648 }
03649
03650 void SearchButtonListDialog::prevClicked(void)
03651 {
03652 bool found = m_parentList->FindPrev();
03653
03654 if (m_searchState)
03655 m_searchState->DisplayState(found ? "found" : "notfound");
03656 }
03657
03658 void MythUIButtonList::SetScrollBarPosition()
03659 {
03660 if (m_clearing || !m_scrollBar || !m_showScrollBar)
03661 return;
03662
03663 int maximum = m_itemCount <= static_cast<int>(m_itemsVisible) ?
03664 0 : m_itemCount;
03665 m_scrollBar->SetMaximum(maximum);
03666 m_scrollBar->SetPageStep(m_itemsVisible);
03667 m_scrollBar->SetSliderPosition(m_selPosition);
03668 m_scrollBar->MoveToTop();
03669 }