mirror of
https://github.com/thewesker/lazy-dsi-file-downloader.git
synced 2025-12-20 04:21:09 -05:00
Compare commits
23 Commits
ghactionst
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
279fa88bbf | ||
|
|
90e8504bf8 | ||
|
|
fd6cb29d39 | ||
|
|
2a7bfd934e | ||
|
|
f09059791d | ||
|
|
9b42582d79 | ||
|
|
604ba5afa0 | ||
|
|
3466ef5b35 | ||
|
|
6df97b1e32 | ||
|
|
68181e58c0 | ||
|
|
50d06876ad | ||
|
|
5937d32b87 | ||
|
|
6367e8f8cc | ||
|
|
958973fe26 | ||
|
|
3aaad7a456 | ||
|
|
498755fd49 | ||
|
|
fc7e2b2e2e | ||
|
|
f2e62ad95e | ||
|
|
46cfe7815a | ||
|
|
9fae5314c1 | ||
|
|
0541727424 | ||
|
|
be1c9bfb18 | ||
|
|
610f1cea18 |
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG] - "
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Python version [if using Python]
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
56
.github/workflows/executables.yml
vendored
56
.github/workflows/executables.yml
vendored
@@ -3,6 +3,7 @@ name: Compile into Executables
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
######################################################################################
|
||||
# Based off of :
|
||||
@@ -31,21 +32,12 @@ jobs:
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
- name: Make binary
|
||||
run: |
|
||||
pyinstaller --onefile ^
|
||||
--add-data "certifi;certifi" ^
|
||||
--add-data "requests;requests" ^
|
||||
--add-data "urllib3;urllib3" ^
|
||||
--add-data "lazy.ico;." ^
|
||||
--add-data "chardet;chardet" ^
|
||||
--icon "lazy.ico" ^
|
||||
--console ^
|
||||
--name "lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}" ^
|
||||
main.py
|
||||
pyinstaller --onefile --add-data "certifi;certifi" --add-data "requests;requests" --add-data "urllib3;urllib3" --add-data "lazy.ico;." --add-data "chardet;chardet" --icon "lazy.ico" --console --name "lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-Windows" main.py
|
||||
cd dist
|
||||
- name: Publish builds
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}.exe
|
||||
path: dist/lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-Windows.exe
|
||||
name: windows
|
||||
|
||||
python:
|
||||
@@ -60,23 +52,55 @@ jobs:
|
||||
- name: Make zip
|
||||
run: |
|
||||
mkdir temporary
|
||||
cp -r certifi chardet Darwin idna Linux requests urllib3 temporary/
|
||||
cp LICENSE main.py README.md temporary/
|
||||
zip lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-Python3.zip temporary
|
||||
cp -r certifi chardet Darwin idna Linux requests urllib3 tkmacosx temporary/
|
||||
cp LICENSE main.py colour.py README.md temporary/
|
||||
cd temporary
|
||||
chmod +x main.py
|
||||
zip -r ../lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-Python3.zip *
|
||||
- name: Publish artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-Python3.zip
|
||||
name: python
|
||||
|
||||
|
||||
macos:
|
||||
runs-on: macos-latest
|
||||
name: macOS
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.x"
|
||||
architecture: "x64"
|
||||
- name: Install pyinstaller
|
||||
run: |
|
||||
pip3 install pyinstaller
|
||||
- name: Get tag
|
||||
id: vars
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
- name: Create executable
|
||||
run: |
|
||||
pyinstaller --onefile --add-data "colour.py:." --add-data "tkmacosx:tkmacosx" --add-data "Darwin:Darwin" --add-binary "Darwin/7za:Darwin" --add-data "certifi:certifi" --add-data "requests:requests" --add-data "urllib3:urllib3" --add-data "lazy.ico:." --add-data "chardet:chardet" --icon "lazy.ico" --console --name "lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-macOS" main.py
|
||||
cd dist
|
||||
chmod +x lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-macOS
|
||||
zip ../lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-macOS.zip lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-macOS
|
||||
- name: Publish artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: lazy-dsi-file-downloader-${{ steps.vars.outputs.tag }}-macOS.zip
|
||||
name: macos
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish builds
|
||||
if: ${{ success() }}
|
||||
needs: [windows,python]
|
||||
needs: [windows,python,macos]
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifacts@v2
|
||||
uses: actions/download-artifact@v2
|
||||
- name: Upload to Release
|
||||
run: |
|
||||
ID=$(jq --raw-output '.release.id' $GITHUB_EVENT_PATH)
|
||||
|
||||
597
main.py
597
main.py
@@ -1,12 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Created by YourKalamity
|
||||
#https://github.com/YourKalamity/lazy-dsi-file-downloader
|
||||
# https://github.com/YourKalamity/lazy-dsi-file-downloader
|
||||
|
||||
|
||||
#Import libraries
|
||||
import tkinter
|
||||
from tkinter import messagebox
|
||||
import tkinter
|
||||
from tkinter import filedialog
|
||||
import tkinter.font
|
||||
import tkinter.ttk
|
||||
@@ -20,127 +18,138 @@ import shutil
|
||||
from subprocess import Popen
|
||||
import zipfile
|
||||
import distutils
|
||||
from distutils import dir_util
|
||||
import webbrowser
|
||||
import threading
|
||||
from requests.exceptions import ConnectionError
|
||||
import hashlib
|
||||
|
||||
pageNumber = 0
|
||||
|
||||
#Memory Pit Links - Points to GitHub repo
|
||||
dsiVersions = ["1.0 - 1.3 (USA, EUR, AUS, JPN)", "1.4 - 1.4.5 (USA, EUR, AUS, JPN)", "All versions (KOR, CHN)"]
|
||||
memoryPitLinks = ["https://github.com/YourKalamity/just-a-dsi-cfw-installer/raw/master/assets/files/memoryPit/256/pit.bin","https://github.com/YourKalamity/just-a-dsi-cfw-installer/raw/master/assets/files/memoryPit/768_1024/pit.bin"]
|
||||
dsiVersions = [
|
||||
"1.0 - 1.3 (USA, EUR, AUS, JPN)",
|
||||
"1.4 - 1.4.5 (USA, EUR, AUS, JPN)",
|
||||
"All versions (KOR, CHN)"
|
||||
]
|
||||
|
||||
linkToRepo = "https://github.com/YourKalamity/lazy-dsi-file-downloader"
|
||||
|
||||
memoryPitLinks = [
|
||||
linkToRepo + "/raw/master/assets/files/memoryPit/256/pit.bin",
|
||||
linkToRepo + "/raw/master/assets/files/memoryPit/768_1024/pit.bin"
|
||||
]
|
||||
|
||||
|
||||
#Downloader
|
||||
def downloadFile(link, destination):
|
||||
try:
|
||||
r = requests.get(link, allow_redirects=True)
|
||||
if link.find('/'):
|
||||
fileName = link.rsplit('/', 1)[1]
|
||||
if destination.endswith("/") == False:
|
||||
if destination.endswith("/") is False:
|
||||
destination = destination + "/"
|
||||
downloadLocation = destination + fileName
|
||||
open(downloadLocation, 'wb').write(r.content)
|
||||
return downloadLocation
|
||||
except ConnectionError:
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print(e)
|
||||
print("File not available, skipping...")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def hashcreator(filetobechecked):
|
||||
string = hashlib.blake2b(open(filetobechecked,'rb').read()).hexdigest()
|
||||
string = hashlib.blake2b(open(filetobechecked, 'rb').read()).hexdigest()
|
||||
return string
|
||||
|
||||
#Get link of latest Github Release
|
||||
|
||||
def getLatestGitHub(usernamerepo, assetNumber):
|
||||
release = json.loads(requests.get("https://api.github.com/repos/"+usernamerepo+"/releases/latest").content)
|
||||
release = json.loads(
|
||||
requests.get(
|
||||
"https://api.github.com/repos/"+usernamerepo+"/releases/latest"
|
||||
).content)
|
||||
url = release["assets"][assetNumber]["browser_download_url"]
|
||||
return url
|
||||
|
||||
#Push text to output box
|
||||
|
||||
def outputbox(message):
|
||||
outputBox.configure(state='normal')
|
||||
outputBox.insert('end', message)
|
||||
outputBox.see(tkinter.END)
|
||||
outputBox.configure(state='disabled')
|
||||
|
||||
#Check if directory exists and has write permissions
|
||||
|
||||
def validateDirectory(directory):
|
||||
try:
|
||||
directory = str(directory)
|
||||
except TypeError:
|
||||
outputbox("That's not a valid directory \n")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
try:
|
||||
string = directory + "/test.file"
|
||||
with open(string, 'w') as file:
|
||||
file.close()
|
||||
os.remove(string)
|
||||
except FileNotFoundError:
|
||||
outputbox("That's not a valid directory")
|
||||
outputbox("or you do not have the")
|
||||
outputbox(" permission to write there")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
except PermissionError:
|
||||
outputbox("You do not have write access to that folder\n")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
try:
|
||||
directory = str(directory)
|
||||
except TypeError:
|
||||
outputbox("That's not a valid directory \n")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
try:
|
||||
string = directory + "/test.file"
|
||||
with open(string, 'w') as file:
|
||||
file.close()
|
||||
os.remove(string)
|
||||
except FileNotFoundError:
|
||||
outputbox("That's not a valid directory")
|
||||
outputbox("or you do not have the")
|
||||
outputbox(" permission to write there")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
except PermissionError:
|
||||
outputbox("You do not have write access to that folder\n")
|
||||
outputbox("Press the Back button to change the folder\n")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def unzipper(unzipped, destination):
|
||||
with zipfile.ZipFile(unzipped, 'r') as zip_ref:
|
||||
zip_ref.extractall(destination)
|
||||
zip_ref.close()
|
||||
zip_ref.extractall(destination)
|
||||
zip_ref.close()
|
||||
|
||||
|
||||
def un7zipper(_7za, zipfile, destination):
|
||||
proc = Popen([_7za,"x", "-aoa", zipfile, '-o'+destination])
|
||||
|
||||
ret_val = proc.wait()
|
||||
|
||||
while True:
|
||||
if ret_val == 0:
|
||||
break
|
||||
|
||||
un7zipper = Popen([_7za, "x", "-aoa", zipfile, '-o'+destination])
|
||||
un7zipper.wait()
|
||||
|
||||
|
||||
def start():
|
||||
|
||||
#Clear outputBox
|
||||
# Clear outputBox
|
||||
outputBox.configure(state='normal')
|
||||
outputBox.delete('1.0', tkinter.END)
|
||||
outputBox.configure(state='disabled')
|
||||
|
||||
# Locate 7z binary
|
||||
sysname = platform.system()
|
||||
#Locate 7z binary
|
||||
_7za = os.path.join(sysname, '7za')
|
||||
_7z = None
|
||||
if sysname in ["Darwin", "Linux"]:
|
||||
#Chmod 7z binary to avoid a permission error
|
||||
import stat
|
||||
os.chmod(_7za, stat.S_IRWXU)
|
||||
# Chmod 7z binary to avoid a permission error
|
||||
import stat
|
||||
os.chmod(_7za, stat.S_IRWXU)
|
||||
if sysname == "Windows":
|
||||
#Search for 7z in the 64-bit Windows Registry
|
||||
from winreg import OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_64KEY
|
||||
# Search for 7z in the 64-bit Windows Registry
|
||||
import winreg
|
||||
print('Searching for 7-Zip in the Windows registry...')
|
||||
|
||||
try:
|
||||
with OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE\\7-Zip', 0, KEY_READ | KEY_WOW64_64KEY) as hkey:
|
||||
_7z = os.path.join(QueryValueEx(hkey, 'Path')[0], '7z.exe')
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
'SOFTWARE\\7-Zip', 0, winreg.KEY_READ | winreg.KEY_WOW64_64KEY
|
||||
) as hkey:
|
||||
_7z = os.path.join(winreg.QueryValueEx(
|
||||
hkey, 'Path')[0], '7z.exe')
|
||||
|
||||
if not os.path.exists(_7z):
|
||||
raise WindowsError
|
||||
|
||||
_7za = _7z
|
||||
except WindowsError:
|
||||
#Search for 7z in the 32-bit Windows Registry
|
||||
# Search for 7z in the 32-bit Windows Registry
|
||||
print('Searching for 7-Zip in the 32-bit Windows registry...')
|
||||
|
||||
try:
|
||||
with OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE\\7-Zip') as hkey:
|
||||
_7z = os.path.join(QueryValueEx(hkey, 'Path')[0], '7z.exe')
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\7-Zip'
|
||||
) as hkey:
|
||||
_7z = os.path.join(winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe')
|
||||
|
||||
if not os.path.exists(_7z):
|
||||
raise WindowsError
|
||||
@@ -154,151 +163,136 @@ def start():
|
||||
print("7-Zip found!")
|
||||
|
||||
lineCounter = 0
|
||||
|
||||
#Variables
|
||||
directory = SDentry
|
||||
if directory.endswith("\\") or directory.endswith("/"):
|
||||
directory = directory[:-1]
|
||||
version = firmwareVersion.get()
|
||||
unlaunchNeeded = unlaunch.get()
|
||||
|
||||
#Validate directory
|
||||
# Validate directory
|
||||
directoryValidated = validateDirectory(directory)
|
||||
if directoryValidated == False:
|
||||
if directoryValidated is False:
|
||||
finalbackButton.configure(state='normal')
|
||||
return
|
||||
if dsiVersions.index(version) == 1:
|
||||
memoryPitDownload = memoryPitLinks[1]
|
||||
elif dsiVersions.index(version) in [0,2]:
|
||||
elif dsiVersions.index(version) in [0, 2]:
|
||||
memoryPitDownload = memoryPitLinks[0]
|
||||
|
||||
#Creates a path called "/lazy-dsi-file-downloader-tmp/" if it does not exist
|
||||
# Creates a path called "/lazy-dsi-file-downloader-tmp/"
|
||||
cwdtemp = os.getcwd() + "/lazy-dsi-file-downloader-tmp/"
|
||||
Path(cwdtemp).mkdir(parents=True,exist_ok=True)
|
||||
Path(cwdtemp).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if downloadmemorypit.get() == 1:
|
||||
#Download Memory Pit
|
||||
# Download Memory Pit
|
||||
memoryPitLocation = directory + "/private/ds/app/484E494A/"
|
||||
Path(memoryPitLocation).mkdir(parents=True, exist_ok=True)
|
||||
outputbox("Downloading Memory Pit\n")
|
||||
downloadLocation = downloadFile(memoryPitDownload, memoryPitLocation)
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
outputbox("Memory Pit Downloaded\n")
|
||||
print("Memory Pit Downloaded")
|
||||
|
||||
if downloadtwlmenu.get() == 1:
|
||||
#Download TWiLight Menu
|
||||
# Download TWiLight Menu
|
||||
outputbox("Downloading TWiLight Menu ++\n")
|
||||
TWLmenuLocation = downloadFile(getLatestGitHub('DS-Homebrew/TWiLightMenu', 1),cwdtemp)
|
||||
if TWLmenuLocation != None:
|
||||
TWLmenuLocation = downloadFile(getLatestGitHub('DS-Homebrew/TWiLightMenu', 1), cwdtemp)
|
||||
if TWLmenuLocation is not None:
|
||||
outputbox("TWiLight Menu ++ Downloaded\n")
|
||||
print("TWiLight Menu ++ Downloaded")
|
||||
|
||||
#Extract TWiLight Menu
|
||||
# Extract TWiLight Menu
|
||||
proc = Popen([_7za,"x", "-aoa", TWLmenuLocation, '-o'+cwdtemp, '_nds', 'hiya', 'roms','title', 'BOOT.NDS','snemul.cfg'])
|
||||
ret_val = proc.wait()
|
||||
|
||||
while True:
|
||||
if ret_val == 0:
|
||||
outputbox("TWiLight Menu ++ Extracted\n")
|
||||
print("TWiLight Menu ++ Extracted to", cwdtemp)
|
||||
break
|
||||
outputbox("TWiLight Menu ++ Extracted\n")
|
||||
print("TWiLight Menu ++ Extracted to", cwdtemp)
|
||||
originalHash = hashcreator(cwdtemp + "BOOT.NDS")
|
||||
|
||||
#Move TWiLight Menu
|
||||
# Move TWiLight Menu
|
||||
shutil.copy(cwdtemp + "BOOT.NDS", directory)
|
||||
|
||||
distutils.dir_util.copy_tree(cwdtemp + "_nds/" , directory +"/_nds/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "hiya", directory+"/hiya/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "title", directory+"/title/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "roms", directory+"/roms/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "_nds/", directory + "/_nds/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "hiya", directory + "/hiya/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "title", directory + "/title/")
|
||||
distutils.dir_util.copy_tree(cwdtemp + "roms", directory + "/roms/")
|
||||
|
||||
|
||||
#Some Homebrew write to the _nds folder so it is better to clear it first
|
||||
# Some Homebrew write to the _nds folder so it is better to clear it first
|
||||
shutil.rmtree(cwdtemp +"_nds/")
|
||||
Path(cwdtemp +"_nds/").mkdir(parents=True,exist_ok=True)
|
||||
Path(cwdtemp + "_nds/").mkdir(parents=True, exist_ok=True)
|
||||
comparedHash = hashcreator(directory+"/BOOT.NDS")
|
||||
if originalHash == comparedHash:
|
||||
print("TWiLight Menu ++ placed in", directory)
|
||||
outputbox("TWiLight Menu ++ placed on SD \n")
|
||||
|
||||
|
||||
#Download DeadSkullzJr's Cheat Database
|
||||
Path(directory + "/_nds/TWiLightMenu/extras/").mkdir(parents=True,exist_ok=True)
|
||||
# Download DeadSkullzJr's Cheat Database
|
||||
Path(directory + "/_nds/TWiLightMenu/extras/").mkdir(parents=True, exist_ok=True)
|
||||
outputbox("Downloading DeadSkullzJr's Cheat database\n")
|
||||
downloadLocation = downloadFile('https://bitbucket.org/DeadSkullzJr/nds-cheat-databases/raw/933c375545d3ff90854d1e210dcf4b3b31d9d585/Cheats/usrcheat.dat', directory + "/_nds/TWiLightMenu/extras/")
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
print("DeadSkullzJr's Cheat Database downloaded")
|
||||
outputbox("DeadSkullzJr's Cheat Database downloaded\n")
|
||||
|
||||
|
||||
if downloaddumptool.get() == 1:
|
||||
#Download dumpTool
|
||||
if downloaddumptool.get() == 1:
|
||||
# Download dumpTool
|
||||
outputbox("Downloading dumpTool\n")
|
||||
downloadLocation = downloadFile(getLatestGitHub('zoogie/dumpTool', 0), directory)
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
print("dumpTool downloaded")
|
||||
outputbox("dumpTool Downloaded\n")
|
||||
lineCounter = lineCounter + 1
|
||||
|
||||
if unlaunchNeeded == 1 :
|
||||
#Download Unlaunch
|
||||
url = "https://problemkaputt.de/unlaunch.zip"
|
||||
if unlaunchNeeded == 1:
|
||||
# Download Unlaunch
|
||||
url = "https://web.archive.org/web/20210207235625if_/https://problemkaputt.de/unlaunch.zip"
|
||||
outputbox("Downloading Unlaunch\n")
|
||||
unlaunchLocation = downloadFile(url, cwdtemp)
|
||||
if unlaunchLocation != None:
|
||||
if unlaunchLocation is not None:
|
||||
print("Unlaunch Downloaded")
|
||||
outputbox("Unlaunch Downloaded\n")
|
||||
lineCounter = lineCounter + 1
|
||||
# Extract Unlaunch
|
||||
unzipper(unlaunchLocation, irectory)
|
||||
print("Unlaunch Extracted")
|
||||
|
||||
#Extract Unlaunch
|
||||
unzipper(unlaunchLocation,directory)
|
||||
|
||||
|
||||
#Creates roms/nds if it does not exist
|
||||
roms = directory +"/roms/nds/"
|
||||
Path(roms).mkdir(parents=True,exist_ok=True)
|
||||
# Creates roms/nds if it does not exist
|
||||
roms = directory + "/roms/nds/"
|
||||
Path(roms).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if godmode9i.get() == 1:
|
||||
#Download GodMode9i
|
||||
# Download GodMode9i
|
||||
outputbox("Downloading GodMode9i\n")
|
||||
downloadLocation = downloadFile(getLatestGitHub('DS-Homebrew/GodMode9i', 0), cwdtemp)
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
print("GodMode9i downloaded")
|
||||
outputbox("GodMode9i Downloaded\n")
|
||||
lineCounter = lineCounter + 1
|
||||
#Extract TWiLight Menu
|
||||
# Extract TWiLight Menu
|
||||
proc = Popen([_7za,"x", "-aoa", downloadLocation, '-o'+roms, 'GodMode9i.nds'])
|
||||
ret_val = proc.wait()
|
||||
outputbox("GodMode9i Extracted\n")
|
||||
print("GodMode9i Extracted to", roms)
|
||||
|
||||
while True:
|
||||
if ret_val == 0:
|
||||
outputbox("GodMode9i Extracted\n")
|
||||
print("GodMode9i Extracted to", roms)
|
||||
break
|
||||
|
||||
if updateHiyaCFW.get() == 1:
|
||||
#Check if old hiyaCFW insallation exists
|
||||
# Check if old hiyaCFW insallation exists
|
||||
outputbox("Checking for hiyaCFW\n")
|
||||
if os.path.isfile(directory+"/hiya.dsi"):
|
||||
outputbox("hiyaCFW found...\n")
|
||||
outputbox("Downloading latest...\n")
|
||||
downloadLocation = downloadFile(getLatestGitHub("RocketRobz/hiyaCFW",0),cwdtemp)
|
||||
if downloadLocation != None:
|
||||
downloadLocation = downloadFile(getLatestGitHub("RocketRobz/hiyaCFW", 0), cwdtemp)
|
||||
if downloadLocation is not None:
|
||||
outputbox("hiyaCFW.7z downloaded\n")
|
||||
os.remove(directory+"/hiya.dsi")
|
||||
proc = Popen([_7za,"x","-aoa",downloadLocation, "-o"+directory,"for SDNAND SD card\hiya.dsi"])
|
||||
ret_val = proc
|
||||
|
||||
|
||||
ret_val = proc.wait()
|
||||
shutil.move(directory + "/for SDNAND SD card/hiya.dsi", directory + "/hiya.dsi")
|
||||
shutil.rmtree(directory + "/for SDNAND SD card/")
|
||||
else:
|
||||
outputbox("hiya.dsi was not found\n")
|
||||
outputbox("Please run the hiyaCFW helper first")
|
||||
|
||||
|
||||
# Download and extract extra homebrew
|
||||
outputbox("Downloading other homebrew\n")
|
||||
lineCounter = lineCounter + 1
|
||||
print("Downloading other homebrew...")
|
||||
|
||||
|
||||
for count, item in enumerate(homebrewDB):
|
||||
if homebrewList[count].get() == 1:
|
||||
print("Downloading "+item["title"])
|
||||
@@ -306,174 +300,169 @@ def start():
|
||||
lineCounter = lineCounter + 1
|
||||
if item["github"] == "True":
|
||||
downloadlink = getLatestGitHub(item["repo"], int(item["asset"]))
|
||||
else:
|
||||
else:
|
||||
downloadlink = item["link"]
|
||||
if item["extension"] == "nds":
|
||||
downloadFile(downloadlink, roms)
|
||||
outputbox("Downloaded "+item["title"]+'\n')
|
||||
elif item["extension"] == "zip":
|
||||
downloadLocation = downloadFile(downloadlink, cwdtemp)
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
if item["location"]["roms"] == "all":
|
||||
unzipper(downloadLocation, roms)
|
||||
outputbox("Downloaded "+item["title"]+'\n')
|
||||
elif item["extension"] == "7z":
|
||||
downloadLocation = downloadFile(downloadlink, cwdtemp)
|
||||
if downloadLocation != None:
|
||||
if downloadLocation is not None:
|
||||
if item["location"]["roms"] == "all":
|
||||
un7zipper(_7za, downloadLocation, roms)
|
||||
outputbox("Downloaded "+item["title"]+'\n')
|
||||
else:
|
||||
un7zipper(_7za, downloadLocation, cwdtemp)
|
||||
if "root" in item["location"]:
|
||||
Path(directory+(item["location"]["root"].split('/')).pop()).mkdir(parents=True,exist_ok=True)
|
||||
shutil.copy(cwdtemp+item["location"]["root"],directory+((item["location"]["root"].split('/')).pop().pop(0)))
|
||||
Path(directory+(item["location"]["root"].split('/')).pop()).mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy(cwdtemp+item["location"]["root"], directory+((item["location"]["root"].split('/')).pop().pop(0)))
|
||||
if "roms" in item["location"]:
|
||||
shutil.copy(cwdtemp+item["location"]["roms"],roms)
|
||||
shutil.copy(cwdtemp+item["location"]["roms"], roms)
|
||||
outputbox("Downloaded "+item["title"]+'\n')
|
||||
|
||||
|
||||
|
||||
#Delete tmp folder
|
||||
# Delete tmp folder
|
||||
shutil.rmtree(cwdtemp)
|
||||
|
||||
#Restore button access
|
||||
# Restore button access
|
||||
finalnextButton.config(state="normal")
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
|
||||
window.protocol("WM_DELETE_WINDOW", lambda: closeButtonPress(window))
|
||||
print("Done!")
|
||||
outputbox("Done!\n")
|
||||
outputbox("Press the Finish button to continue... \n")
|
||||
|
||||
|
||||
def chooseDir(source,SDentry):
|
||||
source.sourceFolder = filedialog.askdirectory(parent=source, initialdir= "/", title='Please select the directory of your SD card')
|
||||
|
||||
def chooseDir(source, SDentry):
|
||||
source.sourceFolder = filedialog.askdirectory(
|
||||
parent=source, initialdir="/",
|
||||
title='Please select the root directory of your SD card')
|
||||
SDentry.delete(0, tkinter.END)
|
||||
SDentry.insert(0, source.sourceFolder)
|
||||
|
||||
|
||||
def okButtonPress(self,source):
|
||||
def okButtonPress(self, source):
|
||||
self.destroy()
|
||||
source.deiconify()
|
||||
|
||||
|
||||
def extraHomebrew(source):
|
||||
homebrewWindow = tkinter.Toplevel(source)
|
||||
homebrewWindow.config(bg="#f0f0f0")
|
||||
source.withdraw()
|
||||
homebrewWindowLabel = tkinter.Label(homebrewWindow, text="Homebrew List",font=("Segoe UI",12,"bold"),bg="#f0f0f0",fg="#000000")
|
||||
homebrewWindowLabel.pack(anchor = "w")
|
||||
homebrewWindowLabel2 = tkinter.Label(homebrewWindow, text="Select additional homebrew for download then press OK", font=(bodyFont),bg="#f0f0f0",fg="#000000")
|
||||
homebrewWindowLabel2.pack(anchor = "w")
|
||||
|
||||
vscrollbar = tkinter.Scrollbar(homebrewWindow)
|
||||
canvas = tkinter.Canvas(homebrewWindow, yscrollcommand=vscrollbar.set)
|
||||
canvas.config(bg="#f0f0f0")
|
||||
vscrollbar.config(command=canvas.yview)
|
||||
vscrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
|
||||
homebrewWindow = tkinter.Toplevel(source)
|
||||
homebrewWindow.config(bg="#f0f0f0")
|
||||
source.withdraw()
|
||||
homebrewWindowLabel = tkinter.Label(homebrewWindow, text="Homebrew List", font=("Segoe UI",12,"bold"), bg="#f0f0f0", fg="#000000")
|
||||
homebrewWindowLabel.pack(anchor="w")
|
||||
homebrewWindowLabel2 = tkinter.Label(homebrewWindow, text="Select additional homebrew for download then press OK", font=(bodyFont), bg="#f0f0f0", fg="#000000")
|
||||
homebrewWindowLabel2.pack(anchor="w")
|
||||
vscrollbar = tkinter.Scrollbar(homebrewWindow)
|
||||
canvas = tkinter.Canvas(homebrewWindow, yscrollcommand=vscrollbar.set)
|
||||
canvas.config(bg="#f0f0f0")
|
||||
vscrollbar.config(command=canvas.yview)
|
||||
vscrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
|
||||
homebrewFrame = tkinter.Frame(canvas)
|
||||
homebrewFrame.configure(bg="#f0f0f0")
|
||||
homebrewWindow.title("Homebrew List")
|
||||
homebrewWindow.resizable(0, 0)
|
||||
canvas.pack(side="left", fill="both", expand=True)
|
||||
canvas.create_window(0, 0, window=homebrewFrame, anchor="n")
|
||||
for count, x in enumerate(homebrewDB):
|
||||
homebrewListMenu = tkinter.Checkbutton(homebrewFrame, text=x["title"] + " by " + x["author"], font=(bigListFont), variable=homebrewList[count], bg="#f0f0f0", fg="#000000")
|
||||
homebrewListMenu.config(selectcolor="#F0F0F0")
|
||||
homebrewListMenu.pack(anchor = "w")
|
||||
frame = tkinter.ttk.Frame(homebrewWindow, relief=tkinter.RAISED, borderwidth=1)
|
||||
frame.pack(fill=tkinter.BOTH, expand=True)
|
||||
okButton = Button(homebrewWindow, text = "OK", font=(buttonFont), command=lambda: okButtonPress(homebrewWindow,source), bg="#f0f0f0", fg="#000000")
|
||||
okButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
homebrewWindow.update()
|
||||
canvas.config(scrollregion=canvas.bbox("all"))
|
||||
homebrewWindow.protocol("WM_DELETE_WINDOW", lambda: okButtonPress(homebrewWindow, source))
|
||||
|
||||
homebrewFrame = tkinter.Frame(canvas)
|
||||
homebrewFrame.configure(bg="#f0f0f0")
|
||||
|
||||
homebrewWindow.title("Homebrew List")
|
||||
homebrewWindow.resizable(0,0)
|
||||
canvas.pack(side="left", fill="both", expand=True)
|
||||
canvas.create_window(0,0, window=homebrewFrame, anchor="n")
|
||||
for count, x in enumerate(homebrewDB):
|
||||
l = tkinter.Checkbutton(homebrewFrame, text=x["title"] + " by " + x["author"],font=(bigListFont), variable=homebrewList[count],bg="#f0f0f0",fg="#000000")
|
||||
l.config(selectcolor="#F0F0F0")
|
||||
l.pack(anchor = "w")
|
||||
|
||||
frame = tkinter.ttk.Frame(homebrewWindow, relief=tkinter.RAISED, borderwidth=1)
|
||||
frame.pack(fill=tkinter.BOTH, expand=True)
|
||||
|
||||
|
||||
okButton = tkinter.Button(homebrewWindow, text = "OK", font=(buttonFont), command=lambda:okButtonPress(homebrewWindow,source),bg="#f0f0f0",fg="#000000")
|
||||
okButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
homebrewWindow.update()
|
||||
canvas.config(scrollregion=canvas.bbox("all"))
|
||||
|
||||
homebrewWindow.protocol("WM_DELETE_WINDOW",lambda:okButtonPress(homebrewWindow,source))
|
||||
|
||||
def closeButtonPress(source):
|
||||
source.destroy()
|
||||
root.destroy()
|
||||
|
||||
|
||||
def nextWindow(windownumbertosummon):
|
||||
globals()["summonWindow"+windownumbertosummon]
|
||||
|
||||
|
||||
def donothing():
|
||||
return
|
||||
|
||||
|
||||
def summonWindow0():
|
||||
window.title("Lazy DSi file Downloader")
|
||||
window.resizable(0,0)
|
||||
window.resizable(0, 0)
|
||||
window.geometry("500x360")
|
||||
window.option_add("*Background", backgroundColour)
|
||||
window.configure(bg=backgroundColour)
|
||||
topFrame = tkinter.Frame(window)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH,padx=5)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH, padx=5)
|
||||
topFrame.option_add("*Background", backgroundColour)
|
||||
bottomFrame = tkinter.Frame(window)
|
||||
bottomFrame.pack(side=tkinter.BOTTOM, fill=tkinter.X,padx=5)
|
||||
bottomFrame.pack(side=tkinter.BOTTOM, fill=tkinter.X, padx=5)
|
||||
bottomFrame.option_add("*Background", backgroundColour)
|
||||
first = tkinter.Label(topFrame, text="Welcome to the Lazy DSi File Downloader", font=(titleFont), fg=foregroundColour)
|
||||
first.grid(column=0,row=0, sticky="w",padx=5)
|
||||
|
||||
first = tkinter.Label(topFrame, text="Lazy DSi File Downloader", font=(titleFont), fg=foregroundColour)
|
||||
first.grid(column=0, row=0, sticky="w", padx=5)
|
||||
bulletpoints = [
|
||||
"This is an application made by Your Kalamity that downloads and place files for homebrew'ing your Nintendo DSi in the correct location. If you have already installed homebrew, this can also update the one you have.",
|
||||
"This is to be used in conjunction with the Nintendo DSi Modding guide by NightScript and emiyl",
|
||||
"This is to be used in conjunction with the Nintendo DSi Modding guide by NightScript, emiyl and the rest of the community.",
|
||||
"Check it out here: https://dsi.cfw.guide/",
|
||||
"By using this application, you do not need to follow any of the 'Preparing SD card' steps.",
|
||||
"This application is to be given for free. If you have paid to receive this, contact the person that sold you this application; you have been scammed.",
|
||||
"You may use any part of this application for your own purposes as long as credit is given.",
|
||||
"By using this application, you don't need to follow any of the 'Preparing SD card' steps.",
|
||||
"Please proceed by hitting the 'Next' button"
|
||||
]
|
||||
|
||||
for count, x in enumerate(bulletpoints):
|
||||
bullet = tkinter.Label(topFrame, text=x, font=(paragraphFont),fg=foregroundColour,wraplength=450, justify="left")
|
||||
bullet.grid(column=0,row=count+3, sticky="w", padx=5)
|
||||
|
||||
discordButton = tkinter.Button(bottomFrame, text="DS⁽ⁱ⁾ Mode Hacking Discord server", fg=foregroundColour,bg=buttonColour, font=(buttonFont),command=lambda:webbrowser.open("https://discord.gg/yD3spjv",new=1))
|
||||
discordButton.pack(side=tkinter.LEFT, padx="5", pady="5")
|
||||
nextButton = tkinter.Button(bottomFrame, text="Next",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow1()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
for count, x in enumerate(bulletpoints):
|
||||
bullet = tkinter.Label(topFrame, text=x, font=(paragraphFont), fg=foregroundColour, wraplength=450, justify="left")
|
||||
bullet.grid(column=0, row=count+3, sticky="w", padx=5)
|
||||
|
||||
discordButton = Button(bottomFrame, text="DS⁽ⁱ⁾ Mode Hacking Discord server", fg=foregroundColour, bg=buttonColour, font=(buttonFont), command=lambda: webbrowser.open("https://discord.gg/yD3spjv", new=1))
|
||||
discordButton.pack(side=tkinter.LEFT, padx="5", pady="5")
|
||||
nextButton = Button(bottomFrame, text="Next", width=button_width, fg=foregroundColour, bg=nextButtonColour, font=(buttonFont), command=lambda: [topFrame.destroy(), bottomFrame.destroy(), summonWindow1()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
|
||||
window.protocol("WM_DELETE_WINDOW", lambda: closeButtonPress(window))
|
||||
|
||||
|
||||
def summonWindow1():
|
||||
topFrame = tkinter.Frame(window)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH,padx=5)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH, padx=5)
|
||||
topFrame.option_add("*Background", backgroundColour)
|
||||
bottomFrame = tkinter.Frame(window)
|
||||
bottomFrame.pack(side=tkinter.BOTTOM, fill=tkinter.X,padx=5)
|
||||
bottomFrame.pack(side=tkinter.BOTTOM, fill=tkinter.X, padx=5)
|
||||
bottomFrame.option_add("*Background", backgroundColour)
|
||||
first = tkinter.Label(topFrame, text="Memory Pit", font=(titleFont), fg=foregroundColour)
|
||||
first.grid(column=0,row=0, sticky="w",padx=5)
|
||||
first.grid(column=0, row=0, sticky="w", padx=5)
|
||||
subtitle = tkinter.Label(topFrame, text='thank you, shutterbug2000!', font=(subtitleFont), fg=foregroundColour)
|
||||
subtitle.grid(column=0,row=1, sticky="w",padx=5)
|
||||
subtitle.grid(column=0, row=1, sticky="w", padx=5)
|
||||
filler = tkinter.Label(topFrame, text=" ")
|
||||
filler.grid(column=0,row=3)
|
||||
downloadmemorypitCheck = tkinter.Checkbutton(topFrame, text = "Download Memory pit exploit?",font=(buttonFont),fg=foregroundColour, variable = downloadmemorypit)
|
||||
downloadmemorypitCheck.grid(column=0,row=2, sticky="w")
|
||||
firmwareLabel = tkinter.Label(topFrame, text = "Select your DSi firmware : ",fg=foregroundColour,font=(buttonFont))
|
||||
firmwareLabel.grid(column=0,row=4, sticky="w")
|
||||
filler.grid(column=0, row=3)
|
||||
downloadmemorypitCheck = tkinter.Checkbutton(topFrame, text = "Download Memory pit exploit?", font=(buttonFont), fg=foregroundColour, variable = downloadmemorypit)
|
||||
downloadmemorypitCheck.grid(column=0, row=2, sticky="w")
|
||||
firmwareLabel = tkinter.Label(topFrame, text = "Select your DSi firmware : ", fg=foregroundColour, font=(buttonFont))
|
||||
firmwareLabel.grid(column=0, row=4, sticky="w")
|
||||
selector = tkinter.OptionMenu(topFrame, firmwareVersion, *dsiVersions)
|
||||
selector.config(bg=buttonColour,fg=foregroundColour,font=(buttonFont))
|
||||
selector["menu"].config(bg=buttonColour,fg=foregroundColour,font=(buttonFont))
|
||||
selector.grid(column=0,row=5,sticky="w")
|
||||
selector.config(bg=buttonColour, fg=foregroundColour, font=(buttonFont))
|
||||
selector["menu"].config(bg=buttonColour, fg=foregroundColour, font=(buttonFont))
|
||||
selector.grid(column=0, row=5, sticky="w")
|
||||
|
||||
backButton = tkinter.Button(bottomFrame,text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow0()], width="8")
|
||||
if platform.system() == "Darwin":
|
||||
macOS_hiddentext = tkinter.Label(topFrame, text = "(Click the area above this text\n if you can't see the drop down menu) ", fg=foregroundColour, font=(bodyFont))
|
||||
macOS_hiddentext.grid(column=0, row=6, sticky="w")
|
||||
|
||||
backButton = Button(bottomFrame,text="Back", font=(buttonFont), fg=foregroundColour, bg=backButtonColour, command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow0()], width=button_width)
|
||||
backButton.pack(side=tkinter.LEFT)
|
||||
nextButton = tkinter.Button(bottomFrame, text="Next",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow2()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
nextButton = Button(bottomFrame, text="Next",width=button_width, fg=foregroundColour, bg=nextButtonColour, font=(buttonFont),command=lambda: [topFrame.destroy(), bottomFrame.destroy(), summonWindow2()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
window.protocol("WM_DELETE_WINDOW", lambda: closeButtonPress(window))
|
||||
|
||||
|
||||
def summonWindow2():
|
||||
|
||||
topFrame = tkinter.Frame(window)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH,padx=5)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH, padx=5)
|
||||
topFrame.option_add("*Background", backgroundColour)
|
||||
bottomFrame = tkinter.Frame(window)
|
||||
bottomFrame.pack(side=tkinter.BOTTOM, fill=tkinter.X,padx=5)
|
||||
@@ -496,12 +485,13 @@ def summonWindow2():
|
||||
updateHiyaCheck.grid(column=0,row=7,sticky="w")
|
||||
buttonExtraHomebrew = tkinter.Button(topFrame, text = "Additional homebrew...", command =lambda:[extraHomebrew(window)], fg=foregroundColour,font=(buttonFont),bg=buttonColour)
|
||||
buttonExtraHomebrew.grid(column=0,row=8,sticky="w",pady=5)
|
||||
backButton = tkinter.Button(bottomFrame,text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow1()], width="8")
|
||||
backButton = Button(bottomFrame,text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow1()], width=button_width)
|
||||
backButton.pack(side=tkinter.LEFT)
|
||||
nextButton = tkinter.Button(bottomFrame, text="Next",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow3()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
nextButton = Button(bottomFrame, text="Next",width=button_width, fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow3()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
|
||||
|
||||
def summonWindow3():
|
||||
topFrame = tkinter.Frame(window)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH,padx=5)
|
||||
@@ -517,18 +507,20 @@ def summonWindow3():
|
||||
noticeLabel.grid(column=0,row=2,sticky="w")
|
||||
SDentry = tkinter.Entry(topFrame, fg=foregroundColour,bg=buttonColour,font=(buttonFont),width=25)
|
||||
SDentry.grid(column=0, row=3,sticky="w")
|
||||
chooseDirButton = tkinter.Button(topFrame, text = "Click to select folder", command =lambda:chooseDir(topFrame,SDentry),fg=foregroundColour,bg=buttonColour,font=(buttonFont),width=25)
|
||||
chooseDirButton = Button(topFrame, text = "Click to select folder", command =lambda:chooseDir(topFrame,SDentry),fg=foregroundColour,bg=buttonColour,font=(buttonFont),width=folder_width)
|
||||
chooseDirButton.grid(column=0, row=4,sticky="w",pady=5)
|
||||
backButton = tkinter.Button(bottomFrame,text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow2()], width="8")
|
||||
backButton = Button(bottomFrame,text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow2()], width=button_width)
|
||||
backButton.pack(side=tkinter.LEFT)
|
||||
nextButton = tkinter.Button(bottomFrame, text="Start",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[globalify(SDentry.get()),topFrame.destroy(),bottomFrame.destroy(),summonWindow4()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
nextButton = Button(bottomFrame, text="Start",width=button_width, fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[globalify(SDentry.get()),topFrame.destroy(),bottomFrame.destroy(),summonWindow4()])
|
||||
nextButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
|
||||
|
||||
def globalify(value):
|
||||
global SDentry
|
||||
SDentry = value
|
||||
|
||||
|
||||
def summonWindow4():
|
||||
startThread = threading.Thread(target=start, daemon=True)
|
||||
topFrame = tkinter.Frame(window)
|
||||
@@ -546,15 +538,15 @@ def summonWindow4():
|
||||
outputBox.grid(column=0,row=2,sticky="w")
|
||||
startThread.start()
|
||||
global finalbackButton
|
||||
finalbackButton = tkinter.Button(bottomFrame,state="disabled", text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow3()], width="8")
|
||||
finalbackButton = Button(bottomFrame,state="disabled", text="Back", font=(buttonFont),fg=foregroundColour,bg=backButtonColour,command=lambda: [topFrame.destroy(),bottomFrame.destroy(),summonWindow3()], width=button_width)
|
||||
finalbackButton.pack(side=tkinter.LEFT)
|
||||
global finalnextButton
|
||||
finalnextButton = tkinter.Button(bottomFrame, state="disabled", text="Finish",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow5()])
|
||||
finalnextButton.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
finalnextButton = Button(bottomFrame, state="disabled", text="Finish",width=button_width, fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),summonWindow5()])
|
||||
finalnextButton.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:donothing)
|
||||
|
||||
def summonWindow5():
|
||||
|
||||
def summonWindow5():
|
||||
topFrame = tkinter.Frame(window)
|
||||
topFrame.pack(expand=True, fill=tkinter.BOTH,padx=5)
|
||||
topFrame.option_add("*Background", backgroundColour)
|
||||
@@ -578,84 +570,87 @@ def summonWindow5():
|
||||
w = w + 1
|
||||
label= tkinter.Label(topFrame,text="Press the Close button to Exit",font=(bodyFont),fg=foregroundColour)
|
||||
label.grid(column=0,row=w+1,sticky="w")
|
||||
finish = tkinter.Button(bottomFrame, text="Close",width="8", fg=foregroundColour,bg=nextButtonColour, font=(buttonFont),command=lambda:[topFrame.destroy(),bottomFrame.destroy(),closeButtonPress(window)])
|
||||
finish.pack(side=tkinter.RIGHT, padx="5", pady="5")
|
||||
finish = Button(bottomFrame, text="Close", width=button_width, fg=foregroundColour, bg=nextButtonColour, font=(buttonFont),command=lambda: [topFrame.destroy(), bottomFrame.destroy(), closeButtonPress(window)])
|
||||
finish.pack(side=tkinter.RIGHT, padx=5, pady=5)
|
||||
window.protocol("WM_DELETE_WINDOW",lambda:closeButtonPress(window))
|
||||
|
||||
|
||||
if(sys.version_info.major < 3):
|
||||
if __name__ == "__main__":
|
||||
if(sys.version_info.major < 3):
|
||||
print("This program will ONLY work on Python 3 and above")
|
||||
sys.exit()
|
||||
os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
|
||||
|
||||
root = tkinter.Tk()
|
||||
window = tkinter.Toplevel(root)
|
||||
root.withdraw()
|
||||
root = tkinter.Tk()
|
||||
window = tkinter.Toplevel(root)
|
||||
root.withdraw()
|
||||
|
||||
#Homebrew Database
|
||||
homebrewDB = json.loads(requests.get('https://raw.githubusercontent.com/YourKalamity/just-a-dsi-DB/master/just-a-dsi-DB.json').content)
|
||||
homebrewList = []
|
||||
for x in homebrewDB:
|
||||
homebrewList.append(tkinter.IntVar())
|
||||
# Homebrew Database
|
||||
homebrewDB = json.loads(requests.get('https://raw.githubusercontent.com/YourKalamity/just-a-dsi-DB/master/just-a-dsi-DB.json').content)
|
||||
homebrewList = []
|
||||
for x in homebrewDB:
|
||||
homebrewList.append(tkinter.IntVar())
|
||||
|
||||
# TKinter Vars
|
||||
downloadmemorypit = tkinter.IntVar(value=1)
|
||||
firmwareVersion = tkinter.StringVar()
|
||||
firmwareVersion.set(dsiVersions[1])
|
||||
downloadtwlmenu = tkinter.IntVar(value=1)
|
||||
downloaddumptool = tkinter.IntVar(value=1)
|
||||
unlaunch = tkinter.IntVar(value=0)
|
||||
godmode9i = tkinter.IntVar(value=0)
|
||||
updateHiyaCFW = tkinter.IntVar(value=0)
|
||||
|
||||
#TKinter Vars
|
||||
downloadmemorypit = tkinter.IntVar(value=1)
|
||||
firmwareVersion = tkinter.StringVar()
|
||||
firmwareVersion.set(dsiVersions[0])
|
||||
downloadtwlmenu = tkinter.IntVar(value=1)
|
||||
downloaddumptool = tkinter.IntVar(value=1)
|
||||
unlaunch = tkinter.IntVar(value=0)
|
||||
godmode9i = tkinter.IntVar(value=0)
|
||||
updateHiyaCFW = tkinter.IntVar(value=0)
|
||||
|
||||
#Fonts
|
||||
titleFont = tkinter.font.Font(
|
||||
family= "Segoe UI",
|
||||
size= 15,
|
||||
weight= "bold"
|
||||
# Fonts
|
||||
titleFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
size=15,
|
||||
weight="bold"
|
||||
)
|
||||
subtitleFont = tkinter.font.Font(
|
||||
family= "Segoe UI",
|
||||
size= 11,
|
||||
slant= "italic"
|
||||
)
|
||||
|
||||
bodyFont = tkinter.font.Font(
|
||||
family= "Segoe UI",
|
||||
underline= False,
|
||||
size = 11
|
||||
subtitleFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
size=11,
|
||||
slant="italic"
|
||||
)
|
||||
bodyFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
underline=False,
|
||||
size=11
|
||||
)
|
||||
buttonFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
underline=False,
|
||||
size=11,
|
||||
weight="bold"
|
||||
)
|
||||
bigListFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
underline=False,
|
||||
size=9
|
||||
)
|
||||
paragraphFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
size=10
|
||||
)
|
||||
buttonFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
underline=False,
|
||||
size = 11,
|
||||
weight = "bold"
|
||||
)
|
||||
|
||||
bigListFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
underline=False,
|
||||
size=9
|
||||
)
|
||||
if platform.system() == "Darwin":
|
||||
from tkmacosx import Button
|
||||
backgroundColour = "#f0f0f0"
|
||||
foregroundColour = "black"
|
||||
buttonColour = "#f0f0f0"
|
||||
backButtonColour = "#f0f0f0"
|
||||
nextButtonColour = "#f0f0f0"
|
||||
button_width = 80
|
||||
folder_width = 250
|
||||
else:
|
||||
from tkinter import Button
|
||||
backgroundColour = "#252a34"
|
||||
foregroundColour = "white"
|
||||
buttonColour = "#7289DA"
|
||||
backButtonColour = "#567487"
|
||||
nextButtonColour = "#027b76"
|
||||
button_width = 8
|
||||
folder_width = 25
|
||||
|
||||
paragraphFont = tkinter.font.Font(
|
||||
family="Segoe UI",
|
||||
size=10
|
||||
)
|
||||
|
||||
if platform.system() == "Darwin": #Why is macOS so difficult...
|
||||
backgroundColour = "#f0f0f0" #How dull and boring
|
||||
foregroundColour = "black"
|
||||
buttonColour = "#f0f0f0"
|
||||
backButtonColour = "#f0f0f0"
|
||||
nextButtonColour = "#f0f0f0"
|
||||
else: #Non Jeve Stobs worshippers
|
||||
backgroundColour = "#252a34"
|
||||
foregroundColour = "white"
|
||||
buttonColour = "#7289DA"
|
||||
backButtonColour = "#567487"
|
||||
nextButtonColour = "#027b76"
|
||||
|
||||
|
||||
summonWindow0()
|
||||
root.mainloop()
|
||||
summonWindow0()
|
||||
root.mainloop()
|
||||
|
||||
37
tkmacosx/__init__.py
Normal file
37
tkmacosx/__init__.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
This module provides some modified widgets of Tkinter which works better on macos
|
||||
and some more useful functions and classes as well. For example Button of tkmacosx which
|
||||
looks and feels exactly like a native tkinter button can change its background
|
||||
and foreground colors.
|
||||
|
||||
Read more about tkmacosx in detail on
|
||||
https://github.com/Saadmairaj/tkmacosx/tree/master/tkmacosx.
|
||||
"""
|
||||
|
||||
__version__ = '0.1.4'
|
||||
|
||||
from tkmacosx.basewidget import check_appearance, get_shade, delta
|
||||
from tkmacosx.variables import ColorVar, DictVar, SaveVar, demo_colorvar, demo_savevar
|
||||
from tkmacosx.widget import Button, CircleButton, SFrame, Marquee, demo_sframe, demo_button, demo_marquee
|
||||
from tkmacosx.colors import Hex, OrderedHex, all_colors, named_colors, hue_color
|
||||
from tkmacosx.colorscale import Colorscale, demo_colorscale, gradient
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_sframe()
|
||||
demo_button()
|
||||
demo_colorvar()
|
||||
demo_colorscale()
|
||||
324
tkmacosx/__main__.py
Normal file
324
tkmacosx/__main__.py
Normal file
@@ -0,0 +1,324 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import random
|
||||
if sys.version_info.major == 2:
|
||||
import ttk
|
||||
import Tkinter as tk
|
||||
import tkFont as font
|
||||
from tkColorChooser import askcolor
|
||||
elif sys.version_info.major == 3:
|
||||
from tkinter import ttk
|
||||
import tkinter as tk
|
||||
import tkinter.font as font
|
||||
from tkinter.colorchooser import askcolor
|
||||
|
||||
from tkmacosx.widget import *
|
||||
from tkmacosx.variables import *
|
||||
from tkmacosx.colorscale import Colorscale
|
||||
from tkmacosx.colors import Hex as C_dict, all_colors
|
||||
|
||||
|
||||
color_list = [list(i.values())[0].get('hex') for i in all_colors]
|
||||
|
||||
|
||||
def grid(root, row, column):
|
||||
"Defines rows and columns if grid method is used"
|
||||
if column:
|
||||
for y in range(column):
|
||||
tk.Grid.columnconfigure(root, y, weight=1)
|
||||
if row:
|
||||
for x in range(row):
|
||||
tk.Grid.rowconfigure(root, x, weight=1)
|
||||
return
|
||||
|
||||
|
||||
def sort_random_values(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
value = fn(*args, **kwargs)
|
||||
if isinstance(value, (list, tuple)) and len(value) == 1:
|
||||
return value[0]
|
||||
return value
|
||||
return wrapper
|
||||
|
||||
|
||||
def choices(seq, k):
|
||||
"Random choices."
|
||||
return tuple(random.choice(seq) for i in range(k))
|
||||
|
||||
|
||||
@sort_random_values
|
||||
def get_random_colors(k=1):
|
||||
return choices(color_list, k=k)
|
||||
|
||||
|
||||
@sort_random_values
|
||||
def get_random_font(k=1):
|
||||
def family(): return random.choice(font.families())
|
||||
|
||||
def weight(): return random.choice(('bold', 'normal'))
|
||||
|
||||
def slant(): return random.choice(('italic', 'roman'))
|
||||
|
||||
def size(): return random.randrange(9, 30)
|
||||
|
||||
def underline(): return random.choice((True, False))
|
||||
|
||||
overstrike = underline
|
||||
return tuple(font.Font(family=family(), weight=weight(),
|
||||
slant=slant(), underline=underline(),
|
||||
overstrike=overstrike(), size=30,) for i in range(k))
|
||||
|
||||
|
||||
@sort_random_values
|
||||
def get_random_size(k=1, start=10, end=200):
|
||||
return tuple(choices([i for i in range(start, end)], k=k))
|
||||
|
||||
|
||||
@sort_random_values
|
||||
def get_random_relief(k=1):
|
||||
return choices(('flat', 'groove', 'raised',
|
||||
'ridge', 'solid', 'sunken'), k=k)
|
||||
|
||||
|
||||
class Sample(tk.Tk):
|
||||
def __init__(self):
|
||||
tk.Tk.__init__(self)
|
||||
self.resizable(0, 0)
|
||||
self.geometry('420x700+300+100')
|
||||
self.title('Mac OSX Button Testing')
|
||||
self.wm_attributes('-modified', 1)
|
||||
self.main_color = ColorVar(value='#ffe6f4')
|
||||
self['bg'] = self.main_color
|
||||
grid(self, 25, 5)
|
||||
self.L1 = tk.Label(self, text='Comparison',
|
||||
bg=self.main_color, font=('', 18, 'bold'))
|
||||
self.L1.grid(row=0, column=0, columnspan=5, sticky='nsew')
|
||||
Button(self, text='Hello').grid(row=1, column=1, sticky='s')
|
||||
ttk.Button(self, text='Hello').grid(row=1, column=3, sticky='s')
|
||||
tk.Button(self, text='Hello').grid(row=1, column=2, sticky='s')
|
||||
tk.Label(self, bg=self.main_color, font=('', 10),
|
||||
text='(Mac OSX)').grid(row=2, column=1, sticky='n',)
|
||||
tk.Label(self, bg=self.main_color, font=('', 10),
|
||||
text='(ttk themed)').grid(row=2, column=3, sticky='n')
|
||||
tk.Label(self, bg=self.main_color, font=('', 10),
|
||||
text='(Default)').grid(row=2, column=2, sticky='n')
|
||||
ttk.Separator(self, orient='vertical').grid(
|
||||
row=3, column=0, columnspan=5, sticky='ew')
|
||||
|
||||
# ------------ Seperator -------------
|
||||
|
||||
# ------------ Demonstration ------------
|
||||
|
||||
self.sfr = SFrame(self, bg=self.main_color)
|
||||
self.sfr.grid(rowspan=27, columnspan=5, sticky='nsew')
|
||||
for i in range(5):
|
||||
self.sfr.grid_columnconfigure(i, weight=1)
|
||||
self.L2 = tk.Label(self.sfr, text='Demonstration',
|
||||
bg=self.main_color, font=('', 20, 'bold'))
|
||||
self.L2.grid(row=1, column=0, columnspan=5,
|
||||
sticky='new', pady=(20, 10))
|
||||
|
||||
# ------------ Active Color ------------
|
||||
|
||||
self.L3 = tk.Label(self.sfr, text='1. Change Active color', bg=self.main_color,
|
||||
font=('', 15, 'bold'))
|
||||
self.L3.grid(row=2, column=0, columnspan=5, sticky='nsew', pady=10)
|
||||
self.L4 = tk.Label(self.sfr, text='The active color can be changed to any gradient color.',
|
||||
bg=self.main_color, font=('', 10))
|
||||
self.L4.grid(row=3, column=0, columnspan=5, sticky='new')
|
||||
self.B1 = Button(self.sfr, text='Press Me', pady=20)
|
||||
self.B1.grid(row=4, column=0, columnspan=5, pady=20)
|
||||
self.C1 = tk.StringVar(value='Select')
|
||||
self.L5 = tk.Label(self.sfr, text='From',
|
||||
bg=self.main_color, font=('', 12))
|
||||
self.L5.grid(row=5, column=1, sticky='nwe')
|
||||
self.Om1 = tk.OptionMenu(self.sfr, self.C1, *C_dict.keys(),
|
||||
command=self.change_active_color)
|
||||
self.Om1.config(bg=self.main_color, width=15)
|
||||
self.Om1.grid(row=6, column=1, sticky='s', pady=(0, 10))
|
||||
for i in range(self.Om1['menu'].index('end')+1):
|
||||
self.Om1['menu'].entryconfig(i, foreground=list(C_dict)[i])
|
||||
self.C2 = tk.StringVar(value='Select')
|
||||
self.L6 = tk.Label(self.sfr, text='To',
|
||||
bg=self.main_color, font=('', 12))
|
||||
self.L6.grid(row=5, column=3, sticky='nwe')
|
||||
self.Om2 = tk.OptionMenu(self.sfr, self.C2, *C_dict.keys(),
|
||||
command=self.change_active_color)
|
||||
self.Om2.config(bg=self.main_color, width=15)
|
||||
self.Om2.grid(row=6, column=3, sticky='s', pady=(0, 10))
|
||||
for i in range(self.Om2['menu'].index('end')+1):
|
||||
self.Om2['menu'].entryconfig(i, foreground=list(C_dict)[i])
|
||||
|
||||
# ------------ Background Color ------------
|
||||
|
||||
# ttk.Separator(self.sfr, orient='vertical').grid(row=6, column=2, columnspan=1, sticky='ew')
|
||||
self.L7 = tk.Label(self.sfr, text='2. Change Background color', bg=self.main_color,
|
||||
font=('', 15, 'bold'))
|
||||
self.L7.grid(row=7, column=0, columnspan=5,
|
||||
sticky='nsew', pady=(50, 0))
|
||||
self.L8 = tk.Label(self.sfr, text='Click on the button to choose the color.',
|
||||
bg=self.main_color, font=('', 10))
|
||||
self.L8.grid(row=8, column=0, columnspan=5, sticky='new', pady=10)
|
||||
|
||||
self.B2 = Button(self.sfr, text='Color me',
|
||||
font=('', 30,), pady=10, padx=10)
|
||||
self.B2.grid(row=9, column=0, columnspan=5, sticky='', pady=20)
|
||||
|
||||
self.B3 = Button(self.sfr, text='Change Background Color',
|
||||
bg='#d0c0ea', borderless=1)
|
||||
self.B3['command'] = lambda: self.B2.config(bg=askcolor()[1])
|
||||
self.B3.grid(row=10, column=0, columnspan=5, sticky='w', pady=10, padx=10)
|
||||
self.B4 = Button(self.sfr, text='Change Foreground Color',
|
||||
bg="#d0c0ea", borderless=1)
|
||||
self.B4['command'] = lambda: self.B2.config(fg=askcolor()[1])
|
||||
self.B4.grid(row=10, column=0, columnspan=5, sticky='e', pady=10, padx=10)
|
||||
|
||||
# ------------ Borderless ------------
|
||||
|
||||
self.L9 = tk.Label(self.sfr, text='3. Switch Between Borderless', bg=self.main_color,
|
||||
font=('', 15, 'bold'))
|
||||
self.L9.grid(row=11, column=0, columnspan=5,
|
||||
sticky='sew', pady=(50, 0))
|
||||
self.L10 = tk.Label(self.sfr, text="""
|
||||
In borderless it will blend with its parent widget background color.
|
||||
Give parameter `borderless = True / False` to use it.""", bg=self.main_color, font=('', 10))
|
||||
self.L10.grid(row=12, column=0, columnspan=5, sticky='new')
|
||||
|
||||
self.B5 = Button(self.sfr, text='No Borders', borderless=1, height=40,
|
||||
bg='#212F3D', fg='white', activebackground=("#EAECEE", "#212F3D"))
|
||||
self.B5.grid(row=13, columnspan=5, pady=(20, 5))
|
||||
|
||||
self.B6 = Button(self.sfr, text='No Borders', borderless=1, height=40,
|
||||
bg='#F7DC6F', fg='#21618C', activebackground=('#B3B6B7', '#58D68D'))
|
||||
self.B6.grid(row=14, columnspan=5, pady=(0, 20))
|
||||
self.var1 = tk.BooleanVar(value=True)
|
||||
self.CB1 = tk.Checkbutton(self.sfr, text='Toggle Borderless', variable=self.var1,
|
||||
bg=self.main_color, command=self.change_borderless_state)
|
||||
self.CB1.grid(row=15, columnspan=5, pady=(0, 10))
|
||||
|
||||
# ------------ Bordercolor ------------
|
||||
|
||||
self.L11 = tk.Label(self.sfr, text='4. Change Bordercolor', bg=self.main_color,
|
||||
font=('', 15, 'bold'))
|
||||
self.L11.grid(row=16, column=0, columnspan=5,
|
||||
sticky='sew', pady=(50, 0))
|
||||
self.L12 = tk.Label(self.sfr, text="Change Bordercolor of the button\nNote: if borderless=True, then the bordercolor won't work.",
|
||||
bg=self.main_color, font=('', 10))
|
||||
self.L12.grid(row=17, column=0, columnspan=5, sticky='new')
|
||||
|
||||
self.B7 = Button(self.sfr, text='Button', pady=10,
|
||||
padx=5, font=('Zapfino', 12, 'bold'))
|
||||
self.B7.grid(row=18, columnspan=5, pady=30)
|
||||
|
||||
self.CS1 = Colorscale(self.sfr, value='hex', mousewheel=1,
|
||||
command=lambda e: self.B7.config(bordercolor=e))
|
||||
self.CS1.grid(row=19, columnspan=5, sticky='ew', padx=10)
|
||||
|
||||
self.CS2 = Colorscale(self.sfr, value='hex', mousewheel=1,
|
||||
gradient=('#FCF6F5', '#990011'),
|
||||
command=lambda e: self.B7.config(bg=e))
|
||||
self.CS2.grid(row=20, columnspan=5, sticky='ew', padx=10, pady=5)
|
||||
|
||||
self.CS3 = Colorscale(self.sfr, value='hex', mousewheel=1,
|
||||
gradient=('green', 'yellow'),
|
||||
command=lambda e: self.B7.config(fg=e))
|
||||
self.CS3.grid(row=21, columnspan=5, sticky='ew', padx=10)
|
||||
|
||||
self.CS4 = Colorscale(self.sfr, value='hex', mousewheel=1,
|
||||
gradient=('pink', 'purple'),
|
||||
command=lambda e: self.B7.config(overforeground=e))
|
||||
self.CS4.grid(row=22, columnspan=5, sticky='ew', padx=10, pady=5)
|
||||
|
||||
# ------------ Random button styling ------------
|
||||
self.L11 = tk.Label(self.sfr, text='5. Button Styling', bg=self.main_color,
|
||||
font=('', 15, 'bold'))
|
||||
self.L11.grid(row=23, column=0, columnspan=5,
|
||||
sticky='sew', pady=(50, 0))
|
||||
self.L12 = tk.Label(self.sfr, text="Press the button to ramdomise the style of the button.",
|
||||
bg=self.main_color, font=('', 10))
|
||||
self.L12.grid(row=24, column=0, columnspan=5, sticky='new')
|
||||
|
||||
self.B10 = Button(self.sfr, text='Button', borderless=1)
|
||||
self.B10.grid(row=25, columnspan=5, pady=20)
|
||||
|
||||
self.B11 = Button(self.sfr, text='Change Style', borderless=1, fg='#21618C',
|
||||
activebackground=('#B3B6B7', '#58D68D'), command=self.change_button_style)
|
||||
self.B11.grid(row=26, columnspan=5, ipady=5)
|
||||
|
||||
self.button_clicks = 1
|
||||
self.Text1 = tk.Text(self.sfr, background=self.main_color, highlightthickness=0,
|
||||
relief='sunken', height=20, bd=2, padx=10)
|
||||
self.Text1.grid(row=27, columnspan=5, pady=20, padx=20)
|
||||
self.sfr._avoid_mousewheel((self.Text1, self.CS1, self.CS2, self.CS3, self.CS4))
|
||||
self.change_button_style()
|
||||
self.update_idletasks()
|
||||
|
||||
def change_active_color(self, *ags):
|
||||
c1 = self.C1.get() if not self.C1.get() == 'Select' else None
|
||||
c2 = self.C2.get() if not self.C2.get() == 'Select' else None
|
||||
self.Om1.config(bg=c1)
|
||||
self.Om2.config(bg=c2)
|
||||
self.B1['activebackground'] = (c1, c2)
|
||||
|
||||
def change_borderless_state(self):
|
||||
if self.var1.get():
|
||||
self.B5['borderless'] = 1
|
||||
self.B6['borderless'] = 1
|
||||
else:
|
||||
self.B5['borderless'] = 0
|
||||
self.B6['borderless'] = 0
|
||||
|
||||
def change_button_style(self):
|
||||
cnf = dict(
|
||||
foreground=get_random_colors(),
|
||||
background=get_random_colors(),
|
||||
activebackground=get_random_colors(2),
|
||||
activeforeground=get_random_colors(),
|
||||
overrelief=get_random_relief(),
|
||||
relief=get_random_relief(),
|
||||
highlightthickness=get_random_size(1, 1, 5),
|
||||
borderwidth=get_random_size(1, 1, 5),
|
||||
font=get_random_font(),
|
||||
highlightbackground=get_random_colors(),
|
||||
focuscolor=get_random_colors(),
|
||||
overbackground=get_random_colors(),
|
||||
overforeground=get_random_colors(),
|
||||
)
|
||||
self.B10.config(**cnf)
|
||||
|
||||
self.Text1.insert('end', '\n\nBUTTON STYLE %s\n\n'%self.button_clicks)
|
||||
for k,v in cnf.items():
|
||||
if k == 'font':
|
||||
self.Text1.insert('end', 'font:\n')
|
||||
for i, j in v.config().items():
|
||||
self.Text1.insert('end', '\t%s\t\t= %s\n' %(i,j))
|
||||
else:
|
||||
self.Text1.insert('end', '%s\t\t\t= %s\n' %(k,v))
|
||||
self.Text1.see('end')
|
||||
self.Text1.insert('end', '\n\n'+'-'*40)
|
||||
self.button_clicks += 1
|
||||
self.sfr['canvas'].yview_moveto('1.0')
|
||||
self.update_idletasks()
|
||||
|
||||
|
||||
def main():
|
||||
"Demonstration of tkmacosx."
|
||||
Sample().mainloop()
|
||||
|
||||
|
||||
# Testing Demo
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1532
tkmacosx/basewidget.py
Normal file
1532
tkmacosx/basewidget.py
Normal file
File diff suppressed because it is too large
Load Diff
1266
tkmacosx/colors.py
Normal file
1266
tkmacosx/colors.py
Normal file
File diff suppressed because it is too large
Load Diff
401
tkmacosx/colorscale.py
Normal file
401
tkmacosx/colorscale.py
Normal file
@@ -0,0 +1,401 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''
|
||||
Newer style colorchoosers for tkinter module.
|
||||
|
||||
Version: 0.1.4
|
||||
'''
|
||||
|
||||
__version__ = "0.1.4"
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
if sys.version_info.major == 2: # For python 2.x
|
||||
import Tkinter as _tk
|
||||
from tkFont import Font
|
||||
import tkFont as font
|
||||
elif sys.version_info.major == 3: # For python 3.x
|
||||
import tkinter as _tk
|
||||
from tkinter import font
|
||||
from tkinter.font import Font
|
||||
|
||||
import colour
|
||||
import tkmacosx.basewidget as tkb
|
||||
|
||||
|
||||
HEX = 'hex'
|
||||
RGB = 'rgb'
|
||||
|
||||
|
||||
def gradient(iteration):
|
||||
"""This function returns a list of HSL values
|
||||
of all the colors in an order."""
|
||||
|
||||
ops = {'+': lambda c, step: min(1.0, c + step),
|
||||
'-': lambda c, step: max(0.0, c - step)}
|
||||
|
||||
index = 0
|
||||
operation = '+'
|
||||
iteration = max(0, iteration-2)
|
||||
rgb, _list = [1.0, 0.0, 0.0], []
|
||||
combo = ((2, 1, 0), (2, 0, 1), (0, 2, 1), (0, 1, 2), (1, 0, 2), (1, 2, 0))
|
||||
step = float(len(combo)) / float(iteration)
|
||||
_list.append('#%02x%02x%02x' % (round(rgb[0]*255),
|
||||
round(rgb[1]*255), round(rgb[2]*255)))
|
||||
for i in range(iteration):
|
||||
if (rgb[combo[index][1]] == 1.0 and operation == '+') or \
|
||||
(rgb[combo[index][1]] == 0.0 and operation == '-'):
|
||||
operation = '-' if operation == '+' else '+'
|
||||
index += 1
|
||||
rgb[combo[index][1]] = ops[operation](rgb[combo[index][1]], step)
|
||||
_list.append('#%02x%02x%02x' % (round(rgb[0]*255),
|
||||
round(rgb[1]*255), round(rgb[2]*255)))
|
||||
_list.append('#%02x%02x%02x' % (round(1.0*255),
|
||||
round(0.0*255), round(0.0*255)))
|
||||
return _list
|
||||
|
||||
|
||||
class Colorscale(tkb._Canvas):
|
||||
"""
|
||||
## Color Scale.
|
||||
This is ColorScale alternate to tkinter's colorchooser.
|
||||
|
||||
### Args:
|
||||
- `value`: Get either 'RGB' or 'HEX'.
|
||||
- `command`: callback function with an argument.
|
||||
- `orient`: Set the orientation.
|
||||
- `mousewheel`: Set mousewheel to scroll marker.
|
||||
- `variable`: Give tkinter variable (`StringVar`).
|
||||
- `showinfo`: Shows hex or rbg while selecting color.
|
||||
- `gradient`: Take tuple of two colors or default.
|
||||
- `showinfodelay`: Delay before the showinfo disappears (in ms).
|
||||
"""
|
||||
|
||||
_features = ('value', 'command', 'orient', 'mousewheel', 'variable', 'showinfo',
|
||||
'showinfodelay', 'gradient',) # add more features
|
||||
|
||||
def __init__(self, master=None, cnf={}, **kw):
|
||||
kw = {k: v for k, v in _tk._cnfmerge(
|
||||
(cnf, kw)).items() if v is not None}
|
||||
self.cnf = {k: kw.pop(k, None)
|
||||
for k in kw.copy() if k in self._features}
|
||||
|
||||
self.cnf['value'] = self.cnf.get('value', 'hex')
|
||||
self.cnf['orient'] = self.cnf.get('orient', 'vertical')
|
||||
self.cnf['gradient'] = self.cnf.get('gradient', 'default')
|
||||
self.cnf['showinfo'] = self.cnf.get('showinfo', True)
|
||||
self.cnf['showinfodelay'] = self.cnf.get('showinfodelay', 1500)
|
||||
|
||||
kw['width'] = kw.get(
|
||||
"width", 250 if 'ver' in self.cnf['orient'] else 30)
|
||||
kw['height'] = kw.get(
|
||||
"height", 30 if 'ver' in self.cnf['orient'] else 250)
|
||||
kw['highlightthickness'] = kw.get('highlightthickness', 0)
|
||||
tkb._Canvas.__init__(self, master=master, cnf={}, **kw)
|
||||
|
||||
# Protected members of the class
|
||||
self._size = (0, 0)
|
||||
self._marker_color = 'black'
|
||||
self._xy = int((self.winfo_reqwidth() if 'ver' in \
|
||||
self['orient'] else self.winfo_reqheight()) / 3)
|
||||
|
||||
binds = [{'className': 'set_size', 'sequence': '<Configure>', 'func': self._set_size},
|
||||
{'className': 'b1_on_motion', 'sequence': '<B1-Motion>',
|
||||
'func': self._move_marker},
|
||||
{'className': 'b1_press', 'sequence': '<Button-1>', 'func': self._move_marker}]
|
||||
tkb._bind(self, *binds)
|
||||
self._set_mousewheel()
|
||||
|
||||
def _set_size(self, evt=None):
|
||||
"""Internal function."""
|
||||
if evt.width == self._size[0] and evt.height == self._size[1]:
|
||||
return
|
||||
self._size = (evt.width, evt.height)
|
||||
self._create_items('create', safe_create=True)
|
||||
|
||||
def _callback(self, color):
|
||||
"""Internal function."""
|
||||
if self.cnf.get('command'):
|
||||
self.cnf['command'](color)
|
||||
if self.cnf.get('variable'):
|
||||
self.cnf['variable'].set(color)
|
||||
|
||||
def _create_items(self, cmd, safe_create=False, **kw):
|
||||
"""Internal function.\n
|
||||
Checks and creates (text, marker,
|
||||
showinfo, gradient lines) items."""
|
||||
|
||||
def check_tag(tag):
|
||||
"""Internal function.\n
|
||||
If `cmd="check"` and the tag does not exist then
|
||||
the tag is created, but if `cmd="create"` and
|
||||
safe_create=True this will delete the tag if exists
|
||||
and creates a new tag with same settings."""
|
||||
if cmd == 'check':
|
||||
c = False
|
||||
elif cmd == 'create':
|
||||
c = True
|
||||
else:
|
||||
raise ValueError(
|
||||
'%s is not a valid command! Takes -create, -check' % cmd)
|
||||
cond1 = bool(not self.find('withtag', tag) or c)
|
||||
cond2 = bool(tag not in kw.get('avoid', []))
|
||||
if safe_create and cond1 and cond2:
|
||||
self.delete(tag)
|
||||
return cond1 and cond2
|
||||
|
||||
ids = []
|
||||
|
||||
if check_tag('gradient'):
|
||||
w, h = self.winfo_width(), self.winfo_height()
|
||||
iteration = w if 'ver' in self.cnf['orient'] else h
|
||||
# iteration -=
|
||||
if self.cnf.get('gradient', 'default') == 'default':
|
||||
color_list = gradient(iteration)
|
||||
elif isinstance(self.cnf.get('gradient'), (list, tuple)):
|
||||
c1 = colour.Color(self.cnf.get('gradient')[0])
|
||||
c2 = colour.Color(self.cnf.get('gradient')[1])
|
||||
color_list = c1.range_to(c2, iteration)
|
||||
elif isinstance(self.cnf.get('gradient'), str):
|
||||
c = colour.Color(self.cnf.get('gradient'))
|
||||
color_list = c.range_to(c, iteration)
|
||||
|
||||
for count, c in enumerate(color_list):
|
||||
if self.cnf['orient'] == 'vertical':
|
||||
ags = (count, -1, count, h)
|
||||
elif self.cnf['orient'] == 'horizontal':
|
||||
ags = (-1, count, w, count)
|
||||
ids.append(self._create('line', ags, {
|
||||
'fill': c, 'tag': 'gradient'}))
|
||||
|
||||
if check_tag('borderline'):
|
||||
w, h = self.winfo_width(), self.winfo_height()
|
||||
borderline_points = kw.get('borderline_points',
|
||||
(1, 1, self.winfo_width()-2,
|
||||
self.winfo_height()-2, 0))
|
||||
ids.append(self.rounded_rect(borderline_points, width=2,
|
||||
outline='#81b3f4', tag='borderline',
|
||||
style='arc'))
|
||||
|
||||
if check_tag('marker'):
|
||||
marker_points = kw.get('marker_points', (
|
||||
self._xy if 'ver' in self.cnf['orient'] else 2,
|
||||
2 if 'ver' in self.cnf['orient'] else self._xy,
|
||||
5 if 'ver' in self.cnf['orient'] else self.winfo_width() - 4,
|
||||
self.winfo_height() - 4 if 'ver' in self.cnf['orient'] else 5,
|
||||
2))
|
||||
ids.append(self.rounded_rect(marker_points, width=2,
|
||||
outline=self._marker_color,
|
||||
tag="marker", style='arc'))
|
||||
|
||||
if check_tag('markerbg'):
|
||||
markerbg_points = kw.get('markerbg_points')
|
||||
cnf = kw.get('markerbg_cnf')
|
||||
if not markerbg_points:
|
||||
return None
|
||||
ids.append(self._rounded(markerbg_points, **cnf))
|
||||
|
||||
if check_tag('info'):
|
||||
info_points = kw.get('info_points')
|
||||
cnf = kw.get('info_cnf')
|
||||
if not info_points:
|
||||
return None
|
||||
ids.append(self._create('text', info_points, cnf))
|
||||
|
||||
return ids
|
||||
|
||||
def _release(self, evt=None):
|
||||
"""Internal function."""
|
||||
self.delete('info', 'markerbg')
|
||||
|
||||
def _move_marker(self, evt, mw=None):
|
||||
"""Internal function."""
|
||||
if mw:
|
||||
evt.x = mw if 'ver' in self.cnf['orient'] else 10
|
||||
evt.y = 10 if 'ver' in self.cnf['orient'] else mw
|
||||
|
||||
self.after_cancel(getattr(self, '_remove_id', ' '))
|
||||
self._remove_id = self.after(self.cnf['showinfodelay'], self._release)
|
||||
|
||||
cond_x = bool(evt.x > 0 and evt.x < self.winfo_width())
|
||||
cond_y = bool(evt.y > 0 and evt.y < self.winfo_height())
|
||||
cond_state = bool(self['state'] not in 'disabled')
|
||||
|
||||
if not (cond_x and cond_y and cond_state):
|
||||
return
|
||||
|
||||
if not mw:
|
||||
self._xy = evt.x if 'ver' in self.cnf['orient'] else evt.y
|
||||
|
||||
c_id = self.find('overlapping', evt.x, evt.y, evt.x, evt.y)
|
||||
hexcode = self.itemcget(c_id[0], 'fill')
|
||||
rgb = [int(i/65535.0*255.0) for i in self.winfo_rgb(hexcode)]
|
||||
self._marker_color = 'black' if (
|
||||
rgb[0]*0.299 + rgb[1]*0.587 + rgb[2]*0.114) > 110 else 'white'
|
||||
|
||||
self._configure(('itemconfigure', 'borderline'),
|
||||
{'outline': hexcode}, None)
|
||||
|
||||
if self.cnf['value'] == "rgb":
|
||||
spacer, spacbg = 65, 55
|
||||
text = ' | '.join([v+':'+str(f)
|
||||
for f, v in zip(rgb, ('R', 'G', 'B'))])
|
||||
self._callback(rgb)
|
||||
elif self.cnf['value'] == "hex":
|
||||
spacer, spacbg = 35, 25
|
||||
text = hexcode
|
||||
self._callback(hexcode)
|
||||
|
||||
ver_cond = evt.x < self.winfo_width() - (spacbg+spacer)\
|
||||
and self['orient'] == 'vertical'
|
||||
hor_cond = evt.y < self.winfo_height() - (spacbg+spacer)\
|
||||
and self['orient'] == 'horizontal'
|
||||
markerbg_points = info_points = ()
|
||||
|
||||
if bool(ver_cond or hor_cond) and self['showinfo']:
|
||||
markerbg_points = (
|
||||
evt.x+spacer - spacbg if 'ver' in self.cnf['orient'] else self.winfo_width()/2-6,
|
||||
self.winfo_height()/2-6 if 'ver' in self.cnf['orient'] else evt.y+spacer-spacbg,
|
||||
evt.x+spacer + spacbg if 'ver' in self.cnf['orient'] else self.winfo_width()/2+7,
|
||||
self.winfo_height()/2+7 if 'ver' in self.cnf['orient'] else evt.y+spacer+spacbg,
|
||||
6)
|
||||
|
||||
info_points = (
|
||||
(evt.x+spacer if 'ver' in self.cnf['orient'] else self.winfo_width()/2,
|
||||
self.winfo_height()/2 if 'ver' in self.cnf['orient'] else evt.y+spacer))
|
||||
|
||||
elif self['showinfo']:
|
||||
markerbg_points = (
|
||||
evt.x-spacer - spacbg if 'ver' in self.cnf['orient'] else self.winfo_width()/2-6,
|
||||
self.winfo_height()/2-6 if 'ver' in self.cnf['orient'] else evt.y-spacer-spacbg,
|
||||
evt.x-spacer +spacbg if 'ver' in self.cnf['orient'] else self.winfo_width()/2+7,
|
||||
self.winfo_height()/2+7 if 'ver' in self.cnf['orient'] else evt.y-spacer+spacbg,
|
||||
6)
|
||||
|
||||
info_points = (
|
||||
(evt.x-spacer if 'ver' in self.cnf['orient'] else self.winfo_width()/2,
|
||||
self.winfo_height()/2 if 'ver' in self.cnf['orient'] else evt.y-spacer))
|
||||
|
||||
markerbg_cnf = {'fill': self._marker_color, 'tag': 'markerbg'}
|
||||
info_cnf = {'angle': 0 if 'ver' in self.cnf['orient'] else 90,
|
||||
'text': text, 'font': Font(size=10), 'tag': "info", 'fill': hexcode}
|
||||
|
||||
self._create_items('create', safe_create=True, avoid=('gradient', 'borderline'),
|
||||
info_points=info_points, markerbg_points=markerbg_points,
|
||||
info_cnf=info_cnf, markerbg_cnf=markerbg_cnf)
|
||||
|
||||
return True
|
||||
|
||||
def _set_mousewheel(self, evt=None):
|
||||
"""Internal function.\n
|
||||
Sets mousewheel scrolling."""
|
||||
|
||||
def on_mousewheel(evt=None):
|
||||
"Internal function."
|
||||
ver_cond = self._xy < self.winfo_width() \
|
||||
and self['orient'] == 'vertical'
|
||||
hor_cond = self._xy < self.winfo_height() \
|
||||
and self['orient'] == 'horizontal'
|
||||
if tkb.delta(evt) <= -1 and (ver_cond or hor_cond):
|
||||
self._xy += 1
|
||||
if not self._move_marker(evt, mw=self._xy):
|
||||
self._xy -= 1
|
||||
if tkb.delta(evt) >= 1 and self._xy > 1:
|
||||
self._xy -= 1
|
||||
if not self._move_marker(evt, mw=self._xy):
|
||||
self._xy += 1
|
||||
|
||||
if self.cnf.get('mousewheel'):
|
||||
tkb._bind(self, className='mousewheel',
|
||||
sequence='<MouseWheel>', func=on_mousewheel)
|
||||
tkb._bind(self, className='mousewheel_x11',
|
||||
sequence='<Button-4>', func=on_mousewheel)
|
||||
tkb._bind(self, className='mousewheel_x11',
|
||||
sequence='<Button-5>', func=on_mousewheel)
|
||||
else:
|
||||
tkb._bind(self, className='mousewheel',
|
||||
sequence='<MouseWheel>')
|
||||
tkb._bind(self, className='mousewheel_x11',
|
||||
sequence='<Button-4>')
|
||||
tkb._bind(self, className='mousewheel_x11',
|
||||
sequence='<Button-5>')
|
||||
|
||||
def _configure(self, cmd, cnf=None, kw=None):
|
||||
"""Internal function."""
|
||||
kw1 = _tk._cnfmerge((cnf, kw))
|
||||
self.cnf.update(
|
||||
{k: kw.pop(k, None) for k in kw1.copy() if k in self._features})
|
||||
self.cnf = {k: v for k, v in self.cnf.copy().items() if v is not None}
|
||||
_return = tkb._Canvas._configure(self, cmd, None, kw1)
|
||||
if _tk._cnfmerge((cnf, kw)).get('gradient'):
|
||||
self._create_items('create', safe_create=True,
|
||||
avoid=('borderline', 'marker',
|
||||
'markerbg', 'info'))
|
||||
self._set_mousewheel()
|
||||
if _return and isinstance(_return, dict):
|
||||
_return.update(self.cnf)
|
||||
return _return
|
||||
|
||||
def cget(self, key):
|
||||
"""Return the resource value for a KEY given as string."""
|
||||
if key in self.cnf.keys():
|
||||
return self.cnf.get(key)
|
||||
return tkb._Canvas.cget(self, key)
|
||||
__getitem__ = cget
|
||||
|
||||
def keys(self):
|
||||
"""Return a list of all resource names of this widget."""
|
||||
return list(sorted(self.config() + self._features))
|
||||
|
||||
def destroy(self):
|
||||
"""Destroy this widget."""
|
||||
self.after_cancel(getattr(self, '_remove_id', ' '))
|
||||
return tkb._Canvas.destroy(self)
|
||||
|
||||
|
||||
# ------------------------------------ #
|
||||
# Testing and demo #
|
||||
# ------------------------------------ #
|
||||
|
||||
def demo_colorscale():
|
||||
from tkmacosx.variables import ColorVar
|
||||
|
||||
root = _tk.Tk()
|
||||
root.title("Tkinter Color Bar")
|
||||
var = ColorVar()
|
||||
_tk.Label(root, text="I am a Label, Hello! :-)",
|
||||
bg=var).pack(padx=10, pady=10)
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('pink', 'purple')).pack(padx=10, pady=10)
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('green', 'yellow')).pack(padx=10, pady=10)
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('purple', 'cyan')).pack(padx=10, pady=10)
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('white', '#89ABE3')).pack(padx=10, pady=10)
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('#5F4B8B', '#E69A8D'), orient='horizontal'
|
||||
).pack(padx=10, pady=10, side='left')
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
gradient=('#990011', '#FCF6F5'), orient='horizontal'
|
||||
).pack(padx=60, pady=10, side='left')
|
||||
Colorscale(root, value='hex', variable=var, mousewheel=1,
|
||||
orient='horizontal').pack(padx=10, pady=10, side='left')
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_colorscale()
|
||||
366
tkmacosx/variables.py
Normal file
366
tkmacosx/variables.py
Normal file
@@ -0,0 +1,366 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
import sys
|
||||
import ast
|
||||
import pickle as pkl
|
||||
|
||||
if sys.version_info.major == 2:
|
||||
import Tkinter as _tk
|
||||
elif sys.version_info.major == 3:
|
||||
import tkinter as _tk
|
||||
|
||||
|
||||
# Modified Misc._options(...) to make ColorVar work with tkinter
|
||||
# {(self, option, tag): (var, cbname)}
|
||||
_all_traces_colorvar = {}
|
||||
|
||||
|
||||
def _colorvar_patch_cget(fn):
|
||||
"""Internal function."""
|
||||
def _patch(self, key):
|
||||
"""Return the resource value for a KEY given as string."""
|
||||
if (self, key) in _all_traces_colorvar:
|
||||
return _all_traces_colorvar[(self, key)][0]
|
||||
return fn(self, key)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_destroy(fn):
|
||||
"""Internal function.\n
|
||||
Deletes the traces if any when widget is destroy."""
|
||||
|
||||
def _patch(self):
|
||||
"""Interanl function."""
|
||||
if self._tclCommands is not None:
|
||||
# Deletes the widget from the _all_traces_colorvar
|
||||
# and deletes the traces too.
|
||||
for key, value in dict(_all_traces_colorvar).items():
|
||||
if self == key[0]:
|
||||
var, cbname = value
|
||||
try: var.trace_vdelete('w', cbname)
|
||||
except: pass
|
||||
_all_traces_colorvar.pop(key)
|
||||
return fn(self)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_configure(fn):
|
||||
"""Internal function.\n
|
||||
Patch for Canvas items to support ColorVar functionality."""
|
||||
|
||||
def _patch(self, cmd, cnf, kw):
|
||||
"""Internal function."""
|
||||
|
||||
cnf = _tk._cnfmerge((cnf, kw))
|
||||
cnf_copy = dict(cnf)
|
||||
# -------------------- Added the below block --------------------
|
||||
# Add the resources to the list to have ColorVar functionality.
|
||||
if isinstance(cmd, tuple) and isinstance(self, _tk.Canvas):
|
||||
tags = self.find('withtag', cmd[1])
|
||||
for tag in tags:
|
||||
for i in ('activefill', 'activeoutline', 'disabledfill',
|
||||
'disabledoutline', 'fill', 'outline', 'background',
|
||||
'activebackground', 'activeforeground',
|
||||
'disabledbackground', 'disabledforeground',
|
||||
'foreground'):
|
||||
if isinstance(cnf_copy.get(i), _tk.Variable):
|
||||
var = cnf_copy[i]
|
||||
cbname = var.trace_variable('w', lambda a, b, c,
|
||||
cls=self, opt=i,
|
||||
tagId=tag, var=var:
|
||||
cls._configure(('itemconfigure',tagId),
|
||||
{opt: var.get()}, None))
|
||||
if (self, (i, tag)) in _all_traces_colorvar:
|
||||
v, cb = _all_traces_colorvar.get((self, (i, tag)))
|
||||
v.trace_vdelete('w', cb)
|
||||
_all_traces_colorvar[(self, (i, tag))] = (var, cbname)
|
||||
else:
|
||||
_all_traces_colorvar[(self, (i, tag))] = (var, cbname)
|
||||
cnf[i] = var.get()
|
||||
return fn(self, cmd, cnf, None)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_options(fn):
|
||||
"""Internal function.\n
|
||||
Patch for ColorVar to work with tkinter widgets."""
|
||||
|
||||
def _patch(self, cnf, kw=None):
|
||||
"""Internal function."""
|
||||
if kw:
|
||||
cnf = _tk._cnfmerge((cnf, kw))
|
||||
else:
|
||||
cnf = _tk._cnfmerge(cnf)
|
||||
|
||||
for i in ('fg', 'foreground', 'bg', 'background',
|
||||
'activebackground', 'activeforeground', 'disabledforeground',
|
||||
'highlightbackground', 'highlightcolor', 'selectforeground',
|
||||
'readonlybackground', 'selectbackground', 'insertbackground',
|
||||
'disabledbackground'):
|
||||
if isinstance(cnf.get(i), _tk.Variable):
|
||||
var = cnf[i]
|
||||
cbname = var.trace_variable('w', lambda a, b, c, i=i, var=var,
|
||||
cls=self: cls.config({i: var.get()}))
|
||||
if (self, i) in _all_traces_colorvar:
|
||||
v, cb = _all_traces_colorvar.get((self, i))
|
||||
v.trace_vdelete('w', cb)
|
||||
_all_traces_colorvar[(self, i)] = (var, cbname)
|
||||
else:
|
||||
_all_traces_colorvar[(self, i)] = (var, cbname)
|
||||
cnf[i] = var.get()
|
||||
# [issue-1] once a ColorVar is assigned, it cannot be removed
|
||||
# untill the widget is destroyed or give another ColorVar
|
||||
# [issue-1] (trial) the below doesn't work as excepted.
|
||||
# elif (self, i) in _all_traces_colorvar:
|
||||
# if self[i] != _all_traces_colorvar[(self, i)][0].get():
|
||||
# print( self, i, self[i])
|
||||
# v, cb = _all_traces_colorvar.pop((self, i))
|
||||
# v.trace_vdelete('w', cb)
|
||||
return fn(self, cnf, None)
|
||||
return _patch
|
||||
|
||||
|
||||
def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={})
|
||||
"""Internal function."""
|
||||
args = _tk._flatten(args)
|
||||
cnf = args[-1]
|
||||
if isinstance(cnf, (dict, tuple)):
|
||||
args = args[:-1]
|
||||
else:
|
||||
cnf = {}
|
||||
|
||||
# -------------------- Added the below block --------------------
|
||||
# Add the resources to the list to have ColorVar functionality.
|
||||
ckw = _tk._cnfmerge((cnf, kw))
|
||||
var = None
|
||||
for i in ('activefill', 'activeoutline', 'disabledfill',
|
||||
'disabledoutline', 'fill', 'outline', 'background',
|
||||
'activebackground', 'activeforeground', 'foreground',
|
||||
'disabledbackground', 'disabledforeground'):
|
||||
if isinstance(ckw.get(i), _tk.Variable):
|
||||
var = ckw[i]
|
||||
_all_traces_colorvar[(self, (i, None))] = (var, None)
|
||||
if isinstance(cnf, dict) and i in cnf:
|
||||
cnf[i] = var.get()
|
||||
elif i in kw:
|
||||
kw[i] = var.get()
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
tagId = self.tk.getint(self.tk.call(
|
||||
self._w, 'create', itemType,
|
||||
*(args + self._options(cnf, kw))))
|
||||
|
||||
for key, value in dict(_all_traces_colorvar).items():
|
||||
if isinstance(key[1], (tuple, list)):
|
||||
wid, (opt, tag_id) = key
|
||||
var, cbname = value
|
||||
if tag_id is None and cbname is None:
|
||||
cbname = var.trace_variable('w', lambda a, b, c,
|
||||
cls=self, opt=opt,
|
||||
tagId=tagId, var=var:
|
||||
cls._configure(('itemconfigure',tagId),
|
||||
{opt: var.get()}, None))
|
||||
_all_traces_colorvar[(self, (opt, tagId))] = (var, cbname)
|
||||
_all_traces_colorvar.pop((self, (opt, None)))
|
||||
return tagId
|
||||
|
||||
|
||||
_tk.Misc.destroy = _colorvar_patch_destroy(_tk.Misc.destroy)
|
||||
_tk.Misc._options = _colorvar_patch_options(_tk.Misc._options)
|
||||
_tk.Misc._configure = _colorvar_patch_configure(_tk.Misc._configure)
|
||||
_tk.Canvas._create = _create
|
||||
|
||||
|
||||
class ColorVar(_tk.Variable):
|
||||
"""Value holder for HEX color. Default is white"""
|
||||
|
||||
_default = "white"
|
||||
_rgbstring = re.compile(r'#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$')
|
||||
|
||||
def __init__(self, master=None, value=None, name=None):
|
||||
"""Construct a color variable. (bg, fg, ..)
|
||||
|
||||
MASTER can be given as master widget.
|
||||
VALUE is an optional value (defaults to "")
|
||||
NAME is an optional Tcl name (defaults to PY_VARnum).
|
||||
|
||||
If NAME matches an existing variable and VALUE is omitted
|
||||
then the existing value is retained.
|
||||
"""
|
||||
_tk.Variable.__init__(self, master, value, name)
|
||||
|
||||
def set(self, value=''):
|
||||
"""Set the variable to VALUE."""
|
||||
if value.startswith('#'):
|
||||
if not bool(self._rgbstring.match(value)):
|
||||
raise ValueError('"{}" is not a valid HEX.'.format(value))
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
r, g, b = self._root.winfo_rgb(value)
|
||||
c = (r/257, g/257, b/257)
|
||||
value = '#%02x%02x%02x' % (int(c[0]), int(c[1]), int(c[2]))
|
||||
except:
|
||||
raise ValueError(
|
||||
'Could not find right HEX for "{}".'.format(value))
|
||||
return self._tk.globalsetvar(self._name, value)
|
||||
initialize = set
|
||||
|
||||
def get(self):
|
||||
"""Return value of variable color."""
|
||||
value = self._tk.globalgetvar(self._name)
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
return str(value)
|
||||
|
||||
|
||||
class DictVar(_tk.Variable):
|
||||
"""
|
||||
#### Value holder for Dictionaries.
|
||||
Get a specific value by getting the key from this \
|
||||
`get(self, key=None, d=None)` method if exists in the dictionary. \n
|
||||
if `key=None` it will return the complete dictionary.
|
||||
"""
|
||||
_default = {}
|
||||
|
||||
def __init__(self, master=None, value=None, name=None):
|
||||
"""Construct a string variable.
|
||||
|
||||
MASTER can be given as master widget.
|
||||
VALUE is an optional value (defaults to {})
|
||||
NAME is an optional Tcl name (defaults to PY_VARnum).
|
||||
|
||||
If NAME matches an existing variable and VALUE is omitted
|
||||
then the existing value is retained.
|
||||
"""
|
||||
_tk.Variable.__init__(self, master, value, name)
|
||||
|
||||
def get(self, key=None, d=None):
|
||||
"""Return value of variable as string."""
|
||||
value = self._tk.globalgetvar(self._name)
|
||||
if not isinstance(value, dict):
|
||||
value = ast.literal_eval(value)
|
||||
if key:
|
||||
return value.get(key, d)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def SaveVar(var, master=None, value=None, name=None, filename='data.pkl'):
|
||||
"""Save tkinter variable data in a pickle file and load the
|
||||
same value when the program is executed next time.
|
||||
|
||||
#### If the content of the file changes, it might not load correct values \
|
||||
to the assigned variables. To avoid this issue use `name` to \
|
||||
refer to the exact assigned values later.
|
||||
|
||||
### Args:
|
||||
- `var`: Give the `tkinter.Variable` class like (`tk.StringVar`, `tk.IntVar`).
|
||||
- `master`: Parent widget.
|
||||
- `value`: Set value.
|
||||
- `name`: Set a name to group variables or to refer to assigned value when loaded.
|
||||
- `filename`: Set the name of the save file. (To make the file invisible in the \
|
||||
directory start the name of the file with "." like ".cache-savevar")
|
||||
|
||||
### Return:
|
||||
- returns the tk.Variable instance passed to `var` argument.
|
||||
|
||||
### Example:
|
||||
root = tk.Tk()
|
||||
var1 = SaveVar(tk.StringVar,'Enter Username','Var1','.cache-savevar')
|
||||
var2 = SaveVar(tk.StringVar,'Enter Password','Var2','.cache-savevar')
|
||||
tk.Entry(root,textvariable=var1).pack()
|
||||
tk.Entry(root,textvariable=var2).pack()
|
||||
root.mainloop()"""
|
||||
|
||||
def update_val(*args):
|
||||
"""Internal function for updating the value for variable"""
|
||||
try: # try/except , if the file doesn't exists.
|
||||
open1 = open(filename, 'rb')
|
||||
tmpdict = pkl.load(open1) # load saved dictionary data.
|
||||
# Block of code to check for the right value.
|
||||
if tmpdict.get(str(var)):
|
||||
old, default = tmpdict.get(str(var))
|
||||
new = var.get()
|
||||
if new != default:
|
||||
var.set(new)
|
||||
elif new == default and not startup[0]:
|
||||
var.set(default)
|
||||
else:
|
||||
var.set(old)
|
||||
tmpdict.update({str(var): (var.get(), defaultval)})
|
||||
open1.close()
|
||||
except Exception as e:
|
||||
tmpdict = {}
|
||||
tmpdict[str(var)] = (var.get(), defaultval)
|
||||
|
||||
open2 = open(filename, 'wb')
|
||||
pkl.dump(tmpdict, open2)
|
||||
startup[0] = False
|
||||
open2.close()
|
||||
|
||||
startup = [True]
|
||||
if not(filename.endswith('.pickle') or filename.endswith('.pkl')) \
|
||||
and not filename.startswith('.'):
|
||||
filename = filename+'.pkl'
|
||||
var = var(master=master, value=value, name=name)
|
||||
defaultval = var.get() # get a default value of the variable
|
||||
update_val()
|
||||
for mode, cbname in (var.trace_vinfo()):
|
||||
if mode[0] == 'w' and update_val.__name__ in cbname:
|
||||
try:
|
||||
var.trace_vdelete('w', cbname)
|
||||
except:
|
||||
pass
|
||||
res = var.trace_variable('w', update_val)
|
||||
return var
|
||||
|
||||
|
||||
# ------------------ Testing ------------------
|
||||
|
||||
def demo_colorvar():
|
||||
import tkmacosx.colors as colors
|
||||
root = _tk.Tk()
|
||||
root.geometry('100x100')
|
||||
color = ColorVar()
|
||||
color_list = list(colors.OrderedHex)
|
||||
L = _tk.Label(root, textvariable=color, bg=color)
|
||||
L.place(relx=0.5, rely=0.5, anchor='center')
|
||||
|
||||
def change_color(c=0):
|
||||
if root.winfo_exists():
|
||||
if c >= len(color_list):
|
||||
c = 0
|
||||
color.set(color_list[c])
|
||||
root.after(100, change_color, c+1)
|
||||
|
||||
change_color()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def demo_savevar():
|
||||
root = _tk.Tk()
|
||||
var1 = SaveVar(_tk.StringVar, root, 'Enter Username',
|
||||
'Var1', '.cache-savevar')
|
||||
var2 = SaveVar(_tk.StringVar, root, 'Enter Password',
|
||||
'Var2', '.cache-savevar')
|
||||
_tk.Entry(root, textvariable=var1).pack()
|
||||
_tk.Entry(root, textvariable=var2).pack()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_colorvar()
|
||||
demo_savevar()
|
||||
251
tkmacosx/widget.py
Normal file
251
tkmacosx/widget.py
Normal file
@@ -0,0 +1,251 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
if sys.version_info.major == 2:
|
||||
import Tkinter as _TK
|
||||
elif sys.version_info.major == 3:
|
||||
import tkinter as _TK
|
||||
import tkmacosx.basewidget as tkb
|
||||
|
||||
|
||||
class SFrame(tkb.SFrameBase):
|
||||
"""### Scrollable Frame ButtonBase.
|
||||
(Only supports vertical scrolling)
|
||||
|
||||
Sames as tkinter Frame. These are some extra resources.
|
||||
- `scrollbarwidth`: Set the width of scrollbar.
|
||||
- `mousewheel`: Set mousewheel scrolling.
|
||||
- `avoidmousewheel`: Give widgets that also have mousewheel scrolling and is a child of SFrame \
|
||||
this will configure widgets to support their mousewheel scrolling as well. \
|
||||
For eg:- Text widget inside SFrame can have mousewheel scrolling as well as SFrame.
|
||||
|
||||
Scrollbar of SFrame can be configured by calling `scrollbar_configure(**options)`.
|
||||
To access methods of the scrollbar it can be called through the scrollbar instance `self['scrollbar']`.
|
||||
|
||||
### How to use?
|
||||
Use it like a normal frame.
|
||||
|
||||
### Example:
|
||||
|
||||
root = Tk()
|
||||
frame = SFrame(root, bg='pink')
|
||||
frame.pack()
|
||||
|
||||
for i in range(100):
|
||||
Button(frame, text='Button %s'%i).pack()
|
||||
|
||||
root.mainloop()
|
||||
"""
|
||||
|
||||
def __init__(self, master=None, cnf={}, **kw):
|
||||
tkb.SFrameBase.__init__(self, master=master, cnf=cnf, **kw)
|
||||
# Extra functions
|
||||
self.scrollbar_configure = self['scrollbar'].configure
|
||||
|
||||
|
||||
class Button(tkb.ButtonBase):
|
||||
"""Button for macos, supports almost all the features of tkinter button,
|
||||
- Looks very similar to ttk Button.
|
||||
- There are few extra features as compared to default Tkinter Button:
|
||||
- To check the list of all the resources. To get an overview about
|
||||
the allowed keyword arguments call the method `keys`.
|
||||
print(Button().keys())
|
||||
|
||||
### Examples:
|
||||
import tkinter as tk
|
||||
import tkmacosx as tkm
|
||||
import tkinter.ttk as ttk
|
||||
|
||||
root = tk.Tk()
|
||||
root.geometry('200x200')
|
||||
tkm.Button(root, text='Mac OSX', bg='lightblue', fg='yellow').pack()
|
||||
tk.Button(root, text='Mac OSX', bg='lightblue', fg='yellow').pack()
|
||||
ttk.Button(root, text='Mac OSX').pack()
|
||||
root.mainloop()
|
||||
|
||||
### Get a cool gradient effect in activebackground color.
|
||||
import tkinter as tk
|
||||
import tkmacosx as tkm
|
||||
|
||||
root = tk.Tk()
|
||||
root.geometry('200x200')
|
||||
tkm.Button(root, text='Press Me!!', activebackground=('pink','blue') ).pack()
|
||||
tkm.Button(root, text='Press Me!!', activebackground=('yellow','green') ).pack()
|
||||
tkm.Button(root, text='Press Me!!', activebackground=('red','blue') ).pack()
|
||||
root.mainloop()"""
|
||||
|
||||
def __init__(self, master=None, cnf={}, **kw):
|
||||
tkb.ButtonBase.__init__(self, 'normal', master, cnf, **kw)
|
||||
|
||||
def invoke(self):
|
||||
"""Invoke the command associated with the button.
|
||||
|
||||
The return value is the return value from the command,
|
||||
or an empty string if there is no command associated with
|
||||
the button. This command is ignored if the button's state
|
||||
is disabled.
|
||||
"""
|
||||
if self['state'] not in ('disable', 'disabled'):
|
||||
return self.cnf['command']() if self.cnf.get('command') else None
|
||||
|
||||
|
||||
class CircleButton(tkb.ButtonBase):
|
||||
"""
|
||||
#### Beta-Disclaimer: Please note that this is a BETA version of this widget. \
|
||||
Issues at https://github.com/Saadmairaj/tkmacosx/issues/new/choose \
|
||||
or email me at saadmairaj@yahoo.in.
|
||||
|
||||
Circle shaped Button supports almost all options of a tkinter button
|
||||
and have some few more useful options such as 'activebackground', overbackground',
|
||||
'overforeground', 'activeimage', 'activeforeground', 'borderless' and much more.
|
||||
|
||||
To check all the configurable options for CircleButton run `print(CircleButton().keys())`.
|
||||
|
||||
Example:
|
||||
```
|
||||
import tkinter as tk
|
||||
import tkmacosx as tkm
|
||||
|
||||
root = tk.Tk()
|
||||
cb = tkm.CircleButton(root, text='Hello')
|
||||
cb.pack()
|
||||
root.mainloop()
|
||||
```
|
||||
"""
|
||||
def __init__(self, master=None, cnf={}, **kw):
|
||||
tkb.ButtonBase.__init__(self, 'circle', master, cnf, **kw)
|
||||
|
||||
def invoke(self):
|
||||
"""Invoke the command associated with the button.
|
||||
|
||||
The return value is the return value from the command,
|
||||
or an empty string if there is no command associated with
|
||||
the button. This command is ignored if the button's state
|
||||
is disabled.
|
||||
"""
|
||||
if self['state'] not in ('disable', 'disabled'):
|
||||
return self.cnf['command']() if self.cnf.get('command') else None
|
||||
|
||||
|
||||
class Marquee(tkb.MarqueeBase):
|
||||
"""Use `Marquee` for creating scrolling text which moves from
|
||||
right to left only if the text does not fit completely.
|
||||
|
||||
### Args:
|
||||
- `text`: Give a string to display.
|
||||
- `font`: Font of the text.
|
||||
- `fg`: Set foreground color of the text.
|
||||
- `fps`: Set fps(frames per seconds).
|
||||
- `left_margin`: Set left margin to make text move further to right before reset.
|
||||
- `initial_delay`: Delay before text start to move.
|
||||
- `end_delay`: Delay before text reset.
|
||||
- `smoothness`: Set the smoothness of the animation.
|
||||
|
||||
### Example:
|
||||
root=tk.Tk()
|
||||
marquee = Marquee(root,
|
||||
text='This text will move from right to left if does not fit the window.')
|
||||
marquee.pack()
|
||||
root.mainloop()
|
||||
|
||||
### To move the text when cursor is over the text then follow the below example.
|
||||
|
||||
text = "Please hover over the text to move it. \
|
||||
This text will move only if the cursor hovers over the text widget".
|
||||
root = tk.Tk()
|
||||
m = tkm.Marquee(root, bg='lightgreen', text=text)
|
||||
m.pack()
|
||||
m.stop(True)
|
||||
m.bind('<Enter>', lambda _: m.play())
|
||||
m.bind('<Leave>', lambda _: m.stop())
|
||||
root.mainloop()
|
||||
"""
|
||||
|
||||
def reset(self):
|
||||
"""Reset the text postion."""
|
||||
self._reset(True)
|
||||
self._stop_state = False
|
||||
|
||||
def stop(self, reset=False):
|
||||
"""Stop the text movement."""
|
||||
if reset:
|
||||
self.reset()
|
||||
self._stop_state = True
|
||||
self.after_cancel(self.after_id)
|
||||
self.after_id = ' '
|
||||
|
||||
def play(self, reset=False):
|
||||
"""Play/continue the text movement."""
|
||||
if not self._stop_state and not reset:
|
||||
return
|
||||
self._stop_state = False
|
||||
if reset:
|
||||
self.reset()
|
||||
self._animate()
|
||||
|
||||
|
||||
# ------------------ Testing ------------------
|
||||
|
||||
|
||||
def demo_button():
|
||||
if sys.version_info.major == 2:
|
||||
import ttk
|
||||
elif sys.version_info.major == 3:
|
||||
from tkinter import ttk
|
||||
root = _TK.Tk()
|
||||
root.title('Mac OSX Button Demo')
|
||||
page_color = '#FFFFC6'
|
||||
root.geometry('300x400')
|
||||
root['bg'] = page_color
|
||||
_TK.Label(root, text='Can you tell the difference?', font=(
|
||||
'', 16, 'bold'), bg=page_color).pack(pady=(20, 5))
|
||||
Button(root, text='Press Me', disabledbackground='red').pack(pady=(0, 5))
|
||||
ttk.Button(root, text="Press Me").pack()
|
||||
_TK.Label(root, text='Change Background Color', font=(
|
||||
'', 16, 'bold'), bg=page_color).pack(pady=(20, 5))
|
||||
Button(root, text='Press Me', bg='pink',
|
||||
activebackground=('pink', 'blue')).pack()
|
||||
_TK.Label(root, text='Blend In', font=('', 16, 'bold'),
|
||||
bg=page_color).pack(pady=(20, 5))
|
||||
Button(root, text='Press Me', bg='yellow', activebackground=(
|
||||
'orange', 'lime'), borderless=1).pack()
|
||||
_TK.Label(root, text='Change bordercolor', font=(
|
||||
'', 16, 'bold'), bg=page_color).pack(pady=(20, 5))
|
||||
Button(root, text='Press Me', bg='red', fg='white',
|
||||
activebackground=('red', 'blue'), bordercolor='blue').pack()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def demo_sframe():
|
||||
root = _TK.Tk()
|
||||
frame = SFrame(root, bg='pink')
|
||||
frame.pack()
|
||||
for i in range(50):
|
||||
Button(frame, text='Button %s' % i, borderless=1).pack()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def demo_marquee():
|
||||
root = _TK.Tk()
|
||||
marquee = Marquee(
|
||||
root, text='This text will move from right to left if does not fit the window.')
|
||||
marquee.pack()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_sframe()
|
||||
demo_button()
|
||||
demo_marquee()
|
||||
Reference in New Issue
Block a user