tibia-rme/source/palette_brushlist.cpp

619 lines
15 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)
{
wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL);
// Create the tileset panel
wxSizer* ts_sizer = newd wxStaticBoxSizer(wxVERTICAL, this, "Tileset");
wxChoicebook* tmp_choicebook = newd wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxSize(180,250));
ts_sizer->Add(tmp_choicebook, 1, wxEXPAND);
topsizer->Add(ts_sizer, 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) {
BrushPanel* panel = newd BrushPanel(tmp_choicebook);
panel->AssignTileset(tcg);
tmp_choicebook->AddPage(panel, wxstr(iter->second->name));
}
}
SetSizerAndFit(topsizer);
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;
}
BrushPanel* panel = dynamic_cast<BrushPanel*>(choicebook->GetCurrentPage());
if(!panel) {
return false;
}
for(PalettePanel* toolBar : tool_bars) {
if(toolBar->SelectBrush(whatbrush)) {
panel->SelectBrush(nullptr);
return true;
}
}
if(panel->SelectBrush(whatbrush)) {
for(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(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);
}
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
wxSizer* stacksizer = newd wxBoxSizer(wxVERTICAL);
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);
}
BrushButton* bb = newd BrushButton(this, *iter, rsz);
rowsizer->Add(bb);
brush_buttons.push_back(bb);
if(item_counter % width == 0) { // newd row
stacksizer->Add(rowsizer);
rowsizer = nullptr;
}
}
if(rowsizer) {
stacksizer->Add(rowsizer);
}
SetScrollbars(20,20, 8, item_counter/width, 0, 0);
SetSizer(stacksizer);
}
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<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<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<BrushButton*>::iterator it = brush_buttons.begin(); it != brush_buttons.end(); ++it) {
(*it)->SetValue(false);
}
}
void BrushIconBox::EnsureVisible(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);
}
}
}
}