Skip to content

Commit

Permalink
Fixed multiple progress widget alignment problems
Browse files Browse the repository at this point in the history
Signed-off-by: simonmicro <simon@simonmicro.de>
  • Loading branch information
simonmicro committed Aug 11, 2024
1 parent 3568f29 commit eae8c52
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 48 deletions.
4 changes: 2 additions & 2 deletions emulator/src/tests/unitTests/emulator/widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ UTEST(widgets, OswAppTestProgressWidget) {

OswAppTestProgressWidget app;
OswAppV2Fixture appFixture(app);
while(!app.isDone()) // controlled by the app
while(!app.next()) // controlled by the app
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
101 changes: 74 additions & 27 deletions include/apps/tests/OswAppTestProgressWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class OswAppTestProgressWidget : public OswAppV2 {
OswAppTestProgressWidget() = default;

const char* getAppId() override {
return "osw.test.widget.progress";
return "osw.test.prog";
};
const char* getAppName() override {
return "Test Progress Widget";
Expand All @@ -20,51 +20,98 @@ class OswAppTestProgressWidget : public OswAppV2 {
void onStart() override {
OswAppV2::onStart();
this->viewFlags = (OswAppV2::ViewFlags) (this->viewFlags | OswAppV2::ViewFlags::KEEP_DISPLAY_ON);
this->knownButtonStates[Button::BUTTON_SELECT] = ButtonStateNames::SHORT_PRESS;
this->knownButtonStates[Button::BUTTON_DOWN] = ButtonStateNames::SHORT_PRESS;

feedback = std::make_shared<OswProgressFeedback>();
widget.show(feedback); // link the widget to the feedback object
this->step = 0;
};

void onLoop() override {
OswAppV2::onLoop();
if(time(nullptr) - last > 2) {
last = time(nullptr);
++this->step;
if(this->step == 1) {
this->feedback->setProgress(-1.0f); // indeterminate
} else if(this->step == 2) {
this->feedback->setProgress(0.1); // a little bit
} else if(this->step == 3) {
this->feedback->setProgress(0.8); // a bit more
} else if(this->step == 4) {
this->feedback->setProgress(0.800001); // a little bit
} else if(this->step == 5) {
this->feedback->setProgress(-1.0f); // back to indeterminate
} else {
// done
}
OSW_LOG_D(this->step);
}
this->needsRedraw = this->needsRedraw or widget.getNeedsRedraw();
};

void onDraw() override {
OswAppV2::onDraw();

widget.drawLinear(OswHal::getInstance()->gfx(), 20, 60, 80);
widget.drawLinear(OswHal::getInstance()->gfx(), 20, 80, 160);
widget.drawCircular(OswHal::getInstance()->gfx(), 20, 140, 1, true);
widget.drawCircular(OswHal::getInstance()->gfx(), 80, 140, 2, true);
OswUI::getInstance()->setTextCursor(Button::BUTTON_SELECT);
OswHal::getInstance()->gfx()->print(this->step);
OswHal::getInstance()->gfx()->print(" (");
OswHal::getInstance()->gfx()->print(this->feedback->getProgress());
OswHal::getInstance()->gfx()->print(")");

OswUI::getInstance()->setTextCursor(Button::BUTTON_DOWN);
OswHal::getInstance()->gfx()->setTextSize(0.5);
const auto text = this->feedback->getText();
if(text != nullptr) {
OswHal::getInstance()->gfx()->print(text);
} else {
OswHal::getInstance()->gfx()->print("-");
}

const auto margin = 40;
const auto padding = 10;
auto x = margin;
auto y = margin;
widget.drawLinear(OswHal::getInstance()->gfx(), x, margin, DISP_W / 2);
y += widget.baseDimensions + padding;
widget.drawLinear(OswHal::getInstance()->gfx(), x, y, DISP_W - x * 2);
y += widget.baseDimensions + padding;
widget.drawCircular(OswHal::getInstance()->gfx(), x, y, 1.0f, true);
x += widget.baseDimensions + padding;
widget.drawCircular(OswHal::getInstance()->gfx(), x, y, 2.0f, true);
x += widget.baseDimensions * 2.0f + padding;
widget.drawCircular(OswHal::getInstance()->gfx(), x, y, 3.0f, true);
};

void onStop() override {
OswAppV2::onStop();
};

bool isDone() {
return this->step > 5;
void onButton(Button id, bool up, ButtonStateNames state) override {
OswAppV2::onButton(id, up, state);
if(!up) return;
if(id == Button::BUTTON_SELECT) {
this->next();
} else if(id == Button::BUTTON_DOWN) {
if(this->feedback->getText() == nullptr) {
this->feedback->setText("Text");
} else {
this->feedback->setText(nullptr);
}
} else {
throw std::logic_error("Unhandled button");
}
};

bool next() {
bool looped = false;

++this->step;
if(this->step > 5) {
this->step = 1;
looped = true;
}

if(this->step == 1) {
this->feedback->setProgress(-1.0f); // indeterminate
} else if(this->step == 2) {
this->feedback->setProgress(0.1); // a little bit
} else if(this->step == 3) {
this->feedback->setProgress(0.8); // a bit more
} else if(this->step == 4) {
this->feedback->setProgress(0.800001); // a little bit
} else if(this->step == 5) {
this->feedback->setProgress(-1.0f); // indeterminate
this->feedback->setText("Test Text");
}

return looped;
}
private:
std::shared_ptr<OswProgressFeedback> feedback;
OswProgressWidget widget;
time_t last = 0;
unsigned step = 0;
unsigned step = 1;
};
5 changes: 4 additions & 1 deletion include/widgets/OswProgressWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class OswProgressWidget {
void setTargetProgress(const float& value); // animate to a new value
void updateProgressFromFeedback(); // check if the feedback has something new for us

const bool displayDebugLines = false; // enable in case the behaviour of drawArc() changes...
const short barHeight = 6;

std::mutex lock;
std::shared_ptr<OswProgressFeedback> feedback = nullptr;
float lastPulledProgress = -1.0; // used to check if observed feedback changed
Expand All @@ -68,4 +71,4 @@ class OswProgressWidget {
time_t startTime = 0; // when was this state set?
float endValue = 0; // where the bar will end...
time_t endTime = 0; // ...and when
};
};
60 changes: 42 additions & 18 deletions src/widgets/OswProgressWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ bool OswProgressWidget::getNeedsRedraw() {
void OswProgressWidget::updateProgressFromFeedback() {
if(this->feedback == nullptr)
return; // no update if we have no feedback
float feedValue = this->feedback->getProgress();
const char* feedText = this->feedback->getText();
if(feedValue != this->lastPulledProgress or (feedText != nullptr and feedText != this->lastPulledText)) {
const float feedValue = this->feedback->getProgress();
if(feedValue != this->lastPulledProgress) {
this->setTargetProgress(feedValue);
this->lastPulledProgress = feedValue;
if(feedText)
}
const char* feedText = this->feedback->getText();
if(feedText != nullptr) {
if(feedText != this->lastPulledText)
this->lastPulledText = feedText; // this will COPY the text into this widget
else
} else {
if(this->lastPulledText.size() > 0)
this->lastPulledText = ""; // empty will be treated as not there
}
}
Expand Down Expand Up @@ -71,7 +74,6 @@ void OswProgressWidget::drawCircular(Graphics2DPrint* gfx, int x, int y, float s
std::lock_guard<std::mutex> l(this->lock);
this->updateProgressFromFeedback();

const uint16_t radius = 16;
const float value = this->calcValue();
float arcStart;
float arcLength;
Expand All @@ -82,28 +84,46 @@ void OswProgressWidget::drawCircular(Graphics2DPrint* gfx, int x, int y, float s
arcStart = 0;
arcLength = value * 360;
}
const int16_t steps = (this->baseDimensions / 2) * scale;
const int16_t arcRadius = this->baseDimensions / 8 * scale;
gfx->drawArc(x + this->baseDimensions / 2, y + this->baseDimensions / 2, 0.0f, 360.0f, steps, radius, arcRadius, this->bgColor);
gfx->drawArc(x + this->baseDimensions / 2, y + this->baseDimensions / 2, arcStart, arcStart + arcLength, steps, radius, arcRadius, this->fgColor);
const int16_t size = (this->baseDimensions * scale);
const int16_t steps = (size / 2) * scale;
const int16_t arcRadius = min((short) (size / 8), (short) (barHeight / 2));
const int16_t cx = x + size / 2 + arcRadius - 2; // 2 pixel offset due to floating point errors
const int16_t cy = y + size / 2 + arcRadius - 2; // 2 pixel offset due to floating point errors
const uint16_t radius = size / 2 - arcRadius;
gfx->drawArc(cx, cy, 0.0f, 360.0f, steps, radius, arcRadius, this->bgColor, false, false);
gfx->drawArc(cx, cy, arcStart, arcStart + arcLength, steps, radius, arcRadius, this->fgColor, false, false);

if(showText and this->lastPulledText.size()) {
const char printMe = this->lastPulledText[0];
gfx->setTextCursor(x + radius / 2 - gfx->getCharWidth(printMe) / 2, y + radius / 2 + gfx->getCharHeight(printMe) / 2);
gfx->setTextCursor(x + size / 2 - gfx->getCharWidth(printMe) / 2, y + size / 2 + gfx->getCharHeight(printMe) / 2);
gfx->setTextSize(1);
gfx->setTextColor(this->fgColor);
// gfx->setTextMiddleAligned(); // FIXME, this is still broken
gfx->setTextMiddleAligned();
// TODO: both operator are broken, if used with a single character
// gfx->setTextMiddleAligned();
// gfx->setTextCenterAligned();
gfx->setTextBottomAligned();
gfx->setTextLeftAligned();
gfx->print(printMe);
}


if(this->displayDebugLines) {
gfx->drawVLine(x, y, baseDimensions * scale, rgb565(0, 0, 255));
gfx->drawHLine(x, y, baseDimensions * scale, rgb565(0, 0, 255));

gfx->drawHLine(cx - radius - arcRadius, cy, arcRadius, rgb565(255, 0, 255));
gfx->drawHLine(cx - radius, cy, radius, rgb565(255, 255, 0));
gfx->drawHLine(cx, cy, radius, rgb565(255, 255, 0));
gfx->drawHLine(cx + radius, cy, arcRadius, rgb565(255, 0, 255));
gfx->drawPixel(cx, cy, rgb565(0, 255, 0));
}
}

void OswProgressWidget::drawLinear(Graphics2DPrint* gfx, int x, int y, int width, bool showText) {
std::lock_guard<std::mutex> l(this->lock);
this->updateProgressFromFeedback();

const float barWidth = 0.4; // for unknown progress bouncing
const short barHeight = 6;
const short barRadius = 3;
const float value = this->calcValue();
short bgStart = x;
Expand All @@ -129,12 +149,16 @@ void OswProgressWidget::drawLinear(Graphics2DPrint* gfx, int x, int y, int width
gfx->fillFrame(fgStart, y, fgBarWidth, barHeight, this->fgColor);

if(showText and this->lastPulledText.size()) {
size_t textWidth = gfx->getTextLength((const uint8_t*) this->lastPulledText.c_str(), this->lastPulledText.size());
gfx->setTextCursor(x + width / 2 - textWidth / 2, y + barHeight + gfx->getCharHeight(this->lastPulledText[0])); // 8 fits our chosen text size
gfx->setTextSize(1);
gfx->setTextCursor(x + width / 2, y + barHeight + gfx->getCharHeight(this->lastPulledText[0]));
gfx->setTextColor(this->fgColor);
// gfx->setTextMiddleAligned(); // FIXME, this is still broken
gfx->setTextMiddleAligned();
gfx->setTextBottomAligned();
gfx->setTextCenterAligned();
gfx->print(this->lastPulledText.c_str());
}

if(this->displayDebugLines) {
gfx->drawVLine(x, y, baseDimensions, rgb565(0, 0, 255));
gfx->drawHLine(x, y, width, rgb565(0, 0, 255));
}
}

0 comments on commit eae8c52

Please sign in to comment.