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 newAdaptableControlto suspend layout operations while the control is being configured. - Set any
AdaptableControlproperties desired, such asBackColor. - Create the
ControlAdapterobjects. All of these objects, such asViewingAdapter, eventually derive fromControlAdapter. These adapters all perform different tasks, as noted in the comments. For instance,ViewingAdapterimplementsIViewingContextfor framing or ensuring that items are visible. Configure these adapters as needed. For instance,HoverAdapterneeds to subscribe to some events. - Call
AdaptableControl.Adapt()with an array of theControlAdapterobjects. You can use as manyControlAdapterobjects as you want. - Invoke
ResumeLayout()on the newAdaptableControlto resume layout operations. - Perform any other initialization needed, such as setting up contexts, documents, initializing DOM adapters, and so on.
- Register the
AdaptableControlby invokingRegisterControl()on theControlHostServiceinstance.
// 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);