# main.vp — ViperQtProject:VS Installer 风格安装向导演示 # # 纯界面演示(无真实安装逻辑): # 步骤0 欢迎 → 步骤1 许可协议 → 步骤2 组件选择 → 步骤3 安装进度 → 步骤4 完成 # # 完善功能: # - 许可协议页:协议文本 + "我接受" 勾选后才可继续 # - 组件选择:磁盘占用实时统计 + 安装选项(快捷方式/PATH/桌面图标) # - 安装进度:进度条 + 阶段文案 + 实时日志(QPlainTextEdit) # - 安装按钮点击后禁用,防重复 # # 说明: # - 回调签名统一 def Cb(slot_id: int, data: t.CPtr) # - 跨模块 FFI 调用避免返回指针的函数(用 *_utf8 便捷版 + 整数返回函数) # - 模块级全局只存 t.CPtr 指针(不存对象) import t import stdlib import viperlib import vqt6 # ============================================================ # 全局指针(回调里访问) # ============================================================ app_ptr: t.CPtr = None stack_ptr: t.CPtr = None nav0_ptr: t.CPtr = None nav1_ptr: t.CPtr = None nav2_ptr: t.CPtr = None nav3_ptr: t.CPtr = None nav4_ptr: t.CPtr = None progress_ptr: t.CPtr = None progress_status_ptr: t.CPtr = None log_ptr: t.CPtr = None path_label_ptr: t.CPtr = None summary_ptr: t.CPtr = None disk_ptr: t.CPtr = None finish_summary_ptr: t.CPtr = None timer_ptr: t.CPtr = None comp0_ptr: t.CPtr = None comp1_ptr: t.CPtr = None comp2_ptr: t.CPtr = None comp3_ptr: t.CPtr = None comp4_ptr: t.CPtr = None agree_cb_ptr: t.CPtr = None license_next_ptr: t.CPtr = None install_btn_ptr: t.CPtr = None opt0_ptr: t.CPtr = None opt1_ptr: t.CPtr = None opt2_ptr: t.CPtr = None # 全局状态 cur_step: int = 0 progress_val: int = 0 comp_count: int = 0 install_path: str = "C:/Program Files/Viper6" # ============================================================ # 深色主题 QSS(VS Installer 风格,单行字面量) # ============================================================ dark_qss: str = "QWidget { background-color: #1e1e1e; color: #d4d4d4; font-size: 13px; } QPushButton { background-color: #333333; border: 1px solid #555555; border-radius: 4px; padding: 7px 16px; color: #ffffff; } QPushButton:hover { background-color: #454545; } QPushButton:pressed { background-color: #2a6da8; } QPushButton:disabled { background-color: #2a2a2a; color: #666666; border-color: #3a3a3a; } QLineEdit { background-color: #252526; border: 1px solid #555555; border-radius: 3px; padding: 5px 8px; color: #ffffff; } QCheckBox { color: #d4d4d4; spacing: 10px; font-size: 14px; } QCheckBox::indicator { width: 18px; height: 18px; } QProgressBar { background-color: #252526; border: 1px solid #555555; border-radius: 5px; text-align: center; color: #ffffff; font-size: 13px; } QProgressBar::chunk { background-color: #4a86c8; border-radius: 4px; } QPlainTextEdit { background-color: #1a1a1a; border: 1px solid #444444; color: #cccccc; }" # 导航项样式 nav_active_qss: str = "font-size: 15px; color: #ffffff; font-weight: bold; background-color: #2a6da8; padding: 10px 14px; border-radius: 4px;" nav_idle_qss: str = "font-size: 15px; color: #8a8a8a; padding: 10px 14px;" # 许可协议文本 license_text: str = "VIPER 6.0 最终用户许可协议\n\n重要 - 请仔细阅读:本最终用户许可协议(以下简称\"协议\")是您与 Viper Software Foundation 之间就 Viper 6.0 软件达成的法律协议。\n\n1. 许可授予。在遵守本协议条款的前提下,您被授予一份非独占、不可转让的许可,允许在您的设备上安装和使用本软件用于开发与测试目的。\n\n2. 使用限制。您不得对本软件进行反向工程、反编译或反汇编(适用法律明确允许的除外);不得删除或修改软件中的版权声明。\n\n3. 开源组件。本软件包含根据 MIT、BSD 与 LGPL 许可发布的第三方开源组件,相关许可文本随附于软件文档中。\n\n4. 免责声明。本软件按\"现状\"提供,不附带任何明示或默示的担保,包括但不限于适销性、特定用途适用性及不侵权的担保。\n\n5. 责任限制。在任何情况下,Viper Software Foundation 均不对因使用或无法使用本软件而产生的任何间接、偶然、特殊或后果性损害承担责任。\n\n6. 协议终止。若您违反本协议的任何条款,本协议将自动终止,您应停止使用并删除本软件的全部副本。\n\n请阅读以上条款。要安装 Viper 6.0,必须接受这些条款并勾选下方的\"我接受许可协议中的条款\"。" # ============================================================ # 工具:切换步骤 + 导航高亮 # ============================================================ def SetNavStyle(ptr: t.CPtr, qss: str): vqt6.vqt6_qwidget_set_stylesheet_utf8(ptr, qss) def GotoStep(step: int): global cur_step cur_step = step vqt6.vqt6_qstackedwidget_set_current_index(stack_ptr, step) # 导航高亮 SetNavStyle(nav0_ptr, nav_active_qss if step == 0 else nav_idle_qss) SetNavStyle(nav1_ptr, nav_active_qss if step == 1 else nav_idle_qss) SetNavStyle(nav2_ptr, nav_active_qss if step == 2 else nav_idle_qss) SetNavStyle(nav3_ptr, nav_active_qss if step == 3 else nav_idle_qss) SetNavStyle(nav4_ptr, nav_active_qss if step == 4 else nav_idle_qss) # ============================================================ # 步骤0:欢迎页 # ============================================================ def OnNext(slot_id: int, data: t.CPtr): GotoStep(1) # ============================================================ # 步骤1:许可协议 # ============================================================ def OnLicenseToggled(slot_id: int, data: t.CPtr): """勾选"我接受"后启用下一步""" checked: int = vqt6.vqt6_qcheckbox_is_checked(agree_cb_ptr) vqt6.vqt6_qwidget_set_enabled(license_next_ptr, checked) def OnLicenseNext(slot_id: int, data: t.CPtr): GotoStep(2) def OnLicenseBack(slot_id: int, data: t.CPtr): GotoStep(0) # ============================================================ # 步骤2:组件选择 # ============================================================ def OnBack(slot_id: int, data: t.CPtr): GotoStep(1) def OnBrowse(slot_id: int, data: t.CPtr): global install_path p: str = vqt6.QFileDialog.getExistingDirectory(None, "选择安装目录", "C:/") if p is not None and p != "": install_path = p vqt6.vqt6_qlabel_set_text_utf8(path_label_ptr, p) def UpdateDiskInfo(): """按组件勾选统计磁盘占用""" total_mb: int = 0 if vqt6.vqt6_qcheckbox_is_checked(comp0_ptr) != 0: total_mb += 850 if vqt6.vqt6_qcheckbox_is_checked(comp1_ptr) != 0: total_mb += 1200 if vqt6.vqt6_qcheckbox_is_checked(comp2_ptr) != 0: total_mb += 350 if vqt6.vqt6_qcheckbox_is_checked(comp3_ptr) != 0: total_mb += 220 if vqt6.vqt6_qcheckbox_is_checked(comp4_ptr) != 0: total_mb += 90 buf: bytes = stdlib.malloc(96) viperlib.snprintf(buf, 96, "所需磁盘空间: %d MB / 可用 51200 MB", total_mb) vqt6.vqt6_qlabel_set_text_utf8(disk_ptr, buf) stdlib.free(buf) def OnCompToggled(slot_id: int, data: t.CPtr): """组件勾选变化:重算勾选数 + 磁盘占用""" global comp_count n: int = 0 if vqt6.vqt6_qcheckbox_is_checked(comp0_ptr) != 0: n += 1 if vqt6.vqt6_qcheckbox_is_checked(comp1_ptr) != 0: n += 1 if vqt6.vqt6_qcheckbox_is_checked(comp2_ptr) != 0: n += 1 if vqt6.vqt6_qcheckbox_is_checked(comp3_ptr) != 0: n += 1 if vqt6.vqt6_qcheckbox_is_checked(comp4_ptr) != 0: n += 1 comp_count = n buf: bytes = stdlib.malloc(64) viperlib.snprintf(buf, 64, "已选择 %d 个组件", n) vqt6.vqt6_qlabel_set_text_utf8(summary_ptr, buf) stdlib.free(buf) UpdateDiskInfo() def OnInstall(slot_id: int, data: t.CPtr): """进入安装页并启动模拟进度""" global progress_val vqt6.vqt6_qwidget_set_enabled(install_btn_ptr, 0) GotoStep(3) progress_val = 0 vqt6.vqt6_qprogressbar_set_value(progress_ptr, 0) vqt6.vqt6_qlabel_set_text_utf8(progress_status_ptr, "正在准备安装环境...") vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "== 开始安装 Viper 6.0 ==\n") vqt6.vqt6_qtimer_start(timer_ptr, 80) # ============================================================ # 步骤3:安装进度(QTimer 模拟) # ============================================================ def OnProgressTick(slot_id: int, data: t.CPtr): global progress_val progress_val += 4 vqt6.vqt6_qprogressbar_set_value(progress_ptr, progress_val) if progress_val == 4: vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "[1/4] 正在准备安装环境...\n") elif progress_val == 28: vqt6.vqt6_qlabel_set_text_utf8(progress_status_ptr, "正在复制核心文件...") vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "[2/4] 正在复制核心文件...\n") elif progress_val == 52: vqt6.vqt6_qlabel_set_text_utf8(progress_status_ptr, "正在配置 Qt6 组件...") vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "[3/4] 正在配置 Qt6 组件...\n") elif progress_val == 76: vqt6.vqt6_qlabel_set_text_utf8(progress_status_ptr, "正在注册系统组件...") vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "[4/4] 正在注册系统组件...\n") elif progress_val >= 100: vqt6.vqt6_qtimer_stop(timer_ptr) vqt6.vqt6_qplaintextedit_append_utf8(log_ptr, "安装完成!\n") # 完成页摘要(含安装选项) buf: bytes = stdlib.malloc(512) viperlib.snprintf(buf, 512, "安装位置: %s\n已安装组件: %d 个\nViper 6.0 已成功安装到您的系统。", install_path, comp_count) vqt6.vqt6_qlabel_set_text_utf8(finish_summary_ptr, buf) stdlib.free(buf) GotoStep(4) # ============================================================ # 步骤4:完成页 # ============================================================ def OnFinish(slot_id: int, data: t.CPtr): vqt6.vqt6_qapplication_quit(app_ptr) def main() -> int: global app_ptr, stack_ptr global nav0_ptr, nav1_ptr, nav2_ptr, nav3_ptr, nav4_ptr global progress_ptr, progress_status_ptr, log_ptr, path_label_ptr global summary_ptr, disk_ptr, finish_summary_ptr, timer_ptr global comp0_ptr, comp1_ptr, comp2_ptr, comp3_ptr, comp4_ptr global agree_cb_ptr, license_next_ptr, install_btn_ptr global opt0_ptr, opt1_ptr, opt2_ptr app = vqt6.QApplication(t.CPtr(0)) app_ptr = t.CPtr(app._ptr) # 主窗口 win = vqt6.QMainWindow() win.setWindowTitle("Viper 6.0 Installer") win.resize(920, 600) central = vqt6.QWidget() central.setStyleSheet(dark_qss) win.setCentralWidget(central._ptr) root = vqt6.QHBoxLayout(central) # ===== 左导航面板 ===== nav_panel = vqt6.QWidget() vqt6.vqt6_qwidget_set_fixed_size(nav_panel._ptr, 210, 600) nav_box = vqt6.QVBoxLayout(nav_panel) nav_box.setContentsMargins(10, 16, 10, 10) nav_box.setSpacing(6) title_lb = vqt6.QLabel("Viper 6.0") vqt6.vqt6_qwidget_set_stylesheet_utf8(title_lb._ptr, "font-size: 20px; color: #4a86c8; font-weight: bold; padding: 6px 14px;") nav_box.addWidget(title_lb._ptr) nav0 = vqt6.QLabel("欢迎") nav0.setStyleSheet(nav_active_qss) nav_box.addWidget(nav0._ptr) nav0_ptr = t.CPtr(nav0._ptr) nav1 = vqt6.QLabel("许可协议") nav1.setStyleSheet(nav_idle_qss) nav_box.addWidget(nav1._ptr) nav1_ptr = t.CPtr(nav1._ptr) nav2 = vqt6.QLabel("组件选择") nav2.setStyleSheet(nav_idle_qss) nav_box.addWidget(nav2._ptr) nav2_ptr = t.CPtr(nav2._ptr) nav3 = vqt6.QLabel("安装进度") nav3.setStyleSheet(nav_idle_qss) nav_box.addWidget(nav3._ptr) nav3_ptr = t.CPtr(nav3._ptr) nav4 = vqt6.QLabel("完成") nav4.setStyleSheet(nav_idle_qss) nav_box.addWidget(nav4._ptr) nav4_ptr = t.CPtr(nav4._ptr) nav_box.addStretch(1) ver_lb = vqt6.QLabel("v6.0.1 · 2026") vqt6.vqt6_qwidget_set_stylesheet_utf8(ver_lb._ptr, "color: #666666; padding: 6px 14px;") nav_box.addWidget(ver_lb._ptr) root.addWidget(nav_panel._ptr) # ===== 右侧步骤容器 ===== stack = vqt6.QStackedWidget() root.addWidget(stack._ptr) stack_ptr = t.CPtr(stack._ptr) # ---------- 页0:欢迎 ---------- page0 = vqt6.QWidget() p0 = vqt6.QVBoxLayout(page0) p0.setContentsMargins(36, 40, 36, 24) p0.setSpacing(12) big = vqt6.QLabel("Viper 6.0") vqt6.vqt6_qwidget_set_stylesheet_utf8(big._ptr, "font-size: 34px; color: #ffffff; font-weight: bold;") p0.addWidget(big._ptr) sub = vqt6.QLabel("为 Viper 语言平台安装工具链、Qt6 运行时与开发组件") vqt6.vqt6_qwidget_set_stylesheet_utf8(sub._ptr, "font-size: 16px; color: #9cdcfe;") p0.addWidget(sub._ptr) desc = vqt6.QLabel("本向导将引导您完成 Viper 6.0 的安装。您可以自定义要安装的组件\n和安装位置,安装过程由模拟进度与日志展示(演示界面,无真实安装行为)。") vqt6.vqt6_qwidget_set_stylesheet_utf8(desc._ptr, "font-size: 13px; color: #9a9a9a;") p0.addWidget(desc._ptr) p0.addStretch(1) next_btn = vqt6.QPushButton("下一步 >") p0.addWidget(next_btn._ptr) next_btn.clicked(OnNext, 0) stack.addWidget(page0._ptr) # ---------- 页1:许可协议 ---------- page1 = vqt6.QWidget() p1 = vqt6.QVBoxLayout(page1) p1.setContentsMargins(36, 32, 36, 24) p1.setSpacing(10) lh = vqt6.QLabel("许可协议") vqt6.vqt6_qwidget_set_stylesheet_utf8(lh._ptr, "font-size: 22px; color: #ffffff; font-weight: bold;") p1.addWidget(lh._ptr) license_box = vqt6.QPlainTextEdit() license_box.setPlainText(license_text) license_box.setReadOnly(1) p1.addWidget(license_box._ptr) agree_cb = vqt6.QCheckBox("我接受许可协议中的条款") p1.addWidget(agree_cb._ptr) agree_cb_ptr = t.CPtr(agree_cb._ptr) agree_cb.toggled(OnLicenseToggled, 0) lbrow = vqt6.QHBoxLayout() p1.addLayout(lbrow._ptr) lbrow.addStretch(1) lic_back = vqt6.QPushButton("< 上一步") lbrow.addWidget(lic_back._ptr) lic_back.clicked(OnLicenseBack, 0) lic_next = vqt6.QPushButton("下一步 >") lic_next.setEnabled(0) lbrow.addWidget(lic_next._ptr) license_next_ptr = t.CPtr(lic_next._ptr) lic_next.clicked(OnLicenseNext, 0) stack.addWidget(page1._ptr) # ---------- 页2:组件选择 ---------- page2 = vqt6.QWidget() p2 = vqt6.QVBoxLayout(page2) p2.setContentsMargins(36, 28, 36, 20) p2.setSpacing(8) h2 = vqt6.QLabel("选择要安装的组件") vqt6.vqt6_qwidget_set_stylesheet_utf8(h2._ptr, "font-size: 22px; color: #ffffff; font-weight: bold;") p2.addWidget(h2._ptr) h2b = vqt6.QLabel("勾选您需要的工作负载与组件,取消勾选可减少安装体积与磁盘占用。") vqt6.vqt6_qwidget_set_stylesheet_utf8(h2b._ptr, "font-size: 13px; color: #9a9a9a;") p2.addWidget(h2b._ptr) comp0 = vqt6.QCheckBox("Viper 核心工具链(编译器 + 运行时)[850 MB]") comp0.setChecked(1) p2.addWidget(comp0._ptr) comp0_ptr = t.CPtr(comp0._ptr) comp1 = vqt6.QCheckBox("Qt6 桌面开发(GUI 框架 + vqt6 桥接库)[1200 MB]") comp1.setChecked(1) p2.addWidget(comp1._ptr) comp1_ptr = t.CPtr(comp1._ptr) comp2 = vqt6.QCheckBox("Viper 标准库与 includes 包 [350 MB]") comp2.setChecked(1) p2.addWidget(comp2._ptr) comp2_ptr = t.CPtr(comp2._ptr) comp3 = vqt6.QCheckBox("网络与调试工具(QtNetwork + TPV)[220 MB]") comp3.setChecked(0) p2.addWidget(comp3._ptr) comp3_ptr = t.CPtr(comp3._ptr) comp4 = vqt6.QCheckBox("示例项目与文档 [90 MB]") comp4.setChecked(0) p2.addWidget(comp4._ptr) comp4_ptr = t.CPtr(comp4._ptr) comp0.toggled(OnCompToggled, comp0._ptr) comp1.toggled(OnCompToggled, comp1._ptr) comp2.toggled(OnCompToggled, comp2._ptr) comp3.toggled(OnCompToggled, comp3._ptr) comp4.toggled(OnCompToggled, comp4._ptr) summary = vqt6.QLabel("已选择 3 个组件") vqt6.vqt6_qwidget_set_stylesheet_utf8(summary._ptr, "font-size: 13px; color: #9cdcfe;") p2.addWidget(summary._ptr) summary_ptr = t.CPtr(summary._ptr) disk = vqt6.QLabel("所需磁盘空间: 2400 MB / 可用 51200 MB") vqt6.vqt6_qwidget_set_stylesheet_utf8(disk._ptr, "font-size: 13px; color: #9cdcfe;") p2.addWidget(disk._ptr) disk_ptr = t.CPtr(disk._ptr) # 安装选项 oh = vqt6.QLabel("安装选项") vqt6.vqt6_qwidget_set_stylesheet_utf8(oh._ptr, "font-size: 15px; color: #ffffff; font-weight: bold; padding-top: 6px;") p2.addWidget(oh._ptr) opt0 = vqt6.QCheckBox("创建开始菜单快捷方式") opt0.setChecked(1) p2.addWidget(opt0._ptr) opt0_ptr = t.CPtr(opt0._ptr) opt1 = vqt6.QCheckBox("将 viper 命令添加到系统 PATH") opt1.setChecked(0) p2.addWidget(opt1._ptr) opt1_ptr = t.CPtr(opt1._ptr) opt2 = vqt6.QCheckBox("创建桌面图标") opt2.setChecked(0) p2.addWidget(opt2._ptr) opt2_ptr = t.CPtr(opt2._ptr) # 安装位置行 path_row = vqt6.QHBoxLayout() p2.addLayout(path_row._ptr) path_lb = vqt6.QLabel("安装位置:") path_row.addWidget(path_lb._ptr) path_lb2 = vqt6.QLabel(install_path) vqt6.vqt6_qwidget_set_stylesheet_utf8(path_lb2._ptr, "background-color: #252526; border: 1px solid #555555; border-radius: 3px; padding: 5px 8px; color: #ffffff;") path_row.addWidget(path_lb2._ptr) path_label_ptr = t.CPtr(path_lb2._ptr) browse_btn = vqt6.QPushButton("浏览...") path_row.addWidget(browse_btn._ptr) browse_btn.clicked(OnBrowse, 0) p2.addStretch(1) btn_row2 = vqt6.QHBoxLayout() p2.addLayout(btn_row2._ptr) btn_row2.addStretch(1) back_btn = vqt6.QPushButton("< 上一步") btn_row2.addWidget(back_btn._ptr) back_btn.clicked(OnBack, 0) install_btn = vqt6.QPushButton("安装") vqt6.vqt6_qwidget_set_stylesheet_utf8(install_btn._ptr, "background-color: #2a6da8; border: 1px solid #2a6da8; border-radius: 4px; padding: 8px 22px; color: #ffffff; font-size: 14px; font-weight: bold;") btn_row2.addWidget(install_btn._ptr) install_btn_ptr = t.CPtr(install_btn._ptr) install_btn.clicked(OnInstall, 0) stack.addWidget(page2._ptr) # ---------- 页3:安装进度 ---------- page3 = vqt6.QWidget() p3 = vqt6.QVBoxLayout(page3) p3.setContentsMargins(36, 36, 36, 24) p3.setSpacing(12) h3 = vqt6.QLabel("正在安装 Viper 6.0...") vqt6.vqt6_qwidget_set_stylesheet_utf8(h3._ptr, "font-size: 22px; color: #ffffff; font-weight: bold;") p3.addWidget(h3._ptr) prog = vqt6.QProgressBar() prog.setRange(0, 100) prog.setValue(0) p3.addWidget(prog._ptr) progress_ptr = t.CPtr(prog._ptr) pstat = vqt6.QLabel("正在准备安装环境...") vqt6.vqt6_qwidget_set_stylesheet_utf8(pstat._ptr, "font-size: 13px; color: #9a9a9a;") p3.addWidget(pstat._ptr) progress_status_ptr = t.CPtr(pstat._ptr) log = vqt6.QPlainTextEdit() log.setReadOnly(1) p3.addWidget(log._ptr) log_ptr = t.CPtr(log._ptr) stack.addWidget(page3._ptr) # ---------- 页4:完成 ---------- page4 = vqt6.QWidget() p4 = vqt6.QVBoxLayout(page4) p4.setContentsMargins(36, 40, 36, 24) p4.setSpacing(14) ok = vqt6.QLabel("安装完成") vqt6.vqt6_qwidget_set_stylesheet_utf8(ok._ptr, "font-size: 30px; color: #4ec9b0; font-weight: bold;") p4.addWidget(ok._ptr) fsum = vqt6.QLabel("") vqt6.vqt6_qwidget_set_stylesheet_utf8(fsum._ptr, "font-size: 14px; color: #d4d4d4;") p4.addWidget(fsum._ptr) finish_summary_ptr = t.CPtr(fsum._ptr) p4.addStretch(1) finish_btn = vqt6.QPushButton("完成") vqt6.vqt6_qwidget_set_stylesheet_utf8(finish_btn._ptr, "background-color: #2a6da8; border-radius: 4px; padding: 8px 22px; color: #ffffff; font-size: 14px; font-weight: bold;") p4.addWidget(finish_btn._ptr) finish_btn.clicked(OnFinish, 0) stack.addWidget(page4._ptr) # ===== 定时器(模拟安装进度) ===== timer = vqt6.QTimer() timer.timeout(OnProgressTick, 0) timer_ptr = t.CPtr(timer._ptr) GotoStep(0) win.show() return app.exec()