1150 lines
34 KiB
Python
1150 lines
34 KiB
Python
|
'''
|
||
|
Graphics tests
|
||
|
==============
|
||
|
|
||
|
Testing the simple vertex instructions
|
||
|
'''
|
||
|
|
||
|
import sys
|
||
|
import pytest
|
||
|
import itertools
|
||
|
from threading import Thread
|
||
|
from kivy.tests.common import GraphicUnitTest, requires_graphics
|
||
|
|
||
|
|
||
|
class BoxShadowTest(GraphicUnitTest):
|
||
|
|
||
|
def test_create(self):
|
||
|
from kivy.graphics.boxshadow import BoxShadow
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
# with initial arguments
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 0, 0, 1)
|
||
|
bs = BoxShadow(
|
||
|
pos=(50, 50),
|
||
|
size=(150, 150),
|
||
|
offset=(0, 10),
|
||
|
spread_radius=(10, -10),
|
||
|
border_radius=(10, 10, 10, 10),
|
||
|
blur_radius=80,
|
||
|
)
|
||
|
r(wid)
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(0, 1, 0, 1)
|
||
|
bs = BoxShadow(
|
||
|
inset=True,
|
||
|
pos=(50, 50),
|
||
|
size=(150, 150),
|
||
|
offset=(0, 10),
|
||
|
spread_radius=(10, -10),
|
||
|
border_radius=(10, 10, 10, 10),
|
||
|
blur_radius=80,
|
||
|
)
|
||
|
r(wid)
|
||
|
|
||
|
# changing properties later
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(0, 0, 1, 1)
|
||
|
bs = BoxShadow()
|
||
|
bs.inset = True
|
||
|
bs.pos = [50, 50]
|
||
|
bs.size = [150, 150]
|
||
|
bs.offset = [0, 10]
|
||
|
bs.spread_radius = [10, -10]
|
||
|
bs.border_radius = [10, 10, 10, 10]
|
||
|
bs.blur_radius = 40
|
||
|
r(wid)
|
||
|
|
||
|
def test_adjusted_size(self):
|
||
|
from kivy.graphics.boxshadow import BoxShadow
|
||
|
|
||
|
raw_size = 150, 150
|
||
|
|
||
|
bs = BoxShadow()
|
||
|
bs.pos = 50, 50
|
||
|
bs.size = raw_size
|
||
|
bs.blur_radius = 80
|
||
|
bs.spread_radius = -10, 10
|
||
|
|
||
|
# The size of the rectangle containing the FBO texture (shadow) needs
|
||
|
# to be adjusted according to the size of the shadow, otherwise there
|
||
|
# will be an unwanted cropping behavior.
|
||
|
adjusted_size = (
|
||
|
max(
|
||
|
0,
|
||
|
raw_size[0] + bs.blur_radius * 3 + bs.spread_radius[0] * 2,
|
||
|
),
|
||
|
max(
|
||
|
0,
|
||
|
raw_size[1] + bs.blur_radius * 3 + bs.spread_radius[1] * 2,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
assert bs.size == adjusted_size
|
||
|
|
||
|
# Now we will turn on the inset mode, it is expected that
|
||
|
# there will be no size adjustments.
|
||
|
bs.inset = True
|
||
|
assert bs.size == raw_size
|
||
|
|
||
|
# Now turning off, and reverting back to the default mode.
|
||
|
bs.inset = False
|
||
|
assert bs.size == adjusted_size
|
||
|
|
||
|
# Testing with initial arguments
|
||
|
bs = BoxShadow(
|
||
|
inset=True,
|
||
|
pos=(50, 50),
|
||
|
size=raw_size,
|
||
|
blur_radius=80,
|
||
|
spread_radius=(10, -10)
|
||
|
)
|
||
|
adjusted_size = (
|
||
|
max(
|
||
|
0,
|
||
|
raw_size[0] + bs.blur_radius * 3 + bs.spread_radius[0] * 2,
|
||
|
),
|
||
|
max(
|
||
|
0,
|
||
|
raw_size[1] + bs.blur_radius * 3 + bs.spread_radius[1] * 2,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
assert bs.size == raw_size
|
||
|
|
||
|
# Now turning off, and reverting back to the default mode.
|
||
|
bs.inset = False
|
||
|
assert bs.size == adjusted_size
|
||
|
|
||
|
# Now we will turn on the inset mode, it is expected that
|
||
|
# there will be no size adjustments.
|
||
|
bs.inset = True
|
||
|
assert bs.size == raw_size
|
||
|
|
||
|
def test_adjusted_pos(self):
|
||
|
from kivy.graphics.boxshadow import BoxShadow
|
||
|
|
||
|
raw_pos = 50, 50
|
||
|
raw_size = 150, 150
|
||
|
offset = 10, -100
|
||
|
|
||
|
bs = BoxShadow()
|
||
|
bs.pos = raw_pos
|
||
|
bs.size = raw_size
|
||
|
bs.offset = offset
|
||
|
bs.blur_radius = 80
|
||
|
bs.spread_radius = -10, 10
|
||
|
|
||
|
# If the size of the rectangle containing the FBO texture (shadow)
|
||
|
# changes, its position will need to be adjusted.
|
||
|
adjusted_pos = (
|
||
|
raw_pos[0]
|
||
|
- bs.blur_radius * 1.5
|
||
|
- bs.spread_radius[0]
|
||
|
+ bs.offset[0],
|
||
|
raw_pos[0]
|
||
|
- bs.blur_radius * 1.5
|
||
|
- bs.spread_radius[1]
|
||
|
+ bs.offset[1],
|
||
|
)
|
||
|
|
||
|
assert bs.pos == adjusted_pos
|
||
|
|
||
|
# Now we will turn on the inset mode, it is expected that
|
||
|
# there will be no position adjustments.
|
||
|
bs.inset = True
|
||
|
assert bs.pos == raw_pos
|
||
|
|
||
|
# Now turning off, and reverting back to the default mode.
|
||
|
bs.inset = False
|
||
|
assert bs.pos == adjusted_pos
|
||
|
|
||
|
# Testing with initial arguments
|
||
|
bs = BoxShadow(
|
||
|
inset=True,
|
||
|
pos=raw_pos,
|
||
|
size=raw_size,
|
||
|
offset=offset,
|
||
|
blur_radius=80,
|
||
|
spread_radius=(10, -10)
|
||
|
)
|
||
|
adjusted_pos = (
|
||
|
raw_pos[0]
|
||
|
- bs.blur_radius * 1.5
|
||
|
- bs.spread_radius[0]
|
||
|
+ bs.offset[0],
|
||
|
raw_pos[0]
|
||
|
- bs.blur_radius * 1.5
|
||
|
- bs.spread_radius[1]
|
||
|
+ bs.offset[1],
|
||
|
)
|
||
|
|
||
|
assert bs.pos == raw_pos
|
||
|
|
||
|
# Now turning off, and reverting back to the default mode.
|
||
|
bs.inset = False
|
||
|
assert bs.pos == adjusted_pos
|
||
|
|
||
|
# Now we will turn on the inset mode, it is expected that
|
||
|
# there will be no position adjustments.
|
||
|
bs.inset = True
|
||
|
assert bs.pos == raw_pos
|
||
|
|
||
|
def test_bounded_properties(self):
|
||
|
from kivy.graphics.boxshadow import BoxShadow
|
||
|
|
||
|
bs = BoxShadow()
|
||
|
bs.pos = 50, 50
|
||
|
bs.size = 150, 150
|
||
|
bs.offset = 10, -100
|
||
|
bs.blur_radius = -80
|
||
|
bs.spread_radius = -200, -100
|
||
|
bs.border_radius = 0, 0, 100, 0
|
||
|
|
||
|
assert bs.size == (0, 0)
|
||
|
assert bs.blur_radius == 0
|
||
|
|
||
|
# There is a bug in RoundedRectangle that distorts the texture if the
|
||
|
# radius value is less than 1. Otherwise, it could be 0.
|
||
|
assert bs.border_radius == tuple(
|
||
|
map(
|
||
|
lambda value: max(1.0, min(value, min(bs.size) / 2)),
|
||
|
bs.border_radius,
|
||
|
)
|
||
|
)
|
||
|
|
||
|
# Testing with initial arguments
|
||
|
bs = BoxShadow(
|
||
|
pos=(50, 50),
|
||
|
size=(150, 150),
|
||
|
offset=(10, -100),
|
||
|
blur_radius=-80,
|
||
|
spread_radius=(-200, -100),
|
||
|
border_radius=(0, 0, 100, 0),
|
||
|
)
|
||
|
|
||
|
assert bs.size == (0, 0)
|
||
|
assert bs.blur_radius == 0
|
||
|
assert bs.border_radius == tuple(
|
||
|
map(
|
||
|
lambda value: max(1.0, min(value, min(bs.size) / 2)),
|
||
|
bs.border_radius,
|
||
|
)
|
||
|
)
|
||
|
|
||
|
def test_canvas_management(self):
|
||
|
from kivy.graphics.boxshadow import BoxShadow
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
bs = BoxShadow()
|
||
|
r(wid)
|
||
|
assert bs in wid.canvas.children
|
||
|
|
||
|
wid = Widget()
|
||
|
bs = BoxShadow()
|
||
|
wid.canvas.add(Color(1, 0, 0, 1))
|
||
|
wid.canvas.add(bs)
|
||
|
r(wid)
|
||
|
assert bs in wid.canvas.children
|
||
|
|
||
|
wid.canvas.remove(bs)
|
||
|
assert bs not in wid.canvas.children
|
||
|
|
||
|
wid.canvas.insert(1, bs)
|
||
|
assert bs in wid.canvas.children
|
||
|
assert wid.canvas.children.index(bs) == 1
|
||
|
|
||
|
|
||
|
class VertexInstructionTest(GraphicUnitTest):
|
||
|
|
||
|
def test_circle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Ellipse, Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
# basic circle
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
Ellipse(pos=(100, 100), size=(100, 100))
|
||
|
r(wid)
|
||
|
|
||
|
# reduced circle
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
Ellipse(pos=(100, 100), size=(100, 100), segments=10)
|
||
|
r(wid)
|
||
|
|
||
|
# moving circle
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
self.e = Ellipse(pos=(100, 100), size=(100, 100))
|
||
|
self.e.pos = (10, 10)
|
||
|
r(wid)
|
||
|
|
||
|
def test_ellipse(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Ellipse, Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
# ellipse
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
self.e = Ellipse(pos=(100, 100), size=(200, 100))
|
||
|
r(wid)
|
||
|
|
||
|
def test_point(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Point, Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
# 1 point
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
Point(points=(10, 10))
|
||
|
r(wid)
|
||
|
|
||
|
# 25 points
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
Point(points=[x * 5 for x in range(50)])
|
||
|
r(wid)
|
||
|
|
||
|
def test_point_add(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Point, Color
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
p = Point(pointsize=10)
|
||
|
|
||
|
p.add_point(10, 10)
|
||
|
p.add_point(90, 10)
|
||
|
p.add_point(10, 90)
|
||
|
p.add_point(50, 50)
|
||
|
p.add_point(10, 50)
|
||
|
p.add_point(50, 10)
|
||
|
|
||
|
r(wid)
|
||
|
|
||
|
def test_line_rounded_rectangle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Line, Color
|
||
|
r = self.render
|
||
|
|
||
|
# basic rounded_rectangle
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(100, 100, 100, 100, 10, 20, 30, 40, 100)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 10, 20, 30, 40, 100
|
||
|
)
|
||
|
|
||
|
# The largest angle allowed is equal to the smallest dimension (width
|
||
|
# or height) minus the largest angle value between the anterior angle
|
||
|
# and the posterior angle.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(
|
||
|
100, 100, 100, 100, 100, 20, 10, 30, 100
|
||
|
)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 70, 20, 10, 30, 100
|
||
|
)
|
||
|
|
||
|
# Same approach as above
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(
|
||
|
100, 100, 100, 100, 100, 25, 100, 50, 100
|
||
|
)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 50, 25, 50, 50, 100
|
||
|
)
|
||
|
|
||
|
# A circle should be generated if width and height are equal, and all
|
||
|
# angles passed are greater than or equal to the smallest dimension.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(
|
||
|
100, 100, 100, 100, 150, 50, 50.001, 51, 100
|
||
|
)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 50, 50, 50, 50, 100
|
||
|
)
|
||
|
|
||
|
# Currently the minimum radius should be 1, to avoid rendering issues
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(
|
||
|
100, 100, 100, 100, 0, 0, 0, 0, 100
|
||
|
)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 1, 1, 1, 1, 100
|
||
|
)
|
||
|
|
||
|
# Angles adjustment + avoid issue if radius is less than 1
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = Line(
|
||
|
rounded_rectangle=(
|
||
|
100, 100, 100, 100, 100, 0, 0, 0, 100
|
||
|
)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle == (
|
||
|
100, 100, 100, 100, 99, 1, 1, 1, 100
|
||
|
)
|
||
|
|
||
|
def test_smoothline_rounded_rectangle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import SmoothLine, Color
|
||
|
r = self.render
|
||
|
|
||
|
# If width and/or height < 2px, the figure should not be rendered.
|
||
|
# This avoids some known SmoothLine rendering issues.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
line = SmoothLine(
|
||
|
rounded_rectangle=(100, 100, 0.5, 1.99, 30, 30, 30, 30, 100)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert line.rounded_rectangle is None
|
||
|
|
||
|
def test_enlarged_line(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Line, Color, PushMatrix, PopMatrix, Scale, \
|
||
|
Translate
|
||
|
r = self.render
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1)
|
||
|
|
||
|
# Normal line with width 1
|
||
|
Line(
|
||
|
points=(10, 10, 10, 90),
|
||
|
width=1
|
||
|
)
|
||
|
|
||
|
# Normal line with width 3
|
||
|
Line(
|
||
|
points=(20, 10, 20, 90),
|
||
|
width=3
|
||
|
)
|
||
|
|
||
|
# Enlarged line that should look width 3
|
||
|
PushMatrix()
|
||
|
Translate(30, 10, 1) # So the enlargement goes around 0, 0, 0
|
||
|
Scale(3, 1, 1) # X scaled by 3 so the line width should become 3
|
||
|
Line(
|
||
|
points=(0, 0, 0, 80),
|
||
|
width=1,
|
||
|
force_custom_drawing_method=True
|
||
|
)
|
||
|
PopMatrix()
|
||
|
|
||
|
r(wid)
|
||
|
|
||
|
|
||
|
class SmoothVertexInstructionTest(GraphicUnitTest):
|
||
|
|
||
|
# Code defined in the points setter of AntiAliasingLine class.
|
||
|
def _convert_points(self, points):
|
||
|
if points and isinstance(points[0], (list, tuple)):
|
||
|
return list(itertools.chain(*points))
|
||
|
else:
|
||
|
return list(points)
|
||
|
|
||
|
# The same function present in the AntiAliasingLine code,
|
||
|
# externalized for testing.
|
||
|
def _filtered_points(self, points):
|
||
|
index = 0
|
||
|
p = self._convert_points(points)
|
||
|
|
||
|
# At least 3 points are required, otherwise we will return an empty
|
||
|
# list, which means there are no valid points.
|
||
|
if len(p) < 6:
|
||
|
return []
|
||
|
|
||
|
while index < len(p) - 2:
|
||
|
x1, y1 = p[index], p[index + 1]
|
||
|
x2, y2 = p[index + 2], p[index + 3]
|
||
|
if abs(x2 - x1) < 1.0 and abs(y2 - y1) < 1.0:
|
||
|
del p[index + 2: index + 4]
|
||
|
else:
|
||
|
index += 2
|
||
|
if abs(p[0] - p[-2]) < 1.0 and abs(p[1] - p[-1]) < 1.0:
|
||
|
del p[:2]
|
||
|
return p
|
||
|
|
||
|
def _get_texture(self):
|
||
|
from kivy.graphics.texture import Texture
|
||
|
return Texture.create()
|
||
|
|
||
|
def test_antialiasing_line(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, Rectangle, Instruction
|
||
|
from kivy.graphics.vertex_instructions import AntiAliasingLine
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
# We expect a type error to be thrown if stencil_mask is not an object
|
||
|
# of type Instruction.
|
||
|
with pytest.raises(TypeError):
|
||
|
AntiAliasingLine(None, points=[10, 20, 30, 20, 30, 10])
|
||
|
|
||
|
# No TypeError here.
|
||
|
target_rect = Rectangle()
|
||
|
AntiAliasingLine(target_rect, points=[10, 20, 30, 40, 50, 60])
|
||
|
|
||
|
# Test the gradient responsible for the "smooth line" effect.
|
||
|
pixels = b"\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\x00"
|
||
|
instruction = Instruction()
|
||
|
aa_line = AntiAliasingLine(instruction)
|
||
|
assert aa_line.texture.pixels == pixels
|
||
|
# check the width, defined through tests with the custom texture.
|
||
|
assert aa_line.width == 2.5
|
||
|
|
||
|
# This set of points must remain unchanged.
|
||
|
points_1 = [51.0, 649.0, 199.0, 649.0, 199.0, 501.0, 51.0, 501.0]
|
||
|
|
||
|
# This set of points should be reduced from 16 to 8.
|
||
|
points_2 = [
|
||
|
261.0, 275.0,
|
||
|
335.0, 349.0,
|
||
|
335.0, 349.0,
|
||
|
409.0, 275.0,
|
||
|
409.0, 275.0,
|
||
|
335.0, 201.0,
|
||
|
335.0, 201.0,
|
||
|
261.0, 275.0
|
||
|
]
|
||
|
|
||
|
# This set of points should be reduced from 72 to 50.
|
||
|
points_3 = [
|
||
|
260.0, 275.0,
|
||
|
261.0, 275.0,
|
||
|
261.0, 275.0,
|
||
|
261.999999999999, 275.99999999,
|
||
|
261.06667650085353, 278.14064903651496,
|
||
|
261.26658584785304, 281.2756384111877,
|
||
|
261.56658584785305, 281.3756384111877,
|
||
|
261.5993677908431, 284.39931866126904,
|
||
|
262.0644226342696, 287.50606070381684,
|
||
|
262.0644226342696, 287.50606070381684,
|
||
|
262.6609123178712, 290.59026597968375,
|
||
|
263.3877619269211, 293.6463765424993,
|
||
|
264.2436616292954, 296.66888507446475,
|
||
|
265.22706903587977, 299.65234481091227,
|
||
|
265.22706903587977, 299.65234481091227,
|
||
|
266.3362119800583, 302.59137935574284,
|
||
|
267.5690917112779, 305.48069237005546,
|
||
|
268.9234864969319, 308.31507711650784,
|
||
|
270.39695562607204, 311.089425842209,
|
||
|
270.89695562607204, 311.589425842209,
|
||
|
271.98684380773494, 313.7987389832352,
|
||
|
273.69028595595563, 316.4381341741821,
|
||
|
275.50421235284637, 319.00285504651725,
|
||
|
275.50421235284637, 319.00285504651725,
|
||
|
277.4253541804354, 321.48827979987755,
|
||
|
279.45024941129833, 323.8899295308661,
|
||
|
281.57524904736516, 326.20347630433844,
|
||
|
283.79652369566156, 328.4247509526349,
|
||
|
283.99652369566156, 328.7247509526349,
|
||
|
286.1100704691339, 330.54975058870167,
|
||
|
288.5117202001224, 332.5746458195646,
|
||
|
288.5117202001224, 332.5746458195646,
|
||
|
290.99714495348275, 334.4957876471537,
|
||
|
293.5618658258179, 336.3097140440444,
|
||
|
293.5618658258179, 336.3097140440444,
|
||
|
293.2618658258179, 336.1097140440444
|
||
|
]
|
||
|
|
||
|
# This set of points should be reduced to [].
|
||
|
points_4 = [100, 100, 200, 100]
|
||
|
|
||
|
# line closed (default)
|
||
|
for points in (points_1, points_2, points_3, points_4):
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
inst = Instruction()
|
||
|
aa_line = AntiAliasingLine(inst, points=points)
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(points)
|
||
|
assert aa_line.points == filtered_points + filtered_points[:2]
|
||
|
|
||
|
# without closing the line
|
||
|
for points in (points_1, points_2, points_3, points_4):
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
inst = Instruction()
|
||
|
aa_line = AntiAliasingLine(inst, points=points, close=0)
|
||
|
r(wid)
|
||
|
assert aa_line.points == self._filtered_points(points)
|
||
|
|
||
|
def test_smoothrectangle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, SmoothRectangle
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rect = SmoothRectangle(pos=(100, 100), size=(150, 150))
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(rect.points)
|
||
|
assert (
|
||
|
rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic has one of its
|
||
|
# dimensions decreased to less than 4px.
|
||
|
rect.size = (150, -2)
|
||
|
r(wid)
|
||
|
assert rect.antialiasing_line_points == []
|
||
|
|
||
|
rect.size = (150, 2)
|
||
|
r(wid)
|
||
|
assert rect.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing line rendering.
|
||
|
rect.size = (150, 150)
|
||
|
r(wid)
|
||
|
assert (
|
||
|
rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# disabling antialiasing.
|
||
|
rect.texture = self._get_texture()
|
||
|
r(wid)
|
||
|
assert rect.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing.
|
||
|
rect.source = ""
|
||
|
r(wid)
|
||
|
assert (
|
||
|
rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic is initialized with
|
||
|
# at least one of its dimensions less than 4px.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rect = SmoothRectangle(pos=(100, 100), size=(150, -3))
|
||
|
r(wid)
|
||
|
assert rect.antialiasing_line_points == []
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rect = SmoothRectangle(pos=(100, 100), size=(3.99, 3.99))
|
||
|
r(wid)
|
||
|
assert rect.antialiasing_line_points == []
|
||
|
|
||
|
def test_smoothroundedrectangle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, SmoothRoundedRectangle
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rounded_rect = SmoothRoundedRectangle(
|
||
|
pos=(100, 100),
|
||
|
size=(150, 150),
|
||
|
radius=[(10, 50), (100, 50), (0, 150), (200, 50)],
|
||
|
segments=60,
|
||
|
)
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(rounded_rect.points)
|
||
|
assert (
|
||
|
rounded_rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic has one of its
|
||
|
# dimensions decreased to less than 4px.
|
||
|
rounded_rect.size = (150, -2)
|
||
|
r(wid)
|
||
|
assert rounded_rect.antialiasing_line_points == []
|
||
|
|
||
|
rounded_rect.size = (150, 2)
|
||
|
r(wid)
|
||
|
assert rounded_rect.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing line rendering.
|
||
|
rounded_rect.size = (150, 150)
|
||
|
r(wid)
|
||
|
assert (
|
||
|
rounded_rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# disabling antialiasing.
|
||
|
rounded_rect.texture = self._get_texture()
|
||
|
r(wid)
|
||
|
assert rounded_rect.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing.
|
||
|
rounded_rect.source = ""
|
||
|
r(wid)
|
||
|
assert (
|
||
|
rounded_rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rounded_rect = SmoothRoundedRectangle(
|
||
|
pos=(100, 100), size=(150, 150), segments=0
|
||
|
)
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(rounded_rect.points)
|
||
|
assert (
|
||
|
rounded_rect.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic is initialized with
|
||
|
# at least one of its dimensions less than 4px.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rounded_rect = SmoothRoundedRectangle(
|
||
|
pos=(100, 100), size=(150, -3)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert rounded_rect.antialiasing_line_points == []
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
rounded_rect = SmoothRoundedRectangle(
|
||
|
pos=(100, 100), size=(3.99, 3.99)
|
||
|
)
|
||
|
r(wid)
|
||
|
assert rounded_rect.antialiasing_line_points == []
|
||
|
|
||
|
def test_smoothellipse(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, SmoothEllipse
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
ellipse = SmoothEllipse(pos=(100, 100), size=(150, 150))
|
||
|
r(wid)
|
||
|
ellipse_center = [
|
||
|
ellipse.pos[0] + ellipse.size[0] / 2,
|
||
|
ellipse.pos[1] + ellipse.size[1] / 2,
|
||
|
]
|
||
|
filtered_points = self._filtered_points(
|
||
|
ellipse.points + ellipse_center
|
||
|
)
|
||
|
assert (
|
||
|
ellipse.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic has one of its
|
||
|
# dimensions decreased to less than 4px
|
||
|
ellipse.size = (150, -2)
|
||
|
r(wid)
|
||
|
assert ellipse.antialiasing_line_points == []
|
||
|
|
||
|
ellipse.size = (150, 2)
|
||
|
r(wid)
|
||
|
assert ellipse.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing line rendering.
|
||
|
ellipse.size = (150, 150)
|
||
|
r(wid)
|
||
|
assert (
|
||
|
ellipse.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# disabling antialiasing.
|
||
|
ellipse.texture = self._get_texture()
|
||
|
r(wid)
|
||
|
assert ellipse.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing.
|
||
|
ellipse.source = ""
|
||
|
r(wid)
|
||
|
assert (
|
||
|
ellipse.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
ellipse = SmoothEllipse(
|
||
|
pos=(100, 100), size=(150, 150), angle_start=90, angle_end=-120
|
||
|
)
|
||
|
r(wid)
|
||
|
ellipse_center = [
|
||
|
ellipse.pos[0] + ellipse.size[0] / 2,
|
||
|
ellipse.pos[1] + ellipse.size[1] / 2,
|
||
|
]
|
||
|
filtered_points = self._filtered_points(
|
||
|
ellipse.points + ellipse_center
|
||
|
)
|
||
|
assert (
|
||
|
ellipse.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# test if antialiasing is disabled if the graphic is initialized with
|
||
|
# at least one of its dimensions less than 4px.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
ellipse = SmoothEllipse(pos=(100, 100), size=(150, -3))
|
||
|
r(wid)
|
||
|
assert ellipse.antialiasing_line_points == []
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 1, 1, 0.5)
|
||
|
ellipse = SmoothEllipse(pos=(100, 100), size=(3.99, 3.99))
|
||
|
r(wid)
|
||
|
assert ellipse.antialiasing_line_points == []
|
||
|
|
||
|
def test_smoothtriangle(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, SmoothTriangle
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 0, 0, 0.5)
|
||
|
triangle = SmoothTriangle(
|
||
|
points=[
|
||
|
100, 100,
|
||
|
200, 100,
|
||
|
150, 200,
|
||
|
500, 500, 400, 400 # Irrelevant, just for testing purposes
|
||
|
]
|
||
|
)
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(triangle.points[:6])
|
||
|
assert (
|
||
|
triangle.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(0, 0, 1, 0.5)
|
||
|
triangle = SmoothTriangle(
|
||
|
points=[
|
||
|
125, 200,
|
||
|
200, 100,
|
||
|
100, 100,
|
||
|
500, 500, 400, 400 # Irrelevant, just for testing purposes
|
||
|
]
|
||
|
)
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(triangle.points[:6])
|
||
|
assert (
|
||
|
triangle.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# Test disabling antialiasing if the points are very close.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(0, 1, 0, 0.5)
|
||
|
triangle = SmoothTriangle(
|
||
|
points=[100, 100, 100.5, 100, 100, 100.5]
|
||
|
)
|
||
|
r(wid)
|
||
|
assert triangle.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing line rendering.
|
||
|
triangle.points = [125, 200, 200, 100, 100, 100]
|
||
|
r(wid)
|
||
|
assert (
|
||
|
triangle.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# disabling antialiasing.
|
||
|
triangle.texture = self._get_texture()
|
||
|
r(wid)
|
||
|
assert triangle.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing.
|
||
|
triangle.source = ""
|
||
|
r(wid)
|
||
|
assert (
|
||
|
triangle.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
def test_smoothquad(self):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.graphics import Color, SmoothQuad
|
||
|
|
||
|
r = self.render
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 0, 0, 0.5)
|
||
|
quad = SmoothQuad(points=[100, 100, 100, 200, 200, 200, 200, 100])
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(quad.points)
|
||
|
assert (
|
||
|
quad.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(1, 0, 0, 0.5)
|
||
|
quad = SmoothQuad(points=[200, 100, 200, 200, 100, 200, 100, 100])
|
||
|
r(wid)
|
||
|
filtered_points = self._filtered_points(quad.points)
|
||
|
assert (
|
||
|
quad.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# Test disabling antialiasing if the points are very close.
|
||
|
wid = Widget()
|
||
|
with wid.canvas:
|
||
|
Color(0, 1, 0, 0.5)
|
||
|
quad = SmoothQuad(
|
||
|
points=[200, 100, 200, 100.8, 100, 100.8, 100, 100]
|
||
|
)
|
||
|
r(wid)
|
||
|
assert quad.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing line rendering.
|
||
|
quad.points = [200, 100, 200, 200, 100, 200, 100, 100]
|
||
|
r(wid)
|
||
|
assert (
|
||
|
quad.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
# disabling antialiasing.
|
||
|
quad.texture = self._get_texture()
|
||
|
r(wid)
|
||
|
assert quad.antialiasing_line_points == []
|
||
|
|
||
|
# re-enable antialiasing.
|
||
|
quad.source = ""
|
||
|
r(wid)
|
||
|
assert (
|
||
|
quad.antialiasing_line_points
|
||
|
== filtered_points + filtered_points[:2]
|
||
|
)
|
||
|
|
||
|
|
||
|
class FBOInstructionTestCase(GraphicUnitTest):
|
||
|
|
||
|
def test_fbo_pixels(self):
|
||
|
from kivy.graphics import Fbo, ClearColor, ClearBuffers, Ellipse
|
||
|
|
||
|
fbo = Fbo(size=(512, 512))
|
||
|
with fbo:
|
||
|
ClearColor(0, 0, 0, 1)
|
||
|
ClearBuffers()
|
||
|
Ellipse(pos=(100, 100), size=(100, 100))
|
||
|
fbo.draw()
|
||
|
data = fbo.pixels
|
||
|
fbo.texture.save('results.png')
|
||
|
|
||
|
|
||
|
class TransformationsTestCase(GraphicUnitTest):
|
||
|
|
||
|
def test_identity_creation(self):
|
||
|
from kivy.graphics import LoadIdentity
|
||
|
|
||
|
mat = LoadIdentity()
|
||
|
self.assertTrue(mat.stack)
|
||
|
|
||
|
def check_transform_works(self, transform_type):
|
||
|
# Normal args
|
||
|
transform = transform_type(0, 1, 2)
|
||
|
self.assertEqual(transform.x, 0)
|
||
|
self.assertEqual(transform.y, 1)
|
||
|
self.assertEqual(transform.z, 2)
|
||
|
|
||
|
# Key word args
|
||
|
transform = transform_type(x=0, y=1)
|
||
|
self.assertEqual(transform.x, 0)
|
||
|
self.assertEqual(transform.y, 1)
|
||
|
|
||
|
transform = transform_type(x=0, y=1, z=2)
|
||
|
self.assertEqual(transform.x, 0)
|
||
|
self.assertEqual(transform.y, 1)
|
||
|
self.assertEqual(transform.z, 2)
|
||
|
|
||
|
def test_translate_creation(self):
|
||
|
from kivy.graphics import Translate
|
||
|
self.check_transform_works(Translate)
|
||
|
|
||
|
def test_scale_creation(self):
|
||
|
from kivy.graphics import Scale
|
||
|
self.check_transform_works(Scale)
|
||
|
|
||
|
|
||
|
class CallbackInstructionTest(GraphicUnitTest):
|
||
|
|
||
|
def test_from_kv(self):
|
||
|
from textwrap import dedent
|
||
|
from kivy.lang import Builder
|
||
|
|
||
|
root = Builder.load_string(dedent("""\
|
||
|
Widget:
|
||
|
canvas:
|
||
|
Callback:
|
||
|
callback: lambda __: setattr(self, 'callback_test', 'TEST')
|
||
|
"""))
|
||
|
r = self.render
|
||
|
r(root)
|
||
|
self.assertTrue(root.callback_test == 'TEST')
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def widget_verify_thread(request):
|
||
|
from kivy.uix.widget import Widget
|
||
|
from kivy.config import Config
|
||
|
|
||
|
original = Config.get('graphics', 'verify_gl_main_thread')
|
||
|
Config.set('graphics', 'verify_gl_main_thread', request.param)
|
||
|
|
||
|
widget = Widget()
|
||
|
yield widget, request.param
|
||
|
|
||
|
Config.set('graphics', 'verify_gl_main_thread', original)
|
||
|
|
||
|
|
||
|
@requires_graphics
|
||
|
@pytest.mark.parametrize('widget_verify_thread', ['0', '1'], indirect=True)
|
||
|
def test_graphics_main_thread(widget_verify_thread):
|
||
|
from kivy.graphics import Color
|
||
|
|
||
|
widget, verify_thread = widget_verify_thread
|
||
|
with widget.canvas:
|
||
|
color = Color()
|
||
|
color.rgb = .1, .2, .3
|
||
|
|
||
|
|
||
|
@requires_graphics
|
||
|
@pytest.mark.parametrize('widget_verify_thread', ['0', '1'], indirect=True)
|
||
|
def test_create_graphics_second_thread(widget_verify_thread):
|
||
|
from kivy.graphics import Color
|
||
|
widget, verify_thread = widget_verify_thread
|
||
|
exception = None
|
||
|
|
||
|
def callback():
|
||
|
nonlocal exception
|
||
|
try:
|
||
|
with widget.canvas:
|
||
|
if verify_thread == '1':
|
||
|
with pytest.raises(TypeError):
|
||
|
Color()
|
||
|
else:
|
||
|
Color()
|
||
|
except BaseException as e:
|
||
|
exception = e, sys.exc_info()[2]
|
||
|
raise
|
||
|
|
||
|
thread = Thread(target=callback)
|
||
|
thread.start()
|
||
|
thread.join()
|
||
|
if exception is not None:
|
||
|
raise exception[0].with_traceback(exception[1])
|
||
|
|
||
|
|
||
|
@requires_graphics
|
||
|
@pytest.mark.parametrize('widget_verify_thread', ['0', '1'], indirect=True)
|
||
|
def test_change_graphics_second_thread(widget_verify_thread):
|
||
|
from kivy.graphics import Color
|
||
|
widget, verify_thread = widget_verify_thread
|
||
|
with widget.canvas:
|
||
|
color = Color()
|
||
|
|
||
|
exception = None
|
||
|
|
||
|
def callback():
|
||
|
nonlocal exception
|
||
|
try:
|
||
|
if verify_thread == '1':
|
||
|
with pytest.raises(TypeError):
|
||
|
color.rgb = .1, .2, .3
|
||
|
else:
|
||
|
color.rgb = .1, .2, .3
|
||
|
except BaseException as e:
|
||
|
exception = e, sys.exc_info()[2]
|
||
|
raise
|
||
|
|
||
|
thread = Thread(target=callback)
|
||
|
thread.start()
|
||
|
thread.join()
|
||
|
if exception is not None:
|
||
|
raise exception[0].with_traceback(exception[1])
|