timearea.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* docks/timearea.cpp - time area / timeline dock
  2. * Copyright (C) 2017-2018 caryoscelus
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <QMenu>
  18. #include <QContextMenuEvent>
  19. #include <QScrollBar>
  20. #include <core/node/abstract_value.h>
  21. #include <core/node/abstract_node.h>
  22. #include <core/node/traverse.h>
  23. #include <core/node/make.h>
  24. #include <core/document.h>
  25. #include <widgets/timeline_area.h>
  26. #include <generic/timeline_editor.h>
  27. #include <models/node_list.h>
  28. #include "timearea.h"
  29. #include "ui_timearea.h"
  30. namespace rainynite::studio {
  31. TimeareaDock::TimeareaDock(shared_ptr<EditorContext> context_, QWidget* parent) :
  32. DockWidget(parent),
  33. ContextListener(context_),
  34. ui(make_unique<Ui::TimeareaDock>()),
  35. node_list_model(make_unique<NodeListModel>())
  36. {
  37. node_list_model->set_context(get_context());
  38. ui->setupUi(this);
  39. auto cursor = add_canvas_named_editor(*ui->timeline, "TimelineCursor");
  40. ui->timeline->add_misc_editor(cursor);
  41. ui->timeline->setAlignment(Qt::AlignLeft | Qt::AlignTop);
  42. ui->timeline->load_registered_tools();
  43. ui->timeline->use_tool("Default");
  44. ui->node_list->setModel(node_list_model.get());
  45. connect(node_list_model.get(), &QAbstractItemModel::rowsInserted, this, &TimeareaDock::add_editors);
  46. connect(node_list_model.get(), &QAbstractItemModel::rowsMoved, this, &TimeareaDock::reload_editors);
  47. connect(node_list_model.get(), &QAbstractItemModel::rowsRemoved, this, &TimeareaDock::remove_editors);
  48. connect(ui->reload, &QAbstractButton::clicked, this, &TimeareaDock::reload_editors);
  49. ui->timeline->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  50. ui->node_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
  51. connect(ui->timeline->verticalScrollBar(), &QScrollBar::valueChanged, ui->node_list->verticalScrollBar(), &QScrollBar::setValue);
  52. connect(ui->node_list->verticalScrollBar(), &QScrollBar::valueChanged, ui->timeline->verticalScrollBar(), &QScrollBar::setValue);
  53. connect(ui->timeline->horizontalScrollBar(), &QScrollBar::valueChanged, this, &TimeareaDock::update_ruler);
  54. connect(ui->timeline->scene(), &QGraphicsScene::sceneRectChanged, this, &TimeareaDock::update_ruler);
  55. connect(ui->timeline, &AbstractCanvas::zoomed, this, &TimeareaDock::update_ruler);
  56. ui->timeline->installEventFilter(this);
  57. update_ruler();
  58. set_context(get_context());
  59. }
  60. TimeareaDock::~TimeareaDock() {
  61. }
  62. bool TimeareaDock::eventFilter(QObject* object, QEvent* event) {
  63. if (object == ui->timeline && event->type() == QEvent::Resize)
  64. update_ruler();
  65. return false;
  66. }
  67. void TimeareaDock::contextMenuEvent(QContextMenuEvent* event) {
  68. auto index = ui->node_list->selectionModel()->currentIndex();
  69. if (ui->node_list->underMouse() && index.isValid()) {
  70. QMenu menu(this);
  71. if (index.row() == node_list_model->rowCount()-1 && !pinned) {
  72. menu.addAction(
  73. QIcon::fromTheme("list-add"),
  74. "Pin to timeline area",
  75. [this]() {
  76. pinned = true;
  77. }
  78. );
  79. } else {
  80. menu.addAction(
  81. QIcon::fromTheme("list-remove"),
  82. "Remove from timeline area",
  83. [this, index]() {
  84. node_list_model->removeRow(index.row());
  85. }
  86. );
  87. }
  88. menu.exec(event->globalPos());
  89. }
  90. }
  91. void TimeareaDock::set_context(shared_ptr<EditorContext> context) {
  92. ContextListener::set_context(context);
  93. ui->timeline->set_context(context);
  94. ui->ruler->set_context(context);
  95. node_list_model->set_context(context);
  96. if (auto new_document = context->get_context()->get_document()) {
  97. document = new_document;
  98. load_pinned_from_file(std::move(new_document));
  99. }
  100. connect_boost(
  101. context->changed_active_node(),
  102. [this](auto index) {
  103. if (!pinned && node_list_model->rowCount() > 0)
  104. node_list_model->removeRow(node_list_model->rowCount()-1);
  105. pinned = !node_list_model->insert_unique_node(index);
  106. }
  107. );
  108. }
  109. void TimeareaDock::load_pinned_from_file(shared_ptr<core::AbstractDocument> /*new_document*/) {
  110. // TODO
  111. }
  112. void TimeareaDock::reload_editors() {
  113. ui->timeline->clear_editors();
  114. editor_count = 0;
  115. editor_list.clear();
  116. add_editors();
  117. }
  118. void TimeareaDock::add_editors() {
  119. for (int i = editor_count; i < node_list_model->rowCount(); ++i) {
  120. ++editor_count;
  121. auto index = node_list_model->index(i, 0);
  122. auto inner_index = node_list_model->get_inner_index(index);
  123. auto editors = add_canvas_node_editor(*ui->timeline, inner_index);
  124. editor_list.push_back(editors);
  125. for (auto const& editor : editors) {
  126. auto rect = ui->node_list->visualRect(index);
  127. if (auto timeline_editor = dynamic_cast<TimelineEditor*>(editor.get()))
  128. timeline_editor->set_position_hint(rect.y(), rect.height());
  129. }
  130. }
  131. }
  132. void TimeareaDock::remove_editors(QModelIndex const& /*parent*/, int first, int last) {
  133. for (int i = first; i <= last; ++i) {
  134. for (auto const& editor : editor_list[i])
  135. ui->timeline->remove_editor(editor);
  136. }
  137. editor_count -= last-first+1;
  138. editor_list.erase(editor_list.begin()+first, editor_list.begin()+last+1);
  139. }
  140. void TimeareaDock::update_ruler() {
  141. if (ui == nullptr)
  142. return;
  143. auto timeline_x = ui->timeline->mapFromScene(0, 0);
  144. auto global_x = ui->timeline->mapToGlobal(timeline_x);
  145. // no idea why that +4 offset is necessary..
  146. ui->ruler->set_scroll(ui->ruler->mapFromGlobal(global_x).x()+4);
  147. ui->ruler->set_zoom(ui->timeline->transform().m11());
  148. }
  149. } // namespace rainynite::studio