Plan UI observer frame clipping
This commit is contained in:
@@ -839,8 +839,9 @@ Known local toolchain state:
|
||||
- `pp_app_core_app_frame_tests` covers the legacy initial surface default,
|
||||
idle/redraw/animation update gating, canvas-stroke draw eligibility, VR UI
|
||||
visibility, main UI suppression in VR-only mode, tick layout selection,
|
||||
resize render-target/redraw projection, invalid resize rejection, and redraw
|
||||
reset planning.
|
||||
resize render-target/redraw projection, invalid resize rejection, redraw
|
||||
reset planning, UI observer clipping, on-screen enter/leave transition
|
||||
decisions, scissor projection, and malformed observer geometry rejection.
|
||||
- `pp_app_core_app_thread_tests` covers render/UI task dispatch, immediate
|
||||
same-thread execution, unique queued-task replacement, stopped-worker
|
||||
no-wait behavior, render queue context wrapping, UI tick redraw scheduling,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -200,10 +200,12 @@ and floating-point render targets; `App::title_update`,
|
||||
legacy UI nodes still render the strings and status lights.
|
||||
Frame-level app decisions for the initial surface size, redraw/animation update
|
||||
gating, layout ticking, resize render-target recreation, canvas-stroke drawing,
|
||||
VR UI drawing, main UI drawing, and redraw reset now live in `pp_app_core`;
|
||||
VR UI drawing, main UI drawing, UI observer clipping/on-screen transition/scissor
|
||||
projection, and redraw reset now live in `pp_app_core`;
|
||||
`App::create`, `App::tick`, `App::resize`, `App::update`, `App::draw`, and
|
||||
`pano_cli plan-app-frame` consume those plans while retained layout traversal,
|
||||
render-target recreation, and OpenGL/UI drawing stay in the legacy app.
|
||||
render-target recreation, `Node` parent walking, on-screen callbacks, and
|
||||
OpenGL/UI drawing stay in the legacy app.
|
||||
App input dispatch decisions for pointer coordinate normalization, mouse
|
||||
designer-first routing, gesture midpoint/delta math, touch/key main-layout
|
||||
routing, VR spacebar camera-sync intent, UI visibility toggling, and stylus
|
||||
@@ -1682,7 +1684,11 @@ Results:
|
||||
`pano_cli_plan_app_frame_vr_smoke`, and
|
||||
`pano_cli_plan_app_frame_idle_missing_canvas_smoke`, with resize automation
|
||||
covered by `pano_cli_plan_app_frame_resize_smoke` and
|
||||
`pano_cli_plan_app_frame_rejects_bad_resize`.
|
||||
`pano_cli_plan_app_frame_rejects_bad_resize`. On 2026-06-05, UI observer
|
||||
clipping/on-screen/scissor projection coverage was added through
|
||||
`pp_app_core_app_frame_tests`, `pano_cli_plan_app_frame_observer_smoke`,
|
||||
`pano_cli_plan_app_frame_observer_clipped_smoke`, and
|
||||
`pano_cli_plan_app_frame_rejects_bad_observer`.
|
||||
- `PanoPainter`, `pp_app_core_app_input_tests`, and `pano_cli` built after
|
||||
app input routing and normalization moved into `pp_app_core`.
|
||||
- Focused app-input CTest coverage passed for `pp_app_core_app_input_tests`,
|
||||
|
||||
105
src/app.cpp
105
src/app.cpp
@@ -495,54 +495,67 @@ void App::async_swap()
|
||||
|
||||
bool App::update_ui_observer(Node *n)
|
||||
{
|
||||
if (n && n->m_display)
|
||||
{
|
||||
auto box = n->m_clip_uncut;
|
||||
Node* p = n->m_parent;
|
||||
while (p)
|
||||
{
|
||||
float pt = YGNodeLayoutGetPadding(p->y_node, YGEdgeTop);
|
||||
float pr = YGNodeLayoutGetPadding(p->y_node, YGEdgeRight);
|
||||
float pb = YGNodeLayoutGetPadding(p->y_node, YGEdgeBottom);
|
||||
float pl = YGNodeLayoutGetPadding(p->y_node, YGEdgeLeft);
|
||||
glm::vec2 off_p(pl, pt);
|
||||
glm::vec2 off_s(pr, pb);
|
||||
//glm::vec2 parent_offset = p->m_parent ? -p->m_parent->m_pos_offset_childred : glm::vec2(0.f);
|
||||
glm::vec4 pclip = { xy(p->m_clip_uncut) + off_p, zw(p->m_clip_uncut) - off_s - off_p/* + parent_offset*/ };
|
||||
box = rect_intersection(box, pclip);
|
||||
p = p->m_parent;
|
||||
std::vector<pp::app::AppUiObserverParentClip> parent_clips;
|
||||
if (n) {
|
||||
for (Node* p = n->m_parent; p; p = p->m_parent) {
|
||||
parent_clips.push_back(pp::app::AppUiObserverParentClip {
|
||||
.clip = pp::app::AppUiObserverRect {
|
||||
.x = p->m_clip_uncut.x,
|
||||
.y = p->m_clip_uncut.y,
|
||||
.width = p->m_clip_uncut.z,
|
||||
.height = p->m_clip_uncut.w,
|
||||
},
|
||||
.padding_top = YGNodeLayoutGetPadding(p->y_node, YGEdgeTop),
|
||||
.padding_right = YGNodeLayoutGetPadding(p->y_node, YGEdgeRight),
|
||||
.padding_bottom = YGNodeLayoutGetPadding(p->y_node, YGEdgeBottom),
|
||||
.padding_left = YGNodeLayoutGetPadding(p->y_node, YGEdgeLeft),
|
||||
});
|
||||
}
|
||||
//auto box = n->m_clip;
|
||||
//glm::ivec4 c = glm::vec4((int)box.x - 1, (int)(height / zoom - box.y - box.w) - 1, (int)box.z + 2, (int)box.w + 2) * zoom;
|
||||
glm::vec2 parent_offset = n->m_parent ? n->m_parent->m_pos_offset_childred : glm::vec2(0.f);
|
||||
if (box.z <= 0 || box.w <= 0)
|
||||
{
|
||||
if (n->m_on_screen)
|
||||
{
|
||||
if (dynamic_cast<NodeStrokePreview*>(n))
|
||||
p = p;
|
||||
n->handle_on_screen(true, false);
|
||||
n->m_on_screen = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!n->m_on_screen)
|
||||
{
|
||||
n->handle_on_screen(false, true);
|
||||
n->m_on_screen = true;
|
||||
}
|
||||
glm::ivec4 c = glm::vec4(box.x - 1, (height / zoom - box.y - box.w - 1), box.z + 2, box.w + 2) * zoom;
|
||||
apply_app_scissor(pp::renderer::gl::OpenGlScissorRect {
|
||||
.enabled = 1U,
|
||||
.x = static_cast<std::int32_t>(floorf(c.x + off_x)),
|
||||
.y = static_cast<std::int32_t>(floorf(c.y + off_y)),
|
||||
.width = static_cast<std::int32_t>(ceilf(c.z)),
|
||||
.height = static_cast<std::int32_t>(ceilf(c.w)),
|
||||
});
|
||||
n->draw();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
const auto plan = pp::app::plan_app_ui_observer(
|
||||
n != nullptr,
|
||||
n && n->m_display,
|
||||
n && n->m_on_screen,
|
||||
n
|
||||
? pp::app::AppUiObserverRect {
|
||||
.x = n->m_clip_uncut.x,
|
||||
.y = n->m_clip_uncut.y,
|
||||
.width = n->m_clip_uncut.z,
|
||||
.height = n->m_clip_uncut.w,
|
||||
}
|
||||
: pp::app::AppUiObserverRect {},
|
||||
parent_clips,
|
||||
height,
|
||||
zoom,
|
||||
off_x,
|
||||
off_y);
|
||||
if (!plan) {
|
||||
LOG("UI observer plan failed: %s", plan.status().message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!n)
|
||||
return false;
|
||||
|
||||
if (plan.value().notify_leave_screen)
|
||||
n->handle_on_screen(true, false);
|
||||
if (plan.value().notify_enter_screen)
|
||||
n->handle_on_screen(false, true);
|
||||
n->m_on_screen = plan.value().next_on_screen;
|
||||
|
||||
if (!plan.value().draw_node)
|
||||
return false;
|
||||
|
||||
apply_app_scissor(pp::renderer::gl::OpenGlScissorRect {
|
||||
.enabled = 1U,
|
||||
.x = plan.value().scissor_x,
|
||||
.y = plan.value().scissor_y,
|
||||
.width = plan.value().scissor_width,
|
||||
.height = plan.value().scissor_height,
|
||||
});
|
||||
n->draw();
|
||||
return true;
|
||||
}
|
||||
|
||||
void App::draw(float dt)
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
|
||||
namespace pp::app {
|
||||
|
||||
@@ -39,6 +41,33 @@ struct AppResizePlan {
|
||||
bool request_redraw = true;
|
||||
};
|
||||
|
||||
struct AppUiObserverRect {
|
||||
float x = 0.0F;
|
||||
float y = 0.0F;
|
||||
float width = 0.0F;
|
||||
float height = 0.0F;
|
||||
};
|
||||
|
||||
struct AppUiObserverParentClip {
|
||||
AppUiObserverRect clip;
|
||||
float padding_top = 0.0F;
|
||||
float padding_right = 0.0F;
|
||||
float padding_bottom = 0.0F;
|
||||
float padding_left = 0.0F;
|
||||
};
|
||||
|
||||
struct AppUiObserverPlan {
|
||||
bool draw_node = false;
|
||||
bool notify_enter_screen = false;
|
||||
bool notify_leave_screen = false;
|
||||
bool next_on_screen = false;
|
||||
AppUiObserverRect visible_clip;
|
||||
std::int32_t scissor_x = 0;
|
||||
std::int32_t scissor_y = 0;
|
||||
std::int32_t scissor_width = 0;
|
||||
std::int32_t scissor_height = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr AppInitialSurfacePlan plan_app_initial_surface() noexcept
|
||||
{
|
||||
return AppInitialSurfacePlan {
|
||||
@@ -110,4 +139,102 @@ struct AppResizePlan {
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr AppUiObserverRect intersect_app_ui_observer_rect(
|
||||
AppUiObserverRect a,
|
||||
AppUiObserverRect b) noexcept
|
||||
{
|
||||
const float x0 = a.x > b.x ? a.x : b.x;
|
||||
const float y0 = a.y > b.y ? a.y : b.y;
|
||||
const float x1 = (a.x + a.width) < (b.x + b.width) ? (a.x + a.width) : (b.x + b.width);
|
||||
const float y1 = (a.y + a.height) < (b.y + b.height) ? (a.y + a.height) : (b.y + b.height);
|
||||
return AppUiObserverRect {
|
||||
.x = x0,
|
||||
.y = y0,
|
||||
.width = x1 - x0,
|
||||
.height = y1 - y0,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<AppUiObserverPlan> plan_app_ui_observer(
|
||||
bool has_node,
|
||||
bool display,
|
||||
bool was_on_screen,
|
||||
AppUiObserverRect node_clip,
|
||||
std::span<const AppUiObserverParentClip> parent_clips,
|
||||
float surface_height,
|
||||
float zoom,
|
||||
float offset_x,
|
||||
float offset_y)
|
||||
{
|
||||
if (!has_node || !display) {
|
||||
return pp::foundation::Result<AppUiObserverPlan>::success(AppUiObserverPlan {
|
||||
.draw_node = false,
|
||||
.next_on_screen = was_on_screen,
|
||||
.visible_clip = node_clip,
|
||||
});
|
||||
}
|
||||
|
||||
const auto finite_rect = [](AppUiObserverRect rect) noexcept {
|
||||
return std::isfinite(rect.x) && std::isfinite(rect.y)
|
||||
&& std::isfinite(rect.width) && std::isfinite(rect.height);
|
||||
};
|
||||
|
||||
if (!finite_rect(node_clip) || !std::isfinite(surface_height)
|
||||
|| !std::isfinite(zoom) || !std::isfinite(offset_x) || !std::isfinite(offset_y)) {
|
||||
return pp::foundation::Result<AppUiObserverPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("UI observer geometry must be finite"));
|
||||
}
|
||||
|
||||
if (surface_height < 1.0F || zoom <= 0.0F) {
|
||||
return pp::foundation::Result<AppUiObserverPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("UI observer surface height and zoom must be positive"));
|
||||
}
|
||||
|
||||
AppUiObserverRect visible = node_clip;
|
||||
for (const auto& parent : parent_clips) {
|
||||
if (!finite_rect(parent.clip)
|
||||
|| !std::isfinite(parent.padding_top)
|
||||
|| !std::isfinite(parent.padding_right)
|
||||
|| !std::isfinite(parent.padding_bottom)
|
||||
|| !std::isfinite(parent.padding_left)) {
|
||||
return pp::foundation::Result<AppUiObserverPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("UI observer parent geometry must be finite"));
|
||||
}
|
||||
|
||||
const AppUiObserverRect padded {
|
||||
.x = parent.clip.x + parent.padding_left,
|
||||
.y = parent.clip.y + parent.padding_top,
|
||||
.width = parent.clip.width - parent.padding_right - parent.padding_left,
|
||||
.height = parent.clip.height - parent.padding_bottom - parent.padding_top,
|
||||
};
|
||||
visible = intersect_app_ui_observer_rect(visible, padded);
|
||||
}
|
||||
|
||||
if (visible.width <= 0.0F || visible.height <= 0.0F) {
|
||||
return pp::foundation::Result<AppUiObserverPlan>::success(AppUiObserverPlan {
|
||||
.draw_node = false,
|
||||
.notify_leave_screen = was_on_screen,
|
||||
.next_on_screen = false,
|
||||
.visible_clip = visible,
|
||||
});
|
||||
}
|
||||
|
||||
const float projected_x = (visible.x - 1.0F) * zoom;
|
||||
const float projected_y = (surface_height / zoom - visible.y - visible.height - 1.0F) * zoom;
|
||||
const float projected_width = (visible.width + 2.0F) * zoom;
|
||||
const float projected_height = (visible.height + 2.0F) * zoom;
|
||||
|
||||
return pp::foundation::Result<AppUiObserverPlan>::success(AppUiObserverPlan {
|
||||
.draw_node = true,
|
||||
.notify_enter_screen = !was_on_screen,
|
||||
.notify_leave_screen = false,
|
||||
.next_on_screen = true,
|
||||
.visible_clip = visible,
|
||||
.scissor_x = static_cast<std::int32_t>(std::floor(projected_x + offset_x)),
|
||||
.scissor_y = static_cast<std::int32_t>(std::floor(projected_y + offset_y)),
|
||||
.scissor_width = static_cast<std::int32_t>(std::ceil(projected_width)),
|
||||
.scissor_height = static_cast<std::int32_t>(std::ceil(projected_height)),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pp::app
|
||||
|
||||
@@ -1028,6 +1028,25 @@ if(TARGET pano_cli)
|
||||
WILL_FAIL TRUE
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-frame\".*\"message\":\"resize dimensions")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_frame_observer_smoke
|
||||
COMMAND pano_cli plan-app-frame)
|
||||
set_tests_properties(pano_cli_plan_app_frame_observer_smoke PROPERTIES
|
||||
LABELS "app;ui;integration;desktop-fast"
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-frame\".*\"observer\":\\{\"drawNode\":true,\"notifyEnterScreen\":true,\"notifyLeaveScreen\":false,\"nextOnScreen\":true,\"visibleWidth\":65,\"visibleHeight\":35,\"scissorX\":28,\"scissorY\":433,\"scissorWidth\":134,\"scissorHeight\":74\\}")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_frame_observer_clipped_smoke
|
||||
COMMAND pano_cli plan-app-frame --observer-on-screen --observer-clipped-out)
|
||||
set_tests_properties(pano_cli_plan_app_frame_observer_clipped_smoke PROPERTIES
|
||||
LABELS "app;ui;integration;desktop-fast;fuzz"
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-frame\".*\"observer\":\\{\"drawNode\":false,\"notifyEnterScreen\":false,\"notifyLeaveScreen\":true,\"nextOnScreen\":false")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_frame_rejects_bad_observer
|
||||
COMMAND pano_cli plan-app-frame --observer-bad-geometry)
|
||||
set_tests_properties(pano_cli_plan_app_frame_rejects_bad_observer PROPERTIES
|
||||
LABELS "app;ui;integration;desktop-fast;fuzz"
|
||||
WILL_FAIL TRUE
|
||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-app-frame\".*\"message\":\"UI observer geometry")
|
||||
|
||||
add_test(NAME pano_cli_plan_app_thread_dispatch_smoke
|
||||
COMMAND pano_cli plan-app-thread --kind dispatch --unique --queued-tasks 2 --wait)
|
||||
set_tests_properties(pano_cli_plan_app_thread_dispatch_smoke PROPERTIES
|
||||
|
||||
@@ -101,6 +101,129 @@ void resize_plan_rejects_invalid_dimensions(pp::tests::Harness& harness)
|
||||
PP_EXPECT(harness, !pp::app::plan_app_resize(std::nanf(""), 720.0F));
|
||||
}
|
||||
|
||||
void ui_observer_plan_projects_visible_clip_to_scissor(pp::tests::Harness& harness)
|
||||
{
|
||||
const pp::app::AppUiObserverParentClip parents[] {
|
||||
{
|
||||
.clip = {
|
||||
.x = 0.0F,
|
||||
.y = 0.0F,
|
||||
.width = 80.0F,
|
||||
.height = 60.0F,
|
||||
},
|
||||
.padding_top = 5.0F,
|
||||
.padding_right = 5.0F,
|
||||
.padding_bottom = 5.0F,
|
||||
.padding_left = 5.0F,
|
||||
},
|
||||
};
|
||||
|
||||
const auto plan = pp::app::plan_app_ui_observer(
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
{
|
||||
.x = 10.0F,
|
||||
.y = 20.0F,
|
||||
.width = 100.0F,
|
||||
.height = 50.0F,
|
||||
},
|
||||
parents,
|
||||
540.0F,
|
||||
2.0F,
|
||||
10.0F,
|
||||
5.0F);
|
||||
|
||||
PP_EXPECT(harness, plan);
|
||||
if (plan) {
|
||||
PP_EXPECT(harness, plan.value().draw_node);
|
||||
PP_EXPECT(harness, plan.value().notify_enter_screen);
|
||||
PP_EXPECT(harness, !plan.value().notify_leave_screen);
|
||||
PP_EXPECT(harness, plan.value().next_on_screen);
|
||||
PP_EXPECT(harness, plan.value().visible_clip.width == 65.0F);
|
||||
PP_EXPECT(harness, plan.value().visible_clip.height == 35.0F);
|
||||
PP_EXPECT(harness, plan.value().scissor_x == 28);
|
||||
PP_EXPECT(harness, plan.value().scissor_y == 433);
|
||||
PP_EXPECT(harness, plan.value().scissor_width == 134);
|
||||
PP_EXPECT(harness, plan.value().scissor_height == 74);
|
||||
}
|
||||
}
|
||||
|
||||
void ui_observer_plan_notifies_leave_for_clipped_visible_node(pp::tests::Harness& harness)
|
||||
{
|
||||
const pp::app::AppUiObserverParentClip parents[] {
|
||||
{
|
||||
.clip = {
|
||||
.x = 0.0F,
|
||||
.y = 0.0F,
|
||||
.width = 10.0F,
|
||||
.height = 10.0F,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const auto plan = pp::app::plan_app_ui_observer(
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
{
|
||||
.x = 100.0F,
|
||||
.y = 100.0F,
|
||||
.width = 10.0F,
|
||||
.height = 10.0F,
|
||||
},
|
||||
parents,
|
||||
540.0F,
|
||||
1.0F,
|
||||
0.0F,
|
||||
0.0F);
|
||||
|
||||
PP_EXPECT(harness, plan);
|
||||
if (plan) {
|
||||
PP_EXPECT(harness, !plan.value().draw_node);
|
||||
PP_EXPECT(harness, plan.value().notify_leave_screen);
|
||||
PP_EXPECT(harness, !plan.value().next_on_screen);
|
||||
}
|
||||
}
|
||||
|
||||
void ui_observer_plan_rejects_bad_geometry(pp::tests::Harness& harness)
|
||||
{
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
!pp::app::plan_app_ui_observer(
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
{
|
||||
.x = 0.0F,
|
||||
.y = 0.0F,
|
||||
.width = 10.0F,
|
||||
.height = 10.0F,
|
||||
},
|
||||
{},
|
||||
540.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F));
|
||||
PP_EXPECT(
|
||||
harness,
|
||||
!pp::app::plan_app_ui_observer(
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
{
|
||||
.x = std::nanf(""),
|
||||
.y = 0.0F,
|
||||
.width = 10.0F,
|
||||
.height = 10.0F,
|
||||
},
|
||||
{},
|
||||
540.0F,
|
||||
1.0F,
|
||||
0.0F,
|
||||
0.0F));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
@@ -115,5 +238,8 @@ int main()
|
||||
harness.run("tick plan selects available layouts", tick_plan_selects_available_layouts);
|
||||
harness.run("resize plan projects render target and redraw", resize_plan_projects_render_target_and_redraw);
|
||||
harness.run("resize plan rejects invalid dimensions", resize_plan_rejects_invalid_dimensions);
|
||||
harness.run("ui observer plan projects visible clip to scissor", ui_observer_plan_projects_visible_clip_to_scissor);
|
||||
harness.run("ui observer plan notifies leave for clipped visible node", ui_observer_plan_notifies_leave_for_clipped_visible_node);
|
||||
harness.run("ui observer plan rejects bad geometry", ui_observer_plan_rejects_bad_geometry);
|
||||
return harness.finish();
|
||||
}
|
||||
|
||||
@@ -265,6 +265,10 @@ struct PlanAppFrameArgs {
|
||||
float resize_width = 1280.0F;
|
||||
float resize_height = 720.0F;
|
||||
bool bad_resize = false;
|
||||
bool observer_display = true;
|
||||
bool observer_on_screen = false;
|
||||
bool observer_clipped_out = false;
|
||||
bool observer_bad_geometry = false;
|
||||
};
|
||||
|
||||
struct PlanAppThreadArgs {
|
||||
@@ -2096,7 +2100,7 @@ void print_help()
|
||||
<< " plan-app-preferences [--ui-scale N] [--display-density N] [--current-scale N] [--scale-option N] [--viewport-scale N] [--rtl] [--timelapse-disabled] [--recording-running] [--vr-controllers-disabled] [--cursor-mode N]\n"
|
||||
<< " plan-app-startup [--run-counter N] [--auto-timelapse-disabled] [--vr-controllers-disabled] [--license-invalid]\n"
|
||||
<< " plan-app-startup-resources [--width N] [--height N] [--bad-size]\n"
|
||||
<< " plan-app-frame [--redraw] [--animate] [--no-designer-layout] [--no-main-layout] [--no-canvas] [--no-canvas-document] [--vr-active] [--ui-hidden] [--vr-only] [--resize-width N] [--resize-height N] [--bad-resize]\n"
|
||||
<< " plan-app-frame [--redraw] [--animate] [--no-designer-layout] [--no-main-layout] [--no-canvas] [--no-canvas-document] [--vr-active] [--ui-hidden] [--vr-only] [--resize-width N] [--resize-height N] [--bad-resize] [--observer-hidden] [--observer-on-screen] [--observer-clipped-out] [--observer-bad-geometry]\n"
|
||||
<< " plan-app-thread --kind dispatch|render-drain|ui-drain|ui-tick|ui-loop|redraw|start|stop [--on-target-thread] [--unique] [--worker-stopped] [--wait] [--request-redraw] [--redraw] [--live-reload] [--not-joinable] [--queued-tasks N] [--rendered-frames N] [--dt N] [--frame-accumulator N] [--fps-accumulator N] [--reload-accumulator N] [--bad-timer]\n"
|
||||
<< " plan-app-input --kind pointer|gesture|cancel|main|key|ui-toggle|stylus [--x N] [--y N] [--x1 N] [--y1 N] [--prev-x N] [--prev-y N] [--prev-x1 N] [--prev-y1 N] [--zoom N] [--no-designer-layout] [--no-main-layout] [--spacebar] [--vr-active] [--key-up] [--ui-hidden] [--no-canvas] [--main-child-count N] [--panel-child-count N] [--bad-float]\n"
|
||||
<< " plan-app-shutdown\n"
|
||||
@@ -3866,6 +3870,14 @@ pp::foundation::Status parse_plan_app_frame_args(
|
||||
args.resize_height = value.value();
|
||||
} else if (key == "--bad-resize") {
|
||||
args.bad_resize = true;
|
||||
} else if (key == "--observer-hidden") {
|
||||
args.observer_display = false;
|
||||
} else if (key == "--observer-on-screen") {
|
||||
args.observer_on_screen = true;
|
||||
} else if (key == "--observer-clipped-out") {
|
||||
args.observer_clipped_out = true;
|
||||
} else if (key == "--observer-bad-geometry") {
|
||||
args.observer_bad_geometry = true;
|
||||
} else {
|
||||
return pp::foundation::Status::invalid_argument("unknown option");
|
||||
}
|
||||
@@ -3899,6 +3911,39 @@ int plan_app_frame(int argc, char** argv)
|
||||
print_error("plan-app-frame", resize.status().message);
|
||||
return 2;
|
||||
}
|
||||
const pp::app::AppUiObserverParentClip parent_clips[] {
|
||||
{
|
||||
.clip = {
|
||||
.x = 0.0F,
|
||||
.y = 0.0F,
|
||||
.width = args.observer_clipped_out ? 10.0F : 80.0F,
|
||||
.height = args.observer_clipped_out ? 10.0F : 60.0F,
|
||||
},
|
||||
.padding_top = args.observer_clipped_out ? 0.0F : 5.0F,
|
||||
.padding_right = args.observer_clipped_out ? 0.0F : 5.0F,
|
||||
.padding_bottom = args.observer_clipped_out ? 0.0F : 5.0F,
|
||||
.padding_left = args.observer_clipped_out ? 0.0F : 5.0F,
|
||||
},
|
||||
};
|
||||
const auto observer = pp::app::plan_app_ui_observer(
|
||||
true,
|
||||
args.observer_display,
|
||||
args.observer_on_screen,
|
||||
{
|
||||
.x = args.observer_bad_geometry ? std::nanf("") : (args.observer_clipped_out ? 100.0F : 10.0F),
|
||||
.y = args.observer_clipped_out ? 100.0F : 20.0F,
|
||||
.width = args.observer_clipped_out ? 10.0F : 100.0F,
|
||||
.height = args.observer_clipped_out ? 10.0F : 50.0F,
|
||||
},
|
||||
parent_clips,
|
||||
540.0F,
|
||||
args.observer_bad_geometry ? 0.0F : 2.0F,
|
||||
10.0F,
|
||||
5.0F);
|
||||
if (!observer) {
|
||||
print_error("plan-app-frame", observer.status().message);
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::cout << "{\"ok\":true,\"command\":\"plan-app-frame\""
|
||||
<< ",\"surface\":{\"width\":" << surface.width
|
||||
@@ -3918,6 +3963,16 @@ int plan_app_frame(int argc, char** argv)
|
||||
<< ",\"renderTargetHeight\":" << resize.value().render_target_height
|
||||
<< ",\"recreateUiRenderTarget\":" << json_bool(resize.value().recreate_ui_render_target)
|
||||
<< ",\"requestRedraw\":" << json_bool(resize.value().request_redraw)
|
||||
<< "},\"observer\":{\"drawNode\":" << json_bool(observer.value().draw_node)
|
||||
<< ",\"notifyEnterScreen\":" << json_bool(observer.value().notify_enter_screen)
|
||||
<< ",\"notifyLeaveScreen\":" << json_bool(observer.value().notify_leave_screen)
|
||||
<< ",\"nextOnScreen\":" << json_bool(observer.value().next_on_screen)
|
||||
<< ",\"visibleWidth\":" << observer.value().visible_clip.width
|
||||
<< ",\"visibleHeight\":" << observer.value().visible_clip.height
|
||||
<< ",\"scissorX\":" << observer.value().scissor_x
|
||||
<< ",\"scissorY\":" << observer.value().scissor_y
|
||||
<< ",\"scissorWidth\":" << observer.value().scissor_width
|
||||
<< ",\"scissorHeight\":" << observer.value().scissor_height
|
||||
<< "}}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user