Peoplemon  0.1.0
Peoplemon 3 game source documentation
NPCEditorWindow.cpp
Go to the documentation of this file.
2 
3 #include <Core/Files/NPC.hpp>
4 #include <Core/Properties.hpp>
5 
6 namespace editor
7 {
8 namespace component
9 {
10 namespace
11 {
12 const std::string EmptyFile = "<no file selected>";
13 }
14 using namespace bl::gui;
16 
18 : selectCb(cb)
19 , closeCb(ccb)
20 , clean(true)
21 , filePicker(core::Properties::NpcPath(), {"npc"},
22  std::bind(&NpcEditorWindow::onChooseFile, this, std::placeholders::_1),
23  [this]() {
24  filePicker.close();
25  window->setForceFocus(true);
26  })
27 , animWindow(true, std::bind(&NpcEditorWindow::onChooseAnimation, this, std::placeholders::_1),
28  std::bind(&NpcEditorWindow::forceWindowOnTop, this))
29 , behaviorEditor(
30  std::bind(&NpcEditorWindow::makeDirty, this), [this]() { window->setForceFocus(false); },
31  std::bind(&NpcEditorWindow::forceWindowOnTop, this))
32 , conversationWindow(std::bind(&NpcEditorWindow::onChooseConversation, this, std::placeholders::_1),
33  std::bind(&NpcEditorWindow::forceWindowOnTop, this)) {
34  window = Window::create(LinePacker::create(LinePacker::Vertical, 8), "NPC Editor");
35  window->getSignal(Event::Closed).willAlwaysCall([this](const Event&, Element*) { hide(); });
36 
37  Box::Ptr row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
38  Button::Ptr newBut = Button::create("New");
39  newBut->setTooltip("Create a new NPC file");
40  newBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
41  if (confirmDiscard()) {
42  makingNew = true;
43  window->setForceFocus(false);
44  filePicker.open(FilePicker::CreateNew, "New NPC", parent, true);
45  }
46  });
47  Button::Ptr setBut = Button::create("Set File");
48  setBut->setTooltip("Change the file to save this NPC to");
49  setBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
50  if (fileLabel->getText() == EmptyFile || confirmDiscard()) {
51  makingNew = true;
52  window->setForceFocus(false);
53  filePicker.open(FilePicker::CreateOrPick, "Set NPC File", parent, false);
54  }
55  });
56  Button::Ptr openBut = Button::create("Open");
57  openBut->setTooltip("Open a different NPC file");
58  openBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
59  if (confirmDiscard()) {
60  makingNew = false;
61  window->setForceFocus(false);
62  filePicker.open(FilePicker::PickExisting, "Open NPC", parent, false);
63  }
64  });
65  saveBut = Button::create("Save");
66  saveBut->setTooltip("Overwrite the current NPC file");
67  saveBut->setColor(sf::Color::Yellow, sf::Color::Blue);
68  saveBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
69  if (validate(true)) {
70  core::file::NPC npc;
71  npc.name() = nameEntry->getInput();
72  npc.conversation() = convLabel->getText();
73  npc.animation() = animLabel->getText();
74  npc.behavior() = behaviorEditor.getValue();
75  if (!npc.save(bl::util::FileUtil::joinPath(core::Properties::NpcPath(),
76  fileLabel->getText()))) {
77  bl::dialog::tinyfd_messageBox("Error", "Failed to save NPC", "ok", "error", 1);
78  }
79  else { makeClean(); }
80  }
81  });
82  fileLabel = Label::create("filename.npc");
83  fileLabel->setColor(sf::Color::Cyan, sf::Color::Cyan);
84  row->pack(newBut, false, true);
85  row->pack(setBut, false, true);
86  row->pack(openBut, false, true);
87  row->pack(saveBut, false, true);
88  row->pack(fileLabel, true, true);
89  window->pack(row, true, false);
90 
91  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
92  Label::Ptr label = Label::create("Name:");
93  nameEntry = TextEntry::create();
94  nameEntry->getSignal(Event::ValueChanged)
95  .willAlwaysCall(std::bind(&NpcEditorWindow::makeDirty, this));
96  row->pack(label, false, true);
97  row->pack(nameEntry, true, true);
98  window->pack(row, true, false);
99 
100  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
101  Button::Ptr animBut = Button::create("Select Anim");
102  animBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
103  window->setForceFocus(false);
104  animWindow.open(parent, core::Properties::CharacterAnimationPath(), animLabel->getText());
105  });
106  animLabel = Label::create("animation.anim");
107  animLabel->setColor(sf::Color::Cyan, sf::Color::Cyan);
108  row->pack(animBut, false, true);
109  row->pack(animLabel, true, true);
110  window->pack(row, true, false);
111 
112  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
113  Button::Ptr convBut = Button::create("Select Conversation");
114  convBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
115  window->setForceFocus(false);
116  conversationWindow.open(parent, convLabel->getText());
117  });
118  convLabel = Label::create("conversation.conv");
119  convLabel->setColor(sf::Color::Cyan, sf::Color::Cyan);
120  row->pack(convBut, false, true);
121  row->pack(convLabel, true, true);
122  window->pack(row, true, false);
123 
124  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
125  behaviorEditor.pack(row);
126  window->pack(row, true, false);
127 
128  row = Box::create(LinePacker::create(LinePacker::Horizontal, 4));
129  Button::Ptr selectBut = Button::create("Use NPC");
130  selectBut->setTooltip("Use the current NPC file");
131  selectBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
132  if (confirmDiscard()) {
133  if (validate(false)) {
134  selectCb(fileLabel->getText());
135  hide();
136  }
137  }
138  });
139  selectBut->setColor(sf::Color::Blue, sf::Color::Black);
140  Button::Ptr cancelBut = Button::create("Cancel");
141  cancelBut->getSignal(Event::LeftClicked).willAlwaysCall([this](const Event&, Element*) {
142  hide();
143  });
144  cancelBut->setColor(sf::Color::Red, sf::Color::Black);
145  row->pack(selectBut, false, true);
146  row->pack(cancelBut, false, true);
147  window->pack(row, true, false);
148 }
149 
150 void NpcEditorWindow::show(GUI* p, const std::string& file) {
151  parent = p;
152  reset();
153  if (!file.empty()) {
154  fileLabel->setText(file);
155  load(file);
156  }
157  makeClean();
158  parent->pack(window);
159  window->setForceFocus(true);
160 }
161 
162 void NpcEditorWindow::onChooseFile(const std::string& file) {
163  const std::string f =
164  bl::util::FileUtil::getExtension(file) == core::Properties::NpcFileExtension() ?
165  file :
166  file + "." + core::Properties::NpcFileExtension();
167  filePicker.close();
168  window->setForceFocus(true);
169  if (makingNew) { makeDirty(); }
170  else {
171  reset();
172  load(f);
173  makeClean();
174  }
175  fileLabel->setText(f);
176 }
177 
178 void NpcEditorWindow::makeClean() {
179  saveBut->setColor(sf::Color::Green, sf::Color::Blue);
180  clean = true;
181 }
182 
183 void NpcEditorWindow::makeDirty() {
184  saveBut->setColor(sf::Color::Yellow, sf::Color::Blue);
185  clean = false;
186 }
187 
188 void NpcEditorWindow::reset() {
189  fileLabel->setText(EmptyFile);
190  nameEntry->setInput("");
191  animLabel->setText("<no anim selected>");
192  convLabel->setText("<no conv selected>");
193  behaviorEditor.configure(parent, {});
194 }
195 
196 void NpcEditorWindow::load(const std::string& file) {
197  core::file::NPC npc;
198  if (npc.load(FileUtil::joinPath(core::Properties::NpcPath(), file))) {
199  nameEntry->setInput(npc.name());
200  animLabel->setText(npc.animation());
201  convLabel->setText(npc.conversation());
202  behaviorEditor.configure(parent, npc.behavior());
203  }
204  else {
205  bl::dialog::tinyfd_messageBox(
206  "Error", std::string("Failed to load NPC:\n" + file).c_str(), "ok", "error", 1);
207  }
208 }
209 
210 bool NpcEditorWindow::validate(bool saving) const {
211  if (saving) {
212  if (fileLabel->getText() == EmptyFile) {
213  bl::dialog::tinyfd_messageBox("Warning", "Please select a file", "ok", "warning", 1);
214  return false;
215  }
216  }
217  else {
218  if (!FileUtil::exists(
219  FileUtil::joinPath(core::Properties::NpcPath(), fileLabel->getText()))) {
220  bl::dialog::tinyfd_messageBox("Warning", "Bad file selected", "ok", "warning", 1);
221  return false;
222  }
223  }
224  if (nameEntry->getInput().empty()) {
225  bl::dialog::tinyfd_messageBox("Warning", "Enter a name", "ok", "warning", 1);
226  return false;
227  }
228  if (!FileUtil::directoryExists(
229  FileUtil::joinPath(core::Properties::CharacterAnimationPath(), animLabel->getText()))) {
230  bl::dialog::tinyfd_messageBox("Warning", "Bad animation", "ok", "warning", 1);
231  return false;
232  }
233  const std::string p =
234  FileUtil::joinPath(core::Properties::ConversationPath(), convLabel->getText());
235  if (!FileUtil::exists(p)) {
236  bl::dialog::tinyfd_messageBox("Warning", "Bad conversation", "ok", "warning", 1);
237  return false;
238  }
239  if (behaviorEditor.getValue().type() == core::file::Behavior::Type::FollowingPath &&
240  behaviorEditor.getValue().path().paces.empty()) {
241  bl::dialog::tinyfd_messageBox("Warning", "Behavior path is empty", "ok", "warning", 1);
242  return false;
243  }
244  return true;
245 }
246 
247 bool NpcEditorWindow::confirmDiscard() const {
248  if (!clean) {
249  return 1 == bl::dialog::tinyfd_messageBox(
250  "Warning", "Discard unsaved changes?", "yesno", "warning", 0);
251  }
252  return true;
253 }
254 
256  window->remove();
257  filePicker.close();
258  animWindow.hide();
259  behaviorEditor.hide();
260  window->setForceFocus(false);
261  closeCb();
262 }
263 
264 void NpcEditorWindow::onChooseAnimation(const std::string& f) {
265  animLabel->setText(f);
266  makeDirty();
267 }
268 
269 void NpcEditorWindow::onChooseConversation(const std::string& c) {
270  convLabel->setText(c);
271  window->setForceFocus(true);
272  makeDirty();
273 }
274 
275 void NpcEditorWindow::forceWindowOnTop() { window->setForceFocus(true); }
276 
277 } // namespace component
278 } // namespace editor
Core classes and functionality for both the editor and game.
All classes and functionality used for implementing the game editor.
Definition: Tile.hpp:11
bl::util::FileUtil FileUtil
Type type() const
The type of behavior this is.
Definition: Behavior.cpp:75
Path & path()
The data for path following.
Definition: Behavior.cpp:110
std::vector< Pace > paces
The sections of the path.
Definition: Behavior.hpp:95
File data for NPCs.
Definition: NPC.hpp:26
bool save(const std::string &file) const
Saves the NPC data to the given file.
Definition: NPC.cpp:10
std::string & conversation()
The conversation file of the NPC.
Definition: NPC.cpp:58
Behavior & behavior()
The behavior of the NPC.
Definition: NPC.cpp:62
std::string & name()
The name of the NPC.
Definition: NPC.cpp:50
bool load(const std::string &file, bl::tmap::Direction spawnDir=bl::tmap::Direction::Up)
Loads the NPC data from the given file.
Definition: NPC.cpp:36
std::string & animation()
The directory of the movement animations.
Definition: NPC.cpp:54
static const std::string & NpcFileExtension()
Definition: Properties.cpp:515
static const std::string & ConversationPath()
Definition: Properties.cpp:539
static const std::string & NpcPath()
Definition: Properties.cpp:521
static const std::string & CharacterAnimationPath()
Definition: Properties.cpp:557
void hide()
Removes the window from view.
const core::file::Behavior & getValue() const
Returns the behavior value.
void hide()
Hides the editor window if opened.
void configure(bl::gui::GUI *parent, const core::file::Behavior &behavior)
Sets the parent GUI object and current value. Call before using.
std::function< void(const std::string &file)> SelectCb
Callback for when an NPC file is selected.
void hide()
Hides the window and all created child windows.
NpcEditorWindow(const SelectCb &cb, const CloseCb &closeCb)
Construct a new Npc Editor Window.
void show(bl::gui::GUI *parent, const std::string &file)
Opens the NPC editor.
std::function< void()> CloseCb
Called when the window is closed.