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.


go to top of page
Updated: December 31, 2005          To get more information about EMIS based products