main_window.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. ui(std::make_unique<Ui::MainWindow>()),
  41. error_box(std::make_unique<QErrorMessage>()),
  42. context(std::make_shared<core::Context>())
  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_tool_mouse, SIGNAL(triggered()), this, SLOT(tool_mouse()));
  54. connect(ui->action_tool_zoom, SIGNAL(triggered()), this, SLOT(tool_zoom()));
  55. connect(ui->action_render, SIGNAL(triggered()), this, SLOT(render()));
  56. connect(ui->action_redraw, SIGNAL(triggered()), this, SLOT(redraw()));
  57. connect(ui->action_extra_style, SIGNAL(toggled(bool)), this, SLOT(toggle_extra_style(bool)));
  58. connect(ui->action_time_dock, SIGNAL(triggered()), this, SLOT(add_time_dock()));
  59. connect(ui->action_playback_dock, SIGNAL(triggered()), this, SLOT(add_playback_dock()));
  60. connect(ui->action_node_tree_dock, SIGNAL(triggered()), this, SLOT(add_node_tree_dock()));
  61. add_playback_dock();
  62. add_time_dock();
  63. add_node_tree_dock();
  64. add_node_edit_dock();
  65. new_document();
  66. }
  67. MainWindow::~MainWindow() {
  68. }
  69. void MainWindow::new_document() {
  70. document = std::make_shared<core::Document>();
  71. set_context(document->get_default_context());
  72. }
  73. void MainWindow::open() {
  74. auto fname_qt = QFileDialog::getOpenFileName(this, "Open", "", "RainyNite file (*.rnite)(*.rnite);;Svg paths (*.svgpaths)(*.svgpaths);;All files(*)");
  75. fname = fname_qt.toStdString();
  76. reload();
  77. }
  78. void MainWindow::reload() {
  79. if (fname.empty())
  80. return;
  81. // TODO: proper filter modularization
  82. try {
  83. auto reader = core::filters::JsonReader();
  84. std::ifstream in(fname);
  85. document = reader.read_document(in);
  86. if (!document)
  87. throw std::runtime_error("Unknown parse failure");
  88. set_context(document->get_default_context());
  89. in.close();
  90. return;
  91. } catch (std::exception const& ex) {
  92. auto msg = QString::fromStdString("Uncaught exception in JSON filter:\n{}"_format(ex.what()));
  93. qDebug() << msg;
  94. } catch (...) {
  95. qDebug() << "Unknown error while trying to open document via JSON filter";
  96. }
  97. try {
  98. auto reader = core::filters::SvgPathReader();
  99. std::ifstream in(fname);
  100. document = reader.read_document(in);
  101. set_context(document->get_default_context());
  102. in.close();
  103. } catch (std::exception const& ex) {
  104. auto msg = QString::fromStdString("Uncaught exception while opening document:\n{}"_format(ex.what()));
  105. qDebug() << msg;
  106. error_box->showMessage(msg);
  107. } catch (...) {
  108. qDebug() << "Unknown error while opening document";
  109. }
  110. }
  111. void MainWindow::save_as() {
  112. auto fname_qt = QFileDialog::getSaveFileName(this, "Save", "", "RainyNite file (*.rnite)(*.rnite);;All files(*)");
  113. fname = fname_qt.toStdString();
  114. if (!fname.empty())
  115. save();
  116. }
  117. void MainWindow::save() {
  118. if (fname.empty()) {
  119. save_as();
  120. return;
  121. }
  122. try {
  123. auto writer = core::filters::JsonWriter();
  124. std::ofstream out(fname);
  125. writer.write_document(out, document);
  126. } catch (std::exception const& ex) {
  127. auto msg = QString::fromStdString("Uncaught exception while saving document:\n{}"_format(ex.what()));
  128. qDebug() << msg;
  129. error_box->showMessage(msg);
  130. } catch (...) {
  131. qDebug() << "Unknown error while saving document";
  132. }
  133. }
  134. void MainWindow::render() {
  135. if (context && context->get_document()) {
  136. auto rsettings = core::renderers::SvgRendererSettings();
  137. rsettings.render_pngs = true;
  138. rsettings.extra_style = extra_style;
  139. context->mod_render_settings() = rsettings;
  140. auto renderer = std::make_shared<core::renderers::SvgRenderer>();
  141. if (render_thread.joinable())
  142. render_thread.join();
  143. auto ctx = *context;
  144. render_thread = std::thread([renderer, ctx]() {
  145. try {
  146. renderer->render(ctx);
  147. } catch (std::exception const& ex) {
  148. auto msg = QString::fromStdString("Uncaught exception while rendering:\n{}"_format(ex.what()));
  149. qDebug() << msg;
  150. }
  151. });
  152. }
  153. }
  154. void MainWindow::redraw() {
  155. set_mainarea_image("renders/{:.3f}.png"_format(context->get_time().get_seconds()));
  156. }
  157. void MainWindow::toggle_extra_style(bool checked) {
  158. extra_style = checked;
  159. }
  160. void MainWindow::tool_mouse() {
  161. qDebug() << "mouse selected";
  162. }
  163. void MainWindow::tool_zoom() {
  164. qDebug() << "zoom selected";
  165. }
  166. void MainWindow::about() {
  167. AboutDialog dialog;
  168. dialog.exec();
  169. }
  170. void MainWindow::quit() {
  171. if (render_thread.joinable())
  172. render_thread.join();
  173. QApplication::quit();
  174. }
  175. void MainWindow::set_mainarea_image(std::string const& fname) {
  176. QPixmap pixmap;
  177. pixmap.load(QString::fromStdString(fname));
  178. ui->canvas->set_main_image(pixmap);
  179. }
  180. void MainWindow::add_time_dock() {
  181. auto dock = new TimeDock(context, this);
  182. addDockWidget(Qt::BottomDockWidgetArea, dock);
  183. }
  184. void MainWindow::add_playback_dock() {
  185. auto dock = new PlaybackDock(context, this);
  186. addDockWidget(Qt::BottomDockWidgetArea, dock);
  187. }
  188. void MainWindow::add_node_tree_dock() {
  189. auto dock = new NodeTreeDock(context, this);
  190. addDockWidget(Qt::LeftDockWidgetArea, dock);
  191. }
  192. void MainWindow::add_node_edit_dock() {
  193. auto dock = new NodeEditDock(context, this);
  194. addDockWidget(Qt::LeftDockWidgetArea, dock);
  195. }
  196. void MainWindow::set_context(std::shared_ptr<core::Context> context_) {
  197. context = context_;
  198. context->changed_time.connect([this](core::Time){
  199. redraw();
  200. });
  201. for (auto dock : findChildren<QWidget*>()) {
  202. if (auto ctx_dock = dynamic_cast<ContextListener*>(dock))
  203. ctx_dock->set_context(context_);
  204. if (dock->metaObject()->indexOfSignal("activated(std::shared_ptr<core::AbstractValue>)") != -1)
  205. connect(dock, SIGNAL(activated(std::shared_ptr<core::AbstractValue>)), this, SLOT(activate(std::shared_ptr<core::AbstractValue>)));
  206. }
  207. }
  208. void MainWindow::activate(std::shared_ptr<core::AbstractValue> node) {
  209. context->set_active_node(node);
  210. }
  211. }