Add a new tilemap control that replicates its children into a fixed grid.
Use it for the Edit Terrain Object dialog.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "dialogxml/widgets/scrollbar.hpp"
|
||||
#include "dialogxml/widgets/scrollpane.hpp"
|
||||
#include "dialogxml/widgets/stack.hpp"
|
||||
#include "dialogxml/widgets/tilemap.hpp"
|
||||
#include "tools/keymods.hpp"
|
||||
#include "tools/winutil.hpp"
|
||||
#include "mathutil.hpp"
|
||||
@@ -45,22 +46,14 @@ const short cDialog::BG_DARK = 5, cDialog::BG_LIGHT = 16;
|
||||
short cDialog::defaultBackground = cDialog::BG_DARK;
|
||||
cDialog* cDialog::topWindow = nullptr;
|
||||
void (*cDialog::redraw_everything)() = nullptr;
|
||||
std::mt19937 cDialog::ui_rand;
|
||||
|
||||
extern std::map<std::string,sf::Color> colour_map;
|
||||
|
||||
extern bool check_for_interrupt(std::string);
|
||||
extern void showError(std::string str1, cDialog* parent = nullptr);
|
||||
|
||||
std::string cDialog::generateRandomString(){
|
||||
// Not bothering to seed, because it doesn't actually matter if it's truly random.
|
||||
int n_chars = ui_rand() % 100;
|
||||
std::string s = "$";
|
||||
while(n_chars > 0){
|
||||
s += char(ui_rand() % 96) + ' '; // was 223 ...
|
||||
n_chars--;
|
||||
}
|
||||
return s;
|
||||
std::string cDialog::generateId(const std::string& explicitId) const {
|
||||
return explicitId.empty() ? cControl::generateRandomString() : explicitId;
|
||||
}
|
||||
|
||||
string cControl::dlogStringFilter(string toFilter) {
|
||||
@@ -235,6 +228,10 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
inserted = controls.insert(parsed).first;
|
||||
// TODO: Now, if it contains any fields, their tab order must be accounted for
|
||||
//parsed.second->fillTabOrder(specificTabs, reverseTabs);
|
||||
} else if(type == "tilemap") {
|
||||
auto parsed = parse<cTilemap>(*node);
|
||||
inserted = controls.insert(parsed).first;
|
||||
parsed.second->fillTabOrder(specificTabs, reverseTabs);
|
||||
} else throw xBadNode(type,node->Row(),node->Column(),fname);
|
||||
if(prevCtrl.second) {
|
||||
if(inserted->second->anchor == "$$prev$$" && prevCtrl.second->anchor == "$$next$$") {
|
||||
@@ -271,6 +268,7 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
case CTRL_STACK: ctrlType = "stack"; break;
|
||||
case CTRL_SCROLL: ctrlType = "slider"; break;
|
||||
case CTRL_PANE: ctrlType = "pane"; break;
|
||||
case CTRL_MAP: ctrlType = "tilemap"; break;
|
||||
}
|
||||
throw xBadVal(ctrlType, "anchor", ctrl.anchor, 0, 0, fname);
|
||||
}
|
||||
@@ -293,6 +291,7 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
case CTRL_STACK: ctrlType = "stack"; break;
|
||||
case CTRL_SCROLL: ctrlType = "slider"; break;
|
||||
case CTRL_PANE: ctrlType = "pane"; break;
|
||||
case CTRL_MAP: ctrlType = "tilemap"; break;
|
||||
}
|
||||
throw xBadVal(ctrlType, "anchor", "<circular dependency>", 0, 0, fname);
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <random>
|
||||
|
||||
#include "ticpp.h"
|
||||
#include "dialogxml/keycodes.hpp"
|
||||
@@ -68,14 +67,13 @@ class cDialog {
|
||||
std::string currentFocus;
|
||||
cDialog* parent;
|
||||
cControl* findControl(std::string id);
|
||||
std::string generateRandomString();
|
||||
std::string generateId(const std::string& explicitId) const;
|
||||
void loadFromFile(const DialogDefn& file);
|
||||
void handleTab(bool reverse);
|
||||
template<typename Iter> void handleTabOrder(std::string& itemHit, Iter begin, Iter end);
|
||||
std::vector<std::pair<std::string,cTextField*>> tabOrder;
|
||||
static cDialog* topWindow; // Tracks the frontmost dialog.
|
||||
static bool initCalled;
|
||||
static std::mt19937 ui_rand;
|
||||
public:
|
||||
static void (*redraw_everything)();
|
||||
/// Performs essential startup initialization. Generally should not be called directly.
|
||||
@@ -242,19 +240,21 @@ public:
|
||||
/// Adds a new control described by the passed XML element.
|
||||
/// @tparam Ctrl The type of control to add.
|
||||
/// @param who The XML element describing the control.
|
||||
/// @param parent The parent control, if any. Omit if there is no parent.
|
||||
/// @note It is up to the caller to ensure that that the element
|
||||
/// passed describes the type of control being requested.
|
||||
template<class Ctrl> std::pair<std::string,Ctrl*> parse(ticpp::Element& who) {
|
||||
template<class Ctrl, class Container> std::pair<std::string,Ctrl*> parse(ticpp::Element& who, Container* parent) {
|
||||
std::pair<std::string,Ctrl*> p;
|
||||
p.second = new Ctrl(*this);
|
||||
p.first = p.second->parse(who, fname);
|
||||
if(p.first == ""){
|
||||
do{
|
||||
p.first = generateRandomString();
|
||||
}while(controls.find(p.first) != controls.end());
|
||||
}
|
||||
do{
|
||||
p.first = parent->generateId(p.first);
|
||||
}while(controls.find(p.first) != controls.end());
|
||||
return p;
|
||||
}
|
||||
template<class Ctrl> std::pair<std::string,Ctrl*> parse(ticpp::Element& who) {
|
||||
return parse<Ctrl, cDialog>(who, this);
|
||||
}
|
||||
cDialogIterator begin() {
|
||||
return cDialogIterator(this);
|
||||
}
|
||||
|
@@ -20,32 +20,32 @@ bool cContainer::parseChildControl(ticpp::Element& elem, std::map<std::string,cC
|
||||
ctrlIter inserted;
|
||||
std::string tag = elem.Value();
|
||||
if(tag == "field") {
|
||||
auto field = parent->parse<cTextField>(elem);
|
||||
auto field = parent->parse<cTextField>(elem, this);
|
||||
inserted = controls.insert(field).first;
|
||||
parent->tabOrder.push_back(field);
|
||||
id = field.first;
|
||||
} else if(tag == "text") {
|
||||
auto text = parent->parse<cTextMsg>(elem);
|
||||
auto text = parent->parse<cTextMsg>(elem, this);
|
||||
inserted = controls.insert(text).first;
|
||||
id = text.first;
|
||||
} else if(tag == "pict") {
|
||||
auto pict = parent->parse<cPict>(elem);
|
||||
auto pict = parent->parse<cPict>(elem, this);
|
||||
inserted = controls.insert(pict).first;
|
||||
id = pict.first;
|
||||
} else if(tag == "slider") {
|
||||
auto slide = parent->parse<cScrollbar>(elem);
|
||||
auto slide = parent->parse<cScrollbar>(elem, this);
|
||||
inserted = controls.insert(slide).first;
|
||||
id = slide.first;
|
||||
} else if(tag == "button") {
|
||||
auto button = parent->parse<cButton>(elem);
|
||||
auto button = parent->parse<cButton>(elem, this);
|
||||
inserted = controls.insert(button).first;
|
||||
id = button.first;
|
||||
} else if(tag == "led") {
|
||||
auto led = parent->parse<cLed>(elem);
|
||||
auto led = parent->parse<cLed>(elem, this);
|
||||
inserted = controls.insert(led).first;
|
||||
id = led.first;
|
||||
} else if(tag == "group") {
|
||||
auto group = parent->parse<cLedGroup>(elem);
|
||||
auto group = parent->parse<cLedGroup>(elem, this);
|
||||
inserted = controls.insert(group).first;
|
||||
id = group.first;
|
||||
} else return false;
|
||||
|
@@ -23,6 +23,22 @@
|
||||
|
||||
// Hyperlink forward declaration
|
||||
extern void launchURL(std::string url);
|
||||
std::mt19937 cControl::ui_rand;
|
||||
|
||||
std::string cControl::generateId(const std::string& explicitId) const {
|
||||
return explicitId.empty() ? generateRandomString() : explicitId;
|
||||
}
|
||||
|
||||
std::string cControl::generateRandomString() {
|
||||
// Not bothering to seed, because it doesn't actually matter if it's truly random.
|
||||
int n_chars = ui_rand() % 100;
|
||||
std::string s = "$";
|
||||
while(n_chars > 0){
|
||||
s += char(ui_rand() % 96) + ' '; // was 223 ...
|
||||
n_chars--;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void cControl::setText(std::string l){
|
||||
lbl = l;
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <boost/any.hpp>
|
||||
#include "dialogxml/dialogs/dlogevt.hpp"
|
||||
#include "tools/framerate_limiter.hpp"
|
||||
@@ -62,6 +63,7 @@ enum eControlType {
|
||||
CTRL_STACK, ///< A group of controls that represents one element in an array
|
||||
CTRL_SCROLL,///< A scrollbar
|
||||
CTRL_PANE, ///< A scroll pane
|
||||
CTRL_MAP, ///< A 2-dimensional grid of identical controls
|
||||
};
|
||||
|
||||
enum ePosition {
|
||||
@@ -461,6 +463,11 @@ protected:
|
||||
void redraw();
|
||||
/// Plays the proper sound for this control being clicked on
|
||||
void playClickSound();
|
||||
/// Generate a unique ID for a control. The explicitId is the ID specified in the XML, if any.
|
||||
/// This may be called more than once, so it should not return the same value twice in a row,
|
||||
/// unless it can guarantee the value is not already assigned to another control.
|
||||
virtual std::string generateId(const std::string& explicitId) const;
|
||||
static std::string generateRandomString();
|
||||
private:
|
||||
friend class cDialog; // This is so it can access parseColour and anchor
|
||||
friend class cContainer; // This is so it can access anchor
|
||||
@@ -472,6 +479,7 @@ private:
|
||||
ePosition horz = POS_ABS, vert = POS_ABS;
|
||||
std::string anchor;
|
||||
bool is_link = false;
|
||||
static std::mt19937 ui_rand;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
210
src/dialogxml/widgets/tilemap.cpp
Normal file
210
src/dialogxml/widgets/tilemap.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// tilemap.cpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-02-01.
|
||||
//
|
||||
|
||||
#include "tilemap.hpp"
|
||||
|
||||
#include "button.hpp"
|
||||
#include "dialogxml/dialogs/dialog.hpp"
|
||||
#include "field.hpp"
|
||||
#include "message.hpp"
|
||||
#include "pict.hpp"
|
||||
#include "scrollbar.hpp"
|
||||
#include "stack.hpp"
|
||||
#include <climits>
|
||||
|
||||
std::string cTilemap::generateId(const std::string& baseId) const {
|
||||
if(baseId.empty()) {
|
||||
if(id_tries++ == 0) return current_cell;
|
||||
return cControl::generateId(baseId) + "-" + current_cell;
|
||||
}
|
||||
return baseId + "-" + current_cell;
|
||||
}
|
||||
|
||||
location cTilemap::getCell(const std::string& id) const {
|
||||
size_t y_pos = id.find_last_of("y");
|
||||
size_t x_pos = id.find_last_of("x");
|
||||
std::string x_str = id.substr(x_pos + 1, y_pos);
|
||||
std::string y_str = id.substr(y_pos + 1);
|
||||
return location(std::stoi(x_str) * cellWidth, std::stoi(y_str) * cellHeight);
|
||||
}
|
||||
|
||||
std::string cTilemap::buildId(const std::string& base, size_t x, size_t y) {
|
||||
std::ostringstream sout;
|
||||
if(!base.empty()) {
|
||||
sout << base << '-';
|
||||
}
|
||||
sout << 'x' << x << 'y' << y;
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
bool cTilemap::hasChild(std::string id) const {
|
||||
return controls.find(id) != controls.end();
|
||||
}
|
||||
|
||||
cControl& cTilemap::getChild(std::string id) {
|
||||
if(!hasChild(id)) throw std::invalid_argument(id + " was not found in the tilemap");
|
||||
return *controls[id];
|
||||
}
|
||||
|
||||
bool cTilemap::hasChild(std::string id, size_t x, size_t y) const {
|
||||
return hasChild(buildId(id, x, y));
|
||||
}
|
||||
|
||||
cControl& cTilemap::getChild(std::string id, size_t x, size_t y) {
|
||||
return getChild(buildId(id, x, y));
|
||||
}
|
||||
|
||||
bool cTilemap::hasChild(size_t x, size_t y) const {
|
||||
return hasChild("", x, y);
|
||||
}
|
||||
|
||||
cControl& cTilemap::getChild(size_t x, size_t y) {
|
||||
return getChild("", x, y);
|
||||
}
|
||||
|
||||
bool cTilemap::manageFormat(eFormat prop, bool set, boost::any* val) {
|
||||
switch(prop) {
|
||||
case TXT_FRAME:
|
||||
if(val) {
|
||||
if(set) frameStyle = boost::any_cast<eFrameStyle>(*val);
|
||||
else *val = frameStyle;
|
||||
}
|
||||
break;
|
||||
// TODO: Colour is not supported
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cTilemap::isClickable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cTilemap::isFocusable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cTilemap::isScrollable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void cTilemap::draw() {
|
||||
if(!isVisible()) return;
|
||||
for(auto& ctrl : controls) {
|
||||
rectangle localBounds = ctrl.second->getBounds();
|
||||
rectangle globalBounds = localBounds;
|
||||
globalBounds.offset(getBounds().topLeft());
|
||||
globalBounds.offset(getCell(ctrl.first));
|
||||
ctrl.second->setBounds(globalBounds);
|
||||
ctrl.second->draw();
|
||||
ctrl.second->setBounds(localBounds);
|
||||
}
|
||||
drawFrame(2, frameStyle);
|
||||
}
|
||||
|
||||
void cTilemap::recalcRect() {
|
||||
auto iter = controls.begin();
|
||||
auto location = frame.topLeft();
|
||||
frame = {INT_MAX, INT_MAX, 0, 0};
|
||||
while(iter != controls.end()){
|
||||
cControl& ctrl = *iter->second;
|
||||
rectangle otherFrame = ctrl.getBounds();
|
||||
if(otherFrame.right > frame.right)
|
||||
frame.right = otherFrame.right;
|
||||
if(otherFrame.bottom > frame.bottom)
|
||||
frame.bottom = otherFrame.bottom;
|
||||
if(otherFrame.left < frame.left)
|
||||
frame.left = otherFrame.left;
|
||||
if(otherFrame.top < frame.top)
|
||||
frame.top = otherFrame.top;
|
||||
iter++;
|
||||
}
|
||||
frame.offset(location);
|
||||
frame.right += spacing;
|
||||
frame.bottom += spacing;
|
||||
cellWidth = frame.width();
|
||||
cellHeight = frame.height();
|
||||
frame.width() *= cols;
|
||||
frame.height() *= rows;
|
||||
frame.right -= spacing;
|
||||
frame.bottom -= spacing;
|
||||
}
|
||||
|
||||
void cTilemap::fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reverseTabs) {
|
||||
for(auto p : controls) {
|
||||
cControl& ctrl = *p.second;
|
||||
if(ctrl.getType() == CTRL_FIELD) {
|
||||
cTextField& field = dynamic_cast<cTextField&>(ctrl);
|
||||
if(field.tabOrder > 0)
|
||||
specificTabs.push_back(field.tabOrder);
|
||||
else if(field.tabOrder < 0)
|
||||
reverseTabs.push_back(field.tabOrder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cTilemap::cTilemap(cDialog& parent) : cContainer(CTRL_MAP, parent) {}
|
||||
|
||||
void cTilemap::forEach(std::function<void(std::string,cControl&)> callback) {
|
||||
for(auto ctrl : controls)
|
||||
callback(ctrl.first, *ctrl.second);
|
||||
}
|
||||
|
||||
bool cTilemap::parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) {
|
||||
if(attr.Name() == "rows") {
|
||||
try {
|
||||
attr.GetValue(&rows);
|
||||
} catch(ticpp::Exception&) {
|
||||
throw xBadVal(tagName, attr.Name(), attr.Value(), attr.Row(), attr.Column(), fname);
|
||||
}
|
||||
return true;
|
||||
} else if(attr.Name() == "cols") {
|
||||
try {
|
||||
attr.GetValue(&cols);
|
||||
} catch(ticpp::Exception&) {
|
||||
throw xBadVal(tagName, attr.Name(), attr.Value(), attr.Row(), attr.Column(), fname);
|
||||
}
|
||||
return true;
|
||||
} else if(attr.Name() == "cellspacing") {
|
||||
try {
|
||||
attr.GetValue(&spacing);
|
||||
} catch(ticpp::Exception&) {
|
||||
throw xBadVal(tagName, attr.Name(), attr.Value(), attr.Row(), attr.Column(), fname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return cContainer::parseAttribute(attr, tagName, fname);
|
||||
}
|
||||
|
||||
bool cTilemap::parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) {
|
||||
using namespace ticpp;
|
||||
if(content.Type() == TiXmlNode::ELEMENT) {
|
||||
std::string id;
|
||||
auto& elem = dynamic_cast<Element&>(content);
|
||||
id_tries = 0;
|
||||
current_cell = "x0y0";
|
||||
if(!parseChildControl(elem, controls, id, fname)) return false;
|
||||
for(size_t x = 0; x < cols; x++) {
|
||||
for(size_t y = 0; y < rows; y++) {
|
||||
if(x == 0 && y == 0) continue; // already did this one
|
||||
id_tries = 0;
|
||||
std::ostringstream sout;
|
||||
sout << "x" << x << "y" << y;
|
||||
current_cell = sout.str();
|
||||
parseChildControl(elem, controls, id, fname);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return cContainer::parseContent(content, n, tagName, fname, text);
|
||||
}
|
||||
|
||||
void cTilemap::validatePostParse(ticpp::Element& who, std::string fname, const std::set<std::string>& attrs, const std::multiset<std::string>& nodes) {
|
||||
cControl::validatePostParse(who, fname, attrs, nodes);
|
||||
if(!attrs.count("rows")) throw xMissingAttr(who.Value(), "rows", who.Row(), who.Column(), fname);
|
||||
if(!attrs.count("cols")) throw xMissingAttr(who.Value(), "cols", who.Row(), who.Column(), fname);
|
||||
}
|
54
src/dialogxml/widgets/tilemap.hpp
Normal file
54
src/dialogxml/widgets/tilemap.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// tilemap.hpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-02-01.
|
||||
//
|
||||
|
||||
#ifndef BoE_DIALOG_TILEMAP_HPP
|
||||
#define BoE_DIALOG_TILEMAP_HPP
|
||||
|
||||
#include "container.hpp"
|
||||
|
||||
/// A tilemap defines a two-dimensional array of data using a repeated template.
|
||||
class cTilemap : public cContainer {
|
||||
std::map<std::string,cControl*> controls;
|
||||
size_t rows, cols, spacing = 0, cellWidth, cellHeight;
|
||||
bool manageFormat(eFormat prop, bool set, boost::any* val) override;
|
||||
location getCell(const std::string& id) const;
|
||||
static std::string buildId(const std::string& base, size_t x, size_t y);
|
||||
std::string current_cell;
|
||||
mutable int id_tries = 0;
|
||||
public:
|
||||
std::string generateId(const std::string& baseId) const override;
|
||||
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
|
||||
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
|
||||
void validatePostParse(ticpp::Element& who, std::string fname, const std::set<std::string>& attrs, const std::multiset<std::string>& nodes) override;
|
||||
bool isClickable() const override;
|
||||
bool isFocusable() const override;
|
||||
bool isScrollable() const override;
|
||||
void draw() override;
|
||||
bool hasChild(std::string id) const override;
|
||||
cControl& getChild(std::string id) override;
|
||||
bool hasChild(std::string id, size_t x, size_t y) const;
|
||||
cControl& getChild(std::string id, size_t x, size_t y);
|
||||
bool hasChild(size_t x, size_t y) const;
|
||||
cControl& getChild(size_t x, size_t y);
|
||||
/// Recalculate the tilemap's bounding rect based on its contained controls.
|
||||
void recalcRect() override;
|
||||
/// Adds any fields in this tilemap to the tab order building arrays.
|
||||
/// Meant for internal use.
|
||||
void fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reverseTabs);
|
||||
/// Create a new tilemap
|
||||
/// @param parent The parent dialog.
|
||||
cTilemap(cDialog& parent);
|
||||
/// @copydoc cControl::getSupportedHandlers
|
||||
///
|
||||
/// @todo Document possible handlers
|
||||
std::set<eDlogEvt> getSupportedHandlers() const override {
|
||||
return {EVT_CLICK, EVT_FOCUS, EVT_DEFOCUS};
|
||||
}
|
||||
void forEach(std::function<void(std::string,cControl&)> callback) override;
|
||||
};
|
||||
|
||||
#endif
|
@@ -259,7 +259,7 @@ The `<stack>` tag
|
||||
-----------------
|
||||
|
||||
The `<stack>` tag groups elements that represent a single entry in an array.
|
||||
It can contain any elements except for nested `<stack>` or `<pane>` elements.
|
||||
It can contain any elements except for nested `<stack>`, `<pane>`, or `<tilemap>` elements.
|
||||
|
||||
The `<stack>` tag accepts the following attributes:
|
||||
|
||||
@@ -287,7 +287,7 @@ The `<pane>` tag
|
||||
----------------
|
||||
|
||||
The `<pane>` tag groups elements into a scrollable subpane.
|
||||
It can contain any elements except for nested `<stack>` or `<pane>` elements.
|
||||
It can contain any elements except for nested `<stack>`, `<pane>`, or `<tilemap>` elements.
|
||||
|
||||
The `<pane>` tag accepts the following attributes:
|
||||
|
||||
@@ -295,6 +295,20 @@ The `<pane>` tag accepts the following attributes:
|
||||
* `outline` - See **Common Attributes** above.
|
||||
* `style` - Same as for `<slider>`, see above. Applies to the pane's scrollbar.
|
||||
|
||||
The `<tilemap>` tag
|
||||
-------------------
|
||||
|
||||
The `<tilemap>` tag represents a grid of identical elements based off the provided template.
|
||||
It can contain any elements except for nested `<stack>`, `<pane>`, or `<tilemap>` elements.
|
||||
|
||||
The `<tilemap>` tag accepts the following attributes:
|
||||
|
||||
* `framed` - See **Common Attributes** above. Defaults to `false`.
|
||||
* `outline` - See **Common Attributes** above.
|
||||
* `rows` - The number of rows to generate. Required.
|
||||
* `cols` - The number of columns to generate. Required.
|
||||
* `cellspacing` - If specified, adds a buffer of this size between each cell.
|
||||
|
||||
Keyboard Shortcuts
|
||||
------------------
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "dialogxml/dialogs/dialog.hpp"
|
||||
#include "dialogxml/widgets/control.hpp"
|
||||
#include "dialogxml/widgets/button.hpp"
|
||||
#include "dialogxml/widgets/tilemap.hpp"
|
||||
#include "dialogxml/dialogs/strdlog.hpp"
|
||||
#include "dialogxml/dialogs/3choice.hpp"
|
||||
#include "dialogxml/dialogs/strchoice.hpp"
|
||||
@@ -517,10 +518,10 @@ static bool edit_ter_obj(cDialog& me, ter_num_t which_ter) {
|
||||
obj[check.obj_pos.x][check.obj_pos.y] = check.picture;
|
||||
}
|
||||
obj[me["x"].getTextAsNum()][me["y"].getTextAsNum()] = pic;
|
||||
cTilemap& map = dynamic_cast<cTilemap&>(me["map"]);
|
||||
for(int x = 0; x < 4; x++) {
|
||||
for(int y = 0; y < 4; y++) {
|
||||
std::string id = "x" + std::to_string(x) + "y" + std::to_string(y);
|
||||
dynamic_cast<cPict&>(me[id]).setPict(obj[x][y]);
|
||||
dynamic_cast<cPict&>(map.getChild(x,y)).setPict(obj[x][y]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user