Can now render a canvas without the need for a View
This commit is contained in:
parent
5d0ccf5c76
commit
7b96d45e08
@ -17,7 +17,7 @@ import cairo
|
||||
import gi
|
||||
|
||||
from examples.exampleitems import Box, Circle, FatLine, PortoBox, Text
|
||||
from gaphas import Canvas, GtkView, View, state
|
||||
from gaphas import Canvas, GtkView, state
|
||||
from gaphas.canvas import Context
|
||||
from gaphas.item import Line
|
||||
from gaphas.painter import (
|
||||
@ -112,13 +112,13 @@ def create_window(canvas, title, zoom=1.0): # noqa too complex
|
||||
view = GtkView()
|
||||
view.painter = (
|
||||
PainterChain()
|
||||
.append(FreeHandPainter(ItemPainter(view)))
|
||||
.append(FreeHandPainter(ItemPainter(view.selection)))
|
||||
.append(HandlePainter(view))
|
||||
.append(FocusedItemPainter(view))
|
||||
.append(ToolPainter(view))
|
||||
)
|
||||
view.bounding_box_painter = BoundingBoxPainter(
|
||||
FreeHandPainter(ItemPainter(view)), view.bounding_box_updater
|
||||
FreeHandPainter(ItemPainter(view.selection)), view.bounding_box_updater
|
||||
)
|
||||
w = Gtk.Window()
|
||||
w.set_title(title)
|
||||
@ -236,25 +236,26 @@ def create_window(canvas, title, zoom=1.0): # noqa too complex
|
||||
b = Gtk.Button.new_with_label("Write demo.png")
|
||||
|
||||
def on_write_demo_png_clicked(button):
|
||||
svgview = View(view.canvas)
|
||||
svgview.painter = ItemPainter(svgview)
|
||||
painter = ItemPainter()
|
||||
|
||||
# Update bounding boxes with a temporary CairoContext
|
||||
# (used for stuff like calculating font metrics)
|
||||
tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
|
||||
tmpcr = cairo.Context(tmpsurface)
|
||||
svgview.update_bounding_box(tmpcr)
|
||||
bounding_box = (
|
||||
BoundingBoxPainter(painter)
|
||||
.paint(canvas.get_all_items(), tmpcr)
|
||||
.bounding_box
|
||||
)
|
||||
tmpcr.show_page()
|
||||
tmpsurface.flush()
|
||||
|
||||
w, h = svgview.bounding_box.width, svgview.bounding_box.height
|
||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(w), int(h))
|
||||
surface = cairo.ImageSurface(
|
||||
cairo.FORMAT_ARGB32, int(bounding_box.width), int(bounding_box.height)
|
||||
)
|
||||
cr = cairo.Context(surface)
|
||||
svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
|
||||
cr.save()
|
||||
paint(svgview, cr)
|
||||
|
||||
cr.restore()
|
||||
cr.translate(-bounding_box.x, -bounding_box.y)
|
||||
painter.paint(items=view.canvas.get_all_items(), cairo=cr)
|
||||
cr.show_page()
|
||||
surface.write_to_png("demo.png")
|
||||
|
||||
@ -264,22 +265,26 @@ def create_window(canvas, title, zoom=1.0): # noqa too complex
|
||||
b = Gtk.Button.new_with_label("Write demo.svg")
|
||||
|
||||
def on_write_demo_svg_clicked(button):
|
||||
svgview = View(view.canvas)
|
||||
svgview.painter = ItemPainter(svgview)
|
||||
painter = ItemPainter()
|
||||
|
||||
# Update bounding boxes with a temporaly CairoContext
|
||||
# (used for stuff like calculating font metrics)
|
||||
tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
|
||||
tmpcr = cairo.Context(tmpsurface)
|
||||
svgview.update_bounding_box(tmpcr)
|
||||
bounding_box = (
|
||||
BoundingBoxPainter(painter)
|
||||
.paint(canvas.get_all_items(), tmpcr)
|
||||
.bounding_box
|
||||
)
|
||||
tmpcr.show_page()
|
||||
tmpsurface.flush()
|
||||
|
||||
w, h = svgview.bounding_box.width, svgview.bounding_box.height
|
||||
surface = cairo.SVGSurface("demo.svg", w, h)
|
||||
surface = cairo.SVGSurface(
|
||||
"demo.svg", int(bounding_box.width), int(bounding_box.height)
|
||||
)
|
||||
cr = cairo.Context(surface)
|
||||
svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
|
||||
paint(svgview, cr)
|
||||
cr.translate(-bounding_box.x, -bounding_box.y)
|
||||
painter.paint(items=view.canvas.get_all_items(), cairo=cr)
|
||||
cr.show_page()
|
||||
surface.flush()
|
||||
surface.finish()
|
||||
|
@ -12,7 +12,7 @@ def DefaultPainter(view) -> Painter:
|
||||
"""Default painter, containing item, handle and tool painters."""
|
||||
return (
|
||||
PainterChain()
|
||||
.append(ItemPainter(view))
|
||||
.append(ItemPainter(view.selection))
|
||||
.append(HandlePainter(view))
|
||||
.append(FocusedItemPainter(view))
|
||||
.append(ToolPainter(view))
|
||||
|
@ -98,10 +98,21 @@ class BoundingBoxPainter:
|
||||
def __init__(
|
||||
self,
|
||||
item_painter: ItemPainterType,
|
||||
bounding_box_updater: Callable[[Item, Rectangle], None],
|
||||
bounding_box_updater: Optional[Callable[[Item, Rectangle], None]] = None,
|
||||
):
|
||||
self.item_painter = item_painter
|
||||
self.bounding_box_updater = bounding_box_updater
|
||||
if bounding_box_updater:
|
||||
self.bounding_box_updater = bounding_box_updater
|
||||
else:
|
||||
self.bounding_box = Rectangle()
|
||||
|
||||
def default_bounding_box_updater(item, bounds):
|
||||
if not self.bounding_box:
|
||||
self.bounding_box = Rectangle(*bounds)
|
||||
else:
|
||||
self.bounding_box += bounds
|
||||
|
||||
self.bounding_box_updater = default_bounding_box_updater
|
||||
|
||||
def paint_item(self, item, cairo):
|
||||
cairo = CairoBoundingBoxContext(cairo)
|
||||
@ -118,7 +129,8 @@ class BoundingBoxPainter:
|
||||
bounds.expand(1)
|
||||
self.bounding_box_updater(item, bounds)
|
||||
|
||||
def paint(self, items: Sequence[Item], cairo):
|
||||
def paint(self, items: Sequence[Item], cairo) -> BoundingBoxPainter:
|
||||
"""Draw the items."""
|
||||
for item in items:
|
||||
self.paint_item(item, cairo)
|
||||
return self
|
||||
|
@ -1,9 +1,10 @@
|
||||
from typing import Sequence
|
||||
from typing import Optional, Sequence
|
||||
|
||||
from cairo import LINE_JOIN_ROUND
|
||||
|
||||
from gaphas.canvas import Context
|
||||
from gaphas.item import Item
|
||||
from gaphas.view.selection import Selection
|
||||
|
||||
# The tolerance for Cairo. Bigger values increase speed and reduce accuracy
|
||||
# (default: 0.1)
|
||||
@ -25,25 +26,26 @@ class ItemPainter:
|
||||
|
||||
draw_all = False
|
||||
|
||||
def __init__(self, view=None):
|
||||
assert view
|
||||
self.view = view
|
||||
def __init__(self, selection: Optional[Selection] = None):
|
||||
self.selection = selection
|
||||
|
||||
def paint_item(self, item, cairo):
|
||||
view = self.view
|
||||
cairo.save()
|
||||
try:
|
||||
cairo.transform(item.matrix_i2c.to_cairo())
|
||||
|
||||
selection = self.selection
|
||||
if not selection:
|
||||
selection = Selection()
|
||||
item.draw(
|
||||
DrawContext(
|
||||
painter=self,
|
||||
cairo=cairo,
|
||||
_item=item,
|
||||
selected=(item in view.selection.selected_items),
|
||||
focused=(item is view.selection.focused_item),
|
||||
hovered=(item is view.selection.hovered_item),
|
||||
dropzone=(item is view.selection.dropzone_item),
|
||||
selected=(item in selection.selected_items),
|
||||
focused=(item is selection.focused_item),
|
||||
hovered=(item is selection.hovered_item),
|
||||
dropzone=(item is selection.dropzone_item),
|
||||
draw_all=self.draw_all,
|
||||
)
|
||||
)
|
||||
|
@ -15,7 +15,7 @@ class View:
|
||||
self._matrix = Matrix()
|
||||
self._painter: Painter = DefaultPainter(self)
|
||||
self._bounding_box_painter: Painter = BoundingBoxPainter(
|
||||
ItemPainter(self), self.bounding_box_updater
|
||||
ItemPainter(self.selection), self.bounding_box_updater # type: ignore[attr-defined]
|
||||
)
|
||||
|
||||
self._qtree: Quadtree[Item, Tuple[float, float, float, float]] = Quadtree()
|
||||
|
@ -4,7 +4,7 @@ import pytest
|
||||
from gaphas.canvas import Canvas
|
||||
from gaphas.item import Item
|
||||
from gaphas.segment import HandleFinder, Line, Segment, SegmentHandleFinder
|
||||
from gaphas.view import View
|
||||
from gaphas.view import GtkView
|
||||
|
||||
|
||||
class SegmentFixture:
|
||||
@ -12,7 +12,7 @@ class SegmentFixture:
|
||||
self.canvas = Canvas()
|
||||
self.line = Line()
|
||||
self.canvas.add(self.line)
|
||||
self.view = View(self.canvas)
|
||||
self.view = GtkView(self.canvas)
|
||||
self.item = Item()
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ from gi.repository import Gtk
|
||||
|
||||
from gaphas.canvas import Canvas
|
||||
from gaphas.item import Element as Box
|
||||
from gaphas.view import GtkView, View
|
||||
from gaphas.view import GtkView
|
||||
|
||||
|
||||
class ViewFixture:
|
||||
@ -91,14 +91,6 @@ def test_item_removal(view_fixture):
|
||||
def test_view_registration(view_fixture):
|
||||
canvas = Canvas()
|
||||
|
||||
# Simple views do not register on the canvas
|
||||
|
||||
view = View(canvas)
|
||||
assert len(canvas._registered_views) == 0
|
||||
|
||||
box = Box()
|
||||
canvas.add(box)
|
||||
|
||||
# GTK view does register for updates though
|
||||
|
||||
view = GtkView(canvas)
|
||||
|
Loading…
x
Reference in New Issue
Block a user