|
Programming Cadvance Objects
Introduction. You can program your own custom Cadvance auxiliary objects which in this article will be called widgets. Creating a widget for Cadvance is a fairly simple thing to do. You have a choice of programming environments available for developing your application. What is required is a Windows programming environment like C, C++, or Delphi that can create DLL plug-ins for Cadvance. The examples in this article use the Cadvance Development Interface (CDI) and DELPHI 7 to create widgets. To try out the code, a free 30 day Cadvance demo disk can be obtained at:Cadvance Online. The disk also contains the entire CDI development kit and documentation in PDF format. Cadvance and all its versions also can be downloaded from FIT at http://www.cadvance.com/. Application developers can also get the fully licensed of the the Cadvance 2005 development kit at a greatly reduced rate. |
How widgets work.
Whenever redraw, pan or zoom functions are called Cadvance makes a call to the widget DLL if the widget is encountered and is visible. The DLL draws the widget in response to Cadvance's request. If the widget has been selected for a selection set, Cadvance will tell the DLL what color the widget is to be drawn in.
Widget callback functions.
In its simple interface, Cadvance requires the following callback functions to be declared as exports in the widget's DLL:
AuxNotify
AuxDraw
AuxExtent
Most calls from Cadvance are to the
AuxDraw
callback function where all drawing of the custom object is handled. The
AuxExtent
function provides Cadvance with information about the size of the widget in the form of extents so that it can be selected in the drawing.
Widget Data Structure
Creating a structure for your widget's data is a very important decision you must make. The structure you create will have to serve a variety of functions and be robust enough to stand the test of time. Changing the structure is not easy to do after you have begun using it. Adding additional variables to the structure for future expansion can prevent problems later.
type
BASICOBJ_HEADER=record
name:array[0..63] of char;
objtype:smallint;
version:smallint;
visible:smallint;
Extents:CDI_WORLD_RECT;
end;
BASICOBJ_DEFN=record
ObjInfo:BASICOBJ_HEADER;
ireserved1:smallint;
ireserved2:smallint;
ireserved3:smallint;
ireserved4:smallint;
lreserved1:longint;
lreserved2:longint;
lreserved3:longint;
lreserved4:longint;
dreserved1:double;
dreserved2:double;
dreserved3:double;
dreserved4:double;
Caption:array[0..255] of char;
TextInfo:CDI_TEXT_INFO;
end;
Inserting New Widgets
Widgets are placed in drawings using the CdiObjCreateAux and CdiPutInstance functions. The following code defines the widget and places it. The name of the widget limited to eight characters is the same as the DLL that manages it.
ObjDef.cnt:=Sizeof(ObjBuffer);
ObjDef.flags:=CDI_AUX_STANDARD;
ObjDef.name:='BASICOBJ';
ObjDef.dataptr:=@ObjBuffer;
ObjDef.aux_type:=CDI_2D_OBJECT;
l_ret:=CdiObjCreateAux(ObjDef);
l_ret:=CdiPutInstance(l_ret, basePoint, 1, 1, 1, 0, 0, 0, CDI_TRUE);
Copying widgets.
Widgets can be copied using Cadvance's duplicate function. The resulting widgets will share the same master definition. Changes to an single widget's master definition will cause all widgets sharing the same master definition to change accordingly.
Editing Widgets
Once placed widgets can be edited using Cadvance's editing functions. Altering a widget's layer, scale, color and rotation are all possible without any special functions. Additional editing functions will also be necessary to manage properties and behaviors of the widget.
Strategies for creating widgets.
There are a few things you might want to consider if you a going to distribute your widget's DLL. The issue of distribution might prompt you to create two separate DLL's, one to manage the drawing of the widget and the other to handle editing functions. By doing this you control the editing and creation of widgets. Another issue is multiple widgets managed by a single DLL. Designing your widget data to contain a header defining the widget type will allow you to identify widgets and their data. The widget will need a name and that is limited to eight characters.
Delphi Source Code.
The following widget example has been tested using Borland Delphi 4 and Delphi 7 as the application development environment. The code and concepts are similar if you were using C or C++. The sample application widget draws underlined text using a CAD vector based font.
DELPHI source for a sample widget application is located here.
Paste the code into your DPR file and save it as BASICOBJ.DPR
library BASICOBJ;
uses
SysUtils,
Wintypes,
Cdiconst in '..\common files\Cdiconst.pas',
Cdiprocs in '..\common files\Cdiprocs.pas',
Cditypes in '..\common files\Cditypes.pas';
type
BASICOBJ_HEADER=record
name:array[0..50] of char;
objtype:smallint;
version:smallint;
visible:smallint;
Extents:CDI_WORLD_RECT;
end;
BASICOBJ_DEFN=record
ObjInfo:BASICOBJ_HEADER;
Caption:array[0..255] of char;
TextInfo:CDI_TEXT_INFO;
end;
procedure DrawWidget(ObjId:CDI_SEGID; ObjBuffer:BASICOBJ_DEFN; ObjColor:smallint);
var
i_ret:smallint;
startPoint:CDI_DDD_POINT;
endPoint:CDI_DDD_POINT;
basePoint:CDI_DDD_POINT;
ObjInfo:CDI_SYM_GRP_BUFFER;
text_rectangle:CDI_WORLD_RECT;
begin
i_ret:=CdiObjInfo(ObjId, @ObjInfo);
basePoint.x:=0;
basePoint.y:=0;
basePoint.z:=0;
ObjBuffer.TextInfo.rotation:=0;
i_ret:=CdiGetTextExtents(basePoint, ObjBuffer.Caption, ObjBuffer.TextInfo, text_rectangle);
CdiTransformPoint(basePoint);
ObjBuffer.TextInfo.rotation:=ObjInfo.rotation;
i_ret:=CdiDrawText(basePoint, ObjBuffer.Caption, ObjBuffer.TextInfo, ObjColor);
startPoint.x:=ObjBuffer.ObjInfo.Extents.left;
startPoint.y:=ObjBuffer.ObjInfo.Extents.bottom;
startPoint.z:=0;
CdiTransformPoint(startPoint);
endPoint.x:=ObjBuffer.ObjInfo.Extents.right;
endPoint.y:=ObjBuffer.ObjInfo.Extents.bottom;
endPoint.z:=0;
CdiTransformPoint(endPoint);
i_ret:=CdiDrawLine(startPoint, endPoint, ObjColor, 0, 0);
end;
procedure AuxNew;stdcall;
var
ObjDef:CDI_AUX_DEFN;
ObjBuffer:BASICOBJ_DEFN;
i_ret:smallint;
l_ret:CDI_SEGID;
basePoint:CDI_DDD_POINT;
pnt1:CDI_DDD_POINT;
pnt2:CDI_DDD_POINT;
i_term:smallint;
i_menu:smallint;
text_rectangle:CDI_WORLD_RECT;
begin
ObjBuffer.ObjInfo.objtype:=0;
strpcopy(ObjBuffer.Caption,'Widget');
CdiGetTextInfo(ObjBuffer.Textinfo);
basePoint.x:=0;
basePoint.y:=0;
basePoint.z:=0;
i_ret:=CdiGetTextExtents(basePoint, ObjBuffer.Caption, ObjBuffer.TextInfo, text_rectangle);
ObjBuffer.ObjInfo.Extents:=text_rectangle;
pnt1.x:=text_rectangle.left;
pnt1.y:=text_rectangle.bottom;
pnt2.x:=text_rectangle.right;
pnt2.y:=text_rectangle.top;
i_ret:=CdiMakeCursor(0, CDI_RECT_CURSOR, pnt1, CDI_REL_CURSOR_MOVE, pnt2, CDI_REL_CURSOR_MOVE);
i_ret:=CdiGetPoint('Place widget', basePoint, i_term, i_menu);
i_ret:=CdiObjSnap(basePoint, basePoint);
ObjDef.cnt:=Sizeof(ObjBuffer);
ObjDef.flags:=CDI_AUX_STANDARD;
ObjDef.name:='BASICOBJ';
ObjDef.dataptr:=@ObjBuffer;
ObjDef.aux_type:=CDI_2D_OBJECT;
l_ret:=CdiObjCreateAux(ObjDef);
l_ret:=CdiPutInstance(l_ret, basePoint, 1, 1, 1, 0, 0, 0, CDI_TRUE);
CdiRedraw;
end;
function AuxDraw(
ObjId:CDI_SEGID;
var ObjBuffer:BASICOBJ_DEFN;
ObjColor:smallint
):smallint; stdcall;
begin
if (ObjColor=CDI_HIGHLIGHT) then
begin
ObjColor:=2;
end;
case ObjBuffer.ObjInfo.objtype of
0 : DrawWidget(ObjId, ObjBuffer, ObjColor);
1 : ;
2 : ;
3 : ;
else
end;
result:=CDI_OK;
end;
function AuxNotify(
event:smallint;
ObjId:CDI_SEGID;
var ObjBuffer:BASICOBJ_DEFN;
Reserved:pointer
):smallint;stdcall;
begin
case event of
CDI_LOAD : ;
CDI_SAVE : ;
CDI_CLEAR : ;
CDI_NEW : ;
CDI_QUERY_CLEAR : ;
CDI_DELETED : ;
CDI_COPY_UNIQUE : ;
else
CdiPutMsg('Undefined event has occurred');
end;
result:=CDI_OK;
end;
function AuxExtent(
ObjId:CDI_SEGID;
var ObjBuffer:BASICOBJ_DEFN;
var startPoint:CDI_DDD_POINT;
var endPoint:CDI_DDD_POINT
):smallint; stdcall;
var
i_ret:smallint;
ObjInfo:CDI_SYM_GRP_BUFFER;
begin
i_ret:=CdiObjInfo(ObjId,@ObjInfo);
startPoint.x:=ObjBuffer.ObjInfo.Extents.left;
startPoint.y:=ObjBuffer.ObjInfo.Extents.bottom;
startPoint.z:=0;
endPoint.x:=ObjBuffer.ObjInfo.Extents.right;
endPoint.y:=ObjBuffer.ObjInfo.Extents.top;
endPoint.z:=0;
Result:=CDI_OK;
end;
procedure DllExitHandler(Reason:integer);
Begin
case Reason of
DLL_PROCESS_DETACH : ;
DLL_PROCESS_ATTACH : ;
DLL_THREAD_ATTACH : ;
DLL_THREAD_DETACH : ;
else
end;
end;
exports
AuxNew,
AuxNotify,
AuxDraw,
AuxExtent;
var
copyright:string;
begin
//Perform DLL initialization
DLLProc:=@DLLExitHandler;
DLLExitHandler(DLL_PROCESS_ATTACH);
CdiPutMsg('Initializing object module, please wait...');
end.