Skip to content

Commit

Permalink
Merge pull request #23 from Saadmairaj/Partial-"borderless"-support-f…
Browse files Browse the repository at this point in the history
…or-ttk

Partial "borderless" support for ttk
  • Loading branch information
Saadmairaj authored May 18, 2021
2 parents 8414b1e + 64c5f6a commit 3436f68
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 62 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@ This function returns sequences of rainbow colors hexcodes in order.
- [**v1.0.2**](https://github.com/Saadmairaj/tkmacosx/releases/tag/v1.0.2)

- Fix unknown color name "systemWindowBackgroundColor" ([#20](https://github.com/Saadmairaj/tkmacosx/issues/20))
- Partial "borderless" button option support for ttk widgets ([#19](https://github.com/Saadmairaj/tkmacosx/issues/19))
- Exclude test package in setup.py

- [**v1.0.1**](https://github.com/Saadmairaj/tkmacosx/releases/tag/v1.0.1)
Expand Down
144 changes: 95 additions & 49 deletions test/test_tkmacosx/test_widgets.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import os
import unittest
import tkinter
import tkmacosx
import tkinter.ttk as ttk

from test.support import findfile
from test.widget_tests import (add_standard_options, noconv,
StandardOptionsTests, IntegerSizeTests,
PixelSizeTests, AbstractWidgetTest)
StandardOptionsTests, ButtonOptionsTests,
IntegerSizeTests, PixelSizeTests,
AbstractWidgetTest)


def float_round(x):
Expand Down Expand Up @@ -59,68 +59,93 @@ def test_configure_highlightthickness(self):
0, 1.3, 2.6, 6, -2, '10p')


@add_standard_options(StandardOptionsTests)
class ButtonTest(AbstractWidgetTest, PixelSizeTests, unittest.TestCase):
OPTIONS = (
'activebackground', 'activeforeground', 'activeimage',
'activebitmap', 'anchor', 'background', 'bitmap', 'bordercolor',
'borderless', 'borderwidth', 'command', 'compound', 'cursor', 'disabledbackground',
'disabledforeground', 'font', 'focuscolor', 'focusthickness',
'foreground', 'height', 'highlightbackground', 'highlightcolor',
'highlightthickness', 'image', 'justify', 'overbackground',
'overforeground', 'overrelief', 'padx', 'pady', 'relief',
'repeatdelay', 'repeatinterval', 'state', 'takefocus', 'text',
'textvariable', 'underline', 'width')
class AbstractButtonTest(AbstractWidgetTest, PixelSizeTests):

_conv_pixels = round
_ttk_parent = False
_ttk_parent_with_style = False
_ttk_style = "TFrame"
_type = 'normal'

def create(self, **kwargs):
return tkmacosx.Button(self.root, **kwargs)
self._master = self.root
if self._ttk_parent and self._ttk_parent_with_style:
style = ttk.Style(self.root)
self._ttk_style = "Custom.TFrame"
style.configure(self._ttk_style, background="pink")
self._master = ttk.Frame(self.root, style=self._ttk_style)
self._master.pack()
elif self._ttk_parent:
self._master = ttk.Frame(self.root)
self._master.pack()
if self._type == 'normal':
return tkmacosx.Button(self._master, **kwargs)
if self._type == 'circle':
return tkmacosx.CircleButton(self._master, **kwargs)

def test_configure_state(self):
widget = self.create()
self.checkEnumParam(widget, 'state', 'active',
'disabled', 'normal', 'pressed')

def test_configure_activebitmap(self):
def test_configure_highlightbackground(self):
widget = self.create()
self.checkBitmapParam(widget, 'activebitmap')
self.checkColorParam(widget, 'highlightbackground')

def test_configure_activeimage(self):
widget = self.create()
self.checkImageParam(widget, 'activeimage')
widget['borderless'] = True
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
widget['highlightbackground'] = c
self.assertNotEqual(widget['highlightbackground'], c)

def test_configure_bordercolor(self):
widget = self.create()
self.checkColorParam(widget, 'bordercolor')
widget['borderless'] = False
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
widget['highlightbackground'] = c
self.assertEqual(widget['highlightbackground'], c)

def test_configure_borderless(self):
widget = self.create()
self.checkBooleanParam(widget, 'borderless')

def test_configure_disabledbackground(self):
widget = self.create()
self.checkColorParam(widget, 'disabledbackground')
@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class ButtonTest(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'activebackground', 'activeforeground', 'activeimage',
'activebitmap', 'anchor', 'background', 'bitmap', 'bordercolor',
'borderless', 'borderwidth', 'command', 'compound', 'cursor', 'disabledbackground',
'disabledforeground', 'font', 'focuscolor', 'focusthickness',
'foreground', 'height', 'highlightbackground', 'highlightcolor',
'highlightthickness', 'image', 'justify', 'overbackground',
'overforeground', 'overrelief', 'padx', 'pady', 'relief',
'repeatdelay', 'repeatinterval', 'state', 'takefocus', 'text',
'textvariable', 'underline', 'width')

def test_configure_focuscolor(self):
widget = self.create()
self.checkColorParam(widget, 'focuscolor')
_conv_pixels = round
_ttk_parent = False
_ttk_parent_with_style = False
_type = 'normal'

def test_configure_focusthickness(self):
widget = self.create()
self.checkIntegerParam(
widget, 'focusthickness', 1, 20, 30, 0)

def test_configure_overforeground(self):
widget = self.create()
self.checkColorParam(widget, 'overforeground')
@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class Button_ttk_Test(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'bordercolor', 'borderless', 'highlightbackground',
'highlightcolor', 'highlightthickness')

def test_configure_overbackground(self):
widget = self.create()
self.checkColorParam(widget, 'overbackground')
_conv_pixels = round
_ttk_parent = True


@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class Button_ttk_with_style_Test(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'bordercolor', 'borderless', 'highlightbackground',
'highlightcolor', 'highlightthickness')

_conv_pixels = round
_ttk_parent = True
_ttk_parent_with_style = True


class CircleButtonTest(ButtonTest):
@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class CircleButtonTest(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'activebackground', 'activeforeground', 'activeimage',
'activebitmap', 'anchor', 'background', 'bitmap', 'bordercolor',
Expand All @@ -133,15 +158,36 @@ class CircleButtonTest(ButtonTest):
'textvariable', 'underline', 'width')

_conv_pixels = round

def create(self, **kwargs):
return tkmacosx.CircleButton(self.root, **kwargs)
_type = 'circle'

def test_configure_radius(self):
widget = self.create()
self.checkIntegerParam(widget, 'radius', 402, -402, 0)


@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class CircleButton_ttk_Test(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'bordercolor', 'borderless', 'highlightbackground',
'highlightcolor', 'highlightthickness')

_conv_pixels = round
_ttk_parent = True
_type = 'circle'


@add_standard_options(StandardOptionsTests, ButtonOptionsTests)
class CirclButton_ttk_with_style_Test(AbstractButtonTest, unittest.TestCase):
OPTIONS = (
'bordercolor', 'borderless', 'highlightbackground',
'highlightcolor', 'highlightthickness')

_conv_pixels = round
_ttk_parent = True
_ttk_parent_with_style = True
_type = 'circle'


@add_standard_options(StandardOptionsTests, PixelSizeTests)
class ColorscaleTest(AbstractWidgetTest, unittest.TestCase):
OPTIONS = (
Expand Down
83 changes: 83 additions & 0 deletions test/widget_tests.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tkinter
import tkinter.ttk as ttk
from tkmacosx import ColorVar
from tkmacosx.utils import pixels_conv
from tkmacosx.basewidgets.button_base import ButtonBase
Expand Down Expand Up @@ -523,6 +524,88 @@ def test_configure_width(self):
)


class ButtonOptionsTests:

def test_configure_activebitmap(self):
widget = self.create()
self.checkBitmapParam(widget, 'activebitmap')

def test_configure_activeimage(self):
widget = self.create()
self.checkImageParam(widget, 'activeimage')

def test_configure_bordercolor(self):
widget = self.create()
self.checkColorParam(widget, 'bordercolor')
widget['borderless'] = True
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
widget['bordercolor'] = c
self.assertNotEqual(widget['bordercolor'], c)

widget['borderless'] = False
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
widget['bordercolor'] = c
self.assertEqual(widget['bordercolor'], c)

def test_configure_borderless(self):
widget = self.create()
self.checkBooleanParam(widget, 'borderless')

if not (self._ttk_parent or self._ttk_parent_with_style):
org = self._master['bg']

widget['borderless'] = True
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
if self._ttk_parent or self._ttk_parent_with_style:
print(self._ttk_style)
self.assertEqual(widget['highlightbackground'], ttk.Style(
self._master).lookup(self._ttk_style, "background"))
ttk.Style(self._master).configure(self._ttk_style, bg=c)
else:
self.assertEqual(
widget['highlightbackground'], self._master['bg'])
self._master['bg'] = c

widget['borderless'] = False
for c in ('#ff0000', '#00ff00', '#0000ff', '#123456',
'red', 'green', 'blue', 'white', 'black', 'grey'):
if self._ttk_parent or self._ttk_parent_with_style:
self.assertNotEqual(widget['highlightbackground'], ttk.Style(
self._master).lookup(self._ttk_style, "background"))
ttk.Style(self._master).configure(self._ttk_style, bg=c)
else:
self.assertNotEqual(
widget['highlightbackground'], self._master['bg'])
self._master['bg'] = c

if not (self._ttk_parent or self._ttk_parent_with_style):
self._master['bg'] = org

def test_configure_disabledbackground(self):
widget = self.create()
self.checkColorParam(widget, 'disabledbackground')

def test_configure_focuscolor(self):
widget = self.create()
self.checkColorParam(widget, 'focuscolor')

def test_configure_focusthickness(self):
widget = self.create()
self.checkIntegerParam(
widget, 'focusthickness', 1, 20, 30, 0)

def test_configure_overforeground(self):
widget = self.create()
self.checkColorParam(widget, 'overforeground')

def test_configure_overbackground(self):
widget = self.create()
self.checkColorParam(widget, 'overbackground')


def add_standard_options(*source_classes):
# This decorator adds test_configure_xxx methods from source classes for
# every xxx option in the OPTIONS class attribute if they are not defined
Expand Down
34 changes: 21 additions & 13 deletions tkmacosx/basewidgets/button_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import tkinter
import tkinter.ttk as ttk
from tkmacosx.utils import (SYSTEM_DEFAULT, STDOUT_WARNING,
_cnfmerge, _bind, _Canvas, check_param,
_info_button, _on_press_color,
Expand Down Expand Up @@ -136,25 +137,32 @@ def bitmap(self, kw):
def borderless(self, kw):
def _get_master_bg():
"""Internal function."""
try:
return self.master['bg']
except tkinter.TclError:
if not _warning_msg_shown[0] and STDOUT_WARNING:
print('WARNING: "borderless" option of '
'tkmacosx Button doesn\'t work with ttk widgets. '
'Bordercolor/highlightbackground can be set manually '
'with "highlightbackground" or "bordercolor" options.\n')
_warning_msg_shown[0] = True
return self.cnf.get('bordercolor', self.cnf['highlightbackground'])
ttk_widget_types = tuple(
getattr(ttk, i) for i in ttk.__all__ if isinstance(getattr(ttk, i), type))
if isinstance(self.master, ttk_widget_types):
try:
style = self.master['style'] or 'T' + self.master.__class__.__name__
ttk_bg = ttk.Style(self.master).lookup(style, "background")
return ttk_bg
except tkinter.TclError:
if not _warning_msg_shown[0] and STDOUT_WARNING:
print('WARNING: "borderless" option is partially supported with ttk widgets. '
'Bordercolor/highlightbackground can be set manually '
'with "highlightbackground" or "bordercolor" options.\n')
_warning_msg_shown[0] = True
return self.cnf.get('bordercolor', self.cnf['highlightbackground'])
return self.master['bg']

_opt = {}
if bool(kw.get('borderless')) or self.cnf.get('borderless'):
if not check_function_equality(self.master.config, self._get_functions('borderless', kw)):
self.master.config = self.master.configure = self._get_functions(
'borderless', kw)
self.cnf['highlightbackground'] = self.cnf['bordercolor'] = _get_master_bg()
_opt[1] = [('itemconfigure', '_bd_color'), {'outline': _get_master_bg()}, None]
_opt[2] = ['configure', {'highlightbackground': _get_master_bg()}, None]
master_bg = _get_master_bg()
self.cnf['highlightbackground'] = self.cnf['bordercolor'] = master_bg
_opt[1] = [('itemconfigure', '_bd_color'), {'outline': master_bg}, None]
_opt[2] = ['configure', {'highlightbackground': master_bg}, None]

elif not bool(kw.get('borderless', True)) or not self.cnf.get('borderless'):
if self.cnf.get('bordercolor') == _get_master_bg():
self.cnf.pop('bordercolor', None)
Expand Down

0 comments on commit 3436f68

Please sign in to comment.