# ============================================================ # 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()