Thin app dialog export and popup seams
This commit is contained in:
@@ -163,6 +163,8 @@ set(PP_PANOPAINTER_APP_SOURCES
|
||||
src/legacy_draw_toolbar_binding_services.h
|
||||
src/app_layout_ui_state.cpp
|
||||
src/app_layout_sidebar.cpp
|
||||
src/legacy_sidebar_grid_popup_services.cpp
|
||||
src/legacy_sidebar_grid_popup_services.h
|
||||
src/legacy_sidebar_stroke_popup_services.cpp
|
||||
src/legacy_sidebar_stroke_popup_services.h
|
||||
src/legacy_sidebar_color_popup_services.cpp
|
||||
|
||||
@@ -792,26 +792,40 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
`bind_legacy_click_destroys_node(...)`; menu/layout-owned popup families still
|
||||
remain on separate retained cleanup paths.
|
||||
- 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained
|
||||
usermanual, changelog, and about openers in `src/app_dialogs_info_openers.cpp`
|
||||
now delegate retained dialog construction and overlay close wiring through
|
||||
usermanual, changelog, about, What's New, and shortcuts openers in
|
||||
`src/app_dialogs_info_openers.cpp` now delegate retained dialog construction,
|
||||
overlay close wiring, and remote-page/button ownership through
|
||||
`src/legacy_info_dialog_services.*` with explicit `App&` plus overlay-anchor
|
||||
dependencies, so the app dialog shell no longer owns that info-dialog family
|
||||
inline while `open_whatsnew_dialog()` still owns the retained whats-new flow
|
||||
inline.
|
||||
- 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained New
|
||||
Document and Save dialog openers in `src/app_dialogs_workflow.cpp` now
|
||||
delegate retained dialog construction and button wiring through
|
||||
`src/legacy_document_session_services.*` with explicit `App&` ownership, so
|
||||
the app dialog shell no longer owns that document-session dialog family
|
||||
inline while browse, open, and resize flows still remain there.
|
||||
inline.
|
||||
- 2026-06-17: `DEBT-0058`/`DEBT-0063` were narrowed again. The retained Open,
|
||||
Browse, and Resize dialog openers in `src/app_dialogs_workflow.cpp` now
|
||||
delegate retained dialog construction and overlay/button wiring through
|
||||
`src/legacy_document_open_services.*` and
|
||||
`src/legacy_document_session_services.*`, so the app dialog shell no longer
|
||||
owns those workflow dialog families inline.
|
||||
- 2026-06-17: `DEBT-0035` was narrowed again. `App::title_update()` and the
|
||||
draw-toolbar/stroke-popup binding families now delegate through
|
||||
draw-toolbar/stroke-popup/grid-popup binding families now delegate through
|
||||
`src/legacy_app_status_services.*`,
|
||||
`src/legacy_draw_toolbar_binding_services.*`, and
|
||||
`src/legacy_sidebar_stroke_popup_services.*`, so
|
||||
`src/legacy_sidebar_stroke_popup_services.*`, and
|
||||
`src/legacy_sidebar_grid_popup_services.*`, so
|
||||
`src/app_layout.cpp`, `src/app_layout_draw_toolbar.cpp`, and part of
|
||||
`src/app_layout_sidebar.cpp` are thinner adapters while retained app-shell
|
||||
execution and remaining popup families still stay open under the same debt.
|
||||
execution and the remaining layer popup family still stay open under the same
|
||||
debt.
|
||||
- 2026-06-17: `DEBT-0030`/`DEBT-0043`/`DEBT-0044` were narrowed again.
|
||||
`src/app_dialogs_export.cpp` is now a thin forwarding adapter. Retained
|
||||
document export start/branching flows now live in
|
||||
`src/legacy_document_export_services.*`, and the PPBR export dialog opener
|
||||
now lives in `src/legacy_brush_package_export_services.*`; retained export
|
||||
execution still remains behind those legacy bridges.
|
||||
- 2026-06-15: `DEBT-0036` was narrowed again. `NodeStrokePreview` now drops the
|
||||
retained pass-sequence, mix-execution, final-composite-request, background
|
||||
capture, and preview-copy wrapper structs/functions in favor of direct
|
||||
|
||||
@@ -93,12 +93,13 @@ Current conclusion:
|
||||
app shell is down to adapter calls even though runtime draw/event/sidebar
|
||||
execution still remains.
|
||||
- New-document/save dialog session wiring, app-title rendering, draw-toolbar
|
||||
binding, sidebar stroke-popup binding, and usermanual/changelog/about opener
|
||||
wiring now live in dedicated `legacy_*services.*` seams, so
|
||||
`src/app_dialogs_workflow.cpp`, `src/app_layout.cpp`,
|
||||
`src/app_layout_draw_toolbar.cpp`, `src/app_layout_sidebar.cpp`, and
|
||||
`src/app_dialogs_info_openers.cpp` are thinner adapters even though broader
|
||||
retained dialog/sidebar execution still remains.
|
||||
binding, sidebar stroke/grid-popup binding, export-dialog start wiring, and
|
||||
the full info-opener family now live in dedicated `legacy_*services.*` seams,
|
||||
so `src/app_dialogs_workflow.cpp`, `src/app_dialogs_export.cpp`,
|
||||
`src/app_layout.cpp`, `src/app_layout_draw_toolbar.cpp`,
|
||||
`src/app_layout_sidebar.cpp`, and `src/app_dialogs_info_openers.cpp` are
|
||||
thinner adapters even though broader retained dialog/sidebar execution still
|
||||
remains.
|
||||
- Platform extraction improved substantially and the root app source group no
|
||||
longer compiles Web platform sources directly, but broader CMake and
|
||||
entrypoint cleanup are not complete.
|
||||
|
||||
@@ -65,6 +65,12 @@ Key facts:
|
||||
- `App::dialog_browse()` no longer owns browse-dialog button wiring inline; the
|
||||
retained document-open bridge now owns that handoff in
|
||||
`src/legacy_document_open_services.*`.
|
||||
- `App::dialog_open()`, `App::dialog_browse()`, and `App::dialog_resize()` now
|
||||
delegate retained dialog construction and overlay/button wiring through
|
||||
`src/legacy_document_open_services.*` and
|
||||
`src/legacy_document_session_services.*`, so
|
||||
`src/app_dialogs_workflow.cpp` is thinner while the save-before-workflow
|
||||
policy seam remains local.
|
||||
- `App::init_toolbar_main()` now delegates retained main-toolbar button wiring
|
||||
through `src/legacy_main_toolbar_binding_services.*`, so
|
||||
`src/app_layout_main_toolbar.cpp` is down to a thin root lookup and adapter
|
||||
@@ -104,13 +110,13 @@ Key facts:
|
||||
- `App::dialog_usermanual()`, `App::dialog_changelog()`, and
|
||||
`App::dialog_about()` now delegate the retained info-dialog construction and
|
||||
overlay close wiring through `src/legacy_info_dialog_services.*` with
|
||||
explicit `App&` plus overlay-anchor dependencies, so
|
||||
`src/app_dialogs_info_openers.cpp` is thinner while `open_whatsnew_dialog()`
|
||||
still owns the retained whats-new flow inline.
|
||||
explicit `App&` plus overlay-anchor dependencies, and the remaining
|
||||
What's New plus shortcuts flows now route through the same seam, so
|
||||
`src/app_dialogs_info_openers.cpp` is down to thin forwarding only.
|
||||
- `App::dialog_newdoc()` and `App::dialog_save()` now delegate retained dialog
|
||||
construction and button wiring through `src/legacy_document_session_services.*`,
|
||||
so `src/app_dialogs_workflow.cpp` is thinner at the document-session seam
|
||||
while browse, open, and resize retained workflows still remain there.
|
||||
construction and button wiring through
|
||||
`src/legacy_document_session_services.*`, so
|
||||
`src/app_dialogs_workflow.cpp` is thinner at the document-session seam.
|
||||
- `App::title_update()` now delegates retained document-title and DPI-label
|
||||
rendering through `src/legacy_app_status_services.*`, so
|
||||
`src/app_layout.cpp` no longer owns that app-status family inline.
|
||||
@@ -122,8 +128,16 @@ Key facts:
|
||||
- `App::init_sidebar()` now delegates the retained stroke-popup open/anchor/tick
|
||||
wiring through `src/legacy_sidebar_stroke_popup_services.*` with explicit
|
||||
`App&`, popup-root, trigger-button, and panel dependencies, so
|
||||
`src/app_layout_sidebar.cpp` is thinner while the retained grid and layer
|
||||
popup families still remain inline.
|
||||
`src/app_layout_sidebar.cpp` is thinner while the retained layer popup family
|
||||
still remains inline.
|
||||
- `App::init_sidebar()` now delegates the retained grid-popup
|
||||
open/anchor/tick/close wiring through
|
||||
`src/legacy_sidebar_grid_popup_services.*`, so the `btn-grids-panel` path in
|
||||
`src/app_layout_sidebar.cpp` is down to a thin adapter.
|
||||
- `src/app_dialogs_export.cpp` is now a forwarding adapter; the retained
|
||||
document export start/branching flows live in
|
||||
`src/legacy_document_export_services.*`, and the PPBR dialog opener now lives
|
||||
in `src/legacy_brush_package_export_services.*`.
|
||||
|
||||
## Parallel Assignment Rules
|
||||
|
||||
|
||||
@@ -1,316 +1,51 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "app_core/app_dialog.h"
|
||||
#include "app_core/document_export.h"
|
||||
#include "legacy_brush_package_export_services.h"
|
||||
#include "legacy_document_export_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "node_dialog_export_ppbr.h"
|
||||
|
||||
#include <codec_api.h>
|
||||
#define MP4V2_NO_STDINT_DEFS
|
||||
#include <mp4v2/mp4v2.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool can_start_document_export(App& app, bool requires_license)
|
||||
{
|
||||
const auto decision = pp::app::plan_document_export_start(
|
||||
requires_license,
|
||||
!requires_license || app.check_license(),
|
||||
app.canvas != nullptr);
|
||||
|
||||
switch (decision) {
|
||||
case pp::app::DocumentExportStartDecision::start_now:
|
||||
return true;
|
||||
case pp::app::DocumentExportStartDecision::show_license_disabled:
|
||||
{
|
||||
const auto plan = pp::app::plan_document_export_license_disabled_dialog();
|
||||
app.message_box(plan.title, plan.message, plan.show_cancel);
|
||||
return false;
|
||||
}
|
||||
case pp::app::DocumentExportStartDecision::unavailable_no_canvas:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void start_document_export_collection(
|
||||
App& app,
|
||||
pp::app::DocumentExportCollectionKind kind)
|
||||
{
|
||||
const auto plan = pp::app::plan_document_export_collection_target(
|
||||
kind,
|
||||
app.uses_work_directory_document_export_collections());
|
||||
const auto success_kind = pp::app::document_export_collection_success_kind(kind);
|
||||
|
||||
if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) {
|
||||
const auto target = pp::app::make_document_export_collection_target(
|
||||
app.work_path,
|
||||
app.doc_name,
|
||||
plan.suffix);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_collection(
|
||||
app,
|
||||
plan.kind,
|
||||
target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
kind == pp::app::DocumentExportCollectionKind::layers
|
||||
? pp::app::DocumentExportExecutionKind::layers_collection
|
||||
: pp::app::DocumentExportExecutionKind::animation_frames_collection),
|
||||
status.message);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_dir([
|
||||
&app,
|
||||
kind = plan.kind,
|
||||
success_kind
|
||||
](std::string path) {
|
||||
const auto target = pp::app::make_document_export_stem_target(path, app.doc_name);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_stem(
|
||||
app,
|
||||
kind,
|
||||
target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
kind == pp::app::DocumentExportCollectionKind::layers
|
||||
? pp::app::DocumentExportExecutionKind::layers_stem
|
||||
: pp::app::DocumentExportExecutionKind::animation_frames_stem),
|
||||
status.message);
|
||||
});
|
||||
}
|
||||
|
||||
void start_document_video_export(
|
||||
App& app,
|
||||
pp::app::DocumentVideoExportKind kind,
|
||||
pp::app::DocumentExportSuccessKind success_kind,
|
||||
const char* suffix,
|
||||
pp::app::DocumentExportExecutionKind execution_kind)
|
||||
{
|
||||
if (!can_start_document_export(app, false))
|
||||
return;
|
||||
|
||||
if (app.uses_prepared_file_writes())
|
||||
{
|
||||
const auto target = pp::app::make_document_export_suggested_name(app.doc_name, suffix);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||
success_kind,
|
||||
target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save("mp4", target.value().name,
|
||||
[&app, kind, execution_kind](std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_document_video_export(
|
||||
app,
|
||||
kind,
|
||||
path,
|
||||
false);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(execution_kind),
|
||||
status.message);
|
||||
},
|
||||
[](const std::string& path, bool saved) {
|
||||
(void)path;
|
||||
(void)saved;
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save({ "mp4" }, [&app, kind, execution_kind](std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_document_video_export(
|
||||
app,
|
||||
kind,
|
||||
path,
|
||||
true);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(execution_kind),
|
||||
status.message);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void open_document_export_dialog(App& app, std::string ext)
|
||||
{
|
||||
if (!can_start_document_export(app, true))
|
||||
return;
|
||||
|
||||
// TODO: use picker
|
||||
const auto target = pp::app::make_document_export_file_target(app.work_path, app.doc_name, ext);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||
pp::app::DocumentExportSuccessKind::equirectangular,
|
||||
target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_file(app, target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
pp::app::DocumentExportExecutionKind::equirectangular_file),
|
||||
status.message);
|
||||
open_legacy_document_export_dialog(app, std::move(ext));
|
||||
}
|
||||
|
||||
void open_document_export_layers_dialog(App& app)
|
||||
{
|
||||
if (!can_start_document_export(app, true))
|
||||
return;
|
||||
|
||||
start_document_export_collection(
|
||||
app,
|
||||
pp::app::DocumentExportCollectionKind::layers);
|
||||
open_legacy_document_export_layers_dialog(app);
|
||||
}
|
||||
|
||||
void open_document_export_anim_frames_dialog(App& app)
|
||||
{
|
||||
if (!can_start_document_export(app, true))
|
||||
return;
|
||||
|
||||
start_document_export_collection(
|
||||
app,
|
||||
pp::app::DocumentExportCollectionKind::animation_frames);
|
||||
open_legacy_document_export_anim_frames_dialog(app);
|
||||
}
|
||||
|
||||
void open_document_export_depth_dialog(App& app)
|
||||
{
|
||||
if (!can_start_document_export(app, true))
|
||||
return;
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_depth(app, app.doc_name);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth),
|
||||
status.message);
|
||||
open_legacy_document_export_depth_dialog(app);
|
||||
}
|
||||
|
||||
void open_document_export_cube_faces_dialog(App& app)
|
||||
{
|
||||
if (!can_start_document_export(app, false))
|
||||
return;
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(app, app.doc_name);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces),
|
||||
status.message);
|
||||
}
|
||||
|
||||
void open_document_timelapse_export_dialog(App& app)
|
||||
{
|
||||
start_document_video_export(
|
||||
app,
|
||||
pp::app::DocumentVideoExportKind::timelapse,
|
||||
pp::app::DocumentExportSuccessKind::timelapse,
|
||||
"-timelapse",
|
||||
pp::app::DocumentExportExecutionKind::timelapse);
|
||||
}
|
||||
|
||||
void open_document_export_mp4_dialog(App& app)
|
||||
{
|
||||
start_document_video_export(
|
||||
app,
|
||||
pp::app::DocumentVideoExportKind::animation_mp4,
|
||||
pp::app::DocumentExportSuccessKind::animation_mp4,
|
||||
"-animation",
|
||||
pp::app::DocumentExportExecutionKind::animation_mp4);
|
||||
open_legacy_document_export_cube_faces_dialog(app);
|
||||
}
|
||||
|
||||
void open_ppbr_export_dialog(App& app)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("PPBR export dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
open_legacy_ppbr_export_dialog(app);
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogExportPPBR>(app);
|
||||
void open_document_timelapse_export_dialog(App& app)
|
||||
{
|
||||
open_legacy_document_timelapse_export_dialog(app);
|
||||
}
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("PPBR export dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [&app, dialog] (Node*) {
|
||||
const auto request = pp::panopainter::make_legacy_brush_package_export_request(*dialog);
|
||||
|
||||
if (app.uses_prepared_file_writes())
|
||||
{
|
||||
app.pick_file_save("ppbr", "exported-brushes",
|
||||
[&app, dialog, request] (std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_package_export(
|
||||
app,
|
||||
*dialog,
|
||||
request,
|
||||
path,
|
||||
pp::panopainter::LegacyBrushPackageExportMode::inline_export_only);
|
||||
if (!status.ok())
|
||||
LOG("PPBR export failed: %s", status.message);
|
||||
},
|
||||
[dialog] (const std::string& path, bool saved) {
|
||||
(void)path;
|
||||
pp::panopainter::complete_legacy_brush_package_export(*dialog, saved);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save({ "ppbr" }, [&app, dialog, request] (std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_package_export(
|
||||
app,
|
||||
*dialog,
|
||||
request,
|
||||
path,
|
||||
pp::panopainter::LegacyBrushPackageExportMode::desktop_async_close_and_message);
|
||||
if (!status.ok())
|
||||
LOG("PPBR export failed: %s", status.message);
|
||||
});
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*)
|
||||
{
|
||||
close_dialog();
|
||||
};
|
||||
void open_document_export_mp4_dialog(App& app)
|
||||
{
|
||||
open_legacy_document_export_mp4_dialog(app);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "legacy_preference_storage.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "legacy_info_dialog_services.h"
|
||||
#include "node_remote_page.h"
|
||||
#include "node_shorcuts.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
@@ -45,70 +40,12 @@ void open_about_dialog(App& app)
|
||||
|
||||
void open_whatsnew_dialog(App& app, bool force_show)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("What's new dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto overlay_handle = std::make_shared<pp::ui::NodeHandle>();
|
||||
const auto open_overlay = [overlay_anchor, overlay_handle](const std::shared_ptr<NodeRemotePage>& page) {
|
||||
if (overlay_handle->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto overlay = open_legacy_overlay_node_with_handle(*overlay_anchor, page);
|
||||
if (!overlay) {
|
||||
return;
|
||||
}
|
||||
*overlay_handle = overlay.value();
|
||||
};
|
||||
const auto close_overlay = [overlay_anchor, overlay_handle]() {
|
||||
if (!overlay_handle->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto close_status = close_legacy_overlay_node(*overlay_anchor, *overlay_handle);
|
||||
(void)close_status;
|
||||
*overlay_handle = {};
|
||||
};
|
||||
|
||||
auto whatsnew = std::make_shared<NodeRemotePage>();
|
||||
whatsnew->set_manager(&app.layout);
|
||||
whatsnew->init();
|
||||
std::string url = fmt::format("https://panopainter.com/app-content/whatsnew/?version={}", g_version_build);
|
||||
whatsnew->load_url(url, [whatsnew, force_show, open_overlay](bool success) {
|
||||
if (success)
|
||||
{
|
||||
int last_id = legacy_whatsnew_id_or(0);
|
||||
if (force_show || (whatsnew->m_page_id <= g_version_build && whatsnew->m_page_id > last_id))
|
||||
{
|
||||
whatsnew->set_title(fmt::format("What's new in version {}", g_version_number));
|
||||
if (!force_show)
|
||||
open_overlay(whatsnew);
|
||||
}
|
||||
}
|
||||
});
|
||||
whatsnew->add_button("Reload", 120, [whatsnew](Node*) {
|
||||
whatsnew->reload();
|
||||
});
|
||||
whatsnew->add_button("Read Later", 120, [whatsnew, close_overlay](Node*) {
|
||||
clear_legacy_whatsnew_id();
|
||||
save_legacy_preferences();
|
||||
close_overlay();
|
||||
});
|
||||
whatsnew->add_button("Close", 100, [whatsnew, close_overlay](Node*) {
|
||||
set_legacy_whatsnew_id(whatsnew->m_page_id);
|
||||
save_legacy_preferences();
|
||||
close_overlay();
|
||||
});
|
||||
if (force_show)
|
||||
open_overlay(whatsnew);
|
||||
pp::panopainter::open_legacy_whatsnew_dialog(app, force_show);
|
||||
}
|
||||
|
||||
void open_shortcuts_dialog(App& app)
|
||||
{
|
||||
(void)add_legacy_overlay_node<NodeShortcuts>(app);
|
||||
pp::panopainter::open_legacy_shortcuts_dialog(app);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "app_core/document_resize.h"
|
||||
#include "legacy_document_open_services.h"
|
||||
#include "legacy_document_canvas_services.h"
|
||||
#include "legacy_document_session_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "node_dialog_browse.h"
|
||||
#include "node_dialog_open.h"
|
||||
#include "node_dialog_resize.h"
|
||||
|
||||
void App::continue_document_workflow_after_optional_save(std::function<void()> action)
|
||||
{
|
||||
@@ -34,80 +28,16 @@ void App::dialog_newdoc()
|
||||
// DEPRECATED
|
||||
void App::dialog_open()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
// load thumbnail test
|
||||
auto* overlay_anchor = layout[main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Open document dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogOpen>(*this);
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Open document dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status =
|
||||
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [this, dialog](Node*)
|
||||
{
|
||||
// canvas->reset_camera();
|
||||
// layers->clear();
|
||||
// doc_name = dialog->selected_name;
|
||||
// canvas->m_canvas->project_open(dialog->selected_path, [this](bool success) {
|
||||
// // on complete
|
||||
// async_start();
|
||||
// title_update();
|
||||
// for (auto& i : canvas->m_canvas->m_order)
|
||||
// layers->add_layer(canvas->m_canvas->m_layers[i]->m_name.c_str());
|
||||
// async_end();
|
||||
// });
|
||||
// dialog->destroy();
|
||||
// ActionManager::clear();
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*)
|
||||
{
|
||||
close_dialog();
|
||||
};
|
||||
};
|
||||
|
||||
continue_document_workflow_after_optional_save(show_dialog);
|
||||
continue_document_workflow_after_optional_save([this] {
|
||||
pp::panopainter::open_legacy_document_open_dialog(*this);
|
||||
});
|
||||
}
|
||||
|
||||
void App::dialog_browse()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
auto* overlay_anchor = layout[main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Browse document dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogBrowse>(*this);
|
||||
dialog->search_paths = document_browse_roots();
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Browse document dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
pp::panopainter::wire_legacy_document_browse_dialog_actions(
|
||||
*this,
|
||||
dialog,
|
||||
*overlay_anchor,
|
||||
overlay_handle);
|
||||
};
|
||||
|
||||
continue_document_workflow_after_optional_save(show_dialog);
|
||||
continue_document_workflow_after_optional_save([this] {
|
||||
pp::panopainter::open_legacy_document_browse_dialog(*this);
|
||||
});
|
||||
}
|
||||
|
||||
void App::dialog_save_ver()
|
||||
@@ -148,41 +78,5 @@ void App::dialog_save()
|
||||
|
||||
void App::dialog_resize()
|
||||
{
|
||||
auto* overlay_anchor = layout[main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Resize dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogResize>(*this);
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Resize dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status =
|
||||
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [this, dialog, close_dialog](Node*)
|
||||
{
|
||||
const auto plan = pp::app::plan_document_resize(
|
||||
dialog->combo ? dialog->combo->m_current_index : 0);
|
||||
if (!plan)
|
||||
{
|
||||
close_dialog();
|
||||
return;
|
||||
}
|
||||
const auto status = pp::panopainter::execute_legacy_document_resize_plan(*this, plan.value());
|
||||
if (!status.ok())
|
||||
LOG("Document resize failed: %s", status.message);
|
||||
close_dialog();
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*) {
|
||||
close_dialog();
|
||||
};
|
||||
pp::panopainter::open_legacy_document_resize_dialog(*this);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "node_panel_floating.h"
|
||||
#include "app_core/brush_ui.h"
|
||||
#include "app_core/document_layer.h"
|
||||
#include "legacy_sidebar_grid_popup_services.h"
|
||||
#include "legacy_sidebar_color_popup_services.h"
|
||||
#include "legacy_sidebar_stroke_popup_services.h"
|
||||
#include "legacy_brush_ui_services.h"
|
||||
@@ -321,49 +322,7 @@ void App::init_sidebar()
|
||||
if (!popup_root) {
|
||||
return;
|
||||
}
|
||||
auto screen = popup_root->m_size;
|
||||
glm::vec2 pos = button->m_pos + glm::vec2(button->m_size.x * 0.5f, button->m_size.y);
|
||||
grid->find("title")->SetVisibility(true);
|
||||
grid->SetSize(350, YGUndefined);
|
||||
if (grid->m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(grid->m_parent->m_parent))
|
||||
{
|
||||
pp::panopainter::detach_legacy_node_from_parent(*grid);
|
||||
pp::panopainter::close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
const auto popup_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, grid);
|
||||
if (!popup_overlay)
|
||||
{
|
||||
LOG("Grid popup overlay failed: %s", popup_overlay.status().message);
|
||||
return;
|
||||
}
|
||||
auto tick = pp::panopainter::make_legacy_overlay_node_for_anchor<NodeImage>(*popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
auto tick_overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(*popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root->update();
|
||||
|
||||
grid->SetPosition(pos.x - grid->m_size.x / 2.f, pos.y + 16);
|
||||
grid->SetPositioning(YGPositionTypeAbsolute);
|
||||
pp::panopainter::activate_legacy_popup_overlay(*grid);
|
||||
auto scroll = grid->find<NodeScroll>("scroller");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f));
|
||||
|
||||
grid->on_popup_close = [popup_root, popup_handle, tick_handle](Node*) {
|
||||
close_legacy_overlay_handle_ignoring_status(*popup_root, popup_handle);
|
||||
close_legacy_overlay_handle_ignoring_status(*popup_root, tick_handle);
|
||||
};
|
||||
pp::panopainter::open_legacy_sidebar_grid_popup(*popup_root, *button, *grid);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
@@ -134,4 +135,67 @@ void complete_legacy_brush_package_export(NodeDialogExportPPBR& dialog, bool sav
|
||||
}
|
||||
}
|
||||
|
||||
void open_legacy_ppbr_export_dialog(App& app)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("PPBR export dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogExportPPBR>(app);
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("PPBR export dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status = pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [&app, dialog] (Node*) {
|
||||
const auto request = pp::panopainter::make_legacy_brush_package_export_request(*dialog);
|
||||
|
||||
if (app.uses_prepared_file_writes())
|
||||
{
|
||||
app.pick_file_save("ppbr", "exported-brushes",
|
||||
[&app, dialog, request] (std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_package_export(
|
||||
app,
|
||||
*dialog,
|
||||
request,
|
||||
path,
|
||||
pp::panopainter::LegacyBrushPackageExportMode::inline_export_only);
|
||||
if (!status.ok())
|
||||
LOG("PPBR export failed: %s", status.message);
|
||||
},
|
||||
[dialog] (const std::string& path, bool saved) {
|
||||
(void)path;
|
||||
pp::panopainter::complete_legacy_brush_package_export(*dialog, saved);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save({ "ppbr" }, [&app, dialog, request] (std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_brush_package_export(
|
||||
app,
|
||||
*dialog,
|
||||
request,
|
||||
path,
|
||||
pp::panopainter::LegacyBrushPackageExportMode::desktop_async_close_and_message);
|
||||
if (!status.ok())
|
||||
LOG("PPBR export failed: %s", status.message);
|
||||
});
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*)
|
||||
{
|
||||
close_dialog();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -26,5 +26,6 @@ enum class LegacyBrushPackageExportMode {
|
||||
LegacyBrushPackageExportMode mode);
|
||||
|
||||
void complete_legacy_brush_package_export(NodeDialogExportPPBR& dialog, bool saved);
|
||||
void open_legacy_ppbr_export_dialog(App& app);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -13,10 +13,34 @@
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool can_start_legacy_document_export(App& app, bool requires_license)
|
||||
{
|
||||
const auto decision = pp::app::plan_document_export_start(
|
||||
requires_license,
|
||||
!requires_license || app.check_license(),
|
||||
app.canvas != nullptr);
|
||||
|
||||
switch (decision) {
|
||||
case pp::app::DocumentExportStartDecision::start_now:
|
||||
return true;
|
||||
case pp::app::DocumentExportStartDecision::show_license_disabled:
|
||||
{
|
||||
const auto plan = pp::app::plan_document_export_license_disabled_dialog();
|
||||
app.message_box(plan.title, plan.message, plan.show_cancel);
|
||||
return false;
|
||||
}
|
||||
case pp::app::DocumentExportStartDecision::unavailable_no_canvas:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void show_export_success_dialog(
|
||||
App& app,
|
||||
const pp::app::DocumentExportSuccessDialogPlan& plan)
|
||||
@@ -26,6 +50,124 @@ void show_export_success_dialog(
|
||||
}
|
||||
}
|
||||
|
||||
void start_legacy_document_export_collection(
|
||||
App& app,
|
||||
pp::app::DocumentExportCollectionKind kind)
|
||||
{
|
||||
const auto plan = pp::app::plan_document_export_collection_target(
|
||||
kind,
|
||||
app.uses_work_directory_document_export_collections());
|
||||
const auto success_kind = pp::app::document_export_collection_success_kind(kind);
|
||||
|
||||
if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) {
|
||||
const auto target = pp::app::make_document_export_collection_target(
|
||||
app.work_path,
|
||||
app.doc_name,
|
||||
plan.suffix);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_collection(
|
||||
app,
|
||||
plan.kind,
|
||||
target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
kind == pp::app::DocumentExportCollectionKind::layers
|
||||
? pp::app::DocumentExportExecutionKind::layers_collection
|
||||
: pp::app::DocumentExportExecutionKind::animation_frames_collection),
|
||||
status.message);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_dir([
|
||||
&app,
|
||||
kind = plan.kind,
|
||||
success_kind
|
||||
](std::string path) {
|
||||
const auto target = pp::app::make_document_export_stem_target(path, app.doc_name);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_stem(
|
||||
app,
|
||||
kind,
|
||||
target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
kind == pp::app::DocumentExportCollectionKind::layers
|
||||
? pp::app::DocumentExportExecutionKind::layers_stem
|
||||
: pp::app::DocumentExportExecutionKind::animation_frames_stem),
|
||||
status.message);
|
||||
});
|
||||
}
|
||||
|
||||
void start_legacy_document_video_export(
|
||||
App& app,
|
||||
pp::app::DocumentVideoExportKind kind,
|
||||
pp::app::DocumentExportSuccessKind success_kind,
|
||||
const char* suffix,
|
||||
pp::app::DocumentExportExecutionKind execution_kind)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, false))
|
||||
return;
|
||||
|
||||
if (app.uses_prepared_file_writes())
|
||||
{
|
||||
const auto target = pp::app::make_document_export_suggested_name(app.doc_name, suffix);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||
success_kind,
|
||||
target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save("mp4", target.value().name,
|
||||
[&app, kind, execution_kind](std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_document_video_export(
|
||||
app,
|
||||
kind,
|
||||
path,
|
||||
false);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(execution_kind),
|
||||
status.message);
|
||||
},
|
||||
[](const std::string& path, bool saved) {
|
||||
(void)path;
|
||||
(void)saved;
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
app.pick_file_save({ "mp4" }, [&app, kind, execution_kind](std::string path) {
|
||||
const auto status = pp::panopainter::execute_legacy_document_video_export(
|
||||
app,
|
||||
kind,
|
||||
path,
|
||||
true);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(execution_kind),
|
||||
status.message);
|
||||
});
|
||||
}
|
||||
|
||||
struct LegacyDocumentExportSnapshotReports {
|
||||
pp::app::DocumentCanvasSnapshotResult snapshot;
|
||||
pp::paint_renderer::DocumentFrameFacePngExportResult face_pngs;
|
||||
@@ -834,6 +976,96 @@ void execute_legacy_document_export_equirectangular_thread(std::string file_path
|
||||
execute_legacy_document_export_equirectangular_thread_impl(std::move(file_path));
|
||||
}
|
||||
|
||||
void open_legacy_document_export_dialog(App& app, std::string ext)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, true))
|
||||
return;
|
||||
|
||||
// TODO: use picker
|
||||
const auto target = pp::app::make_document_export_file_target(app.work_path, app.doc_name, ext);
|
||||
if (!target) {
|
||||
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||
pp::app::DocumentExportSuccessKind::equirectangular,
|
||||
target.status().message);
|
||||
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_file(app, target.value());
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(
|
||||
pp::app::DocumentExportExecutionKind::equirectangular_file),
|
||||
status.message);
|
||||
}
|
||||
|
||||
void open_legacy_document_export_layers_dialog(App& app)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, true))
|
||||
return;
|
||||
|
||||
start_legacy_document_export_collection(
|
||||
app,
|
||||
pp::app::DocumentExportCollectionKind::layers);
|
||||
}
|
||||
|
||||
void open_legacy_document_export_anim_frames_dialog(App& app)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, true))
|
||||
return;
|
||||
|
||||
start_legacy_document_export_collection(
|
||||
app,
|
||||
pp::app::DocumentExportCollectionKind::animation_frames);
|
||||
}
|
||||
|
||||
void open_legacy_document_export_depth_dialog(App& app)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, true))
|
||||
return;
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_depth(app, app.doc_name);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth),
|
||||
status.message);
|
||||
}
|
||||
|
||||
void open_legacy_document_export_cube_faces_dialog(App& app)
|
||||
{
|
||||
if (!can_start_legacy_document_export(app, false))
|
||||
return;
|
||||
|
||||
const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(app, app.doc_name);
|
||||
if (!status.ok())
|
||||
LOG(
|
||||
"%s: %s",
|
||||
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces),
|
||||
status.message);
|
||||
}
|
||||
|
||||
void open_legacy_document_timelapse_export_dialog(App& app)
|
||||
{
|
||||
start_legacy_document_video_export(
|
||||
app,
|
||||
pp::app::DocumentVideoExportKind::timelapse,
|
||||
pp::app::DocumentExportSuccessKind::timelapse,
|
||||
"-timelapse",
|
||||
pp::app::DocumentExportExecutionKind::timelapse);
|
||||
}
|
||||
|
||||
void open_legacy_document_export_mp4_dialog(App& app)
|
||||
{
|
||||
start_legacy_document_video_export(
|
||||
app,
|
||||
pp::app::DocumentVideoExportKind::animation_mp4,
|
||||
pp::app::DocumentExportSuccessKind::animation_mp4,
|
||||
"-animation",
|
||||
pp::app::DocumentExportExecutionKind::animation_mp4);
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_document_export_file(
|
||||
App& app,
|
||||
const pp::app::DocumentExportFileTarget& target)
|
||||
|
||||
@@ -7,6 +7,7 @@ class App;
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
@@ -38,6 +39,14 @@ namespace pp::panopainter {
|
||||
std::string_view path,
|
||||
bool asynchronous);
|
||||
|
||||
void open_legacy_document_export_dialog(App& app, std::string ext);
|
||||
void open_legacy_document_export_layers_dialog(App& app);
|
||||
void open_legacy_document_export_anim_frames_dialog(App& app);
|
||||
void open_legacy_document_export_depth_dialog(App& app);
|
||||
void open_legacy_document_export_cube_faces_dialog(App& app);
|
||||
void open_legacy_document_timelapse_export_dialog(App& app);
|
||||
void open_legacy_document_export_mp4_dialog(App& app);
|
||||
|
||||
void execute_legacy_document_export_equirectangular(
|
||||
std::string file_path,
|
||||
std::function<void()> on_complete);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "legacy_history_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "log.h"
|
||||
#include "node_dialog_open.h"
|
||||
#include "node_dialog_browse.h"
|
||||
#include "node_panel_brush.h"
|
||||
#include "node_panel_layer.h"
|
||||
@@ -112,6 +113,38 @@ void prompt_discard_unsaved_project(App& app, const pp::app::DocumentOpenRoute&
|
||||
};
|
||||
}
|
||||
|
||||
void open_legacy_document_open_dialog_impl(App& app)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Open document dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogOpen>(app);
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Open document dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status =
|
||||
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [](Node*)
|
||||
{
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*)
|
||||
{
|
||||
close_dialog();
|
||||
};
|
||||
}
|
||||
|
||||
class LegacyDocumentOpenServices final : public pp::app::DocumentOpenServices {
|
||||
public:
|
||||
explicit LegacyDocumentOpenServices(App& app) noexcept
|
||||
@@ -181,6 +214,30 @@ void wire_legacy_document_browse_dialog_actions(
|
||||
};
|
||||
}
|
||||
|
||||
void open_legacy_document_browse_dialog(App& app)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Browse document dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogBrowse>(app);
|
||||
dialog->search_paths = app.document_browse_roots();
|
||||
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Browse document dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
|
||||
pp::panopainter::wire_legacy_document_browse_dialog_actions(
|
||||
app,
|
||||
dialog,
|
||||
*overlay_anchor,
|
||||
overlay.value());
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_document_open_plan(
|
||||
App& app,
|
||||
pp::app::DocumentOpenPlanAction action,
|
||||
@@ -219,4 +276,9 @@ void execute_legacy_downloaded_project_open(
|
||||
reconcile_downloaded_project_open(app);
|
||||
}
|
||||
|
||||
void open_legacy_document_open_dialog(App& app)
|
||||
{
|
||||
open_legacy_document_open_dialog_impl(app);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
class App;
|
||||
class Node;
|
||||
class NodeDialogOpen;
|
||||
class NodeDialogBrowse;
|
||||
|
||||
namespace pp::panopainter {
|
||||
@@ -18,11 +19,15 @@ namespace pp::panopainter {
|
||||
App& app,
|
||||
std::string path);
|
||||
|
||||
void open_legacy_document_open_dialog(App& app);
|
||||
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_document_open_plan(
|
||||
App& app,
|
||||
pp::app::DocumentOpenPlanAction action,
|
||||
const pp::app::DocumentOpenRoute& route);
|
||||
|
||||
void open_legacy_document_browse_dialog(App& app);
|
||||
|
||||
void wire_legacy_document_browse_dialog_actions(
|
||||
App& app,
|
||||
const std::shared_ptr<NodeDialogBrowse>& dialog,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "legacy_history_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "node_dialog_open.h"
|
||||
#include "node_dialog_resize.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -487,6 +488,47 @@ void open_legacy_document_file_save_dialog_impl(App& app)
|
||||
wire_document_file_save_dialog_buttons(app, dialog);
|
||||
}
|
||||
|
||||
void open_legacy_document_resize_dialog_impl(App& app)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("Resize dialog open failed: main layout anchor is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto dialog = pp::panopainter::make_legacy_overlay_node<NodeDialogResize>(app);
|
||||
const auto overlay = pp::panopainter::open_legacy_overlay_node_with_handle(*overlay_anchor, dialog);
|
||||
if (!overlay) {
|
||||
LOG("Resize dialog open failed: %s", overlay.status().message);
|
||||
return;
|
||||
}
|
||||
const auto overlay_handle = overlay.value();
|
||||
|
||||
const auto close_dialog = [overlay_anchor, overlay_handle]() {
|
||||
const auto close_status =
|
||||
pp::panopainter::close_legacy_overlay_node(*overlay_anchor, overlay_handle);
|
||||
(void)close_status;
|
||||
};
|
||||
|
||||
dialog->btn_ok->on_click = [&app, dialog, close_dialog](Node*)
|
||||
{
|
||||
const auto plan = pp::app::plan_document_resize(
|
||||
dialog->combo ? dialog->combo->m_current_index : 0);
|
||||
if (!plan)
|
||||
{
|
||||
close_dialog();
|
||||
return;
|
||||
}
|
||||
const auto status = pp::panopainter::execute_legacy_document_resize_plan(app, plan.value());
|
||||
if (!status.ok())
|
||||
LOG("Document resize failed: %s", status.message);
|
||||
close_dialog();
|
||||
};
|
||||
dialog->btn_cancel->on_click = [close_dialog](Node*) {
|
||||
close_dialog();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
pp::foundation::Status execute_legacy_close_request_decision(
|
||||
@@ -561,6 +603,11 @@ void open_legacy_document_file_save_dialog(App& app)
|
||||
open_legacy_document_file_save_dialog_impl(app);
|
||||
}
|
||||
|
||||
void open_legacy_document_resize_dialog(App& app)
|
||||
{
|
||||
open_legacy_document_resize_dialog_impl(app);
|
||||
}
|
||||
|
||||
pp::foundation::Status execute_legacy_document_version_save(
|
||||
App& app,
|
||||
const pp::app::DocumentVersionTarget& target)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
class App;
|
||||
class NodeDialogNewDoc;
|
||||
class NodeDialogSave;
|
||||
class NodeDialogResize;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
@@ -44,6 +45,8 @@ void open_legacy_new_document_dialog(App& app);
|
||||
|
||||
void open_legacy_document_file_save_dialog(App& app);
|
||||
|
||||
void open_legacy_document_resize_dialog(App& app);
|
||||
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_document_version_save(
|
||||
App& app,
|
||||
const pp::app::DocumentVersionTarget& target);
|
||||
|
||||
@@ -3,14 +3,27 @@
|
||||
#include "legacy_info_dialog_services.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "legacy_preference_storage.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "node_remote_page.h"
|
||||
#include "node_shorcuts.h"
|
||||
#include "node_about.h"
|
||||
#include "node_changelog.h"
|
||||
#include "node_usermanual.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
Node* get_legacy_info_dialog_overlay_anchor(App& app, const char* log_name)
|
||||
{
|
||||
auto* overlay_anchor = app.layout[app.main_id];
|
||||
if (!overlay_anchor) {
|
||||
LOG("%s dialog open failed: main layout anchor is missing", log_name);
|
||||
}
|
||||
return overlay_anchor;
|
||||
}
|
||||
|
||||
template <typename DialogNode>
|
||||
void open_legacy_info_dialog(App& app, Node& overlay_anchor, const char* log_name)
|
||||
{
|
||||
@@ -49,4 +62,71 @@ void open_about_dialog(App& app, Node& overlay_anchor, const char* log_name)
|
||||
open_legacy_info_dialog<NodeAbout>(app, overlay_anchor, log_name);
|
||||
}
|
||||
|
||||
void open_legacy_whatsnew_dialog(App& app, bool force_show)
|
||||
{
|
||||
auto* overlay_anchor = get_legacy_info_dialog_overlay_anchor(app, "What's new");
|
||||
if (!overlay_anchor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto overlay_handle = std::make_shared<pp::ui::NodeHandle>();
|
||||
const auto open_overlay = [overlay_anchor, overlay_handle](const std::shared_ptr<NodeRemotePage>& page) {
|
||||
if (overlay_handle->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto overlay = open_legacy_overlay_node_with_handle(*overlay_anchor, page);
|
||||
if (!overlay) {
|
||||
return;
|
||||
}
|
||||
*overlay_handle = overlay.value();
|
||||
};
|
||||
const auto close_overlay = [overlay_anchor, overlay_handle]() {
|
||||
if (!overlay_handle->valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto close_status = close_legacy_overlay_node(*overlay_anchor, *overlay_handle);
|
||||
(void)close_status;
|
||||
*overlay_handle = {};
|
||||
};
|
||||
|
||||
auto whatsnew = std::make_shared<NodeRemotePage>();
|
||||
whatsnew->set_manager(&app.layout);
|
||||
whatsnew->init();
|
||||
const std::string url = fmt::format("https://panopainter.com/app-content/whatsnew/?version={}", g_version_build);
|
||||
whatsnew->load_url(url, [whatsnew, force_show, open_overlay](bool success) {
|
||||
if (success) {
|
||||
const int last_id = legacy_whatsnew_id_or(0);
|
||||
if (force_show || (whatsnew->m_page_id <= g_version_build && whatsnew->m_page_id > last_id)) {
|
||||
whatsnew->set_title(fmt::format("What's new in version {}", g_version_number));
|
||||
if (!force_show) {
|
||||
open_overlay(whatsnew);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
whatsnew->add_button("Reload", 120, [whatsnew](Node*) {
|
||||
whatsnew->reload();
|
||||
});
|
||||
whatsnew->add_button("Read Later", 120, [whatsnew, close_overlay](Node*) {
|
||||
clear_legacy_whatsnew_id();
|
||||
save_legacy_preferences();
|
||||
close_overlay();
|
||||
});
|
||||
whatsnew->add_button("Close", 100, [whatsnew, close_overlay](Node*) {
|
||||
set_legacy_whatsnew_id(whatsnew->m_page_id);
|
||||
save_legacy_preferences();
|
||||
close_overlay();
|
||||
});
|
||||
if (force_show) {
|
||||
open_overlay(whatsnew);
|
||||
}
|
||||
}
|
||||
|
||||
void open_legacy_shortcuts_dialog(App& app)
|
||||
{
|
||||
(void)add_legacy_overlay_node<NodeShortcuts>(app);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
@@ -8,5 +8,7 @@ namespace pp::panopainter {
|
||||
void open_usermanual_dialog(App& app, Node& overlay_anchor, const char* log_name);
|
||||
void open_changelog_dialog(App& app, Node& overlay_anchor, const char* log_name);
|
||||
void open_about_dialog(App& app, Node& overlay_anchor, const char* log_name);
|
||||
void open_legacy_whatsnew_dialog(App& app, bool force_show);
|
||||
void open_legacy_shortcuts_dialog(App& app);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
73
src/legacy_sidebar_grid_popup_services.cpp
Normal file
73
src/legacy_sidebar_grid_popup_services.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "pch.h"
|
||||
#include "legacy_sidebar_grid_popup_services.h"
|
||||
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "log.h"
|
||||
#include "node_button_custom.h"
|
||||
#include "node_image.h"
|
||||
#include "node_panel_floating.h"
|
||||
#include "node_panel_grid.h"
|
||||
#include "node_scroll.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void open_legacy_sidebar_grid_popup(
|
||||
Node& popup_root,
|
||||
NodeButtonCustom& trigger_button,
|
||||
NodePanelGrid& popup_panel)
|
||||
{
|
||||
const glm::vec2 pos = trigger_button.m_pos + glm::vec2(trigger_button.m_size.x * 0.5f, trigger_button.m_size.y);
|
||||
const auto screen = popup_root.m_size;
|
||||
|
||||
popup_panel.find("title")->SetVisibility(true);
|
||||
popup_panel.SetSize(350, YGUndefined);
|
||||
|
||||
if (popup_panel.m_parent)
|
||||
{
|
||||
if (auto fp = dynamic_cast<NodePanelFloating*>(popup_panel.m_parent->m_parent))
|
||||
{
|
||||
detach_legacy_node_from_parent(popup_panel);
|
||||
close_legacy_dialog_node(*fp);
|
||||
}
|
||||
}
|
||||
|
||||
const auto popup_overlay = open_legacy_overlay_node_with_handle(
|
||||
popup_root,
|
||||
std::static_pointer_cast<NodePanelGrid>(popup_panel.shared_from_this()));
|
||||
if (!popup_overlay)
|
||||
{
|
||||
LOG("Grid popup overlay failed: %s", popup_overlay.status().message);
|
||||
return;
|
||||
}
|
||||
|
||||
auto tick = make_legacy_overlay_node_for_anchor<NodeImage>(popup_root);
|
||||
tick->SetPositioning(YGPositionTypeAbsolute);
|
||||
tick->SetSize(32, 16);
|
||||
tick->SetPosition(pos.x - 16, pos.y);
|
||||
tick->set_image("data/ui/popup-tick-up.png");
|
||||
|
||||
const auto tick_overlay = open_legacy_overlay_node_with_handle(popup_root, tick);
|
||||
if (!popup_overlay || !tick_overlay)
|
||||
{
|
||||
close_legacy_overlay_handles_if_open(popup_root, popup_overlay, tick_overlay);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto popup_handle = popup_overlay.value();
|
||||
const auto tick_handle = tick_overlay.value();
|
||||
popup_root.update();
|
||||
|
||||
popup_panel.SetPosition(pos.x - popup_panel.m_size.x / 2.f, pos.y + 16);
|
||||
popup_panel.SetPositioning(YGPositionTypeAbsolute);
|
||||
activate_legacy_popup_overlay(popup_panel);
|
||||
|
||||
auto scroll = popup_panel.find<NodeScroll>("scroller");
|
||||
scroll->SetMaxHeight(glm::max(100.f, screen.y - pos.y - 250.f));
|
||||
|
||||
popup_panel.on_popup_close = [&popup_root, popup_handle, tick_handle](Node*) {
|
||||
close_legacy_overlay_handle_ignoring_status(popup_root, popup_handle);
|
||||
close_legacy_overlay_handle_ignoring_status(popup_root, tick_handle);
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
14
src/legacy_sidebar_grid_popup_services.h
Normal file
14
src/legacy_sidebar_grid_popup_services.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
class Node;
|
||||
class NodeButtonCustom;
|
||||
class NodePanelGrid;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void open_legacy_sidebar_grid_popup(
|
||||
Node& popup_root,
|
||||
NodeButtonCustom& trigger_button,
|
||||
NodePanelGrid& popup_panel);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
Reference in New Issue
Block a user