//////////////////////////////////////////////////////////////////////
// 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 .
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "settings.h"
#include "gui.h"
#include "brush.h"
#include "map_display.h"
#include "palette_window.h"
#include "palette_brushlist.h"
#include "palette_house.h"
#include "palette_creature.h"
#include "palette_waypoints.h"
#include "house_brush.h"
#include "map.h"
// ============================================================================
// Palette window
BEGIN_EVENT_TABLE(PaletteWindow, wxPanel)
EVT_CHOICEBOOK_PAGE_CHANGING(PALETTE_CHOICEBOOK, PaletteWindow::OnSwitchingPage)
EVT_CHOICEBOOK_PAGE_CHANGED(PALETTE_CHOICEBOOK, PaletteWindow::OnPageChanged)
EVT_CLOSE(PaletteWindow::OnClose)
EVT_KEY_DOWN(PaletteWindow::OnKey)
EVT_TEXT(wxID_ANY, PaletteWindow::OnActionIDChange)
EVT_CHECKBOX(wxID_ANY, PaletteWindow::OnActionIDToggle)
END_EVENT_TABLE()
PaletteWindow::PaletteWindow(wxWindow* parent, const TilesetContainer& tilesets) :
wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(230, 250)),
choicebook(nullptr),
terrain_palette(nullptr),
doodad_palette(nullptr),
item_palette(nullptr),
collection_palette(nullptr),
creature_palette(nullptr),
house_palette(nullptr),
waypoint_palette(nullptr),
raw_palette(nullptr),
action_id_input(nullptr),
action_id_checkbox(nullptr),
action_id(0),
action_id_enabled(false) {
// Allow resizing but maintain minimum size
SetMinSize(wxSize(225, 250));
// Create main sizer
wxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
// Create action ID controls
wxSizer* action_id_sizer = new wxBoxSizer(wxHORIZONTAL);
action_id_input = new wxTextCtrl(this, wxID_ANY, "0", wxDefaultPosition, wxSize(60, -1));
action_id_input->SetToolTip("Enter action ID (0-65535)");
action_id_checkbox = new wxCheckBox(this, wxID_ANY, "Enable Action ID");
action_id_checkbox->SetToolTip("When enabled, placed items will have this action ID");
action_id_sizer->Add(action_id_input, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
action_id_sizer->Add(action_id_checkbox, 0, wxALIGN_CENTER_VERTICAL);
main_sizer->Add(action_id_sizer, 0, wxEXPAND | wxALL, 5);
// Create choicebook with EXPAND flag to fill available space
choicebook = new wxChoicebook(this, PALETTE_CHOICEBOOK, wxDefaultPosition, wxDefaultSize);
terrain_palette = static_cast(CreateTerrainPalette(choicebook, tilesets));
choicebook->AddPage(terrain_palette, terrain_palette->GetName());
doodad_palette = static_cast(CreateDoodadPalette(choicebook, tilesets));
choicebook->AddPage(doodad_palette, doodad_palette->GetName());
collection_palette = static_cast(CreateCollectionPalette(choicebook, tilesets));
choicebook->AddPage(collection_palette, collection_palette->GetName());
item_palette = static_cast(CreateItemPalette(choicebook, tilesets));
choicebook->AddPage(item_palette, item_palette->GetName());
house_palette = static_cast(CreateHousePalette(choicebook, tilesets));
choicebook->AddPage(house_palette, house_palette->GetName());
waypoint_palette = static_cast(CreateWaypointPalette(choicebook, tilesets));
choicebook->AddPage(waypoint_palette, waypoint_palette->GetName());
creature_palette = static_cast(CreateCreaturePalette(choicebook, tilesets));
choicebook->AddPage(creature_palette, creature_palette->GetName());
raw_palette = static_cast(CreateRAWPalette(choicebook, tilesets));
choicebook->AddPage(raw_palette, raw_palette->GetName());
// Add choicebook to main sizer
main_sizer->Add(choicebook, 1, wxEXPAND | wxALL, 2);
SetSizer(main_sizer);
// Load first page
LoadCurrentContents();
}
PaletteWindow::~PaletteWindow() {
// Clean up all brushes and caches in each palette panel
if (choicebook) {
// Ensure each panel type is properly cleaned up
if (terrain_palette) {
terrain_palette->DestroyAllCaches();
}
if (doodad_palette) {
doodad_palette->DestroyAllCaches();
}
if (item_palette) {
item_palette->DestroyAllCaches();
}
if (collection_palette) {
collection_palette->DestroyAllCaches();
}
if (raw_palette) {
raw_palette->DestroyAllCaches();
}
// Other palette types may need specific cleanup
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
PalettePanel* panel = dynamic_cast(choicebook->GetPage(iz));
if (panel) {
panel->InvalidateContents();
}
}
}
}
PalettePanel* PaletteWindow::CreateTerrainPalette(wxWindow* parent, const TilesetContainer& tilesets) {
BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_TERRAIN);
panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_TERRAIN_STYLE)));
BrushToolPanel* tool_panel = newd BrushToolPanel(panel);
tool_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR));
panel->AddToolPanel(tool_panel);
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR));
panel->AddToolPanel(size_panel);
ZoneBrushPanel* zone_brush_panel = newd ZoneBrushPanel(panel);
zone_brush_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR));
panel->AddToolPanel(zone_brush_panel);
return panel;
}
PalettePanel* PaletteWindow::CreateCollectionPalette(wxWindow* parent, const TilesetContainer& tilesets) {
BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_COLLECTION);
panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_COLLECTION_STYLE)));
// terrain palette tools
BrushToolPanel* tool_panel = newd BrushToolPanel(panel);
tool_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR));
panel->AddToolPanel(tool_panel);
// brush thickness panel
panel->AddToolPanel(newd BrushThicknessPanel(panel));
// brush size tools
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR));
panel->AddToolPanel(size_panel);
return panel;
}
PalettePanel* PaletteWindow::CreateDoodadPalette(wxWindow* parent, const TilesetContainer& tilesets) {
BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_DOODAD);
panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_DOODAD_STYLE)));
panel->AddToolPanel(newd BrushThicknessPanel(panel));
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_DOODAD_SIZEBAR));
panel->AddToolPanel(size_panel);
return panel;
}
PalettePanel* PaletteWindow::CreateItemPalette(wxWindow* parent, const TilesetContainer& tilesets) {
BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_ITEM);
panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_ITEM_STYLE)));
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_ITEM_SIZEBAR));
panel->AddToolPanel(size_panel);
return panel;
}
PalettePanel* PaletteWindow::CreateHousePalette(wxWindow* parent, const TilesetContainer& tilesets) {
HousePalettePanel* panel = newd HousePalettePanel(parent);
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_HOUSE_SIZEBAR));
panel->AddToolPanel(size_panel);
return panel;
}
PalettePanel* PaletteWindow::CreateWaypointPalette(wxWindow* parent, const TilesetContainer& tilesets) {
WaypointPalettePanel* panel = newd WaypointPalettePanel(parent);
return panel;
}
PalettePanel* PaletteWindow::CreateCreaturePalette(wxWindow* parent, const TilesetContainer& tilesets) {
CreaturePalettePanel* panel = newd CreaturePalettePanel(parent);
return panel;
}
PalettePanel* PaletteWindow::CreateRAWPalette(wxWindow* parent, const TilesetContainer& tilesets) {
BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_RAW);
panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_RAW_STYLE)));
BrushSizePanel* size_panel = newd BrushSizePanel(panel);
size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_RAW_SIZEBAR));
panel->AddToolPanel(size_panel);
return panel;
}
void PaletteWindow::ReloadSettings(Map* map) {
if (terrain_palette) {
terrain_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_TERRAIN_STYLE)));
terrain_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR));
}
if (doodad_palette) {
doodad_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_DOODAD_STYLE)));
doodad_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_DOODAD_SIZEBAR));
}
if (house_palette) {
house_palette->SetMap(map);
house_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_HOUSE_SIZEBAR));
}
if (waypoint_palette) {
waypoint_palette->SetMap(map);
}
if (item_palette) {
item_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_ITEM_STYLE)));
item_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_ITEM_SIZEBAR));
}
if (collection_palette) {
collection_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_COLLECTION_STYLE)));
collection_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR));
}
if (raw_palette) {
raw_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_RAW_STYLE)));
raw_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_RAW_SIZEBAR));
}
InvalidateContents();
}
void PaletteWindow::LoadCurrentContents() {
if (!choicebook) {
return;
}
PalettePanel* panel = dynamic_cast(choicebook->GetCurrentPage());
panel->LoadCurrentContents();
Fit();
Refresh();
Update();
}
void PaletteWindow::InvalidateContents() {
if (!choicebook) {
return;
}
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
PalettePanel* panel = dynamic_cast(choicebook->GetPage(iz));
panel->InvalidateContents();
}
LoadCurrentContents();
if (creature_palette) {
creature_palette->OnUpdate();
}
if (house_palette) {
house_palette->OnUpdate();
}
if (waypoint_palette) {
waypoint_palette->OnUpdate();
}
}
void PaletteWindow::SelectPage(PaletteType id) {
if (!choicebook) {
return;
}
if (id == GetSelectedPage()) {
return;
}
// First notify the current page that it's being switched out
PalettePanel* currentPanel = dynamic_cast(choicebook->GetCurrentPage());
if (currentPanel) {
currentPanel->OnSwitchOut();
}
// Find and select the new page
for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) {
PalettePanel* panel = dynamic_cast(choicebook->GetPage(iz));
if (panel->GetType() == id) {
choicebook->SetSelection(iz);
panel->OnSwitchIn();
break;
}
}
}
Brush* PaletteWindow::GetSelectedBrush() const {
if (!choicebook) {
return nullptr;
}
PalettePanel* panel = dynamic_cast(choicebook->GetCurrentPage());
return panel->GetSelectedBrush();
}
int PaletteWindow::GetSelectedBrushSize() const {
if (!choicebook) {
return 0;
}
PalettePanel* panel = dynamic_cast(choicebook->GetCurrentPage());
return panel->GetSelectedBrushSize();
}
PaletteType PaletteWindow::GetSelectedPage() const {
if (!choicebook) {
return TILESET_UNKNOWN;
}
PalettePanel* panel = dynamic_cast(choicebook->GetCurrentPage());
ASSERT(panel);
return panel->GetType();
}
bool PaletteWindow::OnSelectBrush(const Brush* whatbrush, PaletteType primary) {
if (!choicebook || !whatbrush) {
return false;
}
if (whatbrush->isHouse() && house_palette) {
house_palette->SelectBrush(whatbrush);
SelectPage(TILESET_HOUSE);
return true;
}
switch (primary) {
case TILESET_TERRAIN: {
// This is already searched first
break;
}
case TILESET_DOODAD: {
// Ok, search doodad before terrain
if (doodad_palette && doodad_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_DOODAD);
return true;
}
break;
}
case TILESET_COLLECTION: {
if (collection_palette && collection_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_COLLECTION);
return true;
}
}
case TILESET_ITEM: {
if (item_palette && item_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_ITEM);
return true;
}
break;
}
case TILESET_CREATURE: {
if (creature_palette && creature_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_CREATURE);
return true;
}
break;
}
case TILESET_RAW: {
if (raw_palette && raw_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_RAW);
return true;
}
break;
}
default:
break;
}
// Test if it's a terrain brush
if (terrain_palette && terrain_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_TERRAIN);
return true;
}
// Test if it's a doodad brush
if (primary != TILESET_DOODAD) {
if (doodad_palette && doodad_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_DOODAD);
return true;
}
}
// Test if it's an item brush
if (primary != TILESET_ITEM) {
if (item_palette && item_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_ITEM);
return true;
}
}
// Test if it's a creature brush
if (primary != TILESET_CREATURE) {
if (creature_palette && creature_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_CREATURE);
return true;
}
}
// Test if it's a raw brush
if (primary != TILESET_RAW) {
if (raw_palette && raw_palette->SelectBrush(whatbrush)) {
SelectPage(TILESET_RAW);
return true;
}
}
return false;
}
void PaletteWindow::OnSwitchingPage(wxChoicebookEvent& event) {
event.Skip();
if (!choicebook) {
return;
}
wxWindow* old_page = choicebook->GetPage(choicebook->GetSelection());
PalettePanel* old_panel = dynamic_cast(old_page);
if (old_panel) {
old_panel->OnSwitchOut();
}
wxWindow* page = choicebook->GetPage(event.GetSelection());
PalettePanel* panel = dynamic_cast(page);
if (panel) {
panel->OnSwitchIn();
}
}
void PaletteWindow::OnPageChanged(wxChoicebookEvent& event) {
if (!choicebook) {
return;
}
g_gui.SelectBrush();
}
void PaletteWindow::OnUpdateBrushSize(BrushShape shape, int size) {
if (!choicebook) {
return;
}
PalettePanel* page = dynamic_cast(choicebook->GetCurrentPage());
ASSERT(page);
page->OnUpdateBrushSize(shape, size);
}
void PaletteWindow::OnUpdate(Map* map) {
if (creature_palette) {
creature_palette->OnUpdate();
}
if (house_palette) {
house_palette->SetMap(map);
}
if (waypoint_palette) {
waypoint_palette->SetMap(map);
waypoint_palette->OnUpdate();
}
}
void PaletteWindow::OnKey(wxKeyEvent& event) {
if (g_gui.GetCurrentTab() != nullptr) {
g_gui.GetCurrentMapTab()->GetEventHandler()->AddPendingEvent(event);
}
}
void PaletteWindow::OnClose(wxCloseEvent& event) {
if (!event.CanVeto()) {
// We can't do anything! This sucks!
// (application is closed, we have to destroy ourselves)
Destroy();
} else {
Show(false);
event.Veto(true);
}
}
void PaletteWindow::OnActionIDChange(wxCommandEvent& event) {
wxString value = action_id_input->GetValue();
long val;
if (value.ToLong(&val)) {
if (val >= 0 && val <= 65535) {
action_id = static_cast(val);
} else {
// Reset to previous valid value
action_id_input->SetValue(wxString::Format("%d", action_id));
}
} else {
// Reset to previous valid value
action_id_input->SetValue(wxString::Format("%d", action_id));
}
}
void PaletteWindow::OnActionIDToggle(wxCommandEvent& event) {
action_id_enabled = action_id_checkbox->GetValue();
}