Skip to content

Commit eb1a22c

Browse files
committed
Add export tool
Signed-off-by: Darby Johnston <darbyjohnston@yahoo.com>
1 parent f565123 commit eb1a22c

File tree

11 files changed

+191
-32
lines changed

11 files changed

+191
-32
lines changed

cmake/SuperBuild/Builddtk-deps.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
include(ExternalProject)
22

33
set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
4-
set(dtk_GIT_TAG "957d7bb8e6f7e12fc291e8c31a4180ee4a9dfd8f")
4+
set(dtk_GIT_TAG "fe317ed208c6befeeb832fd9e8c6cce18575f9cb")
55

66
set(dtk-deps_ARGS
77
${toucan_EXTERNAL_PROJECT_ARGS}

cmake/SuperBuild/Builddtk.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
include(ExternalProject)
22

33
set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
4-
set(dtk_GIT_TAG "957d7bb8e6f7e12fc291e8c31a4180ee4a9dfd8f")
4+
set(dtk_GIT_TAG "fe317ed208c6befeeb832fd9e8c6cce18575f9cb")
55

66
set(dtk_DEPS dtk-deps)
77
set(dtk_ARGS

lib/toucan/Util.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,17 @@ namespace toucan
118118
}
119119

120120
std::string getSequenceFrame(
121-
const std::string& base,
121+
const std::filesystem::path& path,
122122
const std::string& namePrefix,
123123
int frame,
124124
int padding,
125125
const std::string& nameSuffix)
126126
{
127127
std::stringstream ss;
128-
ss << base <<
129-
namePrefix <<
128+
ss << namePrefix <<
130129
std::setw(padding) << std::setfill('0') << frame <<
131130
nameSuffix;
132-
return ss.str();
131+
return (path / ss.str()).string();
133132
}
134133

135134
namespace

lib/toucan/Util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace toucan
3636

3737
//! Get an image sequence file name.
3838
std::string getSequenceFrame(
39-
const std::string& base,
39+
const std::filesystem::path&,
4040
const std::string& namePrefix,
4141
int frame,
4242
int padding,

lib/toucanView/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ set(HEADERS
44
DocumentTab.h
55
Document.h
66
DocumentsModel.h
7-
Export.h
87
ExportTool.h
98
GapItem.h
109
GraphTool.h
@@ -35,7 +34,6 @@ set(SOURCE
3534
DocumentTab.cpp
3635
Document.cpp
3736
DocumentsModel.cpp
38-
Export.cpp
3937
ExportTool.cpp
4038
GapItem.cpp
4139
GraphTool.cpp

lib/toucanView/Export.cpp

Lines changed: 0 additions & 8 deletions
This file was deleted.

lib/toucanView/Export.h

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/toucanView/ExportTool.cpp

Lines changed: 147 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,115 @@
33

44
#include "ExportTool.h"
55

6+
#include "App.h"
7+
#include "DocumentsModel.h"
8+
#include "PlaybackModel.h"
9+
10+
#include <toucan/Util.h>
11+
12+
#include <dtk/ui/GridLayout.h>
13+
#include <dtk/ui/PushButton.h>
14+
#include <dtk/ui/Window.h>
15+
616
namespace toucan
717
{
818
void ExportWidget::_init(
919
const std::shared_ptr<dtk::Context>& context,
20+
const std::shared_ptr<App>& app,
1021
const std::shared_ptr<dtk::IWidget>& parent)
1122
{
1223
IWidget::_init(context, "toucan::ExportWidget", parent);
1324

25+
_host = app->getHost();
26+
_formats =
27+
{
28+
".tiff",
29+
".png"
30+
};
31+
1432
_layout = dtk::VerticalLayout::create(context, shared_from_this());
33+
_layout->setMarginRole(dtk::SizeRole::MarginSmall);
34+
_layout->setSpacingRole(dtk::SizeRole::SpacingSmall);
35+
36+
auto vLayout = dtk::VerticalLayout::create(context, _layout);
37+
vLayout->setSpacingRole(dtk::SizeRole::SpacingSmall);
38+
auto label = dtk::Label::create(context, "Output directory:", vLayout);
39+
_outputPathEdit = dtk::FileEdit::create(context, vLayout);
40+
41+
auto gridLayout = dtk::GridLayout::create(context, _layout);
42+
gridLayout->setSpacingRole(dtk::SizeRole::SpacingSmall);
43+
44+
label = dtk::Label::create(context, "Base name:", gridLayout);
45+
gridLayout->setGridPos(label, 0, 0);
46+
_baseNameEdit = dtk::LineEdit::create(context, gridLayout);
47+
_baseNameEdit->setText("render.");
48+
gridLayout->setGridPos(_baseNameEdit, 0, 1);
49+
50+
label = dtk::Label::create(context, "Number padding:", gridLayout);
51+
gridLayout->setGridPos(label, 1, 0);
52+
_paddingEdit = dtk::IntEdit::create(context, gridLayout);
53+
_paddingEdit->setRange(dtk::RangeI(0, 9));
54+
gridLayout->setGridPos(_paddingEdit, 1, 1);
55+
56+
label = dtk::Label::create(context, "File format:", gridLayout);
57+
gridLayout->setGridPos(label, 2, 0);
58+
_formatComboBox = dtk::ComboBox::create(context, _formats, gridLayout);
59+
gridLayout->setGridPos(_formatComboBox, 2, 1);
60+
61+
auto divider = dtk::Divider::create(context, dtk::Orientation::Vertical, _layout);
62+
63+
auto exportSequenceButton = dtk::PushButton::create(context, "Export Sequence", _layout);
64+
exportSequenceButton->setClickedCallback(
65+
[this]
66+
{
67+
_timeRange = _document->getPlaybackModel()->getInOutRange();
68+
_export();
69+
});
70+
71+
auto exportCurrentButton = dtk::PushButton::create(context, "Export Current Frame", _layout);
72+
exportCurrentButton->setClickedCallback(
73+
[this]
74+
{
75+
_timeRange = OTIO_NS::TimeRange(
76+
_document->getPlaybackModel()->getCurrentTime(),
77+
OTIO_NS::RationalTime(1.0, _document->getPlaybackModel()->getTimeRange().duration().rate()));
78+
_export();
79+
});
80+
81+
_timer = dtk::Timer::create(context);
82+
_timer->setRepeating(true);
83+
84+
_documentObserver = dtk::ValueObserver<std::shared_ptr<Document> >::create(
85+
app->getDocumentsModel()->observeCurrent(),
86+
[this](const std::shared_ptr<Document>& document)
87+
{
88+
_document = document;
89+
if (_document)
90+
{
91+
_graph = std::make_shared<ImageGraph>(
92+
_document->getPath(),
93+
_document->getTimelineWrapper());
94+
}
95+
else
96+
{
97+
_timeRange = OTIO_NS::TimeRange();
98+
_time = OTIO_NS::RationalTime();
99+
_graph.reset();
100+
}
101+
setEnabled(_document.get());
102+
});
15103
}
16104

17105
ExportWidget::~ExportWidget()
18106
{}
19107

20108
std::shared_ptr<ExportWidget> ExportWidget::create(
21109
const std::shared_ptr<dtk::Context>& context,
110+
const std::shared_ptr<App>& app,
22111
const std::shared_ptr<dtk::IWidget>& parent)
23112
{
24113
auto out = std::shared_ptr<ExportWidget>(new ExportWidget);
25-
out->_init(context, parent);
114+
out->_init(context, app, parent);
26115
return out;
27116
}
28117

@@ -38,15 +127,68 @@ namespace toucan
38127
_setSizeHint(_layout->getSizeHint());
39128
}
40129

130+
void ExportWidget::_export()
131+
{
132+
_time = _timeRange.start_time();
133+
134+
_dialog = dtk::ProgressDialog::create(
135+
getContext(),
136+
"Export",
137+
"Exporting:",
138+
getWindow());
139+
_dialog->setCloseCallback(
140+
[this]
141+
{
142+
_timer->stop();
143+
_dialog.reset();
144+
});
145+
_dialog->show();
146+
147+
_timer->start(
148+
std::chrono::microseconds(0),
149+
[this]
150+
{
151+
if (auto node = _graph->exec(_host, _time))
152+
{
153+
const auto buf = node->exec();
154+
const std::string fileName = getSequenceFrame(
155+
_outputPathEdit->getPath().string(),
156+
_baseNameEdit->getText(),
157+
_time.to_frames(),
158+
_paddingEdit->getValue(),
159+
_formats[_formatComboBox->getCurrentIndex()]);
160+
buf.write(fileName);
161+
}
162+
163+
const OTIO_NS::RationalTime end = _timeRange.end_time_inclusive();
164+
if (_time < end)
165+
{
166+
_time += OTIO_NS::RationalTime(1.0, _timeRange.duration().rate());
167+
const OTIO_NS::RationalTime duration = _timeRange.duration();
168+
const double v = duration.value() > 0.0 ?
169+
(_time - _timeRange.start_time()).value() / static_cast<double>(duration.value()) :
170+
0.0;
171+
_dialog->setValue(v);
172+
}
173+
else
174+
{
175+
_dialog->close();
176+
}
177+
});
178+
}
179+
41180
void ExportTool::_init(
42181
const std::shared_ptr<dtk::Context>& context,
43182
const std::shared_ptr<App>& app,
44183
const std::shared_ptr<dtk::IWidget>& parent)
45184
{
46185
IToolWidget::_init(context, app, "toucan::ExportTool", "Export", parent);
47186

48-
_layout = dtk::VerticalLayout::create(context, shared_from_this());
49-
_layout->setSpacingRole(dtk::SizeRole::None);
187+
_scrollWidget = dtk::ScrollWidget::create(context, dtk::ScrollType::Both, shared_from_this());
188+
_scrollWidget->setBorder(false);
189+
190+
_widget = ExportWidget::create(context, app);
191+
_scrollWidget->setWidget(_widget);
50192
}
51193

52194
ExportTool::~ExportTool()
@@ -65,12 +207,12 @@ namespace toucan
65207
void ExportTool::setGeometry(const dtk::Box2I& value)
66208
{
67209
IToolWidget::setGeometry(value);
68-
_layout->setGeometry(value);
210+
_scrollWidget->setGeometry(value);
69211
}
70212

71213
void ExportTool::sizeHintEvent(const dtk::SizeHintEvent& event)
72214
{
73215
IToolWidget::sizeHintEvent(event);
74-
_setSizeHint(_layout->getSizeHint());
216+
_setSizeHint(_scrollWidget->getSizeHint());
75217
}
76218
}

lib/toucanView/ExportTool.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,61 @@
55

66
#include "IToolWidget.h"
77

8+
#include <toucan/ImageGraph.h>
9+
10+
#include <dtk/ui/ComboBox.h>
11+
#include <dtk/ui/Divider.h>
12+
#include <dtk/ui/FileEdit.h>
13+
#include <dtk/ui/IntEdit.h>
14+
#include <dtk/ui/Label.h>
15+
#include <dtk/ui/LineEdit.h>
16+
#include <dtk/ui/ProgressDialog.h>
817
#include <dtk/ui/RowLayout.h>
18+
#include <dtk/ui/ScrollWidget.h>
19+
#include <dtk/core/Timer.h>
920

1021
namespace toucan
1122
{
23+
class Document;
24+
1225
class ExportWidget : public dtk::IWidget
1326
{
1427
protected:
1528
void _init(
1629
const std::shared_ptr<dtk::Context>&,
30+
const std::shared_ptr<App>&,
1731
const std::shared_ptr<IWidget>& parent);
1832

1933
public:
2034
virtual ~ExportWidget();
2135

2236
static std::shared_ptr<ExportWidget> create(
2337
const std::shared_ptr<dtk::Context>&,
38+
const std::shared_ptr<App>&,
2439
const std::shared_ptr<IWidget>& parent = nullptr);
2540

2641
void setGeometry(const dtk::Box2I&) override;
2742
void sizeHintEvent(const dtk::SizeHintEvent&) override;
2843

2944
private:
45+
void _export();
46+
47+
std::shared_ptr<ImageEffectHost> _host;
48+
std::shared_ptr<Document> _document;
49+
OTIO_NS::TimeRange _timeRange;
50+
OTIO_NS::RationalTime _time;
51+
std::shared_ptr<ImageGraph> _graph;
52+
std::vector<std::string> _formats;
53+
3054
std::shared_ptr<dtk::VerticalLayout> _layout;
55+
std::shared_ptr<dtk::FileEdit> _outputPathEdit;
56+
std::shared_ptr<dtk::LineEdit> _baseNameEdit;
57+
std::shared_ptr<dtk::IntEdit> _paddingEdit;
58+
std::shared_ptr<dtk::ComboBox> _formatComboBox;
59+
std::shared_ptr<dtk::ProgressDialog> _dialog;
60+
std::shared_ptr<dtk::Timer> _timer;
61+
62+
std::shared_ptr<dtk::ValueObserver<std::shared_ptr<Document> > > _documentObserver;
3163
};
3264

3365
class ExportTool : public IToolWidget
@@ -50,7 +82,7 @@ namespace toucan
5082
void sizeHintEvent(const dtk::SizeHintEvent&) override;
5183

5284
private:
53-
std::shared_ptr<dtk::VerticalLayout> _layout;
85+
std::shared_ptr<dtk::ScrollWidget> _scrollWidget;
5486
std::shared_ptr<ExportWidget> _widget;
5587
};
5688
}

lib/toucanView/JSONTool.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ namespace toucan
111111
_scrollLayout->setSpacingRole(dtk::SizeRole::None);
112112
_scrollWidget->setWidget(_scrollLayout);
113113

114+
_nothingSelectedLabel = dtk::Label::create(context, "Nothing selected", _scrollLayout);
115+
_nothingSelectedLabel->setMarginRole(dtk::SizeRole::MarginSmall);
116+
114117
dtk::Divider::create(context, dtk::Orientation::Vertical, _layout);
115118

116119
_bottomLayout = dtk::HorizontalLayout::create(context, _layout);
@@ -181,6 +184,7 @@ namespace toucan
181184
widget->setFilter(_searchBox->getText());
182185
_widgets.push_back(widget);
183186
}
187+
_nothingSelectedLabel->setVisible(selection.empty());
184188
});
185189
}
186190
else

lib/toucanView/JSONTool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ namespace toucan
7777
std::shared_ptr<dtk::ScrollWidget> _scrollWidget;
7878
std::shared_ptr<dtk::VerticalLayout> _scrollLayout;
7979
std::vector<std::shared_ptr<JSONWidget> > _widgets;
80+
std::shared_ptr<dtk::Label> _nothingSelectedLabel;
8081
std::shared_ptr<dtk::HorizontalLayout> _bottomLayout;
8182

8283
std::shared_ptr<dtk::ValueObserver<std::shared_ptr<Document> > > _documentObserver;

0 commit comments

Comments
 (0)