mirror of
https://github.com/baketnk/frame-yap.git
synced 2026-10-06 02:00:06 +02:00
Add Settings -> About screen with version, license and credits
Static page: build version (with git commit when untagged/dirty), source URL, MIT license, selected model's manifest license, font license and a pointer to docs/third-party.md. Recording controls stay live; Settings returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ec5dd03ba
commit
0f36a45358
5 files changed
+62
-5
No files matched your search
@@ -76,6 +76,12 @@ not every frame. Settings toggles 12/24-hour time and cycles date Off →
|
||||
MM/DD/YYYY → DD/MM/YYYY → YYYY-MM-DD → Off. These only affect display;
|
||||
mount choices remain in Settings.
|
||||
|
||||
Settings → **About** replaces the settings area with static information: the
|
||||
build version (plus git commit when built from an untagged or modified tree),
|
||||
source URL, MIT license, the selected model's name and license from its manifest,
|
||||
the bundled font's license, and a pointer to `docs/third-party.md`. It performs
|
||||
no checks and no network access; Settings returns. Recording controls stay live.
|
||||
|
||||
The complete transcript preview is paginated by glyph width and six-line
|
||||
height; Previous and Next navigate it without changing the source transcript.
|
||||
Status fits on the single status line; the old bottom detail label is gone.
|
||||
|
||||
@@ -189,6 +189,8 @@ struct Overlay::Impl {
|
||||
surface.set_layout_locked(config.lock_layout);
|
||||
surface.set_clock_24h(config.clock_24h);
|
||||
surface.set_date_format(config.date_format);
|
||||
surface.set_version(std::string(FRAMEYAP_VERSION) +
|
||||
(std::string(FRAMEYAP_GIT_INFO).empty() ? "" : " " FRAMEYAP_GIT_INFO));
|
||||
overlay_check(overlay->SetOverlayFlag(handle, vr::VROverlayFlags_VisibleInDashboard, true), overlay, "VisibleInDashboard");
|
||||
vr::HmdVector2_t mouse_scale{{float(W), float(H)}};
|
||||
overlay_check(overlay->SetOverlayMouseScale(handle, &mouse_scale), overlay, "SetOverlayMouseScale");
|
||||
|
||||
+33
-5
@@ -31,10 +31,10 @@ struct Rect {
|
||||
enum class Control { Review, Settings, Bindings, Prev, Next, Record, Cancel, Insert, Enter, Quit,
|
||||
World, Left, Right, Head, Recenter, LasersAnytime, AdvancedDebug, AutoInsert,
|
||||
Clock24h, Date, LockLayout, CloseMicWhenIdle, Models, ModelRow,
|
||||
ModelInstall, ModelPrev, ModelNext };
|
||||
enum class Tab { Review, Settings, Models };
|
||||
ModelInstall, ModelPrev, ModelNext, About };
|
||||
enum class Tab { Review, Settings, Models, About };
|
||||
struct Button { Rect r; Control id; const char* label; };
|
||||
constexpr std::array<Button, 32> buttons{{
|
||||
constexpr std::array<Button, 33> buttons{{
|
||||
{{32, 138, 180, 46}, Control::Review, "Review"},
|
||||
{{226, 138, 180, 46}, Control::Settings, "Settings"},
|
||||
{{420, 138, 180, 46}, Control::Bindings, "Bindings"},
|
||||
@@ -67,6 +67,7 @@ constexpr std::array<Button, 32> buttons{{
|
||||
{{514, 530, 454, 36}, Control::ModelInstall, "Install"},
|
||||
{{32, 530, 214, 36}, Control::ModelPrev, "Previous"},
|
||||
{{260, 530, 214, 36}, Control::ModelNext, "Next"},
|
||||
{{346, 378, 154, 44}, Control::About, "About"},
|
||||
}};
|
||||
std::optional<UiAction> action(Control c) {
|
||||
switch (c) {
|
||||
@@ -126,7 +127,7 @@ struct PanelSurface::Impl {
|
||||
DateFormat date_format = DateFormat::MonthDayYear;
|
||||
std::time_t clock_time = std::time(nullptr);
|
||||
ClockLabel displayed_clock;
|
||||
std::string placement_note, binding_note;
|
||||
std::string placement_note, binding_note, version;
|
||||
StatusIndicators indicators;
|
||||
std::array<int, 2> pressed{{-1, -1}};
|
||||
std::array<PanelSurface::Clock::time_point, 2> press_time{};
|
||||
@@ -354,7 +355,7 @@ struct PanelSurface::Impl {
|
||||
}
|
||||
bool visible(Control c) const {
|
||||
if (panel.quick_open && c != Control::Cancel && c != Control::Enter && c != Control::Quit) return false;
|
||||
if (c == Control::Models) return tab == Tab::Settings;
|
||||
if (c == Control::Models || c == Control::About) return tab == Tab::Settings;
|
||||
if (c == Control::ModelRow) return tab == Tab::Models && !install_confirm;
|
||||
if (c == Control::ModelPrev || c == Control::ModelNext) return tab == Tab::Models;
|
||||
if (c == Control::ModelInstall) return tab == Tab::Models;
|
||||
@@ -395,6 +396,27 @@ struct PanelSurface::Impl {
|
||||
pressed.fill(-1);
|
||||
drag_cursor = -1;
|
||||
}
|
||||
// Static facts only: nothing here is a live check of the model or device.
|
||||
void about() {
|
||||
rounded({32, 204, 936, 334}, 16, mix(card, muted, .08f), mix(card, cyan, .25f), .18f);
|
||||
text("FrameYap", 48, 244, 30, ink, 952);
|
||||
text("Version " + (version.empty() ? std::string("unknown") : version), 48, 276, 22, cyan, 952);
|
||||
text("On-device voice typing for Steam Frame. Nothing is sent to the cloud.", 48, 306, 19, muted, 952);
|
||||
const auto it = std::find_if(panel.models.begin(), panel.models.end(), [&](const auto& m) { return m.id == panel.selected_backend; });
|
||||
const std::array<std::pair<const char*, std::string>, 5> rows{{
|
||||
{"Source", "github.com/baketnk/frame-yap"},
|
||||
{"License", "MIT (FrameYap contributors)"},
|
||||
{"Model", it == panel.models.end() ? "none selected" :
|
||||
it->license.empty() ? it->name : it->name + " (" + it->license + ")"},
|
||||
{"Font", "Inconsolata (SIL OFL 1.1)"},
|
||||
{"Notices", "docs/third-party.md in the source"}}};
|
||||
for (size_t i = 0; i < rows.size(); ++i) {
|
||||
const int y = 352 + int(i) * 36;
|
||||
text(rows[i].first, 48, y, 22, cyan, 190);
|
||||
text(rows[i].second, 200, y, 22, ink, 952);
|
||||
}
|
||||
text("Press Settings to go back.", 48, 524, 17, muted, 952);
|
||||
}
|
||||
bool render(const Panel& p, Clock::time_point now, bool animate) {
|
||||
if (!animation_start) animation_start = now;
|
||||
if (gradient.enabled && animate && now - last_animation_frame >= std::chrono::milliseconds(100))
|
||||
@@ -502,6 +524,8 @@ struct PanelSurface::Impl {
|
||||
text("Select Install to review full source, size and license before download.", 32, 225, 18, cyan, 968);
|
||||
}
|
||||
} else text("No model selected.", 32, 225, 18, pink, 968);
|
||||
} else if (tab == Tab::About) {
|
||||
about();
|
||||
} else {
|
||||
text("Hold Quit: hold 0.9s then release. Lasers anytime: system-wide; may affect games.",
|
||||
32, 204, 18, pink, 968);
|
||||
@@ -647,6 +671,7 @@ SurfaceEvent PanelSurface::pointer_up(unsigned cursor, float x, float y, Clock::
|
||||
impl_->tab = Tab::Models; impl_->model_page = 0;
|
||||
impl_->install_confirm = false; impl_->consent_snapshot.reset(); impl_->reset(); impl_->dirty = true;
|
||||
}
|
||||
else if (c == Control::About) { impl_->tab = Tab::About; impl_->reset(); impl_->dirty = true; }
|
||||
else if (c == Control::ModelRow) {
|
||||
const auto& model = impl_->panel.models[impl_->model_page * 6 + index - 23];
|
||||
result.model_action = ModelAction{model.id, false, {}};
|
||||
@@ -700,6 +725,9 @@ void PanelSurface::set_layout_locked(bool locked) {
|
||||
impl_->layout_locked = locked; impl_->reset(); impl_->dirty = true;
|
||||
}
|
||||
}
|
||||
void PanelSurface::set_version(std::string version) {
|
||||
if (impl_->version != version) { impl_->version = std::move(version); impl_->dirty = true; }
|
||||
}
|
||||
void PanelSurface::set_placement_note(std::string note) {
|
||||
if (impl_->placement_note != note) { impl_->placement_note = std::move(note); impl_->dirty = true; }
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
void set_layout_locked(bool locked);
|
||||
void reset_pointers();
|
||||
void set_placement_note(std::string note);
|
||||
// Shown on Settings -> About; empty shows "version unknown".
|
||||
void set_version(std::string version);
|
||||
void set_lasers_anytime(bool enabled);
|
||||
void set_advanced_debug(bool enabled);
|
||||
void set_auto_insert(bool enabled);
|
||||
|
||||
@@ -518,5 +518,24 @@ int main(int argc, char** argv) {
|
||||
model_panel.model_busy = true;
|
||||
chooser.render(model_panel);
|
||||
no_action(chooser.pointer_up(0, 700, 546)); // change invalidates approval
|
||||
// About: reached only from Settings; display-only, recording stays usable.
|
||||
PanelSurface about(argv[1], Mount::World, {}, {.enabled = false});
|
||||
Panel about_panel{"Ready", "", "", true, false};
|
||||
about.render(about_panel);
|
||||
no_action(click(about, 420, 400)); // hidden on Review
|
||||
assert(!about.render(about_panel));
|
||||
no_action(click(about, 290, 160)); about.render(about_panel); // Settings
|
||||
const auto settings_pixels = about.pixels();
|
||||
no_action(click(about, 420, 400)); // About
|
||||
assert(about.render(about_panel));
|
||||
const auto about_pixels = about.pixels();
|
||||
assert(about_pixels != settings_pixels);
|
||||
no_action(click(about, 100, 250)); // Settings' World-space button is not live under About
|
||||
no_action(click(about, 700, 400)); // nor Lasers anytime
|
||||
about.set_version("0.1.202609261200");
|
||||
assert(about.render(about_panel) && about.pixels() != about_pixels);
|
||||
assert(click(about, 100, 610).action == UiAction::BeginRecord);
|
||||
no_action(click(about, 290, 160)); about.render(about_panel); // Settings returns
|
||||
assert(about.pixels() == settings_pixels);
|
||||
std::cout << "panel checks passed (no OpenVR, microphone or input injection)\n";
|
||||
}
|
||||
Reference in new issue
Block a user