From 64e9c2a6df1c0bec65a94d0a87af20c72074df0d Mon Sep 17 00:00:00 2001 From: Angel Romero Date: Wed, 31 Aug 2022 17:45:34 -0400 Subject: [PATCH] Delete app_windows directory --- app_windows/app.py | 11 - app_windows/lib/easygui/PKG-INFO | 94 -- app_windows/lib/easygui/README.txt | 83 -- .../lib/easygui/build/lib/easygui/__init__.py | 57 - .../build/lib/easygui/boxes/__init__.py | 0 .../easygui/build/lib/easygui/boxes/about.py | 221 ---- .../build/lib/easygui/boxes/base_boxes.py | 1103 ----------------- .../easygui/build/lib/easygui/boxes/demo.py | 378 ------ .../build/lib/easygui/boxes/derived_boxes.py | 542 -------- .../build/lib/easygui/boxes/egstore.py | 158 --- .../easygui/build/lib/easygui/boxes/state.py | 23 - .../build/lib/easygui/boxes/text_box.py | 199 --- .../lib/easygui/boxes/updatable_text_box.py | 270 ---- .../easygui/build/lib/easygui/boxes/utils.py | 180 --- .../lib/easygui/build/lib/easygui/easygui.py | 79 -- .../lib/easygui/python_and_check_logo.gif | Bin 25112 -> 0 bytes .../lib/easygui/python_and_check_logo.jpg | Bin 8928 -> 0 bytes .../lib/easygui/python_and_check_logo.png | Bin 3585 -> 0 bytes .../lib/easygui/build/lib/easygui/zzzzz.gif | Bin 1703 -> 0 bytes .../lib/easygui/dist/easygui-0.97.4-py2.7.egg | Bin 114317 -> 0 bytes .../lib/easygui/easygui.egg-info/PKG-INFO | 94 -- .../lib/easygui/easygui.egg-info/SOURCES.txt | 23 - .../easygui.egg-info/dependency_links.txt | 1 - .../easygui/easygui.egg-info/top_level.txt | 1 - app_windows/lib/easygui/easygui/__init__.py | 57 - .../lib/easygui/easygui/boxes/__init__.py | 0 .../lib/easygui/easygui/boxes/about.py | 221 ---- .../lib/easygui/easygui/boxes/base_boxes.py | 1103 ----------------- app_windows/lib/easygui/easygui/boxes/demo.py | 378 ------ .../easygui/easygui/boxes/derived_boxes.py | 542 -------- .../lib/easygui/easygui/boxes/egstore.py | 158 --- .../lib/easygui/easygui/boxes/state.py | 23 - .../lib/easygui/easygui/boxes/text_box.py | 199 --- .../easygui/boxes/updatable_text_box.py | 270 ---- .../lib/easygui/easygui/boxes/utils.py | 180 --- app_windows/lib/easygui/easygui/easygui.py | 79 -- .../easygui/easygui/python_and_check_logo.gif | Bin 25112 -> 0 bytes .../easygui/easygui/python_and_check_logo.jpg | Bin 8928 -> 0 bytes .../easygui/easygui/python_and_check_logo.png | Bin 3585 -> 0 bytes app_windows/lib/easygui/easygui/zzzzz.gif | Bin 1703 -> 0 bytes app_windows/lib/easygui/setup.cfg | 8 - app_windows/lib/easygui/setup.py | 115 -- app_windows/lib/splinter-0.7.2/MANIFEST.in | 2 - app_windows/lib/splinter-0.7.2/PKG-INFO | 60 - app_windows/lib/splinter-0.7.2/README.rst | 44 - .../build/lib/splinter/__init__.py | 8 - .../build/lib/splinter/browser.py | 63 - .../build/lib/splinter/cookie_manager.py | 75 -- .../build/lib/splinter/driver/__init__.py | 588 --------- .../build/lib/splinter/driver/djangoclient.py | 441 ------- .../build/lib/splinter/driver/flaskclient.py | 433 ------- .../lib/splinter/driver/webdriver/__init__.py | 654 ---------- .../lib/splinter/driver/webdriver/chrome.py | 34 - .../driver/webdriver/cookie_manager.py | 57 - .../lib/splinter/driver/webdriver/firefox.py | 48 - .../splinter/driver/webdriver/phantomjs.py | 39 - .../lib/splinter/driver/webdriver/remote.py | 68 - .../lib/splinter/driver/zopetestbrowser.py | 400 ------ .../build/lib/splinter/element_list.py | 75 -- .../build/lib/splinter/exceptions.py | 32 - .../splinter-0.7.2/build/lib/splinter/meta.py | 27 - .../lib/splinter/request_handler/__init__.py | 3 - .../request_handler/request_handler.py | 72 -- .../splinter/request_handler/status_code.py | 62 - .../build/lib/splinter/utils.py | 12 - .../dist/splinter-0.7.2-py2.7.egg | Bin 73933 -> 0 bytes app_windows/lib/splinter-0.7.2/setup.cfg | 5 - app_windows/lib/splinter-0.7.2/setup.py | 31 - .../splinter-0.7.2/splinter.egg-info/PKG-INFO | 60 - .../splinter.egg-info/SOURCES.txt | 29 - .../splinter.egg-info/dependency_links.txt | 1 - .../splinter.egg-info/requires.txt | 16 - .../splinter.egg-info/top_level.txt | 1 - .../lib/splinter-0.7.2/splinter/__init__.py | 8 - .../lib/splinter-0.7.2/splinter/browser.py | 63 - .../splinter-0.7.2/splinter/cookie_manager.py | 75 -- .../splinter/driver/__init__.py | 588 --------- .../splinter/driver/djangoclient.py | 441 ------- .../splinter/driver/flaskclient.py | 433 ------- .../splinter/driver/webdriver/__init__.py | 654 ---------- .../splinter/driver/webdriver/chrome.py | 34 - .../driver/webdriver/cookie_manager.py | 57 - .../splinter/driver/webdriver/firefox.py | 48 - .../splinter/driver/webdriver/phantomjs.py | 39 - .../splinter/driver/webdriver/remote.py | 68 - .../splinter/driver/zopetestbrowser.py | 400 ------ .../splinter-0.7.2/splinter/element_list.py | 75 -- .../lib/splinter-0.7.2/splinter/exceptions.py | 32 - .../lib/splinter-0.7.2/splinter/meta.py | 27 - .../splinter/request_handler/__init__.py | 3 - .../request_handler/request_handler.py | 72 -- .../splinter/request_handler/status_code.py | 62 - .../lib/splinter-0.7.2/splinter/utils.py | 12 - .../splinter-chrome-driver/chromedriver.exe | Bin 11884544 -> 0 bytes 94 files changed, 13481 deletions(-) delete mode 100644 app_windows/app.py delete mode 100644 app_windows/lib/easygui/PKG-INFO delete mode 100644 app_windows/lib/easygui/README.txt delete mode 100644 app_windows/lib/easygui/build/lib/easygui/__init__.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/__init__.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/about.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/base_boxes.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/demo.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/derived_boxes.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/egstore.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/state.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/text_box.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/updatable_text_box.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/boxes/utils.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/easygui.py delete mode 100644 app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.gif delete mode 100644 app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.jpg delete mode 100644 app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.png delete mode 100644 app_windows/lib/easygui/build/lib/easygui/zzzzz.gif delete mode 100644 app_windows/lib/easygui/dist/easygui-0.97.4-py2.7.egg delete mode 100644 app_windows/lib/easygui/easygui.egg-info/PKG-INFO delete mode 100644 app_windows/lib/easygui/easygui.egg-info/SOURCES.txt delete mode 100644 app_windows/lib/easygui/easygui.egg-info/dependency_links.txt delete mode 100644 app_windows/lib/easygui/easygui.egg-info/top_level.txt delete mode 100644 app_windows/lib/easygui/easygui/__init__.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/__init__.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/about.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/base_boxes.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/demo.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/derived_boxes.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/egstore.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/state.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/text_box.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/updatable_text_box.py delete mode 100644 app_windows/lib/easygui/easygui/boxes/utils.py delete mode 100644 app_windows/lib/easygui/easygui/easygui.py delete mode 100644 app_windows/lib/easygui/easygui/python_and_check_logo.gif delete mode 100644 app_windows/lib/easygui/easygui/python_and_check_logo.jpg delete mode 100644 app_windows/lib/easygui/easygui/python_and_check_logo.png delete mode 100644 app_windows/lib/easygui/easygui/zzzzz.gif delete mode 100644 app_windows/lib/easygui/setup.cfg delete mode 100644 app_windows/lib/easygui/setup.py delete mode 100644 app_windows/lib/splinter-0.7.2/MANIFEST.in delete mode 100644 app_windows/lib/splinter-0.7.2/PKG-INFO delete mode 100644 app_windows/lib/splinter-0.7.2/README.rst delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/browser.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/cookie_manager.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/djangoclient.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/flaskclient.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/chrome.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/cookie_manager.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/firefox.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/phantomjs.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/webdriver/remote.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/zopetestbrowser.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/element_list.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/exceptions.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/meta.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/request_handler/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/request_handler/request_handler.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/request_handler/status_code.py delete mode 100644 app_windows/lib/splinter-0.7.2/build/lib/splinter/utils.py delete mode 100644 app_windows/lib/splinter-0.7.2/dist/splinter-0.7.2-py2.7.egg delete mode 100644 app_windows/lib/splinter-0.7.2/setup.cfg delete mode 100644 app_windows/lib/splinter-0.7.2/setup.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter.egg-info/PKG-INFO delete mode 100644 app_windows/lib/splinter-0.7.2/splinter.egg-info/SOURCES.txt delete mode 100644 app_windows/lib/splinter-0.7.2/splinter.egg-info/dependency_links.txt delete mode 100644 app_windows/lib/splinter-0.7.2/splinter.egg-info/requires.txt delete mode 100644 app_windows/lib/splinter-0.7.2/splinter.egg-info/top_level.txt delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/browser.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/cookie_manager.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/djangoclient.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/flaskclient.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/chrome.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/cookie_manager.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/firefox.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/phantomjs.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/webdriver/remote.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/driver/zopetestbrowser.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/element_list.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/exceptions.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/meta.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/request_handler/__init__.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/request_handler/request_handler.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/request_handler/status_code.py delete mode 100644 app_windows/lib/splinter-0.7.2/splinter/utils.py delete mode 100644 app_windows/lib/splinter-chrome-driver/chromedriver.exe diff --git a/app_windows/app.py b/app_windows/app.py deleted file mode 100644 index ec8c304..0000000 --- a/app_windows/app.py +++ /dev/null @@ -1,11 +0,0 @@ -from splinter import Browser -from easygui import * -from sys import exit -from time import sleep -from re import sub -from os import path, makedirs - -executable_path = {'executable_path': 'C:/path/to/chromedriver.exe'} - -chrome = Browser('chrome', **executable_path) -chrome_options.add_argument("--app=https://redlinuxclick.ml/") \ No newline at end of file diff --git a/app_windows/lib/easygui/PKG-INFO b/app_windows/lib/easygui/PKG-INFO deleted file mode 100644 index 8471ff2..0000000 --- a/app_windows/lib/easygui/PKG-INFO +++ /dev/null @@ -1,94 +0,0 @@ -Metadata-Version: 1.1 -Name: easygui -Version: 0.97.4 -Summary: EasyGUI is a module for very simple, very easy GUI programming in Python. EasyGUI is different from other GUI generators in that EasyGUI is NOT event-driven. Instead, all GUI interactions are invoked by simple function calls. -Home-page: https://github.com/robertlugg/easygui/ -Author: Stephen Ferg and Robert Lugg (active) -Author-email: robert.lugg@gmail.com -License: BSD -Description: - ABOUT EASYGUI - ============= - - EasyGui provides an easy-to-use interface for simple GUI interaction - with a user. It does not require the programmer to know anything about - tkinter, frames, widgets, callbacks or lambda. All GUI interactions are - invoked by simple function calls that return results. - - Example Usage - ------------- - - >>> import easygui - >>> easygui.ynbox('Shall I continue?', 'Title', ('Yes', 'No')) - 1 - >>> easygui.msgbox('This is a basic message box.', 'Title Goes Here') - 'OK' - >>> easygui.buttonbox('Click on your favorite flavor.', 'Favorite Flavor', ('Chocolate', 'Vanilla', 'Strawberry')) - 'Chocolate' - - - A full tutorial is available at - . - - LICENSE INFORMATION - =================== - EasyGui version |version| - - Copyright (c) 2015, Stephen Raymond Ferg - - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - ABOUT THE EASYGUI LICENSE - ------------------------- - | This license is what is generally known as the "modified BSD license", - | aka "revised BSD", "new BSD", "3-clause BSD". - | See http://www.opensource.org/licenses/bsd-license.php - | - | This license is GPL-compatible. - | See ``_ - | See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses - | - | The BSD License is less restrictive than GPL. - | It allows software released under the license to be incorporated into proprietary products. - | Works based on the software may be released under a proprietary license or as closed source software. - | ``_ - -Keywords: gui linux windows graphical user interface -Platform: UNKNOWN -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: License :: OSI Approved :: BSD License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Topic :: Software Development :: User Interfaces diff --git a/app_windows/lib/easygui/README.txt b/app_windows/lib/easygui/README.txt deleted file mode 100644 index 0423745..0000000 --- a/app_windows/lib/easygui/README.txt +++ /dev/null @@ -1,83 +0,0 @@ -EasyGUI -======= - -EasyGUI is a module for very simple, very easy GUI programming in Python. EasyGUI is different from other GUI -libraries in that EasyGUI is NOT event-driven. Instead, all GUI interactions are invoked by simple function calls. - -EasyGUI runs on Python 2 and 3, and does not have any dependencies beyond python. - -Example Usage -------------- - - >>> import easygui - >>> easygui.ynbox('Shall I continue?', 'Title', ('Yes', 'No')) - 1 - >>> easygui.msgbox('This is a basic message box.', 'Title Goes Here') - 'OK' - >>> easygui.buttonbox('Click on your favorite flavor.', 'Favorite Flavor', ('Chocolate', 'Vanilla', 'Strawberry')) - 'Chocolate' - - -A full tutorial is available at -. - -======================================================================== -0.97.4 -======================================================================== -This is a minor bug-fix release to address python 3 import errors. - -0.97.3 -======================================================================== -We are happy to release version 0.97.N of easygui. The intent of this release is to address some basic -functionality issues as well as improve easygui in the ways people have asked. - -Robert Lugg (me) was searching for a GUI library for my python work. I saw easygui and liked very much its -paradigm. Stephen Ferg, the creator and developer of easygui, graciously allowed me to start development -back up. With the help of Alexander Zawadzki, Horst Jens, and others I set a goal to release before the -end of 2014. - -We rely on user feedback so please bring up problems, ideas, or just say how you are using easygui. - -BUG FIXES ---------- - * sourceforge #4: easygui docs contain bad references to easygui_pydoc.html - * sourceforge #6: no index.html in docs download file. Updated to sphinx which as autolinking. - * sourceforge #8: unicode issues with file*box. Fixed all that I knew how. - * sourceforge #12: Cannot Exit with 'X'. Now X and escape either return "cancel_button", if set, or None - -ENHANCEMENTS ------------- - * Added ability to specify default_choice and cancel_choice for button widgets (See API docs) - * True and False are returned instead of 1 and 0 for several boxes - * Allow user to map keyboard keys to buttons by enclosing a hotkey in square braces like: "Pick [M]e", which would assign - keyboard key M to that button. Double braces hide that character, and keysyms are allowed: - [[q]]Exit Would show Exit on the button, and the button would be controlled by the q key - []Help Would show Help on the button, and the button would be controlled by the F1 function key - NOTE: We are still working on the exact syntax of these key mappings as Enter, space, and arrows are already being - used. - * Escape and the windows 'X' button always work in buttonboxes. Those return None in that case. - * sourceforge #9: let fileopenbox open multiple files. Added optional argument 'multiple' - * Location of dialogs on screen is preserved. This isn't perfect yet, but now, at least, the dialogs don't - always reset to their default position! - * added some, but not all of the bugs/enhancements developed by Robbie Brook: - http://all-you-need-is-tech.blogspot.com/2013/01/improving-easygui-for-python.html - -KNOWN ISSUES ------------- - * In the documentation, there were previous references to issues when using the IDLE IDE. I haven't - experienced those, but also didn't do anything to fix them, so they may still be there. Please report - any problems and we'll try to address them - * I am fairly new to contributing to open source, so I don't understand packaging, pypi, etc. There - are likely problems as well as better ways to do things. Again, I appreciate any help or guidance. - -Other Changes (that you likely don't care about) ------------------------------------------------- - * Restructured loading of image files to try PIL first throw error if file doesn't exist. - * Converted docs to sphinx with just a bit of doctest. Most content was retained from the old site, so - there might be some redundancies still. Please make any suggested improvements. - * Set up a GitHub repository for development: https://github.com/robertlugg/easygui - * Improved output/packaging for Debian distribution - -EasyGui is licensed under what is generally known as -the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD"). -This license is GPL-compatible but less restrictive than GPL. diff --git a/app_windows/lib/easygui/build/lib/easygui/__init__.py b/app_windows/lib/easygui/build/lib/easygui/__init__.py deleted file mode 100644 index 203ea2a..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Hello from easygui/__init__.py - -""" - -# __all__ must be defined in order for Sphinx to generate the API automatically. -__all__ = ['buttonbox', - 'diropenbox', - 'fileopenbox', - 'filesavebox', - 'textbox', - 'ynbox', - 'ccbox', - 'boolbox', - 'indexbox', - 'msgbox', - 'integerbox', - 'multenterbox', - 'enterbox', - 'exceptionbox', - 'choicebox', - 'codebox', - 'passwordbox', - 'multpasswordbox', - 'multchoicebox', - 'EgStore', - 'eg_version', - 'egversion', - 'abouteasygui', - 'egdemo', -] - -# Import all functions that form the API -from .boxes.base_boxes import buttonbox -from .boxes.base_boxes import diropenbox -from .boxes.base_boxes import fileopenbox -from .boxes.base_boxes import filesavebox - -from .boxes.text_box import textbox - -from .boxes.derived_boxes import ynbox -from .boxes.derived_boxes import ccbox -from .boxes.derived_boxes import boolbox -from .boxes.derived_boxes import indexbox -from .boxes.derived_boxes import msgbox -from .boxes.derived_boxes import integerbox -from .boxes.derived_boxes import multenterbox -from .boxes.derived_boxes import enterbox -from .boxes.derived_boxes import exceptionbox -from .boxes.derived_boxes import choicebox -from .boxes.derived_boxes import codebox -from .boxes.derived_boxes import passwordbox -from .boxes.derived_boxes import multpasswordbox -from .boxes.derived_boxes import multchoicebox -from .boxes.egstore import EgStore -from .boxes.about import eg_version, egversion, abouteasygui -from .boxes.demo import egdemo \ No newline at end of file diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/__init__.py b/app_windows/lib/easygui/build/lib/easygui/boxes/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/about.py b/app_windows/lib/easygui/build/lib/easygui/boxes/about.py deleted file mode 100644 index 313b65d..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/about.py +++ /dev/null @@ -1,221 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - - -from .derived_boxes import codebox - -eg_version = '0.97.4' -egversion = eg_version - - -def abouteasygui(): - """ - shows the easygui revision history - """ - codebox("About EasyGui\n{}".format(eg_version), - "EasyGui", EASYGUI_ABOUT_INFORMATION) - return None - - -EASYGUI_ABOUT_INFORMATION = ''' -======================================================================== -0.97.4 -======================================================================== -This is a minor bug-fix release to address python 3 import errors. - -======================================================================== -0.97.3 -======================================================================== -Some more fixes especially to fix Debian distro problems. - -======================================================================== -0.97.1 & 0.97.2 (2014-12-24) -======================================================================== -Boring, embarrassing uploads to fix pypi install problems. - -======================================================================== -0.97(2014-12-20) -======================================================================== -We are happy to release version 0.97 of easygui. The intent of this release is to address some basic -functionality issues as well as improve easygui in the ways people have asked. - -Robert Lugg (me) was searching for a GUI library for my python work. I saw easygui and liked very much its -paradigm. Stephen Ferg, the creator and developer of easygui, graciously allowed me to start development -back up. With the help of Alexander Zawadzki, Horst Jens, and others I set a goal to release before the -end of 2014. - -We rely on user feedback so please bring up problems, ideas, or just say how you are using easygui. - -BUG FIXES ---------- - * sourceforge #4: easygui docs contain bad references to easygui_pydoc.html - * sourceforge #6: no index.html in docs download file. Updated to sphinx which as autolinking. - * sourceforge #8: unicode issues with file*box. Fixed all that I knew how. - * sourceforge #12: Cannot Exit with 'X'. Now X and escape either return "cancel_button", if set, or None - -ENHANCEMENTS ------------- - * Added ability to specify default_choice and cancel_choice for button widgets (See API docs) - * True and False are returned instead of 1 and 0 for several boxes - * Allow user to map keyboard keys to buttons by enclosing a hotkey in square braces like: "Pick [M]e", which would assign - keyboard key M to that button. Double braces hide that character, and keysyms are allowed: - [[q]]Exit Would show Exit on the button, and the button would be controlled by the q key - []Help Would show Help on the button, and the button would be controlled by the F1 function key - NOTE: We are still working on the exact syntax of these key mappings as Enter, space, and arrows are already being - used. - * Escape and the windows 'X' button always work in buttonboxes. Those return None in that case. - * sourceforge #9: let fileopenbox open multiple files. Added optional argument 'multiple' - * Location of dialogs on screen is preserved. This isn't perfect yet, but now, at least, the dialogs don't - always reset to their default position! - * added some, but not all of the bugs/enhancements developed by Robbie Brook: - http://all-you-need-is-tech.blogspot.com/2013/01/improving-easygui-for-python.html - -KNOWN ISSUES ------------- - * In the documentation, there were previous references to issues when using the IDLE IDE. I haven't - experienced those, but also didn't do anything to fix them, so they may still be there. Please report - any problems and we'll try to address them - * I am fairly new to contributing to open source, so I don't understand packaging, pypi, etc. There - are likely problems as well as better ways to do things. Again, I appreciate any help or guidance. - -Other Changes (that you likely don't care about) ------------------------------------------------- - * Restructured loading of image files to try PIL first throw error if file doesn't exist. - * Converted docs to sphinx with just a bit of doctest. Most content was retained from the old site, so - there might be some redundancies still. Please make any suggested improvements. - * Set up a GitHub repository for development: https://github.com/robertlugg/easygui - -EasyGui is licensed under what is generally known as -the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD"). -This license is GPL-compatible but less restrictive than GPL. - -======================================================================== -0.96(2010-08-29) -======================================================================== -This version fixes some problems with version independence. - -BUG FIXES ------------------------------------------------------- - * A statement with Python 2.x-style exception-handling syntax raised - a syntax error when running under Python 3.x. - Thanks to David Williams for reporting this problem. - - * Under some circumstances, PIL was unable to display non-gif images - that it should have been able to display. - The cause appears to be non-version-independent import syntax. - PIL modules are now imported with a version-independent syntax. - Thanks to Horst Jens for reporting this problem. - -LICENSE CHANGE ------------------------------------------------------- -Starting with this version, EasyGui is licensed under what is generally known as -the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD"). -This license is GPL-compatible but less restrictive than GPL. -Earlier versions were licensed under the Creative Commons Attribution License 2.0. - - -======================================================================== -0.95(2010-06-12) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - * Previous versions of EasyGui could display only .gif image files using the - msgbox "image" argument. This version can now display all image-file formats - supported by PIL the Python Imaging Library) if PIL is installed. - If msgbox is asked to open a non-gif image file, it attempts to import - PIL and to use PIL to convert the image file to a displayable format. - If PIL cannot be imported (probably because PIL is not installed) - EasyGui displays an error message saying that PIL must be installed in order - to display the image file. - - Note that - http://www.pythonware.com/products/pil/ - says that PIL doesn't yet support Python 3.x. - - -======================================================================== -0.94(2010-06-06) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - * The codebox and textbox functions now return the contents of the box, rather - than simply the name of the button ("Yes"). This makes it possible to use - codebox and textbox as data-entry widgets. A big "thank you!" to Dominic - Comtois for requesting this feature, patiently explaining his requirement, - and helping to discover the tkinter techniques to implement it. - - NOTE THAT in theory this change breaks backward compatibility. But because - (in previous versions of EasyGui) the value returned by codebox and textbox - was meaningless, no application should have been checking it. So in actual - practice, this change should not break backward compatibility. - - * Added support for SPACEBAR to command buttons. Now, when keyboard - focus is on a command button, a press of the SPACEBAR will act like - a press of the ENTER key; it will activate the command button. - - * Added support for keyboard navigation with the arrow keys (up,down,left,right) - to the fields and buttons in enterbox, multenterbox and multpasswordbox, - and to the buttons in choicebox and all buttonboxes. - - * added highlightthickness=2 to entry fields in multenterbox and - multpasswordbox. Now it is easier to tell which entry field has - keyboard focus. - - -BUG FIXES ------------------------------------------------------- - * In EgStore, the pickle file is now opened with "rb" and "wb" rather than - with "r" and "w". This change is necessary for compatibility with Python 3+. - Thanks to Marshall Mattingly for reporting this problem and providing the fix. - - * In integerbox, the actual argument names did not match the names described - in the docstring. Thanks to Daniel Zingaro of at University of Toronto for - reporting this problem. - - * In integerbox, the "argLowerBound" and "argUpperBound" arguments have been - renamed to "lowerbound" and "upperbound" and the docstring has been corrected. - - NOTE THAT THIS CHANGE TO THE ARGUMENT-NAMES BREAKS BACKWARD COMPATIBILITY. - If argLowerBound or argUpperBound are used, an AssertionError with an - explanatory error message is raised. - - * In choicebox, the signature to choicebox incorrectly showed choicebox as - accepting a "buttons" argument. The signature has been fixed. - - -======================================================================== -0.93(2009-07-07) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - - * Added exceptionbox to display stack trace of exceptions - - * modified names of some font-related constants to make it - easier to customize them - - -======================================================================== -0.92(2009-06-22) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - - * Added EgStore class to to provide basic easy-to-use persistence. - -BUG FIXES ------------------------------------------------------- - - * Fixed a bug that was preventing Linux users from copying text out of - a textbox and a codebox. This was not a problem for Windows users. - -''' diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/base_boxes.py b/app_windows/lib/easygui/build/lib/easygui/boxes/base_boxes.py deleted file mode 100644 index be697d6..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/base_boxes.py +++ /dev/null @@ -1,1103 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - - -import os -import string - - -from . import utils as ut -from .utils import * -from . import state as st - -# Initialize some global variables that will be reset later -__choiceboxMultipleSelect = None -__replyButtonText = None -__choiceboxResults = None -__firstWidget = None -__enterboxText = None -__enterboxDefaultText = "" -__multenterboxText = "" -choiceboxChoices = None -choiceboxWidget = None -entryWidget = None -boxRoot = None - -# ------------------------------------------------------------------- -# buttonbox -# ------------------------------------------------------------------- - - -def buttonbox(msg="", title=" ", choices=("Button[1]", "Button[2]", "Button[3]"), image=None, root=None, default_choice=None, cancel_choice=None): - """ - Display a msg, a title, an image, and a set of buttons. - The buttons are defined by the members of the choices list. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which button should be pressed - :return: the text of the button that the user selected - """ - global boxRoot, __replyButtonText, buttonsFrame - - # If default is not specified, select the first button. This matches old - # behavior. - if default_choice is None: - default_choice = choices[0] - - # Initialize __replyButtonText to the first choice. - # This is what will be used if the window is closed by the close button. - __replyButtonText = choices[0] - - if root: - root.withdraw() - boxRoot = Toplevel(master=root) - boxRoot.withdraw() - else: - boxRoot = Tk() - boxRoot.withdraw() - - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.minsize(400, 100) - - # ------------- define the messageFrame --------------------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the imageFrame --------------------------------- - if image: - tk_Image = None - try: - tk_Image = ut.load_tk_image(image) - except Exception as inst: - print(inst) - if tk_Image: - imageFrame = Frame(master=boxRoot) - imageFrame.pack(side=TOP, fill=BOTH) - label = Label(imageFrame, image=tk_Image) - label.image = tk_Image # keep a reference! - label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m') - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # -------------------- place the widgets in the frames ------------------- - messageWidget = Message(messageFrame, text=msg, width=400) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m') - - __put_buttons_in_buttonframe(choices, default_choice, cancel_choice) - - # -------------- the action begins ----------- - boxRoot.deiconify() - boxRoot.mainloop() - boxRoot.destroy() - if root: - root.deiconify() - return __replyButtonText - - -def bindArrows(widget): - - widget.bind("", tabRight) - widget.bind("", tabLeft) - - widget.bind("", tabRight) - widget.bind("", tabLeft) - - -def tabRight(event): - boxRoot.event_generate("") - - -def tabLeft(event): - boxRoot.event_generate("") - - -# ----------------------------------------------------------------------- -# __multfillablebox -# ----------------------------------------------------------------------- -def __multfillablebox(msg="Fill in values for the fields.", title=" ", fields=(), values=(), mask=None): - global boxRoot, __multenterboxText, __multenterboxDefaultText, cancelButton, entryWidget, okButton - - choices = ["OK", "Cancel"] - if len(fields) == 0: - return None - - fields = list(fields[:]) # convert possible tuples to a list - values = list(values[:]) # convert possible tuples to a list - - # TODO RL: The following seems incorrect when values>fields. Replace - # below with zip? - if len(values) == len(fields): - pass - elif len(values) > len(fields): - fields = fields[0:len(values)] - else: - while len(values) < len(fields): - values.append("") - - boxRoot = Tk() - - boxRoot.protocol('WM_DELETE_WINDOW', __multenterboxQuit) - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.bind("", __multenterboxCancel) - - # -------------------- put subframes in the boxRoot -------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # -------------------- the msg widget ---------------------------- - messageWidget = Message(messageFrame, width="4.5i", text=msg) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m') - - global entryWidgets - entryWidgets = list() - - lastWidgetIndex = len(fields) - 1 - - for widgetIndex in range(len(fields)): - argFieldName = fields[widgetIndex] - argFieldValue = values[widgetIndex] - entryFrame = Frame(master=boxRoot) - entryFrame.pack(side=TOP, fill=BOTH) - - # --------- entryWidget ---------------------------------------------- - labelWidget = Label(entryFrame, text=argFieldName) - labelWidget.pack(side=LEFT) - - entryWidget = Entry(entryFrame, width=40, highlightthickness=2) - entryWidgets.append(entryWidget) - entryWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.TEXT_ENTRY_FONT_SIZE)) - entryWidget.pack(side=RIGHT, padx="3m") - - bindArrows(entryWidget) - - entryWidget.bind("", __multenterboxGetText) - entryWidget.bind("", __multenterboxCancel) - - # for the last entryWidget, if this is a multpasswordbox, - # show the contents as just asterisks - if widgetIndex == lastWidgetIndex: - if mask: - entryWidgets[widgetIndex].configure(show=mask) - - # put text into the entryWidget - if argFieldValue is None: - argFieldValue = '' - entryWidgets[widgetIndex].insert(0, '{}'.format(argFieldValue)) - widgetIndex += 1 - - # ------------------ ok button ------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=BOTTOM, fill=BOTH) - - okButton = Button(buttonsFrame, takefocus=1, text="OK") - bindArrows(okButton) - okButton.pack( - expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __multenterboxGetText - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ------------------ cancel button ------------------------------- - cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel") - bindArrows(cancelButton) - cancelButton.pack( - expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __multenterboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ------------------- time for action! ----------------- - entryWidgets[0].focus_force() # put the focus on the entryWidget - boxRoot.mainloop() # run it! - - # -------- after the run has completed ---------------------------------- - boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now - return __multenterboxText - - -# ----------------------------------------------------------------------- -# __multenterboxGetText -# ----------------------------------------------------------------------- -def __multenterboxGetText(event): - global __multenterboxText - - __multenterboxText = list() - for entryWidget in entryWidgets: - __multenterboxText.append(entryWidget.get()) - boxRoot.quit() - - -def __multenterboxCancel(event): - global __multenterboxText - __multenterboxText = None - boxRoot.quit() - - -def __multenterboxQuit(): - __multenterboxCancel(None) - - - -def __fillablebox(msg, title="", default="", mask=None, image=None, root=None): - """ - Show a box in which a user can enter some text. - You may optionally specify some default text, which will appear in the - enterbox when it is displayed. - Returns the text that the user entered, or None if he cancels the operation. - """ - - global boxRoot, __enterboxText, __enterboxDefaultText - global cancelButton, entryWidget, okButton - - if title is None: - title == "" - if default is None: - default = "" - __enterboxDefaultText = default - __enterboxText = __enterboxDefaultText - - if root: - root.withdraw() - boxRoot = Toplevel(master=root) - boxRoot.withdraw() - else: - boxRoot = Tk() - boxRoot.withdraw() - - boxRoot.protocol('WM_DELETE_WINDOW', __enterboxQuit) - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.bind("", __enterboxCancel) - - # ------------- define the messageFrame --------------------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the imageFrame --------------------------------- - try: - tk_Image = ut.load_tk_image(image) - except Exception as inst: - print(inst) - tk_Image = None - if tk_Image: - imageFrame = Frame(master=boxRoot) - imageFrame.pack(side=TOP, fill=BOTH) - label = Label(imageFrame, image=tk_Image) - label.image = tk_Image # keep a reference! - label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m') - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the entryFrame --------------------------------- - entryFrame = Frame(master=boxRoot) - entryFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # -------------------- the msg widget ---------------------------- - messageWidget = Message(messageFrame, width="4.5i", text=msg) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m') - - # --------- entryWidget ---------------------------------------------- - entryWidget = Entry(entryFrame, width=40) - bindArrows(entryWidget) - entryWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.TEXT_ENTRY_FONT_SIZE)) - if mask: - entryWidget.configure(show=mask) - entryWidget.pack(side=LEFT, padx="3m") - entryWidget.bind("", __enterboxGetText) - entryWidget.bind("", __enterboxCancel) - # put text into the entryWidget - entryWidget.insert(0, __enterboxDefaultText) - - # ------------------ ok button ------------------------------- - okButton = Button(buttonsFrame, takefocus=1, text="OK") - bindArrows(okButton) - okButton.pack( - expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __enterboxGetText - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<{}>".format(selectionEvent), handler) - - # ------------------ cancel button ------------------------------- - cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel") - bindArrows(cancelButton) - cancelButton.pack( - expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __enterboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<{}>".format(selectionEvent), handler) - - # ------------------- time for action! ----------------- - entryWidget.focus_force() # put the focus on the entryWidget - boxRoot.deiconify() - boxRoot.mainloop() # run it! - - # -------- after the run has completed ---------------------------------- - if root: - root.deiconify() - boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now - return __enterboxText - - -def __enterboxGetText(event): - global __enterboxText - - __enterboxText = entryWidget.get() - boxRoot.quit() - - -def __enterboxRestore(event): - global entryWidget - - entryWidget.delete(0, len(entryWidget.get())) - entryWidget.insert(0, __enterboxDefaultText) - - -def __enterboxCancel(event): - global __enterboxText - - __enterboxText = None - boxRoot.quit() - - -def __enterboxQuit(): - return __enterboxCancel(None) - - -# ----------------------------------------------------------------------- -# __choicebox -# ----------------------------------------------------------------------- -def __choicebox(msg, title, choices): - """ - internal routine to support choicebox() and multchoicebox() - """ - global boxRoot, __choiceboxResults, choiceboxWidget, defaultText - global choiceboxWidget, choiceboxChoices - # ------------------------------------------------------------------- - # If choices is a tuple, we make it a list so we can sort it. - # If choices is already a list, we make a new list, so that when - # we sort the choices, we don't affect the list object that we - # were given. - # ------------------------------------------------------------------- - choices = list(choices[:]) - - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - defaultButtons = ["OK", "Cancel"] - - choices = [str(c) for c in choices] - - # TODO RL: lines_to_show is set to a min and then set to 20 right after - # that. Figure out why. - lines_to_show = min(len(choices), 20) - lines_to_show = 20 - - if title is None: - title = "" - - # Initialize __choiceboxResults - # This is the value that will be returned if the user clicks the close icon - __choiceboxResults = None - - boxRoot = Tk() - # RL: Removed so top-level program can be closed with an 'x' - boxRoot.protocol('WM_DELETE_WINDOW', __choiceboxQuit) - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - st.rootWindowPosition = "+0+0" - boxRoot.geometry(st.rootWindowPosition) - boxRoot.expand = NO - boxRoot.minsize(root_width, root_height) - st.rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(st.rootWindowPosition) - - # ---------------- put the frames in the window -------------------------- - message_and_buttonsFrame = Frame(master=boxRoot) - message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO) - - messageFrame = Frame(message_and_buttonsFrame) - messageFrame.pack(side=LEFT, fill=X, expand=YES) - - buttonsFrame = Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=RIGHT, expand=NO, pady=0) - - choiceboxFrame = Frame(master=boxRoot) - choiceboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES) - - # -------------------------- put the widgets in the frames --------------- - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = Message( - messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m') - - # -------- put the choiceboxWidget in the choiceboxFrame ---------------- - choiceboxWidget = Listbox(choiceboxFrame, height=lines_to_show, borderwidth="1m", relief="flat", bg="white" - ) - - if __choiceboxMultipleSelect: - choiceboxWidget.configure(selectmode=MULTIPLE) - - choiceboxWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - - # add a vertical scrollbar to the frame - rightScrollbar = Scrollbar( - choiceboxFrame, orient=VERTICAL, command=choiceboxWidget.yview) - choiceboxWidget.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = Scrollbar( - choiceboxFrame, orient=HORIZONTAL, command=choiceboxWidget.xview) - choiceboxWidget.configure(xscrollcommand=bottomScrollbar.set) - - # pack the Listbox and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, so that the bottomScrollbar will - # be located properly. - - bottomScrollbar.pack(side=BOTTOM, fill=X) - rightScrollbar.pack(side=RIGHT, fill=Y) - - choiceboxWidget.pack( - side=LEFT, padx="1m", pady="1m", expand=YES, fill=BOTH) - - # --------------------------------------------------- - # sort the choices - # eliminate duplicates - # put the choices into the choicebox Widget - # --------------------------------------------------- - - choices = ut.lower_case_sort(choices) - - lastInserted = None - choiceboxChoices = list() - for choice in choices: - if choice == lastInserted: - continue - else: - choiceboxWidget.insert(END, choice) - choiceboxChoices.append(choice) - lastInserted = choice - - boxRoot.bind('', KeyboardListener) - - # put the buttons in the buttonsFrame - if len(choices): - okButton = Button( - buttonsFrame, takefocus=YES, text="OK", height=1, width=6) - bindArrows(okButton) - okButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __choiceboxGetChoice - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # now bind the keyboard events - choiceboxWidget.bind("", __choiceboxGetChoice) - choiceboxWidget.bind("", __choiceboxGetChoice) - else: - # now bind the keyboard events - choiceboxWidget.bind("", __choiceboxCancel) - choiceboxWidget.bind("", __choiceboxCancel) - - cancelButton = Button( - buttonsFrame, takefocus=YES, text="Cancel", height=1, width=6) - bindArrows(cancelButton) - cancelButton.pack( - expand=NO, side=BOTTOM, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __choiceboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # add special buttons for multiple select features - if len(choices) and __choiceboxMultipleSelect: - selectionButtonsFrame = Frame(messageFrame) - selectionButtonsFrame.pack(side=RIGHT, fill=Y, expand=NO) - - selectAllButton = Button( - selectionButtonsFrame, text="Select All", height=1, width=6) - bindArrows(selectAllButton) - - selectAllButton.bind("", __choiceboxSelectAll) - selectAllButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - clearAllButton = Button( - selectionButtonsFrame, text="Clear All", height=1, width=6) - bindArrows(clearAllButton) - clearAllButton.bind("", __choiceboxClearAll) - clearAllButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # -------------------- bind some keyboard events ------------------------- - boxRoot.bind("", __choiceboxCancel) - - # --------------------- the action begins -------------------------------- - # put the focus on the choiceboxWidget, and the select highlight on the - # first item - choiceboxWidget.select_set(0) - choiceboxWidget.focus_force() - - # --- run it! ----- - boxRoot.mainloop() - try: - boxRoot.destroy() - except: - pass - return __choiceboxResults - - -def __choiceboxGetChoice(event): - global boxRoot, __choiceboxResults, choiceboxWidget - - if __choiceboxMultipleSelect: - __choiceboxResults = [ - choiceboxWidget.get(index) for index in choiceboxWidget.curselection()] - else: - choice_index = choiceboxWidget.curselection() - __choiceboxResults = choiceboxWidget.get(choice_index) - - boxRoot.quit() - - -def __choiceboxSelectAll(event): - global choiceboxWidget, choiceboxChoices - - choiceboxWidget.selection_set(0, len(choiceboxChoices) - 1) - - -def __choiceboxClearAll(event): - global choiceboxWidget, choiceboxChoices - - choiceboxWidget.selection_clear(0, len(choiceboxChoices) - 1) - - -def __choiceboxCancel(event): - global boxRoot, __choiceboxResults - - __choiceboxResults = None - boxRoot.quit() - - -def __choiceboxQuit(): - __choiceboxCancel(None) - - -def KeyboardListener(event): - global choiceboxChoices, choiceboxWidget - key = event.keysym - if len(key) <= 1: - if key in string.printable: - # Find the key in the list. - # before we clear the list, remember the selected member - try: - start_n = int(choiceboxWidget.curselection()[0]) - except IndexError: - start_n = -1 - - # clear the selection. - choiceboxWidget.selection_clear(0, 'end') - - # start from previous selection +1 - for n in range(start_n + 1, len(choiceboxChoices)): - item = choiceboxChoices[n] - if item[0].lower() == key.lower(): - choiceboxWidget.selection_set(first=n) - choiceboxWidget.see(n) - return - else: - # has not found it so loop from top - for n, item in enumerate(choiceboxChoices): - if item[0].lower() == key.lower(): - choiceboxWidget.selection_set(first=n) - choiceboxWidget.see(n) - return - - # nothing matched -- we'll look for the next logical choice - for n, item in enumerate(choiceboxChoices): - if item[0].lower() > key.lower(): - if n > 0: - choiceboxWidget.selection_set(first=(n - 1)) - else: - choiceboxWidget.selection_set(first=0) - choiceboxWidget.see(n) - return - - # still no match (nothing was greater than the key) - # we set the selection to the first item in the list - lastIndex = len(choiceboxChoices) - 1 - choiceboxWidget.selection_set(first=lastIndex) - choiceboxWidget.see(lastIndex) - return - - -# ------------------------------------------------------------------- -# diropenbox -# ------------------------------------------------------------------- -def diropenbox(msg=None, title=None, default=None): - """ - A dialog to get a directory name. - Note that the msg argument, if specified, is ignored. - - Returns the name of a directory, or None if user chose to cancel. - - If the "default" argument specifies a directory name, and that - directory exists, then the dialog box will start with that directory. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str default: starting directory when dialog opens - :return: Normalized path selected by user - """ - title = getFileDialogTitle(msg, title) - localRoot = Tk() - localRoot.withdraw() - if not default: - default = None - f = ut.tk_FileDialog.askdirectory( - parent=localRoot, title=title, initialdir=default, initialfile=None - ) - localRoot.destroy() - if not f: - return None - return os.path.normpath(f) - - -# ------------------------------------------------------------------- -# getFileDialogTitle -# ------------------------------------------------------------------- -def getFileDialogTitle(msg, title): - """ - Create nicely-formatted string based on arguments msg and title - :param msg: the msg to be displayed - :param title: the window title - :return: None - """ - if msg and title: - return "%s - %s" % (title, msg) - if msg and not title: - return str(msg) - if title and not msg: - return str(title) - return None # no message and no title - - -# ------------------------------------------------------------------- -# class FileTypeObject for use with fileopenbox -# ------------------------------------------------------------------- -class FileTypeObject: - - def __init__(self, filemask): - if len(filemask) == 0: - raise AssertionError('Filetype argument is empty.') - - self.masks = list() - - if isinstance(filemask, ut.basestring): # a str or unicode - self.initializeFromString(filemask) - - elif isinstance(filemask, list): - if len(filemask) < 2: - raise AssertionError('Invalid filemask.\n' - + 'List contains less than 2 members: "{}"'.format(filemask)) - else: - self.name = filemask[-1] - self.masks = list(filemask[:-1]) - else: - raise AssertionError('Invalid filemask: "{}"'.format(filemask)) - - def __eq__(self, other): - if self.name == other.name: - return True - return False - - def add(self, other): - for mask in other.masks: - if mask in self.masks: - pass - else: - self.masks.append(mask) - - def toTuple(self): - return self.name, tuple(self.masks) - - def isAll(self): - if self.name == "All files": - return True - return False - - def initializeFromString(self, filemask): - # remove everything except the extension from the filemask - self.ext = os.path.splitext(filemask)[1] - if self.ext == "": - self.ext = ".*" - if self.ext == ".": - self.ext = ".*" - self.name = self.getName() - self.masks = ["*" + self.ext] - - def getName(self): - e = self.ext - file_types = {".*": "All", ".txt": "Text", - ".py": "Python", ".pyc": "Python", ".xls": "Excel"} - if e in file_types: - return '{} files'.format(file_types[e]) - if e.startswith("."): - return '{} files'.format(e[1:].upper()) - return '{} files'.format(e.upper()) - - -# ------------------------------------------------------------------- -# fileopenbox -# ------------------------------------------------------------------- -def fileopenbox(msg=None, title=None, default='*', filetypes=None, multiple=False): - """ - A dialog to get a file name. - - **About the "default" argument** - - The "default" argument specifies a filepath that (normally) - contains one or more wildcards. - fileopenbox will display only files that match the default filepath. - If omitted, defaults to "\*" (all files in the current directory). - - WINDOWS EXAMPLE:: - - ...default="c:/myjunk/*.py" - - will open in directory c:\\myjunk\\ and show all Python files. - - WINDOWS EXAMPLE:: - - ...default="c:/myjunk/test*.py" - - will open in directory c:\\myjunk\\ and show all Python files - whose names begin with "test". - - - Note that on Windows, fileopenbox automatically changes the path - separator to the Windows path separator (backslash). - - **About the "filetypes" argument** - - If specified, it should contain a list of items, - where each item is either: - - - a string containing a filemask # e.g. "\*.txt" - - a list of strings, where all of the strings except the last one - are filemasks (each beginning with "\*.", - such as "\*.txt" for text files, "\*.py" for Python files, etc.). - and the last string contains a filetype description - - EXAMPLE:: - - filetypes = ["*.css", ["*.htm", "*.html", "HTML files"] ] - - .. note:: If the filetypes list does not contain ("All files","*"), it will be added. - - If the filetypes list does not contain a filemask that includes - the extension of the "default" argument, it will be added. - For example, if default="\*abc.py" - and no filetypes argument was specified, then - "\*.py" will automatically be added to the filetypes argument. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: filepath with wildcards - :param object filetypes: filemasks that a user can choose, e.g. "\*.txt" - :param bool multiple: If true, more than one file can be selected - :return: the name of a file, or None if user chose to cancel - """ - localRoot = Tk() - localRoot.withdraw() - - initialbase, initialfile, initialdir, filetypes = fileboxSetup( - default, filetypes) - - # ------------------------------------------------------------ - # if initialfile contains no wildcards; we don't want an - # initial file. It won't be used anyway. - # Also: if initialbase is simply "*", we don't want an - # initialfile; it is not doing any useful work. - # ------------------------------------------------------------ - if (initialfile.find("*") < 0) and (initialfile.find("?") < 0): - initialfile = None - elif initialbase == "*": - initialfile = None - - func = ut.tk_FileDialog.askopenfilenames if multiple else ut.tk_FileDialog.askopenfilename - ret_val = func(parent=localRoot, title=getFileDialogTitle(msg, title), initialdir=initialdir, initialfile=initialfile, filetypes=filetypes - ) - - if multiple: - f = [os.path.normpath(x) for x in localRoot.tk.splitlist(ret_val)] - else: - f = os.path.normpath(ret_val) - - localRoot.destroy() - - if not f: - return None - return f - - -# ------------------------------------------------------------------- -# filesavebox -# ------------------------------------------------------------------- -def filesavebox(msg=None, title=None, default="", filetypes=None): - """ - A file to get the name of a file to save. - Returns the name of a file, or None if user chose to cancel. - - The "default" argument should contain a filename (i.e. the - current name of the file to be saved). It may also be empty, - or contain a filemask that includes wildcards. - - The "filetypes" argument works like the "filetypes" argument to - fileopenbox. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: default filename to return - :param object filetypes: filemasks that a user can choose, e.g. " \*.txt" - :return: the name of a file, or None if user chose to cancel - """ - - localRoot = Tk() - localRoot.withdraw() - - initialbase, initialfile, initialdir, filetypes = fileboxSetup( - default, filetypes) - - f = ut.tk_FileDialog.asksaveasfilename(parent=localRoot, title=getFileDialogTitle(msg, title), initialfile=initialfile, initialdir=initialdir, filetypes=filetypes - ) - localRoot.destroy() - if not f: - return None - return os.path.normpath(f) - - -# ------------------------------------------------------------------- -# -# fileboxSetup -# -# ------------------------------------------------------------------- -def fileboxSetup(default, filetypes): - if not default: - default = os.path.join(".", "*") - initialdir, initialfile = os.path.split(default) - if not initialdir: - initialdir = "." - if not initialfile: - initialfile = "*" - initialbase, initialext = os.path.splitext(initialfile) - initialFileTypeObject = FileTypeObject(initialfile) - - allFileTypeObject = FileTypeObject("*") - ALL_filetypes_was_specified = False - - if not filetypes: - filetypes = list() - filetypeObjects = list() - - for filemask in filetypes: - fto = FileTypeObject(filemask) - - if fto.isAll(): - ALL_filetypes_was_specified = True # remember this - - if fto == initialFileTypeObject: - initialFileTypeObject.add(fto) # add fto to initialFileTypeObject - else: - filetypeObjects.append(fto) - - # ------------------------------------------------------------------ - # make sure that the list of filetypes includes the ALL FILES type. - # ------------------------------------------------------------------ - if ALL_filetypes_was_specified: - pass - elif allFileTypeObject == initialFileTypeObject: - pass - else: - filetypeObjects.insert(0, allFileTypeObject) - # ------------------------------------------------------------------ - # Make sure that the list includes the initialFileTypeObject - # in the position in the list that will make it the default. - # This changed between Python version 2.5 and 2.6 - # ------------------------------------------------------------------ - if len(filetypeObjects) == 0: - filetypeObjects.append(initialFileTypeObject) - - if initialFileTypeObject in (filetypeObjects[0], filetypeObjects[-1]): - pass - else: - if ut.runningPython27: - filetypeObjects.append(initialFileTypeObject) - else: - filetypeObjects.insert(0, initialFileTypeObject) - - filetypes = [fto.toTuple() for fto in filetypeObjects] - - return initialbase, initialfile, initialdir, filetypes - - -def __buttonEvent(event=None, buttons=None, virtual_event=None): - """ - Handle an event that is generated by a person interacting with a button. It may be a button press - or a key press. - """ - # TODO: Replace globals with tkinter variables - global boxRoot, __replyButtonText - - # Determine window location and save to global - m = re.match("(\d+)x(\d+)([-+]\d+)([-+]\d+)", boxRoot.geometry()) - if not m: - raise ValueError( - "failed to parse geometry string: {}".format(boxRoot.geometry())) - width, height, xoffset, yoffset = [int(s) for s in m.groups()] - st.rootWindowPosition = '{0:+g}{1:+g}'.format(xoffset, yoffset) - - # print('{0}:{1}:{2}'.format(event, buttons, virtual_event)) - if virtual_event == 'cancel': - for button_name, button in buttons.items(): - if 'cancel_choice' in button: - __replyButtonText = button['original_text'] - __replyButtonText = None - boxRoot.quit() - return - - if virtual_event == 'select': - text = event.widget.config('text')[-1] - if not isinstance(text, ut.basestring): - text = ' '.join(text) - for button_name, button in buttons.items(): - if button['clean_text'] == text: - __replyButtonText = button['original_text'] - boxRoot.quit() - return - - # Hotkeys - if buttons: - for button_name, button in buttons.items(): - hotkey_pressed = event.keysym - if event.keysym != event.char: # A special character - hotkey_pressed = '<{}>'.format(event.keysym) - if button['hotkey'] == hotkey_pressed: - __replyButtonText = button_name - boxRoot.quit() - return - - print("Event not understood") - - -def __put_buttons_in_buttonframe(choices, default_choice, cancel_choice): - """Put the buttons in the buttons frame - """ - global buttonsFrame, cancel_invoke - - # TODO: I'm using a dict to hold buttons, but this could all be cleaned up if I subclass Button to hold - # all the event bindings, etc - # TODO: Break __buttonEvent out into three: regular keyboard, default - # select, and cancel select. - unique_choices = ut.uniquify_list_of_strings(choices) - # Create buttons dictionary and Tkinter widgets - buttons = dict() - for button_text, unique_button_text in zip(choices, unique_choices): - this_button = dict() - this_button['original_text'] = button_text - this_button['clean_text'], this_button[ - 'hotkey'], hotkey_position = ut.parse_hotkey(button_text) - this_button['widget'] = Button(buttonsFrame, - takefocus=1, - text=this_button['clean_text'], - underline=hotkey_position) - this_button['widget'].pack( - expand=YES, side=LEFT, padx='1m', pady='1m', ipadx='2m', ipady='1m') - buttons[unique_button_text] = this_button - # Bind arrows, Enter, Escape - for this_button in buttons.values(): - bindArrows(this_button['widget']) - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - this_button['widget'].bind("<{}>".format(selectionEvent), - lambda e: __buttonEvent( - e, buttons, virtual_event='select'), - add=True) - - # Assign default and cancel buttons - if cancel_choice in buttons: - buttons[cancel_choice]['cancel_choice'] = True - boxRoot.bind_all('', lambda e: __buttonEvent( - e, buttons, virtual_event='cancel'), add=True) - boxRoot.protocol('WM_DELETE_WINDOW', lambda: __buttonEvent( - None, buttons, virtual_event='cancel')) - if default_choice in buttons: - buttons[default_choice]['default_choice'] = True - buttons[default_choice]['widget'].focus_force() - # Bind hotkeys - for hk in [button['hotkey'] for button in buttons.values() if button['hotkey']]: - boxRoot.bind_all(hk, lambda e: __buttonEvent(e, buttons), add=True) - - return diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/demo.py b/app_windows/lib/easygui/build/lib/easygui/boxes/demo.py deleted file mode 100644 index 88e3cdf..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/demo.py +++ /dev/null @@ -1,378 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - -import os -import sys - -from . import utils as ut - -from .base_boxes import buttonbox -from .text_box import textbox -from .base_boxes import diropenbox -from .base_boxes import fileopenbox -from .base_boxes import filesavebox - -from .derived_boxes import ynbox -from .derived_boxes import ccbox -from .derived_boxes import boolbox -from .derived_boxes import indexbox -from .derived_boxes import msgbox -from .derived_boxes import integerbox -from .derived_boxes import multenterbox -from .derived_boxes import enterbox -from .derived_boxes import exceptionbox -from .derived_boxes import choicebox -from .derived_boxes import codebox -from .derived_boxes import passwordbox -from .derived_boxes import multpasswordbox -from .derived_boxes import multchoicebox - -from . import about -from .about import eg_version -from .about import abouteasygui - -# -------------------------------------------------------------- -# -# test/demo easygui -# -# ----------------------------------------------------------------------- - -package_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - - -def egdemo(): - """ - Run the EasyGui demo. - """ - # clear the console - print('\n' * 100) - - msg = list() - msg.append("Pick the kind of box that you wish to demo.") - msg.append(" * Python version {}".format(sys.version)) - msg.append(" * EasyGui version {}".format(eg_version)) - msg.append(" * Tk version {}".format(ut.TkVersion)) - intro_message = "\n".join(msg) - - while True: # do forever - choices = [ - "msgbox", - "buttonbox", - "buttonbox(image) -- a buttonbox that displays an image", - "choicebox", - "multchoicebox", - "textbox", - "ynbox", - "ccbox", - "enterbox", - "enterbox(image) -- an enterbox that displays an image", - "exceptionbox", - "codebox", - "integerbox", - "boolbox", - "indexbox", - "filesavebox", - "fileopenbox", - "passwordbox", - "multenterbox", - "multpasswordbox", - "diropenbox", - "About EasyGui", - " Help" - ] - choice = choicebox( - msg=intro_message, title="EasyGui " + eg_version, - choices=choices) - - if not choice: - return - - reply = choice.split() - - if reply[0] == "msgbox": - reply = msgbox("short msg", "This is a long title") - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "About": - reply = abouteasygui() - - elif reply[0] == "Help": - _demo_help() - - elif reply[0] == "buttonbox": - reply = buttonbox( - choices=['one', 'two', 'two', 'three'], default_choice='two') - print("Reply was: {!r}".format(reply)) - - title = "Demo of Buttonbox with many, many buttons!" - msg = ("This buttonbox shows what happens when you " - "specify too many buttons.") - reply = buttonbox( - msg=msg, title=title, choices=choices, cancel_choice='msgbox') - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "buttonbox(image)": - _demo_buttonbox_with_image() - - elif reply[0] == "boolbox": - reply = boolbox() - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "enterbox": - image = os.path.join(package_dir, "python_and_check_logo.gif") - message = ("Enter the name of your best friend." - "\n(Result will be stripped.)") - reply = enterbox(message, "Love!", " Suzy Smith ") - print("Reply was: {!r}".format(reply)) - - message = ("Enter the name of your best friend." - "\n(Result will NOT be stripped.)") - reply = enterbox( - message, "Love!", " Suzy Smith ", strip=False) - print("Reply was: {!r}".format(reply)) - - reply = enterbox("Enter the name of your worst enemy:", "Hate!") - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "enterbox(image)": - image = os.path.join(package_dir, "python_and_check_logo.gif") - message = "What kind of snake is this?" - reply = enterbox(message, "Quiz", image=image) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "exceptionbox": - try: - thisWillCauseADivideByZeroException = 1 / 0 - except: - exceptionbox() - - elif reply[0] == "integerbox": - reply = integerbox( - "Enter a number between 3 and 333", - "Demo: integerbox WITH a default value", 222, 3, 333) - print("Reply was: {!r}".format(reply)) - - reply = integerbox( - "Enter a number between 0 and 99", - "Demo: integerbox WITHOUT a default value" - ) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "diropenbox": - _demo_diropenbox() - elif reply[0] == "fileopenbox": - _demo_fileopenbox() - elif reply[0] == "filesavebox": - _demo_filesavebox() - - elif reply[0] == "indexbox": - title = reply[0] - msg = "Demo of " + reply[0] - choices = ["Choice1", "Choice2", "Choice3", "Choice4"] - reply = indexbox(msg, title, choices) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "passwordbox": - reply = passwordbox("Demo of password box WITHOUT default" - + "\n\nEnter your secret password", - "Member Logon") - print("Reply was: {!s}".format(reply)) - - reply = passwordbox("Demo of password box WITH default" - + "\n\nEnter your secret password", - "Member Logon", "alfie") - print("Reply was: {!s}".format(reply)) - - elif reply[0] == "multenterbox": - msg = "Enter your personal information" - title = "Credit Card Application" - fieldNames = ["Name", "Street Address", "City", "State", "ZipCode"] - fieldValues = list() # we start with blanks for the values - fieldValues = multenterbox(msg, title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: - break - errs = list() - for n, v in zip(fieldNames, fieldValues): - if v.strip() == "": - errs.append('"{}" is a required field.'.format(n)) - if not len(errs): - break # no problems found - fieldValues = multenterbox( - "\n".join(errs), title, fieldNames, fieldValues) - - print("Reply was: {}".format(fieldValues)) - - elif reply[0] == "multpasswordbox": - msg = "Enter logon information" - title = "Demo of multpasswordbox" - fieldNames = ["Server ID", "User ID", "Password"] - fieldValues = list() # we start with blanks for the values - fieldValues = multpasswordbox(msg, title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: - break - errs = list() - for n, v in zip(fieldNames, fieldValues): - if v.strip() == "": - errs.append('"{}" is a required field.\n\n'.format(n)) - if not len(errs): - break # no problems found - fieldValues = multpasswordbox( - "".join(errs), title, fieldNames, fieldValues) - - print("Reply was: {!s}".format(fieldValues)) - - elif reply[0] == "ynbox": - title = "Demo of ynbox" - msg = "Were you expecting the Spanish Inquisition?" - reply = ynbox(msg, title) - print("Reply was: {!r}".format(reply)) - if reply: - msgbox("NOBODY expects the Spanish Inquisition!", "Wrong!") - - elif reply[0] == "ccbox": - msg = "Insert your favorite message here" - title = "Demo of ccbox" - reply = ccbox(msg, title) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "choicebox": - title = "Demo of choicebox" - longchoice = ( - "This is an example of a very long option " - "which you may or may not wish to choose." - * 2) - listChoices = ["nnn", "ddd", "eee", "fff", "aaa", - longchoice, "aaa", "bbb", "ccc", "ggg", "hhh", - "iii", "jjj", "kkk", "LLL", "mmm", "nnn", - "ooo", "ppp", "qqq", - "rrr", "sss", "ttt", "uuu", "vvv"] - - msg = ("Pick something. " + - ("A wrapable sentence of text ?! " * 30) + - "\nA separate line of text." * 6) - reply = choicebox(msg=msg, choices=listChoices) - print("Reply was: {!r}".format(reply)) - - msg = "Pick something. " - reply = choicebox(msg=msg, title=title, choices=listChoices) - print("Reply was: {!r}".format(reply)) - - msg = "Pick something. " - reply = choicebox( - msg="The list of choices is empty!", choices=list()) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "multchoicebox": - listChoices = ["aaa", "bbb", "ccc", "ggg", "hhh", "iii", - "jjj", "kkk", "LLL", "mmm", "nnn", "ooo", - "ppp", "qqq", "rrr", "sss", "ttt", "uuu", - "vvv"] - - msg = "Pick as many choices as you wish." - reply = multchoicebox(msg, "Demo of multchoicebox", listChoices) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "textbox": - _demo_textbox(reply[0]) - elif reply[0] == "codebox": - _demo_codebox(reply[0]) - - else: - msgbox("Choice\n\n{}\n\nis not recognized".format( - choice), "Program Logic Error") - return - - -def _demo_textbox(reply): - text_snippet = (( - "It was the best of times, and it was the worst of times. The rich " - "ate cake, and the poor had cake recommended to them, but wished " - "only for enough cash to buy bread. The time was ripe for " - "revolution! " - * 5) + "\n\n") * 10 - title = "Demo of textbox" - msg = "Here is some sample text. " * 16 - reply = textbox(msg, title, text_snippet) - print("Reply was: {!s}".format(reply)) - - -def _demo_codebox(reply): - # TODO RL: Turn this sample code into the code in this module, just for fun - code_snippet = ("dafsdfa dasflkj pp[oadsij asdfp;ij asdfpjkop asdfpok asdfpok asdfpok" * 3) + "\n" + """# here is some dummy Python code -for someItem in myListOfStuff: - do something(someItem) - do something() - do something() - if somethingElse(someItem): - doSomethingEvenMoreInteresting() - -""" * 16 - msg = "Here is some sample code. " * 16 - reply = codebox(msg, "Code Sample", code_snippet) - print("Reply was: {!r}".format(reply)) - - -def _demo_buttonbox_with_image(): - msg = "Do you like this picture?\nIt is " - choices = ["Yes", "No", "No opinion"] - - for image in [ - os.path.join(package_dir, "python_and_check_logo.gif"), - os.path.join(package_dir, "python_and_check_logo.jpg"), - os.path.join(package_dir, "python_and_check_logo.png"), - os.path.join(package_dir, "zzzzz.gif")]: - reply = buttonbox(msg + image, image=image, choices=choices) - print("Reply was: {!r}".format(reply)) - - -def _demo_help(): - codebox("EasyGui Help", text=about.EASYGUI_ABOUT_INFORMATION) - - -def _demo_filesavebox(): - filename = "myNewFile.txt" - title = "File SaveAs" - msg = "Save file as:" - - f = filesavebox(msg, title, default=filename) - print("You chose to save file: {}".format(f)) - - -def _demo_diropenbox(): - title = "Demo of diropenbox" - msg = "Pick the directory that you wish to open." - d = diropenbox(msg, title) - print("You chose directory...: {}".format(d)) - - d = diropenbox(msg, title, default="./") - print("You chose directory...: {}".format(d)) - - d = diropenbox(msg, title, default="c:/") - print("You chose directory...: {}".format(d)) - - -def _demo_fileopenbox(): - msg = "Python files" - title = "Open files" - default = "*.py" - f = fileopenbox(msg, title, default=default) - print("You chose to open file: {}".format(f)) - - default = "./*.gif" - msg = "Some other file types (Multi-select)" - filetypes = ["*.jpg", ["*.zip", "*.tgs", "*.gz", - "Archive files"], ["*.htm", "*.html", "HTML files"]] - f = fileopenbox( - msg, title, default=default, filetypes=filetypes, multiple=True) - print("You chose to open file: %s" % f) diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/derived_boxes.py b/app_windows/lib/easygui/build/lib/easygui/boxes/derived_boxes.py deleted file mode 100644 index cdf4ae3..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/derived_boxes.py +++ /dev/null @@ -1,542 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - -from . import base_boxes as bb -from . import text_box as tb -from . import utils as ut - -# ------------------------------------------------------------------- -# various boxes built on top of the basic buttonbox -# ----------------------------------------------------------------------- - -# ----------------------------------------------------------------------- -# ynbox -# ----------------------------------------------------------------------- - - -def ynbox(msg="Shall I continue?", title=" ", - choices=("[]Yes", "[]No"), image=None, - default_choice='[]Yes', cancel_choice='[]No'): - """ - Display a msgbox with choices of Yes and No. - - The returned value is calculated this way:: - - if the first choice ("Yes") is chosen, or if the dialog is cancelled: - return True - else: - return False - - If invoked without a msg argument, displays a generic - request for a confirmation - that the user wishes to continue. So it can be used this way:: - - if ynbox(): - pass # continue - else: - sys.exit(0) # exit the program - - :param msg: the msg to be displayed - :type msg: str - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which - button should be pressed - - :return: True if 'Yes' or dialog is cancelled, False if 'No' - """ - return boolbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - -# ----------------------------------------------------------------------- -# ccbox -# ----------------------------------------------------------------------- - - -def ccbox(msg="Shall I continue?", title=" ", - choices=("C[o]ntinue", "C[a]ncel"), image=None, - default_choice='Continue', cancel_choice='Cancel'): - """ - Display a msgbox with choices of Continue and Cancel. - - The returned value is calculated this way:: - - if the first choice ("Continue") is chosen, - or if the dialog is cancelled: - return True - else: - return False - - If invoked without a msg argument, displays a generic - request for a confirmation - that the user wishes to continue. So it can be used this way:: - - if ccbox(): - pass # continue - else: - sys.exit(0) # exit the program - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, - which button should be pressed - - :return: True if 'Continue' or dialog is cancelled, False if 'Cancel' - """ - return boolbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - -# ----------------------------------------------------------------------- -# boolbox -# ----------------------------------------------------------------------- - - -def boolbox(msg="Shall I continue?", title=" ", - choices=("[Y]es", "[N]o"), image=None, - default_choice='Yes', cancel_choice='No'): - """ - Display a boolean msgbox. - - The returned value is calculated this way:: - - if the first choice is chosen, or if the dialog is cancelled: - returns True - else: - returns False - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which button - should be pressed - :return: True if first button pressed or dialog is cancelled, False if - second button is pressed - """ - if len(choices) != 2: - raise AssertionError( - 'boolbox takes exactly 2 choices! Consider using indexbox instead' - ) - - reply = bb.buttonbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - if reply == choices[0]: - return True - else: - return False - - -# ----------------------------------------------------------------------- -# indexbox -# ----------------------------------------------------------------------- -def indexbox(msg="Shall I continue?", title=" ", - choices=("Yes", "No"), image=None, - default_choice='Yes', cancel_choice='No'): - """ - Display a buttonbox with the specified choices. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, - which button should be pressed - :return: the index of the choice selected, starting from 0 - """ - reply = bb.buttonbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - if reply is None: - return None - for i, choice in enumerate(choices): - if reply == choice: - return i - msg = ("There is a program logic error in the EasyGui code " - "for indexbox.\nreply={0}, choices={1}".format( - reply, choices)) - raise AssertionError(msg) - - -# ----------------------------------------------------------------------- -# msgbox -# ----------------------------------------------------------------------- -def msgbox(msg="(Your message goes here)", title=" ", - ok_button="OK", image=None, root=None): - """ - Display a message box - - :param str msg: the msg to be displayed - :param str title: the window title - :param str ok_button: text to show in the button - :param str image: Filename of image to display - :param tk_widget root: Top-level Tk widget - :return: the text of the ok_button - """ - if not isinstance(ok_button, ut.basestring): - raise AssertionError( - "The 'ok_button' argument to msgbox must be a string.") - - return bb.buttonbox(msg=msg, - title=title, - choices=[ok_button], - image=image, - root=root, - default_choice=ok_button, - cancel_choice=ok_button) - - -# ------------------------------------------------------------------- -# integerbox -# ------------------------------------------------------------------- -def integerbox(msg="", title=" ", default="", - lowerbound=0, upperbound=99, image=None, root=None): - """ - Show a box in which a user can enter an integer. - - In addition to arguments for msg and title, this function accepts - integer arguments for "default", "lowerbound", and "upperbound". - - The default argument may be None. - - When the user enters some text, the text is checked to verify that it - can be converted to an integer between the lowerbound and upperbound. - - If it can be, the integer (not the text) is returned. - - If it cannot, then an error msg is displayed, and the integerbox is - redisplayed. - - If the user cancels the operation, None is returned. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str default: The default value to return - :param int lowerbound: The lower-most value allowed - :param int upperbound: The upper-most value allowed - :param str image: Filename of image to display - :param tk_widget root: Top-level Tk widget - :return: the integer value entered by the user - - """ - - if not msg: - msg = "Enter an integer between {0} and {1}".format( - lowerbound, upperbound) - - # Validate the arguments for default, lowerbound and upperbound and - # convert to integers - exception_string = ( - 'integerbox "{0}" must be an integer. It is >{1}< of type {2}') - if default: - try: - default = int(default) - except ValueError: - raise ValueError( - exception_string.format('default', default, type(default))) - try: - lowerbound = int(lowerbound) - except ValueError: - raise ValueError( - exception_string.format('lowerbound', - lowerbound, type(lowerbound))) - try: - upperbound = int(upperbound) - except ValueError: - raise ValueError( - exception_string.format('upperbound', - upperbound, type(upperbound))) - - while True: - reply = enterbox(msg, title, str(default), image=image, root=root) - if reply is None: - return None - try: - reply = int(reply) - except: - msgbox('The value that you entered:\n\t"{}"\nis not an integer.' - .format(reply), "Error") - continue - if reply < lowerbound: - msgbox('The value that you entered is less than the lower ' - 'bound of {}.'.format(lowerbound), "Error") - continue - if reply > upperbound: - msgbox('The value that you entered is greater than the upper bound' - ' of {}.'.format( - upperbound), "Error") - continue - # reply has passed all validation checks. - # It is an integer between the specified bounds. - return reply - - -# ------------------------------------------------------------------- -# multenterbox -# ------------------------------------------------------------------- -# TODO RL: Should defaults be list constructors. -# i think after multiple calls, the value is retained. -# TODO RL: Rename/alias to multienterbox? -# default should be None and then in the logic create an empty list. -def multenterbox(msg="Fill in values for the fields.", title=" ", - fields=(), values=()): - r""" - Show screen with multiple data entry fields. - - If there are fewer values than names, the list of values is padded with - empty strings until the number of values is the same as the number - of names. - - If there are more values than names, the list of values - is truncated so that there are as many values as names. - - Returns a list of the values of the fields, - or None if the user cancels the operation. - - Here is some example code, that shows how values returned from - multenterbox can be checked for validity before they are accepted:: - - msg = "Enter your personal information" - title = "Credit Card Application" - fieldNames = ["Name","Street Address","City","State","ZipCode"] - fieldValues = [] # we start with blanks for the values - fieldValues = multenterbox(msg,title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: break - errmsg = "" - for i in range(len(fieldNames)): - if fieldValues[i].strip() == "": - errmsg += ('"%s" is a required field.\n\n' % fieldNames[i]) - if errmsg == "": - break # no problems found - fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues) - - print("Reply was: %s" % str(fieldValues)) - - :param str msg: the msg to be displayed. - :param str title: the window title - :param list fields: a list of fieldnames. - :param list values: a list of field values - :return: String - """ - return bb.__multfillablebox(msg, title, fields, values, None) - - -# ----------------------------------------------------------------------- -# multpasswordbox -# ----------------------------------------------------------------------- -def multpasswordbox(msg="Fill in values for the fields.", - title=" ", fields=tuple(), values=tuple()): - r""" - Same interface as multenterbox. But in multpassword box, - the last of the fields is assumed to be a password, and - is masked with asterisks. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param list fields: a list of fieldnames. - :param list values: a list of field values - :return: String - - **Example** - - Here is some example code, that shows how values returned from - multpasswordbox can be checked for validity before they are accepted:: - - msg = "Enter logon information" - title = "Demo of multpasswordbox" - fieldNames = ["Server ID", "User ID", "Password"] - fieldValues = [] # we start with blanks for the values - fieldValues = multpasswordbox(msg,title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: break - errmsg = "" - for i in range(len(fieldNames)): - if fieldValues[i].strip() == "": - errmsg = errmsg + ('"%s" is a required field.\n\n' % - fieldNames[i]) - if errmsg == "": break # no problems found - fieldValues = multpasswordbox(errmsg, title, - fieldNames, fieldValues) - - print("Reply was: %s" % str(fieldValues)) - - """ - return bb.__multfillablebox(msg, title, fields, values, "*") - - -# ------------------------------------------------------------------- -# enterbox -# ------------------------------------------------------------------- -def enterbox(msg="Enter something.", title=" ", default="", - strip=True, image=None, root=None): - """ - Show a box in which a user can enter some text. - - You may optionally specify some default text, which will appear in the - enterbox when it is displayed. - - Example:: - - reply = enterbox(....) - if reply: - ... - else: - ... - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: value returned if user does not change it - :param bool strip: If True, the return value will have - its whitespace stripped before being returned - :return: the text that the user entered, or None if he cancels - the operation. - """ - result = bb.__fillablebox( - msg, title, default=default, mask=None, image=image, root=root) - if result and strip: - result = result.strip() - return result - - -def passwordbox(msg="Enter your password.", title=" ", default="", - image=None, root=None): - """ - Show a box in which a user can enter a password. - The text is masked with asterisks, so the password is not displayed. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: value returned if user does not change it - :return: the text that the user entered, or None if he cancels - the operation. - """ - return bb.__fillablebox(msg, title, default, mask="*", - image=image, root=root) - - -# ------------------------------------------------------------------- -# multchoicebox -# ------------------------------------------------------------------- -def multchoicebox(msg="Pick as many items as you like.", title=" ", - choices=(), **kwargs): - """ - Present the user with a list of choices. - allow him to select multiple items and return them in a list. - if the user doesn't choose anything from the list, return the empty list. - return None if he cancelled selection. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :return: List containing choice selected or None if cancelled - - """ - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - - global __choiceboxMultipleSelect - __choiceboxMultipleSelect = 1 - return bb.__choicebox(msg, title, choices) - - -# ----------------------------------------------------------------------- -# choicebox -# ----------------------------------------------------------------------- -def choicebox(msg="Pick something.", title=" ", choices=()): - """ - Present the user with a list of choices. - return the choice that he selects. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :return: List containing choice selected or None if cancelled - """ - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - - global __choiceboxMultipleSelect - __choiceboxMultipleSelect = 0 - return bb.__choicebox(msg, title, choices) - - -# ----------------------------------------------------------------------- -# exceptionbox -# ----------------------------------------------------------------------- -def exceptionbox(msg=None, title=None): - """ - Display a box that gives information about - an exception that has just been raised. - - The caller may optionally pass in a title for the window, or a - msg to accompany the error information. - - Note that you do not need to (and cannot) pass an exception object - as an argument. The latest exception will automatically be used. - - :param str msg: the msg to be displayed - :param str title: the window title - :return: None - - """ - if title is None: - title = "Error Report" - if msg is None: - msg = "An error (exception) has occurred in the program." - - codebox(msg, title, ut.exception_format()) - - -# ------------------------------------------------------------------- -# codebox -# ------------------------------------------------------------------- - -def codebox(msg="", title=" ", text=""): - """ - Display some text in a monospaced font, with no line wrapping. - This function is suitable for displaying code and text that is - formatted using spaces. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - """ - return tb.textbox(msg, title, text, codebox=1) diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/egstore.py b/app_windows/lib/easygui/build/lib/easygui/boxes/egstore.py deleted file mode 100644 index 3a382b1..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/egstore.py +++ /dev/null @@ -1,158 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - - -import os -import pickle - - -# ----------------------------------------------------------------------- -# -# class EgStore -# -# ----------------------------------------------------------------------- -class EgStore: - - r""" -A class to support persistent storage. - -You can use EgStore to support the storage and retrieval -of user settings for an EasyGui application. - -**Example A: define a class named Settings as a subclass of EgStore** -:: - - class Settings(EgStore): - def __init__(self, filename): # filename is required - #------------------------------------------------- - # Specify default/initial values for variables that - # this particular application wants to remember. - #------------------------------------------------- - self.userId = "" - self.targetServer = "" - - #------------------------------------------------- - # For subclasses of EgStore, these must be - # the last two statements in __init__ - #------------------------------------------------- - self.filename = filename # this is required - self.restore() # restore values from the storage file if possible - -**Example B: create settings, a persistent Settings object** -:: - - settingsFile = "myApp_settings.txt" - settings = Settings(settingsFile) - - user = "obama_barak" - server = "whitehouse1" - settings.userId = user - settings.targetServer = server - settings.store() # persist the settings - - # run code that gets a new value for userId, and persist the settings - user = "biden_joe" - settings.userId = user - settings.store() - -**Example C: recover the Settings instance, change an attribute, and store it again.** -:: - - settings = Settings(settingsFile) - settings.userId = "vanrossum_g" - settings.store() - -""" - - def __init__(self, filename): # obtaining filename is required - self.filename = None - raise NotImplementedError() - - def restore(self): - """ - Set the values of whatever attributes are recoverable - from the pickle file. - - Populate the attributes (the __dict__) of the EgStore object - from the attributes (the __dict__) of the pickled object. - - If the pickled object has attributes that have been initialized - in the EgStore object, then those attributes of the EgStore object - will be replaced by the values of the corresponding attributes - in the pickled object. - - If the pickled object is missing some attributes that have - been initialized in the EgStore object, then those attributes - of the EgStore object will retain the values that they were - initialized with. - - If the pickled object has some attributes that were not - initialized in the EgStore object, then those attributes - will be ignored. - - IN SUMMARY: - - After the recover() operation, the EgStore object will have all, - and only, the attributes that it had when it was initialized. - - Where possible, those attributes will have values recovered - from the pickled object. - """ - if not os.path.exists(self.filename): - return self - if not os.path.isfile(self.filename): - return self - - try: - with open(self.filename, "rb") as f: - unpickledObject = pickle.load(f) - - for key in list(self.__dict__.keys()): - default = self.__dict__[key] - self.__dict__[key] = unpickledObject.__dict__.get(key, default) - except: - pass - - return self - - def store(self): - """ - Save the attributes of the EgStore object to a pickle file. - Note that if the directory for the pickle file does not already exist, - the store operation will fail. - """ - with open(self.filename, "wb") as f: - pickle.dump(self, f) - - def kill(self): - """ - Delete my persistent file (i.e. pickle file), if it exists. - """ - if os.path.isfile(self.filename): - os.remove(self.filename) - return - - def __str__(self): - """ - return my contents as a string in an easy-to-read format. - """ - # find the length of the longest attribute name - longest_key_length = 0 - keys = list() - for key in self.__dict__.keys(): - keys.append(key) - longest_key_length = max(longest_key_length, len(key)) - - keys.sort() # sort the attribute names - lines = list() - for key in keys: - value = self.__dict__[key] - key = key.ljust(longest_key_length) - lines.append("%s : %s\n" % (key, repr(value))) - return "".join(lines) # return a string showing the attributes diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/state.py b/app_windows/lib/easygui/build/lib/easygui/boxes/state.py deleted file mode 100644 index eabd32a..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/state.py +++ /dev/null @@ -1,23 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -# Starting and global variables - -rootWindowPosition = "+300+200" - -PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif") -MONOSPACE_FONT_FAMILY = "Courier" - -PROPORTIONAL_FONT_SIZE = 10 -# a little smaller, because it is more legible at a smaller size -MONOSPACE_FONT_SIZE = 9 -TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see - - -STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"] diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/text_box.py b/app_windows/lib/easygui/build/lib/easygui/boxes/text_box.py deleted file mode 100644 index 4e6d6c2..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/text_box.py +++ /dev/null @@ -1,199 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -import sys - -from . import utils as ut -from .utils import * -from . import state as st - - -def textbox(msg="", title=" ", text="", codebox=0): - """ - Display some text in a proportional font with line wrapping at word breaks. - This function is suitable for displaying general written text. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - :param str codebox: if 1, act as a codebox - """ - - if msg is None: - msg = "" - if title is None: - title = "" - - boxRoot = tk.Tk() - - def __textboxOK(event): - boxRoot.quit() - - # Quit when x button pressed - boxRoot.protocol('WM_DELETE_WINDOW', boxRoot.quit) - - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - st.rootWindowPosition = "+0+0" - boxRoot.geometry(st.rootWindowPosition) - boxRoot.expand = tk.NO - boxRoot.minsize(root_width, root_height) - st.rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(st.rootWindowPosition) - - mainframe = tk.Frame(master=boxRoot) - mainframe.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) - - # ---- put frames in the window ----------------------------------- - # we pack the textboxFrame first, so it will expand first - textboxFrame = tk.Frame(mainframe, borderwidth=3) - textboxFrame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=tk.YES) - - message_and_buttonsFrame = tk.Frame(mainframe) - message_and_buttonsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) - - messageFrame = tk.Frame(message_and_buttonsFrame) - messageFrame.pack(side=tk.LEFT, fill=tk.X, expand=tk.YES) - - buttonsFrame = tk.Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=tk.RIGHT, expand=tk.NO) - - # -------------------- put widgets in the frames -------------------- - - # put a textArea in the top frame - if codebox: - character_width = int((root_width * 0.6) / st.MONOSPACE_FONT_SIZE) - textArea = tk.Text( - textboxFrame, height=25, width=character_width, padx="2m", - pady="1m") - textArea.configure(wrap=tk.NONE) - textArea.configure(font=(st.MONOSPACE_FONT_FAMILY, - st.MONOSPACE_FONT_SIZE)) - - else: - character_width = int((root_width * 0.6) / st.MONOSPACE_FONT_SIZE) - textArea = tk.Text( - textboxFrame, height=25, width=character_width, padx="2m", - pady="1m" - ) - textArea.configure(wrap=tk.WORD) - textArea.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - - # some simple keybindings for scrolling - mainframe.bind("", textArea.yview_scroll(1, tk.PAGES)) - mainframe.bind("", textArea.yview_scroll(-1, tk.PAGES)) - - mainframe.bind("", textArea.xview_scroll(1, tk.PAGES)) - mainframe.bind("", textArea.xview_scroll(-1, tk.PAGES)) - - mainframe.bind("", textArea.yview_scroll(1, tk.UNITS)) - mainframe.bind("", textArea.yview_scroll(-1, tk.UNITS)) - - # add a vertical scrollbar to the frame - rightScrollbar = tk.Scrollbar( - textboxFrame, orient=tk.VERTICAL, command=textArea.yview) - textArea.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = tk.Scrollbar( - textboxFrame, orient=tk.HORIZONTAL, command=textArea.xview) - textArea.configure(xscrollcommand=bottomScrollbar.set) - - # pack the textArea and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, - # so that the bottomScrollbar will be located properly. - - # Note that we need a bottom scrollbar only for code. - # Text will be displayed with wordwrap, so we don't need to have - # a horizontal scroll for it. - if codebox: - bottomScrollbar.pack(side=tk.BOTTOM, fill=tk.X) - rightScrollbar.pack(side=tk.RIGHT, fill=tk.Y) - - textArea.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES) - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = tk.Message( - messageFrame, anchor=tk.NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH, - padx='1m', pady='1m') - - # put the buttons in the buttonsFrame - okButton = tk.Button( - buttonsFrame, takefocus=tk.YES, text="OK", height=1, width=6) - okButton.pack( - expand=tk.NO, side=tk.TOP, padx='2m', pady='1m', ipady="1m", - ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __textboxOK - for selectionEvent in ["Return", "Button-1", "Escape"]: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ----------------- the action begins ------------------------------------ - text = to_string(text) - try: - textArea.insert('end', text, "normal") - except: - msgbox("Exception when trying to load the textArea.") - sys.exit(16) - - try: - okButton.focus_force() - except: - msgbox("Exception when trying to put focus on okButton.") - sys.exit(16) - - boxRoot.mainloop() - - # this line MUST go before the line that destroys boxRoot - areaText = textArea.get(0.0, 'end-1c') - boxRoot.destroy() - return areaText # return __replyButtonText - - -def to_string(something): - if isinstance(something, ut.basestring): - return something - try: - text = "".join(something) # convert a list or a tuple to a string - except: - msgbox( - "Exception when trying to convert {} to text in textArea" - .format(type(something))) - sys.exit(16) - return text - - -def demo_textbox(): - text_snippet = (( - "It was the best of times, and it was the worst of times. The rich " - "ate cake, and the poor had cake recommended to them, but wished " - "only for enough cash to buy bread. The time was ripe for " - "revolution! " - * 5) + "\n\n") * 10 - title = "Demo of textbox" - msg = "Here is some sample text. " * 16 - reply = textbox(msg, title, text_snippet) - print("Reply was: {!s}".format(reply)) diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/updatable_text_box.py b/app_windows/lib/easygui/build/lib/easygui/boxes/updatable_text_box.py deleted file mode 100644 index 638ade8..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/updatable_text_box.py +++ /dev/null @@ -1,270 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -import sys - -if sys.hexversion >= 0x020600F0: - runningPython26 = True -else: - runningPython26 = False - -if sys.hexversion >= 0x030000F0: - runningPython3 = True -else: - runningPython3 = False - -# Try to import the Python Image Library. If it doesn't exist, only .gif -# images are supported. -try: - from PIL import Image as PILImage - from PIL import ImageTk as PILImageTk -except: - pass - -if runningPython3: - from tkinter import * - import tkinter.filedialog as tk_FileDialog - from io import StringIO -else: - from Tkinter import * - import tkFileDialog as tk_FileDialog - from StringIO import StringIO - -# Set up basestring appropriately -if runningPython3: - basestring = str - - -if TkVersion < 8.0: - stars = "*" * 75 - print("""\n\n\n""" + stars + """ -You are running Tk version: """ + str(TkVersion) + """ -You must be using Tk version 8.0 or greater to use EasyGui. -Terminating. -""" + stars + """\n\n\n""") - sys.exit(0) - -rootWindowPosition = "+300+200" - -PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif") -MONOSPACE_FONT_FAMILY = ("Courier") - -PROPORTIONAL_FONT_SIZE = 10 -# a little smaller, because it it more legible at a smaller size -MONOSPACE_FONT_SIZE = 9 -TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see - - -STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"] - -# Initialize some global variables that will be reset later -__choiceboxMultipleSelect = None -__replyButtonText = None -__choiceboxResults = None -__firstWidget = None -__enterboxText = None -__enterboxDefaultText = "" -__multenterboxText = "" -choiceboxChoices = None -choiceboxWidget = None -entryWidget = None -boxRoot = None - - -#------------------------------------------------------------------- -# textbox -#------------------------------------------------------------------- -def textbox(msg="", title=" ", text="", codebox=0, get_updated_text=None): - """ - Display some text in a proportional font with line wrapping at word breaks. - This function is suitable for displaying general written text. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - :param str codebox: if 1, act as a codebox - """ - - if msg is None: - msg = "" - if title is None: - title = "" - - global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame - global rootWindowPosition - choices = ["OK"] - __replyButtonText = choices[0] - - boxRoot = Tk() - - # Quit when x button pressed - boxRoot.protocol('WM_DELETE_WINDOW', boxRoot.quit) - - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - rootWindowPosition = "+0+0" - boxRoot.geometry(rootWindowPosition) - boxRoot.expand = NO - boxRoot.minsize(root_width, root_height) - rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(rootWindowPosition) - - mainframe = Frame(master=boxRoot) - mainframe.pack(side=TOP, fill=BOTH, expand=YES) - - # ---- put frames in the window ----------------------------------- - # we pack the textboxFrame first, so it will expand first - textboxFrame = Frame(mainframe, borderwidth=3) - textboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES) - - message_and_buttonsFrame = Frame(mainframe) - message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO) - - messageFrame = Frame(message_and_buttonsFrame) - messageFrame.pack(side=LEFT, fill=X, expand=YES) - - buttonsFrame = Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=RIGHT, expand=NO) - - # -------------------- put widgets in the frames -------------------- - - # put a textArea in the top frame - if codebox: - character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE) - textArea = Text( - textboxFrame, height=25, width=character_width, padx="2m", pady="1m") - textArea.configure(wrap=NONE) - textArea.configure(font=(MONOSPACE_FONT_FAMILY, MONOSPACE_FONT_SIZE)) - - else: - character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE) - textArea = Text( - textboxFrame, height=25, width=character_width, padx="2m", pady="1m" - ) - textArea.configure(wrap=WORD) - textArea.configure( - font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) - - # some simple keybindings for scrolling - mainframe.bind("", textArea.yview_scroll(1, PAGES)) - mainframe.bind("", textArea.yview_scroll(-1, PAGES)) - - mainframe.bind("", textArea.xview_scroll(1, PAGES)) - mainframe.bind("", textArea.xview_scroll(-1, PAGES)) - - mainframe.bind("", textArea.yview_scroll(1, UNITS)) - mainframe.bind("", textArea.yview_scroll(-1, UNITS)) - - # add a vertical scrollbar to the frame - rightScrollbar = Scrollbar( - textboxFrame, orient=VERTICAL, command=textArea.yview) - textArea.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = Scrollbar( - textboxFrame, orient=HORIZONTAL, command=textArea.xview) - textArea.configure(xscrollcommand=bottomScrollbar.set) - - # pack the textArea and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, so that the bottomScrollbar will - # be located properly. - - # Note that we need a bottom scrollbar only for code. - # Text will be displayed with wordwrap, so we don't need to have a horizontal - # scroll for it. - if codebox: - bottomScrollbar.pack(side=BOTTOM, fill=X) - rightScrollbar.pack(side=RIGHT, fill=Y) - - textArea.pack(side=LEFT, fill=BOTH, expand=YES) - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = Message( - messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m') - - # put the buttons in the buttonsFrame - okButton = Button( - buttonsFrame, takefocus=YES, text="Update", height=1, width=6) - okButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - def __update_myself(event): - new_text = get_updated_text() - textArea.delete(1.0, END) - textArea.insert('end', new_text, "normal") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __textboxOK - handler = __update_myself - for selectionEvent in ["Return", "Button-1", "Escape"]: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ----------------- the action begins ------------------------------------ - try: - # load the text into the textArea - if isinstance(text, basestring): - pass - else: - try: - text = "".join(text) # convert a list or a tuple to a string - except: - msgbox( - "Exception when trying to convert {} to text in textArea".format(type(text))) - sys.exit(16) - textArea.insert('end', text, "normal") - - except: - msgbox("Exception when trying to load the textArea.") - sys.exit(16) - - try: - okButton.focus_force() - except: - msgbox("Exception when trying to put focus on okButton.") - sys.exit(16) - - boxRoot.mainloop() - - # this line MUST go before the line that destroys boxRoot - areaText = textArea.get(0.0, 'end-1c') - boxRoot.destroy() - return areaText # return __replyButtonText - - -def __textboxOK(event): - global boxRoot - boxRoot.quit() - - -def update(reply=None): - return "To close, use the x button" - - -def _demo_textbox(): - title = "Demo of updatable textbox" - msg = "Push update button to update. " * 16 - text_snippet = (( - "Update button!!!. " * 5) + "\n\n") * 10 - reply = textbox(msg, title, text_snippet, get_updated_text=update) - print("Reply was: {!s}".format(reply)) \ No newline at end of file diff --git a/app_windows/lib/easygui/build/lib/easygui/boxes/utils.py b/app_windows/lib/easygui/build/lib/easygui/boxes/utils.py deleted file mode 100644 index f527144..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/boxes/utils.py +++ /dev/null @@ -1,180 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| - -""" - -import os -import sys -import traceback - -# A set of variables and functions to centralize differences between python 2 and 3 -runningPython27 = False -runningPython34 = False -if 0x020700F0 <= sys.hexversion <= 0x030000F0: - runningPython27 = True -if 0x030400F0 <= sys.hexversion <= 0x040000F0: - runningPython34 = True -if not runningPython27 and not runningPython34: - raise Exception("You must run on Python 2.7+ or Python 3.4+") - -# Import Tkinter, the tk filedialog, and put everything in tkinter into the current namespace -try: - import tkinter as tk # python3 - from tkinter import * - import tkinter.filedialog as tk_FileDialog -except ImportError: - try: - import Tkinter as tk # python2 - from Tkinter import * - import tkFileDialog as tk_FileDialog - except ImportError: - raise ImportError("Unable to find tkinter package.") - -if tk.TkVersion < 8.0: - raise ImportError("You must use python-tk (tkinter) version 8.0 or higher") - -# Try to import the Python Image Library. If it doesn't exist, only .gif -# images are supported. -try: - from PIL import Image as PILImage - from PIL import ImageTk as PILImageTk -except: - pass - -# Code should use 'basestring' anywhere you might think to use the system 'str'. This is all to support -# Python 2. If 2 ever goes away, this logic can go away and uses of utils.basestring should be changed to just str -if runningPython27: - basestring = basestring -if runningPython34: - basestring = str - -def lower_case_sort(things): - if runningPython34: - things.sort(key=str.lower) - else: - # case-insensitive sort - things.sort(lambda x, y: cmp(x.lower(), y.lower())) - return things # RL: Not sure of this exactly - - -# ----------------------------------------------------------------------- -# exception_format -# ----------------------------------------------------------------------- -def exception_format(): - """ - Convert exception info into a string suitable for display. - """ - return "".join(traceback.format_exception( - sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2] - )) - - -# ------------------------------------------------------------------- -# utility routines -# ------------------------------------------------------------------- -# These routines are used by several other functions in the EasyGui module. - -def uniquify_list_of_strings(input_list): - """ - Ensure that every string within input_list is unique. - :param list input_list: List of strings - :return: New list with unique names as needed. - """ - output_list = list() - for i, item in enumerate(input_list): - tempList = input_list[:i] + input_list[i + 1:] - if item not in tempList: - output_list.append(item) - else: - output_list.append('{0}_{1}'.format(item, i)) - return output_list - -import re - - -def parse_hotkey(text): - """ - Extract a desired hotkey from the text. The format to enclose - the hotkey in square braces - as in Button_[1] which would assign the keyboard key 1 to that button. - The one will be included in the - button text. To hide they key, use double square braces as in: Ex[[qq]] - it , which would assign - the q key to the Exit button. Special keys such as may also be - used: Move [] for a full - list of special keys, see this reference: http://infohost.nmt.edu/tcc/help/ - pubs/tkinter/web/key-names.html - :param text: - :return: list containing cleaned text, hotkey, and hotkey position within - cleaned text. - """ - - ret_val = [text, None, None] # Default return values - if text is None: - return ret_val - - # Single character, remain visible - res = re.search('(?<=\[).(?=\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 1] + text[start:end] + text[end + 1:] - ret_val = [caption, text[start:end], start - 1] - - # Single character, hide it - res = re.search('(?<=\[\[).(?=\]\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 2] + text[end + 2:] - ret_val = [caption, text[start:end], None] - - # a Keysym. Always hide it - res = re.search('(?<=\[\<).+(?=\>\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 2] + text[end + 2:] - ret_val = [caption, '<{}>'.format(text[start:end]), None] - - return ret_val - -def load_tk_image(filename): - """ - Load in an image file and return as a tk Image. - - :param filename: image filename to load - :return: tk Image object - """ - - if filename is None: - return None - - if not os.path.isfile(filename): - raise ValueError('Image file {} does not exist.'.format(filename)) - - tk_image = None - - filename = os.path.normpath(filename) - _, ext = os.path.splitext(filename) - - try: - pil_image = PILImage.open(filename) - tk_image = PILImageTk.PhotoImage(pil_image) - except: - try: - # Fallback if PIL isn't available - tk_image = tk.PhotoImage(file=filename) - except: - msg = "Cannot load {}. Check to make sure it is an image file.".format(filename) - try: - _ = PILImage - except: - msg += "\nPIL library isn't installed. If it isn't installed, only .gif files can be used." - raise ValueError(msg) - return tk_image diff --git a/app_windows/lib/easygui/build/lib/easygui/easygui.py b/app_windows/lib/easygui/build/lib/easygui/easygui.py deleted file mode 100644 index 910a77c..0000000 --- a/app_windows/lib/easygui/build/lib/easygui/easygui.py +++ /dev/null @@ -1,79 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| - -ABOUT EASYGUI -============= - -EasyGui provides an easy-to-use interface for simple GUI interaction -with a user. It does not require the programmer to know anything about -tkinter, frames, widgets, callbacks or lambda. All GUI interactions are -invoked by simple function calls that return results. - -.. warning:: Using EasyGui with IDLE - - You may encounter problems using IDLE to run programs that use EasyGui. Try it - and find out. EasyGui is a collection of Tkinter routines that run their own - event loops. IDLE is also a Tkinter application, with its own event loop. The - two may conflict, with unpredictable results. If you find that you have - problems, try running your EasyGui program outside of IDLE. - -.. note:: EasyGui requires Tk release 8.0 or greater. - -LICENSE INFORMATION -=================== -EasyGui version |version| - -Copyright (c) 2014, Stephen Raymond Ferg - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -ABOUT THE EASYGUI LICENSE -------------------------- -| This license is what is generally known as the "modified BSD license", -| aka "revised BSD", "new BSD", "3-clause BSD". -| See http://www.opensource.org/licenses/bsd-license.php -| -| This license is GPL-compatible. -| See ``_ -| See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses -| -| The BSD License is less restrictive than GPL. -| It allows software released under the license to be incorporated into proprietary products. -| Works based on the software may be released under a proprietary license or as closed source software. -| ``_ - -API -=== -""" - diff --git a/app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.gif b/app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.gif deleted file mode 100644 index 5eb75a4fb80cf4c94986293180b74d216140bccf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25112 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 M3jcpYpV#I81DhA-cmMzZ diff --git a/app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.png b/app_windows/lib/easygui/build/lib/easygui/python_and_check_logo.png deleted file mode 100644 index fac900bc413327515e28b2c7a79189d647cd0ebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3585 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 NU>DntRc5h2=6?rf{-OW? diff --git a/app_windows/lib/easygui/build/lib/easygui/zzzzz.gif b/app_windows/lib/easygui/build/lib/easygui/zzzzz.gif deleted file mode 100644 index 6c04ef2dd09b8c5e72f1111e68cf0162dcb25d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1703 zcmXYwdr(l<5ysbv4~j9RspBKTOw|lgu1In5LC}sG>$9LyuhK*S`5Q7bCws#v_B5j9SzDM-gud6@yX*S6=MGw1Bg*>8W}ccx66 zJSJ>WEF?i2{BI!u0Wg37C|Cd%f<<64SOS)U4PYbK1U7>$U@JHP4uV7AFgOB^f&nlH zhQKfw0i)moxCkzR%is#Q>b(t$pajaG0_q(A0TBp+5yY#Z1!y5!gchSEXeru&Hlj^v zGunc-q66q4I)o0RBj_j^K!a!q4Wkh>iY}mw=n}e&uAr-^fQqPu%BX_s>F~xz0wQ1n z@nn$&WFc8Z7Lz4pDcL|al1*eY*+RCG1LPn%L=KZ9+gJg&dlMymXE|81l61hyS zkgKFXilju!q(bT;@Q5P=F))L8MA!nhkS$`1*%G#tZD1SOCbpSvVO!Y&c90!nhuIN! zlnt;!HpGV62peS=*hO}UU1nFC3^wF>0+3r8BIJa{5kU1v0viR_o%wNY|-Z$;U z=U21FtZuBUJdt<(;P}nH1E!bc-^iJ|J22*Q$&u>3Svk}9Pd{ngg83&B?wXPJLszu) z`(rn&^$)kU#9j~l-Hebsq06g_vsd+O%P3h^-rBJFQQ)zXsHD8x7YZ_uFF3pA@x!~} zUnG^D`Ad)B$flZ*CCgHV{&ho!@9T@t9xsgBF|x4khf_{W+?DPH&C9Ouj5^gP{K|?-mU1Q+_}8jX}+WKkC{#rT&A}1CH$4xhif>#Lm&z4*Px*5y^hL zXHWcn-;o1Oo_H_4drJRWYhj-^KmRc9)#L#7P3!;KcK?*>tiW-vEXi51#y9z`BD^*4m}+C?JvU9(zaH;eg0XVU*6>BnSS{P z0?MzgTp3qdADx}HK5lt_iME-9q8guqqdpBUEe`xLq3fcJ(SsW1jhZ)nOjPuR#p{O^ z`47)pKKW5|?fg$`wp@IeUlwzES?NvRoBK}Qja-rwpBgl$YV5JOc{77<&oxKJKU;Y! z@pNa|>6za&7C%ay(B61BsjOqw()f*?Etg+e*!=FcVH28iM@0PXT1fb;^FQyITUh>m z*vmz+m9zhJaMIJgJ!*r#?`-K;d5POIbI$R$UYDQbclcfjI5TXPjQ@Mn2pJLn(~8qW zW=@LSxHdZ>H!WySZ1L)QVVTLxYbVsyR-51M|2A~xo|o2Cr*hw8U;OLhKVlB2Mg#;U zmWP$j-@WO^o#6{_A5A@arSsgLtE+x0j5rnlS=a~deqV12>s}xG>Ws`@wfjd+o>y^w zSJ2wRmlN7ED=&RrygnwQwf45Y&2 zWDPsLF8_X0jdgRETJ2S^mu1$ V-MYt}ZQpGTe%@Yxu(uzC{|6-}T8#hz diff --git a/app_windows/lib/easygui/dist/easygui-0.97.4-py2.7.egg b/app_windows/lib/easygui/dist/easygui-0.97.4-py2.7.egg deleted file mode 100644 index 01b88083182eff1cd16bbe6d96e51671c62dd407..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114317 zcmV)RK(oJ4O9KQH00008063jQM%QDX`A!A^0J97L01^NI0A*owd1rNLFJ)nKd1rNL zE^v9ZS6y%7MihNV;y+xmFS`#Q>Dyb1YEkV)Nnvs-RGHD8&^tE5D(Qte&|kubxfWcJZ2E7-+$kyqJU4P1%Rvd1i4tT!&(PB3ZYXToGG|e-H!__P!@8>y@fV_cZS zI^K&Gv_2{ud#cJU4C~IQDJv~9+$YfCEG+q3IzcQOn5D^g`{dAp^|Fnrh7<^a_2)I3 zE-IAeV_6I;l?C8P`kbNI1QOP-?&{7UJnH&^J~}^e@$9rn5U@2|_)~8gdE_teg7CqO z{b2c*Ch1$H2R`&&)?L^xo2u%hxgqIo`i^dXc>m-0yX|f}5+!Tb8dgW>gUBqE5UQD4 z%S~hR%Vp3uAQ{Mj2IMCjStbw&y;zt|a74u4kc9`1-1a#f4$ucw30=s#Mk90`-pSAX zxJ5OoBMXfjX7b!TREYYvFY)&deapAXfu^I1^OfDvv#fY z8CYS3Mwg)6B--t34s7PE`9&z_AU`jJXG9w#;-9>D}@mSpmE{=>xizqXtQ7Fm| zp8{<_ZR{wp41Q5xXFgjjXrnc1TOT>seeIY^q+C2OmRwSrtEO!0$C#d7eD6mT1$Xh2 z8=`9>T7|)*Kl5fZd8YW@BX=F&2O*8z2yd|wy2}~4%V+XFuR<@12=Dxd)xw7bAVPN; z`(89g|4kR`nZKNmX@dP~8N{^kAN&~0;$X~vz3MBm_rTl`aI~I8u^+EvkLE!zvyw($_=rgseZoWwBCE?f^2YEHyVf-@AWHO! zuP5usxAOSQ*bBq;il-h99QVN!1OQDJwlgbau(aVqiy(YvRMx@jJf^3656?rE4uQp? zYh{Sy(4WSa>)NlS0O@aNug>harvVV?ZRdq-~QgWH_dw2q%#cwO7DIUnHF zUS1R-d~({zzaw|{=ri+fH8LIfT~%1!ruUubwv_v`5ijk|N7QWx!@<=*eTIWC=uJB= zQc?1JHgx2Hitn8$aR|xtlRevD7#Q2SqjoH#TPM-1w;PQaDS1t3q{Ts+_U&j)qf#9E z%MVu=HoOV&y~75P5VWuB>h}8jcsx3)0+t=cj?%m94%=LBOm@}XIMu#_<@b2cSBtAu z6%|GoHs3S;?>~1QMClymtE@0@6N}Gx*NYb5rMHy1tWUrG{_-7qyR!L~S9fv6v)0+y zMg9gHre_Krv^n#&k<;QUo4`dzvM+TtDOE2l0zDD{dFV4+J=jLW9jxW5f(+*FZo1bi!Q1`3$m%wl^ zYJaQz2~bM|1QY-O00;oWZCgfjHlKT?1^@u^3;+NV0001GVRLzBb!jhUVRLzBb!jee zd1JL#QEubN5%ne?35etl1@Dgskm+4dJ~p$PMJS1u3CN^EQuaC+z)O)WsbP}MbdwSU z%yDv}TqPICt0p<4$!wCZ2oOcGyI#F|T~*!s^*?{_{Qc@5X?`($zQXs<_!XmQz5m_Ch2yv`RjTMpk#+4}>38oaX+^UaHO1MfQguOhLhmTUO{_LTx3uhb zJG#p9RvyF~wlBms>&o`JP*o;tAT%d_y_dUviEnG)0K9gbN1=^WHGR+m9*y|mINmf` zr{sId^I{!1e>(p-j-Q#+qLb8Ub&!QH;6boEUAOAGGlFE@3cby8L0hHC$f_v?0jD2e zj_`Vv?Vd8ieC-kiEfoq#wQ5O=zjaazYWIR&>~vODLQ|{gwN^(s18rF&`i<&Zr+u}k z6WU^)FcUh;VkcVM|{DKdES%JSd2AOI~KSs&D^C}?vUDQ~;lj$0%H zJ{gm1J6+?)KwRV6r8;K11|cZAHcV{P$A%cpm%if=KF_M7Dm#&=bJekTj&4(m%0LCS zk{!7Hmept_Xm6Uo*>asq56E>HrojgBQEqFj}w==rNHrM*m~F;muJj0T<{ zv(%)HwM7&MQMXho)fiqDX2fWvQGgslvZg6zo-y{Mk5aaVA&zYo~wEb zyLPbY>PCwK&lyDcs3-+nIzcHLmLq?(8E|y z!wu?brka!HvZJf~4c&h8?H?w;SkkCG$LYY>}O=lOB*S)VaG6)@& z#&0&V&L9ekt}=thh=YG21veDA9aqgk##1A7CEFG`KUDG{I2Ya)*`toEEmp0NAIpR) z(Z1{R`CFGhr)5~`flscWeAO9SF=#**6cu~mp-~GghRnspqH&(=k!mFX8Ry)s&4hDK z@S2yItnBiz>Ft+X;PXt7kqaU%x?KFf=+F>pq4KUmDP-ev-6%ccDooHQ2qc$8VSN(c zu9&qx3uFlJt;^*^HF_M=vGncUU@ME;=0z^APG0y-{!gpePZGjV@UU72FaSdAg=yd?6I9x4xt<5%VnS2w zLt&KCGI$75OiQDQ!@ysfQFKQSemuL!qc;tfLHbPW?=DC~_J!glk5*os2DA0ji)pov zS5e|SOnn|Cv!xe2_;Yli5FW{Y^uv^rdvCcsk7VkDiZ?}Hw0MYR9>o4EWzxf)1NzVa zES9M9l|Kvk#{bC&WiNi7aMZI19px`;Ou`_|y$5gMC(hM>51iGVtz-XznIYO_Jx$Ue zU8g=RqG)dAO#Ju}{VMt1Sw@M~WS#gEct}0#7!VL7`JV5m>m;z!1YzpO@p{Fr?TvFE zJt25-^k6!-8b+ZF6*@%mGlQ}QR^kag-TQbSvuubejXjniN#kIao==0nG>TLD6eETH zVi_#_aOU%9#3)Ze;=ds;4!~>yA+6gd4?fp6WL^od>Tl0-Z{qNJQE*4z{4rqK!(^;* z5)9d3C7az3awC0*a}LiN&N?(Sd*}K;eVh-dMB5p1QF9MAbmXpy-<_y&rYOskJ*lAX zjV;v6zV)Iur^$S@yPN?45z*$iB5$h7=Kw-m;1 zi0F&n)kjB0*8 zX2$sD#l8K`y}b>^@rCCN!r_g3`$t|M$6MKByc1sW-;ee;xV*ezmwI`*;{PO{E{3n0 zPL{>{4evvsQop@@FLt~4e8%5(a{P7i|KYco{6qg&<;Re%8RB11O9KQH0000806Yh7 zMMB+rf~sKv02pEb03iSX0A*owd1rNLFK~HuXm4&`VQyq!V`yb#YhP?{XKyZNX=WT( z2{hE-`~J*6#xP?a491qh&{(sZF_y75S+azN2vLnv(YIw7%UDCmnz4o?RH8*=Uy??t zR1~s>ib`pnf4~3po_o(d&w0=DzW2TFJ@;HEXGb&hkPsjQ_zwIJ(ElGu06+s!C=>~W zVx|8PNGKX0prO+E|M4UM@IfMRSmZz27z(wAVxiLibMQfl)!fNUu4pIR&$O$LBMBJ!Vf0svGHkw`3-UMgu^dG!}=I#$vJm{9DjCG#bso zW3d3x0fm+zkqKC=nHdxf1=<0i8;uUaVky$n1hapM0)t3oIvO2?#nO=kBo6nF8izt# z(CAn!mVw1%rKSG`eU3)|Q}73XH`3BpBrH}MFRdZ{Z)ZzxPykE#=R?Qg{>A<121QB} z{ssMp!`c{419|0Z+$w0D!SEooq$! z{L%8FrTZ-)2BKmR8lgriUxZvcQ!p%8-bOaGW~ zoV~sOM*yI>QE*W>LO32Dh5PnTKZ-ziV+j8x5Q}$n3-Nbz!zbW1PT&a%1RtLe!dU_% zh~X3D3j5fycqSV25| zIDuG2jE#*weBv;%j(FlkLc)m?#1>-g*;rBwDIp<+)J{q`n{f8*S<)R+;yZ%E6gkWA4&=<3M)!VDk>_fs_On((?7H{wfsYS zOM82J$N!Ixj*jl`?%v+s!NI}t@$u)+pTBzb>dl)sOG`^1KYsl7?VC_2RQ&-3{X6yl zbvOY0?@j8K?=I8uyheGUg@Zx}m-N~I=PUluB^6^wV zZqZf08=?0n5*=atKK(Yow(W5Ng4b(}40^a%R9bQ;y0dqeY^b&M&iLk_W1N0LjnjVg z;n{o396J?qy$}L2Q+GjRf z*@RIb*)6owcjDLr%1@mlanj{EeEu!lEuceOs^LClcGgOKl6{Ccfme z2Wmpvq77mF#Cn{Lt3T_5O8RL^JaoyOV*6mqm=T^fQStFUlIUuv8>U;kD$C^$rFY)P zVI$&+nGJKR&q93jxVwHH?^rfh_PwFHtZ{>ur?ppSS}5%|_JFK@IWr zNI!>$D)ijDA=6`yIv$33cpZlFxc%xQy?8T&N@_&u3lLfL{+Hh3@Er@p+I+`XE=DkU zVZPhddGB{ftsl7l+5o?>+*QZFXAFp9?gq(G*C@b-=(YIY<_v3JH0`QcUwKG&osePF z=VKVNGOS^VTS{8Ls+HuMSOP4Q}@T5Cu-TW$Bm4o<7ij9a4CF zK>ylah*O&oc}Av27Iwo@^{QwzkA|5;dgW%nFt(07H$5%1ymEH!HM+XM zMn2wc!nN!9#XcW}d&5|*CoZSaT2u4-S9T$b4>N2cxH%v39q+5;WZ}sDSevcl@1{Ymw*~u@yJkI-@ltB?>v7U*3!uMY=ueM_S zkv+nNsA*6$d~sMnC;&zA7>Q{MeVDG}aGiDNt>Ysivf|Nnjhw2+!awRN_)e5aOj{l6 zUI_R|e7`n&xK~ygo2;fWN89d6H_uhYNaN`?wb;f3_Pwf0`IB10PE{=IPF>s=9H-}d*&f58pjk#sVJQ61`ktTct3VT3RX zA{1Ckrx^_rz|L-8Dy{=;i3DC+DlZgUM}%7S@`N2h+@ldNSxDCBIaRr?Lyo#1kx=t;5Byzz3e|jg;>^t&kxRuoKGaPGy)d@H zZwi(8mjN~?rYQyE1`Y5b(EfxPi4WZVfOj`VwF3cU-SE1a6_7lga6tN)Nn?4yM5b0b zGv##Mdn033;io?}xc`_{TGMRs9bv`+Y%t~Jfm^C#R#P1czN71U!{0N_*_>1@87Jd% zGN`e>s44p{N_XHs0 z06tPVSH}p7tto1%&)Mw<7OEtq6jMcivl1;?MWWjaU^(n8G<2m8?~z+vUN4dSw0^JT z2`(pf*Vvpb{YFYvyqztcSERU7CGtE)O?}(-r87Td@3EgStVS!>o3D1`-Uis9MIs#t zOS*T}jD38rQN)fN0s_pS#s_;BO19_4fT<(}+@4{qutw6L69o!;T!z&0^5Wb z#!QDwpx|uiJ$9Ps)JdU-FR>@hJR#j|k^qSCDA3#xxg*?p5vhhAslO6IswDPBOTV2v zt;k4BL3INq)5{Q_2-4+!%WWnkBd1u|F2pBC;xm!9Z}M!PMF^1dEvIIq`xG zzS6v4b7h zcz~i&ERkbkpLmgr?SUU`%QE3QoVT=oIYB;nbZiJ?Q-l zW%AY^dvCvvN10ghF!-;7^7=)?&yyajjWHlrI}gZs!xVqcvLgg0%F68te*=P6}fcDmVO6Yd7mj zy~ao~o6OJ7DyHba%F7gun}76l)Lh!XDpibc=JC3iWBC!9bd}Nr9lyx62vbXi*UrMR z#eCVntSGtmP;hH82iKdI{qMQJ5NzQI0|pt1wwn@CjFj5ySh(iqmW~R6;k2>m|+2?bhwQMiF7M_^v4|QyQj|zS7M`e{P8sR&WBfPt> zcqPUB9d4-A{)-qLC6Uz|e~&=h>31+gI?w?bi4`#cYGEX|9{+7VeD`-0cO#r4g|^(V zm;QcYJXZusmP53i@7_GGzURE}9+;B=|BDYlK8S*nMRUK=ao98GvCwb%=vD$OVM7x+ zA@0DId2>Z->XZz91J>7r*-buo9e^jbf*og(KGo)Lu+ZZjoFJyiaR5lApsP%+NVCfK zA|!w3!tRGa;sp3l zHE#fYs-owalx6|^^DOo+S=ne-Ie-FfqhxB$Ve0wkjp;!2S5$be?ZPa4iJKE#E52g` zw6v-0K(X(yLdy$$19+hGorr2CW*;+Xxi|*}lHoA`GrrOvxhzvVys#C+1HhF~7?epV zB?AZsT_znXkP<(bC>x*(k>{Z^==kkhxky_A6g}&4y%qS_kJ91+jhB#)B}f|(K*)ut z5aj(Qz<8eM3uOLRHXO~5CiSCCm}&tmNN@t=L8oj%4~Qp7CZuCG$$)l!Vc<(ye+h^U zSy8|&iYURhvyroA1xcGHJzkyLluB!wW*=s81Bqn8&Jj>;B^8&8vqx1k^z1m( zCCdARFAMMaU%oz!KEo@Bp1>5a5fhP@M+hR~6p@i*$_Izl?nIh?nMH~4U}?Mxz#?k^ zN7$l3^gJ`XJTVudE~8g7u2ayJd6);2*?3CjAu=>O-{EmN>*iXb?Gr27m{F8G{%9L0~EB7|zVr^osR6A6UPz$Ol z71@AaPpH;%NmDtNPf9Aa>b=~+ukkAti(p=gj>SafiuwJ_NH2zEl6iI10!M#EdgJAp zYRp4E@ce!4F@-eED1!2o+AbE_>lj8#q2BK&Iu3i;cmiXwdgX~9`aBuB$gdv}Mu0O$ zilv{5UtoZa0cpoAu6X+sRvIqd&a3pC7f(6VVD(D0f*@BR5UsYzenO}m1uEhu%Dqn4 ze4ejo{j9un`l_}CfyIyg3W7Ql8WySI=Qr{jM{8R~asZHw-YVKG!l7eTm;3at9ICC0jo$x?*wR7Nx$>M?t33~?81yL#D8`mby6+p6^f6my1dEQ7>qTW|TD7J1t$dyOd??|NZoR>TVs zubsmr@UOm_0JqB#zw;{ta+6~eyIwacf7e#E9#TK~>$cS^u|jR>em<)7;jKb8?4W`i z#8S0I_Lljv4i^FRG$B720c3mzmI2*p1<|{J^q*N^MwkC&MbwRg zewAsWg1vpy;CxJyfegR)TUpN)HZZ?WZkr79i#ls+*(i3w87?3Fyy$wjuGDHqp<)!oBLw992 zc6Ee5RR1}Pl3^i&e-C`ie6XHz@Vn}N$uN)*KXfm>cd!r9#~*$&jE>@=johRZ z9-eb*QvWXybQ&1u;nNh)j2xwkJ=&qF%`CHQ7j5VB1{er9MG{0oidfxy&VtA3O8gaw zxA!^8IeEq0u5~gf+r0U*S6VN}}gOR1QCLI{GNE%%7N84c^#!CU}jEDE4 zZ&BJF-d}&%vW+fu8zsjMNhX2oGL?s$!5seB7=CaRbXw|jl~px-j9>O7_fhvhMis)i*W}_x#bXem{;s z0PHyPu**tfRsgv^`)DC%ya+GXD*#CeJ;53Fge^95FZQvV-s75byiec_p|+w`?3=PNFk$quRC`sOKfDdK{Dz33J7zM2@AD;F6aJuU=AZk=*eoU z=VndjkHC(Ky%5Gc(aU-gy(is|32kg0?#6eX+32>~)Aii|i zRmgZWmD$#A)r^>=OR_$1$EAa~IgfVji@D&d=tf#9r+Wl5kg4t-p_7f_E8Ykho$=Qs?vCc z57-q>@T!8i!hbCzt}V(x%a<;ANWy_TsKa73_PALrrd|MPoqe+S3mrkYYSs2E{LOfD zB8JO?B?Yfqe0)`9@Kn;SupTt>OrdGdXV!JuS5 zL@7w_4*{*im>Lyd3jHhJcuwWnt2bj+m}v6CQ{s~gM}WK8A7=Q__YYhPKMLsxoDF=q&G3`Rb^Ra%=0=5{ktlS*RV zf>Eb(QQ03-hQf0yjU>76On5+Rhur>ECZ&_NXU6#$NbCasicZNGb0If)SxZISB^dv^ zRn#%}J!%Xcl)Gt?CxYJl>Z*;@?^%>P^R4CnRZgo&)!e&pbDNgc=-iR#^rL{fU};3 zTnoh#sttYrr}Xoxm4F-v{cTH2NtH6)%42T^%6vZscawIjvK4(d zY|qM0DUWkQ*O-IZP70Y0dp|FZh9QX8Q(+lMprNE8bt~J>zm|Zc6CJV^TF)8JlIctlq(oFrscWxi8 z<|`e49lQK3{_|oq2c-2U;sLm^>y&qMu#F)8zm~TuWtsUMF54nM4a2)#Lezv%aqX{GR&_WZni+C4ov?1mnil-B4n`XM&Vpek_hkD*Fc zaeK1p8IOgS%i7J+ZB0jT=@GjE?67(2l7RzX7sK4TiGp%c5l zjE*`Dy~y)p#v#l9`rWK6)KgLy@X2*Q4d~+=C4g&oQ7c>J`tPXvBq|STEcmP=hfrb@y;RRD#;Uet}U~B=Ccc+ zDJFZnTOx-TfmW1TkZ_BNqcY00@I2{A4Z|A)zTCMJt>=j8=qXOKe~sYLk^#s^B_~p+ z(y3NpzxU{aN7~|H&%Z8%G$aQuJ`GE`n<^b4vA&caqIsua;D{_UZl>k;%eu}}qNh`H z&Y9hid?xGS-lP&@W(EyRQz?qNV)Cp+)i>m;%y@(n}@{Ia*D;&H0kE}btEz%%tLOIa7f3T*Vt9FJ_4Oc_bI zK|(rj)IlZ-ox2ViVfW}&h2<~3tO~iQatddybNj}Z*$0Z5aG5*Vu1i^|XI6(2YbBZ& ziyn5ZM&upz-OGwTF13|YeJ(J)*KYXe_aYj;>)WgGsol1smBx;5%iH~AN3^sYK&nCStEmX#o@^zz-qihP@;lw^ZM><&>27-< zMyV_6yWK$let^A~u+Yr?<#{$*3x2!q{ zoo__41`N>(XU56wML|i;L)kl*^ z!TC}22|O4^Y?_)(=+ zMfS%9qlfkbh#Iv$L|Wr1(FY#}lhnPYT{WvG7zW45V)Hp-`V?A$?5&;E6t=1EK`jj{ ze$8;!d$aEZt@k&3Wl1`NYH=n6}*OZeLK=|DrW$6ghO+1hd|+d>!gS9;AFIYvYEZi=}1WN zo!#m<#g}R8p(psCqXO}Fi^RPtrs)ocI|nr@dO{l;cRSQes+*%-is|y9sul0eeqqm( zLXUiE&tpD!DNrK!@eW;l*2{34 zQ2hL4KMc((KlaR3%FiVYSUw$--1!Sb3cMCSS=PXoTGzksLO zLBbf1woGw5UZTf=wwn#YzwbKM*9MhW->Z6UCpk1uJv;y7r+zdV)S>2F>zJ&gjJS>4 z0c7VG*&Vt9-n*^xgAD$q4>HtgtdUT~hoo5lYB?~Fk|pmiw1bkFo^rbqGhVQo3$w$Gu6lzr zlK?VZfq!B-Ge^ZT+S?@PX!Bav?&8^{rqq6zu34)L$~`Y&_Rn2DiW9Xskq@<&#%u&$+zdv|4KE8P!`-( zQ%wXEFVKx8^Nzjq{`q8e(+T+4w7wGB_pa)Rsq>p2xc!5`DaH}E5Xr5`a@#PaDE_zD z+6ly=U90V+&pT`X^dL-9GjeSF9dWqzubvMQj22}iqMMW@&XiZJf0sAvf3e7d&K#Y6 zDf7j_VIJdqFY$xNe&Yj2Qevtxh(; z!NpaJuh|hc-a}bjv(eU*Gort+7g*@A0E?eut7`nbNY z7W>)K-8wUllh+yr2dUWDJjWg!$yMvWA_{Dkq4RspmoFCRTZ&PcZQC@f-v?0IUbT|% zZSn*Nn++%kT5L?juQcwI4S|Kd?EES!vm4pag*1hutv|lLsC2qTL_;KICFx{!hPNLi z@@~2KfxJS_&C!d}5}|2OyPm#x)`PfR66x$+$EX>@X%1wt-)vVzE)>B?tu!h)h=a-I zDU?I3oL{na*$)W6JJt?lIX*PI?`oGmoVK3@2(17ZlP`U+A;o1FOd=wVCSA@*x&#zk z;?Wmlu#jpnt)uKgXJjgx*;Hmp6O^Py@sh;=wi6UE>4dS!w6F5!LKa}zd_ylLFM^R| zD`GEjwYttXLnM^hTiteDzpleEwh7A%o=U72b+{sRzo*#TQo_tT`KBJ{c9++{FJcO; z%wa~o;|BM}ho=KUq#d$z$?Vd**B=&`3z9;bZJa33p3XE`dchHwL5p_?L}VVu-dg#d zcvO7i;~GbSVt>o_ZQ8mc9m1AD4#>5R{4Cfm@k(GAv< zzZ^z}Q?-gabD9UEzoI&vrL)zYKN>niLF|tYM@Di}#aQOW&D|%$P=~0dI`>A5Rw=Sn z%H&=0C=)KrAXH`9p8JZ@ZNC`pJo+Q_N|a*ve{@JgAic@HCv73a?&d|W>Cu^0m-;x0 z;@Zg76__~Brrqk^g)kJdT?$p4dMm4?&OY}`ndMcr%;3nRoi|-OZa7}&(n)!i4;Gp` z?_qkHEe_8nw{cR zw-@ps%^e?TSb_8%A14Hk)kiw9jc>0`HWuE?S+~FMmUPj^kN+u*^7wc90kXXlNB>KI zgXNmUXtPE96fR{2ZV~rO$1DtR5v=j&nBpzN!h@!*10@j;SS# z!BVt3QDX?D&OdhC7zP-1jR8*{uOypVO1O)sXz9i=-!C`Y)gBsu~qq!Sz%ukom-hcI&V z<3r;lCS0@FMN7<12!Wv*Z%EC%jZXG(oOO|DE}X8PwMU^+_m1@>t3OpT^D@3AsN;>i zFW{F=rt#A=Tq9w%Zbg$Z61zUwbS4elfljWv?#Yj@Z|*NDbCdYx$qkH@w`?C%?z%PD znRdD%&83!*XW-^?&3lFeHT6Ro#^ti_IcvHjz3JUXz0cOT*4J0kj?F>o`HBsA321ffyWcme%Hk#)1qIf#bD>z2dviA03KMQmLLp# z^eB1nj2Fn~tS%~&n!j+jX#203M?;}hSUdBL!{Rm*#P zf88}-dXMnxN^0$m{?jpeH{PL+MRqg{>p0Fx1{DvcR1CPvqq*MK8_E?G4pBZR zWWVI40Dl%<^wRzEom-gdKk32l$W5^F`S|23DX;vqUexklsYUI{SO{p^2bZj6(b^25}VrOpFjwI!geoR{sN~j^a z)sGXNBXV|J3*>f9kIhVv|Ctt~*aH;6o*8V28f7&e9hu5hktNBDjx~C1NnJbg~8FDefEu-!3-K)Hyi+O>wV!_l{sO`q| z4tD?I;Wx`E!S5@A=ggkHKa5zbNOg}44x(qse3-bMMLOSrh-be!nd{3XPhS=I%!ceH z=lRzS<3|KufBww;6)V`yf|>&mT{-};-bAqxipg3ieMyyDZN_oHu5AtpmSR5)2LAPC z3isOp%6iqQGj>`zc`&@YGNr=SU z+>cU(O{ATlB68n0M>Y3)`Zn__Kd3XEu>?W=D$G(dDsdVP)q9@#FdJgnnuG!X)2ZaB z$h56zSB+2Rn&h-Z@;S#GkWqXNqXMZph;qiIJ(x(XS?ec2GNg87K4{v9j}5R}%5*k^ z8cujlZ94ULccY@rI6i|CMX-yJA4Sgl zL3ZEIkfgbsi3}a`gMVs1SlXIw*$IY{Az|#abB+VCgOc>c=Ac}daAY{;;YIEN<)vIB z`OLu!zdxjVtfY+aA}WUwp}4)kFjyU615=okkEqy44!cOiUBJLs*9|tRB^De*9`EM|ydDt$!c-JUB5;>DWQ;9`jj$>*9G9urK^{mzT zzTu}4ZuFh9Pbl8M8&?R&$VQ2D_eDI`a4a5p{x{(oa47D z+67t1EbnN)L%#nQ0HIyaGK$=V`4J_=9nR>qU<{$6{2&A&BFIQwS2o=p81TK7ysH7Q zr(bbd&M;rjv3RSKtt=XC#tAn$T<4K27ALK`{5hSRTH$rb@JsqyEn4m9qKiz5Wh7X$ zA(gazB7Nh;+bO~DlT-_ec&=2sgp`t=#5r zM;KQ?|FybrCnM1|^E^osmaVV*AS-5j^U9{4)ozZqbk2WgFOs*?BIyvH$C!+7(FK+{ z`%}0rgL^cV0iy<5K}1#*&zIELwu1UFK|h=>NYmfgXrsdxUS{7fDzJiQisG|{d$h>3 zoQNslQbHQJL11$9%dUviL%7FkRd;3-j*kH0dEAf9Lm6Q!V3uEORktZqmGT%6d&fNC zD?|)O=H%L}_oq73FU7fB_|?;}_hYM1W5mgK%+ULfKTWKpx)g&oKBBmAS&z?Y2}sdv zx<@LDHy%!XT06J*?Y*tQw_BsjSwgn~NkukC*t`CY@ZaO*Up_*P!^&)J{6Xggn6Dqy z3L7)x_o))Nxx}5PjT{*t`*!%#$!SbZOco_Rh*izVR+_2mRw%u<6SwS z!%0Dm-+3#Nl@StAEVdRuew6#Sa_aaffZSjISK{}T>sdQ|P;!PbD;ui)TuCj@=E%)Z z2X`iJ<&N)$`f#qAQ$8u`v&LwFj&FNRqh}>d%P`_ebJSB2NwEH@&))BMD`_IqDbI8c zPRbFjtXm_W`nFy!V|iZjymn}7)!Xxh%lz6!G2N+Fukfwy#e(JP(9jp{_YY;~g7zO? zPQCbindB04d8OmSAatj#sfdA4Qa@&!Jl|K^u`;`KU29=DU(2f{@X1?tS*Z!6b=_R^ z!9Gz1kkqd+uM0uHk)`<$FCDHv5qQ5l__f&H3wxFKDP;Qm`aT)P3ISoFSeg7By*Xw37YTMgshVM? z=9ohd8BAPj>{QEq_YCMySaxUc&MeaA4EbIUKR%)_wC7|bd;8x=Jxy3Vo*F>)EF4o& z{QX45`FnX{RlbjP-v}~U!)sCKJy5+bGFTl@n1BG`|9OsTd>f(=>43ZKZxxY5G8G+p~&~%V@&g2 z;&Yb5I4`rlcDLLCcnMks)-{hPYa0!iA?Of1cUN|;-dVF{^K+LEO0fIZT>dgV1I~5b z%-=2Nt#9V0h0j@dtW%q%Q)t{AW?*l$QT$3()7cJ%4z$bqJa%hlgZRPu=hwEz{F%5s z47Fv&K)3tH-dY5rEYO9-2VHP-Me+|7^%#IFZ)P49J+$>mGgq9};QT^ko^DezgNxZ zg{MK^+lL0UCKC0teVftS8<*7(U<>w$@mxyT&@{yJJ;V{?iQNFPxpRw-fnK&`WE-SFI6)~i?V(uRGmOclA`dkR}9Ffe-kNNhYZO4bC&URQj!)G zq25BQ3MC~G9_Dhyo^mDJ1F32Dwa%hE>3(yab)*fk+U?syXCqbTkZkGxbG3P?rDr$M zEhB1buk$lZh9xv#_=#Wf>nJ^yOwBHu^pHj|TFa!FXX1Wq@TK#>Ru)vh981|NY-;*> zcC7b|FtT5NLo5GGaj#gntA_s7-YjDxt!RgKR# zCj6pXm>n3RLg-02!%B{l^!AJ);1%DO*Wp-eV z5$c3e#@L&^w+0KX{oHL=__iKZNtkF85!;h7p$Xt2qIbEj>|MFhe%Urt8zOJTbJ22K zs)S|wH0ZyBGUNT~?%Gc=@xMcn0G*?#GjYeIQx%}`?9C%H^E>Vw3x>uHsmu$D(80l{ zG(OC76c0_j*hiCWvk8)N8+|(U^8oDnwK^vre%)G8s~^ z$D`op0aW6Afaynu_+Au%Hf)9YDs%KaS2&O;@#-(H!mk z(hwSwmDCK$4}3kZw?vXW-(U(Pw;E*L*dv-#VyEPvv#ciBHuJ$iO&OX#sQB~VjR$Q! zrBeY%dd2nDixy~*$ZYl9U#TKi^pc$_N=aEejgtLcS1=!mbgOTz^Fp0x)rcGJ&Ni}} zi0Fn=Q8+hQuOWLNrYi(=n>}=O_Y;glO{v#QI_H{@>KwGTjil(EKh&pUKq ze&1kAT8LQtq*LXUMi!5n;b8I^ zw+oq6WCx5b+5~ZY_FgSJl#mh!r$DqCC>KUoI3KT5ekC=Tc01LMd}>qZ7cWh;P0I7+ zac#Tl;u(8ESNrE{N~fHUB>H&-^@hV@eOIrCXX^-im2cBIr=y={hfac}BZ=}rSlS(n zd)H4~r&WLetm(IlhoiFywP9alGnJ>`B;V)Zs8AYyTe-~7PC5o$d=IIePH|DKgq)V! z%9V_$N0bKa?hPu2 zm?yGmcT*Z_=`9ITd#uQ$-aKn>8wS_b7C>y6*lJ;+Umf(>fcs=Ilosp0Yf=HL54J93 z7@iT+iVV{CQ4X8tTr{ymo)gzL=AGJnE}p|xS*Ms3_*FX-Dy3ED|0pPHOS_zTyo~JM z>7FPHcfRbNXN&7A4$m{m>P1c_X8e$G8BsE0QWfx_viF}@%Rp_3J?APyPWmOubS9-H z_8TA-wDlD5YATy^6Ovf|9M$7zSWkT+)SJs3OzgLqmev0O4rGCJ*F&Z$m98r^^Wxq^ zb44NsG`ZRRX=k{ap=m^Rq9i}i86RY4;z3kXnX8f!Bfq0Ba3l(HO@1fF6!c%{7fU%~ zZzG`YZ1ys+??oa(#IVXyjXpK}8>eX@&8UHjq4%n4dXlDO=u;03g42}Ofn9hR(7inp z+Cj!@DsDU(q*d=(faQ*v8rQ$4MKpldxI9ojJ9oNO701G|QX4 z;MyKytNPL(Dk-u5(boef{OqJ6LsJAmfW$OaZGUf`XHp^5pcO1TVh7KMHcijq@)n%V za1`0WKf_#=ve=+W(90|rGY?nmNSZFQ2izdEwFR(HF)GHAA>UJ6vb4eNHkl@5xrD=DfCwwoi@o%_I@{J0#A|XpDAdYjBxP zlj~Qq*`)fk`I~8QMoP-wbH#|#5N3zJLMP3-pwIYsuUZ2LusRs#vBN7IqWsm9z73Iu z<{p%UYpes7oyoT7+THqMQL-~%c|Hh=le3wIngduh3#?4yOGEi;#xzT4wk>XSd3s-W zBGiJ>W4&7Mt-)DggXMVpf64>v8j(o~L?A3tkq##E?F?FLqkn*9elw|KjFXasimg36 zs{5^q*>?JZc*&Vll3~yZRcAhpYdw#QK^cW{Ry2|%h9ivF5E&MMWv^=BQmtK%VYjE4 zv|{okh3{E#Z67*Bxwtp&@ao0P?NIFr6OPt=o<~u? zq?)Hv^A103FR6f`L8by`l;k!$1FnlHD+$Y3DL;8=A3&3{r=`ny9bJsF=h{h+CF-H= z+XtZ9F9AGKXCj3d@MnQO22s|?H_779oZw(7T31@ZaxuP!NRZY_!pY_j;wd-p>kltH&YU2H@~j%+*(h{QdF=uok?riA*ssp@*_j!2nSR7 z%6@c+Y8FuQM0Y5aW)Mb|DzUePCP{Cs(fq)OK!JDMphxo6z?`c+;$>0u6A7isN;^Dv zv3l}c91M7%cG)3f!`i^}MC|W~q46k#&K|X?gLIY$xS(l7r(cOk-9AABHtelu!{P^< zdt?*?tg;&+rWoV3Eh|`znjrY>+4HJxq4xV z%k@yxTIxyz<$Y7qgYf|McwN_mh)uD{HPk-Ed5Nh*yv2nleeDCQVG>42s>XE1&NCXd zu$^ir_UWEELLYwW7~Th`Uu~>z9u0Lk)s<`*2S~#AZ7GyKoR@f4)GsyfISxK*7I##( zEorc2z=#i11$2KNbc;zTbz#!v@EJG(WAaUp=sHP$vmYW&?fLepDynh)aj% zrA6J#>{R`0A?B(G=Ck#%npTo>7wmeFs;>~VBvJ9kS^T#4ftLyZu~}FAwu2%6rQSka9!XJXMT1ce zU$#hs7Q74KV|VxKD@!OytCYTIUzE)3*C+YtyB{fg2I@a3p?b2-#}7hut5d%md)SYr zg9E8F^hG4u2g_6YPxQU{yr#|WkuqDnWF1RSCI=`TQBizVIX_`noou@@XCdGI@A}YI zSJ(PK_z2XJ97{B`>h&~w;Y1o?Kirf7QuP|pYbZ6IG_ff7eOrfErynp76NHeZ6G*P5t!C-kytfKV^(2!CKx^*y3K} zu|BVwVJB(Sf`En|y-3apcSq~uUi6_&QRZ^$A*zZWPlKB3xAX0xwUg4($0fS- zT{imUi`zz#r~G1K%YXWC&S>Zk@7fzi(~JQO-1_uLyWT3nqjwFlKm@BXp9ZK z+W3COq1PLAVjq7mhRq>8qgm30myUUw9j~uUv^C4WU6!}gT$Thrw3}uxu4fVCWFUM1Vtq*_{x~{hC+f87`n%nQDhLTP8C3)qq#ImFbZ*wzIB!O#mSBrZk8fyw{X7O+7RNA1uHhobPXx zf);Ej7^w7Xbc0q)hBt64T1ED+5C0gXS97%&LpN8A%JsYZainJ+$ea# zgiixJh+4qhLpj{S1{gsl07FtwMK^r6W`22?^92`1M#V?aO;7xQ`NK;$aiFpU#H<%A zOzd1Z2%{sCjDo@+^uWl&!@I8tV`{@KFlQP_LM_<(S`@;*%A}$veK_c%WSDS5Z#B;o zRQ_Ii33!7`$fj$xE3-?*vER2w7X#Bfzy?slG^j&8nEYql!#qrbDGY&g)&khKMK5%D zS<<@JheIh(M$n-Zte*XVx&Qc@x4BDD!Z55?y3+YobOV+odyrZ~+BAY2^Z)=1!6Mwk z-uL}vJQs2*Cm*C=8sGsa_=1+_hc!q*W*%d>|Ex6J7iF}&p`JPAU)DXSK?cA8^Ebcq zGyiaHMy9I-%pCqu!5-Q@0~gdm^P{w4H*eMgwUZ}KoXltj6&lVH7*$7+ zCRMtWX;Y_9p+fz{q5s#=j@{1O!?=~}R$(0=h7~(@tOs0O(WX_qmTgdWPq{6iHUh~HFC7NSmiSzoVv-(#%V+`#+NZ?*1Y*+vK^=Lh88`V zw5mxPfG*w>ukOWu1qhRsEqemK*0*uz*1el|Z?%XVl}0*A4;c&s3QVX{uU}k!U9xf3 zd@^;+XI$!7lfIpM_s!j2SQ0*-{AfQfv@d3aZnw7*v*C-C=$n3h`}gtR_J;s;d8C#G zAwvcPTxka`eENvaJF6UXX(pB&Tu{OZDFkVbJN(N~!=&DrBQo{a)6Jg?iipodCra=p zzZF?*(M8|zQU77XrTn;p0bTNO3!gMTtWc(IA~C=Vo_HF?r(%HN36n7@^U=vCHOnQ6 z8L1ralqfE_Y(3uGJ25^a9`NVIG07~`%&ovNs>-B3xq|~G%HfBtco^vsN|lm%;*n|i z69IWIjBdmFLDW627EmS^$J zSKo^CssDgor9`WX?m{u0rTJqKt=_uXfmb%(+3b;unz~9+IH;7dZ1z}(zAlp% z%dn^M&YM0nd{$ejNuqdU){Odi=Imn9Xhk2m_#vi;N(?_+@{pdX;9|f16J-Zshq9)R zdgw#C?uaJR+w{}x@+SbynL306VV1Q>A3CZ!+ZHC2F}N*$z`-JoTFRarW?os(P;<_O zdjDpPkb9$h^oLNW8TIL@XR977if1a09jbY_qJBC_Me=S^Y1n(W?zzQ*Mp6=f=U7h8 zo;*!9zl<3=7N?J&B<6j-hzF_{Kml$g8f1{)Qbh3vB}mUA%1A`;6ehDFL_>FN>4!S_ zU<6ns%zfRm#s)rdK;dXY36Wb&F8EME-hAbG5J}MhVK~51iEt^JkOCXPR*`k2VQXfy zh9?~Gi~PYQAHP^YA`;cXZq30DG$aiPdnlA{T%r}{>kU3y5F7tpz=|>SqTUbyDJLog z5>0SL?EZm|GgxMF-GD_8Op!ylw1X0lYo8Jo1q>OCQ8bfKLKK5yjWc`$Kbasw3;!ST z!Y?jTZ!zK{Q~XeYWmu#ii-<)BeUSz}7zi=o;KLDZ!9hGqs2dxQ)+3?fM?lgf8Ck&( zJWzm0ClrB;jI`y`)UgFrF69(*U;`R=aR~^*EE$OyLOHr?$MIYs$L;(K43Xb-ZCf2A0Aq+5rNNk{Q6-CM+47wO;q(N@^;l~G%0RK)ENtCF~ z$_EE*x)eDGVu<`$gxl~4j7BV=6%3qyB`Ya)TmRrC;VT?{HZp~Cv$V*;{tLiG3=+cVAZuSpR_ z7=q!wZ**a$O0)(n(l7*N46Zf(n8!3Iu>d0^f)&Mprp~faj8QZq4FFI>E2dG8eJrB4 zUO2>G?_k=YWaAIfa1k6Fg2?&Emc3&NV{Mlb2Q~~YAAIlxTqP%sRR0)34dAF}UGmWm zVk`m+0O)}mBmoLv6a&8!Vn#7E>jnobU=htwM`QoNk2Ca8O5p9oVwlkdceu!TEre}* zQM@8Y!WURy&fVyv9_5&ZDHag`u2L2jKH?xh)#0)P>sm zhAs=`TiDR6ZxoRN*R}w|X*P9kXv^lM+yM*3jd5>T+6`b-BL52;xP>~Xe4l*OgV*pN z6rp$>Y+;xBHvPDT7i5%FFbFLu*^q>+#LjDt-3>)-Q|m1}J8TSv*>Hd9Wqg-OD=3&@*uNB(K& zMG)h{60OHHl%S@HYJu4^u|^^&q3`>wA_lGn0X6s?a=NVf-%XK&E2_)~@g1Bb#b5<> z0ljiOXsoB+pQ?gf|f7X=sDj%qqLt2fP3WxPcS3U?WIg zq051uBJM#+#Ts->CXTxn27vhc>(g?*!9(Q`Y^b0=qCo{&FutV_1_dVw{bW8Y;uq6U z$E54i4_<>~8h#Ek05;G0<}N-Q){uZ0t9gnh$XzDMNP{wLZXb6{+qJcU{rL%Kz}Y`# z5@o0-KXzdRT=9M}$tVUaK+%XM2O0o>1{5)VEdcqX75ooS761SifY2%d6pD<&ghC8R z<(#yyc48tMVujdTC35&^7M@Zh>Z z0z#;o*k%Vyq8k{7fkfCqZY2+>dWl29tj00Y}$3KVY&>8}tl1Pkj2CTgJv zh@l8u1dGb-c~U?T%h$Q7~Fson$T0mPYi7U4tNp$;6Vz2F*Mp> z;Lze8_}~vdPZ@=$as*F=Ca@%!0S^`dbnqn~f?xv?X$e|j8ncn#%BdSe;|;(OE#P4h zvOr?YadL=fmt;T-YvK>oAoZF>6Tiu|e!v;>@%$)?AM@hm*a9EaClzY2AQ=UIs;Tt0 z&X}wUU+lmI#1OB-uOd@y#V|52?m!oIM;RQT5~L6$7v+Pl@R8sRB)Xv%j9`;S1`Nf} z31|QwUDEGJE+(VGAKk(qz+ngyAsKb@PMBzyVXE1@&?XgDgO=> zoiZ=lfEeGR9rz#(Y~d-~+;vF!^mBaPTmLaSaiJ7#zS8a`G{y zW13KD5?-Jio z5|m&T@Bj|L`~cP6^yiIP*di%D@)i0v~>11O5PbnsYnc?vXTs14f_~ z9MWl|?I??Y2)&c(`b9iPqy4bcE#To6jwlt|^D=Jmkwl>aaPxHPAqe`gg?M1Z_EY3? z$v;QK5gwr>(ZV0v!4wui693BaK!XB2!jp!y4+H-asE+ak&ay&7F4ZtJF9u-~cB3E4 zVG(-36S9s(Ut+EJXcQImbowC)_HHEy6Gr*X9~c1pW;8FRt~c~S8?e9#SfMq2v?F+u zkJ@s2HnTH5^B$EnJ{7Wp$YP}G-{Mt^1;^@VF7x8vVeg(`-vG3=o3hAdg8$jBD95o zAPE9AVq?osD|R&K6kqh=xF}%*Hc!E@RA;Oq0n$-zl+|QW7EkSQSzVT|EH!3FBUVMG z?0#$r49pE00TeuMXLCgk)v*k?HE&KfWhInCk2cNvQ)x-#6O>?KL50WEVH(g5YBw(t z7|^-SE@Nq4@|5`V^2zd;(WFEhlyY_}oAO zpiX|e6m`sj2fX%q%#v?UO-2DXG~yr_yy)_nuTTDL=K^ie6m4}^*9iFUb%$>eZh=oI zuNt`VfEv|w{hmRP1uarctf*8*`O6!Cv;6UTeUR@zMx-y_lrm~ zcuV6Hb|87pkQ*efcuMtjfE7=H;0w^UdT&V=<`8>FV_&Hk+xkHV5Y}%F!SGNA7q(Md zkst`T7k&BaBH4E|E;bv5K~9Tj64>B^RX zc3=7-5C3*kTZzCNBpA(Lwt_{2X#>%7)kgb_R$uZV3BdFyN4SL1j1Arnh0FGA%@8J8 zXL$AI9)jRV=anLD7{&M@0d!b61os1zmUZOdAMs`#=22T8f?kgp#g27}NyB+Pa2vB{ zfc3^1FxQHm0E@G@y;zuw^8$!p&mUM|et*UiY)@|pD}SwcbJMuJfR~L^cze&!dy7XD zbYNWfMIS)ejGaJI_ZY>l*N;oXeP1twfA(JzQ*Y|w17F?V{41^`9BjF+u&G^ z|HX@&h8luEoXwaB3fiFg3YilcDxw(MmVuhorin*}9~1!uGS{_g7^7pWk2hL0ngE{n zijw_?ggQ7><{=40t(TX82S`|@V+)L1I+FR-Tbrnb0eNKn0T)c*-mG|k!Pcku>RW@F zG-fi*gc)PpSYHC#ffd;YJ^-ennvt|^s!78Nw)UKJcxu)eU;059!nv0p0tUXooBzX_ zk;;^;!dXW{OrtA8Pf)lSxBYamH3r-YcBw1hhVHK8ou$|xr zLV=kN`*dJgu|*>a>QkZwd1?rmuFnJ=K472~c?pQ%7&be$uG+Js!felXfErqD%vxXc zK@nzPmCbm6d-}Eas+wgxG;TSzM*C+@*;)GG7(O7U2ipgN;H-svoZ7j#MI#JKk*IF_ zXBfL##^D2Q;G`q<3yitC8EI^>n=~}1wy7t%lX;n+C7^MDse2g*Lcy@nJBF%3T?W|^ z0NfEC`%-(AyW{w0XxmvPy9IKv*6000o6!!vvk9KoU2atppKqTrid-uWS&!2(3U!5_i~K7hI>{Fd;!N+2N)uAl-K zV8jVU(s<2~mG9xEVG|I60RSKYtRM<9+!4|mBemDGtEam$#>JV%AH3lLOd7|X-~{qO z%X>VA5Slzh;Sk8c3IKo&kf9yW{4L7vxTXOS*Z={pKo3}a{Tu-i#wo_v1)@J?94?>) z>|3XC02een&GqK#$YT=tf&&oX5h!m=%GDJZKn2Kvd6RItzlh7(CD21f9crMy$=nH~ zo8BOOuUJ|X-P{TSzzlRj9nO0XqrnUkU<>@fNoTK^ZHdr-g{D6R)&FOJh;cjyssOBC z-HS{nG(I5?R3HHMq~;`B9b5qcnjj7a{NDTdD*3OZATtGs*nK6dUBn;Cp$3wD)gK}SKH#a{U80y2*posN z-XH-s!RSt>q&6V{t^m~G>lNGmArJgt-oU)-%^4n`1kl~VmjDD5!Mz{8dhQx2PC*Zv zKnJP;=J%x?%peMSMb+YLC*>AOy&}mrtMy>OJbc=psKs4*xiS4MZxU?qL&Dz?@jj z=mY+HrzN*pG;}viv^gVHFA> z0w}upTfW(sKmA>!8dv}fBy*rDpuufm1|EPG0DkxV-dDVwKJeifYQO{lLWGln1PdBG zh%li-gEl@;`v)zjAJc%-;N`KsRY|*4Drp%c% zYudbtGv`f69|$4|fr0=ncq)rl^vB|p&ZSIa>TzWhBEDlaCS(AzFss(B1(D2vlP{{+ zv1H4dJ&QK2+O-_jDUs7OuH3n*q{J}zGbpZlY(sJbLpQK0O-lR~&F8G@Rj!O1BNXug zUEj%+D_g#dIrCb7%bHjc3|jCf9Yqi#@j&ANE_jADPt*Z3bkkF1?xnof?1%;sSRMOz zY@@|0ey)ofKaM=P@~HQ)z?BW1>751(i+DgWKoPjGuHi|E&J+wcll;`JBG4j(kKgPW z7g+(v_VW4k>)XGNnX_l`{B2gqu~iBYXi&pyt^ZkO#w7jWT6;ERfI8D_!f=!2}4KL6x1&or4F z0RRmpWDqH^?h;f)3Bw{wZ@u;!S2);0ssR5qR2EZa;s6Sc3x4% z0|01X0tFNhHA1-qA>6?&Oloq0q*80F zp^!QEyX(UY7dX?8+JX;GI7$6HqQ~1hVF1J4 zjve5&j9aAaIHf6=aD+NV7tVR-p8rSW${UK~ol*&F2hmU2L_K4Yh80Egz{-;Y1Y`mo{1`7xaWwfH%~dQ9TU^aPlY z?Wsmk`D>s9k9D}j`R{!KY@duop@ZHa@F4T6-{u|&!VtpAAEEQ#DJp<5>Jd;zcG=)T zV8A_GFi?avtRb9ihr8SjLILZupovK3!hyh`1O)(u{cMQDBp!)*&U@Z}RA@IQSt4vM z%s~V!0ElvYPl;UYVu$L%hX2@%jwjUfVSn(ZxA`j_P!$D-nbpO*V*4bmUgZBtQWk#jb=-jQ~nnP$bzS(GXAo1*uw~`z^EmJWh9_LwNhnMT1*2TzTB!`|0$E~8+A4ebn001BWAZ|;uz1}RRrR}Y6N3y@BI?EDR_~1!4amzD?>$l8p zu2JyOJd=rMEdTnbfQhtF4(DojyCs2c6Gin278sW#!id9y8pPf7s@Eg(C__W-B!^{0 zr5_1+uWZ02+V$#pzwNcJjKXP@zbxnt)!46r4=fROgn?iGEDBPD8y!fn0l^eL@HyJR zFBOm!B|3u+ek%-O{YK-Jg$k-l92Ok{hj_*6b)~a3jFNja;Y4g0FN<#s*kG8q#6mr8 za-$>C4dZyozV(MsMFr!M@FM~Jd4qh33}xT)LkSR;k%>!EUj9s?#!>EaY3t$MLM2%w z{y>0#1v6$ZtJ$vtw$qhG(&p&Icg=MED{{pwmLFWw`}R_^ha7yxO|v^v?; zR;4&F%p_q`B+jAHb+x~(NpH^D*%*P%opgXzaH|`RM*bm_Wi9>|gprO$gNe*-T<@rYZCo$P!seBsaz9uDj{FdsI&R%5s&7ZIFu&;f+ zMxQ&&+kW@PQa$Sn<$2x<-&nF&+{K5F{7&KCWUf!X^EKuBknSMA&#%6SitnrjTYvj+ zTK@0E%l+^hDf)%dx%kgdB!Sf^4yIb(e50D1%WkcYxgVJnsMEVa0{NKR9L_^0yMMOdR2lL|r5Rj1ohyYXs zL?n#=P!uF&R5S!c^nYpi1cXGyq$EHFJ_B+Jdfl{)%z5}f4i&3<0Td;)YLARz`ZJ)g8Ci53IDrnc4W1*wcjI5Z`- zaOQOdfc;Mt5g!R3AO+|dPNIC4STc38bVnkQ4I zReH*7cK1+K>6+W%=o}h4%=9ra;FJe-Q_so6REJ}6*8B?L#{l-u(V>?D(SnSAW;oJt zON;15i8sqJrb8N8;$^+N2k zP$0upF0f=4L|@5(W=m{Nhi~Pf)ip{*zxdvRpy#4q@GS49CkAGG&C^38`1Fmwa*Rw@ zs>v1{Gt@-5YjW#EAJXM5cDV}%J8xOst}UU-!5jMOKgu;JTNZ0>)+}sSImhBhv#}O^ zqW7b-s@^Iv3Os}f#V)xXYekK)$K%msv>I{|)vh=(*E?3lWwWQWI}|CEb$65&1s*3f zYD(Tt`fRA)P72Khd*%7UMJ5Gu?a8mYPHI=x#JgDdx<(J`vVjzEsA5@ZZE-^)oA@)^ zb6(8$?;$*o3Kt|6MCZK345b4B$tXM!Ps|pkRr>#WK|jBxHG5&QePn5mC{k` zega=^>sLKXfG;;^=Kj?iHMK;AerG|9>N&SEV=kyKyCvNRwN+l+)&!m3nHfWwS}5D0 zA-wl}a0HIMuw9mK)WA*9%#IV_!Iv%{J6$D11eKhQ<`oc}2fghYdYG*e`Dw4|Eln@D zKvenNn81v2Bmg_lFk??%+>nUs*nBva&jLmFhHj!Mo;RG+fG^o7)1pKpNWiQpJ0UUb zu3&CNB*Ta#&MxU%#ZDu>Wpb*M`X}+8pXt|DK9!%f_idy7 z)SGt=QSM-gZUXqcx}a`#G*I71NE;$DF-U51X0oG+ig*3B;jMh**ZW5jj6wq!90HHg zI@XoWCB^~8fo^1Rg1D?w9et@od`3sn(qf}mfCXjlcc;4QGdPKI_TC#feN%!L~J@S@-Hepm0P1qB)lKthG zCB62R%2-Ef;<(KMUP$rF`U{u=A~GMq=^y>&2-9QM`i5jroiygn`Vano6?=+8=K665 zrM~q2$J4xwl+k#e?p3$uqtoU`dvP{_tij{fpz7XSYHHHY($)%g0vLQg7xOB(gSE6IWPk_8Ym@#(g~8@&cXJ?`5;C zJL1mb7977Nm*0tvqM+!>vZxv(jpa(@zi0WJKQS{G{d;u$!*;%WFm8b9XDFu@1trc$ zzj((2OG($fiWG>y3u=jPo{uGpMx5*SaBV0jUmqS)6SK%1Mhuw5z#^7Lkv>82Pv=Dj z$k@;X%8y4G&>mq_tF%2cdOR$=DnAvaD8&)-`HJ{cGO?U3(@UD?cv8@gzTf=N*}e^sXl(N>Qt z+l7QpL_?z&?k3X~YIl@$2L=@S1=g0)d^)Q#{%-TS4RlY47fho`OKqCH0zOTY{`w_) z>@zfY7uT-_W;s-oBTenLz4KWT zbe6CAnpvwhTG5ZMqZqgH3UH5)r!(8?F2Mu=Zm4WiMF;Fm1}FI*iOxrSW_?)Ns~J~ zJqOMT+^)s3I+Fa}`RPKYOpmu3+H2P2Y2028cFwVD+&N=#s-+hQpshe-zt}EdRPil{ z=lV{d%$~xwK*`qzR^p%x#Z)$QAkrq9-Gq-^G1DgRbKQ67!WQAhdG@)@1Wtjz?e9ie z@8)-!;#6GxAfCAdDG^G0^eIWF6ce`gw!PI#f61M7XA24Aj`|WYGy0jnnuKViUT(V* z2E2_I6j~7UUa%pCpEY}?;F8x=ey3^qc#4v&{>xvQHrlI$n}+bT?Yx}3k@GjF$Zot? zxW46-=;O&zb#79IS4Zo-N&jxP^Ea=+CI{7%U=qg;63?I`5>MtqVwX`q8Nahj!tDFp z7s_?g)a)fmE?|0-7({QZnr*9m)w1!2f^+8lB5za)6l7~EPGOPgouX&-!&3KcJsx(o zp;hDF66W%(uq=l;BXZ&`DA}sevmQ*lx~ZF_-nVm-WK}PxHmQ~`0ls2B4lVm1%dwAp zayj=3aNWT77Eg{M4)|F0$%vOmL$lShnu3)ZMW<9|^f;whdnl*Lngj1pJVqwc=qqek zByt#^?ooa#o1UfU#7U4QN`c|xK3Q6`yhMYpeBMq3C*IPM;qtc%9tjbh2V@TPbyFs) z$)z`tq=Ip|SpJ|zT9QEB)MK({Gsd&&`7Gn2qa2w6Q+{s$U$MF}F}szyDDrDQZ|Zt~drPm4JE&9jWAO z?^gN=zuH@0t7~a=GHl8DT$3G2`<>2v;X-NmuF4s&T$35{i1Lv9C}6tNv-kn&OD_&> z=+s~x&R)V3bXHP(bM5_bm%v>yy1LkK9jw{p8}k=spMzA@S3o~e0=wReNy?L46HcYB+H z@73aZJgQ?%!)>CMVYpb6)`s!oVs|_|Hn!pA_a3&uR)6+){BjcEDvJr@%Gq)y^!SQs z-GTFKKYo(vQgbJH{SnvA&EyK3cq?;R$Ufi8O{G#V53E4nx%d7mAp^J?iD-6xp`zMSK85fc)_#q2>{gPIJ!vNNS6~gCf*t~SD0E=K9)>?Ei?VgPqp#T;vAoyq%ZcJ2abFCOe1;?EA7DI zXxiYbG?Qi#%&F24qhP~FAh2)O-qGO5UzNIvQo|{KrKa96;2h`i7Zl4=I~-P$J~W%o z{ph>1P|XL~$20m_pn3&J^J(xgl6rZ7m>6wi_eiW;dQ8fnqOEoRRz;aF+ z0ZUvJwJF_TJ+KZ|X5r(l7xa-UeWW%R$N?)W1#UxhAa0QijR7+TiGfcP2||kbm50QW zF7y1E2uGeP8Bx4!UiwrYh`YmpDR@qmqf_aug*luq7gX}`T2v1EqcU5LC zkyBjb`7&dNmw+Gb#4O77Z&Jy=Jrhz_m(p0+eOY>IwTiervPX*JQMzGFTukt--T<&a zu(mi0M*e0utC#Ng@#?JjbjwDDbv^%t+bXjgLZGa#J~FHmnjn{F#2IQMi2V{c32!v! zYa>vlX{I=sfBVZxZz5NI5`yMO)GW;9mw-PnXe%mZOGmCZcJ}SWQj`7T&vaSjHiJpP30rlGm$_%^m{y`dQU zz3XW3C8fs19)y`$^quw3(kGUT2BC zCTOJ1Y}@4;7jdY5wxU~Z1^Hn!c2o5Rf6QBr>T|AdS3|J8;1)gWkP4jZZ&+{pQ4F_w zuZ*lH2Pa5z`Izd2fY7#(sA!P5i93>6k*QuCBbJVrQ?A?ls>a%c?Rw~5<31K;$Q5+& zwfaW{RZ5@uV20TlX1U}uM-$L+WacVR%z779B1<7?I+#P@L6NP0sA$Xv^NTp3!|ew~ zv9*{wZ+iUE83=HLh`s`+X5}4e{%nu}A~Y<_eAn>kr%YAPH`A>a zvslx0uB$8RvwhZH%avw}6I$<$jX8Jlo}HtzRZ*{F>abj8w%O{mJ7j;uNz3Yo%^k=_ zpw#3zQfPKLbl`DdOW&}BChR1hCCFOjqi))p;z$MG4RZK?rqa?M7d@>A!(n)WpCc|^ zsSe!4C93@V^QF?M4_wt}?!PWL)b3c#SKWSG&6nTI!t&+wM5&*tVUHZQHhO+qP|+9O&_*#rM z8lLDJ{xQXdR3}9Dy6;N+9b{#?OHu2{r*50A-$tpF#$3yl-D@}|Bnomlcu-ul9}k>= z`+X79?9WqF21*hJs=Nv^{+_$n)DZg4B$RBYg^8j{!-Syj7RFXtJkySaiJ)t(JU7lZ z4bFzWOE z`qaf!p9C^>N}jP(NIE(V=}hLD1UpPw_&7cu;V83~As9%#@Mr#D+K)LP6P+)FY!QY}m{?bP;MQ#`n_fz9psh-ON*C5LZ-8J)4E~9L3q&3?%4L zD8iIdH z!Q^04?mJn*qk`0dTU@`91(!xm-kx@~zv>+jh{B5E!g&eP2oLgNpxPK24^!e5RUjo| z5Da+JATQmJoG0rwJV7Jq(ETh?_9a>G&BZth3SdqQMlHAseJ3^QWy`KeQ)u%uD`YE~ zLTdlyT`f3^=J`d)E47Z~9`C`xob`8kxkX$*sRP%(c3`eOvc0BuY-skN%m%4F%}b&3 zsG0CkLRS!ReE4&b)BL!=SCu8-r^RL;qWazs4ZSDj%J;(w73Em;52Okvr{eMQ5n>0& zS)Q_JF{%%O^mUU#{qTfPjx1)~NWlg&nRI9@GEXaO>mETxm*Fw>eINVE9LpDoW?Gt!B}Fs&x^VW8eE5ou`amzj7Iw%T7w8{zq8M>uvMAl z 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�MD@-I#txRQY+Ywm~)E-MU&t8`Q4fDLs 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 import easygui - >>> easygui.ynbox('Shall I continue?', 'Title', ('Yes', 'No')) - 1 - >>> easygui.msgbox('This is a basic message box.', 'Title Goes Here') - 'OK' - >>> easygui.buttonbox('Click on your favorite flavor.', 'Favorite Flavor', ('Chocolate', 'Vanilla', 'Strawberry')) - 'Chocolate' - - - A full tutorial is available at - . - - LICENSE INFORMATION - =================== - EasyGui version |version| - - Copyright (c) 2015, Stephen Raymond Ferg - - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - ABOUT THE EASYGUI LICENSE - ------------------------- - | This license is what is generally known as the "modified BSD license", - | aka "revised BSD", "new BSD", "3-clause BSD". - | See http://www.opensource.org/licenses/bsd-license.php - | - | This license is GPL-compatible. - | See ``_ - | See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses - | - | The BSD License is less restrictive than GPL. - | It allows software released under the license to be incorporated into proprietary products. - | Works based on the software may be released under a proprietary license or as closed source software. - | ``_ - -Keywords: gui linux windows graphical user interface -Platform: UNKNOWN -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: License :: OSI Approved :: BSD License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Topic :: Software Development :: User Interfaces diff --git a/app_windows/lib/easygui/easygui.egg-info/SOURCES.txt b/app_windows/lib/easygui/easygui.egg-info/SOURCES.txt deleted file mode 100644 index c6e1b2d..0000000 --- a/app_windows/lib/easygui/easygui.egg-info/SOURCES.txt +++ /dev/null @@ -1,23 +0,0 @@ -README.txt -setup.cfg -setup.py -easygui/__init__.py -easygui/easygui.py -easygui/python_and_check_logo.gif -easygui/python_and_check_logo.jpg -easygui/python_and_check_logo.png -easygui/zzzzz.gif -easygui.egg-info/PKG-INFO -easygui.egg-info/SOURCES.txt -easygui.egg-info/dependency_links.txt -easygui.egg-info/top_level.txt -easygui/boxes/__init__.py -easygui/boxes/about.py -easygui/boxes/base_boxes.py -easygui/boxes/demo.py -easygui/boxes/derived_boxes.py -easygui/boxes/egstore.py -easygui/boxes/state.py -easygui/boxes/text_box.py -easygui/boxes/updatable_text_box.py -easygui/boxes/utils.py \ No newline at end of file diff --git a/app_windows/lib/easygui/easygui.egg-info/dependency_links.txt b/app_windows/lib/easygui/easygui.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/app_windows/lib/easygui/easygui.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app_windows/lib/easygui/easygui.egg-info/top_level.txt b/app_windows/lib/easygui/easygui.egg-info/top_level.txt deleted file mode 100644 index 8f33f7d..0000000 --- a/app_windows/lib/easygui/easygui.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -easygui diff --git a/app_windows/lib/easygui/easygui/__init__.py b/app_windows/lib/easygui/easygui/__init__.py deleted file mode 100644 index 203ea2a..0000000 --- a/app_windows/lib/easygui/easygui/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Hello from easygui/__init__.py - -""" - -# __all__ must be defined in order for Sphinx to generate the API automatically. -__all__ = ['buttonbox', - 'diropenbox', - 'fileopenbox', - 'filesavebox', - 'textbox', - 'ynbox', - 'ccbox', - 'boolbox', - 'indexbox', - 'msgbox', - 'integerbox', - 'multenterbox', - 'enterbox', - 'exceptionbox', - 'choicebox', - 'codebox', - 'passwordbox', - 'multpasswordbox', - 'multchoicebox', - 'EgStore', - 'eg_version', - 'egversion', - 'abouteasygui', - 'egdemo', -] - -# Import all functions that form the API -from .boxes.base_boxes import buttonbox -from .boxes.base_boxes import diropenbox -from .boxes.base_boxes import fileopenbox -from .boxes.base_boxes import filesavebox - -from .boxes.text_box import textbox - -from .boxes.derived_boxes import ynbox -from .boxes.derived_boxes import ccbox -from .boxes.derived_boxes import boolbox -from .boxes.derived_boxes import indexbox -from .boxes.derived_boxes import msgbox -from .boxes.derived_boxes import integerbox -from .boxes.derived_boxes import multenterbox -from .boxes.derived_boxes import enterbox -from .boxes.derived_boxes import exceptionbox -from .boxes.derived_boxes import choicebox -from .boxes.derived_boxes import codebox -from .boxes.derived_boxes import passwordbox -from .boxes.derived_boxes import multpasswordbox -from .boxes.derived_boxes import multchoicebox -from .boxes.egstore import EgStore -from .boxes.about import eg_version, egversion, abouteasygui -from .boxes.demo import egdemo \ No newline at end of file diff --git a/app_windows/lib/easygui/easygui/boxes/__init__.py b/app_windows/lib/easygui/easygui/boxes/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app_windows/lib/easygui/easygui/boxes/about.py b/app_windows/lib/easygui/easygui/boxes/about.py deleted file mode 100644 index 313b65d..0000000 --- a/app_windows/lib/easygui/easygui/boxes/about.py +++ /dev/null @@ -1,221 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - - -from .derived_boxes import codebox - -eg_version = '0.97.4' -egversion = eg_version - - -def abouteasygui(): - """ - shows the easygui revision history - """ - codebox("About EasyGui\n{}".format(eg_version), - "EasyGui", EASYGUI_ABOUT_INFORMATION) - return None - - -EASYGUI_ABOUT_INFORMATION = ''' -======================================================================== -0.97.4 -======================================================================== -This is a minor bug-fix release to address python 3 import errors. - -======================================================================== -0.97.3 -======================================================================== -Some more fixes especially to fix Debian distro problems. - -======================================================================== -0.97.1 & 0.97.2 (2014-12-24) -======================================================================== -Boring, embarrassing uploads to fix pypi install problems. - -======================================================================== -0.97(2014-12-20) -======================================================================== -We are happy to release version 0.97 of easygui. The intent of this release is to address some basic -functionality issues as well as improve easygui in the ways people have asked. - -Robert Lugg (me) was searching for a GUI library for my python work. I saw easygui and liked very much its -paradigm. Stephen Ferg, the creator and developer of easygui, graciously allowed me to start development -back up. With the help of Alexander Zawadzki, Horst Jens, and others I set a goal to release before the -end of 2014. - -We rely on user feedback so please bring up problems, ideas, or just say how you are using easygui. - -BUG FIXES ---------- - * sourceforge #4: easygui docs contain bad references to easygui_pydoc.html - * sourceforge #6: no index.html in docs download file. Updated to sphinx which as autolinking. - * sourceforge #8: unicode issues with file*box. Fixed all that I knew how. - * sourceforge #12: Cannot Exit with 'X'. Now X and escape either return "cancel_button", if set, or None - -ENHANCEMENTS ------------- - * Added ability to specify default_choice and cancel_choice for button widgets (See API docs) - * True and False are returned instead of 1 and 0 for several boxes - * Allow user to map keyboard keys to buttons by enclosing a hotkey in square braces like: "Pick [M]e", which would assign - keyboard key M to that button. Double braces hide that character, and keysyms are allowed: - [[q]]Exit Would show Exit on the button, and the button would be controlled by the q key - []Help Would show Help on the button, and the button would be controlled by the F1 function key - NOTE: We are still working on the exact syntax of these key mappings as Enter, space, and arrows are already being - used. - * Escape and the windows 'X' button always work in buttonboxes. Those return None in that case. - * sourceforge #9: let fileopenbox open multiple files. Added optional argument 'multiple' - * Location of dialogs on screen is preserved. This isn't perfect yet, but now, at least, the dialogs don't - always reset to their default position! - * added some, but not all of the bugs/enhancements developed by Robbie Brook: - http://all-you-need-is-tech.blogspot.com/2013/01/improving-easygui-for-python.html - -KNOWN ISSUES ------------- - * In the documentation, there were previous references to issues when using the IDLE IDE. I haven't - experienced those, but also didn't do anything to fix them, so they may still be there. Please report - any problems and we'll try to address them - * I am fairly new to contributing to open source, so I don't understand packaging, pypi, etc. There - are likely problems as well as better ways to do things. Again, I appreciate any help or guidance. - -Other Changes (that you likely don't care about) ------------------------------------------------- - * Restructured loading of image files to try PIL first throw error if file doesn't exist. - * Converted docs to sphinx with just a bit of doctest. Most content was retained from the old site, so - there might be some redundancies still. Please make any suggested improvements. - * Set up a GitHub repository for development: https://github.com/robertlugg/easygui - -EasyGui is licensed under what is generally known as -the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD"). -This license is GPL-compatible but less restrictive than GPL. - -======================================================================== -0.96(2010-08-29) -======================================================================== -This version fixes some problems with version independence. - -BUG FIXES ------------------------------------------------------- - * A statement with Python 2.x-style exception-handling syntax raised - a syntax error when running under Python 3.x. - Thanks to David Williams for reporting this problem. - - * Under some circumstances, PIL was unable to display non-gif images - that it should have been able to display. - The cause appears to be non-version-independent import syntax. - PIL modules are now imported with a version-independent syntax. - Thanks to Horst Jens for reporting this problem. - -LICENSE CHANGE ------------------------------------------------------- -Starting with this version, EasyGui is licensed under what is generally known as -the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD"). -This license is GPL-compatible but less restrictive than GPL. -Earlier versions were licensed under the Creative Commons Attribution License 2.0. - - -======================================================================== -0.95(2010-06-12) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - * Previous versions of EasyGui could display only .gif image files using the - msgbox "image" argument. This version can now display all image-file formats - supported by PIL the Python Imaging Library) if PIL is installed. - If msgbox is asked to open a non-gif image file, it attempts to import - PIL and to use PIL to convert the image file to a displayable format. - If PIL cannot be imported (probably because PIL is not installed) - EasyGui displays an error message saying that PIL must be installed in order - to display the image file. - - Note that - http://www.pythonware.com/products/pil/ - says that PIL doesn't yet support Python 3.x. - - -======================================================================== -0.94(2010-06-06) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - * The codebox and textbox functions now return the contents of the box, rather - than simply the name of the button ("Yes"). This makes it possible to use - codebox and textbox as data-entry widgets. A big "thank you!" to Dominic - Comtois for requesting this feature, patiently explaining his requirement, - and helping to discover the tkinter techniques to implement it. - - NOTE THAT in theory this change breaks backward compatibility. But because - (in previous versions of EasyGui) the value returned by codebox and textbox - was meaningless, no application should have been checking it. So in actual - practice, this change should not break backward compatibility. - - * Added support for SPACEBAR to command buttons. Now, when keyboard - focus is on a command button, a press of the SPACEBAR will act like - a press of the ENTER key; it will activate the command button. - - * Added support for keyboard navigation with the arrow keys (up,down,left,right) - to the fields and buttons in enterbox, multenterbox and multpasswordbox, - and to the buttons in choicebox and all buttonboxes. - - * added highlightthickness=2 to entry fields in multenterbox and - multpasswordbox. Now it is easier to tell which entry field has - keyboard focus. - - -BUG FIXES ------------------------------------------------------- - * In EgStore, the pickle file is now opened with "rb" and "wb" rather than - with "r" and "w". This change is necessary for compatibility with Python 3+. - Thanks to Marshall Mattingly for reporting this problem and providing the fix. - - * In integerbox, the actual argument names did not match the names described - in the docstring. Thanks to Daniel Zingaro of at University of Toronto for - reporting this problem. - - * In integerbox, the "argLowerBound" and "argUpperBound" arguments have been - renamed to "lowerbound" and "upperbound" and the docstring has been corrected. - - NOTE THAT THIS CHANGE TO THE ARGUMENT-NAMES BREAKS BACKWARD COMPATIBILITY. - If argLowerBound or argUpperBound are used, an AssertionError with an - explanatory error message is raised. - - * In choicebox, the signature to choicebox incorrectly showed choicebox as - accepting a "buttons" argument. The signature has been fixed. - - -======================================================================== -0.93(2009-07-07) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - - * Added exceptionbox to display stack trace of exceptions - - * modified names of some font-related constants to make it - easier to customize them - - -======================================================================== -0.92(2009-06-22) -======================================================================== - -ENHANCEMENTS ------------------------------------------------------- - - * Added EgStore class to to provide basic easy-to-use persistence. - -BUG FIXES ------------------------------------------------------- - - * Fixed a bug that was preventing Linux users from copying text out of - a textbox and a codebox. This was not a problem for Windows users. - -''' diff --git a/app_windows/lib/easygui/easygui/boxes/base_boxes.py b/app_windows/lib/easygui/easygui/boxes/base_boxes.py deleted file mode 100644 index be697d6..0000000 --- a/app_windows/lib/easygui/easygui/boxes/base_boxes.py +++ /dev/null @@ -1,1103 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - - -import os -import string - - -from . import utils as ut -from .utils import * -from . import state as st - -# Initialize some global variables that will be reset later -__choiceboxMultipleSelect = None -__replyButtonText = None -__choiceboxResults = None -__firstWidget = None -__enterboxText = None -__enterboxDefaultText = "" -__multenterboxText = "" -choiceboxChoices = None -choiceboxWidget = None -entryWidget = None -boxRoot = None - -# ------------------------------------------------------------------- -# buttonbox -# ------------------------------------------------------------------- - - -def buttonbox(msg="", title=" ", choices=("Button[1]", "Button[2]", "Button[3]"), image=None, root=None, default_choice=None, cancel_choice=None): - """ - Display a msg, a title, an image, and a set of buttons. - The buttons are defined by the members of the choices list. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which button should be pressed - :return: the text of the button that the user selected - """ - global boxRoot, __replyButtonText, buttonsFrame - - # If default is not specified, select the first button. This matches old - # behavior. - if default_choice is None: - default_choice = choices[0] - - # Initialize __replyButtonText to the first choice. - # This is what will be used if the window is closed by the close button. - __replyButtonText = choices[0] - - if root: - root.withdraw() - boxRoot = Toplevel(master=root) - boxRoot.withdraw() - else: - boxRoot = Tk() - boxRoot.withdraw() - - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.minsize(400, 100) - - # ------------- define the messageFrame --------------------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the imageFrame --------------------------------- - if image: - tk_Image = None - try: - tk_Image = ut.load_tk_image(image) - except Exception as inst: - print(inst) - if tk_Image: - imageFrame = Frame(master=boxRoot) - imageFrame.pack(side=TOP, fill=BOTH) - label = Label(imageFrame, image=tk_Image) - label.image = tk_Image # keep a reference! - label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m') - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # -------------------- place the widgets in the frames ------------------- - messageWidget = Message(messageFrame, text=msg, width=400) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m') - - __put_buttons_in_buttonframe(choices, default_choice, cancel_choice) - - # -------------- the action begins ----------- - boxRoot.deiconify() - boxRoot.mainloop() - boxRoot.destroy() - if root: - root.deiconify() - return __replyButtonText - - -def bindArrows(widget): - - widget.bind("", tabRight) - widget.bind("", tabLeft) - - widget.bind("", tabRight) - widget.bind("", tabLeft) - - -def tabRight(event): - boxRoot.event_generate("") - - -def tabLeft(event): - boxRoot.event_generate("") - - -# ----------------------------------------------------------------------- -# __multfillablebox -# ----------------------------------------------------------------------- -def __multfillablebox(msg="Fill in values for the fields.", title=" ", fields=(), values=(), mask=None): - global boxRoot, __multenterboxText, __multenterboxDefaultText, cancelButton, entryWidget, okButton - - choices = ["OK", "Cancel"] - if len(fields) == 0: - return None - - fields = list(fields[:]) # convert possible tuples to a list - values = list(values[:]) # convert possible tuples to a list - - # TODO RL: The following seems incorrect when values>fields. Replace - # below with zip? - if len(values) == len(fields): - pass - elif len(values) > len(fields): - fields = fields[0:len(values)] - else: - while len(values) < len(fields): - values.append("") - - boxRoot = Tk() - - boxRoot.protocol('WM_DELETE_WINDOW', __multenterboxQuit) - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.bind("", __multenterboxCancel) - - # -------------------- put subframes in the boxRoot -------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # -------------------- the msg widget ---------------------------- - messageWidget = Message(messageFrame, width="4.5i", text=msg) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m') - - global entryWidgets - entryWidgets = list() - - lastWidgetIndex = len(fields) - 1 - - for widgetIndex in range(len(fields)): - argFieldName = fields[widgetIndex] - argFieldValue = values[widgetIndex] - entryFrame = Frame(master=boxRoot) - entryFrame.pack(side=TOP, fill=BOTH) - - # --------- entryWidget ---------------------------------------------- - labelWidget = Label(entryFrame, text=argFieldName) - labelWidget.pack(side=LEFT) - - entryWidget = Entry(entryFrame, width=40, highlightthickness=2) - entryWidgets.append(entryWidget) - entryWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.TEXT_ENTRY_FONT_SIZE)) - entryWidget.pack(side=RIGHT, padx="3m") - - bindArrows(entryWidget) - - entryWidget.bind("", __multenterboxGetText) - entryWidget.bind("", __multenterboxCancel) - - # for the last entryWidget, if this is a multpasswordbox, - # show the contents as just asterisks - if widgetIndex == lastWidgetIndex: - if mask: - entryWidgets[widgetIndex].configure(show=mask) - - # put text into the entryWidget - if argFieldValue is None: - argFieldValue = '' - entryWidgets[widgetIndex].insert(0, '{}'.format(argFieldValue)) - widgetIndex += 1 - - # ------------------ ok button ------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=BOTTOM, fill=BOTH) - - okButton = Button(buttonsFrame, takefocus=1, text="OK") - bindArrows(okButton) - okButton.pack( - expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __multenterboxGetText - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ------------------ cancel button ------------------------------- - cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel") - bindArrows(cancelButton) - cancelButton.pack( - expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __multenterboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ------------------- time for action! ----------------- - entryWidgets[0].focus_force() # put the focus on the entryWidget - boxRoot.mainloop() # run it! - - # -------- after the run has completed ---------------------------------- - boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now - return __multenterboxText - - -# ----------------------------------------------------------------------- -# __multenterboxGetText -# ----------------------------------------------------------------------- -def __multenterboxGetText(event): - global __multenterboxText - - __multenterboxText = list() - for entryWidget in entryWidgets: - __multenterboxText.append(entryWidget.get()) - boxRoot.quit() - - -def __multenterboxCancel(event): - global __multenterboxText - __multenterboxText = None - boxRoot.quit() - - -def __multenterboxQuit(): - __multenterboxCancel(None) - - - -def __fillablebox(msg, title="", default="", mask=None, image=None, root=None): - """ - Show a box in which a user can enter some text. - You may optionally specify some default text, which will appear in the - enterbox when it is displayed. - Returns the text that the user entered, or None if he cancels the operation. - """ - - global boxRoot, __enterboxText, __enterboxDefaultText - global cancelButton, entryWidget, okButton - - if title is None: - title == "" - if default is None: - default = "" - __enterboxDefaultText = default - __enterboxText = __enterboxDefaultText - - if root: - root.withdraw() - boxRoot = Toplevel(master=root) - boxRoot.withdraw() - else: - boxRoot = Tk() - boxRoot.withdraw() - - boxRoot.protocol('WM_DELETE_WINDOW', __enterboxQuit) - boxRoot.title(title) - boxRoot.iconname('Dialog') - boxRoot.geometry(st.rootWindowPosition) - boxRoot.bind("", __enterboxCancel) - - # ------------- define the messageFrame --------------------------------- - messageFrame = Frame(master=boxRoot) - messageFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the imageFrame --------------------------------- - try: - tk_Image = ut.load_tk_image(image) - except Exception as inst: - print(inst) - tk_Image = None - if tk_Image: - imageFrame = Frame(master=boxRoot) - imageFrame.pack(side=TOP, fill=BOTH) - label = Label(imageFrame, image=tk_Image) - label.image = tk_Image # keep a reference! - label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m') - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the entryFrame --------------------------------- - entryFrame = Frame(master=boxRoot) - entryFrame.pack(side=TOP, fill=BOTH) - - # ------------- define the buttonsFrame --------------------------------- - buttonsFrame = Frame(master=boxRoot) - buttonsFrame.pack(side=TOP, fill=BOTH) - - # -------------------- the msg widget ---------------------------- - messageWidget = Message(messageFrame, width="4.5i", text=msg) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m') - - # --------- entryWidget ---------------------------------------------- - entryWidget = Entry(entryFrame, width=40) - bindArrows(entryWidget) - entryWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.TEXT_ENTRY_FONT_SIZE)) - if mask: - entryWidget.configure(show=mask) - entryWidget.pack(side=LEFT, padx="3m") - entryWidget.bind("", __enterboxGetText) - entryWidget.bind("", __enterboxCancel) - # put text into the entryWidget - entryWidget.insert(0, __enterboxDefaultText) - - # ------------------ ok button ------------------------------- - okButton = Button(buttonsFrame, takefocus=1, text="OK") - bindArrows(okButton) - okButton.pack( - expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __enterboxGetText - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<{}>".format(selectionEvent), handler) - - # ------------------ cancel button ------------------------------- - cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel") - bindArrows(cancelButton) - cancelButton.pack( - expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m') - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __enterboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<{}>".format(selectionEvent), handler) - - # ------------------- time for action! ----------------- - entryWidget.focus_force() # put the focus on the entryWidget - boxRoot.deiconify() - boxRoot.mainloop() # run it! - - # -------- after the run has completed ---------------------------------- - if root: - root.deiconify() - boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now - return __enterboxText - - -def __enterboxGetText(event): - global __enterboxText - - __enterboxText = entryWidget.get() - boxRoot.quit() - - -def __enterboxRestore(event): - global entryWidget - - entryWidget.delete(0, len(entryWidget.get())) - entryWidget.insert(0, __enterboxDefaultText) - - -def __enterboxCancel(event): - global __enterboxText - - __enterboxText = None - boxRoot.quit() - - -def __enterboxQuit(): - return __enterboxCancel(None) - - -# ----------------------------------------------------------------------- -# __choicebox -# ----------------------------------------------------------------------- -def __choicebox(msg, title, choices): - """ - internal routine to support choicebox() and multchoicebox() - """ - global boxRoot, __choiceboxResults, choiceboxWidget, defaultText - global choiceboxWidget, choiceboxChoices - # ------------------------------------------------------------------- - # If choices is a tuple, we make it a list so we can sort it. - # If choices is already a list, we make a new list, so that when - # we sort the choices, we don't affect the list object that we - # were given. - # ------------------------------------------------------------------- - choices = list(choices[:]) - - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - defaultButtons = ["OK", "Cancel"] - - choices = [str(c) for c in choices] - - # TODO RL: lines_to_show is set to a min and then set to 20 right after - # that. Figure out why. - lines_to_show = min(len(choices), 20) - lines_to_show = 20 - - if title is None: - title = "" - - # Initialize __choiceboxResults - # This is the value that will be returned if the user clicks the close icon - __choiceboxResults = None - - boxRoot = Tk() - # RL: Removed so top-level program can be closed with an 'x' - boxRoot.protocol('WM_DELETE_WINDOW', __choiceboxQuit) - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - st.rootWindowPosition = "+0+0" - boxRoot.geometry(st.rootWindowPosition) - boxRoot.expand = NO - boxRoot.minsize(root_width, root_height) - st.rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(st.rootWindowPosition) - - # ---------------- put the frames in the window -------------------------- - message_and_buttonsFrame = Frame(master=boxRoot) - message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO) - - messageFrame = Frame(message_and_buttonsFrame) - messageFrame.pack(side=LEFT, fill=X, expand=YES) - - buttonsFrame = Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=RIGHT, expand=NO, pady=0) - - choiceboxFrame = Frame(master=boxRoot) - choiceboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES) - - # -------------------------- put the widgets in the frames --------------- - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = Message( - messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m') - - # -------- put the choiceboxWidget in the choiceboxFrame ---------------- - choiceboxWidget = Listbox(choiceboxFrame, height=lines_to_show, borderwidth="1m", relief="flat", bg="white" - ) - - if __choiceboxMultipleSelect: - choiceboxWidget.configure(selectmode=MULTIPLE) - - choiceboxWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - - # add a vertical scrollbar to the frame - rightScrollbar = Scrollbar( - choiceboxFrame, orient=VERTICAL, command=choiceboxWidget.yview) - choiceboxWidget.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = Scrollbar( - choiceboxFrame, orient=HORIZONTAL, command=choiceboxWidget.xview) - choiceboxWidget.configure(xscrollcommand=bottomScrollbar.set) - - # pack the Listbox and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, so that the bottomScrollbar will - # be located properly. - - bottomScrollbar.pack(side=BOTTOM, fill=X) - rightScrollbar.pack(side=RIGHT, fill=Y) - - choiceboxWidget.pack( - side=LEFT, padx="1m", pady="1m", expand=YES, fill=BOTH) - - # --------------------------------------------------- - # sort the choices - # eliminate duplicates - # put the choices into the choicebox Widget - # --------------------------------------------------- - - choices = ut.lower_case_sort(choices) - - lastInserted = None - choiceboxChoices = list() - for choice in choices: - if choice == lastInserted: - continue - else: - choiceboxWidget.insert(END, choice) - choiceboxChoices.append(choice) - lastInserted = choice - - boxRoot.bind('', KeyboardListener) - - # put the buttons in the buttonsFrame - if len(choices): - okButton = Button( - buttonsFrame, takefocus=YES, text="OK", height=1, width=6) - bindArrows(okButton) - okButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __choiceboxGetChoice - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # now bind the keyboard events - choiceboxWidget.bind("", __choiceboxGetChoice) - choiceboxWidget.bind("", __choiceboxGetChoice) - else: - # now bind the keyboard events - choiceboxWidget.bind("", __choiceboxCancel) - choiceboxWidget.bind("", __choiceboxCancel) - - cancelButton = Button( - buttonsFrame, takefocus=YES, text="Cancel", height=1, width=6) - bindArrows(cancelButton) - cancelButton.pack( - expand=NO, side=BOTTOM, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = cancelButton - handler = __choiceboxCancel - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - commandButton.bind("<%s>" % selectionEvent, handler) - - # add special buttons for multiple select features - if len(choices) and __choiceboxMultipleSelect: - selectionButtonsFrame = Frame(messageFrame) - selectionButtonsFrame.pack(side=RIGHT, fill=Y, expand=NO) - - selectAllButton = Button( - selectionButtonsFrame, text="Select All", height=1, width=6) - bindArrows(selectAllButton) - - selectAllButton.bind("", __choiceboxSelectAll) - selectAllButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - clearAllButton = Button( - selectionButtonsFrame, text="Clear All", height=1, width=6) - bindArrows(clearAllButton) - clearAllButton.bind("", __choiceboxClearAll) - clearAllButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - # -------------------- bind some keyboard events ------------------------- - boxRoot.bind("", __choiceboxCancel) - - # --------------------- the action begins -------------------------------- - # put the focus on the choiceboxWidget, and the select highlight on the - # first item - choiceboxWidget.select_set(0) - choiceboxWidget.focus_force() - - # --- run it! ----- - boxRoot.mainloop() - try: - boxRoot.destroy() - except: - pass - return __choiceboxResults - - -def __choiceboxGetChoice(event): - global boxRoot, __choiceboxResults, choiceboxWidget - - if __choiceboxMultipleSelect: - __choiceboxResults = [ - choiceboxWidget.get(index) for index in choiceboxWidget.curselection()] - else: - choice_index = choiceboxWidget.curselection() - __choiceboxResults = choiceboxWidget.get(choice_index) - - boxRoot.quit() - - -def __choiceboxSelectAll(event): - global choiceboxWidget, choiceboxChoices - - choiceboxWidget.selection_set(0, len(choiceboxChoices) - 1) - - -def __choiceboxClearAll(event): - global choiceboxWidget, choiceboxChoices - - choiceboxWidget.selection_clear(0, len(choiceboxChoices) - 1) - - -def __choiceboxCancel(event): - global boxRoot, __choiceboxResults - - __choiceboxResults = None - boxRoot.quit() - - -def __choiceboxQuit(): - __choiceboxCancel(None) - - -def KeyboardListener(event): - global choiceboxChoices, choiceboxWidget - key = event.keysym - if len(key) <= 1: - if key in string.printable: - # Find the key in the list. - # before we clear the list, remember the selected member - try: - start_n = int(choiceboxWidget.curselection()[0]) - except IndexError: - start_n = -1 - - # clear the selection. - choiceboxWidget.selection_clear(0, 'end') - - # start from previous selection +1 - for n in range(start_n + 1, len(choiceboxChoices)): - item = choiceboxChoices[n] - if item[0].lower() == key.lower(): - choiceboxWidget.selection_set(first=n) - choiceboxWidget.see(n) - return - else: - # has not found it so loop from top - for n, item in enumerate(choiceboxChoices): - if item[0].lower() == key.lower(): - choiceboxWidget.selection_set(first=n) - choiceboxWidget.see(n) - return - - # nothing matched -- we'll look for the next logical choice - for n, item in enumerate(choiceboxChoices): - if item[0].lower() > key.lower(): - if n > 0: - choiceboxWidget.selection_set(first=(n - 1)) - else: - choiceboxWidget.selection_set(first=0) - choiceboxWidget.see(n) - return - - # still no match (nothing was greater than the key) - # we set the selection to the first item in the list - lastIndex = len(choiceboxChoices) - 1 - choiceboxWidget.selection_set(first=lastIndex) - choiceboxWidget.see(lastIndex) - return - - -# ------------------------------------------------------------------- -# diropenbox -# ------------------------------------------------------------------- -def diropenbox(msg=None, title=None, default=None): - """ - A dialog to get a directory name. - Note that the msg argument, if specified, is ignored. - - Returns the name of a directory, or None if user chose to cancel. - - If the "default" argument specifies a directory name, and that - directory exists, then the dialog box will start with that directory. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str default: starting directory when dialog opens - :return: Normalized path selected by user - """ - title = getFileDialogTitle(msg, title) - localRoot = Tk() - localRoot.withdraw() - if not default: - default = None - f = ut.tk_FileDialog.askdirectory( - parent=localRoot, title=title, initialdir=default, initialfile=None - ) - localRoot.destroy() - if not f: - return None - return os.path.normpath(f) - - -# ------------------------------------------------------------------- -# getFileDialogTitle -# ------------------------------------------------------------------- -def getFileDialogTitle(msg, title): - """ - Create nicely-formatted string based on arguments msg and title - :param msg: the msg to be displayed - :param title: the window title - :return: None - """ - if msg and title: - return "%s - %s" % (title, msg) - if msg and not title: - return str(msg) - if title and not msg: - return str(title) - return None # no message and no title - - -# ------------------------------------------------------------------- -# class FileTypeObject for use with fileopenbox -# ------------------------------------------------------------------- -class FileTypeObject: - - def __init__(self, filemask): - if len(filemask) == 0: - raise AssertionError('Filetype argument is empty.') - - self.masks = list() - - if isinstance(filemask, ut.basestring): # a str or unicode - self.initializeFromString(filemask) - - elif isinstance(filemask, list): - if len(filemask) < 2: - raise AssertionError('Invalid filemask.\n' - + 'List contains less than 2 members: "{}"'.format(filemask)) - else: - self.name = filemask[-1] - self.masks = list(filemask[:-1]) - else: - raise AssertionError('Invalid filemask: "{}"'.format(filemask)) - - def __eq__(self, other): - if self.name == other.name: - return True - return False - - def add(self, other): - for mask in other.masks: - if mask in self.masks: - pass - else: - self.masks.append(mask) - - def toTuple(self): - return self.name, tuple(self.masks) - - def isAll(self): - if self.name == "All files": - return True - return False - - def initializeFromString(self, filemask): - # remove everything except the extension from the filemask - self.ext = os.path.splitext(filemask)[1] - if self.ext == "": - self.ext = ".*" - if self.ext == ".": - self.ext = ".*" - self.name = self.getName() - self.masks = ["*" + self.ext] - - def getName(self): - e = self.ext - file_types = {".*": "All", ".txt": "Text", - ".py": "Python", ".pyc": "Python", ".xls": "Excel"} - if e in file_types: - return '{} files'.format(file_types[e]) - if e.startswith("."): - return '{} files'.format(e[1:].upper()) - return '{} files'.format(e.upper()) - - -# ------------------------------------------------------------------- -# fileopenbox -# ------------------------------------------------------------------- -def fileopenbox(msg=None, title=None, default='*', filetypes=None, multiple=False): - """ - A dialog to get a file name. - - **About the "default" argument** - - The "default" argument specifies a filepath that (normally) - contains one or more wildcards. - fileopenbox will display only files that match the default filepath. - If omitted, defaults to "\*" (all files in the current directory). - - WINDOWS EXAMPLE:: - - ...default="c:/myjunk/*.py" - - will open in directory c:\\myjunk\\ and show all Python files. - - WINDOWS EXAMPLE:: - - ...default="c:/myjunk/test*.py" - - will open in directory c:\\myjunk\\ and show all Python files - whose names begin with "test". - - - Note that on Windows, fileopenbox automatically changes the path - separator to the Windows path separator (backslash). - - **About the "filetypes" argument** - - If specified, it should contain a list of items, - where each item is either: - - - a string containing a filemask # e.g. "\*.txt" - - a list of strings, where all of the strings except the last one - are filemasks (each beginning with "\*.", - such as "\*.txt" for text files, "\*.py" for Python files, etc.). - and the last string contains a filetype description - - EXAMPLE:: - - filetypes = ["*.css", ["*.htm", "*.html", "HTML files"] ] - - .. note:: If the filetypes list does not contain ("All files","*"), it will be added. - - If the filetypes list does not contain a filemask that includes - the extension of the "default" argument, it will be added. - For example, if default="\*abc.py" - and no filetypes argument was specified, then - "\*.py" will automatically be added to the filetypes argument. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: filepath with wildcards - :param object filetypes: filemasks that a user can choose, e.g. "\*.txt" - :param bool multiple: If true, more than one file can be selected - :return: the name of a file, or None if user chose to cancel - """ - localRoot = Tk() - localRoot.withdraw() - - initialbase, initialfile, initialdir, filetypes = fileboxSetup( - default, filetypes) - - # ------------------------------------------------------------ - # if initialfile contains no wildcards; we don't want an - # initial file. It won't be used anyway. - # Also: if initialbase is simply "*", we don't want an - # initialfile; it is not doing any useful work. - # ------------------------------------------------------------ - if (initialfile.find("*") < 0) and (initialfile.find("?") < 0): - initialfile = None - elif initialbase == "*": - initialfile = None - - func = ut.tk_FileDialog.askopenfilenames if multiple else ut.tk_FileDialog.askopenfilename - ret_val = func(parent=localRoot, title=getFileDialogTitle(msg, title), initialdir=initialdir, initialfile=initialfile, filetypes=filetypes - ) - - if multiple: - f = [os.path.normpath(x) for x in localRoot.tk.splitlist(ret_val)] - else: - f = os.path.normpath(ret_val) - - localRoot.destroy() - - if not f: - return None - return f - - -# ------------------------------------------------------------------- -# filesavebox -# ------------------------------------------------------------------- -def filesavebox(msg=None, title=None, default="", filetypes=None): - """ - A file to get the name of a file to save. - Returns the name of a file, or None if user chose to cancel. - - The "default" argument should contain a filename (i.e. the - current name of the file to be saved). It may also be empty, - or contain a filemask that includes wildcards. - - The "filetypes" argument works like the "filetypes" argument to - fileopenbox. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: default filename to return - :param object filetypes: filemasks that a user can choose, e.g. " \*.txt" - :return: the name of a file, or None if user chose to cancel - """ - - localRoot = Tk() - localRoot.withdraw() - - initialbase, initialfile, initialdir, filetypes = fileboxSetup( - default, filetypes) - - f = ut.tk_FileDialog.asksaveasfilename(parent=localRoot, title=getFileDialogTitle(msg, title), initialfile=initialfile, initialdir=initialdir, filetypes=filetypes - ) - localRoot.destroy() - if not f: - return None - return os.path.normpath(f) - - -# ------------------------------------------------------------------- -# -# fileboxSetup -# -# ------------------------------------------------------------------- -def fileboxSetup(default, filetypes): - if not default: - default = os.path.join(".", "*") - initialdir, initialfile = os.path.split(default) - if not initialdir: - initialdir = "." - if not initialfile: - initialfile = "*" - initialbase, initialext = os.path.splitext(initialfile) - initialFileTypeObject = FileTypeObject(initialfile) - - allFileTypeObject = FileTypeObject("*") - ALL_filetypes_was_specified = False - - if not filetypes: - filetypes = list() - filetypeObjects = list() - - for filemask in filetypes: - fto = FileTypeObject(filemask) - - if fto.isAll(): - ALL_filetypes_was_specified = True # remember this - - if fto == initialFileTypeObject: - initialFileTypeObject.add(fto) # add fto to initialFileTypeObject - else: - filetypeObjects.append(fto) - - # ------------------------------------------------------------------ - # make sure that the list of filetypes includes the ALL FILES type. - # ------------------------------------------------------------------ - if ALL_filetypes_was_specified: - pass - elif allFileTypeObject == initialFileTypeObject: - pass - else: - filetypeObjects.insert(0, allFileTypeObject) - # ------------------------------------------------------------------ - # Make sure that the list includes the initialFileTypeObject - # in the position in the list that will make it the default. - # This changed between Python version 2.5 and 2.6 - # ------------------------------------------------------------------ - if len(filetypeObjects) == 0: - filetypeObjects.append(initialFileTypeObject) - - if initialFileTypeObject in (filetypeObjects[0], filetypeObjects[-1]): - pass - else: - if ut.runningPython27: - filetypeObjects.append(initialFileTypeObject) - else: - filetypeObjects.insert(0, initialFileTypeObject) - - filetypes = [fto.toTuple() for fto in filetypeObjects] - - return initialbase, initialfile, initialdir, filetypes - - -def __buttonEvent(event=None, buttons=None, virtual_event=None): - """ - Handle an event that is generated by a person interacting with a button. It may be a button press - or a key press. - """ - # TODO: Replace globals with tkinter variables - global boxRoot, __replyButtonText - - # Determine window location and save to global - m = re.match("(\d+)x(\d+)([-+]\d+)([-+]\d+)", boxRoot.geometry()) - if not m: - raise ValueError( - "failed to parse geometry string: {}".format(boxRoot.geometry())) - width, height, xoffset, yoffset = [int(s) for s in m.groups()] - st.rootWindowPosition = '{0:+g}{1:+g}'.format(xoffset, yoffset) - - # print('{0}:{1}:{2}'.format(event, buttons, virtual_event)) - if virtual_event == 'cancel': - for button_name, button in buttons.items(): - if 'cancel_choice' in button: - __replyButtonText = button['original_text'] - __replyButtonText = None - boxRoot.quit() - return - - if virtual_event == 'select': - text = event.widget.config('text')[-1] - if not isinstance(text, ut.basestring): - text = ' '.join(text) - for button_name, button in buttons.items(): - if button['clean_text'] == text: - __replyButtonText = button['original_text'] - boxRoot.quit() - return - - # Hotkeys - if buttons: - for button_name, button in buttons.items(): - hotkey_pressed = event.keysym - if event.keysym != event.char: # A special character - hotkey_pressed = '<{}>'.format(event.keysym) - if button['hotkey'] == hotkey_pressed: - __replyButtonText = button_name - boxRoot.quit() - return - - print("Event not understood") - - -def __put_buttons_in_buttonframe(choices, default_choice, cancel_choice): - """Put the buttons in the buttons frame - """ - global buttonsFrame, cancel_invoke - - # TODO: I'm using a dict to hold buttons, but this could all be cleaned up if I subclass Button to hold - # all the event bindings, etc - # TODO: Break __buttonEvent out into three: regular keyboard, default - # select, and cancel select. - unique_choices = ut.uniquify_list_of_strings(choices) - # Create buttons dictionary and Tkinter widgets - buttons = dict() - for button_text, unique_button_text in zip(choices, unique_choices): - this_button = dict() - this_button['original_text'] = button_text - this_button['clean_text'], this_button[ - 'hotkey'], hotkey_position = ut.parse_hotkey(button_text) - this_button['widget'] = Button(buttonsFrame, - takefocus=1, - text=this_button['clean_text'], - underline=hotkey_position) - this_button['widget'].pack( - expand=YES, side=LEFT, padx='1m', pady='1m', ipadx='2m', ipady='1m') - buttons[unique_button_text] = this_button - # Bind arrows, Enter, Escape - for this_button in buttons.values(): - bindArrows(this_button['widget']) - for selectionEvent in st.STANDARD_SELECTION_EVENTS: - this_button['widget'].bind("<{}>".format(selectionEvent), - lambda e: __buttonEvent( - e, buttons, virtual_event='select'), - add=True) - - # Assign default and cancel buttons - if cancel_choice in buttons: - buttons[cancel_choice]['cancel_choice'] = True - boxRoot.bind_all('', lambda e: __buttonEvent( - e, buttons, virtual_event='cancel'), add=True) - boxRoot.protocol('WM_DELETE_WINDOW', lambda: __buttonEvent( - None, buttons, virtual_event='cancel')) - if default_choice in buttons: - buttons[default_choice]['default_choice'] = True - buttons[default_choice]['widget'].focus_force() - # Bind hotkeys - for hk in [button['hotkey'] for button in buttons.values() if button['hotkey']]: - boxRoot.bind_all(hk, lambda e: __buttonEvent(e, buttons), add=True) - - return diff --git a/app_windows/lib/easygui/easygui/boxes/demo.py b/app_windows/lib/easygui/easygui/boxes/demo.py deleted file mode 100644 index 88e3cdf..0000000 --- a/app_windows/lib/easygui/easygui/boxes/demo.py +++ /dev/null @@ -1,378 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - -import os -import sys - -from . import utils as ut - -from .base_boxes import buttonbox -from .text_box import textbox -from .base_boxes import diropenbox -from .base_boxes import fileopenbox -from .base_boxes import filesavebox - -from .derived_boxes import ynbox -from .derived_boxes import ccbox -from .derived_boxes import boolbox -from .derived_boxes import indexbox -from .derived_boxes import msgbox -from .derived_boxes import integerbox -from .derived_boxes import multenterbox -from .derived_boxes import enterbox -from .derived_boxes import exceptionbox -from .derived_boxes import choicebox -from .derived_boxes import codebox -from .derived_boxes import passwordbox -from .derived_boxes import multpasswordbox -from .derived_boxes import multchoicebox - -from . import about -from .about import eg_version -from .about import abouteasygui - -# -------------------------------------------------------------- -# -# test/demo easygui -# -# ----------------------------------------------------------------------- - -package_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - - -def egdemo(): - """ - Run the EasyGui demo. - """ - # clear the console - print('\n' * 100) - - msg = list() - msg.append("Pick the kind of box that you wish to demo.") - msg.append(" * Python version {}".format(sys.version)) - msg.append(" * EasyGui version {}".format(eg_version)) - msg.append(" * Tk version {}".format(ut.TkVersion)) - intro_message = "\n".join(msg) - - while True: # do forever - choices = [ - "msgbox", - "buttonbox", - "buttonbox(image) -- a buttonbox that displays an image", - "choicebox", - "multchoicebox", - "textbox", - "ynbox", - "ccbox", - "enterbox", - "enterbox(image) -- an enterbox that displays an image", - "exceptionbox", - "codebox", - "integerbox", - "boolbox", - "indexbox", - "filesavebox", - "fileopenbox", - "passwordbox", - "multenterbox", - "multpasswordbox", - "diropenbox", - "About EasyGui", - " Help" - ] - choice = choicebox( - msg=intro_message, title="EasyGui " + eg_version, - choices=choices) - - if not choice: - return - - reply = choice.split() - - if reply[0] == "msgbox": - reply = msgbox("short msg", "This is a long title") - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "About": - reply = abouteasygui() - - elif reply[0] == "Help": - _demo_help() - - elif reply[0] == "buttonbox": - reply = buttonbox( - choices=['one', 'two', 'two', 'three'], default_choice='two') - print("Reply was: {!r}".format(reply)) - - title = "Demo of Buttonbox with many, many buttons!" - msg = ("This buttonbox shows what happens when you " - "specify too many buttons.") - reply = buttonbox( - msg=msg, title=title, choices=choices, cancel_choice='msgbox') - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "buttonbox(image)": - _demo_buttonbox_with_image() - - elif reply[0] == "boolbox": - reply = boolbox() - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "enterbox": - image = os.path.join(package_dir, "python_and_check_logo.gif") - message = ("Enter the name of your best friend." - "\n(Result will be stripped.)") - reply = enterbox(message, "Love!", " Suzy Smith ") - print("Reply was: {!r}".format(reply)) - - message = ("Enter the name of your best friend." - "\n(Result will NOT be stripped.)") - reply = enterbox( - message, "Love!", " Suzy Smith ", strip=False) - print("Reply was: {!r}".format(reply)) - - reply = enterbox("Enter the name of your worst enemy:", "Hate!") - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "enterbox(image)": - image = os.path.join(package_dir, "python_and_check_logo.gif") - message = "What kind of snake is this?" - reply = enterbox(message, "Quiz", image=image) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "exceptionbox": - try: - thisWillCauseADivideByZeroException = 1 / 0 - except: - exceptionbox() - - elif reply[0] == "integerbox": - reply = integerbox( - "Enter a number between 3 and 333", - "Demo: integerbox WITH a default value", 222, 3, 333) - print("Reply was: {!r}".format(reply)) - - reply = integerbox( - "Enter a number between 0 and 99", - "Demo: integerbox WITHOUT a default value" - ) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "diropenbox": - _demo_diropenbox() - elif reply[0] == "fileopenbox": - _demo_fileopenbox() - elif reply[0] == "filesavebox": - _demo_filesavebox() - - elif reply[0] == "indexbox": - title = reply[0] - msg = "Demo of " + reply[0] - choices = ["Choice1", "Choice2", "Choice3", "Choice4"] - reply = indexbox(msg, title, choices) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "passwordbox": - reply = passwordbox("Demo of password box WITHOUT default" - + "\n\nEnter your secret password", - "Member Logon") - print("Reply was: {!s}".format(reply)) - - reply = passwordbox("Demo of password box WITH default" - + "\n\nEnter your secret password", - "Member Logon", "alfie") - print("Reply was: {!s}".format(reply)) - - elif reply[0] == "multenterbox": - msg = "Enter your personal information" - title = "Credit Card Application" - fieldNames = ["Name", "Street Address", "City", "State", "ZipCode"] - fieldValues = list() # we start with blanks for the values - fieldValues = multenterbox(msg, title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: - break - errs = list() - for n, v in zip(fieldNames, fieldValues): - if v.strip() == "": - errs.append('"{}" is a required field.'.format(n)) - if not len(errs): - break # no problems found - fieldValues = multenterbox( - "\n".join(errs), title, fieldNames, fieldValues) - - print("Reply was: {}".format(fieldValues)) - - elif reply[0] == "multpasswordbox": - msg = "Enter logon information" - title = "Demo of multpasswordbox" - fieldNames = ["Server ID", "User ID", "Password"] - fieldValues = list() # we start with blanks for the values - fieldValues = multpasswordbox(msg, title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: - break - errs = list() - for n, v in zip(fieldNames, fieldValues): - if v.strip() == "": - errs.append('"{}" is a required field.\n\n'.format(n)) - if not len(errs): - break # no problems found - fieldValues = multpasswordbox( - "".join(errs), title, fieldNames, fieldValues) - - print("Reply was: {!s}".format(fieldValues)) - - elif reply[0] == "ynbox": - title = "Demo of ynbox" - msg = "Were you expecting the Spanish Inquisition?" - reply = ynbox(msg, title) - print("Reply was: {!r}".format(reply)) - if reply: - msgbox("NOBODY expects the Spanish Inquisition!", "Wrong!") - - elif reply[0] == "ccbox": - msg = "Insert your favorite message here" - title = "Demo of ccbox" - reply = ccbox(msg, title) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "choicebox": - title = "Demo of choicebox" - longchoice = ( - "This is an example of a very long option " - "which you may or may not wish to choose." - * 2) - listChoices = ["nnn", "ddd", "eee", "fff", "aaa", - longchoice, "aaa", "bbb", "ccc", "ggg", "hhh", - "iii", "jjj", "kkk", "LLL", "mmm", "nnn", - "ooo", "ppp", "qqq", - "rrr", "sss", "ttt", "uuu", "vvv"] - - msg = ("Pick something. " + - ("A wrapable sentence of text ?! " * 30) + - "\nA separate line of text." * 6) - reply = choicebox(msg=msg, choices=listChoices) - print("Reply was: {!r}".format(reply)) - - msg = "Pick something. " - reply = choicebox(msg=msg, title=title, choices=listChoices) - print("Reply was: {!r}".format(reply)) - - msg = "Pick something. " - reply = choicebox( - msg="The list of choices is empty!", choices=list()) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "multchoicebox": - listChoices = ["aaa", "bbb", "ccc", "ggg", "hhh", "iii", - "jjj", "kkk", "LLL", "mmm", "nnn", "ooo", - "ppp", "qqq", "rrr", "sss", "ttt", "uuu", - "vvv"] - - msg = "Pick as many choices as you wish." - reply = multchoicebox(msg, "Demo of multchoicebox", listChoices) - print("Reply was: {!r}".format(reply)) - - elif reply[0] == "textbox": - _demo_textbox(reply[0]) - elif reply[0] == "codebox": - _demo_codebox(reply[0]) - - else: - msgbox("Choice\n\n{}\n\nis not recognized".format( - choice), "Program Logic Error") - return - - -def _demo_textbox(reply): - text_snippet = (( - "It was the best of times, and it was the worst of times. The rich " - "ate cake, and the poor had cake recommended to them, but wished " - "only for enough cash to buy bread. The time was ripe for " - "revolution! " - * 5) + "\n\n") * 10 - title = "Demo of textbox" - msg = "Here is some sample text. " * 16 - reply = textbox(msg, title, text_snippet) - print("Reply was: {!s}".format(reply)) - - -def _demo_codebox(reply): - # TODO RL: Turn this sample code into the code in this module, just for fun - code_snippet = ("dafsdfa dasflkj pp[oadsij asdfp;ij asdfpjkop asdfpok asdfpok asdfpok" * 3) + "\n" + """# here is some dummy Python code -for someItem in myListOfStuff: - do something(someItem) - do something() - do something() - if somethingElse(someItem): - doSomethingEvenMoreInteresting() - -""" * 16 - msg = "Here is some sample code. " * 16 - reply = codebox(msg, "Code Sample", code_snippet) - print("Reply was: {!r}".format(reply)) - - -def _demo_buttonbox_with_image(): - msg = "Do you like this picture?\nIt is " - choices = ["Yes", "No", "No opinion"] - - for image in [ - os.path.join(package_dir, "python_and_check_logo.gif"), - os.path.join(package_dir, "python_and_check_logo.jpg"), - os.path.join(package_dir, "python_and_check_logo.png"), - os.path.join(package_dir, "zzzzz.gif")]: - reply = buttonbox(msg + image, image=image, choices=choices) - print("Reply was: {!r}".format(reply)) - - -def _demo_help(): - codebox("EasyGui Help", text=about.EASYGUI_ABOUT_INFORMATION) - - -def _demo_filesavebox(): - filename = "myNewFile.txt" - title = "File SaveAs" - msg = "Save file as:" - - f = filesavebox(msg, title, default=filename) - print("You chose to save file: {}".format(f)) - - -def _demo_diropenbox(): - title = "Demo of diropenbox" - msg = "Pick the directory that you wish to open." - d = diropenbox(msg, title) - print("You chose directory...: {}".format(d)) - - d = diropenbox(msg, title, default="./") - print("You chose directory...: {}".format(d)) - - d = diropenbox(msg, title, default="c:/") - print("You chose directory...: {}".format(d)) - - -def _demo_fileopenbox(): - msg = "Python files" - title = "Open files" - default = "*.py" - f = fileopenbox(msg, title, default=default) - print("You chose to open file: {}".format(f)) - - default = "./*.gif" - msg = "Some other file types (Multi-select)" - filetypes = ["*.jpg", ["*.zip", "*.tgs", "*.gz", - "Archive files"], ["*.htm", "*.html", "HTML files"]] - f = fileopenbox( - msg, title, default=default, filetypes=filetypes, multiple=True) - print("You chose to open file: %s" % f) diff --git a/app_windows/lib/easygui/easygui/boxes/derived_boxes.py b/app_windows/lib/easygui/easygui/boxes/derived_boxes.py deleted file mode 100644 index cdf4ae3..0000000 --- a/app_windows/lib/easygui/easygui/boxes/derived_boxes.py +++ /dev/null @@ -1,542 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -""" - -from . import base_boxes as bb -from . import text_box as tb -from . import utils as ut - -# ------------------------------------------------------------------- -# various boxes built on top of the basic buttonbox -# ----------------------------------------------------------------------- - -# ----------------------------------------------------------------------- -# ynbox -# ----------------------------------------------------------------------- - - -def ynbox(msg="Shall I continue?", title=" ", - choices=("[]Yes", "[]No"), image=None, - default_choice='[]Yes', cancel_choice='[]No'): - """ - Display a msgbox with choices of Yes and No. - - The returned value is calculated this way:: - - if the first choice ("Yes") is chosen, or if the dialog is cancelled: - return True - else: - return False - - If invoked without a msg argument, displays a generic - request for a confirmation - that the user wishes to continue. So it can be used this way:: - - if ynbox(): - pass # continue - else: - sys.exit(0) # exit the program - - :param msg: the msg to be displayed - :type msg: str - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which - button should be pressed - - :return: True if 'Yes' or dialog is cancelled, False if 'No' - """ - return boolbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - -# ----------------------------------------------------------------------- -# ccbox -# ----------------------------------------------------------------------- - - -def ccbox(msg="Shall I continue?", title=" ", - choices=("C[o]ntinue", "C[a]ncel"), image=None, - default_choice='Continue', cancel_choice='Cancel'): - """ - Display a msgbox with choices of Continue and Cancel. - - The returned value is calculated this way:: - - if the first choice ("Continue") is chosen, - or if the dialog is cancelled: - return True - else: - return False - - If invoked without a msg argument, displays a generic - request for a confirmation - that the user wishes to continue. So it can be used this way:: - - if ccbox(): - pass # continue - else: - sys.exit(0) # exit the program - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, - which button should be pressed - - :return: True if 'Continue' or dialog is cancelled, False if 'Cancel' - """ - return boolbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - -# ----------------------------------------------------------------------- -# boolbox -# ----------------------------------------------------------------------- - - -def boolbox(msg="Shall I continue?", title=" ", - choices=("[Y]es", "[N]o"), image=None, - default_choice='Yes', cancel_choice='No'): - """ - Display a boolean msgbox. - - The returned value is calculated this way:: - - if the first choice is chosen, or if the dialog is cancelled: - returns True - else: - returns False - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, which button - should be pressed - :return: True if first button pressed or dialog is cancelled, False if - second button is pressed - """ - if len(choices) != 2: - raise AssertionError( - 'boolbox takes exactly 2 choices! Consider using indexbox instead' - ) - - reply = bb.buttonbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - if reply == choices[0]: - return True - else: - return False - - -# ----------------------------------------------------------------------- -# indexbox -# ----------------------------------------------------------------------- -def indexbox(msg="Shall I continue?", title=" ", - choices=("Yes", "No"), image=None, - default_choice='Yes', cancel_choice='No'): - """ - Display a buttonbox with the specified choices. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :param str image: Filename of image to display - :param str default_choice: The choice you want highlighted - when the gui appears - :param str cancel_choice: If the user presses the 'X' close, - which button should be pressed - :return: the index of the choice selected, starting from 0 - """ - reply = bb.buttonbox(msg=msg, - title=title, - choices=choices, - image=image, - default_choice=default_choice, - cancel_choice=cancel_choice) - if reply is None: - return None - for i, choice in enumerate(choices): - if reply == choice: - return i - msg = ("There is a program logic error in the EasyGui code " - "for indexbox.\nreply={0}, choices={1}".format( - reply, choices)) - raise AssertionError(msg) - - -# ----------------------------------------------------------------------- -# msgbox -# ----------------------------------------------------------------------- -def msgbox(msg="(Your message goes here)", title=" ", - ok_button="OK", image=None, root=None): - """ - Display a message box - - :param str msg: the msg to be displayed - :param str title: the window title - :param str ok_button: text to show in the button - :param str image: Filename of image to display - :param tk_widget root: Top-level Tk widget - :return: the text of the ok_button - """ - if not isinstance(ok_button, ut.basestring): - raise AssertionError( - "The 'ok_button' argument to msgbox must be a string.") - - return bb.buttonbox(msg=msg, - title=title, - choices=[ok_button], - image=image, - root=root, - default_choice=ok_button, - cancel_choice=ok_button) - - -# ------------------------------------------------------------------- -# integerbox -# ------------------------------------------------------------------- -def integerbox(msg="", title=" ", default="", - lowerbound=0, upperbound=99, image=None, root=None): - """ - Show a box in which a user can enter an integer. - - In addition to arguments for msg and title, this function accepts - integer arguments for "default", "lowerbound", and "upperbound". - - The default argument may be None. - - When the user enters some text, the text is checked to verify that it - can be converted to an integer between the lowerbound and upperbound. - - If it can be, the integer (not the text) is returned. - - If it cannot, then an error msg is displayed, and the integerbox is - redisplayed. - - If the user cancels the operation, None is returned. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str default: The default value to return - :param int lowerbound: The lower-most value allowed - :param int upperbound: The upper-most value allowed - :param str image: Filename of image to display - :param tk_widget root: Top-level Tk widget - :return: the integer value entered by the user - - """ - - if not msg: - msg = "Enter an integer between {0} and {1}".format( - lowerbound, upperbound) - - # Validate the arguments for default, lowerbound and upperbound and - # convert to integers - exception_string = ( - 'integerbox "{0}" must be an integer. It is >{1}< of type {2}') - if default: - try: - default = int(default) - except ValueError: - raise ValueError( - exception_string.format('default', default, type(default))) - try: - lowerbound = int(lowerbound) - except ValueError: - raise ValueError( - exception_string.format('lowerbound', - lowerbound, type(lowerbound))) - try: - upperbound = int(upperbound) - except ValueError: - raise ValueError( - exception_string.format('upperbound', - upperbound, type(upperbound))) - - while True: - reply = enterbox(msg, title, str(default), image=image, root=root) - if reply is None: - return None - try: - reply = int(reply) - except: - msgbox('The value that you entered:\n\t"{}"\nis not an integer.' - .format(reply), "Error") - continue - if reply < lowerbound: - msgbox('The value that you entered is less than the lower ' - 'bound of {}.'.format(lowerbound), "Error") - continue - if reply > upperbound: - msgbox('The value that you entered is greater than the upper bound' - ' of {}.'.format( - upperbound), "Error") - continue - # reply has passed all validation checks. - # It is an integer between the specified bounds. - return reply - - -# ------------------------------------------------------------------- -# multenterbox -# ------------------------------------------------------------------- -# TODO RL: Should defaults be list constructors. -# i think after multiple calls, the value is retained. -# TODO RL: Rename/alias to multienterbox? -# default should be None and then in the logic create an empty list. -def multenterbox(msg="Fill in values for the fields.", title=" ", - fields=(), values=()): - r""" - Show screen with multiple data entry fields. - - If there are fewer values than names, the list of values is padded with - empty strings until the number of values is the same as the number - of names. - - If there are more values than names, the list of values - is truncated so that there are as many values as names. - - Returns a list of the values of the fields, - or None if the user cancels the operation. - - Here is some example code, that shows how values returned from - multenterbox can be checked for validity before they are accepted:: - - msg = "Enter your personal information" - title = "Credit Card Application" - fieldNames = ["Name","Street Address","City","State","ZipCode"] - fieldValues = [] # we start with blanks for the values - fieldValues = multenterbox(msg,title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: break - errmsg = "" - for i in range(len(fieldNames)): - if fieldValues[i].strip() == "": - errmsg += ('"%s" is a required field.\n\n' % fieldNames[i]) - if errmsg == "": - break # no problems found - fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues) - - print("Reply was: %s" % str(fieldValues)) - - :param str msg: the msg to be displayed. - :param str title: the window title - :param list fields: a list of fieldnames. - :param list values: a list of field values - :return: String - """ - return bb.__multfillablebox(msg, title, fields, values, None) - - -# ----------------------------------------------------------------------- -# multpasswordbox -# ----------------------------------------------------------------------- -def multpasswordbox(msg="Fill in values for the fields.", - title=" ", fields=tuple(), values=tuple()): - r""" - Same interface as multenterbox. But in multpassword box, - the last of the fields is assumed to be a password, and - is masked with asterisks. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param list fields: a list of fieldnames. - :param list values: a list of field values - :return: String - - **Example** - - Here is some example code, that shows how values returned from - multpasswordbox can be checked for validity before they are accepted:: - - msg = "Enter logon information" - title = "Demo of multpasswordbox" - fieldNames = ["Server ID", "User ID", "Password"] - fieldValues = [] # we start with blanks for the values - fieldValues = multpasswordbox(msg,title, fieldNames) - - # make sure that none of the fields was left blank - while 1: - if fieldValues is None: break - errmsg = "" - for i in range(len(fieldNames)): - if fieldValues[i].strip() == "": - errmsg = errmsg + ('"%s" is a required field.\n\n' % - fieldNames[i]) - if errmsg == "": break # no problems found - fieldValues = multpasswordbox(errmsg, title, - fieldNames, fieldValues) - - print("Reply was: %s" % str(fieldValues)) - - """ - return bb.__multfillablebox(msg, title, fields, values, "*") - - -# ------------------------------------------------------------------- -# enterbox -# ------------------------------------------------------------------- -def enterbox(msg="Enter something.", title=" ", default="", - strip=True, image=None, root=None): - """ - Show a box in which a user can enter some text. - - You may optionally specify some default text, which will appear in the - enterbox when it is displayed. - - Example:: - - reply = enterbox(....) - if reply: - ... - else: - ... - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: value returned if user does not change it - :param bool strip: If True, the return value will have - its whitespace stripped before being returned - :return: the text that the user entered, or None if he cancels - the operation. - """ - result = bb.__fillablebox( - msg, title, default=default, mask=None, image=image, root=root) - if result and strip: - result = result.strip() - return result - - -def passwordbox(msg="Enter your password.", title=" ", default="", - image=None, root=None): - """ - Show a box in which a user can enter a password. - The text is masked with asterisks, so the password is not displayed. - - :param str msg: the msg to be displayed. - :param str title: the window title - :param str default: value returned if user does not change it - :return: the text that the user entered, or None if he cancels - the operation. - """ - return bb.__fillablebox(msg, title, default, mask="*", - image=image, root=root) - - -# ------------------------------------------------------------------- -# multchoicebox -# ------------------------------------------------------------------- -def multchoicebox(msg="Pick as many items as you like.", title=" ", - choices=(), **kwargs): - """ - Present the user with a list of choices. - allow him to select multiple items and return them in a list. - if the user doesn't choose anything from the list, return the empty list. - return None if he cancelled selection. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :return: List containing choice selected or None if cancelled - - """ - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - - global __choiceboxMultipleSelect - __choiceboxMultipleSelect = 1 - return bb.__choicebox(msg, title, choices) - - -# ----------------------------------------------------------------------- -# choicebox -# ----------------------------------------------------------------------- -def choicebox(msg="Pick something.", title=" ", choices=()): - """ - Present the user with a list of choices. - return the choice that he selects. - - :param str msg: the msg to be displayed - :param str title: the window title - :param list choices: a list or tuple of the choices to be displayed - :return: List containing choice selected or None if cancelled - """ - if len(choices) == 0: - choices = ["Program logic error - no choices were specified."] - - global __choiceboxMultipleSelect - __choiceboxMultipleSelect = 0 - return bb.__choicebox(msg, title, choices) - - -# ----------------------------------------------------------------------- -# exceptionbox -# ----------------------------------------------------------------------- -def exceptionbox(msg=None, title=None): - """ - Display a box that gives information about - an exception that has just been raised. - - The caller may optionally pass in a title for the window, or a - msg to accompany the error information. - - Note that you do not need to (and cannot) pass an exception object - as an argument. The latest exception will automatically be used. - - :param str msg: the msg to be displayed - :param str title: the window title - :return: None - - """ - if title is None: - title = "Error Report" - if msg is None: - msg = "An error (exception) has occurred in the program." - - codebox(msg, title, ut.exception_format()) - - -# ------------------------------------------------------------------- -# codebox -# ------------------------------------------------------------------- - -def codebox(msg="", title=" ", text=""): - """ - Display some text in a monospaced font, with no line wrapping. - This function is suitable for displaying code and text that is - formatted using spaces. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - """ - return tb.textbox(msg, title, text, codebox=1) diff --git a/app_windows/lib/easygui/easygui/boxes/egstore.py b/app_windows/lib/easygui/easygui/boxes/egstore.py deleted file mode 100644 index 3a382b1..0000000 --- a/app_windows/lib/easygui/easygui/boxes/egstore.py +++ /dev/null @@ -1,158 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - - -import os -import pickle - - -# ----------------------------------------------------------------------- -# -# class EgStore -# -# ----------------------------------------------------------------------- -class EgStore: - - r""" -A class to support persistent storage. - -You can use EgStore to support the storage and retrieval -of user settings for an EasyGui application. - -**Example A: define a class named Settings as a subclass of EgStore** -:: - - class Settings(EgStore): - def __init__(self, filename): # filename is required - #------------------------------------------------- - # Specify default/initial values for variables that - # this particular application wants to remember. - #------------------------------------------------- - self.userId = "" - self.targetServer = "" - - #------------------------------------------------- - # For subclasses of EgStore, these must be - # the last two statements in __init__ - #------------------------------------------------- - self.filename = filename # this is required - self.restore() # restore values from the storage file if possible - -**Example B: create settings, a persistent Settings object** -:: - - settingsFile = "myApp_settings.txt" - settings = Settings(settingsFile) - - user = "obama_barak" - server = "whitehouse1" - settings.userId = user - settings.targetServer = server - settings.store() # persist the settings - - # run code that gets a new value for userId, and persist the settings - user = "biden_joe" - settings.userId = user - settings.store() - -**Example C: recover the Settings instance, change an attribute, and store it again.** -:: - - settings = Settings(settingsFile) - settings.userId = "vanrossum_g" - settings.store() - -""" - - def __init__(self, filename): # obtaining filename is required - self.filename = None - raise NotImplementedError() - - def restore(self): - """ - Set the values of whatever attributes are recoverable - from the pickle file. - - Populate the attributes (the __dict__) of the EgStore object - from the attributes (the __dict__) of the pickled object. - - If the pickled object has attributes that have been initialized - in the EgStore object, then those attributes of the EgStore object - will be replaced by the values of the corresponding attributes - in the pickled object. - - If the pickled object is missing some attributes that have - been initialized in the EgStore object, then those attributes - of the EgStore object will retain the values that they were - initialized with. - - If the pickled object has some attributes that were not - initialized in the EgStore object, then those attributes - will be ignored. - - IN SUMMARY: - - After the recover() operation, the EgStore object will have all, - and only, the attributes that it had when it was initialized. - - Where possible, those attributes will have values recovered - from the pickled object. - """ - if not os.path.exists(self.filename): - return self - if not os.path.isfile(self.filename): - return self - - try: - with open(self.filename, "rb") as f: - unpickledObject = pickle.load(f) - - for key in list(self.__dict__.keys()): - default = self.__dict__[key] - self.__dict__[key] = unpickledObject.__dict__.get(key, default) - except: - pass - - return self - - def store(self): - """ - Save the attributes of the EgStore object to a pickle file. - Note that if the directory for the pickle file does not already exist, - the store operation will fail. - """ - with open(self.filename, "wb") as f: - pickle.dump(self, f) - - def kill(self): - """ - Delete my persistent file (i.e. pickle file), if it exists. - """ - if os.path.isfile(self.filename): - os.remove(self.filename) - return - - def __str__(self): - """ - return my contents as a string in an easy-to-read format. - """ - # find the length of the longest attribute name - longest_key_length = 0 - keys = list() - for key in self.__dict__.keys(): - keys.append(key) - longest_key_length = max(longest_key_length, len(key)) - - keys.sort() # sort the attribute names - lines = list() - for key in keys: - value = self.__dict__[key] - key = key.ljust(longest_key_length) - lines.append("%s : %s\n" % (key, repr(value))) - return "".join(lines) # return a string showing the attributes diff --git a/app_windows/lib/easygui/easygui/boxes/state.py b/app_windows/lib/easygui/easygui/boxes/state.py deleted file mode 100644 index eabd32a..0000000 --- a/app_windows/lib/easygui/easygui/boxes/state.py +++ /dev/null @@ -1,23 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -# Starting and global variables - -rootWindowPosition = "+300+200" - -PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif") -MONOSPACE_FONT_FAMILY = "Courier" - -PROPORTIONAL_FONT_SIZE = 10 -# a little smaller, because it is more legible at a smaller size -MONOSPACE_FONT_SIZE = 9 -TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see - - -STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"] diff --git a/app_windows/lib/easygui/easygui/boxes/text_box.py b/app_windows/lib/easygui/easygui/boxes/text_box.py deleted file mode 100644 index 4e6d6c2..0000000 --- a/app_windows/lib/easygui/easygui/boxes/text_box.py +++ /dev/null @@ -1,199 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -import sys - -from . import utils as ut -from .utils import * -from . import state as st - - -def textbox(msg="", title=" ", text="", codebox=0): - """ - Display some text in a proportional font with line wrapping at word breaks. - This function is suitable for displaying general written text. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - :param str codebox: if 1, act as a codebox - """ - - if msg is None: - msg = "" - if title is None: - title = "" - - boxRoot = tk.Tk() - - def __textboxOK(event): - boxRoot.quit() - - # Quit when x button pressed - boxRoot.protocol('WM_DELETE_WINDOW', boxRoot.quit) - - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - st.rootWindowPosition = "+0+0" - boxRoot.geometry(st.rootWindowPosition) - boxRoot.expand = tk.NO - boxRoot.minsize(root_width, root_height) - st.rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(st.rootWindowPosition) - - mainframe = tk.Frame(master=boxRoot) - mainframe.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) - - # ---- put frames in the window ----------------------------------- - # we pack the textboxFrame first, so it will expand first - textboxFrame = tk.Frame(mainframe, borderwidth=3) - textboxFrame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=tk.YES) - - message_and_buttonsFrame = tk.Frame(mainframe) - message_and_buttonsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) - - messageFrame = tk.Frame(message_and_buttonsFrame) - messageFrame.pack(side=tk.LEFT, fill=tk.X, expand=tk.YES) - - buttonsFrame = tk.Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=tk.RIGHT, expand=tk.NO) - - # -------------------- put widgets in the frames -------------------- - - # put a textArea in the top frame - if codebox: - character_width = int((root_width * 0.6) / st.MONOSPACE_FONT_SIZE) - textArea = tk.Text( - textboxFrame, height=25, width=character_width, padx="2m", - pady="1m") - textArea.configure(wrap=tk.NONE) - textArea.configure(font=(st.MONOSPACE_FONT_FAMILY, - st.MONOSPACE_FONT_SIZE)) - - else: - character_width = int((root_width * 0.6) / st.MONOSPACE_FONT_SIZE) - textArea = tk.Text( - textboxFrame, height=25, width=character_width, padx="2m", - pady="1m" - ) - textArea.configure(wrap=tk.WORD) - textArea.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - - # some simple keybindings for scrolling - mainframe.bind("", textArea.yview_scroll(1, tk.PAGES)) - mainframe.bind("", textArea.yview_scroll(-1, tk.PAGES)) - - mainframe.bind("", textArea.xview_scroll(1, tk.PAGES)) - mainframe.bind("", textArea.xview_scroll(-1, tk.PAGES)) - - mainframe.bind("", textArea.yview_scroll(1, tk.UNITS)) - mainframe.bind("", textArea.yview_scroll(-1, tk.UNITS)) - - # add a vertical scrollbar to the frame - rightScrollbar = tk.Scrollbar( - textboxFrame, orient=tk.VERTICAL, command=textArea.yview) - textArea.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = tk.Scrollbar( - textboxFrame, orient=tk.HORIZONTAL, command=textArea.xview) - textArea.configure(xscrollcommand=bottomScrollbar.set) - - # pack the textArea and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, - # so that the bottomScrollbar will be located properly. - - # Note that we need a bottom scrollbar only for code. - # Text will be displayed with wordwrap, so we don't need to have - # a horizontal scroll for it. - if codebox: - bottomScrollbar.pack(side=tk.BOTTOM, fill=tk.X) - rightScrollbar.pack(side=tk.RIGHT, fill=tk.Y) - - textArea.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES) - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = tk.Message( - messageFrame, anchor=tk.NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(st.PROPORTIONAL_FONT_FAMILY, st.PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH, - padx='1m', pady='1m') - - # put the buttons in the buttonsFrame - okButton = tk.Button( - buttonsFrame, takefocus=tk.YES, text="OK", height=1, width=6) - okButton.pack( - expand=tk.NO, side=tk.TOP, padx='2m', pady='1m', ipady="1m", - ipadx="2m") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __textboxOK - for selectionEvent in ["Return", "Button-1", "Escape"]: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ----------------- the action begins ------------------------------------ - text = to_string(text) - try: - textArea.insert('end', text, "normal") - except: - msgbox("Exception when trying to load the textArea.") - sys.exit(16) - - try: - okButton.focus_force() - except: - msgbox("Exception when trying to put focus on okButton.") - sys.exit(16) - - boxRoot.mainloop() - - # this line MUST go before the line that destroys boxRoot - areaText = textArea.get(0.0, 'end-1c') - boxRoot.destroy() - return areaText # return __replyButtonText - - -def to_string(something): - if isinstance(something, ut.basestring): - return something - try: - text = "".join(something) # convert a list or a tuple to a string - except: - msgbox( - "Exception when trying to convert {} to text in textArea" - .format(type(something))) - sys.exit(16) - return text - - -def demo_textbox(): - text_snippet = (( - "It was the best of times, and it was the worst of times. The rich " - "ate cake, and the poor had cake recommended to them, but wished " - "only for enough cash to buy bread. The time was ripe for " - "revolution! " - * 5) + "\n\n") * 10 - title = "Demo of textbox" - msg = "Here is some sample text. " * 16 - reply = textbox(msg, title, text_snippet) - print("Reply was: {!s}".format(reply)) diff --git a/app_windows/lib/easygui/easygui/boxes/updatable_text_box.py b/app_windows/lib/easygui/easygui/boxes/updatable_text_box.py deleted file mode 100644 index 638ade8..0000000 --- a/app_windows/lib/easygui/easygui/boxes/updatable_text_box.py +++ /dev/null @@ -1,270 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| -""" - -import sys - -if sys.hexversion >= 0x020600F0: - runningPython26 = True -else: - runningPython26 = False - -if sys.hexversion >= 0x030000F0: - runningPython3 = True -else: - runningPython3 = False - -# Try to import the Python Image Library. If it doesn't exist, only .gif -# images are supported. -try: - from PIL import Image as PILImage - from PIL import ImageTk as PILImageTk -except: - pass - -if runningPython3: - from tkinter import * - import tkinter.filedialog as tk_FileDialog - from io import StringIO -else: - from Tkinter import * - import tkFileDialog as tk_FileDialog - from StringIO import StringIO - -# Set up basestring appropriately -if runningPython3: - basestring = str - - -if TkVersion < 8.0: - stars = "*" * 75 - print("""\n\n\n""" + stars + """ -You are running Tk version: """ + str(TkVersion) + """ -You must be using Tk version 8.0 or greater to use EasyGui. -Terminating. -""" + stars + """\n\n\n""") - sys.exit(0) - -rootWindowPosition = "+300+200" - -PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif") -MONOSPACE_FONT_FAMILY = ("Courier") - -PROPORTIONAL_FONT_SIZE = 10 -# a little smaller, because it it more legible at a smaller size -MONOSPACE_FONT_SIZE = 9 -TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see - - -STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"] - -# Initialize some global variables that will be reset later -__choiceboxMultipleSelect = None -__replyButtonText = None -__choiceboxResults = None -__firstWidget = None -__enterboxText = None -__enterboxDefaultText = "" -__multenterboxText = "" -choiceboxChoices = None -choiceboxWidget = None -entryWidget = None -boxRoot = None - - -#------------------------------------------------------------------- -# textbox -#------------------------------------------------------------------- -def textbox(msg="", title=" ", text="", codebox=0, get_updated_text=None): - """ - Display some text in a proportional font with line wrapping at word breaks. - This function is suitable for displaying general written text. - - The text parameter should be a string, or a list or tuple of lines to be - displayed in the textbox. - - :param str msg: the msg to be displayed - :param str title: the window title - :param str text: what to display in the textbox - :param str codebox: if 1, act as a codebox - """ - - if msg is None: - msg = "" - if title is None: - title = "" - - global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame - global rootWindowPosition - choices = ["OK"] - __replyButtonText = choices[0] - - boxRoot = Tk() - - # Quit when x button pressed - boxRoot.protocol('WM_DELETE_WINDOW', boxRoot.quit) - - screen_width = boxRoot.winfo_screenwidth() - screen_height = boxRoot.winfo_screenheight() - root_width = int((screen_width * 0.8)) - root_height = int((screen_height * 0.5)) - root_xpos = int((screen_width * 0.1)) - root_ypos = int((screen_height * 0.05)) - - boxRoot.title(title) - boxRoot.iconname('Dialog') - rootWindowPosition = "+0+0" - boxRoot.geometry(rootWindowPosition) - boxRoot.expand = NO - boxRoot.minsize(root_width, root_height) - rootWindowPosition = '+{0}+{1}'.format(root_xpos, root_ypos) - boxRoot.geometry(rootWindowPosition) - - mainframe = Frame(master=boxRoot) - mainframe.pack(side=TOP, fill=BOTH, expand=YES) - - # ---- put frames in the window ----------------------------------- - # we pack the textboxFrame first, so it will expand first - textboxFrame = Frame(mainframe, borderwidth=3) - textboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES) - - message_and_buttonsFrame = Frame(mainframe) - message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO) - - messageFrame = Frame(message_and_buttonsFrame) - messageFrame.pack(side=LEFT, fill=X, expand=YES) - - buttonsFrame = Frame(message_and_buttonsFrame) - buttonsFrame.pack(side=RIGHT, expand=NO) - - # -------------------- put widgets in the frames -------------------- - - # put a textArea in the top frame - if codebox: - character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE) - textArea = Text( - textboxFrame, height=25, width=character_width, padx="2m", pady="1m") - textArea.configure(wrap=NONE) - textArea.configure(font=(MONOSPACE_FONT_FAMILY, MONOSPACE_FONT_SIZE)) - - else: - character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE) - textArea = Text( - textboxFrame, height=25, width=character_width, padx="2m", pady="1m" - ) - textArea.configure(wrap=WORD) - textArea.configure( - font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) - - # some simple keybindings for scrolling - mainframe.bind("", textArea.yview_scroll(1, PAGES)) - mainframe.bind("", textArea.yview_scroll(-1, PAGES)) - - mainframe.bind("", textArea.xview_scroll(1, PAGES)) - mainframe.bind("", textArea.xview_scroll(-1, PAGES)) - - mainframe.bind("", textArea.yview_scroll(1, UNITS)) - mainframe.bind("", textArea.yview_scroll(-1, UNITS)) - - # add a vertical scrollbar to the frame - rightScrollbar = Scrollbar( - textboxFrame, orient=VERTICAL, command=textArea.yview) - textArea.configure(yscrollcommand=rightScrollbar.set) - - # add a horizontal scrollbar to the frame - bottomScrollbar = Scrollbar( - textboxFrame, orient=HORIZONTAL, command=textArea.xview) - textArea.configure(xscrollcommand=bottomScrollbar.set) - - # pack the textArea and the scrollbars. Note that although we must define - # the textArea first, we must pack it last, so that the bottomScrollbar will - # be located properly. - - # Note that we need a bottom scrollbar only for code. - # Text will be displayed with wordwrap, so we don't need to have a horizontal - # scroll for it. - if codebox: - bottomScrollbar.pack(side=BOTTOM, fill=X) - rightScrollbar.pack(side=RIGHT, fill=Y) - - textArea.pack(side=LEFT, fill=BOTH, expand=YES) - - # ---------- put a msg widget in the msg frame------------------- - messageWidget = Message( - messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9)) - messageWidget.configure( - font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) - messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m') - - # put the buttons in the buttonsFrame - okButton = Button( - buttonsFrame, takefocus=YES, text="Update", height=1, width=6) - okButton.pack( - expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m") - - def __update_myself(event): - new_text = get_updated_text() - textArea.delete(1.0, END) - textArea.insert('end', new_text, "normal") - - # for the commandButton, bind activation events to the activation event - # handler - commandButton = okButton - handler = __textboxOK - handler = __update_myself - for selectionEvent in ["Return", "Button-1", "Escape"]: - commandButton.bind("<%s>" % selectionEvent, handler) - - # ----------------- the action begins ------------------------------------ - try: - # load the text into the textArea - if isinstance(text, basestring): - pass - else: - try: - text = "".join(text) # convert a list or a tuple to a string - except: - msgbox( - "Exception when trying to convert {} to text in textArea".format(type(text))) - sys.exit(16) - textArea.insert('end', text, "normal") - - except: - msgbox("Exception when trying to load the textArea.") - sys.exit(16) - - try: - okButton.focus_force() - except: - msgbox("Exception when trying to put focus on okButton.") - sys.exit(16) - - boxRoot.mainloop() - - # this line MUST go before the line that destroys boxRoot - areaText = textArea.get(0.0, 'end-1c') - boxRoot.destroy() - return areaText # return __replyButtonText - - -def __textboxOK(event): - global boxRoot - boxRoot.quit() - - -def update(reply=None): - return "To close, use the x button" - - -def _demo_textbox(): - title = "Demo of updatable textbox" - msg = "Push update button to update. " * 16 - text_snippet = (( - "Update button!!!. " * 5) + "\n\n") * 10 - reply = textbox(msg, title, text_snippet, get_updated_text=update) - print("Reply was: {!s}".format(reply)) \ No newline at end of file diff --git a/app_windows/lib/easygui/easygui/boxes/utils.py b/app_windows/lib/easygui/easygui/boxes/utils.py deleted file mode 100644 index f527144..0000000 --- a/app_windows/lib/easygui/easygui/boxes/utils.py +++ /dev/null @@ -1,180 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| - -""" - -import os -import sys -import traceback - -# A set of variables and functions to centralize differences between python 2 and 3 -runningPython27 = False -runningPython34 = False -if 0x020700F0 <= sys.hexversion <= 0x030000F0: - runningPython27 = True -if 0x030400F0 <= sys.hexversion <= 0x040000F0: - runningPython34 = True -if not runningPython27 and not runningPython34: - raise Exception("You must run on Python 2.7+ or Python 3.4+") - -# Import Tkinter, the tk filedialog, and put everything in tkinter into the current namespace -try: - import tkinter as tk # python3 - from tkinter import * - import tkinter.filedialog as tk_FileDialog -except ImportError: - try: - import Tkinter as tk # python2 - from Tkinter import * - import tkFileDialog as tk_FileDialog - except ImportError: - raise ImportError("Unable to find tkinter package.") - -if tk.TkVersion < 8.0: - raise ImportError("You must use python-tk (tkinter) version 8.0 or higher") - -# Try to import the Python Image Library. If it doesn't exist, only .gif -# images are supported. -try: - from PIL import Image as PILImage - from PIL import ImageTk as PILImageTk -except: - pass - -# Code should use 'basestring' anywhere you might think to use the system 'str'. This is all to support -# Python 2. If 2 ever goes away, this logic can go away and uses of utils.basestring should be changed to just str -if runningPython27: - basestring = basestring -if runningPython34: - basestring = str - -def lower_case_sort(things): - if runningPython34: - things.sort(key=str.lower) - else: - # case-insensitive sort - things.sort(lambda x, y: cmp(x.lower(), y.lower())) - return things # RL: Not sure of this exactly - - -# ----------------------------------------------------------------------- -# exception_format -# ----------------------------------------------------------------------- -def exception_format(): - """ - Convert exception info into a string suitable for display. - """ - return "".join(traceback.format_exception( - sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2] - )) - - -# ------------------------------------------------------------------- -# utility routines -# ------------------------------------------------------------------- -# These routines are used by several other functions in the EasyGui module. - -def uniquify_list_of_strings(input_list): - """ - Ensure that every string within input_list is unique. - :param list input_list: List of strings - :return: New list with unique names as needed. - """ - output_list = list() - for i, item in enumerate(input_list): - tempList = input_list[:i] + input_list[i + 1:] - if item not in tempList: - output_list.append(item) - else: - output_list.append('{0}_{1}'.format(item, i)) - return output_list - -import re - - -def parse_hotkey(text): - """ - Extract a desired hotkey from the text. The format to enclose - the hotkey in square braces - as in Button_[1] which would assign the keyboard key 1 to that button. - The one will be included in the - button text. To hide they key, use double square braces as in: Ex[[qq]] - it , which would assign - the q key to the Exit button. Special keys such as may also be - used: Move [] for a full - list of special keys, see this reference: http://infohost.nmt.edu/tcc/help/ - pubs/tkinter/web/key-names.html - :param text: - :return: list containing cleaned text, hotkey, and hotkey position within - cleaned text. - """ - - ret_val = [text, None, None] # Default return values - if text is None: - return ret_val - - # Single character, remain visible - res = re.search('(?<=\[).(?=\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 1] + text[start:end] + text[end + 1:] - ret_val = [caption, text[start:end], start - 1] - - # Single character, hide it - res = re.search('(?<=\[\[).(?=\]\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 2] + text[end + 2:] - ret_val = [caption, text[start:end], None] - - # a Keysym. Always hide it - res = re.search('(?<=\[\<).+(?=\>\])', text) - if res: - start = res.start(0) - end = res.end(0) - caption = text[:start - 2] + text[end + 2:] - ret_val = [caption, '<{}>'.format(text[start:end]), None] - - return ret_val - -def load_tk_image(filename): - """ - Load in an image file and return as a tk Image. - - :param filename: image filename to load - :return: tk Image object - """ - - if filename is None: - return None - - if not os.path.isfile(filename): - raise ValueError('Image file {} does not exist.'.format(filename)) - - tk_image = None - - filename = os.path.normpath(filename) - _, ext = os.path.splitext(filename) - - try: - pil_image = PILImage.open(filename) - tk_image = PILImageTk.PhotoImage(pil_image) - except: - try: - # Fallback if PIL isn't available - tk_image = tk.PhotoImage(file=filename) - except: - msg = "Cannot load {}. Check to make sure it is an image file.".format(filename) - try: - _ = PILImage - except: - msg += "\nPIL library isn't installed. If it isn't installed, only .gif files can be used." - raise ValueError(msg) - return tk_image diff --git a/app_windows/lib/easygui/easygui/easygui.py b/app_windows/lib/easygui/easygui/easygui.py deleted file mode 100644 index 910a77c..0000000 --- a/app_windows/lib/easygui/easygui/easygui.py +++ /dev/null @@ -1,79 +0,0 @@ -""" - -.. moduleauthor:: Stephen Raymond Ferg and Robert Lugg (active) -.. default-domain:: py -.. highlight:: python - -Version |release| - -ABOUT EASYGUI -============= - -EasyGui provides an easy-to-use interface for simple GUI interaction -with a user. It does not require the programmer to know anything about -tkinter, frames, widgets, callbacks or lambda. All GUI interactions are -invoked by simple function calls that return results. - -.. warning:: Using EasyGui with IDLE - - You may encounter problems using IDLE to run programs that use EasyGui. Try it - and find out. EasyGui is a collection of Tkinter routines that run their own - event loops. IDLE is also a Tkinter application, with its own event loop. The - two may conflict, with unpredictable results. If you find that you have - problems, try running your EasyGui program outside of IDLE. - -.. note:: EasyGui requires Tk release 8.0 or greater. - -LICENSE INFORMATION -=================== -EasyGui version |version| - -Copyright (c) 2014, Stephen Raymond Ferg - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -ABOUT THE EASYGUI LICENSE -------------------------- -| This license is what is generally known as the "modified BSD license", -| aka "revised BSD", "new BSD", "3-clause BSD". -| See http://www.opensource.org/licenses/bsd-license.php -| -| This license is GPL-compatible. -| See ``_ -| See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses -| -| The BSD License is less restrictive than GPL. -| It allows software released under the license to be incorporated into proprietary products. -| Works based on the software may be released under a proprietary license or as closed source software. -| ``_ - -API -=== -""" - diff --git a/app_windows/lib/easygui/easygui/python_and_check_logo.gif b/app_windows/lib/easygui/easygui/python_and_check_logo.gif deleted file mode 100644 index 5eb75a4fb80cf4c94986293180b74d216140bccf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25112 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 M3jcpYpV#I81DhA-cmMzZ diff --git a/app_windows/lib/easygui/easygui/python_and_check_logo.png b/app_windows/lib/easygui/easygui/python_and_check_logo.png deleted file mode 100644 index fac900bc413327515e28b2c7a79189d647cd0ebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3585 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 NU>DntRc5h2=6?rf{-OW? diff --git a/app_windows/lib/easygui/easygui/zzzzz.gif b/app_windows/lib/easygui/easygui/zzzzz.gif deleted file mode 100644 index 6c04ef2dd09b8c5e72f1111e68cf0162dcb25d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1703 zcmXYwdr(l<5ysbv4~j9RspBKTOw|lgu1In5LC}sG>$9LyuhK*S`5Q7bCws#v_B5j9SzDM-gud6@yX*S6=MGw1Bg*>8W}ccx66 zJSJ>WEF?i2{BI!u0Wg37C|Cd%f<<64SOS)U4PYbK1U7>$U@JHP4uV7AFgOB^f&nlH zhQKfw0i)moxCkzR%is#Q>b(t$pajaG0_q(A0TBp+5yY#Z1!y5!gchSEXeru&Hlj^v zGunc-q66q4I)o0RBj_j^K!a!q4Wkh>iY}mw=n}e&uAr-^fQqPu%BX_s>F~xz0wQ1n z@nn$&WFc8Z7Lz4pDcL|al1*eY*+RCG1LPn%L=KZ9+gJg&dlMymXE|81l61hyS zkgKFXilju!q(bT;@Q5P=F))L8MA!nhkS$`1*%G#tZD1SOCbpSvVO!Y&c90!nhuIN! zlnt;!HpGV62peS=*hO}UU1nFC3^wF>0+3r8BIJa{5kU1v0viR_o%wNY|-Z$;U z=U21FtZuBUJdt<(;P}nH1E!bc-^iJ|J22*Q$&u>3Svk}9Pd{ngg83&B?wXPJLszu) z`(rn&^$)kU#9j~l-Hebsq06g_vsd+O%P3h^-rBJFQQ)zXsHD8x7YZ_uFF3pA@x!~} zUnG^D`Ad)B$flZ*CCgHV{&ho!@9T@t9xsgBF|x4khf_{W+?DPH&C9Ouj5^gP{K|?-mU1Q+_}8jX}+WKkC{#rT&A}1CH$4xhif>#Lm&z4*Px*5y^hL zXHWcn-;o1Oo_H_4drJRWYhj-^KmRc9)#L#7P3!;KcK?*>tiW-vEXi51#y9z`BD^*4m}+C?JvU9(zaH;eg0XVU*6>BnSS{P z0?MzgTp3qdADx}HK5lt_iME-9q8guqqdpBUEe`xLq3fcJ(SsW1jhZ)nOjPuR#p{O^ z`47)pKKW5|?fg$`wp@IeUlwzES?NvRoBK}Qja-rwpBgl$YV5JOc{77<&oxKJKU;Y! z@pNa|>6za&7C%ay(B61BsjOqw()f*?Etg+e*!=FcVH28iM@0PXT1fb;^FQyITUh>m z*vmz+m9zhJaMIJgJ!*r#?`-K;d5POIbI$R$UYDQbclcfjI5TXPjQ@Mn2pJLn(~8qW zW=@LSxHdZ>H!WySZ1L)QVVTLxYbVsyR-51M|2A~xo|o2Cr*hw8U;OLhKVlB2Mg#;U zmWP$j-@WO^o#6{_A5A@arSsgLtE+x0j5rnlS=a~deqV12>s}xG>Ws`@wfjd+o>y^w zSJ2wRmlN7ED=&RrygnwQwf45Y&2 zWDPsLF8_X0jdgRETJ2S^mu1$ V-MYt}ZQpGTe%@Yxu(uzC{|6-}T8#hz diff --git a/app_windows/lib/easygui/setup.cfg b/app_windows/lib/easygui/setup.cfg deleted file mode 100644 index 6f08d0e..0000000 --- a/app_windows/lib/easygui/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[bdist_wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - diff --git a/app_windows/lib/easygui/setup.py b/app_windows/lib/easygui/setup.py deleted file mode 100644 index c94ade0..0000000 --- a/app_windows/lib/easygui/setup.py +++ /dev/null @@ -1,115 +0,0 @@ -import distutils.core -## WARNING: Although the following import appears to do nothing, it is required for bdist_wheel to be recognized -from setuptools import setup, find_packages - -version = "0.97.4" -release = "0.97.4" - -desc = list() -desc.append('EasyGUI is a module for very simple, very easy GUI programming in Python. ') -desc.append('EasyGUI is different from other GUI generators in that EasyGUI is NOT event-driven. ') -desc.append('Instead, all GUI interactions are invoked by simple function calls.') - -long_description = """ -ABOUT EASYGUI -============= - -EasyGui provides an easy-to-use interface for simple GUI interaction -with a user. It does not require the programmer to know anything about -tkinter, frames, widgets, callbacks or lambda. All GUI interactions are -invoked by simple function calls that return results. - -Example Usage -------------- - - >>> import easygui - >>> easygui.ynbox('Shall I continue?', 'Title', ('Yes', 'No')) - 1 - >>> easygui.msgbox('This is a basic message box.', 'Title Goes Here') - 'OK' - >>> easygui.buttonbox('Click on your favorite flavor.', 'Favorite Flavor', ('Chocolate', 'Vanilla', 'Strawberry')) - 'Chocolate' - - -A full tutorial is available at -. - -LICENSE INFORMATION -=================== -EasyGui version |version| - -Copyright (c) 2015, Stephen Raymond Ferg - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -ABOUT THE EASYGUI LICENSE -------------------------- -| This license is what is generally known as the "modified BSD license", -| aka "revised BSD", "new BSD", "3-clause BSD". -| See http://www.opensource.org/licenses/bsd-license.php -| -| This license is GPL-compatible. -| See ``_ -| See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses -| -| The BSD License is less restrictive than GPL. -| It allows software released under the license to be incorporated into proprietary products. -| Works based on the software may be released under a proprietary license or as closed source software. -| ``_ -""" - -distutils.core.setup( - name='easygui', - version=version, - url='https://github.com/robertlugg/easygui/', - description=''.join(desc), - long_description=long_description, - author='Stephen Ferg and Robert Lugg (active)', - author_email='robert.lugg@gmail.com', - license='BSD', - keywords='gui linux windows graphical user interface', - packages=['easygui', 'easygui.boxes'], - package_data={ - 'easygui': ['python_and_check_logo.*', 'zzzzz.gif'] - }, - classifiers=[ - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Topic :: Software Development :: User Interfaces', - ] - ) - diff --git a/app_windows/lib/splinter-0.7.2/MANIFEST.in b/app_windows/lib/splinter-0.7.2/MANIFEST.in deleted file mode 100644 index bb39d55..0000000 --- a/app_windows/lib/splinter-0.7.2/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include *.rst -prune tests diff --git a/app_windows/lib/splinter-0.7.2/PKG-INFO b/app_windows/lib/splinter-0.7.2/PKG-INFO deleted file mode 100644 index 5c0f345..0000000 --- a/app_windows/lib/splinter-0.7.2/PKG-INFO +++ /dev/null @@ -1,60 +0,0 @@ -Metadata-Version: 1.1 -Name: splinter -Version: 0.7.2 -Summary: browser abstraction for web acceptance testing -Home-page: UNKNOWN -Author: CobraTeam -Author-email: andrewsmedina@gmail.com -License: UNKNOWN -Description: .. image:: https://secure.travis-ci.org/cobrateam/splinter.png - :target: http://travis-ci.org/cobrateam/splinter - - - ++++++++++++++++++++++++++++++++++++++++++++++++ - splinter - python tool for test web applications - ++++++++++++++++++++++++++++++++++++++++++++++++ - - splinter is a tool for test web applications with a simple for find elements, form actions, and others browser actions. - - `what's new in splinter? `_ - - first steps - =========== - - * `Installation `_ - * `Quick tutorial `_ - - splinter open source project - ============================ - - * `Community `_ - * `Contribute `_ - - documentation - ============= - - `splinter documentation `_ - - external links - ============== - - `Django Full Stack Testing and BDD with Lettuce and Splinter `_ - - `Splinter: Python tool for acceptance tests on web applications `_ - - `Testes de aceitação com Lettuce e Splinter (pt-br) `_ - - `salad `_, a nice mix of great BDD ingredients (splinter + `lettuce `_ integration) - - - .. image:: https://d2weczhvl823v0.cloudfront.net/cobrateam/splinter/trend.png - :alt: Bitdeli badge - :target: https://bitdeli.com/free - -Platform: UNKNOWN -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 diff --git a/app_windows/lib/splinter-0.7.2/README.rst b/app_windows/lib/splinter-0.7.2/README.rst deleted file mode 100644 index f32c459..0000000 --- a/app_windows/lib/splinter-0.7.2/README.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. image:: https://secure.travis-ci.org/cobrateam/splinter.png - :target: http://travis-ci.org/cobrateam/splinter - - -++++++++++++++++++++++++++++++++++++++++++++++++ -splinter - python tool for test web applications -++++++++++++++++++++++++++++++++++++++++++++++++ - -splinter is a tool for test web applications with a simple for find elements, form actions, and others browser actions. - -`what's new in splinter? `_ - -first steps -=========== - -* `Installation `_ -* `Quick tutorial `_ - -splinter open source project -============================ - -* `Community `_ -* `Contribute `_ - -documentation -============= - -`splinter documentation `_ - -external links -============== - -`Django Full Stack Testing and BDD with Lettuce and Splinter `_ - -`Splinter: Python tool for acceptance tests on web applications `_ - -`Testes de aceitação com Lettuce e Splinter (pt-br) `_ - -`salad `_, a nice mix of great BDD ingredients (splinter + `lettuce `_ integration) - - -.. image:: https://d2weczhvl823v0.cloudfront.net/cobrateam/splinter/trend.png - :alt: Bitdeli badge - :target: https://bitdeli.com/free diff --git a/app_windows/lib/splinter-0.7.2/build/lib/splinter/__init__.py b/app_windows/lib/splinter-0.7.2/build/lib/splinter/__init__.py deleted file mode 100644 index 4a283d7..0000000 --- a/app_windows/lib/splinter-0.7.2/build/lib/splinter/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2012 splinter authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -from splinter.browser import Browser - - -__version__ = '0.7.2' diff --git a/app_windows/lib/splinter-0.7.2/build/lib/splinter/browser.py b/app_windows/lib/splinter-0.7.2/build/lib/splinter/browser.py deleted file mode 100644 index f43afca..0000000 --- a/app_windows/lib/splinter-0.7.2/build/lib/splinter/browser.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2012 splinter authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -import sys - -from splinter.driver.webdriver.firefox import WebDriver as FirefoxWebDriver -from splinter.driver.webdriver.remote import WebDriver as RemoteWebDriver -from splinter.driver.webdriver.chrome import WebDriver as ChromeWebDriver -from splinter.driver.webdriver.phantomjs import WebDriver as PhantomJSWebDriver -from splinter.exceptions import DriverNotFoundError - - -_DRIVERS = { - 'firefox': FirefoxWebDriver, - 'remote': RemoteWebDriver, - 'chrome': ChromeWebDriver, - 'phantomjs': PhantomJSWebDriver, -} - -if sys.version_info[0] <= 2: - try: - from splinter.driver.zopetestbrowser import ZopeTestBrowser - _DRIVERS['zope.testbrowser'] = ZopeTestBrowser - except ImportError: - pass - -try: - import django # noqa - from splinter.driver.djangoclient import DjangoClient - _DRIVERS['django'] = DjangoClient -except ImportError: - pass - -try: - import flask # noqa - from splinter.driver.flaskclient import FlaskClient - _DRIVERS['flask'] = FlaskClient -except ImportError: - pass - - -def Browser(driver_name='firefox', *args, **kwargs): - """ - Returns a driver instance for the given name. - - When working with ``firefox``, it's possible to provide a profile name - and a list of extensions. - - If you don't provide any driver_name, then ``firefox`` will be used. - - If there is no driver registered with the provided ``driver_name``, this - function will raise a :class:`splinter.exceptions.DriverNotFoundError` - exception. - """ - - try: - driver = _DRIVERS[driver_name] - except KeyError: - raise DriverNotFoundError("No driver for %s" % driver_name) - return driver(*args, **kwargs) diff --git a/app_windows/lib/splinter-0.7.2/build/lib/splinter/cookie_manager.py b/app_windows/lib/splinter-0.7.2/build/lib/splinter/cookie_manager.py deleted file mode 100644 index c2a534e..0000000 --- a/app_windows/lib/splinter-0.7.2/build/lib/splinter/cookie_manager.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2012 splinter authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -from splinter.meta import InheritedDocs - - -class CookieManagerAPI(InheritedDocs('_CookieManagerAPI', (object,), {})): - """ - An API that specifies how a splinter driver deals with cookies. - - You can add cookies using the :meth:`add ` method, - and remove one or all cookies using - the :meth:`delete ` method. - - A CookieManager acts like a ``dict``, so you can access the value of a - cookie through the [] operator, passing the cookie identifier: - - >>> cookie_manager.add({'name': 'Tony'}) - >>> assert cookie_manager['name'] == 'Tony' - """ - - def add(self, cookies): - """ - Adds a cookie. - - The ``cookie`` parameter is a ``dict`` where each key is an identifier - for the cookie value (like any ``dict``). - - Example of use: - - >>> cookie_manager.add({'name': 'Tony'}) - """ - raise NotImplementedError - - def delete(self, *cookies): - """ - Deletes one or more cookies. You can pass all the cookies identifier - that you want to delete. - - If none identifier is provided, all cookies are deleted. - - Examples: - - >>> cookie_manager.delete() # deletes all cookies - >>> cookie_manager.delete('name', 'birthday', - 'favorite_color') # deletes these three cookies - >>> cookie_manager.delete('name') # deletes one cookie - """ - raise NotImplementedError - - def all(self, verbose=False): - """ - Returns all of the cookies. - - **Note:** If you're using any webdriver and want more info about - the cookie, set the `verbose` parameter to `True` (in other - drivers, it won't make any difference). In this case, this method - will return a list of dicts, each with one cookie's info. - - Examples: - - >>> cookie_manager.add({'name': 'Tony'}) - >>> cookie_manager.all() - [{'name': 'Tony'}] - """ - raise NotImplementedError - - def __getitem__(self, item): - raise NotImplementedError - - def __eq__(self, other_object): - raise NotImplementedError diff --git a/app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/__init__.py b/app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/__init__.py deleted file mode 100644 index 6ed64e9..0000000 --- a/app_windows/lib/splinter-0.7.2/build/lib/splinter/driver/__init__.py +++ /dev/null @@ -1,588 +0,0 @@ -# -*- coding: utf-8 -*-: - -# Copyright 2012 splinter authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -""" -This module contains the basic API for splinter drivers and elemnts. -""" - -from splinter.meta import InheritedDocs -from splinter.request_handler.request_handler import RequestHandler - - -class DriverAPI(InheritedDocs('_DriverAPI', (RequestHandler,), {})): - """ - Basic driver API class. - """ - driver_name = None - - @property - def title(self): - """ - Title of current page. - """ - raise NotImplementedError("%s doesn't support access to the title." % self.driver_name) - - def __enter__(self): - """ - Context manager to use the browser safely. - """ - raise NotImplementedError("%s doesn't support use by 'with' statement." % self.driver_name) - - def __exit__(self): - """ - Context manager to use the browser safely. - """ - raise NotImplementedError("%s doesn't support use by 'with' statement." % self.driver_name) - - @property - def html(self): - """ - Source of current page. - """ - raise NotImplementedError("%s doesn't support access to the html." % self.driver_name) - - @property - def url(self): - """ - URL of current page. - """ - raise NotImplementedError("%s doesn't support access to the url." % self.driver_name) - - def visit(self, url): - """ - Visits a given URL. - - The ``url`` parameter is a string. - """ - raise NotImplementedError("%s doesn't visit any url." % self.driver_name) - - def back(self): - """ - Back to the last URL in the browsing history. - - If there is no URL to back, this method does nothing. - """ - raise NotImplementedError("%s doesn't support moving back in history." % self.driver_name) - - def forward(self): - """ - Forward to the next URL in the browsing history. - - If there is no URL to forward, this method does nothing. - """ - raise NotImplementedError("%s doesn't support moving forward in history." % self.driver_name) - - def reload(self): - """ - Revisits the current URL - """ - raise NotImplementedError("%s doesn't support reloading the page." % self.driver_name) - - def get_alert(self): - """ - Changes the context for working with alerts and prompts. - - For more details, check the :doc:`docs about iframes, alerts and prompts ` - """ - raise NotImplementedError("%s doesn't support alerts." % self.driver_name) - - def get_iframe(self, name): - """ - Changes the context for working with iframes. - - For more details, check the :doc:`docs about iframes, alerts and prompts ` - """ - raise NotImplementedError("%s doesn't support frames." % self.driver_name) - - def execute_script(self, script): - """ - Executes a given JavaScript in the browser. - - e.g.: :: - >>> browser.execute_script('document.getElementById("body").innerHTML = "

Hello world!

"') - """ - raise NotImplementedError("%s doesn't support executiong of arbitrary JavaScript." % self.driver_name) - - def evaluate_script(self, script): - """ - Similar to :meth:`execute_script ` method. - - Executes javascript in the browser and returns the value of the expression. - - e.g.: :: - >>> assert 4 == browser.evaluate_script('2 + 2') - """ - raise NotImplementedError("%s doesn't support evaluation of arbitrary JavaScript." % self.driver_name) - - def find_by_css(self, css_selector): - """ - Returns an instance of :class:`ElementList `, - using a CSS selector to query the current page content. - """ - raise NotImplementedError("%s doesn't support finding elements by css selector." % self.driver_name) - - def find_by_xpath(self, xpath): - """ - Returns an instance of :class:`ElementList `, - using a xpath selector to query the urrent page content. - """ - raise NotImplementedError("%s doesn't support finding elements by xpath selector." % self.driver_name) - - def find_by_name(self, name): - """ - Finds elements in current page by their name. - - Returns an instance of :class:`ElementList `. - """ - raise NotImplementedError("%s doesn't support finding elements by name." % self.driver_name) - - def find_by_id(self, id): - """ - Finds an element in current page by its id. - - Even when only one element is find, this method returns an instance of - :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding elements by id." % self.driver_name) - - def find_by_value(self, value): - """ - Finds elements in current page by their value. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding elements by value." % self.driver_name) - - def find_by_tag(self, tag): - """ - Find all elements of a given tag in current page. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding elements by tag." % self.driver_name) - - def find_link_by_href(self, href): - """ - Find all elements of a given tag in current page. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding links by href." % self.driver_name) - - def find_link_by_partial_href(self, partial_href): - """ - Find links by looking for a partial ``str`` in their href attribute. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding links by partial href." % self.driver_name) - - def find_link_by_text(self, text): - """ - Find links querying for their text. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding links by text." % self.driver_name) - - def find_link_by_partial_text(self, partial_text): - """ - Find links by looking for a partial ``str`` in their text. - - Returns an instance of :class:`ElementList ` - """ - raise NotImplementedError("%s doesn't support finding links by partial text." % self.driver_name) - - def find_option_by_value(self, value): - """ - Finds ``