Files
panopainter/src/app_core/document_export.h

460 lines
16 KiB
C++

#pragma once
#include "foundation/result.h"
#include <string>
#include <string_view>
#include <utility>
namespace pp::app {
struct DocumentExportFileTarget {
std::string path;
std::string suggested_name;
};
struct DocumentExportCollectionTarget {
std::string directory;
std::string stem_path;
};
struct DocumentExportStemTarget {
std::string stem_path;
};
struct DocumentExportSuggestedName {
std::string name;
};
enum class DocumentExportCollectionDestination {
work_directory_collection,
picked_directory_stem,
};
enum class DocumentExportStartDecision {
start_now,
show_license_disabled,
unavailable_no_canvas,
};
enum class DocumentExportMenuKind {
jpeg,
png,
layers,
cube_faces,
depth,
animation_frames,
animation_mp4,
timelapse,
};
enum class DocumentExportMenuAction {
show_jpeg_dialog,
show_png_dialog,
show_layers_dialog,
show_cube_faces_dialog,
show_depth_dialog,
show_animation_frames_dialog,
show_animation_mp4_dialog,
show_timelapse_dialog,
show_license_disabled,
unavailable_no_canvas,
};
enum class DocumentExportCollectionKind {
layers,
animation_frames,
};
enum class DocumentVideoExportKind {
animation_mp4,
timelapse,
};
struct DocumentExportMenuPlan {
DocumentExportMenuKind kind = DocumentExportMenuKind::jpeg;
DocumentExportMenuAction action = DocumentExportMenuAction::show_jpeg_dialog;
bool opens_dialog = true;
};
struct DocumentExportCollectionTargetPlan {
DocumentExportCollectionKind kind = DocumentExportCollectionKind::layers;
DocumentExportCollectionDestination destination = DocumentExportCollectionDestination::picked_directory_stem;
std::string_view suffix;
};
class DocumentExportMenuServices {
public:
virtual ~DocumentExportMenuServices() = default;
virtual void show_jpeg_dialog() = 0;
virtual void show_png_dialog() = 0;
virtual void show_layers_dialog() = 0;
virtual void show_cube_faces_dialog() = 0;
virtual void show_depth_dialog() = 0;
virtual void show_animation_frames_dialog() = 0;
virtual void show_animation_mp4_dialog() = 0;
virtual void show_timelapse_dialog() = 0;
virtual void show_license_disabled() = 0;
};
class DocumentExportServices {
public:
virtual ~DocumentExportServices() = default;
virtual bool create_directory(std::string_view directory) = 0;
virtual void export_equirectangular(const DocumentExportFileTarget& target) = 0;
virtual void export_layers_to_stem(const DocumentExportStemTarget& target) = 0;
virtual void export_layers_to_collection(const DocumentExportCollectionTarget& target) = 0;
virtual void export_animation_frames_to_stem(const DocumentExportStemTarget& target) = 0;
virtual void export_animation_frames_to_collection(const DocumentExportCollectionTarget& target) = 0;
virtual void export_depth(std::string_view document_name) = 0;
virtual void export_cube_faces(std::string_view document_name) = 0;
};
class DocumentVideoExportServices {
public:
virtual ~DocumentVideoExportServices() = default;
virtual void export_animation_mp4(std::string_view path) = 0;
virtual void export_timelapse_mp4(std::string_view path) = 0;
virtual void show_animation_export_success(std::string_view path) = 0;
virtual void show_timelapse_export_success(std::string_view path) = 0;
};
[[nodiscard]] constexpr DocumentExportStartDecision plan_document_export_start(
bool requires_license,
bool license_valid,
bool has_canvas) noexcept
{
if (requires_license && !license_valid) {
return DocumentExportStartDecision::show_license_disabled;
}
return has_canvas
? DocumentExportStartDecision::start_now
: DocumentExportStartDecision::unavailable_no_canvas;
}
[[nodiscard]] constexpr bool document_export_menu_requires_license(
DocumentExportMenuKind kind) noexcept
{
switch (kind) {
case DocumentExportMenuKind::animation_mp4:
case DocumentExportMenuKind::timelapse:
return true;
case DocumentExportMenuKind::jpeg:
case DocumentExportMenuKind::png:
case DocumentExportMenuKind::layers:
case DocumentExportMenuKind::cube_faces:
case DocumentExportMenuKind::depth:
case DocumentExportMenuKind::animation_frames:
return false;
}
return false;
}
[[nodiscard]] constexpr DocumentExportMenuAction document_export_menu_dialog_action(
DocumentExportMenuKind kind) noexcept
{
switch (kind) {
case DocumentExportMenuKind::jpeg:
return DocumentExportMenuAction::show_jpeg_dialog;
case DocumentExportMenuKind::png:
return DocumentExportMenuAction::show_png_dialog;
case DocumentExportMenuKind::layers:
return DocumentExportMenuAction::show_layers_dialog;
case DocumentExportMenuKind::cube_faces:
return DocumentExportMenuAction::show_cube_faces_dialog;
case DocumentExportMenuKind::depth:
return DocumentExportMenuAction::show_depth_dialog;
case DocumentExportMenuKind::animation_frames:
return DocumentExportMenuAction::show_animation_frames_dialog;
case DocumentExportMenuKind::animation_mp4:
return DocumentExportMenuAction::show_animation_mp4_dialog;
case DocumentExportMenuKind::timelapse:
return DocumentExportMenuAction::show_timelapse_dialog;
}
return DocumentExportMenuAction::show_jpeg_dialog;
}
[[nodiscard]] constexpr DocumentExportMenuPlan plan_document_export_menu_action(
DocumentExportMenuKind kind,
bool has_canvas,
bool license_valid) noexcept
{
DocumentExportMenuPlan plan;
plan.kind = kind;
plan.action = document_export_menu_dialog_action(kind);
const auto start = plan_document_export_start(
document_export_menu_requires_license(kind),
license_valid,
has_canvas);
if (start == DocumentExportStartDecision::show_license_disabled) {
plan.action = DocumentExportMenuAction::show_license_disabled;
plan.opens_dialog = false;
} else if (start == DocumentExportStartDecision::unavailable_no_canvas) {
plan.action = DocumentExportMenuAction::unavailable_no_canvas;
plan.opens_dialog = false;
}
return plan;
}
[[nodiscard]] constexpr std::string_view document_export_collection_suffix(
DocumentExportCollectionKind kind) noexcept
{
switch (kind) {
case DocumentExportCollectionKind::layers:
return "_layers";
case DocumentExportCollectionKind::animation_frames:
return "_frames";
}
return {};
}
[[nodiscard]] constexpr DocumentExportCollectionTargetPlan plan_document_export_collection_target(
DocumentExportCollectionKind kind,
bool use_work_directory_collection) noexcept
{
return {
kind,
use_work_directory_collection
? DocumentExportCollectionDestination::work_directory_collection
: DocumentExportCollectionDestination::picked_directory_stem,
document_export_collection_suffix(kind),
};
}
[[nodiscard]] inline pp::foundation::Result<DocumentExportFileTarget> make_document_export_file_target(
std::string_view work_directory,
std::string_view document_name,
std::string_view extension)
{
if (document_name.empty()) {
return pp::foundation::Result<DocumentExportFileTarget>::failure(
pp::foundation::Status::invalid_argument("document name must not be empty"));
}
if (extension.empty()) {
return pp::foundation::Result<DocumentExportFileTarget>::failure(
pp::foundation::Status::invalid_argument("extension must not be empty"));
}
DocumentExportFileTarget target;
target.suggested_name.reserve(document_name.size() + extension.size());
target.suggested_name += document_name;
target.suggested_name += extension;
target.path.reserve(work_directory.size() + target.suggested_name.size() + 1);
target.path += work_directory;
target.path += "/";
target.path += target.suggested_name;
return pp::foundation::Result<DocumentExportFileTarget>::success(std::move(target));
}
[[nodiscard]] inline pp::foundation::Result<DocumentExportCollectionTarget> make_document_export_collection_target(
std::string_view work_directory,
std::string_view document_name,
std::string_view suffix)
{
if (document_name.empty()) {
return pp::foundation::Result<DocumentExportCollectionTarget>::failure(
pp::foundation::Status::invalid_argument("document name must not be empty"));
}
DocumentExportCollectionTarget target;
target.directory.reserve(work_directory.size() + document_name.size() + suffix.size() + 1);
target.directory += work_directory;
target.directory += "/";
target.directory += document_name;
target.directory += suffix;
target.stem_path.reserve(target.directory.size() + document_name.size() + 1);
target.stem_path += target.directory;
target.stem_path += "/";
target.stem_path += document_name;
return pp::foundation::Result<DocumentExportCollectionTarget>::success(std::move(target));
}
[[nodiscard]] inline pp::foundation::Result<DocumentExportStemTarget> make_document_export_stem_target(
std::string_view directory,
std::string_view document_name)
{
if (document_name.empty()) {
return pp::foundation::Result<DocumentExportStemTarget>::failure(
pp::foundation::Status::invalid_argument("document name must not be empty"));
}
DocumentExportStemTarget target;
target.stem_path.reserve(directory.size() + document_name.size() + 1);
target.stem_path += directory;
target.stem_path += "/";
target.stem_path += document_name;
return pp::foundation::Result<DocumentExportStemTarget>::success(std::move(target));
}
[[nodiscard]] inline pp::foundation::Result<DocumentExportSuggestedName> make_document_export_suggested_name(
std::string_view document_name,
std::string_view suffix)
{
if (document_name.empty()) {
return pp::foundation::Result<DocumentExportSuggestedName>::failure(
pp::foundation::Status::invalid_argument("document name must not be empty"));
}
DocumentExportSuggestedName target;
target.name.reserve(document_name.size() + suffix.size());
target.name += document_name;
target.name += suffix;
return pp::foundation::Result<DocumentExportSuggestedName>::success(std::move(target));
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_file(
const DocumentExportFileTarget& target,
DocumentExportServices& services)
{
if (target.path.empty() || target.suggested_name.empty()) {
return pp::foundation::Status::invalid_argument("export file target requires a path and suggested name");
}
services.export_equirectangular(target);
return pp::foundation::Status::success();
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_stem(
DocumentExportCollectionKind kind,
const DocumentExportStemTarget& target,
DocumentExportServices& services)
{
if (target.stem_path.empty()) {
return pp::foundation::Status::invalid_argument("export stem target requires a stem path");
}
switch (kind) {
case DocumentExportCollectionKind::layers:
services.export_layers_to_stem(target);
return pp::foundation::Status::success();
case DocumentExportCollectionKind::animation_frames:
services.export_animation_frames_to_stem(target);
return pp::foundation::Status::success();
}
return pp::foundation::Status::invalid_argument("unknown document export collection kind");
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_collection(
DocumentExportCollectionKind kind,
const DocumentExportCollectionTarget& target,
DocumentExportServices& services)
{
if (target.directory.empty() || target.stem_path.empty()) {
return pp::foundation::Status::invalid_argument("export collection target requires a directory and stem path");
}
if (!services.create_directory(target.directory)) {
return pp::foundation::Status::success();
}
switch (kind) {
case DocumentExportCollectionKind::layers:
services.export_layers_to_collection(target);
return pp::foundation::Status::success();
case DocumentExportCollectionKind::animation_frames:
services.export_animation_frames_to_collection(target);
return pp::foundation::Status::success();
}
return pp::foundation::Status::invalid_argument("unknown document export collection kind");
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_depth(
std::string_view document_name,
DocumentExportServices& services)
{
if (document_name.empty()) {
return pp::foundation::Status::invalid_argument("document name must not be empty");
}
services.export_depth(document_name);
return pp::foundation::Status::success();
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_cube_faces(
std::string_view document_name,
DocumentExportServices& services)
{
if (document_name.empty()) {
return pp::foundation::Status::invalid_argument("document name must not be empty");
}
services.export_cube_faces(document_name);
return pp::foundation::Status::success();
}
[[nodiscard]] inline pp::foundation::Status execute_document_video_export(
DocumentVideoExportKind kind,
std::string_view path,
DocumentVideoExportServices& services)
{
if (path.empty()) {
return pp::foundation::Status::invalid_argument("video export path must not be empty");
}
switch (kind) {
case DocumentVideoExportKind::animation_mp4:
services.export_animation_mp4(path);
services.show_animation_export_success(path);
return pp::foundation::Status::success();
case DocumentVideoExportKind::timelapse:
services.export_timelapse_mp4(path);
services.show_timelapse_export_success(path);
return pp::foundation::Status::success();
}
return pp::foundation::Status::invalid_argument("unknown document video export kind");
}
[[nodiscard]] inline pp::foundation::Status execute_document_export_menu_plan(
const DocumentExportMenuPlan& plan,
DocumentExportMenuServices& services)
{
switch (plan.action) {
case DocumentExportMenuAction::show_jpeg_dialog:
services.show_jpeg_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_png_dialog:
services.show_png_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_layers_dialog:
services.show_layers_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_cube_faces_dialog:
services.show_cube_faces_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_depth_dialog:
services.show_depth_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_animation_frames_dialog:
services.show_animation_frames_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_animation_mp4_dialog:
services.show_animation_mp4_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_timelapse_dialog:
services.show_timelapse_dialog();
return pp::foundation::Status::success();
case DocumentExportMenuAction::show_license_disabled:
services.show_license_disabled();
return pp::foundation::Status::success();
case DocumentExportMenuAction::unavailable_no_canvas:
return pp::foundation::Status::success();
}
return pp::foundation::Status::invalid_argument("unknown document export menu action");
}
}