add Sequencer/Timeline
This commit is contained in:
parent
e0c79edc55
commit
96e73d3564
@ -63,6 +63,8 @@ target_sources(nf7
|
||||
common/gui_node.hh
|
||||
common/gui_popup.hh
|
||||
common/gui_resizer.hh
|
||||
common/gui_timeline.hh
|
||||
common/gui_timeline.cc
|
||||
common/gui_window.hh
|
||||
common/history.hh
|
||||
common/lambda.hh
|
||||
@ -83,6 +85,7 @@ target_sources(nf7
|
||||
common/node_link_store.hh
|
||||
common/ptr_selector.hh
|
||||
common/queue.hh
|
||||
common/sequencer.hh
|
||||
common/squashed_history.hh
|
||||
common/task.hh
|
||||
common/thread.hh
|
||||
|
@ -134,7 +134,7 @@ struct FileFactory final {
|
||||
std::string default_name_;
|
||||
|
||||
std::string name_;
|
||||
const nf7::File::TypeInfo* type_;
|
||||
const nf7::File::TypeInfo* type_ = nullptr;
|
||||
std::string type_filter_;
|
||||
};
|
||||
|
||||
|
315
common/gui_timeline.cc
Normal file
315
common/gui_timeline.cc
Normal file
@ -0,0 +1,315 @@
|
||||
#include "common/gui_timeline.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
#include <imgui_internal.h>
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
bool Timeline::Begin(uint64_t len) noexcept {
|
||||
assert(frame_state_ == kRoot);
|
||||
layer_y_ = 0;
|
||||
layer_h_ = 0;
|
||||
|
||||
len_ = len;
|
||||
scroll_size_.x = GetXFromTime(len_) + 100;
|
||||
scroll_x_to_mouse_ = false;
|
||||
scroll_y_to_mouse_ = false;
|
||||
|
||||
action_ = kNone;
|
||||
action_target_ = nullptr;
|
||||
|
||||
if (!ImGui::BeginChild(id_, {0, 0}, false, ImGuiWindowFlags_NoMove)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
body_offset_ = {headerWidth(), xgridHeight()};
|
||||
body_size_ = ImGui::GetContentRegionMax() - body_offset_;
|
||||
|
||||
ImGui::SetCursorPos({body_offset_.x, 0});
|
||||
if (ImGui::BeginChild("xgrid", {body_size_.x, body_offset_.y})) {
|
||||
UpdateXGrid();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
constexpr auto kFlags =
|
||||
ImGuiWindowFlags_NoScrollWithMouse |
|
||||
ImGuiWindowFlags_NoScrollbar;
|
||||
ImGui::SetCursorPos({0, body_offset_.y});
|
||||
if (ImGui::BeginChild("layers", {0, 0}, false, kFlags)) {
|
||||
frame_state_ = kHeader;
|
||||
|
||||
ImGui::BeginGroup();
|
||||
return true;
|
||||
}
|
||||
ImGui::EndChild();
|
||||
return false;
|
||||
}
|
||||
void Timeline::End() noexcept {
|
||||
assert(frame_state_ == kRoot);
|
||||
ImGui::EndChild(); // end of root
|
||||
}
|
||||
|
||||
void Timeline::NextLayerHeader(Layer layer, float height) noexcept {
|
||||
assert(frame_state_ == kHeader);
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
if (layer_h_ > 0) {
|
||||
layer_y_ += layer_h_+padding()*2;
|
||||
}
|
||||
layer_h_ = height*em;
|
||||
layer_ = layer;
|
||||
|
||||
const auto mouse = ImGui::GetMousePos().y;
|
||||
if (layerTopScreenY() <= mouse && mouse < layerBottomScreenY()) {
|
||||
mouse_layer_ = layer;
|
||||
mouse_layer_y_ = layer_y_;
|
||||
mouse_layer_h_ = layer_h_;
|
||||
}
|
||||
|
||||
ImGui::SetCursorPos({0, std::round(layer_y_)});
|
||||
const auto col = ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f);
|
||||
const auto spos = ImGui::GetCursorScreenPos();
|
||||
const auto size = ImGui::GetWindowSize();
|
||||
|
||||
auto d = ImGui::GetWindowDrawList();
|
||||
d->AddLine({spos.x, spos.y}, {spos.x+size.x, spos.y}, col);
|
||||
|
||||
ImGui::SetCursorPos({0, std::round(layer_y_+padding())});
|
||||
}
|
||||
|
||||
bool Timeline::BeginBody() noexcept {
|
||||
assert(frame_state_ == kHeader);
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
// end of header group
|
||||
ImGui::EndGroup();
|
||||
scroll_size_.y = ImGui::GetItemRectSize().y;
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (auto wh = ImGui::GetIO().MouseWheel) {
|
||||
scroll_.y -= wh * 5*em;
|
||||
}
|
||||
}
|
||||
|
||||
// beginnign of body
|
||||
ImGui::SameLine(0, 0);
|
||||
if (ImGui::BeginChild("body", {0, scroll_size_.y})) {
|
||||
frame_state_ = kBody;
|
||||
body_screen_offset_ = ImGui::GetCursorScreenPos();
|
||||
|
||||
ImGui::InvisibleButton("viewport-grip", scroll_size_, ImGuiButtonFlags_MouseButtonMiddle);
|
||||
ImGui::SetItemAllowOverlap();
|
||||
if (ImGui::IsItemActive()) {
|
||||
scroll_ -= ImGui::GetIO().MouseDelta;
|
||||
}
|
||||
|
||||
layer_ = nullptr;
|
||||
layer_y_ = 0;
|
||||
layer_h_ = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Timeline::EndBody() noexcept {
|
||||
assert(frame_state_ == kBody);
|
||||
frame_state_ = kRoot;
|
||||
|
||||
const auto& io = ImGui::GetIO();
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
// manipulation by mouse
|
||||
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) {
|
||||
if (io.MouseWheel) {
|
||||
if (io.KeyCtrl) {
|
||||
const auto xscroll_base = scroll_.x/zoom_;
|
||||
|
||||
// zoom
|
||||
const auto zmin = 16.f / static_cast<float>(len_);
|
||||
zoom_ += (zoom_*.99f+.01f)*.1f*io.MouseWheel;
|
||||
zoom_ = std::clamp(zoom_, zmin, 1.f);
|
||||
|
||||
scroll_.x = xscroll_base * zoom_;
|
||||
} else {
|
||||
// x-scrolling
|
||||
scroll_.x -= io.MouseWheel * 2*em;
|
||||
}
|
||||
}
|
||||
}
|
||||
// move x scroll to the mouse
|
||||
if (scroll_x_to_mouse_) {
|
||||
const auto x = ImGui::GetMousePos().x-body_screen_offset_.x;
|
||||
if (x < scroll_.x+2*em) {
|
||||
scroll_.x = x-2*em;
|
||||
} else {
|
||||
const auto right = scroll_.x+body_size_.x - 2*em;
|
||||
if (x > right) {
|
||||
scroll_.x += x-right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scroll_.x = std::clamp(scroll_.x, 0.f, std::max(0.f, scroll_size_.x-body_size_.x));
|
||||
ImGui::SetScrollX(scroll_.x);
|
||||
ImGui::EndChild();
|
||||
|
||||
// move y scroll to the mouse
|
||||
if (scroll_y_to_mouse_ && mouse_layer_) {
|
||||
if (mouse_layer_y_ < scroll_.y) {
|
||||
scroll_.y = mouse_layer_y_;
|
||||
} else {
|
||||
const auto bottom = mouse_layer_y_+mouse_layer_h_;
|
||||
if (bottom > scroll_.y+body_size_.y) {
|
||||
scroll_.y = bottom-body_size_.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scroll_.y = std::clamp(scroll_.y, 0.f, std::max(0.f, scroll_size_.y-body_size_.y));
|
||||
ImGui::SetScrollY(scroll_.y);
|
||||
ImGui::EndChild(); // end of layers
|
||||
}
|
||||
bool Timeline::NextLayer(Layer layer, float height) noexcept {
|
||||
assert(frame_state_ == kBody);
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
if (layer_h_ > 0) {
|
||||
layer_y_ += layer_h_+padding()*2;
|
||||
}
|
||||
layer_h_ = height*em;
|
||||
layer_ = layer;
|
||||
|
||||
return true; // TODO check if shown
|
||||
}
|
||||
|
||||
bool Timeline::BeginItem(Item item, uint64_t begin, uint64_t end) noexcept {
|
||||
assert(frame_state_ == kBody);
|
||||
frame_state_ = kItem;
|
||||
|
||||
item_ = item;
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
const auto pad = padding();
|
||||
const auto left = GetXFromTime(begin);
|
||||
const auto right = GetXFromTime(end);
|
||||
|
||||
const auto w = std::max(1.f, right-left);
|
||||
const auto h = layer_h_;
|
||||
|
||||
ImGui::SetCursorPos({left, std::round(layer_y_+pad)});
|
||||
if (ImGui::BeginChild(ImGui::GetID(item), {w, h})) {
|
||||
const auto resizer_w = std::min(1*em, w/2);
|
||||
|
||||
ImGui::SetCursorPos({0, 0});
|
||||
ImGui::InvisibleButton("begin", {resizer_w, h});
|
||||
ImGui::SetItemAllowOverlap();
|
||||
HandleGrip(item, 0, kResizeBegin, kResizeBeginDone, ImGuiMouseCursor_ResizeEW);
|
||||
|
||||
ImGui::SetCursorPos({w-resizer_w, 0});
|
||||
ImGui::InvisibleButton("end", {resizer_w, h});
|
||||
ImGui::SetItemAllowOverlap();
|
||||
HandleGrip(item, w-resizer_w, kResizeEnd, kResizeEndDone, ImGuiMouseCursor_ResizeEW);
|
||||
|
||||
const auto mover_w = std::max(1.f, w-resizer_w*2);
|
||||
ImGui::SetCursorPos({resizer_w, 0});
|
||||
ImGui::InvisibleButton("mover", {mover_w, h});
|
||||
ImGui::SetItemAllowOverlap();
|
||||
HandleGrip(item, resizer_w, kMove, kMoveDone, ImGuiMouseCursor_Hand);
|
||||
|
||||
ImGui::SetCursorPos({0, 0});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Timeline::EndItem() noexcept {
|
||||
assert(frame_state_ == kItem);
|
||||
frame_state_ = kBody;
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void Timeline::Cursor(const char* name, uint64_t t, uint32_t col) noexcept {
|
||||
const auto d = ImGui::GetWindowDrawList();
|
||||
|
||||
const auto spos = ImGui::GetWindowPos();
|
||||
const auto size = ImGui::GetWindowSize();
|
||||
const auto grid_h = xgridHeight();
|
||||
const auto x = GetScreenXFromTime(t);
|
||||
if (x < body_offset_.x) return;
|
||||
|
||||
d->AddLine({x, spos.y}, {x, spos.y+size.y}, col);
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
const auto num = std::to_string(t);
|
||||
d->AddText({x, spos.y + grid_h*0.1f }, col, num.c_str());
|
||||
d->AddText({x, spos.y + grid_h*0.1f+em}, col, name);
|
||||
}
|
||||
|
||||
void Timeline::UpdateXGrid() noexcept {
|
||||
constexpr uint64_t kAccentInterval = 5;
|
||||
|
||||
const uint64_t unit_min = static_cast<uint64_t>(1/zoom_);
|
||||
uint64_t unit = 1;
|
||||
while (unit < unit_min) unit *= 10;
|
||||
|
||||
const auto spos = ImGui::GetWindowPos();
|
||||
const auto size = ImGui::GetContentRegionMax();
|
||||
const auto color = ImGui::GetColorU32(ImGuiCol_TextDisabled);
|
||||
const auto left = GetTimeFromX(scroll_.x)/unit*unit;
|
||||
const auto right = std::min(len_-1, GetTimeFromX(scroll_.x+body_size_.x)+1);
|
||||
|
||||
const auto d = ImGui::GetWindowDrawList();
|
||||
|
||||
for (uint64_t t = left; t < right; t += unit) {
|
||||
const bool accent = !((t/unit)%kAccentInterval);
|
||||
|
||||
const auto x = GetScreenXFromTime(t);
|
||||
const auto y = spos.y + size.y;
|
||||
const auto h = accent? size.y*0.2f: size.y*0.1f;
|
||||
d->AddLine({x, y}, {x, y-h}, color);
|
||||
|
||||
if (accent) {
|
||||
const auto num = std::to_string(t);
|
||||
const auto num_size = ImGui::CalcTextSize(num.c_str());
|
||||
d->AddText({x - num_size.x/2, y-h - num_size.y}, color, num.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
void Timeline::HandleGrip(Item item, float off, Action ac, Action acdone, ImGuiMouseCursor cur) noexcept {
|
||||
if (ImGui::IsItemActive()) {
|
||||
if (ImGui::IsItemActivated()) {
|
||||
action_ = kSelect;
|
||||
} else {
|
||||
action_ = ac;
|
||||
}
|
||||
action_target_ = item;
|
||||
ImGui::SetMouseCursor(cur);
|
||||
|
||||
off -= 1;
|
||||
off += ImGui::GetCurrentContext()->ActiveIdClickOffset.x;
|
||||
|
||||
const auto pos = ImGui::GetMousePos() - ImVec2{off, 0};
|
||||
grip_time_ = GetTimeFromScreenX(pos.x);
|
||||
|
||||
scroll_x_to_mouse_ = true;
|
||||
scroll_y_to_mouse_ = (ac == kMove);
|
||||
|
||||
} else {
|
||||
if (ImGui::IsItemDeactivated()) {
|
||||
action_ = acdone;
|
||||
action_target_ = item;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetMouseCursor(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace nf7::gui
|
180
common/gui_timeline.hh
Normal file
180
common/gui_timeline.hh
Normal file
@ -0,0 +1,180 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/utility/usertype.hpp>
|
||||
|
||||
#include "common/yas_imgui.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
// if (tl.Begin()) {
|
||||
// tl.NextLayer(layer1, &layer1_height)
|
||||
// ImGui::Button("layer1");
|
||||
// tl.NextLayer(layer2, &layer2_height)
|
||||
// ImGui::Button("layer2");
|
||||
//
|
||||
// if (tl.BeginBody()) {
|
||||
// tl.NextLayer(layer1, &layer);
|
||||
// if (tl.BeginItem(layer1_item1, 0, 10)) {
|
||||
// // update item
|
||||
// }
|
||||
// tl.EndItem();
|
||||
// if (tl.BeginItem(layer1_item2, 0, 10)) {
|
||||
// // update item
|
||||
// }
|
||||
// tl.EndItem();
|
||||
//
|
||||
// tl.NextLayer(layer2, &layer);
|
||||
// if (tl.BeginItem(layer2_item1, 0, 10)) {
|
||||
// // update item
|
||||
// }
|
||||
// tl.EndItem();
|
||||
// if (tl.BeginItem(layer2_item2, 0, 10)) {
|
||||
// // update item
|
||||
// }
|
||||
// tl.EndItem();
|
||||
// }
|
||||
// tl_.EndBody();
|
||||
//
|
||||
// tl_.Cursor(...);
|
||||
// tl_.Cursor(...);
|
||||
//
|
||||
// // handle actions
|
||||
// }
|
||||
// tl.End();
|
||||
|
||||
struct Timeline {
|
||||
public:
|
||||
enum Action {
|
||||
kNone,
|
||||
kSelect,
|
||||
kResizeBegin,
|
||||
kResizeBeginDone,
|
||||
kResizeEnd,
|
||||
kResizeEndDone,
|
||||
kMove,
|
||||
kMoveDone,
|
||||
};
|
||||
using Layer = void*;
|
||||
using Item = void*;
|
||||
|
||||
Timeline() = delete;
|
||||
Timeline(const char* id) noexcept : id_(id) {
|
||||
}
|
||||
Timeline(const Timeline&) = default;
|
||||
Timeline(Timeline&&) = delete;
|
||||
Timeline& operator=(const Timeline&) = default;
|
||||
Timeline& operator=(Timeline&&) = delete;
|
||||
|
||||
template <typename Ar>
|
||||
void serialize(Ar& ar) {
|
||||
ar(header_width_);
|
||||
ar(xgrid_height_);
|
||||
ar(zoom_);
|
||||
ar(padding_);
|
||||
ar(scroll_);
|
||||
}
|
||||
|
||||
bool Begin(uint64_t len) noexcept;
|
||||
void End() noexcept;
|
||||
|
||||
void NextLayerHeader(Layer layer, float height) noexcept;
|
||||
|
||||
bool BeginBody() noexcept;
|
||||
void EndBody() noexcept;
|
||||
bool NextLayer(Layer layer, float height) noexcept;
|
||||
|
||||
bool BeginItem(Item item, uint64_t begin, uint64_t end) noexcept;
|
||||
void EndItem() noexcept;
|
||||
|
||||
void Cursor(const char*, uint64_t t, uint32_t col) noexcept;
|
||||
|
||||
uint64_t GetTimeFromX(float x) const noexcept {
|
||||
return static_cast<uint64_t>(std::max(0.f, x/ImGui::GetFontSize()/zoom_));
|
||||
}
|
||||
uint64_t GetTimeFromScreenX(float x) const noexcept {
|
||||
return GetTimeFromX(x - body_screen_offset_.x);
|
||||
}
|
||||
float GetXFromTime(uint64_t t) const noexcept {
|
||||
return static_cast<float>(t)*zoom_*ImGui::GetFontSize();
|
||||
}
|
||||
float GetScreenXFromTime(uint64_t t) const noexcept {
|
||||
return GetXFromTime(t)+body_screen_offset_.x;
|
||||
}
|
||||
|
||||
float zoom() const noexcept { return zoom_; }
|
||||
float headerWidth() const noexcept { return header_width_*ImGui::GetFontSize(); }
|
||||
float xgridHeight() const noexcept { return xgrid_height_*ImGui::GetFontSize(); }
|
||||
float padding() const noexcept { return padding_*ImGui::GetFontSize(); }
|
||||
|
||||
float layerTopScreenY() noexcept {
|
||||
return body_screen_offset_.y + layer_y_;
|
||||
}
|
||||
float layerBottomScreenY() noexcept {
|
||||
return layerTopScreenY() + layerH() + padding()*2;
|
||||
}
|
||||
float layerH() noexcept {
|
||||
return layer_h_;
|
||||
}
|
||||
|
||||
Layer mouseLayer() const noexcept { return mouse_layer_; }
|
||||
uint64_t mouseTime() const noexcept {
|
||||
return GetTimeFromScreenX(ImGui::GetMousePos().x);
|
||||
}
|
||||
|
||||
Action action() const noexcept { return action_; }
|
||||
Item actionTarget() const noexcept { return action_target_; }
|
||||
uint64_t gripTime() const noexcept { return grip_time_; }
|
||||
|
||||
private:
|
||||
// immutable params
|
||||
const char* id_;
|
||||
|
||||
// permanentized params
|
||||
float header_width_ = 4.f;
|
||||
float xgrid_height_ = 4.f;
|
||||
float zoom_ = 1.f;
|
||||
float padding_ = 0.2f;
|
||||
ImVec2 scroll_;
|
||||
|
||||
// temporary values (immutable on each frame)
|
||||
ImVec2 body_size_;
|
||||
ImVec2 body_offset_;
|
||||
ImVec2 body_screen_offset_;
|
||||
|
||||
// volatile params
|
||||
enum {kRoot, kHeader, kBody, kItem} frame_state_ = kRoot;
|
||||
|
||||
uint64_t len_;
|
||||
ImVec2 scroll_size_;
|
||||
bool scroll_x_to_mouse_;
|
||||
bool scroll_y_to_mouse_;
|
||||
|
||||
|
||||
Layer mouse_layer_;
|
||||
float mouse_layer_y_;
|
||||
float mouse_layer_h_;
|
||||
|
||||
Layer layer_;
|
||||
float layer_y_;
|
||||
float layer_h_;
|
||||
|
||||
Item item_;
|
||||
|
||||
Action action_;
|
||||
Item action_target_;
|
||||
uint64_t grip_time_;
|
||||
|
||||
|
||||
void UpdateXGrid() noexcept;
|
||||
void HandleGrip(
|
||||
Item item, float off, Action ac, Action acdone, ImGuiMouseCursor cur) noexcept;
|
||||
};
|
||||
|
||||
} // namespace nf7::gui
|
68
common/sequencer.hh
Normal file
68
common/sequencer.hh
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/lambda.hh"
|
||||
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
class Sequencer : public nf7::File::Interface {
|
||||
public:
|
||||
class Lambda;
|
||||
class Editor;
|
||||
|
||||
struct Period { uint64_t begin, end; };
|
||||
|
||||
enum Flag : uint8_t {
|
||||
kNone = 0,
|
||||
kCustomItem = 1 << 0, // uses UpdateItem() to draw an item on timeline if enable
|
||||
kTooltip = 1 << 1,
|
||||
kMenu = 1 << 2,
|
||||
};
|
||||
using Flags = uint8_t;
|
||||
|
||||
Sequencer() = delete;
|
||||
Sequencer(Flags flags) noexcept : flags_(flags) { }
|
||||
Sequencer(const Sequencer&) = delete;
|
||||
Sequencer(Sequencer&&) = delete;
|
||||
Sequencer& operator=(const Sequencer&) = delete;
|
||||
Sequencer& operator=(Sequencer&&) = delete;
|
||||
|
||||
// Sequencer* is a dummy parameter to avoid issues of multi inheritance.
|
||||
virtual std::shared_ptr<nf7::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Lambda>&, Sequencer* = nullptr) noexcept = 0;
|
||||
|
||||
virtual void UpdateItem(Editor&) noexcept { }
|
||||
virtual void UpdateTooltip(Editor&) noexcept { }
|
||||
virtual void UpdateMenu(Editor&) noexcept { }
|
||||
|
||||
Flags flags() const noexcept { return flags_; }
|
||||
|
||||
std::span<const std::string> input() const noexcept { return input_; }
|
||||
std::span<const std::string> output() const noexcept { return output_; }
|
||||
|
||||
protected:
|
||||
std::vector<std::string> input_, output_;
|
||||
|
||||
private:
|
||||
Flags flags_;
|
||||
};
|
||||
|
||||
class Sequencer::Editor {
|
||||
public:
|
||||
Editor() noexcept = default;
|
||||
virtual ~Editor() noexcept = default;
|
||||
Editor(const Editor&) = delete;
|
||||
Editor(Editor&&) = delete;
|
||||
Editor& operator=(const Editor&) = delete;
|
||||
Editor& operator=(Editor&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace nf7
|
1147
file/sequencer_timeline.cc
Normal file
1147
file/sequencer_timeline.cc
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user