Peoplemon  0.1.0
Peoplemon 3 game source documentation
BehaviorEditor.cpp
Go to the documentation of this file.
2 
3 namespace editor
4 {
5 namespace component
6 {
7 using namespace bl::gui;
8 
9 namespace
10 {
11 std::string getLabel(core::file::Behavior::Type t) {
13 
14  std::stringstream ss;
15  ss << "Behavior: ";
16  switch (t) {
17  case T::FollowingPath:
18  ss << "Fixed Path";
19  break;
20  case T::SpinInPlace:
21  ss << "Spin";
22  break;
23  case T::StandStill:
24  ss << "Stand Still";
25  break;
26  case T::Wandering:
27  ss << "Wander";
28  break;
29  default:
30  ss << "<unset>";
31  break;
32  }
33  return ss.str();
34 }
35 
36 bool isNumber(const std::string& i) {
37  if (i.empty()) return false;
38  for (char c : i) {
39  if (c < '0' || c > '9') return false;
40  }
41  return true;
42 }
43 
44 } // namespace
45 
47  const NotifyWindowCb& oc)
48 : onSetCb(cb)
49 , onOpen(op)
50 , onClose(oc) {
51  window = Window::create(LinePacker::create(LinePacker::Vertical, 8), "Behavior Editor");
52  window->getSignal(Event::Closed).willAlwaysCall([this](const Event&, Element*) { hide(); });
53 
54  typeLabel = Label::create("");
55  notebook = Notebook::create();
56 
57  Box::Ptr page = Box::create(LinePacker::create(LinePacker::Vertical, 4));
58  Box::Ptr row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
59  dirBox = ComboBox::create();
60  dirBox->addOption("Up");
61  dirBox->addOption("Right");
62  dirBox->addOption("Down");
63  dirBox->addOption("Left");
64  dirBox->setSelectedOption(0);
65  row->pack(Label::create("Direction:"));
66  row->pack(dirBox);
67  page->pack(row, true, true);
68  notebook->addPage("stand", "Stand Still", page);
69 
70  page = Box::create(LinePacker::create(LinePacker::Vertical, 4));
71  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
72  spinBox = ComboBox::create();
73  spinBox->addOption("Clockwise");
74  spinBox->addOption("Counter-Clockwise");
75  spinBox->addOption("Random");
76  spinBox->setSelectedOption(0);
77  row->pack(Label::create("Spin Direction:"));
78  row->pack(spinBox);
79  page->pack(row, true, true);
80  notebook->addPage("spin", "Spin", page);
81 
82  page = Box::create(LinePacker::create(LinePacker::Vertical, 4));
83  pathEditor.pack(page);
84  notebook->addPage("path", "Path", page);
85 
86  page = Box::create(LinePacker::create(LinePacker::Vertical, 4));
87  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
88  row->pack(Label::create("Radius (tiles):"), false, false);
89  radiusEntry = TextEntry::create();
90  radiusEntry->setInput("7");
91  radiusEntry->setMode(TextEntry::Mode::Integer);
92  row->pack(radiusEntry, true, false);
93  page->pack(row, true, true);
94  notebook->addPage("wander", "Wander", page);
95 
96  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
97  Button::Ptr setBut = Button::create("Save");
98  setBut->setColor(sf::Color::Green, sf::Color::Black);
99  setBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
100  using T = core::file::Behavior::Type;
101  switch (notebook->getActivePageIndex()) {
102  case 0:
103  value.setType(T::StandStill);
104  value.standing().facedir =
105  static_cast<bl::tmap::Direction>(dirBox->getSelectedOption());
106  break;
107 
108  case 1:
109  value.setType(T::SpinInPlace);
110  value.spinning().spinDir = static_cast<core::file::Behavior::Spinning::Direction>(
111  spinBox->getSelectedOption());
112  break;
113 
114  case 2:
115  value.setType(T::FollowingPath);
116  value.path() = pathEditor.getValue();
117  break;
118 
119  case 3:
120  if (isNumber(radiusEntry->getInput())) {
121  value.setType(T::Wandering);
122  value.wander().radius = std::atoi(radiusEntry->getInput().c_str());
123  }
124  else {
125  bl::dialog::tinyfd_messageBox(
126  "Error", "Radius must be a positive integer", "ok", "error", 1);
127  return;
128  }
129  break;
130  }
131 
132  typeLabel->setText(getLabel(value.type()));
133  onSetCb();
134  hide();
135  });
136  row->pack(setBut, false, true);
137  Button::Ptr cancelBut = Button::create("Cancel");
138  cancelBut->setColor(sf::Color::Red, sf::Color::Black);
139  cancelBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
140  value = ogValue;
141  hide();
142  });
143  row->pack(cancelBut, false, true);
144  window->pack(notebook, true, true);
145  window->pack(row, true, false);
146 }
147 
148 void BehaviorEditor::pack(Box::Ptr row) {
149  row->pack(typeLabel, true, true);
150  Button::Ptr editBut = Button::create("Edit Behavior");
151  editBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
152  ogValue = value;
153  onOpen();
154  parent->pack(window);
155  window->setForceFocus(true);
156  });
157  row->pack(editBut, false, true);
158 }
159 
160 void BehaviorEditor::configure(GUI* p, const core::file::Behavior& behavior) {
161  using T = core::file::Behavior::Type;
162 
163  parent = p;
164  value = ogValue = behavior;
165 
166  typeLabel->setText(getLabel(behavior.type()));
167  switch (behavior.type()) {
168  case T::StandStill:
169  notebook->makePageActive(0);
170  dirBox->setSelectedOption(static_cast<int>(behavior.standing().facedir));
171  break;
172 
173  case T::SpinInPlace:
174  notebook->makePageActive(1);
175  spinBox->setSelectedOption(static_cast<int>(behavior.spinning().spinDir));
176  break;
177 
178  case T::FollowingPath:
179  notebook->makePageActive(2);
180  pathEditor.init(behavior.path());
181  break;
182 
183  case T::Wandering:
184  notebook->makePageActive(3);
185  radiusEntry->setInput(std::to_string(behavior.wander().radius));
186  break;
187  }
188 }
189 
190 void BehaviorEditor::hide() {
191  window->remove();
192  window->setForceFocus(false);
193  onClose();
194 }
195 
196 const core::file::Behavior& BehaviorEditor::getValue() const { return value; }
197 
198 BehaviorEditor::PathEditor::PathEditor() {
199  container = ScrollArea::create(LinePacker::create(LinePacker::Vertical, 6));
200  container->setOutlineThickness(1);
201  container->setColor(sf::Color::Transparent, sf::Color::Black);
202  container->setMaxSize({10000.f, 300.f});
203  container->includeScrollbarsInRequisition(true);
204 }
205 
206 void BehaviorEditor::PathEditor::pack(Box::Ptr parent) {
207  Box::Ptr row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
208  toggle = CheckButton::create("Reverse Path At End");
209  toggle->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
210  value.reverse = toggle->getValue();
211  });
212  row->pack(toggle, false, true);
213  parent->pack(row);
214  parent->pack(Label::create("Paces:"));
215  parent->pack(container, true, true);
216 
217  Button::Ptr appendBut = Button::create("Add Pace");
218  appendBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element* e) {
219  value.paces.emplace_back(bl::tmap::Direction::Down, 1);
220  e->queueUpdateAction(std::bind(&BehaviorEditor::PathEditor::sync, this));
221  });
222  parent->pack(appendBut);
223 }
224 
225 void BehaviorEditor::PathEditor::init(const core::file::Behavior::Path& path) {
226  value = path;
227  sync();
228 }
229 
230 const core::file::Behavior::Path& BehaviorEditor::PathEditor::getValue() const { return value; }
231 
232 void BehaviorEditor::PathEditor::sync() {
233  container->clearChildren(true);
234 
235  for (unsigned int i = 0; i < value.paces.size(); ++i) {
236  auto& pace = value.paces[i];
237  Box::Ptr row = Box::create(LinePacker::create(LinePacker::Horizontal));
238  ComboBox::Ptr dirBox = ComboBox::create();
239  dirBox->addOption("Up");
240  dirBox->addOption("Right");
241  dirBox->addOption("Down");
242  dirBox->addOption("Left");
243  dirBox->getSignal(Event::ValueChanged)
244  .willAlwaysCall([&pace, dirBox](const Event&, Element*) {
245  pace.direction =
246  static_cast<bl::tmap::Direction>(dirBox->getSelectedOption());
247  });
248  dirBox->setSelectedOption(static_cast<int>(pace.direction));
249  row->pack(dirBox, false, true);
250 
251  TextEntry::Ptr stepEntry = TextEntry::create();
252  stepEntry->setInput(std::to_string(pace.steps));
253  stepEntry->setColor(sf::Color::Green, sf::Color::Transparent);
254  stepEntry->getSignal(Event::TextEntered)
255  .willAlwaysCall([&pace, stepEntry](const Event&, Element*) {
256  if (isNumber(stepEntry->getInput())) {
257  stepEntry->setColor(sf::Color::Green, sf::Color::Transparent);
258  pace.steps = std::atoi(stepEntry->getInput().c_str());
259  }
260  else { stepEntry->setColor(sf::Color::Red, sf::Color::Transparent); }
261  });
262  stepEntry->setRequisition({80, 1});
263  row->pack(Label::create("Steps:"), false, true);
264  row->pack(stepEntry, true, true);
265 
266  Button::Ptr beforeBut = Button::create("Add Before");
267  beforeBut->getSignal(Event::LeftClicked)
268  .willAlwaysCall([this, i](const Event&, Element* e) {
269  value.paces.insert(value.paces.begin() + i, {bl::tmap::Direction::Down, 1});
270  e->queueUpdateAction(std::bind(&BehaviorEditor::PathEditor::sync, this));
271  });
272  row->pack(beforeBut, false, true);
273 
274  Button::Ptr afterBut = Button::create("Add After");
275  afterBut->getSignal(Event::LeftClicked).willAlwaysCall([this, i](const Event&, Element* e) {
276  value.paces.insert(value.paces.begin() + i + 1, {bl::tmap::Direction::Down, 1});
277  e->queueUpdateAction(std::bind(&BehaviorEditor::PathEditor::sync, this));
278  });
279  row->pack(afterBut, false, true);
280 
281  Button::Ptr delBut = Button::create("Remove");
282  delBut->setColor(sf::Color::Red, sf::Color::Black);
283  delBut->getSignal(Event::LeftClicked).willAlwaysCall([this, i](const Event&, Element* e) {
284  value.paces.erase(value.paces.begin() + i);
285  e->queueUpdateAction(std::bind(&BehaviorEditor::PathEditor::sync, this));
286  });
287  row->pack(delBut, false, true);
288 
289  container->pack(row, false, true);
290  }
291 }
292 
293 } // namespace component
294 } // namespace editor
All classes and functionality used for implementing the game editor.
Definition: Tile.hpp:11
Set of behaviors for NPCs and trainers.
Definition: Behavior.hpp:19
Spinning & spinning()
The data for spinning.
Definition: Behavior.cpp:106
Type type() const
The type of behavior this is.
Definition: Behavior.cpp:75
Wander & wander()
The data for wandering.
Definition: Behavior.cpp:114
Standing & standing()
The data for standing still.
Definition: Behavior.cpp:102
Type
The type of behavior.
Definition: Behavior.hpp:22
Path & path()
The data for path following.
Definition: Behavior.cpp:110
bl::tmap::Direction facedir
The direction to face.
Definition: Behavior.hpp:39
enum core::file::Behavior::Spinning::Direction spinDir
Contains data for when the behavior type is following a path.
Definition: Behavior.hpp:70
std::vector< Pace > paces
The sections of the path.
Definition: Behavior.hpp:95
std::uint32_t radius
The radius to stay within, in tiles.
Definition: Behavior.hpp:107
std::function< void()> OnSetCb
BehaviorEditor(const OnSetCb &cb, const NotifyWindowCb &onOpen, const NotifyWindowCb &onClose)
Construct a new Behavior Editor.
void hide()
Hides the editor window if opened.
std::function< void()> NotifyWindowCb