695 lines
20 KiB
C++
695 lines
20 KiB
C++
#include "pch.h"
|
|
#include "app.h"
|
|
#include "app_core/app_frame.h"
|
|
#include "app_core/app_input.h"
|
|
#include "app_core/document_platform_io.h"
|
|
#include "app_core/document_sharing.h"
|
|
#include "platform_api/platform_services.h"
|
|
#include "platform_legacy/legacy_platform_services.h"
|
|
#include "renderer_gl/opengl_capabilities.h"
|
|
|
|
namespace {
|
|
|
|
[[nodiscard]] GLint rgba8_internal_format() noexcept
|
|
{
|
|
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
|
|
}
|
|
|
|
[[nodiscard]] bool should_dispatch_keyboard_visibility(bool visible) noexcept
|
|
{
|
|
const auto action = pp::app::plan_virtual_keyboard(visible);
|
|
return visible
|
|
? action == pp::app::VirtualKeyboardAction::show_keyboard
|
|
: action == pp::app::VirtualKeyboardAction::hide_keyboard;
|
|
}
|
|
|
|
[[nodiscard]] bool should_dispatch_cursor_visibility(bool visible) noexcept
|
|
{
|
|
const auto action = pp::app::plan_cursor_visibility(visible);
|
|
return visible
|
|
? action == pp::app::CursorVisibilityAction::show_cursor
|
|
: action == pp::app::CursorVisibilityAction::hide_cursor;
|
|
}
|
|
|
|
}
|
|
|
|
namespace {
|
|
|
|
[[nodiscard]] pp::platform::PlatformServices& active_platform_services()
|
|
{
|
|
if (App::I)
|
|
{
|
|
if (auto* services = App::I->platform_services())
|
|
return *services;
|
|
}
|
|
return pp::platform::legacy::platform_services();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void App::set_platform_services(pp::platform::PlatformServices* services) noexcept
|
|
{
|
|
platform_services_ = services;
|
|
}
|
|
|
|
pp::platform::PlatformServices* App::platform_services() const noexcept
|
|
{
|
|
return platform_services_;
|
|
}
|
|
|
|
pp::platform::PlatformStoragePaths App::prepare_storage_paths()
|
|
{
|
|
return active_platform_services().prepare_storage_paths();
|
|
}
|
|
|
|
std::string App::clipboard_get_text()
|
|
{
|
|
if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text)
|
|
return {};
|
|
|
|
return active_platform_services().clipboard_text();
|
|
}
|
|
|
|
bool App::clipboard_set_text(const std::string& s)
|
|
{
|
|
if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text)
|
|
return false;
|
|
|
|
return active_platform_services().set_clipboard_text(s);
|
|
}
|
|
|
|
void App::stacktrace()
|
|
{
|
|
active_platform_services().log_stacktrace();
|
|
}
|
|
|
|
void App::crash_test()
|
|
{
|
|
active_platform_services().trigger_crash_test();
|
|
}
|
|
|
|
void App::tick(float dt)
|
|
{
|
|
const auto tick_plan = pp::app::plan_app_frame_tick(
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
if (auto* main = layout_designer[main_id]; tick_plan.tick_designer_layout && main)
|
|
main->tick(dt);
|
|
if (auto* main = layout[main_id]; tick_plan.tick_main_layout && main)
|
|
main->tick(dt);
|
|
}
|
|
|
|
void App::resize(float w, float h)
|
|
{
|
|
LOG("App::resize %d %d", (int)w, (int)h);
|
|
const auto resize_plan = pp::app::plan_app_resize(w, h);
|
|
if (!resize_plan) {
|
|
LOG("App resize plan failed: %s", resize_plan.status().message);
|
|
return;
|
|
}
|
|
|
|
if (resize_plan.value().recreate_ui_render_target) {
|
|
uirtt.create(
|
|
resize_plan.value().render_target_width,
|
|
resize_plan.value().render_target_height,
|
|
-1,
|
|
rgba8_internal_format(),
|
|
true);
|
|
}
|
|
redraw = resize_plan.value().request_redraw;
|
|
width = resize_plan.value().width;
|
|
height = resize_plan.value().height;
|
|
}
|
|
|
|
void App::show_cursor()
|
|
{
|
|
if (!should_dispatch_cursor_visibility(true))
|
|
return;
|
|
|
|
active_platform_services().set_cursor_visible(true);
|
|
}
|
|
|
|
void App::hide_cursor()
|
|
{
|
|
if (!should_dispatch_cursor_visibility(false))
|
|
return;
|
|
|
|
active_platform_services().set_cursor_visible(false);
|
|
}
|
|
|
|
void App::showKeyboard()
|
|
{
|
|
LOG("show keyboard");
|
|
redraw = true;
|
|
if (!should_dispatch_keyboard_visibility(true))
|
|
return;
|
|
|
|
active_platform_services().set_virtual_keyboard_visible(true);
|
|
}
|
|
|
|
void App::hideKeyboard()
|
|
{
|
|
LOG("hide keyboard");
|
|
redraw = true;
|
|
if (!should_dispatch_keyboard_visibility(false))
|
|
return;
|
|
|
|
active_platform_services().set_virtual_keyboard_visible(false);
|
|
}
|
|
|
|
void App::pick_image(std::function<void(std::string path)> callback)
|
|
{
|
|
redraw = true;
|
|
active_platform_services().pick_image(std::move(callback));
|
|
}
|
|
|
|
void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback)
|
|
{
|
|
redraw = true;
|
|
active_platform_services().pick_file(std::move(types), std::move(callback));
|
|
}
|
|
|
|
void App::pick_file_save(const std::string& type, const std::string& default_name,
|
|
std::function<void(std::string)> writer, std::function<void(const std::string& path, bool saved)> callback)
|
|
{
|
|
redraw = true;
|
|
const auto target = active_platform_services().prepare_writable_file(type, default_name, data_path, tmp_path);
|
|
if (target.path.empty())
|
|
{
|
|
callback({}, false);
|
|
return;
|
|
}
|
|
|
|
LOG("App::pick_file_save %s", target.path.c_str());
|
|
auto write_and_save = [=] {
|
|
writer(target.path);
|
|
save_prepared_file(target.path, target.suggested_name, callback);
|
|
};
|
|
|
|
if (target.write_on_background_thread)
|
|
std::thread(write_and_save).detach();
|
|
else
|
|
write_and_save();
|
|
}
|
|
|
|
void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback)
|
|
{
|
|
redraw = true;
|
|
active_platform_services().pick_save_file(std::move(types), std::move(callback));
|
|
}
|
|
|
|
bool App::uses_prepared_file_writes() const
|
|
{
|
|
return active_platform_services().uses_prepared_file_writes();
|
|
}
|
|
|
|
bool App::uses_work_directory_document_export_collections() const
|
|
{
|
|
return active_platform_services().uses_work_directory_document_export_collections();
|
|
}
|
|
|
|
bool App::disables_network_tls_verification() const
|
|
{
|
|
return active_platform_services().disables_network_tls_verification();
|
|
}
|
|
|
|
bool App::uses_ppbr_export_data_directory_override() const
|
|
{
|
|
return active_platform_services().uses_ppbr_export_data_directory_override();
|
|
}
|
|
|
|
bool App::platform_supports_sonarpen() const
|
|
{
|
|
return active_platform_services().supports_sonarpen();
|
|
}
|
|
|
|
void App::start_platform_sonarpen()
|
|
{
|
|
active_platform_services().start_sonarpen();
|
|
}
|
|
|
|
int App::default_canvas_resolution() const
|
|
{
|
|
return active_platform_services().default_canvas_resolution();
|
|
}
|
|
|
|
bool App::draws_canvas_tip_for_input(kEventSource source, kEventType type) const
|
|
{
|
|
return active_platform_services().draws_canvas_tip_for_pointer(
|
|
source == kEventSource::Mouse,
|
|
source == kEventSource::Stylus,
|
|
type == kEventType::MouseUpL);
|
|
}
|
|
|
|
float App::adjust_canvas_input_pressure(float pressure) const
|
|
{
|
|
return active_platform_services().adjust_canvas_input_pressure(pressure);
|
|
}
|
|
|
|
void App::pick_dir(std::function<void(std::string path)> callback)
|
|
{
|
|
redraw = true;
|
|
active_platform_services().pick_directory(std::move(callback));
|
|
}
|
|
|
|
bool App::supports_working_directory_picker() const
|
|
{
|
|
return active_platform_services().supports_working_directory_picker();
|
|
}
|
|
|
|
std::string App::format_working_directory_path(std::string_view path) const
|
|
{
|
|
return active_platform_services().format_working_directory_path(path);
|
|
}
|
|
|
|
void App::display_file(std::string path)
|
|
{
|
|
if (pp::app::plan_display_file(path) == pp::app::DisplayFileAction::ignore_empty_path)
|
|
return;
|
|
|
|
active_platform_services().display_file(path);
|
|
}
|
|
|
|
void App::share_file(std::string path)
|
|
{
|
|
const auto plan = pp::app::plan_document_share(path);
|
|
if (plan == pp::app::DocumentShareAction::show_save_required_warning)
|
|
{
|
|
message_box("Sharing failed", "Please save the document before sharing it.");
|
|
return;
|
|
}
|
|
active_platform_services().share_file(path);
|
|
}
|
|
|
|
void App::request_app_close()
|
|
{
|
|
active_platform_services().request_app_close();
|
|
}
|
|
|
|
bool App::start_platform_vr_mode()
|
|
{
|
|
return active_platform_services().start_vr_mode();
|
|
}
|
|
|
|
void App::stop_platform_vr_mode()
|
|
{
|
|
active_platform_services().stop_vr_mode();
|
|
}
|
|
|
|
void App::attach_ui_thread()
|
|
{
|
|
active_platform_services().attach_ui_thread();
|
|
}
|
|
|
|
void App::detach_ui_thread()
|
|
{
|
|
active_platform_services().detach_ui_thread();
|
|
}
|
|
|
|
void App::acquire_render_context()
|
|
{
|
|
active_platform_services().acquire_render_context();
|
|
}
|
|
|
|
void App::release_render_context()
|
|
{
|
|
active_platform_services().release_render_context();
|
|
}
|
|
|
|
void App::present_render_context()
|
|
{
|
|
active_platform_services().present_render_context();
|
|
}
|
|
|
|
void App::bind_default_render_target()
|
|
{
|
|
active_platform_services().bind_default_render_target();
|
|
}
|
|
|
|
void App::bind_main_render_target()
|
|
{
|
|
active_platform_services().bind_main_render_target();
|
|
}
|
|
|
|
void App::apply_render_platform_hints()
|
|
{
|
|
active_platform_services().apply_render_platform_hints();
|
|
}
|
|
|
|
void App::install_render_debug_callback()
|
|
{
|
|
active_platform_services().install_render_debug_callback();
|
|
}
|
|
|
|
void App::begin_render_capture_frame()
|
|
{
|
|
active_platform_services().begin_render_capture_frame();
|
|
}
|
|
|
|
void App::end_render_capture_frame()
|
|
{
|
|
active_platform_services().end_render_capture_frame();
|
|
}
|
|
|
|
bool App::platform_deletes_recorded_files_on_clear()
|
|
{
|
|
return active_platform_services().deletes_recorded_files_on_clear();
|
|
}
|
|
|
|
void App::clear_platform_recorded_files(std::string path)
|
|
{
|
|
active_platform_services().clear_recorded_files(path);
|
|
}
|
|
|
|
void App::publish_exported_image(std::string path)
|
|
{
|
|
active_platform_services().publish_exported_image(path);
|
|
}
|
|
|
|
void App::flush_platform_storage()
|
|
{
|
|
active_platform_services().flush_persistent_storage();
|
|
}
|
|
|
|
std::vector<std::string> App::document_browse_roots() const
|
|
{
|
|
return active_platform_services().document_browse_roots(work_path, data_path);
|
|
}
|
|
|
|
void App::save_platform_ui_state()
|
|
{
|
|
active_platform_services().save_ui_state();
|
|
}
|
|
|
|
bool App::platform_enables_live_asset_reloading()
|
|
{
|
|
return active_platform_services().enables_live_asset_reloading();
|
|
}
|
|
|
|
void App::update_platform_frame(float delta_time_seconds)
|
|
{
|
|
active_platform_services().update_platform_frame(delta_time_seconds);
|
|
}
|
|
|
|
void App::report_rendered_frames(int frames)
|
|
{
|
|
active_platform_services().report_rendered_frames(frames);
|
|
}
|
|
|
|
void App::save_prepared_file(
|
|
std::string path,
|
|
std::string suggested_name,
|
|
std::function<void(const std::string& path, bool saved)> callback)
|
|
{
|
|
active_platform_services().save_prepared_file(
|
|
path,
|
|
suggested_name,
|
|
[callback = std::move(callback)](std::string saved_path, bool saved) {
|
|
callback(saved_path, saved);
|
|
});
|
|
}
|
|
|
|
bool App::mouse_down(int button, float x, float y, float pressure, kEventSource source, bool eraser)
|
|
{
|
|
const auto plan = pp::app::plan_app_pointer_dispatch(
|
|
x,
|
|
y,
|
|
zoom,
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Mouse down dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
redraw = plan.value().request_redraw;
|
|
MouseEvent e;
|
|
e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_pressure = pressure;
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
|
return main->on_event(&e) == kEventResult::Consumed;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_move(float x, float y, float pressure, kEventSource source, bool eraser)
|
|
{
|
|
const auto plan = pp::app::plan_app_pointer_dispatch(
|
|
x,
|
|
y,
|
|
zoom,
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Mouse move dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
cursor = { plan.value().normalized_x, plan.value().normalized_y };
|
|
redraw = plan.value().request_redraw;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseMove;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_pressure = pressure;
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
|
return main->on_event(&e) == kEventResult::Consumed;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_up(int button, float x, float y, kEventSource source, bool eraser)
|
|
{
|
|
const auto plan = pp::app::plan_app_pointer_dispatch(
|
|
x,
|
|
y,
|
|
zoom,
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Mouse up dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
redraw = plan.value().request_redraw;
|
|
MouseEvent e;
|
|
e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_source = source;
|
|
e.m_eraser = eraser;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
|
return main->on_event(&e) == kEventResult::Consumed;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_scroll(float x, float y, float delta)
|
|
{
|
|
const auto plan = pp::app::plan_app_pointer_dispatch(
|
|
x,
|
|
y,
|
|
zoom,
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Mouse scroll dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
redraw = plan.value().request_redraw;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseScroll;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_scroll_delta = delta;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout_designer[main_id]; plan.value().dispatch_designer_first && main)
|
|
return main->on_event(&e) == kEventResult::Consumed;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main_if_not_consumed && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::mouse_cancel(int button)
|
|
{
|
|
const auto plan = pp::app::plan_app_mouse_cancel_dispatch(
|
|
layout_designer.get(main_id) != nullptr,
|
|
layout.get(main_id) != nullptr);
|
|
redraw = plan.request_redraw;
|
|
MouseEvent e;
|
|
e.m_type = kEventType::MouseCancel;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout_designer[main_id]; plan.dispatch_designer_first && main)
|
|
return main->on_event(&e) == kEventResult::Consumed;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main_if_not_consumed && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1)
|
|
{
|
|
const auto plan = pp::app::plan_app_gesture_dispatch(
|
|
p0.x,
|
|
p0.y,
|
|
p1.x,
|
|
p1.y,
|
|
p0.x,
|
|
p0.y,
|
|
p1.x,
|
|
p1.y,
|
|
zoom,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Gesture start dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
redraw = plan.value().request_redraw;
|
|
GestureEvent e;
|
|
e.m_type = kEventType::GestureStart;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_distance = plan.value().distance;
|
|
gesture_p0 = p0;
|
|
gesture_p1 = p1;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1)
|
|
{
|
|
const auto plan = pp::app::plan_app_gesture_dispatch(
|
|
p0.x,
|
|
p0.y,
|
|
p1.x,
|
|
p1.y,
|
|
gesture_p0.x,
|
|
gesture_p0.y,
|
|
gesture_p1.x,
|
|
gesture_p1.y,
|
|
zoom,
|
|
layout.get(main_id) != nullptr);
|
|
if (!plan) {
|
|
LOG("Gesture move dispatch plan failed: %s", plan.status().message);
|
|
return false;
|
|
}
|
|
|
|
redraw = plan.value().request_redraw;
|
|
GestureEvent e;
|
|
e.m_type = kEventType::GestureMove;
|
|
e.m_pos = { plan.value().normalized_x, plan.value().normalized_y };
|
|
e.m_distance = plan.value().distance;
|
|
e.m_distance_delta = plan.value().distance_delta;
|
|
e.m_pos_delta = { plan.value().position_delta_x, plan.value().position_delta_y };
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.value().dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::gesture_end()
|
|
{
|
|
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
|
redraw = plan.request_redraw;
|
|
GestureEvent e;
|
|
e.m_type = kEventType::GestureEnd;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::touch_tap(const glm::vec2& pos, int fingers, int tap_count)
|
|
{
|
|
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
|
redraw = plan.request_redraw;
|
|
TouchEvent e;
|
|
e.m_type = kEventType::TouchTap;
|
|
e.m_finger_count = fingers;
|
|
e.m_tap_count = tap_count;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_down(kKey key)
|
|
{
|
|
const auto plan = pp::app::plan_app_key_down_dispatch(
|
|
layout.get(main_id) != nullptr,
|
|
key == kKey::KeySpacebar,
|
|
vr_active);
|
|
if (plan.sync_vr_camera_rotation)
|
|
canvas->m_canvas->m_cam_rot = vr_rot;
|
|
redraw = plan.request_redraw;
|
|
keys[(int)key] = plan.set_key_down;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyDown;
|
|
e.m_key = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_up(kKey key)
|
|
{
|
|
const auto plan = pp::app::plan_app_key_up_dispatch(layout.get(main_id) != nullptr);
|
|
redraw = plan.request_redraw;
|
|
keys[(int)key] = plan.set_key_down;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyUp;
|
|
e.m_key = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
bool App::key_char(char key)
|
|
{
|
|
const auto plan = pp::app::plan_app_main_input_dispatch(layout.get(main_id) != nullptr);
|
|
redraw = plan.request_redraw;
|
|
KeyEvent e;
|
|
e.m_type = kEventType::KeyChar;
|
|
e.m_char = key;
|
|
kEventResult ret = kEventResult::Available;
|
|
if (auto* main = layout[main_id]; plan.dispatch_main && main)
|
|
ret = main->on_event(&e);
|
|
return ret == kEventResult::Consumed;
|
|
}
|
|
|
|
void App::toggle_ui()
|
|
{
|
|
auto* main = layout[main_id];
|
|
const std::size_t main_child_count = main ? main->m_children.size() : 0U;
|
|
auto* panel_container = main_child_count > 1U ? main->m_children[1].get() : nullptr;
|
|
const auto plan = pp::app::plan_app_ui_visibility_toggle(
|
|
ui_visible,
|
|
main != nullptr,
|
|
main_child_count,
|
|
panel_container ? panel_container->m_children.size() : 0U);
|
|
if (!plan) {
|
|
LOG("UI toggle plan failed: %s", plan.status().message);
|
|
return;
|
|
}
|
|
|
|
ui_visible = plan.value().next_ui_visible;
|
|
if (!panel_container)
|
|
return;
|
|
|
|
for (std::size_t i = plan.value().first_panel_child_index;
|
|
i < plan.value().panel_child_count;
|
|
++i) {
|
|
panel_container->m_children[i]->m_display = ui_visible;
|
|
}
|
|
}
|
|
|
|
void App::set_stylus()
|
|
{
|
|
const auto plan = pp::app::plan_app_stylus_attach(canvas != nullptr);
|
|
has_stylus = plan.set_has_stylus;
|
|
if (plan.enable_canvas_touch_lock && canvas)
|
|
canvas->m_canvas->m_touch_lock = true;
|
|
}
|