Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Welcome, Guest. Please login or register.
October 20, 2017, 09:17:03 AM
Home Help Search Login Register
News: Please DM @puremvc on Twitter to gain forum access. Spambots are why we can't have nice things.
Pages: [1]
Print
Author Topic: Tool and Canvas Architecture  (Read 11413 times)
ScottR
Newbie
*
Posts: 4


View Profile
« on: July 08, 2009, 09:28:05 AM »

I've been working through converting the beginning of a Flash/Air based application that is a simple drawing program as a test-case for developing a new larger-scale Flash/Air project on the PureMVC framework.

Now that I have spent some time running through examples and getting a pretty good understanding of the framework, I'm having a little bit of trouble trying to model out an implementation model for a ToolBar and Drawing Canvas.

The ToolBar is set up as a View/Mediator pair that sends notifications to the canvas of what the currently selected Tool is.  And the Canvas is set up to handle mouse click events and manage user input.

What I am struggling with is the best-practice approach for implementing the individual tool components and how they would properly fit into a PureMVC application.

For example.  I have a ToolBar, and the user selects the square tool.  This dispatches a notification to the Canvas to filter all user input through a Tool, and allow the Tool to direct the output that is displayed on the canvas.

Before PureMVC I would typically write a base Tool interface, which my ToolSquare would implement, having mouse down, mouse up, and mouse move handlers.  Then the ToolSquare would manage the input, run it through a series of functions to create the drawing object to be added to the canvas, and then dispatch an "AddToCanvas" CustomEvent that would pass a drawing object to the stage.

With PureMVC I would likely dispatch a CreateSquare, {properties} notification that the CanvasMediator would handle, calling the proper View functions to create the drawing object.

But what is the best practice approach for sticking a currently selected Tool within the path of the user input caught by the mediator.

Should I handle a tool as a View Component, like a Button, therefore writing a separate base class library to handle input based on the Interface?  Should the tool be a Command structure that dispatches Notifications based on input?

Am I at all on the right track here?

I'm really excited to dig into this framework and apply some more rigid and better organized development methodologies within the applications we develop here--but just like learning AS3 and the Event model, this is a definite shift in approach from how I am used to thinking.  Definitely it feels like the right direction, I'm just trying to get my habits to catch up.

Any input you folks might have on an approach to architecture here would be appreciated.

Best,

-Scott
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW
« Reply #1 on: July 08, 2009, 03:24:49 PM »

I know that numerous folks on these forums have implemented toolbars, so I'm hoping someone (Simon?, Stef?) might chime in with how they pulled it off.

It sounds to me like the tool and the canvas could talk to each other unmediated (via interfaces), and its a matter of the right tool being set as a property of the canvas, which could be done by a mediator based on that notification you described.

You could follow the State pattern (http://en.wikipedia.org/wiki/State_pattern), where the canvas has different behaviors depending on the tool selected. Those behaviors are handled by sublcasses of an abstract tool class.

Coincidentally, the referenced URL on Wikipedia describes this exact scenario with pseudo code.

-=Cliff>
Logged
ScottR
Newbie
*
Posts: 4


View Profile
« Reply #2 on: July 08, 2009, 07:12:57 PM »

Cliff,

Thanks for the suggestions, hopefully somebody has some insight to share.

My issues are less with PureMVC and more with changing my approach and thought processes when  developing.  I'm so used to tightly integrating my application logic with references to the views in Flash/AS3 that it is very unnatural right now for me to think about abstracting everything out into separate modules.

The more examples I look at and the more reading and thinking I do, the closer I feel I'm coming.

Thanks,

-Scott
Logged
ScottR
Newbie
*
Posts: 4


View Profile
« Reply #3 on: July 10, 2009, 06:55:16 AM »

Cliff,

I went back and looked through that wiki link again, which is how I ended up solving my dilemma.

But I do have a question for you regarding application folder structure.

I have a tool interface, and then a handful of tools that implement that interface.  My CanvasMediator is filtering mouse events through the tools.

But where is a good place to sit these files?  They seem out of place right now sitting in the root of my view folder.... so where would you tuck them away?

Thanks,

-Scott
Logged
Jason MacDonald
Sr. Member
****
Posts: 243


View Profile
« Reply #4 on: July 10, 2009, 07:57:40 AM »

My typical structure is:

APP
+--commands
+--constants
+--model
    +--vo
+--view
    +--components

You could add a tools folder under the components directory. I usually sub divide up my View folder into multiple folders if I have a lot of views.

Example:

view
    |--Main view mediators here
    +--components - main view components
    +-- tools
        |--Tool Mediators Here
        +--components - Tool Components Here
   
« Last Edit: July 10, 2009, 08:03:15 AM by Jason MacDonald » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW
« Reply #5 on: July 10, 2009, 08:32:36 AM »

My suggested structure is:

Standard Version Project
MyApp
+---controller
+---model       
      +---vo     
      +---enum
      +---constants
+---view
      +---components

MultiCore Version Project
MyApp
+---common
   +---model   
      +---vo     
      +---enum
      +---constants
   +---view
         +---components

+---cores
   +---corex
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---corey
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---corez
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---shell
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

-=Cliff>
Logged
Jason MacDonald
Sr. Member
****
Posts: 243


View Profile
« Reply #6 on: July 10, 2009, 09:25:48 AM »

If I'm not mistaken, I believe his "tools" are simply components, not cores. Hence my suggestion of putting them in subfolders of view ONLY if he has a lot of views and wants to organize them.

Otherwise, despite the naming of commands as controller, I use the same setup as you Cliff for MultiCore projects.
Logged
ScottR
Newbie
*
Posts: 4


View Profile
« Reply #7 on: July 23, 2009, 02:35:35 PM »

Thanks for the advice.  It helped me greatly in framing out my toolbar and cursor development.

Now I'm trying to identify another approach for dealing with the drawing objects that the tools will create.

In flash, my process would generally be:

1. On click, create temporary shape, save reference to it in canvas.
2. On mouse move, update shape properties based on X/Y coordinates of Mouse
3. On release, stop updating shape and leave it where it stands.


Within PureMVC I am trying to implement a drawing framework that is Command based and utilizes, Add, Update, and Delete methods so I can build-in an undo stack.


So here is my current thought process on how that will need to be accomplished.

1. On mouse click, trigger Add Draw_Object command.
2. D_O Command generates UniqueName for drawing object.
2. D_O Command calls canvas function to create new Rectangle movie clip, function returns MC.
3. D_O Command creates a new Draw_Object proxy who's only member variable is a reference to the stage MC using the UniqueName.
4. D_O Command references CanvasContentsProxy and Adds new Draw_Object to the CanvasItems array.
5. D_O Command creates new Mediator for Draw_Object using the UniqueName.
6. Notification is Dispatched for Canvas to update view based on contents of CanvasContents' CanvasItems array.
7. Undo comand is stored in UndoStackDO.
8. Command Complete.

Does this seem like I am overcomplicating things?

I sure feel like it.

Thanks,

-Scott

Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW
« Reply #8 on: July 26, 2009, 09:37:55 AM »

Quote
Does this seem like I am overcomplicating things?

Yep.

I'm not sure all this needs to happen in the framework. The framework probably doesn't need to know about the object until it exists, at which time it persists the representation of the object (all the data inputs needed to recreate said object later).

So, you could encapsulate the creation of the new object inside a view component, which alerts its mediator when the object is created, deleted or modified. And it accepts representations of objects to be displayed.

Using the GoF Builder Pattern1, you could separate the building of the object from its representation. That pattern defines the interactions between a Director and a Builder. The Director might be your tool component, the Builder is the class that creates the needed object.

And you'd need a value object to hold the representation to be persisted. The shape objects created by the builder are graphical objects that expose a custom draw method that reads its properties from this representation value object. This representation object should be a public property of the shape objects.

Then we're not far from where you started for the creational process:
  • On mouse down, the tool view component calls the builder to create the new object.
  • On mouse move, the tool updates the new shape object's properties based on the x/y coords (via the representation object exposed by the shape)
  • On mouse up, stop drawing and send a SHAPE_CREATED event that the tool's mediator hears.
  • The tool's mediator responds to the SHAPE_CREATED event by calling the ShapeProxy's addShape method, passing the representation value object of the shape (not the graphical shape object itself) gathered from the tool.
  • If you want to have a history keeper that can undo things, you might send a notification from the ShapeProxy after the shape has been created. (Have a look at the Undo utility).

Referring this new actor type to the hierarchies described previously on this thread, these would go into the view/builders package, sibling to view/components.

1 http://en.wikipedia.org/wiki/Builder_pattern
-=Cliff>
« Last Edit: July 26, 2009, 11:20:50 AM by puremvc » Logged
ABloch
Newbie
*
Posts: 7


View Profile Email
« Reply #9 on: June 06, 2012, 05:03:04 AM »

Hi,
I know this topic is a bit old, but I am currently working on a multicore app architecture, and I 've found the example provided by Cliff in his answer. I think the architecture is great, however I don't really get the differences between the MyApp model/controller and the shell ones? Isn't the shell supposed to be the root core of the application?
TIA,
Cyrill
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW
« Reply #10 on: June 06, 2012, 07:31:56 AM »

I assume you're talking about this structure:

MultiCore Version Project
Code:
MyApp

+---common
   +---model   
      +---vo     
      +---enum
      +---constants
   +---view
         +---components

+---cores
   +---corex
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---corey
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---corez
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

   +---shell
      +---controller
      +---model     
         +---vo     
         +---enum 
      +---view         
         +---components

This structure defines a common package, which all cores including the shell will use. Then it defines a cores package which includes each of the cores in the app, of which shell is one.

Note that while the online demos (PipeWorks and Modularity) have all this stuff built into a single project, you may not actually want to do that in real life. You might have a separate library project for common, and separate libraries for each core, plus one or more application projects that use these libraries. So, in terms of structure what you're seeing is an aggregate of all code in the codebase (i.e., all projects combined).

Hope this helps. Let me know if there's still something you're missing.
Logged
4ucai
Jr. Member
**
Posts: 17


View Profile
« Reply #11 on: July 21, 2012, 09:49:05 PM »

Hi Cliff,

In the multicore version structure you posted, what do you usually put inside the enum folders? and what's the difference between constants and enum under the common package?

Thanks.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW
« Reply #12 on: July 22, 2012, 08:23:06 AM »

The Typesafe Enum1 pattern is a way of enumerating all the possible entries in a restricted list, like a combo box full of color choices, say.

Enums have advantages over just using constants. If you have a bunch of string constants defining your list entries, you're better off than just using string literals for sure, but any string could be supplied, not just ones defined by constant. Also, the order of items in a set of constants is not encoded in any way.

So, there are times when a better solution to predefined list is desired. Some languages such as Java have built-in implementations of the Typesafe Enum pattern, but in AS3, we have to roll our own.

Here is an example from the PureMVC AS3/Flex Employee Admin Demo. It provides the valid list of items, item order, an equals method for comparing against any other enum of the same type, and also a special method for getting a combo list with an additional 'None Selected' entry.  So if you fill the combo box with the result of a call to  comboList(), your combo boxes will come up with something in them other than the first item, but your code that checks to see if the form has been filled out can just check that the combo selection is contained in the result of a call to the list() method.

Code:
package org.puremvc.as3.demos.flex.employeeadmin.model.enum
{
    
    [Bindable]
    public class DeptEnum
    {
        public static const NONE_SELECTED:DeptEnum   = new DeptEnum( "--None Selected--"  ,-1 );
        public static const ACCT:DeptEnum            = new DeptEnum( "Accounting"         , 0 );
        public static const SALES:DeptEnum           = new DeptEnum( "Sales"              , 1 );
        public static const PLANT:DeptEnum           = new DeptEnum( "Plant"              , 2 );
        public static const SHIPPING:DeptEnum        = new DeptEnum( "Shipping"           , 3 );
        public static const QC:DeptEnum              = new DeptEnum( "Quality Control"    , 4 );
        
        public var ordinal:int;
        public var value:String;
        
        public function DeptEnum ( value:String, ordinal:int )
        {
            this.value = value;
            this.ordinal = ordinal;
        }

        public static function get list():Array
        {
            return [ ACCT,
                     SALES,
                     PLANT
                    ];
        }

        public static function get comboList():Array
        {
            var cList:Array = DeptEnum.list;
            cList.unshift( NONE_SELECTED );
            return cList;
        }
        
        public function equals( enum:RoleEnum ):Boolean
        {
            return ( this.ordinal == enum.ordinal && this.value == enum.value );
        }
    }
}


1 Typesafe Enums - http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html
« Last Edit: July 22, 2012, 08:27:01 AM by puremvc » Logged
4ucai
Jr. Member
**
Posts: 17


View Profile
« Reply #13 on: July 24, 2012, 12:56:04 AM »

Ok, I think I could definitely use this in my ongoing project.

Thanks Cliff
Logged
Pages: [1]
Print
Jump to: