Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: refactor text with raylib #34306

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions system/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
spinner
text
1 change: 1 addition & 0 deletions system/ui/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ if not UBUNTU_FOCAL:

if arch != 'aarch64':
renv.Program("spinner", ["raylib/spinner.cc"], LIBS=linked_libs, FRAMEWORKS=mac_frameworks)
renv.Program("text", ["raylib/text.cc"], LIBS=linked_libs, FRAMEWORKS=mac_frameworks)
108 changes: 108 additions & 0 deletions system/ui/raylib/text.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include <string>
#include <vector>
#include <cstring>

#include "system/hardware/hw.h"
#include "system/ui/raylib/util.h"

constexpr int kMargin = 50;
constexpr int kFontSize = 70;
constexpr int kButtonPadding = 50;
constexpr int kButtonSidePadding = 100;
constexpr int kButtonRadius = 20;
constexpr int kTextSpacing = 0.0f;

struct Button {
Rectangle bounds{0, 0, 0, 0};
const char* text{nullptr};
bool hovered{false};

void draw() {
Color color = hovered ? RAYLIB_GRAY : RAYLIB_BLACK;
DrawRectangleRounded(bounds, 0.2f, kButtonRadius, color);
DrawRectangleRoundedLines(bounds, 0.2f, kButtonRadius, RAYLIB_WHITE);

Vector2 textSize = MeasureTextEx(getFont(), text, kFontSize, kTextSpacing);
Vector2 textPos = {
bounds.x + (bounds.width - textSize.x) / 2,
bounds.y + (bounds.height - textSize.y) / 2
};
DrawTextEx(getFont(), text, textPos, kFontSize, kTextSpacing, RAYLIB_WHITE);
}

bool checkHover(Vector2 mousePos) {
hovered = CheckCollisionPointRec(mousePos, bounds);
return hovered;
}
};

int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: ./text <message>\n");
return 1;
}

SetConfigFlags(FLAG_MSAA_4X_HINT);

initApp("text", 60);
SetExitKey(0);

const char* displayText = argv[1];
if (!displayText || strlen(displayText) == 0) {
printf("Error: Empty message\n");
return 1;
}

Button button;
#ifdef __aarch64__
button.text = "Reboot";
#else
button.text = "Exit";
#endif

while (!WindowShouldClose()) {
if (IsKeyPressed(KEY_ESCAPE)) break;

BeginDrawing();
ClearBackground(RAYLIB_BLACK);

// Update button position and size
float buttonWidth = MeasureTextEx(getFont(), button.text, kFontSize, kTextSpacing).x + 2 * kButtonSidePadding;
button.bounds = {
static_cast<float>(GetScreenWidth() - buttonWidth - kMargin * 2),
static_cast<float>(GetScreenHeight() - kFontSize - 2 * kButtonPadding - kMargin),
buttonWidth,
static_cast<float>(kFontSize + 2 * kButtonPadding)
};

// Handle mouse input
Vector2 mousePos = GetMousePosition();
button.checkHover(mousePos);

if (button.hovered && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
#ifdef __aarch64__
Hardware::reboot();
#else
CloseWindow();
return 0;
#endif
}

// Draw text in container
Rectangle textBox = {
static_cast<float>(kMargin),
static_cast<float>(kMargin),
static_cast<float>(GetScreenWidth() - 2 * kMargin),
static_cast<float>(GetScreenHeight() - button.bounds.height - 3 * kMargin)
};

DrawTextBoxed(displayText, textBox, kFontSize, kTextSpacing, true, RAYLIB_WHITE);

button.draw();

EndDrawing();
}

CloseWindow();
return 0;
}
109 changes: 101 additions & 8 deletions system/ui/raylib/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
#include "system/hardware/hw.h"

constexpr std::array<const char *, static_cast<int>(FontWeight::Count)> FONT_FILE_PATHS = {
"../../assets/fonts/Inter-Black.ttf",
"../../assets/fonts/Inter-Bold.ttf",
"../../assets/fonts/Inter-ExtraBold.ttf",
"../../assets/fonts/Inter-ExtraLight.ttf",
"../../assets/fonts/Inter-Medium.ttf",
"../../assets/fonts/Inter-Regular.ttf",
"../../assets/fonts/Inter-SemiBold.ttf",
"../../assets/fonts/Inter-Thin.ttf",
"../../selfdrive/assets/fonts/Inter-Black.ttf",
"../../selfdrive/assets/fonts/Inter-Bold.ttf",
"../../selfdrive/assets/fonts/Inter-ExtraBold.ttf",
"../../selfdrive/assets/fonts/Inter-ExtraLight.ttf",
"../../selfdrive/assets/fonts/Inter-Medium.ttf",
"../../selfdrive/assets/fonts/Inter-Regular.ttf",
"../../selfdrive/assets/fonts/Inter-SemiBold.ttf",
"../../selfdrive/assets/fonts/Inter-Thin.ttf",
};

struct FontManager {
Expand Down Expand Up @@ -50,5 +50,98 @@ void initApp(const char *title, int fps) {
Hardware::set_brightness(65);
// SetTraceLogLevel(LOG_NONE);
InitWindow(2160, 1080, title);

for (int i = 0; i < static_cast<int>(FontWeight::Count); i++) {
SetTextureFilter(getFont(static_cast<FontWeight>(i)).texture, TEXTURE_FILTER_BILINEAR);
}

SetTargetFPS(fps);
}

void DrawTextBoxed(const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) {
int length = TextLength(text);
float textOffsetY = 0;
float textOffsetX = 0.0f;
float scaleFactor = fontSize/(float)getFont().baseSize;

int state = wordWrap? 0 : 1; // 0-Measure, 1-Draw
int startLine = -1;
int endLine = -1;
int lastk = -1;

for (int i = 0, k = 0; i < length; i++, k++) {
int codepointByteCount = 0;
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(getFont(), codepoint);

if (codepoint == 0x3f) codepointByteCount = 1;
i += (codepointByteCount - 1);

float glyphWidth = 0;
if (codepoint != '\n') {
glyphWidth = (getFont().glyphs[index].advanceX == 0) ?
getFont().recs[index].width*scaleFactor :
getFont().glyphs[index].advanceX*scaleFactor;

if (i + 1 < length) glyphWidth = glyphWidth + spacing;
}

if (state == 0) {
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;

if ((textOffsetX + glyphWidth) > rec.width) {
endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= codepointByteCount;
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);

state = !state;
} else if ((i + 1) == length) {
endLine = i;
state = !state;
} else if (codepoint == '\n') state = !state;

if (state == 1) {
textOffsetX = 0;
i = startLine;
glyphWidth = 0;

int tmp = lastk;
lastk = k - 1;
k = tmp;
}
} else {
if (codepoint == '\n') {
if (!wordWrap) {
textOffsetY += (getFont().baseSize + getFont().baseSize/2)*scaleFactor;
textOffsetX = 0;
}
} else {
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) {
textOffsetY += (getFont().baseSize + getFont().baseSize/2)*scaleFactor;
textOffsetX = 0;
}

if ((textOffsetY + getFont().baseSize*scaleFactor) > rec.height) break;

if ((codepoint != ' ') && (codepoint != '\t')) {
DrawTextCodepoint(getFont(), codepoint,
(Vector2){ rec.x + textOffsetX, rec.y + textOffsetY },
fontSize, tint);
}
}

if (wordWrap && (i == endLine)) {
textOffsetY += (getFont().baseSize + getFont().baseSize/2)*scaleFactor;
textOffsetX = 0;
startLine = endLine;
endLine = -1;
glyphWidth = 0;
k = lastk;

state = !state;
}
}

if ((textOffsetX != 0) || (codepoint != ' ')) textOffsetX += glyphWidth;
}
}
3 changes: 2 additions & 1 deletion system/ui/raylib/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ enum class FontWeight {
};

void initApp(const char *title, int fps);
const Font& getFont(FontWeight weight = FontWeight::Normal);
const Font& getFont(FontWeight weight = FontWeight::Regular);
Texture2D LoadTextureResized(const char *fileName, int size);
void DrawTextBoxed(const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint);
Loading