From 551a19c83b88e269a852f5d93b2a1e3aca531582 Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 1 Mar 2021 22:54:21 +0100 Subject: [PATCH 01/29] Create NumberEntry widget An entry that takes only numbers or calculations and calculates the result of the calculation --- ttkwidgets/numberentry.py | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 ttkwidgets/numberentry.py diff --git a/ttkwidgets/numberentry.py b/ttkwidgets/numberentry.py new file mode 100644 index 00000000..ec69b6f3 --- /dev/null +++ b/ttkwidgets/numberentry.py @@ -0,0 +1,91 @@ +""" +Author: rdbende +License: GNU GPLv3 +Copyright (c) 2021 rdbende +""" + +import tkinter as tk +from tkinter import ttk + + +class NumberEntry(ttk.Entry): + """ + An entry that takes only numbers or calculations and calculates the result of the calculation + + :param expressions: Allow the use of expressions (default is True) + :type expressions: bool + + :param roundto: The number of decimals in the result (default is 0) + :type roundto: int + """ + + + def __init__(self, master, **kwargs): + + + self._expr = kwargs.pop("expressions", True) + self._round = kwargs.pop("roundto", 0) + ttk.Entry.__init__(self, master, **kwargs) + self.bind("", self._eval) + self.bind("", self._eval) + self.bind("", self._check) + + + def _eval(self, *args): + current = self.get() + try: + if len(current) > 0: + if int(self._round) == 0: + result = int(round(eval(current), 0)) + self.delete(0, "end") + self.insert(0, result) + else: + result = round(float(eval(current)), self._round) + self.delete(0, "end") + self.insert(0, result) + except SyntaxError: + self.delete(0, "end") + self.insert(0, "SyntaxError") + self.select_range(0, "end") + except ZeroDivisionError: + self.delete(0, "end") + self.insert(0, "ZeroDivisionError") + self.select_range(0, "end") + + + def _check(self, *args): + typed = self.get() + if not typed == "SyntaxError" and not typed == "ZeroDivisionError": + checked = self._replace(typed) + self.delete(0, "end") + self.insert(0, checked) + + + def _replace(self, typed) -> str: + if self._expr: + allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "%", "."] + else: + allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."] + for current in typed: + if not current in allowed: + typed = typed.replace(current, "") + return typed + + + def cget(self, key): + """Return the resource value for a KEY given as string""" + if key == "expressions": + return self._expr + elif key == "roundto": + return self._round + else: + return ttk.Entry.cget(self, key) + + + def keys(self): + """Return a list of all resource names of this widget""" + keys = ttk.Entry.keys(self) + keys.extend(["expressions", "roundto"]) + keys = sorted(keys) + return keys + From a6db0b37d142b00b5c39b74d86daf05411a3bdce Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 1 Mar 2021 22:55:48 +0100 Subject: [PATCH 02/29] Change the default hover-cursor to hand2 Change the default hover-cursor from hand1 to hand2 --- ttkwidgets/linklabel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttkwidgets/linklabel.py b/ttkwidgets/linklabel.py index f1f4f730..7af88e78 100644 --- a/ttkwidgets/linklabel.py +++ b/ttkwidgets/linklabel.py @@ -29,7 +29,7 @@ def __init__(self, master=None, **kwargs): :type clicked_color: str :param kwargs: options to be passed on to the :class:`ttk.Label` initializer """ - self._cursor = kwargs.pop("cursor", "hand1") + self._cursor = kwargs.pop("cursor", "hand2") self._link = kwargs.pop("link", "") self._normal_color = kwargs.pop("normal_color", "#0563c1") self._hover_color = kwargs.pop("hover_color", "#057bc1") From 7611f2a1ffbe6639825e7ab81e3ece98b9209d27 Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 1 Mar 2021 22:57:11 +0100 Subject: [PATCH 03/29] Change the movement cursor to fleur Change the movement cursor from exchange to fleur --- ttkwidgets/itemscanvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttkwidgets/itemscanvas.py b/ttkwidgets/itemscanvas.py index ea7bb128..06f210e9 100644 --- a/ttkwidgets/itemscanvas.py +++ b/ttkwidgets/itemscanvas.py @@ -113,7 +113,7 @@ def left_motion(self, event): return item = results[0] rectangle = self.items[item] - self.config(cursor="exchange") + self.config(cursor="fleur") self.canvas.itemconfigure(item, fill="blue") xc, yc = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) dx, dy = xc - self.current_coords[0], yc - self.current_coords[1] From 61a46c5f7d20764776a084e8dacdb3c4bc7e39f1 Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 1 Mar 2021 22:58:07 +0100 Subject: [PATCH 04/29] Add NumberEntry to __init__.py --- ttkwidgets/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ttkwidgets/__init__.py b/ttkwidgets/__init__.py index 2360b89c..f8d9f0f7 100644 --- a/ttkwidgets/__init__.py +++ b/ttkwidgets/__init__.py @@ -11,6 +11,7 @@ from ttkwidgets.timeline import TimeLine from ttkwidgets.tickscale import TickScale from ttkwidgets.table import Table +from ttkwidgets.numberentry import NumberEntry from ttkwidgets.validated_entries.numbers import ( PercentEntry, IntEntry, FloatEntry, From 8941ab3e8bbb4e7be37413d464041636bb51008b Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 2 Mar 2021 18:33:27 +0100 Subject: [PATCH 05/29] Fixed portability issues Change the default cursor to use the native link pointer on Mac and Windows --- ttkwidgets/linklabel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ttkwidgets/linklabel.py b/ttkwidgets/linklabel.py index 7af88e78..10cb31fd 100644 --- a/ttkwidgets/linklabel.py +++ b/ttkwidgets/linklabel.py @@ -29,7 +29,12 @@ def __init__(self, master=None, **kwargs): :type clicked_color: str :param kwargs: options to be passed on to the :class:`ttk.Label` initializer """ - self._cursor = kwargs.pop("cursor", "hand2") + if root.tk.call('tk', 'windowingsystem') == 'win32': + self._cursor = kwargs.pop("cursor", "hand2") # Native Windows hand pointer + elif root.tk.call('tk', 'windowingsystem') == 'aqua': + self._cursor = kwargs.pop("cursor", "pointinghand") # Native Mac hand pointer + else: + self._cursor = kwargs.pop("cursor", "hand1") self._link = kwargs.pop("link", "") self._normal_color = kwargs.pop("normal_color", "#0563c1") self._hover_color = kwargs.pop("hover_color", "#057bc1") From 8488995fd0d8ef26616a16c8a2cafc8462cd3dd3 Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 09:31:12 +0100 Subject: [PATCH 06/29] Restore cursor --- ttkwidgets/itemscanvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttkwidgets/itemscanvas.py b/ttkwidgets/itemscanvas.py index 06f210e9..ea7bb128 100644 --- a/ttkwidgets/itemscanvas.py +++ b/ttkwidgets/itemscanvas.py @@ -113,7 +113,7 @@ def left_motion(self, event): return item = results[0] rectangle = self.items[item] - self.config(cursor="fleur") + self.config(cursor="exchange") self.canvas.itemconfigure(item, fill="blue") xc, yc = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) dx, dy = xc - self.current_coords[0], yc - self.current_coords[1] From 8b614d2ce7da363483c3aacc19ba7e621082c5c9 Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 09:32:19 +0100 Subject: [PATCH 07/29] Restore linklabel --- ttkwidgets/linklabel.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ttkwidgets/linklabel.py b/ttkwidgets/linklabel.py index 10cb31fd..f1f4f730 100644 --- a/ttkwidgets/linklabel.py +++ b/ttkwidgets/linklabel.py @@ -29,12 +29,7 @@ def __init__(self, master=None, **kwargs): :type clicked_color: str :param kwargs: options to be passed on to the :class:`ttk.Label` initializer """ - if root.tk.call('tk', 'windowingsystem') == 'win32': - self._cursor = kwargs.pop("cursor", "hand2") # Native Windows hand pointer - elif root.tk.call('tk', 'windowingsystem') == 'aqua': - self._cursor = kwargs.pop("cursor", "pointinghand") # Native Mac hand pointer - else: - self._cursor = kwargs.pop("cursor", "hand1") + self._cursor = kwargs.pop("cursor", "hand1") self._link = kwargs.pop("link", "") self._normal_color = kwargs.pop("normal_color", "#0563c1") self._hover_color = kwargs.pop("hover_color", "#057bc1") From 9584d3f36941a6aa89ac3dbe70d36f6032bdb6ee Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 10:03:30 +0100 Subject: [PATCH 08/29] Add __getitem__, __setitem__ and configure Add __getitem__, __setitem__, config and configure, docstring formatting --- ttkwidgets/numberentry.py | 40 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/ttkwidgets/numberentry.py b/ttkwidgets/numberentry.py index ec69b6f3..dfef7310 100644 --- a/ttkwidgets/numberentry.py +++ b/ttkwidgets/numberentry.py @@ -11,27 +11,31 @@ class NumberEntry(ttk.Entry): """ An entry that takes only numbers or calculations and calculates the result of the calculation - - :param expressions: Allow the use of expressions (default is True) - :type expressions: bool - - :param roundto: The number of decimals in the result (default is 0) - :type roundto: int """ - - - def __init__(self, master, **kwargs): - + def __init__(self, master=None, **kwargs): + """ + Create a NumberEntry + :param expressions: Allow the use of expressions (default is True) + :type expressions: bool + :param roundto: The number of decimals in the result (default is 0) + :type roundto: int + """ self._expr = kwargs.pop("expressions", True) self._round = kwargs.pop("roundto", 0) ttk.Entry.__init__(self, master, **kwargs) self.bind("", self._eval) self.bind("", self._eval) self.bind("", self._check) - + + def __getitem__(self, key): + return self.cget(key) + + def __setitem__(self, key, value): + self.configure(**{key: value}) def _eval(self, *args): + """Calculate the result of the entered calculation""" current = self.get() try: if len(current) > 0: @@ -52,7 +56,6 @@ def _eval(self, *args): self.insert(0, "ZeroDivisionError") self.select_range(0, "end") - def _check(self, *args): typed = self.get() if not typed == "SyntaxError" and not typed == "ZeroDivisionError": @@ -60,8 +63,8 @@ def _check(self, *args): self.delete(0, "end") self.insert(0, checked) - def _replace(self, typed) -> str: + """Delete the not allowed characters""" if self._expr: allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "%", "."] else: @@ -70,7 +73,14 @@ def _replace(self, typed) -> str: if not current in allowed: typed = typed.replace(current, "") return typed - + + def configure(self, **kwargs): + """Configure resources of the widget.""" + self._expr = kwargs.pop("expressions", True) + self._round = kwargs.pop("roundto", 0) + ttk.Entry.configure(self, **kwargs) + + config = configure def cget(self, key): """Return the resource value for a KEY given as string""" @@ -81,11 +91,9 @@ def cget(self, key): else: return ttk.Entry.cget(self, key) - def keys(self): """Return a list of all resource names of this widget""" keys = ttk.Entry.keys(self) keys.extend(["expressions", "roundto"]) keys = sorted(keys) return keys - From af423609e1248373b11443eb6cd1c73e66ef71a9 Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 10:20:29 +0100 Subject: [PATCH 09/29] Update AUTHORS.md --- AUTHORS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 1b80c6ff..2d96264b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -27,5 +27,7 @@ This file contains a list of all the authors of widgets in this repository. Plea * `AutocompleteEntryListbox` - [Dogeek](https://github.com/Dogeek) * `validated_entries` submodule +- [rdbende](https://github.com/Dogeek) + * `NumberEntry` - Multiple authors: * `ScaleEntry` (RedFantom and Juliette Monsel) From a4af5668769e0c1e3a491d036e9f429a4b97b4bd Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 10:24:43 +0100 Subject: [PATCH 10/29] Create example for NumberEntry --- examples/example_numberentry.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 examples/example_numberentry.py diff --git a/examples/example_numberentry.py b/examples/example_numberentry.py new file mode 100644 index 00000000..d46d9e8b --- /dev/null +++ b/examples/example_numberentry.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) rdbende 2021 +# For license see LICENSE + +from ttkwidgets import NumberEntry +import tkinter as tk + +root = tk.Tk() +root.title('NumberEntry') + +NumberEntry(root, expressions=True, roundto=4).pack(pady=30) + +root.mainloop() From 439323ee87e87e5d8ea7a5c4dda99ec5236a8474 Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 10:50:14 +0100 Subject: [PATCH 11/29] Create unittest for NumberEntry --- tests/test_numberentry.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_numberentry.py diff --git a/tests/test_numberentry.py b/tests/test_numberentry.py new file mode 100644 index 00000000..6e421775 --- /dev/null +++ b/tests/test_numberentry.py @@ -0,0 +1,41 @@ +# Copyright (c) rdbende 2021 +# For license see LICENSE + +from ttkwidgets import NumberEntry +from tests import BaseWidgetTest +import tkinter as tk + + +class TestNumberEntry(BaseWidgetTest): + def test_numberentry_init(self): + entry = NumberEntry(self.window, expressions=True, roundto=4) + entry.pack() + self.window.update() + + def test_numberentry_events(self): + entry = NumberEntry(self.window, expressions=True, roundto=4) + entry.pack() + self.window.update() + entry.insert(0, "1+2-3*4/5**6") + self.window.update() + entry._check() + self.window.update() + entry._replace("1+2-3*4/5**6") + self.window.update() + entry._eval() + self.window.update() + + def test_numberentry_config(self): + entry = NumberEntry(self.window, expressions=True, roundto=4) + entry.pack() + self.window.update() + entry.keys() + self.window.update() + entry.configure(expressions=False, roundto=0) + self.window.update() + entry.cget("expressions") + self.window.update() + value = entry["roundto"] + self.window.update() + entry["roundto"] = 4 + self.window.update() From 19f361e044aacdfc5ab0e2f87936d6ccc370502c Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 10:59:21 +0100 Subject: [PATCH 12/29] Add NumberEntry to sphinx documentation --- docs/source/ttkwidgets/ttkwidgets.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/ttkwidgets/ttkwidgets.rst b/docs/source/ttkwidgets/ttkwidgets.rst index 21543502..65bef4a9 100644 --- a/docs/source/ttkwidgets/ttkwidgets.rst +++ b/docs/source/ttkwidgets/ttkwidgets.rst @@ -17,6 +17,7 @@ ttkwidgets DebugWindow ItemsCanvas LinkLabel + NumberEntry ScaleEntry ScrolledListbox Table From acdbec576364ceb875536d2eabcf4f5144ac88b6 Mon Sep 17 00:00:00 2001 From: rdbende Date: Tue, 9 Mar 2021 14:59:21 +0100 Subject: [PATCH 13/29] Update AUTHORS.md --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 2d96264b..5aa5cfb0 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -27,7 +27,7 @@ This file contains a list of all the authors of widgets in this repository. Plea * `AutocompleteEntryListbox` - [Dogeek](https://github.com/Dogeek) * `validated_entries` submodule -- [rdbende](https://github.com/Dogeek) +- [rdbende](https://github.com/rdbende) * `NumberEntry` - Multiple authors: * `ScaleEntry` (RedFantom and Juliette Monsel) From fb2dd121122afc866508164b756007ce96c6bdb9 Mon Sep 17 00:00:00 2001 From: rdbende Date: Thu, 11 Mar 2021 11:41:05 +0100 Subject: [PATCH 14/29] Fixed fatal config bug --- ttkwidgets/numberentry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ttkwidgets/numberentry.py b/ttkwidgets/numberentry.py index dfef7310..0d329420 100644 --- a/ttkwidgets/numberentry.py +++ b/ttkwidgets/numberentry.py @@ -76,8 +76,8 @@ def _replace(self, typed) -> str: def configure(self, **kwargs): """Configure resources of the widget.""" - self._expr = kwargs.pop("expressions", True) - self._round = kwargs.pop("roundto", 0) + self._expr = kwargs.pop("expressions", self._expr) + self._round = kwargs.pop("roundto", self._round) ttk.Entry.configure(self, **kwargs) config = configure From e5d60f33b188b36b0cbc7f8b4ac04877dcf44104 Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 22 Mar 2021 17:27:48 +0100 Subject: [PATCH 15/29] Update __init__.py --- ttkwidgets/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ttkwidgets/__init__.py b/ttkwidgets/__init__.py index f8d9f0f7..2360b89c 100644 --- a/ttkwidgets/__init__.py +++ b/ttkwidgets/__init__.py @@ -11,7 +11,6 @@ from ttkwidgets.timeline import TimeLine from ttkwidgets.tickscale import TickScale from ttkwidgets.table import Table -from ttkwidgets.numberentry import NumberEntry from ttkwidgets.validated_entries.numbers import ( PercentEntry, IntEntry, FloatEntry, From de2d5c23ff025895ced00f9c9c9b73179edd240e Mon Sep 17 00:00:00 2001 From: rdbende Date: Mon, 22 Mar 2021 17:28:52 +0100 Subject: [PATCH 16/29] Update __init__.py --- ttkwidgets/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ttkwidgets/__init__.py b/ttkwidgets/__init__.py index 2360b89c..f8d9f0f7 100644 --- a/ttkwidgets/__init__.py +++ b/ttkwidgets/__init__.py @@ -11,6 +11,7 @@ from ttkwidgets.timeline import TimeLine from ttkwidgets.tickscale import TickScale from ttkwidgets.table import Table +from ttkwidgets.numberentry import NumberEntry from ttkwidgets.validated_entries.numbers import ( PercentEntry, IntEntry, FloatEntry, From d2fa5e669d9faa414024b17ca3fdc8fe3160fa16 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 21:50:51 +0100 Subject: [PATCH 17/29] Update ttkwidgets.rst --- docs/source/ttkwidgets/ttkwidgets.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/ttkwidgets/ttkwidgets.rst b/docs/source/ttkwidgets/ttkwidgets.rst index 65bef4a9..21543502 100644 --- a/docs/source/ttkwidgets/ttkwidgets.rst +++ b/docs/source/ttkwidgets/ttkwidgets.rst @@ -17,7 +17,6 @@ ttkwidgets DebugWindow ItemsCanvas LinkLabel - NumberEntry ScaleEntry ScrolledListbox Table From 28d339cdad69cbab31ed908429ecea42f047ce7c Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 21:51:18 +0100 Subject: [PATCH 18/29] Update __init__.py --- ttkwidgets/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ttkwidgets/__init__.py b/ttkwidgets/__init__.py index f8d9f0f7..2360b89c 100644 --- a/ttkwidgets/__init__.py +++ b/ttkwidgets/__init__.py @@ -11,7 +11,6 @@ from ttkwidgets.timeline import TimeLine from ttkwidgets.tickscale import TickScale from ttkwidgets.table import Table -from ttkwidgets.numberentry import NumberEntry from ttkwidgets.validated_entries.numbers import ( PercentEntry, IntEntry, FloatEntry, From d7891cb0c8d97deec0e9386db5e6e188cbec0ad6 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 21:51:47 +0100 Subject: [PATCH 19/29] Update AUTHORS.md --- AUTHORS.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 5aa5cfb0..1b80c6ff 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -27,7 +27,5 @@ This file contains a list of all the authors of widgets in this repository. Plea * `AutocompleteEntryListbox` - [Dogeek](https://github.com/Dogeek) * `validated_entries` submodule -- [rdbende](https://github.com/rdbende) - * `NumberEntry` - Multiple authors: * `ScaleEntry` (RedFantom and Juliette Monsel) From e98f4163cd6d68ec6161662fc92429f2d95c7d51 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:02:44 +0100 Subject: [PATCH 20/29] Delete test_numberentry.py --- tests/test_numberentry.py | 41 --------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 tests/test_numberentry.py diff --git a/tests/test_numberentry.py b/tests/test_numberentry.py deleted file mode 100644 index 6e421775..00000000 --- a/tests/test_numberentry.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) rdbende 2021 -# For license see LICENSE - -from ttkwidgets import NumberEntry -from tests import BaseWidgetTest -import tkinter as tk - - -class TestNumberEntry(BaseWidgetTest): - def test_numberentry_init(self): - entry = NumberEntry(self.window, expressions=True, roundto=4) - entry.pack() - self.window.update() - - def test_numberentry_events(self): - entry = NumberEntry(self.window, expressions=True, roundto=4) - entry.pack() - self.window.update() - entry.insert(0, "1+2-3*4/5**6") - self.window.update() - entry._check() - self.window.update() - entry._replace("1+2-3*4/5**6") - self.window.update() - entry._eval() - self.window.update() - - def test_numberentry_config(self): - entry = NumberEntry(self.window, expressions=True, roundto=4) - entry.pack() - self.window.update() - entry.keys() - self.window.update() - entry.configure(expressions=False, roundto=0) - self.window.update() - entry.cget("expressions") - self.window.update() - value = entry["roundto"] - self.window.update() - entry["roundto"] = 4 - self.window.update() From a386adfa52894938c31faf684c78d1da97735d68 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:03:27 +0100 Subject: [PATCH 21/29] Delete example_numberentry.py --- examples/example_numberentry.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 examples/example_numberentry.py diff --git a/examples/example_numberentry.py b/examples/example_numberentry.py deleted file mode 100644 index d46d9e8b..00000000 --- a/examples/example_numberentry.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) rdbende 2021 -# For license see LICENSE - -from ttkwidgets import NumberEntry -import tkinter as tk - -root = tk.Tk() -root.title('NumberEntry') - -NumberEntry(root, expressions=True, roundto=4).pack(pady=30) - -root.mainloop() From 7806feef9edf24bf6805ac62d5570b785c07796e Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:04:51 +0100 Subject: [PATCH 22/29] Delete numberentry.py --- ttkwidgets/numberentry.py | 99 --------------------------------------- 1 file changed, 99 deletions(-) delete mode 100644 ttkwidgets/numberentry.py diff --git a/ttkwidgets/numberentry.py b/ttkwidgets/numberentry.py deleted file mode 100644 index 0d329420..00000000 --- a/ttkwidgets/numberentry.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Author: rdbende -License: GNU GPLv3 -Copyright (c) 2021 rdbende -""" - -import tkinter as tk -from tkinter import ttk - - -class NumberEntry(ttk.Entry): - """ - An entry that takes only numbers or calculations and calculates the result of the calculation - """ - def __init__(self, master=None, **kwargs): - """ - Create a NumberEntry - - :param expressions: Allow the use of expressions (default is True) - :type expressions: bool - :param roundto: The number of decimals in the result (default is 0) - :type roundto: int - """ - self._expr = kwargs.pop("expressions", True) - self._round = kwargs.pop("roundto", 0) - ttk.Entry.__init__(self, master, **kwargs) - self.bind("", self._eval) - self.bind("", self._eval) - self.bind("", self._check) - - def __getitem__(self, key): - return self.cget(key) - - def __setitem__(self, key, value): - self.configure(**{key: value}) - - def _eval(self, *args): - """Calculate the result of the entered calculation""" - current = self.get() - try: - if len(current) > 0: - if int(self._round) == 0: - result = int(round(eval(current), 0)) - self.delete(0, "end") - self.insert(0, result) - else: - result = round(float(eval(current)), self._round) - self.delete(0, "end") - self.insert(0, result) - except SyntaxError: - self.delete(0, "end") - self.insert(0, "SyntaxError") - self.select_range(0, "end") - except ZeroDivisionError: - self.delete(0, "end") - self.insert(0, "ZeroDivisionError") - self.select_range(0, "end") - - def _check(self, *args): - typed = self.get() - if not typed == "SyntaxError" and not typed == "ZeroDivisionError": - checked = self._replace(typed) - self.delete(0, "end") - self.insert(0, checked) - - def _replace(self, typed) -> str: - """Delete the not allowed characters""" - if self._expr: - allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "%", "."] - else: - allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."] - for current in typed: - if not current in allowed: - typed = typed.replace(current, "") - return typed - - def configure(self, **kwargs): - """Configure resources of the widget.""" - self._expr = kwargs.pop("expressions", self._expr) - self._round = kwargs.pop("roundto", self._round) - ttk.Entry.configure(self, **kwargs) - - config = configure - - def cget(self, key): - """Return the resource value for a KEY given as string""" - if key == "expressions": - return self._expr - elif key == "roundto": - return self._round - else: - return ttk.Entry.cget(self, key) - - def keys(self): - """Return a list of all resource names of this widget""" - keys = ttk.Entry.keys(self) - keys.extend(["expressions", "roundto"]) - keys = sorted(keys) - return keys From 84bcf10c8ab09d0def9405123a5c16306c14c22c Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:18:56 +0100 Subject: [PATCH 23/29] Update functions.py --- ttkwidgets/color/functions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ttkwidgets/color/functions.py b/ttkwidgets/color/functions.py index 57680d29..c0a1aa08 100644 --- a/ttkwidgets/color/functions.py +++ b/ttkwidgets/color/functions.py @@ -35,9 +35,11 @@ import colorsys -PALETTE = ("red", "dark red", "orange", "yellow", "green", "lightgreen", "blue", - "royal blue", "sky blue", "purple", "magenta", "pink", "black", - "white", "gray", "saddle brown", "lightgray", "wheat") +PALETTE = ("white", "black", "lightgray", "gray", + "wheat", "saddle brown", "yellow", "orange", + "red", "red4", "violet", "purple", + "pink", "magenta", "cornflower blue", "blue", + "lightgreen", "green") # in some python versions round returns a float instead of an int From af455328e0bc15587ce629d1d2651f26e2925eb0 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:35:02 +0100 Subject: [PATCH 24/29] Update colorpicker.py --- ttkwidgets/color/colorpicker.py | 224 +++++++++++++++++--------------- 1 file changed, 121 insertions(+), 103 deletions(-) diff --git a/ttkwidgets/color/colorpicker.py b/ttkwidgets/color/colorpicker.py index 4c2ae13b..70bca82b 100644 --- a/ttkwidgets/color/colorpicker.py +++ b/ttkwidgets/color/colorpicker.py @@ -5,6 +5,7 @@ Source: https://github.com/j4321/tkColorPicker Edited by RedFantom for Python 2/3 cross-compatibility and docstring formatting +Edited by rdbende translations, and reliefs tkcolorpicker - Alternative to colorchooser for Tkinter. @@ -26,7 +27,6 @@ Colorpicker dialog """ - from PIL import ImageTk from .functions import tk, ttk, round2, create_checkered_image, \ overlay, PALETTE, hsv_to_rgb, hexa_to_rgb, rgb_to_hexa, col2hue, rgb_to_hsv @@ -40,22 +40,40 @@ # --- Translation -EN = {} +EN = {"Red": "Red", "Green": "Green", "Blue": "Blue", + "Hue": "Hue", "Saturation": "Saturation", "Value": "Value", + "Cancel": "Cancel", "Color Chooser": "Color Chooser", + "Alpha": "Alpha"} + FR = {"Red": "Rouge", "Green": "Vert", "Blue": "Bleu", "Hue": "Teinte", "Saturation": "Saturation", "Value": "Valeur", "Cancel": "Annuler", "Color Chooser": "Sélecteur de couleur", "Alpha": "Alpha"} +DE = {"Red": "Rot", "Green": "Grün", "Blue": "Blau", + "Hue": "Farbton", "Saturation": "Sättigung", "Value": "Farbwert", + "Cancel": "Abbrechen", "Color Chooser": "Farbwähler", + "Alpha": "Alpha"} + +HU = {"Red": "Vörös", "Green": "Zöld", "Blue": "Kék", + "Hue": "Árnyalat", "Saturation": "Telítettség", "Value": "Érték", + "Cancel": "Mégse", "Color Chooser": "Színválasztó", + "Alpha": "Alfa"} + try: - if getdefaultlocale()[0][:2] == 'fr': + if getdefaultlocale()[0][:2] == "fr": TR = FR + elif getdefaultlocale()[0][:2] == "de": + TR = DE + elif getdefaultlocale()[0][:2] == "hu": + TR = EN else: TR = EN except ValueError: TR = EN -def _(text): +def tr(text): """Translate text.""" return TR.get(text, text) @@ -63,13 +81,12 @@ def _(text): class ColorPicker(tk.Toplevel): """Color picker dialog.""" - def __init__(self, parent=None, color=(255, 0, 0), alpha=False, - title=_("Color Chooser")): + def __init__(self, master=None, title=None, color=None, alpha=False): """ Create a ColorPicker dialog. - :param parent: parent widget - :type parent: widget + :param master: parent widget + :type master: widget :param color: initially selected color (RGB(A), HEX or tkinter color name) :type color: sequence[int] or str :param alpha: whether to display the alpha channel @@ -77,7 +94,7 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, :param title: dialog title :type title: str """ - tk.Toplevel.__init__(self, parent) + tk.Toplevel.__init__(self, master) self.title(title) self.transient(self.master) @@ -87,8 +104,8 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, self.color = "" self.alpha_channel = bool(alpha) style = ttk.Style(self) - style.map("palette.TFrame", relief=[('focus', 'sunken')], - bordercolor=[('focus', "#4D4D4D")]) + style.map("palette.TFrame", relief=[("focus", "solid")], + bordercolor=[("focus", "#4D4D4D")]) self.configure(background=style.lookup("TFrame", "background")) if isinstance(color, str): @@ -105,7 +122,7 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, old_color = color if alpha: self._old_alpha = 255 - old_color += 'FF' + old_color += "FF" else: col = self.winfo_rgb(color) self._old_color = tuple(round2(c * 255 / 65535) for c in col) @@ -126,12 +143,12 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, # --- GradientBar hue = col2hue(*self._old_color) - bar = ttk.Frame(self, borderwidth=2, relief='groove') + bar = ttk.Frame(self, borderwidth=2, relief=tk.SOLID) self.bar = GradientBar(bar, hue=hue, width=200, highlightthickness=0) self.bar.pack() # --- ColorSquare - square = ttk.Frame(self, borderwidth=2, relief='groove') + square = ttk.Frame(self, borderwidth=2, relief=tk.SOLID) self.square = ColorSquare(square, hue=hue, width=200, height=200, color=rgb_to_hsv(*self._old_color), highlightthickness=0) @@ -142,7 +159,7 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, frame.rowconfigure(1, weight=1) # --- color preview: initial color and currently selected color side by side - preview_frame = ttk.Frame(frame, relief="groove", borderwidth=2) + preview_frame = ttk.Frame(frame, relief=tk.SOLID, borderwidth=2) preview_frame.grid(row=0, column=0, sticky="nw", pady=2) if alpha: self._transparent_bg = create_checkered_image(42, 32) @@ -174,115 +191,115 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, palette = ttk.Frame(frame) palette.grid(row=0, column=1, rowspan=2, sticky="ne") for i, col in enumerate(PALETTE): - f = ttk.Frame(palette, borderwidth=1, relief="raised", + f = ttk.Frame(palette, borderwidth=1, relief=tk.SOLID, style="palette.TFrame") l = tk.Label(f, background=col, width=2, height=1) l.bind("<1>", self._palette_cmd) - f.bind("", lambda e: e.widget.configure(relief="raised")) + f.bind("", lambda e: e.widget.configure(relief=tk.SOLID)) l.pack() f.grid(row=i % 2, column=i // 2, padx=2, pady=2) col_frame = ttk.Frame(self) # --- hsv - hsv_frame = ttk.Frame(col_frame, relief="ridge", borderwidth=2) + hsv_frame = ttk.Frame(col_frame, relief=tk.SOLID, borderwidth=2) hsv_frame.pack(pady=(0, 4), fill="x") hsv_frame.columnconfigure(0, weight=1) self.hue = LimitVar(0, 360, self) self.saturation = LimitVar(0, 100, self) self.value = LimitVar(0, 100, self) - s_h = Spinbox(hsv_frame, from_=0, to=360, width=4, name='spinbox', + s_h = Spinbox(hsv_frame, from_=0, to=360, width=4, name="spinbox", textvariable=self.hue, command=self._update_color_hsv) s_s = Spinbox(hsv_frame, from_=0, to=100, width=4, - textvariable=self.saturation, name='spinbox', + textvariable=self.saturation, name="spinbox", command=self._update_color_hsv) - s_v = Spinbox(hsv_frame, from_=0, to=100, width=4, name='spinbox', + s_v = Spinbox(hsv_frame, from_=0, to=100, width=4, name="spinbox", textvariable=self.value, command=self._update_color_hsv) h, s, v = rgb_to_hsv(*self._old_color) - s_h.delete(0, 'end') + s_h.delete(0, tk.END) s_h.insert(0, h) - s_s.delete(0, 'end') + s_s.delete(0, tk.END) s_s.insert(0, s) - s_v.delete(0, 'end') + s_v.delete(0, tk.END) s_v.insert(0, v) - s_h.grid(row=0, column=1, sticky='w', padx=4, pady=4) - s_s.grid(row=1, column=1, sticky='w', padx=4, pady=4) - s_v.grid(row=2, column=1, sticky='w', padx=4, pady=4) - ttk.Label(hsv_frame, text=_('Hue')).grid(row=0, column=0, sticky='e', + s_h.grid(row=0, column=1, sticky="w", padx=4, pady=4) + s_s.grid(row=1, column=1, sticky="w", padx=4, pady=4) + s_v.grid(row=2, column=1, sticky="w", padx=4, pady=4) + ttk.Label(hsv_frame, text=tr("Hue")).grid(row=0, column=0, sticky="e", padx=4, pady=4) - ttk.Label(hsv_frame, text=_('Saturation')).grid(row=1, column=0, sticky='e', + ttk.Label(hsv_frame, text=tr("Saturation")).grid(row=1, column=0, sticky="e", padx=4, pady=4) - ttk.Label(hsv_frame, text=_('Value')).grid(row=2, column=0, sticky='e', + ttk.Label(hsv_frame, text=tr("Value")).grid(row=2, column=0, sticky="e", padx=4, pady=4) # --- rgb - rgb_frame = ttk.Frame(col_frame, relief="ridge", borderwidth=2) + rgb_frame = ttk.Frame(col_frame, relief=tk.SOLID, borderwidth=2) rgb_frame.pack(pady=4, fill="x") rgb_frame.columnconfigure(0, weight=1) self.red = LimitVar(0, 255, self) self.green = LimitVar(0, 255, self) self.blue = LimitVar(0, 255, self) - s_red = Spinbox(rgb_frame, from_=0, to=255, width=4, name='spinbox', + s_red = Spinbox(rgb_frame, from_=0, to=255, width=4, name="spinbox", textvariable=self.red, command=self._update_color_rgb) - s_green = Spinbox(rgb_frame, from_=0, to=255, width=4, name='spinbox', + s_green = Spinbox(rgb_frame, from_=0, to=255, width=4, name="spinbox", textvariable=self.green, command=self._update_color_rgb) - s_blue = Spinbox(rgb_frame, from_=0, to=255, width=4, name='spinbox', + s_blue = Spinbox(rgb_frame, from_=0, to=255, width=4, name="spinbox", textvariable=self.blue, command=self._update_color_rgb) - s_red.delete(0, 'end') + s_red.delete(0, tk.END) s_red.insert(0, self._old_color[0]) - s_green.delete(0, 'end') + s_green.delete(0, tk.END) s_green.insert(0, self._old_color[1]) - s_blue.delete(0, 'end') + s_blue.delete(0, tk.END) s_blue.insert(0, self._old_color[2]) - s_red.grid(row=0, column=1, sticky='e', padx=4, pady=4) - s_green.grid(row=1, column=1, sticky='e', padx=4, pady=4) - s_blue.grid(row=2, column=1, sticky='e', padx=4, pady=4) - ttk.Label(rgb_frame, text=_('Red')).grid(row=0, column=0, sticky='e', + s_red.grid(row=0, column=1, sticky="e", padx=4, pady=4) + s_green.grid(row=1, column=1, sticky="e", padx=4, pady=4) + s_blue.grid(row=2, column=1, sticky="e", padx=4, pady=4) + ttk.Label(rgb_frame, text=tr("Red")).grid(row=0, column=0, sticky="e", padx=4, pady=4) - ttk.Label(rgb_frame, text=_('Green')).grid(row=1, column=0, sticky='e', + ttk.Label(rgb_frame, text=tr("Green")).grid(row=1, column=0, sticky="e", padx=4, pady=4) - ttk.Label(rgb_frame, text=_('Blue')).grid(row=2, column=0, sticky='e', + ttk.Label(rgb_frame, text=tr("Blue")).grid(row=2, column=0, sticky="e", padx=4, pady=4) # --- hexa hexa_frame = ttk.Frame(col_frame) hexa_frame.pack(fill="x") - self.hexa = ttk.Entry(hexa_frame, justify="center", width=10, name='entry') + self.hexa = ttk.Entry(hexa_frame, justify=tk.CENTER, width=10, name="entry") self.hexa.insert(0, old_color.upper()) - ttk.Label(hexa_frame, text="HTML").pack(side="left", padx=4, pady=(4, 1)) - self.hexa.pack(side="left", padx=6, pady=(4, 1), fill='x', expand=True) + ttk.Label(hexa_frame, text="Hex").pack(side=tk.LEFT, padx=4, pady=(4, 1)) + self.hexa.pack(side=tk.LEFT, padx=6, pady=(4, 1), fill="x", expand=True) # --- alpha if alpha: alpha_frame = ttk.Frame(self) alpha_frame.columnconfigure(1, weight=1) self.alpha = LimitVar(0, 255, self) - alphabar = ttk.Frame(alpha_frame, borderwidth=2, relief='groove') + alphabar = ttk.Frame(alpha_frame, borderwidth=2, relief=tk.SOLID) self.alphabar = AlphaBar(alphabar, alpha=self._old_alpha, width=200, color=self._old_color, highlightthickness=0) self.alphabar.pack() s_alpha = Spinbox(alpha_frame, from_=0, to=255, width=4, textvariable=self.alpha, command=self._update_alpha) - s_alpha.delete(0, 'end') + s_alpha.delete(0, tk.END) s_alpha.insert(0, self._old_alpha) - alphabar.grid(row=0, column=0, padx=(0, 4), pady=4, sticky='w') - ttk.Label(alpha_frame, text=_('Alpha')).grid(row=0, column=1, sticky='e', + alphabar.grid(row=0, column=0, padx=(0, 4), pady=4, sticky="w") + ttk.Label(alpha_frame, text=tr("Alpha")).grid(row=0, column=1, sticky="e", padx=4, pady=4) - s_alpha.grid(row=0, column=2, sticky='w', padx=(4, 6), pady=4) + s_alpha.grid(row=0, column=2, sticky="w", padx=(4, 6), pady=4) # --- validation button_frame = ttk.Frame(self) ttk.Button(button_frame, text="Ok", command=self.ok).pack(side="right", padx=10) - ttk.Button(button_frame, text=_("Cancel"), + ttk.Button(button_frame, text=tr("Cancel"), command=self.destroy).pack(side="right", padx=10) # --- placement - bar.grid(row=0, column=0, padx=10, pady=(10, 4), sticky='n') - square.grid(row=1, column=0, padx=10, pady=(9, 0), sticky='n') + bar.grid(row=0, column=0, padx=10, pady=(10, 4), sticky="n") + square.grid(row=1, column=0, padx=10, pady=(9, 0), sticky="n") if alpha: alpha_frame.grid(row=2, column=0, columnspan=2, padx=10, - pady=(1, 4), sticky='ewn') + pady=(1, 4), sticky="ewn") col_frame.grid(row=0, rowspan=2, column=1, padx=(4, 10), pady=(10, 4)) frame.grid(row=3, column=0, columnspan=2, pady=(4, 10), padx=10, sticky="new") button_frame.grid(row=4, columnspan=2, pady=(0, 10), padx=10) @@ -296,28 +313,28 @@ def __init__(self, parent=None, color=(255, 0, 0), alpha=False, self.square.bind("", self._unfocus, True) self.square.bind("", self._change_sel_color, True) self.square.bind("", self._change_sel_color, True) - s_red.bind('', self._update_color_rgb) - s_green.bind('', self._update_color_rgb) - s_blue.bind('', self._update_color_rgb) - s_red.bind('', self._update_color_rgb) - s_green.bind('', self._update_color_rgb) - s_blue.bind('', self._update_color_rgb) - s_red.bind('', self._select_all_spinbox) - s_green.bind('', self._select_all_spinbox) - s_blue.bind('', self._select_all_spinbox) - s_h.bind('', self._update_color_hsv) - s_s.bind('', self._update_color_hsv) - s_v.bind('', self._update_color_hsv) - s_h.bind('', self._update_color_hsv) - s_s.bind('', self._update_color_hsv) - s_v.bind('', self._update_color_hsv) - s_h.bind('', self._select_all_spinbox) - s_s.bind('', self._select_all_spinbox) - s_v.bind('', self._select_all_spinbox) + s_red.bind("", self._update_color_rgb) + s_green.bind("", self._update_color_rgb) + s_blue.bind("", self._update_color_rgb) + s_red.bind("", self._update_color_rgb) + s_green.bind("", self._update_color_rgb) + s_blue.bind("", self._update_color_rgb) + s_red.bind("", self._select_all_spinbox) + s_green.bind("", self._select_all_spinbox) + s_blue.bind("", self._select_all_spinbox) + s_h.bind("", self._update_color_hsv) + s_s.bind("", self._update_color_hsv) + s_v.bind("", self._update_color_hsv) + s_h.bind("", self._update_color_hsv) + s_s.bind("", self._update_color_hsv) + s_v.bind("", self._update_color_hsv) + s_h.bind("", self._select_all_spinbox) + s_s.bind("", self._select_all_spinbox) + s_v.bind("", self._select_all_spinbox) if alpha: - s_alpha.bind('', self._update_alpha) - s_alpha.bind('', self._update_alpha) - s_alpha.bind('', self._select_all_spinbox) + s_alpha.bind("", self._update_alpha) + s_alpha.bind("", self._update_alpha) + s_alpha.bind("", self._select_all_spinbox) self.hexa.bind("", self._update_color_hexa) self.hexa.bind("", self._update_color_hexa) self.hexa.bind("", self._select_all_entry) @@ -338,19 +355,19 @@ def get_color(self): @staticmethod def _select_all_spinbox(event): """Select all entry content.""" - event.widget.selection('range', 0, 'end') + event.widget.selection("range", 0, tk.END) return "break" @staticmethod def _select_all_entry(event): """Select all entry content.""" - event.widget.selection_range(0, 'end') + event.widget.selection_range(0, tk.END) return "break" def _unfocus(self, event): """Unfocus palette items when click on bar or square.""" w = self.focus_get() - if w != self and 'spinbox' not in str(w) and 'entry' not in str(w): + if w != self and "spinbox" not in str(w) and "entry" not in str(w): self.focus_set() def _update_preview(self): @@ -367,7 +384,7 @@ def _reset_preview(self, event): """Respond to user click on a palette item.""" label = event.widget label.master.focus_set() - label.master.configure(relief="sunken") + label.master.configure(relief=tk.SOLID) args = self._old_color if self.alpha_channel: args += (self._old_alpha,) @@ -381,7 +398,7 @@ def _reset_preview(self, event): self.hue.set(h) self.saturation.set(s) self.value.set(v) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, color.upper()) self.bar.set(h) self.square.set_hsv((h, s, v)) @@ -391,7 +408,7 @@ def _palette_cmd(self, event): """Respond to user click on a palette item.""" label = event.widget label.master.focus_set() - label.master.configure(relief="sunken") + label.master.configure(relief=tk.SOLID) r, g, b = self.winfo_rgb(label.cget("background")) r = round2(r * 255 / 65535) g = round2(g * 255 / 65535) @@ -409,7 +426,7 @@ def _palette_cmd(self, event): self.hue.set(h) self.saturation.set(s) self.value.set(v) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, color.upper()) self.bar.set(h) self.square.set_hsv((h, s, v)) @@ -423,11 +440,11 @@ def _change_sel_color(self, event): self.blue.set(b) self.saturation.set(s) self.value.set(v) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, color.upper()) if self.alpha_channel: self.alphabar.set_color((r, g, b)) - self.hexa.insert('end', + self.hexa.insert(tk.END, ("%2.2x" % self.alpha.get()).upper()) self._update_preview() @@ -442,11 +459,11 @@ def _change_color(self, event): self.hue.set(h) self.saturation.set(s) self.value.set(v) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, sel_color.upper()) if self.alpha_channel: self.alphabar.set_color((r, g, b)) - self.hexa.insert('end', + self.hexa.insert(tk.END, ("%2.2x" % self.alpha.get()).upper()) self._update_preview() @@ -456,14 +473,14 @@ def _change_alpha(self, event): self.alpha.set(a) hexa = self.hexa.get() hexa = hexa[:7] + ("%2.2x" % a).upper() - self.hexa.delete(0, 'end') + self.hexa.delete(0, tk.END) self.hexa.insert(0, hexa) self._update_preview() def _update_color_hexa(self, event=None): """Update display after a change in the HEX entry.""" color = self.hexa.get().upper() - self.hexa.delete(0, 'end') + self.hexa.delete(0, tk.END) self.hexa.insert(0, color) if re.match(r"^#[0-9A-F]{6}$", color): r, g, b = hexa_to_rgb(color) @@ -478,7 +495,7 @@ def _update_color_hexa(self, event=None): self.square.set_hsv((h, s, v)) if self.alpha_channel: a = self.alpha.get() - self.hexa.insert('end', ("%2.2x" % a).upper()) + self.hexa.insert(tk.END, ("%2.2x" % a).upper()) self.alphabar.set_color((r, g, b, a)) elif self.alpha_channel and re.match(r"^#[0-9A-F]{8}$", color): r, g, b, a = hexa_to_rgb(color) @@ -502,7 +519,7 @@ def _update_alpha(self, event=None): a = self.alpha.get() hexa = self.hexa.get() hexa = hexa[:7] + ("%2.2x" % a).upper() - self.hexa.delete(0, 'end') + self.hexa.delete(0, tk.END) self.hexa.insert(0, hexa) self.alphabar.set(a) self._update_preview() @@ -521,7 +538,7 @@ def _update_color_hsv(self, event=None): sel_color += (self.alpha.get(),) self.alphabar.set_color(sel_color) hexa = rgb_to_hexa(*sel_color) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, hexa) self.square.set_hsv((h, s, v)) self.bar.set(h) @@ -542,7 +559,7 @@ def _update_color_rgb(self, event=None): args += (self.alpha.get(),) self.alphabar.set_color(args) hexa = rgb_to_hexa(*args) - self.hexa.delete(0, "end") + self.hexa.delete(0, tk.END) self.hexa.insert(0, hexa) self.square.set_hsv((h, s, v)) self.bar.set(h) @@ -558,26 +575,27 @@ def ok(self): self.destroy() -def askcolor(color="red", parent=None, title=_("Color Chooser"), alpha=False): +def askcolor(master=None, title=tr("Color Chooser"), color=(255, 0, 0), alpha=False): """ - Open a ColorPicker dialog and return the chosen color. + Opens a :class: `ColorPicker` dialog and return the chosen color. :return: the selected color in RGB(A) and hexadecimal #RRGGBB(AA) formats. (None, None) is returned if the color selection is cancelled. - - :param color: initially selected color (RGB(A), HEX or tkinter color name) - :type color: sequence[int] or str - :param parent: parent widget - :type parent: widget + + :param master: parent widget + :type master: widget :param title: dialog title :type title: str + :param color: initially selected color (RGB(A), HEX or tkinter color name) + :type color: sequence[int] or str :param alpha: whether to display the alpha channel :type alpha: bool """ - col = ColorPicker(parent, color, alpha, title) - col.wait_window(col) - res = col.get_color() + chooser = ColorPicker(master, title, color, alpha) + chooser.wait_window(chooser) + res = chooser.get_color() if res: return res[0], res[2] else: return None, None + From 133ed185cb178d6f3d6d4423e5a1f1fc2bba05f7 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:38:33 +0100 Subject: [PATCH 25/29] Update gradientbar.py --- ttkwidgets/color/gradientbar.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ttkwidgets/color/gradientbar.py b/ttkwidgets/color/gradientbar.py index 66509c74..8a2fdcef 100644 --- a/ttkwidgets/color/gradientbar.py +++ b/ttkwidgets/color/gradientbar.py @@ -73,9 +73,9 @@ def __init__(self, parent, hue=0, height=11, width=256, variable=None, self.gradient = tk.PhotoImage(master=self, width=width, height=height) - self.bind('', lambda e: self._draw_gradient(hue)) - self.bind('', self._on_click) - self.bind('', self._on_move) + self.bind("", lambda e: self._draw_gradient(hue)) + self.bind("", self._on_click) + self.bind("", self._on_move) def _draw_gradient(self, hue): """Draw the gradient and put the cursor on hue.""" @@ -97,19 +97,19 @@ def _draw_gradient(self, hue): self.lower("gradient") x = hue / 360. * width - self.create_line(x, 0, x, height, width=2, tags='cursor') + self.create_line(x, 0, x, height, width=2, tags="cursor") def _on_click(self, event): """Move selection cursor on click.""" x = event.x - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(round2((360. * x) / self.winfo_width())) def _on_move(self, event): """Make selection cursor follow the cursor.""" w = self.winfo_width() x = min(max(event.x, 0), w) - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(round2((360. * x) / w)) def _update_hue(self, *args): @@ -123,7 +123,7 @@ def _update_hue(self, *args): def get(self): """Return hue of color under cursor.""" - coords = self.coords('cursor') + coords = self.coords("cursor") return round2(360 * coords[0] / self.winfo_width()) def set(self, hue): @@ -138,5 +138,5 @@ def set(self, hue): elif hue < 0: hue = 0 x = hue / 360. * self.winfo_width() - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(hue) From 049a9c6f775164f1e623c3a2d74950d7f1c72538 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:41:01 +0100 Subject: [PATCH 26/29] Update alphabar.py --- ttkwidgets/color/alphabar.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ttkwidgets/color/alphabar.py b/ttkwidgets/color/alphabar.py index b71d98e3..02feef23 100644 --- a/ttkwidgets/color/alphabar.py +++ b/ttkwidgets/color/alphabar.py @@ -76,9 +76,9 @@ def __init__(self, parent, alpha=255, color=(255, 0, 0), height=11, except Exception: self._variable.trace("w", self._update_alpha) - self.bind('', lambda e: self._draw_gradient(alpha, color)) - self.bind('', self._on_click) - self.bind('', self._on_move) + self.bind("", lambda e: self._draw_gradient(alpha, color)) + self.bind("", self._on_click) + self.bind("", self._on_move) def _draw_gradient(self, alpha, color): """Draw the gradient and put the cursor on alpha.""" @@ -107,20 +107,20 @@ def _draw_gradient(self, alpha, color): if v < 50: fill = "gray80" else: - fill = 'black' - self.create_line(x, 0, x, height, width=2, tags='cursor', fill=fill) + fill = "black" + self.create_line(x, 0, x, height, width=2, tags="cursor", fill=fill) def _on_click(self, event): """Move selection cursor on click.""" x = event.x - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(round2((255. * x) / self.winfo_width())) def _on_move(self, event): """Make selection cursor follow the cursor.""" w = self.winfo_width() x = min(max(event.x, 0), w) - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(round2((255. * x) / w)) def _update_alpha(self, *args): @@ -134,7 +134,7 @@ def _update_alpha(self, *args): def get(self): """Return alpha value of color under cursor.""" - coords = self.coords('cursor') + coords = self.coords("cursor") return round2((255. * coords[0]) / self.winfo_width()) def set(self, alpha): @@ -149,7 +149,7 @@ def set(self, alpha): elif alpha < 0: alpha = 0 x = alpha / 255. * self.winfo_width() - self.coords('cursor', x, 0, x, self.winfo_height()) + self.coords("cursor", x, 0, x, self.winfo_height()) self._variable.set(alpha) def set_color(self, color): @@ -164,3 +164,4 @@ def set_color(self, color): else: alpha = color[3] self._draw_gradient(alpha, color[:3]) + From 66650b43eecd4bbe330b65c61831fd370a17896b Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:42:31 +0100 Subject: [PATCH 27/29] Update colorsquare.py --- ttkwidgets/color/colorsquare.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ttkwidgets/color/colorsquare.py b/ttkwidgets/color/colorsquare.py index f102e0b6..2fc46df9 100644 --- a/ttkwidgets/color/colorsquare.py +++ b/ttkwidgets/color/colorsquare.py @@ -5,9 +5,9 @@ Source: https://github.com/j4321/tkColorPicker Edited by RedFantom for Python 2/3 cross-compatibility and docstring formatting -""" -""" + + tkcolorpicker - Alternative to colorchooser for Tkinter. Copyright 2017 Juliette Monsel @@ -56,9 +56,9 @@ def __init__(self, parent, hue, color=None, height=256, width=256, **kwargs): self._hue = hue if not color: color = hue2col(self._hue) - self.bind('', lambda e: self._draw(color)) - self.bind('', self._on_click) - self.bind('', self._on_move) + self.bind("", lambda e: self._draw(color)) + self.bind("", self._on_click) + self.bind("", self._on_move) def _fill(self): """Create the gradient.""" @@ -122,8 +122,8 @@ def _on_click(self, event): """Move cross on click.""" x = event.x y = event.y - self.coords('cross_h', 0, y, self.winfo_width(), y) - self.coords('cross_v', x, 0, x, self.winfo_height()) + self.coords("cross_h", 0, y, self.winfo_width(), y) + self.coords("cross_v", x, 0, x, self.winfo_height()) self.event_generate("<>") def _on_move(self, event): @@ -132,8 +132,8 @@ def _on_move(self, event): h = self.winfo_height() x = min(max(event.x, 0), w) y = min(max(event.y, 0), h) - self.coords('cross_h', 0, y, w, y) - self.coords('cross_v', x, 0, x, h) + self.coords("cross_h", 0, y, w, y) + self.coords("cross_v", x, 0, x, h) self.event_generate("<>") def get(self): @@ -142,8 +142,8 @@ def get(self): :return: color under cursor as a (RGB, HSV, HEX) tuple """ - x = self.coords('cross_v')[0] - y = self.coords('cross_h')[1] + x = self.coords("cross_v")[0] + y = self.coords("cross_h")[1] xp = min(x, self.bg.width() - 1) yp = min(y, self.bg.height() - 1) try: @@ -170,8 +170,8 @@ def set_rgb(self, sel_color): self.set_hue(h) x = v / 100. y = (1 - s / 100.) - self.coords('cross_h', 0, y * height, width, y * height) - self.coords('cross_v', x * width, 0, x * width, height) + self.coords("cross_h", 0, y * height, width, y * height) + self.coords("cross_v", x * width, 0, x * width, height) def set_hsv(self, sel_color): """ @@ -186,5 +186,5 @@ def set_hsv(self, sel_color): self.set_hue(h) x = v / 100. y = (1 - s / 100.) - self.coords('cross_h', 0, y * height, width, y * height) - self.coords('cross_v', x * width, 0, x * width, height) + self.coords("cross_h", 0, y * height, width, y * height) + self.coords("cross_v", x * width, 0, x * width, height) From 3e883ba811e13b8d6254bf24dc99edaf19622c69 Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 22:49:23 +0100 Subject: [PATCH 28/29] Update spinbox.py I would consider replacing this entire widget with a ttk.Spinbox. Unfortunately, it doesn't change much on Linux, but it would look better on Windows and Mac anyway. --- ttkwidgets/color/spinbox.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ttkwidgets/color/spinbox.py b/ttkwidgets/color/spinbox.py index 55ae13cb..6c3cd584 100644 --- a/ttkwidgets/color/spinbox.py +++ b/ttkwidgets/color/spinbox.py @@ -6,6 +6,8 @@ Edited by RedFantom for Python 2/3 cross-compatibility and docstring formatting + + tkcolorpicker - Alternative to colorchooser for Tkinter. Copyright 2017 Juliette Monsel @@ -23,6 +25,9 @@ along with this program. If not, see . Nicer Spinbox than the tk.Spinbox + +NOTE from rdbende: I would consider replacing this entire widget with a ttk.Spinbox. +Unfortunately, it doesn't change much on Linux, but it would look better on Windows and Mac anyway. """ @@ -45,7 +50,7 @@ def __init__(self, parent, **kwargs): self.style.configure("%s.spinbox.TFrame" % self.frame, background=self.style.lookup("TSpinbox", "fieldbackground", - default='white')) + default="white")) self.frame.configure(style="%s.spinbox.TFrame" % self.frame) kwargs["relief"] = "flat" kwargs["highlightthickness"] = 0 @@ -57,7 +62,7 @@ def __init__(self, parent, **kwargs): ("focus",)) kwargs["background"] = self.style.lookup("TSpinbox", "fieldbackground", - default='white') + default="white") kwargs["foreground"] = self.style.lookup("TSpinbox", "foreground") kwargs["buttonbackground"] = self.style.lookup("TSpinbox", @@ -97,7 +102,7 @@ def __init__(self, parent, **kwargs): self.place_info = self.frame.place_info self.place_slaves = self.frame.place_slaves - self.bind('<1>', lambda e: self.focus_set()) + self.bind("<1>", lambda e: self.focus_set()) self.frame.bind("", self.focusin) self.frame.bind("", self.focusout) @@ -117,3 +122,4 @@ def focusin(self, event): lc = self.style.lookup("TEntry", "lightcolor", ("focus",)) self.style.configure("%s.spinbox.TFrame" % self.frame, bordercolor=bc, darkcolor=dc, lightcolor=lc) + From d44c3becbc238a818a2d73d6dad3b2aac915723d Mon Sep 17 00:00:00 2001 From: rdbende Date: Wed, 24 Mar 2021 23:24:39 +0100 Subject: [PATCH 29/29] Update colorpicker.py --- ttkwidgets/color/colorpicker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttkwidgets/color/colorpicker.py b/ttkwidgets/color/colorpicker.py index 70bca82b..14387216 100644 --- a/ttkwidgets/color/colorpicker.py +++ b/ttkwidgets/color/colorpicker.py @@ -66,7 +66,7 @@ elif getdefaultlocale()[0][:2] == "de": TR = DE elif getdefaultlocale()[0][:2] == "hu": - TR = EN + TR = HU else: TR = EN except ValueError: