Functionality being added with Version 14 now makes it possible for you to create custom annotations that look and behave in almost any way imaginable. Custom annotations can be made to respond to almost any key sequence: the annotation DLL sends the WM_LTANNEVENT messages LTANNEVENT_LBUTTONDOWN, LTANNEVENT-MOUSEMOVE, and the LTANNEVENT_LBUTTONUP; and the WM_LTANNEVENT IParam points to an ANNMOUSEPOS structure that contains detailed information about the mouse's position and status.
The following functions are used when creating custom annotations:
In addition, functionality for adding and maintaining user-defined handles has been added to the Annotation C++ Class Library. This functionality has been implemented by adding the AddUserHandle, GetUserHandle, GetUserHandles, ChangeUserHandle, DeleteUserHandle, EnumerateHandles, and EnumHandleCallBack functions to each of the following classes:
In addition, several messages have been added to the WM_LTANNEVENT event in order to implement the functionality for creating custom annotations.
There are 5 steps involved in creating a custom annotation:
The following narrative describes the process of creating a custom annotation.
In the LEAD toolkit, there is no LAnnotation::Define capability for moving and resizing a line simultaneously. The following example creates a custom object that demonstrates this capability. More specifically, this custom object creates a rectangle that has a line in the middle of it, and that line continues to stay in the middle whenever you resize and/or rotate the rectangle as shown in the figure below. For compelete sample code, refer to Example1 in your C:\LEADTOOLS22\Examples\Annotation\ClassLibrary\Annotate directory.
This object being created has 4 nodes. The line bisecting the rectangle has a yellow node at the top end and a gray node at the bottom end. The two sides have a node in the middle: a black node on the left and a red node on the right.
When the object is selected, you can click and drag the object to another location by clicking on a point that is not a node.
If you click on one of the two side nodes, you can adjust the width of the rectangle, and as the rectangle is redrawn, the line in the middle adjusts so it stays in the middle.
If you click on the top or bottom node, the opposite node becomes an anchor point and you can simultaneously adjust the height and rotate the rectangle as much as 90 degrees about the anchor point in either the clockwise or counterclockwise direction. The line in the middle continuously adjusts so it remains parallel to the two sides, anchored to the top and bottom, and bisects the rectangle.
To create this object, perform the following steps:
Break the custom annotation into components. At this point, it is easiest to make a copy of example1.h and example1.c, and replace each occurrence of "example1" with the name of your custom annotation object. The custom annotation object Example1 consists of a rectangle and a square. We will create the custom object by grouping together a line and a rectangle.)
Decide on the location and behavior of the annotation object handles (Example1 has four handlesone on each side, one on the top, and one on the bottom). Create defines for the handles, assigning each a unique ID. The defines for Example1 are:
#define HANDLE_ID_HORIZONTAL_TOP 100
#define HANDLE_ID_HORIZONTAL_BOTTOM 101
#define HANDLE_ID_VERTICAL_LEFT 102
#define HANDLE_ID_VERTICAL_RIGHT 103
Decide on their behavior. The behavior for the handles for Example1 are:
HANDLE_ID_VERTICAL_LEFT -- horizontal resize
HANDLE_ID_VERTICAL_RIGHT -- horizontal resize
HANDLE_ID_HORIZONTAL_TOP -- rotate around HANDLE_ID_HORIZONTAL_BOTTOM
HANDLE_ID_HORIZONTAL_BOTTOM -- vertical resize
Define the functions for creating the annotation. Create functions are called (via the WM_LBUTTONDOWN message) when creating the custom annotation using automation and the annotation menu.
Using LAnnotation::Define functions, create the object(s) that will be displayed when drawing your annotation. An outline of the object(s) will be drawn when moving the mouse during object creation.
Create each of the component annotation objects using LAnnotation::CreateAnnObject(). It is useful to create a structure (EXAMPLE1) and add this to the LPCHILDDATA structure. The EXAMPLE1 structure contains fields for everything required to create the custom annotation.
Then call LAnnotation::Define(ANNDEFINE_BEGINSET) to begin definition of the object. For illustration of this in Example1, refer to the code beginning with:
L_VOID Example1_LButtonDown(HWND hWnd, LPCHILDDATA pData);
Call LAnnotation::Define(ANNDEFINE_APPEND) for each of the component objects. For illustration of this in Example1, refer to the code beginning with:
L_VOID Example1_MouseMove(LPCHILDDATA pData);
The Example1 object has a vertical line that is moved and resized as the rectangle grows. There is no LAnnotation::Define state to do this, so it is necessary to process the LTANNEVENT_HIGHLIGHT message. This message allows you to customize the highlighting behavior).
Finish defining all of the component objects (In Example1, the components are a line and a rectangle). For each of the components, set a tag that identifies component as part of a single custom object, and also identifies the part of the custom object. This is accomplished by calling AnnSetID().
Hide the default handles for the component objects using HideDefaultHandles() .
Select the component objects using LAnnotation::SetSelected , give them their default automation values (using LAnnotation::SetAutoDefaults), and finally group them together (using LAnnotation::Group). Grouping the component objects places them all in a new annotation container, which is part of the root annotation container.
Finally, add user handles to the custom object. There are several ways to add user handles. The handles can all be added to one of the component objects, or the handles can be added to one or more of the component objects. The best choice depends on the particular custom object. (Look at the function Example1_AddUserHandles to get an idea how to add user handles.) For illustration of this in Example1, refer to the code beginning with:
L_VOID Example1_LButtonUp(LPCHILDDATA pData, L_UINT uTool);
In some cases, it may be necessary to destroy and recreate an object. (Vertical lines normally exist as independent objects and do not maintain their orientation and length with reference to other objects. These behaviors are required for the vertical line in Example1 and so the vertical line behavior must be customized. To create the illusion that the vertical line is moving you destroy the "dummy" line and recreate it where you want itin the center of the rectangle.)
Define functions for the user handles. ** Update Handle functions are called (via the LTANNEVENT_LBUTTONDOWN message) when the mouse drags a user handle.
In Example1 there are three functions, and these completely define the behavior of each user handle. Each of these functions does the following:
Restricts the mouse cursor. This can easily be done in two ways:
ii. Setting pMousePos->pt (in the pANNMOUSEPOS structure) to the adjusted point.
Set pMousePos->fUpdatePos = TRUE. The function LAnnotation::AdjustPoint can be helpful, especially when working with rotated objects. For details, see the documentation for WM_LTANNEVENT. For illustration of the first needed function in Example1, refer to the code beginning with::
L_VOID Example1_Handle_LButtonDown(LPCHILDDATA pData, pANNMOUSEPOS pMousePos);
If dragging handles HANDLE_ID_VERTICAL_LEFT or HANDLE_ID_VERTICAL_RIGHT, we want to resize the rectangle (LAnnotation::Define(ANNDEFINE_BEGINRESIZE) and move the line (LAnnotation::Define (ANNDEFINE_MOVE).
If dragging handle HANDLE_ID_HORIZONTAL_BOTTOM, we want to again resize the rectangle (LAnnotation::Define(ANNDEFINE_BEGINRESIZE)), but with the line instead of moving it, we now want to resize it. (LAnnotation::Define(ANNDEFINE_BEGINRESIZE)).
If dragging handle HANDLE_ID_HORIZONTAL_TOP, we want to rotate the rectangle around HANDLE_ID_HORIZONTAL_BOTTOM. This is accomplished by setting HANDLE_ID_HORIZONTAL_BOTTOM to be the anchor point, and doing an LAnnotation::Define(ANNDEFINE_BEGINROTATE). This is done for both the line and the rectangle.
Define any Miscellaneous functions that may be necessary. The example custom annotation object needs two miscellaneous functions: one that creates and sets the location of all the user handles, and another that is called whenever any component object is about to be highlighted.