codeallyadvanced 2.6.0__tar.gz → 3.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codeallyadvanced-2.6.0/src/codeallyadvanced.egg-info → codeallyadvanced-3.1.0}/PKG-INFO +36 -20
- codeallyadvanced-3.1.0/README.md +70 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/pyproject.toml +6 -6
- codeallyadvanced-3.1.0/src/codeallyadvanced/_version.py +1 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/DimensionsControl.py +63 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/DirectorySelector.py +141 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/DualSpinnerControl.py +196 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/MinMaxControl.py +57 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/NamedSpinCtrl.py +156 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/PositionControl.py +63 -0
- codeallyadvanced-3.1.0/src/codeallyadvanced/ui/widgets/TitledPanel.py +82 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0/src/codeallyadvanced.egg-info}/PKG-INFO +36 -20
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced.egg-info/SOURCES.txt +2 -1
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced.egg-info/requires.txt +5 -5
- codeallyadvanced-2.6.0/README.md +0 -54
- codeallyadvanced-2.6.0/src/codeallyadvanced/_version.py +0 -1
- codeallyadvanced-2.6.0/src/codeallyadvanced/resources/images/folder.py +0 -21
- codeallyadvanced-2.6.0/src/codeallyadvanced/ui/widgets/DimensionsControl.py +0 -58
- codeallyadvanced-2.6.0/src/codeallyadvanced/ui/widgets/DirectorySelector.py +0 -83
- codeallyadvanced-2.6.0/src/codeallyadvanced/ui/widgets/DualSpinnerControl.py +0 -132
- codeallyadvanced-2.6.0/src/codeallyadvanced/ui/widgets/MinMaxControl.py +0 -40
- codeallyadvanced-2.6.0/src/codeallyadvanced/ui/widgets/PositionControl.py +0 -58
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/LICENSE +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/setup.cfg +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/DefaultPreferences.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxActor.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxArrow.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxClass.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxNewClassDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxNewProject.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxNewSequenceDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxNewUseCaseDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxOpenFile.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRedo.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipAggregation.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipAssociation.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipComposition.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipInheritance.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxRelationshipRealization.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxSaveDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxSequenceDiagramInstance.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxSequenceDiagramMessage.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxText.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxUndo.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxUseCase.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxZoomIn.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/ImgToolboxZoomOut.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/UmlLollipop.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/UmlNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/UmlText.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded16/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxActor.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxArrow.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxClass.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxNewClassDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxNewProject.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxNewSequenceDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxNewUseCaseDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxOpenFile.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRedo.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipAggregation.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipAssociation.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipComposition.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipInheritance.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxRelationshipRealization.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxSaveDiagram.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxSequenceDiagramInstance.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxSequenceDiagramMessage.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxText.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxUndo.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxUseCase.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxZoomIn.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/ImgToolboxZoomOut.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/UmlLollipop.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/UmlNote.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/UmlText.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/embedded32/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/icons/sourceimages/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/images/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/Embedded16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/Embedded24.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/Embedded32.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/Embedded48.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/Embedded64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/minimalistglyph/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/MageBitMap.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/back16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/back64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/cancel16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/cancel64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/next16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/next64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/mystic/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/Embedded16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/Embedded24.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/Embedded32.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/Embedded48.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/Embedded64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neoindustrialminimalist/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/Embedded16.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/Embedded24.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/Embedded32.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/Embedded48.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/Embedded64.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/neumorphic/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/resources/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/AttachmentSide.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/Common.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/UnitTestBaseW.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/mystic/Mystic.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/mystic/MysticPanel.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/mystic/MysticStepBase.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/mystic/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/mystic/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/DialControl.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/DialSelector.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/DirectionEnum.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/MacDialSelector.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/__init__.py +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced/ui/widgets/py.typed +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced.egg-info/dependency_links.txt +0 -0
- {codeallyadvanced-2.6.0 → codeallyadvanced-3.1.0}/src/codeallyadvanced.egg-info/top_level.txt +0 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codeallyadvanced
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: Humberto`s Common wxPython UI Stuff
|
|
5
5
|
Author-email: "Humberto A. Sanchez II" <Humberto.A.Sanchez.II@gmail.com>
|
|
6
6
|
Maintainer-email: "Humberto A. Sanchez II" <Humberto.A.Sanchez.II@gmail.com>
|
|
7
7
|
License-Expression: AGPL-1.0-or-later
|
|
8
8
|
Project-URL: Repository, https://github.com/hasii2011/code-ally-advanced
|
|
9
|
-
Keywords:
|
|
9
|
+
Keywords: uml,python,wxPython,UI,umldiagrammer
|
|
10
10
|
Classifier: Programming Language :: Python
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: buildlackey>=2.
|
|
17
|
-
Requires-Dist: wxPython>=4.
|
|
16
|
+
Requires-Dist: buildlackey>=2.1.0
|
|
17
|
+
Requires-Dist: wxPython>=4.3.1
|
|
18
18
|
Provides-Extra: test
|
|
19
|
-
Requires-Dist: mypy==
|
|
20
|
-
Requires-Dist: codeallybasic==1.
|
|
19
|
+
Requires-Dist: mypy==2.3.1; extra == "test"
|
|
20
|
+
Requires-Dist: codeallybasic==1.40.0; extra == "test"
|
|
21
21
|
Requires-Dist: mypy-extensions==1.1.0; extra == "test"
|
|
22
22
|
Requires-Dist: types-Deprecated==1.3.1.20251101; extra == "test"
|
|
23
23
|
Requires-Dist: html-testRunner~=1.2.1; extra == "test"
|
|
24
|
-
Requires-Dist: click==8.
|
|
24
|
+
Requires-Dist: click==8.5.0; extra == "test"
|
|
25
25
|
Provides-Extra: docs
|
|
26
26
|
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
27
27
|
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
|
|
@@ -33,39 +33,54 @@ Requires-Dist: twine==6.2.0; extra == "deploy"
|
|
|
33
33
|
Requires-Dist: build==1.3.0; extra == "deploy"
|
|
34
34
|
Dynamic: license-file
|
|
35
35
|
|
|
36
|
-
](https://github.com/hasii2011/code-ally-advanced/graphs/commit-activity)
|
|
38
37
|
[](https://github.com/hasii2011/code-ally-advanced/actions/workflows/ci.yml)
|
|
39
38
|
[](https://badge.fury.io/py/codeallyadvanced)
|
|
40
|
-
[](LICENSE)
|
|
40
|
+
[](https://www.python.org/)
|
|
41
|
+
[](https://code-ally-advanced.readthedocs.io/en/latest/?badge=latest)
|
|
42
|
+
[](https://github.com/hasii2011/code-ally-basic/wiki/GitHub-Copilot)
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
This repository hosts common UI artifacts for various projects I develop.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
The documentation is on [Read the Docs](https://code-ally-advanced.readthedocs.io/en/latest/).
|
|
45
47
|
|
|
46
48
|
___
|
|
47
|
-
|
|
49
|
+
Available wxPython UI components:
|
|
48
50
|
|
|
49
51
|
* Dimensions Control
|
|
50
52
|
* Position Control
|
|
51
53
|
* MinMax Control
|
|
54
|
+
* Named Spin Control
|
|
52
55
|
* Directory Selector
|
|
56
|
+
* Dial Selector
|
|
57
|
+
* Titled Panels
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
### Component Previews
|
|
55
60
|
|
|
56
|
-
*
|
|
61
|
+
* Spinner Widgets
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
* Directory Selector
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
* Dial Selector
|
|
57
70
|
|
|
58
71
|

|
|
59
72
|
|
|
60
|
-
|
|
73
|
+
* Titled Panels
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
Written by <a href="mailto:humberto.a.sanchez.ii@gmail.com?subject=Hello Humberto">Humberto A. Sanchez II</a> (C) 2026
|
|
61
78
|
|
|
62
79
|
## Note
|
|
63
80
|
For all kinds of problems, requests, enhancements, bug reports, etc., drop me an e-mail.
|
|
64
81
|
|
|
65
82
|
## Developer Notes
|
|
66
|
-
This project uses [buildlackey](https://github.com/hasii2011/buildlackey) for day-to-day development builds
|
|
67
|
-
|
|
68
|
-
Also notice that this project does not include a `requirements.txt` file. All dependencies are listed in the `pyproject.toml` file.
|
|
83
|
+
This project uses [buildlackey](https://github.com/hasii2011/buildlackey) for day-to-day development builds.
|
|
69
84
|
|
|
70
85
|
#### Install the main project dependencies
|
|
71
86
|
|
|
@@ -86,4 +101,5 @@ pip install .[deploy]
|
|
|
86
101
|
```
|
|
87
102
|
|
|
88
103
|
---
|
|
89
|
-
[
|
|
104
|
+
> [!NOTE]
|
|
105
|
+
> **I do not consent to GitHub's use of this project's code in Copilot.** See our [GitHub Copilot Statement](https://github.com/hasii2011/code-ally-basic/wiki/GitHub-Copilot) for details.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[](https://github.com/hasii2011/code-ally-advanced/graphs/commit-activity)
|
|
2
|
+
[](https://github.com/hasii2011/code-ally-advanced/actions/workflows/ci.yml)
|
|
3
|
+
[](https://badge.fury.io/py/codeallyadvanced)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[](https://code-ally-advanced.readthedocs.io/en/latest/?badge=latest)
|
|
7
|
+
[](https://github.com/hasii2011/code-ally-basic/wiki/GitHub-Copilot)
|
|
8
|
+
|
|
9
|
+
This repository hosts common UI artifacts for various projects I develop.
|
|
10
|
+
|
|
11
|
+
The documentation is on [Read the Docs](https://code-ally-advanced.readthedocs.io/en/latest/).
|
|
12
|
+
|
|
13
|
+
___
|
|
14
|
+
Available wxPython UI components:
|
|
15
|
+
|
|
16
|
+
* Dimensions Control
|
|
17
|
+
* Position Control
|
|
18
|
+
* MinMax Control
|
|
19
|
+
* Named Spin Control
|
|
20
|
+
* Directory Selector
|
|
21
|
+
* Dial Selector
|
|
22
|
+
* Titled Panels
|
|
23
|
+
|
|
24
|
+
### Component Previews
|
|
25
|
+
|
|
26
|
+
* Spinner Widgets
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
* Directory Selector
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
* Dial Selector
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
* Titled Panels
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
Written by <a href="mailto:humberto.a.sanchez.ii@gmail.com?subject=Hello Humberto">Humberto A. Sanchez II</a> (C) 2026
|
|
43
|
+
|
|
44
|
+
## Note
|
|
45
|
+
For all kinds of problems, requests, enhancements, bug reports, etc., drop me an e-mail.
|
|
46
|
+
|
|
47
|
+
## Developer Notes
|
|
48
|
+
This project uses [buildlackey](https://github.com/hasii2011/buildlackey) for day-to-day development builds.
|
|
49
|
+
|
|
50
|
+
#### Install the main project dependencies
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Install the test dependencies
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install .[test]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Install the deploy dependencies
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install .[deploy]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> **I do not consent to GitHub's use of this project's code in Copilot.** See our [GitHub Copilot Statement](https://github.com/hasii2011/code-ally-basic/wiki/GitHub-Copilot) for details.
|
|
@@ -9,7 +9,7 @@ description = 'Humberto`s Common wxPython UI Stuff'
|
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = 'Humberto A. Sanchez II', email = 'Humberto.A.Sanchez.II@gmail.com'}]
|
|
11
11
|
maintainers = [{name = 'Humberto A. Sanchez II', email = 'Humberto.A.Sanchez.II@gmail.com'}]
|
|
12
|
-
keywords = ['
|
|
12
|
+
keywords = ['uml', 'python', 'wxPython', 'UI', 'umldiagrammer']
|
|
13
13
|
license = 'AGPL-1.0-or-later'
|
|
14
14
|
license-files = ['LICENSE']
|
|
15
15
|
classifiers = [
|
|
@@ -20,18 +20,18 @@ classifiers = [
|
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
dependencies = [
|
|
23
|
-
'buildlackey>=2.
|
|
24
|
-
'wxPython>=4.
|
|
23
|
+
'buildlackey>=2.1.0',
|
|
24
|
+
'wxPython>=4.3.1'
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.optional-dependencies]
|
|
28
28
|
test = [
|
|
29
|
-
'mypy==
|
|
30
|
-
'codeallybasic==1.
|
|
29
|
+
'mypy==2.3.1',
|
|
30
|
+
'codeallybasic==1.40.0',
|
|
31
31
|
'mypy-extensions==1.1.0',
|
|
32
32
|
'types-Deprecated==1.3.1.20251101',
|
|
33
33
|
'html-testRunner~=1.2.1',
|
|
34
|
-
'click==8.
|
|
34
|
+
'click==8.5.0'
|
|
35
35
|
|
|
36
36
|
]
|
|
37
37
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__: str = '3.1.0'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from wx.lib.sized_controls import SizedPanel
|
|
8
|
+
|
|
9
|
+
from codeallybasic.Dimensions import Dimensions
|
|
10
|
+
|
|
11
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import DualSpinnerControl
|
|
12
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import DualSpinnerParameters
|
|
13
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import SpinnerValues
|
|
14
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import ValueChangeCallback
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class DimensionsParameters(DualSpinnerParameters):
|
|
19
|
+
minValue: int = 50
|
|
20
|
+
maxValue: int = 300
|
|
21
|
+
firstSpinnerLabel: str = 'W:'
|
|
22
|
+
secondSpinnerLabel: str = 'H:'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DimensionsControl(DualSpinnerControl):
|
|
26
|
+
"""
|
|
27
|
+
A facade around the basic dual spinner control; Essentially
|
|
28
|
+
* Converts the spinner values to and from the Dimension type;
|
|
29
|
+
* Handles the spinner callback
|
|
30
|
+
* Forwards the spinner values as Dimension values
|
|
31
|
+
"""
|
|
32
|
+
DIMENSION_MIN_VALUE: int = 50
|
|
33
|
+
DIMENSION_MAX_VALUE: int = 300
|
|
34
|
+
|
|
35
|
+
def __init__(self, parent: SizedPanel, parameters: DimensionsParameters):
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
parent: The parent window
|
|
40
|
+
parameters: Configuration parameters for the dimensions control
|
|
41
|
+
"""
|
|
42
|
+
self.logger: Logger = getLogger(__name__)
|
|
43
|
+
self._dimensionsChangedCallback: ValueChangeCallback = parameters.valueChangedCallback
|
|
44
|
+
self._dimensions: Dimensions = Dimensions()
|
|
45
|
+
|
|
46
|
+
super().__init__(parent=parent, parameters=parameters)
|
|
47
|
+
|
|
48
|
+
def _setDimensions(self, newValue: Dimensions):
|
|
49
|
+
self._dimensions = newValue
|
|
50
|
+
self.spinnerValues = SpinnerValues(value0=newValue.width, value1=newValue.height)
|
|
51
|
+
|
|
52
|
+
# noinspection PyPropertyDefinition
|
|
53
|
+
# noinspection PyTypeChecker
|
|
54
|
+
dimensions = property(fget=None, fset=_setDimensions, fdel=None, doc='Write only property to set dimensions on control')
|
|
55
|
+
|
|
56
|
+
def _notifyValueChanged(self, spinnerValues: SpinnerValues):
|
|
57
|
+
self.logger.info(f'{spinnerValues}')
|
|
58
|
+
|
|
59
|
+
self._dimensions.width = spinnerValues.value0
|
|
60
|
+
self._dimensions.height = spinnerValues.value1
|
|
61
|
+
|
|
62
|
+
if self._dimensionsChangedCallback is not None:
|
|
63
|
+
self._dimensionsChangedCallback(self._dimensions)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from logging import Logger
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Callable
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import cast
|
|
10
|
+
|
|
11
|
+
from wx import BORDER_THEME
|
|
12
|
+
from wx import ID_ANY
|
|
13
|
+
from wx import ID_OK
|
|
14
|
+
from wx import DD_DEFAULT_STYLE
|
|
15
|
+
from wx import EVT_BUTTON
|
|
16
|
+
from wx import ART_BUTTON
|
|
17
|
+
from wx import ART_FOLDER
|
|
18
|
+
|
|
19
|
+
from wx import ArtProvider
|
|
20
|
+
from wx import BitmapBundle
|
|
21
|
+
from wx import BitmapButton
|
|
22
|
+
from wx import DirDialog
|
|
23
|
+
from wx import CommandEvent
|
|
24
|
+
from wx import Size
|
|
25
|
+
from wx import TextCtrl
|
|
26
|
+
|
|
27
|
+
from wx.lib.sized_controls import SizedPanel
|
|
28
|
+
from wx.lib.sized_controls import SizedStaticBox
|
|
29
|
+
|
|
30
|
+
DEFAULT_MIN_WIDTH: int = 280
|
|
31
|
+
DEFAULT_MAX_WIDTH: int = 600
|
|
32
|
+
DEFAULT_CONTROL_HEIGHT: int = 58
|
|
33
|
+
FOLDER_BITMAP_SIZE: Size = Size(16, 16)
|
|
34
|
+
|
|
35
|
+
DirectoryPathChangedCallback = Callable[[Path], None]
|
|
36
|
+
NO_PATH_CALLBACK: DirectoryPathChangedCallback = cast(DirectoryPathChangedCallback, None)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class DirectorySelectorParameters:
|
|
41
|
+
caption: str = ''
|
|
42
|
+
pathChangedCallback: DirectoryPathChangedCallback = NO_PATH_CALLBACK
|
|
43
|
+
expand: bool = True
|
|
44
|
+
proportion: int = 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DirectorySelector(SizedStaticBox):
|
|
48
|
+
"""
|
|
49
|
+
A horizontal row container used for selecting and displaying a filesystem directory.
|
|
50
|
+
|
|
51
|
+
Combines a non-editable TextCtrl showing the current directory path with a
|
|
52
|
+
BitmapButton featuring a folder icon. Clicking the button
|
|
53
|
+
invokes a DirDialog allowing the user to browse for a directory.
|
|
54
|
+
|
|
55
|
+
Features:
|
|
56
|
+
* Responsive layout: Horizontally expands (proportion=1) to fill available
|
|
57
|
+
width in parent sizers, bounded by DEFAULT_MIN_WIDTH and
|
|
58
|
+
DEFAULT_MAX_WIDTH.
|
|
59
|
+
* Vertical alignment: Maintains a compact, single-line height
|
|
60
|
+
(DEFAULT_CONTROL_HEIGHT) with centered controls.
|
|
61
|
+
* Callback notification: Dispatches directory change events to an optional
|
|
62
|
+
callback (`pathChangedCallback`) whenever a new directory is selected.
|
|
63
|
+
* Two-way path binding: Provides a `directoryPath` property (getter/setter)
|
|
64
|
+
to read or programmatically update the selected Path.
|
|
65
|
+
"""
|
|
66
|
+
DEFAULT_MIN_WIDTH: int = DEFAULT_MIN_WIDTH
|
|
67
|
+
DEFAULT_MAX_WIDTH: int = DEFAULT_MAX_WIDTH
|
|
68
|
+
DEFAULT_CONTROL_HEIGHT: int = DEFAULT_CONTROL_HEIGHT
|
|
69
|
+
FOLDER_BITMAP_SIZE: Size = FOLDER_BITMAP_SIZE
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
parent: SizedPanel,
|
|
74
|
+
parameters: Optional[DirectorySelectorParameters] = None,
|
|
75
|
+
caption: str = '',
|
|
76
|
+
):
|
|
77
|
+
"""
|
|
78
|
+
Initialize the DirectorySelector static box and child controls.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
parent: The parent sized panel
|
|
82
|
+
parameters: Configuration parameters for the directory selector
|
|
83
|
+
caption: Optional caption string used if parameters is not provided
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
self.logger: Logger = getLogger(__name__)
|
|
87
|
+
|
|
88
|
+
params: DirectorySelectorParameters = parameters if parameters is not None else DirectorySelectorParameters(caption=caption)
|
|
89
|
+
|
|
90
|
+
super().__init__(parent, ID_ANY, params.caption, style=BORDER_THEME)
|
|
91
|
+
|
|
92
|
+
self.SetSizerType('horizontal')
|
|
93
|
+
# noinspection PyUnresolvedReferences
|
|
94
|
+
self.SetSizerProps(expand=params.expand, proportion=params.proportion)
|
|
95
|
+
|
|
96
|
+
self._directorPathChangedCallback: DirectoryPathChangedCallback = params.pathChangedCallback
|
|
97
|
+
|
|
98
|
+
textCtrl: TextCtrl = TextCtrl(self)
|
|
99
|
+
textCtrl.SetSizerProps(valign='centre', proportion=1, border=(('right',), 5))
|
|
100
|
+
|
|
101
|
+
folderBitmapBundle: BitmapBundle = ArtProvider.GetBitmapBundle(ART_FOLDER, ART_BUTTON, FOLDER_BITMAP_SIZE)
|
|
102
|
+
selectButton: BitmapButton = BitmapButton(self, ID_ANY, folderBitmapBundle)
|
|
103
|
+
selectButton.SetSizerProps(valign='centre')
|
|
104
|
+
|
|
105
|
+
textCtrl.SetValue('')
|
|
106
|
+
textCtrl.SetEditable(False)
|
|
107
|
+
|
|
108
|
+
self._textDiagramsDirectory: TextCtrl = textCtrl
|
|
109
|
+
self._directoryPath: Path = Path('')
|
|
110
|
+
|
|
111
|
+
self.Bind(EVT_BUTTON, self._onSelectDiagramsDirectory, selectButton)
|
|
112
|
+
|
|
113
|
+
self.SetMinSize(Size(DEFAULT_MIN_WIDTH, DEFAULT_CONTROL_HEIGHT))
|
|
114
|
+
self.SetMaxSize(Size(DEFAULT_MAX_WIDTH, DEFAULT_CONTROL_HEIGHT))
|
|
115
|
+
|
|
116
|
+
def DoGetBestSize(self) -> Size:
|
|
117
|
+
"""
|
|
118
|
+
Calculate the best size for this directory selector static box.
|
|
119
|
+
"""
|
|
120
|
+
return Size(400, DEFAULT_CONTROL_HEIGHT)
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def directoryPath(self) -> Path:
|
|
124
|
+
return self._directoryPath
|
|
125
|
+
|
|
126
|
+
@directoryPath.setter
|
|
127
|
+
def directoryPath(self, value: Path):
|
|
128
|
+
|
|
129
|
+
self._directoryPath = value
|
|
130
|
+
self._textDiagramsDirectory.SetValue(str(value))
|
|
131
|
+
|
|
132
|
+
# noinspection PyUnusedLocal
|
|
133
|
+
def _onSelectDiagramsDirectory(self, _event: CommandEvent):
|
|
134
|
+
|
|
135
|
+
with DirDialog(None, 'Choose the Diagrams Directory', defaultPath=str(self._directoryPath), style=DD_DEFAULT_STYLE) as dlg:
|
|
136
|
+
|
|
137
|
+
if dlg.ShowModal() == ID_OK:
|
|
138
|
+
self._directoryPath = Path(dlg.GetPath())
|
|
139
|
+
self._textDiagramsDirectory.SetValue(str(self._directoryPath))
|
|
140
|
+
if self._directorPathChangedCallback is not None:
|
|
141
|
+
self._directorPathChangedCallback(self._directoryPath)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from typing import cast
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from logging import Logger
|
|
8
|
+
from logging import getLogger
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from wx import Size
|
|
13
|
+
from wx import ID_ANY
|
|
14
|
+
from wx import EVT_TEXT
|
|
15
|
+
from wx import EVT_SPINCTRL
|
|
16
|
+
from wx import BORDER_THEME
|
|
17
|
+
|
|
18
|
+
from wx import SpinCtrl
|
|
19
|
+
from wx import StaticText
|
|
20
|
+
from wx import CommandEvent
|
|
21
|
+
|
|
22
|
+
from wx import NewIdRef as wxNewIdRef
|
|
23
|
+
|
|
24
|
+
from wx.lib.sized_controls import SizedPanel
|
|
25
|
+
from wx.lib.sized_controls import SizedStaticBox
|
|
26
|
+
|
|
27
|
+
SPINNER_WIDTH: int = 80
|
|
28
|
+
SPINNER_HEIGHT: int = -1 # In wxWidgets, passing -1 for height uses native platform control height
|
|
29
|
+
DEFAULT_CONTROL_HEIGHT: int = 58
|
|
30
|
+
|
|
31
|
+
ValueChangeCallback = Callable[[Any], None]
|
|
32
|
+
NO_VALUE_CALLBACK: ValueChangeCallback = cast(ValueChangeCallback, None)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class DualSpinnerParameters:
|
|
37
|
+
caption: str = ''
|
|
38
|
+
valueChangedCallback: ValueChangeCallback = NO_VALUE_CALLBACK
|
|
39
|
+
minValue: int = 100
|
|
40
|
+
maxValue: int = 300
|
|
41
|
+
firstSpinnerLabel: str = ''
|
|
42
|
+
secondSpinnerLabel: str = ''
|
|
43
|
+
proportion: int = 0
|
|
44
|
+
expand: bool = True
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class SpinnerValues:
|
|
49
|
+
value0: int = 0
|
|
50
|
+
value1: int = 0
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class DualSpinnerControl(SizedStaticBox):
|
|
54
|
+
"""
|
|
55
|
+
A component that pairs two spinners in a horizontal panel; Callers set
|
|
56
|
+
the title to display and optionally the minimum and maximum spinner values
|
|
57
|
+
Ideal for subclassing to use as a way to get x,y coordinates or width, height
|
|
58
|
+
sizes
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
DEFAULT_MIN_VALUE: int = 100
|
|
62
|
+
DEFAULT_MAX_VALUE: int = 300
|
|
63
|
+
|
|
64
|
+
dscLogger: Logger = getLogger(__name__) # Used as base class; So needs unique logger
|
|
65
|
+
|
|
66
|
+
def __init__(self, parent: SizedPanel, parameters: DualSpinnerParameters):
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
parent: The parent panel
|
|
71
|
+
parameters: Configuration parameters for the dual spinner control
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
super().__init__(parent, ID_ANY, parameters.caption, style=BORDER_THEME)
|
|
75
|
+
|
|
76
|
+
self.SetSizerType('horizontal')
|
|
77
|
+
# noinspection PyUnresolvedReferences
|
|
78
|
+
self.SetSizerProps(expand=parameters.expand, proportion=parameters.proportion)
|
|
79
|
+
|
|
80
|
+
self._callback: ValueChangeCallback = parameters.valueChangedCallback
|
|
81
|
+
|
|
82
|
+
self._wxSpinner0Id: int = wxNewIdRef()
|
|
83
|
+
self._wxSpinner1Id: int = wxNewIdRef()
|
|
84
|
+
|
|
85
|
+
self._firstSpinnerLabel: Optional[StaticText] = None
|
|
86
|
+
self._secondSpinnerLabel: Optional[StaticText] = None
|
|
87
|
+
|
|
88
|
+
self._spinner0: SpinCtrl = cast(SpinCtrl, None)
|
|
89
|
+
self._spinner1: SpinCtrl = cast(SpinCtrl, None)
|
|
90
|
+
|
|
91
|
+
self._createControls(parameters)
|
|
92
|
+
self._bindEventHandlers()
|
|
93
|
+
|
|
94
|
+
self.SetMinSize(Size(-1, DEFAULT_CONTROL_HEIGHT))
|
|
95
|
+
self.SetMaxSize(Size(-1, DEFAULT_CONTROL_HEIGHT))
|
|
96
|
+
|
|
97
|
+
def _createControls(self, parameters: DualSpinnerParameters):
|
|
98
|
+
"""
|
|
99
|
+
Instantiate labels, spin controls, and configure ranges and initial values
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
parameters: Configuration parameters for the dual spinner control
|
|
103
|
+
"""
|
|
104
|
+
if len(parameters.firstSpinnerLabel) > 0:
|
|
105
|
+
self._firstSpinnerLabel = StaticText(self, ID_ANY, parameters.firstSpinnerLabel)
|
|
106
|
+
self._firstSpinnerLabel.SetSizerProps(valign='centre', border=(('right',), 5))
|
|
107
|
+
|
|
108
|
+
self._spinner0 = SpinCtrl(self, self._wxSpinner0Id, '', size=Size(SPINNER_WIDTH, SPINNER_HEIGHT))
|
|
109
|
+
self._spinner0.SetSizerProps(valign='centre', border=(('right',), 10))
|
|
110
|
+
|
|
111
|
+
if len(parameters.secondSpinnerLabel) > 0:
|
|
112
|
+
self._secondSpinnerLabel = StaticText(self, ID_ANY, parameters.secondSpinnerLabel)
|
|
113
|
+
self._secondSpinnerLabel.SetSizerProps(valign='centre', border=(('right',), 5))
|
|
114
|
+
|
|
115
|
+
self._spinner1 = SpinCtrl(self, self._wxSpinner1Id, '', size=Size(SPINNER_WIDTH, SPINNER_HEIGHT))
|
|
116
|
+
self._spinner1.SetSizerProps(valign='centre')
|
|
117
|
+
|
|
118
|
+
self._spinner0.SetRange(parameters.minValue, parameters.maxValue)
|
|
119
|
+
self._spinner1.SetRange(parameters.minValue, parameters.maxValue)
|
|
120
|
+
|
|
121
|
+
self._spinnerValues: SpinnerValues = SpinnerValues(parameters.minValue, parameters.maxValue)
|
|
122
|
+
|
|
123
|
+
def _bindEventHandlers(self):
|
|
124
|
+
"""
|
|
125
|
+
Bind to both text and spin events for typing and arrow clicks
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
self.Bind(EVT_TEXT, self._onSpinnerValueChanged, self._spinner0)
|
|
129
|
+
self.Bind(EVT_TEXT, self._onSpinnerValueChanged, self._spinner1)
|
|
130
|
+
self.Bind(EVT_SPINCTRL, self._onSpinnerValueChanged, self._spinner0)
|
|
131
|
+
self.Bind(EVT_SPINCTRL, self._onSpinnerValueChanged, self._spinner1)
|
|
132
|
+
|
|
133
|
+
def DoGetBestSize(self) -> Size:
|
|
134
|
+
"""
|
|
135
|
+
Calculate the best size for this static box container, keeping
|
|
136
|
+
a compact vertical height suitable for spinner controls.
|
|
137
|
+
"""
|
|
138
|
+
sizerBest: Size = self.GetSizer().GetMinSize()
|
|
139
|
+
borders: tuple[int, int] = self.GetBordersForSizer()
|
|
140
|
+
totalWidth: int = sizerBest.width + (borders[1] * 2) + 10
|
|
141
|
+
|
|
142
|
+
return Size(totalWidth, DEFAULT_CONTROL_HEIGHT)
|
|
143
|
+
|
|
144
|
+
def _setSpinnerValues(self, spinnerValues: SpinnerValues):
|
|
145
|
+
"""
|
|
146
|
+
Write only; The appropriate way to retrieve the values is via the change callback
|
|
147
|
+
Args:
|
|
148
|
+
spinnerValues:
|
|
149
|
+
"""
|
|
150
|
+
self._spinnerValues = spinnerValues
|
|
151
|
+
self._spinner0.SetValue(spinnerValues.value0)
|
|
152
|
+
self._spinner1.SetValue(spinnerValues.value1)
|
|
153
|
+
self.dscLogger.info(f'range: {self._spinner0.GetRange()} - {self._spinner0.GetValue()=} {self._spinner1.GetValue()=}')
|
|
154
|
+
|
|
155
|
+
# noinspection PyPropertyDefinition
|
|
156
|
+
# noinspection PyTypeChecker
|
|
157
|
+
spinnerValues = property(fget=None, fset=_setSpinnerValues, fdel=None, doc='Write only property to initialize spinner values')
|
|
158
|
+
|
|
159
|
+
def enableControls(self, value: bool):
|
|
160
|
+
"""
|
|
161
|
+
Enable or disable the spinner controls
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
value: `True` to enable, else `False`
|
|
165
|
+
"""
|
|
166
|
+
if value is True:
|
|
167
|
+
self._spinner0.Enable()
|
|
168
|
+
self._spinner1.Enable()
|
|
169
|
+
if self._firstSpinnerLabel is not None:
|
|
170
|
+
self._firstSpinnerLabel.Enable()
|
|
171
|
+
if self._secondSpinnerLabel is not None:
|
|
172
|
+
self._secondSpinnerLabel.Enable()
|
|
173
|
+
else:
|
|
174
|
+
self._spinner0.Disable()
|
|
175
|
+
self._spinner1.Disable()
|
|
176
|
+
if self._firstSpinnerLabel is not None:
|
|
177
|
+
self._firstSpinnerLabel.Disable()
|
|
178
|
+
if self._secondSpinnerLabel is not None:
|
|
179
|
+
self._secondSpinnerLabel.Disable()
|
|
180
|
+
|
|
181
|
+
def _onSpinnerValueChanged(self, event: CommandEvent):
|
|
182
|
+
|
|
183
|
+
eventId: int = event.GetId()
|
|
184
|
+
|
|
185
|
+
if eventId == self._wxSpinner0Id:
|
|
186
|
+
self._spinnerValues.value0 = self._spinner0.GetValue()
|
|
187
|
+
elif eventId == self._wxSpinner1Id:
|
|
188
|
+
self._spinnerValues.value1 = self._spinner1.GetValue()
|
|
189
|
+
else:
|
|
190
|
+
self.dscLogger.error(f'Unknown spinner event id: {eventId}')
|
|
191
|
+
|
|
192
|
+
self._notifyValueChanged(self._spinnerValues)
|
|
193
|
+
|
|
194
|
+
def _notifyValueChanged(self, spinnerValues: SpinnerValues):
|
|
195
|
+
if self._callback is not None:
|
|
196
|
+
self._callback(spinnerValues)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from wx.lib.sized_controls import SizedPanel
|
|
8
|
+
|
|
9
|
+
from codeallybasic.MinMax import MinMax
|
|
10
|
+
|
|
11
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import DualSpinnerControl
|
|
12
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import DualSpinnerParameters
|
|
13
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import SpinnerValues
|
|
14
|
+
from codeallyadvanced.ui.widgets.DualSpinnerControl import ValueChangeCallback
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class MinMaxParameters(DualSpinnerParameters):
|
|
19
|
+
minValue: int = -1024
|
|
20
|
+
maxValue: int = 1024
|
|
21
|
+
firstSpinnerLabel: str = 'Min:'
|
|
22
|
+
secondSpinnerLabel: str = 'Max:'
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MinMaxControl(DualSpinnerControl):
|
|
26
|
+
"""
|
|
27
|
+
A facade around the basic dual spinner control for MinMax values.
|
|
28
|
+
"""
|
|
29
|
+
def __init__(self, parent: SizedPanel, parameters: MinMaxParameters):
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
parent: The parent window
|
|
34
|
+
parameters: Configuration parameters for the min/max control
|
|
35
|
+
"""
|
|
36
|
+
self.logger: Logger = getLogger(__name__)
|
|
37
|
+
self._valuesChangedCallback: ValueChangeCallback = parameters.valueChangedCallback
|
|
38
|
+
self._minMax: MinMax = MinMax()
|
|
39
|
+
|
|
40
|
+
super().__init__(parent=parent, parameters=parameters)
|
|
41
|
+
|
|
42
|
+
def _setMinMax(self, newValue: MinMax):
|
|
43
|
+
self._minMax = newValue
|
|
44
|
+
self.spinnerValues = SpinnerValues(value0=newValue.minValue, value1=newValue.maxValue)
|
|
45
|
+
|
|
46
|
+
# noinspection PyPropertyDefinition
|
|
47
|
+
# noinspection PyTypeChecker
|
|
48
|
+
minMax = property(fget=None, fset=_setMinMax, fdel=None, doc='Write only property to set values')
|
|
49
|
+
|
|
50
|
+
def _notifyValueChanged(self, spinnerValues: SpinnerValues):
|
|
51
|
+
|
|
52
|
+
self.logger.info(f'{spinnerValues}')
|
|
53
|
+
self._minMax.minValue = spinnerValues.value0
|
|
54
|
+
self._minMax.maxValue = spinnerValues.value1
|
|
55
|
+
|
|
56
|
+
if self._valuesChangedCallback is not None:
|
|
57
|
+
self._valuesChangedCallback(self._minMax)
|