├── .gitattributes ├── .github └── workflows │ └── ruff.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets └── readme │ └── silicon_main.png ├── docs ├── README_zh.md ├── coding_standard.md └── template │ └── layer.md ├── examples ├── Gallery for siui │ ├── __init__.py │ ├── components │ │ ├── __init__.py │ │ ├── option_card │ │ │ ├── __init__.py │ │ │ └── plane.py │ │ ├── page_about │ │ │ ├── __init__.py │ │ │ └── page_about.py │ │ ├── page_container │ │ │ ├── __init__.py │ │ │ └── page_container.py │ │ ├── page_dialog │ │ │ ├── __init__.py │ │ │ ├── components │ │ │ │ ├── __init__.py │ │ │ │ ├── child_page_example.py │ │ │ │ ├── modal_dialog_example.py │ │ │ │ └── side_msg_box.py │ │ │ └── page_dialog.py │ │ ├── page_functional │ │ │ ├── __init__.py │ │ │ ├── components │ │ │ │ ├── __init__.py │ │ │ │ └── music_displayer │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── music_displayer.py │ │ │ └── page_functional.py │ │ ├── page_homepage │ │ │ ├── __init__.py │ │ │ ├── components │ │ │ │ ├── __init__.py │ │ │ │ └── themed_option_card.py │ │ │ └── page_homepage.py │ │ ├── page_icons │ │ │ ├── __init__.py │ │ │ └── page_icons.py │ │ ├── page_option_cards │ │ │ ├── __init__.py │ │ │ └── page_option_cards.py │ │ ├── page_page_control │ │ │ ├── __init__.py │ │ │ └── page_control.py │ │ ├── page_refactor │ │ │ ├── __init__.py │ │ │ └── page_refactor.py │ │ └── page_widgets │ │ │ ├── __init__.py │ │ │ ├── components │ │ │ ├── __init__.py │ │ │ └── demo_tables.py │ │ │ └── page_widgets.py │ ├── icons │ │ ├── __init__.py │ │ ├── icons.dat │ │ └── parser.py │ ├── img │ │ ├── about_version.png │ │ ├── avatar1.png │ │ ├── avatar2.png │ │ ├── empty_icon.png │ │ ├── homepage_background.png │ │ ├── logo.png │ │ ├── logo_new.png │ │ ├── pages │ │ │ └── functional │ │ │ │ └── music_covers │ │ │ │ ├── cover1.jpg │ │ │ │ ├── cover2.png │ │ │ │ ├── cover3.png │ │ │ │ ├── cover4.png │ │ │ │ ├── cover5.png │ │ │ │ └── cover6.png │ │ └── table │ │ │ ├── flags │ │ │ ├── CN.png │ │ │ ├── GB.png │ │ │ └── UM.png │ │ │ └── ranks │ │ │ ├── rank_s.png │ │ │ └── rank_ss.png │ ├── start.py │ ├── test_new_button.py │ └── ui.py ├── My-TODOs │ ├── components │ │ ├── __init__.py │ │ ├── core.py │ │ ├── page_about │ │ │ ├── __init__.py │ │ │ └── page_about.py │ │ ├── page_homepage │ │ │ ├── __init__.py │ │ │ ├── components │ │ │ │ ├── __init__.py │ │ │ │ └── today.py │ │ │ └── homepage.py │ │ └── widgets │ │ │ ├── __init__.py │ │ │ ├── button.py │ │ │ ├── group_title.py │ │ │ └── tasks.py │ ├── icons │ │ ├── __init__.py │ │ ├── icons.dat │ │ └── parser.py │ ├── images │ │ └── default_background.png │ ├── start.py │ └── ui.py └── button │ └── demo_button.py ├── pyproject.toml ├── setup.py └── siui ├── __init__.py ├── components ├── __init__.py ├── button.py ├── chart.py ├── combobox │ ├── __init__.py │ └── combobox.py ├── container.py ├── editbox.py ├── graphic.py ├── label.py ├── menu │ ├── __init__.py │ ├── abstracts │ │ ├── __init__.py │ │ ├── ani_manager.py │ │ └── menu.py │ ├── menu.py │ └── option.py ├── menu_.py ├── option_card │ ├── __init__.py │ ├── abstracts │ │ ├── __init__.py │ │ └── option_card.py │ └── option_card.py ├── page │ ├── __init__.py │ ├── child_page.py │ └── page.py ├── popover.py ├── progress_bar │ ├── __init__.py │ └── progress_bar.py ├── slider │ ├── __init__.py │ └── slider.py ├── slider_.py ├── spinbox │ ├── __init__.py │ └── spinbox.py ├── titled_widget_group │ ├── __init__.py │ └── titled_widget_group.py ├── tooltip │ ├── __init__.py │ └── tooltip.py └── widgets │ ├── __init__.py │ ├── abstracts │ ├── __init__.py │ ├── button.py │ ├── container.py │ ├── label.py │ ├── line_edit.py │ ├── navigation_bar.py │ ├── table.py │ └── widget.py │ ├── button.py │ ├── container.py │ ├── expands.py │ ├── label.py │ ├── line_edit.py │ ├── navigation_bar.py │ ├── scrollarea.py │ ├── table.py │ ├── timedate.py │ └── timeline.py ├── core ├── __init__.py ├── alignment.py ├── animation.py ├── color.py ├── effect.py ├── enumrates.py ├── function │ ├── __init__.py │ └── chain.py ├── globals.py ├── painter.py └── token.py ├── gui ├── __init__.py ├── color_group │ ├── __init__.py │ ├── bright.py │ ├── color_group.py │ └── dark.py ├── font.py ├── icons │ ├── __init__.py │ ├── packages │ │ ├── fluent_ui_icon_filled.icons │ │ ├── fluent_ui_icon_light.icons │ │ └── fluent_ui_icon_regular.icons │ └── parser.py └── scale.py ├── templates ├── __init__.py └── application │ ├── __init__.py │ ├── application.py │ └── components │ ├── __init__.py │ ├── dialog │ ├── __init__.py │ └── modal.py │ ├── layer │ ├── __init__.py │ ├── global_drawer.py │ ├── layer.py │ ├── layer_child_page │ │ ├── __init__.py │ │ └── layer_child_page.py │ ├── layer_left_global_drawer │ │ ├── __init__.py │ │ └── layer_left_global_drawer.py │ ├── layer_main │ │ ├── __init__.py │ │ └── layer_main.py │ ├── layer_modal_dialog │ │ ├── __init__.py │ │ └── layer_modal_dialog.py │ ├── layer_overlays │ │ ├── __init__.py │ │ └── layer_overlays.py │ └── layer_right_message_sidebar │ │ ├── __init__.py │ │ ├── layer_right_message_sidebar.py │ │ └── messagebox.py │ ├── message │ ├── __init__.py │ ├── box.py │ └── sidebar.py │ └── page_view │ ├── __init__.py │ └── page_view.py └── typing.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/ruff.yml: -------------------------------------------------------------------------------- 1 | name: Ruff 2 | on: [ push, pull_request ] 3 | jobs: 4 | ruff: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - uses: chartboost/ruff-action@v1 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # pdm 98 | .pdm-python 99 | 100 | # poetry 101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 102 | # This is especially recommended for binary packages to ensure reproducibility, and is more 103 | # commonly ignored for libraries. 104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 105 | #poetry.lock 106 | 107 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 108 | __pypackages__/ 109 | 110 | # Celery stuff 111 | celerybeat-schedule 112 | celerybeat.pid 113 | 114 | # SageMath parsed files 115 | *.sage.py 116 | 117 | # Environments 118 | .env 119 | .venv 120 | env/ 121 | venv/ 122 | ENV/ 123 | env.bak/ 124 | venv.bak/ 125 | 126 | # Spyder project settings 127 | .spyderproject 128 | .spyproject 129 | 130 | # Rope project settings 131 | .ropeproject 132 | 133 | # mkdocs documentation 134 | /site 135 | 136 | # mypy 137 | .mypy_cache/ 138 | .dmypy.json 139 | dmypy.json 140 | 141 | # Pyre type checker 142 | .pyre/ 143 | 144 | # pytype static type analyzer 145 | .pytype/ 146 | 147 | # Cython debug symbols 148 | cython_debug/ 149 | 150 | # PyCharm 151 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 152 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 153 | # and can be added to the globals gitignore or merged into this file. For a more nuclear 154 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 155 | #.idea/ 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | Logo 6 | 7 | 8 |

PyQt-SiliconUI

9 |

A powerful and artistic UI library based on PyQt5

10 | 11 |

12 | English | 简体中文 13 |

14 | 15 | ## Install 16 | Download this repository and run setup.py in cmd line: 17 | ```cmd 18 | python setup.py install 19 | ``` 20 | Due to the fact that this project is still in the development stage, it is temporarily not available on PyPi. 21 | 22 | However, we are currently working hard on it and will be available soon. 23 | 24 | 25 | ## Run Examples 26 | Run `examples/Gallery for siui/start.py` to take a look at widgets and components of PyQt-SiliconUI 27 | 28 | To quick start, run: 29 | ```cmd 30 | cd "examples/Gallery for siui" 31 | start start.py 32 | ``` 33 | Other more detailed examples for widgets are coming soon. 34 | 35 | 36 | ## See Also 37 | Here are some project that created based on PyQt-SiliconUI: 38 | * [My-TODOs](https://github.com/ChinaIceF/My-TODOs) - A cross-platform desktop To-Do list. 39 | 40 | 41 | ## License 42 | PyQt-SiliconUI is licensed under [GPLv3](LICENSE) 43 | 44 | Copyright © 2024 by ChinaIceF. -------------------------------------------------------------------------------- /assets/readme/silicon_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/assets/readme/silicon_main.png -------------------------------------------------------------------------------- /docs/README_zh.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | Logo 6 | 7 | 8 |

PyQt-SiliconUI

9 |

基于 PyQt5 的UI框架,灵动、优雅而轻便

10 | 11 |

12 | English | 简体中文 13 |

14 | 15 | ## 安装 16 | 下载该仓库,在命令行中输入以下命令: 17 | ```cmd 18 | python setup.py install 19 | ``` 20 | 由于本项目还在积极开发中,在发布正式版本前不能在 PyPi 上安装,敬请期待。 21 | 22 | 23 | ## 运行示例程序 24 | 运行 `examples/Gallery for siui/start.py` 来体验 PyQt-SiliconUI 提供的控件、组件和框架 25 | 26 | 也可直接在项目目录下运行以下命令: 27 | ```cmd 28 | cd "examples/Gallery for siui" 29 | start start.py 30 | ``` 31 | 其他针对各类控件的详细实例将逐一编写 32 | 33 | 34 | ## 另请参阅 35 | 一些基于 PyQt-SiliconUI 编写的项目: 36 | * [My-TODOs](https://github.com/ChinaIceF/My-TODOs) - 简洁轻便的跨平台桌面待办小工具 37 | 38 | 39 | ## 许可证 40 | PyQt-SiliconUI 使用 [GPLv3](../LICENSE) 许可证 41 | 42 | 版权所有 © 2024 by ChinaIceF. 43 | 44 | 45 | ## 特别声明 46 | 用户阅读、下载、基于该软件开发或修改该软件,即代表用户已经理解并同意开源许可证声明的权利与限制,用户理解并同意不进行违反当地法律法规的开发或/和修改,若因用户的开发或/和修改违反了当地的法律,或是用户的开发或/和修改的传播和使用过程中违反了传播者和使用者所在地区适用的法律,或是造成了任何负面的个人或公众影响,用户应承担全部责任,本软件的开发者不承担任何责任。 47 | 48 | -------------------------------------------------------------------------------- /docs/coding_standard.md: -------------------------------------------------------------------------------- 1 | # 代码规范 2 | 创建于 2024.10.25 3 | 4 | 为了提高可读性和可维护性,新编写的 PyQt-SiliconUI 代码将遵守以下规范。 5 | 6 | ## 命名规范 7 | ### 命名法 8 | * 变量名采用 snake_case。 9 | * 方法名沿袭 PyQt 特点,采用 lowerCamelCase 10 | * 类名采用 UpperCamelCase 11 | * 旗标类、枚举类和常量采用全大写命名 12 | 13 | ### 命名构成 14 | #### 变量名 15 | * 采用正常英文语序命名,例如 `day_counter`, `month_counter`, `year_counter` 16 | * 具有大量语义类似,而类型不同的变量,将强调的类型提前作为前缀,例如 `container_name`, `label_name` 17 | * 变量名与方法名冲突时,变量名后加 `_` 后缀,如 `self.name()`, `self.name_` 18 | 19 | 20 | ## 控件 / 组件类 21 | 约定模版化的方法和其功能。 22 | 23 | ### _initWidget() 24 | 初始化组件中需要用到的控件,仅做声明,不包含样式表,几何信息等。 25 | 26 | ### _initStyle() 27 | 初始化样式表、字体、颜色等外观相关的属性到自身以及 `_initWidget()` 声明的控件中。 28 | 29 | ### _initLayout() 30 | 初始化布局。除了使用 `QLayout` 外,几何信息也在这里定义,包括位置和大小。 31 | 32 | ### _initAnimation() 33 | 初始化动画。包括 `QPropertyAnimation` 和 `SiAnimation`,在这里完成他们的初始化和信号绑定。 34 | 例如: 35 | ```python 36 | def _initAnimation(self): 37 | self.animation = SiExpAnimation(self) 38 | self.animation.setFactor(1/8) 39 | self.animation.setBias(0.2) 40 | self.animation.setTarget(self.idle_color) 41 | self.animation.setCurrent(self.idle_color) 42 | self.animation.ticked.connect(self.animate) 43 | ``` 44 | 45 | ### \_\_init\_\_() 46 | * 初始化变量。 47 | * 依次调用 `_initWidget()` `_initStyle()` `_initLayout()` `_initAnimation()`。 -------------------------------------------------------------------------------- /docs/template/layer.md: -------------------------------------------------------------------------------- 1 | # SiLayer 2 | 在应用界面上的可叠加容器,实现主界面、子界面、弹窗和侧边栏等等叠加场景。 3 | 4 | | | | 5 | |------:|:---------| 6 | | 继承自 | SiWidget | 7 | | 被继承对象 | - | 8 | 9 | ## 公共方法 10 | | 方法名 | 返回值类型 | 11 | |:-----------------------------------------|:---------| 12 | | setBody(SiWidget) | None | 13 | | body() | SiWidget | 14 | | setCloseUpperLayerOnDimClicked(on :bool) | None | 15 | | closeLayer() | None | 16 | 17 | ## 信号 18 | | 信号名 | 返回值类型 | 19 | |:--------------|:------| 20 | | closed | None | 21 | | closedToUpper | bool | 22 | -------------------------------------------------------------------------------- /examples/Gallery for siui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/option_card/__init__.py: -------------------------------------------------------------------------------- 1 | from .plane import * -------------------------------------------------------------------------------- /examples/Gallery for siui/components/option_card/plane.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PyQt5.QtCore import Qt 4 | 5 | from siui.components import SiOptionCardPlane 6 | from siui.components.widgets import SiLabel, SiSimpleButton 7 | from siui.core import SiGlobal 8 | from siui.core import Si 9 | 10 | 11 | class OptionCardPlaneForWidgetDemos(SiOptionCardPlane): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | 15 | self.source_code_url = None 16 | 17 | self.additional_description = SiLabel(self) 18 | self.additional_description.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 19 | self.additional_description.setFixedHeight(24) 20 | self.additional_description.setAlignment(Qt.AlignLeft | Qt.AlignBottom) 21 | 22 | self.button_bug = SiSimpleButton(self) 23 | self.button_bug.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_bug_regular")) 24 | self.button_bug.resize(32, 32) 25 | self.button_bug.setHint("报告问题") 26 | self.button_bug.clicked.connect( 27 | lambda: os.system("start https://github.com/ChinaIceF/PyQt-SiliconUI/issues/new")) 28 | 29 | self.button_source_code = SiSimpleButton(self) 30 | self.button_source_code.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_open_regular")) 31 | self.button_source_code.resize(32, 32) 32 | self.button_source_code.setHint("查看源代码") 33 | self.button_source_code.clicked.connect(self.openSourceCode) 34 | 35 | self.header().addWidget(self.additional_description, "left") 36 | self.header().addWidget(self.button_source_code, "right") 37 | self.header().addWidget(self.button_bug, "right") 38 | 39 | self.body().setSpacing(16) 40 | 41 | def setSourceCodeURL(self, url): 42 | self.source_code_url = url 43 | 44 | def openSourceCode(self): 45 | if self.source_code_url is None: 46 | raise ValueError("未指定源代码 URL") 47 | os.system(f"start {self.source_code_url}") 48 | 49 | def setAdditionalDescription(self, text: str): 50 | self.additional_description.setText(text) 51 | 52 | def reloadStyleSheet(self): 53 | super().reloadStyleSheet() 54 | self.additional_description.setStyleSheet("color: {}".format(SiGlobal.siui.colors["TEXT_C"])) 55 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_about/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_about import About -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_about/page_about.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, QUrl 2 | from PyQt5.QtGui import QDesktopServices 3 | from PyQt5.QtWidgets import QSizePolicy 4 | 5 | from siui.components import ( 6 | SiDenseVContainer, 7 | SiLabel, 8 | SiOptionCardLinear, 9 | SiPixLabel, 10 | SiPushButton, 11 | SiSimpleButton, 12 | SiTitledWidgetGroup, 13 | ) 14 | from siui.components.page import SiPage 15 | from siui.core import GlobalFont, Si, SiColor, SiGlobal, SiQuickEffect 16 | from siui.gui import SiFont 17 | 18 | 19 | class About(SiPage): 20 | def __init__(self, *args, **kwargs): 21 | super().__init__(*args, **kwargs) 22 | 23 | self.setPadding(64) 24 | self.setScrollMaximumWidth(950) 25 | self.setTitle("关于") 26 | 27 | self.titled_widget_group = SiTitledWidgetGroup(self) 28 | self.titled_widget_group.setSiliconWidgetFlag(Si.EnableAnimationSignals) 29 | 30 | version_picture_container = SiDenseVContainer(self) 31 | version_picture_container.setAlignment(Qt.AlignCenter) 32 | version_picture_container.setFixedHeight(128 + 48) 33 | SiQuickEffect.applyDropShadowOn(version_picture_container, color=(28, 25, 31, 255), blur_radius=48) 34 | 35 | self.version_picture = SiPixLabel(self) 36 | self.version_picture.setFixedSize(128, 128) 37 | self.version_picture.setBorderRadius(0) 38 | self.version_picture.load("./img/logo_new.png") 39 | 40 | self.version_label = SiLabel(self) 41 | self.version_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 42 | self.version_label.setFont(SiFont.tokenized(GlobalFont.M_NORMAL)) 43 | self.version_label.setStyleSheet(f"color: {self.getColor(SiColor.TEXT_D)}") 44 | self.version_label.setText("PyQt-SiliconUI") 45 | 46 | version_picture_container.addWidget(self.version_picture) 47 | version_picture_container.addWidget(self.version_label) 48 | self.titled_widget_group.addWidget(version_picture_container) 49 | 50 | with self.titled_widget_group as group: 51 | group.addTitle("开源") 52 | 53 | self.button_to_repo = SiSimpleButton(self) 54 | self.button_to_repo.resize(32, 32) 55 | self.button_to_repo.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_open_regular")) 56 | self.button_to_repo.clicked.connect(lambda: QDesktopServices.openUrl(QUrl("https://github.com/ChinaIceF/PyQt-SiliconUI"))) 57 | 58 | self.option_card_repo = SiOptionCardLinear(self) 59 | self.option_card_repo.setTitle("开源仓库", "在 GitHub 上查看 Silicon UI 的项目主页") 60 | self.option_card_repo.load(SiGlobal.siui.iconpack.get("ic_fluent_home_database_regular")) 61 | self.option_card_repo.addWidget(self.button_to_repo) 62 | 63 | self.option_card_license = SiOptionCardLinear(self) 64 | self.option_card_license.setTitle("开源许可证", "本项目遵循 GPLv3.0 许可证供非商业使用") 65 | self.option_card_license.load(SiGlobal.siui.iconpack.get("ic_fluent_certificate_regular")) 66 | 67 | group.addWidget(self.option_card_repo) 68 | group.addWidget(self.option_card_license) 69 | 70 | with self.titled_widget_group as group: 71 | group.addTitle("版权") 72 | 73 | self.option_card_copyright = SiOptionCardLinear(self) 74 | self.option_card_copyright.setTitle("版权声明", "PyQt-SiliconUI 版权所有 © 2024 by ChinaIceF") 75 | self.option_card_copyright.load(SiGlobal.siui.iconpack.get("ic_fluent_info_regular")) 76 | 77 | group.addWidget(self.option_card_copyright) 78 | 79 | with self.titled_widget_group as group: 80 | group.addTitle("第三方资源") 81 | 82 | self.option_card_icon_pack = SiOptionCardLinear(self) 83 | self.option_card_icon_pack.setTitle("Fluent UI 图标库", "本项目内置了 Fluent UI 图标库,Microsoft 公司保有这些图标的版权") 84 | self.option_card_icon_pack.load(SiGlobal.siui.iconpack.get("ic_fluent_diversity_regular")) 85 | 86 | group.addWidget(self.option_card_icon_pack) 87 | 88 | # add placeholder for better outfit 89 | self.titled_widget_group.addPlaceholder(64) 90 | 91 | # Set SiTitledWidgetGroup object as the attachment of the page's scroll area 92 | self.setAttachment(self.titled_widget_group) -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_container/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_container import ExampleContainer -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_dialog/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_dialog import ExampleDialogs -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_dialog/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/page_dialog/components/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_dialog/components/modal_dialog_example.py: -------------------------------------------------------------------------------- 1 | from siui.components import SiLabel, SiLongPressButton, SiPushButton 2 | from siui.core import SiColor, SiGlobal 3 | from siui.templates.application.components.dialog.modal import SiModalDialog 4 | 5 | 6 | class ModalDialogExample(SiModalDialog): 7 | def __init__(self, *args, **kwargs): 8 | super().__init__(*args, **kwargs) 9 | 10 | self.setFixedWidth(500) 11 | self.icon().load(SiGlobal.siui.iconpack.get("ic_fluent_save_filled", 12 | color_code=SiColor.mix( 13 | self.getColor(SiColor.SVG_NORMAL), 14 | self.getColor(SiColor.INTERFACE_BG_B), 15 | 0.05)) 16 | ) 17 | 18 | label = SiLabel(self) 19 | label.setStyleSheet(f"color: {self.getColor(SiColor.TEXT_E)}") 20 | label.setText( 21 | f'是否保存刚刚编辑的文件?
' 22 | "
" 23 | "- 田所浩二志.doc
" 24 | "- 八十天游览下北泽——从百草园到三味书屋.docx
" 25 | "- 小黑子是怎样练成的.pdf" 26 | ) 27 | label.adjustSize() 28 | self.contentContainer().addWidget(label) 29 | 30 | button1 = SiPushButton(self) 31 | button1.setFixedHeight(32) 32 | button1.attachment().setText("继续编辑我的文档") 33 | button1.colorGroup().assign(SiColor.BUTTON_PANEL, self.getColor(SiColor.INTERFACE_BG_D)) 34 | button1.clicked.connect(SiGlobal.siui.windows["MAIN_WINDOW"].layerModalDialog().closeLayer) 35 | 36 | button2 = SiPushButton(self) 37 | button2.setFixedHeight(32) 38 | button2.attachment().setText("保存并退出") 39 | button2.colorGroup().assign(SiColor.BUTTON_PANEL, self.getColor(SiColor.INTERFACE_BG_D)) 40 | button2.clicked.connect(SiGlobal.siui.windows["MAIN_WINDOW"].layerModalDialog().closeLayer) 41 | 42 | self.button3 = SiLongPressButton(self) 43 | self.button3.setFixedHeight(32) 44 | self.button3.attachment().setText("丢弃一切创作成果并退出") 45 | self.button3.longPressed.connect(SiGlobal.siui.windows["MAIN_WINDOW"].layerModalDialog().closeLayer) 46 | 47 | self.buttonContainer().addWidget(button1) 48 | self.buttonContainer().addWidget(button2) 49 | self.buttonContainer().addWidget(self.button3) 50 | 51 | SiGlobal.siui.reloadStyleSheetRecursively(self) 52 | self.adjustSize() 53 | 54 | def deleteLater(self): 55 | # print("你好") 56 | self.button3.hold_thread.safe_to_stop = True 57 | self.button3.hold_thread.wait() 58 | self.button3.deleteLater() 59 | SiGlobal.siui.windows["TOOL_TIP"].setNowInsideOf(None) 60 | SiGlobal.siui.windows["TOOL_TIP"].hide_() 61 | super().deleteLater() 62 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_dialog/components/side_msg_box.py: -------------------------------------------------------------------------------- 1 | from siui.components import SiDenseHContainer, SiDenseVContainer, SiLabel, SiPixLabel, SiSimpleButton 2 | from siui.core import GlobalFont, SiColor, SiGlobal 3 | from siui.gui import SiFont 4 | from siui.templates.application.components.message.box import SiSideMessageBox 5 | 6 | 7 | def send_simple_message(type_, auto_close=False, auto_close_duration=1000): 8 | fold_after = auto_close_duration if auto_close is True else None 9 | SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send( 10 | "这是一条测试消息\n" 11 | "比具标题信息更加简洁方便", 12 | msg_type=type_, 13 | fold_after=fold_after, 14 | ) 15 | 16 | 17 | def send_titled_message(type_, auto_close=False, auto_close_duration=1000): 18 | fold_after = auto_close_duration if auto_close is True else None 19 | SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send( 20 | title="Sent Successfully", 21 | text="A titled message has been successfully sent to the sidebar.\n" + 22 | "Click this message box for more information.", 23 | msg_type=type_, 24 | fold_after=fold_after, 25 | ) 26 | 27 | 28 | def send_custom_message(type_, auto_close=False, auto_close_duration=1000): 29 | fold_after = auto_close_duration if auto_close is True else None 30 | container = SiDenseHContainer() 31 | container.setAdjustWidgetsSize(True) 32 | container.setFixedHeight(80) 33 | container.setSpacing(0) 34 | 35 | info_label = SiLabel() 36 | info_label.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 37 | info_label.setStyleSheet(f"color: {info_label.getColor(SiColor.TEXT_D)}; padding-left: 16px") 38 | info_label.setText("以下账号已成功登录") 39 | info_label.adjustSize() 40 | 41 | split_line = SiLabel() 42 | split_line.resize(300, 1) 43 | split_line.setFixedStyleSheet("margin-left: 20px") 44 | split_line.setColor(SiColor.trans(split_line.getColor(SiColor.TEXT_D), 0.3)) 45 | 46 | avatar = SiPixLabel(container) 47 | avatar.resize(80, 80) 48 | avatar.setBorderRadius(40) 49 | avatar.load("./img/avatar1.png") 50 | avatar.setHint("霏泠Ice") 51 | 52 | container_v = SiDenseVContainer(container) 53 | container_v.setFixedWidth(200) 54 | container_v.setSpacing(0) 55 | 56 | name_label = SiLabel() 57 | name_label.setFont(SiFont.tokenized(GlobalFont.M_BOLD)) 58 | name_label.setStyleSheet(f"color: {name_label.getColor(SiColor.TEXT_B)}; padding-left:8px") 59 | name_label.setText("霏泠Ice") 60 | name_label.adjustSize() 61 | 62 | button_1 = SiSimpleButton() 63 | button_1.setFixedHeight(22) 64 | button_1.attachment().setText("打开我的主页") 65 | button_1.colorGroup().assign(SiColor.TEXT_B, button_1.getColor(SiColor.TITLE_INDICATOR)) 66 | button_1.adjustSize() 67 | button_1.reloadStyleSheet() 68 | 69 | button_2 = SiSimpleButton() 70 | button_2.setFixedHeight(22) 71 | button_2.attachment().setText("退出账号") 72 | button_2.colorGroup().assign(SiColor.TEXT_B, button_2.getColor(SiColor.TITLE_INDICATOR)) 73 | button_2.adjustSize() 74 | button_2.reloadStyleSheet() 75 | 76 | container_v.addWidget(name_label) 77 | container_v.addPlaceholder(8) 78 | container_v.addWidget(button_1) 79 | container_v.addWidget(button_2) 80 | container_v.adjustSize() 81 | 82 | container.addPlaceholder(24) 83 | container.addWidget(avatar) 84 | container.addPlaceholder(8) 85 | container.addWidget(container_v) 86 | container.adjustSize() 87 | 88 | new_message_box = SiSideMessageBox() 89 | new_message_box.setMessageType(type_) 90 | new_message_box.content().container().setSpacing(0) 91 | new_message_box.content().container().addPlaceholder(16) 92 | new_message_box.content().container().addWidget(info_label) 93 | new_message_box.content().container().addPlaceholder(8) 94 | new_message_box.content().container().addWidget(split_line) 95 | new_message_box.content().container().addPlaceholder(24) 96 | new_message_box.content().container().addWidget(container) 97 | new_message_box.content().container().addPlaceholder(32) 98 | new_message_box.adjustSize() 99 | 100 | if fold_after is not None: 101 | new_message_box.setFoldAfter(fold_after) 102 | 103 | SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().sendMessageBox(new_message_box) 104 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_functional/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_functional import ExampleFunctional -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_functional/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/page_functional/components/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_functional/components/music_displayer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/page_functional/components/music_displayer/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_functional/page_functional.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import SiTitledWidgetGroup, SiPushButton, SiLabel, SiLongPressButton, SiDenseHContainer, \ 4 | SiMasonryContainer 5 | from siui.components.combobox import SiComboBox 6 | from siui.components.page import SiPage 7 | from siui.core import SiColor 8 | from siui.core import SiQuickEffect 9 | from siui.core import SiGlobal 10 | from siui.templates.application.components.dialog.modal import SiModalDialog 11 | 12 | from ..option_card import OptionCardPlaneForWidgetDemos 13 | from .components.music_displayer.music_displayer import SiMusicDisplayer 14 | 15 | class ExampleFunctional(SiPage): 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | 19 | self.setPadding(64) 20 | self.setScrollMaximumWidth(1040) 21 | self.setScrollAlignment(Qt.AlignHCenter) 22 | self.setTitle("功能组件") 23 | 24 | # 创建控件组 25 | self.titled_widgets_group = SiTitledWidgetGroup(self) 26 | self.titled_widgets_group.setSpacing(32) 27 | self.titled_widgets_group.setAdjustWidgetsSize(False) # 禁用调整宽度 28 | 29 | # 音乐展示框 30 | with self.titled_widgets_group as group: 31 | group.addTitle("音乐展示框") 32 | 33 | self.displayer_container = SiMasonryContainer(self) 34 | self.displayer_container.setColumns(2) 35 | self.displayer_container.setColumnWidth(512) 36 | self.displayer_container.setFixedWidth(512 + 512 + 16) 37 | self.displayer_container.setSpacing(horizontal=16, vertical=16) 38 | 39 | self.demo_displayer_1 = SiMusicDisplayer(self) 40 | self.demo_displayer_1.resize(512, 128) 41 | self.demo_displayer_1.loadInfo("./img/pages/functional/music_covers/cover1.jpg", "Moon Without The Stars", "Unknown Artist", "Unknown Album") # noqa: E501 42 | 43 | self.demo_displayer_2 = SiMusicDisplayer(self) 44 | self.demo_displayer_2.resize(512, 128) 45 | self.demo_displayer_2.loadInfo("./img/pages/functional/music_covers/cover2.png", "Never Gonna Give You Up", "Rick Astley", "Whenever You Need Somebody") # noqa: E501 46 | 47 | self.demo_displayer_3 = SiMusicDisplayer(self) 48 | self.demo_displayer_3.resize(512, 128) 49 | self.demo_displayer_3.loadInfo("./img/pages/functional/music_covers/cover3.png", "Friend", "玉置浩二", "ワインレッドの心") # noqa: E501 50 | 51 | self.demo_displayer_4 = SiMusicDisplayer(self) 52 | self.demo_displayer_4.resize(512, 128) 53 | self.demo_displayer_4.loadInfo("./img/pages/functional/music_covers/cover4.png", "雨中的重逢", "Parion圆周率", "Reunion In The Rain") # noqa: E501 54 | 55 | self.demo_displayer_5 = SiMusicDisplayer(self) 56 | self.demo_displayer_5.resize(512, 128) 57 | self.demo_displayer_5.loadInfo("./img/pages/functional/music_covers/cover5.png", "Melting White", "塞壬唱片-MSR / Cubes Collective", "Melting White") # noqa: E501 58 | 59 | self.demo_displayer_6 = SiMusicDisplayer(self) 60 | self.demo_displayer_6.resize(512, 128) 61 | self.demo_displayer_6.loadInfo("./img/pages/functional/music_covers/cover6.png", "Axolotl", "C418", "Axolotl") # noqa: E501 62 | 63 | self.displayer_container.addWidget(self.demo_displayer_1) 64 | self.displayer_container.addWidget(self.demo_displayer_2) 65 | self.displayer_container.addWidget(self.demo_displayer_3) 66 | self.displayer_container.addWidget(self.demo_displayer_4) 67 | self.displayer_container.addWidget(self.demo_displayer_5) 68 | self.displayer_container.addWidget(self.demo_displayer_6) 69 | 70 | group.addWidget(self.displayer_container) 71 | 72 | # 添加页脚的空白以增加美观性 73 | self.titled_widgets_group.addPlaceholder(64) 74 | 75 | # 设置控件组为页面对象 76 | self.setAttachment(self.titled_widgets_group) 77 | 78 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_homepage/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_homepage import ExampleHomepage -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_homepage/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/page_homepage/components/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_homepage/components/themed_option_card.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PyQt5.QtCore import Qt 4 | 5 | from siui.components.option_card import SiOptionCardPlane 6 | from siui.components.widgets import SiDenseVContainer, SiLabel, SiSimpleButton 7 | from siui.core import SiGlobal 8 | from siui.core import Si 9 | 10 | 11 | class ThemedOptionCardPlane(SiOptionCardPlane): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | 15 | self.my_theme_color = "#855198" 16 | self.setSpacing(32) 17 | 18 | # 标题边的指示器 19 | self.title_indicator = SiLabel(self) 20 | self.title_indicator.setGeometry(0, 24, 4, 18) 21 | 22 | # 解释说明 23 | self.description = SiLabel(self) 24 | self.description.setWordWrap(True) 25 | self.description.setFixedHeight(128) 26 | self.description.setAlignment(Qt.AlignLeft | Qt.AlignTop) 27 | self.body().setAdjustWidgetsSize(True) 28 | self.body().addWidget(self.description) 29 | 30 | # 链接按钮 31 | self.link_button = SiSimpleButton(self) 32 | self.link_button.setFixedSize(32, 32) 33 | self.link_button.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_open_regular")) 34 | 35 | link_button_container = SiDenseVContainer(self) 36 | link_button_container.setAlignment(Qt.AlignCenter) 37 | link_button_container.setFixedHeight(48) 38 | link_button_container.addWidget(self.link_button) 39 | self.footer().setSiliconWidgetFlag(Si.EnableAnimationSignals) 40 | self.footer().resized.connect(lambda size: link_button_container.setFixedWidth(size[0])) 41 | self.footer().setFixedHeight(48) 42 | self.footer().addWidget(link_button_container) 43 | 44 | def setDescription(self, text): 45 | self.description.setText(f"

{text}

") 46 | 47 | def setThemeColor(self, color_code): 48 | self.my_theme_color = color_code 49 | self.reloadStyleSheet() 50 | 51 | def setURL(self, url): 52 | self.link_button.setHint(url) 53 | self.link_button.clicked.connect(lambda: os.system(f"start {url}")) 54 | 55 | def reloadStyleSheet(self): 56 | super().reloadStyleSheet() 57 | 58 | self.outfit_label_upper.setStyleSheet( 59 | """ 60 | border-radius: 8px; background-color: {} 61 | """.format(SiGlobal.siui.colors["INTERFACE_BG_C"]) 62 | ) 63 | self.outfit_label_lower.setStyleSheet(f"border-radius: 8px; background-color: {self.my_theme_color}") 64 | self.title_indicator.setStyleSheet(f"border-radius: 2px; background-color: {self.my_theme_color}") 65 | self.description.setStyleSheet("color: {}".format(SiGlobal.siui.colors["TEXT_B"])) 66 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_icons/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_icons import ExampleIcons 2 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_option_cards/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_option_cards import ExampleOptionCards -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_page_control/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_control import ExamplePageControl -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_page_control/page_control.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import ( 4 | SiPushButton, 5 | SiTitledWidgetGroup, 6 | ) 7 | from siui.components.page import SiPage 8 | from siui.core import SiGlobal 9 | 10 | from ..option_card import OptionCardPlaneForWidgetDemos 11 | 12 | 13 | class ExamplePageControl(SiPage): 14 | def __init__(self, *args, **kwargs): 15 | super().__init__(*args, **kwargs) 16 | 17 | self.setPadding(64) 18 | self.setScrollMaximumWidth(950) 19 | self.setScrollAlignment(Qt.AlignLeft) 20 | self.setTitle("页面控制") 21 | 22 | # 创建控件组 23 | self.titled_widgets_group = SiTitledWidgetGroup(self) 24 | self.titled_widgets_group.setSpacing(32) 25 | self.titled_widgets_group.setAdjustWidgetsSize(False) # 禁用调整宽度 26 | 27 | # 侧边栏信息 28 | with self.titled_widgets_group as group: 29 | group.addTitle("页面偏移") 30 | 31 | # 侧边栏信息 32 | self.global_shifting = OptionCardPlaneForWidgetDemos(self) 33 | self.global_shifting.setSourceCodeURL("https://github.com/ChinaIceF/PyQt-SiliconUI/blob/main/siui/components" 34 | "/widgets/progress_bar/progress_bar.py") 35 | self.global_shifting.setTitle("页面偏移") 36 | self.global_shifting.setFixedWidth(800) 37 | 38 | self.ctrl_shift_left = SiPushButton(self) 39 | self.ctrl_shift_left.resize(128, 32) 40 | self.ctrl_shift_left.attachment().setText("向左偏移") 41 | self.ctrl_shift_left.clicked.connect( 42 | lambda: SiGlobal.siui.windows["MAIN_WINDOW"].groups()["MAIN_INTERFACE"].moveTo(-100, 0)) 43 | 44 | self.ctrl_shift_right = SiPushButton(self) 45 | self.ctrl_shift_right.resize(128, 32) 46 | self.ctrl_shift_right.attachment().setText("向右偏移") 47 | self.ctrl_shift_right.clicked.connect( 48 | lambda: SiGlobal.siui.windows["MAIN_WINDOW"].groups()["MAIN_INTERFACE"].moveTo(100, 0)) 49 | 50 | self.ctrl_shift_restore = SiPushButton(self) 51 | self.ctrl_shift_restore.resize(128, 32) 52 | self.ctrl_shift_restore.attachment().setText("恢复") 53 | self.ctrl_shift_restore.clicked.connect( 54 | lambda: SiGlobal.siui.windows["MAIN_WINDOW"].groups()["MAIN_INTERFACE"].moveTo(0, 0)) 55 | 56 | self.global_shifting.body().addWidget(self.ctrl_shift_left) 57 | self.global_shifting.body().addWidget(self.ctrl_shift_right) 58 | self.global_shifting.body().addWidget(self.ctrl_shift_restore) 59 | self.global_shifting.body().addPlaceholder(12) 60 | self.global_shifting.adjustSize() 61 | 62 | group.addWidget(self.global_shifting) 63 | 64 | # 添加页脚的空白以增加美观性 65 | self.titled_widgets_group.addPlaceholder(64) 66 | 67 | # 设置控件组为页面对象 68 | self.setAttachment(self.titled_widgets_group) 69 | -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_refactor/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_refactor import RefactoredWidgets -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_widgets/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_widgets import ExampleWidgets -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_widgets/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/components/page_widgets/components/__init__.py -------------------------------------------------------------------------------- /examples/Gallery for siui/components/page_widgets/components/demo_tables.py: -------------------------------------------------------------------------------- 1 | from siui.components import SiLabel, SiPixLabel 2 | from siui.components.widgets.abstracts.table import ABCSiTabelManager, SiRow 3 | from siui.core import GlobalFont, Si, SiColor 4 | from siui.gui import SiFont 5 | 6 | 7 | class DemoOsuPlayerRankingTableManager(ABCSiTabelManager): 8 | # #0 排名 SiLabel 9 | # #1 评级图片 SiPixLabel 10 | # #2 得分 SiLabel 11 | # #3 准确度 SiLabel 12 | # #4 国旗 SiPixLabel 13 | # #5 玩家用户名 SiLabel 14 | # #6 GREAT SiLabel 15 | # #7 OK SiLabel 16 | # #8 MEM SiLabel 17 | # #9 MISS SiLabel 18 | # #10 PP SiLabel 19 | 20 | rank_dict = { 21 | "S": "./img/table/ranks/rank_s.png", 22 | "SS": "./img/table/ranks/rank_ss.png", 23 | } 24 | 25 | country_dict = { 26 | "China": "./img/table/flags/CN.png", 27 | "United State": "./img/table/flags/UM.png", 28 | "Great Britain": "./img/table/flags/GB.png", 29 | } 30 | 31 | def _value_read_parser(self, row_index, col_index): 32 | if col_index in [0, 2, 3, 5, 6, 7, 8, 9, 10]: 33 | return self.parent().getRowWidget(row_index)[col_index].text() 34 | 35 | if col_index in [1, 4]: 36 | path = self.parent().getRowWidget(row_index)[col_index].path() 37 | return list(self.country_dict.keys())[list(self.country_dict.values()).index(path)] 38 | 39 | def _value_write_parser(self, row_index, col_index, value): 40 | widget = self.parent().getRowWidget(row_index)[col_index] 41 | if col_index == 0: 42 | widget.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 43 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_B)) 44 | 45 | if col_index == 1: 46 | widget.load(self.rank_dict[value]) 47 | widget.setHint(value) 48 | 49 | if col_index == 2: 50 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_B)) 51 | if row_index == 0: 52 | widget.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 53 | else: 54 | widget.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 55 | 56 | if col_index == 3: 57 | if value == "100.00%": 58 | widget.setTextColor("#B2D844") 59 | else: 60 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_B)) 61 | 62 | if col_index == 4: 63 | widget.load(self.country_dict[value]) 64 | widget.setHint(value) 65 | 66 | if col_index == 5: 67 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_THEME)) 68 | widget.setHint("Click to view profile") 69 | 70 | if col_index in [6, 7, 8, 9, 10]: 71 | if value == "0": 72 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_E)) 73 | else: 74 | widget.setTextColor(self.parent().getColor(SiColor.TEXT_B)) 75 | 76 | if col_index in [0, 2, 3, 5, 6, 7, 8, 9, 10]: 77 | widget.setText(value) 78 | 79 | def _widget_creator(self, col_index): 80 | if col_index in [0, 2, 3, 5, 6, 7, 8, 9, 10]: 81 | label = SiLabel(self.parent()) 82 | label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 83 | return label 84 | if col_index == 1: 85 | pix_label = SiPixLabel(self.parent()) 86 | pix_label.resize(48, 24) 87 | pix_label.setBorderRadius(0) 88 | return pix_label 89 | if col_index == 4: 90 | pix_label = SiPixLabel(self.parent()) 91 | pix_label.resize(33, 24) 92 | pix_label.setBorderRadius(0) 93 | return pix_label 94 | 95 | def on_header_created(self, header: SiRow): 96 | for name in self.parent().column_names: 97 | new_label = SiLabel(self.parent()) 98 | new_label.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 99 | new_label.setTextColor(self.parent().getColor(SiColor.TEXT_D)) 100 | new_label.setText(name) 101 | new_label.adjustSize() 102 | header.container().addWidget(new_label) 103 | 104 | header.container().arrangeWidgets() 105 | 106 | -------------------------------------------------------------------------------- /examples/Gallery for siui/icons/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import * 2 | -------------------------------------------------------------------------------- /examples/Gallery for siui/icons/icons.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/icons/icons.dat -------------------------------------------------------------------------------- /examples/Gallery for siui/icons/parser.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import os 3 | 4 | current_module_path = os.path.dirname(os.path.abspath(__file__)) 5 | data_file_path = os.path.join(current_module_path, './icons.dat') 6 | 7 | class IconDictionary: 8 | def __init__(self, library_path=data_file_path, color=None): 9 | 10 | # !注意! 你不应使用这些文件,他们已经过加密处理 11 | # 如果你需要这些图标文件,你可以直接在 flaticon.com 免费获取他们 12 | 13 | # 读取数据并解密 14 | f = open(library_path, 'rb') 15 | library_raw = f.read() 16 | library_list = list(library_raw) 17 | library = bytes(list((numpy.array(library_list) + numpy.array(range(len(library_list))) * 17) % 255)).decode() # 解密 18 | 19 | # 整理成字典 20 | items = library.split('!!!') 21 | names = [] 22 | datas = [] 23 | for item in items[1:]: 24 | name, data = item.split('###') 25 | data = data.replace('/>', ' fill="{}" />'.format(color)) 26 | names.append(name) 27 | datas.append(data.encode()) 28 | self.icons = dict(zip(names, datas)) 29 | 30 | def get(self, name): 31 | svg_data = self.icons[name] 32 | return svg_data.encode() 33 | -------------------------------------------------------------------------------- /examples/Gallery for siui/img/about_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/about_version.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/avatar1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/avatar1.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/avatar2.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/empty_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/empty_icon.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/homepage_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/homepage_background.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/logo.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/logo_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/logo_new.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover1.jpg -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover2.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover3.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover4.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover5.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/pages/functional/music_covers/cover6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/pages/functional/music_covers/cover6.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/table/flags/CN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/table/flags/CN.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/table/flags/GB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/table/flags/GB.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/table/flags/UM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/table/flags/UM.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/table/ranks/rank_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/table/ranks/rank_s.png -------------------------------------------------------------------------------- /examples/Gallery for siui/img/table/ranks/rank_ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/Gallery for siui/img/table/ranks/rank_ss.png -------------------------------------------------------------------------------- /examples/Gallery for siui/start.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | from PyQt5.QtCore import QTimer 5 | from PyQt5.QtWidgets import QApplication 6 | from ui import MySiliconApp 7 | 8 | import siui 9 | from siui.core import SiGlobal 10 | 11 | # 12 | # siui.gui.set_scale_factor(1) 13 | 14 | 15 | def show_version_message(window): 16 | window.LayerRightMessageSidebar().send( 17 | title="Welcome to Silicon UI Gallery", 18 | text="You are currently running v1.14.514\n" 19 | "Click this message box to check out what's new.", 20 | msg_type=1, 21 | icon=SiGlobal.siui.iconpack.get("ic_fluent_hand_wave_filled"), 22 | fold_after=5000, 23 | slot=lambda: window.LayerRightMessageSidebar().send("Oops, it seems that nothing will happen due to the fact " 24 | "that this function is currently not completed.", 25 | icon=SiGlobal.siui.iconpack.get("ic_fluent_info_regular")) 26 | ) 27 | 28 | window.LayerRightMessageSidebar().send( 29 | title="Refactoring in Progress", 30 | text="To optimize the project structure, " 31 | "we are currently undergoing a refactoring process.\n\n" 32 | "We strongly discourage you from using any deprecated components " 33 | 'other than those displayed on the "Refactored Components" page.', 34 | msg_type=4, 35 | icon=SiGlobal.siui.iconpack.get("ic_fluent_warning_filled"), 36 | ) 37 | 38 | 39 | if __name__ == "__main__": 40 | app = QApplication(sys.argv) 41 | 42 | window = MySiliconApp() 43 | window.show() 44 | 45 | timer = QTimer(window) 46 | timer.singleShot(500, lambda: show_version_message(window)) 47 | 48 | sys.exit(app.exec_()) 49 | -------------------------------------------------------------------------------- /examples/Gallery for siui/test_new_button.py: -------------------------------------------------------------------------------- 1 | # NOTE This is the refactor of button component. It's working in progress. It will 2 | # replace button once it's done. Now it's draft, code may be ugly and verbose temporarily. 3 | from __future__ import annotations 4 | 5 | import os 6 | 7 | from PyQt5.QtCore import QRect, QRectF, Qt 8 | from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPaintEvent 9 | from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget 10 | 11 | from siui.core import GlobalFont, SiColor, SiExpAnimation 12 | from siui.gui import SiFont 13 | 14 | os.environ["QT_SCALE_FACTOR"] = str(2) 15 | 16 | 17 | class SiPushButton(QPushButton): 18 | def __init__(self, parent: QWidget | None = None) -> None: 19 | super().__init__(parent) 20 | 21 | self.idle_color = SiColor.toArray("#00FFFFFF") 22 | self.hover_color = SiColor.toArray("#10FFFFFF") 23 | self.click_color = SiColor.toArray("#40FFFFFF") 24 | 25 | self.animation = SiExpAnimation(self) 26 | self.animation.setFactor(1/8) 27 | self.animation.setBias(0.2) 28 | self.animation.setTarget(self.idle_color) 29 | self.animation.setCurrent(self.idle_color) 30 | self.animation.ticked.connect(self.animate) 31 | 32 | self.clicked.connect(self._onButtonClicked) 33 | 34 | @classmethod 35 | def withText(cls, text: str, parent: QWidget | None = None) -> "SiPushButton": 36 | cls = cls(parent) 37 | cls.setText(text) 38 | return cls 39 | 40 | @classmethod 41 | def withIcon(cls, icon: QIcon, parent: QWidget | None = None) -> "SiPushButton": 42 | cls = cls(parent) 43 | cls.setIcon(icon) 44 | return cls 45 | 46 | def withTextAndIcon(cls, text: str, icon: str, parent: QWidget | None = None) -> "SiPushButton": 47 | cls = cls(parent) 48 | cls.setText(text) 49 | cls.setIcon(icon) 50 | return cls 51 | 52 | @property 53 | def bottomBorderHeight(self) -> int: 54 | return round(3) 55 | 56 | @staticmethod 57 | def _drawBackgroundPath(rect: QRect) -> QPainterPath: 58 | path = QPainterPath() 59 | path.addRoundedRect(QRectF(0, 0, rect.width(), rect.height()), 4, 4) 60 | return path 61 | 62 | def _drawBackgroundRect(self, painter: QPainter, rect: QRect) -> None: 63 | painter.setBrush(QColor("#2D2932")) 64 | painter.drawPath(self._drawBackgroundPath(rect)) 65 | 66 | def _drawButtonPath(self, rect: QRect) -> QPainterPath: 67 | path = QPainterPath() 68 | path.addRoundedRect(QRectF(0, 0, rect.width(), rect.height() - self.bottomBorderHeight), 3, 3) 69 | return path 70 | 71 | def _drawButtonRect(self, painter: QPainter, rect: QRect) -> None: 72 | painter.setBrush(QColor("#4C4554")) 73 | painter.drawPath(self._drawButtonPath(rect)) 74 | 75 | def _drawHighLightRect(self, painter: QPainter, rect: QRect) -> None: 76 | painter.setBrush(QColor(SiColor.toCode(self.animation.current_))) 77 | painter.drawPath(self._drawButtonPath(rect)) 78 | 79 | def _onButtonClicked(self) -> None: 80 | self.animation.setCurrent(self.click_color) 81 | self.animation.start() 82 | 83 | def animate(self, _) -> None: 84 | self.update() 85 | 86 | def enterEvent(self, event) -> None: 87 | super().enterEvent(event) 88 | self.animation.setTarget(self.hover_color) 89 | self.animation.start() 90 | 91 | def leaveEvent(self, event) -> None: 92 | super().leaveEvent(event) 93 | self.animation.setTarget(self.idle_color) 94 | self.animation.start() 95 | 96 | def resizeEvent(self, event) -> None: 97 | super().resizeEvent(event) 98 | 99 | def paintEvent(self, event: QPaintEvent) -> None: 100 | painter = QPainter(self) 101 | painter.setRenderHint(QPainter.RenderHint.Antialiasing) 102 | painter.setRenderHint(QPainter.TextAntialiasing) 103 | 104 | painter.setPen(Qt.PenStyle.NoPen) 105 | rect = self.rect() 106 | self._drawBackgroundRect(painter, rect) 107 | self._drawButtonRect(painter, rect) 108 | self._drawHighLightRect(painter, rect) 109 | 110 | text_rect = QRect(0, 0, self.width(), self.height() - 4) 111 | painter.setPen(QColor(239, 239, 239)) # 设置文本颜色 112 | painter.setFont(self.font()) # 设置字体和大小 113 | painter.drawText(text_rect, Qt.AlignCenter, self.text()) # 在按钮中心绘制文本 114 | painter.end() 115 | 116 | 117 | class Window(QWidget): 118 | def __init__(self) -> None: 119 | super().__init__() 120 | self.resize(600, 800) 121 | self.setStyleSheet("background-color: #332E38") 122 | 123 | self.btn = SiPushButton(self) 124 | self.btn.setFixedSize(128, 32) 125 | self.btn.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 126 | self.btn.setText("我是按钮") 127 | self.btn.clicked.connect(lambda: print("clicked!")) 128 | 129 | self.main_layout = QVBoxLayout(self) 130 | self.main_layout.addWidget(self.btn, alignment=Qt.AlignmentFlag.AlignCenter) 131 | 132 | 133 | if __name__ == "__main__": 134 | app = QApplication([]) 135 | window = Window() 136 | window.show() 137 | app.exec() -------------------------------------------------------------------------------- /examples/Gallery for siui/ui.py: -------------------------------------------------------------------------------- 1 | import icons 2 | from components.page_about import About 3 | from components.page_container import ExampleContainer 4 | from components.page_dialog import ExampleDialogs 5 | from components.page_functional import ExampleFunctional 6 | from components.page_homepage import ExampleHomepage 7 | from components.page_icons import ExampleIcons 8 | from components.page_option_cards import ExampleOptionCards 9 | from components.page_page_control import ExamplePageControl 10 | from components.page_refactor import RefactoredWidgets 11 | from components.page_widgets import ExampleWidgets 12 | from PyQt5.QtGui import QIcon 13 | from PyQt5.QtWidgets import QDesktopWidget 14 | 15 | import siui 16 | from siui.core import SiColor, SiGlobal 17 | from siui.templates.application.application import SiliconApplication 18 | 19 | # 载入图标 20 | siui.core.globals.SiGlobal.siui.loadIcons( 21 | icons.IconDictionary(color=SiGlobal.siui.colors.fromToken(SiColor.SVG_NORMAL)).icons 22 | ) 23 | 24 | 25 | class MySiliconApp(SiliconApplication): 26 | def __init__(self, *args, **kwargs): 27 | super().__init__(*args, **kwargs) 28 | 29 | screen_geo = QDesktopWidget().screenGeometry() 30 | self.setMinimumSize(1024, 380) 31 | self.resize(1366, 916) 32 | self.move((screen_geo.width() - self.width()) // 2, (screen_geo.height() - self.height()) // 2) 33 | self.layerMain().setTitle("Silicon UI Gallery") 34 | self.setWindowTitle("Silicon UI Gallery") 35 | self.setWindowIcon(QIcon("./img/empty_icon.png")) 36 | 37 | self.layerMain().addPage(ExampleHomepage(self), 38 | icon=SiGlobal.siui.iconpack.get("ic_fluent_home_filled"), 39 | hint="主页", side="top") 40 | self.layerMain().addPage(ExampleIcons(self), 41 | icon=SiGlobal.siui.iconpack.get("ic_fluent_diversity_filled"), 42 | hint="图标包", side="top") 43 | self.layerMain().addPage(RefactoredWidgets(self), 44 | icon=SiGlobal.siui.iconpack.get("ic_fluent_box_arrow_up_filled"), 45 | hint="重构控件", side="top") 46 | self.layerMain().addPage(ExampleWidgets(self), 47 | icon=SiGlobal.siui.iconpack.get("ic_fluent_box_multiple_filled"), 48 | hint="控件", side="top") 49 | self.layerMain().addPage(ExampleContainer(self), 50 | icon=SiGlobal.siui.iconpack.get("ic_fluent_align_stretch_vertical_filled"), 51 | hint="容器", side="top") 52 | self.layerMain().addPage(ExampleOptionCards(self), 53 | icon=SiGlobal.siui.iconpack.get("ic_fluent_list_bar_filled"), 54 | hint="选项卡", side="top") 55 | self.layerMain().addPage(ExampleDialogs(self), 56 | icon=SiGlobal.siui.iconpack.get("ic_fluent_panel_separate_window_filled"), 57 | hint="消息与二级界面", side="top") 58 | self.layerMain().addPage(ExamplePageControl(self), 59 | icon=SiGlobal.siui.iconpack.get("ic_fluent_wrench_screwdriver_filled"), 60 | hint="页面控制", side="top") 61 | self.layerMain().addPage(ExampleFunctional(self), 62 | icon=SiGlobal.siui.iconpack.get("ic_fluent_puzzle_piece_filled"), 63 | hint="功能组件", side="top") 64 | 65 | self.layerMain().addPage(About(self), 66 | icon=SiGlobal.siui.iconpack.get("ic_fluent_info_filled"), 67 | hint="关于", side="bottom") 68 | 69 | self.layerMain().setPage(0) 70 | 71 | SiGlobal.siui.reloadAllWindowsStyleSheet() 72 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/My-TODOs/components/__init__.py -------------------------------------------------------------------------------- /examples/My-TODOs/components/core.py: -------------------------------------------------------------------------------- 1 | class Task: 2 | def __init__(self, name, description, due_time_stamp, color): 3 | self.name = name 4 | self.description = description 5 | self.due_time_stamp = due_time_stamp 6 | self.color = color 7 | 8 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/page_about/__init__.py: -------------------------------------------------------------------------------- 1 | from .page_about import About -------------------------------------------------------------------------------- /examples/My-TODOs/components/page_about/page_about.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, QUrl 2 | from PyQt5.QtGui import QDesktopServices 3 | 4 | from siui.components import ( 5 | SiDenseVContainer, 6 | SiLabel, 7 | SiOptionCardLinear, 8 | SiPixLabel, 9 | SiSimpleButton, 10 | SiTitledWidgetGroup, 11 | ) 12 | from siui.components.page import SiPage 13 | from siui.core import GlobalFont, Si, SiColor, SiGlobal, SiQuickEffect 14 | from siui.gui import SiFont 15 | 16 | 17 | class About(SiPage): 18 | def __init__(self, *args, **kwargs): 19 | super().__init__(*args, **kwargs) 20 | 21 | self.setPadding(64) 22 | self.setScrollMaximumWidth(950) 23 | self.setTitle("关于") 24 | 25 | self.titled_widget_group = SiTitledWidgetGroup(self) 26 | self.titled_widget_group.setSiliconWidgetFlag(Si.EnableAnimationSignals) 27 | 28 | version_picture_container = SiDenseVContainer(self) 29 | version_picture_container.setAlignment(Qt.AlignCenter) 30 | version_picture_container.setFixedHeight(128 + 48) 31 | SiQuickEffect.applyDropShadowOn(version_picture_container, color=(28, 25, 31, 255), blur_radius=48) 32 | 33 | self.version_picture = SiPixLabel(self) 34 | self.version_picture.setFixedSize(128, 128) 35 | self.version_picture.setBorderRadius(0) 36 | self.version_picture.load("./img/logo_new.png") 37 | 38 | self.version_label = SiLabel(self) 39 | self.version_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 40 | self.version_label.setFont(SiFont.tokenized(GlobalFont.M_NORMAL)) 41 | self.version_label.setStyleSheet(f"color: {self.getColor(SiColor.TEXT_D)}") 42 | self.version_label.setText("PyQt-SiliconUI") 43 | 44 | version_picture_container.addWidget(self.version_picture) 45 | version_picture_container.addWidget(self.version_label) 46 | self.titled_widget_group.addWidget(version_picture_container) 47 | 48 | with self.titled_widget_group as group: 49 | group.addTitle("开源") 50 | 51 | self.button_to_repo = SiSimpleButton(self) 52 | self.button_to_repo.resize(32, 32) 53 | self.button_to_repo.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_open_regular")) 54 | self.button_to_repo.clicked.connect(lambda: QDesktopServices.openUrl(QUrl("https://github.com/ChinaIceF/PyQt-SiliconUI"))) 55 | 56 | self.option_card_repo = SiOptionCardLinear(self) 57 | self.option_card_repo.setTitle("开源仓库", "在 GitHub 上查看 Silicon UI 的项目主页") 58 | self.option_card_repo.load(SiGlobal.siui.iconpack.get("ic_fluent_home_database_regular")) 59 | self.option_card_repo.addWidget(self.button_to_repo) 60 | 61 | self.option_card_license = SiOptionCardLinear(self) 62 | self.option_card_license.setTitle("开源许可证", "本项目遵循 GPLv3.0 许可证供非商业使用") 63 | self.option_card_license.load(SiGlobal.siui.iconpack.get("ic_fluent_certificate_regular")) 64 | 65 | group.addWidget(self.option_card_repo) 66 | group.addWidget(self.option_card_license) 67 | 68 | with self.titled_widget_group as group: 69 | group.addTitle("版权") 70 | 71 | self.option_card_copyright = SiOptionCardLinear(self) 72 | self.option_card_copyright.setTitle("版权声明", "PyQt-SiliconUI 版权所有 © 2024 by ChinaIceF") 73 | self.option_card_copyright.load(SiGlobal.siui.iconpack.get("ic_fluent_info_regular")) 74 | 75 | group.addWidget(self.option_card_copyright) 76 | 77 | with self.titled_widget_group as group: 78 | group.addTitle("第三方资源") 79 | 80 | self.option_card_icon_pack = SiOptionCardLinear(self) 81 | self.option_card_icon_pack.setTitle("Fluent UI 图标库", "本项目内置了 Fluent UI 图标库,Microsoft 公司保有这些图标的版权") 82 | self.option_card_icon_pack.load(SiGlobal.siui.iconpack.get("ic_fluent_diversity_regular")) 83 | 84 | group.addWidget(self.option_card_icon_pack) 85 | 86 | # add placeholder for better outfit 87 | self.titled_widget_group.addPlaceholder(64) 88 | 89 | # Set SiTitledWidgetGroup object as the attachment of the page's scroll area 90 | self.setAttachment(self.titled_widget_group) 91 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/page_homepage/__init__.py: -------------------------------------------------------------------------------- 1 | from .homepage import Homepage -------------------------------------------------------------------------------- /examples/My-TODOs/components/page_homepage/components/__init__.py: -------------------------------------------------------------------------------- 1 | from .today import TodayMainWidget -------------------------------------------------------------------------------- /examples/My-TODOs/components/page_homepage/homepage.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from PyQt5.QtCore import Qt 4 | 5 | from siui.components import SiTitledWidgetGroup, SiPixLabel, SiDenseVContainer 6 | from siui.components.page import SiPage 7 | from siui.core import Si, SiColor 8 | 9 | from ..core import Task 10 | from ..widgets import SmallGroupTitle, TaskCardLinear 11 | from .components import TodayMainWidget 12 | 13 | 14 | class SmallTitledWidgetGroup(SiTitledWidgetGroup): 15 | def addTitle(self, title): 16 | 17 | if len(self.widgets_top) > 0: 18 | self.addPlaceholder(16) 19 | 20 | new_title = SmallGroupTitle(self) 21 | new_title.setTitle(title) 22 | self.addWidget(new_title) 23 | 24 | 25 | class Homepage(SiPage): 26 | def __init__(self, *args, **kwargs): 27 | super().__init__(*args, **kwargs) 28 | 29 | self.setPadding(0) 30 | self.setScrollMaximumWidth(10000) 31 | # self.setTitle("主页") 32 | 33 | self.head_pic_and_content = SiDenseVContainer(self) 34 | self.head_pic_and_content.setAlignment(Qt.AlignHCenter) 35 | self.head_pic_and_content.setSpacing(0) 36 | 37 | self.background_image = SiPixLabel(self) 38 | self.background_image.load("./images/default_background.png") 39 | self.background_image.setFixedHeight(320) 40 | self.background_image.setBorderRadius(6) 41 | 42 | self.titled_widget_group = SmallTitledWidgetGroup(self) 43 | self.titled_widget_group.setSiliconWidgetFlag(Si.EnableAnimationSignals) 44 | self.titled_widget_group.addPlaceholder(32) 45 | 46 | with self.titled_widget_group as group: 47 | #group.addTitle("时间线") 48 | 49 | self.today_main_widget = TodayMainWidget(self) 50 | self.today_main_widget.adjustSize() 51 | 52 | group.addPlaceholder(16) 53 | group.addWidget(self.today_main_widget) 54 | 55 | self.titled_widget_group.addPlaceholder(32) 56 | 57 | with self.titled_widget_group as group: 58 | group.addTitle("待办详情") 59 | 60 | self.test_task_card = TaskCardLinear(Task("上床睡觉", "闭上眼睛直接睡觉就行", time.time(), self.getColor(SiColor.PROGRESS_BAR_COMPLETING)), parent=self) 61 | self.test_task_card.resize(0, 80) 62 | 63 | self.test_task_card2 = TaskCardLinear(Task("写数学作业", "不写完作业该怎么交作业呢", time.time(), self.getColor(SiColor.PROGRESS_BAR_PROCESSING)), parent=self) 64 | self.test_task_card2.resize(0, 80) 65 | 66 | group.addPlaceholder(16) 67 | group.addWidget(self.test_task_card) 68 | group.addWidget(self.test_task_card2) 69 | 70 | self.titled_widget_group.addPlaceholder(64) 71 | 72 | self.head_pic_and_content.addWidget(self.background_image) 73 | self.head_pic_and_content.addWidget(self.titled_widget_group) 74 | 75 | self.setAttachment(self.head_pic_and_content) 76 | 77 | def resizeEvent(self, event): 78 | super().resizeEvent(event) 79 | self.background_image.resize(event.size().width(), 200) 80 | self.titled_widget_group.resize(event.size().width() - 128, self.titled_widget_group.height()) 81 | self.head_pic_and_content.arrangeWidget() 82 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | from .group_title import SmallGroupTitle 2 | from .tasks import TaskCardLinear 3 | from .button import RectButtonWithIconAndDescription -------------------------------------------------------------------------------- /examples/My-TODOs/components/widgets/button.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtGui import QFont 2 | 3 | from siui.components import SiLabel, SiSimpleButton, SiSvgLabel, SiWidget 4 | from siui.core import SiColor, SiGlobal 5 | from siui.gui import SiFont 6 | 7 | 8 | class RectButtonWithIconAndDescription(SiWidget): 9 | def __init__(self, title, description, icon_name, parent=None): 10 | super().__init__(parent) 11 | 12 | self.panel = SiLabel(self) 13 | self.panel.setFixedStyleSheet("border-radius: 4px") 14 | self.panel.setColor(self.getColor(SiColor.INTERFACE_BG_C)) 15 | 16 | self.icon_circle = SiLabel(self) 17 | self.icon_circle.setFixedSize(32, 32) 18 | self.icon_circle.move(20, 24) 19 | self.icon_circle.setFixedStyleSheet("border-radius: 16px") 20 | self.icon_circle.setColor(self.getColor(SiColor.INTERFACE_BG_D)) 21 | 22 | self.icon = SiSvgLabel(self.icon_circle) 23 | self.icon.resize(32, 32) 24 | self.icon.load(SiGlobal.siui.iconpack.get(icon_name, color_code=self.getColor(SiColor.SVG_NORMAL))) 25 | self.icon.setSvgSize(16, 16) 26 | 27 | self.title = SiLabel(self) 28 | self.title.setFont(SiFont.getFont(size=16, weight=QFont.Weight.Bold)) 29 | self.title.setTextColor(self.getColor(SiColor.TEXT_B)) 30 | self.title.setText(title) 31 | self.title.adjustSize() 32 | self.title.move(72, 20) 33 | 34 | self.description = SiLabel(self) 35 | self.description.setFont(SiFont.getFont(size=14, weight=QFont.Weight.Light)) 36 | self.description.setTextColor(self.getColor(SiColor.TEXT_D)) 37 | self.description.setText(description) 38 | self.description.adjustSize() 39 | self.description.move(72, 20 + 20) 40 | 41 | self.button_ = SiSimpleButton(self) 42 | self.button_.setBorderRadius(4) 43 | 44 | def button(self): 45 | return self.button_ 46 | 47 | def resizeEvent(self, event): 48 | super().resizeEvent(event) 49 | self.panel.resize(event.size()) 50 | self.button_.resize(event.size()) 51 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/widgets/group_title.py: -------------------------------------------------------------------------------- 1 | from PyQt5.Qt import QFont 2 | 3 | from siui.components import SiLabel, SiWidget 4 | from siui.core import SiColor 5 | from siui.gui import SiFont 6 | 7 | 8 | class SmallGroupTitle(SiWidget): 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | self.title = SiLabel(self) 12 | self.title.setFont(SiFont.getFont(size=16, weight=QFont.Weight.Bold)) 13 | 14 | self.title_indicator = SiLabel(self) 15 | self.title_indicator.setFixedStyleSheet("border-radius: 1px") 16 | 17 | def reloadStyleSheet(self): 18 | super().reloadStyleSheet() 19 | self.title.setTextColor(self.getColor(SiColor.TEXT_B)) 20 | self.title_indicator.setColor(self.getColor(SiColor.TITLE_INDICATOR)) 21 | 22 | def setTitle(self, title): 23 | self.title.setText(title) 24 | self.title.adjustSize() 25 | self.adjustSize() 26 | 27 | def adjustSize(self): 28 | self.resize(self.title.width(), self.title.height() + 8) 29 | self.title_indicator.setGeometry(0, self.height() - 3, self.width(), 3) 30 | -------------------------------------------------------------------------------- /examples/My-TODOs/components/widgets/tasks.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtGui import QFont 2 | 3 | from siui.components import SiLabel, SiWidget 4 | from siui.core import SiColor 5 | from siui.gui import SiFont 6 | 7 | from ..core import Task 8 | 9 | 10 | class TaskCardLinear(SiWidget): 11 | def __init__(self, task, parent=None): 12 | super().__init__(parent) 13 | self.task = None 14 | 15 | self.theme_color_indicator = SiLabel(self) 16 | self.theme_color_indicator.setFixedStyleSheet("border-radius: 8px") 17 | 18 | self.original_panel = SiLabel(self) 19 | self.original_panel.setFixedStyleSheet("border-radius: 8px") 20 | self.original_panel.setColor(self.getColor(SiColor.INTERFACE_BG_C)) 21 | 22 | self.panel = SiLabel(self) 23 | self.panel.setFixedStyleSheet("border-radius: 8px; border-top-left-radius: 6px; border-bottom-left-radius: 6px") 24 | 25 | self.title = SiLabel(self) 26 | self.title.setFont(SiFont.getFont(size=18, weight=QFont.Weight.Bold)) 27 | 28 | self.description = SiLabel(self) 29 | self.description.setFont(SiFont.getFont(size=14, weight=QFont.Weight.Normal)) 30 | 31 | self.loadTask(task) 32 | 33 | def loadTask(self, task: Task): 34 | self.task = task 35 | self.theme_color_indicator.setColor(task.color) 36 | self.panel.setColor(SiColor.mix(self.getColor(SiColor.INTERFACE_BG_C), task.color, weight=0.9)) 37 | self.title.setTextColor(self.getColor(SiColor.TEXT_B)) 38 | self.description.setTextColor(SiColor.mix(self.getColor(SiColor.TEXT_B), task.color)) 39 | 40 | self.title.setText(task.name) 41 | self.description.setText(task.description) 42 | 43 | def getTask(self): 44 | return self.task 45 | 46 | def resizeEvent(self, event): 47 | super().resizeEvent(event) 48 | self.theme_color_indicator.resize(48, event.size().height()) 49 | self.original_panel.setGeometry(24, 0, event.size().width() - 24, event.size().height()) 50 | self.panel.setGeometry(24, 0, event.size().width() - 24 - 60, event.size().height()) 51 | self.title.move(80, 18) 52 | self.description.move(80, 18 + 24) 53 | -------------------------------------------------------------------------------- /examples/My-TODOs/icons/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import * 2 | -------------------------------------------------------------------------------- /examples/My-TODOs/icons/icons.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/My-TODOs/icons/icons.dat -------------------------------------------------------------------------------- /examples/My-TODOs/icons/parser.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import os 3 | 4 | current_module_path = os.path.dirname(os.path.abspath(__file__)) 5 | data_file_path = os.path.join(current_module_path, './icons.dat') 6 | 7 | class IconDictionary: 8 | def __init__(self, library_path=data_file_path, color=None): 9 | 10 | # !注意! 你不应使用这些文件,他们已经过加密处理 11 | # 如果你需要这些图标文件,你可以直接在 flaticon.com 免费获取他们 12 | 13 | # 读取数据并解密 14 | f = open(library_path, 'rb') 15 | library_raw = f.read() 16 | library_list = list(library_raw) 17 | library = bytes(list((numpy.array(library_list) + numpy.array(range(len(library_list))) * 17) % 255)).decode() # 解密 18 | 19 | # 整理成字典 20 | items = library.split('!!!') 21 | names = [] 22 | datas = [] 23 | for item in items[1:]: 24 | name, data = item.split('###') 25 | data = data.replace('/>', ' fill="{}" />'.format(color)) 26 | names.append(name) 27 | datas.append(data.encode()) 28 | self.icons = dict(zip(names, datas)) 29 | 30 | def get(self, name): 31 | svg_data = self.icons[name] 32 | return svg_data.encode() 33 | -------------------------------------------------------------------------------- /examples/My-TODOs/images/default_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/examples/My-TODOs/images/default_background.png -------------------------------------------------------------------------------- /examples/My-TODOs/start.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PyQt5.QtWidgets import QApplication 3 | from ui import MySiliconApp 4 | 5 | 6 | if __name__ == "__main__": 7 | app = QApplication(sys.argv) 8 | 9 | window = MySiliconApp() 10 | window.show() 11 | 12 | sys.exit(app.exec_()) 13 | -------------------------------------------------------------------------------- /examples/My-TODOs/ui.py: -------------------------------------------------------------------------------- 1 | import icons 2 | from components.page_about import About 3 | from components.page_homepage import Homepage 4 | from PyQt5.QtGui import QIcon 5 | from PyQt5.QtWidgets import QDesktopWidget 6 | 7 | import siui 8 | from siui.core import SiColor, SiGlobal 9 | from siui.templates.application.application import SiliconApplication 10 | 11 | # 载入图标 12 | siui.core.globals.SiGlobal.siui.loadIcons( 13 | icons.IconDictionary(color=SiGlobal.siui.colors.fromToken(SiColor.SVG_NORMAL)).icons 14 | ) 15 | 16 | 17 | class MySiliconApp(SiliconApplication): 18 | def __init__(self, *args, **kwargs): 19 | super().__init__(*args, **kwargs) 20 | 21 | screen_geo = QDesktopWidget().screenGeometry() 22 | self.setMinimumSize(1024, 380) 23 | self.resize(1366, 916) 24 | self.move((screen_geo.width() - self.width()) // 2, (screen_geo.height() - self.height()) // 2) 25 | self.layerMain().setTitle("My-TODOs") 26 | self.setWindowTitle("My-TODOs") 27 | self.setWindowIcon(QIcon("./img/empty_icon.png")) 28 | 29 | self.layerMain().addPage(Homepage(self), 30 | icon=SiGlobal.siui.iconpack.get("ic_fluent_home_filled"), 31 | hint="主页", side="top") 32 | 33 | self.layerMain().addPage(About(self), 34 | icon=SiGlobal.siui.iconpack.get("ic_fluent_info_filled"), 35 | hint="关于", side="bottom") 36 | 37 | self.layerMain().setPage(0) 38 | 39 | SiGlobal.siui.reloadAllWindowsStyleSheet() 40 | -------------------------------------------------------------------------------- /examples/button/demo_button.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton 3 | 4 | from SiliconUI.SiButton import SiButton, SiButtonHoldtoConfirm 5 | from SiliconUI.SiLayout import SiLayoutV 6 | from SiliconUI.SiGlobal import colorset 7 | 8 | # 当按钮点击事件触发时 9 | def when_button_clicked(): 10 | print('Clicked.') 11 | 12 | # 当按钮按下状态改变时 13 | def when_button_holdstatechanged(state): 14 | print('Hold state changed.', state) 15 | 16 | 17 | class ButtonExample(QWidget): 18 | def __init__(self): 19 | super().__init__() 20 | 21 | # 初始化窗口 22 | self.initUI() 23 | 24 | def initUI(self): 25 | 26 | # 创建垂直布局 27 | self.layout = SiLayoutV(self) 28 | self.layout.setFixedWidth(128) 29 | self.layout.setAlignment(Qt.AlignCenter) # 设置元素居中 30 | 31 | # 创建三个按钮 32 | btn1 = SiButton(self.layout) 33 | btn1.resize(128, 32) 34 | btn1.setText('普通按钮') 35 | btn1.clicked.connect(when_button_clicked) 36 | btn1.holdStateChanged.connect(when_button_holdstatechanged) 37 | 38 | btn2 = SiButton(self.layout) 39 | btn2.resize(128, 32) 40 | btn2.setText('高亮按钮') 41 | btn2.clicked.connect(when_button_clicked) 42 | btn2.holdStateChanged.connect(when_button_holdstatechanged) 43 | 44 | btn3 = SiButtonHoldtoConfirm(self.layout) 45 | btn3.resize(128, 32) 46 | btn3.setText('长按按钮') 47 | btn3.clicked.connect(when_button_clicked) 48 | btn3.holdStateChanged.connect(when_button_holdstatechanged) 49 | 50 | # 将按钮添加到垂直布局中 51 | self.layout.addItem(btn1) 52 | self.layout.addItem(btn2) 53 | self.layout.addItem(btn3) 54 | 55 | # 设置布局位置 56 | self.layout.move(96, 64) 57 | 58 | # 设置窗口属性 59 | self.setWindowTitle('SiliconUI.SiButton 三类按钮实例') 60 | self.setStyleSheet('background-color: {}'.format(colorset.BG_GRAD_HEX[2])) 61 | self.setGeometry(300, 300, 320, 256) 62 | 63 | if __name__ == '__main__': 64 | 65 | app = QApplication(sys.argv) 66 | ex = ButtonExample() 67 | ex.show() 68 | sys.exit(app.exec_()) 69 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "PyQt-SiliconUI" 3 | version = "1.0.1" 4 | authors = [ 5 | { name = "ChinaIceF", email = "ChinaIceF@outlook.com" }, 6 | { name = "rainzee wang", email = "rainzee.w@gmail.com" }, 7 | ] 8 | description = "A powerful and artistic UI library based on PyQt5 / PySide6" 9 | readme = "README.md" 10 | license = { file = "LICENSE" } 11 | requires-python = ">=3.8" 12 | dependencies = ["PyQt5>=5.15.10", "typing-extensions>=4.12.2", "python-dateutil>=2.9.0"] 13 | 14 | [project.urls] 15 | Repository = "https://github.com/ChinaIceF/PyQt-SiliconUI" 16 | 17 | [tool.pdm.dev-dependencies] 18 | stub = ["pyqt5-stubs>=5.15.6.0"] 19 | lint = ["ruff>=0.5.0"] 20 | build = ["nuitka>=2.3.10"] 21 | profile = ["viztracer>=0.16.3"] 22 | 23 | [tool.ruff] 24 | line-length = 120 25 | target-version = "py38" 26 | 27 | [tool.ruff.lint] 28 | select = ["I", "E", "W", "F", "C", "Q", "PT", "UP", "PYI", "T20"] 29 | 30 | [tool.pyright] 31 | pythonVersion = "3.8" 32 | pythonPlatform = "All" 33 | typeCheckingMode = "standard" 34 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages, setup 2 | 3 | # 定义项目需要的依赖项 4 | install_requires = [ 5 | "PyQt5>=5.15.10", 6 | "numpy", 7 | "pyperclip", 8 | ] 9 | 10 | # 定义项目元数据 11 | setup( 12 | name = "PyQt-SiliconUI", 13 | version = "1.01", 14 | packages = find_packages(exclude = ["examples"]), # 自动找到所有包 15 | data_files=[("./siui/gui/icons/packages", ["./siui/gui/icons/packages/fluent_ui_icon_filled.icons", 16 | "./siui/gui/icons/packages/fluent_ui_icon_regular.icons", 17 | "./siui/gui/icons/packages/fluent_ui_icon_light.icons"]),], 18 | include_package_data = True, 19 | install_requires = install_requires, # 依赖项列表 20 | # 以下为可选元数据 21 | description = "A powerful and artistic UI library based on PyQt5 / PySide6", # 包的简短描述 22 | long_description = open("README.md", encoding="utf-8").read(), # 包的详细描述,通常来自README文件 23 | long_description_content_type = "text/markdown", # README文件的格式 24 | url = "https://github.com/ChinaIceF/PyQt-SiliconUI", # 项目主页 25 | author = "ChinaIceF", # 作者名 26 | author_email = "ChinaIceF@outlook.com", # 作者邮箱 27 | license = "GPL-3.0", # 许可证 28 | classifiers=[ # 项目的分类信息 29 | "Development Status :: 3 - Alpha", 30 | "Intended Audience :: Developers", 31 | "License :: OSI Approved :: GPL-3.0 License", 32 | "Programming Language :: Python :: 3", 33 | "Programming Language :: Python :: 3.6", 34 | "Programming Language :: Python :: 3.7", 35 | "Programming Language :: Python :: 3.8", 36 | "Programming Language :: Python :: 3.9", 37 | "Programming Language :: Python :: 3.10", 38 | "Programming Language :: Python :: 3.11", 39 | "Programming Language :: Python :: 3.12", 40 | "Topic :: Software Development :: Libraries :: Python Modules", 41 | ], 42 | entry_points={ # 如果包是可执行的,定义入口点 43 | "console_scripts": [ 44 | "" 45 | ], 46 | }, 47 | ) 48 | -------------------------------------------------------------------------------- /siui/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import siui 4 | import siui.components as components 5 | import siui.components.widgets as widgets 6 | import siui.core as core 7 | import siui.core.globals 8 | import siui.gui as gui 9 | import siui.templates as templates 10 | 11 | # 加载全局缩放比例 12 | siui.gui.scale.reload_scale_factor() 13 | -------------------------------------------------------------------------------- /siui/components/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.option_card import * 2 | from siui.components.progress_bar import * 3 | # from siui.components.slider import * 4 | from siui.components.titled_widget_group import * 5 | from siui.components.widgets import * 6 | -------------------------------------------------------------------------------- /siui/components/combobox/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.combobox.combobox import SiComboBox -------------------------------------------------------------------------------- /siui/components/menu/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.menu.menu import SiMenuOption, SiMenu -------------------------------------------------------------------------------- /siui/components/menu/abstracts/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.menu.abstracts.menu import ABCSiMenu 2 | from siui.components.menu.abstracts.ani_manager import AnimationManager -------------------------------------------------------------------------------- /siui/components/menu/menu.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, pyqtSignal, QSize 2 | from PyQt5.QtGui import QColor 3 | from PyQt5.QtWidgets import QGraphicsDropShadowEffect 4 | 5 | from siui.components import SiWidget, SiLabel, SiDenseVContainer 6 | from siui.components.menu.abstracts import ABCSiMenu, AnimationManager 7 | from siui.components.menu.option import SiMenuOption 8 | from siui.core import SiQuickEffect, SiColor, SiGlobal 9 | 10 | 11 | class SiMenu(ABCSiMenu): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | self.setAnimationManager(AnimationManager.PULL_DOWN) 15 | 16 | def addOption(self, 17 | text: str, 18 | value=None, 19 | icon=None, 20 | child_menu=None): 21 | new_option = SiMenuOption(self, child_menu, text, value=value, icon=icon) 22 | new_option.setSelectable(self.is_selection_menu) 23 | new_option.setFixedHeight(32) 24 | 25 | self.options_.append(new_option) 26 | self.body().addWidget(new_option) 27 | self.body().arrangeWidget() 28 | 29 | 30 | class SiInteractionMenu(SiWidget): 31 | indexChanged = pyqtSignal(int) 32 | valueChanged = pyqtSignal(object) 33 | unfoldSignal = pyqtSignal() 34 | closeSignal = pyqtSignal() 35 | 36 | def __init__(self, *args, **kwargs): 37 | super().__init__(*args, **kwargs) 38 | 39 | # 在窗口列表里注册菜单,用于重载样式表 40 | SiGlobal.siui.windows[str(self)] = self 41 | 42 | self.animation_manager = None 43 | self.margin = 32 44 | self.padding = 4 45 | 46 | self.setAnimationManager(AnimationManager.PULL_DOWN) 47 | 48 | self.setMoveAnchor(self.margin + self.padding, self.margin + self.padding) 49 | self.setMinimumSize(self.margin*2, self.margin*2) 50 | self.setAttribute(Qt.WA_TranslucentBackground) 51 | self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint) 52 | 53 | self.body_frame = SiWidget(self) 54 | 55 | self.body_panel = SiLabel(self.body_frame) 56 | self.body_panel.setObjectName("menu_body_panel") 57 | 58 | self.flash_layer = SiLabel(self) 59 | self.flash_layer.setFixedStyleSheet("border-radius: 6px") 60 | self.flash_layer.setAttribute(Qt.WA_TransparentForMouseEvents) 61 | self.flash_layer.animationGroup().fromToken("color").setFactor(1/16) 62 | 63 | self.body_ = SiDenseVContainer(self.body_panel) 64 | self.body_.setAdjustWidgetsSize(True) 65 | self.body_.setSpacing(2) 66 | self.body_.resize(0, 0) 67 | 68 | SiQuickEffect.applyDropShadowOn(self.body_frame, (0, 0, 0, 80), (0, 0), 32) 69 | 70 | def reloadStyleSheet(self): 71 | super().reloadStyleSheet() 72 | self.body_panel.setStyleSheet( 73 | f"""#menu_body_panel {{ 74 | background-color: {self.getColor(SiColor.MENU_BG)}; 75 | border: 1px solid {SiColor.mix(self.getColor(SiColor.MENU_BG), self.getColor(SiColor.TEXT_E), 0.9)}; 76 | border-radius: 6px 77 | }}""" 78 | ) 79 | 80 | def setAnimationManager(self, token): 81 | self.animation_manager = token.value 82 | 83 | def animationManager(self): 84 | return self.animation_manager 85 | 86 | def unfold(self, x, y): 87 | """ unfold the menu """ 88 | self.animationManager().on_parent_unfolded(self, x, y) 89 | SiGlobal.siui.windows["TOOL_TIP"].raise_() 90 | 91 | def setContentFixedWidth(self, w): 92 | self.setFixedWidth(w + self.padding*2 + self.margin*2) 93 | 94 | def closeEvent(self, a0): 95 | super().closeEvent(a0) 96 | self.closeSignal.emit() 97 | self.resize(self.width(), self.margin * 2) 98 | 99 | def resizeEvent(self, event): 100 | self.animationManager().on_parent_resized(self, event) 101 | super().resizeEvent(event) 102 | 103 | def sizeHint(self): 104 | w = self.body_.sizeHint().width() + 2 * self.padding + 2 * self.margin 105 | h = self.body_.sizeHint().height() + 2 * self.padding + 2 * self.margin 106 | return QSize(w, h) 107 | 108 | -------------------------------------------------------------------------------- /siui/components/option_card/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.option_card.option_card import * 2 | import siui.components.option_card.abstracts as abstracts -------------------------------------------------------------------------------- /siui/components/option_card/abstracts/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.option_card.abstracts.option_card import ABCSiOptionCardPlane -------------------------------------------------------------------------------- /siui/components/option_card/abstracts/option_card.py: -------------------------------------------------------------------------------- 1 | from siui.components.widgets import SiDenseHContainer, SiDenseVContainer, SiLabel 2 | from siui.core import SiGlobal 3 | 4 | 5 | class ABCSiOptionCardPlane(SiLabel): 6 | """ 7 | 平面型选项卡,划分 header, body, footer,为一般场景提供支持 8 | """ 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | 12 | self.spacing_ = 24 13 | 14 | # 构建组成外观的控件 15 | self.outfit_label_lower = SiLabel(self) 16 | self.outfit_label_lower.setFixedStyleSheet("border-radius: 6px") 17 | 18 | self.outfit_label_upper = SiLabel(self) 19 | self.outfit_label_upper.setFixedStyleSheet("border-radius: 6px") 20 | 21 | # 创建容器 22 | self.container = SiDenseVContainer(self) 23 | self.container.setSpacing(0) 24 | self.container.setAdjustWidgetsSize(True) 25 | 26 | # 创建划分区域 27 | self.header_ = SiDenseHContainer(self) 28 | self.header_.resize(0, 0) 29 | 30 | self.body_ = SiDenseVContainer(self) # 只有 body 是竖直密堆积容器 31 | self.body_.setSpacing(8) 32 | self.body_.resize(0, 0) 33 | 34 | self.footer_ = SiDenseHContainer(self) 35 | self.footer_.resize(0, 0) 36 | 37 | # 设置子控件适应容器,并把三个组成部分添加到自己 38 | 39 | self.container.addWidget(self.header_) 40 | self.container.addWidget(self.body_) 41 | self.container.addWidget(self.footer_, "bottom") 42 | 43 | def setSpacing(self, spacing): 44 | """ 45 | 设置容器与边缘左右的间隔 46 | :param spacing: 间隔 47 | """ 48 | self.spacing_ = spacing 49 | 50 | def spacing(self): 51 | """ 52 | 获取容器与边缘左右的间隔 53 | :return: 间隔 54 | """ 55 | return self.spacing_ 56 | 57 | def header(self): 58 | """ 59 | 返回 header 容器 60 | :return: header 容器 61 | """ 62 | return self.header_ 63 | 64 | def body(self): 65 | """ 66 | 返回 body 容器 67 | :return: body 容器 68 | """ 69 | return self.body_ 70 | 71 | def footer(self): 72 | """ 73 | 返回 footer 容器 74 | :return: footer 容器 75 | """ 76 | return self.footer_ 77 | 78 | def adjustSize(self): 79 | self.resize(self.width(), self.header().height() + self.body().height() + self.footer().height() + 3) 80 | 81 | def reloadStyleSheet(self): 82 | super().reloadStyleSheet() 83 | 84 | self.outfit_label_lower.setStyleSheet("background-color: {}".format(SiGlobal.siui.colors["INTERFACE_BG_A"])) 85 | self.outfit_label_upper.setStyleSheet("background-color: {}".format(SiGlobal.siui.colors["INTERFACE_BG_C"])) 86 | 87 | def resizeEvent(self, event): 88 | super().resizeEvent(event) 89 | size = event.size() 90 | w, h = size.width(), size.height() 91 | 92 | self.container.setGeometry(self.spacing(), 0, w-self.spacing()*2, h-3) 93 | 94 | self.outfit_label_lower.setGeometry(0, 8, w, h-8) # 防止上边出现底色毛边 95 | self.outfit_label_upper.resize(w, h - 3) 96 | -------------------------------------------------------------------------------- /siui/components/option_card/option_card.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components.option_card.abstracts.option_card import ABCSiOptionCardPlane 4 | from siui.components.widgets.abstracts.widget import SiWidget 5 | from siui.components.widgets.container import SiDenseHContainer 6 | from siui.components.widgets.label import SiLabel, SiSvgLabel 7 | from siui.core import GlobalFont, Si, SiGlobal 8 | from siui.gui import SiFont 9 | 10 | 11 | class SiOptionCardLinear(SiWidget): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | 15 | self.panel = SiLabel(self) 16 | self.panel.setFixedStyleSheet(f"background-color:{SiGlobal.siui.colors['INTERFACE_BG_C']}; border-radius:4px") 17 | 18 | # 设定最小高度 19 | self.setMinimumHeight(80) 20 | 21 | # 创建整体容器 22 | self.container = SiDenseHContainer(self) 23 | self.container.setSpacing(0) 24 | self.container.setAlignment(Qt.AlignCenter) 25 | self.container.setAdjustWidgetsSize(True) 26 | 27 | # 开始从左到右构建所需控件 28 | # svg图标 29 | self.svg_icon = SiSvgLabel(self) 30 | self.svg_icon.setSvgSize(24, 24) 31 | self.svg_icon.resize(80, 80) 32 | 33 | # 文字标签 34 | self.text_label = SiLabel(self) 35 | self.text_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 36 | self.text_label.setFixedStyleSheet("padding-top: 20px; padding-bottom: 20px;") 37 | 38 | # 控件紧密排列容器 39 | self.widgets_container = SiDenseHContainer(self) 40 | self.widgets_container.setAlignment(Qt.AlignCenter) 41 | self.widgets_container.resize(0, 0) 42 | 43 | # 添加到整体容器中 44 | self.container.addWidget(self.svg_icon) 45 | self.container.addWidget(self.text_label) 46 | 47 | self.container.addPlaceholder(28, "right") # 防止控件和右侧边缘紧贴 48 | self.container.addWidget(self.widgets_container, "right") 49 | self.container.addPlaceholder(16, "right") # 防止文字和控件紧贴 50 | 51 | def reloadStyleSheet(self): 52 | super().reloadStyleSheet() 53 | 54 | def setTitle(self, title, subtitle=""): 55 | """ 56 | 为选项卡设置文字 57 | :param title: 选项卡标题 58 | :param subtitle: 选项卡副标题 59 | :return: 60 | """ 61 | # 根据是否有副标题,设置两种文字显示方式 62 | if subtitle == "": 63 | self.text_label.setText("{}".format(SiGlobal.siui.colors["TEXT_A"], title)) 64 | 65 | else: 66 | subtitle = subtitle.replace("\n", "
") 67 | self.text_label.setText("{}
{}".format( 68 | SiGlobal.siui.colors["TEXT_A"], title, SiGlobal.siui.colors["TEXT_C"], subtitle)) 69 | 70 | self.adjustSize() 71 | 72 | def setText(self, text: str): 73 | raise AttributeError("请使用 setTitle 方法设置选项卡文字") 74 | 75 | def load(self, path_or_data): 76 | """ 77 | 加载图标 78 | :param path_or_data: svg 文件路径或 svg 数据 79 | :return: 80 | """ 81 | self.svg_icon.load(path_or_data) 82 | 83 | def addWidget(self, widget): 84 | """ 85 | 添加控件于选项卡右侧,这将改变控件的父对象 86 | :param widget: 控件 87 | :return: 88 | """ 89 | self.widgets_container.addWidget(widget, "right") 90 | 91 | def adjustSize(self): 92 | self.container.resize(self.container.width(), self.text_label.height()) 93 | self.container.adjustSize() 94 | self.resize(self.container.size()) 95 | 96 | def resizeEvent(self, event): 97 | super().resizeEvent(event) 98 | w, h = event.size().width(), event.size().height() 99 | 100 | self.panel.resize(w, h) 101 | self.container.resize(w, h) 102 | 103 | # 让文字标签充满闲置区域 104 | spare_space = self.container.getSpareSpace() 105 | self.text_label.setFixedWidth(spare_space + self.text_label.width()) 106 | 107 | # 确保其所有控件都在中轴线上,需要调用调整尺寸方法 108 | self.container.adjustSize() 109 | 110 | 111 | class SiOptionCardPlane(ABCSiOptionCardPlane): 112 | """ 113 | 平面式选项卡。相较于其抽象类,此类提供 114 | """ 115 | def __init__(self, *args, **kwargs): 116 | super().__init__(*args, **kwargs) 117 | 118 | # 在 header 创建标题 119 | self.title = SiLabel(self) 120 | self.title.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 121 | self.title.setFont(SiFont.tokenized(GlobalFont.M_BOLD)) 122 | self.title.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) 123 | self.title.setFixedHeight(32) 124 | 125 | self.header().setAlignment(Qt.AlignCenter) 126 | self.header().setFixedHeight(64) 127 | self.header().addWidget(self.title, "left") 128 | 129 | def reloadStyleSheet(self): 130 | super().reloadStyleSheet() 131 | self.title.setStyleSheet("color: {}".format(SiGlobal.siui.colors["TEXT_A"])) 132 | 133 | def setTitle(self, text: str): 134 | """ 135 | 设置标题 136 | :param text: 标题 137 | :return: 138 | """ 139 | self.title.setText(text) 140 | -------------------------------------------------------------------------------- /siui/components/page/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.page.page import * -------------------------------------------------------------------------------- /siui/components/page/child_page.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import SiWidget, SiDenseHContainer, SiLabel, SiTitledWidgetGroup 4 | from siui.components.page import SiPage 5 | from siui.core import SiColor 6 | from siui.core import SiQuickEffect 7 | from siui.core import Si 8 | 9 | 10 | class SiChildPage(SiWidget): 11 | def __init__(self, *args, **kwargs): 12 | super().__init__(*args, **kwargs) 13 | 14 | self.width_ratio = 0.618 15 | self.height_ratio = (1-0.618) * 2 16 | 17 | self.view_ = SiWidget(self) 18 | 19 | # content 20 | self.background_content = SiLabel(self.view_) 21 | self.background_content.setStyleSheet( 22 | "border-radius: 8px;" 23 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_B)};" 24 | f"border: 1px solid {self.getColor(SiColor.INTERFACE_BG_C)};" 25 | ) 26 | 27 | 28 | self.content_ = SiPage(self.view_) 29 | 30 | # panel 31 | self.background_panel = SiLabel(self.view_) 32 | self.background_panel.setStyleSheet( 33 | "border-top-left-radius: 8px;" 34 | "border-top-right-radius: 8px;" 35 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_C)}" 36 | ) 37 | SiQuickEffect.applyDropShadowOn(self.background_panel, (0, 0, 0, 60), blur_radius=48) 38 | 39 | self.panel_ = SiDenseHContainer(self.view_) 40 | self.panel_.setAlignment(Qt.AlignCenter) 41 | self.panel_.setFixedHeight(80) 42 | 43 | # set self.view as center widget 44 | self.setCenterWidget(self.view_) 45 | 46 | def content(self): 47 | return self.content_ 48 | 49 | def panel(self): 50 | return self.panel_ 51 | 52 | def view(self): 53 | return self.view_ 54 | 55 | def closeParentLayer(self): 56 | self.parent().closeLayer() 57 | 58 | def setSizeRatio(self, width_ratio, height_ratio): 59 | self.width_ratio = width_ratio 60 | self.height_ratio = height_ratio 61 | 62 | def getSizeFitParent(self): 63 | return int(self.parent().width() * self.width_ratio), int(self.parent().height() * self.height_ratio) 64 | 65 | def adjustSize(self): 66 | width_from_ratio = int(self.parent().width() * self.width_ratio) 67 | height_from_ratio = int(self.parent().height() * self.height_ratio) 68 | self.view_.resize(width_from_ratio, height_from_ratio) 69 | 70 | total_width, total_height = self.view_.width(), self.view_.height() 71 | self.resize(total_width, total_height) # to update position of center widget 72 | self.content_.resize(total_width, total_height - self.panel_.height()) 73 | self.panel_.setGeometry(48, total_height - self.panel_.height(), total_width - 96, self.panel_.height()) 74 | 75 | self.background_content.resize(total_width, total_height) 76 | self.background_panel.setGeometry(0, total_height - self.panel_.height(), total_width, self.panel_.height()) -------------------------------------------------------------------------------- /siui/components/page/page.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components.widgets.container import SiDenseHContainer, SiDenseVContainer 4 | from siui.components.widgets.label import SiLabel 5 | from siui.components.widgets.scrollarea import SiScrollArea 6 | from siui.core import SiGlobal, GlobalFont 7 | from siui.core import Si 8 | from siui.gui import SiFont 9 | 10 | 11 | class SiPage(SiDenseVContainer): 12 | """ 页面类,实例化后作为 SiliconApplication 中的单个页面 """ 13 | def __init__(self, *args, **kwargs): 14 | super().__init__(*args, **kwargs) 15 | 16 | self.setSpacing(0) 17 | self.setSiliconWidgetFlag(Si.EnableAnimationSignals) 18 | 19 | self.scroll_maximum_width = 10000 # 滚动区域宽度限制 20 | self.title_height = 0 # 标题引入的高度偏移,内容的高度要减去标题的高度 21 | self.padding = 0 # 左右空白区域的宽度 22 | 23 | # 滚动区域对齐方式 24 | self.scroll_alignment = Qt.AlignCenter 25 | 26 | # 滚动区域 27 | self.scroll_area = SiScrollArea(self) 28 | self.setAdjustWidgetsSize(True) 29 | 30 | # 添加到垂直容器 31 | self.addWidget(self.scroll_area) 32 | 33 | def setAttachment(self, widget): 34 | """ 设置子控件 """ 35 | self.scroll_area.setAttachment(widget) 36 | 37 | def attachment(self): 38 | """ 获取子控件 """ 39 | return self.scroll_area.attachment() 40 | 41 | def setScrollMaximumWidth(self, width: int): 42 | """ 43 | 设置滚动区域的子控件的最大宽度 44 | :param width: 最大宽度 45 | """ 46 | self.scroll_maximum_width = width 47 | self.resize(self.size()) 48 | 49 | def setScrollAlignment(self, a0): 50 | """ 51 | 设置滚动区域的对齐方式 52 | :param a0: Qt 枚举值 53 | """ 54 | self.scroll_alignment = a0 55 | self.resize(self.size()) 56 | 57 | def setPadding(self, padding): 58 | """ 59 | 内容左右距离边框的距离 60 | :param padding: 像素数 61 | """ 62 | self.padding = padding 63 | self.resize(self.size()) 64 | 65 | def setTitle(self, title: str): 66 | """ 67 | 设置页面标题 68 | :param title: 标题 69 | """ 70 | # 套标题用的水平容器 71 | self.title_container = SiDenseHContainer(self) 72 | self.title_container.setSpacing(0) 73 | self.title_container.setFixedHeight(32) 74 | self.title_container.setAlignment(Qt.AlignCenter) 75 | 76 | # 标题 77 | self.title = SiLabel(self) 78 | self.title.setFont(SiFont.tokenized(GlobalFont.L_BOLD)) 79 | self.title.setFixedHeight(32) 80 | self.title.setContentsMargins(64, 0, 0, 0) 81 | self.title.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) 82 | self.title.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 83 | 84 | # 添加到水平容器 85 | self.title_container.addWidget(self.title) 86 | 87 | self.title.setText(title) 88 | 89 | # 添加到垂直容器 90 | self.addPlaceholder(32, index=0) 91 | self.addWidget(self.title_container, index=0) 92 | self.addPlaceholder(32, index=0) 93 | 94 | self.title_height = 96 95 | 96 | def reloadStyleSheet(self): 97 | super().reloadStyleSheet() 98 | self.title.setStyleSheet("color: {}".format(SiGlobal.siui.colors["TEXT_A"])) 99 | 100 | def resizeEvent(self, event): 101 | super().resizeEvent(event) 102 | size = event.size() 103 | 104 | self.scroll_area.resize(size.width(), size.height() - self.title_height) 105 | self.scroll_area.attachment().setFixedWidth(min(size.width() - self.padding * 2, self.scroll_maximum_width)) 106 | 107 | # 处理对齐 108 | if (self.scroll_alignment & Qt.AlignHCenter) == Qt.AlignHCenter: 109 | scroll_widget_x = (size.width() - self.scroll_area.attachment().width())//2 110 | elif (self.scroll_alignment & Qt.AlignLeft) == Qt.AlignLeft: 111 | scroll_widget_x = self.padding 112 | elif (self.scroll_alignment & Qt.AlignRight) == Qt.AlignRight: 113 | scroll_widget_x = size.width() - self.scroll_area.attachment().width() - self.padding 114 | else: 115 | raise ValueError(f"Invalid alignment value: {self.scroll_alignment}") 116 | 117 | scroll_widget_y = self.scroll_area.attachment().y() 118 | 119 | self.scroll_area.attachment().move(scroll_widget_x, scroll_widget_y) 120 | self.scroll_area.animationGroup().fromToken("scroll").setTarget([scroll_widget_x, scroll_widget_y]) 121 | self.scroll_area.animationGroup().fromToken("scroll").setCurrent([scroll_widget_x, scroll_widget_y]) 122 | -------------------------------------------------------------------------------- /siui/components/progress_bar/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.progress_bar.progress_bar import * -------------------------------------------------------------------------------- /siui/components/slider/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.slider.slider import * -------------------------------------------------------------------------------- /siui/components/spinbox/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/components/spinbox/__init__.py -------------------------------------------------------------------------------- /siui/components/spinbox/spinbox.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtGui import QDoubleValidator, QIntValidator 2 | 3 | from siui.components.widgets.button import SiSimpleButton 4 | from siui.components.widgets.line_edit import SiLineEdit 5 | from siui.core import SiGlobal 6 | 7 | 8 | class ABCSiSpinBox(SiLineEdit): 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | self.single_step_ = 1 12 | self.value_ = 0 13 | self.minimum_ = 0 14 | self.maximum_ = 99 15 | 16 | self.button_plus = SiSimpleButton(self) 17 | self.button_plus.resize(24, 24) 18 | self.button_plus.attachment().setSvgSize(12, 12) 19 | self.button_plus.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_chevron_up_regular")) 20 | self.button_plus.setRepetitiveClicking(True) 21 | self.button_plus.clicked.connect(self.stepForth) 22 | 23 | self.button_minus = SiSimpleButton(self) 24 | self.button_minus.resize(24, 24) 25 | self.button_minus.attachment().setSvgSize(12, 12) 26 | self.button_minus.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_chevron_down_regular")) 27 | self.button_minus.setRepetitiveClicking(True) 28 | self.button_minus.clicked.connect(self.stepBack) 29 | 30 | self.container().setSpacing(0) 31 | self.container().addPlaceholder(8, "right") 32 | self.container().addWidget(self.button_plus, "right") 33 | self.container().addPlaceholder(4, "right") 34 | self.container().addWidget(self.button_minus, "right") 35 | 36 | def singleStep(self): 37 | return self.single_step_ 38 | 39 | def setSingleStep(self, step): 40 | self.single_step_ = step 41 | 42 | def minimum(self): 43 | return self.minimum_ 44 | 45 | def setMinimum(self, minimum): 46 | self.minimum_ = minimum 47 | 48 | def maximum(self): 49 | return self.maximum_ 50 | 51 | def setMaximum(self, maximum): 52 | self.maximum_ = maximum 53 | 54 | def value(self): 55 | return self.value_ 56 | 57 | def setValue(self, value): 58 | self.value_ = min(self.maximum_, max(value, self.minimum_)) 59 | 60 | def stepForth(self): 61 | self.setValue(self.value() + self.singleStep()) 62 | 63 | def stepBack(self): 64 | self.setValue(self.value() - self.singleStep()) 65 | 66 | def stepBy(self, step): 67 | self.setValue(self.value() + step) 68 | 69 | 70 | class SiIntSpinBox(ABCSiSpinBox): 71 | def __init__(self, *args, **kwargs): 72 | super().__init__(*args, **kwargs) 73 | 74 | self.lineEdit().setValidator(QIntValidator()) 75 | self.lineEdit().setText(str(self.value())) 76 | self.lineEdit().editingFinished.connect(self.on_editing_finished) 77 | 78 | def on_editing_finished(self): 79 | value = int(self.lineEdit().text()) 80 | self.setValue(value) 81 | if value < self.minimum() or value > self.maximum(): 82 | try: 83 | SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send( 84 | title="输入值超出范围", 85 | text=f"限制输入值为介于 {self.minimum()} 到 {self.maximum()} 的整数\n" 86 | "已修改为最接近的值", 87 | msg_type=3, 88 | icon=SiGlobal.siui.iconpack.get("ic_fluent_warning_regular"), 89 | fold_after=2500, 90 | ) 91 | except ValueError: 92 | pass 93 | 94 | def setValue(self, value): 95 | super().setValue(value) 96 | self.lineEdit().setText(str(self.value())) 97 | 98 | 99 | class SiDoubleSpinBox(ABCSiSpinBox): 100 | def __init__(self, *args, **kwargs): 101 | super().__init__(*args, **kwargs) 102 | 103 | self.setSingleStep(0.1) 104 | 105 | self.lineEdit().setValidator(QDoubleValidator()) 106 | self.lineEdit().setText(str(self.value())) 107 | self.lineEdit().editingFinished.connect(self.on_editing_finished) 108 | 109 | def on_editing_finished(self): 110 | value = float(self.lineEdit().text()) 111 | self.setValue(value) 112 | if value < self.minimum() or value > self.maximum(): 113 | try: 114 | SiGlobal.siui.windows["MAIN_WINDOW"].LayerRightMessageSidebar().send( 115 | title="输入值超出范围", 116 | text=f"限制输入值为介于 {self.minimum()} 到 {self.maximum()} 的浮点数\n" 117 | "已修改为最接近的值", 118 | msg_type=3, 119 | icon=SiGlobal.siui.iconpack.get("ic_fluent_warning_regular"), 120 | fold_after=2500, 121 | ) 122 | except ValueError: 123 | pass 124 | 125 | def setValue(self, value): 126 | # 重写以解决浮点数有效位溢出问题 127 | self.value_ = round(min(self.maximum_, max(value, self.minimum_)), 13) # 舍掉一些精度以追求计算准确 128 | self.lineEdit().setText(str(self.value())) 129 | -------------------------------------------------------------------------------- /siui/components/titled_widget_group/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.titled_widget_group.titled_widget_group import SiTitledWidgetGroup -------------------------------------------------------------------------------- /siui/components/titled_widget_group/titled_widget_group.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components.widgets.container import SiDenseVContainer 4 | from siui.components.widgets.label import SiLabel 5 | from siui.core import SiGlobal, GlobalFont 6 | from siui.core import Si 7 | from siui.gui import SiFont 8 | 9 | 10 | class GroupTitle(SiLabel): 11 | def __init__(self, *args, **kwargs): 12 | super().__init__(*args, **kwargs) 13 | 14 | self.setFixedHeight(26) 15 | 16 | # 标题文字 17 | self.title_label = SiLabel(self) 18 | self.title_label.setFont(SiFont.tokenized(GlobalFont.M_BOLD)) 19 | self.title_label.setFixedHeight(26) 20 | self.title_label.setAlignment(Qt.AlignBottom) 21 | self.title_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 22 | 23 | # 标题高光,显示在文字下方 24 | self.title_highlight = SiLabel(self) 25 | self.title_highlight.lower() 26 | self.title_highlight.setFixedStyleSheet("border-radius: 4px") 27 | 28 | # 标题指示器,显示在文字左侧 29 | self.title_indicator = SiLabel(self) 30 | self.title_indicator.resize(5, 18) 31 | self.title_indicator.setFixedStyleSheet("border-radius: 2px") 32 | 33 | def reloadStyleSheet(self): 34 | super().reloadStyleSheet() 35 | 36 | self.setStyleSheet("background-color: transparent") 37 | self.title_label.setStyleSheet("color: {}".format(SiGlobal.siui.colors["TEXT_A"])) 38 | self.title_indicator.setStyleSheet("background-color: {}".format(SiGlobal.siui.colors["TITLE_INDICATOR"])) 39 | self.title_highlight.setStyleSheet("background-color: {}".format(SiGlobal.siui.colors["TITLE_HIGHLIGHT"])) 40 | 41 | def setText(self, text: str): 42 | self.title_label.setText(text) 43 | self.adjustSize() 44 | 45 | def adjustSize(self): 46 | self.resize(self.title_label.width() + 12 + 4, self.height()) 47 | 48 | def resizeEvent(self, event): 49 | super().resizeEvent(event) 50 | 51 | self.title_indicator.move(0, 4) 52 | self.title_label.move(12, 0) 53 | self.title_highlight.setGeometry(12, 12, self.title_label.width() + 4, 13) 54 | 55 | 56 | class SiTitledWidgetGroup(SiDenseVContainer): 57 | def __init__(self, *args, **kwargs): 58 | super().__init__(*args, **kwargs) 59 | 60 | self.setAdjustWidgetsSize(True) 61 | self.setSpacing(8) 62 | 63 | def addTitle(self, title): 64 | """ 65 | 添加新标题,这将创建一个标题组件并添加到自身中 66 | :param title: 标题文字 67 | """ 68 | if len(self.widgets_top) > 0: 69 | self.addPlaceholder(16) 70 | 71 | new_title = GroupTitle(self) 72 | new_title.setText(title) 73 | self.addWidget(new_title) 74 | 75 | def addWidget(self, widget, side="top", index=10000): 76 | super().addWidget(widget, side, index) 77 | try: 78 | widget.resized.connect(self._on_child_resized) 79 | except: # noqa: E722 80 | pass 81 | # print(f"子控件 {widget} 似乎不具有正确形式的 resized 信号(pyqtSignal(list))") 82 | 83 | def _on_child_resized(self, _): 84 | self.adjustSize() 85 | -------------------------------------------------------------------------------- /siui/components/tooltip/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.components.tooltip.tooltip import ToolTipWindow -------------------------------------------------------------------------------- /siui/components/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | import siui.components.widgets.abstracts as abstarcts 2 | from siui.components.widgets.button import * 3 | from siui.components.widgets.container import * 4 | from siui.components.widgets.label import * 5 | from siui.components.widgets.line_edit import * 6 | from siui.components.widgets.scrollarea import * 7 | -------------------------------------------------------------------------------- /siui/components/widgets/abstracts/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from siui.components.widgets.abstracts.button import * 3 | from siui.components.widgets.abstracts.label import * 4 | from siui.components.widgets.abstracts.line_edit import * 5 | from siui.components.widgets.abstracts.navigation_bar import * 6 | from siui.components.widgets.abstracts.widget import * 7 | -------------------------------------------------------------------------------- /siui/components/widgets/abstracts/container.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import QSize 2 | 3 | from siui.components.widgets.abstracts.widget import SiWidget 4 | 5 | 6 | class SiSection: 7 | def __init__(self, width=0, height=0, alignment=None): 8 | self.width_ = width 9 | self.height_ = height 10 | self.alignment_ = alignment 11 | 12 | def setWidth(self, width): 13 | self.width_ = width 14 | 15 | def setHeight(self, height): 16 | self.height_ = height 17 | 18 | def setAlignment(self, alignment): 19 | self.alignment_ = alignment 20 | 21 | def width(self): 22 | return self.width_ 23 | 24 | def height(self): 25 | return self.height_ 26 | 27 | def size(self): 28 | return QSize(self.width_, self.height_) 29 | 30 | def alignment(self): 31 | return self.alignment_ 32 | 33 | def __str__(self): 34 | text = f"" 35 | return text 36 | 37 | 38 | class SiSectionTemplate: 39 | def __init__(self): 40 | self.sections_ = [] 41 | self.spacing_ = 0 42 | 43 | def sections(self): 44 | return self.sections_ 45 | 46 | def addSection(self, width=0, height=0, alignment=None): 47 | self.sections_.append(SiSection(width, height, alignment)) 48 | 49 | def spacing(self): 50 | return self.spacing_ 51 | 52 | def setSpacing(self, spacing: int): 53 | self.spacing_ = spacing 54 | 55 | 56 | class ABCSiDividedContainer(SiWidget): 57 | def __init__(self, *args, **kwargs): 58 | super().__init__(*args, **kwargs) 59 | 60 | self.sections_and_widgets = [] 61 | self.spacing_ = 0 62 | 63 | def spacing(self): 64 | return self.spacing_ 65 | 66 | def setSpacing(self, spacing: int): 67 | self.spacing_ = spacing 68 | 69 | def sections(self): 70 | return [a[0] for a in self.sections_and_widgets] 71 | 72 | def addSection(self, width=None, height=None, alignment=None): 73 | self.sections_and_widgets.append([SiSection(width, height, alignment), None]) 74 | 75 | def setTemplate(self, template: SiSectionTemplate): 76 | self.setSpacing(template.spacing()) 77 | for index, section in enumerate(template.sections()): 78 | if index < len(self.sections_and_widgets): 79 | self.sections_and_widgets[index][0] = section 80 | else: 81 | self.sections_and_widgets.append([section, None]) 82 | 83 | def widgets(self): 84 | return [a[1] for a in self.sections_and_widgets] 85 | 86 | def addWidget(self, widget, index=None): 87 | if index is None: 88 | index = self.widgets().index(None) 89 | 90 | widget.setParent(self) 91 | 92 | if self.sections_and_widgets[index][1] is not None: 93 | self.sections_and_widgets[index][1].deleteLater() 94 | self.sections_and_widgets[index][1] = widget 95 | -------------------------------------------------------------------------------- /siui/components/widgets/abstracts/line_edit.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, pyqtSignal 2 | from PyQt5.QtWidgets import QLineEdit 3 | 4 | from siui.components.widgets.abstracts.widget import SiWidget 5 | from siui.components.widgets.container import SiDenseHContainer 6 | from siui.components.widgets.label import SiLabel 7 | from siui.core import SiColor, GlobalFont 8 | from siui.core import SiGlobal 9 | from siui.gui import SiFont 10 | 11 | 12 | class SiSimpleLineEdit(QLineEdit): 13 | onFocus = pyqtSignal(bool) 14 | 15 | def __init__(self, *args, **kwargs): 16 | super().__init__(*args, **kwargs) 17 | 18 | # 设置字体 19 | self.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 20 | 21 | def reloadStyleSheet(self): 22 | self.setStyleSheet( 23 | "QLineEdit {" 24 | " selection-background-color: #493F4E;" 25 | " background-color: transparent;" 26 | f" color: {self.parent().getColor(SiColor.TEXT_C)};" 27 | " border: 0px" 28 | "}" 29 | ) 30 | 31 | def focusInEvent(self, event): 32 | super().focusInEvent(event) 33 | self.onFocus.emit(True) 34 | 35 | def focusOutEvent(self, event): 36 | super().focusOutEvent(event) 37 | self.onFocus.emit(False) 38 | 39 | 40 | class ABCSiLineEdit(SiWidget): 41 | def __init__(self, *args, **kwargs): 42 | super().__init__(*args, **kwargs) 43 | 44 | self.is_focus_in = False 45 | self.padding_ = 0 46 | 47 | self.container_ = SiDenseHContainer(self) 48 | self.container_.setAlignment(Qt.AlignVCenter) 49 | 50 | self.outfit_label_top = SiLabel(self) 51 | self.outfit_label_top.lower() 52 | self.outfit_label_top.setFixedStyleSheet( 53 | "border-top-left-radius: 4px;" 54 | "border-top-right-radius: 4px;" 55 | "border-bottom-left-radius: 2px;" 56 | "border-bottom-right-radius: 2px;" 57 | ) 58 | 59 | self.outfit_label_bottom = SiLabel(self) 60 | self.outfit_label_bottom.stackUnder(self.outfit_label_top) 61 | self.outfit_label_bottom.setFixedStyleSheet("border-radius: 4px") 62 | 63 | def container(self): 64 | return self.container_ 65 | 66 | def setPadding(self, padding): 67 | self.padding_ = padding 68 | self.resize(self.size()) 69 | 70 | def padding(self): 71 | return self.padding_ 72 | 73 | def setFocusState(self, state): 74 | self.is_focus_in = state 75 | self.on_focus_changed(self.is_focus_in) 76 | 77 | def focusState(self): 78 | return self.is_focus_in 79 | 80 | def on_focus_changed(self, is_on): 81 | w, h = self.size().width(), self.size().height() 82 | if is_on: 83 | self.outfit_label_top.resize(w, h - 2) 84 | else: 85 | self.outfit_label_top.resize(w, h - 1) 86 | 87 | def reloadStyleSheet(self): 88 | super().reloadStyleSheet() 89 | 90 | self.outfit_label_top.setStyleSheet( 91 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_B)};" 92 | f"border-left: 1px solid {self.getColor(SiColor.INTERFACE_BG_D)};" 93 | f"border-right: 1px solid {self.getColor(SiColor.INTERFACE_BG_D)};" 94 | f"border-top: 1px solid {self.getColor(SiColor.INTERFACE_BG_D)};" 95 | ) 96 | self.outfit_label_bottom.setStyleSheet( 97 | "background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1," 98 | f" stop:0 {self.getColor(SiColor.THEME_TRANSITION_A)}," 99 | f" stop:1 {self.getColor(SiColor.THEME_TRANSITION_B)}" 100 | ")" 101 | ) 102 | 103 | def resizeEvent(self, event): 104 | super().resizeEvent(event) 105 | self.container_.resize(event.size()) 106 | self.outfit_label_bottom.resize(event.size()) 107 | self.outfit_label_top.setGeometry( 108 | self.padding_, 0, event.size().width() - 2 * self.padding_, event.size().height() - 1) 109 | -------------------------------------------------------------------------------- /siui/components/widgets/abstracts/navigation_bar.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import pyqtSignal 2 | 3 | from siui.components.widgets.abstracts.widget import SiWidget 4 | 5 | 6 | class ABCSiNavigationBar(SiWidget): 7 | """ 抽象导航栏 """ 8 | indexChanged = pyqtSignal(int) 9 | 10 | def __init__(self, *args, **kwargs): 11 | super().__init__(*args, **kwargs) 12 | 13 | # 当前索引 14 | self.current_index_ = -1 15 | 16 | # 最大索引,需要最先设置 17 | self.maximum_index_ = -1 18 | 19 | def setCurrentIndex(self, index): 20 | """ 设置当前索引 """ 21 | self.current_index_ = index % (self.maximumIndex() + 1) 22 | self.indexChanged.emit(self.currentIndex()) 23 | 24 | def currentIndex(self): 25 | """ 获取当前索引 """ 26 | return self.current_index_ 27 | 28 | def setMaximumIndex(self, max_index): 29 | """ 设置最大的索引,超过最大索引的索引将会被取余数 """ 30 | if max_index < self.maximumIndex(): 31 | self.maximum_index_ = max_index 32 | self.setCurrentIndex(self.currentIndex()) # 如果最大索引变小,这样可以防止其超过界限 33 | else: 34 | self.maximum_index_ = max_index 35 | 36 | def maximumIndex(self): 37 | """ 获取最大的索引 """ 38 | return self.maximum_index_ 39 | 40 | def shift(self, step: int): 41 | """ 42 | 将当前索引加 step 43 | :param step: 步长 44 | """ 45 | self.setCurrentIndex(self.currentIndex() + step) 46 | -------------------------------------------------------------------------------- /siui/components/widgets/expands.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | from PyQt5.QtWidgets import QWidget 3 | 4 | from siui.components import SiDenseHContainer, SiIconLabel, SiLabel, SiSvgLabel, SiWidget 5 | from siui.core import SiColor, SiExpAccelerateAnimation, SiGlobal 6 | 7 | 8 | class SiHExpandWidget(SiWidget): 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | 12 | self.attachment_ = SiWidget(self) 13 | 14 | self.expand_animation = SiExpAccelerateAnimation(self) 15 | self.expand_animation.setAccelerateFunction(lambda x: (x / 10) ** 3) 16 | self.expand_animation.setFactor(1/4) 17 | self.expand_animation.setBias(0.01) 18 | self.expand_animation.setCurrent(1) 19 | self.expand_animation.setTarget(1) 20 | self.expand_animation.ticked.connect(self.on_ani_ticked) 21 | 22 | self.animationGroup().addMember(self.expand_animation, "expand") 23 | 24 | def attachment(self): 25 | return self.attachment_ 26 | 27 | def setAttachment(self, att: QWidget): 28 | self.attachment_.deleteLater() 29 | self.attachment_ = att 30 | att.setParent(self) 31 | 32 | def expand(self, percent): 33 | self.expand_animation.stop() 34 | self.expand_animation.setTarget(percent) 35 | self.expand_animation.setCurrent(percent) 36 | 37 | def expandTo(self, percent): 38 | self.expand_animation.setTarget(percent) 39 | self.expand_animation.try_to_start() 40 | 41 | def on_ani_ticked(self, value): 42 | value = float(value) # 绑定控件半边的长度占整个控件半侧的百分比 43 | one_side_width = int(self.width() / 2 * value) 44 | x = self.width() // 2 - one_side_width 45 | width = one_side_width * 2 46 | self.attachment_.setGeometry(x, 0, width, self.height()) 47 | 48 | def resizeEvent(self, event): 49 | super().resizeEvent(event) 50 | self.on_ani_ticked(self.expand_animation.current()) # 强制刷新绑定控件大小 51 | 52 | 53 | class SiVExpandWidget(SiWidget): 54 | def __init__(self, *args, **kwargs): 55 | super().__init__(*args, **kwargs) 56 | 57 | self.attachment_ = SiWidget(self) 58 | 59 | self.expand_animation = SiExpAccelerateAnimation(self) 60 | self.expand_animation.setAccelerateFunction(lambda x: (x / 10) ** 3) 61 | self.expand_animation.setFactor(1/4) 62 | self.expand_animation.setBias(0.01) 63 | self.expand_animation.setCurrent(1) 64 | self.expand_animation.setTarget(1) 65 | self.expand_animation.ticked.connect(self.on_ani_ticked) 66 | 67 | self.animationGroup().addMember(self.expand_animation, "expand") 68 | 69 | def attachment(self): 70 | return self.attachment_ 71 | 72 | def setAttachment(self, att: QWidget): 73 | self.attachment_.deleteLater() 74 | self.attachment_ = att 75 | att.setParent(self) 76 | 77 | def expand(self, percent): 78 | self.expand_animation.stop() 79 | self.expand_animation.setTarget(percent) 80 | self.expand_animation.setCurrent(percent) 81 | 82 | def expandTo(self, percent): 83 | self.expand_animation.setTarget(percent) 84 | self.expand_animation.try_to_start() 85 | 86 | def on_ani_ticked(self, value): 87 | value = float(value) # 绑定控件半边的长度占整个控件半侧的百分比 88 | one_side_height = int(self.height() / 2 * value) 89 | y = self.height() // 2 - one_side_height 90 | height = one_side_height * 2 91 | self.attachment_.setGeometry(0, y, self.width(), height) 92 | 93 | def resizeEvent(self, event): 94 | super().resizeEvent(event) 95 | self.on_ani_ticked(self.expand_animation.current()) # 强制刷新绑定控件大小 96 | 97 | 98 | class SiHoverExpandWidget(SiVExpandWidget): 99 | def __init__(self, *args, **kwargs): 100 | super().__init__(*args, **kwargs) 101 | 102 | self.h_expand_widget = SiHExpandWidget(self) 103 | 104 | self.frame = SiLabel(self) 105 | self.frame.setFixedStyleSheet("border-radius: 4px") 106 | self.frame.setColor(SiColor.mix(self.getColor(SiColor.INTERFACE_BG_D), self.getColor(SiColor.SIDE_MSG_THEME_SUCCESS))) 107 | 108 | self.container = SiDenseHContainer(self.frame) 109 | self.container.setFixedHeight(32) 110 | 111 | self.icon = SiSvgLabel(self) 112 | self.icon.load(SiGlobal.siui.iconpack.get("ic_fluent_arrow_sync_filled")) 113 | self.icon.resize(32, 32) 114 | 115 | self.label = SiLabel(self) 116 | self.label.setTextColor(self.getColor(SiColor.TEXT_B)) 117 | self.label.setAlignment(Qt.AlignCenter) 118 | self.label.setText("重载成功") 119 | self.label.setFixedHeight(32) 120 | self.label.adjustSize() 121 | 122 | self.container.setSpacing(0) 123 | self.container.addWidget(self.icon) 124 | self.container.addWidget(self.label) 125 | 126 | self.frame.adjustSize() 127 | 128 | self.h_expand_widget.setAttachment(self.frame) 129 | self.setAttachment(self.h_expand_widget) 130 | 131 | def enterEvent(self, a0): 132 | super().enterEvent(a0) 133 | self.expandTo(1) 134 | self.h_expand_widget.expandTo(1) 135 | # self.frame.setOpacityTo(1) 136 | 137 | def leaveEvent(self, a0): 138 | super().leaveEvent(a0) 139 | self.expandTo(1) 140 | self.h_expand_widget.expandTo(32 / self.width()) 141 | # self.frame.setOpacityTo(0.1) 142 | -------------------------------------------------------------------------------- /siui/components/widgets/line_edit.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | from PyQt5.QtWidgets import QLineEdit 3 | 4 | from siui.components.widgets import SiLabel, SiWidget 5 | from siui.components.widgets.abstracts import ABCSiLineEdit, SiSimpleLineEdit 6 | from siui.components.widgets.button import SiSimpleButton 7 | from siui.core import SiGlobal, SiColor, SiExpAnimation 8 | 9 | 10 | class SiLineEdit(ABCSiLineEdit): 11 | def __init__(self, *args, **kwargs): 12 | super().__init__(*args, **kwargs) 13 | 14 | self.line_edit = SiSimpleLineEdit(self) 15 | self.line_edit.setTextMargins(12, 0, 12, 1) 16 | self.line_edit.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) 17 | self.line_edit.onFocus.connect(self.on_focus_changed) 18 | self.line_edit.returnPressed.connect(self.line_edit.clearFocus) # 按下回车,移出焦点 19 | self.container().addWidget(self.line_edit) 20 | 21 | def adjustLineEditSize(self): 22 | preferred_width = self.container().width() - self.container().getUsedSpace("right") 23 | self.line_edit.resize(preferred_width, self.line_edit.height()) 24 | 25 | def lineEdit(self): 26 | return self.line_edit 27 | 28 | def resizeEvent(self, event): 29 | super().resizeEvent(event) 30 | self.adjustLineEditSize() 31 | 32 | 33 | class SiLineEditWithDeletionButton(SiLineEdit): 34 | def __init__(self, *args, **kwargs): 35 | super().__init__(*args, **kwargs) 36 | 37 | self.deletion_button = SiSimpleButton(self) 38 | self.deletion_button.resize(24, 24) 39 | self.deletion_button.attachment().setSvgSize(16, 16) 40 | self.deletion_button.attachment().load(SiGlobal.siui.iconpack.get("ic_fluent_delete_regular")) 41 | self.deletion_button.clicked.connect(self.clear_text) 42 | self.container().setSpacing(0) 43 | self.container().addPlaceholder(8, "right") 44 | self.container().addWidget(self.deletion_button, "right") 45 | 46 | def clear_text(self): 47 | self.lineEdit().setText("") 48 | 49 | 50 | class SiLineEditWithItemName(SiWidget): 51 | def __init__(self, *args, **kwargs): 52 | super().__init__(*args, **kwargs) 53 | 54 | self.name_spacing = 128 55 | 56 | self.base_panel = SiLabel(self) 57 | self.base_panel.setFixedStyleSheet("border-radius: 6px") 58 | self.base_panel.animation_color.setBias(1) 59 | self.base_panel.animation_color.setFactor(1/32) 60 | 61 | self.edit_panel = SiLabel(self) 62 | self.edit_panel.setFixedStyleSheet("border-radius: 6px") 63 | 64 | self.name_label = SiLabel(self) 65 | self.name_label.setContentsMargins(16, 0, 16, 0) 66 | self.name_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) 67 | 68 | self.line_edit = SiSimpleLineEdit(self.edit_panel) 69 | self.line_edit.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) 70 | self.line_edit.setTextMargins(16, 0, 16, 0) 71 | self.line_edit.textEdited.connect(self.flash_on_edited) 72 | 73 | def reloadStyleSheet(self): 74 | super().reloadStyleSheet() 75 | c = self.getColor(SiColor.INTERFACE_BG_C) 76 | b = self.getColor(SiColor.INTERFACE_BG_B) 77 | a = self.getColor(SiColor.INTERFACE_BG_A) 78 | 79 | self.base_panel.setColor(SiColor.mix(c, b, 0.3)) 80 | self.edit_panel.setColor(SiColor.mix(b, a, 0.5)) 81 | self.name_label.setTextColor(self.getColor(SiColor.TEXT_D)) 82 | 83 | def flash_on_edited(self): 84 | c = self.getColor(SiColor.INTERFACE_BG_C) 85 | b = self.getColor(SiColor.INTERFACE_BG_B) 86 | self.base_panel.setColor(self.getColor(SiColor.INTERFACE_BG_E)) 87 | self.base_panel.setColorTo(SiColor.mix(c, b, 0.3)) 88 | 89 | def setName(self, name: str): 90 | self.name_label.setText(name) 91 | 92 | def lineEdit(self): 93 | return self.line_edit 94 | 95 | def setNameSpacing(self, spacing): 96 | self.name_spacing = spacing 97 | self.resize(self.size()) 98 | 99 | def resizeEvent(self, event): 100 | super().resizeEvent(event) 101 | self.base_panel.resize(event.size()) 102 | self.edit_panel.setGeometry( 103 | self.name_spacing, 0, event.size().width() - self.name_spacing, event.size().height()) 104 | self.name_label.resize(self.name_spacing, event.size().height()) 105 | self.line_edit.resize(self.edit_panel.size()) 106 | -------------------------------------------------------------------------------- /siui/components/widgets/table.py: -------------------------------------------------------------------------------- 1 | from siui.components import SiLabel, SiMasonryContainer, SiScrollArea, SiWidget 2 | from siui.components.widgets.abstracts.table import ABCSiTabelManager, ABCSiTable, SiRow 3 | from siui.core import GlobalFont, Si, SiColor 4 | from siui.gui import SiFont 5 | 6 | 7 | class SiTableValueManagerLabels(ABCSiTabelManager): 8 | def _value_read_parser(self, row_index, col_index): 9 | return self.parent().getRowWidget(row_index)[col_index].text() 10 | 11 | def _value_write_parser(self, row_index, col_index, value): 12 | self.parent().getRowWidget(row_index)[col_index].setText(value) 13 | 14 | def _widget_creator(self, col_index): 15 | label = SiLabel(self.parent()) 16 | label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 17 | label.setFixedStyleSheet("color: #e5e5e5") 18 | return label 19 | 20 | def on_header_created(self, header: SiRow): 21 | for name in self.parent().column_names: 22 | new_label = SiLabel(self.parent()) 23 | new_label.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 24 | new_label.setTextColor(self.parent().getColor(SiColor.TEXT_B)) 25 | new_label.setText(name) 26 | new_label.adjustSize() 27 | header.container().addWidget(new_label) 28 | 29 | header.container().arrangeWidgets() 30 | 31 | 32 | class SiTableView(ABCSiTable): 33 | def __init__(self, *args, **kwargs): 34 | super().__init__(*args, **kwargs) 35 | 36 | self.padding = 20 37 | 38 | self.panel = SiLabel(self) 39 | self.panel.setFixedStyleSheet("border-radius: 8px") 40 | 41 | self.header_panel = SiLabel(self) 42 | self.header_panel.setFixedStyleSheet("border-top-left-radius: 8px; border-top-right-radius: 8px") 43 | 44 | self.container_ = SiMasonryContainer(self) 45 | self.container_.setSpacing(vertical=0) 46 | self.container_.setColumns(1) 47 | 48 | self.scroll_area = SiScrollArea(self) 49 | self.scroll_area.setAttachment(self.container_) 50 | 51 | self.setManager(SiTableValueManagerLabels(self)) 52 | self.header_row = SiRow(self) 53 | 54 | self.indicator_frame = SiWidget(self) 55 | self.indicator_frame.setFixedHeight(6) 56 | self.indicator_frame.move(8, 44) 57 | self.indicator_frame.hide() 58 | 59 | self.indicator_track = SiLabel(self.indicator_frame) 60 | self.indicator_track.setFixedStyleSheet("border-radius: 1px") 61 | self.indicator_track.move(0, 2) 62 | 63 | def addRow(self, widgets: list = None, data: list = None): 64 | super().addRow(widgets, data) 65 | 66 | if len(self.rows_) % 2 == 0: 67 | color = self.getColor(SiColor.INTERFACE_BG_C) 68 | else: 69 | color = self.getColor(SiColor.INTERFACE_BG_B) 70 | 71 | self.rows_[-1].setFixedStyleSheet("border-radius: 6px") 72 | self.rows_[-1].setColor(color) 73 | self.rows_[-1].resize(self.width() - self.padding * 2, 40) 74 | self.container().arrangeWidgets() 75 | 76 | def addColumn(self, 77 | name: str, 78 | width: int = None, 79 | height: int = None, 80 | alignment=None): 81 | super().addColumn(name, width, height, alignment) 82 | self._load_header() 83 | 84 | def _load_header(self): 85 | self.header_row.deleteLater() 86 | self.header_row = SiRow(self) 87 | self.header_row.container().setTemplate(self.sectionTemplate()) 88 | self.header_row.setGeometry(self.padding, 4, self.width() - self.padding * 2, 40) 89 | self.manager().on_header_created(self.header_row) 90 | 91 | def reloadStyleSheet(self): 92 | super().reloadStyleSheet() 93 | 94 | self.panel.setStyleSheet( 95 | f"border: 1px solid {self.getColor(SiColor.INTERFACE_BG_D)};" 96 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_B)};" 97 | ) 98 | 99 | self.header_panel.setStyleSheet( 100 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_D)};" 101 | ) 102 | 103 | self.indicator_track.setStyleSheet( 104 | f"background-color: {self.getColor(SiColor.THEME)}" 105 | ) 106 | 107 | def resizeEvent(self, event): 108 | super().resizeEvent(event) 109 | self.panel.resize(event.size()) 110 | self.header_panel.resize(event.size().width(), 48) 111 | self.header_row.setGeometry(self.padding, 4, event.size().width() - self.padding * 2, 40) 112 | self.indicator_frame.resize(event.size().width() - self.indicator_frame.x() * 2, 6) 113 | self.indicator_track.resize(self.indicator_frame.width(), 3) 114 | 115 | self.scroll_area.setGeometry(self.padding, 48, event.size().width() - self.padding, event.size().height() - 48 - 1) 116 | self.container().setGeometry(0, 0, event.size().width() - self.padding * 2, self.container().height()) 117 | for row in self.rows(): 118 | row.resize(event.size().width() - self.padding * 2, 40) 119 | self.container().arrangeWidgets() 120 | -------------------------------------------------------------------------------- /siui/components/widgets/timeline.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, QSize 2 | 3 | from siui.components import SiLabel, SiMasonryContainer, SiSvgLabel, SiWidget 4 | from siui.core import SiColor, SiGlobal 5 | from siui.gui import SiFont 6 | 7 | 8 | class SiTimeLineItem(SiWidget): 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | 12 | self.icon = SiSvgLabel(self) 13 | self.icon.setSvgSize(24, 24) 14 | self.icon.setFixedSize(32, 32) 15 | self.icon.move(16, 0) 16 | 17 | self.anchor = SiLabel(self) 18 | self.anchor.setFixedSize(24, 24) 19 | self.anchor.setFixedStyleSheet("border-radius: 12px") 20 | self.anchor.setStyleSheet( 21 | f"border: 4px solid {self.getColor(SiColor.INTERFACE_BG_C)};" 22 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_E)};" 23 | ) 24 | self.anchor.move(64 + 4, 4) 25 | 26 | self.anchor_dot = SiLabel(self.anchor) 27 | self.anchor_dot.setFixedSize(8, 8) 28 | self.anchor_dot.setFixedStyleSheet("border-radius: 4px") 29 | self.anchor_dot.move(8, 8) 30 | self.anchor_dot.setStyleSheet( 31 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_C)};" 32 | ) 33 | 34 | self.title = SiLabel(self) 35 | self.title.setFont(SiFont.getFont(size=12)) 36 | self.title.setTextColor(self.getColor(SiColor.TEXT_D)) 37 | self.title.setAlignment(Qt.AlignLeft) 38 | self.title.setContentsMargins(0, 8, 0, 2) 39 | self.title.move(112, 0) 40 | self.title.adjustSize() 41 | 42 | self.description = SiLabel(self) 43 | self.description.setTextColor(self.getColor(SiColor.TEXT_B)) 44 | self.description.setAlignment(Qt.AlignLeft | Qt.AlignTop) 45 | self.description.move(112, self.title.height()) 46 | self.description.adjustSize() 47 | 48 | def setContent(self, title, description): 49 | self.title.setText(title) 50 | self.title.adjustSize() 51 | self.description.setText(description) 52 | self.description.adjustSize() 53 | 54 | def setIconHint(self, text): 55 | self.icon.setHint(text) 56 | 57 | def setThemeColor(self, code, background_color=None): 58 | background_color = self.getColor(SiColor.INTERFACE_BG_C) if background_color is None else background_color 59 | self.anchor.setStyleSheet( 60 | f"border: 4px solid {background_color};" 61 | f"background-color: {code};" 62 | ) 63 | self.anchor_dot.setStyleSheet( 64 | f"background-color: {background_color};" 65 | ) 66 | 67 | def setIcon(self, path_or_data): 68 | self.icon.load(path_or_data) 69 | 70 | def sizeHint(self): 71 | return QSize(self.width(), max(self.title.height() + self.description.height(), 64)) 72 | 73 | def resizeEvent(self, event): 74 | super().resizeEvent(event) 75 | 76 | self.title.resize(event.size().width() - 112, self.title.height()) 77 | self.description.resize(event.size().width() - 112, self.description.height()) 78 | self.description.move(112, self.title.height()) 79 | 80 | 81 | class SiTimeLine(SiMasonryContainer): 82 | def __init__(self, *args, **kwargs): 83 | super().__init__(*args, **kwargs) 84 | 85 | self.setColumns(1) 86 | self.setColumnWidth(500) 87 | 88 | self.track = SiLabel(self) 89 | self.track.setFixedStyleSheet("border-radius: 2px") 90 | self.track.setColor(self.getColor(SiColor.INTERFACE_BG_E)) 91 | self.track.setFixedWidth(4) 92 | self.track.resize(4, 100) 93 | self.track.move(14 + 64, 0) 94 | 95 | self.setMinimumWidth(500) 96 | 97 | def addWidget(self, widget, arrange=True, ani=True): 98 | super().addWidget(widget, arrange, ani) 99 | widget.resize(self.width(), widget.sizeHint().height()) 100 | 101 | def resizeEvent(self, event): 102 | super().resizeEvent(event) 103 | 104 | for item in self.widgets(): 105 | item.resize(event.size().width(), item.height()) 106 | 107 | self.track.resize(4, event.size().height()) 108 | -------------------------------------------------------------------------------- /siui/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .alignment import SiQuickAlignmentManager 2 | from .animation import ( 3 | ABCSiAnimation, 4 | Curve, 5 | SiAnimationGroup, 6 | SiCounterAnimation, 7 | SiExpAccelerateAnimation, 8 | SiExpAnimation, 9 | SiSqrExpAnimation, 10 | ) 11 | from .color import SiColor 12 | from .effect import SiQuickEffect 13 | from .enumrates import Si 14 | from .globals import NewGlobal, SiGlobal, hideToolTip, isToolTipInsideOf, isTooltipShown, showToolTip, updateToolTip 15 | from .painter import createPainter as createPainter 16 | from .token import FontStyle as FontStyle 17 | from .token import GlobalFont as GlobalFont 18 | from .token import GlobalFontSize as GlobalFontSize 19 | from .token import GlobalFontWeight as GlobalFontWeight 20 | 21 | __all__ = ( 22 | "SiQuickAlignmentManager", 23 | "ABCSiAnimation", 24 | "Curve", 25 | "SiAnimationGroup", 26 | "SiCounterAnimation", 27 | "SiExpAccelerateAnimation", 28 | "SiExpAnimation", 29 | "SiSqrExpAnimation", 30 | "SiColor", 31 | "SiQuickEffect", 32 | "Si", 33 | "NewGlobal", 34 | "SiGlobal", 35 | "FontStyle", 36 | "GlobalFont", 37 | "GlobalFontSize", 38 | "GlobalFontWeight", 39 | "hideToolTip", 40 | "showToolTip", 41 | "updateToolTip", 42 | "isTooltipShown", 43 | "isToolTipInsideOf", 44 | ) 45 | -------------------------------------------------------------------------------- /siui/core/alignment.py: -------------------------------------------------------------------------------- 1 | 2 | from PyQt5.QtCore import QPoint, QSize, Qt 3 | 4 | 5 | class SiQuickAlignmentManager: 6 | @staticmethod 7 | def toPos(container_size: QSize, 8 | widget_size: QSize, 9 | flag): 10 | if (flag & Qt.AlignLeft) == Qt.AlignLeft: 11 | x = 0 12 | elif (flag & Qt.AlignHCenter) == Qt.AlignHCenter: 13 | x = (container_size.width() - widget_size.width()) // 2 14 | elif (flag & Qt.AlignRight) == Qt.AlignRight: 15 | x = container_size.width() - widget_size.width() 16 | else: 17 | x = 0 18 | 19 | if (flag & Qt.AlignTop) == Qt.AlignTop: 20 | y = 0 21 | elif (flag & Qt.AlignVCenter) == Qt.AlignVCenter: 22 | y = (container_size.height() - widget_size.height()) // 2 23 | elif (flag & Qt.AlignBottom) == Qt.AlignBottom: 24 | y = container_size.height() - widget_size.height() 25 | else: 26 | y = 0 27 | 28 | return QPoint(x, y) 29 | -------------------------------------------------------------------------------- /siui/core/effect.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Union 2 | 3 | from PyQt5.QtGui import QColor 4 | from PyQt5.QtWidgets import QGraphicsDropShadowEffect, QGraphicsOpacityEffect, QWidget 5 | 6 | 7 | class SiQuickEffect: 8 | @staticmethod 9 | def applyDropShadowOn(widget: QWidget, 10 | color: Union[Tuple[int, int, int, int], None], 11 | offset: Union[Tuple[int, int], None] = None, 12 | blur_radius: int = 16): 13 | if color is None: 14 | color = (0, 0, 0, 255) 15 | if offset is None: 16 | offset = (0, 0) 17 | 18 | shadow = QGraphicsDropShadowEffect(widget) 19 | shadow.setColor(QColor(*color)) 20 | shadow.setOffset(*offset) 21 | shadow.setBlurRadius(blur_radius) 22 | widget.setGraphicsEffect(shadow) 23 | 24 | @staticmethod 25 | def applyOpacityOn(widget: QWidget, 26 | opacity: float): 27 | opacity_effect = QGraphicsOpacityEffect() 28 | opacity_effect.setOpacity(opacity) 29 | widget.setGraphicsEffect(opacity_effect) 30 | -------------------------------------------------------------------------------- /siui/core/enumrates.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, auto 2 | 3 | 4 | class Si(Enum): 5 | # the namespace of SiliconUI 6 | # Flags for SiWidget 7 | FlashOnHintUpdated = auto() # 在工具提示被重新设置时,使工具提示闪烁 8 | InstantMove = auto() # 是否立即移动而不运行动画 9 | InstantResize = auto() # 是否立即重设大小而不运行动画 10 | InstantSetOpacity = auto() # 是否立即重设透明度而不运行动画 11 | HasMoveLimits = auto() # 是否有移动限定区域 12 | AdjustSizeOnTextChanged = auto() # 是否在setText被调用时自动调整空间大小 13 | EnableAnimationSignals = auto() # 是否启用moved,resized,opacityChanged信号 14 | DeleteOnHidden = auto() # 下一次被隐藏时,运行 deleteLater() 15 | DeleteCenterWidgetOnCenterWidgetHidden = auto() # 中心控件下一次被隐藏时,运行 centerWidget().deleteLater() 16 | -------------------------------------------------------------------------------- /siui/core/function/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.core.function.chain import SiFunctionChain, chain_trigger, CalcLater # noqa: I001, F401 2 | -------------------------------------------------------------------------------- /siui/core/globals.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from PyQt5.QtWidgets import QWidget 4 | 5 | from siui.core import SiColor 6 | from siui.gui.color_group import DarkColorGroup 7 | from siui.gui.icons.parser import GlobalIconPack 8 | 9 | 10 | class SiliconUIGlobal: 11 | """ 12 | SiliconUI 内部使用的全局数据\n 13 | 如果你也需要使用全局数据,可以将你的类添加到 SiGlobal 的一个属性 14 | """ 15 | # 窗口字典,储存窗口对象 16 | windows = {} 17 | 18 | # 颜色字典,存储全部动态设置的颜色 19 | # 值为 RRGGBB 或 AARRGGBB 色号 20 | colors = DarkColorGroup() 21 | 22 | # 图标字典,储存所有 SVG 类型的图标数据 23 | # 值为 SVG信息的 bytes 24 | icons = {} 25 | iconpack = GlobalIconPack() 26 | iconpack.setDefaultColor("#D1CBD4") 27 | 28 | # 样式表字典,储存所有动态样式表 29 | # 值为字符串 30 | qss = {} 31 | 32 | # 字体字典,储存所有字体 33 | # 值为 QFont 类型的字体 34 | 35 | def loadWindows(self, dictionary): 36 | SiliconUIGlobal.windows.update(dictionary) 37 | 38 | def loadColors(self, dictionary): 39 | SiliconUIGlobal.colors.update(dictionary) 40 | 41 | def loadIcons(self, dictionary): 42 | SiliconUIGlobal.icons.update(dictionary) 43 | 44 | def loadQSS(self, dictionary): 45 | SiliconUIGlobal.qss.update(dictionary) 46 | 47 | def loadFonts(self, dictionary): 48 | SiliconUIGlobal.fonts.update(dictionary) 49 | 50 | def reloadAllWindowsStyleSheet(self): 51 | """ 52 | 调用各个窗口下的reloadStyleSheet方法并递归,重载所有窗口下所有控件的样式表 53 | """ 54 | for window in self.windows.values(): 55 | try: 56 | window.reloadStyleSheet() 57 | except AttributeError: 58 | pass 59 | self._reloadWidgetStyleSheet(window) 60 | 61 | def reloadStyleSheetRecursively(self, widget): 62 | """ run reloadStyleSheet() for all children of this widget """ 63 | try: 64 | widget.reloadStyleSheet() 65 | except AttributeError: 66 | pass 67 | self._reloadWidgetStyleSheet(widget) 68 | 69 | def _reloadWidgetStyleSheet(self, widget): 70 | for child in widget.children(): 71 | self._reloadWidgetStyleSheet(child) 72 | try: 73 | child.reloadStyleSheet() 74 | except AttributeError: 75 | pass 76 | return 77 | 78 | 79 | class SiGlobal: 80 | """ 81 | 全局数据\n 82 | 在 siui 模块被第一次导入时初始化 .siui 下的变量 83 | """ 84 | siui = SiliconUIGlobal() 85 | 86 | 87 | class NewGlobal: 88 | """ 89 | 新全局数据 90 | """ 91 | create_time = time.time() 92 | 93 | 94 | def toolTipWindow() -> QWidget: 95 | return SiGlobal.siui.windows.get("TOOL_TIP") 96 | 97 | 98 | def raiseToolTipWindow(): 99 | window = toolTipWindow() 100 | if window is not None: 101 | window.raise_() 102 | 103 | 104 | def showToolTip(widget, flash: bool = True) -> None: 105 | """ Show tool tip of specified widget """ 106 | window = toolTipWindow() 107 | if window is None: 108 | return 109 | if widget.toolTip() == "": 110 | return 111 | window.setText(widget.toolTip(), flash=flash) 112 | window.setNowInsideOf(widget) 113 | window.show_() 114 | 115 | 116 | def hideToolTip(widget) -> None: 117 | window = toolTipWindow() 118 | if window is None: 119 | return 120 | window.setNowInsideOf(None) 121 | window.hide_() 122 | 123 | 124 | def updateToolTip(widget, flash: bool = True) -> None: 125 | window = toolTipWindow() 126 | if window is None: 127 | return 128 | if widget.toolTip() == "": 129 | return 130 | window.setText(widget.toolTip(), flash=flash) 131 | 132 | 133 | def isTooltipShown() -> bool: 134 | return toolTipWindow().is_shown 135 | 136 | 137 | def isToolTipInsideOf(widget: QWidget) -> bool: 138 | return widget == toolTipWindow().nowInsideOf() 139 | 140 | -------------------------------------------------------------------------------- /siui/core/painter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import math 4 | from functools import lru_cache 5 | from typing import TYPE_CHECKING 6 | 7 | from PyQt5.QtCore import QPointF, QRectF, Qt 8 | from PyQt5.QtGui import QPainter, QPainterPath 9 | 10 | if TYPE_CHECKING: 11 | from PyQt5.QtGui import QFont, QPaintDevice 12 | 13 | from siui.typing import T_Brush, T_PenStyle, T_RenderHint 14 | 15 | 16 | def createPainter( 17 | paintDevice: QPaintDevice, 18 | renderHint: T_RenderHint = QPainter.RenderHint.Antialiasing, 19 | penStyle: T_PenStyle = Qt.PenStyle.NoPen, 20 | brush: T_Brush = None, 21 | font: QFont | None = None, 22 | ) -> QPainter: 23 | """构造并初始化 QPainter 对象 24 | 应该使用 with 关键字来创建和关闭 QPainter 对象 25 | 26 | 参数: 27 | - parent: QPaintDevice 的子类实例,通常是 QWidget 或 QImage 28 | - renderHint: 指定渲染提示,默认为 QPainter.RenderHint.Antialiasing 标准抗锯齿 29 | - penStyle: Qt.PenStyle 类型,指定画笔样式,默认为 Qt.PenStyle.NoPen 30 | - brushColor: 字符串或 QColor 对象,指定画刷颜色,默认不指定 31 | - font: QFont 对象,指定字体,默认不指定 32 | 33 | 返回: 34 | QPainter 对象实例 35 | """ 36 | painter = QPainter(paintDevice) 37 | if renderHint is not None: 38 | painter.setRenderHints(renderHint) 39 | 40 | if penStyle is not None: 41 | painter.setPen(penStyle) 42 | 43 | if brush is not None: 44 | painter.setBrush(brush) 45 | 46 | if font is not None: 47 | painter.setFont(font) 48 | 49 | return painter 50 | 51 | 52 | def _superSin(x: float, power: float = 5.0) -> float: 53 | return math.copysign(abs(math.sin(x)) ** (2 / power), math.sin(x)) 54 | 55 | 56 | def _superCos(x: float, power: float = 5.0) -> float: 57 | return math.copysign(abs(math.cos(x)) ** (2 / power), math.cos(x)) 58 | 59 | 60 | @lru_cache(maxsize=None) 61 | def _getSuperRoundedPoints(radius_x: float, radius_y: float, power: float, quality: int): 62 | points = [] 63 | for i in range(quality + 1): 64 | points.append(QPointF((_superSin(2 * math.pi * i / quality, power) + 0) * radius_x, 65 | (_superCos(2 * math.pi * i / quality, power) + 0) * radius_y)) 66 | return points 67 | 68 | 69 | @lru_cache(maxsize=None) 70 | def _cachedGetSuperRoundedRectPath(rect_tuple: tuple, 71 | radius_x: float, 72 | radius_y: float, 73 | power: float, 74 | quality: int) -> QPainterPath: 75 | rect = QRectF(*rect_tuple) 76 | path = QPainterPath() 77 | 78 | if quality == -1: 79 | quality = max(radius_x, radius_y) // 4 * 4 80 | 81 | points = _getSuperRoundedPoints(radius_x, radius_y, power, quality) 82 | inner_rect = QRectF(rect.x() + radius_x, rect.y() + radius_y, 83 | rect.width() - 2 * radius_x, rect.height() - 2 * radius_y) 84 | 85 | q = quality 86 | 87 | path.moveTo(points[q // 4 * 0] + inner_rect.bottomRight()) 88 | delta = inner_rect.bottomRight() 89 | for i in range(q // 4 * 0, q // 4 * 1 + 1): 90 | mid_point = (points[i] + points[i + 1]) / 2 + delta 91 | point = points[i] + delta 92 | path.quadTo(point, mid_point) 93 | 94 | delta = inner_rect.topRight() 95 | for i in range(q // 4 * 1, q // 4 * 2 + 1): 96 | mid_point = (points[i] + points[i + 1]) / 2 + delta 97 | point = points[i] + delta 98 | path.quadTo(point, mid_point) 99 | 100 | delta = inner_rect.topLeft() 101 | for i in range(q // 4 * 2, q // 4 * 3 + 1): 102 | mid_point = (points[i] + points[i + 1]) / 2 + delta 103 | point = points[i] + delta 104 | path.quadTo(point, mid_point) 105 | 106 | delta = inner_rect.bottomLeft() 107 | for i in range(q // 4 * 3, q // 4 * 4): 108 | mid_point = (points[i] + points[i + 1]) / 2 + delta 109 | point = points[i] + delta 110 | path.quadTo(point, mid_point) 111 | 112 | path.lineTo(points[-1] + inner_rect.bottomLeft()) # 连接到最后一个点 113 | 114 | return path 115 | 116 | 117 | def getSuperRoundedRectPath(rect: QRectF, 118 | radius_x: float, 119 | radius_y: float, 120 | power: float = 5.0, 121 | quality: int = -1) -> QPainterPath: 122 | """生成并返回一个超椭圆圆角矩形的路径 123 | 124 | 参数: 125 | - radius_x: float 圆角的横轴半径 126 | - radius_y: float 圆角的纵轴半径 127 | - power: float 超椭圆方程的幂数 128 | - quality: int 采样品质,若传入 -1,则根据圆角半径自动选择品质,其他传入值应为 4 的整数倍 129 | 130 | 返回: 131 | QPainterPath 对象实例 132 | 133 | 该函数启用了缓存,密集绘制友好 134 | """ 135 | 136 | rect_tuple = (rect.x(), rect.y(), rect.width(), rect.height()) 137 | return _cachedGetSuperRoundedRectPath(rect_tuple, radius_x, radius_y, power, quality) 138 | 139 | 140 | __all__ = [ 141 | "createPainter", "getSuperRoundedRectPath" 142 | ] 143 | -------------------------------------------------------------------------------- /siui/core/token.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | from PyQt5.QtGui import QFont 4 | 5 | 6 | class GlobalFontSize(Enum): 7 | """Tokenized Global Font Size""" 8 | 9 | S = 14 10 | M = 20 11 | L = 24 12 | XL = 32 13 | 14 | 15 | class GlobalFontWeight(Enum): 16 | """Tokenized Global Font Weight""" 17 | 18 | LIGHT = QFont.Weight.Light 19 | NORMAL = QFont.Weight.Normal 20 | MEDIUM = QFont.Weight.Medium 21 | DEMI_BOLD = QFont.Weight.DemiBold 22 | BOLD = QFont.Weight.Bold 23 | 24 | 25 | class FontStyle(Enum): 26 | """Tokenized Font Style""" 27 | 28 | REGULAR = QFont.Style.StyleNormal 29 | ITALIC = QFont.Style.StyleItalic 30 | OBLIQUE = QFont.Style.StyleOblique 31 | 32 | 33 | class GlobalFont(Enum): 34 | """Tokenized Global Font""" 35 | 36 | S_LIGHT = GlobalFontSize.S, GlobalFontWeight.LIGHT, FontStyle.REGULAR 37 | M_LIGHT = GlobalFontSize.M, GlobalFontWeight.LIGHT, FontStyle.REGULAR 38 | L_LIGHT = GlobalFontSize.L, GlobalFontWeight.LIGHT, FontStyle.REGULAR 39 | XL_LIGHT = GlobalFontSize.XL, GlobalFontWeight.LIGHT, FontStyle.REGULAR 40 | 41 | S_LIGHT_ITALIC = GlobalFontSize.S, GlobalFontWeight.LIGHT, FontStyle.ITALIC 42 | M_LIGHT_ITALIC = GlobalFontSize.M, GlobalFontWeight.LIGHT, FontStyle.ITALIC 43 | L_LIGHT_ITALIC = GlobalFontSize.L, GlobalFontWeight.LIGHT, FontStyle.ITALIC 44 | XL_LIGHT_ITALIC = GlobalFontSize.XL, GlobalFontWeight.LIGHT, FontStyle.ITALIC 45 | 46 | S_NORMAL = GlobalFontSize.S, GlobalFontWeight.NORMAL, FontStyle.REGULAR 47 | M_NORMAL = GlobalFontSize.M, GlobalFontWeight.NORMAL, FontStyle.REGULAR 48 | L_NORMAL = GlobalFontSize.L, GlobalFontWeight.NORMAL, FontStyle.REGULAR 49 | XL_NORMAL = GlobalFontSize.XL, GlobalFontWeight.NORMAL, FontStyle.REGULAR 50 | 51 | S_NORMAL_ITALIC = GlobalFontSize.S, GlobalFontWeight.NORMAL, FontStyle.ITALIC 52 | M_NORMAL_ITALIC = GlobalFontSize.M, GlobalFontWeight.NORMAL, FontStyle.ITALIC 53 | L_NORMAL_ITALIC = GlobalFontSize.L, GlobalFontWeight.NORMAL, FontStyle.ITALIC 54 | XL_NORMAL_ITALIC = GlobalFontSize.XL, GlobalFontWeight.NORMAL, FontStyle.ITALIC 55 | 56 | S_MEDIUM = GlobalFontSize.S, GlobalFontWeight.MEDIUM, FontStyle.REGULAR 57 | M_MEDIUM = GlobalFontSize.M, GlobalFontWeight.MEDIUM, FontStyle.REGULAR 58 | L_MEDIUM = GlobalFontSize.L, GlobalFontWeight.MEDIUM, FontStyle.REGULAR 59 | XL_MEDIUM = GlobalFontSize.XL, GlobalFontWeight.MEDIUM, FontStyle.REGULAR 60 | 61 | S_MEDIUM_ITALIC = GlobalFontSize.S, GlobalFontWeight.MEDIUM, FontStyle.ITALIC 62 | M_MEDIUM_ITALIC = GlobalFontSize.M, GlobalFontWeight.MEDIUM, FontStyle.ITALIC 63 | L_MEDIUM_ITALIC = GlobalFontSize.L, GlobalFontWeight.MEDIUM, FontStyle.ITALIC 64 | XL_MEDIUM_ITALIC = GlobalFontSize.XL, GlobalFontWeight.MEDIUM, FontStyle.ITALIC 65 | 66 | S_DEMI_BOLD = GlobalFontSize.S, GlobalFontWeight.DEMI_BOLD, FontStyle.REGULAR 67 | M_DEMI_BOLD = GlobalFontSize.M, GlobalFontWeight.DEMI_BOLD, FontStyle.REGULAR 68 | L_DEMI_BOLD = GlobalFontSize.L, GlobalFontWeight.DEMI_BOLD, FontStyle.REGULAR 69 | XL_DEMI_BOLD = GlobalFontSize.XL, GlobalFontWeight.DEMI_BOLD, FontStyle.REGULAR 70 | 71 | S_DEMI_BOLD_ITALIC = GlobalFontSize.S, GlobalFontWeight.DEMI_BOLD, FontStyle.ITALIC 72 | M_DEMI_BOLD_ITALIC = GlobalFontSize.M, GlobalFontWeight.DEMI_BOLD, FontStyle.ITALIC 73 | L_DEMI_BOLD_ITALIC = GlobalFontSize.L, GlobalFontWeight.DEMI_BOLD, FontStyle.ITALIC 74 | XL_DEMI_BOLD_ITALIC = GlobalFontSize.XL, GlobalFontWeight.DEMI_BOLD, FontStyle.ITALIC 75 | 76 | S_BOLD = GlobalFontSize.S, GlobalFontWeight.BOLD, FontStyle.REGULAR 77 | M_BOLD = GlobalFontSize.M, GlobalFontWeight.BOLD, FontStyle.REGULAR 78 | L_BOLD = GlobalFontSize.L, GlobalFontWeight.BOLD, FontStyle.REGULAR 79 | XL_BOLD = GlobalFontSize.XL, GlobalFontWeight.BOLD, FontStyle.REGULAR 80 | 81 | S_BOLD_ITALIC = GlobalFontSize.S, GlobalFontWeight.BOLD, FontStyle.ITALIC 82 | M_BOLD_ITALIC = GlobalFontSize.M, GlobalFontWeight.BOLD, FontStyle.ITALIC 83 | L_BOLD_ITALIC = GlobalFontSize.L, GlobalFontWeight.BOLD, FontStyle.ITALIC 84 | XL_BOLD_ITALIC = GlobalFontSize.XL, GlobalFontWeight.BOLD, FontStyle.ITALIC 85 | -------------------------------------------------------------------------------- /siui/gui/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from .color_group import BrightColorGroup, DarkColorGroup, SiColorGroup 4 | from .font import SiFont 5 | from .icons import GlobalIconPack 6 | from .scale import get_windows_scaling_factor, reload_scale_factor, set_scale_factor 7 | 8 | __all__ = ("SiFont", 9 | "set_scale_factor", "get_windows_scaling_factor", "reload_scale_factor", 10 | "GlobalIconPack", 11 | "BrightColorGroup", "DarkColorGroup", "SiColorGroup") 12 | 13 | -------------------------------------------------------------------------------- /siui/gui/color_group/__init__.py: -------------------------------------------------------------------------------- 1 | from .bright import BrightColorGroup 2 | from .color_group import SiColorGroup 3 | from .dark import DarkColorGroup 4 | 5 | __all__ = ("BrightColorGroup", "SiColorGroup", "DarkColorGroup") 6 | 7 | -------------------------------------------------------------------------------- /siui/gui/color_group/bright.py: -------------------------------------------------------------------------------- 1 | 2 | from siui.core import SiColor 3 | 4 | from .color_group import SiColorGroup 5 | 6 | 7 | class BrightColorGroup(SiColorGroup): 8 | def __init__(self): 9 | super().__init__() 10 | 11 | self.assign(SiColor.THEME, "#2accb3") 12 | self.assign(SiColor.THEME_TRANSITION_A, "#2abed8") 13 | self.assign(SiColor.THEME_TRANSITION_B, "#2ad98e") 14 | 15 | self.assign(SiColor.SVG_NORMAL, "#494f4d") 16 | self.assign(SiColor.SVG_THEME, "#53857d") 17 | 18 | self.assign(SiColor.LAYER_DIM, "#60000000") 19 | 20 | self.assign(SiColor.TOOLTIP_BG, "#eff9f9f9") 21 | 22 | self.assign(SiColor.INTERFACE_BG_A, "#d6d6d6") 23 | self.assign(SiColor.INTERFACE_BG_B, "#dddddd") 24 | self.assign(SiColor.INTERFACE_BG_C, "#e5e5e5") 25 | self.assign(SiColor.INTERFACE_BG_D, "#eeeeee") 26 | self.assign(SiColor.INTERFACE_BG_E, "#f6f6f6") 27 | 28 | self.assign(SiColor.TEXT_A, "#171d1b") 29 | self.assign(SiColor.TEXT_B, "#2e3432") 30 | self.assign(SiColor.TEXT_C, "#363d3b") 31 | self.assign(SiColor.TEXT_D, "#3f4644") 32 | self.assign(SiColor.TEXT_E, "#494f4d") 33 | self.assign(SiColor.TEXT_THEME, "#237165") 34 | 35 | self.assign(SiColor.SIDE_MSG_FLASH, "#90FFFFFF") 36 | self.assign(SiColor.SIDE_MSG_THEME_NORMAL, "#242027") 37 | self.assign(SiColor.SIDE_MSG_THEME_SUCCESS, "#519868") 38 | self.assign(SiColor.SIDE_MSG_THEME_INFO, "#855198") 39 | self.assign(SiColor.SIDE_MSG_THEME_WARNING, "#986351") 40 | self.assign(SiColor.SIDE_MSG_THEME_ERROR, "#98515b") 41 | 42 | self.assign(SiColor.MENU_BG, "#e5e5e5") 43 | 44 | # 标题相关 45 | self.assign(SiColor.TITLE_INDICATOR, "#2accb3") 46 | self.assign(SiColor.TITLE_HIGHLIGHT, "#b4ceca") 47 | 48 | # 按钮鼠标相关 49 | self.assign(SiColor.BUTTON_IDLE, "#00FFFFFF") 50 | self.assign(SiColor.BUTTON_HOVER, "#10FFFFFF") 51 | self.assign(SiColor.BUTTON_FLASH, "#20FFFFFF") 52 | 53 | # 按钮外观 54 | self.assign(SiColor.BUTTON_PANEL, "#f6f6f6") 55 | self.assign(SiColor.BUTTON_SHADOW, SiColor.mix(self.fromToken(SiColor.INTERFACE_BG_C), "#000000", 0.9)) 56 | 57 | self.assign(SiColor.BUTTON_THEMED_BG_A, "#2abed8") 58 | self.assign(SiColor.BUTTON_THEMED_BG_B, "#2ad98e") 59 | self.assign(SiColor.BUTTON_THEMED_SHADOW_A, "#1d8699") 60 | self.assign(SiColor.BUTTON_THEMED_SHADOW_B, "#1d9963") 61 | 62 | self.assign(SiColor.BUTTON_ON, "#372456") 63 | self.assign(SiColor.BUTTON_OFF, "#562b49") 64 | 65 | self.assign(SiColor.RADIO_BUTTON_UNCHECKED, "#211F25") 66 | self.assign(SiColor.RADIO_BUTTON_CHECKED, "#9c65ae") 67 | 68 | self.assign(SiColor.CHECKBOX_SVG, "#1C191F") 69 | self.assign(SiColor.CHECKBOX_UNCHECKED, "#979797") 70 | self.assign(SiColor.CHECKBOX_CHECKED, "#9c65ae") 71 | 72 | self.assign(SiColor.BUTTON_TEXT_BUTTON_IDLE, "#237165") 73 | self.assign(SiColor.BUTTON_TEXT_BUTTON_FLASH, "#237165") 74 | self.assign(SiColor.BUTTON_TEXT_BUTTON_HOVER, "#fabef8") 75 | 76 | # 长按按钮 77 | self.assign(SiColor.BUTTON_LONG_PRESS_PANEL, "#E76856") 78 | self.assign(SiColor.BUTTON_LONG_PRESS_SHADOW, "#a64a3d") 79 | self.assign(SiColor.BUTTON_LONG_PRESS_PROGRESS, "#ff836f") 80 | 81 | # 开关 82 | self.assign(SiColor.SWITCH_DEACTIVATE, "#D2D2D2") 83 | self.assign(SiColor.SWITCH_ACTIVATE, "#100912") 84 | 85 | # 滚动条 86 | self.assign(SiColor.SCROLL_BAR, "#50FFFFFF") 87 | 88 | # 进度条 89 | self.assign(SiColor.PROGRESS_BAR_TRACK, "#d4d4d4") 90 | self.assign(SiColor.PROGRESS_BAR_PROCESSING, "#4183a3") 91 | self.assign(SiColor.PROGRESS_BAR_COMPLETING, "#e3c15b") 92 | self.assign(SiColor.PROGRESS_BAR_PAUSED, "#a8a8a8") 93 | self.assign(SiColor.PROGRESS_BAR_FLASHES, "#9fFFFFFF") 94 | -------------------------------------------------------------------------------- /siui/gui/color_group/color_group.py: -------------------------------------------------------------------------------- 1 | 2 | from siui.core import SiColor 3 | 4 | 5 | class SiColorGroup: 6 | def __getitem__(self, item): 7 | return self.colors[item] 8 | 9 | def __init__(self, 10 | overwrite=None, 11 | reference=None): 12 | 13 | self.valid_state = True 14 | self.colors = {} 15 | 16 | if overwrite is not None: 17 | self.overwrite(overwrite) 18 | if reference is None: 19 | self.reference = overwrite.reference 20 | else: 21 | self.reference = reference 22 | else: 23 | self.reference = reference 24 | 25 | def assign(self, token, code): 26 | self.colors[token.name] = code 27 | 28 | def remove(self, token): 29 | if token.name in self.colors.keys(): 30 | self.colors.pop(token.name) 31 | 32 | def fromToken(self, token): 33 | if token.name in self.colors.keys() and self.valid_state: 34 | return self.colors[token.name] 35 | if self.reference is None: 36 | raise ValueError( 37 | f"Color under token {token.name} is not assigned yet either in this group or in its reference\n" 38 | f"Valid state: {self.valid_state}" 39 | ) 40 | else: 41 | return self.reference.fromToken(token) 42 | 43 | def isAssigned(self, token): 44 | if self.reference is None: 45 | return token.name in self.colors.keys() 46 | else: 47 | return ((token.name in self.colors.keys()) and self.valid_state) or self.reference.isAssigned(token) 48 | 49 | def overwrite(self, color_group): 50 | self.colors.update(color_group.colors) 51 | 52 | def setReference(self, color_group): 53 | self.reference = color_group 54 | 55 | def setValid(self, state): 56 | self.valid_state = state 57 | 58 | def isValid(self): 59 | return self.valid_state 60 | 61 | -------------------------------------------------------------------------------- /siui/gui/color_group/dark.py: -------------------------------------------------------------------------------- 1 | 2 | from siui.core import SiColor 3 | 4 | from .color_group import SiColorGroup 5 | 6 | 7 | class DarkColorGroup(SiColorGroup): 8 | def __init__(self): 9 | super().__init__() 10 | 11 | self.assign(SiColor.THEME, "#855198") 12 | self.assign(SiColor.THEME_TRANSITION_A, "#52389a") 13 | self.assign(SiColor.THEME_TRANSITION_B, "#9c4e8b") 14 | 15 | self.assign(SiColor.SVG_NORMAL, "#DFDFDF") 16 | self.assign(SiColor.SVG_THEME, "#855198") 17 | 18 | self.assign(SiColor.LAYER_DIM, "#60000000") 19 | 20 | self.assign(SiColor.TOOLTIP_BG, "#ef4C4554") 21 | 22 | self.assign(SiColor.INTERFACE_BG_A, "#1C191F") 23 | self.assign(SiColor.INTERFACE_BG_B, "#25222A") 24 | self.assign(SiColor.INTERFACE_BG_C, "#332E38") 25 | self.assign(SiColor.INTERFACE_BG_D, "#403a46") 26 | self.assign(SiColor.INTERFACE_BG_E, "#4C4554") 27 | 28 | self.assign(SiColor.TEXT_A, "#E5E5E5") 29 | self.assign(SiColor.TEXT_B, "#DFDFDF") 30 | self.assign(SiColor.TEXT_C, "#C7C7C7") 31 | self.assign(SiColor.TEXT_D, "#AFAFAF") 32 | self.assign(SiColor.TEXT_E, "#979797") 33 | self.assign(SiColor.TEXT_THEME, "#c58bc2") 34 | 35 | self.assign(SiColor.SIDE_MSG_FLASH, "#90FFFFFF") 36 | self.assign(SiColor.SIDE_MSG_THEME_NORMAL, "#4C4554") 37 | self.assign(SiColor.SIDE_MSG_THEME_SUCCESS, "#519868") 38 | self.assign(SiColor.SIDE_MSG_THEME_INFO, "#855198") 39 | self.assign(SiColor.SIDE_MSG_THEME_WARNING, "#986351") 40 | self.assign(SiColor.SIDE_MSG_THEME_ERROR, "#98515b") 41 | 42 | self.assign(SiColor.MENU_BG, "#332E38") 43 | 44 | # 标题相关 45 | self.assign(SiColor.TITLE_INDICATOR, "#c58bc2") 46 | self.assign(SiColor.TITLE_HIGHLIGHT, "#52324E") 47 | 48 | # 按钮鼠标相关 49 | self.assign(SiColor.BUTTON_IDLE, "#00FFFFFF") 50 | self.assign(SiColor.BUTTON_HOVER, "#10FFFFFF") 51 | self.assign(SiColor.BUTTON_FLASH, "#20FFFFFF") 52 | 53 | # 按钮外观 54 | self.assign(SiColor.BUTTON_PANEL, "#4C4554") 55 | self.assign(SiColor.BUTTON_SHADOW, SiColor.mix(self.fromToken(SiColor.INTERFACE_BG_C), "#000000", 0.9)) 56 | 57 | self.assign(SiColor.BUTTON_THEMED_BG_A, "#52389a") 58 | self.assign(SiColor.BUTTON_THEMED_BG_B, "#9c4e8b") 59 | self.assign(SiColor.BUTTON_THEMED_SHADOW_A, "#372456") 60 | self.assign(SiColor.BUTTON_THEMED_SHADOW_B, "#562b49") 61 | 62 | self.assign(SiColor.BUTTON_ON, "#372456") 63 | self.assign(SiColor.BUTTON_OFF, "#562b49") 64 | 65 | self.assign(SiColor.RADIO_BUTTON_UNCHECKED, "#211F25") 66 | self.assign(SiColor.RADIO_BUTTON_CHECKED, "#9c65ae") 67 | 68 | self.assign(SiColor.CHECKBOX_SVG, "#1C191F") 69 | self.assign(SiColor.CHECKBOX_UNCHECKED, "#979797") 70 | self.assign(SiColor.CHECKBOX_CHECKED, "#9c65ae") 71 | 72 | self.assign(SiColor.BUTTON_TEXT_BUTTON_IDLE, "#c58bc2") 73 | self.assign(SiColor.BUTTON_TEXT_BUTTON_FLASH, "#c58bc2") 74 | self.assign(SiColor.BUTTON_TEXT_BUTTON_HOVER, "#fabef8") 75 | 76 | # 长按按钮 77 | self.assign(SiColor.BUTTON_LONG_PRESS_PANEL, "#932a48") 78 | self.assign(SiColor.BUTTON_LONG_PRESS_SHADOW, "#642d41") 79 | self.assign(SiColor.BUTTON_LONG_PRESS_PROGRESS, "#DA3462") 80 | 81 | # 开关 82 | self.assign(SiColor.SWITCH_DEACTIVATE, "#D2D2D2") 83 | self.assign(SiColor.SWITCH_ACTIVATE, "#100912") 84 | 85 | # 滚动条 86 | self.assign(SiColor.SCROLL_BAR, "#50FFFFFF") 87 | 88 | # 进度条 89 | self.assign(SiColor.PROGRESS_BAR_TRACK, "#252229") 90 | self.assign(SiColor.PROGRESS_BAR_PROCESSING, "#66CBFF") 91 | self.assign(SiColor.PROGRESS_BAR_COMPLETING, "#FED966") 92 | self.assign(SiColor.PROGRESS_BAR_PAUSED, "#7F7F7F") 93 | self.assign(SiColor.PROGRESS_BAR_FLASHES, "#FFFFFF") 94 | -------------------------------------------------------------------------------- /siui/gui/font.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from PyQt5.QtGui import QFont 6 | from PyQt5.QtWidgets import qApp 7 | 8 | from siui.core.token import FontStyle, GlobalFont, GlobalFontSize, GlobalFontWeight 9 | 10 | if TYPE_CHECKING: 11 | from collections.abc import Sequence 12 | 13 | 14 | class SiFont: 15 | """SiUI Font Class 16 | 17 | You can use low-level API to customize fonts details, 18 | or use tokenized global fonts to quickly create fonts. 19 | """ 20 | Weight = QFont.Weight 21 | 22 | @staticmethod 23 | def getFont( 24 | families=None, 25 | size: int = 14, 26 | weight: QFont.Weight = QFont.Weight.Normal, 27 | italic: bool = False, 28 | hinting_preference: QFont.HintingPreference = QFont.PreferFullHinting 29 | ) -> QFont: 30 | """Low-level API for creating font instance 31 | 32 | Application-level configuration takes the highest priority, 33 | and it is recommended to use the tokenized Hier-level API. 34 | 35 | Args: 36 | - families: 字体族列表,如果指定了应用程序级别的全局配置,则会覆盖默认字体家族 37 | - size: 字体大小 38 | - weight: 字体粗细 39 | - italic: 是否斜体 40 | - hinting_preference: 字体 Hinting 偏好, 默认为 PreferFullHinting 41 | 42 | Returns: 43 | - QFont: 字体实例 44 | 45 | """ 46 | if families is None: 47 | families = ( 48 | qApp.font().families() or 49 | ["Segoe UI", "Microsoft YaHei", "San Francisco Fonts", ".PingFang TC", "PingFang SC"] 50 | ) 51 | 52 | font = QFont() 53 | font.setFamilies(families) 54 | font.setPixelSize(size) 55 | font.setWeight(weight) 56 | font.setItalic(italic) 57 | font.setHintingPreference(hinting_preference) 58 | return font 59 | 60 | @staticmethod 61 | def fromToken(size: GlobalFontSize, weight: GlobalFontWeight, style: FontStyle) -> QFont: 62 | """通过已经令牌化的字体属性构造字体""" 63 | 64 | return SiFont.getFont(size=size.value, weight=weight.value, italic=style == FontStyle.ITALIC) 65 | 66 | @staticmethod 67 | def tokenized(token: GlobalFont) -> QFont: 68 | """返回一个已经被令牌化的全局字体""" 69 | 70 | try: 71 | return SiFont.fromToken(*token.value) 72 | except KeyError: 73 | raise ValueError(f"Invalid token: {token}") 74 | -------------------------------------------------------------------------------- /siui/gui/icons/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import GlobalIconPack 2 | 3 | __all__ = ("GlobalIconPack",) 4 | -------------------------------------------------------------------------------- /siui/gui/icons/parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PyQt5.QtCore import QByteArray, QSize, Qt 4 | from PyQt5.QtGui import QPainter, QPixmap, QIcon 5 | from PyQt5.QtSvg import QSvgRenderer 6 | 7 | 8 | class GlobalIconPack: 9 | current_module_path = os.path.dirname(os.path.abspath(__file__)) 10 | package_folder_path = os.path.join(current_module_path, "packages") 11 | 12 | def __init__(self): 13 | self.default_color = None 14 | 15 | self.icons = {} 16 | self.icons_classified = { 17 | "__unclassified__": {} 18 | } 19 | 20 | # load internal icon packages 21 | self.reload_internals() 22 | 23 | def setDefaultColor(self, code) -> None: 24 | self.default_color = code 25 | 26 | @property 27 | def defaultColor(self) -> str: 28 | return self.default_color 29 | 30 | def reload_internals(self) -> None: 31 | for package_filename in os.listdir(self.package_folder_path): 32 | full_path = os.path.join(self.package_folder_path, package_filename) 33 | if os.path.isfile(full_path): 34 | self.load_from_file(full_path) 35 | 36 | def load_from_file(self, path) -> None: 37 | class_name = os.path.basename(path) 38 | self.append_class(class_name) 39 | with open(path, encoding="utf-8") as file: 40 | for line in file.readlines(): 41 | if line[0:2] == "##": 42 | continue 43 | if line.strip() == "": 44 | continue 45 | 46 | line = line.strip() 47 | icon_name, icon_data = line.split("////") 48 | self.append(icon_name, icon_data, class_name) 49 | 50 | def append_class(self, class_name, force=False) -> None: 51 | if class_name in self.icons_classified.keys() and (force is False): 52 | raise ValueError(f"Class name {class_name} is already exist.") 53 | self.icons_classified[class_name] = {} 54 | 55 | def append(self, name, data, class_name: str = "__unclassified__") -> None: 56 | self.icons[name] = data 57 | self.icons_classified[class_name][name] = data 58 | 59 | def get(self, name, color_code: str = None) -> bytes: 60 | color_code = self.default_color if color_code is None else color_code 61 | return self.icons[name].replace("<<>>", color_code).encode() 62 | 63 | def getFromData(self, data, color_code: str = None) -> bytes: 64 | color_code = self.default_color if color_code is None else color_code 65 | return data.replace("<<>>", color_code).encode() 66 | 67 | def getByteArray(self, name, color_code: str = None) -> QByteArray: 68 | svg_bytes = self.get(name, color_code) 69 | return QByteArray(svg_bytes) 70 | 71 | def getDict(self, class_name=None) -> dict: 72 | """ 73 | Get dictionary of an icon package. 74 | If class name is assigned, returns the specific package dictionary. 75 | If class name is None, returns a dictionary that contains all icons. 76 | """ 77 | if class_name is None: 78 | return self.icons 79 | else: 80 | return self.icons_classified[class_name] 81 | 82 | def getClassNames(self) -> dict.keys: 83 | return self.icons_classified.keys() 84 | 85 | def toPixmap(self, name: str, size: QSize = QSize(64, 64), color_code: str = None): 86 | svg_bytes = self.get(name, color_code) 87 | pixmap = QPixmap(size) 88 | pixmap.fill(Qt.transparent) 89 | painter = QPainter(pixmap) 90 | painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform) 91 | svg_renderer = QSvgRenderer(svg_bytes) 92 | svg_renderer.render(painter) 93 | painter.end() 94 | return pixmap 95 | 96 | def toIcon(self, name: str, size: QSize = QSize(64, 64), color_code: str = None) -> QIcon: 97 | return QIcon(self.toPixmap(name, size, color_code)) 98 | 99 | -------------------------------------------------------------------------------- /siui/gui/scale.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | 4 | 5 | def get_windows_scaling_factor(): 6 | try: 7 | # 调用 Windows API 函数获取缩放比例 8 | user32 = ctypes.windll.user32 9 | user32.SetProcessDPIAware() 10 | scaling_factor = user32.GetDpiForSystem() 11 | 12 | # 计算缩放比例 13 | return scaling_factor / 96.0 14 | 15 | except Exception as e: 16 | print("无法获取缩放比例,设置为1,错误:", e) 17 | return 1 18 | 19 | 20 | def reload_scale_factor(): 21 | set_scale_factor(get_windows_scaling_factor(), identity="Windows API") 22 | 23 | 24 | def set_scale_factor(factor, identity="External calls"): 25 | os.environ["QT_SCALE_FACTOR"] = str(factor) 26 | print("已将环境变量 QT_SCALE_FACTOR 设为", factor, f" (来源: {identity})") 27 | -------------------------------------------------------------------------------- /siui/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/application.py: -------------------------------------------------------------------------------- 1 | 2 | from PyQt5.QtWidgets import QMainWindow 3 | 4 | from siui.components.tooltip import ToolTipWindow 5 | from siui.components.widgets.abstracts import SiWidget 6 | from siui.core import SiGlobal 7 | from siui.templates.application.components.layer.layer_child_page.layer_child_page import LayerChildPage 8 | from siui.templates.application.components.layer.layer_left_global_drawer.layer_left_global_drawer import ( 9 | LayerLeftGlobalDrawer, 10 | ) 11 | from siui.templates.application.components.layer.layer_main.layer_main import LayerMain 12 | from siui.templates.application.components.layer.layer_modal_dialog.layer_modal_dialog import LayerModalDialog 13 | from siui.templates.application.components.layer.layer_overlays.layer_overlays import LayerOverLays 14 | from siui.templates.application.components.layer.layer_right_message_sidebar.layer_right_message_sidebar import ( 15 | LayerRightMessageSidebar, 16 | ) 17 | 18 | 19 | class SiliconApplication(QMainWindow): 20 | """ 21 | SiliconUI 应用程序模板,包含工具提示窗口 22 | """ 23 | def __init__(self, *args, **kwargs): 24 | super().__init__(*args, **kwargs) 25 | 26 | # 添加全局窗口 27 | SiGlobal.siui.windows["MAIN_WINDOW"] = self 28 | SiGlobal.siui.windows["TOOL_TIP"] = ToolTipWindow() 29 | SiGlobal.siui.windows["TOOL_TIP"].show() 30 | SiGlobal.siui.windows["TOOL_TIP"].setOpacity(0) 31 | 32 | # 初始化窗口 33 | self.resize(1200, 700) 34 | self.setWindowTitle("Silicon Application Template") 35 | 36 | # 层的组 37 | self.group_main_interface = SiWidget(self) 38 | self.groups_ = { 39 | "MAIN_INTERFACE": self.group_main_interface 40 | } 41 | 42 | # 构建界面 43 | self.layer_main = LayerMain(self.group_main_interface) 44 | self.layer_child_page = LayerChildPage(self.group_main_interface) 45 | 46 | self.layer_left_global_drawer = LayerLeftGlobalDrawer(self) 47 | self.layer_right_message_sidebar = LayerRightMessageSidebar(self) 48 | self.layer_modal_dialog = LayerModalDialog(self) 49 | self.layer_overlays = LayerOverLays(self) 50 | 51 | def groups(self): 52 | return self.groups_ 53 | 54 | def layerMain(self): 55 | return self.layer_main 56 | 57 | def LayerRightMessageSidebar(self): 58 | return self.layer_right_message_sidebar 59 | 60 | def layerChildPage(self): 61 | return self.layer_child_page 62 | 63 | def layerModalDialog(self): 64 | return self.layer_modal_dialog 65 | 66 | def layerLeftGlobalDrawer(self): 67 | return self.layer_left_global_drawer 68 | 69 | def resizeEvent(self, event): 70 | super().resizeEvent(event) 71 | size = event.size() 72 | w, h = size.width(), size.height() 73 | 74 | self.group_main_interface.resize(w, h) 75 | 76 | # Set the maximum height of the sidebar to prevent performance from dropping when too many message boxes exist. 77 | self.layer_right_message_sidebar.setMaximumHeight(event.size().height()) 78 | self.layer_right_message_sidebar.adjustSize() 79 | 80 | self.layer_main.resize(event.size()) 81 | self.layer_child_page.resize(event.size()) 82 | self.layer_right_message_sidebar.setGeometry(w - 400, 80, 400, self.layer_right_message_sidebar.height()) 83 | self.layer_modal_dialog.resize(event.size()) 84 | self.layer_left_global_drawer.resize(event.size()) 85 | self.layer_overlays.resize(event.size()) 86 | -------------------------------------------------------------------------------- /siui/templates/application/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/dialog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/dialog/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/dialog/modal.py: -------------------------------------------------------------------------------- 1 | from siui.components import SiWidget, SiLabel, SiSvgLabel, SiDenseVContainer 2 | from siui.core import SiColor 3 | from siui.core import SiGlobal 4 | 5 | 6 | class SiModalDialog(SiWidget): 7 | def __init__(self, *args, **kwargs): 8 | super().__init__(*args, **kwargs) 9 | 10 | self.body_padding_h = 43 11 | self.theme_padding_h = 26 12 | self.content_padding_v = 32 13 | self.button_padding_v = 24 14 | self.theme_label_top_height = 2 15 | self.theme_label_bottom_height = 0 16 | self.setFixedWidth(460) 17 | 18 | self.theme_label = SiLabel(self) 19 | self.theme_label.setFixedStyleSheet("border-radius: 8px") 20 | self.theme_label.setColor(self.getColor(SiColor.THEME)) 21 | 22 | self.body_content_label = SiLabel(self) 23 | self.body_content_label.setObjectName("body_content_label") 24 | 25 | self.body_button_label = SiLabel(self) 26 | self.body_button_label.setObjectName("body_button_label") 27 | 28 | self.content_container = SiDenseVContainer(self.body_content_label) 29 | self.content_container.setAdjustWidgetsSize(True) 30 | 31 | self.button_container = SiDenseVContainer(self.body_button_label) 32 | self.button_container.setAdjustWidgetsSize(True) 33 | self.button_container.setSpacing(8) 34 | 35 | self.icon_ = SiSvgLabel(self.content_container) 36 | self.icon_.resize(64, 64) 37 | self.icon_.setSvgSize(64, 64) 38 | 39 | def icon(self): 40 | return self.icon_ 41 | 42 | def contentContainer(self): 43 | return self.content_container 44 | 45 | def buttonContainer(self): 46 | return self.button_container 47 | 48 | def reloadStyleSheet(self): 49 | super().reloadStyleSheet() 50 | self.theme_label.setColor(self.getColor(SiColor.THEME)) 51 | self.body_content_label.setStyleSheet( 52 | "#body_content_label {" 53 | " border-radius: 8px;" 54 | f" background-color: {self.getColor(SiColor.INTERFACE_BG_B)};" 55 | f" border: 1px solid {self.getColor(SiColor.INTERFACE_BG_C)};" 56 | "}" 57 | ) 58 | self.body_button_label.setStyleSheet( 59 | "#body_button_label {" 60 | " border-radius: 8px;" 61 | f" background-color: {self.getColor(SiColor.INTERFACE_BG_C)};" 62 | f" border: 1px solid {self.getColor(SiColor.INTERFACE_BG_C)};" 63 | "}" 64 | 65 | ) 66 | 67 | def adjustSize(self): 68 | self.content_container.setFixedWidth(self.width() - 2 * self.body_padding_h) 69 | self.button_container.setFixedWidth(self.width() - 2 * self.body_padding_h) 70 | self.content_container.adjustSize() 71 | self.button_container.adjustSize() 72 | 73 | self.body_content_label.setGeometry( 74 | 0, 75 | self.theme_label_top_height, 76 | self.width(), 77 | self.content_container.height() + 2 * self.content_padding_v + self.button_container.height() + 2 * self.button_padding_v 78 | ) 79 | 80 | self.body_button_label.setGeometry( 81 | 0, 82 | self.theme_label_top_height + self.content_container.height() + 2 * self.content_padding_v, 83 | self.width(), 84 | self.button_container.height() + 2 * self.button_padding_v 85 | ) 86 | 87 | self.content_container.move(self.body_padding_h, self.content_padding_v) 88 | self.button_container.move(self.body_padding_h, self.button_padding_v) 89 | self.theme_label.setGeometry( 90 | self.theme_padding_h, 91 | 0, 92 | self.width() - 2 * self.theme_padding_h, 93 | self.content_container.height() + 2 * self.content_padding_v + self.button_container.height() + 2 * self.button_padding_v + self.theme_label_top_height + self.theme_label_bottom_height 94 | ) 95 | self.icon_.move(self.content_container.width() - self.icon_.width(), 0) 96 | self.resize(self.width(), self.theme_label.height()) 97 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/global_drawer.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | from PyQt5.QtWidgets import QWidget 3 | 4 | from siui.components import SiLabel, SiWidget, SiTitledWidgetGroup 5 | from siui.components.page import SiPage 6 | from siui.templates.application.components.layer.layer import SiLayer 7 | 8 | 9 | class Drawer(SiWidget): 10 | def resizeEvent(self, event): 11 | super().resizeEvent(event) 12 | for child in self.children(): 13 | if isinstance(child, QWidget): 14 | child.resize(event.size()) 15 | 16 | 17 | class SiLayerDrawer(SiLayer): 18 | def __init__(self, *args, **kwargs): 19 | super().__init__(*args, **kwargs) 20 | 21 | self.is_opened = False 22 | 23 | self.drawer = Drawer(self) 24 | self.drawer_panel = SiLabel(self.drawer) 25 | self.drawer_page = SiPage(self.drawer) 26 | 27 | self.setDrawerWidth(400) 28 | self.closeLayer() 29 | 30 | def isOpened(self): 31 | return self.is_opened 32 | 33 | def setOpened(self, state): 34 | self.is_opened = state 35 | 36 | def setDrawerWidth(self, width): 37 | self.drawer.resize(width, self.drawer.height()) 38 | 39 | def showLayer(self): 40 | super().showLayer() 41 | self.setAttribute(Qt.WA_TransparentForMouseEvents, False) 42 | self.setOpened(True) 43 | 44 | def closeLayer(self): 45 | super().closeLayer() 46 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 47 | self.setOpened(False) 48 | 49 | def resizeEvent(self, event): 50 | super().resizeEvent(event) 51 | self.drawer.resize(self.drawer.width(), event.size().height()) 52 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, pyqtSignal 2 | 3 | from siui.components.widgets.abstracts.widget import SiWidget 4 | from siui.components.widgets.label import SiLabel 5 | from siui.core import SiColor 6 | 7 | 8 | class SiLabelHasClickedSignal(SiLabel): 9 | clicked = pyqtSignal() 10 | 11 | def mousePressEvent(self, event): 12 | super().mousePressEvent(event) 13 | if event.button() == Qt.LeftButton: 14 | self.clicked.emit() 15 | event.accept() 16 | 17 | 18 | class SiLayer(SiWidget): 19 | closed = pyqtSignal() 20 | showed = pyqtSignal() 21 | 22 | def __init__(self, *args, **kwargs): 23 | super().__init__(*args, **kwargs) 24 | 25 | self.close_on_dim_clicked = True 26 | 27 | self.dim_ = SiLabelHasClickedSignal(self) 28 | self.dim_.setColor(SiColor.trans(self.getColor(SiColor.LAYER_DIM), 0.0)) 29 | self.dim_.clicked.connect(self.on_dim_layer_clicked) 30 | 31 | def setCloseOnDimClicked(self, on): 32 | self.close_on_dim_clicked = on 33 | 34 | def on_dim_layer_clicked(self): 35 | if self.close_on_dim_clicked is True: 36 | self.closeLayer() 37 | 38 | def closeLayer(self): 39 | self.closed.emit() 40 | self.hideDimMask() 41 | 42 | def showLayer(self): 43 | self.showed.emit() 44 | self.show() 45 | self.showDimMask() 46 | 47 | def showDimMask(self, ani=True): 48 | if ani is True: 49 | self.dim_.setColorTo(SiColor.trans(self.getColor(SiColor.LAYER_DIM), 1.0)) 50 | else: 51 | self.dim_.setColor(SiColor.trans(self.getColor(SiColor.LAYER_DIM), 1.0)) 52 | 53 | def hideDimMask(self, ani=True): 54 | if ani is True: 55 | self.dim_.setColorTo(SiColor.trans(self.getColor(SiColor.LAYER_DIM), 0.0)) 56 | else: 57 | self.dim_.setColor(SiColor.trans(self.getColor(SiColor.LAYER_DIM), 0.0)) 58 | 59 | def resizeEvent(self, event): 60 | super().resizeEvent(event) 61 | self.dim_.resize(event.size()) 62 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_child_page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_child_page/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_child_page/layer_child_page.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, QTimer 2 | 3 | from ..layer import SiLayer 4 | 5 | 6 | class LayerChildPage(SiLayer): 7 | def __init__(self, *args, **kwargs): 8 | super().__init__(*args, **kwargs) 9 | 10 | self.child_page = None 11 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 12 | 13 | def childPage(self): 14 | return self.child_page 15 | 16 | def setChildPage(self, page): 17 | if self.childPage() is not None: 18 | page.deleteLater() 19 | return 20 | 21 | self.child_page = page 22 | self.child_page.animationGroup().fromToken("move").setFactor(1/4) 23 | self.child_page.animationGroup().fromToken("move").setBias(0.5) 24 | self.child_page.setParent(self) 25 | self.child_page.adjustSize() 26 | self.child_page.move((self.width() - self.childPage().width()) // 2, self.height()) 27 | self.child_page.show() 28 | self.showLayer() 29 | 30 | def showLayer(self): 31 | super().showLayer() 32 | self.showChildPage() 33 | 34 | def closeLayer(self): 35 | super().closeLayer() 36 | self.closeChildPage() 37 | 38 | def showChildPage(self): 39 | self.setAttribute(Qt.WA_TransparentForMouseEvents, False) 40 | self.child_page.moveTo((self.width() - self.childPage().width()) // 2, self.height() - self.childPage().height()) 41 | 42 | def closeChildPage(self): 43 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 44 | self.child_page.moveTo((self.width() - self.childPage().width()) // 2, self.height()) 45 | self.child_page.delete_timer = QTimer() 46 | self.child_page.delete_timer.singleShot(500, self.child_page.deleteLater) 47 | self.child_page = None 48 | 49 | def resizeEvent(self, event): 50 | super().resizeEvent(event) 51 | if self.child_page is not None: 52 | self.child_page.adjustSize() 53 | self.child_page.move((self.width() - self.childPage().width()) // 2, self.height() - self.childPage().height()) 54 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_left_global_drawer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_left_global_drawer/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_left_global_drawer/layer_left_global_drawer.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import SiLabel, SiTitledWidgetGroup, SiWidget 4 | from siui.components.slider.slider import SiSliderH 5 | from siui.components.combobox import SiComboBox 6 | from siui.core import SiColor 7 | from siui.core import SiGlobal 8 | 9 | from ..global_drawer import SiLayerDrawer 10 | 11 | 12 | class LayerLeftGlobalDrawer(SiLayerDrawer): 13 | def __init__(self, *args, **kwargs): 14 | super().__init__(*args, **kwargs) 15 | self.drawer.move(-self.drawer.width(), 0) 16 | 17 | self.drawer_widget_group = SiTitledWidgetGroup(self) 18 | self.drawer_widget_group.setSpacing(8) 19 | 20 | self.drawer_page.setPadding(48) 21 | self.drawer_page.setTitle("全局左侧抽屉") 22 | self.drawer_page.title.setContentsMargins(32, 0, 0, 0) 23 | self.drawer_page.setScrollAlignment(Qt.AlignLeft) 24 | 25 | with self.drawer_widget_group as group: 26 | group.addTitle("全局性") 27 | 28 | self.text_label = SiLabel(self) 29 | self.text_label.setTextColor(self.getColor(SiColor.TEXT_D)) 30 | self.text_label.setWordWrap(True) 31 | self.text_label.setText("这里是全局抽屉,无论在何种情况下,该抽屉被打开时都会令界面发生侧移,保证抽屉正常展开\n\n" 32 | "不同于其他页面,全局抽屉推荐为唯一的,全局抽屉中的控件推荐为静态的") 33 | self.text_label.setFixedHeight(128) 34 | 35 | group.addWidget(self.text_label) 36 | 37 | with self.drawer_widget_group as group: 38 | group.addTitle("声音") 39 | 40 | self.label_output_device = SiLabel(self) 41 | self.label_output_device.setTextColor(self.getColor(SiColor.TEXT_C)) 42 | self.label_output_device.setText("输出设备") 43 | 44 | self.demo_output_device = SiComboBox(self) 45 | self.demo_output_device.resize(256, 32) 46 | self.demo_output_device.addOption("默认设备") 47 | self.demo_output_device.addOption("RealTek(R) Output") 48 | self.demo_output_device.addOption("姬霓太美(R) Output") 49 | self.demo_output_device.menu().setShowIcon(False) 50 | self.demo_output_device.menu().setIndex(0) 51 | 52 | self.label_slider_1 = SiLabel(self) 53 | self.label_slider_1.setTextColor(self.getColor(SiColor.TEXT_C)) 54 | self.label_slider_1.setText("总音量") 55 | 56 | self.demo_slider_1 = SiSliderH(self) 57 | self.demo_slider_1.resize(0, 16) 58 | self.demo_slider_1.setMinimum(0) 59 | self.demo_slider_1.setMaximum(100) 60 | self.demo_slider_1.setValue(80, move_to=False) 61 | 62 | self.label_slider_2 = SiLabel(self) 63 | self.label_slider_2.setTextColor(self.getColor(SiColor.TEXT_C)) 64 | self.label_slider_2.setText("音乐音量") 65 | 66 | self.demo_slider_2 = SiSliderH(self) 67 | self.demo_slider_2.resize(0, 16) 68 | self.demo_slider_2.setMinimum(0) 69 | self.demo_slider_2.setMaximum(100) 70 | self.demo_slider_2.setValue(100, move_to=False) 71 | 72 | self.label_slider_3 = SiLabel(self) 73 | self.label_slider_3.setTextColor(self.getColor(SiColor.TEXT_C)) 74 | self.label_slider_3.setText("音效音量") 75 | 76 | self.demo_slider_3 = SiSliderH(self) 77 | self.demo_slider_3.resize(0, 16) 78 | self.demo_slider_3.setMinimum(0) 79 | self.demo_slider_3.setMaximum(100) 80 | self.demo_slider_3.setValue(61, move_to=False) 81 | 82 | group.addWidget(self.label_output_device) 83 | group.addWidget(self.demo_output_device) 84 | group.addPlaceholder(8) 85 | group.addWidget(self.label_slider_1) 86 | group.addWidget(self.demo_slider_1) 87 | group.addPlaceholder(8) 88 | group.addWidget(self.label_slider_2) 89 | group.addWidget(self.demo_slider_2) 90 | group.addPlaceholder(8) 91 | group.addWidget(self.label_slider_3) 92 | group.addWidget(self.demo_slider_3) 93 | 94 | group.addPlaceholder(64) 95 | 96 | self.drawer_page.setAttachment(self.drawer_widget_group) 97 | 98 | def setOpened(self, state): 99 | super().setOpened(state) 100 | if state: 101 | self.drawer.moveTo(0, 0) 102 | else: 103 | self.drawer.moveTo(-self.drawer.width(), 0) 104 | 105 | def reloadStyleSheet(self): 106 | super().reloadStyleSheet() 107 | self.drawer_panel.setStyleSheet( 108 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_C)};" 109 | f"border-right: 1px solid {self.getColor(SiColor.INTERFACE_BG_D)}" 110 | ) 111 | 112 | def showLayer(self): 113 | super().showLayer() 114 | SiGlobal.siui.windows["MAIN_WINDOW"].groups()["MAIN_INTERFACE"].moveTo(100, 0) 115 | 116 | def closeLayer(self): 117 | super().closeLayer() 118 | SiGlobal.siui.windows["MAIN_WINDOW"].groups()["MAIN_INTERFACE"].moveTo(0, 0) 119 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_main/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_main/layer_main.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import SiDenseHContainer, SiDenseVContainer, SiLabel, SiPixLabel 4 | from siui.core import GlobalFont, Si, SiColor 5 | from siui.gui import SiFont 6 | from siui.templates.application.components.page_view import PageView 7 | 8 | from ..layer import SiLayer 9 | 10 | 11 | class LayerMain(SiLayer): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | 15 | # 整个窗口的垫底标签 16 | self.background_label = SiLabel(self) 17 | self.background_label.setFixedStyleSheet("border-radius: 8px") 18 | 19 | # -> 垂直容器,上方是标题,下方是窗口内容 20 | self.container_title_and_content = SiDenseVContainer(self) 21 | self.container_title_and_content.setSpacing(0) 22 | self.container_title_and_content.setAdjustWidgetsSize(True) 23 | 24 | # -> 标题栏处的水平容器,左侧是图标和标题,右侧是操作按钮 25 | self.container_title = SiDenseHContainer(self) 26 | self.container_title.setSpacing(0) 27 | self.container_title.setAlignment(Qt.AlignCenter) 28 | self.container_title.setFixedHeight(64) 29 | 30 | # 应用内图标 31 | self.app_icon = SiPixLabel(self) 32 | self.app_icon.resize(24, 24) 33 | self.app_icon.load("./img/logo_new.png") 34 | 35 | # 应用标题 36 | self.app_title = SiLabel(self) 37 | self.app_title.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) 38 | self.app_title.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 39 | self.app_title.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 40 | self.app_title.setText("Silicon 应用模版") 41 | 42 | self.container_title.addPlaceholder(2) 43 | self.container_title.addPlaceholder(16) 44 | self.container_title.addWidget(self.app_icon) 45 | self.container_title.addPlaceholder(16) 46 | self.container_title.addWidget(self.app_title) 47 | 48 | self.page_view = PageView(self) 49 | 50 | # <- 添加到垂直容器 51 | self.container_title_and_content.addWidget(self.container_title) 52 | self.container_title_and_content.addWidget(self.page_view) 53 | 54 | # 隐藏阴影层,因为没有任何用 55 | self.dim_.hide() 56 | 57 | def reloadStyleSheet(self): 58 | self.background_label.setStyleSheet( 59 | f"background-color: {self.getColor(SiColor.INTERFACE_BG_A)};" 60 | f"border: 1px solid {self.getColor(SiColor.INTERFACE_BG_B)};" 61 | ) 62 | self.app_title.setStyleSheet(f"color: {self.getColor(SiColor.TEXT_B)}") 63 | 64 | def setTitle(self, title): 65 | self.app_title.setText(title) 66 | 67 | def addPage(self, page, icon, hint: str, side="top"): 68 | """ 69 | 添加新页面 70 | :param page: 页面控件 71 | :param icon: 页面按钮的 svg 数据或路径 72 | :param hint: 页面按钮的工具提示 73 | :param side: 页面按钮置于哪一侧 74 | """ 75 | self.page_view.addPage(page, icon, hint, side) 76 | 77 | def setPage(self, index): 78 | """ Set current page by index """ 79 | self.page_view.stacked_container.setCurrentIndex(index) 80 | 81 | def resizeEvent(self, event): 82 | super().resizeEvent(event) 83 | self.background_label.resize(event.size()) 84 | self.container_title_and_content.resize(event.size()) 85 | self.page_view.resize(event.size().width(), event.size().height() - 64) 86 | self.dim_.resize(event.size()) 87 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_modal_dialog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_modal_dialog/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_modal_dialog/layer_modal_dialog.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt 2 | 3 | from siui.components import SiWidget 4 | from siui.core import Si 5 | 6 | from ..layer import SiLayer 7 | 8 | 9 | class LayerModalDialog(SiLayer): 10 | def __init__(self, *args, **kwargs): 11 | super().__init__(*args, **kwargs) 12 | 13 | self.dialog_ = None 14 | self.dialog_frame = SiWidget(self) 15 | self.dialog_frame.hideCenterWidgetFadeOut() 16 | self.dialog_frame.animationGroup().fromToken("showing").setBias(0.08) 17 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 18 | 19 | def dialog(self): 20 | return self.dialog_ 21 | 22 | def setDialog(self, dialog): 23 | if self.dialog() is not None: 24 | return 25 | 26 | self.dialog_ = dialog 27 | self.dialog_.show() 28 | self.dialog_frame.setCenterWidget(self.dialog_) 29 | self.showLayer() 30 | 31 | def showLayer(self): 32 | super().showLayer() 33 | self.showDialog() 34 | 35 | def closeLayer(self): 36 | super().closeLayer() 37 | self.closeDialog() 38 | 39 | def showDialog(self): 40 | self.setAttribute(Qt.WA_TransparentForMouseEvents, False) 41 | self.dialog_frame.setSiliconWidgetFlag(Si.DeleteCenterWidgetOnCenterWidgetHidden, False) 42 | self.dialog_frame.showCenterWidgetFadeIn() 43 | 44 | def closeDialog(self): 45 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 46 | self.dialog_frame.hideCenterWidgetFadeOut() 47 | self.dialog_frame.setSiliconWidgetFlag(Si.DeleteCenterWidgetOnCenterWidgetHidden) 48 | self.dialog_ = None 49 | 50 | def resizeEvent(self, event): 51 | super().resizeEvent(event) 52 | self.dialog_frame.resize(event.size()) 53 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_overlays/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_overlays/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_overlays/layer_overlays.py: -------------------------------------------------------------------------------- 1 | from PyQt5.QtCore import Qt, QTimer 2 | from PyQt5.QtGui import QFont 3 | from PyQt5.QtWidgets import QGraphicsOpacityEffect 4 | 5 | from siui.components import SiDenseVContainer, SiLabel 6 | from siui.components.widgets.expands import SiVExpandWidget 7 | from siui.core import Si, SiColor, SiExpAccelerateAnimation, SiQuickEffect, SiGlobal 8 | from siui.gui import SiFont 9 | 10 | from ..layer import SiLayer 11 | 12 | 13 | class DenseVContainerBG(SiDenseVContainer): 14 | def __init__(self, *args, **kwargs): 15 | super().__init__(*args, **kwargs) 16 | 17 | self.background = SiLabel(self) 18 | self.background.setFixedStyleSheet("border-radius: 12px") 19 | self.background.setColor(SiColor.trans(self.getColor(SiColor.INTERFACE_BG_A), 0.9)) 20 | 21 | def resizeEvent(self, event): 22 | super().resizeEvent(event) 23 | self.background.resize(event.size()) 24 | 25 | 26 | class StateChangeOverlay(SiVExpandWidget): 27 | def __init__(self, *args, **kwargs): 28 | super().__init__(*args, **kwargs) 29 | 30 | self.container = DenseVContainerBG(self) 31 | 32 | self.title = SiLabel(self) 33 | self.title.setFont(SiFont.getFont(size=18, weight=QFont.Weight.Normal)) 34 | self.title.setTextColor(self.getColor(SiColor.TEXT_B)) 35 | self.title.setAlignment(Qt.AlignCenter) 36 | self.title.setFixedHeight(24) 37 | self.title.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 38 | 39 | self.subtitle = SiLabel(self) 40 | self.subtitle.setFont(SiFont.getFont(size=15, weight=QFont.Weight.DemiBold)) 41 | self.subtitle.setTextColor(self.getColor(SiColor.TEXT_THEME)) 42 | self.subtitle.setAlignment(Qt.AlignCenter) 43 | self.subtitle.setFixedHeight(16) 44 | self.subtitle.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 45 | 46 | self.div = SiLabel(self) 47 | self.div.setFixedStyleSheet("border-radius: 1px") 48 | self.div.resize(168, 2) 49 | self.div.setColor("#20FFFFFF") 50 | 51 | self.tip = SiLabel(self) 52 | self.tip.setFont(SiFont.getFont(size=12, weight=QFont.Weight.Normal)) 53 | self.tip.setTextColor(self.getColor(SiColor.TEXT_C)) 54 | self.tip.setAlignment(Qt.AlignCenter) 55 | self.tip.setFixedHeight(16) 56 | self.tip.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 57 | 58 | self.container.setSpacing(0) 59 | self.container.setAlignment(Qt.AlignCenter) 60 | self.container.addPlaceholder(16) 61 | self.container.addWidget(self.title) 62 | self.container.addPlaceholder(4) 63 | self.container.addWidget(self.subtitle) 64 | self.container.addPlaceholder(16) 65 | self.container.addWidget(self.div) 66 | self.container.addPlaceholder(10) 67 | self.container.addWidget(self.tip) 68 | 69 | self.setAttachment(self.container) 70 | 71 | self.fade_out_timer = QTimer(self) 72 | self.fade_out_timer.setSingleShot(True) 73 | self.fade_out_timer.setInterval(2000) 74 | self.fade_out_timer.timeout.connect(lambda: self.expandTo(0)) 75 | self.fade_out_timer.timeout.connect(lambda: self.setOpacityTo(0)) 76 | 77 | self.animationGroup().fromToken("expand").setAccelerateFunction(lambda x: (x / 10) ** 5) 78 | 79 | self.animation_opacity = SiExpAccelerateAnimation(self) 80 | self.animation_opacity.setAccelerateFunction(lambda x: (x / 10) ** 3) 81 | self.animation_opacity.setFactor(1/2) 82 | self.animation_opacity.setBias(0.01) 83 | self.animation_opacity.setCurrent(1) 84 | self.animation_opacity.setTarget(1) 85 | self.animation_opacity.ticked.connect(self.on_opacity_changed) 86 | 87 | def on_opacity_changed(self, opacity): 88 | effect = QGraphicsOpacityEffect() 89 | effect.setOpacity(opacity) 90 | self.setGraphicsEffect(effect) 91 | 92 | def emerge(self): 93 | self.expandTo(1) 94 | self.setOpacityTo(1) 95 | self.animation_opacity.start() 96 | self.fade_out_timer.start() 97 | 98 | def resizeEvent(self, event): 99 | super().resizeEvent(event) 100 | 101 | def setContent(self, title, subtitle, tip, emerge=True): 102 | self.title.setText(title) 103 | self.subtitle.setText(subtitle) 104 | self.tip.setText(tip) 105 | if emerge: 106 | self.emerge() 107 | 108 | 109 | class LayerOverLays(SiLayer): 110 | def __init__(self, *args, **kwargs): 111 | super().__init__(*args, **kwargs) 112 | 113 | self.setAttribute(Qt.WA_TransparentForMouseEvents, True) 114 | self.state_change_overlay = StateChangeOverlay(self) 115 | self.state_change_overlay.adjustSize() 116 | self.state_change_overlay.setFixedSize(216, 120) 117 | 118 | def resizeEvent(self, event): 119 | super().resizeEvent(event) 120 | self.state_change_overlay.move((self.width() - self.state_change_overlay.width()) // 2, 121 | int((self.height() - self.state_change_overlay.height()) * 0.785)) 122 | 123 | self.state_change_overlay.setContent( 124 | "设置窗口大小", f"{self.width()}×{self.height()}", "无快捷键" 125 | ) 126 | 127 | -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_right_message_sidebar/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/layer/layer_right_message_sidebar/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/layer/layer_right_message_sidebar/layer_right_message_sidebar.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from siui.components import SiLabel, SiMasonryContainer 4 | from siui.core import GlobalFont, Si, SiColor, SiQuickEffect 5 | from siui.gui import SiFont 6 | 7 | from .messagebox import SiSideMessageBox 8 | 9 | 10 | class MessageSidebar(SiMasonryContainer): 11 | def __init__(self, *args, **kwargs): 12 | super().__init__(*args, **kwargs) 13 | 14 | self.setColumns(1) 15 | self.setColumnWidth(400) 16 | self.setSpacing(horizontal=None, vertical=16) 17 | 18 | self.debug_label = SiLabel(self) 19 | # self.debug_label.setColor("#20FF0000") 20 | 21 | def sendMessageBox(self, message_box): 22 | self.addWidget(message_box) 23 | message_box.setFixedWidth(self.width()-20) 24 | message_box.move(80, self.height() - message_box.height()) 25 | message_box.show() 26 | 27 | def send(self, 28 | text: str, 29 | title: str = None, 30 | msg_type: int = 0, 31 | icon: Union[bytes, str] = None, 32 | slot=None, 33 | close_on_clicked=True, 34 | fold_after: int = None): 35 | """ Create a simple message box which only has a label and send it to sidebar """ 36 | new_message_box = SiSideMessageBox(self) 37 | new_message_box.setMessageType(msg_type) 38 | new_message_box.setFixedWidth(self.width()-20) 39 | 40 | if slot is not None: 41 | new_message_box.clicked.connect(slot) 42 | 43 | if close_on_clicked is True: 44 | new_message_box.clicked.connect(new_message_box.closeLater) 45 | 46 | if title is None: 47 | label = SiLabel(self) 48 | label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 49 | label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 50 | label.setWordWrap(True) 51 | label.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 52 | label.setFixedStyleSheet( 53 | "padding-top: 16px;" 54 | "padding-bottom: 16px;" 55 | "padding-left: 12px;" 56 | "padding-right: 12px;" 57 | "color: {}".format(self.getColor(SiColor.TEXT_D)) 58 | ) 59 | label.setText(text) 60 | new_message_box.content().container().addWidget(label) 61 | else: 62 | new_message_box.content().container().setSpacing(0) 63 | title_label = SiLabel(self) 64 | title_label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 65 | title_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 66 | title_label.setWordWrap(True) 67 | title_label.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 68 | title_label.setFixedStyleSheet( 69 | "padding-top: 16px;" 70 | "padding-bottom: 1px;" 71 | "padding-left: 12px;" 72 | "padding-right: 12px;" 73 | "color: {}".format(self.getColor(SiColor.TEXT_B)) 74 | ) 75 | title_label.setText(title) 76 | 77 | description_label = SiLabel(self) 78 | description_label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 79 | description_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 80 | description_label.setWordWrap(True) 81 | description_label.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 82 | description_label.setFixedStyleSheet( 83 | "padding-top: 1px;" 84 | "padding-bottom: 16px;" 85 | "padding-left: 12px;" 86 | "padding-right: 12px;" 87 | "color: {}".format(self.getColor(SiColor.TEXT_D)) 88 | ) 89 | description_label.setText(text) 90 | 91 | new_message_box.content().container().addWidget(title_label) 92 | new_message_box.content().container().addWidget(description_label) 93 | 94 | if fold_after is not None: 95 | new_message_box.setFoldAfter(fold_after) 96 | 97 | if icon is not None: 98 | new_message_box.content().themeIcon().load(icon) 99 | 100 | new_message_box.adjustSize() 101 | self.sendMessageBox(new_message_box) 102 | 103 | def resizeEvent(self, event): 104 | super().resizeEvent(event) 105 | self.debug_label.resize(event.size()) 106 | 107 | 108 | class LayerRightMessageSidebar(MessageSidebar): 109 | def __init__(self, *args, **kwargs): 110 | super().__init__(*args, **kwargs) 111 | 112 | SiQuickEffect.applyDropShadowOn(self, 113 | color=(28, 25, 31, 200), 114 | blur_radius=64) -------------------------------------------------------------------------------- /siui/templates/application/components/message/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaIceF/PyQt-SiliconUI/35f0eff570decac7d1b84e9f53d1582c13e19006/siui/templates/application/components/message/__init__.py -------------------------------------------------------------------------------- /siui/templates/application/components/message/sidebar.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Union 3 | 4 | from siui.components import SiLabel 5 | from siui.components.widgets.container import SiMasonryContainer 6 | from siui.core import GlobalFont, Si, SiColor 7 | from siui.gui import SiFont 8 | from siui.templates.application.components.message.box import SiSideMessageBox 9 | 10 | 11 | class MessageSidebar(SiMasonryContainer): 12 | def __init__(self, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | 15 | self.setColumns(1) 16 | self.setColumnWidth(400) 17 | self.setSpacing(horizontal=None, vertical=16) 18 | 19 | # self.debug_label = SiLabel(self) 20 | # self.debug_label.setColor("#20FF0000") 21 | 22 | def sendMessageBox(self, message_box): 23 | self.addWidget(message_box) 24 | message_box.setFixedWidth(self.width()-20) 25 | message_box.move(80, self.height() - message_box.height()) 26 | message_box.show() 27 | 28 | def send(self, 29 | text: str, 30 | title: str = None, 31 | msg_type: int = 0, 32 | icon: Union[bytes, str] = None, 33 | slot=None, 34 | close_on_clicked=True, 35 | fold_after: int = None): 36 | """ Create a simple message box which only has a label and send it to sidebar """ 37 | new_message_box = SiSideMessageBox(self) 38 | new_message_box.setMessageType(msg_type) 39 | new_message_box.setFixedWidth(self.width()-20) 40 | 41 | if slot is not None: 42 | new_message_box.clicked.connect(slot) 43 | 44 | if close_on_clicked is True: 45 | new_message_box.clicked.connect(new_message_box.closeLater) 46 | 47 | if title is None: 48 | label = SiLabel(self) 49 | label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 50 | label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 51 | label.setWordWrap(True) 52 | label.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 53 | label.setFixedStyleSheet( 54 | "padding-top: 16px;" 55 | "padding-bottom: 16px;" 56 | "padding-left: 12px;" 57 | "padding-right: 12px;" 58 | f"color: {self.getColor(SiColor.TEXT_D)}" 59 | ) 60 | label.setText(text) 61 | new_message_box.content().container().addWidget(label) 62 | else: 63 | new_message_box.content().container().setSpacing(0) 64 | title_label = SiLabel(self) 65 | title_label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 66 | title_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 67 | title_label.setWordWrap(True) 68 | title_label.setFont(SiFont.tokenized(GlobalFont.S_BOLD)) 69 | title_label.setFixedStyleSheet( 70 | "padding-top: 16px;" 71 | "padding-bottom: 1px;" 72 | "padding-left: 12px;" 73 | "padding-right: 12px;" 74 | f"color: {self.getColor(SiColor.TEXT_B)}" 75 | ) 76 | title_label.setText(title) 77 | 78 | description_label = SiLabel(self) 79 | description_label.setFixedWidth(380 - new_message_box.content().theme_wing_width - 32) 80 | description_label.setSiliconWidgetFlag(Si.AdjustSizeOnTextChanged) 81 | description_label.setWordWrap(True) 82 | description_label.setFont(SiFont.tokenized(GlobalFont.S_NORMAL)) 83 | description_label.setFixedStyleSheet( 84 | "padding-top: 1px;" 85 | "padding-bottom: 16px;" 86 | "padding-left: 12px;" 87 | "padding-right: 12px;" 88 | f"color: {self.getColor(SiColor.TEXT_D)}" 89 | ) 90 | description_label.setText(text) 91 | 92 | new_message_box.content().container().addWidget(title_label) 93 | new_message_box.content().container().addWidget(description_label) 94 | 95 | if fold_after is not None: 96 | new_message_box.setFoldAfter(fold_after) 97 | 98 | if icon is not None: 99 | new_message_box.content().themeIcon().load(icon) 100 | 101 | new_message_box.adjustSize() 102 | self.sendMessageBox(new_message_box) 103 | 104 | def resizeEvent(self, event): 105 | super().resizeEvent(event) 106 | # self.debug_label.resize(event.size()) 107 | -------------------------------------------------------------------------------- /siui/templates/application/components/page_view/__init__.py: -------------------------------------------------------------------------------- 1 | from siui.templates.application.components.page_view.page_view import PageView -------------------------------------------------------------------------------- /siui/typing.py: -------------------------------------------------------------------------------- 1 | """ 2 | ## This module defines global shared types 3 | 4 | Use Python's Type Hint syntax, reference: 5 | - [`typing`](https://docs.python.org/3/library/typing.html) 6 | - [`PEP 484`](https://www.python.org/dev/peps/pep-0484/) 7 | - [`PEP 526`](https://www.python.org/dev/peps/pep-0526/) 8 | """ 9 | 10 | from typing import Optional, Union 11 | 12 | from PyQt5.QtCore import QObject, Qt 13 | from PyQt5.QtGui import QColor, QGradient, QPainter, QPen 14 | from PyQt5.QtWidgets import QWidget 15 | from typing_extensions import TypeAlias 16 | 17 | T_WidgetParent: TypeAlias = Optional[QWidget] 18 | """Type of widget parent""" 19 | 20 | T_ObjectParent: TypeAlias = Optional[QObject] 21 | """Type of object parent""" 22 | 23 | T_PenStyle: TypeAlias = Union[QPen, Qt.PenStyle, QColor, Qt.GlobalColor] 24 | """Type of QPen style""" 25 | 26 | T_Brush: TypeAlias = Optional[Union[QGradient, QColor, Qt.GlobalColor]] 27 | """Type of QBrush""" 28 | 29 | T_RenderHint: TypeAlias = Optional[Union[QPainter.RenderHint, int]] 30 | """Type of QPainter.RenderHint""" --------------------------------------------------------------------------------