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::CalculateButtonPositions(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::CalculateArrowStates()
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 CalculateButtonPositions();
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 CalculateArrowStates();
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 if (buttonstate)
01746 total += m_itemHorizSpacing + buttonstate->GetArea().width();
01747 }
01748
01749 return 0;
01750 }
01751
01752
01753 int dec;
01754
01755 if (m_layout == LayoutGrid)
01756 {
01757
01758
01759
01760
01761
01762
01763 pos -= (m_columns * (m_topRows + 2 +
01764 qMax(m_bottomRows - m_topRows, 0)));
01765 dec = m_columns;
01766 }
01767 else
01768 {
01769 pos -= (m_topRows + 1);
01770 dec = 1;
01771 }
01772
01773 int max_height = m_contentsRect.height() / 2;
01774
01775 for (; pos >= 0; pos -= dec)
01776 {
01777 InitButton(pos, realButton, buttonItem);
01778 buttonItem->SetToRealButton(realButton, true);
01779 buttonstate = dynamic_cast<MythUIGroup *>
01780 (realButton->GetCurrentState());
01781
01782 if (buttonstate == NULL)
01783 {
01784 LOG(VB_GENERAL, LOG_ERR,
01785 "PageUp: Failed to query buttonlist state");
01786 return pos;
01787 }
01788
01789 if (total + m_itemHorizSpacing +
01790 buttonstate->GetArea().height() / 2 >= max_height)
01791 return pos + dec;
01792
01793 buttonItem->SetToRealButton(realButton, false);
01794 buttonstate = dynamic_cast<MythUIGroup *>
01795 (realButton->GetCurrentState());
01796 if (buttonstate)
01797 total += m_itemHorizSpacing + buttonstate->GetArea().height();
01798 }
01799
01800 return 0;
01801 }
01802
01803 int MythUIButtonList::PageDown(void)
01804 {
01805 int pos = m_selPosition;
01806 int num_items = m_itemList.size();
01807 int total = 0;
01808 MythUIGroup *buttonstate;
01809 MythUIStateType *realButton;
01810 MythUIButtonListItem *buttonItem;
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823 if (m_layout == LayoutHorizontal)
01824 {
01825 pos += (m_rightColumns + 1);
01826
01827 int max_width = m_contentsRect.width() / 2;
01828
01829 for (; pos < num_items; ++pos)
01830 {
01831 InitButton(pos, realButton, buttonItem);
01832 buttonItem->SetToRealButton(realButton, true);
01833 buttonstate = dynamic_cast<MythUIGroup *>
01834 (realButton->GetCurrentState());
01835
01836 if (buttonstate == NULL)
01837 {
01838 LOG(VB_GENERAL, LOG_ERR,
01839 "PageDown: Failed to query buttonlist state");
01840 return pos;
01841 }
01842
01843 if (total + m_itemHorizSpacing +
01844 buttonstate->GetArea().width() / 2 >= max_width)
01845 return pos - 1;
01846
01847 buttonItem->SetToRealButton(realButton, false);
01848 buttonstate = dynamic_cast<MythUIGroup *>
01849 (realButton->GetCurrentState());
01850 if (buttonstate)
01851 total += m_itemHorizSpacing + buttonstate->GetArea().width();
01852 }
01853
01854 return num_items - 1;
01855 }
01856
01857
01858 int inc;
01859
01860 if (m_layout == LayoutGrid)
01861 {
01862
01863
01864
01865
01866
01867
01868 pos += (m_columns * (m_bottomRows + 2 +
01869 qMax(m_topRows - m_bottomRows, 0)));
01870 inc = m_columns;
01871 }
01872 else
01873 {
01874 pos += (m_bottomRows + 1);
01875 inc = 1;
01876 }
01877
01878 int max_height = m_contentsRect.height() / 2;
01879
01880 for (; pos < num_items; pos += inc)
01881 {
01882 InitButton(pos, realButton, buttonItem);
01883 buttonItem->SetToRealButton(realButton, true);
01884 buttonstate = dynamic_cast<MythUIGroup *>
01885 (realButton->GetCurrentState());
01886
01887 if (!buttonstate)
01888 {
01889 LOG(VB_GENERAL, LOG_ERR,
01890 "PageDown: Failed to query buttonlist state");
01891 return pos;
01892 }
01893
01894 if (total + m_itemHorizSpacing +
01895 buttonstate->GetArea().height() / 2 >= max_height)
01896 return pos - inc;
01897
01898 buttonItem->SetToRealButton(realButton, false);
01899 buttonstate = dynamic_cast<MythUIGroup *>
01900 (realButton->GetCurrentState());
01901 if (buttonstate)
01902 total += m_itemHorizSpacing + buttonstate->GetArea().height();
01903 }
01904
01905 return num_items - 1;
01906 }
01907
01908 bool MythUIButtonList::MoveUp(MovementUnit unit, uint amount)
01909 {
01910 int pos = m_selPosition;
01911
01912 if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
01913 return false;
01914
01915 switch (unit)
01916 {
01917 case MoveItem:
01918 if (m_selPosition > 0)
01919 --m_selPosition;
01920 else if (m_wrapStyle > WrapNone)
01921 m_selPosition = m_itemList.size() - 1;
01922 else if (m_wrapStyle == WrapCaptive)
01923 return true;
01924
01925 break;
01926
01927 case MoveColumn:
01928 if (pos % m_columns > 0)
01929 --m_selPosition;
01930 else if (m_wrapStyle == WrapFlowing)
01931 if (m_selPosition == 0)
01932 --m_selPosition = m_itemList.size() - 1;
01933 else
01934 --m_selPosition;
01935 else if (m_wrapStyle > WrapNone)
01936 m_selPosition = pos + (m_columns - 1);
01937 else if (m_wrapStyle == WrapCaptive)
01938 return true;
01939
01940 break;
01941
01942 case MoveRow:
01943 if (m_scrollStyle != ScrollFree)
01944 {
01945 m_selPosition -= m_columns;
01946 if (m_selPosition < 0)
01947 m_selPosition += m_itemList.size();
01948 else
01949 m_selPosition %= m_itemList.size();
01950 }
01951 else if ((pos - m_columns) >= 0)
01952 m_selPosition -= m_columns;
01953 else if (m_wrapStyle > WrapNone)
01954 {
01955 m_selPosition = ((m_itemList.size() - 1) / m_columns) *
01956 m_columns + pos;
01957
01958 if ((m_selPosition / m_columns)
01959 < ((m_itemList.size() - 1) / m_columns))
01960 m_selPosition = m_itemList.size() - 1;
01961
01962 if (m_layout == LayoutVertical)
01963 m_topPosition = qMax(0, m_selPosition - (int)m_itemsVisible + 1);
01964 }
01965 else if (m_wrapStyle == WrapCaptive)
01966 return true;
01967
01968 break;
01969
01970 case MovePage:
01971 if (m_arrange == ArrangeFixed)
01972 m_selPosition = qMax(0, m_selPosition - (int)m_itemsVisible);
01973 else
01974 m_selPosition = PageUp();
01975
01976 break;
01977
01978 case MoveMid:
01979 m_selPosition = (int)(m_itemList.size() / 2);
01980 break;
01981
01982 case MoveMax:
01983 m_selPosition = 0;
01984 break;
01985
01986 case MoveByAmount:
01987 for (uint i = 0; i < amount; ++i)
01988 {
01989 if (m_selPosition > 0)
01990 --m_selPosition;
01991 else if (m_wrapStyle > WrapNone)
01992 m_selPosition = m_itemList.size() - 1;
01993 }
01994
01995 break;
01996 }
01997
01998 SanitizePosition();
01999
02000 if (pos != m_selPosition)
02001 {
02002 Update();
02003 emit itemSelected(GetItemCurrent());
02004 }
02005 else
02006 return false;
02007
02008 return true;
02009 }
02010
02011 bool MythUIButtonList::MoveDown(MovementUnit unit, uint amount)
02012 {
02013 int pos = m_selPosition;
02014
02015 if (pos == -1 || m_itemList.isEmpty() || !m_initialized)
02016 return false;
02017
02018 switch (unit)
02019 {
02020 case MoveItem:
02021 if (m_selPosition < m_itemList.size() - 1)
02022 ++m_selPosition;
02023 else if (m_wrapStyle > WrapNone)
02024 m_selPosition = 0;
02025 else if (m_wrapStyle == WrapCaptive)
02026 return true;
02027
02028 break;
02029
02030 case MoveColumn:
02031 if ((pos + 1) % m_columns > 0)
02032 ++m_selPosition;
02033 else if (m_wrapStyle == WrapFlowing)
02034 if (m_selPosition < m_itemList.size() - 1)
02035 ++m_selPosition;
02036 else
02037 m_selPosition = 0;
02038 else if (m_wrapStyle > WrapNone)
02039 m_selPosition = pos - (m_columns - 1);
02040 else if (m_wrapStyle == WrapCaptive)
02041 return true;
02042
02043 break;
02044
02045 case MoveRow:
02046 if (m_itemList.empty() || m_columns < 1)
02047 return true;
02048 if (m_scrollStyle != ScrollFree)
02049 {
02050 m_selPosition += m_columns;
02051 m_selPosition %= m_itemList.size();
02052 }
02053 else if (((m_itemList.size() - 1) / qMax(m_columns, 0))
02054 > (pos / m_columns))
02055 {
02056 m_selPosition += m_columns;
02057 if (m_selPosition > m_itemList.size() - 1)
02058 m_selPosition = m_itemList.size() - 1;
02059 }
02060 else if (m_wrapStyle > WrapNone)
02061 m_selPosition = (pos % m_columns);
02062 else if (m_wrapStyle == WrapCaptive)
02063 return true;
02064
02065 break;
02066
02067 case MovePage:
02068 if (m_arrange == ArrangeFixed)
02069 m_selPosition = qMin(m_itemCount - 1,
02070 m_selPosition + (int)m_itemsVisible);
02071 else
02072 m_selPosition = PageDown();
02073
02074 break;
02075
02076 case MoveMax:
02077 m_selPosition = m_itemCount - 1;
02078 break;
02079
02080 case MoveByAmount:
02081 for (uint i = 0; i < amount; ++i)
02082 {
02083 if (m_selPosition < m_itemList.size() - 1)
02084 ++m_selPosition;
02085 else if (m_wrapStyle > WrapNone)
02086 m_selPosition = 0;
02087 }
02088 break;
02089
02090 case MoveMid:
02091 break;
02092 }
02093
02094 SanitizePosition();
02095
02096 if (pos != m_selPosition)
02097 {
02098 m_keepSelAtBottom = true;
02099 Update();
02100 emit itemSelected(GetItemCurrent());
02101 }
02102 else
02103 return false;
02104
02105 return true;
02106 }
02107
02108 bool MythUIButtonList::MoveToNamedPosition(const QString &position_name)
02109 {
02110 if (!m_initialized)
02111 Init();
02112
02113 if (m_selPosition < 0 || m_itemList.isEmpty() || !m_initialized)
02114 return false;
02115
02116 bool found_it = false;
02117 int selectedPosition = 0;
02118 QList<MythUIButtonListItem *>::iterator it = m_itemList.begin();
02119
02120 while (it != m_itemList.end())
02121 {
02122 if ((*it)->GetText() == position_name)
02123 {
02124 found_it = true;
02125 break;
02126 }
02127
02128 ++it;
02129 ++selectedPosition;
02130 }
02131
02132 if (!found_it || m_selPosition == selectedPosition)
02133 return false;
02134
02135 SetItemCurrent(selectedPosition);
02136 return true;
02137 }
02138
02139 bool MythUIButtonList::MoveItemUpDown(MythUIButtonListItem *item, bool up)
02140 {
02141 if (GetItemCurrent() != item)
02142 return false;
02143
02144 if (item == m_itemList.first() && up)
02145 return false;
02146
02147 if (item == m_itemList.last() && !up)
02148 return false;
02149
02150 int oldpos = m_selPosition;
02151 int insertat = 0;
02152 bool dolast = false;
02153
02154 if (up)
02155 {
02156 insertat = m_selPosition - 1;
02157
02158 if (item == m_itemList.last())
02159 dolast = true;
02160 else
02161 ++m_selPosition;
02162
02163 if (item == m_itemList.at(m_topPosition))
02164 ++m_topPosition;
02165 }
02166 else
02167 insertat = m_selPosition + 1;
02168
02169 m_itemList.removeAt(oldpos);
02170 m_itemList.insert(insertat, item);
02171
02172 if (up)
02173 {
02174 MoveUp();
02175
02176 if (!dolast)
02177 MoveUp();
02178 }
02179 else
02180 MoveDown();
02181
02182 return true;
02183 }
02184
02185 void MythUIButtonList::SetAllChecked(MythUIButtonListItem::CheckState state)
02186 {
02187 QMutableListIterator<MythUIButtonListItem *> it(m_itemList);
02188
02189 while (it.hasNext())
02190 it.next()->setChecked(state);
02191 }
02192
02193 void MythUIButtonList::Init()
02194 {
02195 if (m_initialized)
02196 return;
02197
02198 m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
02199 m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
02200 m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
02201
02202 if (m_upArrow)
02203 m_upArrow->SetVisible(true);
02204
02205 if (m_downArrow)
02206 m_downArrow->SetVisible(true);
02207
02208 if (m_scrollBar)
02209 m_scrollBar->SetVisible(m_showScrollBar);
02210
02211 m_contentsRect.CalculateArea(m_Area);
02212
02213 m_buttontemplate = dynamic_cast<MythUIStateType *>(GetChild("buttonitem"));
02214
02215 if (!m_buttontemplate)
02216 {
02217 LOG(VB_GENERAL, LOG_ERR, QString("(%1) Statetype buttonitem is "
02218 "required in mythuibuttonlist: %2")
02219 .arg(GetXMLLocation()).arg(objectName()));
02220 return;
02221 }
02222
02223 m_buttontemplate->SetVisible(false);
02224
02225 MythRect buttonItemArea;
02226
02227 MythUIGroup *buttonActiveState = dynamic_cast<MythUIGroup *>
02228 (m_buttontemplate->GetState("active"));
02229
02230 if (buttonActiveState)
02231 buttonItemArea = buttonActiveState->GetArea();
02232 else
02233 buttonItemArea = m_buttontemplate->GetArea();
02234
02235 buttonItemArea.CalculateArea(m_contentsRect);
02236
02237 m_itemHeight = buttonItemArea.height();
02238 m_itemWidth = buttonItemArea.width();
02239
02240
02241
02242
02243
02244 if (m_arrange == ArrangeFixed)
02245 {
02246
02247 CalculateVisibleItems();
02248
02249 int col = 1;
02250 int row = 1;
02251
02252 for (int i = 0; i < (int)m_itemsVisible; i++)
02253 {
02254 QString name = QString("buttonlist button %1").arg(i);
02255 MythUIStateType *button = new MythUIStateType(this, name);
02256 button->CopyFrom(m_buttontemplate);
02257 button->ConnectDependants(true);
02258
02259 if (col > m_columns)
02260 {
02261 col = 1;
02262 row++;
02263 }
02264
02265 button->SetPosition(GetButtonPosition(col, row));
02266 col++;
02267
02268 m_ButtonList.push_back(button);
02269 }
02270 }
02271
02272
02273
02274
02275
02276
02277 MythUIGroup *buttonSelectedState = dynamic_cast<MythUIGroup *>
02278 (m_buttontemplate->GetState("selected"));
02279
02280 if (buttonSelectedState)
02281 {
02282 MythRect itemArea = buttonSelectedState->GetArea();
02283 itemArea.CalculateArea(m_contentsRect);
02284
02285 if (m_itemHeight < itemArea.height())
02286 m_itemHeight = itemArea.height();
02287
02288 if (m_itemWidth < itemArea.width())
02289 m_itemWidth = itemArea.width();
02290 }
02291
02292
02293
02294 m_initialized = true;
02295 }
02296
02297 uint MythUIButtonList::ItemWidth(void)
02298 {
02299 if (!m_initialized)
02300 Init();
02301
02302 return m_itemWidth;
02303 }
02304
02305 uint MythUIButtonList::ItemHeight(void)
02306 {
02307 if (!m_initialized)
02308 Init();
02309
02310 return m_itemHeight;
02311 }
02312
02316 bool MythUIButtonList::keyPressEvent(QKeyEvent *e)
02317 {
02318 QStringList actions;
02319 bool handled = false;
02320 handled = GetMythMainWindow()->TranslateKeyPress("Global", e, actions);
02321
02322
02323 for (int i = 0; i < actions.size(); i++)
02324 {
02325 if (!m_actionRemap.contains(actions[i]))
02326 continue;
02327
02328 QString key = m_actionRemap[actions[i]];
02329 if (key.isEmpty())
02330 return true;
02331
02332 QKeySequence a(key);
02333 if (a.isEmpty())
02334 continue;
02335
02336 int keyCode = a[0];
02337 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
02338 QStringList parts = key.split('+');
02339 for (int j = 0; j < parts.count(); j++)
02340 {
02341 if (parts[j].toUpper() == "CTRL")
02342 modifiers |= Qt::ControlModifier;
02343 if (parts[j].toUpper() == "SHIFT")
02344 modifiers |= Qt::ShiftModifier;
02345 if (parts[j].toUpper() == "ALT")
02346 modifiers |= Qt::AltModifier;
02347 if (parts[j].toUpper() == "META")
02348 modifiers |= Qt::MetaModifier;
02349 }
02350
02351 QCoreApplication::postEvent(
02352 GetMythMainWindow(),
02353 new QKeyEvent(QEvent::KeyPress, keyCode, modifiers, key));
02354 QCoreApplication::postEvent(
02355 GetMythMainWindow(),
02356 new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers, key));
02357
02358 return true;
02359 }
02360
02361
02362 for (int i = 0; i < actions.size() && !handled; i++)
02363 {
02364 QString action = actions[i];
02365 handled = true;
02366
02367 if (action == "UP")
02368 {
02369 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02370 handled = MoveUp(MoveRow);
02371 else
02372 handled = false;
02373 }
02374 else if (action == "DOWN")
02375 {
02376 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02377 handled = MoveDown(MoveRow);
02378 else
02379 handled = false;
02380 }
02381 else if (action == "RIGHT")
02382 {
02383 if (m_layout == LayoutHorizontal)
02384 handled = MoveDown(MoveItem);
02385 else if (m_layout == LayoutGrid)
02386 {
02387 if (m_scrollStyle == ScrollFree)
02388 handled = MoveDown(MoveColumn);
02389 else
02390 handled = MoveDown(MoveItem);
02391 }
02392 else
02393 handled = false;
02394 }
02395 else if (action == "LEFT")
02396 {
02397 if (m_layout == LayoutHorizontal)
02398 handled = MoveUp(MoveItem);
02399 else if (m_layout == LayoutGrid)
02400 {
02401 if (m_scrollStyle == ScrollFree)
02402 handled = MoveUp(MoveColumn);
02403 else
02404 handled = MoveUp(MoveItem);
02405 }
02406 else
02407 handled = false;
02408 }
02409 else if (action == "PAGEUP")
02410 {
02411 MoveUp(MovePage);
02412 }
02413 else if (action == "PAGEDOWN")
02414 {
02415 MoveDown(MovePage);
02416 }
02417 else if (action == "PAGETOP")
02418 {
02419 MoveUp(MoveMax);
02420 }
02421 else if (action == "PAGEMIDDLE")
02422 {
02423 MoveUp(MoveMid);
02424 }
02425 else if (action == "PAGEBOTTOM")
02426 {
02427 MoveDown(MoveMax);
02428 }
02429 else if (action == "SELECT")
02430 {
02431 MythUIButtonListItem *item = GetItemCurrent();
02432
02433 if (item)
02434 emit itemClicked(item);
02435 }
02436 else if (action == "SEARCH")
02437 {
02438 ShowSearchDialog();
02439 }
02440 else
02441 handled = false;
02442 }
02443
02444 return handled;
02445 }
02446
02450 bool MythUIButtonList::gestureEvent(MythGestureEvent *event)
02451 {
02452 bool handled = false;
02453
02454 if (event->gesture() == MythGestureEvent::Click)
02455 {
02456
02457 QPoint position = event->GetPosition() -
02458 m_Parent->GetArea().topLeft();
02459
02460 MythUIType *type = GetChildAt(position, false, false);
02461
02462 if (!type)
02463 return false;
02464
02465 MythUIStateType *object = dynamic_cast<MythUIStateType *>(type);
02466
02467 if (object)
02468 {
02469 handled = true;
02470 QString name = object->objectName();
02471
02472 if (name == "upscrollarrow")
02473 {
02474 MoveUp(MovePage);
02475 }
02476 else if (name == "downscrollarrow")
02477 {
02478 MoveDown(MovePage);
02479 }
02480 else if (name.startsWith("buttonlist button"))
02481 {
02482 int pos = name.section(' ', 2, 2).toInt();
02483 MythUIButtonListItem *item = m_ButtonToItem[pos];
02484
02485 if (item)
02486 {
02487 if (item == GetItemCurrent())
02488 emit itemClicked(item);
02489 else
02490 SetItemCurrent(item);
02491 }
02492 }
02493 else
02494 handled = false;
02495 }
02496 }
02497
02498 return handled;
02499 }
02500
02501 class NextButtonListPageEvent : public QEvent
02502 {
02503 public:
02504 NextButtonListPageEvent(int start, int pageSize) :
02505 QEvent(kEventType), m_start(start), m_pageSize(pageSize) {}
02506 const int m_start;
02507 const int m_pageSize;
02508 static Type kEventType;
02509 };
02510
02511 QEvent::Type NextButtonListPageEvent::kEventType =
02512 (QEvent::Type) QEvent::registerEventType();
02513
02514 void MythUIButtonList::customEvent(QEvent *event)
02515 {
02516 if (event->type() == NextButtonListPageEvent::kEventType)
02517 {
02518 NextButtonListPageEvent *npe =
02519 static_cast<NextButtonListPageEvent*>(event);
02520 int cur = npe->m_start;
02521 for (; cur < npe->m_start + npe->m_pageSize && cur < GetCount(); ++cur)
02522 {
02523 const int loginterval = (cur < 1000 ? 100 : 500);
02524 if (cur > 200 && cur % loginterval == 0)
02525 LOG(VB_GENERAL, LOG_INFO,
02526 QString("Build background buttonlist item %1").arg(cur));
02527 emit itemLoaded(GetItemAt(cur));
02528 }
02529 m_nextItemLoaded = cur;
02530 if (cur < GetCount())
02531 LoadInBackground(cur, npe->m_pageSize);
02532 }
02533 }
02534
02535 void MythUIButtonList::LoadInBackground(int start, int pageSize)
02536 {
02537 m_nextItemLoaded = start;
02538 QCoreApplication::
02539 postEvent(this, new NextButtonListPageEvent(start, pageSize));
02540 }
02541
02542 int MythUIButtonList::StopLoad(void)
02543 {
02544 QCoreApplication::
02545 removePostedEvents(this, NextButtonListPageEvent::kEventType);
02546 return m_nextItemLoaded;
02547 }
02548
02549 QPoint MythUIButtonList::GetButtonPosition(int column, int row) const
02550 {
02551 int x = m_contentsRect.x() +
02552 ((column - 1) * (m_itemWidth + m_itemHorizSpacing));
02553 int y = m_contentsRect.y() +
02554 ((row - 1) * (m_itemHeight + m_itemVertSpacing));
02555
02556 return QPoint(x, y);
02557 }
02558
02559 void MythUIButtonList::CalculateVisibleItems(void)
02560 {
02561 m_itemsVisible = 0;
02562 m_rows = 0;
02563 m_columns = 0;
02564
02565 if ((m_layout == LayoutHorizontal) || (m_layout == LayoutGrid))
02566 {
02567 int x = 0;
02568
02569 while (x <= m_contentsRect.width() - m_itemWidth)
02570 {
02571 x += m_itemWidth + m_itemHorizSpacing;
02572 m_columns++;
02573 }
02574 }
02575
02576 if ((m_layout == LayoutVertical) || (m_layout == LayoutGrid))
02577 {
02578 int y = 0;
02579
02580 while (y <= m_contentsRect.height() - m_itemHeight)
02581 {
02582 y += m_itemHeight + m_itemVertSpacing;
02583 m_rows++;
02584 }
02585 }
02586
02587 if (m_rows <= 0)
02588 m_rows = 1;
02589
02590 if (m_columns <= 0)
02591 m_columns = 1;
02592
02593 m_itemsVisible = m_columns * m_rows;
02594 }
02595
02596 void MythUIButtonList::SetButtonArea(const MythRect &rect)
02597 {
02598 if (rect == m_contentsRect)
02599 return;
02600
02601 m_contentsRect = rect;
02602
02603 if (m_Area.isValid())
02604 m_contentsRect.CalculateArea(m_Area);
02605 else if (m_Parent)
02606 m_contentsRect.CalculateArea(m_Parent->GetFullArea());
02607 else
02608 m_contentsRect.CalculateArea(GetMythMainWindow()->GetUIScreenRect());
02609 }
02610
02614 bool MythUIButtonList::ParseElement(
02615 const QString &filename, QDomElement &element, bool showWarnings)
02616 {
02617 if (element.tagName() == "buttonarea")
02618 SetButtonArea(parseRect(element));
02619 else if (element.tagName() == "layout")
02620 {
02621 QString layout = getFirstText(element).toLower();
02622
02623 if (layout == "grid")
02624 m_layout = LayoutGrid;
02625 else if (layout == "horizontal")
02626 m_layout = LayoutHorizontal;
02627 else
02628 m_layout = LayoutVertical;
02629 }
02630 else if (element.tagName() == "arrange")
02631 {
02632 QString arrange = getFirstText(element).toLower();
02633
02634 if (arrange == "fill")
02635 m_arrange = ArrangeFill;
02636 else if (arrange == "spread")
02637 m_arrange = ArrangeSpread;
02638 else if (arrange == "stack")
02639 m_arrange = ArrangeStack;
02640 else
02641 m_arrange = ArrangeFixed;
02642
02643 }
02644 else if (element.tagName() == "align")
02645 {
02646 QString align = getFirstText(element).toLower();
02647 m_alignment = parseAlignment(align);
02648 }
02649 else if (element.tagName() == "scrollstyle")
02650 {
02651 QString layout = getFirstText(element).toLower();
02652
02653 if (layout == "center")
02654 m_scrollStyle = ScrollCenter;
02655 else if (layout == "groupcenter")
02656 m_scrollStyle = ScrollGroupCenter;
02657 else if (layout == "free")
02658 m_scrollStyle = ScrollFree;
02659 }
02660 else if (element.tagName() == "wrapstyle")
02661 {
02662 QString wrapstyle = getFirstText(element).toLower();
02663
02664 if (wrapstyle == "captive")
02665 m_wrapStyle = WrapCaptive;
02666 else if (wrapstyle == "none")
02667 m_wrapStyle = WrapNone;
02668 else if (wrapstyle == "selection")
02669 m_wrapStyle = WrapSelect;
02670 else if (wrapstyle == "flowing")
02671 m_wrapStyle = WrapFlowing;
02672 else if (wrapstyle == "items")
02673 m_wrapStyle = WrapItems;
02674 }
02675 else if (element.tagName() == "showarrow")
02676 m_showArrow = parseBool(element);
02677 else if (element.tagName() == "showscrollbar")
02678 m_showScrollBar = parseBool(element);
02679 else if (element.tagName() == "spacing")
02680 {
02681 m_itemHorizSpacing = NormX(getFirstText(element).toInt());
02682 m_itemVertSpacing = NormY(getFirstText(element).toInt());
02683 }
02684 else if (element.tagName() == "drawfrombottom")
02685 {
02686 m_drawFromBottom = parseBool(element);
02687
02688 if (m_drawFromBottom)
02689 m_alignment |= Qt::AlignBottom;
02690 }
02691 else if (element.tagName() == "searchposition")
02692 {
02693 m_searchPosition = parsePoint(element);
02694 }
02695 else if (element.tagName() == "triggerevent")
02696 {
02697 QString trigger = getFirstText(element);
02698 if (!trigger.isEmpty())
02699 {
02700 QString action = element.attribute("action", "");
02701 if (action.isEmpty())
02702 {
02703 m_actionRemap[trigger] = "";
02704 }
02705 else
02706 {
02707 QString context = element.attribute("context", "");
02708 QString keylist = GetMythMainWindow()->GetKey(context, action);
02709 QStringList keys = keylist.split(',', QString::SkipEmptyParts);
02710 if (!keys.empty())
02711 m_actionRemap[trigger] = keys[0];
02712 }
02713 }
02714 }
02715 else
02716 {
02717 return MythUIType::ParseElement(filename, element, showWarnings);
02718 }
02719
02720 return true;
02721 }
02722
02726 void MythUIButtonList::DrawSelf(MythPainter *, int, int, int, QRect)
02727 {
02728 if (m_needsUpdate)
02729 {
02730 CalculateArrowStates();
02731 SetScrollBarPosition();
02732 }
02733 }
02734
02738 void MythUIButtonList::CreateCopy(MythUIType *parent)
02739 {
02740 MythUIButtonList *lb = new MythUIButtonList(parent, objectName());
02741 lb->CopyFrom(this);
02742 }
02743
02747 void MythUIButtonList::CopyFrom(MythUIType *base)
02748 {
02749 MythUIButtonList *lb = dynamic_cast<MythUIButtonList *>(base);
02750
02751 if (!lb)
02752 return;
02753
02754 m_layout = lb->m_layout;
02755 m_arrange = lb->m_arrange;
02756 m_alignment = lb->m_alignment;
02757
02758 m_contentsRect = lb->m_contentsRect;
02759
02760 m_itemHeight = lb->m_itemHeight;
02761 m_itemWidth = lb->m_itemWidth;
02762 m_itemHorizSpacing = lb->m_itemHorizSpacing;
02763 m_itemVertSpacing = lb->m_itemVertSpacing;
02764 m_itemsVisible = lb->m_itemsVisible;
02765 m_maxVisible = lb->m_maxVisible;
02766
02767 m_active = lb->m_active;
02768 m_showArrow = lb->m_showArrow;
02769 m_showScrollBar = lb->m_showScrollBar;
02770
02771 m_drawFromBottom = lb->m_drawFromBottom;
02772
02773 m_scrollStyle = lb->m_scrollStyle;
02774 m_wrapStyle = lb->m_wrapStyle;
02775
02776 m_clearing = false;
02777 m_selPosition = m_topPosition = m_itemCount = 0;
02778
02779 m_searchPosition = lb->m_searchPosition;
02780 m_searchFields = lb->m_searchFields;
02781
02782 MythUIType::CopyFrom(base);
02783
02784 m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
02785 m_downArrow = dynamic_cast<MythUIStateType *>(GetChild("downscrollarrow"));
02786 m_scrollBar = dynamic_cast<MythUIScrollBar *>(GetChild("scrollbar"));
02787
02788 for (int i = 0; i < (int)m_itemsVisible; i++)
02789 {
02790 QString name = QString("buttonlist button %1").arg(i);
02791 DeleteChild(name);
02792 }
02793
02794 m_ButtonList.clear();
02795
02796 m_actionRemap = lb->m_actionRemap;
02797
02798 m_initialized = false;
02799 }
02800
02804 void MythUIButtonList::Finalize(void)
02805 {
02806 MythUIType::Finalize();
02807 }
02808
02809 void MythUIButtonList::SetLCDTitles(const QString &title, const QString &columnList)
02810 {
02811 m_lcdTitle = title;
02812 m_lcdColumns = columnList.split('|');
02813 }
02814
02815 void MythUIButtonList::updateLCD(void)
02816 {
02817 if (!m_HasFocus)
02818 return;
02819
02820 LCD *lcddev = LCD::Get();
02821
02822 if (lcddev == NULL)
02823 return;
02824
02825
02826 QList<LCDMenuItem> menuItems;
02827 bool selected;
02828
02829 int start = std::max(0, (int)(m_selPosition - lcddev->getLCDHeight()));
02830 int end = std::min(m_itemCount, (int)(start + (lcddev->getLCDHeight() * 2)));
02831
02832 for (int r = start; r < end; r++)
02833 {
02834 if (r == GetCurrentPos())
02835 selected = true;
02836 else
02837 selected = false;
02838
02839 MythUIButtonListItem *item = GetItemAt(r);
02840 CHECKED_STATE state = NOTCHECKABLE;
02841
02842 if (item->checkable())
02843 state = (item->state() == MythUIButtonListItem::NotChecked) ? UNCHECKED : CHECKED;
02844
02845 QString text;
02846
02847 for (int x = 0; x < m_lcdColumns.count(); x++)
02848 {
02849 if (!m_lcdColumns[x].isEmpty() && item->m_strings.contains(m_lcdColumns[x]))
02850 {
02851
02852 TextProperties props = item->m_strings[m_lcdColumns[x]];
02853
02854 if (text.isEmpty())
02855 text = props.text;
02856 else
02857 text += " ~ " + props.text;
02858 }
02859 else
02860 {
02861
02862 if (text.isEmpty())
02863 text = item->GetText();
02864 else
02865 text += " ~ " + item->GetText();
02866 }
02867 }
02868
02869 if (!text.isEmpty())
02870 menuItems.append(LCDMenuItem(selected, state, text));
02871 else
02872 menuItems.append(LCDMenuItem(selected, state, item->GetText()));
02873 }
02874
02875 if (!menuItems.isEmpty())
02876 lcddev->switchToMenu(menuItems, m_lcdTitle);
02877 }
02878
02879 void MythUIButtonList::ShowSearchDialog(void)
02880 {
02881 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
02882
02883 SearchButtonListDialog *dlg = new SearchButtonListDialog(popupStack, "MythSearchListDialog", this, "");
02884
02885 if (dlg->Create())
02886 {
02887 if (m_searchPosition.x() != -2 || m_searchPosition.y() != -2)
02888 {
02889 int x = m_searchPosition.x();
02890 int y = m_searchPosition.y();
02891 QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
02892 QRect dialogArea = dlg->GetArea();
02893
02894 if (x == -1)
02895 x = (screenArea.width() - dialogArea.width()) / 2;
02896
02897 if (y == -1)
02898 y = (screenArea.height() - dialogArea.height()) / 2;
02899
02900 dlg->SetPosition(x, y);
02901 }
02902
02903 popupStack->AddScreen(dlg);
02904 }
02905 else
02906 delete dlg;
02907 }
02908
02909 bool MythUIButtonList::Find(const QString &searchStr, bool startsWith)
02910 {
02911 m_searchStr = searchStr;
02912 m_searchStartsWith = startsWith;
02913 return DoFind(false, true);
02914 }
02915
02916 bool MythUIButtonList::FindNext(void)
02917 {
02918 return DoFind(true, true);
02919 }
02920
02921 bool MythUIButtonList::FindPrev(void)
02922 {
02923 return DoFind(true, false);
02924 }
02925
02926 bool MythUIButtonList::DoFind(bool doMove, bool searchForward)
02927 {
02928 if (m_searchStr.isEmpty())
02929 return true;
02930
02931 if (GetCount() == 0)
02932 return false;
02933
02934 int startPos = GetCurrentPos();
02935 int currPos = startPos;
02936 bool found = false;
02937
02938 if (doMove)
02939 {
02940 if (searchForward)
02941 {
02942 currPos++;
02943
02944 if (currPos >= GetCount())
02945 currPos = 0;
02946 }
02947 else
02948 {
02949 currPos--;
02950
02951 if (currPos < 0)
02952 currPos = GetCount() - 1;
02953 }
02954 }
02955
02956 while (true)
02957 {
02958 found = GetItemAt(currPos)->FindText(m_searchStr, m_searchFields, m_searchStartsWith);
02959
02960 if (found)
02961 {
02962 SetItemCurrent(currPos);
02963 return true;
02964 }
02965
02966 if (searchForward)
02967 {
02968 currPos++;
02969
02970 if (currPos >= GetCount())
02971 currPos = 0;
02972 }
02973 else
02974 {
02975 currPos--;
02976
02977 if (currPos < 0)
02978 currPos = GetCount() - 1;
02979 }
02980
02981 if (startPos == currPos)
02982 break;
02983 }
02984
02985 return false;
02986 }
02987
02989
02990 MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList *lbtype,
02991 const QString &text, const QString &image,
02992 bool checkable, CheckState state,
02993 bool showArrow, int listPosition)
02994 {
02995 if (!lbtype)
02996 LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
02997
02998 m_parent = lbtype;
02999 m_text = text;
03000 m_image = NULL;
03001 m_imageFilename = image;
03002 m_checkable = checkable;
03003 m_state = state;
03004 m_showArrow = showArrow;
03005 m_data = 0;
03006
03007 if (state >= NotChecked)
03008 m_checkable = true;
03009
03010 if (m_parent)
03011 m_parent->InsertItem(this, listPosition);
03012 }
03013
03014 MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList *lbtype,
03015 const QString &text,
03016 QVariant data, int listPosition)
03017 {
03018 if (!lbtype)
03019 LOG(VB_GENERAL, LOG_ERR, "Cannot add a button to a non-existent list!");
03020
03021 m_parent = lbtype;
03022 m_text = text;
03023 m_data = data;
03024
03025 m_image = NULL;
03026
03027 m_checkable = false;
03028 m_state = CantCheck;
03029 m_showArrow = false;
03030
03031 if (m_parent)
03032 m_parent->InsertItem(this, listPosition);
03033 }
03034
03035 MythUIButtonListItem::~MythUIButtonListItem()
03036 {
03037 if (m_parent)
03038 m_parent->RemoveItem(this);
03039
03040 if (m_image)
03041 m_image->DecrRef();
03042
03043 QMap<QString, MythImage*>::iterator it;
03044 for (it = m_images.begin(); it != m_images.end(); ++it)
03045 {
03046 if (*it)
03047 (*it)->DecrRef();
03048 }
03049 m_images.clear();
03050 }
03051
03052 void MythUIButtonListItem::SetText(const QString &text, const QString &name,
03053 const QString &state)
03054 {
03055 if (!name.isEmpty())
03056 {
03057 TextProperties textprop;
03058 textprop.text = text;
03059 textprop.state = state;
03060 m_strings.insert(name, textprop);
03061 }
03062 else
03063 m_text = text;
03064
03065 if (m_parent)
03066 m_parent->Update();
03067 }
03068
03069 void MythUIButtonListItem::SetTextFromMap(InfoMap &infoMap,
03070 const QString &state)
03071 {
03072 QHash<QString, QString>::iterator map_it = infoMap.begin();
03073
03074 while (map_it != infoMap.end())
03075 {
03076 TextProperties textprop;
03077 textprop.text = (*map_it);
03078 textprop.state = state;
03079 m_strings[map_it.key()] = textprop;
03080 ++map_it;
03081 }
03082
03083 if (m_parent)
03084 m_parent->Update();
03085 }
03086
03087 void MythUIButtonListItem::SetTextFromMap(QMap<QString, TextProperties> &stringMap)
03088 {
03089 m_strings.clear();
03090 m_strings = stringMap;
03091 }
03092
03093 QString MythUIButtonListItem::GetText(const QString &name) const
03094 {
03095 if (name.isEmpty())
03096 return m_text;
03097 else if (m_strings.contains(name))
03098 return m_strings[name].text;
03099 else
03100 return QString();
03101 }
03102
03103 bool MythUIButtonListItem::FindText(const QString &searchStr, const QString &fieldList,
03104 bool startsWith) const
03105 {
03106 if (fieldList.isEmpty())
03107 {
03108 if (startsWith)
03109 return m_text.startsWith(searchStr, Qt::CaseInsensitive);
03110 else
03111 return m_text.contains(searchStr, Qt::CaseInsensitive);
03112 }
03113 else if (fieldList == "**ALL**")
03114 {
03115 if (startsWith)
03116 {
03117 if (m_text.startsWith(searchStr, Qt::CaseInsensitive))
03118 return true;
03119 }
03120 else
03121 {
03122 if (m_text.contains(searchStr, Qt::CaseInsensitive))
03123 return true;
03124 }
03125
03126 QMap<QString, TextProperties>::const_iterator i = m_strings.constBegin();
03127
03128 while (i != m_strings.constEnd())
03129 {
03130 if (startsWith)
03131 {
03132 if (i.value().text.startsWith(searchStr, Qt::CaseInsensitive))
03133 return true;
03134 }
03135 else
03136 {
03137 if (i.value().text.contains(searchStr, Qt::CaseInsensitive))
03138 return true;
03139 }
03140
03141 ++i;
03142 }
03143 }
03144 else
03145 {
03146 QStringList fields = fieldList.split(',', QString::SkipEmptyParts);
03147
03148 for (int x = 0; x < fields.count(); x++)
03149 {
03150 if (m_strings.contains(fields.at(x).trimmed()))
03151 {
03152 if (startsWith)
03153 {
03154 if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
03155 return true;
03156 }
03157 else
03158 {
03159 if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
03160 return true;
03161 }
03162 }
03163 }
03164 }
03165
03166 return false;
03167 }
03168
03169 void MythUIButtonListItem::SetFontState(const QString &state,
03170 const QString &name)
03171 {
03172 if (!name.isEmpty())
03173 {
03174 if (m_strings.contains(name))
03175 m_strings[name].state = state;
03176 }
03177 else
03178 m_fontState = state;
03179
03180 if (m_parent)
03181 m_parent->Update();
03182 }
03183
03184 void MythUIButtonListItem::SetImage(MythImage *image, const QString &name)
03185 {
03186 if (image)
03187 image->IncrRef();
03188
03189 if (!name.isEmpty())
03190 {
03191 QMap<QString, MythImage*>::iterator it = m_images.find(name);
03192 if (it != m_images.end())
03193 {
03194 (*it)->DecrRef();
03195 if (image)
03196 *it = image;
03197 else
03198 m_images.erase(it);
03199 }
03200 else if (image)
03201 {
03202 m_images[name] = image;
03203 }
03204 }
03205 else
03206 {
03207 if (m_image)
03208 m_image->DecrRef();
03209 m_image = image;
03210 }
03211
03212 if (m_parent)
03213 m_parent->Update();
03214 }
03215
03216 void MythUIButtonListItem::SetImageFromMap(const InfoMap &imageMap)
03217 {
03218 m_imageFilenames.clear();
03219 m_imageFilenames = imageMap;
03220 }
03221
03222 MythImage *MythUIButtonListItem::GetImage(const QString &name)
03223 {
03224 if (!name.isEmpty())
03225 {
03226 QMap<QString, MythImage*>::iterator it = m_images.find(name);
03227 if (it != m_images.end())
03228 {
03229 (*it)->IncrRef();
03230 return (*it);
03231 }
03232 }
03233 else if (m_image)
03234 {
03235 m_image->IncrRef();
03236 return m_image;
03237 }
03238
03239 return NULL;
03240 }
03241
03242 void MythUIButtonListItem::SetImage(
03243 const QString &filename, const QString &name, bool force_reload)
03244 {
03245 bool do_update = force_reload;
03246
03247 if (!name.isEmpty())
03248 {
03249 InfoMap::iterator it = m_imageFilenames.find(name);
03250
03251 if (it == m_imageFilenames.end())
03252 {
03253 m_imageFilenames.insert(name, filename);
03254 do_update = true;
03255 }
03256 else if (*it != filename)
03257 {
03258 *it = filename;
03259 do_update = true;
03260 }
03261 }
03262 else if (m_imageFilename != filename)
03263 {
03264 m_imageFilename = filename;
03265 do_update = true;
03266 }
03267
03268 if (m_parent && do_update)
03269 m_parent->Update();
03270 }
03271
03272 QString MythUIButtonListItem::GetImageFilename(const QString &name) const
03273 {
03274 if (name.isEmpty())
03275 return m_imageFilename;
03276
03277 InfoMap::const_iterator it = m_imageFilenames.find(name);
03278
03279 if (it != m_imageFilenames.end())
03280 return *it;
03281
03282 return QString();
03283 }
03284
03285 void MythUIButtonListItem::DisplayState(const QString &state,
03286 const QString &name)
03287 {
03288 if (name.isEmpty())
03289 return;
03290
03291 bool do_update = false;
03292 InfoMap::iterator it = m_states.find(name);
03293
03294 if (it == m_states.end())
03295 {
03296 m_states.insert(name, state);
03297 do_update = true;
03298 }
03299 else if (*it != state)
03300 {
03301 *it = state;
03302 do_update = true;
03303 }
03304
03305 if (m_parent && do_update)
03306 m_parent->Update();
03307 }
03308
03309 void MythUIButtonListItem::SetStatesFromMap(const InfoMap &stateMap)
03310 {
03311 m_states.clear();
03312 m_states = stateMap;
03313 }
03314
03315 bool MythUIButtonListItem::checkable() const
03316 {
03317 return m_checkable;
03318 }
03319
03320 MythUIButtonListItem::CheckState MythUIButtonListItem::state() const
03321 {
03322 return m_state;
03323 }
03324
03325 MythUIButtonList *MythUIButtonListItem::parent() const
03326 {
03327 return m_parent;
03328 }
03329
03330 void MythUIButtonListItem::setChecked(MythUIButtonListItem::CheckState state)
03331 {
03332 if (!m_checkable || m_state == state)
03333 return;
03334
03335 m_state = state;
03336
03337 if (m_parent)
03338 m_parent->Update();
03339 }
03340
03341 void MythUIButtonListItem::setCheckable(bool flag)
03342 {
03343 m_checkable = flag;
03344 }
03345
03346 void MythUIButtonListItem::setDrawArrow(bool flag)
03347 {
03348 m_showArrow = flag;
03349 }
03350
03351 void MythUIButtonListItem::SetData(QVariant data)
03352 {
03353 m_data = data;
03354 }
03355
03356 QVariant MythUIButtonListItem::GetData()
03357 {
03358 return m_data;
03359 }
03360
03361 bool MythUIButtonListItem::MoveUpDown(bool flag)
03362 {
03363 if (m_parent)
03364 return m_parent->MoveItemUpDown(this, flag);
03365 else
03366 return false;
03367 }
03368
03369 void MythUIButtonListItem::SetToRealButton(MythUIStateType *button, bool selected)
03370 {
03371 if (!m_parent)
03372 return;
03373
03374 m_parent->ItemVisible(this);
03375
03376 QString state;
03377
03378 if (selected)
03379 {
03380 button->MoveToTop();
03381 state = m_parent->m_active ? "selectedactive" : "selectedinactive";
03382 }
03383 else
03384 state = m_parent->m_active ? "active" : "inactive";
03385
03386 if (!button->DisplayState(state) && state == "inactive")
03387 {
03388 state = "active";
03389 button->DisplayState(state);
03390 }
03391
03392 MythUIGroup *buttonstate = dynamic_cast<MythUIGroup *>
03393 (button->GetCurrentState());
03394
03395 if (!buttonstate)
03396 {
03397 LOG(VB_GENERAL, LOG_ERR, QString("Failed to query buttonlist state: %1")
03398 .arg(state));
03399 return;
03400 }
03401
03402 buttonstate->SetVisible(true);
03403 buttonstate->Reset();
03404
03405 MythUIText *buttontext = dynamic_cast<MythUIText *>
03406 (buttonstate->GetChild("buttontext"));
03407
03408 if (buttontext)
03409 {
03410 buttontext->SetText(m_text);
03411 buttontext->SetFontState(m_fontState);
03412 }
03413
03414 MythUIImage *buttonimage = dynamic_cast<MythUIImage *>
03415 (buttonstate->GetChild("buttonimage"));
03416
03417 if (buttonimage)
03418 {
03419 if (!m_imageFilename.isEmpty())
03420 {
03421 buttonimage->SetFilename(m_imageFilename);
03422 buttonimage->Load();
03423 }
03424 else if (m_image)
03425 buttonimage->SetImage(m_image);
03426 }
03427
03428 MythUIImage *buttonarrow = dynamic_cast<MythUIImage *>
03429 (buttonstate->GetChild("buttonarrow"));
03430
03431 if (buttonarrow)
03432 buttonarrow->SetVisible(m_showArrow);
03433
03434 MythUIStateType *buttoncheck = dynamic_cast<MythUIStateType *>
03435 (buttonstate->GetChild("buttoncheck"));
03436
03437 if (buttoncheck)
03438 {
03439 buttoncheck->SetVisible(m_checkable);
03440
03441 if (m_checkable)
03442 {
03443 if (m_state == NotChecked)
03444 buttoncheck->DisplayState(MythUIStateType::Off);
03445 else if (m_state == HalfChecked)
03446 buttoncheck->DisplayState(MythUIStateType::Half);
03447 else
03448 buttoncheck->DisplayState(MythUIStateType::Full);
03449 }
03450 }
03451
03452 MythUIText *text;
03453 QMap<QString, TextProperties>::iterator string_it = m_strings.begin();
03454
03455 while (string_it != m_strings.end())
03456 {
03457 text = dynamic_cast<MythUIText *>
03458 (buttonstate->GetChild(string_it.key()));
03459
03460 if (text)
03461 {
03462 TextProperties textprop = string_it.value();
03463
03464 QString newText = text->GetTemplateText();
03465
03466 QRegExp regexp("%(([^\\|%]+)?\\||\\|(.))?(\\w+)(\\|(.+))?%");
03467 regexp.setMinimal(true);
03468
03469 if (!newText.isEmpty() && newText.contains(regexp))
03470 {
03471 int pos = 0;
03472 QString tempString = newText;
03473
03474 while ((pos = regexp.indexIn(newText, pos)) != -1)
03475 {
03476 QString key = regexp.cap(4).toLower().trimmed();
03477 QString replacement;
03478 QString value = m_strings.value(key).text;
03479
03480 if (!value.isEmpty())
03481 {
03482 replacement = QString("%1%2%3%4")
03483 .arg(regexp.cap(2))
03484 .arg(regexp.cap(3))
03485 .arg(m_strings.value(key).text)
03486 .arg(regexp.cap(6));
03487 }
03488
03489 tempString.replace(regexp.cap(0), replacement);
03490 pos += regexp.matchedLength();
03491 }
03492
03493 newText = tempString;
03494 }
03495 else
03496 newText = textprop.text;
03497
03498 if (newText.isEmpty())
03499 text->Reset();
03500 else
03501 text->SetText(newText);
03502
03503 text->SetFontState(textprop.state.isEmpty() ? m_fontState : textprop.state);
03504 }
03505
03506 ++string_it;
03507 }
03508
03509 MythUIImage *image;
03510 InfoMap::iterator imagefile_it = m_imageFilenames.begin();
03511
03512 while (imagefile_it != m_imageFilenames.end())
03513 {
03514 image = dynamic_cast<MythUIImage *>
03515 (buttonstate->GetChild(imagefile_it.key()));
03516
03517 if (image)
03518 {
03519 if (!imagefile_it.value().isEmpty())
03520 {
03521 image->SetFilename(imagefile_it.value());
03522 image->Load();
03523 }
03524 else
03525 image->Reset();
03526 }
03527
03528 ++imagefile_it;
03529 }
03530
03531 QMap<QString, MythImage *>::iterator image_it = m_images.begin();
03532
03533 while (image_it != m_images.end())
03534 {
03535 image = dynamic_cast<MythUIImage *>
03536 (buttonstate->GetChild(image_it.key()));
03537
03538 if (image)
03539 {
03540 if (image_it.value())
03541 image->SetImage(image_it.value());
03542 else
03543 image->Reset();
03544 }
03545
03546 ++image_it;
03547 }
03548
03549 MythUIStateType *statetype;
03550 InfoMap::iterator state_it = m_states.begin();
03551
03552 while (state_it != m_states.end())
03553 {
03554 statetype = dynamic_cast<MythUIStateType *>
03555 (buttonstate->GetChild(state_it.key()));
03556
03557 if (statetype)
03558 {
03559 if (!statetype->DisplayState(state_it.value()))
03560 statetype->Reset();
03561 }
03562
03563 ++state_it;
03564 }
03565 }
03566
03567
03568
03569
03570 SearchButtonListDialog::SearchButtonListDialog(MythScreenStack *parent, const char *name,
03571 MythUIButtonList *parentList, QString searchText)
03572 : MythScreenType(parent, name, false),
03573 m_startsWith(false), m_parentList(parentList),
03574 m_searchText(searchText), m_searchEdit(NULL),
03575 m_prevButton(NULL), m_nextButton(NULL),
03576 m_searchState(NULL)
03577 {
03578 }
03579
03580 SearchButtonListDialog::~SearchButtonListDialog(void)
03581 {
03582 }
03583
03584 bool SearchButtonListDialog::Create(void)
03585 {
03586 if (!CopyWindowFromBase("MythSearchListDialog", this))
03587 return false;
03588
03589 bool err = false;
03590 UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
03591 UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
03592 UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
03593 UIUtilW::Assign(this, m_searchState, "searchstate");
03594
03595 if (err)
03596 {
03597 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'MythSearchListDialog'");
03598 return false;
03599 }
03600
03601 m_searchEdit->SetText(m_searchText);
03602
03603 connect(m_searchEdit, SIGNAL(valueChanged()), SLOT(searchChanged()));
03604 connect(m_prevButton, SIGNAL(Clicked()), SLOT(prevClicked()));
03605 connect(m_nextButton, SIGNAL(Clicked()), SLOT(nextClicked()));
03606
03607 BuildFocusList();
03608
03609 return true;
03610 }
03611
03612 bool SearchButtonListDialog::keyPressEvent(QKeyEvent *event)
03613 {
03614 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
03615 return true;
03616
03617 QStringList actions;
03618 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions, false);
03619
03620 for (int i = 0; i < actions.size() && !handled; i++)
03621 {
03622 QString action = actions[i];
03623 handled = true;
03624
03625 if (action == "0")
03626 {
03627 m_startsWith = !m_startsWith;
03628 searchChanged();
03629 }
03630 else
03631 handled = false;
03632 }
03633
03634 if (!handled && MythScreenType::keyPressEvent(event))
03635 handled = true;
03636
03637 return handled;
03638 }
03639
03640 void SearchButtonListDialog::searchChanged(void)
03641 {
03642 bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);
03643
03644 if (m_searchState)
03645 m_searchState->DisplayState(found ? "found" : "notfound");
03646 }
03647
03648 void SearchButtonListDialog::nextClicked(void)
03649 {
03650 bool found = m_parentList->FindNext();
03651
03652 if (m_searchState)
03653 m_searchState->DisplayState(found ? "found" : "notfound");
03654 }
03655
03656 void SearchButtonListDialog::prevClicked(void)
03657 {
03658 bool found = m_parentList->FindPrev();
03659
03660 if (m_searchState)
03661 m_searchState->DisplayState(found ? "found" : "notfound");
03662 }
03663
03664 void MythUIButtonList::SetScrollBarPosition()
03665 {
03666 if (m_clearing || !m_scrollBar || !m_showScrollBar)
03667 return;
03668
03669 int maximum = m_itemCount <= static_cast<int>(m_itemsVisible) ?
03670 0 : m_itemCount;
03671 m_scrollBar->SetMaximum(maximum);
03672 m_scrollBar->SetPageStep(m_itemsVisible);
03673 m_scrollBar->SetSliderPosition(m_selPosition);
03674 m_scrollBar->MoveToTop();
03675 }