mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
A new desktop app whose whole point is to say sorry, and to look like
saying it took effort. Nothing in it is a static bitmap.
The heart is the classic parametric heart curve, x = 16sin^3(t) and
y = 13cos(t) - 5cos(2t) - 2cos(3t) - cos(4t), precomputed as a 96-point
integer polygon normalised to a half-width of 1000 and scanline-filled at
whatever size the beat currently has it at. Even-odd crossing counting is
what keeps the notch between the lobes open. The beat is a two-thump
cardiac envelope -- a strong systolic beat and a softer echo -- and the
fill carries a vertical gradient, a soft specular highlight on the upper
lobe, and a six-layer glow. The kernel is built -mno-sse with no floating
point, so every curve, gradient, easing and physics step is integer-only
and needs no trigonometry at runtime.
Around it: three apology letters that type themselves out a character at
a time, and a slow drift of small hearts using the same fill routine.
Answering "I forgive you" brightens the heart and bursts the drift
outward; answering "Not yet" dims it, slows the beat, and starts an
honest count of how long it has been waiting. Neither answer is an exit.
Supporting changes, all of them general rather than app-specific:
- gui_desktop_request_animation_frame(), so an app can opt into
full-rate recompositing instead of the ~10 Hz live-content
heartbeat. It is renewed per paint, so it lapses by itself when the
app stops animating or its window closes.
- gui_button_styled() and gui_hitzone() in SUB-WT, letting an app with
its own palette keep the toolkit's click handling. gui_button_colored
is now a thin wrapper over the former.
- A heart glyph in the icon set.
The glow layers skip whatever the heart body is about to cover, which
cuts their blended-pixel cost by roughly 3.5x and pays for the extra
layers that turn contour rings into a smooth halo.
Verified in QEMU on x86_64: all three states driven by real clicks --
hover, forgiveness (brighter heart, burst, live typewriter) and waiting
(dimmed heart, slower beat, running counter). Builds clean on x86_64,
aarch64 and armv8i.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
99 lines
4.4 KiB
C
99 lines
4.4 KiB
C
#ifndef _GUI_WIDGETS_H
|
|
#define _GUI_WIDGETS_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <gui/gui_wm.h>
|
|
#include <gui/gui_gfx.h>
|
|
#include <gui/gui_theme.h>
|
|
|
|
// SUB-WT: immediate-mode widget toolkit for SUB-OS desktop applications.
|
|
//
|
|
// An app feeds the toolkit whatever event the window manager delivered
|
|
// (gui_widget_feed_event) and then simply calls widget functions from inside
|
|
// its paint routine. Each call both draws the control and reports what the
|
|
// user did with it, so no retained widget tree has to be kept in sync with
|
|
// the window's state.
|
|
//
|
|
// static void my_paint(gui_window_t* win) {
|
|
// gui_widget_begin(win);
|
|
// if (gui_button(1, 10, 10, 90, 24, "Refresh")) do_refresh();
|
|
// gui_checkbox(2, 10, 44, "Verbose", &verbose);
|
|
// gui_widget_end();
|
|
// }
|
|
|
|
#define GUI_FONT_W 8
|
|
#define GUI_FONT_H 8
|
|
#define GUI_FONT16_H 16
|
|
#define GUI_WIDGET_ROW_H 22
|
|
|
|
typedef enum {
|
|
GUI_ALIGN_LEFT,
|
|
GUI_ALIGN_CENTER,
|
|
GUI_ALIGN_RIGHT
|
|
} gui_align_t;
|
|
|
|
// Per-frame input snapshot the widgets consult.
|
|
typedef struct {
|
|
int mouse_x; // Window-relative, client area origin
|
|
int mouse_y;
|
|
bool mouse_down; // Button currently held
|
|
bool mouse_clicked; // Press edge, consumed by the first widget hit
|
|
bool mouse_released;
|
|
uint16_t key; // Pending keystroke, consumed by the focused field
|
|
int hot_id; // Widget under the cursor this frame
|
|
int active_id; // Widget holding the press
|
|
int focus_id; // Widget receiving keystrokes
|
|
} gui_widget_input_t;
|
|
|
|
// Called from an app's handle_event to record what the WM delivered.
|
|
void gui_widget_feed_event(gui_window_t* win, const gui_event_t* ev);
|
|
|
|
// Frame scope. Everything between these two is drawn in client-area
|
|
// coordinates: (0,0) is the top-left pixel below the title bar.
|
|
void gui_widget_begin(gui_window_t* win);
|
|
void gui_widget_end(void);
|
|
|
|
const gui_widget_input_t* gui_widget_get_input(void);
|
|
void gui_widget_set_focus(int id);
|
|
int gui_widget_client_width(void);
|
|
int gui_widget_client_height(void);
|
|
|
|
// --- Static content ---------------------------------------------------------
|
|
void gui_label(int x, int y, const char* text, uint32_t color);
|
|
void gui_label_bold(int x, int y, const char* text, uint32_t color);
|
|
void gui_label_aligned(int x, int y, int w, const char* text, uint32_t color, gui_align_t align);
|
|
void gui_panel(int x, int y, int w, int h, const char* title);
|
|
void gui_separator(int x, int y, int w);
|
|
void gui_progress_bar(int x, int y, int w, int h, int percent, uint32_t fill);
|
|
void gui_sparkline(int x, int y, int w, int h, const uint8_t* samples, int count, uint32_t color);
|
|
void gui_badge(int x, int y, const char* text, uint32_t bg, uint32_t fg);
|
|
|
|
// --- Interactive controls ---------------------------------------------------
|
|
// Every control takes a caller-assigned id that must be unique and stable
|
|
// within one window.
|
|
bool gui_button(int id, int x, int y, int w, int h, const char* label);
|
|
bool gui_button_colored(int id, int x, int y, int w, int h, const char* label, uint32_t accent);
|
|
|
|
// Fully styled variant, for apps that paint their own palette instead of
|
|
// inheriting the desktop's slate theme. The three faces cover the idle,
|
|
// hovered and pressed states.
|
|
bool gui_button_styled(int id, int x, int y, int w, int h, const char* label,
|
|
uint32_t face, uint32_t face_hover, uint32_t face_press,
|
|
uint32_t border, uint32_t text);
|
|
|
|
// Claims a click inside a rectangle without drawing anything, so an app can
|
|
// make a custom-drawn region clickable. Place it after the real controls: a
|
|
// widget only ever sees a click no earlier widget already claimed.
|
|
bool gui_hitzone(int id, int x, int y, int w, int h);
|
|
bool gui_checkbox(int id, int x, int y, const char* label, bool* value);
|
|
bool gui_radio(int id, int x, int y, const char* label, int* selected, int this_value);
|
|
bool gui_slider(int id, int x, int y, int w, int* value, int min_val, int max_val);
|
|
bool gui_listbox(int id, int x, int y, int w, int h, const char* const* items, int count, int* selected);
|
|
bool gui_textfield(int id, int x, int y, int w, char* buffer, size_t capacity);
|
|
int gui_tabbar(int id, int x, int y, int w, const char* const* labels, int count, int* active);
|
|
bool gui_scrollbar(int id, int x, int y, int h, int* offset, int total, int visible);
|
|
|
|
#endif // _GUI_WIDGETS_H
|