Add an SDF picker for selecting a stuff done flag and optionally giving it a name.
In effect, this is a combination of two of the previous pickers: the location picker, and the editable string picker. This required quite a significant rework of how the tilemap places its children. Currently it's only used in special node editing. I plan to add its use in many other places too though.
This commit is contained in:
@@ -10,6 +10,7 @@ scened_sources = Split("""
|
||||
scen.keydlgs.cpp
|
||||
scen.locpicker.cpp
|
||||
scen.main.cpp
|
||||
scen.sdfpicker.cpp
|
||||
scen.townout.cpp
|
||||
../view_dialogs.cpp
|
||||
../fileio/fileio_party.cpp
|
||||
|
@@ -415,6 +415,16 @@ void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) {
|
||||
data.PushText(scenario.itf_names[i]);
|
||||
data.CloseElement("item-typeflag");
|
||||
}
|
||||
for(int x = 0; x < scenario.sdf_names.size(); x++) {
|
||||
for(int y = 0; y < scenario.sdf_names[x].size(); y++) {
|
||||
if(scenario.sdf_names[x][y].empty()) continue;
|
||||
data.OpenElement("sdf");
|
||||
data.PushAttribute("row", x);
|
||||
data.PushAttribute("col", y);
|
||||
data.PushText(scenario.sdf_names[x][y]);
|
||||
data.CloseElement("sdf");
|
||||
}
|
||||
}
|
||||
data.CloseElement("editor");
|
||||
data.CloseElement("scenario");
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "scen.graphics.hpp"
|
||||
#include "scen.keydlgs.hpp"
|
||||
#include "scen.locpicker.hpp"
|
||||
#include "scen.sdfpicker.hpp"
|
||||
#include "scen.core.hpp"
|
||||
#include "dialogxml/dialogs/dialog.hpp"
|
||||
#include "dialogxml/widgets/control.hpp"
|
||||
@@ -1118,6 +1119,16 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
|
||||
store = loc.x;
|
||||
me[otherField].setTextToNum(loc.y);
|
||||
} break;
|
||||
case eSpecPicker::SDF: {
|
||||
// NOTE: Yes, it's correct that the main field has y and the "other field" has x.
|
||||
auto otherField = get_control_for_field(fcn.continuation);
|
||||
location sdf;
|
||||
sdf.y = val;
|
||||
sdf.x = me[otherField].getTextAsNum();
|
||||
sdf = cStuffDonePicker(sdf).run();
|
||||
store = sdf.y;
|
||||
me[otherField].setTextToNum(sdf.x);
|
||||
} break;
|
||||
case eSpecPicker::FIELD: store = choose_field_type(val, &me, fcn.augmented); break;
|
||||
case eSpecPicker::DAMAGE_TYPE: store = choose_damage_type(val, &me, true); break;
|
||||
case eSpecPicker::EXPLOSION: store = choose_boom_type(val, &me); break;
|
||||
|
@@ -110,8 +110,8 @@ bool cLocationPicker::handle_scroll(std::string item_hit) {
|
||||
}
|
||||
|
||||
bool cLocationPicker::handle_select(std::string item_hit) {
|
||||
location clickedLoc = map->getCellPos(dlog[item_hit]);
|
||||
location check{viewport.x + clickedLoc.x / 24, viewport.y + clickedLoc.y / 24};
|
||||
location clickedLoc = map->getCellIdx(dlog[item_hit]);
|
||||
location check{viewport.x + clickedLoc.x, viewport.y + clickedLoc.y};
|
||||
if(check.x < area->max_dim && check.y < area->max_dim) {
|
||||
chosen_loc = check;
|
||||
place_pointer();
|
||||
|
164
src/scenedit/scen.sdfpicker.cpp
Normal file
164
src/scenedit/scen.sdfpicker.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// scen.sdfpicker.cpp
|
||||
// BoE Scenario Editor
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-03-02.
|
||||
//
|
||||
|
||||
#include "scen.sdfpicker.hpp"
|
||||
|
||||
#include "dialogxml/widgets/field.hpp"
|
||||
#include "dialogxml/widgets/ledgroup.hpp"
|
||||
#include "dialogxml/widgets/tilemap.hpp"
|
||||
#include "fileio/resmgr/res_dialog.hpp"
|
||||
#include "scenario/scenario.hpp"
|
||||
#include "sounds.hpp"
|
||||
|
||||
extern cScenario scenario;
|
||||
|
||||
cStuffDonePicker::cStuffDonePicker(location sdf)
|
||||
: dlog(*ResMgr::dialogs.get("choose-sdf"))
|
||||
, initial_sdf(sdf)
|
||||
, chosen_sdf(sdf)
|
||||
{
|
||||
grid = dynamic_cast<cTilemap*>(&dlog["map"]);
|
||||
row_labels = dynamic_cast<cTilemap*>(&dlog["rows"]);
|
||||
col_labels = dynamic_cast<cTilemap*>(&dlog["cols"]);
|
||||
rows = grid->getNumRows();
|
||||
cols = grid->getNumCols();
|
||||
clamp_sdf();
|
||||
fill_names();
|
||||
handle_scroll(""); // Hide unusable scroll buttons
|
||||
using namespace std::placeholders;
|
||||
dlog.attachClickHandlers(std::bind(&cStuffDonePicker::handle_close, this, _2), {"done", "cancel"});
|
||||
dlog.attachClickHandlers(std::bind(&cStuffDonePicker::handle_scroll, this, _2), {"up", "down", "left", "right"});
|
||||
grid->attachFocusHandlers(std::bind(&cStuffDonePicker::handle_focus, this, _2, _3), "name");
|
||||
dlog["choice"].attachFocusHandler(std::bind(&cStuffDonePicker::handle_select, this, _3));
|
||||
}
|
||||
|
||||
bool cStuffDonePicker::handle_close(std::string item_hit) {
|
||||
dlog.toast(item_hit == "done");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cStuffDonePicker::handle_scroll(std::string item_hit) {
|
||||
if(!item_hit.empty()) save_names();
|
||||
if(item_hit == "up") {
|
||||
if(viewport.y > 0) viewport.y -= rows;
|
||||
} else if(item_hit == "down") {
|
||||
if(viewport.y < scenario.sdf_names[0].size() - rows) viewport.y += rows;
|
||||
} else if(item_hit == "left") {
|
||||
if(viewport.x > 0) viewport.x -= cols;
|
||||
} else if(item_hit == "right") {
|
||||
if(viewport.x < scenario.sdf_names.size() - cols) viewport.x += cols;
|
||||
}
|
||||
if(viewport.x == 0) dlog["left"].hide();
|
||||
else dlog["left"].show();
|
||||
if(viewport.y == 0) dlog["up"].hide();
|
||||
else dlog["up"].show();
|
||||
if(viewport.x >= scenario.sdf_names.size() - cols) dlog["right"].hide();
|
||||
else dlog["right"].show();
|
||||
if(viewport.y >= scenario.sdf_names[0].size() - rows) dlog["down"].hide();
|
||||
else dlog["down"].show();
|
||||
fill_names();
|
||||
if(!item_hit.empty()) select_active();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cStuffDonePicker::handle_select(bool losing) {
|
||||
if(losing) return true;
|
||||
std::string item_hit = dynamic_cast<cLedGroup&>(dlog["choice"]).getSelected();
|
||||
location clickedFlag = grid->getCellIdx(dlog[item_hit]);
|
||||
chosen_sdf = {viewport.x + clickedFlag.x, viewport.y + clickedFlag.y};
|
||||
auto& field = dynamic_cast<cTextField&>(grid->getChild("name", clickedFlag.x, clickedFlag.y));
|
||||
skipNextFocus = true;
|
||||
dlog.setFocus(&field);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cStuffDonePicker::handle_focus(std::string item_hit, bool losing) {
|
||||
if(losing) return true;
|
||||
if(skipNextFocus) {
|
||||
skipNextFocus = false;
|
||||
return true;
|
||||
}
|
||||
auto& field = dlog[item_hit];
|
||||
if(!field.getText().empty()) return true;
|
||||
location clickedFlag = grid->getCellIdx(field);
|
||||
chosen_sdf = {viewport.x + clickedFlag.x, viewport.y + clickedFlag.y};
|
||||
play_sound(34);
|
||||
auto& group = dynamic_cast<cLedGroup&>(dlog["choice"]);
|
||||
// TODO: It would be nice to do it like this, but getChild currently doesn't recurse to children of children.
|
||||
// auto& led = grid->getChild("select", clickedFlag.x, clickedFlag.y);
|
||||
// group.setSelected(led.getName());
|
||||
auto name = field.getName();
|
||||
auto hyphen = name.find_last_of("-");
|
||||
group.setSelected("select" + name.substr(hyphen));
|
||||
return true;
|
||||
}
|
||||
|
||||
location cStuffDonePicker::run() {
|
||||
skipNextFocus = true;
|
||||
dlog.run([this](cDialog&) { select_active(); });
|
||||
save_names();
|
||||
if(dlog.accepted()) return chosen_sdf;
|
||||
return initial_sdf;
|
||||
}
|
||||
|
||||
void cStuffDonePicker::clamp_sdf() {
|
||||
chosen_sdf.x = minmax(0, scenario.sdf_names.size() - 1, chosen_sdf.x);
|
||||
chosen_sdf.y = minmax(0, scenario.sdf_names[0].size() - 1, chosen_sdf.y);
|
||||
viewport.x = cols * floor(chosen_sdf.x / float(cols));
|
||||
viewport.y = rows * floor(chosen_sdf.y / float(rows));
|
||||
}
|
||||
|
||||
void cStuffDonePicker::fill_names() {
|
||||
for(int x = 0; x < cols; x++) {
|
||||
for(int y = 0; y < rows; y++) {
|
||||
auto& field = grid->getChild("name", x, y);
|
||||
location sdf = viewport;
|
||||
sdf.x += x;
|
||||
sdf.y += y;
|
||||
field.setText(scenario.sdf_names[sdf.x][sdf.y]);
|
||||
if(x == 0) {
|
||||
// Add row labels
|
||||
row_labels->getChild("row", 0, y).setTextToNum(sdf.y);
|
||||
}
|
||||
if(y == 0) {
|
||||
// Add column labels
|
||||
col_labels->getChild("col", x, 0).setTextToNum(sdf.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cStuffDonePicker::save_names() {
|
||||
for(int x = 0; x < cols; x++) {
|
||||
for(int y = 0; y < rows; y++) {
|
||||
auto& field = grid->getChild("name", x, y);
|
||||
location sdf = viewport;
|
||||
sdf.x += x;
|
||||
sdf.y += y;
|
||||
scenario.sdf_names[sdf.x][sdf.y] = field.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cStuffDonePicker::select_active() {
|
||||
auto& group = dynamic_cast<cLedGroup&>(dlog["choice"]);
|
||||
if(chosen_sdf.x >= viewport.x && chosen_sdf.x < viewport.x + cols && chosen_sdf.y >= viewport.y && chosen_sdf.y < viewport.y + rows) {
|
||||
location relative_sdf = chosen_sdf;
|
||||
relative_sdf.x -= viewport.x;
|
||||
relative_sdf.y -= viewport.y;
|
||||
auto& field = dynamic_cast<cTextField&>(grid->getChild("name", relative_sdf.x, relative_sdf.y));
|
||||
// TODO: It would be nice to do it like this, but getChild currently doesn't recurse to children of children.
|
||||
// auto& led = grid->getChild("select", relative_sdf.x, relative_sdf.y);
|
||||
// group.setSelected(led.getName());
|
||||
auto name = field.getName();
|
||||
auto hyphen = name.find_last_of("-");
|
||||
group.setSelected("select" + name.substr(hyphen));
|
||||
dlog.setFocus(&field);
|
||||
} else {
|
||||
group.setSelected("");
|
||||
}
|
||||
}
|
38
src/scenedit/scen.sdfpicker.hpp
Normal file
38
src/scenedit/scen.sdfpicker.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// scen.sdfpicker.hpp
|
||||
// BoE Scenario Editor
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-03-02.
|
||||
//
|
||||
|
||||
#ifndef BoE_scen_sdfpicker_h
|
||||
#define BoE_scen_sdfpicker_h
|
||||
|
||||
#include <string>
|
||||
#include "location.hpp"
|
||||
#include "dialogxml/dialogs/dialog.hpp"
|
||||
|
||||
class cTilemap;
|
||||
|
||||
class cStuffDonePicker {
|
||||
cDialog dlog;
|
||||
location initial_sdf, chosen_sdf, viewport;
|
||||
cTilemap* grid;
|
||||
cTilemap* row_labels;
|
||||
cTilemap* col_labels;
|
||||
int rows, cols;
|
||||
bool skipNextFocus = true;
|
||||
void clamp_sdf();
|
||||
void fill_names();
|
||||
void save_names();
|
||||
void select_active();
|
||||
bool handle_close(std::string item_hit);
|
||||
bool handle_scroll(std::string item_hit);
|
||||
bool handle_select(bool losing);
|
||||
bool handle_focus(std::string item_hit, bool losing);
|
||||
public:
|
||||
cStuffDonePicker(location sdf);
|
||||
location run();
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user