210 lines
6.5 KiB
C++
210 lines
6.5 KiB
C++
#pragma once
|
|
|
|
#include "foundation/result.h"
|
|
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
|
|
namespace pp::app {
|
|
|
|
struct AppPointerDispatchPlan {
|
|
bool request_redraw = true;
|
|
bool dispatch_designer_first = false;
|
|
bool dispatch_main_if_not_consumed = false;
|
|
float normalized_x = 0.0F;
|
|
float normalized_y = 0.0F;
|
|
};
|
|
|
|
struct AppInputDispatchPlan {
|
|
bool request_redraw = true;
|
|
bool dispatch_main = false;
|
|
};
|
|
|
|
struct AppGestureDispatchPlan {
|
|
bool request_redraw = true;
|
|
bool dispatch_main = false;
|
|
float normalized_x = 0.0F;
|
|
float normalized_y = 0.0F;
|
|
float distance = 0.0F;
|
|
float distance_delta = 0.0F;
|
|
float position_delta_x = 0.0F;
|
|
float position_delta_y = 0.0F;
|
|
};
|
|
|
|
struct AppKeyDispatchPlan {
|
|
bool request_redraw = true;
|
|
bool dispatch_main = false;
|
|
bool set_key_down = false;
|
|
bool sync_vr_camera_rotation = false;
|
|
};
|
|
|
|
struct AppUiVisibilityTogglePlan {
|
|
bool next_ui_visible = true;
|
|
std::size_t first_panel_child_index = 1;
|
|
std::size_t panel_child_count = 0;
|
|
};
|
|
|
|
struct AppStylusAttachPlan {
|
|
bool set_has_stylus = true;
|
|
bool enable_canvas_touch_lock = false;
|
|
};
|
|
|
|
[[nodiscard]] inline pp::foundation::Status validate_input_zoom(float zoom)
|
|
{
|
|
if (!std::isfinite(zoom) || zoom <= 0.0F) {
|
|
return pp::foundation::Status::invalid_argument("input zoom must be finite and positive");
|
|
}
|
|
|
|
return pp::foundation::Status::success();
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<AppPointerDispatchPlan> plan_app_pointer_dispatch(
|
|
float x,
|
|
float y,
|
|
float zoom,
|
|
bool has_designer_layout,
|
|
bool has_main_layout)
|
|
{
|
|
const auto zoom_status = validate_input_zoom(zoom);
|
|
if (!zoom_status.ok()) {
|
|
return pp::foundation::Result<AppPointerDispatchPlan>::failure(zoom_status);
|
|
}
|
|
|
|
if (!std::isfinite(x) || !std::isfinite(y)) {
|
|
return pp::foundation::Result<AppPointerDispatchPlan>::failure(
|
|
pp::foundation::Status::invalid_argument("input coordinates must be finite"));
|
|
}
|
|
|
|
return pp::foundation::Result<AppPointerDispatchPlan>::success(AppPointerDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_designer_first = has_designer_layout,
|
|
.dispatch_main_if_not_consumed = has_main_layout,
|
|
.normalized_x = x / zoom,
|
|
.normalized_y = y / zoom,
|
|
});
|
|
}
|
|
|
|
[[nodiscard]] constexpr AppPointerDispatchPlan plan_app_mouse_cancel_dispatch(
|
|
bool has_designer_layout,
|
|
bool has_main_layout) noexcept
|
|
{
|
|
return AppPointerDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_designer_first = has_designer_layout,
|
|
.dispatch_main_if_not_consumed = has_main_layout,
|
|
.normalized_x = 0.0F,
|
|
.normalized_y = 0.0F,
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] constexpr AppInputDispatchPlan plan_app_main_input_dispatch(bool has_main_layout) noexcept
|
|
{
|
|
return AppInputDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_main = has_main_layout,
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<AppGestureDispatchPlan> plan_app_gesture_dispatch(
|
|
float x0,
|
|
float y0,
|
|
float x1,
|
|
float y1,
|
|
float previous_x0,
|
|
float previous_y0,
|
|
float previous_x1,
|
|
float previous_y1,
|
|
float zoom,
|
|
bool has_main_layout)
|
|
{
|
|
const auto zoom_status = validate_input_zoom(zoom);
|
|
if (!zoom_status.ok()) {
|
|
return pp::foundation::Result<AppGestureDispatchPlan>::failure(zoom_status);
|
|
}
|
|
|
|
if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1)
|
|
|| !std::isfinite(previous_x0) || !std::isfinite(previous_y0)
|
|
|| !std::isfinite(previous_x1) || !std::isfinite(previous_y1)) {
|
|
return pp::foundation::Result<AppGestureDispatchPlan>::failure(
|
|
pp::foundation::Status::invalid_argument("gesture coordinates must be finite"));
|
|
}
|
|
|
|
const float midpoint_x = (x0 + x1) * 0.5F;
|
|
const float midpoint_y = (y0 + y1) * 0.5F;
|
|
const float previous_midpoint_x = (previous_x0 + previous_x1) * 0.5F;
|
|
const float previous_midpoint_y = (previous_y0 + previous_y1) * 0.5F;
|
|
const float dx = x1 - x0;
|
|
const float dy = y1 - y0;
|
|
const float previous_dx = previous_x1 - previous_x0;
|
|
const float previous_dy = previous_y1 - previous_y0;
|
|
const float distance = std::sqrt(dx * dx + dy * dy);
|
|
const float previous_distance = std::sqrt(previous_dx * previous_dx + previous_dy * previous_dy);
|
|
|
|
return pp::foundation::Result<AppGestureDispatchPlan>::success(AppGestureDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_main = has_main_layout,
|
|
.normalized_x = midpoint_x / zoom,
|
|
.normalized_y = midpoint_y / zoom,
|
|
.distance = distance,
|
|
.distance_delta = distance - previous_distance,
|
|
.position_delta_x = midpoint_x - previous_midpoint_x,
|
|
.position_delta_y = midpoint_y - previous_midpoint_y,
|
|
});
|
|
}
|
|
|
|
[[nodiscard]] constexpr AppKeyDispatchPlan plan_app_key_down_dispatch(
|
|
bool has_main_layout,
|
|
bool is_spacebar,
|
|
bool vr_active) noexcept
|
|
{
|
|
return AppKeyDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_main = has_main_layout,
|
|
.set_key_down = true,
|
|
.sync_vr_camera_rotation = is_spacebar && vr_active,
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] constexpr AppKeyDispatchPlan plan_app_key_up_dispatch(bool has_main_layout) noexcept
|
|
{
|
|
return AppKeyDispatchPlan {
|
|
.request_redraw = true,
|
|
.dispatch_main = has_main_layout,
|
|
.set_key_down = false,
|
|
.sync_vr_camera_rotation = false,
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] inline pp::foundation::Result<AppUiVisibilityTogglePlan> plan_app_ui_visibility_toggle(
|
|
bool current_ui_visible,
|
|
bool has_main_layout,
|
|
std::size_t main_child_count,
|
|
std::size_t panel_child_count)
|
|
{
|
|
if (!has_main_layout) {
|
|
return pp::foundation::Result<AppUiVisibilityTogglePlan>::failure(
|
|
pp::foundation::Status::invalid_argument("UI toggle requires a main layout"));
|
|
}
|
|
|
|
if (main_child_count <= 1U) {
|
|
return pp::foundation::Result<AppUiVisibilityTogglePlan>::failure(
|
|
pp::foundation::Status::invalid_argument("UI toggle requires a panel container child"));
|
|
}
|
|
|
|
return pp::foundation::Result<AppUiVisibilityTogglePlan>::success(AppUiVisibilityTogglePlan {
|
|
.next_ui_visible = !current_ui_visible,
|
|
.first_panel_child_index = 1U,
|
|
.panel_child_count = panel_child_count,
|
|
});
|
|
}
|
|
|
|
[[nodiscard]] constexpr AppStylusAttachPlan plan_app_stylus_attach(bool has_canvas) noexcept
|
|
{
|
|
return AppStylusAttachPlan {
|
|
.set_has_stylus = true,
|
|
.enable_canvas_touch_lock = has_canvas,
|
|
};
|
|
}
|
|
|
|
} // namespace pp::app
|