#pragma once #include "foundation/result.h" #include #include #include 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 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, }; struct DocumentExportMenuPlan { DocumentExportMenuKind kind = DocumentExportMenuKind::jpeg; DocumentExportMenuAction action = DocumentExportMenuAction::show_jpeg_dialog; bool opens_dialog = true; }; 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; }; [[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]] inline pp::foundation::Result 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::failure( pp::foundation::Status::invalid_argument("document name must not be empty")); } if (extension.empty()) { return pp::foundation::Result::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::success(std::move(target)); } [[nodiscard]] inline pp::foundation::Result 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::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::success(std::move(target)); } [[nodiscard]] inline pp::foundation::Result make_document_export_stem_target( std::string_view directory, std::string_view document_name) { if (document_name.empty()) { return pp::foundation::Result::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::success(std::move(target)); } [[nodiscard]] inline pp::foundation::Result make_document_export_suggested_name( std::string_view document_name, std::string_view suffix) { if (document_name.empty()) { return pp::foundation::Result::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::success(std::move(target)); } [[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"); } }