| @@ -0,0 +1,845 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #include "main.h" | |
| 19 | + | ||
| 20 | + | #include "palette_house.h" | |
| 21 | + | ||
| 22 | + | #include "settings.h" | |
| 23 | + | ||
| 24 | + | #include "brush.h" | |
| 25 | + | #include "editor.h" | |
| 26 | + | #include "map.h" | |
| 27 | + | ||
| 28 | + | #include "application.h" | |
| 29 | + | #include "map_display.h" | |
| 30 | + | ||
| 31 | + | #include "house_brush.h" | |
| 32 | + | #include "house_exit_brush.h" | |
| 33 | + | #include "spawn_brush.h" | |
| 34 | + | ||
| 35 | + | // ============================================================================ | |
| 36 | + | // House palette | |
| 37 | + | ||
| 38 | + | BEGIN_EVENT_TABLE(HousePalettePanel, PalettePanel) | |
| 39 | + | EVT_TIMER(PALETTE_LAYOUT_FIX_TIMER, HousePalettePanel::OnLayoutFixTimer) | |
| 40 | + | ||
| 41 | + | EVT_CHOICE(PALETTE_HOUSE_TOWN_CHOICE, HousePalettePanel::OnTownChange) | |
| 42 | + | ||
| 43 | + | EVT_LISTBOX(PALETTE_HOUSE_LISTBOX, HousePalettePanel::OnListBoxChange) | |
| 44 | + | EVT_LISTBOX_DCLICK(PALETTE_HOUSE_LISTBOX, HousePalettePanel::OnListBoxDoubleClick) | |
| 45 | + | EVT_CONTEXT_MENU(HousePalettePanel::OnListBoxContextMenu) | |
| 46 | + | ||
| 47 | + | EVT_BUTTON(PALETTE_HOUSE_ADD_HOUSE, HousePalettePanel::OnClickAddHouse) | |
| 48 | + | EVT_BUTTON(PALETTE_HOUSE_EDIT_HOUSE, HousePalettePanel::OnClickEditHouse) | |
| 49 | + | EVT_BUTTON(PALETTE_HOUSE_REMOVE_HOUSE, HousePalettePanel::OnClickRemoveHouse) | |
| 50 | + | ||
| 51 | + | EVT_TOGGLEBUTTON(PALETTE_HOUSE_BRUSH_BUTTON, HousePalettePanel::OnClickHouseBrushButton) | |
| 52 | + | EVT_TOGGLEBUTTON(PALETTE_HOUSE_SELECT_EXIT_BUTTON, HousePalettePanel::OnClickSelectExitButton) | |
| 53 | + | ||
| 54 | + | EVT_MENU(PALETTE_HOUSE_CONTEXT_MOVE_TO_TOWN, HousePalettePanel::OnMoveHouseToTown) | |
| 55 | + | END_EVENT_TABLE() | |
| 56 | + | ||
| 57 | + | HousePalettePanel::HousePalettePanel(wxWindow* parent, wxWindowID id) : | |
| 58 | + | PalettePanel(parent, id), | |
| 59 | + | map(nullptr), | |
| 60 | + | do_resize_on_display(true), | |
| 61 | + | fix_size_timer(this, PALETTE_LAYOUT_FIX_TIMER) { | |
| 62 | + | wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL); | |
| 63 | + | wxSizer* tmpsizer; | |
| 64 | + | ||
| 65 | + | wxSizer* sidesizer = newd wxStaticBoxSizer(wxVERTICAL, this, "Houses"); | |
| 66 | + | town_choice = newd wxChoice(this, PALETTE_HOUSE_TOWN_CHOICE, wxDefaultPosition, wxDefaultSize, (int)0, (const wxString*)nullptr); | |
| 67 | + | sidesizer->Add(town_choice, 0, wxEXPAND); | |
| 68 | + | ||
| 69 | + | house_list = newd SortableListBox(this, PALETTE_HOUSE_LISTBOX, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_EXTENDED); | |
| 70 | + | #ifdef __APPLE__ | |
| 71 | + | // Used for detecting a deselect | |
| 72 | + | house_list->Bind(wxEVT_LEFT_UP, &HousePalettePanel::OnListBoxClick, this); | |
| 73 | + | #endif | |
| 74 | + | // Bind context menu event to the list box | |
| 75 | + | house_list->Bind(wxEVT_CONTEXT_MENU, &HousePalettePanel::OnListBoxContextMenu, this); | |
| 76 | + | sidesizer->Add(house_list, 1, wxEXPAND); | |
| 77 | + | ||
| 78 | + | tmpsizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 79 | + | wxSizerFlags sizerFlags(1); | |
| 80 | + | tmpsizer->Add(add_house_button = newd wxButton(this, PALETTE_HOUSE_ADD_HOUSE, "Add", wxDefaultPosition, wxSize(50, -1)), sizerFlags); | |
| 81 | + | tmpsizer->Add(edit_house_button = newd wxButton(this, PALETTE_HOUSE_EDIT_HOUSE, "Edit", wxDefaultPosition, wxSize(50, -1)), sizerFlags); | |
| 82 | + | tmpsizer->Add(remove_house_button = newd wxButton(this, PALETTE_HOUSE_REMOVE_HOUSE, "Remove", wxDefaultPosition, wxSize(70, -1)), sizerFlags); | |
| 83 | + | sidesizer->Add(tmpsizer, wxSizerFlags(0).Right()); | |
| 84 | + | ||
| 85 | + | topsizer->Add(sidesizer, 1, wxEXPAND); | |
| 86 | + | ||
| 87 | + | // Temple position | |
| 88 | + | sidesizer = newd wxStaticBoxSizer(newd wxStaticBox(this, wxID_ANY, "Brushes", wxDefaultPosition, wxSize(150, 200)), wxVERTICAL); | |
| 89 | + | ||
| 90 | + | // sidesizer->Add(180, 1, wxEXPAND); | |
| 91 | + | ||
| 92 | + | tmpsizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 93 | + | house_brush_button = newd wxToggleButton(this, PALETTE_HOUSE_BRUSH_BUTTON, "House tiles"); | |
| 94 | + | tmpsizer->Add(house_brush_button); | |
| 95 | + | sidesizer->Add(tmpsizer, wxSizerFlags(1).Center()); | |
| 96 | + | ||
| 97 | + | tmpsizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 98 | + | select_position_button = newd wxToggleButton(this, PALETTE_HOUSE_SELECT_EXIT_BUTTON, "Select Exit"); | |
| 99 | + | tmpsizer->Add(select_position_button); | |
| 100 | + | sidesizer->Add(tmpsizer, wxSizerFlags(1).Center()); | |
| 101 | + | ||
| 102 | + | topsizer->Add(sidesizer, 0, wxEXPAND); | |
| 103 | + | ||
| 104 | + | SetSizerAndFit(topsizer); | |
| 105 | + | ||
| 106 | + | // Create context menu | |
| 107 | + | context_menu = newd wxMenu(); | |
| 108 | + | context_menu->Append(PALETTE_HOUSE_CONTEXT_MOVE_TO_TOWN, "Move to Town..."); | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | HousePalettePanel::~HousePalettePanel() { | |
| 112 | + | //// | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | void HousePalettePanel::SetMap(Map* m) { | |
| 116 | + | g_gui.house_brush->setHouse(nullptr); | |
| 117 | + | map = m; | |
| 118 | + | OnUpdate(); | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | void HousePalettePanel::OnSwitchIn() { | |
| 122 | + | PalettePanel::OnSwitchIn(); | |
| 123 | + | // Extremely ugly hack to fix layout issue | |
| 124 | + | if (do_resize_on_display) { | |
| 125 | + | fix_size_timer.Start(100, true); | |
| 126 | + | do_resize_on_display = false; | |
| 127 | + | } | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | void HousePalettePanel::OnLayoutFixTimer(wxTimerEvent& WXUNUSED(event)) { | |
| 131 | + | wxWindow* w = this; | |
| 132 | + | while ((w = w->GetParent()) && dynamic_cast<PaletteWindow*>(w) == nullptr) | |
| 133 | + | ; | |
| 134 | + | ||
| 135 | + | if (w) { | |
| 136 | + | w->SetSize(w->GetSize().GetWidth(), w->GetSize().GetHeight() + 1); | |
| 137 | + | w->SetSize(w->GetSize().GetWidth(), w->GetSize().GetHeight() - 1); | |
| 138 | + | } | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | void HousePalettePanel::SelectFirstBrush() { | |
| 142 | + | SelectHouseBrush(); | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | Brush* HousePalettePanel::GetSelectedBrush() const { | |
| 146 | + | if (select_position_button->GetValue()) { | |
| 147 | + | House* house = GetCurrentlySelectedHouse(); | |
| 148 | + | if (house) { | |
| 149 | + | g_gui.house_exit_brush->setHouse(house); | |
| 150 | + | } | |
| 151 | + | return (g_gui.house_exit_brush->getHouseID() != 0 ? g_gui.house_exit_brush : nullptr); | |
| 152 | + | } else if (house_brush_button->GetValue()) { | |
| 153 | + | g_gui.house_brush->setHouse(GetCurrentlySelectedHouse()); | |
| 154 | + | return (g_gui.house_brush->getHouseID() != 0 ? g_gui.house_brush : nullptr); | |
| 155 | + | } | |
| 156 | + | return nullptr; | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | bool HousePalettePanel::SelectBrush(const Brush* whatbrush) { | |
| 160 | + | if (!whatbrush) { | |
| 161 | + | return false; | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | if (whatbrush->isHouse() && map) { | |
| 165 | + | const HouseBrush* house_brush = static_cast<const HouseBrush*>(whatbrush); | |
| 166 | + | for (HouseMap::iterator house_iter = map->houses.begin(); house_iter != map->houses.end(); ++house_iter) { | |
| 167 | + | if (house_iter->second->getID() == house_brush->getHouseID()) { | |
| 168 | + | for (uint32_t i = 0; i < town_choice->GetCount(); ++i) { | |
| 169 | + | Town* town = reinterpret_cast<Town*>(town_choice->GetClientData(i)); | |
| 170 | + | // If it's "No Town" (nullptr) select it, or if it has the same town ID as the house | |
| 171 | + | if (town == nullptr || town->getID() == house_iter->second->townid) { | |
| 172 | + | SelectTown(i); | |
| 173 | + | for (uint32_t j = 0; j < house_list->GetCount(); ++j) { | |
| 174 | + | if (house_iter->second->getID() == reinterpret_cast<House*>(house_list->GetClientData(j))->getID()) { | |
| 175 | + | SelectHouse(j); | |
| 176 | + | return true; | |
| 177 | + | } | |
| 178 | + | } | |
| 179 | + | return true; | |
| 180 | + | } | |
| 181 | + | } | |
| 182 | + | } | |
| 183 | + | } | |
| 184 | + | } else if (whatbrush->isSpawn()) { | |
| 185 | + | SelectExitBrush(); | |
| 186 | + | } | |
| 187 | + | return false; | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | int HousePalettePanel::GetSelectedBrushSize() const { | |
| 191 | + | return 0; | |
| 192 | + | } | |
| 193 | + | ||
| 194 | + | PaletteType HousePalettePanel::GetType() const { | |
| 195 | + | return TILESET_HOUSE; | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | void HousePalettePanel::SelectTown(size_t index) { | |
| 199 | + | ASSERT(town_choice->GetCount() >= index); | |
| 200 | + | ||
| 201 | + | if (map == nullptr || town_choice->GetCount() == 0) { | |
| 202 | + | // No towns :( | |
| 203 | + | add_house_button->Enable(false); | |
| 204 | + | } else { | |
| 205 | + | Town* what_town = reinterpret_cast<Town*>(town_choice->GetClientData(index)); | |
| 206 | + | ||
| 207 | + | // Clear the old houselist | |
| 208 | + | house_list->Clear(); | |
| 209 | + | ||
| 210 | + | for (HouseMap::iterator house_iter = map->houses.begin(); house_iter != map->houses.end(); ++house_iter) { | |
| 211 | + | if (what_town) { | |
| 212 | + | if (house_iter->second->townid == what_town->getID()) { | |
| 213 | + | house_list->Append(wxstr(house_iter->second->getDescription()), house_iter->second); | |
| 214 | + | } | |
| 215 | + | } else { | |
| 216 | + | // "No Town" selected! | |
| 217 | + | if (map->towns.getTown(house_iter->second->townid) == nullptr) { | |
| 218 | + | // The town doesn't exist | |
| 219 | + | house_list->Append(wxstr(house_iter->second->getDescription()), house_iter->second); | |
| 220 | + | } | |
| 221 | + | } | |
| 222 | + | } | |
| 223 | + | house_list->Sort(); | |
| 224 | + | ||
| 225 | + | // Select first house | |
| 226 | + | SelectHouse(0); | |
| 227 | + | town_choice->SetSelection(index); | |
| 228 | + | add_house_button->Enable(what_town != nullptr); | |
| 229 | + | ASSERT(what_town == nullptr || add_house_button->IsEnabled() || !IsEnabled()); | |
| 230 | + | } | |
| 231 | + | } | |
| 232 | + | ||
| 233 | + | void HousePalettePanel::SelectHouse(size_t index) { | |
| 234 | + | ASSERT(house_list->GetCount() >= index); | |
| 235 | + | ||
| 236 | + | if (house_list->GetCount() > 0) { | |
| 237 | + | edit_house_button->Enable(true); | |
| 238 | + | remove_house_button->Enable(true); | |
| 239 | + | select_position_button->Enable(true); | |
| 240 | + | house_brush_button->Enable(true); | |
| 241 | + | ||
| 242 | + | // Clear any existing selections first | |
| 243 | + | for (unsigned int i = 0; i < house_list->GetCount(); ++i) { | |
| 244 | + | house_list->Deselect(i); | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // Select the house | |
| 248 | + | house_list->SetSelection(index); | |
| 249 | + | SelectHouseBrush(); | |
| 250 | + | } else { | |
| 251 | + | // No houses :( | |
| 252 | + | edit_house_button->Enable(false); | |
| 253 | + | remove_house_button->Enable(false); | |
| 254 | + | select_position_button->Enable(false); | |
| 255 | + | house_brush_button->Enable(false); | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | SelectHouseBrush(); | |
| 259 | + | g_gui.RefreshView(); | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | House* HousePalettePanel::GetCurrentlySelectedHouse() const { | |
| 263 | + | wxArrayInt selections; | |
| 264 | + | if (house_list->GetCount() > 0 && house_list->GetSelections(selections) > 0) { | |
| 265 | + | // Return the first selected house (for brush operations) | |
| 266 | + | return reinterpret_cast<House*>(house_list->GetClientData(selections[0])); | |
| 267 | + | } | |
| 268 | + | return nullptr; | |
| 269 | + | } | |
| 270 | + | ||
| 271 | + | void HousePalettePanel::SelectHouseBrush() { | |
| 272 | + | if (house_list->GetCount() > 0) { | |
| 273 | + | house_brush_button->SetValue(true); | |
| 274 | + | select_position_button->SetValue(false); | |
| 275 | + | } else { | |
| 276 | + | house_brush_button->SetValue(false); | |
| 277 | + | select_position_button->SetValue(false); | |
| 278 | + | } | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | void HousePalettePanel::SelectExitBrush() { | |
| 282 | + | if (house_list->GetCount() > 0) { | |
| 283 | + | house_brush_button->SetValue(false); | |
| 284 | + | select_position_button->SetValue(true); | |
| 285 | + | } | |
| 286 | + | } | |
| 287 | + | ||
| 288 | + | void HousePalettePanel::OnUpdate() { | |
| 289 | + | int old_town_selection = town_choice->GetSelection(); | |
| 290 | + | ||
| 291 | + | town_choice->Clear(); | |
| 292 | + | house_list->Clear(); | |
| 293 | + | ||
| 294 | + | if (map == nullptr) { | |
| 295 | + | return; | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | if (map->towns.count() != 0) { | |
| 299 | + | // Create choice control | |
| 300 | + | for (TownMap::iterator town_iter = map->towns.begin(); town_iter != map->towns.end(); ++town_iter) { | |
| 301 | + | town_choice->Append(wxstr(town_iter->second->getName()), town_iter->second); | |
| 302 | + | } | |
| 303 | + | town_choice->Append("No Town", (void*)(nullptr)); | |
| 304 | + | if (old_town_selection <= 0) { | |
| 305 | + | SelectTown(0); | |
| 306 | + | } else if ((size_t)old_town_selection <= town_choice->GetCount()) { | |
| 307 | + | SelectTown(old_town_selection); | |
| 308 | + | } else { | |
| 309 | + | SelectTown(old_town_selection - 1); | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | house_list->Enable(true); | |
| 313 | + | } else { | |
| 314 | + | town_choice->Append("No Town", (void*)(nullptr)); | |
| 315 | + | select_position_button->Enable(false); | |
| 316 | + | select_position_button->SetValue(false); | |
| 317 | + | house_brush_button->Enable(false); | |
| 318 | + | house_brush_button->SetValue(false); | |
| 319 | + | add_house_button->Enable(false); | |
| 320 | + | edit_house_button->Enable(false); | |
| 321 | + | remove_house_button->Enable(false); | |
| 322 | + | ||
| 323 | + | SelectTown(0); | |
| 324 | + | } | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | void HousePalettePanel::OnTownChange(wxCommandEvent& event) { | |
| 328 | + | SelectTown(event.GetSelection()); | |
| 329 | + | g_gui.SelectBrush(); | |
| 330 | + | } | |
| 331 | + | ||
| 332 | + | void HousePalettePanel::OnListBoxChange(wxCommandEvent& event) { | |
| 333 | + | // Check if there are multiple selections | |
| 334 | + | wxArrayInt selections; | |
| 335 | + | int count = house_list->GetSelections(selections); | |
| 336 | + | ||
| 337 | + | if (count == 1) { | |
| 338 | + | // Only one selection - handle it | |
| 339 | + | SelectHouse(event.GetSelection()); | |
| 340 | + | g_gui.SelectBrush(); | |
| 341 | + | } else if (count > 1) { | |
| 342 | + | // Multiple selections - enable/disable buttons appropriately | |
| 343 | + | edit_house_button->Enable(false); // Can only edit one house at a time | |
| 344 | + | remove_house_button->Enable(true); | |
| 345 | + | house_brush_button->Enable(true); | |
| 346 | + | select_position_button->Enable(true); | |
| 347 | + | } | |
| 348 | + | } | |
| 349 | + | ||
| 350 | + | void HousePalettePanel::OnListBoxDoubleClick(wxCommandEvent& event) { | |
| 351 | + | House* house = reinterpret_cast<House*>(event.GetClientData()); | |
| 352 | + | // I find it extremly unlikely that one actually wants the exit at 0,0,0, so just treat it as the null value | |
| 353 | + | if (house && house->getExit() != Position(0, 0, 0)) { | |
| 354 | + | g_gui.SetScreenCenterPosition(house->getExit()); | |
| 355 | + | } | |
| 356 | + | } | |
| 357 | + | ||
| 358 | + | void HousePalettePanel::OnListBoxContextMenu(wxContextMenuEvent& event) { | |
| 359 | + | if (map == nullptr || house_list->GetCount() == 0) { | |
| 360 | + | return; | |
| 361 | + | } | |
| 362 | + | ||
| 363 | + | // Only enable the menu if at least one house is selected | |
| 364 | + | wxArrayInt selections; | |
| 365 | + | if (house_list->GetSelections(selections) > 0) { | |
| 366 | + | // Get mouse position in screen coordinates | |
| 367 | + | wxPoint position = event.GetPosition(); | |
| 368 | + | // If position is (-1, -1), this means the event was generated from the keyboard (e.g., Shift+F10) | |
| 369 | + | // In this case, get the position of the first selected item | |
| 370 | + | if (position == wxPoint(-1, -1)) { | |
| 371 | + | // Get the client rect of the first selected item | |
| 372 | + | wxRect rect; | |
| 373 | + | house_list->GetItemRect(selections[0], rect); | |
| 374 | + | // Convert to screen coordinates | |
| 375 | + | position = house_list->ClientToScreen(rect.GetPosition()); | |
| 376 | + | } | |
| 377 | + | // Show context menu at the proper position | |
| 378 | + | PopupMenu(context_menu, house_list->ScreenToClient(position)); | |
| 379 | + | } | |
| 380 | + | } | |
| 381 | + | ||
| 382 | + | void HousePalettePanel::OnMoveHouseToTown(wxCommandEvent& event) { | |
| 383 | + | if (map == nullptr || map->towns.count() == 0) { | |
| 384 | + | return; | |
| 385 | + | } | |
| 386 | + | ||
| 387 | + | // Get all selected houses | |
| 388 | + | wxArrayInt selections; | |
| 389 | + | int count = house_list->GetSelections(selections); | |
| 390 | + | ||
| 391 | + | if (count == 0) { | |
| 392 | + | return; | |
| 393 | + | } | |
| 394 | + | ||
| 395 | + | // Create a more informative title based on number of selected houses | |
| 396 | + | wxString title = count == 1 ? "Move House to Town" : wxString::Format("Move %d Houses to Town", count); | |
| 397 | + | ||
| 398 | + | // Create dialog to select town | |
| 399 | + | wxDialog* dialog = newd wxDialog(this, wxID_ANY, title, wxDefaultPosition, wxSize(220, 150)); | |
| 400 | + | wxSizer* sizer = newd wxBoxSizer(wxVERTICAL); | |
| 401 | + | ||
| 402 | + | // Create choice control with towns | |
| 403 | + | wxChoice* town_list = newd wxChoice(dialog, wxID_ANY); | |
| 404 | + | for (TownMap::const_iterator town_iter = map->towns.begin(); town_iter != map->towns.end(); ++town_iter) { | |
| 405 | + | town_list->Append(wxstr(town_iter->second->getName()), town_iter->second); | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | if (town_list->GetCount() > 0) { | |
| 409 | + | town_list->SetSelection(0); | |
| 410 | + | } | |
| 411 | + | ||
| 412 | + | sizer->Add(newd wxStaticText(dialog, wxID_ANY, "Select destination town:"), 0, wxEXPAND | wxALL, 5); | |
| 413 | + | sizer->Add(town_list, 0, wxEXPAND | wxALL, 5); | |
| 414 | + | ||
| 415 | + | // Add OK/Cancel buttons | |
| 416 | + | wxSizer* button_sizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 417 | + | button_sizer->Add(newd wxButton(dialog, wxID_OK, "OK"), wxSizerFlags(1).Center()); | |
| 418 | + | button_sizer->Add(newd wxButton(dialog, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center()); | |
| 419 | + | sizer->Add(button_sizer, 0, wxALIGN_CENTER | wxALL, 5); | |
| 420 | + | ||
| 421 | + | dialog->SetSizer(sizer); | |
| 422 | + | ||
| 423 | + | // Show dialog | |
| 424 | + | if (dialog->ShowModal() == wxID_OK) { | |
| 425 | + | if (town_list->GetSelection() != wxNOT_FOUND) { | |
| 426 | + | Town* town = reinterpret_cast<Town*>(town_list->GetClientData(town_list->GetSelection())); | |
| 427 | + | if (town) { | |
| 428 | + | // Change town for each selected house | |
| 429 | + | for (size_t i = 0; i < selections.GetCount(); ++i) { | |
| 430 | + | House* house = reinterpret_cast<House*>(house_list->GetClientData(selections[i])); | |
| 431 | + | if (house) { | |
| 432 | + | house->townid = town->getID(); | |
| 433 | + | } | |
| 434 | + | } | |
| 435 | + | ||
| 436 | + | // Refresh the house list | |
| 437 | + | RefreshHouseList(); | |
| 438 | + | ||
| 439 | + | // Refresh the map | |
| 440 | + | g_gui.RefreshView(); | |
| 441 | + | } | |
| 442 | + | } | |
| 443 | + | } | |
| 444 | + | ||
| 445 | + | dialog->Destroy(); | |
| 446 | + | } | |
| 447 | + | ||
| 448 | + | void HousePalettePanel::RefreshHouseList() { | |
| 449 | + | // Preserve current selections | |
| 450 | + | wxArrayInt selections; | |
| 451 | + | house_list->GetSelections(selections); | |
| 452 | + | std::vector<uint32_t> selected_house_ids; | |
| 453 | + | ||
| 454 | + | // Store IDs of all selected houses | |
| 455 | + | for (size_t i = 0; i < selections.GetCount(); ++i) { | |
| 456 | + | House* house = reinterpret_cast<House*>(house_list->GetClientData(selections[i])); | |
| 457 | + | if (house) { | |
| 458 | + | selected_house_ids.push_back(house->getID()); | |
| 459 | + | } | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | // Reload the house list | |
| 463 | + | Town* what_town = reinterpret_cast<Town*>(town_choice->GetClientData(town_choice->GetSelection())); | |
| 464 | + | ||
| 465 | + | // Clear the old houselist | |
| 466 | + | house_list->Clear(); | |
| 467 | + | ||
| 468 | + | for (HouseMap::iterator house_iter = map->houses.begin(); house_iter != map->houses.end(); ++house_iter) { | |
| 469 | + | if (what_town) { | |
| 470 | + | if (house_iter->second->townid == what_town->getID()) { | |
| 471 | + | house_list->Append(wxstr(house_iter->second->getDescription()), house_iter->second); | |
| 472 | + | } | |
| 473 | + | } else { | |
| 474 | + | // "No Town" selected! | |
| 475 | + | if (map->towns.getTown(house_iter->second->townid) == nullptr) { | |
| 476 | + | // The town doesn't exist | |
| 477 | + | house_list->Append(wxstr(house_iter->second->getDescription()), house_iter->second); | |
| 478 | + | } | |
| 479 | + | } | |
| 480 | + | } | |
| 481 | + | house_list->Sort(); | |
| 482 | + | ||
| 483 | + | // Try to restore previous selections | |
| 484 | + | bool foundAny = false; | |
| 485 | + | for (unsigned int i = 0; i < house_list->GetCount(); ++i) { | |
| 486 | + | House* house = reinterpret_cast<House*>(house_list->GetClientData(i)); | |
| 487 | + | if (house) { | |
| 488 | + | for (uint32_t selected_id : selected_house_ids) { | |
| 489 | + | if (house->getID() == selected_id) { | |
| 490 | + | house_list->SetSelection(i); | |
| 491 | + | foundAny = true; | |
| 492 | + | break; | |
| 493 | + | } | |
| 494 | + | } | |
| 495 | + | } | |
| 496 | + | } | |
| 497 | + | ||
| 498 | + | // If no selections could be restored, ensure buttons are in correct state | |
| 499 | + | if (!foundAny && house_list->GetCount() > 0) { | |
| 500 | + | SelectHouse(0); | |
| 501 | + | } else if (!foundAny) { | |
| 502 | + | edit_house_button->Enable(false); | |
| 503 | + | remove_house_button->Enable(false); | |
| 504 | + | select_position_button->Enable(false); | |
| 505 | + | house_brush_button->Enable(false); | |
| 506 | + | } | |
| 507 | + | } | |
| 508 | + | ||
| 509 | + | void HousePalettePanel::OnClickHouseBrushButton(wxCommandEvent& event) { | |
| 510 | + | SelectHouseBrush(); | |
| 511 | + | g_gui.SelectBrush(); | |
| 512 | + | } | |
| 513 | + | ||
| 514 | + | void HousePalettePanel::OnClickSelectExitButton(wxCommandEvent& event) { | |
| 515 | + | SelectExitBrush(); | |
| 516 | + | g_gui.SelectBrush(); | |
| 517 | + | } | |
| 518 | + | ||
| 519 | + | void HousePalettePanel::OnClickAddHouse(wxCommandEvent& event) { | |
| 520 | + | if (map == nullptr) { | |
| 521 | + | return; | |
| 522 | + | } | |
| 523 | + | ||
| 524 | + | House* new_house = newd House(*map); | |
| 525 | + | new_house->setID(map->houses.getEmptyID()); | |
| 526 | + | ||
| 527 | + | std::ostringstream os; | |
| 528 | + | os << "Unnamed House #" << new_house->getID(); | |
| 529 | + | new_house->name = os.str(); | |
| 530 | + | Town* town = reinterpret_cast<Town*>(town_choice->GetClientData(town_choice->GetSelection())); | |
| 531 | + | ||
| 532 | + | ASSERT(town); | |
| 533 | + | new_house->townid = town->getID(); | |
| 534 | + | ||
| 535 | + | map->houses.addHouse(new_house); | |
| 536 | + | house_list->Append(wxstr(new_house->getDescription()), new_house); | |
| 537 | + | SelectHouse(house_list->FindString(wxstr(new_house->getDescription()))); | |
| 538 | + | g_gui.SelectBrush(); | |
| 539 | + | refresh_timer.Start(300, true); | |
| 540 | + | } | |
| 541 | + | ||
| 542 | + | void HousePalettePanel::OnClickEditHouse(wxCommandEvent& event) { | |
| 543 | + | if (house_list->GetCount() == 0) { | |
| 544 | + | return; | |
| 545 | + | } | |
| 546 | + | if (map == nullptr) { | |
| 547 | + | return; | |
| 548 | + | } | |
| 549 | + | ||
| 550 | + | // Only edit if a single house is selected | |
| 551 | + | wxArrayInt selections; | |
| 552 | + | if (house_list->GetSelections(selections) != 1) { | |
| 553 | + | wxMessageBox("Please select only one house to edit.", "Edit House", wxOK | wxICON_INFORMATION); | |
| 554 | + | return; | |
| 555 | + | } | |
| 556 | + | ||
| 557 | + | int selection = selections[0]; | |
| 558 | + | House* house = reinterpret_cast<House*>(house_list->GetClientData(selection)); | |
| 559 | + | if (house) { | |
| 560 | + | wxDialog* d = newd EditHouseDialog(g_gui.root, map, house); | |
| 561 | + | int ret = d->ShowModal(); | |
| 562 | + | if (ret == 1) { | |
| 563 | + | // Something changed, change name of house | |
| 564 | + | house_list->SetString(selection, wxstr(house->getDescription())); | |
| 565 | + | house_list->Sort(); | |
| 566 | + | ||
| 567 | + | // refresh house list for town | |
| 568 | + | SelectTown(town_choice->GetSelection()); | |
| 569 | + | g_gui.SelectBrush(); | |
| 570 | + | refresh_timer.Start(300, true); | |
| 571 | + | } | |
| 572 | + | } | |
| 573 | + | } | |
| 574 | + | ||
| 575 | + | void HousePalettePanel::OnClickRemoveHouse(wxCommandEvent& event) { | |
| 576 | + | wxArrayInt selections; | |
| 577 | + | int count = house_list->GetSelections(selections); | |
| 578 | + | ||
| 579 | + | if (count == 0) { | |
| 580 | + | return; | |
| 581 | + | } | |
| 582 | + | ||
| 583 | + | // Ask for confirmation when removing multiple houses | |
| 584 | + | if (count > 1) { | |
| 585 | + | wxString message = wxString::Format("Are you sure you want to remove %d houses?", count); | |
| 586 | + | int response = wxMessageBox(message, "Confirm Removal", wxYES_NO | wxICON_QUESTION); | |
| 587 | + | if (response != wxYES) { | |
| 588 | + | return; | |
| 589 | + | } | |
| 590 | + | } | |
| 591 | + | ||
| 592 | + | // Sort selections in descending order to avoid index issues when deleting | |
| 593 | + | std::sort(selections.begin(), selections.end(), std::greater<int>()); | |
| 594 | + | ||
| 595 | + | // Remove all selected houses | |
| 596 | + | for (size_t i = 0; i < selections.GetCount(); ++i) { | |
| 597 | + | int selection = selections[i]; | |
| 598 | + | House* house = reinterpret_cast<House*>(house_list->GetClientData(selection)); | |
| 599 | + | map->houses.removeHouse(house); | |
| 600 | + | house_list->Delete(selection); | |
| 601 | + | } | |
| 602 | + | ||
| 603 | + | refresh_timer.Start(300, true); | |
| 604 | + | ||
| 605 | + | // Select an appropriate remaining item if possible | |
| 606 | + | if (house_list->GetCount() > 0) { | |
| 607 | + | int new_selection = std::min(selections.back(), (int)house_list->GetCount() - 1); | |
| 608 | + | house_list->SetSelection(new_selection); | |
| 609 | + | edit_house_button->Enable(true); | |
| 610 | + | remove_house_button->Enable(true); | |
| 611 | + | select_position_button->Enable(true); | |
| 612 | + | house_brush_button->Enable(true); | |
| 613 | + | } else { | |
| 614 | + | select_position_button->Enable(false); | |
| 615 | + | select_position_button->SetValue(false); | |
| 616 | + | house_brush_button->Enable(false); | |
| 617 | + | house_brush_button->SetValue(false); | |
| 618 | + | edit_house_button->Enable(false); | |
| 619 | + | remove_house_button->Enable(false); | |
| 620 | + | } | |
| 621 | + | ||
| 622 | + | g_gui.SelectBrush(); | |
| 623 | + | g_gui.RefreshView(); | |
| 624 | + | } | |
| 625 | + | ||
| 626 | + | #ifdef __APPLE__ | |
| 627 | + | // On wxMac it is possible to deselect a wxListBox. (Unlike on the other platforms) | |
| 628 | + | // EVT_LISTBOX is not triggered when the deselection is happening. http://trac.wxwidgets.org/ticket/15603 | |
| 629 | + | // Here we find out if the listbox was deselected using a normal mouse up event so we know when to disable the buttons and brushes. | |
| 630 | + | void HousePalettePanel::OnListBoxClick(wxMouseEvent& event) { | |
| 631 | + | if (house_list->GetSelection() == wxNOT_FOUND) { | |
| 632 | + | select_position_button->Enable(false); | |
| 633 | + | select_position_button->SetValue(false); | |
| 634 | + | house_brush_button->Enable(false); | |
| 635 | + | house_brush_button->SetValue(false); | |
| 636 | + | edit_house_button->Enable(false); | |
| 637 | + | remove_house_button->Enable(false); | |
| 638 | + | g_gui.SelectBrush(); | |
| 639 | + | } | |
| 640 | + | } | |
| 641 | + | #endif | |
| 642 | + | ||
| 643 | + | // ============================================================================ | |
| 644 | + | // House Edit Dialog | |
| 645 | + | ||
| 646 | + | BEGIN_EVENT_TABLE(EditHouseDialog, wxDialog) | |
| 647 | + | EVT_SET_FOCUS(EditHouseDialog::OnFocusChange) | |
| 648 | + | EVT_BUTTON(wxID_OK, EditHouseDialog::OnClickOK) | |
| 649 | + | EVT_BUTTON(wxID_CANCEL, EditHouseDialog::OnClickCancel) | |
| 650 | + | END_EVENT_TABLE() | |
| 651 | + | ||
| 652 | + | EditHouseDialog::EditHouseDialog(wxWindow* parent, Map* map, House* house) : | |
| 653 | + | // window title | |
| 654 | + | wxDialog(parent, wxID_ANY, "House Properties", wxDefaultPosition, wxSize(250, 160)), | |
| 655 | + | map(map), | |
| 656 | + | what_house(house) { | |
| 657 | + | ASSERT(map); | |
| 658 | + | ASSERT(house); | |
| 659 | + | ||
| 660 | + | // main properties window box | |
| 661 | + | wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL); | |
| 662 | + | wxSizer* boxsizer = newd wxStaticBoxSizer(wxVERTICAL, this, "House Properties"); | |
| 663 | + | wxFlexGridSizer* housePropContainer = newd wxFlexGridSizer(2, 10, 10); | |
| 664 | + | housePropContainer->AddGrowableCol(1); | |
| 665 | + | ||
| 666 | + | wxFlexGridSizer* subsizer = newd wxFlexGridSizer(2, 10, 10); | |
| 667 | + | subsizer->AddGrowableCol(1); | |
| 668 | + | ||
| 669 | + | house_name = wxstr(house->name); | |
| 670 | + | house_id = i2ws(house->getID()); | |
| 671 | + | house_rent = i2ws(house->rent); | |
| 672 | + | ||
| 673 | + | // House name | |
| 674 | + | subsizer->Add(newd wxStaticText(this, wxID_ANY, "Name:"), wxSizerFlags(0).Border(wxLEFT, 5)); | |
| 675 | + | name_field = newd wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxSize(160, 20), 0, wxTextValidator(wxFILTER_ASCII, &house_name)); | |
| 676 | + | subsizer->Add(name_field, wxSizerFlags(1).Expand()); | |
| 677 | + | ||
| 678 | + | // Town selection menu | |
| 679 | + | subsizer->Add(newd wxStaticText(this, wxID_ANY, "Town:"), wxSizerFlags(0).Border(wxLEFT, 5)); | |
| 680 | + | ||
| 681 | + | const Towns& towns = map->towns; | |
| 682 | + | ||
| 683 | + | town_id_field = newd wxChoice(this, wxID_ANY); | |
| 684 | + | int to_select_index = 0; | |
| 685 | + | uint32_t houseTownId = house->townid; | |
| 686 | + | ||
| 687 | + | if (towns.count() > 0) { | |
| 688 | + | bool found = false; | |
| 689 | + | for (TownMap::const_iterator town_iter = towns.begin(); town_iter != towns.end(); ++town_iter) { | |
| 690 | + | if (town_iter->second->getID() == houseTownId) { | |
| 691 | + | found = true; | |
| 692 | + | } | |
| 693 | + | town_id_field->Append(wxstr(town_iter->second->getName()), newd int(town_iter->second->getID())); | |
| 694 | + | if (!found) { | |
| 695 | + | ++to_select_index; | |
| 696 | + | } | |
| 697 | + | } | |
| 698 | + | ||
| 699 | + | if (!found) { | |
| 700 | + | if (houseTownId != 0) { | |
| 701 | + | town_id_field->Append("Undefined Town (id:" + i2ws(houseTownId) + ")", newd int(houseTownId)); | |
| 702 | + | ++to_select_index; | |
| 703 | + | } | |
| 704 | + | } | |
| 705 | + | } | |
| 706 | + | town_id_field->SetSelection(to_select_index); | |
| 707 | + | subsizer->Add(town_id_field, wxSizerFlags(1).Expand()); | |
| 708 | + | // end town selection | |
| 709 | + | ||
| 710 | + | // Rent price | |
| 711 | + | subsizer->Add(newd wxStaticText(this, wxID_ANY, "Rent:"), wxSizerFlags(0).Border(wxLEFT, 5)); | |
| 712 | + | rent_field = newd wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxSize(160, 20), 0, wxTextValidator(wxFILTER_NUMERIC, &house_rent)); | |
| 713 | + | subsizer->Add(rent_field, wxSizerFlags(1).Expand()); | |
| 714 | + | ||
| 715 | + | // Right column | |
| 716 | + | wxFlexGridSizer* subsizerRight = newd wxFlexGridSizer(1, 10, 10); | |
| 717 | + | ||
| 718 | + | // house ID | |
| 719 | + | wxFlexGridSizer* houseSizer = newd wxFlexGridSizer(2, 10, 10); | |
| 720 | + | ||
| 721 | + | houseSizer->Add(newd wxStaticText(this, wxID_ANY, "ID:"), wxSizerFlags(0).Center()); | |
| 722 | + | id_field = newd wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxSize(40, 20), wxSP_ARROW_KEYS, 1, 0xFFFF, house->getID()); | |
| 723 | + | // id_field->Enable(false); | |
| 724 | + | houseSizer->Add(id_field, wxSizerFlags(1).Expand()); | |
| 725 | + | subsizerRight->Add(houseSizer, wxSizerFlags(1).Expand()); | |
| 726 | + | ||
| 727 | + | // Guildhall checkbox | |
| 728 | + | wxSizer* checkbox_sub_sizer = newd wxBoxSizer(wxVERTICAL); | |
| 729 | + | checkbox_sub_sizer->AddSpacer(4); | |
| 730 | + | ||
| 731 | + | guildhall_field = newd wxCheckBox(this, wxID_ANY, "Guildhall"); | |
| 732 | + | ||
| 733 | + | checkbox_sub_sizer->Add(guildhall_field); | |
| 734 | + | subsizerRight->Add(checkbox_sub_sizer); | |
| 735 | + | guildhall_field->SetValue(house->guildhall); | |
| 736 | + | ||
| 737 | + | // construct the layout | |
| 738 | + | housePropContainer->Add(subsizer, wxSizerFlags(5).Expand()); | |
| 739 | + | housePropContainer->Add(subsizerRight, wxSizerFlags(5).Expand()); | |
| 740 | + | boxsizer->Add(housePropContainer, wxSizerFlags(5).Expand().Border(wxTOP | wxBOTTOM, 10)); | |
| 741 | + | topsizer->Add(boxsizer, wxSizerFlags(0).Expand().Border(wxRIGHT | wxLEFT, 20)); | |
| 742 | + | ||
| 743 | + | // OK/Cancel buttons | |
| 744 | + | wxSizer* buttonsSizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 745 | + | buttonsSizer->Add(newd wxButton(this, wxID_OK, "OK"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); | |
| 746 | + | buttonsSizer->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10)); | |
| 747 | + | topsizer->Add(buttonsSizer, wxSizerFlags(0).Center().Border(wxLEFT | wxRIGHT, 20)); | |
| 748 | + | ||
| 749 | + | SetSizerAndFit(topsizer); | |
| 750 | + | } | |
| 751 | + | ||
| 752 | + | EditHouseDialog::~EditHouseDialog() { | |
| 753 | + | //// | |
| 754 | + | } | |
| 755 | + | ||
| 756 | + | void EditHouseDialog::OnFocusChange(wxFocusEvent& event) { | |
| 757 | + | wxWindow* win = event.GetWindow(); | |
| 758 | + | if (wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>(win)) { | |
| 759 | + | spin->SetSelection(-1, -1); | |
| 760 | + | } else if (wxTextCtrl* text = dynamic_cast<wxTextCtrl*>(win)) { | |
| 761 | + | text->SetSelection(-1, -1); | |
| 762 | + | } | |
| 763 | + | } | |
| 764 | + | ||
| 765 | + | void EditHouseDialog::OnClickOK(wxCommandEvent& WXUNUSED(event)) { | |
| 766 | + | if (Validate() && TransferDataFromWindow()) { | |
| 767 | + | // Verify the new rent information | |
| 768 | + | long new_house_rent; | |
| 769 | + | house_rent.ToLong(&new_house_rent); | |
| 770 | + | if (new_house_rent < 0) { | |
| 771 | + | g_gui.PopupDialog(this, "Error", "House rent cannot be less than 0.", wxOK); | |
| 772 | + | return; | |
| 773 | + | } | |
| 774 | + | ||
| 775 | + | // Verify the new house id | |
| 776 | + | uint32_t new_house_id = id_field->GetValue(); | |
| 777 | + | if (new_house_id < 1) { | |
| 778 | + | g_gui.PopupDialog(this, "Error", "House id cannot be less than 1.", wxOK); | |
| 779 | + | return; | |
| 780 | + | } | |
| 781 | + | ||
| 782 | + | // Verify the new house name | |
| 783 | + | if (house_name.length() == 0) { | |
| 784 | + | g_gui.PopupDialog(this, "Error", "House name cannot be empty.", wxOK); | |
| 785 | + | return; | |
| 786 | + | } | |
| 787 | + | ||
| 788 | + | // Verify town selection | |
| 789 | + | if (town_id_field->GetSelection() == wxNOT_FOUND) { | |
| 790 | + | g_gui.PopupDialog(this, "Error", "You must select a town for this house.", wxOK); | |
| 791 | + | return; | |
| 792 | + | } | |
| 793 | + | ||
| 794 | + | int* new_town_id = reinterpret_cast<int*>(town_id_field->GetClientData(town_id_field->GetSelection())); | |
| 795 | + | if (!new_town_id) { | |
| 796 | + | g_gui.PopupDialog(this, "Error", "Invalid town selection.", wxOK); | |
| 797 | + | return; | |
| 798 | + | } | |
| 799 | + | ||
| 800 | + | if (g_settings.getInteger(Config::WARN_FOR_DUPLICATE_ID)) { | |
| 801 | + | Houses& houses = map->houses; | |
| 802 | + | for (HouseMap::const_iterator house_iter = houses.begin(); house_iter != houses.end(); ++house_iter) { | |
| 803 | + | House* house = house_iter->second; | |
| 804 | + | ASSERT(house); | |
| 805 | + | ||
| 806 | + | if (house->getID() == new_house_id && new_house_id != what_house->getID()) { | |
| 807 | + | g_gui.PopupDialog(this, "Error", "This house id is already in use.", wxOK); | |
| 808 | + | return; | |
| 809 | + | } | |
| 810 | + | ||
| 811 | + | if (wxstr(house->name) == house_name && house->getID() != what_house->getID()) { | |
| 812 | + | int ret = g_gui.PopupDialog(this, "Warning", "This house name is already in use, are you sure you want to continue?", wxYES | wxNO); | |
| 813 | + | if (ret == wxID_NO) { | |
| 814 | + | return; | |
| 815 | + | } | |
| 816 | + | } | |
| 817 | + | } | |
| 818 | + | } | |
| 819 | + | ||
| 820 | + | if (new_house_id != what_house->getID()) { | |
| 821 | + | int ret = g_gui.PopupDialog(this, "Warning", "Changing existing house ids on a production server WILL HAVE DATABASE CONSEQUENCES such as potential item loss, house owner change or invalidating guest lists.\nYou are doing it at own risk!\n\nAre you ABSOLUTELY sure you want to continue?", wxYES | wxNO); | |
| 822 | + | if (ret == wxID_NO) { | |
| 823 | + | return; | |
| 824 | + | } | |
| 825 | + | ||
| 826 | + | uint32_t old_house_id = what_house->getID(); | |
| 827 | + | ||
| 828 | + | map->convertHouseTiles(old_house_id, new_house_id); | |
| 829 | + | map->houses.changeId(what_house, new_house_id); | |
| 830 | + | } | |
| 831 | + | ||
| 832 | + | // Transfer to house | |
| 833 | + | what_house->name = nstr(house_name); | |
| 834 | + | what_house->rent = new_house_rent; | |
| 835 | + | what_house->guildhall = guildhall_field->GetValue(); | |
| 836 | + | what_house->townid = *new_town_id; | |
| 837 | + | ||
| 838 | + | EndModal(1); | |
| 839 | + | } | |
| 840 | + | } | |
| 841 | + | ||
| 842 | + | void EditHouseDialog::OnClickCancel(wxCommandEvent& WXUNUSED(event)) { | |
| 843 | + | // Just close this window | |
| 844 | + | EndModal(0); | |
| 845 | + | } |
| @@ -0,0 +1,123 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_PALETTE_HOUSE_H_ | |
| 19 | + | #define RME_PALETTE_HOUSE_H_ | |
| 20 | + | ||
| 21 | + | #include "palette_common.h" | |
| 22 | + | ||
| 23 | + | class House; | |
| 24 | + | ||
| 25 | + | class HousePalettePanel : public PalettePanel { | |
| 26 | + | public: | |
| 27 | + | HousePalettePanel(wxWindow* parent, wxWindowID id = wxID_ANY); | |
| 28 | + | ~HousePalettePanel(); | |
| 29 | + | ||
| 30 | + | PaletteType GetType() const; | |
| 31 | + | ||
| 32 | + | // Select the first brush | |
| 33 | + | void SelectFirstBrush(); | |
| 34 | + | // Returns the currently selected brush (first brush if panel is not loaded) | |
| 35 | + | Brush* GetSelectedBrush() const; | |
| 36 | + | // Returns the currently selected brush size | |
| 37 | + | int GetSelectedBrushSize() const; | |
| 38 | + | // Select the brush in the parameter, this only changes the look of the panel | |
| 39 | + | bool SelectBrush(const Brush* whatbrush); | |
| 40 | + | ||
| 41 | + | // Called sometimes? | |
| 42 | + | void OnUpdate(); | |
| 43 | + | // Called when this page is about to be displayed | |
| 44 | + | void OnSwitchIn(); | |
| 45 | + | ||
| 46 | + | void OnLayoutFixTimer(wxTimerEvent& event); | |
| 47 | + | ||
| 48 | + | void SetMap(Map* map); | |
| 49 | + | ||
| 50 | + | protected: | |
| 51 | + | // Internal use | |
| 52 | + | void SaveHouse(); | |
| 53 | + | void SelectTown(size_t index); | |
| 54 | + | void SelectHouse(size_t index); | |
| 55 | + | ||
| 56 | + | House* GetCurrentlySelectedHouse() const; | |
| 57 | + | ||
| 58 | + | void SelectHouseBrush(); | |
| 59 | + | void SelectExitBrush(); | |
| 60 | + | void RefreshHouseList(); | |
| 61 | + | ||
| 62 | + | public: | |
| 63 | + | // wxWidgets event handling | |
| 64 | + | void OnTownChange(wxCommandEvent& event); | |
| 65 | + | void OnListBoxChange(wxCommandEvent& event); | |
| 66 | + | void OnListBoxDoubleClick(wxCommandEvent& event); | |
| 67 | + | void OnClickHouseBrushButton(wxCommandEvent& event); | |
| 68 | + | void OnClickSelectExitButton(wxCommandEvent& event); | |
| 69 | + | void OnClickAddHouse(wxCommandEvent& event); | |
| 70 | + | void OnClickEditHouse(wxCommandEvent& event); | |
| 71 | + | void OnClickRemoveHouse(wxCommandEvent& event); | |
| 72 | + | void OnListBoxContextMenu(wxContextMenuEvent& event); | |
| 73 | + | void OnMoveHouseToTown(wxCommandEvent& event); | |
| 74 | + | ||
| 75 | + | #ifdef __APPLE__ | |
| 76 | + | // Used for detecting a deselect | |
| 77 | + | void OnListBoxClick(wxMouseEvent& event); | |
| 78 | + | #endif | |
| 79 | + | ||
| 80 | + | protected: | |
| 81 | + | Map* map; | |
| 82 | + | wxChoice* town_choice; | |
| 83 | + | SortableListBox* house_list; | |
| 84 | + | wxToggleButton* house_brush_button; | |
| 85 | + | wxToggleButton* select_position_button; | |
| 86 | + | wxButton* add_house_button; | |
| 87 | + | wxButton* edit_house_button; | |
| 88 | + | wxButton* remove_house_button; | |
| 89 | + | wxMenu* context_menu; | |
| 90 | + | ||
| 91 | + | // Used for ugly hack | |
| 92 | + | bool do_resize_on_display; | |
| 93 | + | wxTimer fix_size_timer; | |
| 94 | + | ||
| 95 | + | DECLARE_EVENT_TABLE() | |
| 96 | + | }; | |
| 97 | + | ||
| 98 | + | class EditHouseDialog : public wxDialog { | |
| 99 | + | public: | |
| 100 | + | EditHouseDialog(wxWindow* parent, Map* map, House* house); | |
| 101 | + | virtual ~EditHouseDialog(); | |
| 102 | + | ||
| 103 | + | void OnFocusChange(wxFocusEvent&); | |
| 104 | + | ||
| 105 | + | void OnClickOK(wxCommandEvent&); | |
| 106 | + | void OnClickCancel(wxCommandEvent&); | |
| 107 | + | ||
| 108 | + | protected: | |
| 109 | + | Map* map; | |
| 110 | + | House* what_house; | |
| 111 | + | ||
| 112 | + | wxString house_name, house_id, house_rent; | |
| 113 | + | ||
| 114 | + | wxTextCtrl* name_field; | |
| 115 | + | wxChoice* town_id_field; | |
| 116 | + | wxSpinCtrl* id_field; | |
| 117 | + | wxTextCtrl* rent_field; | |
| 118 | + | wxCheckBox* guildhall_field; | |
| 119 | + | ||
| 120 | + | DECLARE_EVENT_TABLE(); | |
| 121 | + | }; | |
| 122 | + | ||
| 123 | + | #endif |
| @@ -0,0 +1,224 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | // ============================================================================ | |
| 19 | + | // Waypoint palette | |
| 20 | + | ||
| 21 | + | #include "main.h" | |
| 22 | + | ||
| 23 | + | #include "gui.h" | |
| 24 | + | #include "palette_waypoints.h" | |
| 25 | + | #include "waypoint_brush.h" | |
| 26 | + | #include "map.h" | |
| 27 | + | ||
| 28 | + | BEGIN_EVENT_TABLE(WaypointPalettePanel, PalettePanel) | |
| 29 | + | EVT_BUTTON(PALETTE_WAYPOINT_ADD_WAYPOINT, WaypointPalettePanel::OnClickAddWaypoint) | |
| 30 | + | EVT_BUTTON(PALETTE_WAYPOINT_REMOVE_WAYPOINT, WaypointPalettePanel::OnClickRemoveWaypoint) | |
| 31 | + | ||
| 32 | + | EVT_LIST_BEGIN_LABEL_EDIT(PALETTE_WAYPOINT_LISTBOX, WaypointPalettePanel::OnBeginEditWaypointLabel) | |
| 33 | + | EVT_LIST_END_LABEL_EDIT(PALETTE_WAYPOINT_LISTBOX, WaypointPalettePanel::OnEditWaypointLabel) | |
| 34 | + | EVT_LIST_ITEM_SELECTED(PALETTE_WAYPOINT_LISTBOX, WaypointPalettePanel::OnClickWaypoint) | |
| 35 | + | END_EVENT_TABLE() | |
| 36 | + | ||
| 37 | + | WaypointPalettePanel::WaypointPalettePanel(wxWindow* parent, wxWindowID id) : | |
| 38 | + | PalettePanel(parent, id), | |
| 39 | + | map(nullptr) { | |
| 40 | + | wxSizer* sidesizer = newd wxStaticBoxSizer(wxVERTICAL, this, "Waypoints"); | |
| 41 | + | ||
| 42 | + | waypoint_list = newd wxListCtrl(this, PALETTE_WAYPOINT_LISTBOX, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_EDIT_LABELS | wxLC_NO_HEADER); | |
| 43 | + | waypoint_list->InsertColumn(0, "UNNAMED", wxLIST_FORMAT_LEFT, 200); | |
| 44 | + | sidesizer->Add(waypoint_list, 1, wxEXPAND); | |
| 45 | + | ||
| 46 | + | wxSizer* tmpsizer = newd wxBoxSizer(wxHORIZONTAL); | |
| 47 | + | tmpsizer->Add(add_waypoint_button = newd wxButton(this, PALETTE_WAYPOINT_ADD_WAYPOINT, "Add", wxDefaultPosition, wxSize(50, -1)), 1, wxEXPAND); | |
| 48 | + | tmpsizer->Add(remove_waypoint_button = newd wxButton(this, PALETTE_WAYPOINT_REMOVE_WAYPOINT, "Remove", wxDefaultPosition, wxSize(70, -1)), 1, wxEXPAND); | |
| 49 | + | sidesizer->Add(tmpsizer, 0, wxEXPAND); | |
| 50 | + | ||
| 51 | + | SetSizerAndFit(sidesizer); | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | WaypointPalettePanel::~WaypointPalettePanel() { | |
| 55 | + | //// | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | void WaypointPalettePanel::OnSwitchIn() { | |
| 59 | + | PalettePanel::OnSwitchIn(); | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | void WaypointPalettePanel::OnSwitchOut() { | |
| 63 | + | PalettePanel::OnSwitchOut(); | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | void WaypointPalettePanel::SetMap(Map* m) { | |
| 67 | + | map = m; | |
| 68 | + | this->Enable(m); | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | void WaypointPalettePanel::SelectFirstBrush() { | |
| 72 | + | // SelectWaypointBrush(); | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | Brush* WaypointPalettePanel::GetSelectedBrush() const { | |
| 76 | + | long item = waypoint_list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); | |
| 77 | + | g_gui.waypoint_brush->setWaypoint( | |
| 78 | + | item == -1 ? nullptr : map->waypoints.getWaypoint(nstr(waypoint_list->GetItemText(item))) | |
| 79 | + | ); | |
| 80 | + | return g_gui.waypoint_brush; | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | bool WaypointPalettePanel::SelectBrush(const Brush* whatbrush) { | |
| 84 | + | ASSERT(whatbrush == g_gui.waypoint_brush); | |
| 85 | + | return false; | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | int WaypointPalettePanel::GetSelectedBrushSize() const { | |
| 89 | + | return 0; | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | PaletteType WaypointPalettePanel::GetType() const { | |
| 93 | + | return TILESET_WAYPOINT; | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | wxString WaypointPalettePanel::GetName() const { | |
| 97 | + | return "Waypoint Palette"; | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | void WaypointPalettePanel::OnUpdate() { | |
| 101 | + | if (wxTextCtrl* tc = waypoint_list->GetEditControl()) { | |
| 102 | + | Waypoint* wp = map->waypoints.getWaypoint(nstr(tc->GetValue())); | |
| 103 | + | if (wp && wp->pos == Position()) { | |
| 104 | + | if (map->getTile(wp->pos)) { | |
| 105 | + | map->getTileL(wp->pos)->decreaseWaypointCount(); | |
| 106 | + | } | |
| 107 | + | map->waypoints.removeWaypoint(wp->name); | |
| 108 | + | } | |
| 109 | + | } | |
| 110 | + | waypoint_list->DeleteAllItems(); | |
| 111 | + | ||
| 112 | + | if (!map) { | |
| 113 | + | waypoint_list->Enable(false); | |
| 114 | + | add_waypoint_button->Enable(false); | |
| 115 | + | remove_waypoint_button->Enable(false); | |
| 116 | + | } else { | |
| 117 | + | waypoint_list->Enable(true); | |
| 118 | + | add_waypoint_button->Enable(true); | |
| 119 | + | remove_waypoint_button->Enable(true); | |
| 120 | + | ||
| 121 | + | Waypoints& waypoints = map->waypoints; | |
| 122 | + | ||
| 123 | + | for (WaypointMap::const_iterator iter = waypoints.begin(); iter != waypoints.end(); ++iter) { | |
| 124 | + | waypoint_list->InsertItem(0, wxstr(iter->second->name)); | |
| 125 | + | } | |
| 126 | + | } | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | void WaypointPalettePanel::OnClickWaypoint(wxListEvent& event) { | |
| 130 | + | if (!map) { | |
| 131 | + | return; | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | std::string wpname = nstr(event.GetText()); | |
| 135 | + | Waypoint* wp = map->waypoints.getWaypoint(wpname); | |
| 136 | + | if (wp) { | |
| 137 | + | g_gui.SetScreenCenterPosition(wp->pos); | |
| 138 | + | g_gui.waypoint_brush->setWaypoint(wp); | |
| 139 | + | } | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | void WaypointPalettePanel::OnBeginEditWaypointLabel(wxListEvent& event) { | |
| 143 | + | // We need to disable all hotkeys, so we can type properly | |
| 144 | + | g_gui.DisableHotkeys(); | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | void WaypointPalettePanel::OnEditWaypointLabel(wxListEvent& event) { | |
| 148 | + | std::string wpname = nstr(event.GetLabel()); | |
| 149 | + | std::string oldwpname = nstr(waypoint_list->GetItemText(event.GetIndex())); | |
| 150 | + | Waypoint* wp = map->waypoints.getWaypoint(oldwpname); | |
| 151 | + | ||
| 152 | + | if (event.IsEditCancelled()) { | |
| 153 | + | return; | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | if (wpname == "") { | |
| 157 | + | map->waypoints.removeWaypoint(oldwpname); | |
| 158 | + | g_gui.RefreshPalettes(); | |
| 159 | + | } else if (wp) { | |
| 160 | + | if (wpname == oldwpname) { | |
| 161 | + | ; // do nothing | |
| 162 | + | } else { | |
| 163 | + | if (map->waypoints.getWaypoint(wpname)) { | |
| 164 | + | // Already exists a waypoint with this name! | |
| 165 | + | g_gui.SetStatusText("There already is a waypoint with this name."); | |
| 166 | + | event.Veto(); | |
| 167 | + | if (oldwpname == "") { | |
| 168 | + | map->waypoints.removeWaypoint(oldwpname); | |
| 169 | + | g_gui.RefreshPalettes(); | |
| 170 | + | } | |
| 171 | + | } else { | |
| 172 | + | Waypoint* nwp = newd Waypoint(*wp); | |
| 173 | + | nwp->name = wpname; | |
| 174 | + | ||
| 175 | + | Waypoint* rwp = map->waypoints.getWaypoint(oldwpname); | |
| 176 | + | if (rwp) { | |
| 177 | + | if (map->getTile(rwp->pos)) { | |
| 178 | + | map->getTileL(rwp->pos)->decreaseWaypointCount(); | |
| 179 | + | } | |
| 180 | + | map->waypoints.removeWaypoint(rwp->name); | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | map->waypoints.addWaypoint(nwp); | |
| 184 | + | g_gui.waypoint_brush->setWaypoint(nwp); | |
| 185 | + | ||
| 186 | + | // Refresh other palettes | |
| 187 | + | refresh_timer.Start(300, true); | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | } | |
| 191 | + | ||
| 192 | + | if (event.IsAllowed()) { | |
| 193 | + | g_gui.EnableHotkeys(); | |
| 194 | + | } | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | void WaypointPalettePanel::OnClickAddWaypoint(wxCommandEvent& event) { | |
| 198 | + | if (map) { | |
| 199 | + | map->waypoints.addWaypoint(newd Waypoint()); | |
| 200 | + | long i = waypoint_list->InsertItem(0, ""); | |
| 201 | + | waypoint_list->EditLabel(i); | |
| 202 | + | ||
| 203 | + | // g_gui.RefreshPalettes(); | |
| 204 | + | } | |
| 205 | + | } | |
| 206 | + | ||
| 207 | + | void WaypointPalettePanel::OnClickRemoveWaypoint(wxCommandEvent& event) { | |
| 208 | + | if (!map) { | |
| 209 | + | return; | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | long item = waypoint_list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); | |
| 213 | + | if (item != -1) { | |
| 214 | + | Waypoint* wp = map->waypoints.getWaypoint(nstr(waypoint_list->GetItemText(item))); | |
| 215 | + | if (wp) { | |
| 216 | + | if (map->getTile(wp->pos)) { | |
| 217 | + | map->getTileL(wp->pos)->decreaseWaypointCount(); | |
| 218 | + | } | |
| 219 | + | map->waypoints.removeWaypoint(wp->name); | |
| 220 | + | } | |
| 221 | + | waypoint_list->DeleteItem(item); | |
| 222 | + | refresh_timer.Start(300, true); | |
| 223 | + | } | |
| 224 | + | } |
| @@ -0,0 +1,69 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_PALETTE_WAYPOINTS_H_ | |
| 19 | + | #define RME_PALETTE_WAYPOINTS_H_ | |
| 20 | + | ||
| 21 | + | #include <wx/listctrl.h> | |
| 22 | + | ||
| 23 | + | #include "waypoints.h" | |
| 24 | + | #include "palette_common.h" | |
| 25 | + | ||
| 26 | + | class WaypointPalettePanel : public PalettePanel { | |
| 27 | + | public: | |
| 28 | + | WaypointPalettePanel(wxWindow* parent, wxWindowID id = wxID_ANY); | |
| 29 | + | ~WaypointPalettePanel(); | |
| 30 | + | ||
| 31 | + | wxString GetName() const; | |
| 32 | + | PaletteType GetType() const; | |
| 33 | + | ||
| 34 | + | // Select the first brush | |
| 35 | + | void SelectFirstBrush(); | |
| 36 | + | // Returns the currently selected brush (first brush if panel is not loaded) | |
| 37 | + | Brush* GetSelectedBrush() const; | |
| 38 | + | // Returns the currently selected brush size | |
| 39 | + | int GetSelectedBrushSize() const; | |
| 40 | + | // Select the brush in the parameter, this only changes the look of the panel | |
| 41 | + | bool SelectBrush(const Brush* whatbrush); | |
| 42 | + | ||
| 43 | + | // Called sometimes? | |
| 44 | + | void OnUpdate(); | |
| 45 | + | // Called when this page is about to be displayed | |
| 46 | + | void OnSwitchIn(); | |
| 47 | + | // Called when this page is hidden | |
| 48 | + | void OnSwitchOut(); | |
| 49 | + | ||
| 50 | + | public: | |
| 51 | + | // wxWidgets event handling | |
| 52 | + | void OnClickWaypoint(wxListEvent& event); | |
| 53 | + | void OnBeginEditWaypointLabel(wxListEvent& event); | |
| 54 | + | void OnEditWaypointLabel(wxListEvent& event); | |
| 55 | + | void OnClickAddWaypoint(wxCommandEvent& event); | |
| 56 | + | void OnClickRemoveWaypoint(wxCommandEvent& event); | |
| 57 | + | ||
| 58 | + | void SetMap(Map* map); | |
| 59 | + | ||
| 60 | + | protected: | |
| 61 | + | Map* map; | |
| 62 | + | wxListCtrl* waypoint_list; | |
| 63 | + | wxButton* add_waypoint_button; | |
| 64 | + | wxButton* remove_waypoint_button; | |
| 65 | + | ||
| 66 | + | DECLARE_EVENT_TABLE() | |
| 67 | + | }; | |
| 68 | + | ||
| 69 | + | #endif |
| @@ -0,0 +1,529 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #include "main.h" | |
| 19 | + | ||
| 20 | + | #include "settings.h" | |
| 21 | + | #include "gui.h" | |
| 22 | + | #include "brush.h" | |
| 23 | + | #include "map_display.h" | |
| 24 | + | ||
| 25 | + | #include "palette_window.h" | |
| 26 | + | #include "palette_brushlist.h" | |
| 27 | + | #include "palette_house.h" | |
| 28 | + | #include "palette_creature.h" | |
| 29 | + | #include "palette_waypoints.h" | |
| 30 | + | ||
| 31 | + | #include "house_brush.h" | |
| 32 | + | #include "map.h" | |
| 33 | + | ||
| 34 | + | // ============================================================================ | |
| 35 | + | // Palette window | |
| 36 | + | ||
| 37 | + | BEGIN_EVENT_TABLE(PaletteWindow, wxPanel) | |
| 38 | + | EVT_CHOICEBOOK_PAGE_CHANGING(PALETTE_CHOICEBOOK, PaletteWindow::OnSwitchingPage) | |
| 39 | + | EVT_CHOICEBOOK_PAGE_CHANGED(PALETTE_CHOICEBOOK, PaletteWindow::OnPageChanged) | |
| 40 | + | EVT_CLOSE(PaletteWindow::OnClose) | |
| 41 | + | ||
| 42 | + | EVT_KEY_DOWN(PaletteWindow::OnKey) | |
| 43 | + | EVT_TEXT(wxID_ANY, PaletteWindow::OnActionIDChange) | |
| 44 | + | EVT_CHECKBOX(wxID_ANY, PaletteWindow::OnActionIDToggle) | |
| 45 | + | END_EVENT_TABLE() | |
| 46 | + | ||
| 47 | + | PaletteWindow::PaletteWindow(wxWindow* parent, const TilesetContainer& tilesets) : | |
| 48 | + | wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(230, 250)), | |
| 49 | + | choicebook(nullptr), | |
| 50 | + | terrain_palette(nullptr), | |
| 51 | + | doodad_palette(nullptr), | |
| 52 | + | item_palette(nullptr), | |
| 53 | + | collection_palette(nullptr), | |
| 54 | + | creature_palette(nullptr), | |
| 55 | + | house_palette(nullptr), | |
| 56 | + | waypoint_palette(nullptr), | |
| 57 | + | raw_palette(nullptr), | |
| 58 | + | action_id_input(nullptr), | |
| 59 | + | action_id_checkbox(nullptr), | |
| 60 | + | action_id(0), | |
| 61 | + | action_id_enabled(false) { | |
| 62 | + | ||
| 63 | + | // Allow resizing but maintain minimum size | |
| 64 | + | SetMinSize(wxSize(225, 250)); | |
| 65 | + | ||
| 66 | + | // Create main sizer | |
| 67 | + | wxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); | |
| 68 | + | ||
| 69 | + | // Create action ID controls | |
| 70 | + | wxSizer* action_id_sizer = new wxBoxSizer(wxHORIZONTAL); | |
| 71 | + | action_id_input = new wxTextCtrl(this, wxID_ANY, "0", wxDefaultPosition, wxSize(60, -1)); | |
| 72 | + | action_id_input->SetToolTip("Enter action ID (0-65535)"); | |
| 73 | + | action_id_checkbox = new wxCheckBox(this, wxID_ANY, "Enable Action ID"); | |
| 74 | + | action_id_checkbox->SetToolTip("When enabled, placed items will have this action ID"); | |
| 75 | + | ||
| 76 | + | action_id_sizer->Add(action_id_input, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); | |
| 77 | + | action_id_sizer->Add(action_id_checkbox, 0, wxALIGN_CENTER_VERTICAL); | |
| 78 | + | ||
| 79 | + | main_sizer->Add(action_id_sizer, 0, wxEXPAND | wxALL, 5); | |
| 80 | + | ||
| 81 | + | // Create choicebook with EXPAND flag to fill available space | |
| 82 | + | choicebook = new wxChoicebook(this, PALETTE_CHOICEBOOK, wxDefaultPosition, wxDefaultSize); | |
| 83 | + | ||
| 84 | + | terrain_palette = static_cast<BrushPalettePanel*>(CreateTerrainPalette(choicebook, tilesets)); | |
| 85 | + | choicebook->AddPage(terrain_palette, terrain_palette->GetName()); | |
| 86 | + | ||
| 87 | + | doodad_palette = static_cast<BrushPalettePanel*>(CreateDoodadPalette(choicebook, tilesets)); | |
| 88 | + | choicebook->AddPage(doodad_palette, doodad_palette->GetName()); | |
| 89 | + | ||
| 90 | + | collection_palette = static_cast<BrushPalettePanel*>(CreateCollectionPalette(choicebook, tilesets)); | |
| 91 | + | choicebook->AddPage(collection_palette, collection_palette->GetName()); | |
| 92 | + | ||
| 93 | + | item_palette = static_cast<BrushPalettePanel*>(CreateItemPalette(choicebook, tilesets)); | |
| 94 | + | choicebook->AddPage(item_palette, item_palette->GetName()); | |
| 95 | + | ||
| 96 | + | house_palette = static_cast<HousePalettePanel*>(CreateHousePalette(choicebook, tilesets)); | |
| 97 | + | choicebook->AddPage(house_palette, house_palette->GetName()); | |
| 98 | + | ||
| 99 | + | waypoint_palette = static_cast<WaypointPalettePanel*>(CreateWaypointPalette(choicebook, tilesets)); | |
| 100 | + | choicebook->AddPage(waypoint_palette, waypoint_palette->GetName()); | |
| 101 | + | ||
| 102 | + | creature_palette = static_cast<CreaturePalettePanel*>(CreateCreaturePalette(choicebook, tilesets)); | |
| 103 | + | choicebook->AddPage(creature_palette, creature_palette->GetName()); | |
| 104 | + | ||
| 105 | + | raw_palette = static_cast<BrushPalettePanel*>(CreateRAWPalette(choicebook, tilesets)); | |
| 106 | + | choicebook->AddPage(raw_palette, raw_palette->GetName()); | |
| 107 | + | ||
| 108 | + | // Add choicebook to main sizer | |
| 109 | + | main_sizer->Add(choicebook, 1, wxEXPAND | wxALL, 2); | |
| 110 | + | SetSizer(main_sizer); | |
| 111 | + | ||
| 112 | + | // Load first page | |
| 113 | + | LoadCurrentContents(); | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | PaletteWindow::~PaletteWindow() { | |
| 117 | + | // Clean up all brushes and caches in each palette panel | |
| 118 | + | if (choicebook) { | |
| 119 | + | // Ensure each panel type is properly cleaned up | |
| 120 | + | if (terrain_palette) { | |
| 121 | + | terrain_palette->DestroyAllCaches(); | |
| 122 | + | } | |
| 123 | + | if (doodad_palette) { | |
| 124 | + | doodad_palette->DestroyAllCaches(); | |
| 125 | + | } | |
| 126 | + | if (item_palette) { | |
| 127 | + | item_palette->DestroyAllCaches(); | |
| 128 | + | } | |
| 129 | + | if (collection_palette) { | |
| 130 | + | collection_palette->DestroyAllCaches(); | |
| 131 | + | } | |
| 132 | + | if (raw_palette) { | |
| 133 | + | raw_palette->DestroyAllCaches(); | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // Other palette types may need specific cleanup | |
| 137 | + | for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) { | |
| 138 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetPage(iz)); | |
| 139 | + | if (panel) { | |
| 140 | + | panel->InvalidateContents(); | |
| 141 | + | } | |
| 142 | + | } | |
| 143 | + | } | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | PalettePanel* PaletteWindow::CreateTerrainPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 147 | + | BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_TERRAIN); | |
| 148 | + | panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_TERRAIN_STYLE))); | |
| 149 | + | ||
| 150 | + | BrushToolPanel* tool_panel = newd BrushToolPanel(panel); | |
| 151 | + | tool_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR)); | |
| 152 | + | panel->AddToolPanel(tool_panel); | |
| 153 | + | ||
| 154 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 155 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR)); | |
| 156 | + | panel->AddToolPanel(size_panel); | |
| 157 | + | ||
| 158 | + | ZoneBrushPanel* zone_brush_panel = newd ZoneBrushPanel(panel); | |
| 159 | + | zone_brush_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR)); | |
| 160 | + | panel->AddToolPanel(zone_brush_panel); | |
| 161 | + | ||
| 162 | + | return panel; | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | PalettePanel* PaletteWindow::CreateCollectionPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 166 | + | BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_COLLECTION); | |
| 167 | + | panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_COLLECTION_STYLE))); | |
| 168 | + | ||
| 169 | + | // terrain palette tools | |
| 170 | + | BrushToolPanel* tool_panel = newd BrushToolPanel(panel); | |
| 171 | + | tool_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR)); | |
| 172 | + | panel->AddToolPanel(tool_panel); | |
| 173 | + | ||
| 174 | + | // brush thickness panel | |
| 175 | + | panel->AddToolPanel(newd BrushThicknessPanel(panel)); | |
| 176 | + | ||
| 177 | + | // brush size tools | |
| 178 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 179 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR)); | |
| 180 | + | panel->AddToolPanel(size_panel); | |
| 181 | + | ||
| 182 | + | return panel; | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | PalettePanel* PaletteWindow::CreateDoodadPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 186 | + | BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_DOODAD); | |
| 187 | + | panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_DOODAD_STYLE))); | |
| 188 | + | ||
| 189 | + | panel->AddToolPanel(newd BrushThicknessPanel(panel)); | |
| 190 | + | ||
| 191 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 192 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_DOODAD_SIZEBAR)); | |
| 193 | + | panel->AddToolPanel(size_panel); | |
| 194 | + | ||
| 195 | + | return panel; | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | PalettePanel* PaletteWindow::CreateItemPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 199 | + | BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_ITEM); | |
| 200 | + | panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_ITEM_STYLE))); | |
| 201 | + | ||
| 202 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 203 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_ITEM_SIZEBAR)); | |
| 204 | + | panel->AddToolPanel(size_panel); | |
| 205 | + | return panel; | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | PalettePanel* PaletteWindow::CreateHousePalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 209 | + | HousePalettePanel* panel = newd HousePalettePanel(parent); | |
| 210 | + | ||
| 211 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 212 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_HOUSE_SIZEBAR)); | |
| 213 | + | panel->AddToolPanel(size_panel); | |
| 214 | + | return panel; | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | PalettePanel* PaletteWindow::CreateWaypointPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 218 | + | WaypointPalettePanel* panel = newd WaypointPalettePanel(parent); | |
| 219 | + | return panel; | |
| 220 | + | } | |
| 221 | + | ||
| 222 | + | PalettePanel* PaletteWindow::CreateCreaturePalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 223 | + | CreaturePalettePanel* panel = newd CreaturePalettePanel(parent); | |
| 224 | + | return panel; | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | PalettePanel* PaletteWindow::CreateRAWPalette(wxWindow* parent, const TilesetContainer& tilesets) { | |
| 228 | + | BrushPalettePanel* panel = newd BrushPalettePanel(parent, tilesets, TILESET_RAW); | |
| 229 | + | panel->SetListType(wxstr(g_settings.getString(Config::PALETTE_RAW_STYLE))); | |
| 230 | + | ||
| 231 | + | BrushSizePanel* size_panel = newd BrushSizePanel(panel); | |
| 232 | + | size_panel->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_RAW_SIZEBAR)); | |
| 233 | + | panel->AddToolPanel(size_panel); | |
| 234 | + | ||
| 235 | + | return panel; | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | void PaletteWindow::ReloadSettings(Map* map) { | |
| 239 | + | if (terrain_palette) { | |
| 240 | + | terrain_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_TERRAIN_STYLE))); | |
| 241 | + | terrain_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_TERRAIN_TOOLBAR)); | |
| 242 | + | } | |
| 243 | + | if (doodad_palette) { | |
| 244 | + | doodad_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_DOODAD_STYLE))); | |
| 245 | + | doodad_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_DOODAD_SIZEBAR)); | |
| 246 | + | } | |
| 247 | + | if (house_palette) { | |
| 248 | + | house_palette->SetMap(map); | |
| 249 | + | house_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_HOUSE_SIZEBAR)); | |
| 250 | + | } | |
| 251 | + | if (waypoint_palette) { | |
| 252 | + | waypoint_palette->SetMap(map); | |
| 253 | + | } | |
| 254 | + | if (item_palette) { | |
| 255 | + | item_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_ITEM_STYLE))); | |
| 256 | + | item_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_ITEM_SIZEBAR)); | |
| 257 | + | } | |
| 258 | + | if (collection_palette) { | |
| 259 | + | collection_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_COLLECTION_STYLE))); | |
| 260 | + | collection_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_COLLECTION_TOOLBAR)); | |
| 261 | + | } | |
| 262 | + | if (raw_palette) { | |
| 263 | + | raw_palette->SetListType(wxstr(g_settings.getString(Config::PALETTE_RAW_STYLE))); | |
| 264 | + | raw_palette->SetToolbarIconSize(g_settings.getBoolean(Config::USE_LARGE_RAW_SIZEBAR)); | |
| 265 | + | } | |
| 266 | + | InvalidateContents(); | |
| 267 | + | } | |
| 268 | + | ||
| 269 | + | void PaletteWindow::LoadCurrentContents() { | |
| 270 | + | if (!choicebook) { | |
| 271 | + | return; | |
| 272 | + | } | |
| 273 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 274 | + | panel->LoadCurrentContents(); | |
| 275 | + | Fit(); | |
| 276 | + | Refresh(); | |
| 277 | + | Update(); | |
| 278 | + | } | |
| 279 | + | ||
| 280 | + | void PaletteWindow::InvalidateContents() { | |
| 281 | + | if (!choicebook) { | |
| 282 | + | return; | |
| 283 | + | } | |
| 284 | + | for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) { | |
| 285 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetPage(iz)); | |
| 286 | + | panel->InvalidateContents(); | |
| 287 | + | } | |
| 288 | + | LoadCurrentContents(); | |
| 289 | + | if (creature_palette) { | |
| 290 | + | creature_palette->OnUpdate(); | |
| 291 | + | } | |
| 292 | + | if (house_palette) { | |
| 293 | + | house_palette->OnUpdate(); | |
| 294 | + | } | |
| 295 | + | if (waypoint_palette) { | |
| 296 | + | waypoint_palette->OnUpdate(); | |
| 297 | + | } | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | void PaletteWindow::SelectPage(PaletteType id) { | |
| 301 | + | if (!choicebook) { | |
| 302 | + | return; | |
| 303 | + | } | |
| 304 | + | if (id == GetSelectedPage()) { | |
| 305 | + | return; | |
| 306 | + | } | |
| 307 | + | ||
| 308 | + | // First notify the current page that it's being switched out | |
| 309 | + | PalettePanel* currentPanel = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 310 | + | if (currentPanel) { | |
| 311 | + | currentPanel->OnSwitchOut(); | |
| 312 | + | } | |
| 313 | + | ||
| 314 | + | // Find and select the new page | |
| 315 | + | for (size_t iz = 0; iz < choicebook->GetPageCount(); ++iz) { | |
| 316 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetPage(iz)); | |
| 317 | + | if (panel->GetType() == id) { | |
| 318 | + | choicebook->SetSelection(iz); | |
| 319 | + | panel->OnSwitchIn(); | |
| 320 | + | break; | |
| 321 | + | } | |
| 322 | + | } | |
| 323 | + | } | |
| 324 | + | ||
| 325 | + | Brush* PaletteWindow::GetSelectedBrush() const { | |
| 326 | + | if (!choicebook) { | |
| 327 | + | return nullptr; | |
| 328 | + | } | |
| 329 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 330 | + | return panel->GetSelectedBrush(); | |
| 331 | + | } | |
| 332 | + | ||
| 333 | + | int PaletteWindow::GetSelectedBrushSize() const { | |
| 334 | + | if (!choicebook) { | |
| 335 | + | return 0; | |
| 336 | + | } | |
| 337 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 338 | + | return panel->GetSelectedBrushSize(); | |
| 339 | + | } | |
| 340 | + | ||
| 341 | + | PaletteType PaletteWindow::GetSelectedPage() const { | |
| 342 | + | if (!choicebook) { | |
| 343 | + | return TILESET_UNKNOWN; | |
| 344 | + | } | |
| 345 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 346 | + | ASSERT(panel); | |
| 347 | + | return panel->GetType(); | |
| 348 | + | } | |
| 349 | + | ||
| 350 | + | bool PaletteWindow::OnSelectBrush(const Brush* whatbrush, PaletteType primary) { | |
| 351 | + | if (!choicebook || !whatbrush) { | |
| 352 | + | return false; | |
| 353 | + | } | |
| 354 | + | ||
| 355 | + | if (whatbrush->isHouse() && house_palette) { | |
| 356 | + | house_palette->SelectBrush(whatbrush); | |
| 357 | + | SelectPage(TILESET_HOUSE); | |
| 358 | + | return true; | |
| 359 | + | } | |
| 360 | + | ||
| 361 | + | switch (primary) { | |
| 362 | + | case TILESET_TERRAIN: { | |
| 363 | + | // This is already searched first | |
| 364 | + | break; | |
| 365 | + | } | |
| 366 | + | case TILESET_DOODAD: { | |
| 367 | + | // Ok, search doodad before terrain | |
| 368 | + | if (doodad_palette && doodad_palette->SelectBrush(whatbrush)) { | |
| 369 | + | SelectPage(TILESET_DOODAD); | |
| 370 | + | return true; | |
| 371 | + | } | |
| 372 | + | break; | |
| 373 | + | } | |
| 374 | + | case TILESET_COLLECTION: { | |
| 375 | + | if (collection_palette && collection_palette->SelectBrush(whatbrush)) { | |
| 376 | + | SelectPage(TILESET_COLLECTION); | |
| 377 | + | return true; | |
| 378 | + | } | |
| 379 | + | } | |
| 380 | + | case TILESET_ITEM: { | |
| 381 | + | if (item_palette && item_palette->SelectBrush(whatbrush)) { | |
| 382 | + | SelectPage(TILESET_ITEM); | |
| 383 | + | return true; | |
| 384 | + | } | |
| 385 | + | break; | |
| 386 | + | } | |
| 387 | + | case TILESET_CREATURE: { | |
| 388 | + | if (creature_palette && creature_palette->SelectBrush(whatbrush)) { | |
| 389 | + | SelectPage(TILESET_CREATURE); | |
| 390 | + | return true; | |
| 391 | + | } | |
| 392 | + | break; | |
| 393 | + | } | |
| 394 | + | case TILESET_RAW: { | |
| 395 | + | if (raw_palette && raw_palette->SelectBrush(whatbrush)) { | |
| 396 | + | SelectPage(TILESET_RAW); | |
| 397 | + | return true; | |
| 398 | + | } | |
| 399 | + | break; | |
| 400 | + | } | |
| 401 | + | default: | |
| 402 | + | break; | |
| 403 | + | } | |
| 404 | + | ||
| 405 | + | // Test if it's a terrain brush | |
| 406 | + | if (terrain_palette && terrain_palette->SelectBrush(whatbrush)) { | |
| 407 | + | SelectPage(TILESET_TERRAIN); | |
| 408 | + | return true; | |
| 409 | + | } | |
| 410 | + | ||
| 411 | + | // Test if it's a doodad brush | |
| 412 | + | if (primary != TILESET_DOODAD) { | |
| 413 | + | if (doodad_palette && doodad_palette->SelectBrush(whatbrush)) { | |
| 414 | + | SelectPage(TILESET_DOODAD); | |
| 415 | + | return true; | |
| 416 | + | } | |
| 417 | + | } | |
| 418 | + | ||
| 419 | + | // Test if it's an item brush | |
| 420 | + | if (primary != TILESET_ITEM) { | |
| 421 | + | if (item_palette && item_palette->SelectBrush(whatbrush)) { | |
| 422 | + | SelectPage(TILESET_ITEM); | |
| 423 | + | return true; | |
| 424 | + | } | |
| 425 | + | } | |
| 426 | + | ||
| 427 | + | // Test if it's a creature brush | |
| 428 | + | if (primary != TILESET_CREATURE) { | |
| 429 | + | if (creature_palette && creature_palette->SelectBrush(whatbrush)) { | |
| 430 | + | SelectPage(TILESET_CREATURE); | |
| 431 | + | return true; | |
| 432 | + | } | |
| 433 | + | } | |
| 434 | + | ||
| 435 | + | // Test if it's a raw brush | |
| 436 | + | if (primary != TILESET_RAW) { | |
| 437 | + | if (raw_palette && raw_palette->SelectBrush(whatbrush)) { | |
| 438 | + | SelectPage(TILESET_RAW); | |
| 439 | + | return true; | |
| 440 | + | } | |
| 441 | + | } | |
| 442 | + | ||
| 443 | + | return false; | |
| 444 | + | } | |
| 445 | + | ||
| 446 | + | void PaletteWindow::OnSwitchingPage(wxChoicebookEvent& event) { | |
| 447 | + | event.Skip(); | |
| 448 | + | if (!choicebook) { | |
| 449 | + | return; | |
| 450 | + | } | |
| 451 | + | ||
| 452 | + | wxWindow* old_page = choicebook->GetPage(choicebook->GetSelection()); | |
| 453 | + | PalettePanel* old_panel = dynamic_cast<PalettePanel*>(old_page); | |
| 454 | + | if (old_panel) { | |
| 455 | + | old_panel->OnSwitchOut(); | |
| 456 | + | } | |
| 457 | + | ||
| 458 | + | wxWindow* page = choicebook->GetPage(event.GetSelection()); | |
| 459 | + | PalettePanel* panel = dynamic_cast<PalettePanel*>(page); | |
| 460 | + | if (panel) { | |
| 461 | + | panel->OnSwitchIn(); | |
| 462 | + | } | |
| 463 | + | } | |
| 464 | + | ||
| 465 | + | void PaletteWindow::OnPageChanged(wxChoicebookEvent& event) { | |
| 466 | + | if (!choicebook) { | |
| 467 | + | return; | |
| 468 | + | } | |
| 469 | + | g_gui.SelectBrush(); | |
| 470 | + | } | |
| 471 | + | ||
| 472 | + | void PaletteWindow::OnUpdateBrushSize(BrushShape shape, int size) { | |
| 473 | + | if (!choicebook) { | |
| 474 | + | return; | |
| 475 | + | } | |
| 476 | + | PalettePanel* page = dynamic_cast<PalettePanel*>(choicebook->GetCurrentPage()); | |
| 477 | + | ASSERT(page); | |
| 478 | + | page->OnUpdateBrushSize(shape, size); | |
| 479 | + | } | |
| 480 | + | ||
| 481 | + | void PaletteWindow::OnUpdate(Map* map) { | |
| 482 | + | if (creature_palette) { | |
| 483 | + | creature_palette->OnUpdate(); | |
| 484 | + | } | |
| 485 | + | if (house_palette) { | |
| 486 | + | house_palette->SetMap(map); | |
| 487 | + | } | |
| 488 | + | if (waypoint_palette) { | |
| 489 | + | waypoint_palette->SetMap(map); | |
| 490 | + | waypoint_palette->OnUpdate(); | |
| 491 | + | } | |
| 492 | + | } | |
| 493 | + | ||
| 494 | + | void PaletteWindow::OnKey(wxKeyEvent& event) { | |
| 495 | + | if (g_gui.GetCurrentTab() != nullptr) { | |
| 496 | + | g_gui.GetCurrentMapTab()->GetEventHandler()->AddPendingEvent(event); | |
| 497 | + | } | |
| 498 | + | } | |
| 499 | + | ||
| 500 | + | void PaletteWindow::OnClose(wxCloseEvent& event) { | |
| 501 | + | if (!event.CanVeto()) { | |
| 502 | + | // We can't do anything! This sucks! | |
| 503 | + | // (application is closed, we have to destroy ourselves) | |
| 504 | + | Destroy(); | |
| 505 | + | } else { | |
| 506 | + | Show(false); | |
| 507 | + | event.Veto(true); | |
| 508 | + | } | |
| 509 | + | } | |
| 510 | + | ||
| 511 | + | void PaletteWindow::OnActionIDChange(wxCommandEvent& event) { | |
| 512 | + | wxString value = action_id_input->GetValue(); | |
| 513 | + | long val; | |
| 514 | + | if (value.ToLong(&val)) { | |
| 515 | + | if (val >= 0 && val <= 65535) { | |
| 516 | + | action_id = static_cast<uint16_t>(val); | |
| 517 | + | } else { | |
| 518 | + | // Reset to previous valid value | |
| 519 | + | action_id_input->SetValue(wxString::Format("%d", action_id)); | |
| 520 | + | } | |
| 521 | + | } else { | |
| 522 | + | // Reset to previous valid value | |
| 523 | + | action_id_input->SetValue(wxString::Format("%d", action_id)); | |
| 524 | + | } | |
| 525 | + | } | |
| 526 | + | ||
| 527 | + | void PaletteWindow::OnActionIDToggle(wxCommandEvent& event) { | |
| 528 | + | action_id_enabled = action_id_checkbox->GetValue(); | |
| 529 | + | } |
| @@ -0,0 +1,102 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_PALETTE_H_ | |
| 19 | + | #define RME_PALETTE_H_ | |
| 20 | + | ||
| 21 | + | #include "palette_common.h" | |
| 22 | + | ||
| 23 | + | class BrushPalettePanel; | |
| 24 | + | class CreaturePalettePanel; | |
| 25 | + | class HousePalettePanel; | |
| 26 | + | class WaypointPalettePanel; | |
| 27 | + | ||
| 28 | + | class PaletteWindow : public wxPanel { | |
| 29 | + | public: | |
| 30 | + | PaletteWindow(wxWindow* parent, const TilesetContainer& tilesets); | |
| 31 | + | ~PaletteWindow(); | |
| 32 | + | ||
| 33 | + | // Interface | |
| 34 | + | // Reloads layout g_settings from g_settings (and using map) | |
| 35 | + | void ReloadSettings(Map* from); | |
| 36 | + | // Flushes all pages and forces them to be reloaded from the palette data again | |
| 37 | + | void InvalidateContents(); | |
| 38 | + | // (Re)Loads all currently displayed data, called from InvalidateContents implicitly | |
| 39 | + | void LoadCurrentContents(); | |
| 40 | + | // Goes to the selected page and selects any brush there | |
| 41 | + | void SelectPage(PaletteType palette); | |
| 42 | + | // The currently selected brush in this palette | |
| 43 | + | Brush* GetSelectedBrush() const; | |
| 44 | + | // The currently selected brush size in this palette | |
| 45 | + | int GetSelectedBrushSize() const; | |
| 46 | + | // The currently selected page (terrain, doodad...) | |
| 47 | + | PaletteType GetSelectedPage() const; | |
| 48 | + | ||
| 49 | + | // Get the current action ID value | |
| 50 | + | uint16_t GetActionID() const { return action_id; } | |
| 51 | + | // Check if action ID is enabled | |
| 52 | + | bool IsActionIDEnabled() const { return action_id_enabled; } | |
| 53 | + | ||
| 54 | + | // Custom Event handlers (something has changed?) | |
| 55 | + | // Finds the brush pointed to by whatbrush and selects it as the current brush (also changes page) | |
| 56 | + | // Returns if the brush was found in this palette | |
| 57 | + | virtual bool OnSelectBrush(const Brush* whatbrush, PaletteType primary = TILESET_UNKNOWN); | |
| 58 | + | // Updates the palette window to use the current brush size | |
| 59 | + | virtual void OnUpdateBrushSize(BrushShape shape, int size); | |
| 60 | + | // Updates the content of the palette (eg. houses, creatures) | |
| 61 | + | virtual void OnUpdate(Map* map); | |
| 62 | + | ||
| 63 | + | // wxWidgets Event Handlers | |
| 64 | + | void OnSwitchingPage(wxChoicebookEvent& event); | |
| 65 | + | void OnPageChanged(wxChoicebookEvent& event); | |
| 66 | + | // Forward key events to the parent window (The Map Window) | |
| 67 | + | void OnKey(wxKeyEvent& event); | |
| 68 | + | void OnClose(wxCloseEvent&); | |
| 69 | + | void OnActionIDChange(wxCommandEvent& event); | |
| 70 | + | void OnActionIDToggle(wxCommandEvent& event); | |
| 71 | + | ||
| 72 | + | protected: | |
| 73 | + | static PalettePanel* CreateTerrainPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 74 | + | static PalettePanel* CreateDoodadPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 75 | + | static PalettePanel* CreateItemPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 76 | + | static PalettePanel* CreateCollectionPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 77 | + | static PalettePanel* CreateCreaturePalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 78 | + | static PalettePanel* CreateHousePalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 79 | + | static PalettePanel* CreateWaypointPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 80 | + | static PalettePanel* CreateRAWPalette(wxWindow* parent, const TilesetContainer& tilesets); | |
| 81 | + | ||
| 82 | + | wxChoicebook* choicebook; | |
| 83 | + | ||
| 84 | + | BrushPalettePanel* terrain_palette; | |
| 85 | + | BrushPalettePanel* doodad_palette; | |
| 86 | + | BrushPalettePanel* item_palette; | |
| 87 | + | BrushPalettePanel* collection_palette; | |
| 88 | + | CreaturePalettePanel* creature_palette; | |
| 89 | + | HousePalettePanel* house_palette; | |
| 90 | + | WaypointPalettePanel* waypoint_palette; | |
| 91 | + | BrushPalettePanel* raw_palette; | |
| 92 | + | ||
| 93 | + | // Action ID controls | |
| 94 | + | wxTextCtrl* action_id_input; | |
| 95 | + | wxCheckBox* action_id_checkbox; | |
| 96 | + | uint16_t action_id; | |
| 97 | + | bool action_id_enabled; | |
| 98 | + | ||
| 99 | + | DECLARE_EVENT_TABLE() | |
| 100 | + | }; | |
| 101 | + | ||
| 102 | + | #endif |