Files
TransPyC/includes/fltk/__init__.vp
T
TermiNexus 6892183cc9 feat(fltk): 新增 FLTK 1.4 纯 extern FFI 绑定库(对接 cfltk C API)
- 生成 24 个 _cfl*.vp(10327 条 extern 声明)+ _types/_enums 常量

- __init__.vp 提供 Fl/Fl_Widget/Fl_Window/Fl_Button/Fl_Input/Fl_Text_Buffer/Fl_Group/Fl_Menu_Bar/Fl_Native_File_Chooser 等包装类

- 回调(Fl_Callback)按 bytes 不透明处理,菜单回调位传 t.CPtr(0)

- 新增 examples/hello.vp、dialog.vp 冒烟样例,26 个 .vp 全部通过 vast parse

- 内嵌 cfltk(C API 封装)与 FLTK 1.4 完整源码,构建目标 cfltk2
2026-09-01 19:53:54 +08:00

819 lines
22 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================
# fltk — Viper 的 FLTK GUI 绑定包(对接 cfltk C API)
#
# 用户用法:
# import fltk
# win = fltk.Fl_Window(400, 300, "Hello")
# box = fltk.Fl_Box(10, 10, 380, 40, "Hello, World!")
# btn = fltk.Fl_Button(150, 100, 100, 30, "Click")
# win.end()
# win.show()
# fltk.Fl.run()
#
# 说明:
# * 本包只做 extern FFI(fltk._cfl* 模块)+ 少量 Pythonic 包装类;
# 所有 FLTK 对象都是不透明指针,方法即 cfltk 的 Fl_<类>_<动作>。
# * 完整 C API 通过 `from fltk._cfl import *` 等直接可用。
# * 回调(Fl_Callback 等)在 FFI 中按 bytes 不透明处理:Viper 端
# 暂无法传函数指针,事件驱动请用 Fl.check()/Fl.event*() 轮询。
# ============================================================
import t, c
from fltk._types import *
from fltk._enums import *
from fltk._cfl import *
from fltk._cfl_widget import *
from fltk._cfl_box import *
from fltk._cfl_button import *
from fltk._cfl_window import *
from fltk._cfl_input import *
from fltk._cfl_text import *
from fltk._cfl_group import *
from fltk._cfl_valuator import *
from fltk._cfl_menu import *
from fltk._cfl_dialog import *
from fltk._cfl_image import *
from fltk._cfl_draw import *
from fltk._cfl_misc import *
from fltk._cfl_browser import *
from fltk._cfl_table import *
from fltk._cfl_tree import *
from fltk._cfl_term import *
from fltk._cfl_prefs import *
from fltk._cfl_printer import *
from fltk._cfl_surface import *
from fltk._cfl_utils import *
from fltk._cfl_lock import *
# ============================================================
# Fl — FLTK 全局静态类(事件循环 / 事件 / 颜色)
# ============================================================
@t.NoVTable
class Fl:
"""FLTK 全局函数集合(静态方法)"""
@staticmethod
def run() -> int:
return Fl_run()
@staticmethod
def check() -> int:
return Fl_check()
@staticmethod
def wait() -> int:
return Fl_wait()
@staticmethod
def wait_for(timeout: t.CDouble) -> t.CDouble:
return Fl_wait_for(timeout)
@staticmethod
def flush():
Fl_flush()
@staticmethod
def redraw():
Fl_redraw()
@staticmethod
def lock() -> int:
return Fl_lock()
@staticmethod
def unlock():
Fl_unlock()
@staticmethod
def event() -> int:
return Fl_event()
@staticmethod
def event_x() -> int:
return Fl_event_x()
@staticmethod
def event_y() -> int:
return Fl_event_y()
@staticmethod
def event_button() -> int:
return Fl_event_button()
@staticmethod
def event_key() -> int:
return Fl_event_key()
@staticmethod
def event_text() -> str:
return Fl_event_text()
@staticmethod
def event_length() -> int:
return Fl_event_length()
@staticmethod
def event_state() -> int:
return Fl_event_state()
@staticmethod
def event_inside(x: int, y: int, w: int, h: int) -> int:
return Fl_event_inside(x, y, w, h)
@staticmethod
def set_scheme(scheme: str) -> int:
return Fl_set_scheme(scheme)
@staticmethod
def visible_focus() -> int:
return Fl_visible_focus()
@staticmethod
def set_visible_focus(v: int):
Fl_set_visible_focus(v)
@staticmethod
def get_rgb_color(r: t.CUInt8T, g: t.CUInt8T, b: t.CUInt8T) -> t.CUInt32T:
return Fl_get_rgb_color(r, g, b)
@staticmethod
def set_color(c: t.CUInt32T, r: t.CUInt8T, g: t.CUInt8T, b: t.CUInt8T):
Fl_set_color(c, r, g, b)
@staticmethod
def first_window() -> Fl_WindowPtr:
return Fl_first_window()
@staticmethod
def next_window(win: Fl_WindowPtr) -> Fl_WindowPtr:
return Fl_next_window(win)
@staticmethod
def set_font_size(size: int):
Fl_set_font_size(size)
@staticmethod
def font_size() -> int:
return Fl_font_size()
@staticmethod
def set_scrollbar_size(sz: int):
Fl_set_scrollbar_size(sz)
@staticmethod
def scrollbar_size() -> int:
return Fl_scrollbar_size()
@staticmethod
def scheme() -> int:
return Fl_scheme()
# 注意: 回调(Fl_Callback 等)Viper 端无法提供函数指针,add_timeout 等
# 需要真实回调的接口请直接使用 extern FFI 并配合 C 层钩子(_cfl.vp)。
# ============================================================
# Fl_Widget — 控件基类包装
# ============================================================
@t.NoVTable
class Fl_Widget:
"""FLTK 控件基类(不透明指针包装)"""
_ptr: Fl_WidgetPtr
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Widget_new(x, y, w, h, label)
def x(self) -> int:
return Fl_Widget_x(self._ptr)
def y(self) -> int:
return Fl_Widget_y(self._ptr)
def width(self) -> int:
return Fl_Widget_width(self._ptr)
def height(self) -> int:
return Fl_Widget_height(self._ptr)
def label(self) -> str:
return Fl_Widget_label(self._ptr)
def set_label(self, label: str):
Fl_Widget_set_label(self._ptr, label)
def show(self):
Fl_Widget_show(self._ptr)
def hide(self):
Fl_Widget_hide(self._ptr)
def activate(self):
Fl_Widget_activate(self._ptr)
def deactivate(self):
Fl_Widget_deactivate(self._ptr)
def redraw(self):
Fl_Widget_redraw(self._ptr)
def resize(self, x: int, y: int, w: int, h: int):
Fl_Widget_resize(self._ptr, x, y, w, h)
def set_color(self, color: t.CUInt32T):
Fl_Widget_set_color(self._ptr, color)
def color(self) -> t.CUInt32T:
return Fl_Widget_color(self._ptr)
def set_box(self, box: int):
Fl_Widget_set_box(self._ptr, box)
def box(self) -> int:
return Fl_Widget_box(self._ptr)
def set_align(self, align: int):
Fl_Widget_set_align(self._ptr, align)
def align(self) -> int:
return Fl_Widget_align(self._ptr)
def set_tooltip(self, tip: str):
Fl_Widget_set_tooltip(self._ptr, tip)
def tooltip(self) -> str:
return Fl_Widget_tooltip(self._ptr)
def parent(self) -> Fl_WidgetPtr:
return Fl_Widget_parent(self._ptr)
def window(self) -> Fl_WindowPtr:
return Fl_Widget_window(self._ptr)
def visible(self) -> int:
return Fl_Widget_visible(self._ptr)
def active(self) -> int:
return Fl_Widget_active(self._ptr)
def delete(self):
Fl_Widget_delete(self._ptr)
# ============================================================
# Fl_Window — 窗口包装
# ============================================================
@t.NoVTable
class Fl_Window(Fl_Widget):
"""FLTK 窗口"""
def __init__(self, w: int, h: int, title: str = ""):
self._ptr = Fl_Window_new(0, 0, w, h, title)
def begin(self):
Fl_Window_begin(self._ptr)
def end(self):
Fl_Window_end(self._ptr)
def set_modal(self, flag: t.CUInt32T):
Fl_Window_make_modal(self._ptr, flag)
def fullscreen(self, flag: t.CUInt32T):
Fl_Window_fullscreen(self._ptr, flag)
def make_current(self):
Fl_Window_make_current(self._ptr)
def set_border(self, flag: int):
Fl_Window_set_border(self._ptr, flag)
def border(self) -> int:
return Fl_Window_border(self._ptr)
def iconize(self):
Fl_Window_iconize(self._ptr)
def free_position(self):
Fl_Window_free_position(self._ptr)
def shown(self) -> int:
return Fl_Window_shown(self._ptr)
def set_xclass(self, xc: str):
Fl_Window_set_xclass(self._ptr, xc)
def x_root(self) -> int:
return Fl_Window_x_root(self._ptr)
def y_root(self) -> int:
return Fl_Window_y_root(self._ptr)
def size_range(self, minw: int, minh: int, maxw: int, maxh: int):
Fl_Window_size_range(self._ptr, minw, minh, maxw, maxh)
def set_cursor(self, cursor: int):
Fl_Window_set_cursor(self._ptr, cursor)
def resize(self, x: int, y: int, w: int, h: int):
Fl_Window_resize(self._ptr, x, y, w, h)
# ============================================================
# Fl_Box — 静态文本/装饰框
# ============================================================
@t.NoVTable
class Fl_Box(Fl_Widget):
"""FLTK 文本框/装饰框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Box_new(x, y, w, h, label)
# ============================================================
# Fl_Button — 按钮包装
# ============================================================
@t.NoVTable
class Fl_Button(Fl_Widget):
"""FLTK 按钮"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Button_new(x, y, w, h, label)
def value(self) -> int:
return Fl_Button_value(self._ptr)
def set_value(self, v: int):
Fl_Button_set_value(self._ptr, v)
def set(self):
Fl_Button_set_value(self._ptr, 1)
def clear(self) -> int:
return Fl_Button_clear(self._ptr)
def set_shortcut(self, s: int):
Fl_Button_set_shortcut(self._ptr, s)
def shortcut(self) -> int:
return Fl_Button_shortcut(self._ptr)
def set_down_box(self, box: int):
Fl_Button_set_down_box(self._ptr, box)
def down_box(self) -> int:
return Fl_Button_down_box(self._ptr)
@t.NoVTable
class Fl_Check_Button(Fl_Button):
"""FLTK 复选框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Check_Button_new(x, y, w, h, label)
def is_checked(self) -> int:
return Fl_Check_Button_is_checked(self._ptr)
def set_checked(self, checked: int):
Fl_Check_Button_set_checked(self._ptr, checked)
@t.NoVTable
class Fl_Radio_Button(Fl_Button):
"""FLTK 单选按钮"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Radio_Button_new(x, y, w, h, label)
def is_toggled(self) -> int:
return Fl_Radio_Button_is_toggled(self._ptr)
def toggle(self, v: int):
Fl_Radio_Button_toggle(self._ptr, v)
@t.NoVTable
class Fl_Repeat_Button(Fl_Button):
"""FLTK 重复触发按钮"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Repeat_Button_new(x, y, w, h, label)
@t.NoVTable
class Fl_Return_Button(Fl_Button):
"""FLTK 回车按钮"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Return_Button_new(x, y, w, h, label)
@t.NoVTable
class Fl_Light_Button(Fl_Button):
"""FLTK 指示灯按钮"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Light_Button_new(x, y, w, h, label)
def is_on(self) -> int:
return Fl_Light_Button_is_on(self._ptr)
def turn_on(self, v: int):
Fl_Light_Button_turn_on(self._ptr, v)
# ============================================================
# Fl_Input / Fl_Output — 文本输入输出
# ============================================================
@t.NoVTable
class Fl_Input(Fl_Widget):
"""FLTK 单行文本输入框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Input_new(x, y, w, h, label)
def value(self) -> str:
return Fl_Input_value(self._ptr)
def set_value(self, text: str):
Fl_Input_set_value(self._ptr, text)
def set_maximum_size(self, m: int):
Fl_Input_set_maximum_size(self._ptr, m)
def maximum_size(self) -> int:
return Fl_Input_maximum_size(self._ptr)
def set_readonly(self, v: int):
Fl_Input_set_readonly(self._ptr, v)
def readonly(self) -> int:
return Fl_Input_readonly(self._ptr)
@t.NoVTable
class Fl_Output(Fl_Widget):
"""FLTK 单行文本输出框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Output_new(x, y, w, h, label)
def value(self) -> str:
return Fl_Output_value(self._ptr)
def set_value(self, text: str) -> int:
return Fl_Output_set_value(self._ptr, text)
@t.NoVTable
class Fl_Int_Input(Fl_Input):
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Int_Input_new(x, y, w, h, label)
@t.NoVTable
class Fl_Float_Input(Fl_Input):
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Float_Input_new(x, y, w, h, label)
# ============================================================
# Fl_Text_Buffer / Fl_Text_Display — 多行文本
# ============================================================
@t.NoVTable
class Fl_Text_Buffer:
"""FLTK 文本缓冲"""
_ptr: Fl_Text_BufferPtr
def __init__(self):
self._ptr = Fl_Text_Buffer_new()
def text(self) -> str:
return Fl_Text_Buffer_text(self._ptr)
def set_text(self, text: str):
Fl_Text_Buffer_set_text(self._ptr, text)
def append(self, text: str):
Fl_Text_Buffer_append(self._ptr, text)
def length(self) -> int:
return Fl_Text_Buffer_length(self._ptr)
def insert(self, pos: int, text: str):
Fl_Text_Buffer_insert(self._ptr, pos, text)
def remove(self, start: int, end: int):
Fl_Text_Buffer_remove(self._ptr, start, end)
def save_file(self, path: str) -> int:
return Fl_Text_Buffer_save_file(self._ptr, path)
def load_file(self, path: str) -> int:
return Fl_Text_Buffer_load_file(self._ptr, path)
def free(self):
Fl_Text_Buffer_delete(self._ptr)
@t.NoVTable
class Fl_Text_Display(Fl_Widget):
"""FLTK 多行文本显示"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Text_Display_new(x, y, w, h, label)
def set_buffer(self, buf: Fl_Text_BufferPtr):
Fl_Text_Display_set_buffer(self._ptr, buf)
def set_text_font(self, font: int):
Fl_Text_Display_set_text_font(self._ptr, font)
def set_text_size(self, size: int):
Fl_Text_Display_set_text_size(self._ptr, size)
def set_text_color(self, color: t.CUInt32T):
Fl_Text_Display_set_text_color(self._ptr, color)
def set_scrollbar_size(self, size: int):
Fl_Text_Display_set_scrollbar_size(self._ptr, size)
# ============================================================
# Fl_Group — 容器包装
# ============================================================
@t.NoVTable
class Fl_Group(Fl_Widget):
"""FLTK 控件组"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Group_new(x, y, w, h, label)
def begin(self):
Fl_Group_begin(self._ptr)
def end(self):
Fl_Group_end(self._ptr)
def add(self, wid: Fl_WidgetPtr):
Fl_Group_add(self._ptr, wid)
def remove(self, wid: Fl_WidgetPtr):
Fl_Group_remove(self._ptr, wid)
def clear(self):
Fl_Group_clear(self._ptr)
def children(self) -> int:
return Fl_Group_children(self._ptr)
def child(self, index: int) -> Fl_WidgetPtr:
return Fl_Group_child(self._ptr, index)
def set_resizable(self, wid: Fl_WidgetPtr):
Fl_Group_resizable(self._ptr, wid)
@t.NoVTable
class Fl_Scroll(Fl_Group):
"""FLTK 滚动容器"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Scroll_new(x, y, w, h, label)
def set_scrollbar_size(self, size: int):
Fl_Scroll_set_scrollbar_size(self._ptr, size)
def scrollbar_size(self) -> int:
return Fl_Scroll_scrollbar_size(self._ptr)
def scroll_to(self, x: int, y: int):
Fl_Scroll_scroll_to(self._ptr, x, y)
def xposition(self) -> int:
return Fl_Scroll_xposition(self._ptr)
def yposition(self) -> int:
return Fl_Scroll_yposition(self._ptr)
@t.NoVTable
class Fl_Tabs(Fl_Group):
"""FLTK 选项卡容器"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Tabs_new(x, y, w, h, label)
def value(self) -> Fl_WidgetPtr:
return Fl_Tabs_value(self._ptr)
def set_value(self, wid: Fl_WidgetPtr):
Fl_Tabs_set_value(self._ptr, wid)
# ============================================================
# Fl_Slider / Fl_Value_Input / Fl_Value_Output — 数值控件
# ============================================================
@t.NoVTable
class Fl_Slider(Fl_Widget):
"""FLTK 滑动条"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Slider_new(x, y, w, h, label)
def value(self) -> t.CDouble:
return Fl_Slider_value(self._ptr)
def set_value(self, v: t.CDouble):
Fl_Slider_set_value(self._ptr, v)
def minimum(self) -> t.CDouble:
return Fl_Slider_minimum(self._ptr)
def set_minimum(self, v: t.CDouble):
Fl_Slider_set_minimum(self._ptr, v)
def maximum(self) -> t.CDouble:
return Fl_Slider_maximum(self._ptr)
def set_maximum(self, v: t.CDouble):
Fl_Slider_set_maximum(self._ptr, v)
def step(self) -> t.CDouble:
return Fl_Slider_step(self._ptr)
def set_step(self, v: t.CDouble):
Fl_Slider_set_step(self._ptr, v)
def set_bounds(self, a: t.CDouble, b: t.CDouble):
Fl_Slider_set_bounds(self._ptr, a, b)
@t.NoVTable
class Fl_Value_Input(Fl_Widget):
"""FLTK 数值输入框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Value_Input_new(x, y, w, h, label)
def value(self) -> t.CDouble:
return Fl_Value_Input_value(self._ptr)
def set_value(self, v: t.CDouble):
Fl_Value_Input_set_value(self._ptr, v)
def set_bounds(self, a: t.CDouble, b: t.CDouble):
Fl_Value_Input_set_bounds(self._ptr, a, b)
@t.NoVTable
class Fl_Value_Output(Fl_Widget):
"""FLTK 数值输出框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Value_Output_new(x, y, w, h, label)
def value(self) -> t.CDouble:
return Fl_Value_Output_value(self._ptr)
def set_value(self, v: t.CDouble):
Fl_Value_Output_set_value(self._ptr, v)
@t.NoVTable
class Fl_Progress(Fl_Widget):
"""FLTK 进度条"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Progress_new(x, y, w, h, label)
def value(self) -> t.CDouble:
return Fl_Progress_value(self._ptr)
def set_value(self, v: t.CDouble):
Fl_Progress_set_value(self._ptr, v)
def set_minimum(self, v: t.CDouble):
Fl_Progress_set_minimum(self._ptr, v)
def set_maximum(self, v: t.CDouble):
Fl_Progress_set_maximum(self._ptr, v)
# ============================================================
# Fl_Choice — 下拉选择
# ============================================================
@t.NoVTable
class Fl_Choice(Fl_Widget):
"""FLTK 下拉选择框"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Choice_new(x, y, w, h, label)
def add(self, text: str):
Fl_Choice_add_choice(self._ptr, text)
def value(self) -> int:
return Fl_Choice_value(self._ptr)
def set_value(self, v: int):
Fl_Choice_set_value(self._ptr, v)
def text(self, idx: int) -> str:
return Fl_Choice_text(self._ptr, idx)
# ============================================================
# Fl_Menu_Bar — 菜单栏
# ============================================================
@t.NoVTable
class Fl_Menu_Bar(Fl_Widget):
"""FLTK 菜单栏
add 走 cfltk 完整 6 参签名(name/shortcut/回调/数据/flags),
Viper 端回调按 bytes 无法传函数指针,回调/数据位固定传 t.CPtr(0);
简单下拉建议直接用 add_choice。"""
def __init__(self, x: int, y: int, w: int, h: int, label: str = ""):
self._ptr = Fl_Menu_Bar_new(x, y, w, h, label)
def add(self, path: str, shortcut: int, flags: int):
Fl_Menu_Bar_add(self._ptr, path, shortcut, t.CPtr(0), t.CPtr(0), flags)
def add_choice(self, text: str) -> int:
return Fl_Menu_Bar_add_choice(self._ptr, text)
# ============================================================
# Fl_Native_File_Chooser — 系统文件对话框
# ============================================================
@t.NoVTable
class Fl_Native_File_Chooser:
"""FLTK 原生文件选择对话框
构造需传对话框类型常量(如 Fl_Native_File_Chooser_BROWSE_FILE /
BROWSE_DIRECTORY / BROWSE_MULTI_FILE / BROWSE_MULTI_DIRECTORY /
BROWSE_SAVE_FILE,见 _enums.vp)。"""
_ptr: Fl_Native_File_ChooserPtr
def __init__(self, type_: int):
self._ptr = Fl_Native_File_Chooser_new(type_)
def set_title(self, title: str):
Fl_Native_File_Chooser_set_title(self._ptr, title)
def set_filter(self, filter_: str):
Fl_Native_File_Chooser_set_filter(self._ptr, filter_)
def filter(self) -> str:
return Fl_Native_File_Chooser_filter(self._ptr)
def set_directory(self, dir_: str):
Fl_Native_File_Chooser_set_directory(self._ptr, dir_)
def directory(self) -> str:
return Fl_Native_File_Chooser_directory(self._ptr)
def set_preset_file(self, path: str):
Fl_Native_File_Chooser_set_preset_file(self._ptr, path)
def set_option(self, opt: int):
Fl_Native_File_Chooser_set_option(self._ptr, opt)
def set_type(self, type_: int):
Fl_Native_File_Chooser_set_type(self._ptr, type_)
def show(self) -> int:
return Fl_Native_File_Chooser_show(self._ptr)
def count(self) -> int:
return Fl_Native_File_Chooser_count(self._ptr)
def filename(self) -> str:
return Fl_Native_File_Chooser_filename(self._ptr)
def filenames(self, index: int) -> str:
return Fl_Native_File_Chooser_filenames(self._ptr, index)
def filter_value(self) -> int:
return Fl_Native_File_Chooser_filter_value(self._ptr)
def set_filter_value(self, v: int):
Fl_Native_File_Chooser_set_filter_value(self._ptr, v)
def errmsg(self) -> str:
return Fl_Native_File_Chooser_errmsg(self._ptr)
def delete(self):
Fl_Native_File_Chooser_delete(self._ptr)
# ============================================================
# 常用别名
# ============================================================
def fltk_init():
"""初始化 FLTK(多线程环境需先 Fl_lock 再 init_all)。"""
Fl_init_all()