feat(ViperQtProject): 复选框指示器改用对勾图标(灰框/蓝勾 PNG)
This commit is contained in:
1 parent
503d23fc1a
commit
93a0babde6
4 files changed
+122
-2
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 242 B |
Binary file not shown.
|
After Width: | Height: | Size: 404 B |
@@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# make_check_icons.py — 生成复选框指示器 PNG(未勾=灰框 / 勾选=蓝框+白对勾)
|
||||
# 纯 Python + zlib 实现,无第三方依赖;4x4 子采样抗锯齿
|
||||
import os
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
W = 32
|
||||
SS = 4 # 子采样
|
||||
|
||||
|
||||
def rounded_inside(x, y, pad, rad):
|
||||
x0, y0 = float(pad), float(pad)
|
||||
x1, y1 = float(W - pad), float(W - pad)
|
||||
if x < x0 or x > x1 or y < y0 or y > y1:
|
||||
return False
|
||||
cx = min(max(x, x0 + rad), x1 - rad)
|
||||
cy = min(max(y, y0 + rad), y1 - rad)
|
||||
return (x - cx) ** 2 + (y - cy) ** 2 <= rad * rad
|
||||
|
||||
|
||||
def stroke_inside(x, y, pad, rad, th):
|
||||
if rounded_inside(x, y, pad, rad):
|
||||
if not rounded_inside(x, y, pad + th, max(0.0, rad - th)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def seg_dist(px, py, ax, ay, bx, by):
|
||||
vx, vy = bx - ax, by - ay
|
||||
wx, wy = px - ax, py - ay
|
||||
c1 = vx * wx + vy * wy
|
||||
if c1 <= 0:
|
||||
return (wx * wx + wy * wy) ** 0.5
|
||||
c2 = vx * vx + vy * vy
|
||||
if c2 <= c1:
|
||||
return ((px - bx) ** 2 + (py - by) ** 2) ** 0.5
|
||||
t = c1 / c2
|
||||
dx, dy = px - (ax + t * vx), py - (ay + t * vy)
|
||||
return (dx * dx + dy * dy) ** 0.5
|
||||
|
||||
|
||||
CHECK_SEGS = (((8.0, 17.0), (14.0, 23.0)), ((14.0, 23.0), (25.0, 10.0)))
|
||||
CHECK_W = 3.2
|
||||
|
||||
|
||||
def render(checked):
|
||||
rows = []
|
||||
step = 1.0 / SS
|
||||
for py in range(W):
|
||||
row = bytearray()
|
||||
for px in range(W):
|
||||
r = g = b = a = 0
|
||||
for sy in range(SS):
|
||||
for sx in range(SS):
|
||||
x = px + (sx + 0.5) * step
|
||||
y = py + (sy + 0.5) * step
|
||||
col = None
|
||||
if checked:
|
||||
if rounded_inside(x, y, 2.0, 7.0):
|
||||
col = (42, 109, 168) # #2a6da8 蓝底
|
||||
for (p1, p2) in CHECK_SEGS:
|
||||
if seg_dist(x, y, p1[0], p1[1], p2[0], p2[1]) <= CHECK_W:
|
||||
col = (255, 255, 255) # 白对勾
|
||||
break
|
||||
else:
|
||||
if stroke_inside(x, y, 2.0, 7.0, 2.4):
|
||||
col = (122, 130, 140) # 灰框
|
||||
if col is not None:
|
||||
r += col[0]
|
||||
g += col[1]
|
||||
b += col[2]
|
||||
a += 255
|
||||
n = SS * SS
|
||||
row += bytes((r // n, g // n, b // n, a // n))
|
||||
rows.append(bytes(row))
|
||||
return rows
|
||||
|
||||
|
||||
def write_png(path, w, h, rgba_rows):
|
||||
def chunk(tag, data):
|
||||
out = struct.pack(">I", len(data)) + tag + data
|
||||
out += struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
|
||||
return out
|
||||
|
||||
raw = b"".join(b"\x00" + r for r in rgba_rows)
|
||||
sig = b"\x89PNG\r\n\x1a\n"
|
||||
ihdr = struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0)
|
||||
idat = zlib.compress(raw, 9)
|
||||
with open(path, "wb") as f:
|
||||
f.write(sig + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", b""))
|
||||
|
||||
|
||||
def main():
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
write_png(os.path.join(here, "check_off.png"), W, W, render(False))
|
||||
write_png(os.path.join(here, "check_on.png"), W, W, render(True))
|
||||
print("icons written:", os.path.join(here, "check_off.png"), os.path.join(here, "check_on.png"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -79,9 +79,9 @@ cur_theme: int = 0
|
||||
# ============================================================
|
||||
# 深色主题 QSS(VS Installer 风格,单行字面量)
|
||||
# ============================================================
|
||||
dark_qss: str = "QWidget { background-color: #1e1e1e; color: #d4d4d4; font-family: \"Segoe UI\", \"Microsoft YaHei UI\", \"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif; font-size: 13px; } QPushButton { background-color: #333333; border: 1px solid #555555; border-radius: 4px; padding: 7px 16px; color: #ffffff; } QPushButton:hover { background-color: #454545; border-color: #6a6a6a; } QPushButton:pressed { background-color: #2a6da8; border-color: #4a86c8; } QPushButton:disabled { background-color: #2a2a2a; color: #666666; border-color: #3a3a3a; } QLineEdit, QTextEdit { background-color: #252526; border: 1px solid #555555; border-radius: 4px; padding: 5px 8px; color: #ffffff; } QPlainTextEdit { background-color: #1a1a1a; border: 1px solid #555555; border-radius: 4px; color: #cccccc; } QCheckBox { color: #d4d4d4; spacing: 10px; font-size: 14px; } QCheckBox::indicator, QTreeWidget::indicator { width: 16px; height: 16px; border: 1px solid #8a8a8a; border-radius: 3px; background-color: transparent; } QCheckBox::indicator:hover, QTreeWidget::indicator:hover { border-color: #c8c8c8; } QCheckBox::indicator:checked, QTreeWidget::indicator:checked { background-color: #2a6da8; border-color: #2a6da8; } QProgressBar { background-color: #252526; border: 1px solid #555555; border-radius: 4px; text-align: center; color: #ffffff; font-size: 13px; } QProgressBar::chunk { background-color: #4a86c8; border-radius: 3px; } QTreeWidget { background-color: #1a1a1a; border: 1px solid #555555; border-radius: 4px; color: #d4d4d4; } QTreeWidget::item { height: 26px; padding-left: 4px; } QTreeWidget::item:selected { background-color: #2a6da8; color: #ffffff; } QComboBox { background-color: #252526; border: 1px solid #555555; border-radius: 4px; padding: 5px 10px; color: #ffffff; } QComboBox:hover { border-color: #6a6a6a; } QComboBox::drop-down { border: none; width: 22px; } QComboBox QAbstractItemView { background-color: #252526; color: #ffffff; border: 1px solid #555555; selection-background-color: #2a6da8; } QScrollBar:vertical { background: #252526; width: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:vertical { background: #4a4a4a; min-height: 24px; border-radius: 5px; } QScrollBar::handle:vertical:hover { background: #5a5a5a; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } QScrollBar:horizontal { background: #252526; height: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:horizontal { background: #4a4a4a; min-width: 24px; border-radius: 5px; } QScrollBar::handle:horizontal:hover { background: #5a5a5a; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: transparent; }"
|
||||
dark_qss: str = "QWidget { background-color: #1e1e1e; color: #d4d4d4; font-family: \"Segoe UI\", \"Microsoft YaHei UI\", \"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif; font-size: 13px; } QPushButton { background-color: #333333; border: 1px solid #555555; border-radius: 4px; padding: 7px 16px; color: #ffffff; } QPushButton:hover { background-color: #454545; border-color: #6a6a6a; } QPushButton:pressed { background-color: #2a6da8; border-color: #4a86c8; } QPushButton:disabled { background-color: #2a2a2a; color: #666666; border-color: #3a3a3a; } QLineEdit, QTextEdit { background-color: #252526; border: 1px solid #555555; border-radius: 4px; padding: 5px 8px; color: #ffffff; } QPlainTextEdit { background-color: #1a1a1a; border: 1px solid #555555; border-radius: 4px; color: #cccccc; } QCheckBox { color: #d4d4d4; spacing: 10px; font-size: 14px; } QProgressBar { background-color: #252526; border: 1px solid #555555; border-radius: 4px; text-align: center; color: #ffffff; font-size: 13px; } QProgressBar::chunk { background-color: #4a86c8; border-radius: 3px; } QTreeWidget { background-color: #1a1a1a; border: 1px solid #555555; border-radius: 4px; color: #d4d4d4; } QTreeWidget::item { height: 26px; padding-left: 4px; } QTreeWidget::item:selected { background-color: #2a6da8; color: #ffffff; } QComboBox { background-color: #252526; border: 1px solid #555555; border-radius: 4px; padding: 5px 10px; color: #ffffff; } QComboBox:hover { border-color: #6a6a6a; } QComboBox::drop-down { border: none; width: 22px; } QComboBox QAbstractItemView { background-color: #252526; color: #ffffff; border: 1px solid #555555; selection-background-color: #2a6da8; } QScrollBar:vertical { background: #252526; width: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:vertical { background: #4a4a4a; min-height: 24px; border-radius: 5px; } QScrollBar::handle:vertical:hover { background: #5a5a5a; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } QScrollBar:horizontal { background: #252526; height: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:horizontal { background: #4a4a4a; min-width: 24px; border-radius: 5px; } QScrollBar::handle:horizontal:hover { background: #5a5a5a; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: transparent; }"
|
||||
|
||||
light_qss: str = "QWidget { background-color: #f5f6f8; color: #1e1e1e; font-family: \"Segoe UI\", \"Microsoft YaHei UI\", \"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif; font-size: 13px; } QPushButton { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 7px 16px; color: #1e1e1e; } QPushButton:hover { background-color: #eef1f6; border-color: #8a97a8; } QPushButton:pressed { background-color: #2a6da8; border-color: #2a6da8; color: #ffffff; } QPushButton:disabled { background-color: #eceef1; color: #9aa3b0; border-color: #d3d8e0; } QLineEdit, QTextEdit { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 5px 8px; color: #1e1e1e; } QPlainTextEdit { background-color: #ffffff; border: 1px solid #c6ccd6; border-radius: 4px; color: #1e1e1e; } QCheckBox { color: #1e1e1e; spacing: 10px; font-size: 14px; } QCheckBox::indicator, QTreeWidget::indicator { width: 16px; height: 16px; border: 1px solid #000000; border-radius: 3px; background-color: #ffffff; } QCheckBox::indicator:hover, QTreeWidget::indicator:hover { border-color: #2a6da8; } QCheckBox::indicator:checked, QTreeWidget::indicator:checked { background-color: #2a6da8; border-color: #2a6da8; } QProgressBar { background-color: #e2e6ec; border: 1px solid #c6ccd6; border-radius: 4px; text-align: center; color: #1e1e1e; font-size: 13px; } QProgressBar::chunk { background-color: #2a6da8; border-radius: 3px; } QTreeWidget { background-color: #ffffff; border: 1px solid #c6ccd6; border-radius: 4px; color: #1e1e1e; } QTreeWidget::item { height: 26px; padding-left: 4px; } QTreeWidget::item:selected { background-color: #d6e4f5; color: #1e1e1e; } QComboBox { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 5px 10px; color: #1e1e1e; } QComboBox:hover { border-color: #8a97a8; } QComboBox::drop-down { border: none; width: 22px; } QComboBox QAbstractItemView { background-color: #ffffff; color: #1e1e1e; border: 1px solid #b9c0cb; selection-background-color: #d6e4f5; } QScrollBar:vertical { background: #e2e6ec; width: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:vertical { background: #b0b9c6; min-height: 24px; border-radius: 5px; } QScrollBar::handle:vertical:hover { background: #9aa3b0; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } QScrollBar:horizontal { background: #e2e6ec; height: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:horizontal { background: #b0b9c6; min-width: 24px; border-radius: 5px; } QScrollBar::handle:horizontal:hover { background: #9aa3b0; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: transparent; }"
|
||||
light_qss: str = "QWidget { background-color: #f5f6f8; color: #1e1e1e; font-family: \"Segoe UI\", \"Microsoft YaHei UI\", \"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif; font-size: 13px; } QPushButton { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 7px 16px; color: #1e1e1e; } QPushButton:hover { background-color: #eef1f6; border-color: #8a97a8; } QPushButton:pressed { background-color: #2a6da8; border-color: #2a6da8; color: #ffffff; } QPushButton:disabled { background-color: #eceef1; color: #9aa3b0; border-color: #d3d8e0; } QLineEdit, QTextEdit { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 5px 8px; color: #1e1e1e; } QPlainTextEdit { background-color: #ffffff; border: 1px solid #c6ccd6; border-radius: 4px; color: #1e1e1e; } QCheckBox { color: #1e1e1e; spacing: 10px; font-size: 14px; } QProgressBar { background-color: #e2e6ec; border: 1px solid #c6ccd6; border-radius: 4px; text-align: center; color: #1e1e1e; font-size: 13px; } QProgressBar::chunk { background-color: #2a6da8; border-radius: 3px; } QTreeWidget { background-color: #ffffff; border: 1px solid #c6ccd6; border-radius: 4px; color: #1e1e1e; } QTreeWidget::item { height: 26px; padding-left: 4px; } QTreeWidget::item:selected { background-color: #d6e4f5; color: #1e1e1e; } QComboBox { background-color: #ffffff; border: 1px solid #b9c0cb; border-radius: 4px; padding: 5px 10px; color: #1e1e1e; } QComboBox:hover { border-color: #8a97a8; } QComboBox::drop-down { border: none; width: 22px; } QComboBox QAbstractItemView { background-color: #ffffff; color: #1e1e1e; border: 1px solid #b9c0cb; selection-background-color: #d6e4f5; } QScrollBar:vertical { background: #e2e6ec; width: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:vertical { background: #b0b9c6; min-height: 24px; border-radius: 5px; } QScrollBar::handle:vertical:hover { background: #9aa3b0; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } QScrollBar:horizontal { background: #e2e6ec; height: 10px; margin: 0px; border: none; border-radius: 5px; } QScrollBar::handle:horizontal { background: #b0b9c6; min-width: 24px; border-radius: 5px; } QScrollBar::handle:horizontal:hover { background: #9aa3b0; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: transparent; }"
|
||||
|
||||
|
||||
# 导航项样式
|
||||
@@ -466,6 +466,19 @@ def OnThemeChanged(slot_id: int, data: t.CPtr):
|
||||
ApplyTheme(idx)
|
||||
|
||||
|
||||
def ApplyIndicatorIcons(ptr: t.CPtr, is_tree: int):
|
||||
"""复选框/树叶子指示器用带对勾的 PNG 图标(未勾=灰框,勾选=蓝框+白勾)
|
||||
图标放 exe 目录 assets/ 下,路径用 vqt6_app_dir_utf8 运行时拼接"""
|
||||
sel: str = "QTreeWidget" if is_tree != 0 else "QCheckBox"
|
||||
dbuf: bytes = stdlib.malloc(640)
|
||||
vqt6.vqt6_app_dir_utf8(dbuf, 640)
|
||||
buf: bytes = stdlib.malloc(1100)
|
||||
viperlib.snprintf(buf, 1100, "%s::indicator { width: 16px; height: 16px; } %s::indicator:unchecked { image: url(file:///%s/assets/check_off.png); } %s::indicator:checked { image: url(file:///%s/assets/check_on.png); }", sel, sel, dbuf, sel, dbuf)
|
||||
vqt6.vqt6_qwidget_set_stylesheet_utf8(ptr, buf)
|
||||
stdlib.free(dbuf)
|
||||
stdlib.free(buf)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
global app_ptr, stack_ptr
|
||||
global nav0_ptr, nav1_ptr, nav2_ptr, nav3_ptr, nav4_ptr, nav5_ptr
|
||||
@@ -617,6 +630,7 @@ def main() -> int:
|
||||
agree_cb = vqt6.QCheckBox("我接受上述协议条款")
|
||||
p1.addWidget(agree_cb._ptr)
|
||||
agree_cb_ptr = t.CPtr(agree_cb._ptr)
|
||||
ApplyIndicatorIcons(agree_cb_ptr, 0)
|
||||
agree_cb.toggled(OnLicenseToggled, 0)
|
||||
|
||||
lbrow = vqt6.QHBoxLayout()
|
||||
@@ -651,6 +665,7 @@ def main() -> int:
|
||||
tree.setHeaderHidden(1)
|
||||
p2.addWidget(tree._ptr)
|
||||
tree_ptr = t.CPtr(tree._ptr)
|
||||
ApplyIndicatorIcons(tree_ptr, 1)
|
||||
|
||||
# 叶子磁盘占用经 setSize 存入节点 UserRole,统计时自动读取
|
||||
g0 = vqt6.QTreeWidgetItem("开发工具链")
|
||||
@@ -748,16 +763,19 @@ def main() -> int:
|
||||
opt0.setChecked(1)
|
||||
p3.addWidget(opt0._ptr)
|
||||
opt0_ptr = t.CPtr(opt0._ptr)
|
||||
ApplyIndicatorIcons(opt0_ptr, 0)
|
||||
|
||||
opt1 = vqt6.QCheckBox("将 viper 命令添加到系统 PATH")
|
||||
opt1.setChecked(0)
|
||||
p3.addWidget(opt1._ptr)
|
||||
opt1_ptr = t.CPtr(opt1._ptr)
|
||||
ApplyIndicatorIcons(opt1_ptr, 0)
|
||||
|
||||
opt2 = vqt6.QCheckBox("创建桌面图标")
|
||||
opt2.setChecked(0)
|
||||
p3.addWidget(opt2._ptr)
|
||||
opt2_ptr = t.CPtr(opt2._ptr)
|
||||
ApplyIndicatorIcons(opt2_ptr, 0)
|
||||
|
||||
# 安装位置行
|
||||
path_row = vqt6.QHBoxLayout()
|
||||
|
||||
Reference in new issue
Block a user