What changed, and why it matters
This commit is a user-interface cleanup: it removes a special 'draw text upside-down' flag from the graphics library and instead uses a generic 180-degree rotation helper when the screen is flipped. It does not fix a security vulnerability and does not appear to introduce one. The change is mostly about simplifying how text and buttons are rendered on the BitBox02 hardware wallet screen.
No security action required. Treat as a normal code-quality/UI refactor. If reviewing, verify that the new rotation helper correctly preserves the previous upside-down appearance for the orientation screen and that no call sites still pass the removed `inverted` argument.
Security signals we found
No memory-unsafe patterns introduced: the change removes a boolean parameter and adds a bounded rotation helper with width/height validation.
No attacker-controlled data is newly parsed or exposed.
No cryptographic, bootloader-verification, or secure-storage code is modified.
The only functional risk is a rendering regression (e.g., upside-down text appearing wrong) in the orientation screen, which is a UI/UX issue rather than a security issue.
Evidence from the diff
The patch refactors the UGUI text API by dropping the per-call inverted boolean and replacing it with a temporary 180-degree rendering transform (UG_RenderRotated180) plus a component helper (ui_util_component_render_rotated_180). Call sites in the bootloader, Rust UI layer, screen debug output, buttons, labels, keyboard switch, trinary input, and orientation arrows are updated. The old per-character inversion logic (which reversed string order and drew characters right-to-left/bottom-to-top) is removed; rotation is now applied at the pixel level inside a bounded region. Unit tests are added to verify pixel and component rotation math.
Changed components
src/ui/ugui/ugui.csrc/ui/ugui/ugui.hsrc/ui/ui_util.csrc/ui/ui_util.hsrc/ui/components/button.csrc/ui/components/label.csrc/ui/components/orientation_arrows.csrc/bootloader/bootloader.csrc/rust/bitbox02/src/hal/ui.rssrc/rust/bitbox02/src/lib.rsInspect captured patch +291 / −202
diff --git a/src/bootloader/bootloader.c b/src/bootloader/bootloader.c
index 1455158..48d1019 100644
--- a/src/bootloader/bootloader.c
+++ b/src/bootloader/bootloader.c
@@ -316,7 +316,7 @@ static void _render_message(const char* message, int duration)
char print[100];
snprintf(print, sizeof(print), "%s", message);
UG_ClearBuffer();
- UG_PutString(0, 0, print, false);
+ UG_PutString(0, 0, print);
UG_SendBuffer();
delay_ms(duration);
}
@@ -326,20 +326,20 @@ void bootloader_render_default_screen(void)
UG_ClearBuffer();
_load_logo();
#if PLATFORM_BITBOX02PLUS == 1
- UG_PutString(0, SCREEN_HEIGHT - 9 * 2 - 5, "See the BitBoxApp", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9 * 2 - 5, "See the BitBoxApp");
if (rust_communication_mode_ble_enabled() &&
da14531_connected_state < DA14531_CONNECTED_CONNECTED_SECURED) {
char buf[MEMORY_DEVICE_MAX_LEN_WITH_NULL] = {0};
memory_random_name(buf);
- UG_PutString(0, SCREEN_HEIGHT - 9, buf, false);
+ UG_PutString(0, SCREEN_HEIGHT - 9, buf);
} else if (_is_app_flash_empty) {
- UG_PutString(0, SCREEN_HEIGHT - 9, "Let's get started!", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9, "Let's get started!");
}
#else
if (_is_app_flash_empty) {
- UG_PutString(0, SCREEN_HEIGHT - 9 * 2, "Let's get started!", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9 * 2, "Let's get started!");
}
- UG_PutString(0, SCREEN_HEIGHT - 9, "See the BitBoxApp", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9, "See the BitBoxApp");
#endif
UG_SendBuffer();
}
@@ -360,14 +360,14 @@ void bootloader_render_ble_confirm_screen(bool confirmed)
UG_ClearBuffer();
uint16_t check_width = IMAGE_DEFAULT_CHECKMARK_HEIGHT + IMAGE_DEFAULT_CHECKMARK_HEIGHT / 2 - 1;
if (confirmed) {
- UG_PutString(15, 0, "Confirm on app", false);
+ UG_PutString(15, 0, "Confirm on app");
} else {
- UG_PutString(30, 0, "Pairing code", false);
+ UG_PutString(30, 0, "Pairing code");
image_cross(SCREEN_WIDTH / 16, 0, IMAGE_DEFAULT_CROSS_HEIGHT);
image_checkmark(SCREEN_WIDTH * 15 / 16 - check_width, 0, IMAGE_DEFAULT_CHECKMARK_HEIGHT);
}
UG_FontSelect(&font_monogram_5X9);
- UG_PutString(45, SCREEN_HEIGHT / 2 - 9, code_str, false);
+ UG_PutString(45, SCREEN_HEIGHT / 2 - 9, code_str);
UG_FontSelect(&font_font_a_9X9);
UG_SendBuffer();
}
@@ -380,7 +380,7 @@ static void _render_progress(float progress)
if (progress > 0) {
char label[5] = {0};
snprintf(label, sizeof(label), "%2d%%", (int)(100 * progress));
- UG_PutString(0, SCREEN_HEIGHT - 9 * 2, label, false);
+ UG_PutString(0, SCREEN_HEIGHT - 9 * 2, label);
_load_progress_bar(progress);
} else {
_load_arrow(0, SCREEN_HEIGHT - 16, 10);
@@ -389,7 +389,7 @@ static void _render_progress(float progress)
if (_is_app_flash_empty) {
msg = "INSTALLING";
}
- UG_PutString(SCREEN_WIDTH / 2 - 3, SCREEN_HEIGHT - 9 * 2, msg, false);
+ UG_PutString(SCREEN_WIDTH / 2 - 3, SCREEN_HEIGHT - 9 * 2, msg);
UG_SendBuffer();
}
@@ -423,18 +423,15 @@ static void _render_hash(const char* title, const uint8_t* hash)
for (uint8_t i = 1; i <= seconds; i++) {
UG_ClearBuffer();
- UG_PutString(0, 0, title, false);
+ UG_PutString(0, 0, title);
snprintf(timer_buf, sizeof(timer_buf), "%ds", seconds - i);
UG_MeasureString(&timer_str_width, NULL, timer_buf);
UG_PutString(
- SCREEN_WIDTH - timer_str_width,
- SCREEN_HEIGHT - f_regular->char_height,
- timer_buf,
- false);
+ SCREEN_WIDTH - timer_str_width, SCREEN_HEIGHT - f_regular->char_height, timer_buf);
UG_FontSelect(f_mono);
- UG_PutString(0, title_margin + f_regular->char_height, hash_multiline, false);
+ UG_PutString(0, title_margin + f_regular->char_height, hash_multiline);
UG_FontSelect(f_regular);
@@ -1005,14 +1002,14 @@ static void _check_init(boot_data_t* data)
static bool _devdevice_enter(secbool_u32 firmware_verified)
{
UG_ClearBuffer();
- UG_PutString(0, 0, " <Enter bootloader>", false);
- UG_PutString(0, SCREEN_HEIGHT / 2 - 11, "DEV DEVICE", false);
- UG_PutString(0, SCREEN_HEIGHT / 2 + 2, "NOT FOR VALUE", false);
+ UG_PutString(0, 0, " <Enter bootloader>");
+ UG_PutString(0, SCREEN_HEIGHT / 2 - 11, "DEV DEVICE");
+ UG_PutString(0, SCREEN_HEIGHT / 2 + 2, "NOT FOR VALUE");
// Check that the firmware's reset handler isn't invalid.
if (((uint32_t*)FLASH_APP_START)[1] != 0xffffffff) {
- UG_PutString(0, SCREEN_HEIGHT - 9, " <Continue>", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9, " <Continue>");
} else {
- UG_PutString(0, SCREEN_HEIGHT - 9, " No firmware found", false);
+ UG_PutString(0, SCREEN_HEIGHT - 9, " No firmware found");
}
#if PLATFORM_BITBOX02PLUS == 1
struct da14531_firmware_version version;
@@ -1020,7 +1017,7 @@ static bool _devdevice_enter(secbool_u32 firmware_verified)
if (res) {
char buf[50];
snprintf(buf, sizeof(buf), "ble: %d (%s)", version.version, util_dbg_hex(version.hash, 4));
- UG_PutString(0, SCREEN_HEIGHT - 18, buf, false);
+ UG_PutString(0, SCREEN_HEIGHT - 18, buf);
}
#endif
uint16_t ypos = SCREEN_HEIGHT / 2 - 4;
diff --git a/src/rust/bitbox02/src/hal/ui.rs b/src/rust/bitbox02/src/hal/ui.rs
index 440bfbf..0b8414b 100644
--- a/src/rust/bitbox02/src/hal/ui.rs
+++ b/src/rust/bitbox02/src/hal/ui.rs
@@ -165,7 +165,7 @@ impl<Timer: bitbox_hal::timer::Timer> Ui for BitBox02Ui<Timer> {
fn print_screen(&mut self, duration: Duration, msg: &str) {
crate::screen_clear();
crate::ug_font_select_9x9();
- crate::ug_put_string(0, 0, msg, false);
+ crate::ug_put_string(0, 0, msg);
crate::ug_send_buffer();
crate::delay(duration);
}
diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs
index ddae004..23184d5 100644
--- a/src/rust/bitbox02/src/lib.rs
+++ b/src/rust/bitbox02/src/lib.rs
@@ -49,7 +49,7 @@ pub mod usb_processing;
pub use bitbox02_sys::buffer_t;
use core::time::Duration;
-pub fn ug_put_string(x: i16, y: i16, input: &str, inverted: bool) {
+pub fn ug_put_string(x: i16, y: i16, input: &str) {
unsafe {
bitbox02_sys::UG_PutString(
x,
@@ -58,7 +58,6 @@ pub fn ug_put_string(x: i16, y: i16, input: &str, inverted: bool) {
.unwrap()
.as_ptr()
.cast(),
- inverted,
);
}
}
diff --git a/src/screen.c b/src/screen.c
index b0eef92..0f77566 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -35,7 +35,7 @@ void screen_print_debug(const char* message, int duration)
snprintf(print, sizeof(print), "%s", message);
screen_clear();
UG_FontSelect(&font_font_a_9X9);
- UG_PutString(0, 0, print, false);
+ UG_PutString(0, 0, print);
UG_SendBuffer();
#ifndef TESTING
if (duration > 0) delay_ms(duration);
diff --git a/src/ui/components/button.c b/src/ui/components/button.c
index 5db2c64..85a640f 100644
--- a/src/ui/components/button.c
+++ b/src/ui/components/button.c
@@ -21,7 +21,6 @@ typedef struct {
char text[20];
slider_location_t location;
bool span_over_slider;
- bool upside_down;
void (*callback)(component_t*);
} button_data_t;
@@ -39,8 +38,7 @@ static void _render(component_t* component)
component->position.top,
component->dimension.width,
component->dimension.height,
- data->text,
- data->upside_down);
+ data->text);
UG_FontSetHSpace(1);
}
@@ -74,8 +72,7 @@ static component_t* _button_create(
const char* text,
const slider_location_t location,
void (*callback)(component_t*),
- component_t* parent,
- bool upside_down)
+ component_t* parent)
{
button_data_t* data = malloc(sizeof(button_data_t));
if (!data) {
@@ -83,7 +80,6 @@ static component_t* _button_create(
}
memset(data, 0, sizeof(button_data_t));
data->location = location;
- data->upside_down = upside_down;
data->span_over_slider = false;
component_t* button = malloc(sizeof(component_t));
@@ -104,10 +100,9 @@ static component_t* _button_create_wide(
const char* text,
const slider_location_t location,
void (*callback)(component_t*),
- component_t* parent,
- bool upside_down)
+ component_t* parent)
{
- component_t* button = _button_create(text, location, callback, parent, upside_down);
+ component_t* button = _button_create(text, location, callback, parent);
button_data_t* data = (button_data_t*)button->data;
data->span_over_slider = true;
@@ -124,10 +119,9 @@ static component_t* _button_create_at_position(
const slider_location_t location,
const uint8_t screen_position,
void (*callback)(component_t*),
- component_t* parent,
- bool upside_down)
+ component_t* parent)
{
- component_t* button = _button_create(text, location, callback, parent, upside_down);
+ component_t* button = _button_create(text, location, callback, parent);
int16_t pos = screen_position - button->dimension.width / 2;
if (pos < 0) {
@@ -152,7 +146,7 @@ component_t* button_create(
void (*callback)(component_t*),
component_t* parent)
{
- return _button_create_at_position(text, location, screen_position, callback, parent, false);
+ return _button_create_at_position(text, location, screen_position, callback, parent);
}
component_t* button_create_wide(
@@ -161,26 +155,7 @@ component_t* button_create_wide(
void (*callback)(component_t*),
component_t* parent)
{
- return _button_create_wide(text, location, callback, parent, false);
-}
-
-component_t* button_create_upside_down(
- const char* text,
- const slider_location_t location,
- const uint8_t screen_position,
- void (*callback)(component_t*),
- component_t* parent)
-{
- return _button_create_at_position(text, location, screen_position, callback, parent, true);
-}
-
-component_t* button_create_wide_upside_down(
- const char* text,
- const slider_location_t location,
- void (*callback)(component_t*),
- component_t* parent)
-{
- return _button_create_wide(text, location, callback, parent, true);
+ return _button_create_wide(text, location, callback, parent);
}
void button_update(component_t* button, const char* text, void (*callback)(component_t*))
diff --git a/src/ui/components/button.h b/src/ui/components/button.h
index 1f8cb4f..dbcc3c8 100644
--- a/src/ui/components/button.h
+++ b/src/ui/components/button.h
@@ -36,34 +36,6 @@ component_t* button_create_wide(
void (*callback)(component_t*),
component_t* parent);
-/**
- * Creates an upside-down button with the given text.
- * @param[in] text The text of the button.
- * @param[in] location The location of the button (top or bottom).
- * @param[in] screen_position The location of the button.
- * @param[in] callback The callback that is called when the button is pushed.
- * @param[in] parent The parent component.
- */
-component_t* button_create_upside_down(
- const char* text,
- slider_location_t location,
- uint8_t screen_position,
- void (*callback)(component_t*),
- component_t* parent);
-
-/**
- * Creates an upside-down button with the given text that spans over the whole slider.
- * @param[in] text The text of the button.
- * @param[in] location The location of the button (top or bottom).
- * @param[in] callback The callback that is called when the button is pushed.
- * @param[in] parent The parent component.
- */
-component_t* button_create_wide_upside_down(
- const char* text,
- slider_location_t location,
- void (*callback)(component_t*),
- component_t* parent);
-
/**
* Updates a button with the given text and callback.
* @param[in] text The text of the button.
diff --git a/src/ui/components/keyboard_switch.c b/src/ui/components/keyboard_switch.c
index bc1190c..392224a 100644
--- a/src/ui/components/keyboard_switch.c
+++ b/src/ui/components/keyboard_switch.c
@@ -37,24 +37,24 @@ static void _render(component_t* component)
switch (ks_data->mode) {
case LOWER_CASE:
UG_MeasureString(&w, &h, "ABC");
- UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "ABC", false);
+ UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "ABC");
break;
case UPPER_CASE:
UG_MeasureString(&w, &h, "123");
- UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "123", false);
+ UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "123");
break;
case DIGITS:
if (ks_data->special_chars) {
UG_MeasureString(&w, &h, "&?+");
- UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "&?+", false);
+ UG_PutString((SCREEN_WIDTH - w) / 2 + 1, 1, "&?+");
} else {
UG_MeasureString(&w, &h, "abc");
- UG_PutString((SCREEN_WIDTH - w) / 2 + 2, 1, "abc", false);
+ UG_PutString((SCREEN_WIDTH - w) / 2 + 2, 1, "abc");
}
break;
case SPECIAL_CHARS:
UG_MeasureString(&w, &h, "abc");
- UG_PutString((SCREEN_WIDTH - w) / 2 + 2, 1, "abc", false);
+ UG_PutString((SCREEN_WIDTH - w) / 2 + 2, 1, "abc");
break;
default:
Abort("Keyboard mode unrecognized");
diff --git a/src/ui/components/label.c b/src/ui/components/label.c
index 2305275..d571732 100644
--- a/src/ui/components/label.c
+++ b/src/ui/components/label.c
@@ -16,7 +16,6 @@ typedef struct {
// +3 for '...' if truncated, +1 for null terminator.
char text[MAX_LABEL_SIZE + 3 + 1];
const UG_FONT* font;
- bool upside_down;
enum screen_position_t position;
bool scrollable;
bool slider_is_touched;
@@ -101,8 +100,7 @@ static void _render(component_t* component)
UG_PutStringNoBreak(
data->text_position - component->dimension.width / 2,
component->position.top,
- data->text,
- data->upside_down);
+ data->text);
} else if (
data->position == CENTER || data->position == CENTER_TOP ||
data->position == CENTER_BOTTOM) {
@@ -111,14 +109,10 @@ static void _render(component_t* component)
component->position.top,
component->dimension.width,
component->dimension.height,
- data->text,
- data->upside_down);
+ data->text);
} else {
UG_PutString(
- component->position.left + data->text_position,
- component->position.top,
- data->text,
- data->upside_down);
+ component->position.left + data->text_position, component->position.top, data->text);
}
UG_FontSetVSpace(0);
}
@@ -203,7 +197,6 @@ static const component_functions_t _component_functions = {
static component_t* _label_create(
const char* text,
- const bool upside_down,
const UG_FONT* font,
enum screen_position_t position,
uint8_t xoffset,
@@ -223,7 +216,6 @@ static component_t* _label_create(
memset(label, 0, sizeof(component_t));
data->font = font != NULL ? font : &font_font_a_11X10;
- data->upside_down = upside_down;
data->scrollable = scrollable;
data->position = position;
data->xoffset = xoffset;
@@ -246,7 +238,7 @@ component_t* label_create(
enum screen_position_t position,
component_t* parent)
{
- return _label_create(text, false, font, position, 0, 0, false, parent);
+ return _label_create(text, font, position, 0, 0, false, parent);
}
component_t* label_create_offset(
@@ -257,7 +249,7 @@ component_t* label_create_offset(
uint8_t yoffset,
component_t* parent)
{
- return _label_create(text, false, font, position, xoffset, yoffset, false, parent);
+ return _label_create(text, font, position, xoffset, yoffset, false, parent);
}
component_t* label_create_scrollable(
@@ -266,7 +258,7 @@ component_t* label_create_scrollable(
enum screen_position_t position,
component_t* parent)
{
- return _label_create(text, false, font, position, 0, 0, true, parent);
+ return _label_create(text, font, position, 0, 0, true, parent);
}
component_t* label_create_scrollable_offset(
@@ -277,5 +269,5 @@ component_t* label_create_scrollable_offset(
uint8_t yoffset,
component_t* parent)
{
- return _label_create(text, false, font, position, xoffset, yoffset, true, parent);
+ return _label_create(text, font, position, xoffset, yoffset, true, parent);
}
diff --git a/src/ui/components/orientation_arrows.c b/src/ui/components/orientation_arrows.c
index 032e106..9a6f70a 100644
--- a/src/ui/components/orientation_arrows.c
+++ b/src/ui/components/orientation_arrows.c
@@ -7,6 +7,7 @@
#include <hardfault.h>
#include <screen.h>
+#include <ui/ui_util.h>
#include <util.h>
#include <string.h>
@@ -56,6 +57,15 @@ static void _stay(component_t* component)
}
}
+static void _render_button(component_t* button, bool rotated)
+{
+ if (rotated) {
+ ui_util_component_render_rotated_180(button);
+ } else {
+ button->f->render(button);
+ }
+}
+
static void _render(component_t* component)
{
orientation_data_t* data = (orientation_data_t*)component->data;
@@ -88,7 +98,7 @@ static void _render(component_t* component)
component_t* sc = component->sub_components.sub_components[i];
sc->position.top =
i ? MIN(0, y - 12) : SCREEN_HEIGHT - sc->dimension.height - MIN(0, y - 12);
- sc->f->render(sc);
+ _render_button(sc, i);
}
} else {
// Render sub-components
@@ -109,7 +119,7 @@ static void _render(component_t* component)
// Bounce text
component_t* sc = component->sub_components.sub_components[i];
sc->position.top = i ? y : SCREEN_HEIGHT - sc->dimension.height - y;
- sc->f->render(sc);
+ _render_button(sc, i);
}
if ((data->screen_count - period / 4) % period < period / 2) {
component_t* sc_rotate = component->sub_components.sub_components[2];
@@ -162,9 +172,8 @@ component_t* orientation_arrows_create(void (*done_callback)(bool, void*), void*
orientation->position.top = 0;
orientation->position.left = 0;
- component_t* button_normal = button_create_wide(TEXT, bottom_slider, _stay, orientation);
- component_t* button_upside_down =
- button_create_wide_upside_down(TEXT, top_slider, _flip, orientation);
+ component_t* button_bottom = button_create_wide(TEXT, bottom_slider, _stay, orientation);
+ component_t* button_top = button_create_wide(TEXT, top_slider, _flip, orientation);
component_t* rotate = image_create(
IMAGE_ROTATE, sizeof(IMAGE_ROTATE), IMAGE_ROTATE_W, IMAGE_ROTATE_H, CENTER, orientation);
component_t* rotate_reverse = image_create(
@@ -176,8 +185,8 @@ component_t* orientation_arrows_create(void (*done_callback)(bool, void*), void*
orientation);
// Order/presence is important and affects rendering `sc->f->render(sc)`;
- ui_util_add_sub_component(orientation, button_normal);
- ui_util_add_sub_component(orientation, button_upside_down);
+ ui_util_add_sub_component(orientation, button_bottom);
+ ui_util_add_sub_component(orientation, button_top);
ui_util_add_sub_component(orientation, rotate);
ui_util_add_sub_component(orientation, rotate_reverse);
diff --git a/src/ui/components/trinary_input_char.c b/src/ui/components/trinary_input_char.c
index 14b9669..6e5bfbf 100644
--- a/src/ui/components/trinary_input_char.c
+++ b/src/ui/components/trinary_input_char.c
@@ -231,12 +231,7 @@ static void _render(component_t* component)
continue;
}
UG_PutChar(
- element->character,
- element->x,
- element->y,
- screen_front_color,
- screen_back_color,
- false);
+ element->character, element->x, element->y, screen_front_color, screen_back_color);
}
ui_util_component_render_subcomponents(component);
}
diff --git a/src/ui/components/trinary_input_string.c b/src/ui/components/trinary_input_string.c
index 38d11c4..43514f5 100644
--- a/src/ui/components/trinary_input_string.c
+++ b/src/ui/components/trinary_input_string.c
@@ -194,7 +194,7 @@ static void _render(component_t* component)
if (chr == '\0') {
UG_FillCircle(string_x + 3, string_y + 4, 2, screen_front_color);
} else {
- UG_PutChar(chr, string_x, string_y, screen_front_color, screen_back_color, false);
+ UG_PutChar(chr, string_x, string_y, screen_front_color, screen_back_color);
}
}
string_x += width + 1;
@@ -208,7 +208,7 @@ static void _render(component_t* component)
if (data->target_x < STRING_POS_X_START) {
// HACK: blank out the chars rendered at this position first.
UG_FillFrame(0, STRING_POS_Y, 11, STRING_POS_Y + _font->char_height, screen_back_color);
- UG_PutString(0, STRING_POS_Y, "...", false);
+ UG_PutString(0, STRING_POS_Y, "...");
}
// Render sub-components
diff --git a/src/ui/ugui/ugui.c b/src/ui/ugui/ugui.c
index 5b02675..392c517 100644
--- a/src/ui/ugui/ugui.c
+++ b/src/ui/ugui/ugui.c
@@ -57,8 +57,30 @@
/* Pointer to the gui */
static UG_GUI *gui = NULL;
+typedef struct {
+ bool active;
+ UG_S16 x;
+ UG_S16 y;
+ UG_S16 width;
+ UG_S16 height;
+} ug_rotation_t;
+
+static ug_rotation_t rotation = {0};
+
+static void _UG_PSet(UG_S16 x, UG_S16 y, UG_COLOR c)
+{
+ if (gui == NULL) {
+ return;
+ }
+ if (rotation.active) {
+ x = rotation.x + rotation.width - 1 - (x - rotation.x);
+ y = rotation.y + rotation.height - 1 - (y - rotation.y);
+ }
+ gui->pset(x, y, c);
+}
+
static void _UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc,
- const UG_FONT *font, bool inverted, bool transparent)
+ const UG_FONT *font, bool transparent)
{
UG_U16 i, j, k, xo, yo, c, bn, actual_char_width;
UG_U8 b, bt;
@@ -100,7 +122,7 @@ static void _UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc,
return;
}
- yo = inverted ? (y + font->char_height) : y;
+ yo = y;
bn = font->char_width;
if ( !bn ) {
return;
@@ -119,33 +141,24 @@ static void _UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc,
if (font->font_type == FONT_TYPE_1BPP) {
index = (bt - font->start_char) * font->char_height * bn;
for ( j = 0; j < font->char_height; j++ ) {
- xo = inverted ? (x + actual_char_width) : x;
+ xo = x;
c = actual_char_width;
for ( i = 0; i < bn; i++ ) {
b = font->p[index++];
for ( k = 0; (k < 8) && c; k++ ) {
if ( b & 0x01 ) {
- gui->pset(xo, yo, fc);
+ _UG_PSet(xo, yo, fc);
} else if ( !transparent ) {
- gui->pset(xo, yo, bc);
+ _UG_PSet(xo, yo, bc);
}
b >>= 1;
- if (inverted) {
- xo--;
- } else {
- xo++;
- }
+ xo++;
c--;
}
}
- if (inverted) {
- yo--;
- } else {
- yo++;
- }
+ yo++;
}
} else if (font->font_type == FONT_TYPE_8BPP) {
- // inversion not supported
index = (bt - font->start_char) * font->char_height * font->char_width;
for ( j = 0; j < font->char_height; j++ ) {
xo = x;
@@ -154,7 +167,7 @@ static void _UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc,
color = ((((fc & 0xFF) * b + (bc & 0xFF) * (256 - b)) >> 8) & 0xFF) |//Blue component
((((fc & 0xFF00) * b + (bc & 0xFF00) * (256 - b)) >> 8) & 0xFF00) |//Green component
((((fc & 0xFF0000) * b + (bc & 0xFF0000) * (256 - b)) >> 8) & 0xFF0000); //Red component
- gui->pset(xo, yo, color);
+ _UG_PSet(xo, yo, color);
xo++;
}
index += font->char_width - actual_char_width;
@@ -164,7 +177,7 @@ static void _UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc,
}
static void _UG_PutString( UG_S16 x, UG_S16 y, UG_S16 *xout, UG_S16 *yout, const char *str,
- int autobreak, int calconly, bool inverted )
+ int autobreak, int calconly )
{
if (gui == NULL) {
return;
@@ -181,7 +194,7 @@ static void _UG_PutString( UG_S16 x, UG_S16 y, UG_S16 *xout, UG_S16 *yout, const
const int str_length = strlens(str);
for (int i = 0; i < str_length; i++) {
- chr = (char)(inverted ? str[str_length - 1 - i] : str[i]);
+ chr = str[i];
if (chr != '\n' && (chr < gui->font.start_char || chr > gui->font.end_char)) {
continue;
}
@@ -203,7 +216,7 @@ static void _UG_PutString( UG_S16 x, UG_S16 y, UG_S16 *xout, UG_S16 *yout, const
}
if (!calconly) {
- UG_PutChar(chr, xp, yp, gui->fore_color, gui->back_color, inverted);
+ UG_PutChar(chr, xp, yp, gui->fore_color, gui->back_color);
}
xp += cw + gui->char_h_space;
@@ -234,6 +247,7 @@ UG_S16 UG_Init( UG_GUI *g, void (*p)(UG_S16, UG_S16, UG_COLOR),
g->char_v_space = 1;
g->fore_color = C_WHITE;
g->back_color = C_BLACK;
+ rotation.active = false;
gui = g;
return 1;
@@ -274,7 +288,7 @@ void UG_FillFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c )
for ( m = y1; m <= y2; m++ ) {
for ( n = x1; n <= x2; n++ ) {
- gui->pset(n, m, c);
+ _UG_PSet(n, m, c);
}
}
}
@@ -369,7 +383,7 @@ void UG_DrawRoundFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_S16 r, UG
void UG_DrawPixel( UG_S16 x0, UG_S16 y0, UG_COLOR c )
{
if (gui) {
- gui->pset(x0, y0, c);
+ _UG_PSet(x0, y0, c);
}
}
@@ -398,14 +412,14 @@ void UG_DrawCircle( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_COLOR c )
y = 0;
while ( x >= y ) {
- gui->pset(x0 - x, y0 + y, c);
- gui->pset(x0 - x, y0 - y, c);
- gui->pset(x0 + x, y0 + y, c);
- gui->pset(x0 + x, y0 - y, c);
- gui->pset(x0 - y, y0 + x, c);
- gui->pset(x0 - y, y0 - x, c);
- gui->pset(x0 + y, y0 + x, c);
- gui->pset(x0 + y, y0 - x, c);
+ _UG_PSet(x0 - x, y0 + y, c);
+ _UG_PSet(x0 - x, y0 - y, c);
+ _UG_PSet(x0 + x, y0 + y, c);
+ _UG_PSet(x0 + x, y0 - y, c);
+ _UG_PSet(x0 - y, y0 + x, c);
+ _UG_PSet(x0 - y, y0 - x, c);
+ _UG_PSet(x0 + y, y0 + x, c);
+ _UG_PSet(x0 + y, y0 - x, c);
y++;
e += yd;
@@ -483,34 +497,34 @@ void UG_DrawArc( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_U8 s, UG_COLOR c )
while ( x >= y ) {
// Q1
if ( s & 0x01 ) {
- gui->pset(x0 + x, y0 - y, c);
+ _UG_PSet(x0 + x, y0 - y, c);
}
if ( s & 0x02 ) {
- gui->pset(x0 + y, y0 - x, c);
+ _UG_PSet(x0 + y, y0 - x, c);
}
// Q2
if ( s & 0x04 ) {
- gui->pset(x0 - y, y0 - x, c);
+ _UG_PSet(x0 - y, y0 - x, c);
}
if ( s & 0x08 ) {
- gui->pset(x0 - x, y0 - y, c);
+ _UG_PSet(x0 - x, y0 - y, c);
}
// Q3
if ( s & 0x10 ) {
- gui->pset(x0 - x, y0 + y, c);
+ _UG_PSet(x0 - x, y0 + y, c);
}
if ( s & 0x20 ) {
- gui->pset(x0 - y, y0 + x, c);
+ _UG_PSet(x0 - y, y0 + x, c);
}
// Q4
if ( s & 0x40 ) {
- gui->pset(x0 + y, y0 + x, c);
+ _UG_PSet(x0 + y, y0 + x, c);
}
if ( s & 0x80 ) {
- gui->pset(x0 + x, y0 + y, c);
+ _UG_PSet(x0 + x, y0 + y, c);
}
y++;
@@ -543,7 +557,7 @@ void UG_DrawLine( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c )
drawx = x1;
drawy = y1;
- gui->pset(drawx, drawy, c);
+ _UG_PSet(drawx, drawy, c);
if ( dxabs >= dyabs ) {
for ( n = 0; n < dxabs; n++ ) {
@@ -553,7 +567,7 @@ void UG_DrawLine( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c )
drawy += sgndy;
}
drawx += sgndx;
- gui->pset(drawx, drawy, c);
+ _UG_PSet(drawx, drawy, c);
}
} else {
for ( n = 0; n < dyabs; n++ ) {
@@ -563,14 +577,14 @@ void UG_DrawLine( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c )
drawx += sgndx;
}
drawy += sgndy;
- gui->pset(drawx, drawy, c);
+ _UG_PSet(drawx, drawy, c);
}
}
}
void UG_MeasureString(UG_S16 *xout, UG_S16 *yout, const char *str)
{
- _UG_PutString(0, 0, xout, yout, str, 1, 1, false);
+ _UG_PutString(0, 0, xout, yout, str, 1, 1);
}
/**
@@ -579,7 +593,7 @@ void UG_MeasureString(UG_S16 *xout, UG_S16 *yout, const char *str)
*/
void UG_MeasureStringNoBreak(UG_S16 *xout, UG_S16 *yout, const char *str)
{
- _UG_PutString(0, 0, xout, yout, str, 0, 1, false);
+ _UG_PutString(0, 0, xout, yout, str, 0, 1);
}
/**
@@ -605,7 +619,7 @@ void UG_MeasureStringCentered(UG_S16 *xout, UG_S16 *yout, const char *str)
for (c = str; *c != '\0'; c++) {
if (*c == '\n') {
snprintf(line, sizeof(line), "%.*s", (int)(c - start), start);
- _UG_PutString(0, 0, &calc_width_line, &calc_height_line, line, 0, 1, false);
+ _UG_PutString(0, 0, &calc_width_line, &calc_height_line, line, 0, 1);
*yout += calc_height_line;
*yout += gui->char_v_space;
*xout = MAX(*xout, calc_width_line);
@@ -613,7 +627,7 @@ void UG_MeasureStringCentered(UG_S16 *xout, UG_S16 *yout, const char *str)
}
}
snprintf(line, sizeof(line), "%.*s", (int)(c - start), start);
- _UG_PutString(0, 0, &calc_width_line, &calc_height_line, line, 0, 1, false);
+ _UG_PutString(0, 0, &calc_width_line, &calc_height_line, line, 0, 1);
*yout += calc_height_line;
*yout += gui->char_v_space;
*xout = MAX(*xout, calc_width_line);
@@ -700,14 +714,38 @@ void UG_WrapTitleString(const char* str, char* str_out, UG_S16 width) {
}
}
-void UG_PutString( UG_S16 x, UG_S16 y, const char *str, bool inverted)
+void UG_RenderRotated180(
+ UG_S16 x,
+ UG_S16 y,
+ UG_S16 width,
+ UG_S16 height,
+ UG_RenderCallback render,
+ void* ctx)
+{
+ if (gui == NULL || render == NULL || width <= 0 || height <= 0) {
+ return;
+ }
+
+ const ug_rotation_t previous_rotation = rotation;
+ rotation = (ug_rotation_t){
+ .active = true,
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height,
+ };
+ render(ctx);
+ rotation = previous_rotation;
+}
+
+void UG_PutString( UG_S16 x, UG_S16 y, const char *str)
{
- _UG_PutString(x, y, NULL, NULL, str, 1, 0, inverted);
+ _UG_PutString(x, y, NULL, NULL, str, 1, 0);
}
-void UG_PutStringNoBreak( UG_S16 x, UG_S16 y, const char *str, bool inverted)
+void UG_PutStringNoBreak( UG_S16 x, UG_S16 y, const char *str)
{
- _UG_PutString(x, y, NULL, NULL, str, 0, 0, inverted);
+ _UG_PutString(x, y, NULL, NULL, str, 0, 0);
}
/**
@@ -718,7 +756,7 @@ void UG_PutStringNoBreak( UG_S16 x, UG_S16 y, const char *str, bool inverted)
* the overflowing lines on top of each other.
* Auto-break is disabled with this feature.
*/
-void UG_PutStringCentered( UG_S16 x, UG_S16 y, UG_S16 width, UG_S16 height, const char *str, bool inverted) {
+void UG_PutStringCentered( UG_S16 x, UG_S16 y, UG_S16 width, UG_S16 height, const char *str) {
if (gui == NULL) {
return;
}
@@ -753,17 +791,17 @@ void UG_PutStringCentered( UG_S16 x, UG_S16 y, UG_S16 width, UG_S16 height, cons
snprintf(lines[current_line], sizeof(lines[current_line]), "%.*s", (int)(c - start), start);
// calculate the height of each line
- _UG_PutString(0, 0, NULL, &calc_height, "W", 0, 1, inverted);
+ _UG_PutString(0, 0, NULL, &calc_height, "W", 0, 1);
y = y + (height - ((calc_height + gui->char_v_space) * num_lines)) / 2;
for (uint16_t i = 0; i < num_lines; i++) {
UG_S16 current_y = y + (i * (calc_height + gui->char_v_space));
- _UG_PutString(0, 0, &calc_width, NULL, lines[i], 0, 1, inverted);
+ _UG_PutString(0, 0, &calc_width, NULL, lines[i], 0, 1);
UG_S16 pos_x = x + (width - calc_width) / 2;
- _UG_PutString(pos_x, current_y, NULL, NULL, lines[i], 0, 0, inverted);
+ _UG_PutString(pos_x, current_y, NULL, NULL, lines[i], 0, 0);
}
}
-void UG_PutStringNoBreakCenter( UG_S16 x, UG_S16 y, UG_S16 width, const char *str, bool inverted)
+void UG_PutStringNoBreakCenter( UG_S16 x, UG_S16 y, UG_S16 width, const char *str)
{
if (gui == NULL) {
return;
@@ -773,26 +811,26 @@ void UG_PutStringNoBreakCenter( UG_S16 x, UG_S16 y, UG_S16 width, const char *st
if (x == 0 && width == 0) {
width = gui->x_dim - 1;
}
- _UG_PutString(x, y, &calc_width, NULL, str, 0, 1, inverted);
- _UG_PutString(x + (width - calc_width) / 2, y, NULL, NULL, str, 0, 0, inverted);
+ _UG_PutString(x, y, &calc_width, NULL, str, 0, 1);
+ _UG_PutString(x + (width - calc_width) / 2, y, NULL, NULL, str, 0, 0);
}
-void UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc, bool inverted )
+void UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc )
{
if (gui == NULL) {
return;
}
- _UG_PutChar(chr, x, y, fc, bc, &gui->font, inverted, false);
+ _UG_PutChar(chr, x, y, fc, bc, &gui->font, false);
}
-void UG_PutCharTransparent( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, bool inverted )
+void UG_PutCharTransparent( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc )
{
if (gui == NULL) {
return;
}
- _UG_PutChar(chr, x, y, fc, 0x00, &gui->font, inverted, true);
+ _UG_PutChar(chr, x, y, fc, 0x00, &gui->font, true);
}
void UG_SetForecolor( UG_COLOR c )
diff --git a/src/ui/ugui/ugui.h b/src/ui/ugui/ugui.h
index b470edc..fb23690 100644
--- a/src/ui/ugui/ugui.h
+++ b/src/ui/ugui/ugui.h
@@ -107,15 +107,23 @@ void UG_FillCircle( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_COLOR c );
void UG_DrawArc( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_U8 s, UG_COLOR c );
void UG_DrawLine( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c );
void UG_WrapTitleString(const char* str, char* str_out, UG_S16 width);
-void UG_PutString( UG_S16 x, UG_S16 y, const char *str, bool inverted);
-void UG_PutStringNoBreak( UG_S16 x, UG_S16 y, const char *str, bool inverted);
+typedef void (*UG_RenderCallback)(void* ctx);
+void UG_RenderRotated180(
+ UG_S16 x,
+ UG_S16 y,
+ UG_S16 width,
+ UG_S16 height,
+ UG_RenderCallback render,
+ void* ctx);
+void UG_PutString( UG_S16 x, UG_S16 y, const char *str);
+void UG_PutStringNoBreak( UG_S16 x, UG_S16 y, const char *str);
void UG_MeasureString( UG_S16 *xout, UG_S16 *yout, const char *str);
void UG_MeasureStringNoBreak(UG_S16 *xout, UG_S16 *yout, const char *str);
void UG_MeasureStringCentered( UG_S16 *xout, UG_S16 *yout, const char *str);
-void UG_PutStringNoBreakCenter( UG_S16 x, UG_S16 y, UG_S16 width, const char *str, bool inverted);
-void UG_PutStringCentered( UG_S16 x, UG_S16 y, UG_S16 width, UG_S16 height, const char *str, bool inverted);
-void UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc, bool inverted );
-void UG_PutCharTransparent( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, bool inverted );
+void UG_PutStringNoBreakCenter( UG_S16 x, UG_S16 y, UG_S16 width, const char *str);
+void UG_PutStringCentered( UG_S16 x, UG_S16 y, UG_S16 width, UG_S16 height, const char *str);
+void UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc );
+void UG_PutCharTransparent( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc );
void UG_SetForecolor( UG_COLOR c );
void UG_SetBackcolor( UG_COLOR c );
UG_S16 UG_GetXDim( void );
diff --git a/src/ui/ui_util.c b/src/ui/ui_util.c
index 6b9337b..bffafd7 100644
--- a/src/ui/ui_util.c
+++ b/src/ui/ui_util.c
@@ -37,6 +37,23 @@ void ui_util_component_render_subcomponents(component_t* component)
}
}
+static void _render_component(void* ctx)
+{
+ component_t* component = (component_t*)ctx;
+ component->f->render(component);
+}
+
+void ui_util_component_render_rotated_180(component_t* component)
+{
+ UG_RenderRotated180(
+ component->position.left,
+ component->position.top,
+ component->dimension.width,
+ component->dimension.height,
+ _render_component,
+ component);
+}
+
/**
* A utility function that cleans up the current component and all sub-components.
* @param[in] component The cleaned up component.
diff --git a/src/ui/ui_util.h b/src/ui/ui_util.h
index f613b75..fd9c395 100644
--- a/src/ui/ui_util.h
+++ b/src/ui/ui_util.h
@@ -35,6 +35,13 @@ void ui_util_add_sub_component(component_t* parent, component_t* child);
*/
void ui_util_component_render_subcomponents(component_t* component);
+/**
+ * A utility function that renders the component rotated by 180 degrees inside its current
+ * component bounds.
+ * @param[in] component The rendered component.
+ */
+void ui_util_component_render_rotated_180(component_t* component);
+
/**
* A utility function that cleans up the current component and all sub-components.
* @param[in] component The cleaned up component.
diff --git a/test/hardware-fakes/include/fake_component.h b/test/hardware-fakes/include/fake_component.h
index 5c851f5..fa2934f 100644
--- a/test/hardware-fakes/include/fake_component.h
+++ b/test/hardware-fakes/include/fake_component.h
@@ -7,12 +7,6 @@
/********************************** Create Instance **********************************/
-/**
- * Creates a label with the given font either upside down or normal.
- * @param[in] text The text of the label.
- * @param[in] upside_down Whether the text should be rotated 180 degree or not.
- * @param[in] font The font of the label.
- */
component_t* fake_component_create(void);
#endif
diff --git a/test/hardware-fakes/src/fake_component.c b/test/hardware-fakes/src/fake_component.c
index 5b91175..6f7dfb2 100644
--- a/test/hardware-fakes/src/fake_component.c
+++ b/test/hardware-fakes/src/fake_component.c
@@ -20,12 +20,6 @@ static const component_functions_t FAKE_COMPONENT_FUNCTIONS = {
/********************************** Create Instance **********************************/
-/**
- * Creates a label with the given font either upside down or normal.
- * @param[in] text The text of the label.
- * @param[in] upside_down Whether the text should be rotated 180 degree or not.
- * @param[in] font The font of the label.
- */
component_t* fake_component_create(void)
{
component_t* fake = malloc(sizeof(component_t));
diff --git a/test/unit-test/test_ugui.c b/test/unit-test/test_ugui.c
index a4eed9d..aadcaca 100644
--- a/test/unit-test/test_ugui.c
+++ b/test/unit-test/test_ugui.c
@@ -21,10 +21,25 @@ const char* data[][2] = {
};
static UG_GUI gui;
+static UG_S16 last_x;
+static UG_S16 last_y;
+static UG_COLOR last_color;
+static uint8_t pixels_set;
static void _set_pixel(UG_S16 x, UG_S16 y, UG_COLOR color)
{
- /* nop */
+ last_x = x;
+ last_y = y;
+ last_color = color;
+ pixels_set++;
+}
+
+static void _reset_pixel_capture(void)
+{
+ last_x = 0;
+ last_y = 0;
+ last_color = 0;
+ pixels_set = 0;
}
static void _test_ugui_word_wrap(void** state)
@@ -40,10 +55,36 @@ static void _test_ugui_word_wrap(void** state)
}
}
+static void _draw_pixel(void* ctx)
+{
+ (void)ctx;
+ UG_DrawPixel(12, 24, C_WHITE);
+}
+
+static void _test_ugui_render_rotated_180(void** state)
+{
+ (void)state; /* unused */
+ UG_Init(&gui, _set_pixel, &font_font_a_11X10, 128, 64);
+
+ _reset_pixel_capture();
+ UG_RenderRotated180(10, 20, 30, 10, _draw_pixel, NULL);
+ assert_int_equal(pixels_set, 1);
+ assert_int_equal(last_x, 37);
+ assert_int_equal(last_y, 25);
+ assert_int_equal(last_color, C_WHITE);
+
+ _reset_pixel_capture();
+ UG_DrawPixel(12, 24, C_WHITE);
+ assert_int_equal(pixels_set, 1);
+ assert_int_equal(last_x, 12);
+ assert_int_equal(last_y, 24);
+}
+
int main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(_test_ugui_word_wrap),
+ cmocka_unit_test(_test_ugui_render_rotated_180),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/unit-test/test_ui_util.c b/test/unit-test/test_ui_util.c
index 59e34e5..f8f77e4 100644
--- a/test/unit-test/test_ui_util.c
+++ b/test/unit-test/test_ui_util.c
@@ -6,10 +6,42 @@
#include <stddef.h>
#include <cmocka.h>
+#include <ui/fonts/arial_fonts.h>
#include <ui/ui_util.h>
#include "fake_component.h"
+static UG_GUI gui;
+static UG_S16 last_x;
+static UG_S16 last_y;
+static uint8_t pixels_set;
+
+static void _set_pixel(UG_S16 x, UG_S16 y, UG_COLOR color)
+{
+ (void)color;
+ last_x = x;
+ last_y = y;
+ pixels_set++;
+}
+
+static void _reset_pixel_capture(void)
+{
+ last_x = 0;
+ last_y = 0;
+ pixels_set = 0;
+}
+
+static void _render_pixel(component_t* component)
+{
+ UG_DrawPixel(component->position.left + 2, component->position.top + 3, C_WHITE);
+}
+
+static const component_functions_t _pixel_component_functions = {
+ .cleanup = NULL,
+ .render = _render_pixel,
+ .on_event = NULL,
+};
+
static void test_ui_util_position_center(void** state)
{
component_t* mock_component_1 = fake_component_create();
@@ -178,6 +210,24 @@ static void test_ui_util_position_right_top(void** state)
mock_component_2->f->cleanup(mock_component_2);
}
+static void test_ui_util_component_render_rotated_180(void** state)
+{
+ (void)state;
+ UG_Init(&gui, _set_pixel, &font_font_a_11X10, 128, 64);
+ component_t component = {
+ .f = &_pixel_component_functions,
+ .dimension = {.width = 10, .height = 8},
+ .position = {.left = 5, .top = 7},
+ };
+
+ _reset_pixel_capture();
+ ui_util_component_render_rotated_180(&component);
+
+ assert_int_equal(pixels_set, 1);
+ assert_int_equal(last_x, 12);
+ assert_int_equal(last_y, 11);
+}
+
int main(void)
{
const struct CMUnitTest tests[] = {
@@ -188,6 +238,7 @@ int main(void)
cmocka_unit_test(test_ui_util_position_left_top),
cmocka_unit_test(test_ui_util_position_right_bottom),
cmocka_unit_test(test_ui_util_position_right_top),
+ cmocka_unit_test(test_ui_util_component_render_rotated_180),
};
return cmocka_run_group_tests(tests, NULL, NULL);
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.