Skip to content

Commit

Permalink
New, more modern KivaFont trait (#929)
Browse files Browse the repository at this point in the history
* Add a new font-editor that uses Enable to draw fonts

This font editor is laregly toolkit independent - it embeds a Window with a
Label component to display the font and the simple editor uses the Pyface
font dialog to get new font values.

Some functionality is broken out into experimental base classes for building
editors with components.

* New more modern KivaFont trait

This creates a KivaFont TraitType, which is:
- in enable, rather than Kiva, meaning Kiva can potentially not need traits
- has a better font parser that supports more weight types
- the font parser can be swapped out for something better easily
- uses the new KivaFontEditor, which is available for Qt
- converts Pyface Fonts to Kiva Fonts

* Fix long line.

* Save all files before finishing merge!

* Fix tests.

* Apply suggestions from code review

Co-authored-by: Mark Dickinson <mdickinson@enthought.com>

* Handle color editor tests for null backend.

* Fixes from PR review.

* Some more small fixes coming from PR discussion.

Co-authored-by: Mark Dickinson <mdickinson@enthought.com>
  • Loading branch information
corranwebster and mdickinson committed Apr 28, 2022
1 parent c23a50a commit 74536e0
Show file tree
Hide file tree
Showing 28 changed files with 670 additions and 305 deletions.
5 changes: 3 additions & 2 deletions docs/source/enable/traits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ the form of an HTML color name ("blue" or "#0000FF").

font_trait
----------
:class:`~.font_trait` is a synonym for :class:`kiva.trait_defs.api.KivaFont`.
The trait maps a font-description string to a valid :class:`kiva.fonttools.Font`
:class:`~.font_trait` is a synonym for
:class:`enable.trait_defs.kiva_font_trait.KivaFont`. The trait maps a
font-description string to a valid :class:`kiva.fonttools.Font`
instance which can be passed to :py:meth:`AbstractGraphicsContext.set_font`

LineStyle
Expand Down
6 changes: 3 additions & 3 deletions docs/source/kiva/drawing_details.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,17 +280,17 @@ The ``KivaFont`` trait and ``set_font``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you're already doing your drawing within an application using traits, you can
use the :class:`~kiva.trait_defs.kiva_font_trait.KivaFont` trait.
use the :class:`~enable.trait_defs.kiva_font_trait.KivaFont` trait.

:class:`~kiva.trait_defs.kiva_font_trait.KivaFont` traits are initialized with
:class:`~enable.trait_defs.kiva_font_trait.KivaFont` traits are initialized with
a string which describes the font: "Times Italic 18", "Courier Bold 10", etc.
The *value* of the trait is a :class:`~kiva.fonttools.font.Font` instance which
can be passed to the :py:meth:`~.AbstractGraphicsContext.set_font` method.

*Supported backends*: all backends

.. note::
The :class:`~kiva.trait_defs.kiva_font_trait.KivaFont` parser is very
The :class:`~enable.trait_defs.kiva_font_trait.KivaFont` parser is very
simplistic and special-cases some words. For example "roman" means a
generic serif-style font family, so for example a face name of "Times New
Roman" will not resolve as expected. In these cases, use a
Expand Down
2 changes: 1 addition & 1 deletion enable/drawing/drawing_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Thanks for using Enthought open source!
from enable.api import Container, Component, ColorTrait
from kiva.api import FILL, FILL_STROKE
from kiva.trait_defs.api import KivaFont
from enable.trait_defs.kiva_font_trait import KivaFont
from traits.api import Any, Bool, Delegate, Enum, Instance, Int, List, Str


Expand Down
2 changes: 1 addition & 1 deletion enable/enable_traits.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from numpy import array, ndarray

# Enthought library imports
from kiva.trait_defs.api import KivaFont
from enable.trait_defs.kiva_font_trait import KivaFont
from traits.api import (
BaseFloat, List, Map, PrefixList, PrefixMap, Range, TraitType, Union,
)
Expand Down
2 changes: 1 addition & 1 deletion enable/examples/demo/enable/container_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from enable.api import ColorTrait
from enable.examples._example_support import DemoFrame, demo_main
from enable.tools.api import DragTool
from kiva.trait_defs.api import KivaFont
from enable.trait_defs.api import KivaFont


class Region(PlotComponent, DragTool):
Expand Down
19 changes: 12 additions & 7 deletions enable/examples/demo/enable/editors/font_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from traits.api import HasStrictTraits
from traitsui.api import View, Item

from enable.api import Container, TextField, font_trait
from enable.trait_defs.api import KivaFont
from enable.trait_defs.ui.api import KivaFontEditor
from enable.examples._example_support import demo_main

Expand All @@ -26,14 +26,19 @@
class Demo(HasStrictTraits):
""" An example which shows the KivaFontEditor's variations. """

font = font_trait(Font("Times", 24, SWISS, WEIGHT_BOLD, ITALIC))
font = KivaFont(Font("Times", 24, SWISS, WEIGHT_BOLD, ITALIC))

view = View(
Item('font', editor=KivaFontEditor(), style='simple', label="Simple"),
Item('font', editor=KivaFontEditor(), style='custom', label="Custom"),
Item('font', editor=KivaFontEditor(), style='text', label="Text"),
Item('font', editor=KivaFontEditor(), style='readonly', label="Readonly"),
Item('font', editor=KivaFontEditor(sample_text=sample_text), style='readonly', label="sample text"),
Item('font', style='simple', label="Simple"),
Item('font', style='custom', label="Custom"),
Item('font', style='text', label="Text"),
Item('font', style='readonly', label="Readonly"),
Item(
'font',
editor=KivaFontEditor(sample_text=sample_text),
style='readonly',
label="sample text",
),
resizable=True,
width=size[0],
height=size[1],
Expand Down
2 changes: 1 addition & 1 deletion enable/gadgets/vu_meter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from traits.api import Float, Property, List, Str, Range
from enable.api import Component
from kiva.trait_defs.api import KivaFont
from enable.trait_defs.kiva_font_trait import KivaFont
from kiva import affine


Expand Down
2 changes: 1 addition & 1 deletion enable/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# Enthought library imports
from kiva.api import FILL, STROKE
from kiva.trait_defs.api import KivaFont
from enable.trait_defs.kiva_font_trait import KivaFont
from traits.api import Bool, Enum, Float, HasTraits, Int, List, Str, observe

# Local, relative imports
Expand Down
Empty file.
Empty file.
9 changes: 6 additions & 3 deletions enable/tests/trait_defs/test_kiva_font_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def test_readonly_default_view(self):

self.assertIs(editor.value, new_font)
self.assertIs(component.font, new_font)
self.assertEqual(editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(
editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(component.text, "24 point Helvetica Bold Italic")
finally:
ui.dispose()
Expand Down Expand Up @@ -120,7 +121,8 @@ def test_simple_default_object_change(self):
self.assertIs(editor.value, new_font)
self.assertIs(editor.font, new_font)
self.assertIs(component.font, new_font)
self.assertEqual(editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(
editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(component.text, "24 point Helvetica Bold Italic")
finally:
ui.dispose()
Expand Down Expand Up @@ -151,7 +153,8 @@ def test_simple_default_editor_change(self):
self.assertIs(editor.value, new_font)
self.assertIs(editor.font, new_font)
self.assertIs(component.font, new_font)
self.assertEqual(editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(
editor.str_value, "24 point Helvetica Bold Italic")
self.assertEqual(component.text, "24 point Helvetica Bold Italic")
finally:
ui.dispose()
Expand Down
97 changes: 97 additions & 0 deletions enable/tests/trait_defs/test_kiva_font_trait.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# (C) Copyright 2008-2022 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!

import unittest

from kiva import constants
from kiva.fonttools.font import Font, FAMILIES, WEIGHTS, STYLES
from pyface.font import Font as PyfaceFont
from traits.api import HasTraits, TraitError

from enable.trait_defs.kiva_font_trait import KivaFont


class FontExample(HasTraits):

font = KivaFont()


class TestKivaFont(unittest.TestCase):

def test_validate_str(self):
expected_outcomes = {}
expected_outcomes[""] = Font(size=10, family=constants.DEFAULT)

for weight, kiva_weight in WEIGHTS.items():
expected_outcomes[weight] = Font(
weight=kiva_weight, size=10, family=constants.DEFAULT)

for style, kiva_style in STYLES.items():
expected_outcomes[style] = Font(
style=kiva_style, size=10, family=constants.DEFAULT)

expected_outcomes["underline"] = Font(
underline=True, size=10, family=constants.DEFAULT)

expected_outcomes["18"] = Font(size=18, family=constants.DEFAULT)
expected_outcomes["18 pt"] = Font(size=18, family=constants.DEFAULT)
expected_outcomes["18 point"] = Font(size=18, family=constants.DEFAULT)

for family, kiva_family in FAMILIES.items():
expected_outcomes[family] = Font(family=kiva_family, size=10)

expected_outcomes["Courier"] = Font(
"Courier", size=10, family=constants.DEFAULT)
expected_outcomes["Comic Sans"] = Font(
"Comic Sans", size=10, family=constants.DEFAULT)
expected_outcomes["18 pt Bold Italic Underline Comic Sans script"] = Font( # noqa: E501
"Comic Sans", 18, constants.SCRIPT, weight=constants.WEIGHT_BOLD,
style=constants.ITALIC, underline=True,
)

for name, expected in expected_outcomes.items():
with self.subTest(name=name):
example = FontExample(font=name)
result = example.font

# test we get expected font
self.assertIsInstance(result, Font)
self.assertEqual(result, expected)

def test_validate_font(self):
font = Font("Comic Sans", 18)
example = FontExample(font=font)

result = example.font

# test we get expected font
self.assertIsInstance(result, Font)
self.assertIs(result, font)

def test_validate_pyface_font(self):
font = Font("Comic Sans", 18, constants.DEFAULT)
pyface_font = PyfaceFont(family=["Comic Sans"], size=18)
example = FontExample(font=pyface_font)

result = example.font

# test we get expected font
self.assertIsInstance(result, Font)
self.assertEqual(result, font)

def test_font_trait_default(self):
example = FontExample()

self.assertIsInstance(example.font, Font)
self.assertEqual(example.font, Font(size=12, family=constants.SWISS))

def test_font_trait_none(self):
with self.assertRaises(TraitError):
FontExample(font=None)
Loading

0 comments on commit 74536e0

Please sign in to comment.