1520 lines
63 KiB
Plaintext
1520 lines
63 KiB
Plaintext
import vpsdk.window as window
|
||
import vpsdk.process as process
|
||
import vpsdk.syscall as _syscall
|
||
from stdint import *
|
||
import t, c
|
||
import string
|
||
|
||
define TITLE_H = 32
|
||
define MAX_WIDGETS = 24
|
||
define CHAR_W = 8
|
||
define CHAR_H = 16
|
||
|
||
define WIDGET_LABEL = 1
|
||
define WIDGET_BUTTON = 2
|
||
define WIDGET_ENTRY = 3
|
||
define WIDGET_TEXT = 4
|
||
define WIDGET_SCROLLBAR = 5
|
||
define WIDGET_FBCANVAS = 6
|
||
|
||
define VERTICAL = 1
|
||
define HORIZONTAL = 2
|
||
define TEXT_MAX_LINES = 200
|
||
|
||
define PACK_TOP = 1
|
||
define PACK_BOTTOM = 2
|
||
define PACK_LEFT = 3
|
||
define PACK_RIGHT = 4
|
||
|
||
define FILL_NONE = 0
|
||
define FILL_X = 1
|
||
define FILL_Y = 2
|
||
define FILL_BOTH = 3
|
||
|
||
define STICKY_NONE = 0
|
||
define STICKY_W = 1
|
||
define STICKY_E = 2
|
||
define STICKY_N = 4
|
||
define STICKY_S = 8
|
||
define STICKY_NSEW = 15
|
||
|
||
_g_wl_type: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_side: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_fill: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_expand: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_padx: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_pady: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_row: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_col: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_rowspan: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_colspan: t.CArray[int, MAX_WIDGETS]
|
||
_g_wl_sticky: t.CArray[int, MAX_WIDGETS]
|
||
_g_layout_init: int
|
||
|
||
_hex_tbl: t.CArray[char, 17] = "0123456789ABCDEF"
|
||
_hex_buf: t.CArray[char, 20] = "0000000000000000000"
|
||
|
||
def _serial_puts(s: const str):
|
||
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(s))
|
||
|
||
def _ptr_to_hex(val: uint64, buf: t.CPtr):
|
||
buf[0] = 48
|
||
buf[1] = 120
|
||
i: int = 15
|
||
while i >= 0:
|
||
nibble: int = int(val & uint64(0xF))
|
||
buf[2 + i] = _hex_tbl[nibble]
|
||
val = val >> 4
|
||
i -= 1
|
||
buf[18] = 0
|
||
|
||
def _fill_rect(fb: UINT32PTR, fw: int, fh: int, x1: int, y1: int, w: int, h: int, color: uint32):
|
||
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: int, fh: int, x1: int, y: int, w: int, color: uint32):
|
||
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: int, fh: int, x: int, y1: int, h: int, color: uint32):
|
||
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: uint32, amount: int) -> uint32:
|
||
r: int = int(color & 0xFF)
|
||
g: int = int((color >> 8) & 0xFF)
|
||
b: int = int((color >> 16) & 0xFF)
|
||
r = r + ((255 - r) * amount) / 256
|
||
g = g + ((255 - g) * amount) / 256
|
||
b = b + ((255 - b) * amount) / 256
|
||
return uint32(r | (g << 8) | (b << 16))
|
||
|
||
def _darken(color: uint32, amount: int) -> uint32:
|
||
r: int = int(color & 0xFF)
|
||
g: int = int((color >> 8) & 0xFF)
|
||
b: int = int((color >> 16) & 0xFF)
|
||
r = r - (r * amount) / 256
|
||
g = g - (g * amount) / 256
|
||
b = b - (b * amount) / 256
|
||
return uint32(r | (g << 8) | (b << 16))
|
||
|
||
|
||
font: t.CArray[t.CArray[uint8, 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: int, bh: int, x: int, y: int, ch: char, color: uint32):
|
||
if not buf: return
|
||
if bw <= 0 or bh <= 0: return
|
||
ci: uint8 = uint8(ch)
|
||
if ci >= 128: ci = 0
|
||
fy: int = 0
|
||
while fy < CHAR_H:
|
||
if y + fy < 0 or y + fy >= bh:
|
||
fy += 1
|
||
continue
|
||
row: uint8 = font[ci][fy]
|
||
if row == 0:
|
||
fy += 1
|
||
continue
|
||
for fx in range(CHAR_W):
|
||
if row & (0x80 >> fx):
|
||
px: int = x + fx
|
||
if px >= 0 and px < bw:
|
||
buf[(y + fy) * bw + px] = color
|
||
fy += 1
|
||
|
||
def _draw_text(buf: UINT32PTR, bw: int, bh: int, x: int, y: int, s: const str, color: uint32):
|
||
if not buf: return
|
||
if bw <= 0 or bh <= 0: return
|
||
cx: int = x
|
||
cy: int = y
|
||
i: int = 0
|
||
while True:
|
||
ch: char = 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.CPtr, widget: Widget*) -> int:
|
||
tk: Tk* = t.CType(master, Tk, t.CPtr)
|
||
idx: int = tk.widget_count
|
||
if idx < MAX_WIDGETS:
|
||
tk.widgets[idx] = widget
|
||
tk.widget_count = idx + 1
|
||
return idx
|
||
|
||
virtual class Widget:
|
||
x: int
|
||
y: int
|
||
w: int
|
||
h: int
|
||
visible: int
|
||
master: t.CPtr
|
||
widget_type: int
|
||
focused: int
|
||
hovered: int
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
pass
|
||
|
||
def handle_event(self, evt: window.InputEvent*) -> int:
|
||
return 0
|
||
|
||
def contains(self, px: int, py: int) -> int:
|
||
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: int = 0, y: int = 0, w: int = 0, h: int = 0):
|
||
self.x = x
|
||
self.y = y
|
||
if w > 0:
|
||
self.w = w
|
||
if h > 0:
|
||
self.h = h
|
||
|
||
virtual class Label(Widget):
|
||
text: t.CArray[char, 64]
|
||
color: uint32
|
||
|
||
def __init__(self, master: t.CPtr, text: str, color: uint32):
|
||
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: int = 0
|
||
for ch in text:
|
||
if i >= 63: break
|
||
self.text[i] = ch
|
||
i += 1
|
||
self.text[i] = 0
|
||
_register_widget(master, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
_draw_text(fb, fw, fh, self.x, self.y, &self.text[0], self.color)
|
||
|
||
def handle_event(self, evt: window.InputEvent*) -> int:
|
||
return 0
|
||
|
||
def config(self, text: const str = None, color: uint32 = None):
|
||
if text is not None:
|
||
i: int = 0
|
||
while i < 63:
|
||
ch: char = *(text + i)
|
||
self.text[i] = ch
|
||
if ch == 0: break
|
||
i += 1
|
||
self.text[i] = 0
|
||
if color is not None:
|
||
self.color = color
|
||
|
||
virtual class Button(Widget):
|
||
text: t.CArray[char, 32]
|
||
fill_color: uint32
|
||
text_color: uint32
|
||
pressed: int
|
||
callback: t.CPtr
|
||
|
||
def __init__(self, master: t.CPtr, w: int, h: int, text: str, callback: 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 = uint32(0x3C3C5A)
|
||
self.text_color = uint32(0xFFFFFFFF)
|
||
self.pressed = 0
|
||
self.callback = callback
|
||
i: int = 0
|
||
for ch in text:
|
||
if i >= 31: break
|
||
self.text[i] = ch
|
||
i += 1
|
||
self.text[i] = 0
|
||
_register_widget(master, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
fill: uint32 = self.fill_color
|
||
border: uint32 = uint32(0x8080B0)
|
||
if self.pressed:
|
||
fill = _lighten(self.fill_color, 60)
|
||
border = uint32(0xA0A0D0)
|
||
elif self.hovered:
|
||
fill = _lighten(self.fill_color, 30)
|
||
border = uint32(0xA0A0D0)
|
||
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, fill)
|
||
top_left: uint32 = _lighten(fill, 80)
|
||
bottom_right: uint32 = _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: int = int(string.strlen(&self.text[0]))
|
||
tx: int = self.x + (self.w - 8 * tl) / 2
|
||
ty: int = self.y + (self.h - CHAR_H) / 2
|
||
_draw_text(fb, fw, fh, tx, ty, &self.text[0], self.text_color)
|
||
|
||
def handle_event(self, evt: window.InputEvent*) -> int:
|
||
etype: uint32 = evt.type
|
||
ex: int = evt.x
|
||
ey: int = 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:
|
||
# 闭包调用约定(VPC 生成):callback 是堆上的 {fn, env} 对象,fn 期望 rdi = env。
|
||
# 之前直接 `call r13`(r13 = 闭包对象地址)会跳到堆上执行
|
||
# (现场:rip=0x2040400a 在堆区、cr2=0x1、err=0x5)。
|
||
c.Asm(f"""push r12
|
||
push r13
|
||
mov r13, {c.AsmInp(self.callback, t.ASM_DESCR.REG_ANY)}
|
||
mov rdi, qword ptr [r13 + 8]
|
||
mov r12, rsp
|
||
and rsp, -16
|
||
call qword ptr [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: const str = None, fill_color: uint32 = None, text_color: uint32 = None, callback: t.CPtr = None):
|
||
if text is not None:
|
||
i: int = 0
|
||
while i < 31:
|
||
ch: char = *(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
|
||
|
||
virtual class Entry(Widget):
|
||
text: t.CArray[char, 64]
|
||
text_len: int
|
||
cursor_pos: int
|
||
max_len: int
|
||
bg_color: uint32
|
||
border_color: uint32
|
||
text_color: uint32
|
||
cursor_color: uint32
|
||
|
||
def __init__(self, master: t.CPtr, w: int, h: int):
|
||
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 = uint32(0xFF231919)
|
||
self.border_color = uint32(0x606080)
|
||
self.text_color = uint32(0x000000)
|
||
self.cursor_color = uint32(0x000000)
|
||
for i in range(64):
|
||
self.text[i] = 0
|
||
_register_widget(master, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
bg: uint32 = self.bg_color
|
||
bdr: uint32 = self.border_color
|
||
if self.focused:
|
||
bg = uint32(0xFFFFFF)
|
||
bdr = uint32(0x4488FF)
|
||
elif self.hovered:
|
||
bdr = uint32(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: uint32 = self.text_color
|
||
if not self.focused:
|
||
tc = uint32(0xCCCCCC)
|
||
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, &self.text[0], tc)
|
||
elif not self.focused:
|
||
_draw_text(fb, fw, fh, self.x + 6, self.y + 7, "Type here...", uint32(0x888888))
|
||
if self.focused:
|
||
cx_pos: int = 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*) -> int:
|
||
etype: uint32 = evt.type
|
||
ex: int = evt.x
|
||
ey: int = evt.y
|
||
if etype == window.EVENT_TYPE_HOVER:
|
||
if self.contains(ex, ey):
|
||
if not self.hovered:
|
||
self.hovered = 1
|
||
tk: Tk* = 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.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.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.CType(self.master, Tk, t.CPtr)
|
||
tk4.focused_widget = Widget*(self)
|
||
rel_x: int = ex - self.x - 6
|
||
if rel_x < 0: rel_x = 0
|
||
new_pos: int = (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.CType(self.master, Tk, t.CPtr)
|
||
tk5.focused_widget = None
|
||
return 1
|
||
elif etype == window.EVENT_TYPE_KEY:
|
||
if self.focused:
|
||
ebtn: uint8 = evt.button
|
||
if ebtn == window.KEY_STATE_RELEASE:
|
||
return 0
|
||
ch: int = 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: int = self.text_len
|
||
while i > self.cursor_pos:
|
||
self.text[i] = self.text[i - 1]
|
||
i -= 1
|
||
self.text[self.cursor_pos] = char(ch)
|
||
self.text_len += 1
|
||
self.cursor_pos += 1
|
||
self.text[self.text_len] = 0
|
||
return 1
|
||
return 0
|
||
|
||
def get(self) -> const str:
|
||
return &self.text[0]
|
||
|
||
def delete(self, start: int, end: int):
|
||
self.text_len = 0
|
||
for i in range(64):
|
||
self.text[i] = 0
|
||
|
||
def config(self, bg_color: uint32 = None, text_color: uint32 = None, border_color: uint32 = 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
|
||
|
||
virtual class Scrollbar(Widget):
|
||
orient: int
|
||
command: t.CPtr
|
||
slider_first: int
|
||
slider_last: int
|
||
action: int
|
||
action_value: int
|
||
pressed: int
|
||
dragging: int
|
||
drag_start_y: int
|
||
drag_start_first: int
|
||
trough_color: uint32
|
||
slider_color: uint32
|
||
arrow_color: uint32
|
||
slider_hover: int
|
||
|
||
def __init__(self, master: t.CPtr, w: int, h: int, orient: int):
|
||
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 = uint32(0x1E1E2E)
|
||
self.slider_color = uint32(0x4A4A6A)
|
||
self.arrow_color = uint32(0xAAAAAA)
|
||
self.slider_hover = 0
|
||
_register_widget(master, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
_fill_rect(fb, fw, fh, self.x, self.y, self.w, self.h, self.trough_color)
|
||
if self.orient != VERTICAL: return
|
||
arrow_sz: int = 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: int = self.y + arrow_sz
|
||
trough_h: int = self.h - 2 * arrow_sz
|
||
if trough_h <= 0: return
|
||
if self.slider_last > self.slider_first:
|
||
sl_h: int = (self.slider_last - self.slider_first) * trough_h / 1000
|
||
if sl_h < 8: sl_h = 8
|
||
sl_y: int = 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: uint32 = 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: uint32 = _lighten(color, 60)
|
||
bot_c: uint32 = _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: int, fh: int, bx: int, by: int, bw: int, bh: int, direction: int, is_pressed: int):
|
||
color: uint32 = self.slider_color
|
||
if is_pressed:
|
||
color = _lighten(self.slider_color, 30)
|
||
_fill_rect(fb, fw, fh, bx, by, bw, bh, color)
|
||
top_c: uint32 = _lighten(color, 60)
|
||
bot_c: uint32 = _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: int = bx + bw / 2
|
||
cy: int = 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*) -> int:
|
||
etype: uint32 = evt.type
|
||
ex: int = evt.x
|
||
ey: int = 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: int = 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: int = self.y + arrow_sz
|
||
trough_h: int = self.h - 2 * arrow_sz
|
||
if trough_h <= 0: return 1
|
||
sl_h: int = (self.slider_last - self.slider_first) * trough_h / 1000
|
||
if sl_h < 8: sl_h = 8
|
||
sl_y: int = 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: int):
|
||
arrow_sz: int = self.w
|
||
if arrow_sz > 16: arrow_sz = 16
|
||
trough_y: int = self.y + arrow_sz
|
||
trough_h: int = self.h - 2 * arrow_sz
|
||
if trough_h <= 0: return
|
||
delta_y: int = ey - self.drag_start_y
|
||
delta_first: int = delta_y * 1000 / trough_h
|
||
new_first: int = self.drag_start_first + delta_first
|
||
slider_size: int = 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:
|
||
# 同 Button.handle_event:command 是闭包 {fn, env},必须 rdi = env 后 call fn。
|
||
c.Asm(f"""push r12
|
||
push r13
|
||
mov r13, {c.AsmInp(self.command, t.ASM_DESCR.REG_ANY)}
|
||
mov rdi, qword ptr [r13 + 8]
|
||
mov r12, rsp
|
||
and rsp, -16
|
||
call qword ptr [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: int, last: int):
|
||
self.slider_first = first
|
||
self.slider_last = last
|
||
|
||
virtual class FBCanvas(Widget):
|
||
_fb: UINT32PTR
|
||
_cw: int
|
||
_ch: int
|
||
|
||
def __init__(self, master: t.CPtr, w: int, h: int):
|
||
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, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
if not self._fb: return
|
||
if self._cw <= 0 or self._ch <= 0: return
|
||
copy_w: int = self._cw
|
||
if copy_w > self.w: copy_w = self.w
|
||
copy_h: int = self._ch
|
||
if copy_h > self.h: copy_h = self.h
|
||
for py in range(copy_h):
|
||
ty: int = self.y + py
|
||
if ty < 0 or ty >= fh: continue
|
||
for px in range(copy_w):
|
||
tx: int = 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*) -> int:
|
||
return 0
|
||
|
||
def set_fb(self, fb: UINT32PTR, cw: int, ch: int):
|
||
self._fb = fb
|
||
self._cw = cw
|
||
self._ch = ch
|
||
|
||
def get_fb(self) -> UINT32PTR:
|
||
return self._fb
|
||
|
||
def get_w(self) -> int:
|
||
return self._cw
|
||
|
||
def get_h(self) -> int:
|
||
return self._ch
|
||
|
||
virtual class Text(Widget):
|
||
lines: t.CArray[t.CArray[char, 80], TEXT_MAX_LINES]
|
||
line_count: int
|
||
input_buf: t.CArray[char, 80]
|
||
input_len: int
|
||
cursor_pos: int
|
||
bg_color: uint32
|
||
text_color: uint32
|
||
prompt_color: uint32
|
||
cursor_color: uint32
|
||
border_color: uint32
|
||
on_command: t.CPtr
|
||
history: t.CArray[t.CArray[char, 80], 16]
|
||
history_count: int
|
||
history_idx: int
|
||
scroll_offset: int
|
||
max_lines: int
|
||
yscrollbar: t.CPtr
|
||
|
||
def __init__(self, master: t.CPtr, w: int, h: int):
|
||
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 = uint32(0x0C0C0C)
|
||
self.text_color = uint32(0xCCCCCC)
|
||
self.prompt_color = uint32(0x00FF00)
|
||
self.cursor_color = uint32(0x00FF00)
|
||
self.border_color = uint32(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
|
||
for i in range(TEXT_MAX_LINES):
|
||
for j in range(79 + 1):
|
||
self.lines[i][j] = 0
|
||
for i in range(80):
|
||
self.input_buf[i] = 0
|
||
_register_widget(master, Widget*(self))
|
||
|
||
def draw(self, fb: UINT32PTR, fw: int, fh: int):
|
||
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: int = self._visible_lines()
|
||
for i in range(visible):
|
||
line_idx: int = self.scroll_offset + i
|
||
if line_idx < self.line_count:
|
||
_draw_text(fb, fw, fh, self.x + 4, self.y + i * CHAR_H, &self.lines[line_idx][0], self.text_color)
|
||
prompt_y: int = 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, &self.input_buf[0], uint32(0xFFFFFF))
|
||
cx_pos: int = 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*) -> int:
|
||
etype: uint32 = evt.type
|
||
ex: int = evt.x
|
||
ey: int = evt.y
|
||
if etype == window.EVENT_TYPE_CLICK:
|
||
if self.contains(ex, ey):
|
||
if not self.focused:
|
||
self.focused = 1
|
||
tk: Tk* = t.CType(self.master, Tk, t.CPtr)
|
||
tk.focused_widget = Widget*(self)
|
||
prompt_y: int = self.y + self.h - CHAR_H - 4
|
||
if ey >= prompt_y and ey < prompt_y + CHAR_H:
|
||
rel_x: int = ex - self.x - 4 - 2 * CHAR_W
|
||
if rel_x < 0: rel_x = 0
|
||
new_pos: int = (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.CType(self.master, Tk, t.CPtr)
|
||
tk2.focused_widget = None
|
||
return 1
|
||
elif etype == window.EVENT_TYPE_KEY:
|
||
if self.focused:
|
||
ebtn2: uint8 = evt.button
|
||
if ebtn2 == window.KEY_STATE_RELEASE:
|
||
return 0
|
||
ch: int = ex
|
||
if ch == 8:
|
||
if self.cursor_pos > 0:
|
||
i: int = 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: int = 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: int = 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: int = 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: int = 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: int = self._visible_lines()
|
||
max_off: int = 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: int = 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] = char(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: int = self.line_count - 1
|
||
j: int = 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:
|
||
for k in range(80):
|
||
self.history[self.history_count][k] = self.input_buf[k]
|
||
self.history_count += 1
|
||
else:
|
||
for i in range(15):
|
||
for k2 in range(80):
|
||
self.history[i][k2] = self.history[i + 1][k2]
|
||
for k3 in range(80):
|
||
self.history[15][k3] = self.input_buf[k3]
|
||
self.history_idx = 0
|
||
|
||
cmd: t.CPtr = self.on_command
|
||
if cmd is not None:
|
||
# 同 Button.handle_event:on_command 是闭包 {fn, env},必须 rdi = env 后 call fn。
|
||
c.Asm(f"""push r12
|
||
push r13
|
||
mov r13, {c.AsmInp(cmd, t.ASM_DESCR.REG_ANY)}
|
||
mov rdi, qword ptr [r13 + 8]
|
||
mov r12, rsp
|
||
and rsp, -16
|
||
call qword ptr [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: int = 0
|
||
pos: int = 0
|
||
while True:
|
||
ch: char = *(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: const str):
|
||
start: int = 0
|
||
pos: int = 0
|
||
while True:
|
||
ch: char = *(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: const str, start: int, end: int):
|
||
if self.line_count >= self.max_lines:
|
||
for i in range(self.max_lines - 1):
|
||
for j in range(79 + 1):
|
||
self.lines[i][j] = self.lines[i + 1][j]
|
||
self.line_count -= 1
|
||
if self.scroll_offset > 0:
|
||
self.scroll_offset -= 1
|
||
idx: int = self.line_count
|
||
j: int = 0
|
||
k: int = start
|
||
while k < end and j < 79:
|
||
ch: char = *(text + k)
|
||
if ch == 9:
|
||
tab_stop: int = 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: int = 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: int, end: int):
|
||
self.line_count = 0
|
||
self.scroll_offset = 0
|
||
self._update_scrollbar()
|
||
|
||
def get(self) -> const str:
|
||
return &self.input_buf[0]
|
||
|
||
def config(self, text_color: uint32 = None, bg_color: uint32 = None, prompt_color: uint32 = None, cursor_color: uint32 = None, border_color: uint32 = 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) -> int:
|
||
return (self.h - CHAR_H - 4) / CHAR_H
|
||
|
||
def _update_scrollbar(self):
|
||
vis: int = self._visible_lines()
|
||
if self.line_count <= vis:
|
||
self.scroll_offset = 0
|
||
else:
|
||
max_off: int = self.line_count - vis
|
||
if self.scroll_offset > max_off:
|
||
self.scroll_offset = max_off
|
||
if self.yscrollbar is not None:
|
||
sb: Scrollbar* = t.CType(self.yscrollbar, Scrollbar, t.CPtr)
|
||
if self.line_count <= vis:
|
||
sb.set(0, 1000)
|
||
else:
|
||
first: int = self.scroll_offset * 1000 / self.line_count
|
||
last: int = (self.scroll_offset + vis) * 1000 / self.line_count
|
||
sb.set(first, last)
|
||
|
||
@t.Object
|
||
class Tk:
|
||
win_id: int
|
||
buf: UINT32PTR
|
||
bw: int
|
||
bh: int
|
||
style: int
|
||
bg_color: uint32
|
||
widgets: t.CArray[Widget*, MAX_WIDGETS]
|
||
widget_count: int
|
||
focused_widget: Widget*
|
||
_win_x: int
|
||
_win_y: int
|
||
_title: t.CArray[char, 32]
|
||
resizable_w: int
|
||
resizable_h: int
|
||
_grid_rows: int
|
||
_grid_cols: int
|
||
|
||
def __init__(self):
|
||
global _g_layout_init
|
||
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 = uint32(0xFF231919)
|
||
self.resizable_w = 1
|
||
self.resizable_h = 1
|
||
self._grid_rows = 0
|
||
self._grid_cols = 0
|
||
if _g_layout_init == 0:
|
||
for i in range(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
|
||
_g_layout_init = 1
|
||
for j in range(32):
|
||
self._title[j] = 0
|
||
|
||
def pack(self, idx: int, side: int, fill: int, expand: int, padx: int, pady: int):
|
||
_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: int, row: int, col: int, rowspan: int, colspan: int, sticky: int):
|
||
_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: int = 0
|
||
while i < 31:
|
||
ch: char = 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, &self._title[0])
|
||
|
||
def set_style(self, s: int):
|
||
self.style = s
|
||
|
||
def resizable(self, rw: int, rh: int):
|
||
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: int, y: int, w: int, h: int):
|
||
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, &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: int, y: int, w: int, h: int, title: const str, style: int):
|
||
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 = uint32(0xFF231919)
|
||
|
||
def redraw(self):
|
||
self._do_layout()
|
||
self.buf = window.get_winbuf(self.win_id)
|
||
sz: int = 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)
|
||
for i in range(self.widget_count):
|
||
w: Widget* = self.widgets[i]
|
||
if w.visible:
|
||
w.draw(self.buf, self.bw, self.bh)
|
||
window.flush(self.win_id)
|
||
|
||
def _do_layout(self):
|
||
self._grid_rows = 0
|
||
self._grid_cols = 0
|
||
cav_x: int = 0
|
||
cav_y: int = 0
|
||
cav_w: int = self.bw
|
||
cav_h: int = self.bh
|
||
for i in range(self.widget_count):
|
||
w: Widget* = self.widgets[i]
|
||
lt: int = _g_wl_type[i]
|
||
if lt == 2:
|
||
side: int = _g_wl_side[i]
|
||
fill: int = _g_wl_fill[i]
|
||
expand: int = _g_wl_expand[i]
|
||
px: int = _g_wl_padx[i]
|
||
py: int = _g_wl_pady[i]
|
||
ww: int = w.w
|
||
wh: int = 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: int = _g_wl_row[i] + _g_wl_rowspan[i]
|
||
c: int = _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
|
||
for i in range(self.widget_count):
|
||
w: Widget* = 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: int = self.bw / self._grid_cols
|
||
cell_h: int = self.bh / self._grid_rows
|
||
wx: int = _g_wl_col[i] * cell_w
|
||
wy: int = _g_wl_row[i] * cell_h
|
||
ww: int = _g_wl_colspan[i] * cell_w
|
||
wh: int = _g_wl_rowspan[i] * cell_h
|
||
sticky: int = _g_wl_sticky[i]
|
||
if sticky == 0:
|
||
ox: int = (ww - w.w) / 2
|
||
oy: int = (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
|
||
|
||
def update(self):
|
||
self.redraw()
|
||
|
||
def winfo_exists(self) -> int:
|
||
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: int = window.poll_event(&evt)
|
||
if result != 0:
|
||
if evt.win_id == self.win_id:
|
||
need_redraw: int = 0
|
||
etype: uint32 = 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: int = 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: int = self.focused_widget.handle_event(&evt)
|
||
if handled: need_redraw = 1
|
||
else:
|
||
if etype == window.EVENT_TYPE_HOVER:
|
||
i: int = self.widget_count - 1
|
||
while i >= 0:
|
||
w: Widget* = self.widgets[i]
|
||
if w.visible:
|
||
handled2: int = w.handle_event(&evt)
|
||
if handled2:
|
||
need_redraw = 1
|
||
break
|
||
i -= 1
|
||
else:
|
||
for i in range(self.widget_count):
|
||
w: Widget* = self.widgets[i]
|
||
if w.visible:
|
||
handled2: int = w.handle_event(&evt)
|
||
if handled2: need_redraw = 1
|
||
if need_redraw:
|
||
self.redraw()
|
||
else:
|
||
process.yield_cpu()
|