bugMyPaint - Bugs: bug #18574, Need a better abstraction of...

Show feedback again

You are not allowed to post comments on this tracker with your current authentification level.

bug #18574: Need a better abstraction of canvas interaction modes

Submitted by:  Andrew Chadwick <achadwick>
Submitted on:  Sat Aug 27 00:46:51 2011  
Severity: 5 - BlockerPriority: 6
Status: FixedPrivacy: Public
Assigned to: Andrew Chadwick <achadwick>Open/Closed: Closed
Release: git 796d220Planned Release: None
Operating System: 

(Jump to the original submission Jump to the original submission)

Tue Nov 20 14:33:09 2012, comment #11:

We now have a reasonable mode stack abstraction for housing temporary modes, and what seems like reliable logic for switching new temp modes on or switching to other modes wholesale via actions. All of the previous methods of doing stuff on the canvas now go via the top thing on the stack, and the system seems to cope well with on-canvas overlays like the frame and is capable of handling per-mode special dialog windows. Nice and flexible, I hope :)

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Tue Aug 7 02:02:23 2012, comment #10:

https://gitorious.org/mypaint/mypaint/commit/366e1007755c8e572 contains the basis of a proper interaction mode stack, which abstracts out the event handling. Hopefully it doesn't introduce any regressions yet :)

Input events are connected to each TDW's eventbox, but are dispatched only to the handler methods of the top mode on the stack.

Backend-wise, rendering can be farmed out to anything canvas-like which can sit in an eventbox.

It should now be possible to add actions for manipulating the mode stack in a stateful way: so if we want a button for entering a oneshot frame manipulation mode which starts on the next button-press-drag, we can add it.

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Thu Jan 12 02:22:59 2012, comment #9:

Generalised interface for drawing overlays via Cairo added to master: https://gitorious.org/mypaint/mypaint/commit/619789d13

That's one part of the puzzle: drawing routines can be exposed as overlay objects that know when/how/where they should draw. Let's migrate the frame drawing code to this at our leisure.

Next step is to work on the whole "what's a mode" question. I'm looking at https://gitorious.org/~optigon/mypaint/optigon-mypaint/commits/rj/straight_lines_with_angle_constraints interestedly now since it introduces modality for basic drawing operations and has some interesting UI.

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Fri Jan 6 15:45:43 2012, comment #8:

Yet another usecase:
When picking context (in fullscreen mode) display the name of the layer picked from.

Till Hartmann <tillux>
Project Member
Sun Jan 1 15:26:45 2012, comment #7:

Wishlist bug #19207 ("Selection and transformation tools") too, since fancy overlay rendering would be required.

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Mon Oct 3 11:24:38 2011, comment #6:

I'd say that the frame is an overlay too.

My thoughts:
Currently the tileddrawwdget is fully or partially responsible for three different things (sometimes in tight cooperation with gui.Document):
1. document rendering (including transformations)
2. UI overlays (frame, stategroups, et.c.)
3. event handling

What I would like to see as a result of this refactoring is that each of these "aspects"/responsibilities is handled by its own component.
1) stays in tileddrawwidget
2) done by one or more external instances
3) done by a Gtk.EventBox subclass

Ideally each of these components have no direct knowledge of each other.

Jon Nordby <jonnor>
Project Administrator
Mon Oct 3 09:36:33 2011, comment #5:

More whiffle, but I need to get implementing this at some point. I guess blink states aren't user-enterable canvas interaction modes, but looks like I'll be revisiting blink states too anyway (which may be sensible given there's overlay drawing involved).

Spring-loaded modes are also referred to as quasimodes in some places.

No reason why a mode can't be spring-loaded on a keypress, but implemented as a one-off mode elsewhere. One-off modes : http://designinginterfaces.com/firstedition/index.php?page=One-Off_Mode#. I'd want one-off modes to be exitable by pressing Escape, so that you don't have to draw anything or click your previous mode to get out and back to where you were. Other than that, I want everything to behave like a single bank of radio buttons would.

So line drawing, would be spring-loaded on the shift key (by default), and set as a one-off mode on its toolbar button and menu entry. Press the modifier down and the toolbar buttons change state to reflect the temporary mode. Release it and you go back to the previous state.

(Could this get irritating since modifiers also get held down for accelerators? Sigh.)

Looks like a regular RadioAction group, but with some sort of keypress-aware manager watching its changes, keeping a record of the previous action, and sometimes prodding the group's state in response to key releases. Sounds familiar, and probably makes it easier to avoid entering another mode while currently in a spring-loaded mode (can signal handlers stop RadioActions from changing state by returning particular values?)

Overlay drawing looks wider in scope than this, but could also be mutually exclusive. Unless we want blink states to be rendered at the same time as overlays for line drawing or other stuff?

Maybe the frame (not the manipulatable one, the one you get while painting) is an overlay in the same sense too. In which case that's three categories of overlay (or two).

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Sat Aug 27 09:05:56 2011, comment #4:

Absolutely no objection if you want to refactor this code.

The stategroups code confuses me too (and I introduced it...), but I do like many of the ways of interaction that are implemented with them. But maybe I used a single concept for too many different things here.

Exiting a stategroup is hairy, but IIRC it also abstracts (or was meant to abstract) some common functionality (eg. do we have a mouse grab active or was it activated by keyboard, do we have an active timeout handler that we must remove...). The idea was to seperate how the state is entered or left from the setup/teardown code that is state-specific.

At some point, my idea was to put all mutually exclusive states into a single stategroup, so they can cancel each other (maybe not a good idea; a stack might work better?). And somewhere interweaved with all this code lives the unification of "mouse buttons" and "keyboard buttons" into the same "button state" concept, so you can use the same color picker code by either holding a mouse button or by holding a key. And also the concept of a pop-up timeout, and so on...

Some thought input:

What I miss in your list (maybe intentional?) is the "layerblink", "layersolo" and "strokeblink" states. Layersolo at least is a persistent state at the moment (but maybe it should not be a state? but I like to enter it "spring-loaded" by holding a key down sometimes), working mostly independent of things like color picker and brush modes. Talking about independence, the timeout of the "blink" states should not prevent the user from doing an action; but they can be either independent of other states, or they can be canceled whenever the user does something else.

OK I'm done babbling now :-)

Martin Renold <martinxyz>
Project Administrator
Sat Aug 27 01:09:43 2011, comment #3:

Bug #16869 too: it may be helped by making modes like the pickers enter-able using GtkActions.

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Sat Aug 27 00:50:24 2011, comment #2:

Also, bah. For bug 18423, read bug #18374.

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Sat Aug 27 00:47:33 2011, comment #1:

Linking properly, bug #17856, bug #17983, and bug #18423

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.
Sat Aug 27 00:46:51 2011, original submission:

Blocks bug 17856, bug 17983, and bug 18423; maybe others.

As mentioned in the bugs above and on the mailing list[1], we need a better abstraction of how the user switches between different ways of interaction with the canvas. Currently this is handled by gui/stategroup.py and a bunch of special modifier key detection in the drawing motion handlers. Exiting a State looks hairy and I find it difficult to wrap my head around!

So, planning this slice of work:

  • MyPaint should be in just one mode at a time.
  • Mode objects should provide drawing routines for any fancy overlays they do, and handlers for what happens when the user mouses around on the canvas while in the mode.
  • Modes need to be bindable to gtk.Actions so they can be activated (entered) reliably from menu and toolbar entries. Probably RadioActions would be the best fit.
  • Ideally, make the current modifiers enter and leave their equivalent Mode while the key is held: in other words make them "spring loaded"[2] on shift, ctrl or whatever. This may require a small history stack of modes, or a ref to the previous mode somewhere.
  • Retain existing State leaving conditions: timer, move-outside, perform-action etc.

The list of modes should probably be something like that in [1]. Specifically:

  • freehand painting (with the current brush blend mode)
  • line drawing (x2: with continuation and without; using the current brush blend mode)
  • frame editing (as yet unimplemented ☺)
  • colour changing (arguable; may not really be a mode; oneshot if it is)
  • pickers (x3: layer, color, context; should be oneshots)
  • (arguably) panning, rotation, zooming (x3; all oneshots)
  • (arguably) resizing the brush with on-screen feedback (as yet

unimplemented; bug #18423)

A "one-shot mode"[3] is one which does one thing then resets to a different mode when the action is complete.

[1] https://mail.gna.org/public/mypaint-discuss/2011-07/msg00030.html
[2] http://www.useit.com/alertbox/springload.html
[3] http://books.google.com/books?id=oCTSeKfMaWUC&lpg=PA257&ots=mmf4eYTZPx&dq=designing%20interfaces%20%22spring%20loaded%20modes%22&pg=PA255#v=onepage&q&f=false

Andrew Chadwick <achadwick>
Project AdministratorIn charge of this item.


No files currently attached


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -unavailable- added by tillux (Posted a comment)
  • -unavailable- added by jonnor (Posted a comment)
  • -unavailable- added by martinxyz (Posted a comment)
  • -unavailable- added by achadwick (Submitted the item)

    Do you think this task is very important?
    If so, you can click here to add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.


    Error: not logged in



    Follow 5 latest changes.

    Date Changed By Updated Field Previous Value => Replaced By
    Tue Nov 20 14:33:09 2012achadwickStatusIn Progress=>Fixed
    Tue Aug 7 02:02:23 2012achadwickStatusConfirmed=>In Progress
    Thu Jan 12 02:22:59 2012achadwickStatusWish=>Confirmed
      Assigned toNone=>achadwick
    Show feedback again

    Back to the top

    Powered by Savane 3.1-cleanup