From 37f849a6ae4d96a22d7b972d3021c235aa294ad8 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 29 Jun 2013 16:02:11 +0300 Subject: Add support for multilines in extendedlistbox. --- src/gui/widgets/extendedlistbox.cpp | 174 ++++++++++++++++++++++++++++-------- src/gui/widgets/extendedlistbox.h | 25 ++++++ src/gui/widgets/listbox.cpp | 10 ++- src/gui/widgets/listbox.h | 4 +- 4 files changed, 174 insertions(+), 39 deletions(-) (limited to 'src/gui/widgets') diff --git a/src/gui/widgets/extendedlistbox.cpp b/src/gui/widgets/extendedlistbox.cpp index 3126b14b0..00bb5e5fd 100644 --- a/src/gui/widgets/extendedlistbox.cpp +++ b/src/gui/widgets/extendedlistbox.cpp @@ -44,7 +44,10 @@ ExtendedListBox::ExtendedListBox(const Widget2 *const widget, mRowHeight(rowHeight), mImagePadding(mSkin ? mSkin->getOption("imagePadding") : 0), mSpacing(mSkin ? mSkin->getOption("spacing") : 0), - mItemPadding(mSkin ? mSkin->getOption("itemPadding") : 1) + mItemPadding(mSkin ? mSkin->getOption("itemPadding") : 1), + mHeight(0), + mListItems(), + mSelectedItems() { if (!mRowHeight) { @@ -73,71 +76,172 @@ void ExtendedListBox::draw(gcn::Graphics *graphics) updateAlpha(); gcn::Font *const font = getFont(); - const int height = getRowHeight(); + const int height = mRowHeight; const int pad2 = 2 + mPadding; + const int width = mDimension.width; int textPos = (height - font->getHeight()) / 2 + mPadding; if (textPos < 0) textPos = 0; - // Draw filled rectangle around the selected list element - if (mSelected >= 0) + const int sz = mListModel->getNumberOfElements(); + mListItems.clear(); + mSelectedItems.clear(); + int y = 0; + const int insideWidth = width - pad2; + for (int f = 0; f < sz; f ++) + { + int row = f; + bool useImage = true; + std::string str = mListModel->getElementAt(f); + int strWidth = font->getWidth(str) + 8; + + const Image *const image = model->getImageAt(row); + if (image) + strWidth += image->getWidth() + mImagePadding; + + std::vector &list = + row == mSelected ? mSelectedItems : mListItems; + + if (insideWidth < strWidth) + { + const int strSize = str.size(); + list.push_back(ExtendedListBoxItem(row, + str.substr(0, strSize / 2), useImage, y)); + str = str.substr(strSize / 2); + y += height; + useImage = false; + } + list.push_back(ExtendedListBoxItem(row, str, useImage, y)); + + y += height; + } + mHeight = y + height; + + const int itemsSz = mListItems.size(); + const int selSz = mSelectedItems.size(); + int minY = -1; + int maxY = -1; + for (int f = 0; f < selSz; f ++) + { + const ExtendedListBoxItem &item = mSelectedItems[f]; + const int y1 = item.y; + if (minY == -1) + minY = y1; + if (maxY < y1) + maxY = y1; + } + + if (minY != -1) { mHighlightColor.a = static_cast(mAlpha * 255.0f); graphics->setColor(mHighlightColor); - graphics->fillRectangle(gcn::Rectangle(mPadding, - height * mSelected + mPadding, - getWidth() - pad2, height)); + graphics->fillRectangle(gcn::Rectangle(mPadding, minY + mPadding, + width - pad2, maxY - minY + height)); } - const int sz = mListModel->getNumberOfElements(); - for (int i = 0, y = 0; i < sz; ++i, y += height) + for (int f = 0; f < itemsSz; ++f) { - if (i != mSelected) + const ExtendedListBoxItem &item = mListItems[f]; + const int row1 = item.row; + if (item.image) { - const Image *const image = model->getImageAt(i); + const Image *const image = model->getImageAt(row1); if (image) { - g->drawImage(image, mImagePadding, y + (height + g->drawImage(image, mImagePadding, item.y + (height - image->getHeight()) / 2 + mPadding); } } } + g->setColorAll(mForegroundColor, mForegroundColor2); - for (int i = 0, y = 0; i < sz; ++i, y += height) + + for (int f = 0; f < itemsSz; ++f) { - if (i != mSelected) + const ExtendedListBoxItem &item = mListItems[f]; + const int row1 = item.row; + const int y1 = item.y; + const Image *const image = model->getImageAt(row1); + if (!image || !item.image) { - const Image *const image = model->getImageAt(i); - if (!image) - { - font->drawString(graphics, mListModel->getElementAt(i), - mPadding, y + textPos); - } - else + font->drawString(graphics, item.text, mPadding, y1 + textPos); + } + else + { + font->drawString(graphics, item.text, + image->getWidth() + mImagePadding + mSpacing, y1 + textPos); + } + } + + + + for (int f = 0; f < selSz; ++f) + { + const ExtendedListBoxItem &item = mSelectedItems[f]; + const int row1 = item.row; + if (item.image) + { + const Image *const image = model->getImageAt(row1); + if (image) { - font->drawString(graphics, mListModel->getElementAt(i), - image->getWidth() + mImagePadding + mSpacing, y + textPos); + g->drawImage(image, mImagePadding, item.y + (height + - image->getHeight()) / 2 + mPadding); } } } - if (mSelected >= 0) + + g->setColorAll(mForegroundSelectedColor, mForegroundSelectedColor2); + + for (int f = 0; f < selSz; ++f) { - const Image *const image = model->getImageAt(mSelected); - if (!image) + const ExtendedListBoxItem &item = mSelectedItems[f]; + const int row1 = item.row; + const int y1 = item.y; + const Image *const image = model->getImageAt(row1); + if (!image || !item.image) { - font->drawString(graphics, mListModel->getElementAt(mSelected), - mPadding, mSelected * height + textPos); + font->drawString(graphics, item.text, mPadding, y1 + textPos); } else { - const int y = mSelected * height; - g->drawImage(image, mImagePadding, y + (height - - image->getHeight()) / 2 + mPadding); - g->setColorAll(mForegroundSelectedColor, - mForegroundSelectedColor2); - font->drawString(graphics, mListModel->getElementAt(mSelected), - image->getWidth() + mImagePadding + mSpacing, y + textPos); + font->drawString(graphics, item.text, + image->getWidth() + mImagePadding + mSpacing, y1 + textPos); } } + BLOCK_END("ExtendedListBox::draw") } + +void ExtendedListBox::adjustSize() +{ + if (mHeight) + setHeight(mHeight + 2 * mPadding); + else + ListBox::adjustSize(); +} + +int ExtendedListBox::getSelectionByMouse(const int y) const +{ + if (mListItems.empty() && mSelectedItems.empty()) + return ListBox::getSelectionByMouse(y); + + const int height = mRowHeight; + const int itemsSz = mListItems.size(); + for (int f = 0; f < itemsSz; f ++) + { + const ExtendedListBoxItem &item = mListItems[f]; + const int y2 = item.y; + if (y2 <= y && y2 + height > y) + return item.row; + } + + const int selSz = mSelectedItems.size(); + for (int f = 0; f < selSz; f ++) + { + const ExtendedListBoxItem &item = mSelectedItems[f]; + const int y2 = item.y; + if (y2 <= y && y2 + height > y) + return item.row; + } + return 0; +} diff --git a/src/gui/widgets/extendedlistbox.h b/src/gui/widgets/extendedlistbox.h index 9d3394dd4..79fef2f50 100644 --- a/src/gui/widgets/extendedlistbox.h +++ b/src/gui/widgets/extendedlistbox.h @@ -23,6 +23,24 @@ #include "gui/widgets/listbox.h" +struct ExtendedListBoxItem +{ + ExtendedListBoxItem(const int row0, + const std::string &text0, + const bool image0, + const int y0) : + row(row0), + text(text0), + image(image0), + y(y0) + { + } + int row; + std::string text; + bool image; + int y; +}; + class ExtendedListBox final : public ListBox { public: @@ -49,11 +67,18 @@ class ExtendedListBox final : public ListBox void setRowHeight(unsigned int n) { mRowHeight = n; } + void adjustSize() override; + + int getSelectionByMouse(const int y) const override; + protected: unsigned int mRowHeight; int mImagePadding; int mSpacing; int mItemPadding; + int mHeight; + std::vector mListItems; + std::vector mSelectedItems; }; #endif // GUI_WIDGETS_EXTENDEDLISTBOX_H diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp index 2f0f8d941..e5229eca6 100644 --- a/src/gui/widgets/listbox.cpp +++ b/src/gui/widgets/listbox.cpp @@ -209,8 +209,7 @@ void ListBox::mousePressed1(gcn::MouseEvent &mouseEvent) { if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) { - setSelected(std::max(0, mouseEvent.getY() - mPadding) - / getRowHeight()); + setSelected(std::max(0, getSelectionByMouse(mouseEvent.getY()))); distributeActionEvent(); } } @@ -222,7 +221,7 @@ void ListBox::mouseDragged(gcn::MouseEvent &event) // Make list selection update on drag, but guard against negative y if (getRowHeight()) - setSelected(std::max(0, event.getY() - mPadding) / getRowHeight()); + setSelected(std::max(0, getSelectionByMouse(event.getY()))); } void ListBox::refocus() @@ -249,3 +248,8 @@ void ListBox::logic() { adjustSize(); } + +int ListBox::getSelectionByMouse(const int y) const +{ + return (y - mPadding) / getRowHeight(); +} diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h index a4a931a1f..113174332 100644 --- a/src/gui/widgets/listbox.h +++ b/src/gui/widgets/listbox.h @@ -85,10 +85,12 @@ class ListBox : public gcn::ListBox, void setDistributeMousePressed(bool b) { mDistributeMousePressed = b; } - void adjustSize(); + virtual void adjustSize(); void logic() override; + virtual int getSelectionByMouse(const int y) const; + protected: gcn::Color mHighlightColor; gcn::Color mForegroundColor2; -- cgit v1.2.3-60-g2f50