/* * The ManaPlus Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2010 The Mana Developers * Copyright (C) 2011-2019 The ManaPlus Developers * * This file is part of The ManaPlus Client. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GUI_WIDGETS_SKILLLISTBOX_H #define GUI_WIDGETS_SKILLLISTBOX_H #include "const/resources/skill.h" #include "dragdrop.h" #include "gui/skin.h" #include "gui/viewport.h" #include "gui/widgets/listbox.h" #include "gui/fonts/font.h" #include "gui/models/skillmodel.h" #include "gui/popups/popupmenu.h" #include "gui/popups/skillpopup.h" #include "utils/delete2.h" #include "render/graphics.h" #include "localconsts.h" class SkillModel; class SkillListBox final : public ListBox { public: SkillListBox(const Widget2 *const widget, SkillModel *const model) : ListBox(widget, model, "skilllistbox.xml"), mModel(model), mTextColor(getThemeColor(ThemeColorId::TEXT, 255U)), mTextColor2(getThemeColor(ThemeColorId::TEXT_OUTLINE, 255U)), mCooldownColor(getThemeColor(ThemeColorId::SKILL_COOLDOWN, 255U)), mTextPadding(mSkin != nullptr ? mSkin->getOption("textPadding", 34) : 34), mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 0) : 0), mSkillClicked(false) { mRowHeight = getFont()->getHeight() * 2 + mSpacing + 2 * mPadding; mHighlightColor = getThemeColor(ThemeColorId::HIGHLIGHT, 255U); if (mRowHeight < 34) mRowHeight = 34; } A_DELETE_COPY(SkillListBox) ~SkillListBox() override final { delete2(mModel) } SkillInfo *getSelectedInfo() const { const int selected = getSelected(); if ((mListModel == nullptr) || selected < 0 || selected > mListModel->getNumberOfElements()) { return nullptr; } return static_cast(mListModel)->getSkillAt(selected); } void draw(Graphics *const graphics) override final A_NONNULL(2) { if (mListModel == nullptr) return; SkillModel *const model = static_cast(mListModel); updateAlpha(); mHighlightColor.a = CAST_S32(mAlpha * 255.0F); graphics->setColor(mHighlightColor); const int width1 = getWidth(); const int usableWidth = width1 - 2 * mPadding; // Draw filled rectangle around the selected list element if (mSelected >= 0) { graphics->fillRectangle(Rect(mPadding, getRowHeight() * mSelected + mPadding, usableWidth, getRowHeight())); } // Draw the list elements Font *const font = getFont(); const int space = font->getHeight() + mSpacing; const int width2 = width1 - mPadding; graphics->setColor(mCooldownColor); for (int i = 0, y = 1 + mPadding; i < model->getNumberOfElements(); ++i, y += getRowHeight()) { SkillInfo *const e = model->getSkillAt(i); if (e != nullptr) { if (e->cooldown != 0) { graphics->fillRectangle(Rect(mPadding, y, usableWidth * 100 / e->cooldown, 10)); } } } for (int i = 0, y = 1 + mPadding; i < model->getNumberOfElements(); ++i, y += getRowHeight()) { SkillInfo *const e = model->getSkillAt(i); if (e != nullptr) { const SkillData *const data = e->data; const std::string &description = data->description; graphics->drawImage(data->icon, mPadding, y); font->drawString(graphics, mTextColor, mTextColor2, data->name, mTextPadding, y); if (!description.empty()) { font->drawString(graphics, mTextColor, mTextColor2, description, mTextPadding, y + space); } if (e->skillLevelWidth < 0) { // Add one for padding e->skillLevelWidth = font->getWidth(e->skillLevel) + 1; } font->drawString(graphics, mTextColor, mTextColor2, e->skillLevel, width2 - e->skillLevelWidth, y); } } } void safeDraw(Graphics *const graphics) override final A_NONNULL(2) { SkillListBox::draw(graphics); } unsigned int getRowHeight() const override final { return mRowHeight; } const SkillInfo *getSkillByEvent(const MouseEvent &event) const { const int y = (event.getY() + mPadding) / getRowHeight(); if (mModel == nullptr || y >= mModel->getNumberOfElements()) return nullptr; const SkillInfo *const skill = mModel->getSkillAt(y); if (skill == nullptr) return nullptr; return skill; } void mouseMoved(MouseEvent &event) override final { ListBox::mouseMoved(event); if ((viewport == nullptr) || !dragDrop.isEmpty()) return; const SkillInfo *const skill = getSkillByEvent(event); if (skill == nullptr) return; skillPopup->show(skill, skill->customSelectedLevel, skill->customCastType, skill->customOffsetX, skill->customOffsetY); skillPopup->position(viewport->mMouseX, viewport->mMouseY); } void mouseDragged(MouseEvent &event) override final { if (event.getButton() == MouseButton::LEFT) { if (dragDrop.isEmpty()) { if (mSkillClicked) { mSkillClicked = false; const SkillInfo *const skill = getSkillByEvent(event); if (skill == nullptr) return; dragDrop.dragSkill(skill, DragDropSource::Skills, 0); dragDrop.setItem(skill->id + SKILL_MIN_ID); dragDrop.setItemData(skill->toDataStr()); } ListBox::mouseDragged(event); } } else { ListBox::mouseDragged(event); } } void mousePressed(MouseEvent &event) override final { ListBox::mousePressed(event); const MouseButtonT button = event.getButton(); if (button == MouseButton::LEFT || button == MouseButton::RIGHT) { const SkillInfo *const skill = getSkillByEvent(event); if (skill == nullptr) return; event.consume(); mSkillClicked = true; SkillModel *const model = static_cast( mListModel); if ((model != nullptr) && mSelected >= 0 && model->getSkillAt(mSelected) == skill) { skillPopup->hide(); if (button == MouseButton::LEFT && event.getX() > getWidth() - mPadding - skill->skillLevelWidth) { popupMenu->showSkillLevelPopup(skill); } else if (button == MouseButton::RIGHT) { popupMenu->showSkillPopup(skill); } } } } void mouseReleased(MouseEvent &event) override final { ListBox::mouseReleased(event); } void mouseExited(MouseEvent &event A_UNUSED) override final { skillPopup->hide(); } private: SkillModel *mModel; Color mTextColor; Color mTextColor2; Color mCooldownColor; int mTextPadding; int mSpacing; bool mSkillClicked; }; #endif // GUI_WIDGETS_SKILLLISTBOX_H