1557 lines
64 KiB
Python
1557 lines
64 KiB
Python
import vpsdk.window as window
|
|
import vpsdk.process as process
|
|
import vpsdk.syscall as _syscall
|
|
from stdint import *
|
|
import t, c
|
|
import string
|
|
|
|
TITLE_H: t.CDefine = 32
|
|
MAX_WIDGETS: t.CDefine = 24
|
|
CHAR_W: t.CDefine = 8
|
|
CHAR_H: t.CDefine = 16
|
|
|
|
WIDGET_LABEL: t.CDefine = 1
|
|
WIDGET_BUTTON: t.CDefine = 2
|
|
WIDGET_ENTRY: t.CDefine = 3
|
|
WIDGET_TEXT: t.CDefine = 4
|
|
WIDGET_SCROLLBAR: t.CDefine = 5
|
|
WIDGET_FBCANVAS: t.CDefine = 6
|
|
|
|
VERTICAL: t.CDefine = 1
|
|
HORIZONTAL: t.CDefine = 2
|
|
TEXT_MAX_LINES: t.CDefine = 200
|
|
|
|
PACK_TOP: t.CDefine = 1
|
|
PACK_BOTTOM: t.CDefine = 2
|
|
PACK_LEFT: t.CDefine = 3
|
|
PACK_RIGHT: t.CDefine = 4
|
|
|
|
FILL_NONE: t.CDefine = 0
|
|
FILL_X: t.CDefine = 1
|
|
FILL_Y: t.CDefine = 2
|
|
FILL_BOTH: t.CDefine = 3
|
|
|
|
STICKY_NONE: t.CDefine = 0
|
|
STICKY_W: t.CDefine = 1
|
|
STICKY_E: t.CDefine = 2
|
|
STICKY_N: t.CDefine = 4
|
|
STICKY_S: t.CDefine = 8
|
|
STICKY_NSEW: t.CDefine = 15
|
|
|
|
_g_wl_type: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_side: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_fill: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_expand: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_padx: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_pady: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_row: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_col: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_rowspan: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_colspan: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_wl_sticky: t.CArray[t.CInt, MAX_WIDGETS]
|
|
_g_layout_init: t.CInt
|
|
|
|
_hex_tbl: t.CArray[t.CChar, 17] = "0123456789ABCDEF"
|
|
_hex_buf: t.CArray[t.CChar, 20] = "0000000000000000000"
|
|
|
|
def _serial_puts(s: t.CConst | t.CChar | t.CPtr) -> t.CVoid:
|
|
_syscall._syscall1(t.CUInt64T(_syscall.SERIAL_PUTS), t.CUInt64T(s))
|
|
|
|
def _ptr_to_hex(val: t.CUInt64T, buf: t.CVoid | t.CPtr) -> t.CVoid:
|
|
buf[0] = 48
|
|
buf[1] = 120
|
|
i: t.CInt = 15
|
|
while i >= 0:
|
|
nibble: t.CInt = t.CInt(val & t.CUInt64T(0xF))
|
|
buf[2 + i] = _hex_tbl[nibble]
|
|
val = val >> 4
|
|
i -= 1
|
|
buf[18] = 0
|
|
|
|
def _fill_rect(fb: UINT32PTR, fw: t.CInt, fh: t.CInt, x1: t.CInt, y1: t.CInt, w: t.CInt, h: t.CInt, color: t.CUInt32T):
|
|
if not fb: return
|
|
if x1 < 0: w += x1; x1 = 0
|
|
if y1 < 0: h += y1; y1 = 0
|
|
if w <= 0 or h <= 0: return
|
|
for py in range(y1, y1 + h):
|
|
if py >= 0 and py < fh:
|
|
for px in range(x1, x1 + w):
|
|
if px >= 0 and px < fw:
|
|
fb[py * fw + px] = color
|
|
|
|
def _draw_hline(fb: UINT32PTR, fw: t.CInt, fh: t.CInt, x1: t.CInt, y: t.CInt, w: t.CInt, color: t.CUInt32T):
|
|
if not fb: return
|
|
if y < 0 or y >= fh: return
|
|
for px in range(x1, x1 + w):
|
|
if px >= 0 and px < fw:
|
|
fb[y * fw + px] = color
|
|
|
|
def _draw_vline(fb: UINT32PTR, fw: t.CInt, fh: t.CInt, x: t.CInt, y1: t.CInt, h: t.CInt, color: t.CUInt32T):
|
|
if not fb: return
|
|
if x < 0 or x >= fw: return
|
|
for py in range(y1, y1 + h):
|
|
if py >= 0 and py < fh:
|
|
fb[py * fw + x] = color
|
|
|
|
def _lighten(color: t.CUInt32T, amount: t.CInt) -> t.CUInt32T:
|
|
r: t.CInt = t.CInt(color & 0xFF)
|
|
g: t.CInt = t.CInt((color >> 8) & 0xFF)
|
|
b: t.CInt = t.CInt((color >> 16) & 0xFF)
|
|
r = r + ((255 - r) * amount) / 256
|
|
g = g + ((255 - g) * amount) / 256
|
|
b = b + ((255 - b) * amount) / 256
|
|
return t.CUInt32T(r | (g << 8) | (b << 16))
|
|
|
|
def _darken(color: t.CUInt32T, amount: t.CInt) -> t.CUInt32T:
|
|
r: t.CInt = t.CInt(color & 0xFF)
|
|
g: t.CInt = t.CInt((color >> 8) & 0xFF)
|
|
b: t.CInt = t.CInt((color >> 16) & 0xFF)
|
|
r = r - (r * amount) / 256
|
|
g = g - (g * amount) / 256
|
|
b = b - (b * amount) / 256
|
|
return t.CUInt32T(r | (g << 8) | (b << 16))
|
|
|
|
|
|
font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
|
|
{0x00,0x00,0x00,0x00,0x00,0x40,0x55,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x02,0x56,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x42,0x56,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x55,0x55,0x57,0x71,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x54,0x57,0x71,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x54,0x57,0x75,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x51,0x52,0x72,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x55,0x57,0x75,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x55,0x57,0x71,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x56,0x51,0x57,0x75,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x54,0x54,0x57,0x75,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x50,0x50,0x57,0x74,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x51,0x51,0x57,0x75,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x57,0x55,0x57,0x74,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x53,0x54,0x56,0x74,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x15,0x15,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x32,0x16,0x12,0x12,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x20,0x6E,0x22,0x2E,0x28,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x11,0x13,0x11,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x35,0x15,0x17,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x14,0x17,0x11,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x14,0x17,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x11,0x12,0x12,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x15,0x17,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x15,0x17,0x11,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x36,0x11,0x17,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x34,0x14,0x17,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x30,0x10,0x17,0x14,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x31,0x11,0x17,0x15,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x37,0x15,0x17,0x14,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x10,0x33,0x14,0x16,0x14,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
|
|
{0x6C,0x6C,0x6C,0x6C,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x36,0x36,0x36,0x7F,0x7F,0x36,0x36,0x36,0x7F,0x7F,0x36,0x36,0x36,0x00,0x00,0x00},
|
|
{0x0C,0x0C,0x3E,0x7F,0x68,0x68,0x3E,0x0B,0x0B,0x7F,0x3E,0x18,0x18,0x00,0x00,0x00},
|
|
{0x60,0x60,0x66,0x06,0x0C,0x0C,0x18,0x30,0x30,0x60,0x66,0x06,0x06,0x00,0x00,0x00},
|
|
{0x38,0x6C,0x6C,0x6C,0x6C,0x6C,0x38,0x6C,0x6D,0x66,0x66,0x6F,0x3B,0x00,0x00,0x00},
|
|
{0x18,0x18,0x18,0x18,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x1C,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x1C,0x00,0x00},
|
|
{0x38,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x38,0x00,0x00},
|
|
{0x00,0x00,0x18,0x18,0x7E,0x3C,0x3C,0x3C,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x18,0x18,0x18,0x7E,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x30,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00},
|
|
{0x00,0x00,0x06,0x06,0x0C,0x0C,0x18,0x30,0x30,0x60,0x60,0x00,0x00,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x6E,0x6E,0x7E,0x76,0x76,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x18,0x38,0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x06,0x06,0x0E,0x1C,0x38,0x70,0x60,0x60,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x06,0x06,0x1C,0x1C,0x06,0x06,0x06,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x0C,0x0C,0x1C,0x1C,0x3C,0x2C,0x6C,0x7E,0x7E,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x06,0x06,0x06,0x06,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x60,0x60,0x7C,0x7E,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x06,0x06,0x0C,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x66,0x7E,0x3C,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x66,0x7E,0x3E,0x06,0x06,0x06,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x30,0x00},
|
|
{0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x7E,0x7E,0x00,0x00,0x7E,0x7E,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x40,0x60,0x30,0x18,0x0C,0x06,0x06,0x0C,0x18,0x30,0x60,0x40,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x6E,0x6A,0x6A,0x6A,0x6E,0x60,0x60,0x7C,0x3C,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x66,0x7E,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x7C,0x7E,0x66,0x66,0x66,0x7C,0x7C,0x66,0x66,0x66,0x66,0x7E,0x7C,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x78,0x7C,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0x7C,0x78,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x60,0x60,0x60,0x7C,0x7C,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x60,0x60,0x60,0x7C,0x7C,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x60,0x60,0x60,0x6E,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x66,0x7E,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x3E,0x3E,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x6C,0x7C,0x38,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x6C,0x6C,0x78,0x78,0x78,0x6C,0x6C,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x76,0x76,0x7E,0x6E,0x6E,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x7C,0x7E,0x66,0x66,0x66,0x7E,0x7C,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x6A,0x6A,0x6C,0x7E,0x36,0x00,0x00,0x00},
|
|
{0x7C,0x7E,0x66,0x66,0x66,0x7E,0x7C,0x6C,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x60,0x60,0x78,0x3C,0x0E,0x06,0x06,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x3C,0x18,0x18,0x00,0x00,0x00},
|
|
{0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x77,0x77,0x22,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x3C,0x3C,0x18,0x3C,0x3C,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x66,0x66,0x66,0x66,0x7E,0x3C,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00},
|
|
{0x7E,0x7E,0x06,0x06,0x0C,0x0C,0x18,0x30,0x30,0x60,0x60,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x78,0x78,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x78,0x78,0x00,0x00},
|
|
{0xC0,0xC0,0x60,0x60,0x30,0x30,0x18,0x0C,0x0C,0x06,0x06,0x03,0x03,0x00,0x00,0x00},
|
|
{0x1E,0x1E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x1E,0x1E,0x00,0x00},
|
|
{0x3C,0x7E,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00},
|
|
{0x30,0x38,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3C,0x3E,0x06,0x3E,0x7E,0x66,0x66,0x7E,0x3E,0x00,0x00,0x00},
|
|
{0x60,0x60,0x60,0x60,0x7C,0x7E,0x66,0x66,0x66,0x66,0x66,0x7E,0x7C,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3C,0x7E,0x66,0x60,0x60,0x60,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x06,0x06,0x06,0x06,0x3E,0x7E,0x66,0x66,0x66,0x66,0x66,0x7E,0x3E,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3C,0x7E,0x66,0x7E,0x7E,0x60,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x1C,0x3E,0x30,0x30,0x30,0x7C,0x7C,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3E,0x7E,0x66,0x66,0x66,0x7E,0x3E,0x06,0x06,0x3E,0x3C,0x00},
|
|
{0x60,0x60,0x60,0x60,0x7C,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x18,0x18,0x00,0x00,0x38,0x38,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x0C,0x0C,0x00,0x00,0x3C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C,0x78,0x00},
|
|
{0x60,0x60,0x60,0x60,0x66,0x66,0x6C,0x78,0x78,0x6C,0x6C,0x66,0x66,0x00,0x00,0x00},
|
|
{0x38,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x36,0x7F,0x6B,0x6B,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x7C,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3C,0x7E,0x66,0x66,0x66,0x66,0x66,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x7C,0x7E,0x66,0x66,0x66,0x7E,0x7C,0x60,0x60,0x60,0x60,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3E,0x7E,0x66,0x66,0x66,0x7E,0x3E,0x06,0x06,0x07,0x07,0x00},
|
|
{0x00,0x00,0x00,0x00,0x6C,0x7E,0x76,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x3C,0x7E,0x62,0x70,0x3C,0x0E,0x46,0x7E,0x3C,0x00,0x00,0x00},
|
|
{0x30,0x30,0x30,0x30,0x7C,0x7C,0x30,0x30,0x30,0x30,0x30,0x3C,0x1C,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x3E,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x3C,0x18,0x18,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x7F,0x36,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x66,0x66,0x3C,0x3C,0x18,0x3C,0x3C,0x66,0x66,0x00,0x00,0x00},
|
|
{0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7E,0x3E,0x06,0x06,0x7E,0x7C,0x00},
|
|
{0x00,0x00,0x00,0x00,0x7E,0x7E,0x0C,0x0C,0x18,0x30,0x30,0x7E,0x7E,0x00,0x00,0x00},
|
|
{0x0E,0x1E,0x18,0x18,0x18,0x18,0x30,0x30,0x18,0x18,0x18,0x18,0x1E,0x0E,0x00,0x00},
|
|
{0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00},
|
|
{0x70,0x78,0x18,0x18,0x18,0x18,0x0C,0x0C,0x18,0x18,0x18,0x18,0x78,0x70,0x00,0x00},
|
|
{0x31,0x79,0x6B,0x4F,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
{0x00,0x00,0x70,0x13,0x24,0x26,0x24,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
|
]
|
|
|
|
def _draw_char(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, ch: t.CChar, color: t.CUInt32T):
|
|
if not buf: return
|
|
if bw <= 0 or bh <= 0: return
|
|
ci: t.CUInt8T = t.CUInt8T(ch)
|
|
if ci >= 128: ci = 0
|
|
fy: t.CInt = 0
|
|
while fy < CHAR_H:
|
|
if y + fy < 0 or y + fy >= bh:
|
|
fy += 1
|
|
continue
|
|
row: t.CUInt8T = font[ci][fy]
|
|
if row == 0:
|
|
fy += 1
|
|
continue
|
|
fx: t.CInt = 0
|
|
while fx < CHAR_W:
|
|
if row & (0x80 >> fx):
|
|
px: t.CInt = x + fx
|
|
if px >= 0 and px < bw:
|
|
buf[(y + fy) * bw + px] = color
|
|
fx += 1
|
|
fy += 1
|
|
|
|
def _draw_text(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, s: t.CConst | str, color: t.CUInt32T):
|
|
if not buf: return
|
|
if bw <= 0 or bh <= 0: return
|
|
cx: t.CInt = x
|
|
cy: t.CInt = y
|
|
i: t.CInt = 0
|
|
while True:
|
|
ch: t.CChar = s[i]
|
|
if ch == 0: break
|
|
if ch == 10:
|
|
cy += 16
|
|
cx = x
|
|
else:
|
|
_draw_char(buf, bw, bh, cx, cy, ch, color)
|
|
cx += 8
|
|
i += 1
|
|
|
|
def _register_widget(master: t.CVoid | t.CPtr, widget: Widget | t.CPtr) -> t.CInt:
|
|
tk: Tk | t.CPtr = t.CType(master, Tk, t.CPtr)
|
|
idx: t.CInt = tk.widget_count
|
|
if idx < MAX_WIDGETS:
|
|
tk.widgets[idx] = widget
|
|
tk.widget_count = idx + 1
|
|
return idx
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Widget:
|
|
x: t.CInt
|
|
y: t.CInt
|
|
w: t.CInt
|
|
h: t.CInt
|
|
visible: t.CInt
|
|
master: t.CVoid | t.CPtr
|
|
widget_type: t.CInt
|
|
focused: t.CInt
|
|
hovered: t.CInt
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
pass
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
return 0
|
|
|
|
def contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
|
|
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
|
|
return 1
|
|
return 0
|
|
|
|
def place(self, x: t.CInt = 0, y: t.CInt = 0, w: t.CInt = 0, h: t.CInt = 0):
|
|
self.x = x
|
|
self.y = y
|
|
if w > 0:
|
|
self.w = w
|
|
if h > 0:
|
|
self.h = h
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Label(Widget):
|
|
text: t.CArray[t.CChar, 64]
|
|
color: t.CUInt32T
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, text: str, color: t.CUInt32T):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = 0
|
|
self.h = 0
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_LABEL
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self.color = color
|
|
i: t.CInt = 0
|
|
for ch in text:
|
|
if i >= 63: break
|
|
self.text[i] = ch
|
|
i += 1
|
|
self.text[i] = 0
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
_draw_text(fb, fw, fh, self.x, self.y, c.Addr(self.text[0]), self.color)
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
return 0
|
|
|
|
def config(self, text: t.CConst | t.CChar | t.CPtr = None, color: t.CUInt32T = None):
|
|
if text is not None:
|
|
i: t.CInt = 0
|
|
while i < 63:
|
|
ch: t.CChar = c.Deref(text + i)
|
|
self.text[i] = ch
|
|
if ch == 0: break
|
|
i += 1
|
|
self.text[i] = 0
|
|
if color is not None:
|
|
self.color = color
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Button(Widget):
|
|
text: t.CArray[t.CChar, 32]
|
|
fill_color: t.CUInt32T
|
|
text_color: t.CUInt32T
|
|
pressed: t.CInt
|
|
callback: t.CVoid | t.CPtr
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt, text: str, callback: t.CVoid | t.CPtr):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = w
|
|
self.h = h
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_BUTTON
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self.fill_color = t.CUInt32T(0x3C3C5A)
|
|
self.text_color = t.CUInt32T(0xFFFFFFFF)
|
|
self.pressed = 0
|
|
self.callback = callback
|
|
i: t.CInt = 0
|
|
for ch in text:
|
|
if i >= 31: break
|
|
self.text[i] = ch
|
|
i += 1
|
|
self.text[i] = 0
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
fill: t.CUInt32T = self.fill_color
|
|
border: t.CUInt32T = t.CUInt32T(0x8080B0)
|
|
if self.pressed:
|
|
fill = _lighten(self.fill_color, 60)
|
|
border = t.CUInt32T(0xA0A0D0)
|
|
elif self.hovered:
|
|
fill = _lighten(self.fill_color, 30)
|
|
border = t.CUInt32T(0xA0A0D0)
|
|
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, fill)
|
|
top_left: t.CUInt32T = _lighten(fill, 80)
|
|
bottom_right: t.CUInt32T = _darken(fill, 80)
|
|
if self.pressed:
|
|
top_left = _darken(fill, 60)
|
|
bottom_right = _lighten(fill, 40)
|
|
_draw_hline(fb, fw, fh, self.x, self.y, self.w, top_left)
|
|
_draw_hline(fb, fw, fh, self.x, self.y + 1, self.w, top_left)
|
|
_draw_vline(fb, fw, fh, self.x, self.y, self.h, top_left)
|
|
_draw_vline(fb, fw, fh, self.x + 1, self.y, self.h, top_left)
|
|
_draw_hline(fb, fw, fh, self.x, self.y + self.h - 1, self.w, bottom_right)
|
|
_draw_hline(fb, fw, fh, self.x, self.y + self.h - 2, self.w, bottom_right)
|
|
_draw_vline(fb, fw, fh, self.x + self.w - 1, self.y, self.h, bottom_right)
|
|
_draw_vline(fb, fw, fh, self.x + self.w - 2, self.y, self.h, bottom_right)
|
|
_draw_hline(fb, fw, fh, self.x - 1, self.y - 1, self.w + 2, border)
|
|
_draw_hline(fb, fw, fh, self.x - 1, self.y + self.h, self.w + 2, border)
|
|
_draw_vline(fb, fw, fh, self.x - 1, self.y - 1, self.h + 2, border)
|
|
_draw_vline(fb, fw, fh, self.x + self.w, self.y - 1, self.h + 2, border)
|
|
tl: t.CInt = string.strlen(c.Addr(self.text[0]))
|
|
tx: t.CInt = self.x + (self.w - 8 * tl) / 2
|
|
ty: t.CInt = self.y + (self.h - CHAR_H) / 2
|
|
_draw_text(fb, fw, fh, tx, ty, c.Addr(self.text[0]), self.text_color)
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
etype: t.CUInt32T = evt.type
|
|
ex: t.CInt = evt.x
|
|
ey: t.CInt = evt.y
|
|
if etype == window.EVENT_TYPE_HOVER:
|
|
if self.contains(ex, ey):
|
|
if not self.hovered:
|
|
self.hovered = 1
|
|
return 1
|
|
else:
|
|
if self.hovered and not self.pressed:
|
|
self.hovered = 0
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_HOVER_LEAVE:
|
|
if self.hovered:
|
|
self.hovered = 0
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_CLICK:
|
|
if self.contains(ex, ey):
|
|
self.pressed = 1
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_RELEASE:
|
|
if self.pressed:
|
|
self.pressed = 0
|
|
if self.contains(ex, ey) and self.callback is not None:
|
|
c.Asm(f"""push r12
|
|
push r13
|
|
mov r13, {c.AsmInp(self.callback, t.ASM_DESCR.REG_ANY)}
|
|
mov r12, rsp
|
|
and rsp, -16
|
|
call r13
|
|
mov rsp, r12
|
|
pop r13
|
|
pop r12""",
|
|
op=[t.ASM_DESCR.CLOBBER_MEMORY,
|
|
t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
|
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RSI,
|
|
t.ASM_DESCR.CLOBBER_RDI,
|
|
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
|
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
|
|
return 1
|
|
return 0
|
|
|
|
def config(self, text: t.CConst | t.CChar | t.CPtr = None, fill_color: t.CUInt32T = None, text_color: t.CUInt32T = None, callback: t.CVoid | t.CPtr = None):
|
|
if text is not None:
|
|
i: t.CInt = 0
|
|
while i < 31:
|
|
ch: t.CChar = c.Deref(text + i)
|
|
self.text[i] = ch
|
|
if ch == 0: break
|
|
i += 1
|
|
self.text[i] = 0
|
|
if fill_color is not None:
|
|
self.fill_color = fill_color
|
|
if text_color is not None:
|
|
self.text_color = text_color
|
|
if callback is not None:
|
|
self.callback = callback
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Entry(Widget):
|
|
text: t.CArray[t.CChar, 64]
|
|
text_len: t.CInt
|
|
cursor_pos: t.CInt
|
|
max_len: t.CInt
|
|
bg_color: t.CUInt32T
|
|
border_color: t.CUInt32T
|
|
text_color: t.CUInt32T
|
|
cursor_color: t.CUInt32T
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = w
|
|
self.h = h
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_ENTRY
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self.text_len = 0
|
|
self.cursor_pos = 0
|
|
self.max_len = 30
|
|
self.bg_color = t.CUInt32T(0xFF231919)
|
|
self.border_color = t.CUInt32T(0x606080)
|
|
self.text_color = t.CUInt32T(0x000000)
|
|
self.cursor_color = t.CUInt32T(0x000000)
|
|
for i in range(64):
|
|
self.text[i] = 0
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
bg: t.CUInt32T = self.bg_color
|
|
bdr: t.CUInt32T = self.border_color
|
|
if self.focused:
|
|
bg = t.CUInt32T(0xFFFFFF)
|
|
bdr = t.CUInt32T(0x4488FF)
|
|
elif self.hovered:
|
|
bdr = t.CUInt32T(0x8080B0)
|
|
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, bg)
|
|
_draw_hline(fb, fw, fh, self.x, self.y, self.w, bdr)
|
|
_draw_hline(fb, fw, fh, self.x, self.y + self.h - 1, self.w, bdr)
|
|
_draw_vline(fb, fw, fh, self.x, self.y, self.h, bdr)
|
|
_draw_vline(fb, fw, fh, self.x + self.w - 1, self.y, self.h, bdr)
|
|
if self.text_len > 0:
|
|
tc: t.CUInt32T = self.text_color
|
|
if not self.focused:
|
|
tc = t.CUInt32T(0xCCCCCC)
|
|
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, c.Addr(self.text[0]), tc)
|
|
elif not self.focused:
|
|
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, "Type here...", t.CUInt32T(0x888888))
|
|
if self.focused:
|
|
cx_pos: t.CInt = self.x + 6 + self.cursor_pos * CHAR_W
|
|
if cx_pos < self.x + self.w - 2:
|
|
_draw_vline(fb, fw, fh, cx_pos, self.y + 5, self.h - 10, self.cursor_color)
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
etype: t.CUInt32T = evt.type
|
|
ex: t.CInt = evt.x
|
|
ey: t.CInt = evt.y
|
|
if etype == window.EVENT_TYPE_HOVER:
|
|
if self.contains(ex, ey):
|
|
if not self.hovered:
|
|
self.hovered = 1
|
|
tk: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
window.set_cursor_type(tk.win_id, window.CURSOR_IBEAM)
|
|
return 1
|
|
else:
|
|
if self.hovered:
|
|
self.hovered = 0
|
|
tk2: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
window.set_cursor_type(tk2.win_id, window.CURSOR_DEFAULT)
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_HOVER_LEAVE:
|
|
if self.hovered:
|
|
self.hovered = 0
|
|
tk3: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
window.set_cursor_type(tk3.win_id, window.CURSOR_DEFAULT)
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_CLICK:
|
|
if self.contains(ex, ey):
|
|
if not self.focused:
|
|
self.focused = 1
|
|
tk4: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
tk4.focused_widget = t.CType(self, Widget, t.CPtr)
|
|
rel_x: t.CInt = ex - self.x - 6
|
|
if rel_x < 0: rel_x = 0
|
|
new_pos: t.CInt = (rel_x + CHAR_W / 2) / CHAR_W
|
|
if new_pos > self.text_len: new_pos = self.text_len
|
|
self.cursor_pos = new_pos
|
|
return 1
|
|
else:
|
|
if self.focused:
|
|
self.focused = 0
|
|
tk5: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
tk5.focused_widget = None
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_KEY:
|
|
if self.focused:
|
|
ebtn: t.CUInt8T = evt.button
|
|
if ebtn == window.KEY_STATE_RELEASE:
|
|
return 0
|
|
ch: t.CInt = ex
|
|
if ch == 8:
|
|
if self.cursor_pos > 0:
|
|
for i in range(self.cursor_pos, self.text_len):
|
|
self.text[i - 1] = self.text[i]
|
|
self.text_len -= 1
|
|
self.cursor_pos -= 1
|
|
self.text[self.text_len] = 0
|
|
return 1
|
|
elif ch == window.VK_LEFT:
|
|
if self.cursor_pos > 0:
|
|
self.cursor_pos -= 1
|
|
return 1
|
|
elif ch == window.VK_RIGHT:
|
|
if self.cursor_pos < self.text_len:
|
|
self.cursor_pos += 1
|
|
return 1
|
|
elif ch == window.VK_HOME:
|
|
self.cursor_pos = 0
|
|
return 1
|
|
elif ch == window.VK_END:
|
|
self.cursor_pos = self.text_len
|
|
return 1
|
|
elif ch == window.VK_DELETE:
|
|
if self.cursor_pos < self.text_len:
|
|
for i in range(self.cursor_pos, self.text_len - 1):
|
|
self.text[i] = self.text[i + 1]
|
|
self.text_len -= 1
|
|
self.text[self.text_len] = 0
|
|
return 1
|
|
elif ch >= 32 and ch < 127:
|
|
if self.text_len < self.max_len:
|
|
i: t.CInt = self.text_len
|
|
while i > self.cursor_pos:
|
|
self.text[i] = self.text[i - 1]
|
|
i -= 1
|
|
self.text[self.cursor_pos] = t.CChar(ch)
|
|
self.text_len += 1
|
|
self.cursor_pos += 1
|
|
self.text[self.text_len] = 0
|
|
return 1
|
|
return 0
|
|
|
|
def get(self) -> t.CConst | t.CChar | t.CPtr:
|
|
return c.Addr(self.text[0])
|
|
|
|
def delete(self, start: t.CInt, end: t.CInt):
|
|
self.text_len = 0
|
|
for i in range(64):
|
|
self.text[i] = 0
|
|
|
|
def config(self, bg_color: t.CUInt32T = None, text_color: t.CUInt32T = None, border_color: t.CUInt32T = None):
|
|
if bg_color is not None:
|
|
self.bg_color = bg_color
|
|
if text_color is not None:
|
|
self.text_color = text_color
|
|
if border_color is not None:
|
|
self.border_color = border_color
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Scrollbar(Widget):
|
|
orient: t.CInt
|
|
command: t.CVoid | t.CPtr
|
|
slider_first: t.CInt
|
|
slider_last: t.CInt
|
|
action: t.CInt
|
|
action_value: t.CInt
|
|
pressed: t.CInt
|
|
dragging: t.CInt
|
|
drag_start_y: t.CInt
|
|
drag_start_first: t.CInt
|
|
trough_color: t.CUInt32T
|
|
slider_color: t.CUInt32T
|
|
arrow_color: t.CUInt32T
|
|
slider_hover: t.CInt
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt, orient: t.CInt):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = w
|
|
self.h = h
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_SCROLLBAR
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self.orient = orient
|
|
self.command = None
|
|
self.slider_first = 0
|
|
self.slider_last = 1000
|
|
self.action = 0
|
|
self.action_value = 0
|
|
self.pressed = 0
|
|
self.dragging = 0
|
|
self.drag_start_y = 0
|
|
self.drag_start_first = 0
|
|
self.trough_color = t.CUInt32T(0x1E1E2E)
|
|
self.slider_color = t.CUInt32T(0x4A4A6A)
|
|
self.arrow_color = t.CUInt32T(0xAAAAAA)
|
|
self.slider_hover = 0
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, self.trough_color)
|
|
if self.orient != VERTICAL: return
|
|
arrow_sz: t.CInt = self.w
|
|
if arrow_sz > 16: arrow_sz = 16
|
|
self._draw_arrow_btn(fb, fw, fh, self.x, self.y, self.w, arrow_sz, 0, 1 if self.pressed == 1 else 0)
|
|
self._draw_arrow_btn(fb, fw, fh, self.x, self.y + self.h - arrow_sz, self.w, arrow_sz, 1, 1 if self.pressed == 2 else 0)
|
|
trough_y: t.CInt = self.y + arrow_sz
|
|
trough_h: t.CInt = self.h - 2 * arrow_sz
|
|
if trough_h <= 0: return
|
|
if self.slider_last > self.slider_first:
|
|
sl_h: t.CInt = (self.slider_last - self.slider_first) * trough_h / 1000
|
|
if sl_h < 8: sl_h = 8
|
|
sl_y: t.CInt = trough_y + self.slider_first * trough_h / 1000
|
|
if sl_y + sl_h > trough_y + trough_h:
|
|
sl_y = trough_y + trough_h - sl_h
|
|
if sl_y < trough_y: sl_y = trough_y
|
|
color: t.CUInt32T = self.slider_color
|
|
if self.dragging:
|
|
color = _lighten(self.slider_color, 40)
|
|
elif self.slider_hover:
|
|
color = _lighten(self.slider_color, 20)
|
|
_fill_rect(fb, fw, fh, self.x + 1, sl_y, self.w - 2, sl_h, color)
|
|
top_c: t.CUInt32T = _lighten(color, 60)
|
|
bot_c: t.CUInt32T = _darken(color, 60)
|
|
_draw_hline(fb, fw, fh, self.x + 1, sl_y, self.w - 2, top_c)
|
|
_draw_hline(fb, fw, fh, self.x + 1, sl_y + sl_h - 1, self.w - 2, bot_c)
|
|
_draw_vline(fb, fw, fh, self.x + 1, sl_y, sl_h, top_c)
|
|
_draw_vline(fb, fw, fh, self.x + self.w - 2, sl_y, sl_h, bot_c)
|
|
|
|
def _draw_arrow_btn(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt, bx: t.CInt, by: t.CInt, bw: t.CInt, bh: t.CInt, direction: t.CInt, is_pressed: t.CInt):
|
|
color: t.CUInt32T = self.slider_color
|
|
if is_pressed:
|
|
color = _lighten(self.slider_color, 30)
|
|
_fill_rect(fb, fw, fh, bx, by, bw, bh, color)
|
|
top_c: t.CUInt32T = _lighten(color, 60)
|
|
bot_c: t.CUInt32T = _darken(color, 60)
|
|
if is_pressed:
|
|
top_c = _darken(color, 40)
|
|
bot_c = _lighten(color, 30)
|
|
_draw_hline(fb, fw, fh, bx, by, bw, top_c)
|
|
_draw_hline(fb, fw, fh, bx, by + bh - 1, bw, bot_c)
|
|
_draw_vline(fb, fw, fh, bx, by, bh, top_c)
|
|
_draw_vline(fb, fw, fh, bx + bw - 1, by, bh, bot_c)
|
|
cx: t.CInt = bx + bw / 2
|
|
cy: t.CInt = by + bh / 2
|
|
if direction == 0:
|
|
_fill_rect(fb, fw, fh, cx - 1, cy - 3, 3, 1, self.arrow_color)
|
|
_fill_rect(fb, fw, fh, cx - 2, cy - 2, 5, 1, self.arrow_color)
|
|
_fill_rect(fb, fw, fh, cx - 3, cy - 1, 7, 1, self.arrow_color)
|
|
else:
|
|
_fill_rect(fb, fw, fh, cx - 3, cy - 1, 7, 1, self.arrow_color)
|
|
_fill_rect(fb, fw, fh, cx - 2, cy, 5, 1, self.arrow_color)
|
|
_fill_rect(fb, fw, fh, cx - 1, cy + 1, 3, 1, self.arrow_color)
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
etype: t.CUInt32T = evt.type
|
|
ex: t.CInt = evt.x
|
|
ey: t.CInt = evt.y
|
|
if etype == window.EVENT_TYPE_HOVER:
|
|
if self.dragging:
|
|
self._handle_drag(ey)
|
|
return 1
|
|
if self.contains(ex, ey):
|
|
if not self.slider_hover:
|
|
self.slider_hover = 1
|
|
return 1
|
|
else:
|
|
if self.slider_hover and self.pressed == 0:
|
|
self.slider_hover = 0
|
|
return 1
|
|
return 0
|
|
elif etype == window.EVENT_TYPE_HOVER_LEAVE:
|
|
if self.slider_hover:
|
|
self.slider_hover = 0
|
|
if not self.dragging:
|
|
self.pressed = 0
|
|
return 1
|
|
return 0
|
|
elif etype == window.EVENT_TYPE_CLICK:
|
|
if self.contains(ex, ey):
|
|
if self.orient == VERTICAL:
|
|
arrow_sz: t.CInt = self.w
|
|
if arrow_sz > 16: arrow_sz = 16
|
|
if ey < self.y + arrow_sz:
|
|
self.pressed = 1
|
|
self.action = 1
|
|
self._fire_command()
|
|
return 1
|
|
elif ey >= self.y + self.h - arrow_sz:
|
|
self.pressed = 2
|
|
self.action = 2
|
|
self._fire_command()
|
|
return 1
|
|
else:
|
|
trough_y: t.CInt = self.y + arrow_sz
|
|
trough_h: t.CInt = self.h - 2 * arrow_sz
|
|
if trough_h <= 0: return 1
|
|
sl_h: t.CInt = (self.slider_last - self.slider_first) * trough_h / 1000
|
|
if sl_h < 8: sl_h = 8
|
|
sl_y: t.CInt = trough_y + self.slider_first * trough_h / 1000
|
|
if sl_y + sl_h > trough_y + trough_h:
|
|
sl_y = trough_y + trough_h - sl_h
|
|
if ey >= sl_y and ey < sl_y + sl_h:
|
|
self.pressed = 4
|
|
self.dragging = 1
|
|
self.drag_start_y = ey
|
|
self.drag_start_first = self.slider_first
|
|
else:
|
|
self.pressed = 3
|
|
if ey < sl_y:
|
|
self.action = 3
|
|
else:
|
|
self.action = 4
|
|
self._fire_command()
|
|
return 1
|
|
return 0
|
|
elif etype == window.EVENT_TYPE_RELEASE:
|
|
if self.pressed:
|
|
self.pressed = 0
|
|
self.dragging = 0
|
|
return 1
|
|
return 0
|
|
return 0
|
|
|
|
def _handle_drag(self, ey: t.CInt):
|
|
arrow_sz: t.CInt = self.w
|
|
if arrow_sz > 16: arrow_sz = 16
|
|
trough_y: t.CInt = self.y + arrow_sz
|
|
trough_h: t.CInt = self.h - 2 * arrow_sz
|
|
if trough_h <= 0: return
|
|
delta_y: t.CInt = ey - self.drag_start_y
|
|
delta_first: t.CInt = delta_y * 1000 / trough_h
|
|
new_first: t.CInt = self.drag_start_first + delta_first
|
|
slider_size: t.CInt = self.slider_last - self.slider_first
|
|
if slider_size <= 0: slider_size = 1
|
|
if new_first < 0: new_first = 0
|
|
if new_first + slider_size > 1000: new_first = 1000 - slider_size
|
|
if new_first != self.slider_first:
|
|
self.slider_first = new_first
|
|
self.slider_last = new_first + slider_size
|
|
self.action = 5
|
|
self.action_value = new_first
|
|
self._fire_command()
|
|
|
|
def _fire_command(self):
|
|
if self.command is not None:
|
|
c.Asm(f"""push r12
|
|
push r13
|
|
mov r13, {c.AsmInp(self.command, t.ASM_DESCR.REG_ANY)}
|
|
mov r12, rsp
|
|
and rsp, -16
|
|
call r13
|
|
mov rsp, r12
|
|
pop r13
|
|
pop r12""",
|
|
op=[t.ASM_DESCR.CLOBBER_MEMORY,
|
|
t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
|
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RSI,
|
|
t.ASM_DESCR.CLOBBER_RDI,
|
|
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
|
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
|
|
|
|
def set(self, first: t.CInt, last: t.CInt):
|
|
self.slider_first = first
|
|
self.slider_last = last
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class FBCanvas(Widget):
|
|
_fb: UINT32PTR
|
|
_cw: t.CInt
|
|
_ch: t.CInt
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = w
|
|
self.h = h
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_FBCANVAS
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self._fb = None
|
|
self._cw = w
|
|
self._ch = h
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
if not self._fb: return
|
|
if self._cw <= 0 or self._ch <= 0: return
|
|
copy_w: t.CInt = self._cw
|
|
if copy_w > self.w: copy_w = self.w
|
|
copy_h: t.CInt = self._ch
|
|
if copy_h > self.h: copy_h = self.h
|
|
for py in range(copy_h):
|
|
ty: t.CInt = self.y + py
|
|
if ty < 0 or ty >= fh: continue
|
|
for px in range(copy_w):
|
|
tx: t.CInt = self.x + px
|
|
if tx < 0 or tx >= fw: continue
|
|
fb[ty * fw + tx] = self._fb[py * self._cw + px]
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
return 0
|
|
|
|
def set_fb(self, fb: UINT32PTR, cw: t.CInt, ch: t.CInt):
|
|
self._fb = fb
|
|
self._cw = cw
|
|
self._ch = ch
|
|
|
|
def get_fb(self) -> UINT32PTR:
|
|
return self._fb
|
|
|
|
def get_w(self) -> t.CInt:
|
|
return self._cw
|
|
|
|
def get_h(self) -> t.CInt:
|
|
return self._ch
|
|
|
|
@t.Object
|
|
@t.CVTable
|
|
class Text(Widget):
|
|
lines: t.CArray[t.CArray[t.CChar, 80], TEXT_MAX_LINES]
|
|
line_count: t.CInt
|
|
input_buf: t.CArray[t.CChar, 80]
|
|
input_len: t.CInt
|
|
cursor_pos: t.CInt
|
|
bg_color: t.CUInt32T
|
|
text_color: t.CUInt32T
|
|
prompt_color: t.CUInt32T
|
|
cursor_color: t.CUInt32T
|
|
border_color: t.CUInt32T
|
|
on_command: t.CVoid | t.CPtr
|
|
history: t.CArray[t.CArray[t.CChar, 80], 16]
|
|
history_count: t.CInt
|
|
history_idx: t.CInt
|
|
scroll_offset: t.CInt
|
|
max_lines: t.CInt
|
|
yscrollbar: t.CVoid | t.CPtr
|
|
|
|
def __init__(self, master: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt):
|
|
self.x = 0
|
|
self.y = 0
|
|
self.w = w
|
|
self.h = h
|
|
self.visible = 1
|
|
self.master = master
|
|
self.widget_type = WIDGET_TEXT
|
|
self.focused = 0
|
|
self.hovered = 0
|
|
self.line_count = 0
|
|
self.input_len = 0
|
|
self.cursor_pos = 0
|
|
self.bg_color = t.CUInt32T(0x0C0C0C)
|
|
self.text_color = t.CUInt32T(0xCCCCCC)
|
|
self.prompt_color = t.CUInt32T(0x00FF00)
|
|
self.cursor_color = t.CUInt32T(0x00FF00)
|
|
self.border_color = t.CUInt32T(0x333333)
|
|
self.on_command = None
|
|
self.history_count = 0
|
|
self.history_idx = 0
|
|
self.scroll_offset = 0
|
|
self.max_lines = TEXT_MAX_LINES
|
|
self.yscrollbar = None
|
|
i: t.CInt = 0
|
|
while i < TEXT_MAX_LINES:
|
|
j: t.CInt = 0
|
|
while j <= 79:
|
|
self.lines[i][j] = 0
|
|
j += 1
|
|
i += 1
|
|
i = 0
|
|
while i < 80:
|
|
self.input_buf[i] = 0
|
|
i += 1
|
|
_register_widget(master, t.CType(self, Widget, t.CPtr))
|
|
|
|
def draw(self, fb: UINT32PTR, fw: t.CInt, fh: t.CInt):
|
|
self._update_scrollbar()
|
|
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, self.bg_color)
|
|
_fill_rect(fb, fw, fh, self.x, self.y + self.h - 2, self.w, 2, self.border_color)
|
|
visible: t.CInt = self._visible_lines()
|
|
for i in range(visible):
|
|
line_idx: t.CInt = self.scroll_offset + i
|
|
if line_idx < self.line_count:
|
|
_draw_text(fb, fw, fh, self.x + 4, self.y + i * CHAR_H, c.Addr(self.lines[line_idx][0]), self.text_color)
|
|
prompt_y: t.CInt = self.y + self.h - CHAR_H - 4
|
|
_draw_text(fb, fw, fh, self.x + 4, prompt_y, "> ", self.prompt_color)
|
|
if self.input_len > 0:
|
|
_draw_text(fb, fw, fh, self.x + 4 + 2 * CHAR_W, prompt_y, c.Addr(self.input_buf[0]), t.CUInt32T(0xFFFFFF))
|
|
cx_pos: t.CInt = self.x + 4 + (2 + self.cursor_pos) * CHAR_W
|
|
if cx_pos < self.x + self.w - 4:
|
|
_fill_rect(fb, fw, fh, cx_pos, prompt_y, CHAR_W // 2, CHAR_H, self.cursor_color)
|
|
|
|
def handle_event(self, evt: window.InputEvent | t.CPtr) -> t.CInt:
|
|
etype: t.CUInt32T = evt.type
|
|
ex: t.CInt = evt.x
|
|
ey: t.CInt = evt.y
|
|
if etype == window.EVENT_TYPE_CLICK:
|
|
if self.contains(ex, ey):
|
|
if not self.focused:
|
|
self.focused = 1
|
|
tk: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
tk.focused_widget = t.CType(self, Widget, t.CPtr)
|
|
prompt_y: t.CInt = self.y + self.h - CHAR_H - 4
|
|
if ey >= prompt_y and ey < prompt_y + CHAR_H:
|
|
rel_x: t.CInt = ex - self.x - 4 - 2 * CHAR_W
|
|
if rel_x < 0: rel_x = 0
|
|
new_pos: t.CInt = (rel_x + CHAR_W / 2) / CHAR_W
|
|
if new_pos > self.input_len: new_pos = self.input_len
|
|
self.cursor_pos = new_pos
|
|
return 1
|
|
else:
|
|
if self.focused:
|
|
self.focused = 0
|
|
tk2: Tk | t.CPtr = t.CType(self.master, Tk, t.CPtr)
|
|
tk2.focused_widget = None
|
|
return 1
|
|
elif etype == window.EVENT_TYPE_KEY:
|
|
if self.focused:
|
|
ebtn2: t.CUInt8T = evt.button
|
|
if ebtn2 == window.KEY_STATE_RELEASE:
|
|
return 0
|
|
ch: t.CInt = ex
|
|
if ch == 8:
|
|
if self.cursor_pos > 0:
|
|
i: t.CInt = self.cursor_pos
|
|
while i < self.input_len:
|
|
self.input_buf[i - 1] = self.input_buf[i]
|
|
i += 1
|
|
self.input_len -= 1
|
|
self.cursor_pos -= 1
|
|
self.input_buf[self.input_len] = 0
|
|
return 1
|
|
elif ch == 13:
|
|
self._exec_input()
|
|
self.input_len = 0
|
|
self.cursor_pos = 0
|
|
for i in range(80):
|
|
self.input_buf[i] = 0
|
|
return 1
|
|
elif ch == window.VK_LEFT:
|
|
if self.cursor_pos > 0:
|
|
self.cursor_pos -= 1
|
|
return 1
|
|
elif ch == window.VK_RIGHT:
|
|
if self.cursor_pos < self.input_len:
|
|
self.cursor_pos += 1
|
|
return 1
|
|
elif ch == window.VK_UP:
|
|
if self.history_count > 0:
|
|
if self.history_idx < self.history_count:
|
|
self.history_idx += 1
|
|
hi: t.CInt = self.history_count - self.history_idx
|
|
if hi < 0: hi = 0
|
|
for j in range(80):
|
|
self.input_buf[j] = self.history[hi][j]
|
|
self.input_len = 0
|
|
while self.input_len < 79 and self.input_buf[self.input_len] != 0:
|
|
self.input_len += 1
|
|
self.cursor_pos = self.input_len
|
|
return 1
|
|
elif ch == window.VK_DOWN:
|
|
if self.history_count > 0:
|
|
if self.history_idx > 0:
|
|
self.history_idx -= 1
|
|
if self.history_idx == 0:
|
|
self.input_len = 0
|
|
self.cursor_pos = 0
|
|
for j2 in range(80):
|
|
self.input_buf[j2] = 0
|
|
else:
|
|
hi2: t.CInt = self.history_count - self.history_idx
|
|
for j3 in range(80):
|
|
self.input_buf[j3] = self.history[hi2][j3]
|
|
self.input_len = 0
|
|
while self.input_len < 79 and self.input_buf[self.input_len] != 0:
|
|
self.input_len += 1
|
|
self.cursor_pos = self.input_len
|
|
return 1
|
|
elif ch == window.VK_HOME:
|
|
self.cursor_pos = 0
|
|
return 1
|
|
elif ch == window.VK_END:
|
|
self.cursor_pos = self.input_len
|
|
return 1
|
|
elif ch == window.VK_DELETE:
|
|
if self.cursor_pos < self.input_len:
|
|
i: t.CInt = self.cursor_pos
|
|
while i < self.input_len - 1:
|
|
self.input_buf[i] = self.input_buf[i + 1]
|
|
i += 1
|
|
self.input_len -= 1
|
|
self.input_buf[self.input_len] = 0
|
|
return 1
|
|
elif ch == window.VK_PRIOR:
|
|
if self.scroll_offset > 0:
|
|
vis: t.CInt = self._visible_lines()
|
|
self.scroll_offset -= vis
|
|
if self.scroll_offset < 0: self.scroll_offset = 0
|
|
self._update_scrollbar()
|
|
return 1
|
|
elif ch == window.VK_NEXT:
|
|
vis2: t.CInt = self._visible_lines()
|
|
max_off: t.CInt = self.line_count - vis2
|
|
if max_off < 0: max_off = 0
|
|
if self.scroll_offset < max_off:
|
|
self.scroll_offset += vis2
|
|
if self.scroll_offset > max_off: self.scroll_offset = max_off
|
|
self._update_scrollbar()
|
|
return 1
|
|
elif ch >= 32 and ch < 127:
|
|
if self.input_len < 79:
|
|
i: t.CInt = self.input_len
|
|
while i > self.cursor_pos:
|
|
self.input_buf[i] = self.input_buf[i - 1]
|
|
i -= 1
|
|
self.input_buf[self.cursor_pos] = t.CChar(ch)
|
|
self.input_len += 1
|
|
self.cursor_pos += 1
|
|
self.input_buf[self.input_len] = 0
|
|
return 1
|
|
return 0
|
|
|
|
def _exec_input(self):
|
|
self.insert("> ")
|
|
if self.input_len > 0:
|
|
last: t.CInt = self.line_count - 1
|
|
j: t.CInt = 0
|
|
while j < self.input_len and j < 77:
|
|
self.lines[last][2 + j] = self.input_buf[j]
|
|
j += 1
|
|
self.lines[last][2 + j] = 0
|
|
if self.history_count < 16:
|
|
k: t.CInt = 0
|
|
while k < 80:
|
|
self.history[self.history_count][k] = self.input_buf[k]
|
|
k += 1
|
|
self.history_count += 1
|
|
else:
|
|
i: t.CInt = 0
|
|
while i < 15:
|
|
k2: t.CInt = 0
|
|
while k2 < 80:
|
|
self.history[i][k2] = self.history[i + 1][k2]
|
|
k2 += 1
|
|
i += 1
|
|
k3: t.CInt = 0
|
|
while k3 < 80:
|
|
self.history[15][k3] = self.input_buf[k3]
|
|
k3 += 1
|
|
self.history_idx = 0
|
|
|
|
cmd: t.CVoid | t.CPtr = self.on_command
|
|
if cmd is not None:
|
|
c.Asm(f"""push r12
|
|
push r13
|
|
mov r13, {c.AsmInp(cmd, t.ASM_DESCR.REG_ANY)}
|
|
mov r12, rsp
|
|
and rsp, -16
|
|
call r13
|
|
mov rsp, r12
|
|
pop r13
|
|
pop r12""",
|
|
op=[t.ASM_DESCR.CLOBBER_MEMORY,
|
|
t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
|
|
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RSI,
|
|
t.ASM_DESCR.CLOBBER_RDI,
|
|
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
|
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
|
|
else:
|
|
self.insert("(no callback)")
|
|
|
|
def insert(self, text: str):
|
|
start: t.CInt = 0
|
|
pos: t.CInt = 0
|
|
while True:
|
|
ch: t.CChar = c.Deref(text + pos)
|
|
if ch == 0:
|
|
if pos > start:
|
|
self._insert_substring(text, start, pos)
|
|
break
|
|
if ch == 10:
|
|
self._insert_substring(text, start, pos)
|
|
start = pos + 1
|
|
pos += 1
|
|
|
|
def insert_ptr(self, text: t.CConst | t.CChar | t.CPtr):
|
|
start: t.CInt = 0
|
|
pos: t.CInt = 0
|
|
while True:
|
|
ch: t.CChar = c.Deref(text + pos)
|
|
if ch == 0:
|
|
if pos > start:
|
|
self._insert_substring(text, start, pos)
|
|
break
|
|
if ch == 10:
|
|
self._insert_substring(text, start, pos)
|
|
start = pos + 1
|
|
pos += 1
|
|
|
|
def _insert_substring(self, text: t.CConst | t.CChar | t.CPtr, start: t.CInt, end: t.CInt):
|
|
if self.line_count >= self.max_lines:
|
|
i: t.CInt = 0
|
|
while i < self.max_lines - 1:
|
|
j: t.CInt = 0
|
|
while j <= 79:
|
|
self.lines[i][j] = self.lines[i + 1][j]
|
|
j += 1
|
|
i += 1
|
|
self.line_count -= 1
|
|
if self.scroll_offset > 0:
|
|
self.scroll_offset -= 1
|
|
idx: t.CInt = self.line_count
|
|
j: t.CInt = 0
|
|
k: t.CInt = start
|
|
while k < end and j < 79:
|
|
ch: t.CChar = c.Deref(text + k)
|
|
if ch == 9:
|
|
tab_stop: t.CInt = 8 - (j % 8)
|
|
while tab_stop > 0 and j < 79:
|
|
self.lines[idx][j] = 32
|
|
j += 1
|
|
tab_stop -= 1
|
|
elif ch == 13:
|
|
pass
|
|
else:
|
|
self.lines[idx][j] = ch
|
|
j += 1
|
|
k += 1
|
|
self.lines[idx][j] = 0
|
|
self.line_count += 1
|
|
vis: t.CInt = self._visible_lines()
|
|
if self.line_count > vis:
|
|
self.scroll_offset = self.line_count - vis
|
|
else:
|
|
self.scroll_offset = 0
|
|
self._update_scrollbar()
|
|
|
|
def delete(self, start: t.CInt, end: t.CInt):
|
|
self.line_count = 0
|
|
self.scroll_offset = 0
|
|
self._update_scrollbar()
|
|
|
|
def get(self) -> t.CConst | t.CChar | t.CPtr:
|
|
return c.Addr(self.input_buf[0])
|
|
|
|
def config(self, text_color: t.CUInt32T = None, bg_color: t.CUInt32T = None, prompt_color: t.CUInt32T = None, cursor_color: t.CUInt32T = None, border_color: t.CUInt32T = None):
|
|
if text_color is not None:
|
|
self.text_color = text_color
|
|
if bg_color is not None:
|
|
self.bg_color = bg_color
|
|
if prompt_color is not None:
|
|
self.prompt_color = prompt_color
|
|
if cursor_color is not None:
|
|
self.cursor_color = cursor_color
|
|
if border_color is not None:
|
|
self.border_color = border_color
|
|
|
|
def _visible_lines(self) -> t.CInt:
|
|
return (self.h - CHAR_H - 4) / CHAR_H
|
|
|
|
def _update_scrollbar(self):
|
|
vis: t.CInt = self._visible_lines()
|
|
if self.line_count <= vis:
|
|
self.scroll_offset = 0
|
|
else:
|
|
max_off: t.CInt = self.line_count - vis
|
|
if self.scroll_offset > max_off:
|
|
self.scroll_offset = max_off
|
|
if self.yscrollbar is not None:
|
|
sb: Scrollbar | t.CPtr = t.CType(self.yscrollbar, Scrollbar, t.CPtr)
|
|
if self.line_count <= vis:
|
|
sb.set(0, 1000)
|
|
else:
|
|
first: t.CInt = self.scroll_offset * 1000 / self.line_count
|
|
last: t.CInt = (self.scroll_offset + vis) * 1000 / self.line_count
|
|
sb.set(first, last)
|
|
|
|
@t.Object
|
|
class Tk:
|
|
win_id: t.CInt
|
|
buf: UINT32PTR
|
|
bw: t.CInt
|
|
bh: t.CInt
|
|
style: t.CInt
|
|
bg_color: t.CUInt32T
|
|
widgets: t.CArray[Widget | t.CPtr, MAX_WIDGETS]
|
|
widget_count: t.CInt
|
|
focused_widget: Widget | t.CPtr
|
|
_win_x: t.CInt
|
|
_win_y: t.CInt
|
|
_title: t.CArray[t.CChar, 32]
|
|
resizable_w: t.CInt
|
|
resizable_h: t.CInt
|
|
_grid_rows: t.CInt
|
|
_grid_cols: t.CInt
|
|
|
|
def __init__(self):
|
|
self.widget_count = 0
|
|
self.focused_widget = None
|
|
self.win_id = -1
|
|
self._win_x = 0
|
|
self._win_y = 0
|
|
self.style = 0
|
|
self.bg_color = t.CUInt32T(0xFF231919)
|
|
self.resizable_w = 1
|
|
self.resizable_h = 1
|
|
self._grid_rows = 0
|
|
self._grid_cols = 0
|
|
if _g_layout_init == 0:
|
|
i: t.CInt = 0
|
|
while i < MAX_WIDGETS:
|
|
_g_wl_type[i] = 0
|
|
_g_wl_side[i] = 0
|
|
_g_wl_fill[i] = 0
|
|
_g_wl_expand[i] = 0
|
|
_g_wl_padx[i] = 0
|
|
_g_wl_pady[i] = 0
|
|
_g_wl_row[i] = 0
|
|
_g_wl_col[i] = 0
|
|
_g_wl_rowspan[i] = 0
|
|
_g_wl_colspan[i] = 1
|
|
_g_wl_sticky[i] = 0
|
|
i += 1
|
|
_g_layout_init = 1
|
|
j: t.CInt = 0
|
|
while j < 32:
|
|
self._title[j] = 0
|
|
j += 1
|
|
|
|
def pack(self, idx: t.CInt, side: t.CInt, fill: t.CInt, expand: t.CInt, padx: t.CInt, pady: t.CInt):
|
|
_g_wl_type[idx] = 2
|
|
_g_wl_side[idx] = side
|
|
_g_wl_fill[idx] = fill
|
|
_g_wl_expand[idx] = expand
|
|
_g_wl_padx[idx] = padx
|
|
_g_wl_pady[idx] = pady
|
|
|
|
def grid(self, idx: t.CInt, row: t.CInt, col: t.CInt, rowspan: t.CInt, colspan: t.CInt, sticky: t.CInt):
|
|
_g_wl_type[idx] = 3
|
|
_g_wl_row[idx] = row
|
|
_g_wl_col[idx] = col
|
|
_g_wl_rowspan[idx] = rowspan
|
|
_g_wl_colspan[idx] = colspan
|
|
_g_wl_sticky[idx] = sticky
|
|
|
|
def title(self, text: str):
|
|
i: t.CInt = 0
|
|
while i < 31:
|
|
ch: t.CChar = text[i]
|
|
if ch == 0: break
|
|
self._title[i] = ch
|
|
i += 1
|
|
self._title[i] = 0
|
|
if self.win_id >= 0:
|
|
window.set_title(self.win_id, c.Addr(self._title[0]))
|
|
|
|
def set_style(self, s: t.CInt):
|
|
self.style = s
|
|
|
|
def resizable(self, rw: t.CInt, rh: t.CInt):
|
|
self.resizable_w = rw
|
|
self.resizable_h = rh
|
|
if self.win_id >= 0:
|
|
window.set_resizable(self.win_id, rw, rh)
|
|
|
|
def geometry(self, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
|
|
self._win_x = x
|
|
self._win_y = y
|
|
self.bw = w
|
|
self.bh = h - TITLE_H - 2
|
|
if self.win_id < 0:
|
|
self.win_id = window.create_window(x, y, w, h, c.Addr(self._title[0]), self.style)
|
|
self.buf = window.get_winbuf(self.win_id)
|
|
window.set_resizable(self.win_id, self.resizable_w, self.resizable_h)
|
|
else:
|
|
window.set_geometry(self.win_id, x, y, w, h)
|
|
self.buf = window.get_winbuf(self.win_id)
|
|
|
|
def setup(self, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt):
|
|
self._win_x = x
|
|
self._win_y = y
|
|
self.win_id = window.create_window(x, y, w, h, title, style)
|
|
self.buf = window.get_winbuf(self.win_id)
|
|
self.bw = w
|
|
self.bh = h - TITLE_H - 2
|
|
self.style = style
|
|
self.bg_color = t.CUInt32T(0xFF231919)
|
|
|
|
def redraw(self):
|
|
self._do_layout()
|
|
self.buf = window.get_winbuf(self.win_id)
|
|
sz: t.CInt = window.get_win_size(self.win_id)
|
|
if sz != 0:
|
|
self.bw = sz >> 16
|
|
self.bh = sz & 0xFFFF
|
|
if not self.buf: return
|
|
if self.bw <= 0 or self.bh <= 0: return
|
|
_fill_rect(self.buf, self.bw, self.bh, 0, 0, self.bw, self.bh, self.bg_color)
|
|
i: t.CInt = 0
|
|
while i < self.widget_count:
|
|
w: Widget | t.CPtr = self.widgets[i]
|
|
if w.visible:
|
|
w.draw(self.buf, self.bw, self.bh)
|
|
i += 1
|
|
window.flush(self.win_id)
|
|
|
|
def _do_layout(self):
|
|
self._grid_rows = 0
|
|
self._grid_cols = 0
|
|
cav_x: t.CInt = 0
|
|
cav_y: t.CInt = 0
|
|
cav_w: t.CInt = self.bw
|
|
cav_h: t.CInt = self.bh
|
|
i: t.CInt = 0
|
|
while i < self.widget_count:
|
|
w: Widget | t.CPtr = self.widgets[i]
|
|
lt: t.CInt = _g_wl_type[i]
|
|
if lt == 2:
|
|
side: t.CInt = _g_wl_side[i]
|
|
fill: t.CInt = _g_wl_fill[i]
|
|
expand: t.CInt = _g_wl_expand[i]
|
|
px: t.CInt = _g_wl_padx[i]
|
|
py: t.CInt = _g_wl_pady[i]
|
|
ww: t.CInt = w.w
|
|
wh: t.CInt = w.h
|
|
if side == PACK_TOP:
|
|
if fill == FILL_X or fill == FILL_BOTH:
|
|
ww = cav_w - 2 * px
|
|
if expand:
|
|
if fill == FILL_Y or fill == FILL_BOTH:
|
|
wh = cav_h - 2 * py
|
|
w.x = cav_x + px
|
|
w.y = cav_y + py
|
|
w.w = ww
|
|
w.h = wh
|
|
cav_y += wh + 2 * py
|
|
cav_h -= wh + 2 * py
|
|
elif side == PACK_BOTTOM:
|
|
if fill == FILL_X or fill == FILL_BOTH:
|
|
ww = cav_w - 2 * px
|
|
if expand:
|
|
if fill == FILL_Y or fill == FILL_BOTH:
|
|
wh = cav_h - 2 * py
|
|
w.x = cav_x + px
|
|
w.y = cav_y + cav_h - wh - py
|
|
w.w = ww
|
|
w.h = wh
|
|
cav_h -= wh + 2 * py
|
|
elif side == PACK_LEFT:
|
|
if fill == FILL_Y or fill == FILL_BOTH:
|
|
wh = cav_h - 2 * py
|
|
if expand:
|
|
if fill == FILL_X or fill == FILL_BOTH:
|
|
ww = cav_w - 2 * px
|
|
w.x = cav_x + px
|
|
w.y = cav_y + py
|
|
w.w = ww
|
|
w.h = wh
|
|
cav_x += ww + 2 * px
|
|
cav_w -= ww + 2 * px
|
|
elif side == PACK_RIGHT:
|
|
if fill == FILL_Y or fill == FILL_BOTH:
|
|
wh = cav_h - 2 * py
|
|
if expand:
|
|
if fill == FILL_X or fill == FILL_BOTH:
|
|
ww = cav_w - 2 * px
|
|
w.x = cav_x + cav_w - ww - px
|
|
w.y = cav_y + py
|
|
w.w = ww
|
|
w.h = wh
|
|
cav_w -= ww + 2 * px
|
|
elif lt == 3:
|
|
r: t.CInt = _g_wl_row[i] + _g_wl_rowspan[i]
|
|
c: t.CInt = _g_wl_col[i] + _g_wl_colspan[i]
|
|
if r > self._grid_rows: self._grid_rows = r
|
|
if c > self._grid_cols: self._grid_cols = c
|
|
i += 1
|
|
i = 0
|
|
while i < self.widget_count:
|
|
w: Widget | t.CPtr = self.widgets[i]
|
|
if _g_wl_type[i] == 3:
|
|
if self._grid_rows <= 0: self._grid_rows = 1
|
|
if self._grid_cols <= 0: self._grid_cols = 1
|
|
cell_w: t.CInt = self.bw / self._grid_cols
|
|
cell_h: t.CInt = self.bh / self._grid_rows
|
|
wx: t.CInt = _g_wl_col[i] * cell_w
|
|
wy: t.CInt = _g_wl_row[i] * cell_h
|
|
ww: t.CInt = _g_wl_colspan[i] * cell_w
|
|
wh: t.CInt = _g_wl_rowspan[i] * cell_h
|
|
sticky: t.CInt = _g_wl_sticky[i]
|
|
if sticky == 0:
|
|
ox: t.CInt = (ww - w.w) / 2
|
|
oy: t.CInt = (wh - w.h) / 2
|
|
w.x = wx + ox
|
|
w.y = wy + oy
|
|
else:
|
|
w.x = wx
|
|
w.y = wy
|
|
if (sticky & 1) != 0:
|
|
w.w = ww
|
|
if (sticky & 2) != 0:
|
|
w.h = wh
|
|
i += 1
|
|
|
|
def update(self):
|
|
self.redraw()
|
|
|
|
def winfo_exists(self) -> t.CInt:
|
|
if self.win_id < 0: return 0
|
|
return window.is_active(self.win_id)
|
|
|
|
def mainloop(self):
|
|
self.redraw()
|
|
evt: window.InputEvent
|
|
while window.is_active(self.win_id):
|
|
result: t.CInt = window.poll_event(c.Addr(evt))
|
|
if result != 0:
|
|
if evt.win_id == self.win_id:
|
|
need_redraw: t.CInt = 0
|
|
etype: t.CUInt32T = evt.type
|
|
if etype == window.EVENT_TYPE_PING:
|
|
window.flush(self.win_id)
|
|
elif etype == window.EVENT_TYPE_RESIZE:
|
|
self.buf = window.get_winbuf(self.win_id)
|
|
sz: t.CInt = window.get_win_size(self.win_id)
|
|
self.bw = sz >> 16
|
|
self.bh = sz & 0xFFFF
|
|
need_redraw = 1
|
|
elif etype == window.EVENT_TYPE_KEY or etype == window.EVENT_TYPE_KEY_RELEASE:
|
|
if self.focused_widget is not None:
|
|
handled: t.CInt = self.focused_widget.handle_event(c.Addr(evt))
|
|
if handled: need_redraw = 1
|
|
else:
|
|
if etype == window.EVENT_TYPE_HOVER:
|
|
i: t.CInt = self.widget_count - 1
|
|
while i >= 0:
|
|
w: Widget | t.CPtr = self.widgets[i]
|
|
if w.visible:
|
|
handled2: t.CInt = w.handle_event(c.Addr(evt))
|
|
if handled2:
|
|
need_redraw = 1
|
|
break
|
|
i -= 1
|
|
else:
|
|
i: t.CInt = 0
|
|
while i < self.widget_count:
|
|
w: Widget | t.CPtr = self.widgets[i]
|
|
if w.visible:
|
|
handled2: t.CInt = w.handle_event(c.Addr(evt))
|
|
if handled2: need_redraw = 1
|
|
i += 1
|
|
if need_redraw:
|
|
self.redraw()
|
|
else:
|
|
process.yield_cpu()
|