mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
.ttf fonts (beta)
This commit is contained in:
parent
8b3ca448ed
commit
3c7d36a50f
42 changed files with 5841 additions and 78 deletions
14
Makefile
14
Makefile
|
|
@ -31,7 +31,7 @@ OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) \
|
||||||
|
|
||||||
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
||||||
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
||||||
-m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
||||||
-I$(SRC_DIR) -I$(SRC_DIR)/lwip
|
-I$(SRC_DIR) -I$(SRC_DIR)/lwip
|
||||||
|
|
||||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||||
|
|
@ -134,6 +134,16 @@ $(ISO_IMAGE): $(KERNEL_ELF) limine.conf limine-setup
|
||||||
cp limine/BOOTX64.EFI $(ISO_DIR)/EFI/BOOT/
|
cp limine/BOOTX64.EFI $(ISO_DIR)/EFI/BOOT/
|
||||||
cp limine/BOOTIA32.EFI $(ISO_DIR)/EFI/BOOT/
|
cp limine/BOOTIA32.EFI $(ISO_DIR)/EFI/BOOT/
|
||||||
|
|
||||||
|
# Copy Fonts
|
||||||
|
mkdir -p $(ISO_DIR)/Library/Fonts
|
||||||
|
@for f in $(SRC_DIR)/fonts/*.ttf; do \
|
||||||
|
if [ -f "$$f" ]; then \
|
||||||
|
basename=$$(basename "$$f"); \
|
||||||
|
cp "$$f" $(ISO_DIR)/Library/Fonts/; \
|
||||||
|
echo " module_path: boot():/Library/Fonts/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
|
||||||
# Generate ISO
|
# Generate ISO
|
||||||
$(XORRISO) -as mkisofs -b limine-bios-cd.bin \
|
$(XORRISO) -as mkisofs -b limine-bios-cd.bin \
|
||||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||||
|
|
@ -152,6 +162,6 @@ run: $(ISO_IMAGE)
|
||||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom $< -boot d \
|
qemu-system-x86_64 -m 2G -serial stdio -cdrom $< -boot d \
|
||||||
-m 4G \
|
-m 4G \
|
||||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||||
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
-netdev user,id=net0,hostfwd=udp::12346-:12345 -device e1000,netdev=net0 \
|
||||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||||
-drive file=disk.img,format=raw,file.locking=off
|
-drive file=disk.img,format=raw,file.locking=off
|
||||||
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
Binary file not shown.
BIN
build/e1000.o
BIN
build/e1000.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
build/nanojpeg.o
BIN
build/nanojpeg.o
Binary file not shown.
Binary file not shown.
BIN
build/pci.o
BIN
build/pci.o
Binary file not shown.
BIN
build/platform.o
BIN
build/platform.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/rtc.o
BIN
build/rtc.o
Binary file not shown.
|
|
@ -25,6 +25,7 @@
|
||||||
#define DEFAULT_CMD_COLS 116
|
#define DEFAULT_CMD_COLS 116
|
||||||
#define DEFAULT_CMD_ROWS 41
|
#define DEFAULT_CMD_ROWS 41
|
||||||
#define MAX_CMD_COLS 256
|
#define MAX_CMD_COLS 256
|
||||||
|
// Terminal cell dimensions — fixed to match the 8x8 bitmap font
|
||||||
#define LINE_HEIGHT 10
|
#define LINE_HEIGHT 10
|
||||||
#define CHAR_WIDTH 8
|
#define CHAR_WIDTH 8
|
||||||
|
|
||||||
|
|
@ -1801,7 +1802,7 @@ static void cmd_paint(Window *win) {
|
||||||
if (r == cursor_row && c == cursor_col && win->focused) {
|
if (r == cursor_row && c == cursor_col && win->focused) {
|
||||||
color = shell_config.bg_color;
|
color = shell_config.bg_color;
|
||||||
}
|
}
|
||||||
draw_char(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, color);
|
draw_char_bitmap(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "explorer.h"
|
#include "explorer.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
#include "font_manager.h"
|
||||||
#include "fat32.h"
|
#include "fat32.h"
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
|
|
@ -189,13 +190,13 @@ static void explorer_draw_icon_label(int x, int y, const char *label, uint32_t c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center in EXPLORER_ITEM_WIDTH
|
// Center in EXPLORER_ITEM_WIDTH
|
||||||
int l1_len = 0; while(line1[l1_len]) l1_len++;
|
ttf_font_t *font = graphics_get_current_ttf();
|
||||||
int l1_w = l1_len * 8;
|
|
||||||
|
int l1_w = font_manager_get_string_width(font, line1);
|
||||||
draw_string(x + (EXPLORER_ITEM_WIDTH - l1_w)/2, y + 56, line1, color);
|
draw_string(x + (EXPLORER_ITEM_WIDTH - l1_w)/2, y + 56, line1, color);
|
||||||
|
|
||||||
if (line2[0]) {
|
if (line2[0]) {
|
||||||
int l2_len = 0; while(line2[l2_len]) l2_len++;
|
int l2_w = font_manager_get_string_width(font, line2);
|
||||||
int l2_w = l2_len * 8;
|
|
||||||
draw_string(x + (EXPLORER_ITEM_WIDTH - l2_w)/2, y + 66, line2, color);
|
draw_string(x + (EXPLORER_ITEM_WIDTH - l2_w)/2, y + 66, line2, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -926,7 +927,7 @@ static void explorer_paint(Window *win) {
|
||||||
draw_rect(offset_x, offset_y, win->w - 8, win->h - 28, COLOR_DARK_BG);
|
draw_rect(offset_x, offset_y, win->w - 8, win->h - 28, COLOR_DARK_BG);
|
||||||
|
|
||||||
// Draw Drive Button (modern rounded style)
|
// Draw Drive Button (modern rounded style)
|
||||||
char drive_label[9]; // 8 chars + null
|
char drive_label[20];
|
||||||
// Extract drive from the window's current_path instead of using global current_drive
|
// Extract drive from the window's current_path instead of using global current_drive
|
||||||
char current_drv = 'A';
|
char current_drv = 'A';
|
||||||
if (state->current_path[0] && state->current_path[1] == ':') {
|
if (state->current_path[0] && state->current_path[1] == ':') {
|
||||||
|
|
@ -935,27 +936,48 @@ static void explorer_paint(Window *win) {
|
||||||
current_drv = state->current_path[0];
|
current_drv = state->current_path[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
drive_label[0] = '[';
|
// Look up drive type
|
||||||
drive_label[1] = ' ';
|
const char *type_str = "RAM";
|
||||||
drive_label[2] = current_drv;
|
Disk *drv = disk_get_by_letter(current_drv);
|
||||||
drive_label[3] = ':';
|
if (drv) {
|
||||||
drive_label[4] = ' ';
|
switch (drv->type) {
|
||||||
drive_label[5] = 'v';
|
case DISK_TYPE_RAM: type_str = "RAM"; break;
|
||||||
drive_label[6] = ' ';
|
case DISK_TYPE_IDE: type_str = "IDE"; break;
|
||||||
drive_label[7] = ']';
|
case DISK_TYPE_SATA: type_str = "SATA"; break;
|
||||||
drive_label[8] = 0;
|
case DISK_TYPE_USB: type_str = "USB"; break;
|
||||||
|
default: type_str = "???"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Button at x+4, y+3, w=60 (rounded)
|
// Build label: "[ A:TYPE v ]"
|
||||||
draw_rounded_rect_filled(win->x + 4, offset_y + 3, 60, 22, 5, COLOR_DARK_PANEL);
|
int di = 0;
|
||||||
|
drive_label[di++] = '[';
|
||||||
|
drive_label[di++] = ' ';
|
||||||
|
drive_label[di++] = current_drv;
|
||||||
|
drive_label[di++] = ':';
|
||||||
|
const char *ts = type_str;
|
||||||
|
while (*ts) drive_label[di++] = *ts++;
|
||||||
|
drive_label[di++] = ' ';
|
||||||
|
drive_label[di++] = 'v';
|
||||||
|
drive_label[di++] = ' ';
|
||||||
|
drive_label[di++] = ']';
|
||||||
|
drive_label[di] = 0;
|
||||||
|
|
||||||
|
// Button at x+4, y+3, sized to fit label (rounded)
|
||||||
|
ttf_font_t *ttf_ = graphics_get_current_ttf();
|
||||||
|
int drive_label_w = ttf_ ? font_manager_get_string_width(ttf_, drive_label) + 16 : 80;
|
||||||
|
if (drive_label_w < 60) drive_label_w = 60;
|
||||||
|
draw_rounded_rect_filled(win->x + 4, offset_y + 3, drive_label_w, 22, 5, COLOR_DARK_PANEL);
|
||||||
draw_string(win->x + 12, offset_y + 8, drive_label, COLOR_DARK_TEXT);
|
draw_string(win->x + 12, offset_y + 8, drive_label, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
// Draw path bar (shifted right, rounded, dark mode)
|
// Draw path bar (shifted right after drive button, rounded, dark mode)
|
||||||
int path_height = 22;
|
int path_height = 22;
|
||||||
int path_x = offset_x + 64;
|
int path_x = offset_x + drive_label_w + 8;
|
||||||
int path_w = win->w - 16 - 64;
|
int path_w = win->w - 16 - drive_label_w - 8;
|
||||||
draw_rounded_rect_filled(path_x, offset_y + 3, path_w, path_height, 5, COLOR_DARK_PANEL);
|
draw_rounded_rect_filled(path_x, offset_y + 3, path_w, path_height, 5, COLOR_DARK_PANEL);
|
||||||
draw_string(path_x + 6, offset_y + 8, "Path", COLOR_DARK_TEXT);
|
draw_string(path_x + 6, offset_y + 8, "Path:", COLOR_DARK_TEXT);
|
||||||
draw_string(path_x + 46, offset_y + 8, state->current_path, COLOR_DARK_TEXT);
|
int path_label_w = ttf_ ? font_manager_get_string_width(ttf_, "Path:") : 40;
|
||||||
|
draw_string(path_x + 6 + path_label_w + 6, offset_y + 8, state->current_path, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
// Draw dropdown menu button (right-aligned, before back button, rounded)
|
// Draw dropdown menu button (right-aligned, before back button, rounded)
|
||||||
int dropdown_btn_x = win->x + win->w - 90;
|
int dropdown_btn_x = win->x + win->w - 90;
|
||||||
|
|
@ -1073,7 +1095,19 @@ static void explorer_paint(Window *win) {
|
||||||
// Input field (rounded dark)
|
// Input field (rounded dark)
|
||||||
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
||||||
draw_rect(dlg_x + 15 + state->dialog_input_cursor * 8, dlg_y + 39, 2, 12, COLOR_WHITE);
|
// Dynamic cursor — find start offset so text doesn't overflow the input box
|
||||||
|
{ int max_w = 265; /* input box is 280px wide with 15px left pad */
|
||||||
|
ttf_font_t *ttf_ = graphics_get_current_ttf();
|
||||||
|
int total_w = font_manager_get_string_width(ttf_, state->dialog_input);
|
||||||
|
int scroll_x = 0;
|
||||||
|
if (total_w > max_w) scroll_x = total_w - max_w;
|
||||||
|
char sub_[128]; int k_=0;
|
||||||
|
for(k_=0; k_<state->dialog_input_cursor && state->dialog_input[k_]; k_++) sub_[k_]=state->dialog_input[k_];
|
||||||
|
sub_[k_]=0;
|
||||||
|
int cx_ = font_manager_get_string_width(ttf_, sub_) - scroll_x;
|
||||||
|
if (cx_ < 0) cx_ = 0;
|
||||||
|
if (cx_ > max_w) cx_ = max_w;
|
||||||
|
draw_rect(dlg_x+15+cx_, dlg_y+39, 2, 12, COLOR_WHITE); }
|
||||||
|
|
||||||
// Buttons (rounded)
|
// Buttons (rounded)
|
||||||
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
||||||
|
|
@ -1093,7 +1127,19 @@ static void explorer_paint(Window *win) {
|
||||||
// Input field (rounded dark)
|
// Input field (rounded dark)
|
||||||
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
||||||
draw_rect(dlg_x + 15 + state->dialog_input_cursor * 8, dlg_y + 39, 2, 12, COLOR_WHITE);
|
// Dynamic cursor — find start offset so text doesn't overflow the input box
|
||||||
|
{ int max_w = 265; /* input box is 280px wide with 15px left pad */
|
||||||
|
ttf_font_t *ttf_ = graphics_get_current_ttf();
|
||||||
|
int total_w = font_manager_get_string_width(ttf_, state->dialog_input);
|
||||||
|
int scroll_x = 0;
|
||||||
|
if (total_w > max_w) scroll_x = total_w - max_w;
|
||||||
|
char sub_[128]; int k_=0;
|
||||||
|
for(k_=0; k_<state->dialog_input_cursor && state->dialog_input[k_]; k_++) sub_[k_]=state->dialog_input[k_];
|
||||||
|
sub_[k_]=0;
|
||||||
|
int cx_ = font_manager_get_string_width(ttf_, sub_) - scroll_x;
|
||||||
|
if (cx_ < 0) cx_ = 0;
|
||||||
|
if (cx_ > max_w) cx_ = max_w;
|
||||||
|
draw_rect(dlg_x+15+cx_, dlg_y+39, 2, 12, COLOR_WHITE); }
|
||||||
|
|
||||||
// Buttons (rounded)
|
// Buttons (rounded)
|
||||||
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
||||||
|
|
@ -1203,7 +1249,19 @@ static void explorer_paint(Window *win) {
|
||||||
draw_string(dlg_x + 10, dlg_y + 10, "Rename", COLOR_WHITE);
|
draw_string(dlg_x + 10, dlg_y + 10, "Rename", COLOR_WHITE);
|
||||||
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
draw_string(dlg_x + 15, dlg_y + 40, state->dialog_input, COLOR_WHITE);
|
||||||
draw_rect(dlg_x + 15 + state->dialog_input_cursor * 8, dlg_y + 39, 2, 12, COLOR_WHITE);
|
// Dynamic cursor — find start offset so text doesn't overflow the input box
|
||||||
|
{ int max_w = 265; /* input box is 280px wide with 15px left pad */
|
||||||
|
ttf_font_t *ttf_ = graphics_get_current_ttf();
|
||||||
|
int total_w = font_manager_get_string_width(ttf_, state->dialog_input);
|
||||||
|
int scroll_x = 0;
|
||||||
|
if (total_w > max_w) scroll_x = total_w - max_w;
|
||||||
|
char sub_[128]; int k_=0;
|
||||||
|
for(k_=0; k_<state->dialog_input_cursor && state->dialog_input[k_]; k_++) sub_[k_]=state->dialog_input[k_];
|
||||||
|
sub_[k_]=0;
|
||||||
|
int cx_ = font_manager_get_string_width(ttf_, sub_) - scroll_x;
|
||||||
|
if (cx_ < 0) cx_ = 0;
|
||||||
|
if (cx_ > max_w) cx_ = max_w;
|
||||||
|
draw_rect(dlg_x+15+cx_, dlg_y+39, 2, 12, COLOR_WHITE); }
|
||||||
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
||||||
draw_string(dlg_x + 68, dlg_y + 72, "Rename", COLOR_WHITE);
|
draw_string(dlg_x + 68, dlg_y + 72, "Rename", COLOR_WHITE);
|
||||||
draw_rounded_rect_filled(dlg_x + 170, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(dlg_x + 170, dlg_y + 65, 80, 25, 6, COLOR_DARK_BORDER);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
|
|
||||||
#define MAX_FILES 256
|
#define MAX_FILES 256
|
||||||
#define MAX_CLUSTERS 1024
|
#define MAX_CLUSTERS 8192
|
||||||
#define MAX_OPEN_HANDLES 32
|
#define MAX_OPEN_HANDLES 32
|
||||||
|
|
||||||
// In-memory FAT table
|
// In-memory FAT table
|
||||||
|
|
|
||||||
159
src/kernel/font_manager.c
Normal file
159
src/kernel/font_manager.c
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "font_manager.h"
|
||||||
|
#include "stb_truetype.h"
|
||||||
|
#include "fat32.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Simple math implementations for stb_truetype
|
||||||
|
float ksqrtf(float x) {
|
||||||
|
float res;
|
||||||
|
asm volatile("sqrtss %1, %0" : "=x"(res) : "x"(x));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float kfabsf(float x) {
|
||||||
|
return (x < 0) ? -x : x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float kpowf(float b, float e) {
|
||||||
|
// Very simplified pow for stb_truetype's needs
|
||||||
|
if (e == 0) return 1.0f;
|
||||||
|
if (e == 1) return b;
|
||||||
|
if (e == 0.5f) return ksqrtf(b);
|
||||||
|
|
||||||
|
// Fallback/log-based would be complex, let's see if this suffices
|
||||||
|
float res = 1.0f;
|
||||||
|
for (int i = 0; i < (int)e; i++) res *= b;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float kfmodf(float x, float y) {
|
||||||
|
return x - (int)(x / y) * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float kcosf(float x) {
|
||||||
|
// Taylor series for cos(x) around 0
|
||||||
|
float x2 = x * x;
|
||||||
|
return 1.0f - (x2 / 2.0f) + (x2 * x2 / 24.0f) - (x2 * x2 * x2 / 720.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float kacosf(float x) {
|
||||||
|
// Very rough approximation for acos(x)
|
||||||
|
if (x >= 1.0f) return 0;
|
||||||
|
if (x <= -1.0f) return 3.14159f;
|
||||||
|
return 1.57079f - x - (x*x*x)/6.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void serial_write(const char *s);
|
||||||
|
extern uint32_t graphics_get_pixel(int x, int y);
|
||||||
|
|
||||||
|
static inline uint32_t alpha_blend(uint32_t bg, uint32_t fg, uint8_t alpha) {
|
||||||
|
if (alpha == 0) return bg;
|
||||||
|
if (alpha == 255) return fg;
|
||||||
|
|
||||||
|
uint32_t rb = (((fg & 0xFF00FF) * alpha) + ((bg & 0xFF00FF) * (255 - alpha))) >> 8;
|
||||||
|
uint32_t g = (((fg & 0x00FF00) * alpha) + ((bg & 0x00FF00) * (255 - alpha))) >> 8;
|
||||||
|
return (rb & 0xFF00FF) | (g & 0x00FF00);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ttf_font_t *default_font = NULL;
|
||||||
|
|
||||||
|
bool font_manager_init(void) {
|
||||||
|
// We'll load a default font later if available
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ttf_font_t* font_manager_load(const char *path, float size) {
|
||||||
|
FAT32_FileHandle *fh = fat32_open(path, "r");
|
||||||
|
if (!fh || !fh->valid) {
|
||||||
|
serial_write("[FONT] Failed to open font file: ");
|
||||||
|
serial_write(path);
|
||||||
|
serial_write("\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fsize = fh->size;
|
||||||
|
unsigned char *buffer = kmalloc(fsize);
|
||||||
|
if (!buffer) {
|
||||||
|
fat32_close(fh);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read = fat32_read(fh, buffer, fsize);
|
||||||
|
fat32_close(fh);
|
||||||
|
|
||||||
|
ttf_font_t *font = kmalloc(sizeof(ttf_font_t));
|
||||||
|
if (!font) {
|
||||||
|
kfree(buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
stbtt_fontinfo *info = kmalloc(sizeof(stbtt_fontinfo));
|
||||||
|
if (!info) {
|
||||||
|
kfree(buffer);
|
||||||
|
kfree(font);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stbtt_InitFont(info, buffer, 0)) {
|
||||||
|
serial_write("[FONT] Failed to init font: ");
|
||||||
|
serial_write(path);
|
||||||
|
serial_write("\n");
|
||||||
|
kfree(info);
|
||||||
|
kfree(buffer);
|
||||||
|
kfree(font);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
font->data = buffer;
|
||||||
|
font->size = fsize;
|
||||||
|
font->info = info;
|
||||||
|
font->scale = stbtt_ScaleForPixelHeight(info, size);
|
||||||
|
|
||||||
|
stbtt_GetFontVMetrics(info, &font->ascent, &font->descent, &font->line_gap);
|
||||||
|
|
||||||
|
if (!default_font) default_font = font;
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t)) {
|
||||||
|
if (!font) font = default_font;
|
||||||
|
if (!font) return;
|
||||||
|
|
||||||
|
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
|
||||||
|
int w, h, xoff, yoff;
|
||||||
|
unsigned char *bitmap = stbtt_GetCodepointBitmap(info, 0, font->scale, c, &w, &h, &xoff, &yoff);
|
||||||
|
|
||||||
|
if (bitmap) {
|
||||||
|
for (int row = 0; row < h; row++) {
|
||||||
|
for (int col = 0; col < w; col++) {
|
||||||
|
unsigned char alpha = bitmap[row * w + col];
|
||||||
|
if (alpha > 0) {
|
||||||
|
int px = x + col + xoff;
|
||||||
|
int py = y + row + yoff;
|
||||||
|
uint32_t bg = graphics_get_pixel(px, py);
|
||||||
|
put_pixel_fn(px, py, alpha_blend(bg, color, alpha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stbtt_FreeBitmap(bitmap, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int font_manager_get_string_width(ttf_font_t *font, const char *s) {
|
||||||
|
if (!font) font = default_font;
|
||||||
|
if (!font || !s) return 0;
|
||||||
|
|
||||||
|
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
|
||||||
|
int width = 0;
|
||||||
|
while (*s) {
|
||||||
|
int advance, lsb;
|
||||||
|
stbtt_GetCodepointHMetrics(info, *s, &advance, &lsb);
|
||||||
|
// Round per-character to match draw_string's accumulation
|
||||||
|
width += (int)(advance * font->scale + 0.5f);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
53
src/kernel/font_manager.h
Normal file
53
src/kernel/font_manager.h
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef FONT_MANAGER_H
|
||||||
|
#define FONT_MANAGER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// stb_truetype math stubs
|
||||||
|
extern float ksqrtf(float x);
|
||||||
|
extern float kpowf(float b, float e);
|
||||||
|
extern float kfmodf(float x, float y);
|
||||||
|
extern float kcosf(float x);
|
||||||
|
extern float kacosf(float x);
|
||||||
|
extern float kfabsf(float x);
|
||||||
|
|
||||||
|
#define STBTT_ifloor(x) ((int)(x))
|
||||||
|
#define STBTT_iceil(x) ((int)(x + 0.999999f))
|
||||||
|
#define STBTT_sqrt(x) ksqrtf(x)
|
||||||
|
#define STBTT_pow(x,y) kpowf(x,y)
|
||||||
|
#define STBTT_fmod(x,y) kfmodf(x,y)
|
||||||
|
#define STBTT_cos(x) kcosf(x)
|
||||||
|
#define STBTT_acos(x) kacosf(x)
|
||||||
|
#define STBTT_fabs(x) kfabsf(x)
|
||||||
|
|
||||||
|
#define STBTT_assert(x) ((void)0)
|
||||||
|
|
||||||
|
// Memory management
|
||||||
|
#define STBTT_malloc(x,u) kmalloc(x)
|
||||||
|
#define STBTT_free(x,u) kfree(x)
|
||||||
|
|
||||||
|
// String functions
|
||||||
|
#define STBTT_memcpy mem_memcpy
|
||||||
|
#define STBTT_memset mem_memset
|
||||||
|
|
||||||
|
// Data types
|
||||||
|
typedef uint64_t STBTT_ptrsize;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *data;
|
||||||
|
size_t size;
|
||||||
|
void *info; // stbtt_fontinfo
|
||||||
|
float scale;
|
||||||
|
int ascent;
|
||||||
|
int descent;
|
||||||
|
int line_gap;
|
||||||
|
} ttf_font_t;
|
||||||
|
|
||||||
|
bool font_manager_init(void);
|
||||||
|
ttf_font_t* font_manager_load(const char *path, float size);
|
||||||
|
void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t));
|
||||||
|
int font_manager_get_string_width(ttf_font_t *font, const char *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
src/kernel/fonts/firamono.ttf
Normal file
BIN
src/kernel/fonts/firamono.ttf
Normal file
Binary file not shown.
BIN
src/kernel/fonts/inter.ttf
Normal file
BIN
src/kernel/fonts/inter.ttf
Normal file
Binary file not shown.
BIN
src/kernel/fonts/times.ttf
Normal file
BIN
src/kernel/fonts/times.ttf
Normal file
Binary file not shown.
|
|
@ -5,10 +5,13 @@
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "font_manager.h"
|
||||||
|
|
||||||
static struct limine_framebuffer *g_fb = NULL;
|
static struct limine_framebuffer *g_fb = NULL;
|
||||||
static uint32_t g_bg_color = 0xFF696969;
|
static uint32_t g_bg_color = 0xFF696969;
|
||||||
|
|
||||||
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
#define PATTERN_SIZE 128
|
#define PATTERN_SIZE 128
|
||||||
static uint32_t g_bg_pattern[PATTERN_SIZE * PATTERN_SIZE];
|
static uint32_t g_bg_pattern[PATTERN_SIZE * PATTERN_SIZE];
|
||||||
static bool g_use_pattern = false;
|
static bool g_use_pattern = false;
|
||||||
|
|
@ -32,6 +35,8 @@ static uint32_t *g_render_target = NULL;
|
||||||
static int g_rt_width = 0;
|
static int g_rt_width = 0;
|
||||||
static int g_rt_height = 0;
|
static int g_rt_height = 0;
|
||||||
|
|
||||||
|
static ttf_font_t *g_current_ttf = NULL;
|
||||||
|
|
||||||
void graphics_init(struct limine_framebuffer *fb) {
|
void graphics_init(struct limine_framebuffer *fb) {
|
||||||
g_fb = fb;
|
g_fb = fb;
|
||||||
g_dirty.active = false;
|
g_dirty.active = false;
|
||||||
|
|
@ -41,6 +46,25 @@ void graphics_init(struct limine_framebuffer *fb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void graphics_init_fonts(void) {
|
||||||
|
font_manager_init();
|
||||||
|
g_current_ttf = font_manager_load("/Library/Fonts/firamono.ttf", 15.0f);
|
||||||
|
if (!g_current_ttf) {
|
||||||
|
serial_write("[FONT] Falling back to bitmap font\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_set_font(const char *path) {
|
||||||
|
ttf_font_t *new_font = font_manager_load(path, 15.0f);
|
||||||
|
if (new_font) {
|
||||||
|
// TODO: free old font data if needed
|
||||||
|
g_current_ttf = new_font;
|
||||||
|
serial_write("[FONT] Switched to: ");
|
||||||
|
serial_write(path);
|
||||||
|
serial_write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int get_screen_width(void) {
|
int get_screen_width(void) {
|
||||||
return g_fb ? g_fb->width : 0;
|
return g_fb ? g_fb->width : 0;
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +157,6 @@ void graphics_set_render_target(uint32_t *buffer, int w, int h) {
|
||||||
void put_pixel(int x, int y, uint32_t color) {
|
void put_pixel(int x, int y, uint32_t color) {
|
||||||
if (g_render_target) {
|
if (g_render_target) {
|
||||||
if (x >= 0 && x < g_rt_width && y >= 0 && y < g_rt_height) {
|
if (x >= 0 && x < g_rt_width && y >= 0 && y < g_rt_height) {
|
||||||
// No clipping in custom render targets yet, just bounding box
|
|
||||||
g_render_target[y * g_rt_width + x] = color;
|
g_render_target[y * g_rt_width + x] = color;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -149,11 +172,24 @@ void put_pixel(int x, int y, uint32_t color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw to back buffer
|
|
||||||
uint32_t pixel_offset = y * g_fb->width + x;
|
uint32_t pixel_offset = y * g_fb->width + x;
|
||||||
g_back_buffer[pixel_offset] = color;
|
g_back_buffer[pixel_offset] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t graphics_get_pixel(int x, int y) {
|
||||||
|
if (g_render_target) {
|
||||||
|
if (x >= 0 && x < g_rt_width && y >= 0 && y < g_rt_height) {
|
||||||
|
return g_render_target[y * g_rt_width + x];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_fb) return 0;
|
||||||
|
if (x < 0 || x >= (int)g_fb->width || y < 0 || y >= (int)g_fb->height) return 0;
|
||||||
|
|
||||||
|
return g_back_buffer[y * g_fb->width + x];
|
||||||
|
}
|
||||||
|
|
||||||
void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
||||||
int x1 = x, y1 = y, x2 = x + w, y2 = y + h;
|
int x1 = x, y1 = y, x2 = x + w, y2 = y + h;
|
||||||
|
|
||||||
|
|
@ -268,6 +304,11 @@ void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t c
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_char(int x, int y, char c, uint32_t color) {
|
void draw_char(int x, int y, char c, uint32_t color) {
|
||||||
|
if (g_current_ttf) {
|
||||||
|
font_manager_render_char(g_current_ttf, x, y, c, color, put_pixel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char uc = (unsigned char)c;
|
unsigned char uc = (unsigned char)c;
|
||||||
if (uc > 127) return;
|
if (uc > 127) return;
|
||||||
|
|
||||||
|
|
@ -289,9 +330,80 @@ void draw_char(int x, int y, char c, uint32_t color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bitmap-only version for terminal — always uses 8x8 bitmap font regardless of TTF
|
||||||
|
void draw_char_bitmap(int x, int y, char c, uint32_t color) {
|
||||||
|
unsigned char uc = (unsigned char)c;
|
||||||
|
if (uc > 127) return;
|
||||||
|
|
||||||
|
if (g_clip_enabled && !g_render_target) {
|
||||||
|
if (x + 8 <= g_clip_x || x >= g_clip_x + g_clip_w ||
|
||||||
|
y + 8 <= g_clip_y || y >= g_clip_y + g_clip_h) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *glyph = font8x8_basic[uc];
|
||||||
|
for (int row = 0; row < 8; row++) {
|
||||||
|
for (int col = 0; col < 8; col++) {
|
||||||
|
if ((glyph[row] >> (7 - col)) & 1) {
|
||||||
|
put_pixel(x + col, y + row, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttf_font_t *graphics_get_current_ttf(void) {
|
||||||
|
return g_current_ttf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_string_bitmap(int x, int y, const char *str, uint32_t color) {
|
||||||
|
const char *s = str;
|
||||||
|
int cur_x = x;
|
||||||
|
int cur_y = y;
|
||||||
|
while (*s) {
|
||||||
|
if (*s == '\n') {
|
||||||
|
cur_x = x;
|
||||||
|
cur_y += 10;
|
||||||
|
} else {
|
||||||
|
draw_char_bitmap(cur_x, cur_y, *s, color);
|
||||||
|
cur_x += 8;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int graphics_get_font_height(void) {
|
||||||
|
if (g_current_ttf) {
|
||||||
|
return (int)((g_current_ttf->ascent - g_current_ttf->descent) * g_current_ttf->scale);
|
||||||
|
}
|
||||||
|
return 10; // Fallback bitmap height
|
||||||
|
}
|
||||||
|
|
||||||
void draw_string(int x, int y, const char *s, uint32_t color) {
|
void draw_string(int x, int y, const char *s, uint32_t color) {
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
int cur_x = x;
|
int cur_x = x;
|
||||||
|
|
||||||
|
if (g_current_ttf) {
|
||||||
|
float scale = g_current_ttf->scale;
|
||||||
|
// Shift baseline up by roughly 2 pixels for better vertical centering in bars/inputs
|
||||||
|
int baseline = y + (int)(g_current_ttf->ascent * scale) - 2;
|
||||||
|
int line_height = (int)((g_current_ttf->ascent - g_current_ttf->descent + g_current_ttf->line_gap) * scale);
|
||||||
|
|
||||||
|
while (*s) {
|
||||||
|
if (*s == '\n') {
|
||||||
|
cur_x = x;
|
||||||
|
baseline += line_height;
|
||||||
|
} else {
|
||||||
|
font_manager_render_char(g_current_ttf, cur_x, baseline, *s, color, put_pixel);
|
||||||
|
// Advance by same rounded width that font_manager_get_string_width uses
|
||||||
|
char buf[2] = {*s, 0};
|
||||||
|
cur_x += font_manager_get_string_width(g_current_ttf, buf);
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int cur_y = y;
|
int cur_y = y;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
if (*s == '\n') {
|
if (*s == '\n') {
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,14 @@ typedef struct {
|
||||||
} DirtyRect;
|
} DirtyRect;
|
||||||
|
|
||||||
void graphics_init(struct limine_framebuffer *fb);
|
void graphics_init(struct limine_framebuffer *fb);
|
||||||
|
void graphics_init_fonts(void);
|
||||||
void put_pixel(int x, int y, uint32_t color);
|
void put_pixel(int x, int y, uint32_t color);
|
||||||
|
uint32_t graphics_get_pixel(int x, int y);
|
||||||
void draw_rect(int x, int y, int w, int h, uint32_t color);
|
void draw_rect(int x, int y, int w, int h, uint32_t color);
|
||||||
void draw_rounded_rect(int x, int y, int w, int h, int radius, uint32_t color);
|
void draw_rounded_rect(int x, int y, int w, int h, int radius, uint32_t color);
|
||||||
void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color);
|
void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color);
|
||||||
void draw_char(int x, int y, char c, uint32_t color);
|
void draw_char(int x, int y, char c, uint32_t color);
|
||||||
|
void draw_char_bitmap(int x, int y, char c, uint32_t color);
|
||||||
void draw_string(int x, int y, const char *s, uint32_t color);
|
void draw_string(int x, int y, const char *s, uint32_t color);
|
||||||
void draw_desktop_background(void);
|
void draw_desktop_background(void);
|
||||||
void graphics_set_bg_color(uint32_t color);
|
void graphics_set_bg_color(uint32_t color);
|
||||||
|
|
@ -49,4 +52,10 @@ void graphics_clear_back_buffer(uint32_t color);
|
||||||
void graphics_set_clipping(int x, int y, int w, int h);
|
void graphics_set_clipping(int x, int y, int w, int h);
|
||||||
void graphics_clear_clipping(void);
|
void graphics_clear_clipping(void);
|
||||||
|
|
||||||
|
// Font access (requires font_manager.h for ttf_font_t)
|
||||||
|
#include "font_manager.h"
|
||||||
|
ttf_font_t *graphics_get_current_ttf(void);
|
||||||
|
int graphics_get_font_height(void);
|
||||||
|
void graphics_set_font(const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#define GUI_CMD_GET_EVENT 5
|
#define GUI_CMD_GET_EVENT 5
|
||||||
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
|
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
|
||||||
#define GUI_CMD_DRAW_IMAGE 7
|
#define GUI_CMD_DRAW_IMAGE 7
|
||||||
|
#define GUI_CMD_GET_STRING_WIDTH 8
|
||||||
|
#define GUI_CMD_GET_FONT_HEIGHT 9
|
||||||
|
|
||||||
#define GUI_EVENT_NONE 0
|
#define GUI_EVENT_NONE 0
|
||||||
#define GUI_EVENT_PAINT 1
|
#define GUI_EVENT_PAINT 1
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ void kmain(void) {
|
||||||
fat32_mkdir("/Library");
|
fat32_mkdir("/Library");
|
||||||
fat32_mkdir("/Library/images");
|
fat32_mkdir("/Library/images");
|
||||||
fat32_mkdir("/Library/images/Wallpapers");
|
fat32_mkdir("/Library/images/Wallpapers");
|
||||||
|
fat32_mkdir("/Library/Fonts");
|
||||||
|
|
||||||
if (module_request.response == NULL) {
|
if (module_request.response == NULL) {
|
||||||
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");
|
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");
|
||||||
|
|
@ -165,25 +166,26 @@ void kmain(void) {
|
||||||
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
||||||
struct limine_file *mod = module_request.response->modules[i];
|
struct limine_file *mod = module_request.response->modules[i];
|
||||||
|
|
||||||
|
|
||||||
const char *clean_path = mod->path;
|
const char *clean_path = mod->path;
|
||||||
// Strip boot():/ or boot:/// prefixes common in different Limine versions
|
|
||||||
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
|
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
|
||||||
else if (fs_starts_with(clean_path, "boot:///")) clean_path += 8;
|
else if (fs_starts_with(clean_path, "boot:///")) clean_path += 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FAT32_FileHandle *fh = fat32_open(clean_path, "w");
|
FAT32_FileHandle *fh = fat32_open(clean_path, "w");
|
||||||
if (fh && fh->valid) {
|
if (fh && fh->valid) {
|
||||||
int written = fat32_write(fh, mod->address, mod->size);
|
fat32_write(fh, mod->address, mod->size);
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
} else {
|
}
|
||||||
serial_write("[DEBUG] ERROR: Failed to create file in RAMFS for module: ");
|
}
|
||||||
serial_write(clean_path);
|
}
|
||||||
|
|
||||||
|
// Initialize fonts now that FAT32 and modules are loaded
|
||||||
|
uint64_t current_rsp;
|
||||||
|
asm volatile("mov %%rsp, %0" : "=r"(current_rsp));
|
||||||
|
serial_write("[DEBUG] Stack Alignment: 0x");
|
||||||
|
serial_write_hex(current_rsp);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
}
|
|
||||||
}
|
graphics_init_fonts();
|
||||||
}
|
|
||||||
|
|
||||||
asm("cli");
|
asm("cli");
|
||||||
ps2_init();
|
ps2_init();
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,23 @@ void platform_init(void) {
|
||||||
kernel_phys_base = kernel_addr_request.response->physical_base;
|
kernel_phys_base = kernel_addr_request.response->physical_base;
|
||||||
kernel_virt_base = kernel_addr_request.response->virtual_base;
|
kernel_virt_base = kernel_addr_request.response->virtual_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable FPU and SSE
|
||||||
|
uint64_t cr0;
|
||||||
|
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||||
|
cr0 &= ~(1ULL << 2); // Clear EM (Emulation)
|
||||||
|
cr0 |= (1ULL << 1); // Set MP (Monitor Coprocessor)
|
||||||
|
cr0 |= (1ULL << 5); // Set NE (Numeric Error)
|
||||||
|
asm volatile("mov %0, %%cr0" : : "r"(cr0));
|
||||||
|
|
||||||
|
uint64_t cr4;
|
||||||
|
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||||
|
cr4 |= (1ULL << 9); // Set OSFXSR (FXSAVE/FXRSTOR support)
|
||||||
|
cr4 |= (1ULL << 10); // Set OSXMMEXCPT (SIMD exception support)
|
||||||
|
asm volatile("mov %0, %%cr4" : : "r"(cr4));
|
||||||
|
|
||||||
|
// Initialize FPU
|
||||||
|
asm volatile("fninit");
|
||||||
}
|
}
|
||||||
uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; }
|
uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; }
|
||||||
uint64_t v2p(uint64_t virt) {
|
uint64_t v2p(uint64_t virt) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ extern void cmd_write(const char *str);
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
#define MAX_PROCESSES 16
|
#define MAX_PROCESSES 16
|
||||||
static process_t processes[MAX_PROCESSES];
|
static process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
||||||
static int process_count = 0;
|
static int process_count = 0;
|
||||||
static process_t* current_process = NULL;
|
static process_t* current_process = NULL;
|
||||||
static uint32_t next_pid = 0;
|
static uint32_t next_pid = 0;
|
||||||
|
|
@ -31,6 +31,10 @@ void process_init(void) {
|
||||||
kernel_proc->pml4_phys = paging_get_pml4_phys();
|
kernel_proc->pml4_phys = paging_get_pml4_phys();
|
||||||
kernel_proc->kernel_stack = 0;
|
kernel_proc->kernel_stack = 0;
|
||||||
|
|
||||||
|
// Initialize FPU state for kernel
|
||||||
|
asm volatile("fxsave %0" : "=m"(kernel_proc->fpu_state));
|
||||||
|
kernel_proc->fpu_initialized = true;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
|
||||||
|
|
||||||
kernel_proc->next = kernel_proc; // Circular linked list
|
kernel_proc->next = kernel_proc; // Circular linked list
|
||||||
|
|
@ -102,6 +106,11 @@ void process_create(void* entry_point, bool is_user) {
|
||||||
new_proc->rsp = (uint64_t)stack_ptr;
|
new_proc->rsp = (uint64_t)stack_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize FPU state for new process
|
||||||
|
asm volatile("fninit");
|
||||||
|
asm volatile("fxsave %0" : "=m"(new_proc->fpu_state));
|
||||||
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
// Add to linked list
|
// Add to linked list
|
||||||
new_proc->next = current_process->next;
|
new_proc->next = current_process->next;
|
||||||
current_process->next = new_proc;
|
current_process->next = new_proc;
|
||||||
|
|
@ -260,6 +269,11 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
new_proc->user_stack_alloc = stack;
|
new_proc->user_stack_alloc = stack;
|
||||||
new_proc->rsp = (uint64_t)stack_ptr;
|
new_proc->rsp = (uint64_t)stack_ptr;
|
||||||
|
|
||||||
|
// Initialize FPU state for new process
|
||||||
|
asm volatile("fninit");
|
||||||
|
asm volatile("fxsave %0" : "=m"(new_proc->fpu_state));
|
||||||
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
// Slot is already counted in process_count if new, or reused.
|
// Slot is already counted in process_count if new, or reused.
|
||||||
|
|
||||||
// Add to linked list
|
// Add to linked list
|
||||||
|
|
@ -285,9 +299,19 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
// Save context
|
// Save context
|
||||||
current_process->rsp = current_rsp;
|
current_process->rsp = current_rsp;
|
||||||
|
|
||||||
|
// Save FPU state
|
||||||
|
if (current_process->fpu_initialized) {
|
||||||
|
asm volatile("fxsave %0" : "=m"(current_process->fpu_state));
|
||||||
|
}
|
||||||
|
|
||||||
// Switch process
|
// Switch process
|
||||||
current_process = current_process->next;
|
current_process = current_process->next;
|
||||||
|
|
||||||
|
// Restore FPU state
|
||||||
|
if (current_process->fpu_initialized) {
|
||||||
|
asm volatile("fxrstor %0" : : "m"(current_process->fpu_state));
|
||||||
|
}
|
||||||
|
|
||||||
// Update Kernel Stack for User Mode interrupts and System Calls
|
// Update Kernel Stack for User Mode interrupts and System Calls
|
||||||
if (current_process->is_user && current_process->kernel_stack) {
|
if (current_process->is_user && current_process->kernel_stack) {
|
||||||
tss_set_stack(current_process->kernel_stack);
|
tss_set_stack(current_process->kernel_stack);
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,13 @@ typedef struct process {
|
||||||
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
|
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
|
||||||
void *user_stack_alloc; // Original pointer from kmalloc for freeing
|
void *user_stack_alloc; // Original pointer from kmalloc for freeing
|
||||||
|
|
||||||
bool is_terminal_proc; // Was this process started from the shell?
|
bool is_terminal_proc;
|
||||||
|
|
||||||
struct process *next;
|
struct process *next;
|
||||||
} process_t;
|
|
||||||
|
uint8_t fpu_state[512] __attribute__((aligned(16)));
|
||||||
|
bool fpu_initialized;
|
||||||
|
} __attribute__((aligned(16))) process_t;
|
||||||
|
|
||||||
void process_init(void);
|
void process_init(void);
|
||||||
void process_create(void* entry_point, bool is_user);
|
void process_create(void* entry_point, bool is_user);
|
||||||
|
|
|
||||||
5079
src/kernel/stb_truetype.h
Normal file
5079
src/kernel/stb_truetype.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -16,6 +16,8 @@
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "icmp.h"
|
#include "icmp.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
#include "font_manager.h"
|
||||||
|
#include "graphics.h"
|
||||||
|
|
||||||
// Read MSR
|
// Read MSR
|
||||||
static inline uint64_t rdmsr(uint32_t msr) {
|
static inline uint64_t rdmsr(uint32_t msr) {
|
||||||
|
|
@ -348,6 +350,41 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
|
||||||
draw_string(win->x + ux, win->y + uy, kernel_str, color);
|
draw_string(win->x + ux, win->y + uy, kernel_str, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
}
|
||||||
|
} else if (cmd == 10) { // GUI_CMD_DRAW_STRING_BITMAP
|
||||||
|
Window *win = (Window *)arg2;
|
||||||
|
uint64_t coords = arg3;
|
||||||
|
int ux = coords & 0xFFFFFFFF;
|
||||||
|
int uy = coords >> 32;
|
||||||
|
const char *user_str = (const char *)arg4;
|
||||||
|
uint32_t color = (uint32_t)arg5;
|
||||||
|
if (win && user_str) {
|
||||||
|
extern void draw_string_bitmap(int x, int y, const char *str, uint32_t color);
|
||||||
|
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||||
|
|
||||||
|
// Copy string safely to kernel stack buffer
|
||||||
|
char kernel_str[256];
|
||||||
|
int i = 0;
|
||||||
|
while (i < 255 && user_str[i]) {
|
||||||
|
kernel_str[i] = user_str[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
|
if (win->pixels) {
|
||||||
|
if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) {
|
||||||
|
graphics_set_render_target(win->pixels, win->w, win->h - 20);
|
||||||
|
draw_string_bitmap(ux, uy, kernel_str, color);
|
||||||
|
graphics_set_render_target(NULL, 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
draw_string_bitmap(win->x + ux, win->y + uy, kernel_str, color);
|
||||||
|
}
|
||||||
|
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
} else if (cmd == GUI_CMD_DRAW_IMAGE) {
|
} else if (cmd == GUI_CMD_DRAW_IMAGE) {
|
||||||
|
|
@ -409,6 +446,27 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (cmd == GUI_CMD_GET_STRING_WIDTH) {
|
||||||
|
const char *user_str = (const char *)arg2;
|
||||||
|
if (!user_str) return 0;
|
||||||
|
|
||||||
|
char kernel_str[256];
|
||||||
|
int i = 0;
|
||||||
|
while (i < 255 && user_str[i]) {
|
||||||
|
kernel_str[i] = user_str[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
|
ttf_font_t *font = graphics_get_current_ttf();
|
||||||
|
if (font) {
|
||||||
|
return (uint64_t)font_manager_get_string_width(font, kernel_str);
|
||||||
|
} else {
|
||||||
|
return (uint64_t)i * 8; // Fallback bitmap width
|
||||||
|
}
|
||||||
|
} else if (cmd == GUI_CMD_GET_FONT_HEIGHT) {
|
||||||
|
extern int graphics_get_font_height(void);
|
||||||
|
return (uint64_t)graphics_get_font_height();
|
||||||
}
|
}
|
||||||
} else if (syscall_num == SYS_FS) {
|
} else if (syscall_num == SYS_FS) {
|
||||||
int cmd = (int)arg1;
|
int cmd = (int)arg1;
|
||||||
|
|
@ -548,14 +606,12 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
|
||||||
} else if (cmd == 2) { // SYSTEM_CMD_SET_BG_PATTERN
|
} else if (cmd == 2) { // SYSTEM_CMD_SET_BG_PATTERN
|
||||||
uint32_t *user_pat = (uint32_t *)arg2;
|
uint32_t *user_pat = (uint32_t *)arg2;
|
||||||
if (!user_pat) {
|
if (!user_pat) {
|
||||||
extern void graphics_set_bg_pattern(uint32_t *pattern);
|
|
||||||
graphics_set_bg_pattern(NULL);
|
graphics_set_bg_pattern(NULL);
|
||||||
} else {
|
} else {
|
||||||
static uint32_t global_bg_pattern[128*128];
|
static uint32_t global_bg_pattern[128*128];
|
||||||
for (int i=0; i<128*128; i++) {
|
for (int i=0; i<128*128; i++) {
|
||||||
global_bg_pattern[i] = user_pat[i];
|
global_bg_pattern[i] = user_pat[i];
|
||||||
}
|
}
|
||||||
extern void graphics_set_bg_pattern(uint32_t *pattern);
|
|
||||||
graphics_set_bg_pattern(global_bg_pattern);
|
graphics_set_bg_pattern(global_bg_pattern);
|
||||||
}
|
}
|
||||||
extern void wm_refresh(void);
|
extern void wm_refresh(void);
|
||||||
|
|
@ -778,6 +834,18 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
|
||||||
extern void network_force_unlock(void);
|
extern void network_force_unlock(void);
|
||||||
network_force_unlock();
|
network_force_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (cmd == 40) { // SYSTEM_CMD_SET_FONT
|
||||||
|
const char *user_path = (const char *)arg2;
|
||||||
|
if (!user_path) return -1;
|
||||||
|
// Copy font path from userland
|
||||||
|
char path[128];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 127 && user_path[i]; i++) {
|
||||||
|
path[i] = user_path[i];
|
||||||
|
}
|
||||||
|
path[i] = 0;
|
||||||
|
graphics_set_font(path);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ static void draw_ansi_string(ui_window_t win, int x, int y, const char *str) {
|
||||||
if (*str == '\033' && *(str + 1) == '[') {
|
if (*str == '\033' && *(str + 1) == '[') {
|
||||||
if (seg_idx > 0) {
|
if (seg_idx > 0) {
|
||||||
segment[seg_idx] = 0;
|
segment[seg_idx] = 0;
|
||||||
ui_draw_string(win, current_x, y, segment, current_color);
|
ui_draw_string_bitmap(win, current_x, y, segment, current_color);
|
||||||
current_x += seg_idx * 8;
|
current_x += seg_idx * 8; // Bitmap font is exactly 8px wide
|
||||||
seg_idx = 0;
|
seg_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ static void draw_ansi_string(ui_window_t win, int x, int y, const char *str) {
|
||||||
|
|
||||||
if (seg_idx > 0) {
|
if (seg_idx > 0) {
|
||||||
segment[seg_idx] = 0;
|
segment[seg_idx] = 0;
|
||||||
ui_draw_string(win, current_x, y, segment, current_color);
|
ui_draw_string_bitmap(win, current_x, y, segment, current_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ static void draw_ascii_logo(ui_window_t win, int x, int y) {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; logo[i] != NULL; i++) {
|
for (int i = 0; logo[i] != NULL; i++) {
|
||||||
draw_ansi_string(win, x, y + (i * 10), logo[i]);
|
draw_ansi_string(win, x, y + (i * 10), logo[i]); // Bitmap line height is 10px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,20 +86,22 @@ static void about_paint(ui_window_t win) {
|
||||||
int w = 340;
|
int w = 340;
|
||||||
int h = 240;
|
int h = 240;
|
||||||
|
|
||||||
|
// Clear background to prevent alpha-blended text from accumulating on repaints
|
||||||
|
ui_draw_rect(win, 0, 0, w, h, 0xFF1E1E1E);
|
||||||
|
|
||||||
int offset_x = 15;
|
int offset_x = 15;
|
||||||
int offset_y = 35;
|
int offset_y = 35;
|
||||||
|
|
||||||
draw_ascii_logo(win, 14, offset_y);
|
draw_ascii_logo(win, 14, offset_y);
|
||||||
|
|
||||||
// Version info
|
int fh = ui_get_font_height();
|
||||||
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Retrowave'", 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Retrowave'", 0xFFFFFFFF);
|
||||||
ui_draw_string(win, offset_x, offset_y + 120, "BoredOS Version 1.65", 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105 + fh, "BoredOS Version 1.65", 0xFFFFFFFF);
|
||||||
ui_draw_string(win, offset_x, offset_y + 135, "Kernel Version 3.0.1", 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105 + fh*2, "Kernel Version 3.0.1", 0xFFFFFFFF);
|
||||||
|
|
||||||
// Copyright
|
// Copyright
|
||||||
ui_draw_string(win, offset_x, offset_y + 150, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105 + fh*3, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
|
||||||
ui_draw_string(win, offset_x, offset_y + 165, "All rights reserved.", 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105 + fh*4, "All rights reserved.", 0xFFFFFFFF);
|
||||||
|
|
||||||
ui_mark_dirty(win, 0, 0, w, h);
|
ui_mark_dirty(win, 0, 0, w, h);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -452,7 +452,7 @@ static void parse_html(const char *html) {
|
||||||
while(ph[l] && ph[l] != '\"' && l < 255) { el->attr_value[l] = ph[l]; l++; }
|
while(ph[l] && ph[l] != '\"' && l < 255) { el->attr_value[l] = ph[l]; l++; }
|
||||||
el->attr_value[l] = 0;
|
el->attr_value[l] = 0;
|
||||||
} else el->attr_value[0] = 0;
|
} else el->attr_value[0] = 0;
|
||||||
if (el->tag == TAG_BUTTON) el->w = (int)strlen(el->attr_value) * 8 + 20;
|
if (el->tag == TAG_BUTTON) el->w = ui_get_string_width(el->attr_value) + 20;
|
||||||
line_elements[line_element_count++] = element_count - 1;
|
line_elements[line_element_count++] = element_count - 1;
|
||||||
if (is_centered || cur_line_x + el->w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered);
|
if (is_centered || cur_line_x + el->w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered);
|
||||||
else cur_line_x += el->w;
|
else cur_line_x += el->w;
|
||||||
|
|
@ -471,14 +471,14 @@ static void parse_html(const char *html) {
|
||||||
word[w_idx] = 0;
|
word[w_idx] = 0;
|
||||||
if (w_idx > 0) {
|
if (w_idx > 0) {
|
||||||
if (element_count >= MAX_ELEMENTS) break;
|
if (element_count >= MAX_ELEMENTS) break;
|
||||||
int word_w = w_idx * 8;
|
int word_w = ui_get_string_width(word);
|
||||||
if (cur_line_x + word_w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered);
|
if (cur_line_x + word_w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered);
|
||||||
|
|
||||||
RenderElement *el = &elements[element_count++];
|
RenderElement *el = &elements[element_count++];
|
||||||
for (int k=0; k<(int)sizeof(RenderElement); k++) ((char*)el)[k] = 0;
|
for (int k=0; k<(int)sizeof(RenderElement); k++) ((char*)el)[k] = 0;
|
||||||
int k=0; while(word[k]) { el->content[k] = word[k]; k++; }
|
int k=0; while(word[k]) { el->content[k] = word[k]; k++; }
|
||||||
el->content[k++] = ' '; el->content[k] = 0;
|
el->content[k++] = ' '; el->content[k] = 0;
|
||||||
el->w = (w_idx + 1) * 8; el->h = 16;
|
el->w = ui_get_string_width(el->content); el->h = 16;
|
||||||
el->tag = TAG_NONE; el->color = current_link[0] ? COLOR_LINK : current_color;
|
el->tag = TAG_NONE; el->color = current_link[0] ? COLOR_LINK : current_color;
|
||||||
el->centered = is_centered; el->bold = is_bold;
|
el->centered = is_centered; el->bold = is_bold;
|
||||||
if (current_link[0]) { int k=0; while(current_link[k]) { el->link_url[k] = current_link[k]; k++; } el->link_url[k] = 0; }
|
if (current_link[0]) { int k=0; while(current_link[k]) { el->link_url[k] = current_link[k]; k++; } el->link_url[k] = 0; }
|
||||||
|
|
@ -526,7 +526,12 @@ static void browser_paint(void) {
|
||||||
if (focused_element == i) {
|
if (focused_element == i) {
|
||||||
int cursor_pos = el->input_cursor - el->input_scroll;
|
int cursor_pos = el->input_cursor - el->input_scroll;
|
||||||
if (cursor_pos >= 0 && cursor_pos < max_v) {
|
if (cursor_pos >= 0 && cursor_pos < max_v) {
|
||||||
ui_draw_rect(win_browser, el->x + 5 + cursor_pos * 8, draw_y + 16, 8, 2, 0xFF000000);
|
char sub[64];
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < cursor_pos && visible[k]; k++) sub[k] = visible[k];
|
||||||
|
sub[k] = 0;
|
||||||
|
int cx = ui_get_string_width(sub);
|
||||||
|
ui_draw_rect(win_browser, el->x + 5 + cx, draw_y + 16, 8, 2, 0xFF000000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (el->tag == TAG_BUTTON) {
|
} else if (el->tag == TAG_BUTTON) {
|
||||||
|
|
@ -545,7 +550,12 @@ static void browser_paint(void) {
|
||||||
ui_draw_rect(win_browser, 0, 0, WIN_W, URL_BAR_H, COLOR_URL_BAR);
|
ui_draw_rect(win_browser, 0, 0, WIN_W, URL_BAR_H, COLOR_URL_BAR);
|
||||||
ui_draw_string(win_browser, 10, 8, url_input_buffer, COLOR_URL_TEXT);
|
ui_draw_string(win_browser, 10, 8, url_input_buffer, COLOR_URL_TEXT);
|
||||||
if (focused_element == -1) {
|
if (focused_element == -1) {
|
||||||
ui_draw_rect(win_browser, 10 + url_cursor * 8, 22, 8, 2, COLOR_URL_TEXT);
|
char sub[512];
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < url_cursor && url_input_buffer[k]; k++) sub[k] = url_input_buffer[k];
|
||||||
|
sub[k] = 0;
|
||||||
|
int cx = ui_get_string_width(sub);
|
||||||
|
ui_draw_rect(win_browser, 10 + cx, 22, 8, 2, COLOR_URL_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll bar
|
// Scroll bar
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,11 @@ void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t col
|
||||||
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING, (uint64_t)win, coords, (uint64_t)str, (uint64_t)color);
|
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING, (uint64_t)win, coords, (uint64_t)str, (uint64_t)color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color) {
|
||||||
|
uint64_t coords = ((uint64_t)x & 0xFFFFFFFF) | ((uint64_t)y << 32);
|
||||||
|
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING_BITMAP, (uint64_t)win, coords, (uint64_t)str, (uint64_t)color);
|
||||||
|
}
|
||||||
|
|
||||||
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h) {
|
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h) {
|
||||||
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
|
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
|
||||||
syscall3(SYS_GUI, GUI_CMD_MARK_DIRTY, (uint64_t)win, (uint64_t)params);
|
syscall3(SYS_GUI, GUI_CMD_MARK_DIRTY, (uint64_t)win, (uint64_t)params);
|
||||||
|
|
@ -44,3 +49,11 @@ void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_
|
||||||
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
|
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
|
||||||
syscall4(SYS_GUI, GUI_CMD_DRAW_IMAGE, (uint64_t)win, (uint64_t)params, (uint64_t)image_data);
|
syscall4(SYS_GUI, GUI_CMD_DRAW_IMAGE, (uint64_t)win, (uint64_t)params, (uint64_t)image_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ui_get_string_width(const char *str) {
|
||||||
|
return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_STRING_WIDTH, (uint64_t)str, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ui_get_font_height(void) {
|
||||||
|
return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_FONT_HEIGHT, 0, 0);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
#define GUI_CMD_GET_EVENT 5
|
#define GUI_CMD_GET_EVENT 5
|
||||||
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
|
#define GUI_CMD_DRAW_ROUNDED_RECT_FILLED 6
|
||||||
#define GUI_CMD_DRAW_IMAGE 7
|
#define GUI_CMD_DRAW_IMAGE 7
|
||||||
|
#define GUI_CMD_GET_STRING_WIDTH 8
|
||||||
|
#define GUI_CMD_GET_FONT_HEIGHT 9
|
||||||
|
#define GUI_CMD_DRAW_STRING_BITMAP 10
|
||||||
|
|
||||||
// Event Types
|
// Event Types
|
||||||
#define GUI_EVENT_NONE 0
|
#define GUI_EVENT_NONE 0
|
||||||
|
|
@ -45,5 +48,8 @@ void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, in
|
||||||
void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color);
|
void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color);
|
||||||
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);
|
void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);
|
||||||
void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data);
|
void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data);
|
||||||
|
uint32_t ui_get_string_width(const char *str);
|
||||||
|
uint32_t ui_get_font_height(void);
|
||||||
|
void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ static int cursor_pos = 0;
|
||||||
static int notepad_scroll_line = 0;
|
static int notepad_scroll_line = 0;
|
||||||
|
|
||||||
static void notepad_ensure_cursor_visible(int h) {
|
static void notepad_ensure_cursor_visible(int h) {
|
||||||
int visible_lines = (h - 10) / 10;
|
int fh = (int)ui_get_font_height();
|
||||||
|
if (fh < 8) fh = 8;
|
||||||
|
int visible_lines = (h - 10) / fh;
|
||||||
if (visible_lines < 1) visible_lines = 1;
|
if (visible_lines < 1) visible_lines = 1;
|
||||||
|
|
||||||
int cursor_line = 0;
|
int cursor_line = 0;
|
||||||
|
|
@ -58,6 +60,9 @@ static void notepad_save_state() {
|
||||||
static void notepad_paint(ui_window_t win, int w, int h) {
|
static void notepad_paint(ui_window_t win, int w, int h) {
|
||||||
ui_draw_rect(win, 0, 0, w, h, COLOR_NOTEPAD_BG);
|
ui_draw_rect(win, 0, 0, w, h, COLOR_NOTEPAD_BG);
|
||||||
|
|
||||||
|
int fh = (int)ui_get_font_height();
|
||||||
|
if (fh < 8) fh = 8;
|
||||||
|
|
||||||
int visual_line = 0;
|
int visual_line = 0;
|
||||||
int current_x = 4;
|
int current_x = 4;
|
||||||
int current_y = 4;
|
int current_y = 4;
|
||||||
|
|
@ -70,38 +75,43 @@ static void notepad_paint(ui_window_t win, int w, int h) {
|
||||||
current_x = 4;
|
current_x = 4;
|
||||||
current_y = 4;
|
current_y = 4;
|
||||||
} else {
|
} else {
|
||||||
if (current_x >= window_right) {
|
char ch[2] = {buffer[i], 0};
|
||||||
|
int cw = (int)ui_get_string_width(ch);
|
||||||
|
if (cw < 1) cw = 8;
|
||||||
|
if (current_x + cw >= window_right) {
|
||||||
visual_line++;
|
visual_line++;
|
||||||
current_x = 4;
|
current_x = 4;
|
||||||
current_y += 10;
|
current_y += fh;
|
||||||
}
|
}
|
||||||
current_x += 8;
|
current_x += cw;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visual_line >= notepad_scroll_line + (h - 8) / 10) {
|
if (visual_line >= notepad_scroll_line + (h - 8) / fh) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
current_x = 4;
|
current_x = 4;
|
||||||
current_y += 10;
|
current_y += fh;
|
||||||
visual_line++;
|
visual_line++;
|
||||||
} else {
|
} else {
|
||||||
if (current_x >= window_right) {
|
char ch[2] = {buffer[i], 0};
|
||||||
|
int cw = (int)ui_get_string_width(ch);
|
||||||
|
if (cw < 1) cw = 8;
|
||||||
|
if (current_x + cw >= window_right) {
|
||||||
current_x = 4;
|
current_x = 4;
|
||||||
current_y += 10;
|
current_y += fh;
|
||||||
visual_line++;
|
visual_line++;
|
||||||
|
|
||||||
if (visual_line >= notepad_scroll_line + (h - 8) / 10) {
|
if (visual_line >= notepad_scroll_line + (h - 8) / fh) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char ch[2] = {buffer[i], 0};
|
|
||||||
ui_draw_string(win, current_x, current_y, ch, COLOR_BLACK);
|
ui_draw_string(win, current_x, current_y, ch, COLOR_BLACK);
|
||||||
current_x += 8;
|
current_x += cw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,21 +123,24 @@ static void notepad_paint(ui_window_t win, int w, int h) {
|
||||||
for (int i = 0; i < cursor_pos; i++) {
|
for (int i = 0; i < cursor_pos; i++) {
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
cx = 4;
|
cx = 4;
|
||||||
cy += 10;
|
cy += fh;
|
||||||
c_visual_line++;
|
c_visual_line++;
|
||||||
} else {
|
} else {
|
||||||
if (cx >= window_right) {
|
char ch[2] = {buffer[i], 0};
|
||||||
|
int cw = (int)ui_get_string_width(ch);
|
||||||
|
if (cw < 1) cw = 8;
|
||||||
|
if (cx + cw >= window_right) {
|
||||||
cx = 4;
|
cx = 4;
|
||||||
cy += 10;
|
cy += fh;
|
||||||
c_visual_line++;
|
c_visual_line++;
|
||||||
}
|
}
|
||||||
cx += 8;
|
cx += cw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c_visual_line >= notepad_scroll_line &&
|
if (c_visual_line >= notepad_scroll_line &&
|
||||||
c_visual_line < notepad_scroll_line + (h - 8) / 10) {
|
c_visual_line < notepad_scroll_line + (h - 8) / fh) {
|
||||||
ui_draw_rect(win, cx, cy, 2, 8, COLOR_BLACK);
|
ui_draw_rect(win, cx, cy, 2, fh - 2, COLOR_BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_mark_dirty(win, 0, 0, w, h);
|
ui_mark_dirty(win, 0, 0, w, h);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#define VIEW_NETWORK 2
|
#define VIEW_NETWORK 2
|
||||||
#define VIEW_DESKTOP 3
|
#define VIEW_DESKTOP 3
|
||||||
#define VIEW_MOUSE 4
|
#define VIEW_MOUSE 4
|
||||||
|
#define VIEW_FONTS 5
|
||||||
|
|
||||||
static int current_view = VIEW_MAIN;
|
static int current_view = VIEW_MAIN;
|
||||||
static char rgb_r[4] = "";
|
static char rgb_r[4] = "";
|
||||||
|
|
@ -63,6 +64,16 @@ static int desktop_max_rows_per_col = 10;
|
||||||
static int desktop_max_cols = 10;
|
static int desktop_max_cols = 10;
|
||||||
static int mouse_speed = 10;
|
static int mouse_speed = 10;
|
||||||
|
|
||||||
|
// Font selection
|
||||||
|
#define MAX_FONTS 16
|
||||||
|
typedef struct {
|
||||||
|
char path[128];
|
||||||
|
char name[48];
|
||||||
|
} font_entry_t;
|
||||||
|
static font_entry_t fonts[MAX_FONTS];
|
||||||
|
static int font_count = 0;
|
||||||
|
static int selected_font = -1;
|
||||||
|
|
||||||
static void cli_itoa(int num, char *str) {
|
static void cli_itoa(int num, char *str) {
|
||||||
if (num == 0) {
|
if (num == 0) {
|
||||||
str[0] = '0';
|
str[0] = '0';
|
||||||
|
|
@ -224,6 +235,14 @@ static void control_panel_paint_main(ui_window_t win) {
|
||||||
ui_draw_rect(win, offset_x + 20, offset_y + item_y + 10, 16, 10, 0xFFB0B0B0);
|
ui_draw_rect(win, offset_x + 20, offset_y + item_y + 10, 16, 10, 0xFFB0B0B0);
|
||||||
ui_draw_string(win, offset_x + 60, offset_y + item_y + 15, "Mouse", COLOR_DARK_TEXT);
|
ui_draw_string(win, offset_x + 60, offset_y + item_y + 15, "Mouse", COLOR_DARK_TEXT);
|
||||||
ui_draw_string(win, offset_x + 60, offset_y + item_y + 35, "Pointer settings", COLOR_DKGRAY);
|
ui_draw_string(win, offset_x + 60, offset_y + item_y + 35, "Pointer settings", COLOR_DKGRAY);
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
item_y += item_h + item_spacing;
|
||||||
|
ui_draw_rounded_rect_filled(win, offset_x, offset_y + item_y, win_w - 16, item_h, 8, COLOR_DARK_PANEL);
|
||||||
|
// Font icon: "Aa" stylized
|
||||||
|
ui_draw_string(win, offset_x + 14, offset_y + item_y + 10, "Aa", 0xFF6A9EF5);
|
||||||
|
ui_draw_string(win, offset_x + 60, offset_y + item_y + 15, "Fonts", COLOR_DARK_TEXT);
|
||||||
|
ui_draw_string(win, offset_x + 60, offset_y + item_y + 35, "Choose system font", COLOR_DKGRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void control_panel_paint_wallpaper(ui_window_t win) {
|
static void control_panel_paint_wallpaper(ui_window_t win) {
|
||||||
|
|
@ -429,6 +448,60 @@ static void control_panel_paint_mouse(ui_window_t win) {
|
||||||
ui_draw_string(win, offset_x + 280, section_y + 4, speed_str, COLOR_DARK_TEXT);
|
ui_draw_string(win, offset_x + 280, section_y + 4, speed_str, COLOR_DARK_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void load_fonts(void) {
|
||||||
|
font_count = 0;
|
||||||
|
FAT32_FileInfo info[MAX_FONTS];
|
||||||
|
int count = sys_list("/Library/Fonts", info, MAX_FONTS);
|
||||||
|
if (count < 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < count && font_count < MAX_FONTS; i++) {
|
||||||
|
if (info[i].is_directory) continue;
|
||||||
|
// check if .ttf (case-insensitive)
|
||||||
|
int len = 0; while (info[i].name[len]) len++;
|
||||||
|
if (len < 4) continue;
|
||||||
|
char c1 = info[i].name[len-1]; if (c1 >= 'A' && c1 <= 'Z') c1 += 32;
|
||||||
|
char c2 = info[i].name[len-2]; if (c2 >= 'A' && c2 <= 'Z') c2 += 32;
|
||||||
|
char c3 = info[i].name[len-3]; if (c3 >= 'A' && c3 <= 'Z') c3 += 32;
|
||||||
|
char c4 = info[i].name[len-4]; if (c4 >= 'A' && c4 <= 'Z') c4 += 32;
|
||||||
|
if (c4 != '.' || c3 != 't' || c2 != 't' || c1 != 'f') continue;
|
||||||
|
|
||||||
|
font_entry_t *fe = &fonts[font_count];
|
||||||
|
// Build full path
|
||||||
|
char *pref = "/Library/Fonts/";
|
||||||
|
int pl = 0; while (pref[pl]) { fe->path[pl] = pref[pl]; pl++; }
|
||||||
|
int nl = 0; while (info[i].name[nl]) { fe->path[pl+nl] = info[i].name[nl]; nl++; }
|
||||||
|
fe->path[pl+nl] = 0;
|
||||||
|
// Store display name (strip .ttf)
|
||||||
|
for (int j = 0; j < nl - 4 && j < 47; j++) fe->name[j] = info[i].name[j];
|
||||||
|
fe->name[(nl-4 < 47) ? nl-4 : 47] = 0;
|
||||||
|
font_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void control_panel_paint_fonts(ui_window_t win) {
|
||||||
|
int offset_x = 8;
|
||||||
|
int offset_y = 6;
|
||||||
|
|
||||||
|
ui_draw_rounded_rect_filled(win, offset_x, offset_y + 5, 80, 25, 6, COLOR_DARK_PANEL);
|
||||||
|
ui_draw_string(win, offset_x + 10, offset_y + 13, "< Back", COLOR_DARK_TEXT);
|
||||||
|
|
||||||
|
ui_draw_string(win, offset_x, offset_y + 40, "System Font:", COLOR_DARK_TEXT);
|
||||||
|
|
||||||
|
int item_y = offset_y + 60;
|
||||||
|
for (int i = 0; i < font_count; i++) {
|
||||||
|
uint32_t bg_color = (i == selected_font) ? 0xFF3D5A80 : COLOR_DARK_PANEL;
|
||||||
|
ui_draw_rounded_rect_filled(win, offset_x, item_y, 330, 35, 6, bg_color);
|
||||||
|
// Font icon
|
||||||
|
ui_draw_string(win, offset_x + 10, item_y + 9, "Aa", 0xFF6A9EF5);
|
||||||
|
// Font name
|
||||||
|
ui_draw_string(win, offset_x + 40, item_y + 9, fonts[i].name, COLOR_DARK_TEXT);
|
||||||
|
if (i == selected_font) {
|
||||||
|
ui_draw_string(win, offset_x + 290, item_y + 9, "*", 0xFF90EE90);
|
||||||
|
}
|
||||||
|
item_y += 40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void control_panel_paint(ui_window_t win) {
|
static void control_panel_paint(ui_window_t win) {
|
||||||
// Fill background
|
// Fill background
|
||||||
ui_draw_rect(win, 0, 0, 350, 500, COLOR_DARK_BG);
|
ui_draw_rect(win, 0, 0, 350, 500, COLOR_DARK_BG);
|
||||||
|
|
@ -443,6 +516,8 @@ static void control_panel_paint(ui_window_t win) {
|
||||||
control_panel_paint_desktop(win);
|
control_panel_paint_desktop(win);
|
||||||
} else if (current_view == VIEW_MOUSE) {
|
} else if (current_view == VIEW_MOUSE) {
|
||||||
control_panel_paint_mouse(win);
|
control_panel_paint_mouse(win);
|
||||||
|
} else if (current_view == VIEW_FONTS) {
|
||||||
|
control_panel_paint_fonts(win);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -494,6 +569,11 @@ static void control_panel_handle_click(int x, int y) {
|
||||||
if (x >= offset_x && x < win_w - 8 && y >= item_y && y < item_y + item_h) {
|
if (x >= offset_x && x < win_w - 8 && y >= item_y && y < item_y + item_h) {
|
||||||
current_view = VIEW_MOUSE;
|
current_view = VIEW_MOUSE;
|
||||||
}
|
}
|
||||||
|
item_y += item_h + item_spacing;
|
||||||
|
if (x >= offset_x && x < win_w - 8 && y >= item_y && y < item_y + item_h) {
|
||||||
|
current_view = VIEW_FONTS;
|
||||||
|
if (font_count == 0) load_fonts();
|
||||||
|
}
|
||||||
} else if (current_view == VIEW_WALLPAPER) {
|
} else if (current_view == VIEW_WALLPAPER) {
|
||||||
int offset_x = 8;
|
int offset_x = 8;
|
||||||
int offset_y = 6;
|
int offset_y = 6;
|
||||||
|
|
@ -657,6 +737,26 @@ static void control_panel_handle_click(int x, int y) {
|
||||||
save_mouse_config();
|
save_mouse_config();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (current_view == VIEW_FONTS) {
|
||||||
|
int offset_x = 8;
|
||||||
|
int offset_y = 6;
|
||||||
|
|
||||||
|
// Back button
|
||||||
|
if (x >= offset_x && x < offset_x + 80 && y >= offset_y + 5 && y < offset_y + 30) {
|
||||||
|
current_view = VIEW_MAIN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Font items
|
||||||
|
int item_y = offset_y + 60;
|
||||||
|
for (int i = 0; i < font_count; i++) {
|
||||||
|
if (x >= offset_x && x < offset_x + 330 && y >= item_y && y < item_y + 35) {
|
||||||
|
selected_font = i;
|
||||||
|
sys_system(40 /*SET_FONT*/, (uint64_t)fonts[i].path, 0, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item_y += 40;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1046,7 +1046,7 @@ void draw_window(Window *win) {
|
||||||
// Title Bar (rounded at top only - overdraw bottom to hide rounding)
|
// Title Bar (rounded at top only - overdraw bottom to hide rounding)
|
||||||
draw_rounded_rect_filled(win->x, win->y, win->w, 20, 8, COLOR_DARK_TITLEBAR);
|
draw_rounded_rect_filled(win->x, win->y, win->w, 20, 8, COLOR_DARK_TITLEBAR);
|
||||||
draw_rect(win->x, win->y + 12, win->w, 8, COLOR_DARK_TITLEBAR); // Cover bottom rounded corners
|
draw_rect(win->x, win->y + 12, win->w, 8, COLOR_DARK_TITLEBAR); // Cover bottom rounded corners
|
||||||
draw_string(win->x + 28, win->y + 5, win->title, COLOR_DARK_TEXT);
|
draw_string(win->x + 28, win->y + 4, win->title, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
// Traffic Light (close button - red)
|
// Traffic Light (close button - red)
|
||||||
draw_traffic_light(win->x + 8, win->y + 2);
|
draw_traffic_light(win->x + 8, win->y + 2);
|
||||||
|
|
@ -1061,6 +1061,23 @@ void draw_window(Window *win) {
|
||||||
graphics_blit_buffer(win->pixels, win->x, win->y + 20, win->w, win->h - 20);
|
graphics_blit_buffer(win->pixels, win->x, win->y + 20, win->w, win->h - 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mask bottom corners: clear pixels outside the rounded boundary
|
||||||
|
{
|
||||||
|
int radius = 8;
|
||||||
|
int bx = win->x;
|
||||||
|
int by = win->y + win->h - radius;
|
||||||
|
for (int dy = 0; dy < radius; dy++) {
|
||||||
|
int dx = isqrt(radius*radius - dy*dy);
|
||||||
|
int fill_w = radius - dx;
|
||||||
|
if (fill_w > 0) {
|
||||||
|
// Bottom-left corner
|
||||||
|
draw_rect(bx, by + dy, fill_w, 1, 0xFF000000);
|
||||||
|
// Bottom-right corner
|
||||||
|
draw_rect(bx + win->w - fill_w, by + dy, fill_w, 1, 0xFF000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (win->paint) {
|
if (win->paint) {
|
||||||
win->paint(win);
|
win->paint(win);
|
||||||
}
|
}
|
||||||
|
|
@ -1332,7 +1349,12 @@ void wm_paint(void) {
|
||||||
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, desktop_dialog_input, COLOR_WHITE);
|
draw_string(dlg_x + 15, dlg_y + 40, desktop_dialog_input, COLOR_WHITE);
|
||||||
// Cursor
|
// Cursor
|
||||||
draw_rect(dlg_x + 15 + desktop_dialog_cursor * 8, dlg_y + 39, 2, 12, COLOR_WHITE);
|
char sub[64];
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < desktop_dialog_cursor && desktop_dialog_input[k]; k++) sub[k] = desktop_dialog_input[k];
|
||||||
|
sub[k] = 0;
|
||||||
|
int cx = font_manager_get_string_width(graphics_get_current_ttf(), sub);
|
||||||
|
draw_rect(dlg_x + 15 + cx, dlg_y + 39, 2, 12, COLOR_WHITE);
|
||||||
|
|
||||||
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 4, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 4, COLOR_DARK_BORDER);
|
||||||
draw_string(dlg_x + 70, dlg_y + 72, btn_text, COLOR_WHITE);
|
draw_string(dlg_x + 70, dlg_y + 72, btn_text, COLOR_WHITE);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue