mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 23:27:49 +01:00
status bar 2
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "input_state.hpp"
|
||||
#include "cardboy/sdk/framebuffer_hooks.hpp"
|
||||
#include "input_state.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,12 +20,12 @@ public:
|
||||
|
||||
void run();
|
||||
|
||||
[[nodiscard]] std::size_t appCount() const { return factories.size(); }
|
||||
[[nodiscard]] std::size_t appCount() const { return factories.size(); }
|
||||
[[nodiscard]] const IAppFactory* factoryAt(std::size_t index) const;
|
||||
[[nodiscard]] std::size_t indexOfFactory(const IAppFactory* factory) const;
|
||||
[[nodiscard]] std::size_t currentFactoryIndex() const { return activeIndex; }
|
||||
|
||||
[[nodiscard]] const IApp* currentApp() const { return current.get(); }
|
||||
[[nodiscard]] const IApp* currentApp() const { return current.get(); }
|
||||
[[nodiscard]] const IAppFactory* currentFactory() const { return activeFactory; }
|
||||
|
||||
private:
|
||||
@@ -52,15 +52,15 @@ private:
|
||||
TimerRecord* findTimer(AppTimerHandle handle);
|
||||
bool handlePendingSwitchRequest();
|
||||
|
||||
AppContext context;
|
||||
AppContext context;
|
||||
std::vector<std::unique_ptr<IAppFactory>> factories;
|
||||
std::unique_ptr<IApp> current;
|
||||
IAppFactory* activeFactory = nullptr;
|
||||
std::unique_ptr<IApp> current;
|
||||
IAppFactory* activeFactory = nullptr;
|
||||
std::size_t activeIndex = static_cast<std::size_t>(-1);
|
||||
std::vector<TimerRecord> timers;
|
||||
AppTimerHandle nextTimerId = 1;
|
||||
std::uint32_t currentGeneration = 0;
|
||||
InputState lastInputState{};
|
||||
std::vector<TimerRecord> timers;
|
||||
AppTimerHandle nextTimerId = 1;
|
||||
std::uint32_t currentGeneration = 0;
|
||||
InputState lastInputState{};
|
||||
};
|
||||
|
||||
inline AppTimerHandle AppContext::scheduleTimerInternal(std::uint32_t delay_ms, bool repeat) {
|
||||
|
||||
@@ -19,8 +19,8 @@ public:
|
||||
|
||||
void setServices(Services* services) { services_ = services; }
|
||||
|
||||
void setEnabled(bool value);
|
||||
void toggle();
|
||||
void setEnabled(bool value);
|
||||
void toggle();
|
||||
[[nodiscard]] bool isEnabled() const { return enabled_; }
|
||||
|
||||
void setCurrentAppName(std::string_view name);
|
||||
@@ -43,32 +43,41 @@ private:
|
||||
if (width <= 0)
|
||||
return;
|
||||
|
||||
const int barHeight = font16x8::kGlyphHeight + 2;
|
||||
const int fillHeight = std::min(barHeight, fb.height());
|
||||
if (fillHeight <= 0)
|
||||
return;
|
||||
|
||||
const std::string leftText = prepareLeftText(width);
|
||||
const std::string rightText = prepareRightText();
|
||||
|
||||
for (int y = 0; y < fillHeight; ++y) {
|
||||
for (int x = 0; x < width; ++x)
|
||||
fb.drawPixel(x, y, true);
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
fb.drawPixel(x, 0, true);
|
||||
fb.drawPixel(x, 0, false);
|
||||
|
||||
const int textY = 1;
|
||||
const int barHeight = font16x8::kGlyphHeight + 2;
|
||||
const int bottomSeparatorY = textY + font16x8::kGlyphHeight + 1;
|
||||
if (bottomSeparatorY < barHeight && bottomSeparatorY < fb.height()) {
|
||||
if (bottomSeparatorY < fillHeight) {
|
||||
for (int x = 0; x < width; ++x)
|
||||
fb.drawPixel(x, bottomSeparatorY, (x % 2) == 0);
|
||||
fb.drawPixel(x, bottomSeparatorY, (x % 2) != 0);
|
||||
}
|
||||
|
||||
const int leftX = 2;
|
||||
if (!leftText.empty())
|
||||
font16x8::drawText(fb, leftX, textY, leftText, 1, true, 1);
|
||||
font16x8::drawText(fb, leftX, textY, leftText, 1, false, 1);
|
||||
|
||||
if (!rightText.empty()) {
|
||||
int rightWidth = font16x8::measureText(rightText, 1, 1);
|
||||
int rightX = width - rightWidth - 2;
|
||||
const int minRightX = leftX + font16x8::measureText(leftText, 1, 1) + 6;
|
||||
int rightWidth = font16x8::measureText(rightText, 1, 1);
|
||||
int rightX = width - rightWidth - 2;
|
||||
const int minRightX = leftX + font16x8::measureText(leftText, 1, 1) + 6;
|
||||
if (rightX < minRightX)
|
||||
rightX = std::max(minRightX, width / 2);
|
||||
if (rightX < width)
|
||||
font16x8::drawText(fb, rightX, textY, rightText, 1, true, 1);
|
||||
font16x8::drawText(fb, rightX, textY, rightText, 1, false, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void statusBarPreSendHook(void* framebuffer, void* userData) {
|
||||
} // namespace
|
||||
|
||||
AppSystem::AppSystem(AppContext ctx) : context(std::move(ctx)) {
|
||||
context.system = this;
|
||||
context.system = this;
|
||||
auto& statusBar = StatusBar::instance();
|
||||
statusBar.setServices(context.services);
|
||||
using FBType = typename AppContext::Framebuffer;
|
||||
@@ -252,4 +252,3 @@ bool AppSystem::handlePendingSwitchRequest() {
|
||||
}
|
||||
|
||||
} // namespace cardboy::sdk
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace cardboy::sdk {
|
||||
|
||||
FramebufferHooks::PreSendHook FramebufferHooks::hook_ = nullptr;
|
||||
void* FramebufferHooks::userData_ = nullptr;
|
||||
FramebufferHooks::PreSendHook FramebufferHooks::hook_ = nullptr;
|
||||
void* FramebufferHooks::userData_ = nullptr;
|
||||
|
||||
void FramebufferHooks::setPreSendHook(PreSendHook hook, void* userData) {
|
||||
hook_ = hook;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
namespace cardboy::sdk {
|
||||
@@ -21,9 +22,8 @@ void StatusBar::toggle() {
|
||||
|
||||
void StatusBar::setCurrentAppName(std::string_view name) {
|
||||
appName_.assign(name.begin(), name.end());
|
||||
std::transform(appName_.begin(), appName_.end(), appName_.begin(), [](unsigned char ch) {
|
||||
return static_cast<char>(std::toupper(ch));
|
||||
});
|
||||
std::transform(appName_.begin(), appName_.end(), appName_.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::toupper(ch)); });
|
||||
}
|
||||
|
||||
bool StatusBar::handleToggleInput(const InputState& current, const InputState& previous) {
|
||||
@@ -37,7 +37,7 @@ bool StatusBar::handleToggleInput(const InputState& current, const InputState& p
|
||||
}
|
||||
|
||||
std::string StatusBar::prepareLeftText(int displayWidth) const {
|
||||
std::string text = appName_.empty() ? std::string("CARDBOY") : appName_;
|
||||
std::string text = appName_.empty() ? std::string("CARDBOY") : appName_;
|
||||
int maxWidth = std::max(0, displayWidth - 32);
|
||||
while (!text.empty() && font16x8::measureText(text, 1, 1) > maxWidth)
|
||||
text.pop_back();
|
||||
@@ -50,13 +50,16 @@ std::string StatusBar::prepareRightText() const {
|
||||
|
||||
std::string right;
|
||||
if (services_->battery && services_->battery->hasData()) {
|
||||
const float charge = services_->battery->charge();
|
||||
char buf[32];
|
||||
if (charge > 0.0f && charge <= 1.5f) {
|
||||
const int pct = std::clamp(static_cast<int>(charge * 100.0f + 0.5f), 0, 100);
|
||||
std::snprintf(buf, sizeof(buf), "BAT %d%%", pct);
|
||||
const float current = services_->battery->current();
|
||||
const float chargeMah = services_->battery->charge();
|
||||
const float fallbackV = services_->battery->voltage();
|
||||
char buf[64];
|
||||
if (std::isfinite(current) && std::isfinite(chargeMah)) {
|
||||
const long currentRounded = std::lround(static_cast<double>(current));
|
||||
const long chargeRounded = std::lround(static_cast<double>(chargeMah));
|
||||
std::snprintf(buf, sizeof(buf), "CUR %+ldMA CAP %ldMAH", currentRounded, std::max(0L, chargeRounded));
|
||||
} else {
|
||||
std::snprintf(buf, sizeof(buf), "BAT %.2fV", static_cast<double>(services_->battery->voltage()));
|
||||
std::snprintf(buf, sizeof(buf), "BAT %.2fV", static_cast<double>(fallbackV));
|
||||
}
|
||||
right.assign(buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user