main_window.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * main_window.cpp - main window
  3. * Copyright (C) 2017 caryoscelus
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <fstream>
  19. #include <fmt/format.h>
  20. #include <QFileDialog>
  21. #include <QErrorMessage>
  22. #include <QMessageBox>
  23. #include <QDebug>
  24. #include <core/document.h>
  25. #include <core/filters/svg_path_reader.h>
  26. #include <core/filters/json_reader.h>
  27. #include <core/filters/json_writer.h>
  28. #include <core/renderers/svg_renderer.h>
  29. #include <docks/time_dock.h>
  30. #include <docks/playback_dock.h>
  31. #include <docks/node_tree_dock.h>
  32. #include <docks/node_edit_dock.h>
  33. #include "about.h"
  34. #include "main_window.h"
  35. #include "ui_main_window.h"
  36. using namespace fmt::literals;
  37. namespace studio {
  38. MainWindow::MainWindow(QWidget* parent) :
  39. QMainWindow(parent),
  40. ContextListener(),
  41. ui(std::make_unique<Ui::MainWindow>()),
  42. error_box(std::make_unique<QErrorMessage>())
  43. {
  44. setWindowState(Qt::WindowMaximized);
  45. ui->setupUi(this);
  46. connect(ui->action_new, SIGNAL(triggered()), this, SLOT(new_document()));
  47. connect(ui->action_open, SIGNAL(triggered()), this, SLOT(open()));
  48. connect(ui->action_reload, SIGNAL(triggered()), this, SLOT(reload()));
  49. connect(ui->action_save, SIGNAL(triggered()), this, SLOT(save()));
  50. connect(ui->action_save_as, SIGNAL(triggered()), this, SLOT(save_as()));
  51. connect(ui->action_about, SIGNAL(triggered()), this, SLOT(about()));
  52. connect(ui->action_quit, SIGNAL(triggered()), this, SLOT(quit()));
  53. connect(ui->action_undo, SIGNAL(triggered()), this, SLOT(undo()));
  54. connect(ui->action_redo, SIGNAL(triggered()), this, SLOT(redo()));
  55. connect(ui->action_tool_mouse, SIGNAL(triggered()), this, SLOT(tool_mouse()));
  56. connect(ui->action_tool_zoom, SIGNAL(triggered()), this, SLOT(tool_zoom()));
  57. connect(ui->action_render, SIGNAL(triggered()), this, SLOT(render()));
  58. connect(ui->action_redraw, SIGNAL(triggered()), this, SLOT(redraw()));
  59. connect(ui->action_extra_style, SIGNAL(toggled(bool)), this, SLOT(toggle_extra_style(bool)));
  60. connect(ui->action_time_dock, SIGNAL(triggered()), this, SLOT(add_time_dock()));
  61. connect(ui->action_playback_dock, SIGNAL(triggered()), this, SLOT(add_playback_dock()));
  62. connect(ui->action_node_tree_dock, SIGNAL(triggered()), this, SLOT(add_node_tree_dock()));
  63. add_playback_dock();
  64. add_time_dock();
  65. add_node_tree_dock();
  66. add_node_edit_dock();
  67. new_document();
  68. }
  69. MainWindow::~MainWindow() {
  70. }
  71. void MainWindow::new_document() {
  72. document = std::make_shared<core::Document>();
  73. set_core_context(document->get_default_context());
  74. }
  75. void MainWindow::open() {
  76. auto fname_qt = QFileDialog::getOpenFileName(this, "Open", "", "RainyNite file (*.rnite)(*.rnite);;Svg paths (*.svgpaths)(*.svgpaths);;All files(*)");
  77. fname = fname_qt.toStdString();
  78. reload();
  79. }
  80. void MainWindow::reload() {
  81. if (fname.empty())
  82. return;
  83. // TODO: proper filter modularization
  84. try {
  85. auto reader = core::filters::JsonReader();
  86. std::ifstream in(fname);
  87. document = reader.read_document(in);
  88. if (!document)
  89. throw std::runtime_error("Unknown parse failure");
  90. set_core_context(document->get_default_context());
  91. in.close();
  92. return;
  93. } catch (std::exception const& ex) {
  94. auto msg = QString::fromStdString("Uncaught exception in JSON filter:\n{}"_format(ex.what()));
  95. qDebug() << msg;
  96. } catch (...) {
  97. qDebug() << "Unknown error while trying to open document via JSON filter";
  98. }
  99. try {
  100. auto reader = core::filters::SvgPathReader();
  101. std::ifstream in(fname);
  102. document = reader.read_document(in);
  103. set_core_context(document->get_default_context());
  104. in.close();
  105. } catch (std::exception const& ex) {
  106. auto msg = QString::fromStdString("Uncaught exception while opening document:\n{}"_format(ex.what()));
  107. qDebug() << msg;
  108. error_box->showMessage(msg);
  109. } catch (...) {
  110. qDebug() << "Unknown error while opening document";
  111. }
  112. }
  113. void MainWindow::save_as() {
  114. auto fname_qt = QFileDialog::getSaveFileName(this, "Save", "", "RainyNite file (*.rnite)(*.rnite);;All files(*)");
  115. fname = fname_qt.toStdString();
  116. if (!fname.empty())
  117. save();
  118. }
  119. void MainWindow::save() {
  120. if (fname.empty()) {
  121. save_as();
  122. return;
  123. }
  124. try {
  125. auto writer = core::filters::JsonWriter();
  126. std::ofstream out(fname);
  127. writer.write_document(out, document);
  128. } catch (std::exception const& ex) {
  129. auto msg = QString::fromStdString("Uncaught exception while saving document:\n{}"_format(ex.what()));
  130. qDebug() << msg;
  131. error_box->showMessage(msg);
  132. } catch (...) {
  133. qDebug() << "Unknown error while saving document";
  134. }
  135. }
  136. void MainWindow::render() {
  137. if (get_core_context()->get_document()) {
  138. auto rsettings = core::renderers::SvgRendererSettings();
  139. rsettings.render_pngs = true;
  140. rsettings.extra_style = extra_style;
  141. get_core_context()->mod_render_settings() = rsettings;
  142. auto renderer = std::make_shared<core::renderers::SvgRenderer>();
  143. if (render_thread.joinable())
  144. render_thread.join();
  145. auto ctx = *get_core_context();
  146. render_thread = std::thread([renderer, ctx]() {
  147. try {
  148. renderer->render(ctx);
  149. } catch (std::exception const& ex) {
  150. auto msg = QString::fromStdString("Uncaught exception while rendering:\n{}"_format(ex.what()));
  151. qDebug() << msg;
  152. }
  153. });
  154. }
  155. }
  156. void MainWindow::redraw() {
  157. set_mainarea_image("renders/{:.3f}.png"_format(get_core_context()->get_time().get_seconds()));
  158. }
  159. void MainWindow::toggle_extra_style(bool checked) {
  160. extra_style = checked;
  161. }
  162. void MainWindow::undo() {
  163. get_context()->action_stack().undo();
  164. }
  165. void MainWindow::redo() {
  166. get_context()->action_stack().redo();
  167. }
  168. void MainWindow::tool_mouse() {
  169. qDebug() << "mouse selected";
  170. }
  171. void MainWindow::tool_zoom() {
  172. qDebug() << "zoom selected";
  173. }
  174. void MainWindow::about() {
  175. AboutDialog dialog;
  176. dialog.exec();
  177. }
  178. void MainWindow::quit() {
  179. if (render_thread.joinable())
  180. render_thread.join();
  181. QApplication::quit();
  182. }
  183. void MainWindow::set_mainarea_image(std::string const& fname) {
  184. QPixmap pixmap;
  185. pixmap.load(QString::fromStdString(fname));
  186. ui->canvas->set_main_image(pixmap);
  187. }
  188. void MainWindow::add_time_dock() {
  189. auto dock = new TimeDock(get_context(), this);
  190. addDockWidget(Qt::BottomDockWidgetArea, dock);
  191. }
  192. void MainWindow::add_playback_dock() {
  193. auto dock = new PlaybackDock(get_context(), this);
  194. addDockWidget(Qt::BottomDockWidgetArea, dock);
  195. }
  196. void MainWindow::add_node_tree_dock() {
  197. auto dock = new NodeTreeDock(get_context(), this);
  198. addDockWidget(Qt::LeftDockWidgetArea, dock);
  199. }
  200. void MainWindow::add_node_edit_dock() {
  201. auto dock = new NodeEditDock(get_context(), this);
  202. addDockWidget(Qt::LeftDockWidgetArea, dock);
  203. }
  204. void MainWindow::set_context(std::shared_ptr<EditorContext> context_) {
  205. ContextListener::set_context(context_);
  206. get_context()->changed_time().connect([this](core::Time){
  207. redraw();
  208. });
  209. for (auto dock : findChildren<QWidget*>()) {
  210. if (auto ctx_dock = dynamic_cast<ContextListener*>(dock))
  211. ctx_dock->set_context(context_);
  212. if (dock->metaObject()->indexOfSignal("activated(std::shared_ptr<core::AbstractValue>)") != -1)
  213. connect(dock, SIGNAL(activated(std::shared_ptr<core::AbstractValue>)), this, SLOT(activate(std::shared_ptr<core::AbstractValue>)));
  214. }
  215. }
  216. void MainWindow::activate(std::shared_ptr<core::AbstractValue> node) {
  217. get_context()->set_active_node(node);
  218. }
  219. }