Skip to content

Rethink CanvasItem class and Transform Panel bindings #336

@Alecaddd

Description

@Alecaddd

This is more a of a general issue to discuss basic architecture and future improvements to a substantial area of the application.

The CanvasItem problem

We currently have in place a base abstract class called CanvasItem which we use to build all the different items on top of it (Rectangle, Ellipse, Image, etc.).
The problems for this approach are starting to show as we implement more and more features and we make the interactions and transformations with the Canvas more complex.
These are few highlights of what we stumbled upon so far:

  • Not all the attributes from the base class are necessary/used in the child classes, but we're forced to declare anyway.
  • Some important attributes (eg. X and Y) are not directly accessible from the base object, so we need to typecast the proper class or create helper methods.
  • Unique classes like Images and Artboards, have substantially different needs and don't leverage most of the shared methods coming from the base object.

How can we improve this?

The Transform Panel problem

The Transform panel allows to edit item's attributes (x, y, width, height, etc) through input fields.
These attributes can be also modified directly on the canvas, by moving and resizing the selected items.
These fields need a bidirectional binding with the specific attribute (eg. the X input is binded to the item's X attribute), so when one changes, the other follows accordingly, and proper signals are emitted to allow the UI to react accordingly (eg. the selection bounds follow, the artboards get updated, etc.).

Since items can be manipulated directly from the Canvas, we need to deactivate some of these signals and bindings to not fall into an infinite loop of, the item gets updated, the input field receives the signal which updates the value, the input field emits the signal because the value changed, the item receives the signal to updated the value, the item emits the signal with the new value, the input receives the signal... and it goes on and on and on.

We solved this issue by implementing some conditions and by unbinding properties at the right time, but this solution causes some problems:

  • Whenever an item gets moved, we check if it falls inside or outside an artboard to change hierarchy. We do this when the mouse button gets released. Doing this on the X and Y binding in the Transform Panel, causes that condition to run for every moved pixel. Pretty intense in terms of resources.
  • For Image, we rescale the pixbuf after an image gets scaled down to lower the quality and speed up the canvas. We do this when the mouse button gets released. Doing this on the WIDTH and HEIGHT bindings in the Transform Panel, causes that condition to run for every changed pixel. Pretty intense in terms of resources.

These wouldn't be critical issues if we assume the user mainly interact with the canvas and changes those values sporadically, maybe a few pixels at a time, but we can't assume that.
Sometimes the user might focus on the X input and hold down the arrow up key, causing hundreds of triggers consecutively.

How can we improve this?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions