Oct 16, 2010 at 3:28 PM
Can anyone point me to documention or a high level discussion of what all the following are and how they relate to each other:
I've been studying the code for days now and I follow how each is used in some cases (e.g. ShapeEditorApp, MapControl built in tools)
However, I'd like a set of guildelines to point me to which to use in various patterns.
For example, why are the built in functions Pan/Zoom/ etc built into the map control instead of loaded as plugins? They get loaded to the same List<MapFunction> right? The Built in functions are activated with "Map.FunctionMode"
while othee MapFunctions use ActivateMapFunction(). But activate map function seems only half baked because you need to manage cursors and stuff in the Calling code not in the mapfunction.
Can anyway put me on the path to enlightenment in this area?
Oct 16, 2010 at 6:06 PM
The history of our functional approach gives a little insight into what's going on. Initially we featured no extensibility at all. In MW4, the Map control had the built in functionality and that was the end of that. The up-side was that
you could very easily control which of those built in functions you were using through an enumeration, which not only controlled what the cursor looked like but what behavior you got from the map. On the down side, even if you wanted to control selection,
you had to do that independently. The enumeration was an effort to retain at least some of that easy-to-use feel from the original Map control. The existing system starts with some basic functionality, but then attempts to make things extensible.
Extensible automatically means you can't use an enumeration to control it. This does not necessarilly require the App, Extension, Plugin or token concepts. The idea is that if you added a map to your project, you could then create completely new functionality
regarding the map by writing your own MapFunction, adding it to the list and activating or deactivating it when someone presses a button.
The idea of a YeildStyle is brand new. I wanted to design a MapFunction that appeared like an icon button that you could click on, but suspended above the map. You might be in the middle of zooming as far as the rest of the map is concerned.
So I set it up so that rather than having only one MapFunction active at a time, you could have lots of them active, and any event cycles through the various functions until one of them returns "handled = true". The functions are now in a list,
rather than a dictionary, which means that you can control the priority by re-ordering the functions in the list. The closer to 0, the higher the priority and so on. The YeildStyle of "Always on" would represent a glyph which is on and
active independent of whether you are panning, zooming, selecting or whatever. The rest of the yield functionality reflects when an existing function is turned off. For instance, I might have on the zoom functionality for the scroll wheel in pan
mode. When I switch to the select method, this only affects the behavior related to the left click of the mouse. So it would turn off the pan tools, but leave active the scroll wheel zoom in and out because there is no collision of functionality.
This is an unproven concept and may be more trouble than it is worth, but I thought it was an interesting idea. To ensure that all other functions are turned off when your method is turned on, simply set your system to use all of the possible yield states
except "always on". This will turn off everything but glyph type functions that remain on all the time. Currently you have to control the cursor property manually if you want it to change while using your function.
Since complex functions can have different cursors depending on your mouse location, I didn't bother assigning a single cursor per MapFunction. In the code of the function, you have access to the map, so you can change the cursor if you want to.
I'm not sure I understand why you claim you can't control the cursor in the MapFunction. If you use the constructor that passes in the Map, you have the map all the time in the protected "Map" variable if you inherit from "MapFunction"
when writing your own MapFunction. Just make sure to pass in the Map when you create a new instance of your MapFunction.
The token represents enough information to create an instance of an App, but doesn't require the memory that loading the actual item might require. It is like a handle to instantiate an App when the App it is enabled. The original terminology
was a "Plug-in" which allows you to extend an application though a set of interfaces that give you access to the basic UI of that application. Because the term App is being used more in concept with an application that runs on a specialized
framework, rather than on any one specific application, and because Dan likes having cool logos and modern sounding names, there has been a push to rebrand the plug-in model from MapWindow 4 into more of an "App" model for extensions that can run
on any system running DotSpatial that adds an AppManager to their project. Regardless of the politics, functionally an App is basically a Plugin for DotSpatial applications. You may still see some IPlugin terms around because originally the term
Not every extension to the framework gives UI control to the extension. For instance, DataExtensions don't get access, or want access to the Map control. It is purely about implementing one of the appropriate IVectorProvider, IRasterProvider
or IImageProvider interfaces, and letting DotSpatial.Data know that you have done so. The original idea was to have all Extensions inherit from Extension to keep track of them. I don't remember how well we managed to accomplish that, and we are
leaning on using attribute tags to mark libraries that provide extensions as well as the apps themselves. Further more, data extensions have to be defined at the lower level of the DotSpatial.Data library, while the Extension class might not even be
used until you get up to the level of DotSpatial.Controls.
Oct 17, 2010 at 6:41 PM
Thanks so much for taking the time to address this discussion in so much depth. It is very helpful. I'm just getting reved up to attempt integration of DotSpatial into one of our projects and it is very encouraging to see this kind of support
in the developer community.
I can understand and sympathize with the legacy terminology as this project evolves from MapWindow to Dotspatial and new developers start contributing in various ways.
Is there any ugency to try to simplify and unify these names and objects to taget some define set of core functionality or is that way down the priority list?
I have >15 years building "Apps" and "Extensions" with many of the major commercial Spatial Apps and dev tools. If I can help with this just let me know.