├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── .gitignore ├── .pre-commit-config.yaml ├── AUTHORS ├── HISTORY.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── development ├── devtool.sh ├── makebuild.sh ├── req-extra.py ├── requirements.txt └── runtests.sh ├── pyproject.toml ├── run.sh ├── setup.py ├── src └── pygubu │ ├── __init__.py │ ├── __pyinstaller │ ├── __init__.py │ └── hook-pygubu.py │ ├── api │ ├── __init__.py │ └── v1 │ │ ├── __init__.py │ │ └── _private.py │ ├── binding │ ├── __init__.py │ ├── base.py │ └── bindmanager.py │ ├── builder.py │ ├── component │ ├── __init__.py │ ├── builderobject.py │ ├── plugin_engine.py │ ├── plugin_manager.py │ ├── property_registry.py │ ├── resource.py │ ├── style_manager.py │ ├── uidefinition.py │ └── widgetmeta.py │ ├── forms │ ├── __init__.py │ ├── builder.py │ ├── config.py │ ├── form.py │ ├── nouiforms.py │ ├── pygubuwidget.py │ ├── tkwidget.py │ ├── transformer │ │ ├── __init__.py │ │ └── tkboolean.py │ ├── ttkwidget.py │ ├── validation │ │ ├── __init__.py │ │ ├── base.py │ │ └── constraint │ │ │ ├── __init__.py │ │ │ ├── form.py │ │ │ ├── istrue.py │ │ │ └── notblank.py │ └── widget.py │ ├── i18n.py │ ├── plugins │ ├── __init__.py │ ├── awesometkinter │ │ ├── __init__.py │ │ ├── button.py │ │ ├── designer │ │ │ ├── __init__.py │ │ │ ├── designerplugin.py │ │ │ └── properties.py │ │ ├── frame.py │ │ ├── label.py │ │ ├── progressbar.py │ │ ├── scrollbar.py │ │ └── text.py │ ├── customtkinter │ │ ├── __init__.py │ │ ├── ctkbase.py │ │ ├── designer │ │ │ ├── __init__.py │ │ │ ├── designerplugin.py │ │ │ └── preview.py │ │ ├── scrollableframe.py │ │ ├── tabview.py │ │ ├── widgets.py │ │ └── windows.py │ ├── pygubu │ │ ├── __init__.py │ │ ├── accordionframe_bo.py │ │ ├── calendarframe_bo.py │ │ ├── colorinput_bo.py │ │ ├── combobox_bo.py │ │ ├── designer │ │ │ ├── __init__.py │ │ │ ├── basehelpers.py │ │ │ ├── designerplugin.py │ │ │ ├── properties.py │ │ │ └── toplevelframe.py │ │ ├── dialog_bo.py │ │ ├── dockfw_bo.py │ │ ├── editabletreeview_bo.py │ │ ├── filterabletreeview_bo.py │ │ ├── floodgauge_bo.py │ │ ├── fontinputbo.py │ │ ├── forms │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── pygubuwidget_bo.py │ │ │ ├── tkwidget_bo.py │ │ │ └── ttkwidget_bo.py │ │ ├── hideableframe_bo.py │ │ ├── pathchooserinput_bo.py │ │ ├── scrollbarhelper_bo.py │ │ ├── scrolledframe_bo.py │ │ ├── simpletooltip_bo.py │ │ ├── tkscrollbarhelper_bo.py │ │ └── tkscrolledframe_bo.py │ ├── tk │ │ ├── __init__.py │ │ ├── scrolledtext_bo.py │ │ └── tkstdwidgets.py │ ├── tkcalendar │ │ ├── __init__.py │ │ ├── basecalendar.py │ │ ├── calendar.py │ │ ├── dateentry.py │ │ └── designer │ │ │ ├── __init__.py │ │ │ ├── designerplugin.py │ │ │ ├── previewhelper.py │ │ │ └── properties.py │ ├── tkintermapview │ │ ├── __init__.py │ │ └── mapview.py │ ├── tkintertable │ │ ├── __init__.py │ │ └── table.py │ ├── tkinterweb │ │ ├── __init__.py │ │ ├── designer │ │ │ ├── __init__.py │ │ │ ├── designerplugin.py │ │ │ └── properties.py │ │ ├── extrawidgets.py │ │ └── htmlwidgets.py │ ├── tkmt │ │ ├── __init__.py │ │ ├── base.py │ │ ├── codegen.py │ │ ├── designer │ │ │ ├── __init__.py │ │ │ ├── designerplugin.py │ │ │ ├── preview.py │ │ │ ├── properties.py │ │ │ └── toplevelpreview.py │ │ └── widgets.py │ ├── tksheet │ │ ├── __init__.py │ │ └── sheet.py │ ├── ttk │ │ ├── __init__.py │ │ └── ttkstdwidgets.py │ └── ttkwidgets │ │ ├── __init__.py │ │ ├── autocomplete.py │ │ ├── calendar.py │ │ ├── checkboxtreeview.py │ │ ├── color.py │ │ ├── font.py │ │ ├── frames.py │ │ ├── itemscanvas.py │ │ ├── linklabel.py │ │ ├── scaleentry.py │ │ ├── scrolledlistbox.py │ │ ├── table.py │ │ ├── tickscale.py │ │ └── utils.py │ ├── stockimage │ ├── __init__.py │ ├── config.py │ ├── exceptions.py │ ├── loader.py │ └── registry.py │ ├── theming │ ├── __init__.py │ ├── base.py │ ├── bootstrap │ │ ├── __init__.py │ │ ├── assets.py │ │ ├── builder.py │ │ ├── config.py │ │ ├── style.py │ │ └── themes.py │ ├── color.py │ └── photodraw.py │ ├── utils │ ├── __init__.py │ ├── datatrans.py │ ├── font.py │ └── widget.py │ └── widgets │ ├── __init__.py │ ├── accordionframe.py │ ├── autoarrangeframe.py │ ├── calendarframe.py │ ├── colorinput.py │ ├── colorinputui.py │ ├── combobox.py │ ├── dialog.py │ ├── dockfw │ ├── __init__.py │ ├── dockframe.py │ ├── dockwidget.py │ ├── framework.py │ ├── slotframe.py │ └── widgets.py │ ├── editabletreeview.py │ ├── entrywph.py │ ├── filterabletreeview.py │ ├── floodgauge.py │ ├── fontinput.py │ ├── fontinputui.py │ ├── hideableframe.py │ ├── pathchooserinput.py │ ├── scrollbarhelper.py │ ├── scrolledframe.py │ ├── simpletooltip.py │ ├── tkscrollbarhelper.py │ ├── tkscrolledframe.py │ └── ttkspinbox.py ├── tests ├── fixpath.py ├── images │ └── example.gif ├── support.py ├── test_accordionframe.py ├── test_accordionframe.ui ├── test_autoarrangeframe.ui ├── test_builder_forget_unnamed.py ├── test_builder_forget_unnamed.ui ├── test_builderfont.py ├── test_builderfont.ui ├── test_button.py ├── test_button_command.py ├── test_button_command.ui ├── test_calendarframe.py ├── test_calendarframe.ui ├── test_canvas.py ├── test_canvas.ui ├── test_colorinput.py ├── test_colorinput.ui ├── test_command_id_arg.py ├── test_command_id_arg.ui ├── test_custom_widget.py ├── test_custom_widget.ui ├── test_custom_widget_module.py ├── test_dialog.py ├── test_dialog.ui ├── test_editabletreeview.py ├── test_editabletreeview.ui ├── test_entry.py ├── test_entry_commands.py ├── test_entry_commands.ui ├── test_filterabletreeview.py ├── test_filterabletreeview.ui ├── test_floodgauge.py ├── test_floodgauge.ui ├── test_fontinput.py ├── test_fontinput.ui ├── test_frame.py ├── test_frame.ui ├── test_hideableframe.py ├── test_hideableframe.ui ├── test_idtocommand.py ├── test_idtocommand.ui ├── test_import_variables.py ├── test_import_variables.ui ├── test_label.py ├── test_labelframe.py ├── test_labelframe.ui ├── test_menu.py ├── test_menu.ui ├── test_menu_commands.py ├── test_menu_commands.ui ├── test_notebook.py ├── test_notebook.ui ├── test_optionmenu.py ├── test_optionmenu.ui ├── test_panedwindow.py ├── test_panedwindow.ui ├── test_pathchooserinput.py ├── test_pathchooserinput.ui ├── test_plugin_tkcalendar.py ├── test_plugin_tkcalendar.ui ├── test_scrollbarhelper.py ├── test_scrolledframe.py ├── test_scrolledframe.ui ├── test_text.py ├── test_text.ui ├── test_text_issue58.py ├── test_text_issue58.ui ├── test_tkinterscrolledtext.py ├── test_tkinterscrolledtext.ui ├── test_tkscrolledframe.py ├── test_tkscrolledframe.ui ├── test_tkspinbox.py ├── test_tkspinbox.ui ├── test_toplevelmenuhelper.py ├── test_toplevelmenuhelper.ui ├── test_treeview.py ├── test_ttkcombobox.py ├── test_ttkcombobox.ui ├── test_ttkspinbox.py ├── test_ttkspinbox.ui ├── test_uidefinition_1_1.py ├── test_uidefinition_1_1.ui ├── test_uidefinition_1_2_grid.py ├── test_uidefinition_1_2_grid.ui ├── test_uidefinition_1_3.py ├── test_uidefinition_1_3.ui ├── test_uidefinition_1_4.py ├── test_uidefinition_1_4.ui ├── test_variables.py ├── test_variables.ui ├── wheeltest.ui └── wheeltest_tk.ui └── wdesings ├── colorinput.ui └── fontinput.ui /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # ko_fi: # Replace with a single Ko-fi username 5 | # liberapay: # Replace with a single Liberapay username 6 | custom: ["https://paypal.me/AlejandroA36"] 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Your Environment (please complete the following information):** 27 | - OS: [e.g. iOS, Debian 11, Windows 10] 28 | - Python version: [e.g. Python 3.10] 29 | - Pygubu version: [e.g. pygubu 0.29] 30 | - Designer version: [e.g. pygubu-designer 0.34] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions 4 | url: https://github.com/alejandroautalan/pygubu-designer/discussions 5 | about: "Ask a question in the discussion forum" 6 | - name: Documentation 7 | url: https://github.com/alejandroautalan/pygubu-designer/wiki 8 | about: "Pygubu Designer's documentation" 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Your Environment (please complete the following information):** 20 | - OS: [e.g. iOS, Debian 11, Windows 10] 21 | - Python version: [e.g. Python 3.10] 22 | 23 | **Additional context** 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *~ 3 | *.pyc 4 | output.tkb 5 | exampleui_2.tkb 6 | build/ 7 | dist/ 8 | MANIFEST 9 | TODO 10 | pygubu.nja 11 | pygubu.egg-info/ 12 | myvenv*/ 13 | venv/ 14 | pygubu-core.wpr 15 | pygubu-core.wpu 16 | *.kdev4 17 | *.mo 18 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-added-large-files 6 | - id: check-merge-conflict 7 | # exclude files where underlines are not distinguishable from merge conflicts 8 | exclude: HISTORY\.md$|\.pot?$ 9 | - id: debug-statements 10 | - id: detect-private-key 11 | - id: end-of-file-fixer 12 | 13 | - repo: https://github.com/psf/black 14 | rev: 22.3.0 15 | hooks: 16 | - id: black 17 | args: 18 | - --line-length=80 19 | 20 | - repo: https://github.com/PyCQA/flake8 21 | rev: 7.1.1 22 | hooks: 23 | - id: flake8 24 | args: 25 | - --max-line-length=80 26 | - --ignore=E203,E501,F401,W503 27 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Copyright 2012-2016 Alejandro Autalan 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2020] [Alejandro Autalán] 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 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | include HISTORY.md 4 | graft development 5 | 6 | global-exclude *~ 7 | -------------------------------------------------------------------------------- /development/devtool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | designer_dir="../pygubu-designer" 4 | 5 | project_dir_path="pygubu" 6 | [[ $dde == t ]] && . ${designer_dir}/devtool.sh 7 | 8 | install_designer(){ 9 | pip3 install -e $designer_dir 10 | } 11 | 12 | test_installation(){ 13 | pip3 install -e . 14 | pip3 install -e $designer_dir 15 | pygubu-designer 16 | } 17 | 18 | insd(){ install_designer; } 19 | ti(){ test_installation; } 20 | 21 | $* 22 | -------------------------------------------------------------------------------- /development/makebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | python3 setup.py sdist bdist_wheel 3 | twine upload dist/* 4 | -------------------------------------------------------------------------------- /development/req-extra.py: -------------------------------------------------------------------------------- 1 | import io 2 | import re 3 | from collections import defaultdict 4 | from pprint import pp 5 | 6 | extra_requirements = """ 7 | # FORMAT 8 | # Put your extra requirements here in the following format 9 | # 10 | # package[version_required]: tag1, tag2, ... 11 | 12 | ttkwidgets: ttkwidgets 13 | tksheet: tksheet 14 | tkinterweb: tkinterweb 15 | tkintertable: tkintertable 16 | tkcalendar: tkcalendar 17 | AwesomeTkinter: awesometkinter 18 | """ 19 | 20 | 21 | def get_extra_requires(add_all=True): 22 | ifile = io.StringIO(extra_requirements) 23 | with ifile as fp: 24 | extra_deps = defaultdict(set) 25 | for k in fp: 26 | if k.strip() and not k.startswith("#"): 27 | tags = set() 28 | if ":" in k: 29 | k, v = k.split(":") 30 | tags.update(vv.strip() for vv in v.split(",")) 31 | # tags.add(re.split("[<=>]", k)[0]) 32 | for t in tags: 33 | extra_deps[t].add(k) 34 | # add tag `all` at the end 35 | if add_all: 36 | extra_deps["all"] = set(vv for v in extra_deps.values() for vv in v) 37 | 38 | return extra_deps 39 | 40 | 41 | if __name__ == "__main__": 42 | requires = get_extra_requires() 43 | for key, dep in requires.items(): 44 | print(f"{key} = {list(dep)}") 45 | -------------------------------------------------------------------------------- /development/requirements.txt: -------------------------------------------------------------------------------- 1 | pre-commit 2 | -------------------------------------------------------------------------------- /development/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | python3bin=$(which python3) 3 | echo " =============" 4 | echo " Default Python 3: $python3bin " 5 | echo " version: $($python3bin --version)" 6 | echo " tk version :$($python3bin -c 'import tkinter; print(tkinter.TkVersion)')" 7 | 8 | cd tests; $python3bin -W default -m unittest -v; cd ..; 9 | 10 | #echo "" 11 | #echo "=============" 12 | #echo " Python 3.6.15 (custom build)" 13 | #echo " tk 8.6 (debian package)" 14 | # 15 | #cd tests; cpython3.6 -m unittest; cd ..; 16 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "pygubu" 7 | version="0.38" 8 | description = "A simple GUI builder for the python tkinter module" 9 | readme = "README.md" 10 | requires-python = ">=3.8" 11 | license = "MIT" 12 | keywords = ["gui", "tkinter", "designer"] 13 | authors = [ 14 | { name = "Alejandro Autalan", email = "alejandroautalan@gmail.com" }, 15 | ] 16 | classifiers = [ 17 | "Development Status :: 4 - Beta", 18 | "Programming Language :: Python", 19 | "Programming Language :: Python :: 3.8", 20 | "Programming Language :: Python :: 3.9", 21 | "Programming Language :: Python :: 3.10", 22 | "Programming Language :: Python :: 3.11", 23 | "Programming Language :: Python :: 3.12", 24 | "Programming Language :: Python :: 3.13", 25 | "Operating System :: OS Independent", 26 | "Intended Audience :: Developers", 27 | "Topic :: Software Development :: Libraries :: Python Modules", 28 | "Topic :: Utilities", 29 | "Topic :: Software Development :: User Interfaces", 30 | ] 31 | dependencies = [ 32 | "importlib_resources;python_version<'3.9'", 33 | ] 34 | 35 | [project.urls] 36 | Documentation = "https://github.com/alejandroautalan/pygubu#readme" 37 | Issues = "https://github.com/alejandroautalan/pygubu/issues" 38 | Source = "https://github.com/alejandroautalan/pygubu" 39 | 40 | [project.optional-dependencies] 41 | ttkwidgets = ['ttkwidgets'] 42 | tksheet = ['tksheet'] 43 | tkinterweb = ['tkinterweb'] 44 | tkintertable = ['tkintertable'] 45 | tkcalendar = ['tkcalendar'] 46 | awesometkinter = ['AwesomeTkinter'] 47 | customtkinter = ['customtkinter >=5.2.2', 'packaging', 'pillow'] 48 | tkintermapview = ['tkintermapview'] 49 | all = [ 50 | 'AwesomeTkinter', 51 | 'tkintertable', 52 | 'tksheet', 53 | 'ttkwidgets', 54 | 'tkinterweb', 55 | 'tkcalendar', 56 | 'customtkinter >=5.2.2', 'packaging', 'pillow', 57 | 'tkintermapview'] 58 | 59 | [project.entry-points."pyinstaller40"] 60 | hook-dirs = "pygubu.__pyinstaller:get_hook_dirs" 61 | 62 | [tool.setuptools.packages.find] 63 | where = ["src"] 64 | 65 | [tool.black] 66 | line-length = 80 67 | target-version = ["py38", "py39", "py310"] 68 | include = '\\.pyi?$' 69 | exclude = ''' 70 | /( 71 | \.git 72 | | \.hg 73 | | \.mypy_cache 74 | | \.tox 75 | | \.venv 76 | | _build 77 | | buck-out 78 | | build 79 | | dist 80 | )/ 81 | ''' 82 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # usage: ./run.sh command [argument ...] 4 | # 5 | # Commands used during development / CI. 6 | # Also, executable documentation for project dev practices. 7 | # 8 | # See https://death.andgravity.com/run-sh 9 | # for an explanation of how it works and why it's useful. 10 | 11 | 12 | # First, set up the environment. 13 | # (Check the notes at the end when changing this.) 14 | 15 | set -o nounset 16 | set -o pipefail 17 | set -o errexit 18 | 19 | # Change the current directory to the project root. 20 | PROJECT_ROOT=${0%/*} 21 | if [[ $0 != $PROJECT_ROOT && $PROJECT_ROOT != "" ]]; then 22 | cd "$PROJECT_ROOT" 23 | fi 24 | readonly PROJECT_ROOT=$( pwd ) 25 | 26 | # Store the absolute path to this script (useful for recursion). 27 | readonly SCRIPT="$PROJECT_ROOT/$( basename "$0" )" 28 | 29 | 30 | 31 | # Commands follow. 32 | 33 | # System requirements: 34 | # apt install python3-build twine 35 | # 36 | 37 | python3bin=$(which python3) 38 | 39 | function tests { 40 | cd tests; $python3bin -W default -m unittest -v; cd ..; 41 | } 42 | 43 | function build { 44 | $python3bin -m build 45 | } 46 | 47 | function upload_testpypi { 48 | build && \ 49 | twine upload --skip-existing -r test_pygubu dist/* 50 | } 51 | 52 | function upload_pypi { 53 | build && \ 54 | twine upload --skip-existing -r pygubu_project dist/* 55 | } 56 | 57 | # Commands end. Dispatch to command. 58 | 59 | "$@" 60 | 61 | 62 | # Some dev notes for this script. 63 | # 64 | # The commands *require*: 65 | # 66 | # * The current working directory is the project root. 67 | # * The shell options and globals are set as they are. 68 | # 69 | # Inspired by http://www.oilshell.org/blog/2020/02/good-parts-sketch.html 70 | # 71 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from setuptools import setup 3 | 4 | setup() 5 | -------------------------------------------------------------------------------- /src/pygubu/__init__.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | __all__ = ["Builder"] 4 | 5 | from .builder import Builder 6 | -------------------------------------------------------------------------------- /src/pygubu/__pyinstaller/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | import os 3 | 4 | 5 | def get_hook_dirs() -> List[str]: 6 | return [os.path.dirname(__file__)] 7 | -------------------------------------------------------------------------------- /src/pygubu/__pyinstaller/hook-pygubu.py: -------------------------------------------------------------------------------- 1 | hiddenimports = [ 2 | "pygubu.plugins.pygubu.accordionframe_bo", 3 | "pygubu.plugins.pygubu.calendarframe_bo", 4 | "pygubu.plugins.pygubu.colorinput_bo", 5 | "pygubu.plugins.pygubu.combobox_bo", 6 | "pygubu.plugins.pygubu.dialog_bo", 7 | "pygubu.plugins.pygubu.dockfw_bo", 8 | "pygubu.plugins.pygubu.editabletreeview_bo", 9 | "pygubu.plugins.pygubu.filterabletreeview_bo", 10 | "pygubu.plugins.pygubu.flodgauge_bo", 11 | "pygubu.plugins.pygubu.forms", 12 | "pygubu.plugins.pygubu.forms.pygubuwidget_bo", 13 | "pygubu.plugins.pygubu.forms.tkwidget_bo", 14 | "pygubu.plugins.pygubu.forms.ttkwidget_bo", 15 | "pygubu.plugins.pygubu.hideableframe_bo", 16 | "pygubu.plugins.pygubu.pathchooserinput_bo", 17 | "pygubu.plugins.pygubu.scrollbarhelper_bo", 18 | "pygubu.plugins.pygubu.scrolledframe_bo", 19 | "pygubu.plugins.pygubu.tkscrollbarhelper_bo", 20 | "pygubu.plugins.pygubu.tkscrolledframe_bo", 21 | "pygubu.plugins.tk.scrolledtext_bo", 22 | "pygubu.plugins.tk.tkstdwidgets", 23 | "pygubu.plugins.ttk.ttkstdwidgets", 24 | ] 25 | -------------------------------------------------------------------------------- /src/pygubu/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/api/__init__.py -------------------------------------------------------------------------------- /src/pygubu/api/v1/__init__.py: -------------------------------------------------------------------------------- 1 | from ...component.builderobject import BuilderObject 2 | from ...component.plugin_engine import ( 3 | IPluginBase, 4 | IBuilderLoaderPlugin, 5 | IDesignerPlugin, 6 | BuilderLoaderPlugin, 7 | ) 8 | 9 | from ._private import ( 10 | register_builder, 11 | register_widget, 12 | register_property, 13 | register_custom_property, 14 | copy_custom_property, 15 | ) 16 | -------------------------------------------------------------------------------- /src/pygubu/api/v1/_private.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ...component.builderobject import ( 3 | CLASS_MAP, 4 | WidgetDescription, 5 | ) 6 | from ...component.property_registry import PropertyRegistry 7 | 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | def register_builder( 13 | classname, builder, label=None, tags=None, group=None, public=True 14 | ): 15 | if label is None: 16 | label = classname 17 | if tags is None: 18 | tags = tuple() 19 | if group is None: 20 | group = 9 21 | 22 | CLASS_MAP[classname] = WidgetDescription( 23 | classname, builder, label, tags, group, public 24 | ) 25 | 26 | 27 | def register_widget( 28 | classname, builder, label=None, tags=None, group=None, public=True 29 | ): 30 | return register_builder(classname, builder, label, tags, group, public) 31 | 32 | 33 | def register_property(name, description): 34 | PropertyRegistry.register(name, description) 35 | 36 | 37 | def register_custom_property( 38 | builder_uid, 39 | prop_name, 40 | editor, 41 | default_value=None, 42 | help=None, 43 | **editor_params, 44 | ): 45 | """Helper function to register a custom property. 46 | All custom properties are created using internal dynamic editor. 47 | """ 48 | PropertyRegistry.register_custom( 49 | builder_uid, prop_name, editor, default_value, help, **editor_params 50 | ) 51 | 52 | 53 | def copy_custom_property(from_builder_id, pname, to_builder_id): 54 | PropertyRegistry.copy_to_builder(from_builder_id, pname, to_builder_id) 55 | -------------------------------------------------------------------------------- /src/pygubu/binding/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ["remove_binding", "ApplicationLevelBindManager"] 2 | 3 | from .base import remove_binding 4 | from .bindmanager import ApplicationLevelBindManager 5 | -------------------------------------------------------------------------------- /src/pygubu/binding/base.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import logging 3 | import tkinter as tk 4 | 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def bindings(widget, seq): 10 | return [x for x in widget.bind(seq).splitlines() if x.strip()] 11 | 12 | 13 | def _funcid(binding): 14 | return binding.split()[1][3:] 15 | 16 | 17 | def remove_binding(widget, seq, index=None, funcid=None): 18 | b = bindings(widget, seq) 19 | 20 | if index is not None: 21 | try: 22 | binding = b[index] 23 | widget.unbind(seq, _funcid(binding)) 24 | b.remove(binding) 25 | except IndexError: 26 | logger.info("Binding #%d not defined.", index) 27 | return 28 | 29 | elif funcid: 30 | binding = None 31 | for x in b: 32 | if _funcid(x) == funcid: 33 | binding = x 34 | b.remove(binding) 35 | widget.unbind(seq, funcid) 36 | break 37 | if not binding: 38 | logger.info('Binding "%s" not defined.', funcid) 39 | return 40 | else: 41 | raise ValueError("No index or function id defined.") 42 | 43 | for x in b: 44 | widget.bind(seq, "+" + x, 1) 45 | -------------------------------------------------------------------------------- /src/pygubu/component/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/component/__init__.py -------------------------------------------------------------------------------- /src/pygubu/component/plugin_engine.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, ABCMeta, abstractmethod 2 | from typing import Optional 3 | 4 | 5 | class PluginRegistry(ABCMeta): 6 | plugins = [] 7 | 8 | def __init__(cls, name, bases, attrs): 9 | if name not in ( 10 | "IPluginBase", 11 | "BuilderLoaderPlugin", 12 | ): 13 | PluginRegistry.plugins.append(cls) 14 | 15 | 16 | class IDesignerPlugin(ABC): 17 | def get_preview_builder(self, builder_uid: str): 18 | """Return a BuilderObject subclass used to build a preview 19 | for the target builder_uid""" 20 | return None 21 | 22 | def get_toplevel_preview_for( 23 | self, builder_uid: str, widget_id: str, builder, top_master 24 | ): 25 | """Return a Toplevel with the target widget_id rendered inside.""" 26 | return None 27 | 28 | def configure_for_preview(self, builder_uid: str, widget): 29 | """Make widget just display with minimal functionality.""" 30 | return None 31 | 32 | def ensure_visibility_in_preview(self, builder, selected_uid: str): 33 | """Ensure visibility of selected_uid in preview. 34 | Usage example: 35 | Activate a tab of a Notebook if the selected widget is 36 | inside the notebook. 37 | """ 38 | return None 39 | 40 | 41 | class IPluginBase(ABC, metaclass=PluginRegistry): 42 | @abstractmethod 43 | def do_activate(self) -> bool: 44 | "Initialize plugin and return if it is operational or not." 45 | ... 46 | 47 | def get_designer_plugin(self) -> Optional[IDesignerPlugin]: 48 | """Return class instance that implements IDesignerPlugin""" 49 | return None 50 | 51 | 52 | class IBuilderLoaderPlugin(ABC): 53 | @abstractmethod 54 | def get_module_for(self, identifier: str) -> str: 55 | "Return module name for specified identifier." 56 | ... 57 | 58 | @abstractmethod 59 | def get_all_modules(self): 60 | "Return an iterable with module names of all builders." 61 | ... 62 | 63 | @abstractmethod 64 | def can_load(self, identifier: str) -> bool: 65 | "Return if this loader can manage specified identifier." 66 | ... 67 | 68 | 69 | class BuilderLoaderPlugin(IBuilderLoaderPlugin, IPluginBase): 70 | pass 71 | -------------------------------------------------------------------------------- /src/pygubu/forms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/forms/__init__.py -------------------------------------------------------------------------------- /src/pygubu/forms/builder.py: -------------------------------------------------------------------------------- 1 | from .form import Form, FormField 2 | 3 | 4 | class FormBuilder: 5 | def __init__(self, *args, field_name: str, **kw): 6 | super().__init__(*args, **kw) 7 | self.field_name = field_name 8 | self.fields_scanned = False 9 | self.widgets = {} 10 | self.widgets_info = {} 11 | self.form_info = {} 12 | 13 | def iter_widgets(self, force_scan=False): 14 | if self.fields_scanned is False or force_scan: 15 | self.scan_widgets() 16 | for name, widget in self.widgets.items(): 17 | yield name, widget 18 | self.fields_scanned = True 19 | 20 | def scan_widgets(self): 21 | pass 22 | 23 | def get_form(self, config: dict): 24 | form = Form() 25 | for name, widget in self.iter_widgets(): 26 | params = {} 27 | if name in config: 28 | params = config[name] 29 | field = FormField(widget, **params) 30 | form.add(name, field) 31 | for name, info in self.widgets_info.items(): 32 | form.add_info_display(name, info) 33 | trans_key = "translator" 34 | if trans_key in config: 35 | form.translator = config[trans_key] 36 | return form 37 | -------------------------------------------------------------------------------- /src/pygubu/forms/config.py: -------------------------------------------------------------------------------- 1 | ENTRY_MARK_INVALID_USING_VALIDATE = False 2 | -------------------------------------------------------------------------------- /src/pygubu/forms/nouiforms.py: -------------------------------------------------------------------------------- 1 | """No UI forms""" 2 | 3 | from .forms import FormBase 4 | from .widgets import FieldWidget 5 | from .fields import ( 6 | CharField as CharFieldBase, 7 | IntegerField as IntegerFieldBase, 8 | ChoiceField as ChoiceFieldBase, 9 | ) 10 | 11 | 12 | class Form(FormBase): 13 | pass 14 | 15 | 16 | class NoUIWidget(FieldWidget): 17 | def __init__(self, *args, **kw): 18 | self._value = None 19 | super().__init__(*args, **kw) 20 | 21 | def wset_value(self, value): 22 | self._value = value 23 | 24 | def wget_value(self): 25 | return self._value 26 | 27 | def wmark_invalid(self, state: bool): 28 | print(f"Field {self._field.fname} invalid: {state}") 29 | 30 | def wis_disabled(self) -> bool: 31 | return False 32 | 33 | 34 | class CharField(CharFieldBase, NoUIWidget): 35 | pass 36 | 37 | 38 | class IntegerField(IntegerFieldBase, NoUIWidget): 39 | pass 40 | 41 | 42 | # class NoUIChoiceWidget(NoUIWidget, ChoiceWidget): 43 | # pass 44 | 45 | 46 | # class ChoiceField(ChoiceFieldBase, NoUIChoiceWidget): 47 | # pass 48 | -------------------------------------------------------------------------------- /src/pygubu/forms/pygubuwidget.py: -------------------------------------------------------------------------------- 1 | from pygubu.widgets.combobox import Combobox 2 | from pygubu.widgets.fontinput import FontInput 3 | 4 | from .ttkwidget import TtkVarBasedWidget 5 | 6 | 7 | class PygubuCombobox(TtkVarBasedWidget, Combobox): 8 | tkvar_pname = "keyvariable" 9 | 10 | 11 | class FontInputFW(TtkVarBasedWidget, FontInput): 12 | """A FontInput form field widget.""" 13 | 14 | tkvar_pname = "variable" 15 | -------------------------------------------------------------------------------- /src/pygubu/forms/transformer/__init__.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | """ 5 | Model transformers: 6 | 7 | transform(): "model data" => "norm data" 8 | reverseTransform(): "norm data" => "model data" 9 | 10 | View transformers: 11 | 12 | transform(): "norm data" => "view data" 13 | reverseTransform(): "view data" => "norm data 14 | 15 | 16 | Model data <| 17 | | | 18 | | transform | reverse transform 19 | | | 20 | |> | 21 | Norm data 22 | | <| 23 | | transform | 24 | |> | reverse transform 25 | View data | 26 | """ 27 | 28 | 29 | class DataTransformer(ABC): 30 | @abstractmethod 31 | def transform(self, value): 32 | ... 33 | 34 | @abstractmethod 35 | def reversetransform(self, value): 36 | ... 37 | 38 | 39 | class NoopTransfomer(DataTransformer): 40 | def transform(self, value): 41 | return value 42 | 43 | def reversetransform(self, value): 44 | return value 45 | 46 | 47 | class TransformationError(Exception): 48 | ... 49 | -------------------------------------------------------------------------------- /src/pygubu/forms/transformer/tkboolean.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from . import DataTransformer 3 | 4 | 5 | class BoolTransformer(DataTransformer): 6 | def transform(self, value): 7 | tval = False 8 | try: 9 | tval = tk.getboolean(value) 10 | except (ValueError, tk.TclError): 11 | pass 12 | return tval 13 | 14 | def reversetransform(self, value): 15 | return self.transform(value) 16 | -------------------------------------------------------------------------------- /src/pygubu/forms/validation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/forms/validation/__init__.py -------------------------------------------------------------------------------- /src/pygubu/forms/validation/constraint/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/forms/validation/constraint/__init__.py -------------------------------------------------------------------------------- /src/pygubu/forms/validation/constraint/form.py: -------------------------------------------------------------------------------- 1 | from ..base import Constraint, ConstraintValidator 2 | from .notblank import NotBlank 3 | from pygubu.i18n import _ 4 | 5 | 6 | class Required(NotBlank): 7 | code = "required" 8 | message = _("This value is required.") 9 | 10 | 11 | class Form(Constraint): 12 | def get_targets(self): 13 | return self.CLASS_CONSTRAINT 14 | 15 | def validated_by(self): 16 | return FormValidator 17 | 18 | 19 | class FormValidator(ConstraintValidator): 20 | def validate(self, form, constraint): 21 | for name, field in form.fields.items(): 22 | field_constraints = [] 23 | if field.required: 24 | field_constraints.append(Required()) 25 | field_constraints.extend(field.constraints) 26 | for fc in field_constraints: 27 | validator_class = fc.validated_by() 28 | validator = validator_class() 29 | validator.initialize(self.context) 30 | validator.validate(field.data, fc) 31 | violations = self.context.violations 32 | if violations: 33 | form.add_error(name, violations) 34 | self.context.clear() 35 | -------------------------------------------------------------------------------- /src/pygubu/forms/validation/constraint/istrue.py: -------------------------------------------------------------------------------- 1 | from ..base import Constraint, ConstraintValidator 2 | 3 | 4 | class IsTrue(Constraint): 5 | code = "not_true_error" 6 | message = "This value should be true." 7 | true_values = (True, "1", 1) 8 | 9 | def __init__( 10 | self, *args, message=None, allow_none=False, true_values=None, **kw 11 | ): 12 | super().__init__(*args, **kw) 13 | if message is not None: 14 | self.message = message 15 | if true_values is not None: 16 | self.true_values = true_values 17 | self.allow_none = allow_none 18 | 19 | def validated_by(self): 20 | return IsTrueValidator 21 | 22 | 23 | class IsTrueValidator(ConstraintValidator): 24 | def validate(self, value, constraint): 25 | if constraint.allow_none and value is None: 26 | return 27 | if value not in constraint.true_values: 28 | self.context.add_violation( 29 | message=constraint.message, 30 | constraint=constraint, 31 | code=constraint.code, 32 | params=None, 33 | ) 34 | -------------------------------------------------------------------------------- /src/pygubu/forms/validation/constraint/notblank.py: -------------------------------------------------------------------------------- 1 | from ..base import Constraint, ConstraintValidator 2 | 3 | 4 | class NotBlank(Constraint): 5 | code = "is_blank_error" 6 | message = "This value should not be blank." 7 | empty_values = (None, "", [], (), {}) 8 | 9 | def __init__( 10 | self, *args, message=None, allow_none=False, empty_values=None, **kw 11 | ): 12 | super().__init__(*args, **kw) 13 | if message is not None: 14 | self.message = message 15 | if empty_values is not None: 16 | self.empty_values = empty_values 17 | self.allow_none = allow_none 18 | 19 | def validated_by(self): 20 | return NotBlankValidator 21 | 22 | 23 | class NotBlankValidator(ConstraintValidator): 24 | def validate(self, value, constraint): 25 | if constraint.allow_none and value is None: 26 | return 27 | if value in constraint.empty_values: 28 | self.context.add_violation( 29 | message=constraint.message, 30 | constraint=constraint, 31 | code=constraint.code, 32 | params=None, 33 | ) 34 | -------------------------------------------------------------------------------- /src/pygubu/forms/widget.py: -------------------------------------------------------------------------------- 1 | class FieldWidget: 2 | def __init__(self, *args, field_name: str, **kw): 3 | super().__init__(*args, **kw) 4 | self.field_name = field_name 5 | 6 | def wset_value(self, value): 7 | # will set the value in the widget format 8 | raise NotImplementedError( 9 | f"Subclasses must define this method. {self.__class__}" 10 | f" for field class {self.__class__}" 11 | ) 12 | 13 | def wget_value(self): 14 | # Get value in the widget 15 | raise NotImplementedError( 16 | f"Subclasses must define this method. {self.__class__}" 17 | f" for field class {self.__class__}" 18 | ) 19 | 20 | def wmark_invalid(self, state: bool): 21 | # Visually mark the widget as invalid depending on state parameter. 22 | raise NotImplementedError( 23 | f"Subclasses must define this method. {self.__class__}" 24 | f" for field class {self.__class__}" 25 | ) 26 | 27 | def wis_disabled(self) -> bool: 28 | raise NotImplementedError( 29 | f"Subclasses must define this method. {self.__class__}" 30 | f" for field class {self.__class__}" 31 | ) 32 | 33 | 34 | class WidgetInfoBase: 35 | def __init__(self, *args, field_name: str, **kw): 36 | self.field_name = field_name 37 | super().__init__(*args, **kw) 38 | 39 | def show_error(self, error): 40 | raise NotImplementedError 41 | 42 | def show_help(self, message): 43 | raise NotImplementedError 44 | 45 | def clear(self): 46 | raise NotImplementedError 47 | 48 | 49 | class WidgetInfo(WidgetInfoBase): 50 | pass 51 | 52 | 53 | class FormInfo(WidgetInfoBase): 54 | pass 55 | -------------------------------------------------------------------------------- /src/pygubu/i18n.py: -------------------------------------------------------------------------------- 1 | """ 2 | Keep pygubu as a simple library. Translations will be done in pygubu-designer repo. 3 | 4 | Here _ is used to mark strings in plugins files as translatable. 5 | 6 | Do not use this file in your application projects. 7 | """ 8 | 9 | import os 10 | 11 | 12 | def _real_translator(msg): 13 | return msg 14 | 15 | 16 | _ = _real_translator 17 | 18 | 19 | class LazyTranslator: 20 | def __init__(self, message): 21 | self._message = message 22 | 23 | def __str__(self): 24 | return _real_translator(self._message) 25 | 26 | def __repr__(self): 27 | return f"LazyTranslator('{self._message}')" 28 | 29 | 30 | def setup_translator(translator): 31 | global _real_translator 32 | _real_translator = translator 33 | 34 | 35 | def translator(message: str) -> str: 36 | return LazyTranslator(message) 37 | 38 | 39 | def noop_translator(message: str) -> str: 40 | return message 41 | 42 | 43 | if "PYGUBU_LAZY_TRANSLATOR" in os.environ: 44 | # Environment variable is set in pygubu-designer to activate string translations. 45 | _ = T = translator 46 | -------------------------------------------------------------------------------- /src/pygubu/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import BuilderLoaderPlugin 4 | 5 | _designer_tab_label = _("AwesomeTkinter") 6 | _plugin_uid = "awesometkinter" 7 | _designer_tabs = ("ttk", _designer_tab_label) 8 | 9 | 10 | class AwesometkinterLoader(BuilderLoaderPlugin): 11 | module_map = { 12 | "pygubu.plugins.awesometkinter.frame": ( 13 | f"{_plugin_uid}.Frame3d", 14 | f"{_plugin_uid}.ScrollableFrame", 15 | ), 16 | "pygubu.plugins.awesometkinter.button": ( 17 | f"{_plugin_uid}.Button3d", 18 | f"{_plugin_uid}.Radiobutton", 19 | f"{_plugin_uid}.Checkbutton", 20 | ), 21 | "pygubu.plugins.awesometkinter.label": ( 22 | f"{_plugin_uid}.AutoWrappingLabel", 23 | f"{_plugin_uid}.AutofitLabel", 24 | ), 25 | "pygubu.plugins.awesometkinter.progressbar": ( 26 | f"{_plugin_uid}.RadialProgressbar", 27 | f"{_plugin_uid}.RadialProgressbar3d", 28 | f"{_plugin_uid}.Segmentbar", 29 | ), 30 | "pygubu.plugins.awesometkinter.scrollbar": ( 31 | f"{_plugin_uid}.SimpleScrollbar", 32 | ), 33 | "pygubu.plugins.awesometkinter.text": (f"{_plugin_uid}.ScrolledText",), 34 | } 35 | 36 | def do_activate(self) -> bool: 37 | spec = importlib.util.find_spec("awesometkinter") 38 | return spec is not None 39 | 40 | def get_module_for(self, identifier: str) -> str: 41 | for module, identifiers in self.module_map.items(): 42 | if identifier in identifiers: 43 | return module 44 | return None 45 | 46 | def get_all_modules(self): 47 | return [m for m in self.module_map.keys()] 48 | 49 | def can_load(self, identifier: str) -> bool: 50 | return identifier.startswith("awesometkinter.") 51 | 52 | def get_designer_plugin(self): 53 | """Load class that implements IDesignerPlugin""" 54 | 55 | # Just load the module for properties definitions. 56 | from .designer.designerplugin import AwesometkinterPlugin 57 | 58 | return None 59 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/button.py: -------------------------------------------------------------------------------- 1 | import awesometkinter as atk 2 | from pygubu.api.v1 import register_widget 3 | from pygubu.plugins.tk.tkstdwidgets import TKCheckbutton 4 | from pygubu.plugins.ttk.ttkstdwidgets import TTKButton, TTKRadiobutton 5 | from ..awesometkinter import _plugin_uid, _designer_tabs 6 | 7 | 8 | class Button3dBO(TTKButton): 9 | OPTIONS_STANDARD = tuple(set(TTKButton.OPTIONS_STANDARD) - set(("style",))) 10 | OPTIONS_CUSTOM = ("bg", "fg") 11 | properties = OPTIONS_STANDARD + TTKButton.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 12 | ro_properties = TTKButton.ro_properties + ("bg", "fg") 13 | class_ = atk.Button3d 14 | 15 | 16 | _builder_uid = f"{_plugin_uid}.Button3d" 17 | register_widget(_builder_uid, Button3dBO, "Button3d", _designer_tabs, group=2) 18 | 19 | 20 | class RadiobuttonBO(TTKRadiobutton): 21 | OPTIONS_STANDARD = tuple( 22 | set(TTKRadiobutton.OPTIONS_STANDARD) - set(("style",)) 23 | ) 24 | OPTIONS_CUSTOM = ( 25 | "bg", 26 | "fg", 27 | "ind_bg", 28 | "ind_mark_color", 29 | "ind_outline_color", 30 | "font", 31 | ) 32 | properties = ( 33 | OPTIONS_STANDARD + TTKRadiobutton.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 34 | ) 35 | ro_properties = ( 36 | TTKRadiobutton.ro_properties + OPTIONS_CUSTOM + ("text", "value") 37 | ) 38 | class_ = atk.Radiobutton 39 | 40 | 41 | _builder_uid = f"{_plugin_uid}.Radiobutton" 42 | register_widget( 43 | _builder_uid, 44 | RadiobuttonBO, 45 | "Radiobutton", 46 | _designer_tabs, 47 | group=2, 48 | ) 49 | 50 | 51 | class CheckbuttonBO(TKCheckbutton): 52 | OPTIONS_CUSTOM = ( 53 | "box_color", 54 | "check_mark_color", 55 | "text_color", 56 | ) 57 | properties = ( 58 | TKCheckbutton.OPTIONS_STANDARD 59 | + TKCheckbutton.OPTIONS_SPECIFIC 60 | + OPTIONS_CUSTOM 61 | ) 62 | ro_properties = TKCheckbutton.ro_properties + OPTIONS_CUSTOM 63 | class_ = atk.Checkbutton 64 | 65 | 66 | _builder_uid = f"{_plugin_uid}.Checkbutton" 67 | register_widget( 68 | _builder_uid, 69 | CheckbuttonBO, 70 | "Checkbutton", 71 | _designer_tabs, 72 | group=2, 73 | ) 74 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/awesometkinter/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/designer/designerplugin.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import IPluginBase, IDesignerPlugin 2 | import pygubu.plugins.awesometkinter.designer.properties 3 | 4 | 5 | class AwesometkinterPlugin(IDesignerPlugin): 6 | ... 7 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/frame.py: -------------------------------------------------------------------------------- 1 | """ 2 | Documentation, License etc. 3 | 4 | @package pygubu.plugins.awesometkinter 5 | """ 6 | import tkinter as tk 7 | from pygubu.i18n import _ 8 | from pygubu.api.v1 import register_widget, register_custom_property 9 | from pygubu.plugins.tk.tkstdwidgets import TKFrame 10 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 11 | import awesometkinter as atk 12 | 13 | from ..awesometkinter import _plugin_uid, _designer_tabs 14 | 15 | 16 | class Frame3dBO(TTKFrame): 17 | OPTIONS_STANDARD = tuple(set(TTKFrame.OPTIONS_STANDARD) - set(("style",))) 18 | OPTIONS_CUSTOM = ("bg",) 19 | properties = OPTIONS_STANDARD + TTKFrame.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 20 | ro_properties = TTKFrame.ro_properties + ("bg",) 21 | class_ = atk.Frame3d 22 | 23 | 24 | _builder_uid = f"{_plugin_uid}.Frame3d" 25 | register_widget(_builder_uid, Frame3dBO, "Frame3d", _designer_tabs, group=0) 26 | 27 | 28 | class ScrollableFrameBO(TKFrame): 29 | OPTIONS_STANDARD = tuple() 30 | OPTIONS_SPECIFIC = tuple() 31 | OPTIONS_CUSTOM = ( 32 | "vscroll", 33 | "hscroll", 34 | "autoscroll", 35 | "bg", 36 | "sbar_fg", 37 | "sbar_bg", 38 | "vbar_width", 39 | "hbar_width", 40 | ) 41 | ro_properties = OPTIONS_CUSTOM 42 | class_ = atk.ScrollableFrame 43 | 44 | def _process_property_value(self, pname, value): 45 | if pname in ("vscroll", "hscroll", "autoscroll"): 46 | return tk.getboolean(value) 47 | return super()._process_property_value(pname, value) 48 | 49 | def _code_process_property_value(self, targetid, pname, value): 50 | if pname in ("vscroll", "hscroll", "autoscroll"): 51 | return tk.getboolean(value) 52 | return super()._code_process_property_value(targetid, pname, value) 53 | 54 | 55 | _builder_uid = f"{_plugin_uid}.ScrollableFrame" 56 | register_widget( 57 | _builder_uid, 58 | ScrollableFrameBO, 59 | "ScrollableFrame", 60 | _designer_tabs, 61 | group=0, 62 | ) 63 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/label.py: -------------------------------------------------------------------------------- 1 | import awesometkinter as atk 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import register_widget 4 | from pygubu.plugins.tk.tkstdwidgets import TKLabel 5 | from ..awesometkinter import _plugin_uid, _designer_tabs 6 | 7 | 8 | class AutoWrappingLabelBO(TKLabel): 9 | class_ = atk.label.AutoWrappingLabel 10 | 11 | 12 | _builder_uid = f"{_plugin_uid}.AutoWrappingLabel" 13 | register_widget( 14 | _builder_uid, 15 | AutoWrappingLabelBO, 16 | "AutoWrappingLabel", 17 | _designer_tabs, 18 | group=1, 19 | ) 20 | 21 | 22 | class AutofitLabelBO(TKLabel): 23 | OPTIONS_CUSTOM = ("refresh_time",) 24 | properties = ( 25 | TKLabel.OPTIONS_STANDARD + TKLabel.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 26 | ) 27 | ro_properties = TKLabel.ro_properties + OPTIONS_CUSTOM 28 | class_ = atk.label.AutofitLabel 29 | 30 | 31 | _builder_uid = f"{_plugin_uid}.AutofitLabel" 32 | register_widget( 33 | _builder_uid, 34 | AutofitLabelBO, 35 | "AutofitLabel", 36 | _designer_tabs, 37 | group=1, 38 | ) 39 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/progressbar.py: -------------------------------------------------------------------------------- 1 | import awesometkinter as atk 2 | from pygubu.api.v1 import ( 3 | BuilderObject, 4 | register_widget, 5 | ) 6 | 7 | from ..awesometkinter import _plugin_uid, _designer_tabs 8 | 9 | 10 | class RadialProgressbarBO(BuilderObject): 11 | OPTIONS_CUSTOM = ( 12 | "bg", 13 | "fg", 14 | "text_fg", 15 | "font", 16 | "font_size_ratio", 17 | "base_img", 18 | "indicator_img", 19 | "parent_bg", 20 | ) 21 | ro_properties = OPTIONS_CUSTOM 22 | class_ = atk.RadialProgressbar 23 | 24 | def _process_property_value(self, pname, value): 25 | if pname == "font_size_ratio": 26 | value_ = 0.1 27 | try: 28 | value_ = float(value) 29 | except ValueError: 30 | pass 31 | return value_ 32 | return super()._process_property_value(pname, value) 33 | 34 | 35 | _builder_uid = f"{_plugin_uid}.RadialProgressbar" 36 | register_widget( 37 | _builder_uid, 38 | RadialProgressbarBO, 39 | "RadialProgressbar", 40 | _designer_tabs, 41 | ) 42 | 43 | 44 | class RadialProgressbar3dBO(BuilderObject): 45 | OPTIONS_CUSTOM = ("fg", "text_fg", "text_bg") 46 | ro_properties = OPTIONS_CUSTOM 47 | class_ = atk.RadialProgressbar3d 48 | 49 | 50 | _builder_uid = f"{_plugin_uid}.RadialProgressbar3d" 51 | register_widget( 52 | _builder_uid, 53 | RadialProgressbar3dBO, 54 | "RadialProgressbar3d", 55 | _designer_tabs, 56 | ) 57 | 58 | 59 | class SegmentbarBO(BuilderObject): 60 | OPTIONS_CUSTOM = ("bg", "fg", "width", "height") 61 | ro_properties = OPTIONS_CUSTOM 62 | class_ = atk.Segmentbar 63 | 64 | def _process_property_value(self, pname, value): 65 | if pname in ("width",): 66 | return int(value) 67 | return super()._process_property_value(pname, value) 68 | 69 | 70 | _builder_uid = f"{_plugin_uid}.Segmentbar" 71 | register_widget(_builder_uid, SegmentbarBO, "Segmentbar", _designer_tabs) 72 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/scrollbar.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import register_widget 2 | from pygubu.plugins.ttk.ttkstdwidgets import TTKScrollbar 3 | import awesometkinter as atk 4 | 5 | from ..awesometkinter import _plugin_uid, _designer_tabs 6 | 7 | 8 | class SimpleScrollbarBO(TTKScrollbar): 9 | OPTIONS_STANDARD = tuple( 10 | set(TTKScrollbar.OPTIONS_STANDARD) - set(("style",)) 11 | ) 12 | OPTIONS_CUSTOM = ("bg", "slider_color", "width") 13 | properties = ( 14 | OPTIONS_STANDARD + TTKScrollbar.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 15 | ) 16 | ro_properties = TTKScrollbar.ro_properties + OPTIONS_CUSTOM + ("orient",) 17 | class_ = atk.scrollbar.SimpleScrollbar 18 | 19 | def _process_property_value(self, pname, value): 20 | if pname in ("width",): 21 | value_ = 5 22 | try: 23 | value_ = int(value) 24 | except ValueError: 25 | pass 26 | return value_ 27 | return super()._process_property_value(pname, value) 28 | 29 | 30 | _builder_uid = f"{_plugin_uid}.SimpleScrollbar" 31 | register_widget( 32 | _builder_uid, 33 | SimpleScrollbarBO, 34 | "SimpleScrollbar", 35 | _designer_tabs, 36 | ) 37 | -------------------------------------------------------------------------------- /src/pygubu/plugins/awesometkinter/text.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import register_widget, register_custom_property 4 | from pygubu.plugins.tk.tkstdwidgets import TKText 5 | import awesometkinter as atk 6 | 7 | from ..awesometkinter import _plugin_uid, _designer_tabs 8 | 9 | 10 | class ScrolledTextBO(TKText): 11 | OPTIONS_CUSTOM = TKText.OPTIONS_CUSTOM + ( 12 | "bg", 13 | "fg", 14 | "bd", 15 | "vscroll", 16 | "hscroll", 17 | "autoscroll", 18 | "max_chars", 19 | "sbar_fg", 20 | "sbar_bg", 21 | "vbar_width", 22 | "hbar_width", 23 | ) 24 | properties = ( 25 | TKText.OPTIONS_STANDARD + TKText.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 26 | ) 27 | ro_properties = tuple( 28 | (set(TKText.ro_properties) | set(OPTIONS_CUSTOM) | set(("wrap",))) 29 | - set(("text",)) 30 | ) 31 | class_ = atk.text.ScrolledText 32 | 33 | def _process_property_value(self, pname, value): 34 | if pname in ("vscroll", "hscroll", "autoscroll"): 35 | return tk.getboolean(value) 36 | if pname in ("max_chars", "vbar_width", "hbar_width"): 37 | return int(value) 38 | return super()._process_property_value(pname, value) 39 | 40 | def _code_process_property_value(self, targetid, pname, value): 41 | if pname in ("vscroll", "hscroll", "autoscroll"): 42 | return tk.getboolean(value) 43 | return super()._code_process_property_value(targetid, pname, value) 44 | 45 | 46 | _builder_uid = f"{_plugin_uid}.ScrolledText" 47 | register_widget( 48 | _builder_uid, 49 | ScrolledTextBO, 50 | "ScrolledText", 51 | _designer_tabs, 52 | group=1, 53 | ) 54 | -------------------------------------------------------------------------------- /src/pygubu/plugins/customtkinter/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import IPluginBase, IBuilderLoaderPlugin, IDesignerPlugin 4 | 5 | 6 | _designer_tab_label = _("CustomTkinter") 7 | _plugin_uid = "customtkinter" 8 | 9 | 10 | class CTkBuilderLoader(IBuilderLoaderPlugin, IPluginBase): 11 | module_map = { 12 | "pygubu.plugins.customtkinter.windows": ( 13 | f"{_plugin_uid}.CTkToplevel", 14 | f"{_plugin_uid}.CTk", 15 | ), 16 | "pygubu.plugins.customtkinter.widgets": ( 17 | f"{_plugin_uid}.CTkFrame", 18 | f"{_plugin_uid}.CTkLabel", 19 | f"{_plugin_uid}.CTkProgressBar", 20 | f"{_plugin_uid}.CTkButton", 21 | f"{_plugin_uid}.CTkSlider", 22 | f"{_plugin_uid}.CTkEntry", 23 | f"{_plugin_uid}.CTkOptionMenu", 24 | f"{_plugin_uid}.CTkComboBox", 25 | f"{_plugin_uid}.CTkCheckBox", 26 | f"{_plugin_uid}.CTkRadioButton", 27 | f"{_plugin_uid}.CTkSwitch", 28 | f"{_plugin_uid}.CTkTextbox", 29 | f"{_plugin_uid}.CTkCanvas", 30 | f"{_plugin_uid}.CTkScrollbar", 31 | f"{_plugin_uid}.CTkTabview", 32 | f"{_plugin_uid}.CTkScrollableFrame", 33 | ), 34 | } 35 | 36 | def do_activate(self) -> bool: 37 | spec = importlib.util.find_spec("customtkinter") 38 | return spec is not None 39 | 40 | def get_module_for(self, identifier: str) -> str: 41 | for module, identifiers in self.module_map.items(): 42 | if identifier in identifiers: 43 | return module 44 | return None 45 | 46 | def get_all_modules(self): 47 | return [m for m in self.module_map.keys()] 48 | 49 | def can_load(self, identifier: str) -> bool: 50 | return identifier.startswith("customtkinter.") 51 | 52 | def get_designer_plugin(self): 53 | """Load class that implements IDesignerPlugin""" 54 | from .designer.designerplugin import CTkDesignerPlugin 55 | 56 | return CTkDesignerPlugin() 57 | -------------------------------------------------------------------------------- /src/pygubu/plugins/customtkinter/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/customtkinter/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/customtkinter/scrollableframe.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import ( 2 | BuilderObject, 3 | register_widget, 4 | register_custom_property, 5 | ) 6 | from pygubu.i18n import _ 7 | from ..customtkinter import _designer_tab_label, _plugin_uid 8 | from .ctkbase import CTkBaseMixin, GCONTAINER 9 | 10 | from customtkinter import CTkScrollableFrame 11 | 12 | 13 | class CTkScrollableFrameBO(CTkBaseMixin, BuilderObject): 14 | class_ = CTkScrollableFrame 15 | container = True 16 | # CTkScrollableFrame does some weird things 17 | # with layout so I disable container layout here on purpose. 18 | container_layout = False 19 | properties = ( 20 | "width", 21 | "height", 22 | "corner_radius", 23 | "border_width", 24 | "bg_color", 25 | "fg_color", 26 | "border_color", 27 | "scrollbar_fg_color", 28 | "scrollbar_button_color", 29 | "scrollbar_button_hover_color:", 30 | "label_fg_color", 31 | "label_text_color", 32 | "label_text", 33 | "label_font", 34 | "label_anchor", 35 | "orientation", 36 | ) 37 | ro_properties = ("orientation",) 38 | 39 | 40 | _builder_uid = f"{_plugin_uid}.CTkScrollableFrame" 41 | register_widget( 42 | _builder_uid, 43 | CTkScrollableFrameBO, 44 | "CTkScrollableFrame", 45 | ("ttk", _designer_tab_label), 46 | group=GCONTAINER, 47 | ) 48 | 49 | register_custom_property( 50 | _builder_uid, 51 | "label_anchor", 52 | "choice", 53 | values=( 54 | "", 55 | "n", 56 | "ne", 57 | "nw", 58 | "e", 59 | "w", 60 | "s", 61 | "se", 62 | "sw", 63 | "center", 64 | ), 65 | state="readonly", 66 | ) 67 | 68 | register_custom_property( 69 | _builder_uid, 70 | "orientation", 71 | "choice", 72 | values=("vertical", "horizontal"), 73 | default_value="vertical", 74 | state="readonly", 75 | ) 76 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/accordionframe_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter as tk 3 | from pygubu.api.v1 import ( 4 | BuilderObject, 5 | register_widget, 6 | ) 7 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 8 | from pygubu.widgets.accordionframe import AccordionFrame 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | 12 | class AccordionFrameBO(TTKFrame): 13 | class_ = AccordionFrame 14 | allowed_children = (f"{_plugin_uid}.AccordionFrameGroup",) 15 | _img_properties = ("img_expand", "img_collapse") 16 | properties = TTKFrame.properties + _img_properties 17 | tkimage_properties = TTKFrame.tkimage_properties + _img_properties 18 | 19 | 20 | _builder_uid = f"{_plugin_uid}.AccordionFrame" 21 | 22 | register_widget( 23 | _builder_uid, 24 | AccordionFrameBO, 25 | "AccordionFrame", 26 | (_tab_widgets_label, "ttk"), 27 | ) 28 | 29 | 30 | class AccordionFrameGroupBO(BuilderObject): 31 | allowed_parents = (f"{_plugin_uid}.AccordionFrame",) 32 | properties = ("label", "expanded", "compound", "style") 33 | layout_required = False 34 | container = True 35 | container_layout = True 36 | allow_bindings = False 37 | 38 | def realize(self, parent, extra_init_args: dict = None): 39 | args = self._get_init_args(extra_init_args) 40 | master = parent.get_child_master() 41 | gid = self.wmeta.identifier 42 | self.widget = master.add_group(gid, **args) 43 | self.widget._accordion = parent.widget 44 | return self.widget 45 | 46 | def _process_property_value(self, pname, value): 47 | if pname == "expanded": 48 | return tk.getboolean(value) 49 | return super()._process_property_value(pname, value) 50 | 51 | def _set_property(self, target_widget, pname, value): 52 | if pname in self.properties: 53 | propvalue = self._process_property_value(pname, value) 54 | self.widget._accordion.group_config( 55 | self.wmeta.identifier, **{pname: propvalue} 56 | ) 57 | else: 58 | super()._set_property(target_widget, pname, value) 59 | 60 | 61 | _builder_uid = f"{_plugin_uid}.AccordionFrameGroup" 62 | 63 | register_widget( 64 | _builder_uid, 65 | AccordionFrameGroupBO, 66 | "AccordionFrame.Group", 67 | (_tab_widgets_label, "ttk"), 68 | ) 69 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/calendarframe_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from pygubu.api.v1 import ( 3 | BuilderObject, 4 | register_widget, 5 | register_custom_property, 6 | ) 7 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 8 | from pygubu.widgets.calendarframe import CalendarFrame 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | 12 | class CalendarFrameBuilder(BuilderObject): 13 | class_ = CalendarFrame 14 | OPTIONS_STANDARD = TTKFrame.OPTIONS_STANDARD 15 | OPTIONS_SPECIFIC = TTKFrame.OPTIONS_SPECIFIC 16 | OPTIONS_CUSTOM = ( 17 | "firstweekday", 18 | "year", 19 | "month", 20 | "calendarfg", 21 | "calendarbg", 22 | "headerfg", 23 | "headerbg", 24 | "selectbg", 25 | "selectfg", 26 | "state", 27 | "markbg", 28 | "markfg", 29 | "linewidth", 30 | ) 31 | ro_properties = TTKFrame.ro_properties 32 | properties = OPTIONS_STANDARD + OPTIONS_SPECIFIC + OPTIONS_CUSTOM 33 | virtual_events = ("<>",) 34 | 35 | 36 | _builder_id = f"{_plugin_uid}.CalendarFrame" 37 | register_widget( 38 | _builder_id, 39 | CalendarFrameBuilder, 40 | "CalendarFrame", 41 | ("ttk", _tab_widgets_label), 42 | ) 43 | # Register old name until removal 44 | register_widget( 45 | "pygubu.builder.widgets.calendarframe", CalendarFrameBuilder, public=False 46 | ) 47 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/colorinput_bo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | from pygubu.api.v1 import ( 5 | BuilderObject, 6 | register_widget, 7 | ) 8 | from pygubu.widgets.colorinput import ColorInput 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | 12 | # 13 | # Builder definition section 14 | # 15 | 16 | 17 | class ColorInputBO(BuilderObject): 18 | class_ = ColorInput 19 | virtual_events = (ColorInput.EVENT_COLOR_CHANGED,) 20 | properties = ("value", "textvariable") 21 | 22 | 23 | _builder_id = f"{_plugin_uid}.ColorInput" 24 | register_widget( 25 | _builder_id, ColorInputBO, "ColorInput", ("ttk", _tab_widgets_label) 26 | ) 27 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/combobox_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from pygubu.api.v1 import register_widget 3 | from pygubu.plugins.ttk.ttkstdwidgets import TTKCombobox 4 | from pygubu.widgets.combobox import Combobox 5 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 6 | 7 | 8 | class ComboboxBO(TTKCombobox): 9 | OPTIONS_SPECIFIC = tuple( 10 | set(TTKCombobox.OPTIONS_SPECIFIC) - set(("state",)) 11 | ) 12 | OPTIONS_CUSTOM = TTKCombobox.OPTIONS_CUSTOM + ("keyvariable",) 13 | properties = ( 14 | TTKCombobox.OPTIONS_STANDARD 15 | + TTKCombobox.OPTIONS_SPECIFIC 16 | + OPTIONS_CUSTOM 17 | ) 18 | tkvar_properties = TTKCombobox.tkvar_properties + ("keyvariable",) 19 | class_ = Combobox 20 | 21 | 22 | ComboboxBuilder = ComboboxBO # Alias for future rename of builder. 23 | 24 | 25 | _builder_id = f"{_plugin_uid}.Combobox" 26 | register_widget( 27 | _builder_id, ComboboxBO, "Combobox", ("ttk", _tab_widgets_label) 28 | ) 29 | 30 | # Register old name until removal 31 | register_widget("pygubu.builder.widgets.combobox", ComboboxBO, public=False) 32 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/pygubu/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/designer/toplevelframe.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | from pygubu.api.v1 import BuilderObject, register_widget 4 | from .basehelpers import ( 5 | ToplevelPreviewFactory, 6 | ToplevelPreviewMixin, 7 | ToplevelPreviewBaseBO, 8 | ) 9 | 10 | 11 | ToplevelFramePreview = ToplevelPreviewFactory( 12 | "ToplevelFramePreview", 13 | (ToplevelPreviewMixin, tk.Frame, object), 14 | {}, 15 | ) 16 | 17 | 18 | class ToplevelFramePreviewBO(ToplevelPreviewBaseBO): 19 | class_ = ToplevelFramePreview 20 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/dialog_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from pygubu.api.v1 import register_widget 3 | from pygubu.plugins.tk.tkstdwidgets import TKToplevel 4 | from pygubu.widgets.dialog import Dialog 5 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 6 | 7 | 8 | class DialogBO(TKToplevel): 9 | class_ = Dialog 10 | OPTIONS_STANDARD = TKToplevel.OPTIONS_STANDARD 11 | OPTIONS_SPECIFIC = TKToplevel.OPTIONS_SPECIFIC 12 | OPTIONS_CUSTOM = TKToplevel.OPTIONS_CUSTOM + ("modal",) 13 | properties = OPTIONS_STANDARD + OPTIONS_SPECIFIC + OPTIONS_CUSTOM 14 | virtual_events = ("<>",) 15 | 16 | def layout(self, target=None, *, forget=False): 17 | super(DialogBO, self).layout(self.widget.toplevel, forget=forget) 18 | 19 | def _set_property(self, target_widget, pname, value): 20 | if pname == "modal": 21 | modal = False 22 | value = value.lower() 23 | if value == "true": 24 | modal = True 25 | self.widget.set_modal(modal) 26 | else: 27 | super(DialogBO, self)._set_property( 28 | self.widget.toplevel, pname, value 29 | ) 30 | 31 | def get_child_master(self): 32 | return self.widget.toplevel 33 | 34 | # 35 | # Code generation methods 36 | # 37 | def code_child_master(self): 38 | return "{0}.toplevel".format(self.code_identifier()) 39 | 40 | def _code_set_property(self, targetid, pname, value, code_bag): 41 | if pname == "modal": 42 | code_bag[pname] = '"{0}"'.format(value) 43 | else: 44 | super(DialogBO, self)._code_set_property( 45 | targetid, pname, value, code_bag 46 | ) 47 | 48 | 49 | _builder_id = f"{_plugin_uid}.Dialog" 50 | register_widget( 51 | _builder_id, DialogBO, "Dialog", (_tab_widgets_label, "ttk"), group=0 52 | ) 53 | # Register old name until removal 54 | register_widget("pygubu.builder.widgets.dialog", DialogBO, public=False) 55 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/editabletreeview_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from pygubu.api.v1 import register_widget 3 | from pygubu.plugins.ttk.ttkstdwidgets import ( 4 | TTKTreeviewBO, 5 | TTKTreeviewColumnBO, 6 | ) 7 | from .scrollbarhelper_bo import TTKSBHelperBO 8 | from pygubu.widgets.editabletreeview import EditableTreeview 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | 12 | class EditableTreeviewBO(TTKTreeviewBO): 13 | class_ = EditableTreeview 14 | virtual_events = TTKTreeviewBO.virtual_events + ( 15 | "<>", 16 | "<>", 17 | "<>", 18 | ) 19 | 20 | 21 | _builder_uid = f"{_plugin_uid}.EditableTreeview" 22 | if _builder_uid not in TTKTreeviewColumnBO.allowed_parents: 23 | TTKTreeviewColumnBO.add_allowed_parent(_builder_uid) 24 | if _builder_uid not in TTKSBHelperBO.allowed_children: 25 | TTKSBHelperBO.add_allowed_child(_builder_uid) 26 | 27 | register_widget( 28 | _builder_uid, 29 | EditableTreeviewBO, 30 | "EditableTreeview", 31 | (_tab_widgets_label, "ttk"), 32 | ) 33 | 34 | # Register old name until removal 35 | register_widget( 36 | "pygubu.builder.widgets.editabletreeview", EditableTreeviewBO, public=False 37 | ) 38 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/filterabletreeview_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from pygubu.api.v1 import register_widget 3 | from pygubu.plugins.ttk.ttkstdwidgets import ( 4 | TTKTreeviewBO, 5 | TTKTreeviewColumnBO, 6 | ) 7 | from .scrollbarhelper_bo import TTKSBHelperBO 8 | from pygubu.widgets.filterabletreeview import FilterableTreeview 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | 12 | class FilterableTreeviewBO(TTKTreeviewBO): 13 | class_ = FilterableTreeview 14 | # virtual_events = TTKTreeviewBO.virtual_events + ( 15 | # "<>", 16 | # ) 17 | 18 | 19 | _builder_uid = f"{_plugin_uid}.FilterableTreeview" 20 | if _builder_uid not in TTKTreeviewColumnBO.allowed_parents: 21 | TTKTreeviewColumnBO.add_allowed_parent(_builder_uid) 22 | if _builder_uid not in TTKSBHelperBO.allowed_children: 23 | TTKSBHelperBO.add_allowed_child(_builder_uid) 24 | 25 | register_widget( 26 | _builder_uid, 27 | FilterableTreeviewBO, 28 | "FilterableTreeview", 29 | (_tab_widgets_label, "ttk"), 30 | ) 31 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/floodgauge_bo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import tkinter as tk 3 | from pygubu.api.v1 import ( 4 | BuilderObject, 5 | register_widget, 6 | ) 7 | from pygubu.widgets.floodgauge import Floodgauge 8 | from pygubu.plugins.ttk.ttkstdwidgets import TTKProgressbar 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | 11 | # 12 | # Builder definition section 13 | # 14 | 15 | 16 | class FloodgaugeBO(TTKProgressbar): 17 | class_ = Floodgauge 18 | properties = TTKProgressbar.properties + ("mask", "text", "textvariable") 19 | 20 | 21 | _builder_uid = f"{_plugin_uid}.Floodgauge" 22 | register_widget( 23 | _builder_uid, 24 | FloodgaugeBO, 25 | "Floodgauge", 26 | ("ttk", _tab_widgets_label), 27 | ) 28 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/fontinputbo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | from pygubu.api.v1 import ( 5 | BuilderObject, 6 | register_widget, 7 | ) 8 | 9 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 10 | from pygubu.widgets.fontinput import FontInput 11 | 12 | 13 | # 14 | # Builder definition section 15 | # 16 | 17 | 18 | class FontInputBO(BuilderObject): 19 | class_ = FontInput 20 | virtual_events = (FontInput.EVENT_FONT_CHANGED,) 21 | 22 | 23 | _wname = "FontInput" 24 | _builder_id = f"{_plugin_uid}.{_wname}" 25 | 26 | register_widget(_builder_id, FontInputBO, _wname, ("ttk", _tab_widgets_label)) 27 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/forms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/pygubu/forms/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/forms/base.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from pygubu.api.v1 import BuilderObject 3 | from pygubu.i18n import _ 4 | 5 | 6 | _plugin_forms_uid = "pygubu.forms" 7 | _tab_form_widgets_label = _("Pygubu Forms") 8 | 9 | 10 | class WidgetBOMixin: 11 | """Manages base widget properties.""" 12 | 13 | FIELD_NAME_PROP = "field_name" 14 | base_properties = (FIELD_NAME_PROP,) 15 | 16 | # @classmethod 17 | # def properties(cls): 18 | # if isinstance(super().properties, tuple): 19 | # return super().properties + cls.base_properties 20 | # return super().properties() + cls.base_properties 21 | 22 | # @classmethod 23 | # def ro_properties(cls): 24 | # if isinstance(super().ro_properties, tuple): 25 | # return super().ro_properties + cls.base_properties 26 | # return super().ro_properties() + cls.base_properties 27 | 28 | def _get_init_args(self, extra_init_args: dict = None): 29 | args = super()._get_init_args(extra_init_args) 30 | name = args.get(self.FIELD_NAME_PROP, None) 31 | if not name: 32 | args[self.FIELD_NAME_PROP] = self.wmeta.identifier 33 | return args 34 | 35 | def _code_get_init_args(self, code_identifier): 36 | args = super()._code_get_init_args(code_identifier) 37 | field_name_value = args.get(self.FIELD_NAME_PROP, None) 38 | if not field_name_value: 39 | field_name_value = self.wmeta.identifier 40 | args[self.FIELD_NAME_PROP] = self._code_process_property_value( 41 | code_identifier, self.FIELD_NAME_PROP, field_name_value 42 | ) 43 | return args 44 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/forms/pygubuwidget_bo.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import pygubu.plugins.pygubu.combobox_bo as cbb 3 | import pygubu.plugins.pygubu.fontinputbo as fib 4 | import pygubu.forms.pygubuwidget as pygubuwidget 5 | 6 | from pygubu.api.v1 import ( 7 | BuilderObject, 8 | register_widget, 9 | register_custom_property, 10 | copy_custom_property, 11 | ) 12 | from .base import ( 13 | WidgetBOMixin, 14 | _plugin_forms_uid, 15 | _tab_form_widgets_label, 16 | ) 17 | 18 | 19 | _plugin_uid = f"{_plugin_forms_uid}.pygubuwidget" 20 | _designer_tabs = ("tk", "ttk", _tab_form_widgets_label) 21 | 22 | 23 | class PygubuComboboxBO(WidgetBOMixin, cbb.ComboboxBO): 24 | class_ = pygubuwidget.PygubuCombobox 25 | properties = cbb.ComboboxBuilder.properties + WidgetBOMixin.base_properties 26 | ro_properties = ( 27 | cbb.ComboboxBuilder.ro_properties + WidgetBOMixin.base_properties 28 | ) 29 | 30 | 31 | _builder_uid = f"{_plugin_uid}.PygubuCombobox" 32 | register_widget( 33 | _builder_uid, 34 | PygubuComboboxBO, 35 | "PygubuCombobox", 36 | _designer_tabs, 37 | ) 38 | 39 | 40 | class FontInputFWBO(WidgetBOMixin, fib.FontInputBO): 41 | class_ = pygubuwidget.FontInputFW 42 | properties = fib.FontInputBO.properties + WidgetBOMixin.base_properties 43 | ro_properties = ( 44 | fib.FontInputBO.ro_properties + WidgetBOMixin.base_properties 45 | ) 46 | 47 | 48 | _wname = "FontInput" 49 | _builder_uid = f"{_plugin_uid}.{_wname}" 50 | register_widget( 51 | _builder_uid, 52 | FontInputFWBO, 53 | _wname, 54 | _designer_tabs, 55 | ) 56 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/forms/tkwidget_bo.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import pygubu.plugins.tk.tkstdwidgets as tkw 3 | import pygubu.plugins.ttk.ttkstdwidgets as ttkw 4 | import pygubu.forms.tkwidget as tkwidget 5 | 6 | from pygubu.api.v1 import ( 7 | BuilderObject, 8 | register_widget, 9 | register_custom_property, 10 | ) 11 | from pygubu.i18n import _ 12 | from pygubu.plugins.pygubu.tkscrollbarhelper_bo import TKSBHelperBO 13 | from .base import ( 14 | WidgetBOMixin, 15 | _plugin_forms_uid, 16 | _tab_form_widgets_label, 17 | ) 18 | 19 | 20 | _plugin_uid = f"{_plugin_forms_uid}.tkwidget" 21 | _designer_tabs = ("tk", "ttk", _tab_form_widgets_label) 22 | 23 | 24 | class TextBO(WidgetBOMixin, tkw.TKText): 25 | class_ = tkwidget.Text 26 | properties = tkw.TKText.properties + WidgetBOMixin.base_properties 27 | ro_properties = tkw.TKText.ro_properties + WidgetBOMixin.base_properties 28 | 29 | 30 | _builder_uid = f"{_plugin_uid}.Text" 31 | _tk_text_builder_uid = _builder_uid 32 | 33 | register_widget( 34 | _builder_uid, 35 | TextBO, 36 | "Text", 37 | _designer_tabs, 38 | group=0, 39 | ) 40 | 41 | 42 | TKSBHelperBO.add_allowed_child(_builder_uid) 43 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/hideableframe_bo.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import register_widget 2 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 3 | from pygubu.widgets.hideableframe import HideableFrame 4 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 5 | 6 | 7 | class HideableFrameBO(TTKFrame): 8 | class_ = HideableFrame 9 | 10 | 11 | _builder_uid = f"{_plugin_uid}.hideableframe" 12 | register_widget( 13 | _builder_uid, 14 | HideableFrameBO, 15 | "HideableFrame", 16 | (_tab_widgets_label, "ttk"), 17 | ) 18 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/pathchooserinput_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter as tk 3 | from pygubu.api.v1 import BuilderObject, register_widget 4 | from pygubu.plugins.ttk.ttkstdwidgets import TTKButton 5 | from pygubu.widgets.pathchooserinput import PathChooserInput, PathChooserButton 6 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 7 | 8 | 9 | class PathChooserBaseMixin: 10 | base_properties = ( 11 | "type", 12 | "path", 13 | "initialdir", 14 | "mustexist", 15 | "title", 16 | "defaultextension", 17 | ) 18 | 19 | def _process_property_value(self, pname, value): 20 | if pname == "mustexist": 21 | return tk.getboolean(value) 22 | return super()._process_property_value(pname, value) 23 | 24 | def _code_process_property_value(self, targetid, pname, value: str): 25 | if pname == "mustexist": 26 | return self._process_property_value(pname, value) 27 | return super()._code_process_property_value(targetid, pname, value) 28 | 29 | 30 | class PathChooserInputBO(PathChooserBaseMixin, BuilderObject): 31 | class_ = PathChooserInput 32 | properties = PathChooserBaseMixin.base_properties + ( 33 | "image", 34 | "textvariable", 35 | "state", 36 | ) 37 | virtual_events = ("<>",) 38 | 39 | 40 | _builder_id = f"{_plugin_uid}.PathChooserInput" 41 | register_widget( 42 | _builder_id, 43 | PathChooserInputBO, 44 | "PathChooserInput", 45 | ("ttk", _tab_widgets_label), 46 | ) 47 | _old_bid = "pygubu.builder.widgets.pathchooserinput" 48 | register_widget( 49 | _old_bid, 50 | PathChooserInputBO, 51 | public=False, 52 | ) 53 | 54 | 55 | class PathChooserButtonBO(PathChooserBaseMixin, BuilderObject): 56 | class_ = PathChooserButton 57 | properties = PathChooserBaseMixin.base_properties + tuple( 58 | set(TTKButton.properties) - set(("command", "default")) 59 | ) 60 | virtual_events = ("<>",) 61 | 62 | 63 | _builder_id = f"{_plugin_uid}.PathChooserButton" 64 | register_widget( 65 | _builder_id, 66 | PathChooserButtonBO, 67 | "PathChooserButton", 68 | ("ttk", _tab_widgets_label), 69 | ) 70 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/scrollbarhelper_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter as tk 3 | 4 | from pygubu.api.v1 import BuilderObject, register_widget 5 | from pygubu.widgets.scrollbarhelper import ScrollbarHelper 6 | from pygubu.plugins.pygubu import _tab_helpers_label, _plugin_uid 7 | 8 | 9 | class TTKSBHelperBO(BuilderObject): 10 | class_ = ScrollbarHelper 11 | container = True 12 | maxchildren = 1 13 | allowed_children = ( 14 | "tk.Entry", 15 | "ttk.Entry", 16 | "tk.Text", 17 | "tk.Canvas", 18 | "tk.Listbox", 19 | "ttk.Treeview", 20 | ) 21 | OPTIONS_STANDARD = ("class_", "cursor", "takefocus", "style") 22 | OPTIONS_SPECIFIC = ("borderwidth", "relief", "padding", "height", "width") 23 | OPTIONS_CUSTOM = ("scrolltype", "usemousewheel") 24 | properties = OPTIONS_STANDARD + OPTIONS_SPECIFIC + OPTIONS_CUSTOM 25 | ro_properties = ("class_", "scrolltype") 26 | allow_bindings = False 27 | 28 | def get_child_master(self): 29 | return self.widget.container 30 | 31 | def add_child(self, bobject): 32 | cwidget = bobject.widget 33 | self.widget.add_child(cwidget) 34 | 35 | # 36 | # Code generation methods 37 | # 38 | def code_child_master(self): 39 | return "{0}.container".format(self.code_identifier()) 40 | 41 | def code_child_add(self, childid): 42 | lines = [] 43 | line = "{0}.add_child({1})".format(self.code_identifier(), childid) 44 | lines.append(line) 45 | return lines 46 | 47 | def _code_set_property(self, targetid, pname, value, code_bag): 48 | if pname == "usemousewheel": 49 | code_bag[pname] = "{0}".format(tk.getboolean(value)) 50 | else: 51 | super(TTKSBHelperBO, self)._code_set_property( 52 | targetid, pname, value, code_bag 53 | ) 54 | 55 | 56 | _builder_id = f"{_plugin_uid}.ScrollbarHelper" 57 | register_widget( 58 | _builder_id, 59 | TTKSBHelperBO, 60 | "ScrollbarHelper", 61 | (_tab_helpers_label, "ttk"), 62 | ) 63 | 64 | _builder_old = "pygubu.builder.widgets.scrollbarhelper" 65 | register_widget( 66 | _builder_old, 67 | TTKSBHelperBO, 68 | public=False, 69 | ) 70 | -------------------------------------------------------------------------------- /src/pygubu/plugins/pygubu/simpletooltip_bo.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import ( 2 | BuilderObject, 3 | register_widget, 4 | ) 5 | from pygubu.plugins.pygubu import _tab_widgets_label, _plugin_uid 6 | from pygubu.widgets.simpletooltip import Tooltip, Tooltipttk 7 | from pygubu.component.builderobject import FamilyType 8 | 9 | 10 | class TooltipBaseBO(BuilderObject): 11 | allow_bindings = False 12 | layout_required = False 13 | family = FamilyType.MODIFIER 14 | 15 | def realize(self, parent, extra_init_args: dict = None): 16 | self.widget = parent.get_child_master() 17 | self.widget.simple_tooltip = self.class_(self.widget) 18 | return self.widget 19 | 20 | def _set_property(self, target_widget, pname, value): 21 | target_widget.simple_tooltip.label_options[pname] = value 22 | 23 | 24 | class SimpleTooltipBO(TooltipBaseBO): 25 | class_ = Tooltip 26 | properties = ( 27 | "text", 28 | "font", 29 | "background", 30 | "foreground", 31 | "justify", 32 | "wraplength", 33 | "relief", 34 | "borderwidth", 35 | "padx", 36 | "pady", 37 | ) 38 | 39 | 40 | _builder_uid = f"{_plugin_uid}.Tooltip" 41 | register_widget( 42 | _builder_uid, 43 | SimpleTooltipBO, 44 | "Tooltip", 45 | (_tab_widgets_label, "tk", "ttk"), 46 | ) 47 | 48 | 49 | class SimpleTooltipttkBO(SimpleTooltipBO): 50 | class_ = Tooltipttk 51 | properties = ( 52 | "text", 53 | "font", 54 | "foreground", 55 | "background", 56 | "justify", 57 | "wraplength", 58 | "relief", 59 | "borderwidth", 60 | "style", 61 | ) 62 | 63 | 64 | _builder_uid = f"{_plugin_uid}.Tooltipttk" 65 | register_widget( 66 | _builder_uid, 67 | SimpleTooltipttkBO, 68 | "Tooltipttk", 69 | (_tab_widgets_label, "ttk"), 70 | ) 71 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tk/__init__.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import BuilderLoaderPlugin 2 | 3 | 4 | class StandardTKWidgetsLoader(BuilderLoaderPlugin): 5 | module_default = "pygubu.plugins.tk.tkstdwidgets" 6 | module_map = { 7 | module_default: tuple(), 8 | "pygubu.plugins.tk.scrolledtext_bo": ( 9 | "tk.ScrolledText", 10 | "pygubu.builder.widgets.tkinterscrolledtext", # old name 11 | ), 12 | } 13 | 14 | def do_activate(self) -> bool: 15 | return True 16 | 17 | def get_all_modules(self): 18 | return [m for m in self.module_map.keys()] 19 | 20 | def get_module_for(self, identifier: str) -> str: 21 | for module, identifiers in self.module_map.items(): 22 | if identifier in identifiers: 23 | return module 24 | return self.module_default 25 | 26 | def can_load(self, identifier: str) -> bool: 27 | for module, builders in self.module_map.items(): 28 | if identifier in builders: 29 | return True 30 | return identifier.startswith("tk.") 31 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tk/scrolledtext_bo.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from tkinter.scrolledtext import ScrolledText 3 | 4 | from pygubu.api.v1 import register_widget 5 | from pygubu.plugins.tk.tkstdwidgets import TKText 6 | from pygubu.i18n import _ 7 | 8 | 9 | class TkinterScrolledTextBO(TKText): 10 | class_ = ScrolledText 11 | 12 | 13 | register_widget( 14 | "tk.ScrolledText", 15 | TkinterScrolledTextBO, 16 | "tk.ScrolledText", 17 | (_("Control & Display"), "tk"), 18 | ) 19 | 20 | _builder_old = "pygubu.builder.widgets.tkinterscrolledtext" 21 | register_widget( 22 | _builder_old, 23 | TkinterScrolledTextBO, 24 | public=False, 25 | ) 26 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import BuilderLoaderPlugin 4 | 5 | 6 | _designer_tab_label = _("tkcalendar") 7 | _plugin_uid = "tkcalendar" 8 | 9 | 10 | class TkcalendarLoader(BuilderLoaderPlugin): 11 | module_map = { 12 | "pygubu.plugins.tkcalendar.calendar": (f"{_plugin_uid}.Calendar",), 13 | "pygubu.plugins.tkcalendar.dateentry": (f"{_plugin_uid}.DateEntry",), 14 | } 15 | 16 | def do_activate(self) -> bool: 17 | spec = importlib.util.find_spec("tkcalendar") 18 | return spec is not None 19 | 20 | def get_module_for(self, identifier: str) -> str: 21 | for module, identifiers in self.module_map.items(): 22 | if identifier in identifiers: 23 | return module 24 | return None 25 | 26 | def get_all_modules(self): 27 | return [m for m in self.module_map.keys()] 28 | 29 | def can_load(self, identifier: str) -> bool: 30 | return identifier.startswith("tkcalendar.") 31 | 32 | def get_designer_plugin(self): 33 | """Load class that implements IDesignerPlugin""" 34 | from .designer.designerplugin import TkcalendarPlugin 35 | 36 | return TkcalendarPlugin() 37 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/basecalendar.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from datetime import datetime 3 | from pygubu.api.v1 import BuilderObject 4 | 5 | 6 | class CalendarBaseBO(BuilderObject): 7 | OPTIONS_CUSTOM = ( 8 | "year", 9 | "month", 10 | "day", 11 | "firstweekday", 12 | "mindate", 13 | "maxdate", 14 | "showweeknumbers", 15 | "showothermonthdays", 16 | "date_pattern", 17 | "selectmode", 18 | "textvariable", 19 | "background", 20 | "foreground", 21 | "disabledbackground", 22 | "disabledforeground", 23 | "bordercolor", 24 | "headersbackground", 25 | "headersforeground", 26 | "selectbackground", 27 | "selectforeground", 28 | "disabledselectbackground", 29 | "disabledselectforeground", 30 | "normalbackground", 31 | "normalforeground", 32 | "weekendbackground", 33 | "weekendforeground", 34 | "othermonthforeground", 35 | "othermonthbackground", 36 | "othermonthweforeground", 37 | "othermonthwebackground", 38 | "disableddaybackground", 39 | "disableddayforeground", 40 | "tooltipforeground", 41 | "tooltipbackground", 42 | "tooltipalpha", 43 | "tooltipdelay", 44 | ) 45 | ro_properties = ("year", "month", "day") 46 | 47 | def _process_property_value(self, pname, value): 48 | if pname in ("year", "month", "day", "tooltipdelay"): 49 | return int(value) 50 | if pname in ("showweeknumbers", "showothermonthdays"): 51 | return tk.getboolean(value) 52 | if pname == "tooltipalpha": 53 | return float(value) 54 | if pname in ("mindate", "maxdate"): 55 | return datetime.strptime(value, "%Y-%m-%d") 56 | return super()._process_property_value(pname, value) 57 | 58 | def _code_process_property_value(self, targetid, pname, value: str): 59 | if pname in ("showweeknumbers", "showothermonthdays"): 60 | return self._process_property_value(pname, value) 61 | if pname in ("mindate", "maxdate"): 62 | return f"""Calendar.datetime.strptime("{value}", "%Y-%m-%d")""" 63 | return super()._code_process_property_value(targetid, pname, value) 64 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/calendar.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import register_widget 2 | from tkcalendar import Calendar 3 | 4 | from ..tkcalendar import _designer_tab_label, _plugin_uid 5 | from .basecalendar import CalendarBaseBO 6 | 7 | 8 | class CalendarBO(CalendarBaseBO): 9 | class_ = Calendar 10 | OPTIONS_STANDARD = ("class_", "cursor") 11 | OPTIONS_SPECIFIC = ("borderwidth", "state") 12 | properties = ( 13 | OPTIONS_STANDARD + OPTIONS_SPECIFIC + CalendarBaseBO.OPTIONS_CUSTOM 14 | ) 15 | ro_properties = CalendarBaseBO.ro_properties + ("class_",) 16 | virtual_events = ("<>", "<>") 17 | 18 | 19 | _builder_id = f"{_plugin_uid}.Calendar" 20 | 21 | register_widget( 22 | _builder_id, 23 | CalendarBO, 24 | "Calendar", 25 | ("ttk", _designer_tab_label), 26 | ) 27 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/dateentry.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import register_widget 2 | from pygubu.plugins.ttk.ttkstdwidgets import TTKEntry 3 | from tkcalendar import DateEntry 4 | 5 | from ..tkcalendar import _designer_tab_label, _plugin_uid 6 | from .basecalendar import CalendarBaseBO 7 | 8 | 9 | class DateEntryBO(CalendarBaseBO, TTKEntry): 10 | class_ = DateEntry 11 | OPTIONS_CUSTOM = CalendarBaseBO.OPTIONS_CUSTOM + ("calendar_cursor",) 12 | properties = ( 13 | TTKEntry.OPTIONS_STANDARD + TTKEntry.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 14 | ) 15 | ro_properties = CalendarBaseBO.ro_properties + ("calendar_cursor",) 16 | virtual_events = ("<>",) 17 | 18 | 19 | _builder_id = f"{_plugin_uid}.DateEntry" 20 | 21 | register_widget( 22 | _builder_id, 23 | DateEntryBO, 24 | "DateEntry", 25 | ("ttk", _designer_tab_label), 26 | ) 27 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/tkcalendar/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/tkcalendar/designer/designerplugin.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import IDesignerPlugin 2 | from .properties import _calendar, _dateentry 3 | from .previewhelper import CalendarPreviewBO, DateEntryPreviewBO 4 | 5 | 6 | class TkcalendarPlugin(IDesignerPlugin): 7 | def get_preview_builder(self, builder_uid: str): 8 | if builder_uid == _calendar: 9 | return CalendarPreviewBO 10 | elif builder_uid == _dateentry: 11 | return DateEntryPreviewBO 12 | return None 13 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkintermapview/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from typing import Optional 3 | from pygubu.i18n import _ 4 | from pygubu.api.v1 import BuilderLoaderPlugin, IDesignerPlugin 5 | 6 | 7 | _designer_tab_label = _("TkinterMapView") 8 | _plugin_uid = "tkintermapview" 9 | 10 | 11 | class TkinterMapViewLoader(BuilderLoaderPlugin, IDesignerPlugin): 12 | _module = "pygubu.plugins.tkintermapview.mapview" 13 | 14 | # 15 | # IPluginBase interface methods 16 | # 17 | def do_activate(self) -> bool: 18 | spec = importlib.util.find_spec("tkintermapview") 19 | return spec is not None 20 | 21 | def get_designer_plugin(self) -> Optional[IDesignerPlugin]: 22 | return self 23 | 24 | # 25 | # IBuilderLoaderPlugin interface methods 26 | # 27 | def get_module_for(self, identifier: str) -> str: 28 | return self._module 29 | 30 | def get_all_modules(self): 31 | return (self._module,) 32 | 33 | def can_load(self, identifier: str) -> bool: 34 | return identifier.startswith("tkintermapview.") 35 | 36 | # 37 | # IDesignerPlugin interface methods 38 | # 39 | def configure_for_preview(self, builder_uid: str, widget): 40 | """Make widget just display with minimal functionality.""" 41 | if builder_uid.endswith(f"{_plugin_uid}.TkinterMapView"): 42 | 43 | def _no_op(event=None): 44 | pass 45 | 46 | seqlist = ( 47 | "", 48 | "", 49 | "", 50 | "", 51 | "", 52 | "", 53 | "", 54 | "", 55 | ) 56 | for seq in seqlist: 57 | widget.canvas.bind(seq, _no_op) 58 | widget.button_zoom_in.command = _no_op 59 | widget.button_zoom_out.command = _no_op 60 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkintermapview/mapview.py: -------------------------------------------------------------------------------- 1 | from pygubu.i18n import _ 2 | from pygubu.api.v1 import ( 3 | BuilderObject, 4 | register_widget, 5 | register_custom_property, 6 | ) 7 | from tkintermapview import TkinterMapView 8 | from ..tkintermapview import _designer_tab_label, _plugin_uid 9 | 10 | 11 | class TkinterMapViewBuilder(BuilderObject): 12 | class_ = TkinterMapView 13 | _int_props = ("width", "height", "corner_radius", "max_zoom") 14 | OPTIONS_CUSTOM = _int_props + ("bg_color",) 15 | ro_properties = OPTIONS_CUSTOM 16 | 17 | def _process_property_value(self, pname, value): 18 | if pname in self._int_props: 19 | return int(value) 20 | return super()._process_property_value(pname, value) 21 | 22 | def _code_process_property_value(self, targetid, pname, value: str): 23 | if pname in self._int_props: 24 | return self._process_property_value(pname, value) 25 | return super()._code_process_property_value(targetid, pname, value) 26 | 27 | 28 | _builder_uid = f"{_plugin_uid}.TkinterMapView" 29 | register_widget( 30 | _builder_uid, 31 | TkinterMapViewBuilder, 32 | "TkinterMapView", 33 | ("ttk", _designer_tab_label), 34 | ) 35 | 36 | _none = {} 37 | # pname, editor, options 38 | _properties = ( 39 | ("widht", "naturalnumber", _none), 40 | ("height", "naturalnumber", _none), 41 | ( 42 | "corner_radius", 43 | "choice", 44 | {"values": [""] + [x for x in range(0, 31)], "state": "readonly"}, 45 | ), 46 | ("bg_color", "colorentry", _none), 47 | ( 48 | "max_zoom", 49 | "choice", 50 | {"values": [x for x in range(1, 20)], "state": "readonly"}, 51 | ), 52 | ) 53 | 54 | for pname, editor, options in _properties: 55 | register_custom_property(_builder_uid, pname, editor, **options) 56 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkintertable/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from typing import Optional 3 | from pygubu.i18n import _ 4 | from pygubu.api.v1 import BuilderLoaderPlugin, IDesignerPlugin 5 | 6 | 7 | _designer_tab_label = _("tkintertable") 8 | _plugin_uid = "tkintertable" 9 | 10 | 11 | class StandardTKWidgetsLoader(BuilderLoaderPlugin, IDesignerPlugin): 12 | _module = "pygubu.plugins.tkintertable.table" 13 | 14 | # 15 | # IPluginBase interface methods 16 | # 17 | def do_activate(self) -> bool: 18 | spec = importlib.util.find_spec("tkintertable") 19 | return spec is not None 20 | 21 | def get_designer_plugin(self) -> Optional[IDesignerPlugin]: 22 | return self 23 | 24 | # 25 | # IBuilderLoaderPlugin interface methods 26 | # 27 | def get_module_for(self, identifier: str) -> str: 28 | return self._module 29 | 30 | def get_all_modules(self): 31 | return (self._module,) 32 | 33 | def can_load(self, identifier: str) -> bool: 34 | return identifier.startswith("tkintertable.") 35 | 36 | # 37 | # IDesignerPlugin interface methods 38 | # 39 | def configure_for_preview(self, builder_uid: str, widget): 40 | """Make widget just display with minimal functionality.""" 41 | if builder_uid.endswith(f"{_plugin_uid}.TableCanvas"): 42 | 43 | def _no_op(event=None): 44 | pass 45 | 46 | seqlist = ( 47 | "", 48 | "", 49 | "", 50 | "", 51 | "", 52 | "" "", 53 | "", 54 | "", 55 | "", 56 | ) 57 | for seq in seqlist: 58 | widget.bind(seq, _no_op) 59 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import BuilderLoaderPlugin 4 | 5 | 6 | _designer_tab_label = _("TkinterWeb") 7 | _plugin_uid = "tkinterweb" 8 | 9 | 10 | class TkinterwebLoader(BuilderLoaderPlugin): 11 | module_map = { 12 | "pygubu.plugins.tkinterweb.htmlwidgets": ( 13 | f"{_plugin_uid}.HtmlFrame", 14 | f"{_plugin_uid}.HtmlLabel", 15 | ), 16 | "pygubu.plugins.tkinterweb.extrawidgets": ( 17 | f"{_plugin_uid}.Notebook", 18 | f"{_plugin_uid}.ColourSelector", 19 | ), 20 | } 21 | 22 | def do_activate(self) -> bool: 23 | spec = importlib.util.find_spec("tkinterweb") 24 | return spec is not None 25 | 26 | def get_module_for(self, identifier: str) -> str: 27 | for module, identifiers in self.module_map.items(): 28 | if identifier in identifiers: 29 | return module 30 | return None 31 | 32 | def get_all_modules(self): 33 | return [m for m in self.module_map.keys()] 34 | 35 | def can_load(self, identifier: str) -> bool: 36 | return identifier.startswith("tkinterweb.") 37 | 38 | def get_designer_plugin(self): 39 | """Load class that implements IDesignerPlugin""" 40 | 41 | # Just load the module for properties definitions. 42 | from .designer.designerplugin import TkinterwebPlugin 43 | 44 | return None 45 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/tkinterweb/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/designer/designerplugin.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import IPluginBase, IDesignerPlugin 2 | import pygubu.plugins.tkinterweb.designer.properties 3 | 4 | 5 | class TkinterwebPlugin(IDesignerPlugin): 6 | ... 7 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/designer/properties.py: -------------------------------------------------------------------------------- 1 | from pygubu.i18n import _ 2 | from pygubu.api.v1 import register_custom_property 3 | from pygubu.plugins.tkinterweb import _plugin_uid 4 | 5 | 6 | _builder_all = f"{_plugin_uid}.*" 7 | _htmlFrame = f"{_plugin_uid}.HtmlFrame" 8 | _htmlLabel = f"{_plugin_uid}.HtmlLabel" 9 | _notebook = f"{_plugin_uid}.Notebook" 10 | _colourSelector = f"{_plugin_uid}.ColourSelector" 11 | 12 | 13 | plugin_properties = { 14 | "colour": dict( 15 | buid=_colourSelector, editor="colorentry", default_value="white" 16 | ), 17 | "height": dict( 18 | buid=_notebook, 19 | editor="dimensionentry", 20 | default_value=200, 21 | ), 22 | "horizontal_scrollbar": dict( 23 | buid=_htmlFrame, 24 | editor="choice", 25 | values=("", "true", "false", "auto"), 26 | state="readonly", 27 | ), 28 | "messages_enabled": dict( 29 | buid=_builder_all, 30 | editor="choice", 31 | values=("", "false", "true"), 32 | state="readonly", 33 | help=_("Show debugging messages on console output."), 34 | ), 35 | "text": dict( 36 | buid=_htmlLabel, 37 | editor="text", 38 | ), 39 | "vertical_scrollbar": dict( 40 | buid=_htmlFrame, 41 | editor="choice", 42 | values=("", "true", "false", "auto"), 43 | state="readonly", 44 | ), 45 | "width": dict( 46 | buid=_notebook, 47 | editor="dimensionentry", 48 | default_value=200, 49 | ), 50 | } 51 | 52 | for prop in plugin_properties: 53 | definitions = plugin_properties[prop] 54 | if isinstance(definitions, dict): 55 | definitions = [definitions] 56 | for definition in definitions: 57 | builders = definition.pop("buid", _builder_all) 58 | if isinstance(builders, str): 59 | builders = [builders] 60 | editor = definition.pop("editor", "entry") 61 | for builder_uid in builders: 62 | register_custom_property(builder_uid, prop, editor, **definition) 63 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/extrawidgets.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | from pygubu.api.v1 import BuilderObject, register_widget 4 | from pygubu.plugins.ttk.ttkstdwidgets import TTKNotebookTab 5 | from tkinterweb.utilities import Notebook, ColourSelector 6 | from ..tkinterweb import _designer_tab_label, _plugin_uid 7 | 8 | 9 | class NotebookBO(BuilderObject): 10 | class_ = Notebook 11 | container = True 12 | container_layout = True 13 | ro_properties = ("class_", "takefocus") 14 | properties = ( 15 | # ttk.Frame properties: 16 | "class_", 17 | "cursor", 18 | "style", 19 | "borderwidth", 20 | "relief", 21 | "padding", 22 | "height", 23 | "width", 24 | ) 25 | virtual_events = ("<>",) 26 | 27 | 28 | _builder_uid = f"{_plugin_uid}.Notebook" 29 | _notebook_uid = _builder_uid 30 | register_widget( 31 | _builder_uid, NotebookBO, "Notebook", ("ttk", _designer_tab_label), group=1 32 | ) 33 | 34 | 35 | class NotebookPageBO(TTKNotebookTab): 36 | allowed_parents = (_notebook_uid,) 37 | children_layout_override = True 38 | properties = ( 39 | "state", 40 | "text", 41 | "image", 42 | "compound", 43 | "underline", 44 | ) 45 | 46 | 47 | _builder_uid = f"{_plugin_uid}.Notebook.Page" 48 | NotebookBO.add_allowed_child(_builder_uid) 49 | 50 | register_widget( 51 | _builder_uid, 52 | NotebookPageBO, 53 | "Notebook.Page", 54 | ("ttk", _designer_tab_label), 55 | group=1, 56 | ) 57 | 58 | 59 | class ColourSelectorBO(BuilderObject): 60 | class_ = ColourSelector 61 | properties = ("colour",) 62 | ro_properties = ("colour",) 63 | virtual_events = ("<>",) 64 | 65 | 66 | _builder_uid = f"{_plugin_uid}.ColourSelector" 67 | register_widget( 68 | _builder_uid, 69 | ColourSelectorBO, 70 | "ColourSelector", 71 | ("ttk", _designer_tab_label), 72 | group=2, 73 | ) 74 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkinterweb/htmlwidgets.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | # from pygubu.i18n import _ 4 | from pygubu.api.v1 import register_widget 5 | from tkinterweb import HtmlLabel, HtmlFrame 6 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 7 | from ..tkinterweb import _designer_tab_label, _plugin_uid 8 | 9 | 10 | class HtmlFrameBO(TTKFrame): 11 | class_ = HtmlFrame 12 | container = False 13 | OPTIONS_CUSTOM = ( 14 | "messages_enabled", 15 | "vertical_scrollbar", 16 | "horizontal_scrollbar", 17 | ) 18 | properties = ( 19 | TTKFrame.OPTIONS_STANDARD + TTKFrame.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 20 | ) 21 | ro_properties = OPTIONS_CUSTOM 22 | 23 | def _process_property_value(self, pname, value): 24 | if pname == "messages_enabled": 25 | return tk.getboolean(value) 26 | if pname in ("vertical_scrollbar", "horizontal_scrollbar"): 27 | return value if value == "auto" else tk.getboolean(value) 28 | return super()._process_property_value(pname, value) 29 | 30 | def _code_process_property_value(self, targetid, pname, value): 31 | if pname in self.OPTIONS_CUSTOM: 32 | newval = self._process_property_value(pname, value) 33 | return newval if isinstance(newval, bool) else f"'{newval}'" 34 | return super()._code_process_property_value(targetid, pname, value) 35 | 36 | def code_imports(self): 37 | return (("tkinterweb", "HtmlFrame"),) 38 | 39 | 40 | _builder_uid = f"{_plugin_uid}.HtmlFrame" 41 | register_widget( 42 | _builder_uid, 43 | HtmlFrameBO, 44 | "HtmlFrame", 45 | ("ttk", _designer_tab_label), 46 | group=0, 47 | ) 48 | 49 | 50 | class HtmlLabelBO(HtmlFrameBO): 51 | class_ = HtmlLabel 52 | OPTIONS_CUSTOM = ("messages_enabled", "text") 53 | properties = ( 54 | HtmlFrameBO.OPTIONS_STANDARD 55 | + HtmlFrameBO.OPTIONS_SPECIFIC 56 | + OPTIONS_CUSTOM 57 | ) 58 | ro_properties = OPTIONS_CUSTOM 59 | 60 | def code_imports(self): 61 | return (("tkinterweb", "HtmlLabel"),) 62 | 63 | 64 | _builder_uid = f"{_plugin_uid}.HtmlLabel" 65 | register_widget( 66 | _builder_uid, 67 | HtmlLabelBO, 68 | "HtmlLabel", 69 | ("ttk", _designer_tab_label), 70 | group=0, 71 | ) 72 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkmt/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import BuilderLoaderPlugin 4 | 5 | 6 | _designer_tab_label = _("TkinterModernThemes") 7 | _plugin_uid = "tkmt" 8 | 9 | 10 | class TkmthemesLoader(BuilderLoaderPlugin): 11 | module_map = { 12 | "pygubu.plugins.tkmt.widgets": (f"{_plugin_uid}.ThemedTKinterFrame",), 13 | } 14 | 15 | def do_activate(self) -> bool: 16 | spec = importlib.util.find_spec("TKinterModernThemes") 17 | return spec is not None 18 | 19 | def get_module_for(self, identifier: str) -> str: 20 | for module, identifiers in self.module_map.items(): 21 | if identifier in identifiers: 22 | return module 23 | return None 24 | 25 | def get_all_modules(self): 26 | return [m for m in self.module_map.keys()] 27 | 28 | def can_load(self, identifier: str) -> bool: 29 | for module, builders in self.module_map.items(): 30 | if identifier in builders: 31 | return True 32 | return False 33 | 34 | def get_designer_plugin(self): 35 | """Load class that implements IDesignerPlugin""" 36 | from .designer.designerplugin import PygubuDesignerPlugin 37 | 38 | return PygubuDesignerPlugin() 39 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkmt/codegen.py: -------------------------------------------------------------------------------- 1 | class TkmtWidgetCodeMixin: 2 | def code_configure(self, targetid=None): 3 | return [] 4 | 5 | def code_connect_commands(self): 6 | return [] 7 | 8 | def _code_process_pos_kw_properties(self, code_identifier): 9 | """Creates dict with properties values for code""" 10 | defaults = self._get_property_defaults() 11 | args = {} 12 | for rop in self.properties: 13 | value_is_set = False 14 | pvalue = None 15 | if rop in self.wmeta.properties: 16 | pvalue = self.wmeta.properties[rop] 17 | value_is_set = True 18 | elif rop in defaults: 19 | pvalue = defaults[rop] 20 | value_is_set = True 21 | if value_is_set: 22 | pvalue = self._code_process_property_value( 23 | code_identifier, rop, pvalue 24 | ) 25 | args[rop] = pvalue 26 | return args 27 | 28 | def code_realize(self, boparent, code_identifier=None): 29 | if code_identifier is not None: 30 | self._code_identifier = code_identifier 31 | lines = [] 32 | master = boparent.code_child_master() 33 | 34 | pbag = self._code_process_pos_kw_properties(code_identifier) 35 | kargs = self._get_keyword_args(pbag) 36 | args = self._get_positional_args(pbag) 37 | 38 | pos_args = "" 39 | if args: 40 | pos_args = ",".join(args) 41 | 42 | bag = [] 43 | for pname, value in kargs.items(): 44 | bag.append(f"{pname}={value}") 45 | 46 | kwargs = "" 47 | if bag: 48 | if args: 49 | kwargs = f""", {", ".join(bag)}""" 50 | else: 51 | kwargs = ", ".join(bag) 52 | s = f"{self.code_identifier()} = {self._code_class_name()}({pos_args}{kwargs})" 53 | if hasattr(self, "master_add_method"): 54 | method = self.master_add_method 55 | s = f"{self.code_identifier()} = {master}.{method}({pos_args}{kwargs})" 56 | lines.append(s) 57 | return lines 58 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tkmt/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/plugins/tkmt/designer/__init__.py -------------------------------------------------------------------------------- /src/pygubu/plugins/tksheet/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import BuilderLoaderPlugin 4 | 5 | 6 | _designer_tab_label = _("tksheet") 7 | _plugin_uid = "tksheet" 8 | 9 | 10 | class TksheetLoader(BuilderLoaderPlugin): 11 | _module = "pygubu.plugins.tksheet.sheet" 12 | 13 | def do_activate(self) -> bool: 14 | spec = importlib.util.find_spec("tksheet") 15 | return spec is not None 16 | 17 | def get_module_for(self, identifier: str) -> str: 18 | return self._module 19 | 20 | def get_all_modules(self): 21 | return (self._module,) 22 | 23 | def can_load(self, identifier: str) -> bool: 24 | return identifier.startswith("tksheet.") 25 | -------------------------------------------------------------------------------- /src/pygubu/plugins/tksheet/sheet.py: -------------------------------------------------------------------------------- 1 | from pygubu.i18n import _ 2 | from pygubu.api.v1 import ( 3 | BuilderObject, 4 | register_widget, 5 | ) 6 | from tksheet import Sheet 7 | from ..tksheet import _designer_tab_label, _plugin_uid 8 | 9 | 10 | class SheetBuilder(BuilderObject): 11 | class_ = Sheet 12 | 13 | 14 | _builder_uid = f"{_plugin_uid}.Sheet" 15 | register_widget( 16 | _builder_uid, SheetBuilder, "Sheet", ("ttk", _designer_tab_label) 17 | ) 18 | -------------------------------------------------------------------------------- /src/pygubu/plugins/ttk/__init__.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import BuilderLoaderPlugin 2 | 3 | 4 | class StandardTTKWidgetsLoader(BuilderLoaderPlugin): 5 | _module = "pygubu.plugins.ttk.ttkstdwidgets" 6 | 7 | def do_activate(self) -> bool: 8 | return True 9 | 10 | def get_module_for(self, identifier: str) -> str: 11 | return self._module 12 | 13 | def get_all_modules(self): 14 | return (self._module,) 15 | 16 | def can_load(self, identifier: str) -> bool: 17 | return identifier.startswith("ttk.") 18 | -------------------------------------------------------------------------------- /src/pygubu/plugins/ttkwidgets/calendar.py: -------------------------------------------------------------------------------- 1 | from pygubu.i18n import _ 2 | from pygubu.api.v1 import register_widget, register_custom_property 3 | from pygubu.plugins.ttk.ttkstdwidgets import TTKFrame 4 | from ttkwidgets import Calendar 5 | 6 | from ..ttkwidgets import _designer_tab_label, _plugin_uid 7 | 8 | 9 | class CalendarBO(TTKFrame): 10 | class_ = Calendar 11 | container = False 12 | OPTIONS_CUSTOM = ( 13 | "locale", 14 | "firstweekday", 15 | "year", 16 | "month", 17 | "selectbackground", 18 | "selectforeground", 19 | ) 20 | properties = ( 21 | TTKFrame.OPTIONS_STANDARD + TTKFrame.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 22 | ) 23 | # FIXME: set all custom properties as readonly, there is a bug in the 24 | # ttkwidgets widget definition. 25 | ro_properties = TTKFrame.ro_properties + OPTIONS_CUSTOM 26 | 27 | def _process_property_value(self, pname, value): 28 | if pname in ("firstweekday", "year", "month"): 29 | return int(value) 30 | return super()._process_property_value(pname, value) 31 | 32 | 33 | _builder_uid = f"{_plugin_uid}.Calendar" 34 | register_widget( 35 | _builder_uid, CalendarBO, "Calendar", ("ttk", _designer_tab_label), group=2 36 | ) 37 | 38 | register_custom_property( 39 | _builder_uid, 40 | "locale", 41 | "entry", 42 | help=_("calendar locale (defines the language, date formatting)"), 43 | ) 44 | register_custom_property( 45 | _builder_uid, 46 | "firstweekday", 47 | "choice", 48 | values=("", 0, 1, 2, 3, 4, 5, 6), 49 | state="readonly", 50 | help=_("first day of the week, 0 is monday"), 51 | ) 52 | register_custom_property( 53 | _builder_uid, "year", "integernumber", help=_("year to display") 54 | ) 55 | register_custom_property( 56 | _builder_uid, 57 | "month", 58 | "choice", 59 | values=("", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 60 | state="readonly", 61 | help=_("month to display"), 62 | ) 63 | register_custom_property( 64 | _builder_uid, 65 | "selectbackground", 66 | "colorentry", 67 | help=_("background color of the selected day"), 68 | ) 69 | register_custom_property( 70 | _builder_uid, 71 | "selectforeground", 72 | "colorentry", 73 | help=_("selectforeground color of the selected day"), 74 | ) 75 | -------------------------------------------------------------------------------- /src/pygubu/plugins/ttkwidgets/checkboxtreeview.py: -------------------------------------------------------------------------------- 1 | from pygubu.api.v1 import register_widget 2 | from pygubu.plugins.ttk.ttkstdwidgets import TTKTreeviewBO, TTKTreeviewColumnBO 3 | from pygubu.plugins.pygubu.scrollbarhelper_bo import TTKSBHelperBO 4 | from ttkwidgets.checkboxtreeview import CheckboxTreeview 5 | 6 | from ..ttkwidgets import _designer_tab_label, _plugin_uid 7 | 8 | 9 | class CheckboxTreeviewBO(TTKTreeviewBO): 10 | class_ = CheckboxTreeview 11 | allowed_children = ("ttk.Treeview.Column",) 12 | 13 | 14 | _builder_uid = f"{_plugin_uid}.CheckboxTreeview" 15 | register_widget( 16 | _builder_uid, 17 | CheckboxTreeviewBO, 18 | "CheckboxTreeview", 19 | ("ttk", _designer_tab_label), 20 | ) 21 | 22 | TTKSBHelperBO.add_allowed_child(_builder_uid) 23 | TTKTreeviewColumnBO.add_allowed_parent(_builder_uid) 24 | -------------------------------------------------------------------------------- /src/pygubu/plugins/ttkwidgets/linklabel.py: -------------------------------------------------------------------------------- 1 | from pygubu.i18n import _ 2 | from pygubu.api.v1 import register_widget, register_custom_property 3 | from pygubu.plugins.ttk.ttkstdwidgets import TTKLabel 4 | from ttkwidgets import LinkLabel 5 | 6 | from ..ttkwidgets import _designer_tab_label, _plugin_uid 7 | 8 | 9 | class LinkLabelBO(TTKLabel): 10 | class_ = LinkLabel 11 | OPTIONS_CUSTOM = ("link", "normal_color", "hover_color", "clicked_color") 12 | properties = ( 13 | TTKLabel.OPTIONS_STANDARD + TTKLabel.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 14 | ) 15 | 16 | 17 | _builder_uid = f"{_plugin_uid}.LinkLabel" 18 | register_widget( 19 | _builder_uid, 20 | LinkLabelBO, 21 | "LinkLabel", 22 | ("ttk", _designer_tab_label), 23 | group=1, 24 | ) 25 | 26 | register_custom_property( 27 | _builder_uid, "link", "entry", help=_("link to be opened") 28 | ) 29 | register_custom_property( 30 | _builder_uid, 31 | "normal_color", 32 | "colorentry", 33 | help=_("text color when widget is created"), 34 | ) 35 | register_custom_property( 36 | _builder_uid, 37 | "hover_color", 38 | "colorentry", 39 | help=_("text color when hovering over the widget"), 40 | ) 41 | register_custom_property( 42 | _builder_uid, 43 | "clicked_color", 44 | "colorentry", 45 | help=_("text color when link is clicked"), 46 | ) 47 | -------------------------------------------------------------------------------- /src/pygubu/plugins/ttkwidgets/scrolledlistbox.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from pygubu.i18n import _ 3 | from pygubu.api.v1 import register_widget, register_custom_property 4 | from pygubu.plugins.tk.tkstdwidgets import TKListbox 5 | from ttkwidgets.scrolledlistbox import ScrolledListbox 6 | 7 | from ..ttkwidgets import _designer_tab_label, _plugin_uid 8 | 9 | 10 | class ScrolledListboxBO(TKListbox): 11 | class_ = ScrolledListbox 12 | container = False 13 | OPTIONS_CUSTOM = ("compound", "autohidescrollbar") 14 | properties = ( 15 | TKListbox.OPTIONS_STANDARD + TKListbox.OPTIONS_SPECIFIC + OPTIONS_CUSTOM 16 | ) 17 | ro_properties = TKListbox.ro_properties + OPTIONS_CUSTOM 18 | 19 | def configure(self, target=None): 20 | super(ScrolledListboxBO, self).configure(self.widget.listbox) 21 | 22 | def _process_property_value(self, pname, value): 23 | final_value = value 24 | if pname in ("autohidescrollbar",): 25 | final_value = tk.getboolean(value) 26 | elif pname == "compound": 27 | final_value = tk.RIGHT 28 | values = {"left": tk.LEFT, "right": tk.RIGHT} 29 | if value in values: 30 | final_value = values[value] 31 | else: 32 | final_value = super( 33 | ScrolledListboxBO, self 34 | )._process_property_value(pname, value) 35 | return final_value 36 | 37 | def code_configure(self, targetid=None): 38 | if targetid is None: 39 | targetid = self.code_identifier() 40 | newtarget = f"{targetid}.listbox" 41 | return super(ScrolledListboxBO, self).code_configure(newtarget) 42 | 43 | 44 | _builder_uid = f"{_plugin_uid}.ScrolledListbox" 45 | register_widget( 46 | _builder_uid, 47 | ScrolledListboxBO, 48 | "ScrolledListbox", 49 | ("ttk", _designer_tab_label), 50 | group=3, 51 | ) 52 | 53 | register_custom_property( 54 | _builder_uid, 55 | "compound", 56 | "choice", 57 | default_value=tk.RIGHT, 58 | help="side for the Scrollbar to be on", 59 | values=("", tk.LEFT, tk.RIGHT), 60 | state="readonly", 61 | ) 62 | register_custom_property( 63 | _builder_uid, 64 | "autohidescrollbar", 65 | "choice", 66 | values=("", "true", "false"), 67 | state="readonly", 68 | ) 69 | -------------------------------------------------------------------------------- /src/pygubu/stockimage/__init__.py: -------------------------------------------------------------------------------- 1 | from .registry import StockRegistry 2 | from .loader import StockImageCache 3 | from .exceptions import StockImageException 4 | from .config import TK_BITMAP_FORMATS, TK_IMAGE_FORMATS, TK_PHOTO_FORMATS 5 | 6 | DefaultRegistry = StockRegistry() 7 | 8 | StockImage = StockImageCache(None, DefaultRegistry) 9 | -------------------------------------------------------------------------------- /src/pygubu/stockimage/exceptions.py: -------------------------------------------------------------------------------- 1 | class StockImageException(Exception): 2 | pass 3 | 4 | 5 | class ImageNotFoundError(StockImageException): 6 | pass 7 | 8 | 9 | class ImageFormatNotSupportedError(StockImageException): 10 | pass 11 | -------------------------------------------------------------------------------- /src/pygubu/theming/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/theming/__init__.py -------------------------------------------------------------------------------- /src/pygubu/theming/base.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.ttk as ttk 3 | from abc import ABC, ABCMeta, abstractmethod 4 | 5 | 6 | class IThemeBuilder(ABC): 7 | @abstractmethod 8 | def theme_name(self) -> str: 9 | ... 10 | 11 | @abstractmethod 12 | def theme_parent(self) -> str: 13 | ... 14 | 15 | @abstractmethod 16 | def theme_settings(self): 17 | ... 18 | 19 | @abstractmethod 20 | def db_settings(self): 21 | ... 22 | 23 | @abstractmethod 24 | def tk_palette(self): 25 | ... 26 | 27 | def create(self, master): 28 | style = ttk.Style(master) 29 | name = self.theme_name() 30 | parent = self.theme_parent() 31 | if name not in style.theme_names(): 32 | theme_settings = self.theme_settings() 33 | style.theme_create(name, parent, theme_settings) 34 | else: 35 | raise ValueError("Theme name already exists.") 36 | 37 | def apply(self, master: tk.Widget): 38 | # master.option_clear() 39 | 40 | palette = self.tk_palette() 41 | if palette: 42 | master.tk_setPalette(**palette) 43 | 44 | db_settings = self.db_settings() 45 | for pattern, options in db_settings.items(): 46 | for option, value in options.items(): 47 | fpattern = f"{pattern}{option}" 48 | master.option_add(fpattern, value, "widgetDefault") 49 | style = ttk.Style(master) 50 | style.theme_use(self.theme_name()) 51 | -------------------------------------------------------------------------------- /src/pygubu/theming/bootstrap/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/theming/bootstrap/__init__.py -------------------------------------------------------------------------------- /src/pygubu/theming/bootstrap/config.py: -------------------------------------------------------------------------------- 1 | # Fix background of file selector dialog on linux 2 | 3 | FIX_LINUX_FILE_DIALOG = True 4 | 5 | 6 | # Constants 7 | 8 | TTK_CLAM = "clam" 9 | TTK_ALT = "alt" 10 | TTK_DEFAULT = "default" 11 | 12 | PRIMARY = "primary" 13 | SECONDARY = "secondary" 14 | SUCCESS = "success" 15 | INFO = "info" 16 | WARNING = "warning" 17 | DANGER = "danger" 18 | LIGHT = "light" 19 | DARK = "dark" 20 | -------------------------------------------------------------------------------- /src/pygubu/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/utils/__init__.py -------------------------------------------------------------------------------- /src/pygubu/utils/datatrans.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class ListDTO: 5 | def __init__(self, default_value=None, on_error_default=None): 6 | self.default_value = default_value 7 | self.on_error_default = ( 8 | ["Invalid data"] if on_error_default is None else on_error_default 9 | ) 10 | 11 | def transform(self, value: str, default=None): 12 | val = self.default_value if default is None else default 13 | try: 14 | json_list = json.loads(value) 15 | if isinstance(json_list, list): 16 | val = json_list 17 | else: 18 | val = self.on_error_default 19 | except json.JSONDecodeError: 20 | val = self.on_error_default 21 | return val 22 | -------------------------------------------------------------------------------- /src/pygubu/utils/font.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import re 3 | 4 | RE_FONT = re.compile( 5 | "(?P\\{\\w+(\\w|\\s)*\\}|\\w+)\\s?(?P-?\\d+)?\\s?(?P\\{\\w+(\\w|\\s)*\\}|\\w+)?" 6 | ) 7 | 8 | 9 | def tkfontstr_to_dict(fontstr): 10 | """Parse a string with a tk font format like '{Helvetica} 12 {bold}' 11 | and return a dict with keys family, size and modifiers.""" 12 | 13 | font_dict = { 14 | "family": None, 15 | "size": None, 16 | "modifiers": None, 17 | } 18 | s = RE_FONT.search(fontstr) 19 | if s: 20 | g = s.groupdict() 21 | font_dict["family"] = g["family"].replace("{", "").replace("}", "") 22 | font_dict["size"] = g["size"] 23 | modifiers = g["modifiers"] 24 | if modifiers is not None: 25 | modifiers = modifiers.replace("{", "").replace("}", "") 26 | font_dict["modifiers"] = modifiers 27 | else: 28 | font_dict["family"] = fontstr 29 | return font_dict 30 | 31 | 32 | def tkfontstr_to_tuple(fontstr, default_size=12): 33 | """Convert string with a tk font format like '{Helvetica} 12 {bold}' 34 | to a python tuple ('Helvetica', 12, 'bold').""" 35 | 36 | fdict = tkfontstr_to_dict(fontstr) 37 | font_desc = [ 38 | fdict["family"], 39 | ] 40 | # Add default size 41 | size = fdict["size"] 42 | size = size if size is not None else default_size 43 | font_desc.append(size) 44 | 45 | key = "modifiers" 46 | if fdict[key] is not None: 47 | font_desc.append(fdict[key]) 48 | 49 | return tuple(font_desc) 50 | -------------------------------------------------------------------------------- /src/pygubu/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/widgets/__init__.py -------------------------------------------------------------------------------- /src/pygubu/widgets/colorinputui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | 5 | 6 | # 7 | # Base class definition 8 | # 9 | class ColorInputUI(ttk.Frame): 10 | def __init__(self, master=None, **kw): 11 | super().__init__(master, **kw) 12 | self._frame = tk.Frame(self, name="_frame") 13 | self._frame.configure(borderwidth=0, height=10, relief="flat", width=24) 14 | self._frame.pack(fill="y", side="left") 15 | self._entry = ttk.Entry(self, name="_entry") 16 | self._entry.configure(validate="all") 17 | self._entry.pack(expand=True, fill="both", padx=2, side="left") 18 | self._entry.bind("", self.on_focusout, add="") 19 | self._entry.bind("", self.on_keypress, add="") 20 | self._button = ttk.Button(self, name="_button") 21 | self._button.configure( 22 | compound="center", 23 | style="Toolbutton", 24 | takefocus=True, 25 | text="…", 26 | width=-2, 27 | ) 28 | self._button.pack(fill="both", side="left") 29 | self._button.configure(command=self.on_picker_clicked) 30 | self.configure(height=25, width=100) 31 | # self.pack(side="top") 32 | 33 | def on_focusout(self, event=None): 34 | pass 35 | 36 | def on_keypress(self, event=None): 37 | pass 38 | 39 | def on_picker_clicked(self): 40 | pass 41 | 42 | 43 | if __name__ == "__main__": 44 | root = tk.Tk() 45 | widget = ColorInputUI(root) 46 | widget.pack(expand=True, fill="both") 47 | root.mainloop() 48 | -------------------------------------------------------------------------------- /src/pygubu/widgets/dockfw/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/src/pygubu/widgets/dockfw/__init__.py -------------------------------------------------------------------------------- /src/pygubu/widgets/dockfw/widgets.py: -------------------------------------------------------------------------------- 1 | from .dockwidget import DockPane, DockWidget 2 | from .dockframe import DockFrame 3 | -------------------------------------------------------------------------------- /src/pygubu/widgets/hideableframe.py: -------------------------------------------------------------------------------- 1 | import tkinter.ttk as ttk 2 | 3 | from pygubu.utils.widget import HideableMixin 4 | 5 | 6 | class HideableFrame(HideableMixin, ttk.Frame): 7 | """A frame that can be easily hidden. 8 | Use hidden property to show or hide the frame. 9 | 10 | myframe.hidden = True 11 | """ 12 | 13 | def __init__(self, *args, **kw): 14 | super().__init__(*args, **kw) 15 | -------------------------------------------------------------------------------- /src/pygubu/widgets/scrollbarhelper.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | 5 | from pygubu.widgets.tkscrollbarhelper import ScrollbarHelperBase 6 | 7 | 8 | class TTKScrollbarHelperFactory(type): 9 | def __new__(cls, clsname, superclasses, attrs): 10 | return type.__new__(cls, str(clsname), superclasses, attrs) 11 | 12 | 13 | ScrollbarHelper = TTKScrollbarHelperFactory( 14 | "ScrollbarHelper", 15 | (ScrollbarHelperBase, ttk.Frame, object), 16 | {"_framecls": ttk.Frame, "_sbarcls": ttk.Scrollbar}, 17 | ) 18 | -------------------------------------------------------------------------------- /src/pygubu/widgets/scrolledframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | 5 | from pygubu.binding import ( 6 | ApplicationLevelBindManager as BindManager, 7 | remove_binding, 8 | ) 9 | from .tkscrolledframe import ScrolledFrameBase 10 | 11 | 12 | class ScrolledFrame(ScrolledFrameBase, ttk.Frame): 13 | _framecls = ttk.Frame 14 | _sbarcls = ttk.Scrollbar 15 | -------------------------------------------------------------------------------- /src/pygubu/widgets/ttkspinbox.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import tkinter.ttk as ttk 3 | 4 | 5 | class Spinbox(ttk.Entry): 6 | def __init__(self, master=None, **kw): 7 | ttk.Entry.__init__(self, master, "ttk::spinbox", **kw) 8 | 9 | def current(self, newindex=None): 10 | return self.tk.call(self._w, "current", newindex) 11 | 12 | def set(self, value): 13 | return self.tk.call(self._w, "set", value) 14 | -------------------------------------------------------------------------------- /tests/fixpath.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import pathlib 4 | import importlib 5 | 6 | test_dir = pathlib.Path(sys.argv[0]).parent.resolve() 7 | pygubu_src = str(test_dir.parent / "src") 8 | 9 | if pygubu_src not in sys.path: 10 | sys.path.insert(0, pygubu_src) 11 | -------------------------------------------------------------------------------- /tests/images/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alejandroautalan/pygubu/ebfb979e15ce496cdf6c0ccd2bc87c71b362e8b8/tests/images/example.gif -------------------------------------------------------------------------------- /tests/test_accordionframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.accordionframe import AccordionFrame 12 | 13 | 14 | class TestAccordionFrame(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_accordionframe.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.canvas = builder.get_object("accordionframe1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.canvas, AccordionFrame) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_accordionframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 200 19 | 200 20 | 21 | top 22 | 23 | 24 | 25 | Group1 26 | Toolbutton 27 | 28 | 29 | #0051d9 30 | 31 | top 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Group2 40 | Toolbutton 41 | 42 | 43 | #00bb00 44 | 45 | top 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /tests/test_autoarrangeframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/test_builder_forget_unnamed.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import support 10 | import pygubu 11 | 12 | 13 | class TestBuilder01(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_builder_forget_unnamed.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("fmain") 20 | builder.connect_callbacks({}) 21 | builder.forget_unnamed() 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_builder_forget_unnamed(self): 27 | expected = ["fmain", "mylabel1", "mylabel2"] 28 | result = list(self.builder.objects.keys()) 29 | self.assertEqual(expected, result) 30 | self.widget.destroy() 31 | -------------------------------------------------------------------------------- /tests/test_builder_forget_unnamed.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | 0 9 | 10 | 11 | 12 | Test builder forget unnamed 13 | 14 | top 15 | 16 | 17 | 18 | 19 | 20 | mylabel1 21 | 22 | top 23 | 24 | 25 | 26 | 27 | 28 | mylabel2 29 | 30 | top 31 | 32 | 33 | 34 | 35 | 36 | unnamed label 37 | 38 | top 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /tests/test_builderfont.py: -------------------------------------------------------------------------------- 1 | # encoding: utf8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | import tkinter.font as tkfont 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestBuilderFont(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_builderfont.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | 21 | self.font = font = tkfont.Font( 22 | family="Helvetica", size=32, weight="bold" 23 | ) 24 | builder.set_font("custom_font", font) 25 | 26 | self.widget = builder.get_object("mainwindow") 27 | 28 | def tearDown(self): 29 | support.root_withdraw() 30 | 31 | @unittest.skip("Not implemented yet") 32 | def test_get_font(self): 33 | font = self.builder.get_font("custom_font") 34 | self.assertEqual(self.font, font) 35 | self.widget.destroy() 36 | 37 | @unittest.skip("Not implemented yet") 38 | def test_get_font_notset(self): 39 | fname = "other_font" 40 | font = self.builder.get_font(fname) 41 | self.assertEqual(fname, font) 42 | self.widget.destroy() 43 | 44 | 45 | if __name__ == "__main__": 46 | unittest.main() 47 | -------------------------------------------------------------------------------- /tests/test_builderfont.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 8 | 200 9 | 200 10 | 11 | 0 12 | True 13 | 0 14 | 15 | 16 | 17 | {custom_font} 12 {} 18 | Font Test 19 | 20 | 0 21 | True 22 | 0 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/test_button_command.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestButtonCommand(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_button_command.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainwindow") 20 | self.button1 = builder.get_object("button1") 21 | self.button2 = builder.get_object("button2") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_command_simple(self): 27 | success = [] 28 | 29 | class AnObject: 30 | def button1_clicked(self): 31 | success.append(1) 32 | 33 | def on_button_clicked(self): 34 | pass 35 | 36 | cbobj = AnObject() 37 | self.builder.connect_callbacks(cbobj) 38 | self.button1.invoke() 39 | self.widget.update() 40 | 41 | self.assertTrue(success) 42 | self.widget.destroy() 43 | 44 | def test_command_with_widgetid(self): 45 | success = [] 46 | received_id = [] 47 | 48 | class AnObject: 49 | def button1_clicked(self): 50 | pass 51 | 52 | def on_button_clicked(self, widgetid): 53 | success.append(1) 54 | received_id.append(widgetid) 55 | 56 | cbobj = AnObject() 57 | self.builder.connect_callbacks(cbobj) 58 | self.button2.invoke() 59 | self.widget.update() 60 | 61 | self.assertTrue(success) 62 | self.assertEqual(received_id[0], "button2") 63 | self.widget.destroy() 64 | 65 | # def test_command_generate_event(self): 66 | # success = [] 67 | 68 | # class AnObject: 69 | # def button1_clicked(self): 70 | # pass 71 | # def on_button_clicked(self): 72 | # pass 73 | # def catch_button_event(self, event): 74 | # success.append(1) 75 | 76 | # cbobj = AnObject() 77 | # self.button3.bind('<>', cbobj.catch_button_event) 78 | # self.builder.connect_callbacks(cbobj) 79 | # self.button3.invoke() 80 | # self.widget.update() 81 | 82 | # self.assertTrue(success) 83 | # self.widget.destroy() 84 | -------------------------------------------------------------------------------- /tests/test_button_command.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | button1_clicked 14 | button1 15 | 16 | True 17 | top 18 | 19 | 20 | 21 | 22 | 23 | on_button_clicked 24 | button2 25 | 26 | True 27 | top 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/test_calendarframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | #f0e3f0 14 | #0000a1 15 | 6 16 | #abb8f0 17 | #ffffff 18 | #f06ba4 19 | #ffffff 20 | 9 21 | #d926ff 22 | #ffff00 23 | 2000 24 | 25 | 26 | 0 27 | True 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/test_canvas.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestCanvas(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_canvas.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainframe") 20 | self.canvas = builder.get_object("Canvas_1") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_class(self): 26 | self.assertIsInstance(self.canvas, tk.Canvas) 27 | self.widget.destroy() 28 | -------------------------------------------------------------------------------- /tests/test_canvas.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 2 6 | 200 7 | 8 | 0 9 | True 10 | 0 11 | nesw 12 | 13 | 14 | 1 15 | 16 | 17 | 18 | 19 | 1 20 | 21 | 22 | 23 | 24 | 25 | #ffffff 26 | 0 27 | 28 | 0 29 | True 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/test_colorinput.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.colorinput import ColorInput 12 | 13 | 14 | class TestColorInput(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_colorinput.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wcolor = builder.get_object("colorinput1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wcolor, ColorInput) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_colorinput.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 19 | top 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/test_command_id_arg.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestCommandIdArg(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_command_id_arg.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainwindow") 20 | self.menu = builder.get_object("menu1") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_idtocommand(self): 26 | success = [] 27 | received_id = [] 28 | 29 | class AnObject: 30 | def menu_item_clicked(self, itemid): 31 | success.append(1) 32 | received_id.append(itemid) 33 | 34 | cbobj = AnObject() 35 | self.builder.connect_callbacks(cbobj) 36 | self.menu.invoke(0) 37 | self.widget.update() 38 | 39 | self.assertTrue(success) 40 | self.assertEqual(received_id[0], "menu_item_1") 41 | self.widget.destroy() 42 | -------------------------------------------------------------------------------- /tests/test_command_id_arg.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | True 8 | 9 | 10 | 11 | menubutton_1 12 | 13 | True 14 | top 15 | 16 | 17 | 18 | false 19 | 20 | 21 | menu_item_clicked 22 | true 23 | command1 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/test_custom_widget.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestCustomWidget(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_custom_widget.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainwindow") 20 | self.custom_widget = builder.get_object("custom_widget") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_loading(self): 26 | message = self.custom_widget.get_message() 27 | self.assertEqual(message, "CustomLabel") 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_custom_widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | 0 9 | 10 | 11 | 12 | 13 | top 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/test_custom_widget_module.py: -------------------------------------------------------------------------------- 1 | import tkinter.ttk as ttk 2 | from pygubu.api.v1 import BuilderObject, register_widget 3 | 4 | 5 | class CustomLabel(ttk.Label): 6 | def get_message(self): 7 | return "CustomLabel" 8 | 9 | 10 | class TestCustomWidgetBuilder(BuilderObject): 11 | class_ = CustomLabel 12 | 13 | 14 | register_widget( 15 | "test_custom_widget_module.custom_label", 16 | TestCustomWidgetBuilder, 17 | "CustomWidget", 18 | ("ttk", "Test Custom Widget"), 19 | ) 20 | -------------------------------------------------------------------------------- /tests/test_dialog.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestDialog(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_dialog.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mydialog") 20 | self.dialog = self.widget 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_class(self): 26 | self.assertIsInstance(self.dialog, pygubu.widgets.dialog.Dialog) 27 | self.widget.destroy() 28 | -------------------------------------------------------------------------------- /tests/test_editabletreeview.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.editabletreeview import EditableTreeview 12 | 13 | 14 | class TestEditableTreeview(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_editabletreeview.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wtree = builder.get_object("treeview1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wtree, EditableTreeview) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_editabletreeview.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 19 | top 20 | 21 | 22 | 23 | w 24 | w 25 | 20 26 | true 27 | Tree column 28 | true 29 | true 30 | 200 31 | 32 | 33 | 34 | 35 | w 36 | w 37 | 20 38 | true 39 | Column1 40 | false 41 | true 42 | 200 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/test_entry_commands.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 250 5 | 250 6 | 7 | 8 | 9 | entry_invalid 10 | center 11 | MyEntryStyle.TEntry 12 | Hello 13 | entry_var 14 | key 15 | entry_validate 16 | 17 | 0 18 | True 19 | 0 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/test_filterabletreeview.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.filterabletreeview import FilterableTreeview 12 | 13 | 14 | class TestFilterableTreeview(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_filterabletreeview.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wtree = builder.get_object("treeview1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wtree, FilterableTreeview) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_filterabletreeview.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 19 | top 20 | 21 | 22 | 23 | w 24 | w 25 | 20 26 | true 27 | Tree column 28 | true 29 | true 30 | 200 31 | 32 | 33 | 34 | 35 | w 36 | w 37 | 20 38 | true 39 | Column1 40 | false 41 | true 42 | 200 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/test_floodgauge.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.floodgauge import Floodgauge 12 | 13 | 14 | class TestFloodgauge(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_floodgauge.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wfgauge = builder.get_object("floodgauge1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wfgauge, Floodgauge) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_floodgauge.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | horizontal 19 | floodgauge1 20 | 15 21 | 22 | top 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/test_fontinput.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.fontinput import FontInput 12 | 13 | 14 | class TestFontInput(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_fontinput.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wfinput = builder.get_object("fontinput1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wfinput, FontInput) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_fontinput.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 19 | top 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/test_frame.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 250 5 | 10 6 | 250 7 | MyCustomFrame 8 | sunken 9 | MyFrameStyle.TFrame 10 | 1 11 | cross 12 | 13 | 14 | 15 | 0 16 | 0 17 | nesw 18 | 10 19 | 5 20 | False 21 | 4 22 | 2 23 | 1 24 | 2 25 | 26 | 27 | 28 | label 29 | 30 | 0 31 | True 32 | 1 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/test_hideableframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | from pygubu.widgets.hideableframe import HideableFrame 12 | 13 | 14 | class TestHideableFrame(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_hideableframe.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.wframe = builder.get_object("hideableframe1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.wframe, HideableFrame) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_hideableframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 200 9 | 2 10 | 200 11 | 12 | 0 13 | 0 14 | nesw 15 | 16 | 17 | 18 | 200 19 | 200 20 | 21 | top 22 | 23 | 24 | false 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/test_idtocommand.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestIdtocommand(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_idtocommand.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainwindow") 20 | self.button = builder.get_object("button1") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_idtocommand(self): 26 | success = [] 27 | 28 | class AnObject: 29 | def on_button_clicked(self, widgetid): 30 | success.append(1) 31 | 32 | cbobj = AnObject() 33 | self.builder.connect_callbacks(cbobj) 34 | self.button.invoke() 35 | self.widget.update() 36 | 37 | self.assertTrue(success) 38 | self.widget.destroy() 39 | -------------------------------------------------------------------------------- /tests/test_idtocommand.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | True 8 | 9 | 10 | 11 | on_button_clicked 12 | true 13 | button1 14 | 15 | True 16 | top 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/test_import_variables.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class MyContainer(object): 14 | pass 15 | 16 | 17 | class TestText(unittest.TestCase): 18 | def setUp(self): 19 | support.root_deiconify() 20 | xmldata = "test_import_variables.ui" 21 | self.builder = builder = pygubu.Builder() 22 | builder.add_from_file(xmldata) 23 | self.widget = builder.get_object("mainwindow") 24 | 25 | def tearDown(self): 26 | support.root_withdraw() 27 | 28 | def test_import_variables(self): 29 | container = MyContainer() 30 | self.builder.import_variables(container) 31 | self.assertIsInstance(container.myvar_string, tk.StringVar) 32 | self.assertIsInstance(container.myvar_int, tk.IntVar) 33 | self.assertIsInstance(container.myvar_double, tk.DoubleVar) 34 | self.assertIsInstance(container.myvar_boolean, tk.BooleanVar) 35 | -------------------------------------------------------------------------------- /tests/test_import_variables.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | string:myvar_string 14 | 15 | 0 16 | True 17 | 0 18 | 19 | 20 | 21 | 22 | 23 | int:myvar_int 24 | 25 | 0 26 | True 27 | 1 28 | 29 | 30 | 31 | 32 | 33 | double:myvar_double 34 | 35 | 0 36 | True 37 | 2 38 | 39 | 40 | 41 | 42 | 43 | boolean:myvar_boolean 44 | 45 | 0 46 | True 47 | 3 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /tests/test_labelframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestLabelframe(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_labelframe.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("Labelframe") 20 | 21 | def tearDown(self): 22 | support.root_withdraw() 23 | 24 | def test_class(self): 25 | self.assertIsInstance(self.widget, ttk.Labelframe) 26 | self.widget.destroy() 27 | -------------------------------------------------------------------------------- /tests/test_labelframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | nesw 11 | 12 | 13 | 14 | 4 15 | 200 16 | groove 17 | ttk.Labelframe 18 | 200 19 | 20 | 0 21 | True 22 | 0 23 | nesw 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/test_menu.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestMenu(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_menu.ui" 17 | self.builder = builder = pygubu.Builder() 18 | filepath = os.path.dirname(os.path.realpath(__file__)) 19 | builder.add_resource_path(filepath) 20 | builder.add_from_file(xmldata) 21 | self.widget = builder.get_object("mainmenu") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.widget, tk.Menu) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_menu.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #d9cc93 5 | 2 6 | Helvetica 12 7 | #080060 8 | flat 9 | 10 | 11 | info 12 | left 13 | Submenu_1 14 | 15 | 16 | False 17 | Command_1 18 | 19 | 20 | 21 | 22 | False 23 | Checkbutton_1 24 | 25 | 26 | 27 | 28 | False 29 | Radiobutton_1 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | False 38 | example.gif 39 | Command_2 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/test_menu_commands.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #d9cc93 5 | 2 6 | Helvetica 12 7 | #080060 8 | flat 9 | false 10 | 11 | 12 | info 13 | left 14 | Submenu_1 15 | on_menu_post 16 | true 17 | on_menu_tearoff 18 | 19 | 20 | button1_cb 21 | Command_1 22 | 23 | 24 | 25 | 26 | chkbutton_cb 27 | Checkbutton_1 28 | 29 | 30 | 31 | 32 | Radiobutton_1 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | example.gif 41 | Command_2 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/test_notebook.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestNotebook(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_notebook.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("Notebook") 20 | 21 | def tearDown(self): 22 | support.root_withdraw() 23 | 24 | def test_class(self): 25 | self.assertIsInstance(self.widget, ttk.Notebook) 26 | self.widget.destroy() 27 | -------------------------------------------------------------------------------- /tests/test_notebook.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | nesw 11 | 12 | 13 | 14 | Tab_1 15 | 16 | 17 | #d9c6d9 18 | center 19 | Notebook test 20 | 21 | Tab 1 22 | 200 23 | 24 | 0 25 | True 26 | 0 27 | ew 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Tab_2 36 | 37 | 38 | #80d4d9 39 | center 40 | Notebook test 41 | 42 | Tab 2 43 | 200 44 | 45 | 0 46 | True 47 | 0 48 | ew 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/test_optionmenu.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestOptionMenu(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_optionmenu.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainwindow") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_class(self): 26 | optionmenu = self.builder.get_object("optionmenu1") 27 | self.assertIsInstance(optionmenu, tk.OptionMenu) 28 | self.widget.destroy() 29 | 30 | def test_no_variable_defined(self): 31 | optionmenu2 = self.builder.get_object("optionmenu2") 32 | self.assertIsInstance(optionmenu2, tk.OptionMenu) 33 | self.widget.destroy() 34 | -------------------------------------------------------------------------------- /tests/test_optionmenu.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | nesw 11 | 12 | 13 | 14 | om_command 15 | default 16 | option1,option2,option3 17 | string:om_var 18 | 19 | 0 20 | True 21 | 0 22 | 23 | 24 | 25 | 26 | 27 | om_command 28 | option1 29 | option1,option2,option3 30 | 31 | 0 32 | True 33 | 1 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /tests/test_panedwindow.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import pygubu 10 | import support 11 | 12 | 13 | class TestPanedwindow(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_panedwindow.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("mainframe") 20 | self.pw1 = builder.get_object("Panedwindow_1") 21 | self.pw2 = builder.get_object("Panedwindow_2") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.pw1, ttk.Panedwindow) 28 | self.assertIsInstance(self.pw2, ttk.Panedwindow) 29 | self.widget.destroy() 30 | -------------------------------------------------------------------------------- /tests/test_pathchooserinput.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | from pygubu.widgets.pathchooserinput import PathChooserInput 13 | 14 | 15 | class TestPathChooserInput(unittest.TestCase): 16 | def setUp(self): 17 | support.root_deiconify() 18 | xmldata = "test_pathchooserinput.ui" 19 | self.builder = builder = pygubu.Builder() 20 | builder.add_from_file(xmldata) 21 | self.mainwindow = builder.get_object("mainwindow") 22 | self.widget = builder.get_object("pathchooserinput1") 23 | 24 | def tearDown(self): 25 | support.root_withdraw() 26 | 27 | def test_class(self): 28 | self.assertIsInstance(self.widget, PathChooserInput) 29 | self.widget.destroy() 30 | 31 | def test_path_changed_event(self): 32 | success = [] 33 | 34 | def on_path_changed(event=None): 35 | success.append(1) 36 | 37 | bag = {"on_path_changed": on_path_changed} 38 | self.builder.connect_callbacks(bag) 39 | 40 | self.widget.configure(path="/new/path") 41 | self.assertTrue(success) 42 | self.widget.destroy() 43 | 44 | def test_type(self): 45 | itype = str(self.widget.cget("type")) 46 | self.assertEqual("file", itype) 47 | self.widget.destroy() 48 | 49 | def test_path(self): 50 | path = str(self.widget.cget("path")) 51 | self.assertEqual("/home/user", path) 52 | self.widget.destroy() 53 | 54 | def test_path_dictionary_like(self): 55 | path = str(self.widget["path"]) 56 | self.assertEqual("/home/user", path) 57 | self.widget.destroy() 58 | 59 | def test_state(self): 60 | # allowed states normal/disabled/readonly 61 | 62 | # normal 63 | state = str(self.widget.cget("state")) 64 | self.assertEqual("normal", state) 65 | 66 | # disabled 67 | self.widget.config(state="disabled") 68 | state = str(self.widget.cget("state")) 69 | self.assertEqual("disabled", state) 70 | 71 | # readonly 72 | self.widget.config(state="readonly") 73 | state = str(self.widget.cget("state")) 74 | self.assertEqual("readonly", state) 75 | 76 | self.widget.destroy() 77 | -------------------------------------------------------------------------------- /tests/test_pathchooserinput.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | /home/user 14 | file 15 | 16 | 17 | 0 18 | True 19 | 0 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/test_plugin_tkcalendar.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | from unittest.case import SkipTest 13 | 14 | has_tkcalendar = True 15 | try: 16 | from tkcalendar import Calendar, DateEntry 17 | except ImportError: 18 | has_tkcalendar = False 19 | 20 | 21 | class TestTkcalendarCalendar(unittest.TestCase): 22 | def setUp(self): 23 | if not has_tkcalendar: 24 | raise SkipTest("tkcalendar not installed") 25 | 26 | support.root_deiconify() 27 | xmldata = "test_plugin_tkcalendar.ui" 28 | self.builder = builder = pygubu.Builder() 29 | builder.add_from_file(xmldata) 30 | self.widget = builder.get_object("frame1") 31 | self.calendar = builder.get_object("calendar") 32 | 33 | def tearDown(self): 34 | support.root_withdraw() 35 | 36 | def test_class(self): 37 | self.assertIsInstance(self.calendar, Calendar) 38 | self.widget.destroy() 39 | 40 | 41 | class TestTkcalendarDateEntry(unittest.TestCase): 42 | def setUp(self): 43 | if not has_tkcalendar: 44 | raise SkipTest("tkcalendar not installed") 45 | 46 | support.root_deiconify() 47 | xmldata = "test_plugin_tkcalendar.ui" 48 | self.builder = builder = pygubu.Builder() 49 | builder.add_from_file(xmldata) 50 | self.widget = builder.get_object("frame2") 51 | self.entry = builder.get_object("dateentry") 52 | 53 | def tearDown(self): 54 | support.root_withdraw() 55 | 56 | def test_class(self): 57 | self.assertIsInstance(self.entry, DateEntry) 58 | self.widget.destroy() 59 | -------------------------------------------------------------------------------- /tests/test_plugin_tkcalendar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | 0 9 | 10 | 11 | 12 | 13 | 0 14 | 0 15 | 16 | 17 | 18 | 19 | 20 | 200 21 | 200 22 | 23 | 0 24 | 0 25 | 26 | 27 | 28 | 29 | 0 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/test_scrolledframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | from pygubu.widgets.scrolledframe import ScrolledFrame 13 | 14 | 15 | class TestTtkScrolledframe(unittest.TestCase): 16 | def setUp(self): 17 | support.root_deiconify() 18 | xmldata = "test_scrolledframe.ui" 19 | self.builder = builder = pygubu.Builder() 20 | builder.add_from_file(xmldata) 21 | self.widget = builder.get_object("scrolledframe") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.widget, ScrolledFrame) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_scrolledframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | both 5 | true 6 | 7 | True 8 | 9 | 10 | 11 | 12 | True 13 | top 14 | 15 | 16 | 17 | 18 | 19 | 20 | True 21 | top 22 | 23 | 24 | 25 | 26 | 27 | 28 | True 29 | top 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/test_text.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestText(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_text.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainframe") 21 | self.text = builder.get_object("Text_1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.text, tk.Text) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_text.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 2 6 | 200 7 | 8 | 0 9 | True 10 | 0 11 | nesw 12 | 13 | 14 | 1 15 | 16 | 17 | 18 | 19 | 1 20 | 21 | 22 | 23 | 24 | 25 | #00004e 26 | Verdana 8 27 | #ffffff 28 | 10 29 | #ffffe3 30 | 3 31 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet metus ante, eget vehicula arcu malesuada ut. In aliquam pulvinar metus. Maecenas semper erat orci, id porta metus ullamcorper vel. Suspendisse potenti. Ut et aliquam est. Morbi tempor elementum metus vel hendrerit. Phasellus tincidunt vitae lacus non pulvinar. Aliquam faucibus nunc dui, non sagittis dolor elementum eget. Donec nec imperdiet neque, a congue leo. Proin non quam est. Aliquam vel dolor non arcu porttitor posuere eu a lorem. Nulla ut enim sed elit ultrices sagittis. 32 | 50 33 | char 34 | 35 | 0 36 | True 37 | 0 38 | nesw 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /tests/test_text_issue58.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | expected_text = """In the designer: 15 | - Add a text widget 16 | - Set state to disabled 17 | - Enter content in the text property 18 | - Text content should be set by pygubu-designer. 19 | """ 20 | 21 | 22 | class TestText(unittest.TestCase): 23 | def setUp(self): 24 | support.root_deiconify() 25 | xmldata = "test_text_issue58.ui" 26 | self.builder = builder = pygubu.Builder() 27 | builder.add_from_file(xmldata) 28 | self.widget = builder.get_object("mainframe") 29 | self.text = builder.get_object("Text_1") 30 | 31 | def tearDown(self): 32 | support.root_withdraw() 33 | 34 | def test_set_text_in_disabled_status(self): 35 | text_content = self.text.get("0.0", tk.END) 36 | self.assertEqual(text_content, expected_text) 37 | self.widget.destroy() 38 | -------------------------------------------------------------------------------- /tests/test_text_issue58.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | 10 14 | disabled 15 | In the designer: 16 | - Add a text widget 17 | - Set state to disabled 18 | - Enter content in the text property 19 | - Text content should be set by pygubu-designer. 20 | 50 21 | 22 | 0 23 | True 24 | 0 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/test_tkinterscrolledtext.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | from tkinter.scrolledtext import ScrolledText 8 | 9 | 10 | import fixpath 11 | import pygubu 12 | import support 13 | 14 | 15 | class TestText(unittest.TestCase): 16 | def setUp(self): 17 | support.root_deiconify() 18 | xmldata = "test_tkinterscrolledtext.ui" 19 | self.builder = builder = pygubu.Builder() 20 | builder.add_from_file(xmldata) 21 | self.widget = builder.get_object("mainframe") 22 | self.text = builder.get_object("scrolledtext_1") 23 | 24 | def tearDown(self): 25 | support.root_withdraw() 26 | 27 | def test_class(self): 28 | self.assertIsInstance(self.text, tk.Text) 29 | self.widget.destroy() 30 | -------------------------------------------------------------------------------- /tests/test_tkinterscrolledtext.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | True 8 | 9 | 10 | 11 | 200 12 | 200 13 | 14 | True 15 | top 16 | 17 | 18 | 19 | 10 20 | scrolledtext_1 21 | 22 | True 23 | top 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 200 32 | 200 33 | 34 | True 35 | top 36 | 37 | 38 | 39 | 10 40 | tkinterscrolledtext_1 41 | 42 | True 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/test_tkscrolledframe.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | from pygubu.widgets.tkscrolledframe import TkScrolledFrame 13 | 14 | 15 | class TestTtkScrolledframe(unittest.TestCase): 16 | def setUp(self): 17 | support.root_deiconify() 18 | xmldata = "test_tkscrolledframe.ui" 19 | self.builder = builder = pygubu.Builder() 20 | builder.add_from_file(xmldata) 21 | self.widget = builder.get_object("scrolledframe") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.widget, TkScrolledFrame) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_tkscrolledframe.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | both 5 | true 6 | 7 | True 8 | 9 | 10 | 11 | 12 | True 13 | top 14 | 15 | 16 | 17 | 18 | 19 | 20 | True 21 | top 22 | 23 | 24 | 25 | 26 | 27 | 28 | True 29 | top 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/test_tkspinbox.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestTkSpinbox(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_tkspinbox.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | 21 | def tearDown(self): 22 | support.root_withdraw() 23 | 24 | def test_class(self): 25 | self.widget = self.builder.get_object("test_from") 26 | self.spinbox = self.builder.get_object("spinbox1") 27 | self.assertIsInstance(self.spinbox, tk.Spinbox) 28 | self.widget.destroy() 29 | 30 | def test_from_(self): 31 | self.widget = self.builder.get_object("test_from") 32 | spinbox = self.builder.get_object("spinbox1") 33 | value = spinbox.cget("from") 34 | self.assertEqual(5, value) 35 | self.widget.destroy() 36 | 37 | def test_to(self): 38 | self.widget = self.builder.get_object("test_to") 39 | spinbox = self.builder.get_object("spinbox2") 40 | value = spinbox.cget("to") 41 | self.assertEqual(10, value) 42 | self.widget.destroy() 43 | 44 | def test_from_to(self): 45 | self.widget = self.builder.get_object("test_from_to") 46 | spinbox = self.builder.get_object("spinbox3") 47 | value_from = spinbox.cget("from") 48 | value_to = spinbox.cget("to") 49 | self.assertEqual(2, value_from) 50 | self.assertEqual(10, value_to) 51 | self.widget.destroy() 52 | -------------------------------------------------------------------------------- /tests/test_tkspinbox.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | 5 14 | 15 | True 16 | top 17 | 18 | 19 | 20 | 21 | 22 | 200 23 | 200 24 | 25 | 0 26 | True 27 | 0 28 | 29 | 30 | 31 | 10 32 | 33 | True 34 | top 35 | 36 | 37 | 38 | 39 | 40 | 200 41 | 200 42 | 43 | 0 44 | True 45 | 0 46 | 47 | 48 | 49 | 2 50 | 10 51 | 52 | True 53 | top 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/test_toplevelmenuhelper.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestToplevelMenuHelper(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_toplevelmenuhelper.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("toplevel") 21 | self.menuhelper = builder.get_object("topmenuhelper") 22 | self.menu = builder.get_object("topmenu") 23 | 24 | def tearDown(self): 25 | support.root_withdraw() 26 | 27 | def test_class(self): 28 | self.assertIsInstance(self.menu, tk.Menu) 29 | self.widget.destroy() 30 | 31 | def test_class_topmenu(self): 32 | menu1 = self.widget.nametowidget(self.widget.cget("menu")) 33 | self.assertEqual(menu1, self.menu) 34 | self.widget.destroy() 35 | -------------------------------------------------------------------------------- /tests/test_toplevelmenuhelper.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 320x240 5 | 200 6 | 200 7 | 8 | 9 | 200 10 | 200 11 | 12 | true 13 | True 14 | top 15 | 16 | 17 | 18 | Toplevel Menu Helper Test 19 | 20 | True 21 | top 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | false 32 | 33 | 34 | Topmenu 35 | false 36 | 37 | 38 | false 39 | command 1 40 | 41 | 42 | 43 | 44 | false 45 | command 2 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/test_ttkcombobox.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | 11 | 12 | 13 | cbox_invalid 14 | %P 15 | key 16 | cbox_validate 17 | %d %P 18 | option1 option2 option3 19 | 20 | 0 21 | True 22 | 0 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/test_ttkspinbox.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestSpinbox(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_ttkspinbox.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainwindow") 21 | self.spinbox = builder.get_object("spinbox1") 22 | 23 | def tearDown(self): 24 | support.root_withdraw() 25 | 26 | def test_class(self): 27 | self.assertIsInstance(self.spinbox, ttk.Spinbox) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_ttkspinbox.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | True 9 | 0 10 | nesw 11 | 12 | 13 | 14 | 0 15 | 50 16 | none 17 | 18 | 0 19 | True 20 | 0 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_1.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import support 10 | import pygubu 11 | 12 | 13 | class TestUIDefinition_1_1(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_uidefinition_1_1.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("fmain") 20 | self.fgrid = builder.get_object("fgrid") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_class(self): 26 | self.assertIsInstance(self.widget, ttk.Frame) 27 | self.widget.destroy() 28 | 29 | def test_gridrc_options(self): 30 | config = self.fgrid.grid_rowconfigure(0) 31 | # {'minsize': 10, 'pad': 10, 'weight': 1, 'uniform': 'x'} 32 | self.assertEqual(config["minsize"], 10) 33 | self.assertEqual(config["pad"], 10) 34 | self.assertEqual(config["weight"], 1) 35 | self.assertEqual(config["uniform"], "x") 36 | 37 | config = self.fgrid.grid_columnconfigure(0) 38 | # {'minsize': 30, 'pad': 15, 'weight': 1, 'uniform': 'y'} 39 | self.assertEqual(config["minsize"], 30) 40 | self.assertEqual(config["pad"], 15) 41 | self.assertEqual(config["weight"], 1) 42 | self.assertEqual(config["uniform"], "y") 43 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_2_grid.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import support 10 | import pygubu 11 | 12 | 13 | class TestUIDefinition_1_2(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_uidefinition_1_2_grid.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("fmain") 20 | self.fgrid = builder.get_object("fgrid") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_class(self): 26 | self.assertIsInstance(self.widget, ttk.Frame) 27 | self.widget.destroy() 28 | 29 | def test_gridrc_row_options(self): 30 | config = self.fgrid.grid_rowconfigure(0) 31 | # {'minsize': 10, 'pad': 10, 'weight': 1, 'uniform': 'x'} 32 | self.assertEqual(config["minsize"], 10) 33 | self.assertEqual(config["pad"], 10) 34 | self.assertEqual(config["weight"], 1) 35 | self.assertEqual(config["uniform"], "x") 36 | 37 | def test_gridrc_column_options(self): 38 | config = self.fgrid.grid_columnconfigure(0) 39 | # {'minsize': 30, 'pad': 15, 'weight': 1, 'uniform': 'y'} 40 | self.assertEqual(config["minsize"], 30) 41 | self.assertEqual(config["pad"], 15) 42 | self.assertEqual(config["weight"], 1) 43 | self.assertEqual(config["uniform"], "y") 44 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_3.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import support 10 | import pygubu 11 | 12 | 13 | class TestUIDefinition_1_3(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_uidefinition_1_3.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("fmain") 20 | 21 | def tearDown(self): 22 | support.root_withdraw() 23 | 24 | def test_is_object_named(self): 25 | self.assertIsInstance(self.widget, ttk.Frame) 26 | is_named = self.builder.objects["fmain"].wmeta.is_named 27 | self.assertTrue(is_named) 28 | self.widget.destroy() 29 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_3.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 200 5 | 200 6 | 7 | 0 8 | 0 9 | 10 | 11 | 12 | Test loading a named object 13 | 14 | top 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_4.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | import fixpath 9 | import support 10 | import pygubu 11 | 12 | 13 | class TestUIDefinition_1_4(unittest.TestCase): 14 | def setUp(self): 15 | support.root_deiconify() 16 | xmldata = "test_uidefinition_1_4.ui" 17 | self.builder = builder = pygubu.Builder() 18 | builder.add_from_file(xmldata) 19 | self.widget = builder.get_object("fmain") 20 | 21 | def tearDown(self): 22 | support.root_withdraw() 23 | 24 | def test_is_version_1_4(self): 25 | value = self.builder.uidefinition.version 26 | self.assertEqual("1.4", value) 27 | self.widget.destroy() 28 | -------------------------------------------------------------------------------- /tests/test_uidefinition_1_4.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 200 6 | 200 7 | 8 | 0 9 | 0 10 | 11 | 12 | 13 | Test UI definition 1.4 14 | 15 | top 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/test_variables.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | import os 3 | import sys 4 | import unittest 5 | import tkinter as tk 6 | import tkinter.ttk as ttk 7 | 8 | 9 | import fixpath 10 | import pygubu 11 | import support 12 | 13 | 14 | class TestVariables(unittest.TestCase): 15 | def setUp(self): 16 | support.root_deiconify() 17 | xmldata = "test_variables.ui" 18 | self.builder = builder = pygubu.Builder() 19 | builder.add_from_file(xmldata) 20 | self.widget = builder.get_object("mainwindow") 21 | 22 | def tearDown(self): 23 | support.root_withdraw() 24 | 25 | def test_string_var(self): 26 | var = self.builder.get_variable("strvar") 27 | self.assertIsInstance(var, tk.StringVar) 28 | self.widget.destroy() 29 | 30 | def test_int_var(self): 31 | var = self.builder.get_variable("intvar") 32 | self.assertIsInstance(var, tk.IntVar) 33 | self.widget.destroy() 34 | 35 | def test_double_var(self): 36 | var = self.builder.get_variable("doublevar") 37 | self.assertIsInstance(var, tk.DoubleVar) 38 | self.widget.destroy() 39 | 40 | def test_boolean_var(self): 41 | var = self.builder.get_variable("booleanvar") 42 | self.assertIsInstance(var, tk.BooleanVar) 43 | self.assertEqual(False, var.get()) 44 | self.widget.destroy() 45 | 46 | def test_bugged_oldformat_var(self): 47 | var = self.builder.get_variable("testoldformat") 48 | self.assertIsInstance(var, tk.StringVar) 49 | self.widget.destroy() 50 | 51 | def test_invalid_variable_type(self): 52 | # self.builder.create_variable('complex:mycomplexvar') 53 | self.assertRaises( 54 | Exception, self.builder.create_variable, "complex:mycomplexvar" 55 | ) 56 | self.widget.destroy() 57 | 58 | 59 | if __name__ == "__main__": 60 | unittest.main() 61 | --------------------------------------------------------------------------------