From 5c4a557755587b38bd7850e0586ce0c2eace2c93 Mon Sep 17 00:00:00 2001 From: Curle Date: Wed, 16 Jun 2021 21:06:49 +0100 Subject: [PATCH] Add startings of the Chroma Editor. --- CMakeLists.txt | 6 +- inc/editor/main.h | 119 ++++++++++++++++++ inc/kernel/video/draw.h | 16 ++- src/editor/EditorMain.c | 32 +++++ src/video/draw.c | 260 ++++++++++++++++++++++++++++++++++++++-- src/video/print.c | 8 -- 6 files changed, 420 insertions(+), 21 deletions(-) create mode 100644 inc/editor/main.h create mode 100644 src/editor/EditorMain.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f98735f..d8a0f47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ SET(src_files ${CMAKE_SOURCE_DIR}/src/system/memory/stack.c ${CMAKE_SOURCE_DIR}/src/system/memory/paging.c ${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.c + ${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.c ${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c ${CMAKE_SOURCE_DIR}/src/system/drivers/keyboard.c ${CMAKE_SOURCE_DIR}/src/system/drivers/elf.c @@ -32,6 +33,9 @@ SET(lib_files ${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.c ${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.c ${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c + ${CMAKE_SOURCE_DIR}/src/lainlib/string/str.c + + ${CMAKE_SOURCE_DIR}/src/editor/EditorMain.c ) include_directories("inc") @@ -44,7 +48,7 @@ SET(src_preamble ${CMAKE_SOURCE_DIR}/src/global/crt0.o ${CMAKE_SOURCE_DIR}/src/global/crti.o ${CMAKE_SOURCE_DIR}/src/global/crtbegin.o -) +) set(src_epilogue ${CMAKE_SOURCE_DIR}/src/global/crtend.o diff --git a/inc/editor/main.h b/inc/editor/main.h new file mode 100644 index 0000000..3eef68b --- /dev/null +++ b/inc/editor/main.h @@ -0,0 +1,119 @@ +#pragma once + +/************************ + *** Team Kitty, 2021 *** + *** Chroma *** + ***********************/ + +/** + * This file contains most of the symbols required to start and run the Chroma Editor. + * + * The Editor uses a six-stage drawing system: + * - Background + * - Bars + * - Text Area + * - Text + * - Effects + * + * The dimensions are derived dynamically from the Print Info settings. + * + * The layout is as such: + * - 3% horizontal header, #BBBBBB. + * - Primary text, #000084. + * - Secondary text, #000000. + * - 97% background, #000084. + * - 15% optional banner, #00AAAA. + * - 80% text area, #BBBBBB. + * - Menus #FFFFFF. + * - Buttons #BBBBBB. + * - Drop shadow #000000. + */ + +// Stores information about a single line. +struct EditorLine { + size_t Line; + size_t Length; + char* Text; +}; + +// Function pointer for menu-clicked callback. +typedef void (*MenuCallback)(void); + +// A single item in the menu. +struct MenuItem { + size_t ParentID; // 0 for the root menu. + size_t ID; + MenuCallback Callback; +}; + +// The full menu that should be rendered. Can be nested. +typedef struct { + size_t MenuSize; + struct MenuItem* Menu; + size_t ActiveMenuItem; +} EditorMenu; + +struct EditorMessage { + size_t TextLength; + char* Text; + + size_t MessageWidth; + size_t MessageHeight; +}; + +// Provides all the context for rendering the editor. +struct EditorLayout { + size_t ScreenWidth; + size_t ScreenHeight; + + size_t HeaderHeight; + + EditorMenu Menu; + + size_t TextBoxX; + size_t TextBoxY; + size_t TextBoxWidth; + size_t TextBoxHeight; + + bool HasMessage; + struct EditorMessage* CurrentMessage; +}; + +// Provides all the context for manipulating state. +typedef struct { + struct EditorLayout Layout; + + size_t Length; // How many lines? + size_t Size; // How many characters? + size_t CurrentLine; + size_t CurrentColumn; + struct EditorLine* Lines; +} EditorState; + + +// Given the kernel's keyboard handler ID, so that it may restore it at a later point. +void StartEditor(int KernelCallbackID); + +// =========================== Drawing routines =========================== // + +// Draw everything. +void DrawEditor(EditorState* currentState); + +void DrawHeader(); +void DrawBackground(); +void DrawTextArea(); +void DrawText(); +void DrawLine(); +void DrawMenus(); +void DrawBoxes(); +void DrawBoxShadows(); + +// =========================== State management =========================== +EditorState* GetState(); + +// Text editing. +void GetLine(EditorState* state, size_t line); +void SetLine(EditorState* state, struct EditorLine* line); +void AppendLine(EditorState* state, struct EditorLine* line); +void AppendToLine(EditorState* state, struct EditorLine* line, size_t textLength, char* text); +void RemoveLine(EditorState* state, size_t line); \ No newline at end of file diff --git a/inc/kernel/video/draw.h b/inc/kernel/video/draw.h index de83a7c..1919d74 100644 --- a/inc/kernel/video/draw.h +++ b/inc/kernel/video/draw.h @@ -12,6 +12,10 @@ * Set color with PrintInfo. */ +void _swap_size_t(size_t a, size_t b); + +int abs(int x); + typedef struct { uint32_t charHeight; uint32_t charWidth; @@ -27,6 +31,9 @@ typedef struct { size_t charsPerRow; size_t rowsPerScrn; uint32_t scrlMode; + + size_t screenWidth; + size_t screenHeight; } PRINTINFO; extern PRINTINFO PrintInfo; @@ -39,8 +46,13 @@ uint32_t GetForegroundColor(); void SetBackgroundColor(uint32_t color); uint32_t GetBackgroundColor(); +void DrawLine(size_t x0, size_t y0, size_t x1, size_t y1); + void DrawFilledRect(size_t x, size_t y, size_t width, size_t height); void DrawLineRect(size_t x, size_t y, size_t width, size_t height, size_t thickness); +void DrawFilledRoundedRect(size_t x, size_t y, size_t width, size_t height, size_t radius); +void DrawLineRoundedRect(size_t x, size_t y, size_t width, size_t height, size_t radius); -// When height == width, this draws a circle. -void DrawOval(size_t centerX, size_t centerY, size_t height, size_t width); \ No newline at end of file +void DrawFilledCircle(size_t centerX, size_t centerY, size_t radius); +void DrawLineCircle(size_t centerX, size_t centerY, size_t radius); +void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char cornerMask); \ No newline at end of file diff --git a/src/editor/EditorMain.c b/src/editor/EditorMain.c new file mode 100644 index 0000000..40699b1 --- /dev/null +++ b/src/editor/EditorMain.c @@ -0,0 +1,32 @@ +#include +#include +#include + +/************************ + *** Team Kitty, 2021 *** + *** Chroma *** + ***********************/ + +/** + * Contains startup and setup routines for the Chroma Editor. + */ +static int KernelID; + +void StartEditor(int callbackID) { + KernelID = callbackID; + + struct EditorLayout layout = (struct EditorLayout) {0}; + layout.ScreenHeight = PrintInfo.screenHeight; + layout.ScreenWidth = PrintInfo.screenWidth; + layout.HeaderHeight = layout.ScreenHeight / 100 * 3; + + SetForegroundColor(0x000084); + FillScreen(); + + SetForegroundColor(0x00BBBBBB); + + DrawFilledRect(0, 0, PrintInfo.screenWidth, layout.HeaderHeight); + + for(;;) {} + +} \ No newline at end of file diff --git a/src/video/draw.c b/src/video/draw.c index 54dbd12..3b65c6b 100644 --- a/src/video/draw.c +++ b/src/video/draw.c @@ -20,14 +20,6 @@ PRINTINFO PrintInfo = {0}; #define FONT bitfont_latin -static size_t strlen(const char* String) { - size_t Len = 0; - while(String[Len] != '\0') { - Len++; - } - return Len; -} - void InitPrint() { PrintInfo.charHeight = 8; PrintInfo.charWidth = 8; @@ -43,6 +35,9 @@ void InitPrint() { PrintInfo.scrlMode = 0; + PrintInfo.screenWidth = bootldr.fb_width; + PrintInfo.screenHeight = bootldr.fb_height; + PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth) - 4; PrintInfo.rowsPerScrn = bootldr.fb_height / (PrintInfo.charScale * PrintInfo.charHeight); SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth, PrintInfo.charScale * PrintInfo.charHeight); @@ -107,8 +102,8 @@ static void DrawChar(const char character, size_t x, size_t y) { } void DrawPixel(size_t x, size_t y) { - if(x > bootldr.fb_width) { - DrawPixel(x - bootldr.fb_width, y + (PrintInfo.charHeight * PrintInfo.charScale)); + if(x > bootldr.fb_scanline) { + DrawPixel(x - bootldr.fb_scanline, y + (PrintInfo.charHeight * PrintInfo.charScale)); } else if(y > bootldr.fb_height) { DrawPixel(x, y - bootldr.fb_height); } else { @@ -235,3 +230,248 @@ void WriteStringWithFont(const char *inChar) { inChar++; kx++; } } + +/********************************** Geometry Rendering **********************************/ +/** + * Implementation borrowed with <3 from Adafruit: https://github.com/adafruit/Adafruit-GFX-Library/blob/master/Adafruit_GFX.cpp + * TODO: Reimplement in Helix. + * + */ + +/******* Internal *******/ + +inline void _swap_size_t(size_t a, size_t b) { + size_t t = a; + a = b; + b = t; +} + +inline int abs(int x) { + return x < 0 ? -x : x; +} + +void DrawLineInternal(size_t x0, size_t y0, size_t x1, size_t y1) { + bool steep = abs(y1 - y0) > abs(x1 - x0); + + if (steep) { + _swap_size_t(x0, y0); + _swap_size_t(x1, y1); + } + + if (x0 > x1) { + _swap_size_t(x0, x1); + _swap_size_t(y0, y1); + } + + size_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int err = dx / 2; + size_t ystep; + + if (y0 < y1) + ystep = 1; + else + ystep = -1; + + for (; x0 <= x1; x0++) { + if (steep) + DrawPixel(y0, x0); + else + DrawPixel(x0, y0); + + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +void DrawHorizontalLine(size_t x, size_t y, size_t w) { + DrawLineInternal(x, y, x + w - 1, y); +} + +void DrawVerticalLine(size_t x, size_t y, size_t h) { + DrawLineInternal(x, y, x, y + h - 1); +} + +void DrawFilledCircleInternal(size_t centerX, size_t centerY, size_t radius, char cornerMask, size_t offset) { + int f = 1 - radius; + size_t ddF_x = 1; + size_t ddF_y = -2 * radius; + size_t x = 0; + size_t y = radius; + size_t px = x; + size_t py = y; + + offset++; + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (x < (y + 1)) { + if (cornerMask & 1) + DrawVerticalLine(centerX + x, centerY - y, 2 * y + offset); + if (cornerMask & 2) + DrawVerticalLine(centerX - x, centerY - y, 2 * y + offset); + } + + if (y != py) { + if (cornerMask & 1) + DrawVerticalLine(centerX + py, centerY - px, 2 * px + offset); + if (cornerMask & 2) + DrawVerticalLine(centerX - py, centerY - px, 2 * px + offset); + py = y; + } + px = x; + } +} + +/******* Public *******/ + +void DrawFilledRect(size_t x, size_t y, size_t width, size_t height) { + for (size_t i = y; i < y + height; i++) + DrawHorizontalLine(x, i, width); +} + +void DrawLineRect(size_t x, size_t y, size_t width, size_t height, size_t thickness) { + UNUSED(thickness); + DrawHorizontalLine(x, y, width); + DrawHorizontalLine(x, y + height - 1, width); + DrawVerticalLine(x, y, height); + DrawVerticalLine(x + width - 1, y, height); +} + +void DrawFilledRoundedRect(size_t x, size_t y, size_t width, size_t height, size_t radius) { + size_t max_radius = ((width < height) ? width : height) / 2; // 1/2 minor axis + if (radius > max_radius) + radius = max_radius; + DrawFilledRect(x + radius, y, width - 2 * radius, height); + // draw four corners + DrawFilledCircleInternal(x + width - radius - 1, y + radius, radius, 1, height - 2 * radius - 1); + DrawFilledCircleInternal(x + radius, y + radius, radius, 2, height - 2 * radius - 1); +} + +void DrawLineRoundedRect(size_t x, size_t y, size_t width, size_t height, size_t radius) { + size_t max_radius = ((width < height) ? width : height) / 2; // 1/2 minor axis + if (radius > max_radius) + radius = max_radius; + DrawHorizontalLine(x + radius, y, width - 2 * radius); // Top + DrawHorizontalLine(x + radius, y + height - 1, width - 2 * radius); // Bottom + DrawVerticalLine(x, y + radius, height - 2 * radius); // Left + DrawVerticalLine(x + width - 1, y + radius, height - 2 * radius); // Right + // draw four corners + DrawLineCircleCorners(x + radius, y + radius, radius, 1); + DrawLineCircleCorners(x + width - radius - 1, y + radius, radius, 2); + DrawLineCircleCorners(x + width - radius - 1, y + height - radius - 1, radius, 4); + DrawLineCircleCorners(x + radius, y + height - radius - 1, radius, 8); +} + +void DrawLine(size_t x0, size_t y0, size_t x1, size_t y1) { + if (x0 == x1) { + if (y0 > y1) + _swap_size_t(y0, y1); + + DrawVerticalLine(x0, y0, y1 - y0 + 1); + } else if (y0 == y1) { + if (x0 > x1) + _swap_size_t(x0, x1); + + DrawHorizontalLine(x0, y0, x1 - x0 + 1); + } else { + DrawLineInternal(x0, y0, x1, y1); + } +} + +void DrawCircle(size_t centerX, size_t centerY, size_t radius) { + int f = 1 - radius; + size_t ddF_x = 1; + size_t ddF_y = -2 * radius; + size_t x = 0; + size_t y = radius; + + DrawPixel(centerX, centerY + radius); + DrawPixel(centerX, centerY - radius); + DrawPixel(centerX + radius, centerY); + DrawPixel(centerX - radius, centerY); + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + DrawPixel(centerX + x, centerY + y); + DrawPixel(centerX - x, centerY + y); + DrawPixel(centerX + x, centerY - y); + DrawPixel(centerX - x, centerY - y); + DrawPixel(centerX + y, centerY + x); + DrawPixel(centerX - y, centerY + x); + DrawPixel(centerX + y, centerY - x); + DrawPixel(centerX - y, centerY - x); + } +} + +void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char cornerMask) { + int f = 1 - radius; + size_t ddF_x = 1; + size_t ddF_y = -2 * radius; + size_t x = 0; + size_t y = radius; + + DrawPixel(centerX, centerY + radius); + DrawPixel(centerX, centerY - radius); + DrawPixel(centerX + radius, centerY); + DrawPixel(centerX - radius, centerY); + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + if(cornerMask & 0x4) { + DrawPixel(centerX + x, centerY + y); + DrawPixel(centerX + y, centerY + x); + } + + if(cornerMask & 0x2) { + DrawPixel(centerX + x, centerY - y); + DrawPixel(centerX - y, centerY - x); + } + + if(cornerMask & 0x8) { + DrawPixel(centerX - y, centerY + x); + DrawPixel(centerX - x, centerY + y); + } + + if(cornerMask & 0x1) { + DrawPixel(centerX - y, centerY - x); + DrawPixel(centerX - x, centerY - y); + } + } +} + +void DrawFilledCircle(size_t centerX, size_t centerY, size_t radius) { + DrawVerticalLine(centerX, centerY - radius, 2 * radius + 1); + DrawFilledCircleInternal(centerX, centerY, radius, 3, 0); +} + diff --git a/src/video/print.c b/src/video/print.c index da78985..1599299 100644 --- a/src/video/print.c +++ b/src/video/print.c @@ -13,14 +13,6 @@ * This file also provides SerialPrintf. */ -static size_t strlen(const char* String) { - size_t Len = 0; - while(String[Len] != '\0') { - Len++; - } - return Len; -} - static void NumToStr(char* Buffer, size_t Num, size_t Base) { size_t Temp, i = 0, j = 0;