tibia-rme/source/palette_brushlist.cpp
2023-10-15 21:52:40 +00:00

590 lines
16 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// Remere's Map Editor 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 3 of the License, or
// (at your option) any later version.
//
// Remere's Map Editor 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 <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "palette_brushlist.h"
#include "gui.h"
#include "brush.h"
// ============================================================================
// Brush Palette Panel
// A common class for terrain/doodad/item/raw palette
BEGIN_EVENT_TABLE(BrushPalettePanel, PalettePanel)
EVT_CHOICEBOOK_PAGE_CHANGING(wxID_ANY, BrushPalettePanel::OnSwitchingPage)
EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, BrushPalettePanel::OnPageChanged)
END_EVENT_TABLE()
BrushPalettePanel::BrushPalettePanel(wxWindow* parent, const TilesetContainer &tilesets, TilesetCategoryType category, wxWindowID id) :
PalettePanel(parent, id),
palette_type(category),
choicebook(nullptr),
size_panel(nullptr) {
std::shared_ptr<wxSizer> topsizer = newd<wxBoxSizer>(wxVERTICAL);
// Create the tileset panel
std::shared_ptr<wxSizer> ts_sizer = newd<wxStaticBoxSizer>(wxVERTICAL, this, "Tileset");
std::shared_ptr<wxChoicebook> tmp_choicebook = newd<wxChoicebook>(this, wxID_ANY, wxDefaultPosition, wxSize(180, 250));
ts_sizer->Add(tmp_choicebook.get(), 1, wxEXPAND);
topsizer->Add(ts_sizer.get(), 1, wxEXPAND);
for (TilesetContainer::const_iterator iter = tilesets.begin(); iter != tilesets.end(); ++iter) {
const TilesetCategory* tcg = iter->second->getCategory(category);
if (tcg && tcg->size() > 0) {
auto panel = newd<BrushPanel>(tmp_choicebook);
panel->AssignTileset(tcg);
tmp_choicebook->AddPage(panel.get(), wxstr(iter->second->name));
}
}
SetSizerAndFit(topsizer.get());
choicebook = tmp_choicebook;
}
BrushPalettePanel::~BrushPalettePanel() {
////
}
void BrushPalettePanel::InvalidateContents() {
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
BrushPanel* panel = dynamic_cast<BrushPanel*>(choicebook->GetPage(iz));
panel->InvalidateContents();
}
PalettePanel::InvalidateContents();
}
void BrushPalettePanel::LoadCurrentContents() {
wxWindow* page = choicebook->GetCurrentPage();
BrushPanel* panel = dynamic_cast<BrushPanel*>(page);
if (panel) {
panel->OnSwitchIn();
}
PalettePanel::LoadCurrentContents();
}
void BrushPalettePanel::LoadAllContents() {
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
BrushPanel* panel = dynamic_cast<BrushPanel*>(choicebook->GetPage(iz));
panel->LoadContents();
}
PalettePanel::LoadAllContents();
}
PaletteType BrushPalettePanel::GetType() const {
return palette_type;
}
void BrushPalettePanel::SetListType(BrushListType ltype) {
if (!choicebook) {
return;
}
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
BrushPanel* panel = dynamic_cast<BrushPanel*>(choicebook->GetPage(iz));
panel->SetListType(ltype);
}
}
void BrushPalettePanel::SetListType(wxString ltype) {
if (!choicebook) {
return;
}
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
BrushPanel* panel = dynamic_cast<BrushPanel*>(choicebook->GetPage(iz));
panel->SetListType(ltype);
}
}
Brush* BrushPalettePanel::GetSelectedBrush() const {
if (!choicebook) {
return nullptr;
}
wxWindow* page = choicebook->GetCurrentPage();
BrushPanel* panel = dynamic_cast<BrushPanel*>(page);
Brush* res = nullptr;
if (panel) {
for (ToolBarList::const_iterator iter = tool_bars.begin(); iter != tool_bars.end(); ++iter) {
res = (*iter)->GetSelectedBrush();
if (res) {
return res;
}
}
res = panel->GetSelectedBrush();
}
return res;
}
void BrushPalettePanel::SelectFirstBrush() {
if (!choicebook) {
return;
}
wxWindow* page = choicebook->GetCurrentPage();
BrushPanel* panel = dynamic_cast<BrushPanel*>(page);
panel->SelectFirstBrush();
}
bool BrushPalettePanel::SelectBrush(const Brush* whatbrush) {
if (!choicebook) {
return false;
}
auto panel = dynamic_cast<BrushPanel*>(choicebook->GetCurrentPage());
if (!panel) {
return false;
}
for (const std::shared_ptr<PalettePanel> &toolBar : tool_bars) {
if (toolBar->SelectBrush(whatbrush)) {
panel->SelectBrush(nullptr);
return true;
}
}
if (panel->SelectBrush(whatbrush)) {
for (const std::shared_ptr<PalettePanel> &toolBar : tool_bars) {
toolBar->SelectBrush(nullptr);
}
return true;
}
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
if ((int)iz == choicebook->GetSelection()) {
continue;
}
panel = dynamic_cast<BrushPanel*>(choicebook->GetPage(iz));
if (panel && panel->SelectBrush(whatbrush)) {
choicebook->ChangeSelection(iz);
for (const std::shared_ptr<PalettePanel> &toolBar : tool_bars) {
toolBar->SelectBrush(nullptr);
}
return true;
}
}
return false;
}
void BrushPalettePanel::OnSwitchingPage(wxChoicebookEvent &event) {
event.Skip();
if (!choicebook) {
return;
}
BrushPanel* old_panel = dynamic_cast<BrushPanel*>(choicebook->GetCurrentPage());
if (old_panel) {
old_panel->OnSwitchOut();
for (ToolBarList::iterator iter = tool_bars.begin(); iter != tool_bars.end(); ++iter) {
Brush* tmp = (*iter)->GetSelectedBrush();
if (tmp) {
remembered_brushes[old_panel] = tmp;
}
}
}
wxWindow* page = choicebook->GetPage(event.GetSelection());
BrushPanel* panel = dynamic_cast<BrushPanel*>(page);
if (panel) {
panel->OnSwitchIn();
for (ToolBarList::iterator iter = tool_bars.begin(); iter != tool_bars.end(); ++iter) {
(*iter)->SelectBrush(remembered_brushes[panel]);
}
}
}
void BrushPalettePanel::OnPageChanged(wxChoicebookEvent &event) {
if (!choicebook) {
return;
}
g_gui.ActivatePalette(GetParentPalette());
g_gui.SelectBrush();
}
void BrushPalettePanel::OnSwitchIn() {
LoadCurrentContents();
g_gui.ActivatePalette(GetParentPalette());
g_gui.SetBrushSizeInternal(last_brush_size);
OnUpdateBrushSize(g_gui.GetBrushShape(), last_brush_size);
}
// ============================================================================
// Brush Panel
// A container of brush buttons
BEGIN_EVENT_TABLE(BrushPanel, wxPanel)
// Listbox style
EVT_LISTBOX(wxID_ANY, BrushPanel::OnClickListBoxRow)
END_EVENT_TABLE()
BrushPanel::BrushPanel(wxWindow* parent) :
wxPanel(parent, wxID_ANY),
tileset(nullptr),
brushbox(nullptr),
loaded(false),
list_type(BRUSHLIST_LISTBOX) {
sizer = newd<wxBoxSizer>(wxVERTICAL);
SetSizerAndFit(sizer.get());
}
BrushPanel::~BrushPanel() {
////
}
void BrushPanel::AssignTileset(const TilesetCategory* _tileset) {
if (_tileset != tileset) {
InvalidateContents();
tileset = _tileset;
}
}
void BrushPanel::SetListType(BrushListType ltype) {
if (list_type != ltype) {
InvalidateContents();
list_type = ltype;
}
}
void BrushPanel::SetListType(wxString ltype) {
if (ltype == "small icons") {
SetListType(BRUSHLIST_SMALL_ICONS);
} else if (ltype == "large icons") {
SetListType(BRUSHLIST_LARGE_ICONS);
} else if (ltype == "listbox") {
SetListType(BRUSHLIST_LISTBOX);
} else if (ltype == "textlistbox") {
SetListType(BRUSHLIST_TEXT_LISTBOX);
}
}
void BrushPanel::InvalidateContents() {
sizer->Clear(true);
loaded = false;
brushbox = nullptr;
}
void BrushPanel::LoadContents() {
if (loaded) {
return;
}
loaded = true;
ASSERT(tileset != nullptr);
switch (list_type) {
case BRUSHLIST_LARGE_ICONS:
brushbox = newd<BrushIconBox>(this, tileset, RENDER_SIZE_32x32);
break;
case BRUSHLIST_SMALL_ICONS:
brushbox = newd<BrushIconBox>(this, tileset, RENDER_SIZE_16x16);
break;
case BRUSHLIST_LISTBOX:
brushbox = newd<BrushListBox>(this, tileset);
break;
default:
break;
}
ASSERT(brushbox != nullptr);
sizer->Add(brushbox->GetSelfWindow(), 1, wxEXPAND);
Fit();
brushbox->SelectFirstBrush();
}
void BrushPanel::SelectFirstBrush() {
if (loaded) {
ASSERT(brushbox != nullptr);
brushbox->SelectFirstBrush();
}
}
Brush* BrushPanel::GetSelectedBrush() const {
if (loaded) {
ASSERT(brushbox != nullptr);
return brushbox->GetSelectedBrush();
}
if (tileset && tileset->size() > 0) {
return tileset->brushlist[0];
}
return nullptr;
}
bool BrushPanel::SelectBrush(const Brush* whatbrush) {
if (loaded) {
// std::cout << loaded << std::endl;
// std::cout << brushbox << std::endl;
ASSERT(brushbox != nullptr);
return brushbox->SelectBrush(whatbrush);
}
for (BrushVector::const_iterator iter = tileset->brushlist.begin(); iter != tileset->brushlist.end(); ++iter) {
if (*iter == whatbrush) {
LoadContents();
return brushbox->SelectBrush(whatbrush);
}
}
return false;
}
void BrushPanel::OnSwitchIn() {
LoadContents();
}
void BrushPanel::OnSwitchOut() {
////
}
void BrushPanel::OnClickListBoxRow(wxCommandEvent &event) {
ASSERT(tileset->getType() >= TILESET_UNKNOWN && tileset->getType() <= TILESET_HOUSE);
// We just notify the GUI of the action, it will take care of everything else
ASSERT(brushbox);
size_t n = event.GetSelection();
wxWindow* w = this;
while ((w = w->GetParent()) && dynamic_cast<PaletteWindow*>(w) == nullptr)
;
if (w) {
g_gui.ActivatePalette(static_cast<PaletteWindow*>(w));
}
g_gui.SelectBrush(tileset->brushlist[n], tileset->getType());
}
// ============================================================================
// BrushIconBox
BEGIN_EVENT_TABLE(BrushIconBox, wxScrolledWindow)
// Listbox style
EVT_TOGGLEBUTTON(wxID_ANY, BrushIconBox::OnClickBrushButton)
END_EVENT_TABLE()
BrushIconBox::BrushIconBox(wxWindow* parent, const TilesetCategory* _tileset, RenderSize rsz) :
wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL),
BrushBoxInterface(_tileset),
icon_size(rsz) {
ASSERT(tileset->getType() >= TILESET_UNKNOWN && tileset->getType() <= TILESET_HOUSE);
int width;
if (icon_size == RENDER_SIZE_32x32) {
width = std::max(g_settings.getInteger(Config::PALETTE_COL_COUNT) / 2 + 1, 1);
} else {
width = std::max(g_settings.getInteger(Config::PALETTE_COL_COUNT) + 1, 1);
}
// Create buttons
std::shared_ptr<wxSizer> stacksizer = newd<wxBoxSizer>(wxVERTICAL);
std::shared_ptr<wxSizer> rowsizer = nullptr;
int item_counter = 0;
for (BrushVector::const_iterator iter = tileset->brushlist.begin(); iter != tileset->brushlist.end(); ++iter) {
ASSERT(*iter);
++item_counter;
if (!rowsizer) {
rowsizer = newd<wxBoxSizer>(wxHORIZONTAL);
}
std::shared_ptr<BrushButton> bb = newd<BrushButton>(this, *iter, rsz);
rowsizer->Add(bb.get());
brush_buttons.push_back(bb);
if (item_counter % width == 0) { // newd row
stacksizer->Add(rowsizer.get());
rowsizer = nullptr;
}
}
if (rowsizer) {
stacksizer->Add(rowsizer.get());
}
SetScrollbars(20, 20, 8, item_counter / width, 0, 0);
SetSizer(stacksizer.get());
}
BrushIconBox::~BrushIconBox() {
////
}
void BrushIconBox::SelectFirstBrush() {
if (tileset && tileset->size() > 0) {
DeselectAll();
brush_buttons[0]->SetValue(true);
EnsureVisible((size_t)0);
}
}
Brush* BrushIconBox::GetSelectedBrush() const {
if (!tileset) {
return nullptr;
}
for (std::vector<std::shared_ptr<BrushButton>>::const_iterator it = brush_buttons.begin(); it != brush_buttons.end(); ++it) {
if ((*it)->GetValue()) {
return (*it)->brush;
}
}
return nullptr;
}
bool BrushIconBox::SelectBrush(const Brush* whatbrush) {
DeselectAll();
for (std::vector<std::shared_ptr<BrushButton>>::iterator it = brush_buttons.begin(); it != brush_buttons.end(); ++it) {
if ((*it)->brush == whatbrush) {
(*it)->SetValue(true);
EnsureVisible(*it);
return true;
}
}
return false;
}
void BrushIconBox::DeselectAll() {
for (std::vector<std::shared_ptr<BrushButton>>::iterator it = brush_buttons.begin(); it != brush_buttons.end(); ++it) {
(*it)->SetValue(false);
}
}
void BrushIconBox::EnsureVisible(std::shared_ptr<BrushButton> btn) {
int windowSizeX, windowSizeY;
GetVirtualSize(&windowSizeX, &windowSizeY);
int scrollUnitX;
int scrollUnitY;
GetScrollPixelsPerUnit(&scrollUnitX, &scrollUnitY);
wxRect rect = btn->GetRect();
int y;
CalcUnscrolledPosition(0, rect.y, nullptr, &y);
int maxScrollPos = windowSizeY / scrollUnitY;
int scrollPosY = std::min(maxScrollPos, (y / scrollUnitY));
int startScrollPosY;
GetViewStart(nullptr, &startScrollPosY);
int clientSizeX, clientSizeY;
GetClientSize(&clientSizeX, &clientSizeY);
int endScrollPosY = startScrollPosY + clientSizeY / scrollUnitY;
if (scrollPosY < startScrollPosY || scrollPosY > endScrollPosY) {
// only scroll if the button isnt visible
Scroll(-1, scrollPosY);
}
}
void BrushIconBox::EnsureVisible(size_t n) {
EnsureVisible(brush_buttons[n]);
}
void BrushIconBox::OnClickBrushButton(wxCommandEvent &event) {
wxObject* obj = event.GetEventObject();
BrushButton* btn = dynamic_cast<BrushButton*>(obj);
if (btn) {
wxWindow* w = this;
while ((w = w->GetParent()) && dynamic_cast<PaletteWindow*>(w) == nullptr)
;
if (w) {
g_gui.ActivatePalette(static_cast<PaletteWindow*>(w));
}
g_gui.SelectBrush(btn->brush, tileset->getType());
}
}
// ============================================================================
// BrushListBox
BEGIN_EVENT_TABLE(BrushListBox, wxVListBox)
EVT_KEY_DOWN(BrushListBox::OnKey)
END_EVENT_TABLE()
BrushListBox::BrushListBox(wxWindow* parent, const TilesetCategory* tileset) :
wxVListBox(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_SINGLE),
BrushBoxInterface(tileset) {
SetItemCount(tileset->size());
}
BrushListBox::~BrushListBox() {
////
}
void BrushListBox::SelectFirstBrush() {
SetSelection(0);
wxWindow::ScrollLines(-1);
}
Brush* BrushListBox::GetSelectedBrush() const {
if (!tileset) {
return nullptr;
}
int n = GetSelection();
if (n != wxNOT_FOUND) {
return tileset->brushlist[n];
} else if (tileset->size() > 0) {
return tileset->brushlist[0];
}
return nullptr;
}
bool BrushListBox::SelectBrush(const Brush* whatbrush) {
for (size_t n = 0; n < tileset->size(); ++n) {
if (tileset->brushlist[n] == whatbrush) {
SetSelection(n);
return true;
}
}
return false;
}
void BrushListBox::OnDrawItem(wxDC &dc, const wxRect &rect, size_t n) const {
ASSERT(n < tileset->size());
Sprite* spr = g_gui.gfx.getSprite(tileset->brushlist[n]->getLookID());
if (spr) {
spr->DrawTo(&dc, SPRITE_SIZE_32x32, rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight());
}
if (IsSelected(n)) {
if (HasFocus()) {
dc.SetTextForeground(wxColor(0xFF, 0xFF, 0xFF));
} else {
dc.SetTextForeground(wxColor(0x00, 0x00, 0xFF));
}
} else {
dc.SetTextForeground(wxColor(0x00, 0x00, 0x00));
}
dc.DrawText(wxstr(tileset->brushlist[n]->getName()), rect.GetX() + 40, rect.GetY() + 6);
}
wxCoord BrushListBox::OnMeasureItem(size_t n) const {
return 32;
}
void BrushListBox::OnKey(wxKeyEvent &event) {
switch (event.GetKeyCode()) {
case WXK_UP:
case WXK_DOWN:
case WXK_LEFT:
case WXK_RIGHT:
if (g_settings.getInteger(Config::LISTBOX_EATS_ALL_EVENTS)) {
case WXK_PAGEUP:
case WXK_PAGEDOWN:
case WXK_HOME:
case WXK_END:
event.Skip(true);
} else {
[[fallthrough]];
default:
if (g_gui.GetCurrentTab() != nullptr) {
g_gui.GetCurrentMapTab()->GetEventHandler()->AddPendingEvent(event);
}
}
}
}