Adaptable Controls - kaisu1986/ATF GitHub Wiki
The AdaptableControl
class provides an adaptable control, which is a control decorated with adapters. An adaptable control can be converted into any of its adapters by using the IAdaptable.As
method. Such a control is very versatile.
The AdaptableControl
class provides the Adapt()
method to adapt the control to all the specified adapters:
public void Adapt(params IControlAdapter[] adapters);
Each adapter provided in the array is an object of the ControlAdapter
class, implementing IControlAdapter
. This interface consists of methods to bind and unbind the adapter to or from its underlying control. The Bind()
method for each adapter is called in the order that the adapters were listed in the Adapt()
method. By convention, the bottom-most layer should appear first in the AdaptableControl
's Adapt()
method, and so the Paint
event should be subscribed to in Bind()
.
For more information on adaptation, see Adaptation in ATF.
This example from the Editor
class in the ATF FSM Editor Sample illustrates setting up an AdaptableControl
. The steps in this process are:
- Create the
AdaptableControl
. This example creates an object of the classD2dAdaptableControl
, which derives fromAdaptableControl
. - Invoke
SuspendLayout()
on the newAdaptableControl
to suspend layout operations while the control is being configured. - Set any
AdaptableControl
properties desired, such asBackColor
. - Create the
ControlAdapter
objects. All of these objects, such asViewingAdapter
, eventually derive fromControlAdapter
. These adapters all perform different tasks, as noted in the comments. For instance,ViewingAdapter
implementsIViewingContext
for framing or ensuring that items are visible. Configure these adapters as needed. For instance,HoverAdapter
needs to subscribe to some events. - Call
AdaptableControl.Adapt()
with an array of theControlAdapter
objects. You can use as manyControlAdapter
objects as you want. - Invoke
ResumeLayout()
on the newAdaptableControl
to resume layout operations. - Perform any other initialization needed, such as setting up contexts, documents, initializing DOM adapters, and so on.
- Register the
AdaptableControl
by invokingRegisterControl()
on theControlHostService
instance.
// set up the AdaptableControl for editing FSMs
var control = new D2dAdaptableControl();
control.SuspendLayout();
control.BackColor = SystemColors.ControlLight;
control.AllowDrop = true;
var transformAdapter = new TransformAdapter(); // required by several of the other adapters
transformAdapter.UniformScale = true;
transformAdapter.MinScale = new PointF(0.25f, 0.25f);
transformAdapter.MaxScale = new PointF(4, 4);
var viewingAdapter = new ViewingAdapter(transformAdapter); // implements IViewingContext for framing or ensuring that items are visible
var canvasAdapter = new CanvasAdapter(); // implements a bounded canvas to limit scrolling
var autoTranslateAdapter = // implements auto translate when the user drags out of control's client area
new AutoTranslateAdapter(transformAdapter);
var mouseTransformManipulator = // implements mouse drag translate and scale
new MouseTransformManipulator(transformAdapter);
var mouseWheelManipulator = // implements mouse wheel scale
new MouseWheelManipulator(transformAdapter);
var scrollbarAdapter = // adds scroll bars to control, driven by canvas and transform
new ScrollbarAdapter(transformAdapter, canvasAdapter);
var hoverAdapter = new HoverAdapter(); // add hover events over pickable items
hoverAdapter.HoverStarted += control_HoverStarted;
hoverAdapter.HoverStopped += control_HoverStopped;
var annotationAdaptor = new D2dAnnotationAdapter(m_theme); // display annotations under diagram
var fsmAdapter = // adapt control to allow binding to graph data
new D2dGraphAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, transformAdapter);
var fsmStateEditAdapter = // adapt control to allow state editing
new D2dGraphNodeEditAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, fsmAdapter, transformAdapter);
var fsmTransitionEditAdapter = // adapt control to allow transition
new D2dGraphEdgeEditAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, fsmAdapter, transformAdapter);
var mouseLayoutManipulator = new MouseLayoutManipulator(transformAdapter);
// apply adapters to control; ordering is from back to front, that is, the first adapter
// will be conceptually underneath all the others. Mouse and keyboard events are fed to
// the adapters in the reverse order, so it all makes sense to the user.
control.Adapt(
hoverAdapter,
scrollbarAdapter,
autoTranslateAdapter,
new RectangleDragSelector(),
transformAdapter,
viewingAdapter,
canvasAdapter,
mouseTransformManipulator,
mouseWheelManipulator,
new KeyboardGraphNavigator<State, Transition, NumberedRoute>(),
//new GridAdapter(),
annotationAdaptor,
fsmAdapter,
fsmStateEditAdapter,
fsmTransitionEditAdapter,
new LabelEditAdapter(),
new SelectionAdapter(),
mouseLayoutManipulator,
new DragDropAdapter(m_statusService),
new ContextMenuAdapter(m_commandService, m_contextMenuCommandProviders)
);
control.ResumeLayout();
// associate the control with the viewing context; other adapters use this
// adapter for viewing, layout and calculating bounds.
ViewingContext viewingContext = node.Cast<ViewingContext>();
viewingContext.Control = control;
// set document URI
document = node.As<Document>();
ControlInfo controlInfo = new ControlInfo(fileName, filePath, StandardControlGroup.Center);
//Set IsDocument to true to prevent exception in command service if two files with the
// same name, but in different directories, are opened.
controlInfo.IsDocument = true;
document.ControlInfo = controlInfo;
document.Uri = uri;
// now that the data is complete, initialize the rest of the extensions to the Dom data;
// this is needed for adapters such as validators, which may not be referenced anywhere
// but still need to be initialized.
node.InitializeExtensions();
// set control's context to main editing context
EditingContext editingContext = node.Cast<EditingContext>();
control.Context = editingContext;
// show the FSM control
m_controlHostService.RegisterControl(control, controlInfo, this);