Skip to content

Commit

Permalink
Merge pull request #28 from darbyjohnston/export
Browse files Browse the repository at this point in the history
Add export tool
  • Loading branch information
darbyjohnston authored Nov 27, 2024
2 parents f565123 + eb1a22c commit 80edb53
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 32 deletions.
2 changes: 1 addition & 1 deletion cmake/SuperBuild/Builddtk-deps.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(ExternalProject)

set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
set(dtk_GIT_TAG "957d7bb8e6f7e12fc291e8c31a4180ee4a9dfd8f")
set(dtk_GIT_TAG "fe317ed208c6befeeb832fd9e8c6cce18575f9cb")

set(dtk-deps_ARGS
${toucan_EXTERNAL_PROJECT_ARGS}
Expand Down
2 changes: 1 addition & 1 deletion cmake/SuperBuild/Builddtk.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(ExternalProject)

set(dtk_GIT_REPOSITORY "https://github.com/darbyjohnston/dtk.git")
set(dtk_GIT_TAG "957d7bb8e6f7e12fc291e8c31a4180ee4a9dfd8f")
set(dtk_GIT_TAG "fe317ed208c6befeeb832fd9e8c6cce18575f9cb")

set(dtk_DEPS dtk-deps)
set(dtk_ARGS
Expand Down
7 changes: 3 additions & 4 deletions lib/toucan/Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,17 @@ namespace toucan
}

std::string getSequenceFrame(
const std::string& base,
const std::filesystem::path& path,
const std::string& namePrefix,
int frame,
int padding,
const std::string& nameSuffix)
{
std::stringstream ss;
ss << base <<
namePrefix <<
ss << namePrefix <<
std::setw(padding) << std::setfill('0') << frame <<
nameSuffix;
return ss.str();
return (path / ss.str()).string();
}

namespace
Expand Down
2 changes: 1 addition & 1 deletion lib/toucan/Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace toucan

//! Get an image sequence file name.
std::string getSequenceFrame(
const std::string& base,
const std::filesystem::path&,
const std::string& namePrefix,
int frame,
int padding,
Expand Down
2 changes: 0 additions & 2 deletions lib/toucanView/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ set(HEADERS
DocumentTab.h
Document.h
DocumentsModel.h
Export.h
ExportTool.h
GapItem.h
GraphTool.h
Expand Down Expand Up @@ -35,7 +34,6 @@ set(SOURCE
DocumentTab.cpp
Document.cpp
DocumentsModel.cpp
Export.cpp
ExportTool.cpp
GapItem.cpp
GraphTool.cpp
Expand Down
8 changes: 0 additions & 8 deletions lib/toucanView/Export.cpp

This file was deleted.

9 changes: 0 additions & 9 deletions lib/toucanView/Export.h

This file was deleted.

152 changes: 147 additions & 5 deletions lib/toucanView/ExportTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,115 @@

#include "ExportTool.h"

#include "App.h"
#include "DocumentsModel.h"
#include "PlaybackModel.h"

#include <toucan/Util.h>

#include <dtk/ui/GridLayout.h>
#include <dtk/ui/PushButton.h>
#include <dtk/ui/Window.h>

namespace toucan
{
void ExportWidget::_init(
const std::shared_ptr<dtk::Context>& context,
const std::shared_ptr<App>& app,
const std::shared_ptr<dtk::IWidget>& parent)
{
IWidget::_init(context, "toucan::ExportWidget", parent);

_host = app->getHost();
_formats =
{
".tiff",
".png"
};

_layout = dtk::VerticalLayout::create(context, shared_from_this());
_layout->setMarginRole(dtk::SizeRole::MarginSmall);
_layout->setSpacingRole(dtk::SizeRole::SpacingSmall);

auto vLayout = dtk::VerticalLayout::create(context, _layout);
vLayout->setSpacingRole(dtk::SizeRole::SpacingSmall);
auto label = dtk::Label::create(context, "Output directory:", vLayout);
_outputPathEdit = dtk::FileEdit::create(context, vLayout);

auto gridLayout = dtk::GridLayout::create(context, _layout);
gridLayout->setSpacingRole(dtk::SizeRole::SpacingSmall);

label = dtk::Label::create(context, "Base name:", gridLayout);
gridLayout->setGridPos(label, 0, 0);
_baseNameEdit = dtk::LineEdit::create(context, gridLayout);
_baseNameEdit->setText("render.");
gridLayout->setGridPos(_baseNameEdit, 0, 1);

label = dtk::Label::create(context, "Number padding:", gridLayout);
gridLayout->setGridPos(label, 1, 0);
_paddingEdit = dtk::IntEdit::create(context, gridLayout);
_paddingEdit->setRange(dtk::RangeI(0, 9));
gridLayout->setGridPos(_paddingEdit, 1, 1);

label = dtk::Label::create(context, "File format:", gridLayout);
gridLayout->setGridPos(label, 2, 0);
_formatComboBox = dtk::ComboBox::create(context, _formats, gridLayout);
gridLayout->setGridPos(_formatComboBox, 2, 1);

auto divider = dtk::Divider::create(context, dtk::Orientation::Vertical, _layout);

auto exportSequenceButton = dtk::PushButton::create(context, "Export Sequence", _layout);
exportSequenceButton->setClickedCallback(
[this]
{
_timeRange = _document->getPlaybackModel()->getInOutRange();
_export();
});

auto exportCurrentButton = dtk::PushButton::create(context, "Export Current Frame", _layout);
exportCurrentButton->setClickedCallback(
[this]
{
_timeRange = OTIO_NS::TimeRange(
_document->getPlaybackModel()->getCurrentTime(),
OTIO_NS::RationalTime(1.0, _document->getPlaybackModel()->getTimeRange().duration().rate()));
_export();
});

_timer = dtk::Timer::create(context);
_timer->setRepeating(true);

_documentObserver = dtk::ValueObserver<std::shared_ptr<Document> >::create(
app->getDocumentsModel()->observeCurrent(),
[this](const std::shared_ptr<Document>& document)
{
_document = document;
if (_document)
{
_graph = std::make_shared<ImageGraph>(
_document->getPath(),
_document->getTimelineWrapper());
}
else
{
_timeRange = OTIO_NS::TimeRange();
_time = OTIO_NS::RationalTime();
_graph.reset();
}
setEnabled(_document.get());
});
}

ExportWidget::~ExportWidget()
{}

std::shared_ptr<ExportWidget> ExportWidget::create(
const std::shared_ptr<dtk::Context>& context,
const std::shared_ptr<App>& app,
const std::shared_ptr<dtk::IWidget>& parent)
{
auto out = std::shared_ptr<ExportWidget>(new ExportWidget);
out->_init(context, parent);
out->_init(context, app, parent);
return out;
}

Expand All @@ -38,15 +127,68 @@ namespace toucan
_setSizeHint(_layout->getSizeHint());
}

void ExportWidget::_export()
{
_time = _timeRange.start_time();

_dialog = dtk::ProgressDialog::create(
getContext(),
"Export",
"Exporting:",
getWindow());
_dialog->setCloseCallback(
[this]
{
_timer->stop();
_dialog.reset();
});
_dialog->show();

_timer->start(
std::chrono::microseconds(0),
[this]
{
if (auto node = _graph->exec(_host, _time))
{
const auto buf = node->exec();
const std::string fileName = getSequenceFrame(
_outputPathEdit->getPath().string(),
_baseNameEdit->getText(),
_time.to_frames(),
_paddingEdit->getValue(),
_formats[_formatComboBox->getCurrentIndex()]);
buf.write(fileName);
}

const OTIO_NS::RationalTime end = _timeRange.end_time_inclusive();
if (_time < end)
{
_time += OTIO_NS::RationalTime(1.0, _timeRange.duration().rate());
const OTIO_NS::RationalTime duration = _timeRange.duration();
const double v = duration.value() > 0.0 ?
(_time - _timeRange.start_time()).value() / static_cast<double>(duration.value()) :
0.0;
_dialog->setValue(v);
}
else
{
_dialog->close();
}
});
}

void ExportTool::_init(
const std::shared_ptr<dtk::Context>& context,
const std::shared_ptr<App>& app,
const std::shared_ptr<dtk::IWidget>& parent)
{
IToolWidget::_init(context, app, "toucan::ExportTool", "Export", parent);

_layout = dtk::VerticalLayout::create(context, shared_from_this());
_layout->setSpacingRole(dtk::SizeRole::None);
_scrollWidget = dtk::ScrollWidget::create(context, dtk::ScrollType::Both, shared_from_this());
_scrollWidget->setBorder(false);

_widget = ExportWidget::create(context, app);
_scrollWidget->setWidget(_widget);
}

ExportTool::~ExportTool()
Expand All @@ -65,12 +207,12 @@ namespace toucan
void ExportTool::setGeometry(const dtk::Box2I& value)
{
IToolWidget::setGeometry(value);
_layout->setGeometry(value);
_scrollWidget->setGeometry(value);
}

void ExportTool::sizeHintEvent(const dtk::SizeHintEvent& event)
{
IToolWidget::sizeHintEvent(event);
_setSizeHint(_layout->getSizeHint());
_setSizeHint(_scrollWidget->getSizeHint());
}
}
34 changes: 33 additions & 1 deletion lib/toucanView/ExportTool.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,61 @@

#include "IToolWidget.h"

#include <toucan/ImageGraph.h>

#include <dtk/ui/ComboBox.h>
#include <dtk/ui/Divider.h>
#include <dtk/ui/FileEdit.h>
#include <dtk/ui/IntEdit.h>
#include <dtk/ui/Label.h>
#include <dtk/ui/LineEdit.h>
#include <dtk/ui/ProgressDialog.h>
#include <dtk/ui/RowLayout.h>
#include <dtk/ui/ScrollWidget.h>
#include <dtk/core/Timer.h>

namespace toucan
{
class Document;

class ExportWidget : public dtk::IWidget
{
protected:
void _init(
const std::shared_ptr<dtk::Context>&,
const std::shared_ptr<App>&,
const std::shared_ptr<IWidget>& parent);

public:
virtual ~ExportWidget();

static std::shared_ptr<ExportWidget> create(
const std::shared_ptr<dtk::Context>&,
const std::shared_ptr<App>&,
const std::shared_ptr<IWidget>& parent = nullptr);

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

private:
void _export();

std::shared_ptr<ImageEffectHost> _host;
std::shared_ptr<Document> _document;
OTIO_NS::TimeRange _timeRange;
OTIO_NS::RationalTime _time;
std::shared_ptr<ImageGraph> _graph;
std::vector<std::string> _formats;

std::shared_ptr<dtk::VerticalLayout> _layout;
std::shared_ptr<dtk::FileEdit> _outputPathEdit;
std::shared_ptr<dtk::LineEdit> _baseNameEdit;
std::shared_ptr<dtk::IntEdit> _paddingEdit;
std::shared_ptr<dtk::ComboBox> _formatComboBox;
std::shared_ptr<dtk::ProgressDialog> _dialog;
std::shared_ptr<dtk::Timer> _timer;

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

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

private:
std::shared_ptr<dtk::VerticalLayout> _layout;
std::shared_ptr<dtk::ScrollWidget> _scrollWidget;
std::shared_ptr<ExportWidget> _widget;
};
}
Expand Down
4 changes: 4 additions & 0 deletions lib/toucanView/JSONTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ namespace toucan
_scrollLayout->setSpacingRole(dtk::SizeRole::None);
_scrollWidget->setWidget(_scrollLayout);

_nothingSelectedLabel = dtk::Label::create(context, "Nothing selected", _scrollLayout);
_nothingSelectedLabel->setMarginRole(dtk::SizeRole::MarginSmall);

dtk::Divider::create(context, dtk::Orientation::Vertical, _layout);

_bottomLayout = dtk::HorizontalLayout::create(context, _layout);
Expand Down Expand Up @@ -181,6 +184,7 @@ namespace toucan
widget->setFilter(_searchBox->getText());
_widgets.push_back(widget);
}
_nothingSelectedLabel->setVisible(selection.empty());
});
}
else
Expand Down
1 change: 1 addition & 0 deletions lib/toucanView/JSONTool.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ namespace toucan
std::shared_ptr<dtk::ScrollWidget> _scrollWidget;
std::shared_ptr<dtk::VerticalLayout> _scrollLayout;
std::vector<std::shared_ptr<JSONWidget> > _widgets;
std::shared_ptr<dtk::Label> _nothingSelectedLabel;
std::shared_ptr<dtk::HorizontalLayout> _bottomLayout;

std::shared_ptr<dtk::ValueObserver<std::shared_ptr<Document> > > _documentObserver;
Expand Down

0 comments on commit 80edb53

Please sign in to comment.