├── .gitignore ├── LICENSE ├── ReadMe.md ├── example ├── mainWindowExample.py └── resource │ ├── ArrowDown.png │ ├── ArrowMore.png │ ├── ArrowUp.png │ ├── default.qss │ ├── icon │ ├── 506353.png │ ├── 506354.png │ ├── 506355.png │ ├── 506356.png │ ├── 506357.png │ ├── 506358.png │ ├── 506359.png │ ├── 506362.png │ ├── 506363.png │ ├── 506405.png │ ├── 506406.png │ ├── 506407.png │ ├── 506460.png │ ├── 506461.png │ ├── 506462.png │ ├── 506463.png │ ├── 506464.png │ ├── 506466.png │ ├── 506467.png │ ├── 506468.png │ ├── 506469.png │ ├── 506471.png │ ├── 506501.png │ ├── 506502.png │ ├── 506503.png │ ├── 506504.png │ ├── 506505.png │ ├── 506506.png │ ├── 506507.png │ ├── 506508.png │ ├── 506509.png │ ├── 506510.png │ ├── 506511.png │ ├── 506512.png │ ├── 506513.png │ ├── 506514.png │ ├── 506515.png │ ├── 506516.png │ ├── 506517.png │ ├── 506518.png │ ├── 506519.png │ ├── 529398.png │ ├── 530120.png │ ├── 530150.png │ ├── 530767.png │ ├── Graph-add.png │ ├── arror.png │ ├── chartDataManager.png │ ├── figureIcon.png │ ├── filter.png │ ├── folder.png │ ├── help.png │ ├── icon2.png │ ├── inRangDataRemove.png │ ├── information.png │ ├── layerBarChart.png │ ├── openProject.png │ ├── save.png │ └── warning.png │ ├── office2013.qss │ └── ribbonPannelOptionButton.png └── src ├── PySARibbon ├── SACustomize │ ├── SARibbonActionsManager.py │ ├── SARibbonCustomizeData.py │ ├── SARibbonCustomizeDialog.py │ ├── SARibbonCustomizeWidget.py │ └── __init__.py ├── SAFramelessHelper.py ├── SARibbonBar.py ├── SARibbonButtonGroupWidget.py ├── SARibbonCategory.py ├── SARibbonCategoryLayout.py ├── SARibbonContextCategory.py ├── SARibbonGallery.py ├── SARibbonMainWindow.py ├── SARibbonPannel.py ├── SARibbonPannelLayout.py ├── SARibbonQuickAccessBar.py ├── SATools │ ├── SARibbonDrawHelper.py │ ├── SARibbonElementCreateDelegate.py │ ├── SARibbonElementManager.py │ ├── SARibbonGlobal.py │ └── __init__.py ├── SAWidgets │ ├── SARibbonApplicationButton.py │ ├── SARibbonCategoryScrollButton.py │ ├── SARibbonControlButton.py │ ├── SARibbonCtrlContainer.py │ ├── SARibbonGalleryGroup.py │ ├── SARibbonLineWidgetContainer.py │ ├── SARibbonMenu.py │ ├── SARibbonPannelItem.py │ ├── SARibbonPannelOptionButton.py │ ├── SARibbonSeparatorWidget.py │ ├── SARibbonStackedWidget.py │ ├── SARibbonTabBar.py │ ├── SARibbonToolButton.py │ └── __init__.py ├── SAWindowButtonGroup.py ├── __init__.py ├── resource.rc ├── resource │ ├── ArrowDown.png │ ├── ArrowMore.png │ ├── ArrowUp.png │ ├── default.qss │ ├── icon │ │ ├── 506353.png │ │ ├── 506354.png │ │ ├── 506355.png │ │ ├── 506356.png │ │ ├── 506357.png │ │ ├── 506358.png │ │ ├── 506359.png │ │ ├── 506362.png │ │ ├── 506363.png │ │ ├── 506405.png │ │ ├── 506406.png │ │ ├── 506407.png │ │ ├── 506460.png │ │ ├── 506461.png │ │ ├── 506462.png │ │ ├── 506463.png │ │ ├── 506464.png │ │ ├── 506466.png │ │ ├── 506467.png │ │ ├── 506468.png │ │ ├── 506469.png │ │ ├── 506471.png │ │ ├── 506501.png │ │ ├── 506502.png │ │ ├── 506503.png │ │ ├── 506504.png │ │ ├── 506505.png │ │ ├── 506506.png │ │ ├── 506507.png │ │ ├── 506508.png │ │ ├── 506509.png │ │ ├── 506510.png │ │ ├── 506511.png │ │ ├── 506512.png │ │ ├── 506513.png │ │ ├── 506514.png │ │ ├── 506515.png │ │ ├── 506516.png │ │ ├── 506517.png │ │ ├── 506518.png │ │ ├── 506519.png │ │ ├── 529398.png │ │ ├── 530120.png │ │ ├── 530150.png │ │ ├── 530767.png │ │ ├── Graph-add.png │ │ ├── arror.png │ │ ├── chartDataManager.png │ │ ├── figureIcon.png │ │ ├── filter.png │ │ ├── folder.png │ │ ├── help.png │ │ ├── icon2.png │ │ ├── inRangDataRemove.png │ │ ├── information.png │ │ ├── layerBarChart.png │ │ ├── openProject.png │ │ ├── save.png │ │ └── warning.png │ ├── office2013.qss │ └── ribbonPannelOptionButton.png └── resource_rc.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # idea files 2 | .idea/ 3 | Bak/ 4 | *.pyc 5 | 6 | # Byte-compiled / optimized / DLL files 7 | *__pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # celery beat schedule file 90 | celerybeat-schedule 91 | 92 | # SageMath parsed files 93 | *.sage.py 94 | 95 | # Environments 96 | .env 97 | .venv 98 | env/ 99 | venv/ 100 | ENV/ 101 | env.bak/ 102 | venv.bak/ 103 | 104 | # Spyder project settings 105 | .spyderproject 106 | .spyproject 107 | 108 | # Rope project settings 109 | .ropeproject 110 | 111 | # mkdocs documentation 112 | /site 113 | 114 | # mypy 115 | .mypy_cache/ 116 | .dmypy.json 117 | dmypy.json 118 | 119 | # Pyre type checker 120 | .pyre/ 121 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 sardkit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 本项目是基于[尘中远](https://gitee.com/czyt1988)的一个轻量级的Ribbon控件([SARibbon](https://gitee.com/czyt1988/SARibbon))移植的pyqt版本,功能与原版本基本保持一致 4 | 5 | 界面截图也基本相似: 6 | 7 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/001.gif) 8 | 9 | MIT协议,欢迎大家使用并提出意见 10 | 11 | [gitee(码云) - https://gitee.com/sardkit/saribbon-pyqt5](https://gitee.com/sardkit/saribbon-pyqt5) 12 | 13 | [github(hub) - https://github.com/sardkit/SARibbon-pyqt5](https://github.com/sardkit/SARibbon-pyqt5) 14 | 15 | 它支持4种目前常见的ribbon样式在线切换(目前简单测试通过,未进行深度测试) 16 | 17 | 包括2种office模式,office模式是最常见的ribbon模式了,就是我们经常看到的word模式,office模式的tab和标题栏占用位置较多。 18 | 19 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/office-mode.png) 20 | 21 | 另两种参考wps设计的wps模式,wps模式是office模式的改良版,它为了减小ribbon的高度,把标签和标题栏设置在一起 22 | 23 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/wps-mode.png) 24 | 25 | office模式和wps模式都支持两行和3行设计,满足不同界面需求。 26 | 27 | # 使用方法 28 | 29 | 1. 进入src目录,打开终端,安装此包,命令如下: 30 | 31 | ```shell 32 | python setup.py install 33 | ``` 34 | 35 | 2然后在项目的文件中`import PySARibbon`或`from PySARibbon import *`即可, 36 | 或者引用具体实用类示例如下: 37 | 38 | ```Python 39 | from PySARibbon import SARibbonMainWindow 40 | ``` 41 | 42 | 43 | # 更多截图(copy自原Qt项目) 44 | 45 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/SARibbonBar-screenshot-01.gif) 46 | 47 | - 支持quickAccessBar(word快速菜单),在wps模式和office模式下会有不同的显示效果 48 | 49 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/SARibbonBar-screenshot-quickAccessBar.gif) 50 | 51 | - 支持4种不同的ribbon button,普通按钮,延迟弹出菜单按钮,菜单按钮,action菜单按钮(action菜单按钮是此ribbon控件最主要解决的问题之一) 52 | 53 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/SARibbonBar-screenshot-ribbonbutton.gif) 54 | 55 | - 支持qss对ribbon进行设置 56 | 57 | ![](https://cdn.jsdelivr.net/gh/czyt1988/SARibbon/doc/screenshot/SARibbonBar-screenshot-useqss.gif) 58 | 59 | 60 | # 题外 61 | 62 | 大部分代码是根据原C++代码结构进行移植的,也有部分是基于Python语法特性对原代码结构进行了调整和更改; 63 | 64 | 更多相关功能可看Qt原作者相关项目,欢迎有兴趣的朋友一起完善本并丰富本项目。 65 | 66 | # 计划及进度 67 | 68 | ## 计划 69 | 70 | - 实现C++版最新功能 71 | 72 | ## 已知bug 73 | 74 | - 暂未完全测试 75 | 76 | ## 已解决 77 | 78 | - 略 79 | 80 | # 其他 81 | 82 | > 此处向原作者[尘中远](https://gitee.com/czyt1988)致敬 -------------------------------------------------------------------------------- /example/resource/ArrowDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/ArrowDown.png -------------------------------------------------------------------------------- /example/resource/ArrowMore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/ArrowMore.png -------------------------------------------------------------------------------- /example/resource/ArrowUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/ArrowUp.png -------------------------------------------------------------------------------- /example/resource/default.qss: -------------------------------------------------------------------------------- 1 |  2 | /* start ribbon set*/ 3 | /*SARibbonBar*/ 4 | 5 | SARibbonBar{ 6 | background-color: #E3E6E8; 7 | } 8 | 9 | /*SARibbonButtonGroupWidget*/ 10 | SARibbonButtonGroupWidget{ 11 | background-color: transparent; 12 | } 13 | 14 | /*SARibbonQuickAccessBar*/ 15 | SARibbonQuickAccessBar{ 16 | background-color: #FF0000; 17 | } 18 | 19 | 20 | /*SARibbonCtrlContainer*/ 21 | SARibbonCtrlContainer{ 22 | background-color: transparent; 23 | } 24 | 25 | /*SARibbonCategory*/ 26 | SARibbonCategory:focus{ 27 | outline: none; 28 | } 29 | SARibbonCategory{ 30 | background-color: white; 31 | } 32 | /*SARibbonStackedWidget*/ 33 | SARibbonStackedWidget{ 34 | background-color: white; 35 | } 36 | SARibbonStackedWidget:focus{ 37 | outline: none; 38 | } 39 | /*SARibbonApplicationButton*/ 40 | SARibbonApplicationButton{ 41 | color:white; 42 | border: 1px solid #416ABD; 43 | border-top-left-radius: 2px; 44 | border-top-right-radius: 2px; 45 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #467FBD, stop:0.5 #2A5FAC,stop:0.51 #1A4088, 46 | stop:1 #419ACF); 47 | } 48 | 49 | SARibbonApplicationButton::hover{ 50 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #7BB2EB, stop:0.5 #477ECD,stop:0.51 #114ECF, 51 | stop:1 #80E1FF); 52 | } 53 | 54 | SARibbonApplicationButton::pressed{ 55 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #467BBB, stop:0.5 #2F63AE,stop:0.51 #1C438A, 56 | stop:1 #358BC9); 57 | } 58 | 59 | SARibbonApplicationButton:focus{ 60 | outline: none; 61 | } 62 | 63 | /*SARibbonTabBar*/ 64 | SARibbonTabBar{ 65 | background-color: transparent; 66 | } 67 | 68 | SARibbonTabBar::tab { 69 | color:#444444; 70 | border:none; 71 | background: transparent; 72 | margin-top: 0px; 73 | margin-right: 0px; 74 | margin-left: 6px; 75 | margin-bottom: 0px; 76 | min-width:60px; 77 | max-width:200px; 78 | min-height:30px; 79 | max-height:30px; 80 | padding-left:1px; 81 | padding-right:1px; 82 | padding-top:1px; 83 | padding-bottom:1px; 84 | } 85 | 86 | SARibbonTabBar::tab:selected, SARibbonTabBar::tab:hover { 87 | border-top-left-radius: 2px; 88 | border-top-right-radius: 2px; 89 | } 90 | 91 | SARibbonTabBar::tab:selected{ 92 | color:#000000; 93 | border: 1px solid #BAC9DB; 94 | background: white; 95 | border-bottom-color: #FFFFFF; 96 | } 97 | 98 | SARibbonTabBar::tab:hover:!selected{ 99 | border: 1px solid #ECBC3D; 100 | color: #000000; 101 | } 102 | 103 | SARibbonTabBar::tab:!selected { 104 | margin-top: 0px; 105 | } 106 | 107 | /*SARibbonLineEdit*/ 108 | SARibbonLineEdit { 109 | border: 1px solid #C0C2C4; 110 | background: #FFF; 111 | selection-background-color: #9BBBF7; 112 | selection-color: #000; 113 | } 114 | 115 | /*SARibbonToolButton*/ 116 | SARibbonToolButton{ 117 | border:1px solid transparent; 118 | color:#444444; 119 | background-color:transparent; 120 | } 121 | SARibbonToolButton::pressed{ 122 | color:#444444; 123 | border: 1px solid #FCBF21; 124 | background-color: #FCD364; 125 | } 126 | SARibbonToolButton::checked{ 127 | color:#444444; 128 | border: 1px solid #FCD364; 129 | background-color: #FCD364; 130 | } 131 | SARibbonToolButton::hover { 132 | color:#000000; 133 | border: 1px solid #FCD364; 134 | background-color: #FCDE89; 135 | } 136 | 137 | /*SARibbonControlButton*/ 138 | SARibbonControlButton{ 139 | background-color:transparent; 140 | border: 1px solid transparent; 141 | color:#444444; 142 | } 143 | SARibbonControlButton#SARibbonGalleryButtonUp,#SARibbonGalleryButtonDown,#SARibbonGalleryButtonMore{ 144 | border: 1px solid #C0C2C4; 145 | } 146 | SARibbonControlButton#SARibbonBarHidePannelButton{ 147 | border: 1px solid transparent; 148 | } 149 | SARibbonControlButton::pressed{ 150 | border: 1px solid #FCD364; 151 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 152 | #FCE58C, stop:1 #FDFDEB); 153 | } 154 | SARibbonControlButton::checked{ 155 | border: 1px solid #FCD364; 156 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 157 | #FCE58C, stop:1 #FDFDEB); 158 | } 159 | SARibbonControlButton::hover { 160 | border: 1px solid #FCD364; 161 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 162 | #FCE58C, stop:1 #FDFDEB); 163 | } 164 | 165 | 166 | /*SARibbonMenu*/ 167 | SARibbonMenu { 168 | color:#444444; 169 | background-color: #FCFCFC; 170 | border: 1px solid #8492A6; 171 | } 172 | SARibbonMenu::item { 173 | padding: 5px 25px 5px 25px; 174 | background-color: transparent; 175 | } 176 | SARibbonMenu::item:selected { 177 | background-color: #FCDE89; 178 | } 179 | SARibbonMenu::item:hover { 180 | color:#000; 181 | border: 1px solid #FCD364; 182 | } 183 | SARibbonMenu::icon{ 184 | margin-left: 1px; 185 | } 186 | 187 | /*SARibbonPannelOptionButton*/ 188 | SARibbonPannelOptionButton { 189 | background-color: transparent; 190 | color:#444444; 191 | } 192 | 193 | SARibbonPannelOptionButton::hover { 194 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 195 | #FCE58C, stop:1 #FDFDEB); 196 | border: 0px; 197 | } 198 | 199 | 200 | SARibbonPannel { 201 | background-color: #FFFFFF; 202 | border: 0px; 203 | } 204 | /*SARibbonPannel*/ 205 | SARibbonPannel { 206 | background-color: #FFFFFF; 207 | border: 0px; 208 | } 209 | /*SARibbonGallery*/ 210 | SARibbonGallery { 211 | background-color: transparent; 212 | color: #444444; 213 | border: 1px solid #C0C2C4; 214 | } 215 | 216 | /*SARibbonGalleryGroup*/ 217 | SARibbonGalleryGroup { 218 | show-decoration-selected: 1; 219 | background-color: transparent; 220 | color: #444444; 221 | } 222 | SARibbonGalleryGroup::item:selected { 223 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 224 | #FCE58C, stop:1 #FDFDEB); 225 | } 226 | SARibbonGalleryGroup::item:hover { 227 | border: 2px solid #FDEEB3; 228 | } 229 | 230 | /*SARibbonComboBox*/ 231 | SARibbonComboBox { 232 | border: 1px solid #C0C2C4; 233 | 234 | } 235 | 236 | SARibbonComboBox:hover{ 237 | border: 1px solid #FDEEB3; 238 | color : #000; 239 | } 240 | 241 | SARibbonComboBox:editable { 242 | color : #000; 243 | background: white; 244 | selection-background-color: #9BBBF7; 245 | selection-color: #000; 246 | } 247 | 248 | SARibbonComboBox::drop-down { 249 | subcontrol-origin: padding; 250 | subcontrol-position: top right; 251 | width: 15px; 252 | border-left: none; 253 | border-top-right-radius: 0px; 254 | border-bottom-right-radius: 0px; 255 | } 256 | 257 | SARibbonComboBox::drop-down:hover { 258 | border: 1px solid #FDEEB3; 259 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 260 | #FCE58C, stop:1 #FDFDEB); 261 | } 262 | SARibbonComboBox::down-arrow { 263 | image: url(:/image/resource/ArrowDown.png); 264 | } 265 | 266 | 267 | /*SARibbonSeparatorWidget*/ 268 | SARibbonSeparatorWidget{ 269 | /*background-color: transparent;*/ 270 | background-color: #D3D3D3; 271 | } 272 | -------------------------------------------------------------------------------- /example/resource/icon/506353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506353.png -------------------------------------------------------------------------------- /example/resource/icon/506354.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506354.png -------------------------------------------------------------------------------- /example/resource/icon/506355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506355.png -------------------------------------------------------------------------------- /example/resource/icon/506356.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506356.png -------------------------------------------------------------------------------- /example/resource/icon/506357.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506357.png -------------------------------------------------------------------------------- /example/resource/icon/506358.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506358.png -------------------------------------------------------------------------------- /example/resource/icon/506359.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506359.png -------------------------------------------------------------------------------- /example/resource/icon/506362.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506362.png -------------------------------------------------------------------------------- /example/resource/icon/506363.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506363.png -------------------------------------------------------------------------------- /example/resource/icon/506405.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506405.png -------------------------------------------------------------------------------- /example/resource/icon/506406.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506406.png -------------------------------------------------------------------------------- /example/resource/icon/506407.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506407.png -------------------------------------------------------------------------------- /example/resource/icon/506460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506460.png -------------------------------------------------------------------------------- /example/resource/icon/506461.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506461.png -------------------------------------------------------------------------------- /example/resource/icon/506462.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506462.png -------------------------------------------------------------------------------- /example/resource/icon/506463.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506463.png -------------------------------------------------------------------------------- /example/resource/icon/506464.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506464.png -------------------------------------------------------------------------------- /example/resource/icon/506466.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506466.png -------------------------------------------------------------------------------- /example/resource/icon/506467.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506467.png -------------------------------------------------------------------------------- /example/resource/icon/506468.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506468.png -------------------------------------------------------------------------------- /example/resource/icon/506469.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506469.png -------------------------------------------------------------------------------- /example/resource/icon/506471.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506471.png -------------------------------------------------------------------------------- /example/resource/icon/506501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506501.png -------------------------------------------------------------------------------- /example/resource/icon/506502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506502.png -------------------------------------------------------------------------------- /example/resource/icon/506503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506503.png -------------------------------------------------------------------------------- /example/resource/icon/506504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506504.png -------------------------------------------------------------------------------- /example/resource/icon/506505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506505.png -------------------------------------------------------------------------------- /example/resource/icon/506506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506506.png -------------------------------------------------------------------------------- /example/resource/icon/506507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506507.png -------------------------------------------------------------------------------- /example/resource/icon/506508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506508.png -------------------------------------------------------------------------------- /example/resource/icon/506509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506509.png -------------------------------------------------------------------------------- /example/resource/icon/506510.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506510.png -------------------------------------------------------------------------------- /example/resource/icon/506511.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506511.png -------------------------------------------------------------------------------- /example/resource/icon/506512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506512.png -------------------------------------------------------------------------------- /example/resource/icon/506513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506513.png -------------------------------------------------------------------------------- /example/resource/icon/506514.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506514.png -------------------------------------------------------------------------------- /example/resource/icon/506515.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506515.png -------------------------------------------------------------------------------- /example/resource/icon/506516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506516.png -------------------------------------------------------------------------------- /example/resource/icon/506517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506517.png -------------------------------------------------------------------------------- /example/resource/icon/506518.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506518.png -------------------------------------------------------------------------------- /example/resource/icon/506519.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/506519.png -------------------------------------------------------------------------------- /example/resource/icon/529398.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/529398.png -------------------------------------------------------------------------------- /example/resource/icon/530120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/530120.png -------------------------------------------------------------------------------- /example/resource/icon/530150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/530150.png -------------------------------------------------------------------------------- /example/resource/icon/530767.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/530767.png -------------------------------------------------------------------------------- /example/resource/icon/Graph-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/Graph-add.png -------------------------------------------------------------------------------- /example/resource/icon/arror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/arror.png -------------------------------------------------------------------------------- /example/resource/icon/chartDataManager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/chartDataManager.png -------------------------------------------------------------------------------- /example/resource/icon/figureIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/figureIcon.png -------------------------------------------------------------------------------- /example/resource/icon/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/filter.png -------------------------------------------------------------------------------- /example/resource/icon/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/folder.png -------------------------------------------------------------------------------- /example/resource/icon/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/help.png -------------------------------------------------------------------------------- /example/resource/icon/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/icon2.png -------------------------------------------------------------------------------- /example/resource/icon/inRangDataRemove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/inRangDataRemove.png -------------------------------------------------------------------------------- /example/resource/icon/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/information.png -------------------------------------------------------------------------------- /example/resource/icon/layerBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/layerBarChart.png -------------------------------------------------------------------------------- /example/resource/icon/openProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/openProject.png -------------------------------------------------------------------------------- /example/resource/icon/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/save.png -------------------------------------------------------------------------------- /example/resource/icon/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/icon/warning.png -------------------------------------------------------------------------------- /example/resource/office2013.qss: -------------------------------------------------------------------------------- 1 | /* start ribbon set*/ 2 | 3 | /*SARibbonBar*/ 4 | 5 | SARibbonBar { 6 | background-color: white; 7 | border: 1px solid #2b579a; 8 | } 9 | 10 | /*SARibbonButtonGroupWidget*/ 11 | 12 | SARibbonButtonGroupWidget { 13 | background-color: transparent; 14 | } 15 | 16 | /*SARibbonQuickAccessBar*/ 17 | 18 | SARibbonQuickAccessBar { 19 | background-color: #cee8fc; 20 | } 21 | 22 | /*SARibbonCtrlContainer*/ 23 | 24 | SARibbonCtrlContainer { 25 | background-color: transparent; 26 | } 27 | 28 | /*SARibbonCategory*/ 29 | 30 | SARibbonCategory:focus { 31 | outline: none; 32 | } 33 | 34 | SARibbonCategory { 35 | background-color: #fcfdfe; 36 | } 37 | 38 | /*SARibbonStackedWidget*/ 39 | 40 | SARibbonStackedWidget { 41 | background-color: white; 42 | border-bottom: 1px solid #c5d2e0; 43 | border-left: 1px solid #c5d2e0; 44 | border-right: 1px solid #c5d2e0; 45 | border-top: none; 46 | } 47 | 48 | SARibbonStackedWidget:focus { 49 | outline: none; 50 | } 51 | 52 | /*SARibbonApplicationButton*/ 53 | 54 | SARibbonApplicationButton { 55 | color: white; 56 | border: 1px solid #2b579a; 57 | border-top-left-radius: 2px; 58 | border-top-right-radius: 2px; 59 | background-color: #2b579a; 60 | } 61 | 62 | SARibbonApplicationButton::hover { 63 | background-color: #155889; 64 | } 65 | 66 | SARibbonApplicationButton::pressed { 67 | background-color: #155889; 68 | } 69 | 70 | SARibbonApplicationButton:focus { 71 | outline: none; 72 | } 73 | 74 | /*SARibbonTabBar*/ 75 | 76 | SARibbonTabBar { 77 | background-color: transparent; 78 | } 79 | 80 | SARibbonTabBar::tab { 81 | color: #5779af; 82 | border: none; 83 | background: transparent; 84 | margin-top: 0px; 85 | margin-right: 0px; 86 | margin-left: 6px; 87 | margin-bottom: 0px; 88 | min-width: 60px; 89 | max-width: 200px; 90 | min-height: 25px; 91 | max-height: 25px; 92 | padding-left: 1px; 93 | padding-right: 1px; 94 | padding-top: 1px; 95 | padding-bottom: 1px; 96 | } 97 | 98 | SARibbonTabBar::tab:selected, SARibbonTabBar::tab:hover { 99 | border-top-left-radius: 0px; 100 | border-top-right-radius: 0px; 101 | } 102 | 103 | SARibbonTabBar::tab:selected { 104 | color: #5779af; 105 | border: 1px solid #c5d2e0; 106 | background: white; 107 | border-bottom-color: #FFFFFF; 108 | } 109 | 110 | SARibbonTabBar::tab:hover:!selected { 111 | border: 1px solid #c5d2e0; 112 | color: #5779af; 113 | } 114 | 115 | SARibbonTabBar::tab:!selected { 116 | margin-top: 0px; 117 | } 118 | 119 | /*SARibbonToolButton*/ 120 | 121 | SARibbonToolButton { 122 | border: 1px solid transparent; 123 | color: #333; 124 | background-color: white; 125 | } 126 | 127 | SARibbonToolButton:focus { 128 | border: 1px solid #b9defa; 129 | color: #333; 130 | background-color: #fcfdfe; 131 | } 132 | 133 | SARibbonToolButton::pressed { 134 | color: #000; 135 | border: 1px solid#269bf4; 136 | background-color: #9ed2f9; 137 | } 138 | 139 | SARibbonToolButton::checked { 140 | color: #333; 141 | border: 1px solid #b9defa; 142 | background-color: #cee8fc; 143 | } 144 | 145 | SARibbonToolButton::hover { 146 | color: #000; 147 | border: 1px solid #badffa; 148 | background-color: #cee7fc; 149 | } 150 | 151 | /*SARibbonControlButton*/ 152 | 153 | SARibbonControlButton { 154 | background-color: transparent; 155 | border: 1px solid transparent; 156 | color: #333; 157 | } 158 | 159 | SARibbonControlButton#SARibbonGalleryButtonUp, #SARibbonGalleryButtonDown, #SARibbonGalleryButtonMore { 160 | border: 1px solid #cee8fc; 161 | } 162 | 163 | SARibbonControlButton#SARibbonBarHidePannelButton { 164 | border: 1px solid transparent; 165 | } 166 | 167 | SARibbonControlButton::pressed { 168 | border: 1px solid #269bf4; 169 | background-color: #9ed2f9; 170 | } 171 | 172 | SARibbonControlButton::checked { 173 | border: 1px solid #b9defa; 174 | background-color: #cee8fc; 175 | } 176 | 177 | SARibbonControlButton::hover { 178 | border: 1px solid #badffa; 179 | background-color: #cee7fc; 180 | } 181 | 182 | /*SARibbonMenu*/ 183 | 184 | SARibbonMenu { 185 | color: #333; 186 | background-color: #FCFCFC; 187 | border: 1px solid #c2d0df; 188 | } 189 | 190 | SARibbonMenu::item { 191 | padding: 5px 25px 5px 25px; 192 | background-color: transparent; 193 | } 194 | 195 | SARibbonMenu::item:selected { 196 | background-color: #cee8fc; 197 | } 198 | 199 | SARibbonMenu::item:hover { 200 | color: #000; 201 | background-color: #cee7fc; 202 | border: 1px solid #badffa; 203 | } 204 | 205 | SARibbonMenu::icon { 206 | margin-left: 1px; 207 | } 208 | 209 | /*SARibbonPannelOptionButton*/ 210 | 211 | SARibbonPannelOptionButton { 212 | background-color: transparent; 213 | color: #333; 214 | } 215 | 216 | SARibbonPannelOptionButton::hover { 217 | background-color: #cee7fc; 218 | border: 0px; 219 | } 220 | 221 | /*SARibbonPannel*/ 222 | 223 | SARibbonPannel { 224 | background-color: white; 225 | border: 0px; 226 | } 227 | 228 | /*SARibbonGallery*/ 229 | 230 | SARibbonGallery { 231 | background-color: transparent; 232 | color: #333; 233 | border: 1px solid #c2d0df; 234 | } 235 | 236 | /*SARibbonGalleryGroup*/ 237 | 238 | SARibbonGalleryGroup { 239 | show-decoration-selected: 1; 240 | background-color: transparent; 241 | color: #333; 242 | } 243 | 244 | SARibbonGalleryGroup::item:selected { 245 | background-color: #9ed2f9; 246 | } 247 | 248 | SARibbonGalleryGroup::item:hover { 249 | border: 2px solid #badffa; 250 | background-color: #cee7fc; 251 | } 252 | 253 | /*SARibbonLineEdit*/ 254 | 255 | SARibbonLineEdit { 256 | border: 1px solid #C0C2C4; 257 | background: #FFF; 258 | selection-background-color: #9BBBF7; 259 | selection-color: #000; 260 | } 261 | 262 | /*SARibbonComboBox*/ 263 | 264 | SARibbonComboBox { 265 | border: 1px solid #c2d0df; 266 | } 267 | 268 | SARibbonComboBox:hover { 269 | border: 1px solid #269bf4; 270 | color: #000; 271 | } 272 | 273 | SARibbonComboBox:editable { 274 | color: #000; 275 | background: white; 276 | selection-background-color: #9BBBF7; 277 | selection-color: #000; 278 | } 279 | 280 | SARibbonComboBox::drop-down { 281 | subcontrol-origin: padding; 282 | subcontrol-position: top right; 283 | width: 15px; 284 | border-left: none; 285 | border-top-right-radius: 0px; 286 | border-bottom-right-radius: 0px; 287 | } 288 | 289 | SARibbonComboBox::drop-down:hover { 290 | border: 1px solid #FDEEB3; 291 | background-color: #9ed2f9; 292 | } 293 | 294 | SARibbonComboBox::down-arrow { 295 | image: url(:/image/resource/ArrowDown.png); 296 | } 297 | 298 | /*SARibbonSeparatorWidget*/ 299 | 300 | SARibbonSeparatorWidget { 301 | /*background-color: transparent;*/ 302 | background-color: white; 303 | } 304 | 305 | SARibbonCategoryScrollButton { 306 | border: 1px solid #b9defa; 307 | color: #333; 308 | background-color: white; 309 | } 310 | 311 | SARibbonCategoryScrollButton::hover { 312 | color: #000000; 313 | border: 1px solid #badffa; 314 | background-color: #cee7fc; 315 | } 316 | -------------------------------------------------------------------------------- /example/resource/ribbonPannelOptionButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/example/resource/ribbonPannelOptionButton.png -------------------------------------------------------------------------------- /src/PySARibbon/SACustomize/SARibbonActionsManager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonCustomizeWidget 4 | @Author ROOT 5 | 6 | @brief 用于管理SARibbon的所有Action 7 | 8 | @note SARibbonActionsManager维护着两个表,一个是tag(标签)对应的Action list, 9 | 一个是所有接受SARibbonActionsManager管理的action list。 10 | 11 | SARibbonActionsManager的标签对应一组actions,每个标签对应的action可以重复出现, 12 | 但SARibbonActionsManager维护的action list里只有一份action,不会重复出现。 13 | 14 | tag用于对action list分组,每个tag的实体名字通过@ref setTagName 进行设置,在语言变化时需要及时调用 15 | setTagName设置新的标签对应的文本。 16 | 17 | SARibbonActionsManager默认预设了6个常用标签见@ref SARibbonActionsManager.ActionTag ,用户自定义标签需要在 18 | SARibbonActionsManager.UserDefineActionTag值的基础上进行累加。 19 | 20 | @ref filter (等同@ref actions )函数用于提取标签管理的action list,@ref allActions 函数返回SARibbonActionsManager 21 | 管理的所有标签。 22 | 23 | 通过@ref autoRegisteActions 函数可以快速的建立action的管理,此函数会遍历@ref SARibbonMainWindow 下的所有子object, 24 | 同时遍历SARibbonMainWindow下所有@ref SARibbonPannel 添加的action,并给予Category建立tag,正常使用用户仅需关注此autoRegisteActions函数即可 25 | """ 26 | from typing import Any 27 | from PyQt5.QtCore import Qt, QObject, QAbstractListModel, QModelIndex, pyqtSignal 28 | from PyQt5.QtWidgets import QAction, QWidget 29 | 30 | 31 | class SARibbonActionsManagerPrivate: 32 | def __init__(self, p:QObject): 33 | self.mParent = p 34 | 35 | self.mTagToActions: dict = dict() # tag : dict 36 | self.mTagToName: dict = dict() # tag对应的名字 37 | self.mKeyToAction: dict = dict() # key对应action 38 | self.mActionToKey: dict = dict() # action对应key 39 | self.mTagToCategory: dict = dict() # 仅仅在autoRegisteActions函数会有用 40 | self.mSale: int = 0 # 用于生成固定的id,在用户不主动设置key时,id基于msale生成 41 | 42 | def clear(self) -> None: 43 | self.mTagToActions.clear() 44 | self.mTagToName.clear() 45 | self.mKeyToAction.clear() 46 | self.mActionToKey.clear() 47 | self.mTagToCategory.clear() 48 | self.mSale = 0 49 | 50 | 51 | class SARibbonActionsManager(QObject): 52 | """ 53 | @brief 定义action的标签 54 | """ 55 | UnknowActionTag = 0x00 56 | CommonlyUsedActionTag = 0x01 57 | NotInFunctionalAreaActionTag = 0x02 58 | AutoCategoryDistinguishBeginTag = 0x1000 59 | AutoCategoryDistinguishEndTag = 0x2000 60 | NotInRibbonCategoryTag = 0x2001 61 | UserDefineActionTag = 0x8000 62 | 63 | """标签变化触发的信号,变化包括新增和删除""" 64 | actionTagChanged = pyqtSignal(int, bool) 65 | 66 | def __init__(self, p:QObject): 67 | super().__init__(p) 68 | self.QObject = p 69 | self.m_d = SARibbonActionsManagerPrivate(self) 70 | self.autoRegisteActions(p) 71 | 72 | def setTagName(self, tag:int, name:str) -> None: 73 | """设置tag对应的名字""" 74 | self.m_d.mTagToName[tag] = name 75 | 76 | def tagName(self, tag:int) -> str: 77 | """获取tag对应的名字""" 78 | return self.m_d.mTagToName.get(tag, "") 79 | 80 | def removeTag(self, tag:int) -> None: 81 | """移除tag,注意,这个函数非常耗时""" 82 | oldacts: list = self.actions(tag) 83 | 84 | # 开始移除 85 | self.m_d.mTagToActions.pop(tag) 86 | self.m_d.mTagToName.pop(tag) 87 | # 开始查找需要移出总表的action 88 | needRemoveAct: list = list() 89 | total: list = list() 90 | 91 | for i in self.m_d.mTagToActions: 92 | total.append(i) 93 | 94 | for a in oldacts: 95 | if not a in total: 96 | needRemoveAct.append(a) 97 | 98 | # 从总表移除action 99 | for a in needRemoveAct: 100 | i = self.m_d.mActionToKey.get(a, '') 101 | if i: 102 | self.m_d.mKeyToAction.pop(i) 103 | self.m_d.mActionToKey.pop(a) 104 | 105 | def registeAction(self, act:QAction, tag:int, key:str = '', enableEmit:bool = True) -> bool: 106 | """注册action""" 107 | if not act: 108 | return False 109 | 110 | k: str = key 111 | if not k: 112 | k = "id_{0}_{1}".format(self.m_d.mSale, act.objectName()) 113 | self.m_d.mSale += 1 114 | 115 | if k in self.m_d.mKeyToAction: 116 | print("key: ", k, "have been exist, can you set key in an unique value when use SARibbonActionsManager.registeAction") 117 | return False 118 | 119 | self.m_d.mKeyToAction[k] = act 120 | self.m_d.mActionToKey[act] = k 121 | # 记录tag 对 action 122 | isneedemit: bool = tag not in self.m_d.mTagToActions # 记录是否需要发射信号 123 | if isneedemit: 124 | self.m_d.mTagToActions[tag] = list() 125 | self.m_d.mTagToActions[tag].append(act) 126 | # 绑定槽 127 | act.destroyed.connect(self.onActionDestroyed) 128 | if isneedemit and enableEmit: 129 | # 说明新增tag 130 | self.actionTagChanged.emit(tag, False) 131 | 132 | return True 133 | 134 | def unregisteAction(self, act:QAction, enableEmit:bool = True) -> None: 135 | """取消action的注册""" 136 | if act is None: 137 | return 138 | 139 | # 绑定槽 140 | act.destroyed.disconnect(self.onActionDestroyed) 141 | self.removeAction(act, enableEmit) 142 | 143 | def filter(self, tag:int) -> list: 144 | """过滤得到actions对应的引用,实际是一个迭代器""" 145 | return self.actions(tag) 146 | 147 | def actions(self, tag:int) -> list: 148 | """通过tag筛选出系列action""" 149 | return self.m_d.mTagToActions.get(tag, list()) 150 | 151 | def actionTags(self) -> list: 152 | """获取所有的标签""" 153 | return list(self.m_d.mTagToActions.keys()) 154 | 155 | def action(self, key:str) -> QAction: 156 | """通过key获取action""" 157 | return self.m_d.mKeyToAction.get(key, None) 158 | 159 | def key(self, act:QAction) -> str: 160 | """通过action找到key""" 161 | return self.m_d.mActionToKey.get(act, '') 162 | 163 | def count(self) -> int: 164 | """返回所有管理的action数""" 165 | return len(self.m_d.mKeyToAction) 166 | 167 | def allActions(self) -> list: 168 | """返回所有管理的actions""" 169 | return list(self.m_d.mKeyToAction.values()) 170 | 171 | def autoRegisteActions(self, w:QObject) -> dict: 172 | """自动加载action,返回tag对应的Category指针""" 173 | res: dict = dict() 174 | # 先遍历SARibbonMainWindow下的所有子对象,把所有action找到 175 | mainwindowActions: set = set() 176 | 177 | for o in w.children(): 178 | if isinstance(o, QAction) and o.objectName(): 179 | mainwindowActions.add(o) 180 | 181 | # 开始遍历每个category,加入action 182 | bar = w.ribbonBar() 183 | # 非ribbon模式,直接退出 184 | if not bar: 185 | return res 186 | 187 | categoryActions: set = set() 188 | categorys: list = bar.categoryPages() 189 | tag: int = self.AutoCategoryDistinguishBeginTag 190 | 191 | for c in categorys: 192 | pannels: list = c.pannelList() 193 | for p in pannels: 194 | categoryActions.union(self.autoRegisteWidgetActions(p, tag, False)) 195 | self.setTagName(tag, c.windowTitle()) 196 | res[tag] = c 197 | tag += 1 198 | 199 | # 找到不在功能区的actions 200 | notincategory: set = mainwindowActions - categoryActions 201 | for a in notincategory: 202 | if a.objectName(): 203 | self.registeAction(a, self.NotInRibbonCategoryTag, a.objectName(), False) 204 | 205 | if len(notincategory) > 0: 206 | self.setTagName(self.NotInRibbonCategoryTag, "not in ribbon") 207 | 208 | for i in res.values(): 209 | i.windowTitleChanged.connect(self.onCategoryTitleChanged) 210 | 211 | self.m_d.mTagToCategory = res 212 | return res 213 | 214 | def autoRegisteWidgetActions(self, w:QWidget, tag:int, enableEmit:bool = False) -> set: 215 | """自动加载widget下的actions函数返回的action,返回加载的数量,这些""" 216 | res: set = set() 217 | was: list = w.actions() 218 | for a in was: 219 | if a in res or not a.objectName(): 220 | # 重复内容不重复加入,没有object name不加入 221 | continue 222 | if self.registeAction(a, tag, a.objectName(), enableEmit): 223 | res.add(a) 224 | 225 | return res 226 | 227 | def search(self, text:str) -> list: 228 | """根据标题查找action""" 229 | res: list = list() 230 | if not text: 231 | return res 232 | 233 | kws: list = text.split(" ") 234 | if not kws: 235 | kws.append(text) 236 | 237 | for k in kws: 238 | for i in self.m_d.mActionToKey.keys(): 239 | if i.text().contains(k, Qt.CaseInsensitive): 240 | res.append(i.key()) 241 | 242 | return res 243 | 244 | def clear(self) -> None: 245 | """清除""" 246 | self.m_d.clear() 247 | 248 | def ribbonWindow(self) -> QObject: 249 | """获取ribbonwindow""" 250 | return self.parent() 251 | 252 | def onActionDestroyed(self, o:QObject) -> None: 253 | self.removeAction(o, False) 254 | 255 | def onCategoryTitleChanged(self, title:str) -> None: 256 | c = self.sender() 257 | 258 | tag: int = -1 259 | for key, val in self.m_d.mTagToCategory.items(): 260 | if val == c: 261 | tag = key 262 | break 263 | if tag == -1: 264 | return 265 | 266 | self.setTagName(tag, title) 267 | 268 | def removeAction(self, act:QAction, enableEmit:bool = True) -> None: 269 | deletedTags: list = list() # 记录删除的tag,用于触发actionTagChanged 270 | tagToActions: dict = dict() # tag : list 271 | 272 | for key, value in self.m_d.mTagToActions.items(): 273 | # 把不是act的内容转移到tagToActions和tagToActionKeys中,之后再和m_d里的替换 274 | tagToActions[key] = list() 275 | tmpi = tagToActions[key] 276 | count = 0 277 | for jval in value: 278 | if jval != act: 279 | tmpi.append(act) 280 | count += 1 281 | 282 | if 0 == count: 283 | # 说明这个tag没有内容 284 | tagToActions.pop(tmpi) 285 | deletedTags.append(key) 286 | 287 | # 删除mKeyToAction 288 | key: str = self.m_d.mActionToKey.get(act, '') 289 | if key: 290 | self.m_d.mActionToKey.pop(act) 291 | self.m_d.mKeyToAction.pop(key) 292 | 293 | # 置换 294 | self.m_d.mTagToActions = tagToActions 295 | # 发射信号 296 | if enableEmit: 297 | for tagdelete in deletedTags: 298 | self.actionTagChanged.emit(tagdelete, True) 299 | 300 | 301 | class SARibbonActionsModelPrivete: 302 | def __init__(self, m:QObject): 303 | self.mParent: SARibbonActionsManagerModel = m 304 | self.mMgr: SARibbonActionsManager = None 305 | self.mTag: int = SARibbonActionsManager.CommonlyUsedActionTag 306 | self.mSeatchText: str = '' 307 | self.mActions: list = list() 308 | 309 | def updateRef(self) -> None: 310 | if self.isNull(): 311 | return 312 | 313 | if self.mSeatchText: 314 | self.mActions = self.mMgr.search(self.mSeatchText) 315 | else: 316 | self.mActions = self.mMgr.actions(self.mTag) 317 | 318 | def count(self) -> int: 319 | if self.isNull(): 320 | return 0 321 | 322 | return len(self.mActions) 323 | 324 | def at(self, index:int) -> QAction: 325 | if self.isNull(): 326 | return None 327 | if index >= self.count(): 328 | return None 329 | 330 | return self.mActions[index] 331 | 332 | def isNull(self) -> bool: 333 | return self.mMgr is None 334 | 335 | 336 | class SARibbonActionsManagerModel(QAbstractListModel): 337 | """ 338 | SARibbonActionsManager 对应的model 339 | """ 340 | def __init__(self, *_args): 341 | """ 342 | SARibbonActionsManagerModel(p:QObject = None) 343 | SARibbonActionsManagerModel(m:SARibbonActionsManager, p:QObject = None) 344 | """ 345 | m: SARibbonActionsManager = None 346 | p: QObject = None 347 | if len(_args) == 1: 348 | p = _args[0] 349 | elif len(_args) == 2: 350 | m = _args[0] 351 | p = _args[1] 352 | 353 | super().__init__(p) 354 | self.QAbstractListModel = p 355 | self.m_d = SARibbonActionsModelPrivete(self) 356 | if m: 357 | self.setupActionsManager(m) 358 | 359 | def rowCount(self, parent:QModelIndex) -> int: 360 | if parent.isValid(): # 非顶层 361 | return 0 362 | # 顶层 363 | return self.m_d.count() 364 | 365 | def headerData(self, section:int, orientation:int, role:int = Qt.DisplayRole) -> Any: 366 | if role != Qt.DisplayRole: 367 | return None 368 | if Qt.Horizontal == orientation: 369 | return "action name" 370 | 371 | return None 372 | 373 | def flags(self, index:QModelIndex) -> int: 374 | if not index.isValid(): 375 | return Qt.NoItemFlags 376 | 377 | return Qt.ItemIsSelectable | Qt.ItemIsEnabled 378 | 379 | def data(self, index:QModelIndex, role:int) -> Any: 380 | act: QAction = self.indexToAction(index) 381 | if act is None: 382 | return None 383 | 384 | if Qt.DisplayRole == role: 385 | return act.text() 386 | elif Qt.DecorationRole == role: 387 | return act.icon() 388 | 389 | return None 390 | 391 | def setFilter(self, tag:int) -> None: 392 | self.m_d.mTag = tag 393 | self.update() 394 | 395 | def update(self) -> None: 396 | self.beginResetModel() 397 | self.m_d.updateRef() 398 | self.endResetModel() 399 | 400 | def setupActionsManager(self, m:SARibbonActionsManager) -> None: 401 | self.m_d.mMgr = m 402 | self.m_d.mTag = SARibbonActionsManager.CommonlyUsedActionTag 403 | self.m_d.mActions = m.filter(self.m_d.mTag) 404 | self.m_d.mMgr.actionTagChanged.connect(self.onActionTagChanged) 405 | self.update() 406 | 407 | def uninstallActionsManager(self) -> None: 408 | if not self.m_d.isNull(): 409 | self.m_d.mMgr.actionTagChanged.disconnect(self.onActionTagChanged) 410 | self.m_d.mMgr = None 411 | self.m_d.mTag = SARibbonActionsManager.CommonlyUsedActionTag 412 | self.update() 413 | 414 | def indexToAction(self, index:QModelIndex) -> QAction: 415 | if not index.isValid(): 416 | return None 417 | if index.row() >= self.m_d.count(): 418 | return None 419 | 420 | return self.m_d.at(index.row()) 421 | 422 | def search(self, text:str) -> None: 423 | self.m_d.mSeatchText = text 424 | self.update() 425 | 426 | def onActionTagChanged(self, tag:int, isdelete:bool) -> None: 427 | if isdelete and (tag == self.m_d.mTag): 428 | self.m_d.mTag = SARibbonActionsManager.UnknowActionTag 429 | self.update() 430 | else: 431 | if tag == self.m_d.mTag: 432 | self.update() 433 | -------------------------------------------------------------------------------- /src/PySARibbon/SACustomize/SARibbonCustomizeDialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonCustomizeDialog 4 | @Author ROOT 5 | 6 | @brief SARibbonCustomizeWidget的对话框封装 7 | 此功能依赖于@ref SARibbonActionsManager ,SARibbonActionsManager建议作为mianwindow的成员变量, 8 | SARibbonActionsManager可以快速绑定所有QAction,详细见SARibbonActionsManager的说明 9 | 10 | @note SARibbon的自定义是基于步骤的,如果在窗口生成前调用了@ref sa_apply_customize_from_xml_file 类似函数 11 | 那么在对话框生成前为了保证同步需要调用@ref SARibbonCustomizeDialog::fromXml 同步配置文件,这样再次修改后的配置文件就一致 12 | """ 13 | 14 | from PyQt5.QtCore import Qt, QXmlStreamWriter, QXmlStreamReader 15 | from PyQt5.QtWidgets import QDialog, QWidget, QVBoxLayout, QHBoxLayout, QSpacerItem, QSizePolicy, QPushButton, \ 16 | QApplication 17 | 18 | from .SARibbonCustomizeWidget import SARibbonCustomizeWidget 19 | 20 | 21 | class SARibbonCustomizeDialog(QDialog): 22 | def __init__(self, ribbonWindow, parent=None, f=Qt.WindowFlags()): 23 | super().__init__(parent, f) 24 | 25 | self.ui = SARibbonCustomizeDialogUi() 26 | self.ui.setupUi(ribbonWindow, self) 27 | self.initConnection() 28 | 29 | def setupActionsManager(self, mgr: QWidget): 30 | """设置action管理器""" 31 | self.ui.customWidget.setupActionsManager(mgr) 32 | 33 | def applys(self) -> bool: 34 | """等同SARibbonCustomizeWidget::applys""" 35 | return self.ui.customWidget.applys() 36 | 37 | def clear(self): 38 | """清除所有动作""" 39 | self.ui.customWidget.clear() 40 | 41 | def toXml(self, *_args) -> bool: 42 | """转换为xml 43 | toXml(xml: QXmlStreamWriter) -> bool 44 | toXml(xmlpath: str) -> bool 45 | """ 46 | if len(_args) < 1: 47 | return False 48 | 49 | xml = _args[0] 50 | if isinstance(xml, QXmlStreamWriter) or isinstance(xml, str): 51 | return self.ui.customWidget.toXml(xml) 52 | else: 53 | print('Unknow type of xml:', type(xml)) 54 | 55 | return False 56 | 57 | def fromXml(self, *_args): 58 | """等同SARibbonCustomizeWidget::fromXml 59 | fromXml(xml: QXmlStreamReader) -> None 60 | fromXml(xmlpath: str) -> None 61 | """ 62 | if len(_args) < 1: 63 | return 64 | 65 | xml = _args[0] 66 | if isinstance(xml, QXmlStreamReader) or isinstance(xml, str): 67 | self.ui.customWidget.fromXml(xml) 68 | else: 69 | print('Unknow type of xml:', type(xml)) 70 | 71 | def customizeWidget(self) -> SARibbonCustomizeWidget: 72 | """返回SARibbonCustomizeWidget窗口指针""" 73 | return self.ui.customWidget 74 | 75 | def initConnection(self): 76 | self.ui.pushButtonOk.clicked.connect(self.accept) 77 | self.ui.pushButtonCancel.clicked.connect(self.reject) 78 | 79 | 80 | class SARibbonCustomizeDialogUi: 81 | def __init__(self): 82 | self.customWidget = None 83 | self.verticalLayoutMain = None 84 | self.horizontalLayoutButtonGroup = None 85 | self.pushButtonCancel: QPushButton = None 86 | self.pushButtonOk: QPushButton = None 87 | self.spacerItemleft = None 88 | 89 | def setupUi(self, ribbonWindow, customizeDialog: QWidget): 90 | if not customizeDialog.objectName(): 91 | customizeDialog.setObjectName('SARibbonCustomizeDialog') 92 | customizeDialog.resize(800, 600) 93 | 94 | self.verticalLayoutMain = QVBoxLayout(customizeDialog) 95 | self.verticalLayoutMain.setObjectName('verticalLayoutMain') 96 | self.customWidget = SARibbonCustomizeWidget(ribbonWindow, customizeDialog) 97 | self.customWidget.setObjectName('customWidget') 98 | self.verticalLayoutMain.addWidget(self.customWidget) 99 | 100 | self.horizontalLayoutButtonGroup = QHBoxLayout() 101 | self.horizontalLayoutButtonGroup.setObjectName('horizontalLayoutButtonGroup') 102 | self.spacerItemleft = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) 103 | self.horizontalLayoutButtonGroup.addItem(self.spacerItemleft) 104 | 105 | self.pushButtonCancel = QPushButton(customizeDialog) 106 | self.pushButtonCancel.setObjectName('pushButtonCancel') 107 | self.horizontalLayoutButtonGroup.addWidget(self.pushButtonCancel) 108 | self.pushButtonOk = QPushButton(customizeDialog) 109 | self.pushButtonOk.setObjectName('pushButtonOk') 110 | self.horizontalLayoutButtonGroup.addWidget(self.pushButtonOk) 111 | 112 | self.verticalLayoutMain.addItem(self.horizontalLayoutButtonGroup) 113 | self.retranslateUi(customizeDialog) 114 | 115 | def retranslateUi(self, customizeDialog: QWidget): 116 | """国际化文本""" 117 | customizeDialog.setWindowTitle(QApplication.translate('SARibbonCustomizeDialog', 'Customize Dialog')) 118 | self.pushButtonCancel.setText(QApplication.translate('SARibbonCustomizeDialog', 'Cancel')) 119 | self.pushButtonOk.setText(QApplication.translate('SARibbonCustomizeDialog', 'OK')) 120 | -------------------------------------------------------------------------------- /src/PySARibbon/SACustomize/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module __init__.py 4 | @Author ROOT 5 | """ 6 | 7 | from .SARibbonActionsManager import SARibbonActionsManager 8 | from .SARibbonCustomizeData import SARibbonCustomizeData 9 | from .SARibbonCustomizeDialog import SARibbonCustomizeDialog 10 | from .SARibbonCustomizeWidget import SARibbonCustomizeWidget -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonButtonGroupWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonButtonGroupWidget 4 | @Author ROOT 5 | """ 6 | from typing import List, Union 7 | from PyQt5.QtCore import pyqtSignal, QSize, Qt, QEvent 8 | from PyQt5.QtGui import QActionEvent 9 | from PyQt5.QtWidgets import QFrame, QAction, QMenu, QToolButton, QWidget, QHBoxLayout, QSizePolicy, QWidgetAction 10 | 11 | from .SAWidgets.SARibbonToolButton import SARibbonToolButton 12 | from .SATools.SARibbonElementManager import RibbonSubElementDelegate 13 | 14 | 15 | class SARibbonButtonGroupWidgetItem: 16 | def __init__(self, *_args): 17 | """ 18 | SARibbonButtonGroupWidgetItem() 19 | SARibbonButtonGroupWidgetItem(QAction, QWidget, bool) 20 | """ 21 | if len(_args) < 3: 22 | self.action: QAction = None 23 | self.widget: QWidget = None 24 | self.customWidget: bool = False 25 | else: 26 | self.action: QAction = _args[0] 27 | self.widget: QWidget = _args[1] 28 | self.customWidget: bool = _args[2] 29 | 30 | def compare(self, *_args) -> bool: 31 | """ 32 | compare(QAction) -> bool 33 | compare(SARibbonButtonGroupWidgetItem) -> bool 34 | """ 35 | if len(_args) < 1: 36 | return False 37 | 38 | if isinstance(_args[0], QAction): 39 | return self.action == _args[0] 40 | else: 41 | return self.action == _args[0].action 42 | 43 | 44 | class SARibbonButtonGroupWidget(QFrame): 45 | def __init__(self, parent=None): 46 | super().__init__(parent) 47 | self.mItems: List[SARibbonButtonGroupWidgetItem] = list() 48 | 49 | layout = QHBoxLayout() # 水平排布 50 | layout.setContentsMargins(0, 0, 0, 0) # C++是setMargin(0) 51 | layout.setSpacing(0) 52 | self.setLayout(layout) 53 | self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) 54 | 55 | def addAction(self, *_args) -> Union[None, QAction]: 56 | """ 57 | addAction(QAction) 58 | addAction(QString, QIcon, popMode=QToolButton.InstantPopup) -> QAction 59 | """ 60 | if len(_args) == 1: 61 | super().addAction(_args[0]) 62 | else: 63 | a = QAction(_args[1], _args[0], self) 64 | super().addAction(a) 65 | popMode = QToolButton.InstantPopup if len(_args) < 3 else _args[2] 66 | if self.mItems: 67 | button: SARibbonToolButton = self.mItems[-1].widget 68 | button.setPopupMode(popMode) 69 | return a 70 | 71 | def addMenu(self, menu: QMenu, popMode=QToolButton.InstantPopup) -> QAction: 72 | a = menu.menuAction() 73 | self.addAction(a) 74 | btn = self.mItems[-1].widget 75 | btn.setPopupMode(popMode) 76 | return a 77 | 78 | def addSeparator(self) -> QAction: 79 | a = QAction() 80 | a.setSeparator(True) 81 | self.addAction(a) 82 | return a 83 | 84 | def addWidget(self, w: QWidget) -> QAction: 85 | a = QWidgetAction(self) 86 | a.setDefaultWidget(w) 87 | w.setAttribute(Qt.WA_Hover) 88 | self.addAction(a) 89 | return a 90 | 91 | def hideWidget(self, act: QAction): 92 | """隐藏指定Widget""" 93 | i = len(self.mItems) 94 | for i, it in enumerate(self.mItems): 95 | if isinstance(it.action, QWidgetAction) and it.action == act: 96 | it.widget.hide() 97 | widgetAction: QWidgetAction = it.action 98 | widgetAction.releaseWidget(it.widget) 99 | break 100 | if i < len(self.mItems): 101 | self.mItems.pop(i) 102 | 103 | def sizeHint(self) -> QSize: 104 | return self.layout().sizeHint() 105 | 106 | def minimumSizeHint(self) -> QSize: 107 | return self.layout().minimumSize() 108 | 109 | def actionEvent(self, e: QActionEvent): 110 | """处理action的事件""" 111 | item = SARibbonButtonGroupWidgetItem() 112 | item.action = e.action() 113 | 114 | if e.type() == QEvent.ActionAdded: 115 | if item.action and item.action.parent() != self: 116 | item.action.setParent(self) 117 | 118 | if item.action.isSeparator(): 119 | sp = RibbonSubElementDelegate.createRibbonSeparatorWidget(self) 120 | sp.setTopBottomMargins(3, 3) 121 | item.widget = sp 122 | elif isinstance(item.action, QWidgetAction): 123 | widgetAction: QWidgetAction = item.action 124 | item.widget = widgetAction.requestWidget(self) 125 | item.widget.setAttribute(Qt.WA_LayoutUsesWidgetRect) 126 | item.widget.show() 127 | item.customWidget = True 128 | # 不是widget,自动生成SARibbonToolButton 129 | if not item.widget: 130 | btn = RibbonSubElementDelegate.createRibbonToolButton(self) 131 | btn.setAutoRaise(True) 132 | btn.setFocusPolicy(Qt.NoFocus) 133 | btn.setButtonType(SARibbonToolButton.SmallButton) 134 | btn.setToolButtonStyle(Qt.ToolButtonIconOnly) 135 | btn.setDefaultAction(item.action) 136 | btn.triggered.connect(self.actionTriggered) 137 | item.widget = btn 138 | self.layout().addWidget(item.widget) 139 | self.mItems.append(item) 140 | elif e.type() == QEvent.ActionChanged: 141 | # 让布局重新绘制 142 | self.layout().invalidate() 143 | elif e.type() == QEvent.ActionRemoved: 144 | item.action.disconnect(self) 145 | for it in self.mItems: 146 | if isinstance(it.action, QWidgetAction) and it.customWidget: 147 | widgetAction: QWidgetAction = it.action 148 | widgetAction.releaseWidget(it.widget) 149 | else: 150 | it.widget.hide() 151 | it.widget.deleteLater() 152 | self.mItems.clear() 153 | self.layout().invalidate() 154 | 155 | # 参考QToolBar.actionTriggered的信号 156 | actionTriggered = pyqtSignal(QAction) 157 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonCategoryLayout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonCategoryLayout 4 | @Author ROOT 5 | """ 6 | from typing import List 7 | from PyQt5.QtCore import QRect, QSize, QMargins, Qt 8 | from PyQt5.QtWidgets import QLayout, QWidgetItem, QLayoutItem, QWidget 9 | 10 | from .SAWidgets.SARibbonCategoryScrollButton import SARibbonCategoryScrollButton 11 | from .SAWidgets.SARibbonSeparatorWidget import SARibbonSeparatorWidget 12 | from .SATools.SARibbonElementManager import RibbonSubElementDelegate 13 | 14 | 15 | class SARibbonCategoryLayoutItem(QWidgetItem): 16 | def __init__(self, parent): 17 | super().__init__(parent) 18 | self.separatorWidget: SARibbonSeparatorWidget = None 19 | self.mWillSetGeometry = QRect() # pannel将要设置的Geometry 20 | self.mWillSetSeparatorGeometry = QRect() # pannel将要设置的Separator的Geometry 21 | 22 | 23 | class SARibbonCategoryLayoutPrivate: 24 | def __init__(self, parent): 25 | self.q_d = parent 26 | self.mDirty = True 27 | self.mSizeHint = QSize(50, 50) 28 | self.mTotalWidth = 0 29 | self.mXBase = 0 30 | self.mLeftScrollBtn: SARibbonCategoryScrollButton = None 31 | self.mRightScrollBtn: SARibbonCategoryScrollButton = None 32 | self.mIsLeftScrollBtnShow = False 33 | self.mIsRightScrollBtnShow = False 34 | self.mItemList: List[SARibbonCategoryLayoutItem] = list() 35 | 36 | def totalSizeHintWidth(self) -> int: 37 | """计算所有元素的SizeHint宽度总和""" 38 | mag: QMargins = self.q_d.contentsMargins() 39 | total = 0 40 | if not mag.isNull(): 41 | total += mag.left() + mag.right() 42 | for item in self.mItemList: 43 | if item.isEmpty(): 44 | continue 45 | pannelSize = item.widget().sizeHint() 46 | separatorSize = QSize(0, 0) 47 | if item.separatorWidget: 48 | separatorSize = item.separatorWidget.sizeHint() 49 | total += pannelSize.width() 50 | total += separatorSize.width() 51 | return total 52 | 53 | 54 | class SARibbonCategoryLayout(QLayout): 55 | def __init__(self, parent): 56 | super().__init__(parent) 57 | self.m_d = SARibbonCategoryLayoutPrivate(self) 58 | self.m_d.mLeftScrollBtn = SARibbonCategoryScrollButton(Qt.LeftArrow, parent) 59 | self.m_d.mLeftScrollBtn.setVisible(False) 60 | self.m_d.mLeftScrollBtn.clicked.connect(self.onLeftScrollButtonClicked) 61 | self.m_d.mRightScrollBtn = SARibbonCategoryScrollButton(Qt.RightArrow, parent) 62 | self.m_d.mRightScrollBtn.setVisible(False) 63 | self.m_d.mLeftScrollBtn.clicked.connect(self.onRightScrollButtonClicked) 64 | self.setContentsMargins(1, 1, 1, 1) 65 | 66 | def ribbonCategory(self) -> QWidget: 67 | return self.parentWidget() 68 | 69 | def addItem(self, item: QLayoutItem): 70 | print('Warning: in SARibbonCategoryLayout cannot addItem, use addPannel() instead') 71 | self.invalidate() 72 | 73 | def itemAt(self, index: int) -> QLayoutItem: 74 | """返回pannel的layout""" 75 | item = self.m_d.mItemList[index] if index <= len(self.m_d.mItemList)-1 else None 76 | return item 77 | 78 | def takeAt(self, index: int) -> QLayoutItem: 79 | return self.takePannelItem(index) 80 | 81 | def count(self) -> int: 82 | return len(self.m_d.mItemList) 83 | 84 | def takePannelItem(self, index: int) -> SARibbonCategoryLayoutItem: 85 | if index < 0 or index > len(self.m_d.mItemList)-1: 86 | return None 87 | self.invalidate() 88 | item = self.m_d.mItemList[index] 89 | if item.widget(): 90 | item.widget().hide() 91 | if item.separatorWidget: 92 | item.separatorWidget.hide() 93 | return item 94 | 95 | def takePannel(self, pannel: QWidget) -> SARibbonCategoryLayoutItem: 96 | for i, item in enumerate(self.m_d.mItemList): 97 | if item.widget() == pannel: 98 | return self.takePannelItem(i) 99 | return None 100 | 101 | def addPannel(self, pannel: QWidget): 102 | """追加一个pannel""" 103 | self.insertPannel(self.count(), pannel) 104 | 105 | def insertPannel(self, index: int, pannel: QWidget): 106 | """插入一个pannel""" 107 | index = max(0, index) 108 | index = min(self.count(), index) 109 | item = SARibbonCategoryLayoutItem(pannel) 110 | item.separatorWidget = RibbonSubElementDelegate.createRibbonSeparatorWidget(self.parentWidget()) 111 | self.m_d.mItemList.insert(index, item) 112 | self.invalidate() # 标记需要重新计算尺寸 113 | 114 | def setGeometry(self, rect: QRect): 115 | self.m_d.mDirty = False 116 | self.updateGeometryArr() 117 | super().setGeometry(rect) 118 | self.doLayout() 119 | 120 | def sizeHint(self) -> QSize: 121 | return self.m_d.mSizeHint 122 | 123 | def minimumSize(self) -> QSize: 124 | return self.m_d.mSizeHint 125 | 126 | def expandingDirections(self) -> int: 127 | """SARibbonCategory充满整个stacked widget""" 128 | return Qt.Horizontal | Qt.Vertical 129 | 130 | def invalidate(self): 131 | self.m_d.mDirty = True 132 | super().invalidate() 133 | 134 | def updateGeometryArr(self): 135 | """更新尺寸""" 136 | category: QWidget = self.parentWidget() 137 | categoryWidth = category.width() 138 | mag = self.contentsMargins() 139 | height = category.height() 140 | y = 0 141 | if mag.isNull(): 142 | y = mag.top() 143 | height -= mag.top() + mag.bottom() 144 | categoryWidth -= mag.r + mag.left() 145 | total = self.m_d.totalSizeHintWidth() 146 | canExpandingCount = 0 147 | expandWidth = 0 148 | # 判断是否超过总长度 149 | if total > categoryWidth: 150 | # 超过总长度,需要显示滚动按钮 151 | if self.m_d.mXBase == 0: 152 | # 已经移动到最左,需要可以向右移动 153 | self.m_d.mIsRightScrollBtnShow = True 154 | self.m_d.mIsLeftScrollBtnShow = False 155 | elif self.m_d.mXBase <= categoryWidth - total: 156 | # 已经移动到最右,需要可以向左移动 157 | self.m_d.mIsRightScrollBtnShow = False 158 | self.m_d.mIsLeftScrollBtnShow = True 159 | else: 160 | # 移动到中间两边都可以动 161 | self.m_d.mIsRightScrollBtnShow = True 162 | self.m_d.mIsLeftScrollBtnShow = True 163 | else: 164 | # total 小于 categoryWidth 165 | self.m_d.mIsRightScrollBtnShow = False 166 | self.m_d.mIsLeftScrollBtnShow = False 167 | # 必须这里把mBaseX设置为0,防止滚动按钮调整尺寸导致category无法显示 168 | self.m_d.mXBase = 0 169 | for item in self.m_d.mItemList: 170 | p: QWidget = item.widget() 171 | if p.isExpanding(): # pannel可扩展 172 | canExpandingCount += 1 173 | expandWidth = (categoryWidth-total)/canExpandingCount if canExpandingCount > 0 else 0 174 | 175 | total = 0 # total重新计算 176 | x = self.m_d.mXBase 177 | # 先按照sizeHint设置所有的尺寸 178 | for item in self.m_d.mItemList: 179 | if item.isEmpty(): 180 | if item.separatorWidget: 181 | item.separatorWidget.hide() 182 | item.mWillSetGeometry = QRect(0, 0, 0, 0) 183 | item.mWillSetSeparatorGeometry = QRect(0, 0, 0, 0) 184 | continue 185 | p: QWidget = item.widget() 186 | if not p: 187 | print('unknow widget in SARibbonCategoryLayout') 188 | continue 189 | pSize = p.sizeHint() 190 | separatorSize = item.separatorWidget.sizeHint() if item.separatorWidget else QSize(0, 0) 191 | if p.isExpanding(): 192 | # 可扩展,就把pannel扩展到最大 193 | pSize.setWidth(pSize.width() + expandWidth) 194 | w = pSize.width() 195 | item.mWillSetGeometry = QRect(x, y, w, height) 196 | x += w 197 | total += w 198 | w = separatorSize.width() 199 | item.mWillSetSeparatorGeometry = QRect(x, y, w, height) 200 | x += w 201 | total += w 202 | self.m_d.mTotalWidth = total 203 | cp = category.parentWidget() 204 | parentHeight = height if not cp else cp.height() 205 | parentWidth = total if not cp else cp.width() 206 | self.m_d.mSizeHint = QSize(parentWidth, parentHeight) 207 | 208 | def doLayout(self): 209 | if self.m_d.mDirty: 210 | self.updateGeometryArr() 211 | category: QWidget = self.parentWidget() 212 | # 两个滚动按钮的位置永远不变 213 | self.m_d.mLeftScrollBtn.setGeometry(0, 0, 12, category.height()) 214 | self.m_d.mRightScrollBtn.setGeometry(category.width()-12, 0, 12, category.height()) 215 | showWidgets = list() 216 | hideWidgets = list() 217 | for item in self.m_d.mItemList: 218 | if item.isEmpty(): 219 | hideWidgets.append(item.widget()) 220 | if item.separatorWidget: 221 | hideWidgets.append(item.separatorWidget) 222 | else: 223 | item.widget().setFixedSize(item.mWillSetGeometry.size()) 224 | item.widget().move(item.mWillSetGeometry.topLeft()) 225 | showWidgets.append(item.widget()) 226 | if item.separatorWidget: 227 | item.separatorWidget.setGeometry(item.mWillSetSeparatorGeometry) 228 | showWidgets.append(item.separatorWidget) 229 | self.m_d.mRightScrollBtn.setVisible(self.m_d.mIsRightScrollBtnShow) 230 | self.m_d.mLeftScrollBtn.setVisible(self.m_d.mIsLeftScrollBtnShow) 231 | if self.m_d.mIsRightScrollBtnShow: 232 | self.m_d.mRightScrollBtn.raise_() 233 | if self.m_d.mIsLeftScrollBtnShow: 234 | self.m_d.mLeftScrollBtn.raise_() 235 | # 不在上面进行show和hide因为会触发SARibbonPannelLayout的重绘,导致循环绘制,非常影响效率 236 | for w in showWidgets: 237 | w.show() 238 | for w in hideWidgets: 239 | w.hide() 240 | 241 | def pannels(self) -> List[QWidget]: 242 | """返回所有pannels""" 243 | res = [item.widget() for item in self.m_d.mItemList] 244 | return res 245 | 246 | # 槽函数 247 | def onLeftScrollButtonClicked(self): 248 | category: QWidget = self.parentWidget() 249 | width = category.width() 250 | # 求总宽 251 | totalWidth = self.m_d.mTotalWidth 252 | if totalWidth > width: 253 | tmp = self.m_d.mXBase + width 254 | if tmp > 0: 255 | tmp = 0 256 | self.m_d.mXBase = tmp 257 | else: 258 | self.m_d.mXBase = 0 259 | self.invalidate() 260 | 261 | def onRightScrollButtonClicked(self): 262 | category: QWidget = self.parentWidget() 263 | width = category.width() 264 | # 求总宽 265 | totalWidth = self.m_d.mTotalWidth 266 | if totalWidth > width: 267 | tmp = self.m_d.mXBase - width 268 | if tmp < width - totalWidth: 269 | tmp = width - totalWidth 270 | self.m_d.mXBase = tmp 271 | else: 272 | self.m_d.mXBase = 0 273 | self.invalidate() 274 | 275 | 276 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonContextCategory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonContextCategory 4 | @Author ROOT 5 | 6 | @brief 管理上下文(SARibbonCategory)标签的类 7 | """ 8 | from typing import Any, List 9 | 10 | from PyQt5.QtCore import QObject, pyqtSignal, QEvent 11 | from PyQt5.QtGui import QColor 12 | from PyQt5.QtWidgets import QWidget 13 | 14 | from .SARibbonCategory import SARibbonCategory 15 | 16 | 17 | class SARibbonContextCategory(QObject): 18 | def __init__(self, parent=None): 19 | super().__init__(parent) 20 | self.contextID_ = None 21 | self.contextTitle_ = '' 22 | self.contextColor_ = QColor() 23 | self.categoryDataList: List[SARibbonCategory] = list() 24 | 25 | def addCategoryPage(self, title: str) -> SARibbonCategory: 26 | """上下文目录添加下属目录""" 27 | category = SARibbonCategory(self.parentWidget()) 28 | category.markIsContextCategory(True) 29 | category.setWindowTitle(title) 30 | category.installEventFilter(self) 31 | self.categoryDataList.append(category) 32 | self.categoryPageAdded.emit(category) 33 | 34 | return category 35 | 36 | def categoryCount(self) -> int: 37 | """获取上下文标签下管理的标签个数""" 38 | return len(self.categoryDataList) 39 | 40 | def setId(self, idx): 41 | self.contextID_ = idx 42 | 43 | def id(self) -> Any: 44 | return self.contextID_ 45 | 46 | def setContextColor(self, color: QColor): 47 | self.contextColor_ = color 48 | 49 | def contextColor(self) -> QColor: 50 | return self.contextColor_ 51 | 52 | def setContextTitle(self, contextTitle: str): 53 | self.contextTitle_ = contextTitle 54 | 55 | def contextTitle(self) -> str: 56 | return self.contextTitle_ 57 | 58 | def categoryPage(self, index) -> SARibbonCategory: 59 | """获取对应的tab页""" 60 | return self.categoryDataList[index] 61 | 62 | def categoryList(self) -> List[SARibbonCategory]: 63 | """获取所有的SARibbonCategory""" 64 | return self.categoryDataList 65 | 66 | def takeCategory(self, category: SARibbonCategory) -> bool: 67 | """移除category""" 68 | for i, cat in enumerate(self.categoryDataList): 69 | if category == cat: 70 | self.categoryDataList.pop(i) 71 | return True 72 | return False 73 | 74 | def parentWidget(self) -> QWidget: 75 | """获取父级窗口""" 76 | return self.parent() 77 | 78 | def eventFilter(self, watched, e): 79 | if watched is None: 80 | return False 81 | if e.type() == QEvent.Close: 82 | self.takeCategory(watched) 83 | return False 84 | 85 | # 信号 86 | categoryPageAdded = pyqtSignal(SARibbonCategory) 87 | categoryPageRemoved = pyqtSignal(SARibbonCategory) 88 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonGallery.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonGallery 4 | @Author ROOT 5 | """ 6 | import PySARibbon.resource_rc 7 | from typing import List 8 | from PyQt5.QtCore import QSize, pyqtSignal, Qt, QPoint, QModelIndex 9 | from PyQt5.QtGui import QIcon, QResizeEvent 10 | from PyQt5.QtWidgets import QFrame, QActionGroup, QAction, QWidget, QVBoxLayout, QSizePolicy, QApplication 11 | 12 | from .SAWidgets.SARibbonGalleryGroup import SARibbonGalleryGroup, SARibbonGalleryGroupModel 13 | from .SAWidgets.SARibbonControlButton import SARibbonControlButton 14 | from .SATools.SARibbonElementManager import RibbonSubElementDelegate 15 | 16 | ICON_ARROW_UP = ":/icon/resource/ArrowUp.png" 17 | ICON_ARROW_DOWN = ":/icon/resource/ArrowDown.png" 18 | ICON_ARROW_MORE = ":/icon/resource/ArrowMore.png" 19 | 20 | 21 | class RibbonGalleryViewport(QWidget): 22 | def __init__(self, parent=None): 23 | super().__init__(parent) 24 | self.m_layout: QVBoxLayout = QVBoxLayout(self) 25 | self.m_layout.setSpacing(0) 26 | self.m_layout.setContentsMargins(1, 1, 1, 1) 27 | self.setWindowFlags(Qt.Popup) 28 | 29 | def addWidget(self, w: QWidget): 30 | self.m_layout.addWidget(w) 31 | 32 | 33 | class SARibbonGallery(QFrame): 34 | def __init__(self, parent=None): 35 | super().__init__(parent) 36 | self.buttonUp: SARibbonControlButton = SARibbonControlButton(self) 37 | self.buttonDown: SARibbonControlButton = SARibbonControlButton(self) 38 | self.buttonMore: SARibbonControlButton = SARibbonControlButton(self) 39 | self.actionGroup: QActionGroup = QActionGroup(self) 40 | self.popupWidget: RibbonGalleryViewport = None 41 | self.viewportGroup: SARibbonGalleryGroup = None 42 | 43 | self.init() 44 | self.setFrameShape(QFrame.Box) 45 | self.setFixedHeight(60) 46 | self.setMinimumWidth(88) 47 | self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 48 | 49 | def init(self): 50 | self.buttonUp.setObjectName("SARibbonGalleryButtonUp") 51 | self.buttonUp.setToolButtonStyle(Qt.ToolButtonIconOnly) 52 | self.buttonUp.setFixedSize(15, 20) 53 | self.buttonUp.setIcon(QIcon(ICON_ARROW_UP)) 54 | self.buttonUp.clicked.connect(self.onPageUp) 55 | 56 | self.buttonDown.setObjectName("SARibbonGalleryButtonDown") 57 | self.buttonDown.setToolButtonStyle(Qt.ToolButtonIconOnly) 58 | self.buttonDown.setFixedSize(15, 20) 59 | self.buttonDown.setIcon(QIcon(ICON_ARROW_DOWN)) 60 | self.buttonDown.clicked.connect(self.onPageDown) 61 | 62 | self.buttonMore.setObjectName("SARibbonGalleryButtonMore") 63 | self.buttonMore.setToolButtonStyle(Qt.ToolButtonIconOnly) 64 | self.buttonMore.setFixedSize(15, 20) 65 | self.buttonMore.setIcon(QIcon(ICON_ARROW_MORE)) 66 | self.buttonMore.clicked.connect(self.onShowMoreDetail) 67 | 68 | # self.actionGroup.triggered(self.triggered) 69 | # self.actionGroup.hovered(self.hovered) 70 | 71 | def createPopupWidget(self): 72 | if not self.popupWidget: 73 | self.popupWidget = RibbonGalleryViewport(self) 74 | 75 | def setViewPort(self, group: SARibbonGalleryGroup): 76 | if not self.viewportGroup: 77 | self.viewportGroup = RibbonSubElementDelegate.createRibbonGalleryGroup(self) 78 | self.viewportGroup.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 79 | self.viewportGroup.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 80 | self.viewportGroup.setModel(group.model()) 81 | self.viewportGroup.setEnableIconText(group.enableIconText()) 82 | self.viewportGroup.show() 83 | 84 | def addGalleryGroup(self, *_atgs): 85 | """ 86 | addGalleryGroup() -> SARibbonGalleryGroup 87 | addGalleryGroup(SARibbonGalleryGroup) 88 | """ 89 | if len(_atgs) == 0: 90 | group = RibbonSubElementDelegate.createRibbonGalleryGroup(self) 91 | self.addGalleryGroup(group) 92 | return group 93 | else: 94 | group: SARibbonGalleryGroup = _atgs[0] 95 | group.setModel(SARibbonGalleryGroupModel(self)) 96 | if self.viewportGroup is None: 97 | self.setCurrentViewGroup(group) 98 | group.clicked.connect(self.onItemClicked) 99 | viewport = self.ensureGetPopupViewPort() 100 | viewport.addWidget(group) 101 | 102 | def setCurrentViewGroup(self, group: SARibbonGalleryGroup): 103 | self.setViewPort(group) 104 | QApplication.postEvent(self, QResizeEvent(self.size(), self.size())) 105 | 106 | def currentViewGroup(self) -> SARibbonGalleryGroup: 107 | return self.viewportGroup 108 | 109 | def addCategoryActions(self, title: str, actions: List[QAction]) -> SARibbonGalleryGroup: 110 | group = RibbonSubElementDelegate.createRibbonGalleryGroup(self) 111 | model = SARibbonGalleryGroupModel(self) 112 | group.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) 113 | group.setModel(model) 114 | if title: 115 | group.setGroupTitle(title) 116 | for a in actions: 117 | self.actionGroup.addAction(a) 118 | group.addActionItemList(actions) 119 | group.clicked.connect(self.onItemClicked) 120 | viewport = self.ensureGetPopupViewPort() 121 | viewport.addWidget(group) 122 | self.setCurrentViewGroup(group) 123 | return group 124 | 125 | def getActionGroup(self) -> QActionGroup: 126 | return self.actionGroup 127 | 128 | def ensureGetPopupViewPort(self) -> RibbonGalleryViewport: 129 | if self.popupWidget is None: 130 | self.createPopupWidget() 131 | return self.popupWidget 132 | 133 | def sizeHint(self) -> QSize: 134 | return QSize(232, 60) 135 | 136 | def minimumSizeHint(self) -> QSize: 137 | return QSize(88, 60) 138 | 139 | # 槽函数 140 | def onPageDown(self): 141 | if self.viewportGroup: 142 | vscrollBar = self.viewportGroup.verticalScrollBar() 143 | v = vscrollBar.value() 144 | v += vscrollBar.singleStep() 145 | vscrollBar.setValue(v) 146 | 147 | def onPageUp(self): 148 | if self.viewportGroup: 149 | vscrollBar = self.viewportGroup.verticalScrollBar() 150 | v = vscrollBar.value() 151 | v -= vscrollBar.singleStep() 152 | vscrollBar.setValue(v) 153 | 154 | def onShowMoreDetail(self): 155 | if self.popupWidget: 156 | return 157 | popupMenuSize = self.popupWidget.minimumSizeHint() 158 | start = self.mapToGlobal(QPoint(0, 0)) 159 | self.popupWidget.setGeometry(start.x(), start.y(), self.width(), popupMenuSize.height()) 160 | self.popupWidget.show() 161 | 162 | def onItemClicked(self, index: QModelIndex): 163 | group = self.sender() 164 | curGroup = self.currentViewGroup() 165 | if not curGroup: 166 | self.setCurrentViewGroup(group) 167 | curGroup = self.currentViewGroup() 168 | if curGroup.model() != group.model(): 169 | curGroup.setModel(group.model()) 170 | curGroup.scrollTo(index) 171 | curGroup.setCurrentIndex(index) 172 | curGroup.repaint() 173 | 174 | # 事件 175 | def resizeEvent(self, e): 176 | r = e.size() 177 | subW = 0 178 | self.buttonUp.move(r.width() - self.buttonUp.width(), 0) 179 | subW = max(subW, self.buttonUp.width()) 180 | self.buttonDown.move(r.width() - self.buttonDown.width(), self.buttonDown.height()) 181 | subW = max(subW, self.buttonDown.width()) 182 | self.buttonMore.move(r.width() - self.buttonMore.width(), self.buttonDown.geometry().bottom()) 183 | subW = max(subW, self.buttonMore.width()) 184 | if self.viewportGroup: 185 | self.viewportGroup.setGeometry(0, 0, r.width() - subW, r.height()) 186 | super().resizeEvent(e) 187 | 188 | # 信号 189 | triggered = pyqtSignal(QAction) 190 | hovered = pyqtSignal(QAction) 191 | 192 | 193 | if __name__ == '__main__': 194 | from PyQt5.QtWidgets import QApplication 195 | 196 | app = QApplication([]) 197 | mainWindow = QWidget() 198 | 199 | gallery = SARibbonGallery(mainWindow) 200 | # gallery.resize(mainWindow.width(), gallery.size().height()) 201 | group = gallery.addGalleryGroup() 202 | group.addActionItem(QAction(QIcon('resource/icon/folder.png'), 'test')) 203 | for i in range(10): 204 | group.addItem('test '+str(i), QIcon('resource/icon/folder.png')) 205 | 206 | mainWindow.setMinimumWidth(500) 207 | mainWindow.show() 208 | app.exec() 209 | 210 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonMainWindow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonMainWindow 4 | @Author ROOT 5 | 6 | @brief 如果要使用SARibbonBar,必须使用此类代替QMainWindow 7 | 8 | 由于ribbon的风格和传统的Toolbar风格差异较大, 9 | SARibbonBar使用需要把原有的QMainWindow替换为SARibbonMainWindow, 10 | SARibbonMainWindow是个无边框窗体,继承自QMainWindow,其构造函数的参数useRibbon 11 | 用于指定是否使用ribbon风格,默认为true 12 | 13 | 如果想换回非ribbon风格,只需要把useRibbon设置为false即可, 14 | 成员函数isUseRibbon用于判断当前是否为ribbon模式,这个函数在兼容传统Toolbar风格和ribbon风格时非常有用。 15 | 16 | @ref SARibbonMainWindow 提供了几种常用的ribbon样式,样式可见@ref RibbonTheme 17 | 通过@ref setRibbonTheme 可改变ribbon的样式,用户也可通过qss自己定义自己的样式 18 | """ 19 | from PyQt5.QtCore import QFile, QIODevice 20 | from PyQt5.QtCore import QObject, QEvent 21 | from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QMenuBar 22 | 23 | from .SAFramelessHelper import SAFramelessHelper 24 | from .SAWindowButtonGroup import SAWindowButtonGroup 25 | from .SARibbonBar import SARibbonBar 26 | 27 | 28 | class SARibbonMainWindow(QMainWindow): 29 | def __init__(self, parent=None, useRibbon=True): 30 | super().__init__(parent) 31 | self.m_useRibbon = useRibbon 32 | self.m_currentRibbonTheme = SARibbonMainWindow.Office2013 33 | self.m_ribbonBar: SARibbonBar = None 34 | self.m_windowButtonGroup: SAWindowButtonGroup = None 35 | self.m_framelessHelper: SAFramelessHelper = None 36 | 37 | if self.m_useRibbon: 38 | self.setRibbonTheme(self.ribbonTheme()) 39 | self.setMenuWidget(SARibbonBar(self)) 40 | 41 | def ribbonBar(self) -> SARibbonBar: 42 | """ 43 | 返回SARibbonBar,如果useRibbon为false,会返回None 44 | """ 45 | return self.m_ribbonBar 46 | 47 | def setRibbonTheme(self, theme): 48 | if theme == SARibbonMainWindow.NormalTheme: 49 | self.loadTheme(':/theme/resource/default.qss') 50 | elif theme == SARibbonMainWindow.Office2013: 51 | self.loadTheme(':/theme/resource/office2013.qss') 52 | else: 53 | self.loadTheme(':/theme/resource/default.qss') 54 | 55 | def ribbonTheme(self) -> int: 56 | return self.m_currentRibbonTheme 57 | 58 | def isUseRibbon(self) -> bool: 59 | """ 60 | 判断当前是否使用ribbon模式 61 | """ 62 | return self.m_useRibbon 63 | 64 | def updateWindowFlag(self, flags): 65 | """ 66 | 此函数仅用于控制最小最大化和关闭按钮的显示 67 | """ 68 | if self.isUseRibbon(): 69 | self.m_windowButtonGroup.updateWindowFlag(flags) 70 | self.repaint() 71 | 72 | def windowButtonFlags(self) -> int: 73 | """ 74 | 获取系统按钮的状态 75 | """ 76 | if self.isUseRibbon(): 77 | return self.m_windowButtonGroup.windowButtonFlags() 78 | return self.windowFlags() 79 | 80 | def loadTheme(self, filepath: str): 81 | """加载主题""" 82 | qFile = QFile(filepath) 83 | if not qFile.open(QIODevice.ReadOnly | QIODevice.Text): 84 | return 85 | style_str = str(qFile.readAll(), encoding='utf-8') 86 | self.setStyleSheet(style_str) 87 | 88 | def setMenuWidget(self, ribbonBar: QWidget): 89 | """ 90 | 覆写setMenuWidget 91 | """ 92 | if ribbonBar: 93 | self.m_ribbonBar: SARibbonBar = ribbonBar 94 | self.m_ribbonBar.installEventFilter(self) 95 | 96 | if self.m_framelessHelper is None: 97 | self.m_framelessHelper = SAFramelessHelper(self) 98 | # 设置窗体的标题栏高度 99 | self.m_framelessHelper.setTitleHeight(ribbonBar.titleBarHeight()) 100 | 101 | # 设置window按钮 102 | if self.m_windowButtonGroup is None: 103 | self.m_windowButtonGroup = SAWindowButtonGroup(self) 104 | s = self.m_windowButtonGroup.size() 105 | s.setHeight(ribbonBar.titleBarHeight()) 106 | self.m_windowButtonGroup.setFixedSize(s) 107 | self.m_windowButtonGroup.setWindowStates(self.windowState()) 108 | self.m_useRibbon = True 109 | 110 | super().setMenuWidget(ribbonBar) 111 | 112 | def setMenuBar(self, ribbonBar: QMenuBar): 113 | """ 114 | 覆写setMenuBar 115 | """ 116 | if ribbonBar: 117 | self.m_ribbonBar = ribbonBar 118 | self.m_ribbonBar.installEventFilter(self) 119 | # 设置窗体的标题栏高度 120 | if self.m_framelessHelper is None: 121 | self.m_framelessHelper = SAFramelessHelper(self) 122 | self.m_framelessHelper.setTitleHeight(self.m_ribbonBar.titleBarHeight()) 123 | 124 | # 设置window按钮 125 | if self.m_windowButtonGroup is None: 126 | self.m_windowButtonGroup = SAWindowButtonGroup(self) 127 | s = self.m_windowButtonGroup.size() 128 | s.setHeight(self.m_ribbonBar.titleBarHeight()) 129 | self.m_windowButtonGroup.setFixedSize(s) 130 | self.m_windowButtonGroup.setWindowStates(self.windowState()) 131 | self.m_useRibbon = True 132 | 133 | super().setMenuBar(ribbonBar) 134 | 135 | def eventFilter(self, obj: QObject, e: QEvent) -> bool: 136 | """ 137 | 过滤是为了把ribbonBar上的动作传递到mainwindow,再传递到frameless 138 | 由于ribbonbar会遮挡frameless的区域,导致frameless无法捕获这些消息 139 | """ 140 | if obj == self.m_ribbonBar: 141 | e_list = [ 142 | QEvent.MouseButtonPress, 143 | QEvent.MouseButtonRelease, 144 | QEvent.MouseMove, 145 | QEvent.Leave, 146 | QEvent.HoverMove, 147 | QEvent.MouseButtonDblClick 148 | ] 149 | if e.type() in e_list: 150 | QApplication.sendEvent(self, e) 151 | return super().eventFilter(obj, e) 152 | 153 | # 事件 154 | def event(self, e: QEvent): 155 | if e and e.type() == QEvent.WindowStateChange: 156 | if self.isUseRibbon(): 157 | self.m_windowButtonGroup.setWindowStates(self.windowState()) 158 | return super().event(e) 159 | 160 | def resizeEvent(self, e): 161 | if self.m_ribbonBar: 162 | if self.m_ribbonBar.size().width() != self.size().width(): 163 | self.m_ribbonBar.setFixedWidth(self.size().width()) 164 | if self.m_windowButtonGroup: 165 | self.m_ribbonBar.setWindowButtonSize(self.m_windowButtonGroup.size()) 166 | super().resizeEvent(e) 167 | 168 | NormalTheme = 0 # 普通主题 169 | Office2013 = 1 # office2013主题 170 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonPannel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonPannel 4 | @Author ROOT 5 | 6 | @brief pannel页窗口,pannel是ribbon的面板用于承放控件 7 | ribbon的pannel分为两行模式和三行模式,以office为代表的ribbon为3行模式,以WPS为代表的“紧凑派”就是2行模式, 8 | SARibbon可通过SARibbonBar的 SARibbonBar.RibbonStyle 来指定模式(通过函数 SARibbonBar.setRibbonStyle) 9 | 10 | 在pannel中,可以通过setExpanding 函数指定pannel水平扩展,如果pannel里面没有能水平扩展的控件,将会留白, 11 | 因此,建议在pannel里面有水平扩展的控件如(SARibbonGallery)才指定这个函数 12 | 13 | pannel的布局通过 SARibbonPannelLayout 来实现,如果有其他布局,可以通过继承 SARibbonElementCreateDelegate.createRibbonPannel 14 | 函数返回带有自己布局的pannel,但你必须继承对应的虚函数 15 | """ 16 | from typing import List, Union 17 | 18 | from PyQt5.QtCore import pyqtSignal, Qt, QEvent, QSize 19 | from PyQt5.QtGui import QPainter 20 | from PyQt5.QtWidgets import QApplication, QWidget, QAction, QToolButton, QMenu, QSizePolicy 21 | 22 | from .SAWidgets.SARibbonPannelOptionButton import SARibbonPannelOptionButton 23 | from .SAWidgets.SARibbonSeparatorWidget import SARibbonSeparatorWidget 24 | from .SAWidgets.SARibbonToolButton import SARibbonToolButton 25 | from .SAWidgets.SARibbonPannelItem import SARibbonPannelItem 26 | from .SATools.SARibbonElementManager import RibbonSubElementDelegate 27 | from .SARibbonGallery import SARibbonGallery 28 | from .SARibbonPannelLayout import SARibbonPannelLayout 29 | 30 | 31 | class SARibbonPannel(QWidget): 32 | def __init__(self, *_args): 33 | """ 34 | SARibbonPannel(parent=None) 35 | SARibbonPannel(str, parent=None) 36 | """ 37 | parent = None 38 | name = '' 39 | arg_len = len(_args) 40 | if arg_len > 0 and isinstance(_args[0], str): 41 | parent = _args[1] if arg_len >= 2 else None 42 | name = _args[0] 43 | elif arg_len > 0: 44 | parent = _args[0] 45 | super().__init__(parent) 46 | 47 | self.m_pannelLayoutMode = SARibbonPannel.ThreeRowMode 48 | self.m_lastRp = SARibbonPannelItem.RPNone 49 | self.m_optionActionButton: SARibbonPannelOptionButton = None 50 | self.m_layout: SARibbonPannelLayout = None 51 | self.m_isCanCustomize = True 52 | 53 | self.createLayout() 54 | self.setPannelLayoutMode(SARibbonPannel.ThreeRowMode) 55 | self.setPannelName(name) 56 | 57 | def createLayout(self): 58 | layout = SARibbonPannelLayout(self) 59 | layout.setRowCount(self.rowCount()) 60 | layout.setSpacing(2) 61 | layout.setContentsMargins(2, 2, 2, 2) 62 | self.setLayout(layout) 63 | self.m_layout = layout 64 | 65 | def rowCount(self) -> int: 66 | # SARibbonPannel.TwoRowMode 或 SARibbonPannel.ThreeRowMode 67 | count = 2 if self.pannelLayoutMode() == SARibbonPannel.TwoRowMode else 3 68 | return count 69 | 70 | def pannelLayoutMode(self) -> int: 71 | return self.m_pannelLayoutMode 72 | 73 | def isTwoRow(self) -> bool: 74 | """判断是否为2行模式""" 75 | return self.rowCount() == 2 76 | 77 | def lastAddActionButton(self) -> SARibbonToolButton: 78 | lastWidget = self.m_layout.lastWidget() 79 | if not isinstance(lastWidget, SARibbonToolButton): 80 | print(__file__, 'lastAddActionButton', type(lastWidget)) 81 | raise Exception('lastAddActionButton: last Widget is not SARibbonToolButton') 82 | return lastWidget 83 | 84 | def setActionRowProportion(self, act: QAction, rp): 85 | lay = self.m_layout 86 | it = lay.pannelItem(act) 87 | if it: 88 | it.rowProportion = rp 89 | lay.invalidate() 90 | 91 | def addAction(self, *_args) -> Union[SARibbonToolButton, QAction]: 92 | """ 93 | addAction(QAction, rp: int) -> SARibbonToolButton 94 | addAction(str, QIcon, popMode: int, rp=SARibbonPannelItem.RPLarge) -> QAction 95 | """ 96 | 97 | if len(_args) >= 3: 98 | rp = SARibbonPannelItem.RPLarge if len(_args) < 4 else _args[3] 99 | act = QAction(_args[1], _args[0], self) 100 | self.m_lastRp = rp 101 | super().addAction(act) 102 | btn = self.lastAddActionButton() 103 | if btn: 104 | btn.setPopupMode(_args[2]) 105 | return act 106 | else: # if len(_args) == 2 107 | self.m_lastRp = _args[1] 108 | super().addAction(_args[0]) 109 | return self.lastAddActionButton() 110 | 111 | def addLargeAction(self, act: QAction) -> SARibbonToolButton: 112 | return self.addAction(act, SARibbonPannelItem.RPLarge) 113 | 114 | def addMediumAction(self, act: QAction) -> SARibbonToolButton: 115 | return self.addAction(act, SARibbonPannelItem.RPMedium) 116 | 117 | def addSmallAction(self, act: QAction) -> SARibbonToolButton: 118 | return self.addAction(act, SARibbonPannelItem.RPSmall) 119 | 120 | def addMenu(self, menu: QMenu, rp, popMode=QToolButton.InstantPopup) -> SARibbonToolButton: 121 | """添加一个普通菜单""" 122 | act = menu.menuAction() 123 | self.addAction(act, rp) 124 | btn = self.lastAddActionButton() 125 | btn.setPopupMode(popMode) 126 | return btn 127 | 128 | def addActionMenu(self, action: QAction, menu: QMenu, rp) -> SARibbonToolButton: 129 | """添加一个ActionMenu""" 130 | self.addAction(action, rp) 131 | btn = self.lastAddActionButton() 132 | btn.setMenu(menu) 133 | btn.setPopupMode(QToolButton.MenuButtonPopup) 134 | return btn 135 | 136 | def addLargeActionMenu(self, action: QAction, menu: QMenu) -> SARibbonToolButton: 137 | return self.addActionMenu(action, menu, SARibbonPannelItem.RPLarge) 138 | 139 | def addLargeMenu(self, menu: QMenu, popMode=QToolButton.InstantPopup) -> SARibbonToolButton: 140 | return self.addMenu(menu, SARibbonPannelItem.RPLarge, popMode) 141 | 142 | def addSmallMenu(self, menu: QMenu, popMode=QToolButton.InstantPopup) -> SARibbonToolButton: 143 | return self.addMenu(menu, SARibbonPannelItem.RPSmall, popMode) 144 | 145 | def addWidget(self, w: QWidget, rp): 146 | """添加Widget窗口""" 147 | w.setAttribute(Qt.WA_Hover) 148 | self.m_layout.addWidget(w, rp) 149 | self.updateGeometry() 150 | 151 | def addSmallWidget(self, w: QWidget): 152 | return self.addWidget(w, SARibbonPannelItem.RPSmall) 153 | 154 | def addLargeWidget(self, w: QWidget): 155 | return self.addWidget(w, SARibbonPannelItem.RPLarge) 156 | 157 | def addGallery(self, gallery: SARibbonGallery): 158 | """SARibbonPannel将拥有SARibbonGallery的管理权""" 159 | self.addLargeWidget(gallery) 160 | self.setExpanding() 161 | 162 | def addSeparator(self, top=6, bottom=6): 163 | """添加分割线""" 164 | sep = SARibbonSeparatorWidget(self) 165 | sep.setTopBottomMargins(top, bottom) 166 | self.m_layout.addWidget(sep) 167 | self.updateGeometry() 168 | 169 | def actionToRibbonToolButton(self, action: QAction) -> Union[SARibbonToolButton, None]: 170 | """从pannel中把action对应的button提取出来""" 171 | lay = self.layout() 172 | if not lay: 173 | return None 174 | 175 | index = lay.indexOf(action) 176 | if index == -1: 177 | return None 178 | item = lay.takeAt(index) 179 | btn = item.widget() if item else None 180 | return btn 181 | 182 | def addOptionAction(self, action: QAction = None): 183 | """添加操作action,如果要去除,传入None即可""" 184 | if action is None and self.m_optionActionButton: 185 | self.m_optionActionButton = None 186 | self.m_layout.setOptionAction(True, self.optionActionButtonSize()) 187 | return 188 | if self.m_optionActionButton is None: 189 | self.m_optionActionButton = RibbonSubElementDelegate.createRibbonPannelOptionButton(self) 190 | self.m_optionActionButton.setFixedSize(self.optionActionButtonSize()) 191 | self.m_optionActionButton.setIconSize(self.optionActionButtonSize() - QSize(-2, -2)) 192 | self.m_optionActionButton.connectAction(action) 193 | self.m_layout.setOptionAction(True, self.optionActionButtonSize()) 194 | self.updateGeometry() 195 | self.repaint() 196 | 197 | def isHaveOptionAction(self) -> bool: 198 | """判断是否存在OptionAction""" 199 | return not (self.m_optionActionButton is None) 200 | 201 | def optionActionButtonSize(self) -> QSize: 202 | """返回optionActionButton的尺寸""" 203 | size = QSize(12, 12) if self.isTwoRow() else QSize(16, 16) 204 | return size 205 | 206 | def ribbonToolButtons(self) -> List[SARibbonToolButton]: 207 | """获取pannel下面的所有toolbutton""" 208 | objs = self.children() 209 | return [obj for obj in objs if isinstance(obj, SARibbonToolButton)] 210 | 211 | def sizeHint(self): 212 | laySize = self.layout().sizeHint() 213 | maxWidth = laySize.width() + 2 214 | if self.pannelLayoutMode() == self.ThreeRowMode: 215 | # 三行模式 216 | fm = self.fontMetrics() 217 | titleSize = fm.size(Qt.TextShowMnemonic, self.windowTitle()) 218 | if self.m_optionActionButton: 219 | # optionActionButton的宽度需要预留 220 | titleSize.setWidth(titleSize.width()+self.m_optionActionButton.width()+4) 221 | maxWidth = max(maxWidth, laySize.height()) 222 | return QSize(maxWidth, laySize.height()) 223 | 224 | def minimumSizeHint(self): 225 | return self.layout().minimumSize() 226 | 227 | def setExpanding(self, isExpanding=True): 228 | """把pannel设置为扩展模式,此时会撑大水平区域""" 229 | p = QSizePolicy.Expanding if isExpanding else QSizePolicy.Preferred 230 | self.setSizePolicy(p, QSizePolicy.Preferred) 231 | 232 | def isExpanding(self) -> bool: 233 | """判断此pannel是否为(水平)扩展模式""" 234 | sp = self.sizePolicy() 235 | return sp.horizontalPolicy() == QSizePolicy.Expanding 236 | 237 | def titleHeight(self) -> int: 238 | """标题栏高度,仅在三行模式下生效""" 239 | h = 0 if self.isTwoRow() else 21 240 | return h 241 | 242 | def actionIndex(self, act: QAction): 243 | """action对应的布局index,此操作一般用于移动,其他意义不大""" 244 | return self.m_layout.indexOf(act) 245 | 246 | def moveAction(self, fr: int, to: int): 247 | """移动action""" 248 | self.m_layout.move(fr, to) 249 | self.updateGeometry() 250 | 251 | def isCanCustomize(self) -> bool: 252 | """判断是否可以自定义""" 253 | return self.m_isCanCustomize 254 | 255 | def setCanCustomize(self, b: bool): 256 | """设置是否可以自定义""" 257 | self.m_isCanCustomize = b 258 | 259 | def pannelName(self) -> str: 260 | """pannel的标题""" 261 | return self.windowTitle() 262 | 263 | def setPannelName(self, title: str): 264 | """设置pannel的标题""" 265 | if not title: 266 | return 267 | self.setWindowTitle(title) 268 | self.update() # 注意会触发windowTitleChange信号 269 | 270 | def setPannelLayoutMode(self, mode): 271 | if self.m_pannelLayoutMode == mode: 272 | return 273 | self.m_pannelLayoutMode = mode 274 | self.resetLayout(mode) 275 | self.resetLargeToolButtonStyle() 276 | 277 | def resetLayout(self, mode): 278 | sp = 4 if self.TwoRowMode == mode else 2 279 | self.layout().setSpacing(sp) 280 | self.updateGeometry() # 通知layout进行重新布局 281 | 282 | def resetLargeToolButtonStyle(self): 283 | """重置大按钮的类型""" 284 | btns = self.ribbonToolButtons() 285 | for b in btns: 286 | if not b or SARibbonToolButton.LargeButton != b.buttonType(): 287 | continue 288 | if SARibbonPannel.ThreeRowMode == self.pannelLayoutMode(): 289 | if SARibbonToolButton.Normal != b.largeButtonType(): 290 | b.setLargeButtonType(SARibbonToolButton.Normal) 291 | else: 292 | if SARibbonToolButton.Lite != b.largeButtonType(): 293 | b.setLargeButtonType(SARibbonToolButton.Lite) 294 | 295 | def ribbonPannelItem(self) -> List[SARibbonPannelItem]: 296 | return self.m_layout.m_items 297 | 298 | @staticmethod 299 | def maxHightIconSize(size: QSize, h: int) -> QSize: 300 | if size.height() < h: 301 | r = h / size.height() 302 | return QSize(int(size.width() * r), h) 303 | return size 304 | 305 | # 事件 306 | def paintEvent(self, e): 307 | # 绘制小标题 308 | if SARibbonPannel.ThreeRowMode == self.pannelLayoutMode(): 309 | p = QPainter(self) 310 | f = self.font() 311 | p.setFont(f) 312 | th = self.titleHeight() 313 | tw = self.width()-self.m_optionActionButton.width()-4 if self.m_optionActionButton else self.width() 314 | p.drawText(1, self.height() - th, tw, th, Qt.AlignCenter, self.windowTitle()) 315 | super().paintEvent(e) 316 | 317 | def resizeEvent(self, e): 318 | # 首先,移动操作按钮到角落 319 | if self.m_optionActionButton: 320 | if SARibbonPannel.ThreeRowMode == self.pannelLayoutMode(): 321 | self.m_optionActionButton.move( 322 | self.width() - self.m_optionActionButton.width() - 2, 323 | self.height() - int((self.titleHeight() + self.m_optionActionButton.height()) / 2) 324 | ) 325 | else: 326 | self.m_optionActionButton.move( 327 | self.width() - self.m_optionActionButton.width(), 328 | self.height() - self.m_optionActionButton.height() 329 | ) 330 | # 由于分割线在布局中,只要分割线足够高就可以,不需要重新设置 331 | return super().resizeEvent(e) 332 | 333 | def actionEvent(self, e): 334 | """ 335 | 处理action的事件 336 | 这里处理了ActionAdded,ActionChanged,ActionRemoved三个事件 337 | """ 338 | action: QAction = e.action() 339 | if e.type() == QEvent.ActionAdded: 340 | if action and action.parent() != self: 341 | action.setParent(self) 342 | # if e.before(): # 说明是插入 343 | # index = lay.indexOf(action) 344 | self.m_layout.addAction(action, self.m_lastRp) 345 | self.m_lastRp = SARibbonPannelItem.RPNone # 插入完后重置为None 346 | # 由于pannel的尺寸发生变化,需要让category也调整 347 | if self.parentWidget(): 348 | QApplication.postEvent(self.parentWidget(), QEvent(QEvent.LayoutRequest)) 349 | elif e.type() == QEvent.ActionChanged: 350 | # 让布局重新绘制 351 | self.layout().invalidate() 352 | # 由于pannel的尺寸发生变化,需要让category也调整 353 | if self.parentWidget(): 354 | QApplication.postEvent(self.parentWidget(), QEvent(QEvent.LayoutRequest)) 355 | elif e.type() == QEvent.ActionRemoved: 356 | action.disconnect(self) 357 | index = self.m_layout.indexOf(action) 358 | if index != -1: 359 | self.m_layout.takeAt(index) 360 | # 由于pannel的尺寸发生变化,需要让category也调整 361 | if self.parentWidget(): 362 | QApplication.postEvent(self.parentWidget(), QEvent(QEvent.LayoutRequest)) 363 | 364 | # 信号 365 | actionTriggered = pyqtSignal(QAction) 366 | 367 | # PannelLayoutMode 368 | ThreeRowMode = SARibbonPannelLayout.ThreeRowMode 369 | TwoRowMode = SARibbonPannelLayout.TwoRowMode 370 | 371 | 372 | if __name__ == '__main__': 373 | from PyQt5.QtGui import QIcon 374 | 375 | app = QApplication([]) 376 | # mainWindow = QWidget() 377 | pannel = SARibbonPannel('Pannel One', None) 378 | mainWindow = pannel 379 | 380 | act = QAction(QIcon("resource/icon/figureIcon.png"), 'test1', pannel) 381 | pannel.addLargeAction(act) 382 | 383 | act = QAction(QIcon("resource/icon/figureIcon.png"), 'test1', pannel) 384 | pannel.addSmallAction(act) 385 | act = QAction(QIcon("resource/icon/figureIcon.png"), 'test1', pannel) 386 | pannel.addSmallAction(act) 387 | act = QAction(QIcon("resource/icon/figureIcon.png"), 'test1', pannel) 388 | pannel.addSmallAction(act) 389 | 390 | pannel.addSeparator() 391 | 392 | gallery = SARibbonGallery(pannel) 393 | group = gallery.addGalleryGroup() 394 | group.addActionItem(QAction(QIcon('resource/icon/folder.png'), 'test')) 395 | for i in range(10): 396 | group.addItem('test ' + str(i), QIcon('resource/icon/folder.png')) 397 | 398 | pannel.addGallery(gallery) 399 | # pannel.addLargeWidget(gallery) 400 | 401 | mainWindow.setMinimumWidth(500) 402 | mainWindow.show() 403 | app.exec() 404 | -------------------------------------------------------------------------------- /src/PySARibbon/SARibbonQuickAccessBar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonQuickAccessBar 4 | @Author ROOT 5 | 6 | @brief ribbon左上顶部的快速响应栏(WPS风格在右上角) 7 | """ 8 | from PyQt5.QtWidgets import QAction, QWidget, QToolButton, QMenu, QStyleOption 9 | 10 | from .SARibbonButtonGroupWidget import SARibbonButtonGroupWidget 11 | from .SAWidgets.SARibbonCtrlContainer import SARibbonCtrlContainer 12 | 13 | 14 | class SARibbonQuickAccessBar(SARibbonCtrlContainer): 15 | def __init__(self, parent=None): 16 | super().__init__(None, parent) 17 | self.groupWidget = SARibbonButtonGroupWidget() 18 | self.setContainerWidget(self.groupWidget) 19 | 20 | def addSeparator(self): 21 | self.groupWidget.addSeparator() 22 | 23 | def addAction(self, act: QAction): 24 | self.groupWidget.addAction(act) 25 | 26 | def addWidget(self, w: QWidget): 27 | self.groupWidget.addWidget(w) 28 | 29 | def addMenu(self, m: QMenu, popmode=QToolButton.InstantPopup): 30 | self.groupWidget.addMenu(m, popmode) 31 | 32 | def initStyleOption(self, opt: QStyleOption): 33 | opt.initFrom(self) 34 | -------------------------------------------------------------------------------- /src/PySARibbon/SATools/SARibbonDrawHelper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonDrawHelper 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtCore import Qt, QSize, QRect 7 | from PyQt5.QtGui import QPixmap, QIcon, QPainter 8 | from PyQt5.QtWidgets import QWidget, QStyleOption, QStyle 9 | 10 | 11 | class SARibbonDrawHelper: 12 | """ 13 | 绘图辅助 14 | """ 15 | @staticmethod 16 | def iconToPixmap(icon: QIcon, widget: QWidget, opt: QStyleOption, icoSize: QSize) -> QPixmap: 17 | mode = QIcon.Normal 18 | if not (opt.state & QStyle.State_Enabled): 19 | mode = QIcon.Disabled 20 | elif (opt.state & QStyle.State_MouseOver) and (opt.state & QStyle.State_AutoRaise): 21 | mode = QIcon.Active 22 | 23 | state = QIcon.Off 24 | if (opt.state & QStyle.State_Selected) or (opt.state & QStyle.State_On): 25 | state = QIcon.On 26 | 27 | return icon.pixmap(widget.window().windowHandle(), icoSize, mode, state) 28 | 29 | @staticmethod 30 | def drawIcon(icon: QIcon, painter: QPainter, opt: QStyleOption, *_args): 31 | """ 32 | drawIcon(QIcon, QPainter, QStyleOption, int, int, int, int) 33 | drawIcon(QIcon, QPainter, QStyleOption, QRect) 34 | """ 35 | if len(_args) < 1: 36 | return 37 | if isinstance(_args[0], int): 38 | rect = QRect(_args[0], _args[1], _args[2], _args[3]) 39 | else: 40 | rect = _args[0] 41 | 42 | mode = QIcon.Normal 43 | if not (opt.state & QStyle.State_Enabled): 44 | mode = QIcon.Disabled 45 | elif (opt.state & QStyle.State_MouseOver) and (opt.state & QStyle.State_AutoRaise): 46 | mode = QIcon.Active 47 | 48 | state = QIcon.Off 49 | if (opt.state & QStyle.State_Selected) or (opt.state & QStyle.State_On): 50 | state = QIcon.On 51 | 52 | icon.paint(painter, rect, Qt.AlignCenter, mode, state) 53 | 54 | @staticmethod 55 | def iconActualSize(icon: QIcon, opt: QStyleOption, icoSize: QSize) -> QSize: 56 | mode = QIcon.Normal 57 | if not (opt.state & QStyle.State_Enabled): 58 | mode = QIcon.Disabled 59 | elif (opt.state & QStyle.State_MouseOver) and (opt.state & QStyle.State_AutoRaise): 60 | mode = QIcon.Active 61 | 62 | state = QIcon.Off 63 | if (opt.state & QStyle.State_Selected) or (opt.state & QStyle.State_On): 64 | state = QIcon.On 65 | 66 | return icon.actualSize(icoSize, mode, state) 67 | 68 | @staticmethod 69 | def drawText(text: str, painter: QPainter, opt: QStyleOption, align, *_args): 70 | """ 71 | drawText(str, QPainter, QStyleOption, Qt.Alignment, int, int, int, int) 72 | drawText(str, QPainter, QStyleOption, Qt.Alignment, QRect) 73 | """ 74 | if len(_args) < 1: 75 | return 76 | if isinstance(_args[0], int): 77 | rect = QRect(_args[0], _args[1], _args[2], _args[3]) 78 | else: 79 | rect = _args[0] 80 | 81 | painter.drawItemText(rect, align, opt.palette, 82 | opt.state & QStyle.State_Enabled, text) 83 | -------------------------------------------------------------------------------- /src/PySARibbon/SATools/SARibbonElementCreateDelegate.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonElementCreateDelegate 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtCore import Qt, QMargins 7 | from PyQt5.QtGui import QColor 8 | 9 | from ..SAWidgets.SARibbonTabBar import SARibbonTabBar 10 | from ..SAWidgets.SARibbonApplicationButton import SARibbonApplicationButton 11 | from ..SAWidgets.SARibbonSeparatorWidget import SARibbonSeparatorWidget 12 | from ..SAWidgets.SARibbonGalleryGroup import SARibbonGalleryGroup 13 | from ..SAWidgets.SARibbonToolButton import SARibbonToolButton 14 | from ..SAWidgets.SARibbonStackedWidget import SARibbonStackedWidget 15 | from ..SAWidgets.SARibbonControlButton import SARibbonControlButton 16 | from ..SAWidgets.SARibbonPannelOptionButton import SARibbonPannelOptionButton 17 | 18 | 19 | class SARibbonStyleOption: 20 | """ 21 | @brief 定义了saribbon所有尺寸相关信息,saribbon的建立都基于此类的尺寸,如果想调整, 22 | 可以重载 @ref SARibbonElementCreateDelegate 的 @ref getRibbonStyleOption 函数 23 | """ 24 | def __init__(self): 25 | self.mainbarHeightOfficeStyleThreeRow: int = 160 # OfficeStyle 样式下的mainbar高度 26 | self.mainbarHeightWPSStyleThreeRow: int = 130 # WpsLiteStyle 样式下的mainbar高度 27 | self.mainbarHeightOfficeStyleTwoRow: int = 134 # OfficeStyleTwoRow 样式下的mainbar高度 28 | self.mainbarHeightWPSStyleTwoRow: int = 104 # WpsLiteStyleTwoRow 样式下的mainbar高度 29 | self.titleBarHeight: int = 30 # 标题栏高度 30 | self.tabBarHeight: int = 25 # ribbon tab 的高度 31 | self.titleTextColor: QColor = Qt.black # 标题颜色 32 | self.widgetBord: QMargins = QMargins(5, 1, 5, 5) # 整个ribbonbar的四个边框 33 | self.tabBarBaseLineColor: QColor = QColor(186, 201, 219) # tabbar 底部线条颜色 34 | 35 | 36 | class SARibbonElementCreateDelegate: 37 | """ 38 | @brief SARibbon的子元素创建的代理,SARibbon内部创建SAWidgets子元素都通过SARibbonElementCreateDelegate来创建 39 | """ 40 | def __init__(self): 41 | self.m_opt: SARibbonStyleOption = SARibbonStyleOption() 42 | 43 | def createRibbonTabBar(self, parent): 44 | return SARibbonTabBar(parent) 45 | 46 | def createRibbonApplicationButton(self, parent): 47 | return SARibbonApplicationButton(parent) 48 | 49 | def createRibbonSeparatorWidget(self, parent, height: int=None): 50 | if height is not None: 51 | return SARibbonSeparatorWidget(height, parent) 52 | return SARibbonSeparatorWidget(parent) 53 | 54 | def createRibbonGalleryGroup(self, parent): 55 | return SARibbonGalleryGroup(parent) 56 | 57 | def createRibbonToolButton(self, parent): 58 | return SARibbonToolButton(parent) 59 | 60 | def createRibbonStackedWidget(self, parent): 61 | return SARibbonStackedWidget(parent) 62 | 63 | def createHidePannelButton(self, parent): 64 | """ 65 | 创建隐藏ribbon的按钮代理函数, 66 | :param parent: SARibbonBar 67 | """ 68 | btn = SARibbonControlButton(parent) 69 | btn.setAutoRaise(False) 70 | btn.setObjectName('SARibbonBarHidePannelButton') 71 | btn.setToolButtonStyle(Qt.ToolButtonIconOnly) 72 | btn.setFixedSize(parent.tabBarHeight()-4, parent.tabBarHeight()-4) 73 | return btn 74 | 75 | def createRibbonPannelOptionButton(self, parent): 76 | """ 77 | 创建SARibbonPannelOptionButton 78 | """ 79 | return SARibbonPannelOptionButton(parent) 80 | 81 | def createRibbonCommonWidget(self, parent, WidgetClass): 82 | """ 83 | 通用方式创建SARibbon原生的对象,WidgetClass为需要创建对象的类名 84 | """ 85 | return WidgetClass(parent) 86 | 87 | def getRibbonStyleOption(self) -> SARibbonStyleOption: 88 | return self.m_opt 89 | 90 | def setRibbonStyleOption(self, opt: SARibbonStyleOption): 91 | self.m_opt = opt 92 | -------------------------------------------------------------------------------- /src/PySARibbon/SATools/SARibbonElementManager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonElementManager 4 | @Author ROOT 5 | 6 | @brief 此类是一个全局单例,用于管理SARibbonElementCreateDelegate 7 | """ 8 | 9 | from .SARibbonElementCreateDelegate import SARibbonElementCreateDelegate 10 | 11 | 12 | class SARibbonElementManager: 13 | def __init__(self): 14 | self.m_delegate: SARibbonElementCreateDelegate = SARibbonElementCreateDelegate() 15 | 16 | def delegate(self) -> SARibbonElementCreateDelegate: 17 | return self.m_delegate 18 | 19 | def setupDelegate(self, delegate: SARibbonElementCreateDelegate): 20 | self.m_delegate = delegate 21 | 22 | 23 | # 定义全局单例 24 | 25 | RibbonSubElementMgr = SARibbonElementManager() 26 | 27 | RibbonSubElementDelegate = RibbonSubElementMgr.delegate() 28 | 29 | RibbonSubElementStyleOpt = RibbonSubElementDelegate.getRibbonStyleOption() 30 | -------------------------------------------------------------------------------- /src/PySARibbon/SATools/SARibbonGlobal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonGlobal 4 | @Author ROOT 5 | """ 6 | 7 | # ribbon的数字版本 8 | SA_RIBBON_BAR_VERSION = 0.1 9 | 10 | # ribbon 的文字版本 11 | SA_RIBBON_BAR_VERSION_STR = '0.1' 12 | 13 | """ 14 | @def 属性,用于标记是否可以进行自定义,用于动态设置到@ref SARibbonCategory 和@ref SARibbonPannel 15 | 值为bool,在为true时,可以通过@ref SARibbonCustomizeWidget 改变这个SARibbonCategory和SARibbonPannel的布局, 16 | 默认不会有此属性,仅在有此属性且为true时才会在SARibbonCustomizeWidget中能显示为可设置 17 | """ 18 | SA_RIBBON_BAR_PROP_CAN_CUSTOMIZE = '_sa_isCanCustomize' 19 | -------------------------------------------------------------------------------- /src/PySARibbon/SATools/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module __init__.py 4 | @Author ROOT 5 | """ 6 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonApplicationButton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonApplicationButton 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtCore import Qt 7 | from PyQt5.QtWidgets import QPushButton 8 | 9 | 10 | class SARibbonApplicationButton(QPushButton): 11 | def __init__(self, *_args): 12 | """ 13 | __init__(parent=None) 14 | __init__(str, parent=None) 15 | __init__(QIcon, str, parent=None) 16 | """ 17 | super().__init__(*_args) 18 | self.setFocusPolicy(Qt.NoFocus) 19 | self.setFlat(True) 20 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonCategoryScrollButton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonCategoryScrollButton 4 | @Author ROOT 5 | 6 | @brief SARibbonCategory无法完全显示时,显示的调整按钮 7 | 重新定义是为了防止被外部的样式影响,同时可以使用SARibbonCategoryScrollButton的样式定义 8 | """ 9 | from PyQt5.QtWidgets import QToolButton 10 | 11 | 12 | class SARibbonCategoryScrollButton(QToolButton): 13 | def __init__(self, arrType, parent): 14 | super().__init__(parent) 15 | self.setArrowType(arrType) 16 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonControlButton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonControlButton 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtWidgets import QToolButton 7 | 8 | 9 | class SARibbonControlButton(QToolButton): 10 | def __init__(self, parent): 11 | super().__init__(parent) 12 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonCtrlContainer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonCtrlContainer 4 | @Author ROOT 5 | """ 6 | from typing import Union 7 | from PyQt5.QtCore import Qt, QSize, QRect 8 | from PyQt5.QtWidgets import QWidget, QStyleOption, QSizePolicy, QStylePainter 9 | 10 | from ..SATools.SARibbonDrawHelper import SARibbonDrawHelper 11 | 12 | 13 | class SARibbonCtrlContainer(QWidget): 14 | def __init__(self, container: Union[QWidget, None], parent): 15 | super().__init__(parent) 16 | self.containerWidget: QWidget = container 17 | self.enableDrawIcon = False 18 | self.enableDrawTitle = False 19 | 20 | if self.containerWidget: 21 | self.containerWidget.setParent(self) 22 | self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)) 23 | 24 | def sizeHint(self) -> QSize: 25 | if not self.containerWidget: 26 | return super().sizeHint() 27 | sizeHint = self.containerWidget.sizeHint() 28 | if self.enableDrawIcon: 29 | icon = self.windowIcon() 30 | if not icon.isNull(): 31 | sizeHint.setWidth(sizeHint.width() + sizeHint.height()) 32 | if self.enableDrawTitle: 33 | text = self.windowTitle() 34 | if text: 35 | textWidth = self.fontMetrics().horizontalAdvance(text) 36 | sizeHint.setWidth(sizeHint.width() + textWidth) 37 | return sizeHint 38 | 39 | def minimumSizeHint(self) -> QSize: 40 | if not self.containerWidget: 41 | return super().minimumSizeHint() 42 | sizeHint = self.containerWidget.minimumSizeHint() 43 | if self.enableDrawIcon: 44 | icon = self.windowIcon() 45 | if not icon.isNull(): 46 | sizeHint.setWidth(sizeHint.width() + sizeHint.height()) 47 | if self.enableDrawTitle: 48 | text = self.windowTitle() 49 | if text: 50 | textWidth = self.fontMetrics().horizontalAdvance(text[0]) 51 | sizeHint.setWidth(sizeHint.width() + textWidth * 2) 52 | return sizeHint 53 | 54 | def containerWidget(self) -> QWidget: 55 | return self.containerWidget 56 | 57 | def setEnableShowIcon(self, b: bool): 58 | self.enableDrawIcon = b 59 | self.update() 60 | 61 | def setEnableShowTitle(self, b: bool): 62 | self.enableDrawTitle = b 63 | self.update() 64 | 65 | def setContainerWidget(self, container: QWidget): 66 | if self.containerWidget: 67 | self.containerWidget.hide() 68 | self.containerWidget.deleteLater() 69 | if not container: 70 | return 71 | self.containerWidget = container 72 | self.containerWidget.setParent(self) 73 | 74 | def paintEvent(self, w): 75 | painter = QStylePainter(self) 76 | opt = QStyleOption() 77 | self.initStyleOption(opt) 78 | widgetHeight = self.height() 79 | x = 0 80 | # 绘制图标 81 | if self.enableDrawIcon: 82 | icon = self.windowIcon() 83 | if not icon.isNull(): 84 | iconSize = SARibbonDrawHelper.iconActualSize(icon, opt, QSize(widgetHeight, widgetHeight)) 85 | SARibbonDrawHelper.drawIcon(icon, painter, opt, x, 0, widgetHeight, widgetHeight) 86 | x += iconSize.width() + 4 87 | # 绘制文字 88 | if self.enableDrawTitle: 89 | text = self.windowTitle() 90 | if text: 91 | textWidth = self.fontMetrics().horizontalAdvance(text) 92 | if textWidth > opt.rect.width() - widgetHeight - x: 93 | textWidth = opt.rect.width() - widgetHeight - x 94 | text = opt.fontMetrics.elidedText(text, Qt.ElideRight, textWidth) 95 | if textWidth > 0: 96 | SARibbonDrawHelper.drawText( 97 | text, painter, opt, 98 | Qt.AlignLeft | Qt.AlignVCenter, 99 | QRect(x, 0, textWidth, opt.rect.height()) 100 | ) 101 | 102 | def resizeEvent(self, e): 103 | opt = QStyleOption() 104 | self.initStyleOption(opt) 105 | widgetHeight = self.height() 106 | x = 0 107 | # 绘制图标 108 | if self.enableDrawIcon: 109 | icon = self.windowIcon() 110 | if not icon.isNull(): 111 | iconSize = SARibbonDrawHelper.iconActualSize(icon, opt, QSize(widgetHeight, widgetHeight)) 112 | x += iconSize.width() + 4 113 | # 绘制文字 114 | if self.enableDrawTitle: 115 | text = self.windowTitle() 116 | if text: 117 | textWidth = self.fontMetrics().horizontalAdvance(text) 118 | if textWidth > opt.rect.width() - widgetHeight - x: 119 | textWidth = opt.rect.width() - widgetHeight - x 120 | # text = opt.fontMetrics.elidedText(text, Qt.ElideRight, textWidth) 121 | if textWidth > 0: 122 | x += textWidth + 2 123 | 124 | if self.containerWidget: 125 | self.containerWidget.setGeometry(x, 0, self.width() - x, self.height()) 126 | 127 | def initStyleOption(self, opt: QStyleOption): 128 | opt.initFrom(self) 129 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonGalleryGroup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonGalleryGroup 4 | @Author ROOT 5 | 6 | @brief Gallery的组 7 | 组负责显示管理Gallery Item 8 | """ 9 | from typing import List, Union 10 | from PyQt5.QtCore import Qt, QModelIndex, QSize, pyqtSignal, QAbstractListModel, QItemSelectionModel 11 | from PyQt5.QtGui import QIcon, QPainter 12 | from PyQt5.QtWidgets import QAction, QStyledItemDelegate, QStyleOptionViewItem, QStyle, QListView 13 | 14 | 15 | class SARibbonGalleryItem: 16 | def __init__(self, *_args): 17 | """ 18 | __init__() 19 | __init__(str, QIcon) 20 | __init__(QAction) 21 | """ 22 | self.m_datas = dict() # 存储不同role对应的数据 23 | self.m_flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable 24 | self.m_action: QAction = None 25 | if len(_args) > 1: 26 | self.setText(_args[0]) 27 | self.setIcon(_args[1]) 28 | elif len(_args) > 0 and isinstance(_args[0], QAction): 29 | self.setAction(_args[0]) 30 | 31 | def setData(self, role: int, data): 32 | self.m_datas[role] = data 33 | 34 | def data(self, role) -> any: 35 | if self.m_action: 36 | if role == Qt.DisplayRole: 37 | return self.m_action.text() 38 | elif role == Qt.ToolTipRole: 39 | return self.m_action.toolTip() 40 | elif role == Qt.DecorationRole: 41 | return self.m_action.icon() 42 | return self.m_datas.get(role) 43 | 44 | def setText(self, text: str): 45 | self.setData(Qt.DisplayRole, text) 46 | 47 | def text(self) -> str: 48 | if self.m_action: 49 | return self.m_action.text() 50 | return self.data(Qt.DisplayRole) 51 | 52 | def setToolTip(self, text: str): 53 | self.setData(Qt.ToolTipRole, text) 54 | 55 | def toolTip(self) -> str: 56 | if self.m_action: 57 | return self.m_action.toolTip() 58 | return self.data(Qt.ToolTipRole) 59 | 60 | def setIcon(self, icon: QIcon): 61 | self.setData(Qt.DecorationRole, icon) 62 | 63 | def icon(self) -> QIcon: 64 | if self.m_action: 65 | return self.m_action.icon() 66 | return self.data(Qt.DecorationRole) 67 | 68 | def setAction(self, act: QAction): 69 | self.m_action = act 70 | if act.isEnabled(): 71 | self.m_flags |= Qt.ItemIsEnabled 72 | else: 73 | self.m_flags &= ~Qt.ItemIsEnabled 74 | 75 | def action(self) -> QAction: 76 | return self.m_action 77 | 78 | def setSelectable(self, isSelectable: bool): 79 | if isSelectable: 80 | self.m_flags |= Qt.ItemIsSelectable 81 | else: 82 | self.m_flags &= ~Qt.ItemIsSelectable 83 | 84 | def isSelectable(self) -> bool: 85 | return bool(self.m_flags & Qt.ItemIsSelectable) 86 | 87 | def setEnable(self, isEnable: bool): 88 | if self.m_action: 89 | self.m_action.setEnabled(isEnable) 90 | if isEnable: 91 | self.m_flags |= Qt.ItemIsEnabled 92 | else: 93 | self.m_flags &= ~Qt.ItemIsEnabled 94 | 95 | def isEnable(self) -> bool: 96 | if self.m_action: 97 | return self.m_action.isEnabled() 98 | return bool(self.m_flags & Qt.ItemIsEnabled) 99 | 100 | def setFlags(self, flag: int): 101 | self.m_flags = flag 102 | if self.m_flags: 103 | self.m_action.setEnabled(flag & Qt.ItemIsEnabled) 104 | 105 | def flags(self) -> int: 106 | return self.m_flags 107 | 108 | 109 | class SARibbonGalleryGroupItemDelegate(QStyledItemDelegate): 110 | """@brief SARibbonGalleryGroup对应的显示代理""" 111 | def __init__(self, group, parent): 112 | super().__init__(parent) 113 | self.m_group: SARibbonGalleryGroup = group 114 | 115 | def sizeHint(self, option, index) -> QSize: 116 | return QSize(option.rect.width(), option.rect.height()) 117 | 118 | def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): 119 | if self.m_group.enableIconText(): 120 | self.paintIconWithText(painter, option, index) 121 | else: 122 | self.paintIconOnly(painter, option, index) 123 | 124 | def paintIconOnly(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): 125 | painter.save() 126 | painter.setClipRect(option.rect) 127 | style = self.m_group.style() 128 | style.drawPrimitive(QStyle.PE_PanelItemViewItem, option, painter, self.m_group) 129 | iconRect = option.rect 130 | iconRect.adjust(3, 3, -3, -3) 131 | ico: QIcon = index.data(Qt.DecorationRole) 132 | ico.paint(painter, iconRect, Qt.AlignCenter, QIcon.Normal, QIcon.On) 133 | painter.restore() 134 | 135 | def paintIconWithText(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): 136 | super().paint(painter, option, index) 137 | 138 | 139 | class SARibbonGalleryGroupModel(QAbstractListModel): 140 | """@brief SARibbonGalleryGroup对应的model""" 141 | def __init__(self, parent): 142 | super().__init__(parent) 143 | self.m_items: List[SARibbonGalleryItem] = list() 144 | 145 | def rowCount(self, parent=QModelIndex()) -> int: 146 | ret = 0 if parent.isValid() else len(self.m_items) 147 | return ret 148 | 149 | def flags(self, index: QModelIndex) -> int: 150 | if not index.isValid() or index.row() >= len(self.m_items): 151 | return Qt.NoItemFlags 152 | i = index.row() 153 | return self.m_items[i].flags() 154 | 155 | def data(self, index: QModelIndex=None, role: int=0): 156 | if not index.isValid() or index.row() >= len(self.m_items): 157 | return None 158 | i = index.row() 159 | return self.m_items[i].data(role) 160 | 161 | def index(self, row: int, column: int=0, parent: QModelIndex=None): 162 | if self.hasIndex(row, column, parent): 163 | return self.createIndex(row, column, self.m_items[row]) 164 | return QModelIndex() 165 | 166 | def setData(self, index: QModelIndex, value, role: int=0): 167 | if not index.isValid() or index.row() >= len(self.m_items): 168 | return False 169 | i = index.row() 170 | self.m_items[i].setData(role, value) 171 | return True 172 | 173 | def clear(self): 174 | self.beginResetModel() 175 | self.m_items.clear() 176 | self.endResetModel() 177 | 178 | def at(self, row: int) -> SARibbonGalleryItem: 179 | return self.m_items[row] 180 | 181 | def insert(self, row: int, item: SARibbonGalleryItem): 182 | self.beginInsertRows(QModelIndex(), row, row) 183 | self.m_items.insert(row, item) 184 | self.endInsertRows() 185 | 186 | def take(self, row: int) -> Union[None, SARibbonGalleryItem]: 187 | if row < 0 or row >= len(self.m_items): 188 | return None 189 | self.beginRemoveRows(QModelIndex(), row, row) 190 | item = self.m_items[row] 191 | del self.m_items[row] 192 | self.endRemoveRows() 193 | return item 194 | 195 | def append(self, item: SARibbonGalleryItem): 196 | row = len(self.m_items) 197 | self.beginInsertRows(QModelIndex(), row, row+1) 198 | self.m_items.append(item) 199 | self.endInsertRows() 200 | 201 | 202 | class SARibbonGalleryGroup(QListView): 203 | def __init__(self, parent): 204 | super().__init__(parent) 205 | self.enableIconText_ = False 206 | self.groupTitle = '' 207 | 208 | self.setupGroupModel() 209 | self.setViewMode(QListView.IconMode) 210 | self.setResizeMode(QListView.Adjust) 211 | self.setSelectionRectVisible(True) 212 | self.setUniformItemSizes(True) 213 | self.setPreinstallStyle(SARibbonGalleryGroup.LargeIconWithText) 214 | self.setItemDelegate(SARibbonGalleryGroupItemDelegate(self, self)) 215 | self.clicked.connect(self.onItemClicked) 216 | 217 | def setPreinstallStyle(self, style: int): 218 | """设置默认的样式""" 219 | if style == SARibbonGalleryGroup.LargeIconOnly: 220 | self.setIconSize(QSize(72, 56)) 221 | self.setGridSize(QSize(72, 56)) 222 | self.setEnableIconText(False) 223 | else: 224 | self.setIconSize(QSize(72, 36)) 225 | self.setGridSize(QSize(72, 56)) 226 | self.setEnableIconText(True) 227 | 228 | def addItem(self, *_args): 229 | """ 230 | addItem(QAction) 231 | addItem(SARibbonGalleryItem) 232 | addItem(str, QIcon) 233 | """ 234 | if len(_args) < 1: 235 | raise Exception('parameter length < 1') 236 | 237 | if not self.groupModel(): 238 | return 239 | if len(_args) >= 2: 240 | self.groupModel().append(SARibbonGalleryItem(_args[0], _args[1])) 241 | elif isinstance(_args[0], QAction): 242 | self.groupModel().append(SARibbonGalleryItem(_args[0])) 243 | else: 244 | self.groupModel().append(_args[0]) 245 | 246 | def addActionItem(self, act: QAction): 247 | if not self.groupModel(): 248 | return 249 | self.groupModel().append(SARibbonGalleryItem(act)) 250 | 251 | def addActionItemList(self, acts: List[QAction]): 252 | if not self.groupModel(): 253 | return 254 | for act in acts: 255 | self.groupModel().append(SARibbonGalleryItem(act)) 256 | 257 | def setupGroupModel(self): 258 | """构建一个model,这个model的父类是SARibbonGalleryGroup""" 259 | self.setModel(SARibbonGalleryGroupModel(self.parent())) 260 | 261 | def groupModel(self) -> SARibbonGalleryGroupModel: 262 | return self.model() 263 | 264 | def setEnableIconText(self, enable: bool): 265 | self.enableIconText_ = enable 266 | 267 | def enableIconText(self) -> bool: 268 | return self.enableIconText_ 269 | 270 | def setGroupTitle(self, title: str): 271 | self.groupTitle = title 272 | self.groupTitleChanged.emit(self.groupTitle) 273 | 274 | def groupTitle(self) -> str: 275 | return self.groupTitle 276 | 277 | def selectByIndex(self, i: int): 278 | if not self.groupModel(): 279 | return 280 | ind = self.groupModel().index(i, 0, QModelIndex()) 281 | selmodel: QItemSelectionModel = self.selectionModel() 282 | if selmodel: 283 | selmodel.select(ind, QItemSelectionModel.SelectCurrent) 284 | 285 | # 槽函数 286 | def onItemClicked(self, index: QModelIndex): 287 | if not index.isValid(): 288 | return 289 | item: SARibbonGalleryItem = index.internalPointer() 290 | act = item.action() 291 | if act: 292 | act.activate(QAction.Trigger) 293 | 294 | # 信号 295 | groupTitleChanged = pyqtSignal(str) 296 | 297 | # 枚举 298 | LargeIconWithText = 0 299 | LargeIconOnly = 1 300 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonLineWidgetContainer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonLineWidgetContainer 4 | @Author ROOT 5 | 6 | @brief 一个窗口容器,把窗口放置中间,前面后面都可以设置文本,主要用于放置在pannel上的小窗口 7 | 实现如下效果: 8 | PrefixLabel|_Widget_|SuffixLabel 9 | """ 10 | 11 | from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout 12 | 13 | 14 | class SARibbonLineWidgetContainer(QWidget): 15 | def __init__(self, parent=None): 16 | super().__init__(parent) 17 | 18 | self.m_innerWidget: QWidget = None 19 | self.m_labelPrefix = QLabel(self) 20 | self.m_labelSuffix = QLabel(self) 21 | 22 | lay = QHBoxLayout() 23 | lay.setContentsMargins(0, 0, 0, 0) 24 | lay.setSpacing(0) 25 | lay.addWidget(self.m_labelPrefix) 26 | lay.addWidget(self.m_labelSuffix) 27 | self.setLayout(lay) 28 | 29 | def setWidget(self, innerWidget): 30 | """设置widget,不允许设置一个None""" 31 | lay: QHBoxLayout = self.layout() 32 | 33 | if self.m_innerWidget: 34 | lay.replaceWidget(self.m_innerWidget, innerWidget) 35 | else: 36 | lay.insertLayout(1, innerWidget) 37 | self.m_innerWidget = innerWidget 38 | 39 | def setPrefix(self, prefix: str): 40 | """设置前缀""" 41 | self.m_labelPrefix.setText(prefix) 42 | 43 | def setSuffix(self, suffix: str): 44 | """设置后缀""" 45 | self.m_labelSuffix.setText(suffix) 46 | 47 | def labelPrefix(self) -> QLabel: 48 | """前缀文本框""" 49 | return self.m_labelPrefix 50 | 51 | def labelSuffix(self) -> QLabel: 52 | """后缀文本框""" 53 | return self.m_labelSuffix 54 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonMenu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonMenu 4 | @Author ROOT 5 | """ 6 | from typing import Union 7 | 8 | from PyQt5.QtWidgets import QMenu, QAction, QWidget, QSizePolicy, QWidgetAction 9 | 10 | 11 | class SARibbonMenu(QMenu): 12 | def __init__(self, *_args): 13 | """ 14 | __init__(parent=None) 15 | __init__(str, parent=None) 16 | """ 17 | parent = None 18 | arg_len = len(_args) 19 | if arg_len > 0 and isinstance(_args[0], str): 20 | title = _args[0] 21 | parent = _args[1] if arg_len >= 2 else None 22 | super().__init__(title, parent) 23 | else: 24 | super().__init__(parent) 25 | self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) 26 | 27 | def addRibbonMenu(self, *_args) -> Union[QAction, QMenu]: 28 | """ 29 | addRibbonMenu(SARibbonMenu) -> QAction 30 | addRibbonMenu(str) -> SARibbonMenu 31 | addRibbonMenu(QIcon, str) -> SARibbonMenu 32 | """ 33 | arg_len = len(_args) 34 | if arg_len == 1 and isinstance(_args[0], SARibbonMenu): 35 | return super().addMenu(_args[0]) 36 | elif arg_len == 1 and isinstance(_args[0], str): 37 | menu = SARibbonMenu(_args[0], self) 38 | super().addMenu(menu) 39 | return menu 40 | else: 41 | menu = SARibbonMenu(_args[1], self) 42 | menu.setIcon(_args[0]) 43 | super().addMenu(menu) 44 | return menu 45 | 46 | def addWidget(self, w: QWidget) -> QAction: 47 | action = QWidgetAction(self) 48 | action.setDefaultWidget(w) 49 | self.addAction(action) 50 | return action 51 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonPannelItem.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonPannelItem 4 | @Author ROOT 5 | 6 | @brief 是对pannel所有子窗口的抽象,参考qt的toolbar 7 | pannel所有子窗口内容都通过QAction进行抽象,包括gallery这些窗口,也是通过QAction进行抽象 8 | QAction最终会转换为SARibbonPannelItem,每个SARibbonPannelItem都含有一个widget, 9 | SARibbonPannel的布局就基于SARibbonPannelItem 10 | 11 | 无窗口的action会在内部生成一个SARibbonToolButton 12 | """ 13 | from PyQt5.QtCore import QRect 14 | from PyQt5.QtWidgets import QWidgetItem, QAction 15 | 16 | 17 | class SARibbonPannelItem(QWidgetItem): 18 | def __init__(self, widget): 19 | super().__init__(widget) 20 | self.rowIndex = -1 # 记录当前item属于第几行,hide模式下为-1 21 | self.columnIndex = -1 # 记录当前item属于第几列,hide模式下为-1 22 | self.customWidget = True # 对于没有窗口的action,customWidget为False 23 | self.rowProportion = SARibbonPannelItem.RPNone 24 | self.itemWillSetGeometry = QRect() 25 | self.action: QAction = None 26 | 27 | def isEmpty(self): 28 | ret = False 29 | if self.action is not None: 30 | ret = not self.action.isVisible() 31 | return ret 32 | 33 | # 定义枚举 34 | RPNone = 0 # 为定义占比,将会依据expandingDirections来判断 35 | RPLarge = 1 # 大占比,一个widget的高度会充满整个pannel 36 | RPMedium = 2 # 中占比,要同一列里两个都是Medium时,会在三行中占据两行 37 | RPSmall = 3 # 小占比,占SARibbonPannel的一行,Medium在不满足条件时也会变为Small,但不会变为Large 38 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonPannelOptionButton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonPannelOptionButton 4 | @Author ROOT 5 | 6 | @brief Pannel右下角的操作按钮 7 | 此按钮和一个action关联,使用SARibbonPannel.addOptionAction 函数用于生成此按钮,正常来说 8 | 用户并不需要直接操作此类,仅仅用于样式设计 9 | 如果一定要重载此按钮,可以通过重载 SARibbonElementCreateDelegate 10 | 的 SARibbonElementCreateDelegate.createRibbonPannelOptionButton来实现新的OptionButton 11 | """ 12 | import PySARibbon.resource_rc 13 | from PyQt5.QtGui import QIcon 14 | from PyQt5.QtCore import QSize 15 | from PyQt5.QtWidgets import QToolButton, QAction 16 | 17 | 18 | class SARibbonPannelOptionButton(QToolButton): 19 | def __init__(self, parent=None): 20 | super().__init__(parent) 21 | self.setAutoRaise(True) 22 | self.setCheckable(False) 23 | self.setFixedSize(QSize(16, 16)) 24 | self.setIconSize(QSize(16, 16)) 25 | self.setIcon(QIcon(':/icon/resource/ribbonPannelOptionButton.png')) 26 | 27 | def connectAction(self, act: QAction): 28 | self.clicked.connect(act.toggled) 29 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonSeparatorWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonSeparatorWidget 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtCore import QSize, QPoint 7 | from PyQt5.QtGui import QPainter 8 | from PyQt5.QtWidgets import QWidget, QSizePolicy 9 | 10 | 11 | class SARibbonSeparatorWidget(QWidget): 12 | def __init__(self, *_args): 13 | """ 14 | __init__(parent=None) 15 | __init__(int, parent=None) 16 | """ 17 | parent = None 18 | h: int = None 19 | arg_len = len(_args) 20 | if arg_len > 0 and isinstance(_args[0], int): 21 | h = _args[0] 22 | if arg_len > 1: 23 | parent = _args[1] 24 | elif arg_len > 0: 25 | parent = _args[0] 26 | super().__init__(parent) 27 | if h is not None: 28 | self.setFixedSize(6, h) 29 | else: 30 | self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) 31 | self.setFixedWidth(6) 32 | self.m_topMargins = 4 33 | self.m_bottomMargins = 4 34 | 35 | def sizeHint(self) -> QSize: 36 | return QSize(6, self.height()) 37 | 38 | def setTopBottomMargins(self, top: int, bottom: int): 39 | """ 40 | 设置分割线的上下距离 41 | """ 42 | self.m_topMargins = top 43 | self.m_bottomMargins = bottom 44 | 45 | def paintEvent(self, e): 46 | """自定义分割线""" 47 | painter = QPainter(self) 48 | painter.setPen(self.palette().window().color().darker(114)) 49 | x1 = self.rect().center().x() 50 | painter.drawLine(QPoint(x1, self.rect().top() + self.m_topMargins), 51 | QPoint(x1, self.rect().bottom() - self.m_bottomMargins)) 52 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonStackedWidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonStackedWidget 4 | @Author ROOT 5 | 6 | @brief 有qdialog功能的stackwidget,用于在最小化时stack能像dialog那样弹出来 7 | """ 8 | from PyQt5.QtCore import pyqtSignal, QEventLoop, Qt 9 | from PyQt5.QtWidgets import QStackedWidget, QFrame 10 | 11 | 12 | class SARibbonStackedWidget(QStackedWidget): 13 | def __init__(self, parent): 14 | super().__init__(parent) 15 | self.eventLoop: QEventLoop = None 16 | self.isAutoResize = True 17 | 18 | def setPopupMode(self): 19 | self.setMouseTracking(True) 20 | self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint) 21 | self.setFrameShape(QFrame.Panel) 22 | 23 | def isPopupMode(self) -> bool: 24 | return self.windowFlags() & Qt.Popup 25 | 26 | def setNormalMode(self): 27 | if self.eventLoop: 28 | self.eventLoop.exit() 29 | self.eventLoop = None 30 | self.setMouseTracking(False) 31 | self.setWindowFlags(Qt.Widget | Qt.FramelessWindowHint) 32 | self.setFrameShape(QFrame.NoFrame) 33 | 34 | def isNormalMode(self) -> bool: 35 | return not self.isPopupMode() 36 | 37 | def exec(self): 38 | self.show() 39 | if not self.isPopupMode(): 40 | self.eventLoop = None 41 | return 42 | event = QEventLoop() 43 | self.eventLoop = event 44 | event.exec() 45 | self.eventLoop = None 46 | 47 | def setAutoResize(self, autoresize: bool): 48 | self.isAutoResize = autoresize 49 | 50 | def isAutoResize(self) -> bool: 51 | return self.isAutoResize 52 | 53 | def moveWidget(self, fr: int, to: int): 54 | """ 55 | 类似tabbar的moveTab函数,交换两个窗口的index 56 | 此操作会触发widgetRemoved(int index)信号 57 | """ 58 | w = self.widget(fr) 59 | self.removeWidget(w) 60 | self.insertWidget(to, w) 61 | 62 | def hideEvent(self, e): 63 | if self.isPopupMode() and self.eventLoop: 64 | self.eventLoop.exit() 65 | self.setFocus() 66 | self.hidWindow.emit() 67 | super().hideEvent(e) 68 | 69 | def resizeEvent(self, e): 70 | if self.isAutoResize: 71 | for i in range(self.count()): 72 | w = self.widget(i) 73 | if w: 74 | w.resize(e.size()) 75 | return super().resizeEvent(e) 76 | 77 | # 信号 78 | hidWindow = pyqtSignal() 79 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/SARibbonTabBar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SARibbonTabBar 4 | @Author ROOT 5 | """ 6 | from PyQt5.QtCore import QMargins 7 | from PyQt5.QtWidgets import QTabBar 8 | 9 | 10 | class SARibbonTabBar(QTabBar): 11 | def __init__(self, parent): 12 | super().__init__(parent) 13 | self.m_tabMargin: QMargins = QMargins(6, 0, 0, 0) 14 | self.setExpanding(False) 15 | 16 | def tabMargin(self) -> QMargins: 17 | return self.m_tabMargin 18 | 19 | def setTabMargin(self, margin: QMargins): 20 | self.m_tabMargin = margin 21 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWidgets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module __init__.py 4 | @Author ROOT 5 | """ 6 | 7 | from .SARibbonApplicationButton import SARibbonApplicationButton 8 | from .SARibbonCategoryScrollButton import SARibbonCategoryScrollButton 9 | from .SARibbonControlButton import SARibbonControlButton 10 | from .SARibbonCtrlContainer import SARibbonCtrlContainer 11 | from .SARibbonGalleryGroup import SARibbonGalleryGroup 12 | from .SARibbonMenu import SARibbonMenu 13 | from .SARibbonPannelItem import SARibbonPannelItem 14 | from .SARibbonPannelOptionButton import SARibbonPannelOptionButton 15 | from .SARibbonSeparatorWidget import SARibbonSeparatorWidget 16 | from .SARibbonStackedWidget import SARibbonStackedWidget 17 | from .SARibbonTabBar import SARibbonTabBar 18 | from .SARibbonToolButton import SARibbonToolButton 19 | from .SARibbonLineWidgetContainer import SARibbonLineWidgetContainer 20 | -------------------------------------------------------------------------------- /src/PySARibbon/SAWindowButtonGroup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module SAWindowButtonGroup 4 | @Author ROOT 5 | 6 | @brief 窗口的最大最小化按钮 7 | """ 8 | from PyQt5.QtCore import Qt, QSize 9 | from PyQt5.QtCore import QEvent 10 | from PyQt5.QtWidgets import QWidget, QToolButton, QStyle 11 | 12 | 13 | class SAWindowToolButton(QToolButton): 14 | def __init__(self, parent=None): 15 | super().__init__(parent) 16 | self.setAutoRaise(True) 17 | 18 | 19 | class SAWindowButtonGroup(QWidget): 20 | def __init__(self, parent, flags=None): 21 | super().__init__(parent) 22 | self.mCloseStretch = 4 23 | self.mMaxStretch = 3 24 | self.mMinStretch = 3 25 | self.mIconscale = 0.5 26 | self.mFlags = Qt.Widget 27 | self.buttonClose = None 28 | self.buttonMinimize = None 29 | self.buttonMaximize = None 30 | 31 | if flags: 32 | self.mFlags = flags 33 | self.updateWindowFlag() 34 | if parent: 35 | parent.installEventFilter(self) 36 | 37 | def setupMinimizeButton(self, on: bool): 38 | if on: 39 | if self.buttonMinimize: 40 | self.buttonMinimize.show() 41 | return 42 | self.buttonMinimize = SAWindowToolButton(self) 43 | self.buttonMinimize.setObjectName('SAMinimizeWindowButton') 44 | self.buttonMinimize.setFixedSize(30, 28) 45 | self.buttonMinimize.setFocusPolicy(Qt.NoFocus) 46 | self.buttonMinimize.setStyleSheet(""" 47 | SAWindowToolButton { 48 | background-color: transparent; 49 | border:none; 50 | } 51 | SAWindowToolButton:hover {background-color:#C1D1B8;} 52 | SAWindowToolButton:pressed {background-color:#A5AF9B;} 53 | SAWindowToolButton:focus{outline: none} 54 | """) 55 | icon = self.style().standardIcon(QStyle.SP_TitleBarMinButton) 56 | w = int(self.buttonMinimize.size().width() * self.mIconscale) 57 | h = int(self.buttonMinimize.size().height() * self.mIconscale) 58 | self.buttonMinimize.setIconSize(QSize(w, h)) 59 | self.buttonMinimize.setIcon(icon) 60 | self.buttonMinimize.show() 61 | self.buttonMinimize.clicked.connect(self.onMinimizeWindow) 62 | elif self.buttonMinimize: 63 | self.buttonMinimize.hide() 64 | 65 | self.updateSize() 66 | 67 | def setupMaximizeButton(self, on: bool): 68 | if on: 69 | if self.buttonMaximize: 70 | self.buttonMaximize.show() 71 | return 72 | self.buttonMaximize = SAWindowToolButton(self) 73 | self.buttonMaximize.setObjectName('SAMaximizeWindowButton') 74 | self.buttonMaximize.setFixedSize(30, 28) 75 | self.buttonMaximize.setFocusPolicy(Qt.NoFocus) 76 | self.buttonMaximize.setStyleSheet(""" 77 | SAWindowToolButton { 78 | background-color: transparent; 79 | border:none; 80 | } 81 | SAWindowToolButton:hover {background-color:#C1D1B8;} 82 | SAWindowToolButton:pressed {background-color:#A5AF9B;} 83 | SAWindowToolButton:focus{outline: none} 84 | """) 85 | icon = self.style().standardIcon(QStyle.SP_TitleBarMaxButton) 86 | w = int(self.buttonMaximize.size().width() * self.mIconscale) 87 | h = int(self.buttonMaximize.size().height() * self.mIconscale) 88 | self.buttonMaximize.setIconSize(QSize(w, h)) 89 | self.buttonMaximize.setIcon(icon) 90 | self.buttonMaximize.show() 91 | self.buttonMaximize.clicked.connect(self.onMaximizeWindow) 92 | elif self.buttonMaximize: 93 | self.buttonMaximize.hide() 94 | 95 | self.updateSize() 96 | 97 | def setupCloseButton(self, on: bool): 98 | if on: 99 | if self.buttonClose: 100 | self.buttonClose.show() 101 | return 102 | self.buttonClose = SAWindowToolButton(self) 103 | self.buttonClose.setObjectName('SAMaximizeWindowButton') 104 | self.buttonClose.setFixedSize(40, 28) 105 | self.buttonClose.setFocusPolicy(Qt.NoFocus) 106 | self.buttonClose.setStyleSheet(""" 107 | SAWindowToolButton { 108 | background-color: transparent; 109 | border:none; 110 | } 111 | SAWindowToolButton:hover {background-color:#F0604D;} 112 | SAWindowToolButton:pressed {background-color:#F0604D;} 113 | SAWindowToolButton:focus{outline: none} 114 | """) 115 | icon = self.style().standardIcon(QStyle.SP_TitleBarCloseButton) 116 | w = int(self.buttonClose.size().width() * self.mIconscale) 117 | h = int(self.buttonClose.size().height() * self.mIconscale) 118 | self.buttonClose.setIconSize(QSize(w, h)) 119 | self.buttonClose.setIcon(icon) 120 | self.buttonClose.show() 121 | self.buttonClose.clicked.connect(self.onCloseWindow) 122 | elif self.buttonClose: 123 | self.buttonClose.hide() 124 | 125 | self.updateSize() 126 | 127 | def updateWindowFlag(self, flags=None): 128 | if flags: 129 | if flags & Qt.WindowCloseButtonHint: 130 | self.mFlags |= Qt.WindowCloseButtonHint 131 | else: 132 | self.mFlags &= ~Qt.WindowCloseButtonHint 133 | if flags & Qt.WindowMaximizeButtonHint: 134 | self.mFlags |= Qt.WindowMaximizeButtonHint 135 | else: 136 | self.mFlags &= ~Qt.WindowMaximizeButtonHint 137 | if flags & Qt.WindowMinimizeButtonHint: 138 | self.mFlags |= Qt.WindowMinimizeButtonHint 139 | else: 140 | self.mFlags &= ~Qt.WindowMinimizeButtonHint 141 | else: 142 | flags = self.parentWidget().windowFlags() 143 | self.mFlags = flags 144 | 145 | self.setupMinimizeButton(flags & Qt.WindowMinimizeButtonHint) 146 | self.setupMaximizeButton(flags & Qt.WindowMaximizeButtonHint) 147 | self.setupCloseButton(flags & Qt.WindowCloseButtonHint) 148 | 149 | def setButtonWidthStretch(self, close=4, maxst=3, minst=3): 150 | """ 151 | 设置按钮的宽度比例,最终按钮宽度将按照此比例进行设置 152 | """ 153 | self.mCloseStretch = close 154 | self.mMaxStretch = maxst 155 | self.mMinStretch = minst 156 | 157 | def setIconScale(self, iconscale=0.5): 158 | """ 159 | 设置按钮的缩放比例 160 | """ 161 | self.mIconscale = iconscale 162 | 163 | def setWindowStates(self, states): 164 | """ 165 | 设置窗口状态(最大最小化按钮状态) 166 | """ 167 | if states == Qt.WindowNoState: 168 | if self.buttonMaximize: 169 | self.buttonMaximize.setIcon(self.style().standardIcon(QStyle.SP_TitleBarMaxButton)) 170 | if states == Qt.WindowMaximized: 171 | if self.buttonMaximize: 172 | self.buttonMaximize.setIcon(self.style().standardIcon(QStyle.SP_TitleBarNormalButton)) 173 | 174 | def windowButtonFlags(self) -> int: 175 | """ 176 | 仅获取按钮的状态 177 | """ 178 | f = Qt.Widget # widget是000 179 | if self.mFlags & Qt.WindowCloseButtonHint: 180 | f |= Qt.WindowCloseButtonHint 181 | if self.mFlags & Qt.WindowMaximizeButtonHint: 182 | f |= Qt.WindowMaximizeButtonHint 183 | if self.mFlags & Qt.WindowMinimizeButtonHint: 184 | f |= Qt.WindowMinimizeButtonHint 185 | return f 186 | 187 | def parentResize(self): 188 | par = self.parentWidget() 189 | if par: 190 | pSize = par.size() 191 | self.move(pSize.width()-self.width()-1, 1) 192 | 193 | def updateSize(self): 194 | self.setFixedSize(self.sizeHint()) 195 | self.resize(self.size()) 196 | 197 | def resize(self, size: QSize): 198 | tw = 0 199 | if self.buttonClose: 200 | tw += self.mCloseStretch 201 | if self.buttonMaximize: 202 | tw += self.mMaxStretch 203 | if self.buttonMinimize: 204 | tw += self.mMinStretch 205 | 206 | x = 0 207 | if self.buttonMinimize: 208 | w = (self.mMinStretch / tw) * size.width() 209 | self.buttonMinimize.setGeometry(x, 0, w, size.height()) 210 | x += w 211 | if self.buttonMaximize: 212 | w = (self.mMaxStretch / tw) * size.width() 213 | self.buttonMaximize.setGeometry(x, 0, w, size.height()) 214 | x += w 215 | if self.buttonClose: 216 | w = (self.mCloseStretch / tw) * size.width() 217 | self.buttonClose.setGeometry(x, 0, w, size.height()) 218 | 219 | def sizeHint(self) -> QSize: 220 | w = 0 221 | h = 28 222 | 223 | if self.buttonClose: 224 | w += 40 225 | if self.buttonMaximize: 226 | w += 30 227 | if self.buttonMinimize: 228 | w += 30 229 | return QSize(w, h) 230 | 231 | # 事件 232 | def eventFilter(self, watched, e: QEvent) -> bool: 233 | """ 234 | 用于监听父窗口改变尺寸 235 | """ 236 | if watched == self.parentWidget(): 237 | if e.type() == QEvent.Resize: 238 | self.parentResize() 239 | return False # 不截断任何事件 240 | 241 | def resizeEvent(self, e): 242 | self.resize(e.size()) 243 | 244 | # 槽函数 245 | def onCloseWindow(self): 246 | try: 247 | if self.parentWidget(): 248 | self.parentWidget().close() 249 | except Exception as e: 250 | print(__file__, 'onCloseWindow:', e) 251 | 252 | def onMinimizeWindow(self): 253 | if self.parentWidget(): 254 | self.parentWidget().showMinimized() 255 | 256 | def onMaximizeWindow(self): 257 | par = self.parentWidget() 258 | if par: 259 | if par.isMaximized(): 260 | par.showNormal() 261 | else: 262 | par.showMaximized() 263 | 264 | 265 | -------------------------------------------------------------------------------- /src/PySARibbon/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @Module __init__.py 4 | @Author ROOT 5 | """ 6 | 7 | from .SAFramelessHelper import SAFramelessHelper 8 | from .SARibbonBar import SARibbonBar 9 | from .SARibbonButtonGroupWidget import SARibbonButtonGroupWidget 10 | from .SARibbonCategory import SARibbonCategory 11 | from .SARibbonCategoryLayout import SARibbonCategoryLayout 12 | from .SARibbonContextCategory import SARibbonContextCategory 13 | from .SARibbonGallery import SARibbonGallery 14 | from .SARibbonMainWindow import SARibbonMainWindow 15 | from .SARibbonPannel import SARibbonPannel 16 | from .SARibbonPannelLayout import SARibbonPannelLayout 17 | from .SARibbonQuickAccessBar import SARibbonQuickAccessBar 18 | from .SAWindowButtonGroup import SAWindowButtonGroup 19 | -------------------------------------------------------------------------------- /src/PySARibbon/resource.rc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resource/ArrowDown.png 4 | resource/ArrowMore.png 5 | resource/ArrowUp.png 6 | resource/ribbonPannelOptionButton.png 7 | 8 | 9 | resource/default.qss 10 | resource/office2013.qss 11 | 12 | -------------------------------------------------------------------------------- /src/PySARibbon/resource/ArrowDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/ArrowDown.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/ArrowMore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/ArrowMore.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/ArrowUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/ArrowUp.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/default.qss: -------------------------------------------------------------------------------- 1 |  2 | /* start ribbon set*/ 3 | /*SARibbonBar*/ 4 | 5 | SARibbonBar{ 6 | background-color: #E3E6E8; 7 | } 8 | 9 | /*SARibbonButtonGroupWidget*/ 10 | SARibbonButtonGroupWidget{ 11 | background-color: transparent; 12 | } 13 | 14 | /*SARibbonQuickAccessBar*/ 15 | SARibbonQuickAccessBar{ 16 | background-color: #FF0000; 17 | } 18 | 19 | 20 | /*SARibbonCtrlContainer*/ 21 | SARibbonCtrlContainer{ 22 | background-color: transparent; 23 | } 24 | 25 | /*SARibbonCategory*/ 26 | SARibbonCategory:focus{ 27 | outline: none; 28 | } 29 | SARibbonCategory{ 30 | background-color: white; 31 | } 32 | /*SARibbonStackedWidget*/ 33 | SARibbonStackedWidget{ 34 | background-color: white; 35 | } 36 | SARibbonStackedWidget:focus{ 37 | outline: none; 38 | } 39 | /*SARibbonApplicationButton*/ 40 | SARibbonApplicationButton{ 41 | color:white; 42 | border: 1px solid #416ABD; 43 | border-top-left-radius: 2px; 44 | border-top-right-radius: 2px; 45 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #467FBD, stop:0.5 #2A5FAC,stop:0.51 #1A4088, 46 | stop:1 #419ACF); 47 | } 48 | 49 | SARibbonApplicationButton::hover{ 50 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #7BB2EB, stop:0.5 #477ECD,stop:0.51 #114ECF, 51 | stop:1 #80E1FF); 52 | } 53 | 54 | SARibbonApplicationButton::pressed{ 55 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #467BBB, stop:0.5 #2F63AE,stop:0.51 #1C438A, 56 | stop:1 #358BC9); 57 | } 58 | 59 | SARibbonApplicationButton:focus{ 60 | outline: none; 61 | } 62 | 63 | /*SARibbonTabBar*/ 64 | SARibbonTabBar{ 65 | background-color: transparent; 66 | } 67 | 68 | SARibbonTabBar::tab { 69 | color:#444444; 70 | border:none; 71 | background: transparent; 72 | margin-top: 0px; 73 | margin-right: 0px; 74 | margin-left: 6px; 75 | margin-bottom: 0px; 76 | min-width:60px; 77 | max-width:200px; 78 | min-height:30px; 79 | max-height:30px; 80 | padding-left:1px; 81 | padding-right:1px; 82 | padding-top:1px; 83 | padding-bottom:1px; 84 | } 85 | 86 | SARibbonTabBar::tab:selected, SARibbonTabBar::tab:hover { 87 | border-top-left-radius: 2px; 88 | border-top-right-radius: 2px; 89 | } 90 | 91 | SARibbonTabBar::tab:selected{ 92 | color:#000000; 93 | border: 1px solid #BAC9DB; 94 | background: white; 95 | border-bottom-color: #FFFFFF; 96 | } 97 | 98 | SARibbonTabBar::tab:hover:!selected{ 99 | border: 1px solid #ECBC3D; 100 | color: #000000; 101 | } 102 | 103 | SARibbonTabBar::tab:!selected { 104 | margin-top: 0px; 105 | } 106 | 107 | /*SARibbonLineEdit*/ 108 | SARibbonLineEdit { 109 | border: 1px solid #C0C2C4; 110 | background: #FFF; 111 | selection-background-color: #9BBBF7; 112 | selection-color: #000; 113 | } 114 | 115 | /*SARibbonToolButton*/ 116 | SARibbonToolButton{ 117 | border:1px solid transparent; 118 | color:#444444; 119 | background-color:transparent; 120 | } 121 | SARibbonToolButton::pressed{ 122 | color:#444444; 123 | border: 1px solid #FCBF21; 124 | background-color: #FCD364; 125 | } 126 | SARibbonToolButton::checked{ 127 | color:#444444; 128 | border: 1px solid #FCD364; 129 | background-color: #FCD364; 130 | } 131 | SARibbonToolButton::hover { 132 | color:#000000; 133 | border: 1px solid #FCD364; 134 | background-color: #FCDE89; 135 | } 136 | 137 | /*SARibbonControlButton*/ 138 | SARibbonControlButton{ 139 | background-color:transparent; 140 | border: 1px solid transparent; 141 | color:#444444; 142 | } 143 | SARibbonControlButton#SARibbonGalleryButtonUp,#SARibbonGalleryButtonDown,#SARibbonGalleryButtonMore{ 144 | border: 1px solid #C0C2C4; 145 | } 146 | SARibbonControlButton#SARibbonBarHidePannelButton{ 147 | border: 1px solid transparent; 148 | } 149 | SARibbonControlButton::pressed{ 150 | border: 1px solid #FCD364; 151 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 152 | #FCE58C, stop:1 #FDFDEB); 153 | } 154 | SARibbonControlButton::checked{ 155 | border: 1px solid #FCD364; 156 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 157 | #FCE58C, stop:1 #FDFDEB); 158 | } 159 | SARibbonControlButton::hover { 160 | border: 1px solid #FCD364; 161 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 162 | #FCE58C, stop:1 #FDFDEB); 163 | } 164 | 165 | 166 | /*SARibbonMenu*/ 167 | SARibbonMenu { 168 | color:#444444; 169 | background-color: #FCFCFC; 170 | border: 1px solid #8492A6; 171 | } 172 | SARibbonMenu::item { 173 | padding: 5px 25px 5px 25px; 174 | background-color: transparent; 175 | } 176 | SARibbonMenu::item:selected { 177 | background-color: #FCDE89; 178 | } 179 | SARibbonMenu::item:hover { 180 | color:#000; 181 | border: 1px solid #FCD364; 182 | } 183 | SARibbonMenu::icon{ 184 | margin-left: 1px; 185 | } 186 | 187 | /*SARibbonPannelOptionButton*/ 188 | SARibbonPannelOptionButton { 189 | background-color: transparent; 190 | color:#444444; 191 | } 192 | 193 | SARibbonPannelOptionButton::hover { 194 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 195 | #FCE58C, stop:1 #FDFDEB); 196 | border: 0px; 197 | } 198 | 199 | 200 | SARibbonPannel { 201 | background-color: #FFFFFF; 202 | border: 0px; 203 | } 204 | /*SARibbonPannel*/ 205 | SARibbonPannel { 206 | background-color: #FFFFFF; 207 | border: 0px; 208 | } 209 | /*SARibbonGallery*/ 210 | SARibbonGallery { 211 | background-color: transparent; 212 | color: #444444; 213 | border: 1px solid #C0C2C4; 214 | } 215 | 216 | /*SARibbonGalleryGroup*/ 217 | SARibbonGalleryGroup { 218 | show-decoration-selected: 1; 219 | background-color: transparent; 220 | color: #444444; 221 | } 222 | SARibbonGalleryGroup::item:selected { 223 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 224 | #FCE58C, stop:1 #FDFDEB); 225 | } 226 | SARibbonGalleryGroup::item:hover { 227 | border: 2px solid #FDEEB3; 228 | } 229 | 230 | /*SARibbonComboBox*/ 231 | SARibbonComboBox { 232 | border: 1px solid #C0C2C4; 233 | 234 | } 235 | 236 | SARibbonComboBox:hover{ 237 | border: 1px solid #FDEEB3; 238 | color : #000; 239 | } 240 | 241 | SARibbonComboBox:editable { 242 | color : #000; 243 | background: white; 244 | selection-background-color: #9BBBF7; 245 | selection-color: #000; 246 | } 247 | 248 | SARibbonComboBox::drop-down { 249 | subcontrol-origin: padding; 250 | subcontrol-position: top right; 251 | width: 15px; 252 | border-left: none; 253 | border-top-right-radius: 0px; 254 | border-bottom-right-radius: 0px; 255 | } 256 | 257 | SARibbonComboBox::drop-down:hover { 258 | border: 1px solid #FDEEB3; 259 | background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1,stop:0 #FDEEB3, stop:0.1282 #FDE38A,stop:0.8333 260 | #FCE58C, stop:1 #FDFDEB); 261 | } 262 | SARibbonComboBox::down-arrow { 263 | image: url(:/image/resource/ArrowDown.png); 264 | } 265 | 266 | 267 | /*SARibbonSeparatorWidget*/ 268 | SARibbonSeparatorWidget{ 269 | /*background-color: transparent;*/ 270 | background-color: #D3D3D3; 271 | } 272 | -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506353.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506354.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506354.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506355.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506356.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506356.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506357.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506357.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506358.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506358.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506359.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506359.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506362.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506362.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506363.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506363.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506405.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506405.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506406.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506406.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506407.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506407.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506460.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506461.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506461.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506462.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506462.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506463.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506463.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506464.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506464.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506466.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506466.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506467.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506467.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506468.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506468.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506469.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506469.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506471.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506471.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506501.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506502.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506503.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506504.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506505.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506506.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506507.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506508.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506509.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506510.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506510.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506511.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506511.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506512.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506513.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506514.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506514.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506515.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506515.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506516.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506517.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506518.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506518.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/506519.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/506519.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/529398.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/529398.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/530120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/530120.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/530150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/530150.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/530767.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/530767.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/Graph-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/Graph-add.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/arror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/arror.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/chartDataManager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/chartDataManager.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/figureIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/figureIcon.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/filter.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/folder.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/help.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/icon2.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/inRangDataRemove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/inRangDataRemove.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/information.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/layerBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/layerBarChart.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/openProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/openProject.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/save.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/icon/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/icon/warning.png -------------------------------------------------------------------------------- /src/PySARibbon/resource/office2013.qss: -------------------------------------------------------------------------------- 1 | /* start ribbon set*/ 2 | 3 | /*SARibbonBar*/ 4 | 5 | SARibbonBar { 6 | background-color: white; 7 | border: 1px solid #2b579a; 8 | } 9 | 10 | /*SARibbonButtonGroupWidget*/ 11 | 12 | SARibbonButtonGroupWidget { 13 | background-color: transparent; 14 | } 15 | 16 | /*SARibbonQuickAccessBar*/ 17 | 18 | SARibbonQuickAccessBar { 19 | background-color: #cee8fc; 20 | } 21 | 22 | /*SARibbonCtrlContainer*/ 23 | 24 | SARibbonCtrlContainer { 25 | background-color: transparent; 26 | } 27 | 28 | /*SARibbonCategory*/ 29 | 30 | SARibbonCategory:focus { 31 | outline: none; 32 | } 33 | 34 | SARibbonCategory { 35 | background-color: #fcfdfe; 36 | } 37 | 38 | /*SARibbonStackedWidget*/ 39 | 40 | SARibbonStackedWidget { 41 | background-color: white; 42 | border-bottom: 1px solid #c5d2e0; 43 | border-left: 1px solid #c5d2e0; 44 | border-right: 1px solid #c5d2e0; 45 | border-top: none; 46 | } 47 | 48 | SARibbonStackedWidget:focus { 49 | outline: none; 50 | } 51 | 52 | /*SARibbonApplicationButton*/ 53 | 54 | SARibbonApplicationButton { 55 | color: white; 56 | border: 1px solid #2b579a; 57 | border-top-left-radius: 2px; 58 | border-top-right-radius: 2px; 59 | background-color: #2b579a; 60 | } 61 | 62 | SARibbonApplicationButton::hover { 63 | background-color: #155889; 64 | } 65 | 66 | SARibbonApplicationButton::pressed { 67 | background-color: #155889; 68 | } 69 | 70 | SARibbonApplicationButton:focus { 71 | outline: none; 72 | } 73 | 74 | /*SARibbonTabBar*/ 75 | 76 | SARibbonTabBar { 77 | background-color: transparent; 78 | } 79 | 80 | SARibbonTabBar::tab { 81 | color: #5779af; 82 | border: none; 83 | background: transparent; 84 | margin-top: 0px; 85 | margin-right: 0px; 86 | margin-left: 6px; 87 | margin-bottom: 0px; 88 | min-width: 60px; 89 | max-width: 200px; 90 | min-height: 25px; 91 | max-height: 25px; 92 | padding-left: 1px; 93 | padding-right: 1px; 94 | padding-top: 1px; 95 | padding-bottom: 1px; 96 | } 97 | 98 | SARibbonTabBar::tab:selected, SARibbonTabBar::tab:hover { 99 | border-top-left-radius: 0px; 100 | border-top-right-radius: 0px; 101 | } 102 | 103 | SARibbonTabBar::tab:selected { 104 | color: #5779af; 105 | border: 1px solid #c5d2e0; 106 | background: white; 107 | border-bottom-color: #FFFFFF; 108 | } 109 | 110 | SARibbonTabBar::tab:hover:!selected { 111 | border: 1px solid #c5d2e0; 112 | color: #5779af; 113 | } 114 | 115 | SARibbonTabBar::tab:!selected { 116 | margin-top: 0px; 117 | } 118 | 119 | /*SARibbonToolButton*/ 120 | 121 | SARibbonToolButton { 122 | border: 1px solid transparent; 123 | color: #333; 124 | background-color: white; 125 | } 126 | 127 | SARibbonToolButton:focus { 128 | border: 1px solid #b9defa; 129 | color: #333; 130 | background-color: #fcfdfe; 131 | } 132 | 133 | SARibbonToolButton::pressed { 134 | color: #000; 135 | border: 1px solid#269bf4; 136 | background-color: #9ed2f9; 137 | } 138 | 139 | SARibbonToolButton::checked { 140 | color: #333; 141 | border: 1px solid #b9defa; 142 | background-color: #cee8fc; 143 | } 144 | 145 | SARibbonToolButton::hover { 146 | color: #000; 147 | border: 1px solid #badffa; 148 | background-color: #cee7fc; 149 | } 150 | 151 | /*SARibbonControlButton*/ 152 | 153 | SARibbonControlButton { 154 | background-color: transparent; 155 | border: 1px solid transparent; 156 | color: #333; 157 | } 158 | 159 | SARibbonControlButton#SARibbonGalleryButtonUp, #SARibbonGalleryButtonDown, #SARibbonGalleryButtonMore { 160 | border: 1px solid #cee8fc; 161 | } 162 | 163 | SARibbonControlButton#SARibbonBarHidePannelButton { 164 | border: 1px solid transparent; 165 | } 166 | 167 | SARibbonControlButton::pressed { 168 | border: 1px solid #269bf4; 169 | background-color: #9ed2f9; 170 | } 171 | 172 | SARibbonControlButton::checked { 173 | border: 1px solid #b9defa; 174 | background-color: #cee8fc; 175 | } 176 | 177 | SARibbonControlButton::hover { 178 | border: 1px solid #badffa; 179 | background-color: #cee7fc; 180 | } 181 | 182 | /*SARibbonMenu*/ 183 | 184 | SARibbonMenu { 185 | color: #333; 186 | background-color: #FCFCFC; 187 | border: 1px solid #c2d0df; 188 | } 189 | 190 | SARibbonMenu::item { 191 | padding: 5px 25px 5px 25px; 192 | background-color: transparent; 193 | } 194 | 195 | SARibbonMenu::item:selected { 196 | background-color: #cee8fc; 197 | } 198 | 199 | SARibbonMenu::item:hover { 200 | color: #000; 201 | background-color: #cee7fc; 202 | border: 1px solid #badffa; 203 | } 204 | 205 | SARibbonMenu::icon { 206 | margin-left: 1px; 207 | } 208 | 209 | /*SARibbonPannelOptionButton*/ 210 | 211 | SARibbonPannelOptionButton { 212 | background-color: transparent; 213 | color: #333; 214 | } 215 | 216 | SARibbonPannelOptionButton::hover { 217 | background-color: #cee7fc; 218 | border: 0px; 219 | } 220 | 221 | /*SARibbonPannel*/ 222 | 223 | SARibbonPannel { 224 | background-color: white; 225 | border: 0px; 226 | } 227 | 228 | /*SARibbonGallery*/ 229 | 230 | SARibbonGallery { 231 | background-color: transparent; 232 | color: #333; 233 | border: 1px solid #c2d0df; 234 | } 235 | 236 | /*SARibbonGalleryGroup*/ 237 | 238 | SARibbonGalleryGroup { 239 | show-decoration-selected: 1; 240 | background-color: transparent; 241 | color: #333; 242 | } 243 | 244 | SARibbonGalleryGroup::item:selected { 245 | background-color: #9ed2f9; 246 | } 247 | 248 | SARibbonGalleryGroup::item:hover { 249 | border: 2px solid #badffa; 250 | background-color: #cee7fc; 251 | } 252 | 253 | /*SARibbonLineEdit*/ 254 | 255 | SARibbonLineEdit { 256 | border: 1px solid #C0C2C4; 257 | background: #FFF; 258 | selection-background-color: #9BBBF7; 259 | selection-color: #000; 260 | } 261 | 262 | /*SARibbonComboBox*/ 263 | 264 | SARibbonComboBox { 265 | border: 1px solid #c2d0df; 266 | } 267 | 268 | SARibbonComboBox:hover { 269 | border: 1px solid #269bf4; 270 | color: #000; 271 | } 272 | 273 | SARibbonComboBox:editable { 274 | color: #000; 275 | background: white; 276 | selection-background-color: #9BBBF7; 277 | selection-color: #000; 278 | } 279 | 280 | SARibbonComboBox::drop-down { 281 | subcontrol-origin: padding; 282 | subcontrol-position: top right; 283 | width: 15px; 284 | border-left: none; 285 | border-top-right-radius: 0px; 286 | border-bottom-right-radius: 0px; 287 | } 288 | 289 | SARibbonComboBox::drop-down:hover { 290 | border: 1px solid #FDEEB3; 291 | background-color: #9ed2f9; 292 | } 293 | 294 | SARibbonComboBox::down-arrow { 295 | image: url(:/image/resource/ArrowDown.png); 296 | } 297 | 298 | /*SARibbonSeparatorWidget*/ 299 | 300 | SARibbonSeparatorWidget { 301 | /*background-color: transparent;*/ 302 | background-color: white; 303 | } 304 | 305 | SARibbonCategoryScrollButton { 306 | border: 1px solid #b9defa; 307 | color: #333; 308 | background-color: white; 309 | } 310 | 311 | SARibbonCategoryScrollButton::hover { 312 | color: #000000; 313 | border: 1px solid #badffa; 314 | background-color: #cee7fc; 315 | } 316 | -------------------------------------------------------------------------------- /src/PySARibbon/resource/ribbonPannelOptionButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sardkit/SARibbon-pyqt5/f96340356e1b15a91487d92cc39f79f7d16046a9/src/PySARibbon/resource/ribbonPannelOptionButton.png -------------------------------------------------------------------------------- /src/PySARibbon/resource_rc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Resource object code 4 | # 5 | # Created by: The Resource Compiler for PyQt5 (Qt v5.15.2) 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore 10 | 11 | qt_resource_data = b"\ 12 | \x00\x00\x05\x05\ 13 | \x00\ 14 | \x00\x18\x6f\x78\x9c\xdd\x58\xcd\x92\xe2\x36\x10\xbe\x53\xc5\x3b\ 15 | \x28\xc5\x65\x77\x0a\x16\x6c\x03\x63\x34\x27\xdb\xd8\xbb\x87\x6c\ 16 | \xe5\x67\x93\xca\xd9\xd8\x5a\x70\xad\xc7\x72\x64\x93\x61\x6a\x6a\ 17 | \x9e\x2c\x87\x3c\x52\x5e\x21\x92\x65\x83\x64\x49\xc0\x64\xf6\xb0\ 18 | \x09\x54\x51\xb8\xbb\xd5\xfd\x49\xad\xfe\xf3\xdf\x7f\xfe\x35\x1c\ 19 | \x4c\x6f\x40\x55\xc7\xa4\x06\x24\xdb\x6c\x70\x01\x2a\x54\xdf\x4c\ 20 | \x19\xf9\x93\xf7\x73\x43\xf1\x63\xc2\x08\xc3\x81\x40\x78\x1a\x0e\ 21 | \x00\xd8\xc4\xc9\x97\x2d\xc1\xfb\x22\x9d\x24\x38\xc7\x04\x82\x51\ 22 | \xe8\x84\xcb\xd0\xbd\x1b\x0e\x9e\xd9\x02\x41\xc7\xbe\xae\x71\xf1\ 23 | \x9e\x0a\x97\xbf\x65\xe9\x96\x9b\x30\x32\xa9\x76\x55\x77\x4d\xe2\ 24 | \xa2\x2a\x63\x82\x8a\x5a\xd5\xff\xd3\x3e\x4b\xbe\x78\x49\x82\xaa\ 25 | \xaa\x85\xab\xe7\x34\xb8\xb5\xc8\xa3\x68\x46\x3f\x9d\x66\x51\x77\ 26 | \x50\x93\x3c\xc0\x45\x1d\x67\x05\x92\x54\x4b\x0c\xa3\xe6\xb3\xb8\ 27 | \x83\xb8\x46\x5b\x4c\x1e\x25\xb5\x2d\x0d\x7e\xc6\xc9\xbe\x6a\xf4\ 28 | \xe2\x7d\x9d\x53\x23\x10\x14\xb8\x40\x5c\x4b\x5f\xda\xe0\x91\x87\ 29 | \x5d\x56\xb7\x2b\x4e\x56\x3f\xd5\x54\x0e\xa5\xaa\x27\x24\xc6\x65\ 30 | \x8d\xda\x65\xe7\x61\x9f\x40\x78\x65\x99\x67\x49\x5c\x67\xdd\x05\ 31 | \x10\x81\x28\xcc\x46\x1f\x47\xd0\x01\xa0\xe0\x30\x49\x11\x85\x64\ 32 | \x95\x07\x50\xe1\x3c\x4b\xc1\x68\x6e\x2d\x3d\x7f\x2d\x70\x27\x35\ 33 | \x2e\x27\x39\xfa\x5c\x4f\x48\x9c\x66\xfb\x0a\x02\xbb\x3c\xf4\xf9\ 34 | \x24\xdb\xee\x34\x02\xca\xde\x7f\x67\xdb\x89\xc9\x96\x49\x52\x7f\ 35 | \xbe\xa9\x4a\x82\xe2\x14\x96\x71\x3a\x06\x07\x0b\xce\xc6\xe0\xb1\ 36 | \xf9\x3d\xd8\xcd\x7f\x1b\x5a\xe3\x8a\xea\x87\x33\x0a\x6c\x79\x1b\ 37 | \xf9\xeb\x31\xe0\xcf\xef\x16\x60\x64\x7b\x8b\xc8\x0b\xc6\x1d\xc1\ 38 | \x02\x23\xcb\x9b\xcf\x5c\x77\x3c\x1c\x34\x34\x8b\xed\x66\xe5\x05\ 39 | \xd1\xdb\xee\xde\x18\x4f\x07\xc2\x1d\xfe\x03\x99\xa2\xf2\x15\xa8\ 40 | \x6f\x7d\xdf\x0e\x7d\x11\xf5\xfc\xf6\x36\x0c\xd6\x12\x6a\x6b\x1e\ 41 | \x06\x91\x80\xda\x9d\x85\x56\x74\x15\x6a\x0a\xa4\xaa\x50\xfa\xf5\ 42 | \x71\xd3\xd3\xf6\x7d\x09\xb7\x1d\x2d\x1d\x2f\x94\x70\x07\x73\xc7\ 43 | \xf5\x04\xdc\xce\xc2\xf5\x83\xd5\x15\xb8\xcf\xde\x70\xf1\x8e\xff\ 44 | \x12\x6f\x7a\xe9\x88\x53\x5e\x92\x2c\xe4\x95\x10\xd6\xf1\x06\xb4\ 45 | \xeb\xf9\xa2\xd1\xbc\xf9\xdc\xb5\x3a\x79\x4c\xb4\x78\x64\x2b\x7d\ 46 | \xfd\x8c\x7b\x4f\x0f\x38\x2b\x58\x14\x40\x30\x6b\x2f\xfe\x91\xda\ 47 | \xc4\x85\x86\xce\xe2\x09\x82\x65\x9f\xbc\xc1\xf4\x78\xee\x25\x79\ 48 | \x4a\x7d\xc8\xd2\x7a\x07\x97\xa2\x92\x43\x4b\xb4\x67\xb2\xe8\x0e\ 49 | \x35\x06\x1d\x59\x56\xa5\xd2\x2b\x90\x66\xc5\x96\xe3\xb0\x14\x32\ 50 | \x87\xad\xd2\x1b\x3f\x2b\xd4\x16\x35\x67\x98\x8e\x1c\x56\x28\x47\ 51 | \x49\x8d\xe8\xd5\xd3\x71\x9b\xf0\xe3\x6e\x79\x65\xda\xb9\x08\x40\ 52 | \xf6\xfd\x6c\xd6\x96\x2d\xc1\xf7\x62\x3e\xf4\xbd\x60\xb5\xf6\x35\ 53 | \x37\xe1\x94\x45\x8f\x90\xf8\x41\x08\x15\x91\x7d\xce\x41\x6a\x76\ 54 | \x0d\xbf\xeb\x21\xd3\xa0\x08\x03\x3f\x70\xd6\x77\x22\x72\x70\x82\ 55 | \x6e\xd4\x7f\xd4\xdc\x5d\x78\xf5\xb2\xf6\x02\xee\x7b\x1a\x8c\x61\ 56 | \x9a\x49\x45\xad\xa3\x01\x33\xbe\x60\x16\xd8\xc1\x5c\x73\x4a\x23\ 57 | \x7e\x02\x8c\xcc\xb1\xd0\x24\x30\xd1\x74\x0f\x2b\x9a\x6d\xa2\x5b\ 58 | \x45\x52\xd8\xaa\x26\x39\x60\x9c\xab\x95\xef\x44\x95\xe1\x9e\xd0\ 59 | \xaa\x31\xac\xcd\x03\x7d\x90\x4a\x6a\x51\x2d\xca\x09\xf9\x6c\x7e\ 60 | \x11\x4f\x2f\x0a\xfc\xc8\xb6\x4c\x76\x19\x7f\xed\x2c\xe7\x66\xa3\ 61 | \xc9\x0e\xb1\xf6\xe1\xa5\x46\x5b\xa5\xff\xd2\xa8\x10\xb1\x57\x07\ 62 | \xd3\x15\x36\x43\x77\xa5\xe9\xf2\x68\x93\x48\x74\xce\x96\x18\xfa\ 63 | \x2a\xd8\xf7\xb6\x0a\xab\x2f\xd1\x3f\xc0\x67\x83\xbd\x51\x47\x7d\ 64 | \x1f\xe7\x39\x22\x8f\x9c\xfa\x6b\x39\xd6\x33\xd6\xf8\xa1\x30\xb0\ 65 | \x3e\x62\x82\x9e\xf4\xe0\x4e\xa1\x75\x11\x06\x0d\xfb\x0f\x59\x8a\ 66 | \x7e\x8c\x8b\x02\x49\x47\x72\x61\xc7\x26\xc5\xbd\xf6\xe2\xac\x3b\ 67 | \xbf\x6a\xf3\x11\xad\xc3\xd0\x77\x8e\xcd\x87\x65\xbb\x76\x43\x64\ 68 | \xdd\x46\x4b\x73\x1d\xc7\x19\x0e\x28\x82\x70\xe1\x06\xad\xa4\xc5\ 69 | \x84\xa8\x98\xff\xf6\xec\xa6\xc4\x68\xf9\xdf\x6c\x4a\xa9\x9f\xff\ 70 | \x99\x3d\x01\x65\x5e\xfc\x88\x8a\xbd\x18\xe4\xec\x19\x3c\xe9\x22\ 71 | \xd3\x90\x44\xd8\xd7\x34\xdf\xb8\xf3\x95\xed\x2d\xe5\xb3\x64\x06\ 72 | \x20\xa4\xe5\xfc\x9e\x9b\x69\x1b\x1b\x08\x16\x74\x9d\xcd\x7e\xba\ 73 | \x3f\x06\x9b\xc6\x78\x3a\x69\x86\x72\x29\xbe\x90\xfc\x34\xeb\x0d\ 74 | \xf9\xf6\x8a\x64\xab\xea\x4b\xda\xcc\x20\x75\xa3\x96\xae\x1f\xe0\ 75 | \xc9\xe4\x87\x52\x3f\x65\xaa\x5c\xd3\xee\xae\xc8\xb1\xe7\xd4\xca\ 76 | \x17\xfc\x9b\xbb\xc2\xc7\xe3\x17\x7a\xaa\xfe\x76\xcc\x7e\xef\xda\ 77 | \x44\x8d\x9a\xbe\x23\xd4\xc3\x7f\xa5\xda\xb6\x0c\x89\x7a\x5b\xd2\ 78 | \xcb\x3c\x09\xa4\xa0\x3c\x5f\xc5\x34\xf6\x9b\x77\x57\x1a\x10\x0d\ 79 | \x9d\x23\xa9\x76\xf8\x61\x92\xa2\x04\x93\x66\x92\x9c\x74\xf1\x44\ 80 | \xcd\x5c\x15\x95\x1a\xa4\xcf\x7a\x7b\x57\x06\xec\xb7\x53\x0b\x34\ 81 | \xe0\x35\xf5\xc0\x16\x52\x43\x63\x5f\xd7\x67\xdd\x6f\xb0\x8f\x0f\ 82 | \x72\x8b\xc5\x69\xc6\xe2\x72\x74\x6d\x2f\x8a\xbb\x85\xe2\xab\x15\ 83 | \x4d\x96\xea\xa0\xb4\xfe\x01\x72\xb7\xaf\x28\x43\x74\x10\x89\x37\ 84 | \x39\x12\x0a\xc2\x69\x89\x69\x42\xbb\x76\xf4\x38\x3b\x78\x28\x50\ 85 | \x60\x4a\xe8\x0c\x9a\xd2\xb6\xae\xbd\xa1\xfb\x4d\xc2\xab\xf2\x04\ 86 | \xd3\xc9\x34\x2b\x60\x57\x49\xee\x7a\xec\x12\x57\x19\x33\x43\xef\ 87 | \x28\x2e\x41\x33\xc5\x36\x22\x7c\xa8\x07\xd6\x42\x1e\x75\x79\x7e\ 88 | \x3e\xbe\x91\x30\x0e\xc0\x33\x79\x59\x3b\x8e\xea\x64\x2e\x6d\xe8\ 89 | \x52\x3f\x71\x72\xda\xb7\x1c\x17\xc2\xc6\xe8\x9e\x26\x31\x21\xf8\ 90 | \x81\xef\x29\xbb\x8f\xb7\x08\x82\x3d\xc9\xdf\xc0\x69\xf3\x30\xa5\ 91 | \xad\x2e\xde\x93\x04\x4d\x3d\x26\xc6\x9a\xf5\x77\x65\xb1\x3d\xbe\ 92 | \xcc\x92\x5e\xff\x22\x9a\x55\xe2\x1a\x13\xcd\x0b\x60\x99\xd5\x96\ 93 | \xeb\xe9\xcd\xf9\xec\xc4\x34\x18\x46\xa2\xb5\xc3\xbe\x1c\xc5\x3f\ 94 | \xa8\x0c\x82\xed\ 95 | \x00\x00\x04\x46\ 96 | \x00\ 97 | \x00\x16\x42\x78\x9c\xad\x58\xcd\x6e\xdb\x38\x10\xbe\x07\xc8\x3b\ 98 | \xb0\xf0\x65\x37\xa8\xd7\x8a\x52\x37\xb1\x7a\x8a\xdd\xa4\x3d\xb4\ 99 | \x68\x77\xd3\xc5\x9e\x29\x92\xb2\x89\xca\xa2\x40\x51\xeb\x04\x45\ 100 | \x9e\xac\x87\x3e\x52\x5f\xa1\x94\x28\xd9\xe2\x9f\x24\xa7\x49\x2f\ 101 | \xe9\xcc\x68\xbe\xe1\xfc\x4f\x7e\x7e\xff\x31\x3b\x03\x85\x80\x5c\ 102 | \x00\x4e\xe3\x98\x65\xa0\x20\xe2\x6c\x76\x7a\x72\x7a\x32\x3b\xbb\ 103 | \xbb\xfe\xa7\xa6\x2d\x21\x57\xa4\x0e\x01\x7c\x3b\x3d\x01\x20\x86\ 104 | \xe8\xeb\x9a\xb3\x32\xc3\x53\xc4\x52\xc6\x23\xb0\xdb\x50\x41\xde\ 105 | \xd4\x3c\xc6\x31\x91\x94\xf3\xfc\x1e\x14\x2c\xa5\x18\x4c\xc2\x78\ 106 | \x7e\xb9\x80\x92\xfb\x68\x00\x94\x42\xb0\xec\x9d\x54\x94\xff\x47\ 107 | \xf1\xba\xb5\xc0\xcb\xf6\x81\x0b\x0e\xb3\x22\x87\x9c\x64\xc2\x06\ 108 | \xf9\xbb\xa4\xe8\xeb\x35\x42\xa4\x28\xac\x07\xe9\x3c\x9f\xfa\x09\ 109 | \x22\xe4\x2a\x41\xb6\xea\x95\xe0\xe9\x8a\x65\x02\xd2\x8c\x18\x9a\ 110 | \x35\xd6\x93\xec\x5e\x41\x41\xd6\x8c\x3f\x18\x7a\x1b\x6a\x94\x30\ 111 | \x54\x16\x4a\x31\x2b\x45\x2a\x61\x22\x90\xb1\x8c\xb4\x8a\xcc\x0f\ 112 | \xbc\x8f\x4b\x50\x82\x13\x62\xe3\xdf\x09\x29\x4b\xb0\x2b\x30\x1a\ 113 | \x6b\x6c\x46\x4c\x63\x26\xc3\xb9\xd5\x12\x03\xcd\x71\x48\x82\xae\ 114 | \x50\x4a\x12\x31\x20\xc2\xe9\x7a\x33\x24\x23\x58\xee\x76\x87\x66\ 115 | \xfa\xa0\x13\x0f\xde\xb8\xce\xf3\x94\x22\x28\x68\x9b\x96\xba\x47\ 116 | \x2c\xb6\x52\x7a\x54\x71\x74\x8d\xaf\xfd\x30\xe5\x10\xd3\xb2\x88\ 117 | \x40\x98\xdf\x9b\xfc\xda\x09\xb6\x80\x1d\x5e\xbd\xf6\xbc\xf6\x46\ 118 | \xd1\x86\xfd\xef\xcf\xd4\xc9\xf9\x7c\x7e\x75\xb5\x18\xa1\x26\xe7\ 119 | \xb2\x98\x08\xfe\x6d\x45\xe3\x43\xf3\x05\xc6\x56\x61\x2b\xda\x11\ 120 | \x75\xa7\x7f\x18\x45\x02\xc6\x5a\x08\x27\xf3\x4b\xe9\xc6\x44\x0b\ 121 | \x62\x63\x4e\x17\xc1\xd4\x0d\xc0\x16\xf2\x35\xcd\x54\x42\x06\x4d\ 122 | \x98\x1a\x5a\x93\xc8\x06\x55\x55\xc0\x6b\x9d\xd8\xd6\xce\x5e\x56\ 123 | \xd2\x76\x14\x8b\x8d\x94\x3c\x7c\x7f\xdf\xd2\xc2\xa0\x2b\xb8\x21\ 124 | \x0a\x28\x9c\x77\x24\x2d\x62\x0e\x31\xa6\xd9\xfa\x50\x81\x1a\xf5\ 125 | \x50\x74\x1a\xb9\x7e\x96\x49\xec\x14\x7a\x8f\x7b\xa3\x82\xa4\x04\ 126 | \x09\x82\x5f\x02\x17\xb7\x9b\x8e\x9e\xb2\x08\x86\xca\x22\x18\x67\ 127 | \xc0\x60\xa0\x3d\xad\xa6\x13\x75\x4f\xb3\xdb\x67\xfd\x6d\xfd\xd3\ 128 | \x67\x4c\xfd\xde\xe8\x85\x6e\x53\xbf\x01\x96\xc5\x5e\xe5\x86\x5a\ 129 | \x3b\x27\xcd\x92\x62\x2c\x75\xb5\xb9\x03\xdd\x67\x9f\x99\xfe\xad\ 130 | \x8d\x17\x17\x17\x9e\x0e\xd5\xba\xee\xd1\x0d\xd4\x6d\x04\x0e\x77\ 131 | \xc4\x0b\x4c\x12\x38\x12\xca\x98\x75\x0e\x30\xbd\x7d\xb5\x9f\x05\ 132 | \x41\xe0\xce\x87\x49\xf8\x7a\x11\x27\xaf\x7c\x70\x0b\x82\xc3\xc4\ 133 | \xea\x75\x5d\x38\xb4\x21\xd5\x38\xd2\xe1\xf6\x0f\xe8\x7d\xee\xe0\ 134 | \x9e\xe2\xc2\xeb\x54\xd5\xe0\xe3\x24\x1a\xc4\x49\x2f\xda\xa5\x73\ 135 | \x2b\x92\x6b\x0f\x77\xe7\x8f\xc6\x1a\xd7\x9d\x8f\x4f\xb2\x47\x2f\ 136 | \xe2\xa4\xa5\xbe\x83\x69\x4a\xf8\x83\xa2\xfe\x9b\xbf\x04\x6e\xce\ 137 | \x5b\xb6\xcb\x7c\xbc\x8f\x8c\x13\x7f\x91\x3a\x03\xe1\xb6\x45\x16\ 138 | \xe9\x7b\x8a\xc9\x67\x98\x65\xe4\xa8\xe2\xf2\xeb\x36\xa7\xb0\x63\ 139 | \xe9\x78\x42\xde\x1a\x10\x5a\xea\x3e\x53\xaa\x1a\x10\xd6\x0c\x78\ 140 | \x86\xec\xfc\x48\xb2\x52\x4f\xca\x8a\xe2\x29\x40\x5b\xed\xed\xaa\ 141 | \xfa\xe7\x9d\x0e\x21\x0e\xb0\xd5\x89\x2b\x80\x28\x92\x5d\x6e\xab\ 142 | \x60\x9a\x39\x19\x01\x39\x7a\xeb\xf9\xbb\xff\xc5\x83\xda\x13\xf7\ 143 | \x83\x6e\x63\x9c\x8d\xf6\x79\x47\x43\x5f\x77\xe8\xf1\x70\x7f\x74\ 144 | \x5c\x60\xa8\xcd\x71\x6d\xe7\x39\x77\x8d\x22\x55\x17\x9f\x72\xdf\ 145 | \xe6\x6d\xf3\xc7\xf6\x95\x9e\xae\x61\x2b\x1d\xda\x8f\x1d\xce\x70\ 146 | \x4e\x56\xa5\xd9\xf5\x84\xf1\x97\xb5\x53\x71\xd3\x9c\x74\xcd\x0d\ 147 | \xf1\x69\x1e\x19\x91\xe1\x16\x7c\x7d\xac\x3b\x6d\xa8\x39\xca\x90\ 148 | \x62\xc3\x76\x53\x4c\x10\xe3\xf5\xc2\x3f\x6d\x13\x57\x02\x8d\x2a\ 149 | \x80\xde\xd0\x75\xe1\xc6\x16\x86\xbb\xdf\x39\x34\x39\x1a\x52\xf8\ 150 | \xbb\x0d\xe9\x83\x3c\x6d\x6e\x30\x35\x4e\xec\x96\xea\xed\x7e\xab\ 151 | \x60\x15\xae\xcc\x0e\xae\x36\xcd\x9a\xa8\x1e\x5d\xb9\xd7\xf5\xe0\ 152 | \xe5\x72\x79\x7b\x69\xc8\xe9\x25\x6f\x0d\xf5\x6d\xcc\x96\xec\xde\ 153 | \x9c\xe7\x8a\xea\x1f\x84\xce\x86\xd8\x7e\x36\xd0\xe0\x3b\x43\xca\ 154 | \x61\x9b\xa5\x8c\x48\x77\xc1\x38\x25\x43\x0d\xac\x5b\x52\xcf\xe2\ 155 | \x25\xcb\x92\x08\x73\x79\x8b\x60\xb9\x3d\x34\x09\x5f\xc6\x48\x4d\ 156 | \xb6\x29\x93\x17\x0a\xcd\xa2\x76\x06\xbc\x31\xd8\x39\x2b\x68\x05\ 157 | \x23\x53\x9e\xe5\xa0\xbe\x66\x6a\x91\xe6\xae\x3b\x9f\xeb\x27\x8f\ 158 | \xea\x9b\x87\x3b\xb4\xff\x10\x32\x8f\x93\xc1\x63\xc9\xf1\xa0\x81\ 159 | \x90\xdd\xbe\xbd\xb9\x59\x7a\x87\xa7\x6f\xaf\xd8\xa3\x48\x80\x29\ 160 | \xe4\x9c\xed\x14\x00\xdd\xc2\xb5\x3c\xfb\x4b\x9e\xfe\x11\xcd\xea\ 161 | \xff\xcc\xe4\x5e\xc3\x4a\x8e\xc8\xec\xba\x12\xab\x16\xb4\xbf\xf2\ 162 | \x6c\xfd\xa7\x9d\xb0\x77\x44\xf6\x0b\x28\x18\x77\xfe\x01\x4b\x67\ 163 | \x2a\xb4\xd9\x59\x7f\xe3\xa9\x54\x8c\x3e\x60\xda\x3f\xbb\xdd\x21\ 164 | \x19\xd6\x81\xb5\xee\xb8\x23\x66\x34\x9c\x6f\xdb\x7f\x96\x85\xff\ 165 | \x17\x5f\x11\xff\x5f\ 166 | \x00\x00\x00\x8a\ 167 | \x89\ 168 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ 169 | \x00\x00\x09\x00\x00\x00\x09\x04\x03\x00\x00\x00\x12\xbf\x1b\x23\ 170 | \x00\x00\x00\x0f\x50\x4c\x54\x45\xff\xff\xff\x22\x22\x23\x2d\x2d\ 171 | \x2e\x27\x27\x28\x22\x22\x23\x63\x36\x15\x77\x00\x00\x00\x04\x74\ 172 | \x52\x4e\x53\x00\x00\xe6\xf3\x9f\x03\x91\x56\x00\x00\x00\x26\x49\ 173 | \x44\x41\x54\x08\xd7\x63\x60\x00\x03\x26\x25\x25\x05\x20\x29\x28\ 174 | \x28\x80\x20\x0d\x85\x40\xa4\xb0\x12\x88\x14\x72\x02\xa9\x52\x52\ 175 | \x82\xa8\x66\x00\x00\x37\xe2\x02\x18\x83\x28\x69\xeb\x00\x00\x00\ 176 | \x00\x49\x45\x4e\x44\xae\x42\x60\x82\ 177 | \x00\x00\x00\x63\ 178 | \x89\ 179 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ 180 | \x00\x00\x0b\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x4a\x8b\x99\x2e\ 181 | \x00\x00\x00\x02\x74\x52\x4e\x53\x00\x01\x01\x94\xfd\xae\x00\x00\ 182 | \x00\x1c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\x80\x01\x88\x0e\x24\ 183 | \x30\x3c\x78\xc0\xf0\xf1\x01\xc3\x6f\x18\x17\x2c\x0e\x00\xff\xb0\ 184 | \x11\x08\x04\x7a\xdf\xda\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\ 185 | \x60\x82\ 186 | \x00\x00\x00\x63\ 187 | \x89\ 188 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ 189 | \x00\x00\x0b\x00\x00\x00\x0a\x01\x00\x00\x00\x00\x4a\x8b\x99\x2e\ 190 | \x00\x00\x00\x02\x74\x52\x4e\x53\x00\x01\x01\x94\xfd\xae\x00\x00\ 191 | \x00\x1c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\x80\x01\x82\x0e\x24\ 192 | \x30\x3c\x78\xc0\xf0\xf1\x01\xc3\x6f\x98\xc8\xff\x07\x00\x08\x07\ 193 | \x11\xc7\x11\x7b\xe2\x94\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\ 194 | \x60\x82\ 195 | \x00\x00\x00\x68\ 196 | \x89\ 197 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ 198 | \x00\x00\x0b\x00\x00\x00\x0a\x08\x04\x00\x00\x00\xc8\xf9\x6c\x08\ 199 | \x00\x00\x00\x2f\x49\x44\x41\x54\x08\xd7\x63\xfc\xcf\x80\x0d\x30\ 200 | \x31\x90\x22\xcc\xc2\xc0\xc0\xc0\xc0\x08\x61\xff\x87\x30\xfe\xa3\ 201 | \xa8\xfe\x0f\xc5\x28\x86\xfc\x47\xa5\x99\x50\x04\xe1\x6c\x46\x6a\ 202 | \x38\x10\x00\xbd\x94\x0a\x0d\xc6\x7b\xd7\x10\x00\x00\x00\x00\x49\ 203 | \x45\x4e\x44\xae\x42\x60\x82\ 204 | " 205 | 206 | qt_resource_name = b"\ 207 | \x00\x04\ 208 | \x00\x06\xfa\x5e\ 209 | \x00\x69\ 210 | \x00\x63\x00\x6f\x00\x6e\ 211 | \x00\x05\ 212 | \x00\x7a\xec\x35\ 213 | \x00\x74\ 214 | \x00\x68\x00\x65\x00\x6d\x00\x65\ 215 | \x00\x08\ 216 | \x0c\xa6\xc7\x95\ 217 | \x00\x72\ 218 | \x00\x65\x00\x73\x00\x6f\x00\x75\x00\x72\x00\x63\x00\x65\ 219 | \x00\x0b\ 220 | \x0c\xe2\x21\xa3\ 221 | \x00\x64\ 222 | \x00\x65\x00\x66\x00\x61\x00\x75\x00\x6c\x00\x74\x00\x2e\x00\x71\x00\x73\x00\x73\ 223 | \x00\x0e\ 224 | \x0a\xdd\x75\x63\ 225 | \x00\x6f\ 226 | \x00\x66\x00\x66\x00\x69\x00\x63\x00\x65\x00\x32\x00\x30\x00\x31\x00\x33\x00\x2e\x00\x71\x00\x73\x00\x73\ 227 | \x00\x1c\ 228 | \x00\x82\x2a\xa7\ 229 | \x00\x72\ 230 | \x00\x69\x00\x62\x00\x62\x00\x6f\x00\x6e\x00\x50\x00\x61\x00\x6e\x00\x6e\x00\x65\x00\x6c\x00\x4f\x00\x70\x00\x74\x00\x69\x00\x6f\ 231 | \x00\x6e\x00\x42\x00\x75\x00\x74\x00\x74\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ 232 | \x00\x0d\ 233 | \x07\xb6\x8e\xe7\ 234 | \x00\x41\ 235 | \x00\x72\x00\x72\x00\x6f\x00\x77\x00\x4d\x00\x6f\x00\x72\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\ 236 | \x00\x0d\ 237 | \x08\x13\x81\x07\ 238 | \x00\x41\ 239 | \x00\x72\x00\x72\x00\x6f\x00\x77\x00\x44\x00\x6f\x00\x77\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ 240 | \x00\x0b\ 241 | \x0c\x52\x65\x87\ 242 | \x00\x41\ 243 | \x00\x72\x00\x72\x00\x6f\x00\x77\x00\x55\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\ 244 | " 245 | 246 | qt_resource_struct_v1 = b"\ 247 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\ 248 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x06\ 249 | \x00\x00\x00\x0e\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ 250 | \x00\x00\x00\x1e\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\ 251 | \x00\x00\x00\x50\x00\x01\x00\x00\x00\x01\x00\x00\x05\x09\ 252 | \x00\x00\x00\x34\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ 253 | \x00\x00\x00\x1e\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\ 254 | \x00\x00\x00\x72\x00\x00\x00\x00\x00\x01\x00\x00\x09\x53\ 255 | \x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xe1\ 256 | \x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x48\ 257 | \x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xaf\ 258 | " 259 | 260 | qt_resource_struct_v2 = b"\ 261 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\ 262 | \x00\x00\x00\x00\x00\x00\x00\x00\ 263 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x06\ 264 | \x00\x00\x00\x00\x00\x00\x00\x00\ 265 | \x00\x00\x00\x0e\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ 266 | \x00\x00\x00\x00\x00\x00\x00\x00\ 267 | \x00\x00\x00\x1e\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\ 268 | \x00\x00\x00\x00\x00\x00\x00\x00\ 269 | \x00\x00\x00\x50\x00\x01\x00\x00\x00\x01\x00\x00\x05\x09\ 270 | \x00\x00\x01\x7a\x85\x52\x0e\x45\ 271 | \x00\x00\x00\x34\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ 272 | \x00\x00\x01\x7a\x85\x52\x0e\x41\ 273 | \x00\x00\x00\x1e\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\ 274 | \x00\x00\x00\x00\x00\x00\x00\x00\ 275 | \x00\x00\x00\x72\x00\x00\x00\x00\x00\x01\x00\x00\x09\x53\ 276 | \x00\x00\x01\x7a\x85\x52\x0e\x47\ 277 | \x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xe1\ 278 | \x00\x00\x01\x7a\x85\x52\x0e\x3c\ 279 | \x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x48\ 280 | \x00\x00\x01\x7a\x85\x52\x0e\x39\ 281 | \x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xaf\ 282 | \x00\x00\x01\x7a\x85\x52\x0e\x3e\ 283 | " 284 | 285 | qt_version = [int(v) for v in QtCore.qVersion().split('.')] 286 | if qt_version < [5, 8, 0]: 287 | rcc_version = 1 288 | qt_resource_struct = qt_resource_struct_v1 289 | else: 290 | rcc_version = 2 291 | qt_resource_struct = qt_resource_struct_v2 292 | 293 | def qInitResources(): 294 | QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) 295 | 296 | def qCleanupResources(): 297 | QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) 298 | 299 | qInitResources() 300 | -------------------------------------------------------------------------------- /src/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='PySARibbon', 5 | version='1.0.2', 6 | description='4种目前常见的ribbon样式.', 7 | # long_description=read('README.md'), 8 | keywords=('python', 'ribbon'), 9 | license='GPL', 10 | 11 | url='https://github.com/sardkit/pysaribbon', 12 | author='sardkit', 13 | author_email='sardkit@163.com', 14 | 15 | packages=find_packages(), 16 | py_modules=[], 17 | install_requires=[ 18 | 'pyqt5', 19 | ], 20 | 21 | classifiers=[ 22 | # How mature is this project? Common values are 23 | # 3 - Alpha 24 | # 4 - Beta 25 | # 5 - Production/Stable 26 | 'Development Status :: 4 - Beta', 27 | 28 | # Indicate who your project is intended for 29 | 'Intended Audience :: Developers', 30 | 'Topic :: Software Development', 31 | 32 | # Pick your license as you wish (should match "license" above) 33 | 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', 34 | 35 | 'Programming Language :: Python :: 3', 36 | ], 37 | 38 | scripts=[] 39 | ) 40 | --------------------------------------------------------------------------------