mirror of
https://github.com/baketnk/frame-yap.git
synced 2026-10-06 03:00:04 +02:00
Add rigid controller grab and layout lock; fix scale hit mask
This commit is contained in:
1 parent
9c7fdae264
commit
0d4cfbfdb7
15 files changed
+387
-162
No files matched your search
@@ -42,6 +42,7 @@ int main(int argc, char** argv) {
|
||||
assert(!load_config(path).experimental_input_priority);
|
||||
assert(!load_config(path).advanced_debug);
|
||||
assert(!load_config(path).auto_insert);
|
||||
assert(!load_config(path).lock_layout);
|
||||
assert(!load_config(path).clock_24h);
|
||||
assert(load_config(path).date_format == DateFormat::MonthDayYear);
|
||||
assert(load_config(path).wrist.width == .30f);
|
||||
@@ -51,6 +52,7 @@ int main(int argc, char** argv) {
|
||||
assert(!example.experimental_input_priority);
|
||||
assert(!example.advanced_debug);
|
||||
assert(!example.auto_insert);
|
||||
assert(!example.lock_layout);
|
||||
assert(!example.clock_24h && example.date_format == DateFormat::MonthDayYear);
|
||||
assert(example.wrist.y == .18f && example.wrist.z == .089f);
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
@@ -63,6 +65,10 @@ int main(int argc, char** argv) {
|
||||
assert(load_config(path).auto_insert);
|
||||
assert(save_auto_insert(path, false));
|
||||
assert(!load_config(path).auto_insert);
|
||||
assert(save_lock_layout(path, true));
|
||||
assert(load_config(path).lock_layout);
|
||||
assert(save_lock_layout(path, false));
|
||||
assert(!load_config(path).lock_layout);
|
||||
assert(save_clock_24h(path, true) && load_config(path).clock_24h);
|
||||
assert(save_date_format(path, DateFormat::Iso) && load_config(path).date_format == DateFormat::Iso);
|
||||
assert(save_date_format(path, DateFormat::Off) && load_config(path).date_format == DateFormat::Off);
|
||||
@@ -97,6 +103,7 @@ int main(int argc, char** argv) {
|
||||
std::filesystem::create_symlink(path, link);
|
||||
assert(!save_advanced_debug(link, false));
|
||||
assert(!save_auto_insert(link, true));
|
||||
assert(!save_lock_layout(link, true));
|
||||
assert(get(path) == before);
|
||||
std::filesystem::remove(link);
|
||||
put(path, R"({"font":")" + std::string(4090, 'x') + R"("})");
|
||||
@@ -124,6 +131,26 @@ int main(int argc, char** argv) {
|
||||
assert(save_auto_insert(path, true));
|
||||
assert(load_config(path).auto_insert);
|
||||
assert(get(path) == R"({"auto_insert":true,"font":"kept"})");
|
||||
for (const auto* invalid : {R"({"lock_layout":"true"})", R"({"lock_layout":1})",
|
||||
R"({"lock_layout":null})", R"({"lock_layout":[]})",
|
||||
R"({"lock_layout":{}})"}) {
|
||||
put(path, invalid);
|
||||
fails([&] { load_config(path); });
|
||||
assert(!save_lock_layout(path, true));
|
||||
assert(get(path) == invalid);
|
||||
}
|
||||
put(path, R"({"lock_layout":false,"font":"kept","date_format":"iso"})");
|
||||
assert(save_lock_layout(path, true));
|
||||
assert(load_config(path).lock_layout);
|
||||
assert(get(path) == R"({"lock_layout":true,"font":"kept","date_format":"iso"})");
|
||||
before = get(path);
|
||||
assert(save_lock_layout(path, true) && get(path) == before);
|
||||
assert(save_lock_layout(path, false));
|
||||
assert(get(path) == R"({"lock_layout":false,"font":"kept","date_format":"iso"})");
|
||||
put(path, R"({"font":"escaped \u0061","theme":{"ink":"#123ABC"},"auto_insert":true})");
|
||||
assert(save_lock_layout(path, true));
|
||||
assert(get(path) == R"({"font":"escaped \u0061","theme":{"ink":"#123ABC"},"auto_insert":true,"lock_layout":true})");
|
||||
assert(load_config(path).lock_layout && load_config(path).auto_insert);
|
||||
put(path, R"({"input_priority":"normal"})");
|
||||
assert(!load_config(path).experimental_input_priority);
|
||||
for (const auto* invalid : {R"({"input_priority":true})", R"({"input_priority":16777216})",
|
||||
|
||||
+116
-59
@@ -10,6 +10,11 @@ constexpr Matrix34 identity{{{{1.f, 0.f, 0.f, 0.f}},
|
||||
{{0.f, 1.f, 0.f, 0.f}},
|
||||
{{0.f, 0.f, 1.f, 0.f}}}};
|
||||
void near(float actual, float expected) { assert(std::abs(actual - expected) < 1e-4f); }
|
||||
void near_pose(const Matrix34& actual, const Matrix34& expected) {
|
||||
for (int row = 0; row < 3; ++row)
|
||||
for (int col = 0; col < 4; ++col)
|
||||
near(actual[row][col], expected[row][col]);
|
||||
}
|
||||
Matrix34 translated(Matrix34 pose, float x, float y, float z) {
|
||||
pose[0][3] += x; pose[1][3] += y; pose[2][3] += z;
|
||||
return pose;
|
||||
@@ -17,6 +22,22 @@ Matrix34 translated(Matrix34 pose, float x, float y, float z) {
|
||||
Matrix34 controller_at(float x, float y, float z = 1.f) {
|
||||
return translated(identity, x, y, z);
|
||||
}
|
||||
// Right-handed +90 degree rotations around each world axis.
|
||||
Matrix34 pitch() {
|
||||
return Matrix34{{{{1.f, 0.f, 0.f, 0.f}},
|
||||
{{0.f, 0.f, -1.f, 0.f}},
|
||||
{{0.f, 1.f, 0.f, 0.f}}}};
|
||||
}
|
||||
Matrix34 yaw() {
|
||||
return Matrix34{{{{0.f, 0.f, 1.f, 0.f}},
|
||||
{{0.f, 1.f, 0.f, 0.f}},
|
||||
{{-1.f, 0.f, 0.f, 0.f}}}};
|
||||
}
|
||||
Matrix34 roll() {
|
||||
return Matrix34{{{{0.f, -1.f, 0.f, 0.f}},
|
||||
{{1.f, 0.f, 0.f, 0.f}},
|
||||
{{0.f, 0.f, 1.f, 0.f}}}};
|
||||
}
|
||||
void scale_case(float x, float y, float factor) {
|
||||
// 1 m square, top-left (-.5,+.5); shift controller and hence its
|
||||
// intersection by (factor - 1) times the original anchor-to-hit vector.
|
||||
@@ -24,16 +45,30 @@ void scale_case(float x, float y, float factor) {
|
||||
PanelDrag drag;
|
||||
assert(drag.begin(PanelDragKind::Scale, identity, 1.f, 1.f, x, y, down));
|
||||
const auto same = drag.update(down);
|
||||
assert(same); near(same->factor, 1.f); near(same->dx, 0); near(same->dy, 0);
|
||||
assert(same); near(same->factor, 1.f); near_pose(same->pose, identity);
|
||||
const auto changed = drag.update(translated(down, (factor - 1.f) * x, (1.f - factor) * y, 0));
|
||||
assert(changed); near(changed->factor, factor);
|
||||
near(changed->dx, 0); near(changed->dy, 0);
|
||||
assert(changed); near(changed->factor, factor); near_pose(changed->pose, identity);
|
||||
}
|
||||
// Yaw +90 degrees: panel right=-Z, up=+Y, normal=+X.
|
||||
Matrix34 yawed_panel() {
|
||||
return Matrix34{{{{0.f, 0.f, 1.f, 2.f}},
|
||||
{{0.f, 1.f, 0.f, 3.f}},
|
||||
{{-1.f, 0.f, 0.f, 4.f}}}};
|
||||
void grab_rotation_case(const Matrix34& rotation, const Matrix34& expected) {
|
||||
PanelDrag drag;
|
||||
// Nonzero lever arm: rotation must turn the panel position as well as its axes.
|
||||
const auto down = controller_at(0, 0);
|
||||
const auto panel = translated(identity, .25f, .4f, -.3f);
|
||||
assert(drag.begin(PanelDragKind::Grab, panel, 1, 1, .7f, .3f, down));
|
||||
auto turned = rotation;
|
||||
turned[2][3] = 1.f;
|
||||
const auto update = drag.update(turned);
|
||||
assert(update); near(update->factor, 1.f); near_pose(update->pose, expected);
|
||||
// No accumulation: moving back to down restores the exact initial pose.
|
||||
drag.reset();
|
||||
assert(!drag.update(turned));
|
||||
// Release while turned, then pick that rotated panel up again elsewhere.
|
||||
const auto second_down = translated(turned, .12f, -.08f, .2f);
|
||||
assert(drag.begin(PanelDragKind::Grab, update->pose, 1, 1, .4f, .6f, second_down));
|
||||
const auto restored = drag.update(second_down);
|
||||
assert(restored); near_pose(restored->pose, update->pose);
|
||||
const auto shifted = drag.update(translated(second_down, 0.f, 0.f, -.4f));
|
||||
assert(shifted); near_pose(shifted->pose, translated(update->pose, 0.f, 0.f, -.4f));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -41,16 +76,37 @@ int main() {
|
||||
PanelDrag drag;
|
||||
assert(!drag.active()); assert(!drag.update(controller_at(0, 0)));
|
||||
const auto down = controller_at(0, 0);
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1.f, 1.f, .5f, .5f, down));
|
||||
auto panel = translated(identity, .25f, .4f, -.3f);
|
||||
assert(drag.begin(PanelDragKind::Grab, panel, 1.f, 1.f, .5f, .5f, down));
|
||||
assert(drag.active());
|
||||
const auto still = drag.update(down);
|
||||
assert(still); near(still->dx, 0); near(still->dy, 0); near(still->factor, 1);
|
||||
auto moved = drag.update(controller_at(.23f, -.16f));
|
||||
assert(moved); near(moved->dx, .23f); near(moved->dy, -.16f); near(moved->factor, 1);
|
||||
// The original plane is fixed: the ray may hit outside the initial canvas.
|
||||
moved = drag.update(controller_at(2.f, 1.f));
|
||||
assert(moved); near(moved->dx, 2.f); near(moved->dy, 1.f);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
const auto still = drag.update(down);
|
||||
assert(still); near_pose(still->pose, panel); near(still->factor, 1.f);
|
||||
}
|
||||
auto moved = drag.update(controller_at(.23f, -.16f, 1.45f));
|
||||
assert(moved); near_pose(moved->pose, translated(panel, .23f, -.16f, .45f));
|
||||
const auto released_pose = moved->pose;
|
||||
drag.reset(); assert(!drag.active()); assert(!drag.update(down));
|
||||
// A subsequent grab begins at the dropped position and orientation, not the
|
||||
// old calibration; releasing leaves the caller's last pose unchanged.
|
||||
const auto rotated_pose = compose_pose(translated(yaw(), 0.f, .1f, 0.f), released_pose);
|
||||
const auto second_down = controller_at(-.2f, .1f, .9f);
|
||||
assert(drag.begin(PanelDragKind::Grab, rotated_pose, 1, 1, .5f, .5f, second_down));
|
||||
moved = drag.update(second_down);
|
||||
assert(moved); near_pose(moved->pose, rotated_pose);
|
||||
moved = drag.update(translated(second_down, -.1f, .2f, -.3f));
|
||||
assert(moved); near_pose(moved->pose, translated(rotated_pose, -.1f, .2f, -.3f));
|
||||
drag.reset(); assert(!drag.update(second_down));
|
||||
|
||||
grab_rotation_case(pitch(), Matrix34{{{{1.f, 0.f, 0.f, .25f}},
|
||||
{{0.f, 0.f, -1.f, 1.3f}},
|
||||
{{0.f, 1.f, 0.f, 1.4f}}}});
|
||||
grab_rotation_case(yaw(), Matrix34{{{{0.f, 0.f, 1.f, -1.3f}},
|
||||
{{0.f, 1.f, 0.f, .4f}},
|
||||
{{-1.f, 0.f, 0.f, .75f}}}});
|
||||
grab_rotation_case(roll(), Matrix34{{{{0.f, -1.f, 0.f, -.4f}},
|
||||
{{1.f, 0.f, 0.f, .25f}},
|
||||
{{0.f, 0.f, 1.f, -.3f}}}});
|
||||
|
||||
// Independent horizontal, vertical, and diagonal anchor-based scaling;
|
||||
// both contraction and growth, including intersections outside the panel.
|
||||
@@ -59,14 +115,12 @@ int main() {
|
||||
scale_case(0.f, .5f, factor);
|
||||
scale_case(.5f, .5f, factor);
|
||||
}
|
||||
assert(drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f,
|
||||
controller_at(0, 0)));
|
||||
// A perpendicular offset does not alter projected scale.
|
||||
moved = drag.update(controller_at(.25f, .25f));
|
||||
assert(drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f, down));
|
||||
moved = drag.update(controller_at(.25f, .25f)); // perpendicular to anchor vector
|
||||
assert(moved); near(moved->factor, 1);
|
||||
moved = drag.update(controller_at(.5f, -.5f));
|
||||
assert(moved); near(moved->factor, 2);
|
||||
moved = drag.update(controller_at(0, 0)); // no feedback from the previous size
|
||||
moved = drag.update(down); // no feedback from previous size
|
||||
assert(moved); near(moved->factor, 1);
|
||||
drag.reset();
|
||||
assert(!drag.begin(PanelDragKind::Scale, identity, 1, 1, 0, 0,
|
||||
@@ -74,49 +128,40 @@ int main() {
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1, 1, 0, 0,
|
||||
controller_at(-.5f, .5f)));
|
||||
|
||||
// Rotating the controller changes the calibrated ray even without moving
|
||||
// its origin. The initial ray is (.25,0,-1), rotated 90 degrees about Z.
|
||||
// Scaling still uses the captured controller-local ray, not the grab pose.
|
||||
auto angled_down = controller_at(0, 0);
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1, 1, .75f, .5f, angled_down));
|
||||
assert(drag.begin(PanelDragKind::Scale, identity, 1, 1, .75f, .5f, angled_down));
|
||||
auto turned = angled_down;
|
||||
turned[0][0] = 0; turned[0][1] = -1;
|
||||
turned[1][0] = 1; turned[1][1] = 0;
|
||||
moved = drag.update(turned);
|
||||
assert(moved); near(moved->dx, -.25f); near(moved->dy, .25f);
|
||||
assert(moved); near(moved->factor, .5f / .8125f); near_pose(moved->pose, identity);
|
||||
|
||||
const auto panel = yawed_panel();
|
||||
// Use the same rotated basis for both controller and panel; a 0.2 m shift
|
||||
// along panel right (-Z) yields panel-right grab displacement.
|
||||
auto rotated_down = panel;
|
||||
rotated_down[0][3] += 1.f;
|
||||
assert(drag.begin(PanelDragKind::Grab, panel, 1, 1, .5f, .5f, rotated_down));
|
||||
moved = drag.update(translated(rotated_down, 0, -.15f, -.2f));
|
||||
assert(moved); near(moved->dx, .2f); near(moved->dy, -.15f);
|
||||
auto corner_ray = rotated_down;
|
||||
corner_ray[1][3] += .25f;
|
||||
corner_ray[2][3] += .25f; // initial hit at x=.25, y=.25
|
||||
assert(drag.begin(PanelDragKind::Scale, panel, 1, 1, .25f, .25f, corner_ray));
|
||||
const auto yawed_panel = translated(yaw(), 2.f, 3.f, 4.f);
|
||||
auto corner_ray = translated(yawed_panel, 1.f, .25f, .25f);
|
||||
assert(drag.begin(PanelDragKind::Scale, yawed_panel, 1, 1, .25f, .25f, corner_ray));
|
||||
moved = drag.update(translated(corner_ray, 0, -.25f, -.25f));
|
||||
assert(moved); near(moved->factor, 2.f);
|
||||
assert(moved); near(moved->factor, 2.f); near_pose(moved->pose, yawed_panel);
|
||||
|
||||
// Relative poses are valid without converting them to world space: both
|
||||
// inputs here share a rotated/translated parent coordinate system.
|
||||
auto relative_panel = identity;
|
||||
relative_panel[0][3] = -.3f; relative_panel[1][3] = .1f;
|
||||
auto relative_controller = translated(relative_panel, 0, 0, .8f);
|
||||
// The identical grab in a device-relative frame and under an arbitrary
|
||||
// rigid parent in world space must produce equivalent world panel poses.
|
||||
const auto parent = translated(compose_pose(yaw(), pitch()), 2.f, 3.f, 4.f);
|
||||
const auto relative_panel = translated(roll(), -.3f, .1f, -.1f);
|
||||
const auto relative_controller = controller_at(.1f, -.2f, .8f);
|
||||
const auto relative_next = compose_pose(translated(yaw(), .08f, -.04f, .2f), relative_controller);
|
||||
assert(drag.begin(PanelDragKind::Grab, relative_panel, .4f, .2f,
|
||||
.5f, .5f, relative_controller));
|
||||
moved = drag.update(translated(relative_controller, .08f, -.04f, 0));
|
||||
assert(moved); near(moved->dx, .08f); near(moved->dy, -.04f);
|
||||
// Express the same poses in world coordinates under a yawed parent:
|
||||
// (x, y, z) -> (2+z, 3+y, 4-x). The update is invariant.
|
||||
auto world_panel = yawed_panel();
|
||||
world_panel[1][3] += .1f; world_panel[2][3] += .3f;
|
||||
auto world_controller = translated(world_panel, .8f, 0, 0);
|
||||
moved = drag.update(relative_next);
|
||||
assert(moved);
|
||||
const auto relative_result = moved->pose;
|
||||
const auto world_panel = compose_pose(parent, relative_panel);
|
||||
const auto world_controller = compose_pose(parent, relative_controller);
|
||||
assert(drag.begin(PanelDragKind::Grab, world_panel, .4f, .2f,
|
||||
.5f, .5f, world_controller));
|
||||
moved = drag.update(translated(world_controller, 0, -.04f, -.08f));
|
||||
assert(moved); near(moved->dx, .08f); near(moved->dy, -.04f);
|
||||
moved = drag.update(compose_pose(parent, relative_next));
|
||||
assert(moved); near_pose(moved->pose, compose_pose(parent, relative_result));
|
||||
near_pose(relative_pose(parent, moved->pose), relative_result);
|
||||
near_pose(compose_pose(world_controller, relative_pose(world_controller, world_panel)), world_panel);
|
||||
|
||||
const float nan = std::numeric_limits<float>::quiet_NaN();
|
||||
const float inf = std::numeric_limits<float>::infinity();
|
||||
@@ -133,24 +178,36 @@ int main() {
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, inf, 1, .5f, .5f, down));
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, 1, 1, nan, .5f, down));
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, 1, 1, -1, .5f, down));
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f, identity)); // zero ray
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f,
|
||||
// Both inputs are finite but their relative translation cannot fit in Matrix34.
|
||||
const float max = std::numeric_limits<float>::max();
|
||||
assert(!drag.begin(PanelDragKind::Grab, translated(identity, -max, 0, 0),
|
||||
1, 1, .5f, .5f, translated(identity, max, 0, 0)));
|
||||
assert(!drag.active()); assert(!drag.update(down));
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f, identity));
|
||||
assert(drag.update(identity)); // grab does not require a ray to the panel
|
||||
drag.reset();
|
||||
assert(!drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f, identity)); // zero ray
|
||||
assert(!drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f,
|
||||
controller_at(1.f, 0.f, 1e-7f))); // near parallel at down
|
||||
assert(!drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f,
|
||||
assert(!drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f,
|
||||
controller_at(0, 0, 11.f))); // beyond 10 m
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f, down));
|
||||
assert(drag.begin(PanelDragKind::Scale, identity, 1, 1, .5f, .5f, down));
|
||||
bad = down; bad[1][2] = inf;
|
||||
assert(!drag.update(bad));
|
||||
bad = down; bad[0][0] = 0;
|
||||
assert(!drag.update(bad));
|
||||
assert(!drag.update(controller_at(0, 0, -1.f))); // behind ray source
|
||||
assert(!drag.update(controller_at(0, 0, 11.f))); // beyond 10 m
|
||||
// Rotate -Z to -X: ray parallel to initial panel plane.
|
||||
bad = down;
|
||||
bad[0][0] = 0; bad[0][2] = 1;
|
||||
bad[2][0] = -1; bad[2][2] = 0;
|
||||
assert(!drag.update(bad));
|
||||
assert(!drag.update(bad)); // ray parallel to initial panel plane
|
||||
assert(drag.active()); // invalid update leaves original calibration intact
|
||||
assert(drag.update(down));
|
||||
drag.reset(); assert(!drag.active());
|
||||
drag.reset(); assert(!drag.active()); assert(!drag.update(down));
|
||||
assert(drag.begin(PanelDragKind::Grab, identity, 1, 1, .5f, .5f, down));
|
||||
bad = down; bad[2][3] = nan;
|
||||
assert(!drag.update(bad));
|
||||
assert(drag.update(down));
|
||||
drag.reset(); assert(!drag.update(down));
|
||||
}
|
||||
+24
-1
@@ -14,7 +14,7 @@ SurfaceEvent click(PanelSurface& surface, float x, float y, unsigned cursor = 0)
|
||||
}
|
||||
void no_action(const SurfaceEvent& event) {
|
||||
assert(!event.action && !event.mount && !event.lasers_anytime && !event.advanced_debug && !event.auto_insert &&
|
||||
!event.clock_24h && !event.date_format && !event.recenter && !event.open_bindings);
|
||||
!event.lock_layout && !event.clock_24h && !event.date_format && !event.recenter && !event.open_bindings);
|
||||
}
|
||||
void snapshot(PanelSurface& surface, const std::string& path) {
|
||||
std::ofstream out(path, std::ios::binary);
|
||||
@@ -109,6 +109,21 @@ int main(int argc, char** argv) {
|
||||
assert(channel(1012, 723, 0) > 220 && channel(1040, 705, 2) > 220);
|
||||
assert(channel(1030, 704, 3) == 0 && channel(800, 724, 3) == 0);
|
||||
assert(channel(401, 721, 3) == alpha(401, 721));
|
||||
auto regions = surface.input_regions();
|
||||
assert(regions.size() == 3);
|
||||
assert(regions[2].x == 996 && regions[2].y == 680); // masks use TOP-left, not GL mouse Y
|
||||
surface.pointer_down(0, 500, 724);
|
||||
surface.set_layout_locked(true);
|
||||
assert(!surface.dragging(0));
|
||||
assert(surface.render(p));
|
||||
assert(alpha(500, 723) == 0 && alpha(1040, 705) == 0);
|
||||
assert(surface.input_regions().size() == 1);
|
||||
assert(!surface.pointer_down(0, 500, 724));
|
||||
assert(!surface.pointer_down(0, 1028, 712));
|
||||
no_action(surface.pointer_up(0, 900, 610));
|
||||
assert(!surface.render(p));
|
||||
surface.set_layout_locked(false); assert(surface.render(p));
|
||||
assert(alpha(500, 723) == 255 && alpha(1040, 705) == 255);
|
||||
|
||||
p.enabled = true;
|
||||
p.record_available = false;
|
||||
@@ -148,6 +163,13 @@ int main(int argc, char** argv) {
|
||||
surface.render(p);
|
||||
surface.reset_pointers(); surface.render(p);
|
||||
if (argc >= 3) snapshot(surface, std::string(argv[2]) + "-settings.ppm");
|
||||
auto lock = click(surface, 790, 160);
|
||||
assert(lock.lock_layout == true && !lock.action);
|
||||
assert(!surface.render(p)); // caller applies/persists the requested lock
|
||||
surface.set_layout_locked(true); assert(surface.render(p));
|
||||
lock = click(surface, 790, 160);
|
||||
assert(lock.lock_layout == false); // unlock stays accessible in Settings
|
||||
surface.set_layout_locked(false); assert(surface.render(p));
|
||||
assert(click(surface, 200, 420).recenter);
|
||||
auto event = click(surface, 180, 332);
|
||||
assert(event.mount == Mount::LeftWrist && !event.action);
|
||||
@@ -206,6 +228,7 @@ int main(int argc, char** argv) {
|
||||
no_action(click(surface, 680, 420)); // laser toggle only exists on Settings
|
||||
no_action(click(surface, 680, 474)); // debug toggle only exists on Settings
|
||||
no_action(click(surface, 200, 474)); // auto insert only exists on Settings
|
||||
no_action(click(surface, 790, 160)); // layout lock only exists on Settings
|
||||
no_action(click(surface, 200, 528)); // clock/date controls only exist on Settings
|
||||
no_action(click(surface, 680, 528));
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertEqual(json.loads(config.read_text()), installer.CONFIG_DEFAULTS)
|
||||
self.assertIs(json.loads(config.read_text())["advanced_debug"], False)
|
||||
self.assertIs(json.loads(config.read_text())["auto_insert"], False)
|
||||
self.assertIs(json.loads(config.read_text())["lock_layout"], False)
|
||||
self.assertEqual(list(config.parent.glob("config.json.backup-*")), [])
|
||||
self.assertIn("PYTHONDONTWRITEBYTECODE=1", launcher.read_text())
|
||||
self.assertTrue(os.access(root / "versions/v1/runtime/bin/helper", os.X_OK))
|
||||
@@ -129,6 +130,7 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertEqual(fixed["input_priority"], "normal")
|
||||
self.assertIs(fixed["advanced_debug"], False)
|
||||
self.assertIs(fixed["auto_insert"], False)
|
||||
self.assertIs(fixed["lock_layout"], False)
|
||||
self.assertIs(fixed["clock_24h"], False)
|
||||
self.assertEqual(fixed["date_format"], "mdy")
|
||||
self.assertEqual(fixed["wrist"], installer.CONFIG_DEFAULTS["wrist"])
|
||||
@@ -138,6 +140,7 @@ class InstallTests(unittest.TestCase):
|
||||
fixed["input_priority"] = "experimental"
|
||||
fixed["advanced_debug"] = True
|
||||
fixed["auto_insert"] = True
|
||||
fixed["lock_layout"] = True
|
||||
fixed["clock_24h"] = True
|
||||
fixed["date_format"] = "iso"
|
||||
fixed["buttons"]["enter"] = "" # intentional disabling survives upgrades
|
||||
@@ -148,6 +151,7 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertEqual(config.read_bytes(), compact)
|
||||
self.assertIs(json.loads(config.read_text())["advanced_debug"], True)
|
||||
self.assertIs(json.loads(config.read_text())["auto_insert"], True)
|
||||
self.assertIs(json.loads(config.read_text())["lock_layout"], True)
|
||||
self.assertIs(json.loads(config.read_text())["clock_24h"], True)
|
||||
self.assertEqual(json.loads(config.read_text())["date_format"], "iso")
|
||||
self.assertEqual(len(list(config.parent.glob("config.json.backup-*"))), 1)
|
||||
@@ -167,6 +171,7 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertEqual(fixed["input_priority"], "normal")
|
||||
self.assertIs(fixed["advanced_debug"], False)
|
||||
self.assertIs(fixed["auto_insert"], False)
|
||||
self.assertIs(fixed["lock_layout"], False)
|
||||
self.assertEqual(fixed["wrist"]["x"], 0.04)
|
||||
self.assertEqual(fixed["wrist"]["y"], 0.18)
|
||||
self.assertEqual(fixed["wrist"]["width"], 0.30)
|
||||
@@ -215,6 +220,19 @@ class InstallTests(unittest.TestCase):
|
||||
self.assertIs(json.loads(config.read_text())["auto_insert"], False)
|
||||
self.assertIn(original, [p.read_bytes() for p in config.parent.glob("config.json.backup-*")])
|
||||
|
||||
def test_lock_layout_boolean_repair_backs_up_invalid_values(self):
|
||||
archive, digest = self.package("v1")
|
||||
config = self.home / ".config/frameyap/config.json"
|
||||
config.parent.mkdir(parents=True)
|
||||
for invalid in ("true", 1, None, [], {}):
|
||||
original = json.dumps({"lock_layout": invalid, "font": "/custom/font.ttf"}).encode()
|
||||
config.write_bytes(original)
|
||||
self.install("v1", archive, digest)
|
||||
fixed = json.loads(config.read_text())
|
||||
self.assertIs(fixed["lock_layout"], False)
|
||||
self.assertEqual(fixed["font"], "/custom/font.ttf")
|
||||
self.assertIn(original, [p.read_bytes() for p in config.parent.glob("config.json.backup-*")])
|
||||
|
||||
def test_digest_and_same_version_mismatch_leave_previous(self):
|
||||
a, h = self.package("v1")
|
||||
self.install("v1", a, h)
|
||||
|
||||
Reference in new issue
Block a user