You are on page 1of 92

K-DRAW

Software aimed at facilitating easy and intuitive drawing with little training and a
very shallow learning curve.

Submitted by
KIRAN RAJMOHAN
XII A
BHAVANS VARUNA
VIDYALAYA

Table of Contents
ACKNOWLEDGEMENT .................................................................................................................................... 3
INTRODUCTION .............................................................................................................................................. 4
INTERFACE.................................................................................................................................................. 4
NODES ........................................................................................................................................................ 4
LINES .......................................................................................................................................................... 5
RENDER ...................................................................................................................................................... 5
OPTIONS ..................................................................................................................................................... 6
RECURSIVE DRAW ...................................................................................................................................... 6
SAVE ........................................................................................................................................................... 6
OPEN .......................................................................................................................................................... 6
EXIT ............................................................................................................................................................ 7
MEMORY STATUS....................................................................................................................................... 7
HELP ........................................................................................................................................................... 7
SOFTWARE ..................................................................................................................................................... 8
GLOBAL OBJECT DECLARATION ................................................................................................................. 8
PROGRAM EXECUTION and TERMINATION ............................................................................................... 8
NODES and LINES ....................................................................................................................................... 8
DIALOG BOXES ........................................................................................................................................... 9
FILE STRUCTURE ....................................................................................................................................... 10
CLASS HIERARCHY ........................................................................................................................................ 11
K-DRAW.CPP ................................................................................................................................................ 14
HEADERFILES ................................................................................................................................................ 17
MYDEFINE.H ............................................................................................................................................. 17
MYCLASS.H ............................................................................................................................................... 19
MYMOUSE.H ........................................................................................................................................ 27

MYNODES.H ............................................................................................................................................. 31
MYLINE.H ................................................................................................................................................. 42
MYLCOLOR.H............................................................................................................................................ 47
BU.H ......................................................................................................................................................... 50
BUNB.H .................................................................................................................................................... 53
MYDIALOG .H ........................................................................................................................................... 55
MYFILE.H .................................................................................................................................................. 59
MYSAVE.H ................................................................................................................................................ 61
MYOPEN.H ............................................................................................................................................... 66
MYEXIT.H.............................................................................................................................................. 69
MYRENDER.H ........................................................................................................................................... 70
MYOPT.H .................................................................................................................................................. 73
MYTIME.H ................................................................................................................................................ 76
MYHELP.H ................................................................................................................................................ 77
MYSTR.H................................................................................................................................................... 79
MYMISC.H ................................................................................................................................................ 80
SCREEN SHOTS ............................................................................................................................................. 82
BIBLIOGRAPHY ............................................................................................................................................. 91

ACKNOWLEDGEMENT

I gratefully acknowledge the support and guidance given to me by my teachers and friends.
I would like to thank MrsSunitha, Principal , Bhavans Varuna Vidyalaya for giving me the opportunity to
do this project work.I would like to acknowledge theable guidance and support I received fromMrs.
Aleyamma George and MrsSheela, our Computer teachers. I thank my family members for supporting
me throughout the development of this project right from the start. I thank my friends for their support
and the interest they have shown in the completion of this project.

INTRODUCTION
K-DRAW is a software aimed at facilitating easy and intuitive drawing with littletraining and a very
shallow learning curve.
The program uses a pseudo-threaded system which enables the user to use buttons and other features in
a windows-like environment with mouse and keyboard shortcut support. Visual and textual cues have
been incorporated to make the software easier to use and the save and open features ensure that your
work can be resumed after stopping and can be backed up.

INTERFACE
The interface consists of mainlyfive areas.

Top menu
It consists of the four file and program management buttons, viz, SAVE, OPEN, OPTIONS and
EXIT.

Colour selector
It displays the possible line colours that can be used. Clicking over any of the colour activates
the colour.

Node management and render


It gives theuser the option to create, move and delete nodes and also to render the image to
get the final picture.

Help
The help gives context sensitive tips on how to use the software.

Work area
It is the canvas in which all the drawing is done and is the largest and central area of the
interface.

NODES
The basic concept behind the drawing system is the node. Nodes serve as movable anchor points to
which lines can be attached. Each node can be moved separately or made immovable by locking them.
The nodes are represented as small circles which change colour reflecting the status of the node. The
nodes turn light blue when the mouse hovers over them. The nodes are moved by LEFT clicking over
them. Upon LEFT click, the nodes turn green indicating active status and will follow the mouse anywhere
over the workspace till another LEFT click which deactivates the node and frees the mouse. When
activated, the mouse movement is restricted to the work area.

New nodes are created by entering the CREATE mode by clicking the button on the right of the screen.
LEFT clicking creates a single new node at the point of click. If SHIFT key is pressed while clicking, the
create mode remains activated enabling further uninterrupted creation of nodes until a node is created
without the SHIFT key being pressed. The create mode can be exited at any time by RIGHT clicking
anywhere on the work area.
Existing nodes are deleted by entering the DELETE mode by clicking the button on the right of the screen.
The functioning is similar to the create mode, i.e. LEFT clicking on a node deletes it. Keeping the SHIFT
key pressed chains the commands. RIGHT clicking exits the mode.
RIGHT clicking on a node (when not activated) locks the node. This ensures that the node is not
accidentally moved or deleted. It is also very handy when creating lines. RIGHT clicking again on any
locked node unlocks it.
The MOVE mode is automatically selected after returning from any of the modes. All node manipulations
including line creation is done in this mode.

LINES
Lines are created between nodes.
LEFT clicking on a node while pressing the SHIFT key initiates the line creation. The endpoint of the line is
selected by clicking on another node. When selecting the second node, if SHIFT key is pressed, a line is
created between the previous node and the present node and a new line is initiated from the present
node. The mode is chained as long as SHIFT key is pressed during the clicks and is terminated when a
node is selected without pressing the SHIFT key. The mode can also be terminated by RIGHT clicking
anywhere in the work area. Note that locked nodes cannot serve as starting point of lines. However, a
locked node can act as an endpoint and if the line creation is chained when clicking over a locked node, it
can act as a new start point.
The colour of the new lines created depends on the current colour selected. Any of the 16 colours
supported by the compiler can be selected from the colour selector by clicking over the required colour.
The selected colour turns solid while all other colours turn dotted.
Lines are deleted just as they are created. While trying to create a line between two nodes, if a line
already exists between them, the existing line is deleted else a new one is created. All the facilities
associated with creating a line are available while deleting them too.
If any node is moved, all associated lines are automatically updated to reflect their new positions.
Whether only the immediate lines are updated or not depends on the RECURSIVE DRAW status which is
explained in the following sections.

RENDER
The final image is obtained by LEFT clicking the RENDER button. Upon rendering, a new screen is shown
in which only the lines are displayed. All nodes and interface buttons are removed except for a new
button, RETURN. Clicking the RETURN button exits the render mode and returns to work mode.

OPTIONS
The options menu is aimed at providing a facility to the user to choose different performance options to
enable maximum and smooth utilization of resources. Currently only one option, i.e. the recursive draw
option is available. The option is enabled or disabled by checking or unchecking the check box using LEFT
mouse click.

RECURSIVE DRAW
Recursive draw is an algorithm by which all associated nodes, not only the immediate associations but
also the further connections are updated. This requires a lot of processing power depending on the
picture draw and line branching.
If recursive draw is disabled, moving a line over another node or line will erase the node or line
temporarily. The image howeverwill update automaticallywhen any node is hovered over. If however the
recursive draw is enabled, any line which is in any way connected to the activated node will be updated.
This ensures a better working experience at the cost of a little processing power.

SAVE
The SAVE button found on the top left of the screen gives the user the option to save the current file in
the .kdr format. The format is specially designed for use with K-DRAW and hence is currently not
supported by any other software. The user may or may not add the extension to the file name. If the
extension .kdr is already entered by the user, it will not be modified. If however the extension is not used
or any other extension is used, a .kdr extension will be added to the filename automatically. The software
also ensures that a file name entered is not of zero length (empty). If so, a message is displayed
mentioning the same and waits for further action. The file name entry field supports BACKSPACE also.
The dialog box has the options SAVE and CANCEL which have obvious actions associated with them.

OPEN
The OPEN dialog box gives the user the ability to open any previously saved .kdr file to continue, review
or render the work. The user may enter the name of the file to be opened with or without the extension.
If extension is not present, it will automatically be added. If file was previously saved in the current
working session, then that file name willautomaticallyappearas the file name for opening. The empty file
name message will be displayed here too as in the case of the SAVE dialog box.The file name entry field
supports BACKSPACE also.
The dialog box has the options OPEN and CANCEL which have obvious actions associated with them.

EXIT
The EXIT button takes you to the EXIT dialog box which gives the user the option to either SAVE (and exit)
or return to the program (CANCEL) or to exit the program without saving (EXIT). This ensures that the
work is not lost due to unintentional exits.

MEMORY STATUS
The green/yellow/red circle just above the COLOUR SELECTOR is indicative of the amount of free memory
(heap space) left. Green indicates that there is lots of space left. Yellow is a warning that the heap space
is very limited and red indicates critical status. There is only enough space to just open a dialog box and
save and exit the program. The user would either have to delete some nodes to free more space or quit
the program if the red status is shown.

HELP
The help field displays essential tips required to work with K-DRAW depending upon the current mouse
position and program mode.

SOFTWARE
This section explains a few of the programs main algorithms briefly.
All the classes are forward declared in the MYCLASS.H header file to allow bridged usage of the class as in
the case of class nodes and class lines. Numerous #defined constants are declared in the MYDEFINE.H
header file which makes the program far more readable than it would have been otherwise. Some
macros also have been implemented to make the calls to the objects of nodes and lines as they are
referenced and typecasted from object. Some facilities like scenes have been included into the file
format to allow expandability in future stages. Since the format already incorporates the facility, the files
would be cross compatible.
The program has to be compiled with the LARGE memory model and container library and graphics
library enabled.

GLOBAL OBJECT DECLARATION


Numerous global objects have been declared in the program. These need to be global and had to be
declared with the class definitions as they are used in many other member functions. But these cannot
initialize the variables with valid values until performing some manipulations using some graphics
functions. Therefore the program calls default constructors which initializes the variables with dummy
values. The true values are later supplied by creating a temporary instance local to a function and
copying this data into the global object. This way, all the data can be initialized for a global object after
entering the main.

PROGRAM EXECUTION and TERMINATION


The core part of the program is executed in an infinite loop. The loop starts as soon as all the
initializations are done and the welcome message is displayed. The loop and hence the program is exited
from the EXIT dialog box which uses exit() to terminate the program. The graphics termination function is
automatically executed just before the exit by using the atexit() method.

NODES and LINES


The nodes and lines are managed using a modified version of the built in Container class ARRAY. The class
MYARRAY is derived from ARRAY to utilize the reallocate() function used to reallocate memory spaces in
the array to ensure optimum space utilization.
The class ARRAY itself takes all the arguments of the object* type which is a virtual base class of ARRAY.
In order to add, modify or delete the nodes or lines object to MYARRAY, it had to be of type object.
Therefore, class NODES and LINES are derived from class QUEUE, another built-in container class, for the

sole purpose of making them derived from class OBJECT. The retrieved data of the object* type is then
type casted and referenced to get back the actual objects that were stored, i.e. nodes or lines.
This technique has many associated advantages.

All the elements can be accessed using index or pointer.

The Array size can be grown or reduced easily.

The data is well managed since it is a built in class.

The size of the array can be readily retrieved .

The array can be reallocated to change size and to ensure that all indices are properly filled.

The system is very flexible as it can be migrated to most other container class as may be
demanded by future development.

The NODES class employs all the methods required for the creation, modification, deletion and for
updating the on-screen appearance of a node. It also employs some static functions and data members
to manage the overall status and working of the nodes.
The function nodes::mouseact () is used to perform all nodes related changes. It manages the
redistribution of control to various other functions related to node management depending on the
program mode and node status.
The line creation is called from nodeact() which manages the appearance, status and other parameters of
the nodes.
Each node has a pointer list which has a reference to all the lines that are directly connected to that node
and each line in turn has two pointers which refer to the two endpoints of the line. This format ensures
that the lines and nodes can be traversed through without any global map.
The lines and nodes are updated as per the status of the variable option::recursivedrawwhich decides
whether all the connectionsfrom a node are traversed or whether just the immediate lines are updated.

DIALOG BOXES
The dialog boxes are manually implemented using the basic methods available in C++.
The background is first captured using getimage () and is stored. This requires a lot of memory
temporarily and hence the program has to be compiled in the LARGE memory model to allow access
beyond 64kb memory segment. Then the background over that area is erased and the new data is
displayed. After the dialog boxs need is over, the older image saved is returned using putimage ().
Each dialog box can be easily created with upto 3 buttons which can be used for any input purpose.
Further, the text input box implemented for the file access dialog boxes are empowered with backspace

capabilities implemented using bioskey(). The heading of the Dialog box is automatically centered and
the text displayed is automatically divided into multiple lines while ensuring that no line is cut in the
middle or overflows the boundaries of the box. The position of the box can also be easily specified.

FILE STRUCTURE
The .kdr format used for saving the pictures uses a format that is complete and comprehensive and yet
easily accessible. The data is structured so that all data regarding a scene is directly accessible from the
first line of the scene. The file also features a version variable which helps to ensure that only a
compatible file version is readable. This is especially helpful when modifying the file structure to ensure
that only the latest files are read by the program.

10

CLASS HIERARCHY
This section pictorially represents the class inheritance patterns and the class members grouped
by their access mode specifiers.
Buttons and its derivatives

11

Dialog box and its derivatives

12

Other classes

13

K-DRAW.CPP
//if not compiling DO: options->Linker->settings->
//set container libraries & graphics
//increase debugger->heap size to 640k
//**************USE LARGE MEMORY MODEL**************/
//basic i/o & graphics
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#include <fstream.h>
#include <conio.h>
#include <bios.h>
#include <string.h>
#include <alloc.h>
//container class
#include<queue.h>
#include<Array.h>
#include <time.h>
#include<process.h>
#include "mydefine.h"
#include "myStr.h"
#include "myClass.h"
#include "myHelp.h"
#include"MyTime.h"
#include "mymouse.h"
#include "bu1.h"
#include "mynodes.h"
#include "myline.h"
#include "mydialog.h"
#include "myfile.h"
#include "mysave.h"
#include "myopen.h"
#include "myexit.h"
#include "mylcolor.h"
#include "myrender.h"
#include "myopt.h"
#include "myMisc.h"

14

void graphinit(void) //initialise graphics, close maunally


{
/* request auto detection */
int gdriver = DETECT, gmode, errorcode;
/* initialize graphics and local variables */
initgraph(&gdriver, &gmode, "");
/* read result of initialization */
errorcode = graphresult();
if (errorcode != grOk) /* an error occurred */
{
printf("Graphics error: %s\n", grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
exit(1); /* terminate with an error code */
}
setviewport(0,0,getmaxx(),getmaxy(),1);
setcolor(getmaxcolor());
}
void exitmanage()
{
closegraph();
}
void main()
{
clrscr();
graphinit();
////////////PROGRAM STARTS/////////////////
//initialise all basic objects
nodes::nodeinit();
buttoninit();
m.mouseinit();
h.helpinit();

//all buttons
//mouse
//help

m.mouseon();
initexitdiag();
initopendiag();
initsavediag();
lc.disp();
//initialisations over

//colour selector

atexit(exitmanage);

//runs at exit time

welcomediag();

15

while(1)
{
m.mousemodes();

//check mouse pos & find current mode

memshow();

//memory status

if (m.mousemode==bottom_menu)
{
for (int i=0;i<=2;i++)
nb[i].buttonact();
rb.buttonact();//render
if(nb[0].getstat()!=hover && nb[2].getstat()!=hover
&& rb.getstat()!=hover )
h.display();
}
else if(m.mousemode==topbar)
{
sb.buttonact();
//save area checking->automatic
ob.buttonact();
//open
eb.buttonact();
//exit
omb.buttonact();
//options
if(sb.getstat()!=hover && ob.getstat()!=hover
&& eb.getstat()!=hover && omb.getstat()!=hover )
h.display();

}
else if(m.mousemode==top_menu)
lc.act();
//color select
else
//work area
{
switch(nodebuttons::getmode())
{
case new_node:
if (m.mousemode==work)
nodes::newnode();
//call to make a new node
break;
case move_node:
if (m.mousemode==work && nodes::last()>=0)
nodes::mouseact();
//finds and does nodeactions
break;
case delete_node:
h.display(H_delnode);
if (m.mousemode==work)
nodes::deletenode();
break;
}

if(kbhit())
getch();

//clear any unused characters in buffer

}
}

16

HEADERFILES
MYDEFINE.H
// All #define
//mouse.h
//---------------------------------------------------------//mouse clicks
#define LCLICK 1
#define RCLICK 2
#define NOCLICK 0
//mouse modes
#define work 1 //side menu
#define topbar 2
#define bottom_menu 3
#define top_menu 4
//full area constants
#define fullx1 1
#define fullx2 635
#define fully1 1
#define fully2 476
//side bottom menu area constants
#define bmx1 550
#define bmx2 635
#define bmy1 190
#define bmy2 466
//side top menu area constants
#define tmx1 550
#define tmx2 635
#define tmy1 21
#define tmy2 190
//top bar constants
#define tbx1 1
#define tbx2 500
#define tby1 1
#define tby2 20
//work area
#define wx1 27 //20+7 //to avoid crossing work area
#define wx2 543 //500-7
#define wy1 27 //20+7
#define wy2 449 //476-7
//------------------------------------------------------//nodes.h
//------------------------------------------------------#define open 0 //movable
#define hover 1 //mouse over
#define active 2 //currently selected
#define locked 3 //cannot move

17

#define del_hov 4 //when hover for delete


#define linesel 5 //when shift is pressed when hovering
#define wnode(i) ((nodes&)worknodes[(i)])
#define conline(i) ((lines&)conlinesArr[(i)])
#define nodecline(i) ((lines&)cline[(i)])
//------------------------------------------------------//buttons.h
//------------------------------------------------------#define off 0 //active &hover defined in mouse.h
#define on 1//for myoptions->options
#define exitb -2
//work mode definitions
#define node_work 0 //also are corresponding array index
#define scene 1
#define background 2
#define new_node 0//BuNB.h //also are corresponding array index
#define move_node 1
#define delete_node 2
#define button_out_color GREEN
#define button_in_color BLACK
#define button_act_text_color RED
//------------------------------------------------------//MYRENDER.H
//------------------------------------------------------#define renderb 3
#define renderbe 4
//------------------------------------------------------//mydialog.h
//-------------------------------------------------------//open-> 0 defined for nodes
#define cancel 1
#define ok 2
#define save 3
#define yes 2 //same as ok
#define no 1 //same as cancel
//------------------------------------------------------//topbu.h
//------------------------------------------------------#define savebu 0
//------------------------------------------------------//mysave.h
//------------------------------------------------------#define iovar(var) (char*)&(var),sizeof(var)
//------------------------------------------------------//myoption.h
//-------------------------------------------------------------------------#define options 5
//------------------------------------------------------//myIK.h
//--------------------------------------------------------------------#define findlength(x1,y1,x2,y2) sqrt( ( (x2)-(x1) )*( (x2)-(x1) ) + ( (y2)-(y1) )*( (y2)-(y1) ))

18

MYCLASS.H
//All class forward declarations
/************************* MYTIME.H **********************************/
class MyTime
{
int stat;
double elapTicks;
clock_t Begin, End; //initialize Begin and End for the timer
public:

MyTime();
void start();
void stop();
int status();
float time();

};
/************************** MYTIME.H over ******************************/
/************************** MYHELP.H **********************************/
class help
{
int x,y,h,now;
char *s[hstrnum];
public :
help();
void helpinit(); //can do only after init of graphics
void display (int code=-2);
}h;
/************************* MYHELP.H over ******************************/
/************************* MYMOUSE.H *********************************/
union REGS in,out;
short range(int x,int y,int px,int py,int r);
class mouse //class for mouse fuctions
{
private:
int callmouse();
int mousehide();
public:
int mousemode;
void mouseinit();
void mousemax(int x1,int x2,int y1,int y2);
void mouseon()
{callmouse();}
void mouseoff()
{mousehide();}
void mouseposi(int &xpos,int &ypos,int &click );
// return latest coords & click (single look)
int pollmouse(int xcond,int ycond,int click);
//look for a click at a point (single look)

19

int pollmouse(int xcond,int ycond,int click,int w,int h);


int hovermouse(int x1,int y1,int w1,int h1);
// look for hover over an area (single look)
void mouseposi(int &xpos, int &ypos,int &click, int dummy);
//look for any click and return click
//type and coords (polled) ; dummy for overloading
void mouseclick(int &xnew,int &ynew,int c=LCLICK);
// find coords of a click (polled)
void mousemodes();//update mousemode according to current pos
int ifclick();
//return any click anywhere
}m;
/********************* MYMOUSE.H over*************************************/
/************************BU.H *****************************************/
class buttons
{
protected:
int x1,y1,x2,y2,id,stat,prestat;//id same as the corresponding workmode
//stat= off/hover/active
char text[20];
void mouseover();
void buttonclick();
void button_active_draw();
friend nodes;
public:
buttons(){}
buttons(int x1t,int y1t,int x2t,int y2t,int idt,char textt[]);
void drawbutton();
void reset();//stat off,draw button
int getstat();
friend void buttoninit(); //calls all button inits
};
/*********************** BU.H over ************************************/
/********************* MYLINES.H **************************************/
class lines:public Queue
{
static int arraysize();
int recurstat;
public:
int color;
nodes *p[2];//starting and ending nodes
lines()
{
p[0]=NULL;
p[1]=NULL;
recurstat=0;
}
static int num;

20

static void lineact(nodes *p1);


static void newline(int x1,int y1,int x2,int y2,int c);
//to make lines automatically for open
static void del_line(lines *l);
static void empty();
static lines* findcommon(nodes*n1 , nodes*n2);
static void reset_recurstat();
void drawline();//non recursive draws & initial nodes
void drawline(nodes *n);//all recursive draw after 1st node
};
int lines::num=-1;
/********************MYLINES.H over ************************************/
/******************* MYLCOLOR.H ****************************************/
class linecolor
{
int h,w;//height & width of each box;
int x,y,th,tw;//total height & width
public:
linecolor();
static int color;
void disp();
void act();
}lc;
int linecolor::color=WHITE;
/******************* MYLCOLOR.H over**********************************/
/******************MYNODES.H *****************************************/
class MyArray: public Array //to get reallocated function
{
public:
MyArray(int a,int b,int c):Array(a,b,c)
{}

};

void reallocate(int n)
{
Array::reallocate(n);
}

//---------------------------------------------------------------------------class nodes :public Queue


{
private:
int x,y,stat,prex,prey,prestat;
static int laste,activated,globalstat;
//laste->saves last node;
//activated->last elemet index for mouseact //globalstat->for
mouseact management
int pahx,pahy;
//store pre x,y pos to prevent continuous
//change of state b/w active&hover

21

friend int findnode(int x,int y);//search and return 1 node(index) in


//5 pixel range, -1 if not found
friend nodes& latestnode();//return last added node
friend void savescene(char *fname,int sceneid,int newf);
//write node data to file
friend lines;
int numlines;
lines **cline;

//to allow manipulations


//num of lines per node
//all immidiately related lines

void addline( lines *l);


void deleteline( lines *l);
void xy (int x1,int y1); //save old coords & put new coords
void makenode(int x1, int y1);
void nodeact();
//do mouse actions
void drawnode();//called for updating status,calls recursions as needed
void drawnode1();
//draws the nodes
void drawnode(lines *l); //called only for 2nd level recursion
static int delnodeclick(int &newx,int &newy,int &node);
static int arraysize();
MyTime T_l,T_l1;

//T_l=> timer for locked mode

public:
nodes();
//default constructor
nodes(int dummy); //for creating dummy object without affecting laste
static int last() //return last nodes index
{return laste;}
void del_all_lines();

//delete all lines connected to a node

static void nodeinit(); //empty


static void newnode();
//new node mode
static void newnode(int x1,int y1); //to automatically make node at x1,y1
//(used by open dialog)
static void deletenode();
//delete mode, finds node itself
static void empty();
//to delete all existing nodes
static void mouseact();
//called from main
static void draw_all();
~nodes();
};
int nodes::laste=-1;
//no nodes
int nodes::activated=-1;
int nodes::globalstat=open;
/*********************** MYNODES.H over ******************************/

22

/*********************** MYSCENE *************************************/


class scenedat
{
public:
static int curscene;
};
int scenedat::curscene=1;
/*********************** MYSCENE over ********************************/
/*********************** MYDIALOG.H **********************************/
class diagbutton:public buttons
{
public:
static int mode;
diagbutton(){} //for array
diagbutton(int x1t,int y1t,int x2t,int y2t,int idt,char textt[]);
void buttonact();
static void resetmode()
{mode=-1;
}

};
int diagbutton::mode=-1;
//---------------------------------------------------------------------------class dialog
{
int optionnum,numlines;
char heading[20],**line;
void far *buf;
protected:
int x1,y1,x2,y2;
diagbutton b[3];
public:
dialog()
{

line=NULL;
buf=NULL;

}
dialog(int x1t,int y1t,int x2t,int y2t,int optionnum,char **buttontextt,char headingt[20],char
*text,int idt[3]);
void show_diag();
void act_diag();
void clear_diag();
};
/************************** MYDIALOG.H over *************************/

23

/************************** BUNB.H **********************************/


class nodebuttons : public buttons //side bottom work buttons
//only one active at a time
{
private:
static void reset_last_active();
static int lastactive;
static int mode;
public:
void buttonclick();
virtual void buttonact();
friend void nodebuttoninit();
static int getmode();
static void changemode(int to_mode)//change mode,button statsand redraw
}nb[4];
//node buttons
int nodebuttons::lastactive=new_node; //will be correct after 1st click
int nodebuttons::mode=new_node;
/************************ BUNB.H over********************************/
/***************** ****** MYFILE.H **********************************/
class filediag:public dialog
{
protected:
public:
char oldfname[25]; //last used filename without extension
filediag();
filediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],
char *textt,int idt[3]);
void disp_diag();
};
/*********************** MYFILE.H over *******************************/
/*********************** MYSAVE.H ************************************/
class savediag:public filediag
{
public:
static int firstsave;
savediag();
savediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],
char *textt,int idt[3]);
friend void savefile(char *fname,int sceneid,int newf);
void disp_diag();
}dsave;
int savediag::firstsave=1; //1st save or not
//-------------------------------------------------------------------------class savebutton:public diagbutton
{
public:
savebutton()

24

{}
void buttonact();
friend void savebuttoninit();
}sb;
/********************** MYSAVE.H over *******************************/
/**********************MYOPEN.H ************************************/
class opendiag:public filediag
{
public:
opendiag();
opendiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],
char *textt,int idt[3]);
friend void openfile(char *fname);
void disp_diag();
}dopen;
//------------------------------------------------------------------------class openbutton:public diagbutton
{
public:
openbutton(){}
void buttonact();
friend void openbuttoninit();
}ob;
/*********************MYOPEN.H over ***********************************/
/********************* MYEXIT.H ****************************************/
class exitdiag:public filediag
{
public:
exitdiag();
exitdiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],
char *textt,int idt[3]);
friend void exit(char *fname);
void disp_diag();
}dexit;
//-----------------------------------------------------------------------class exitbutton:public diagbutton
{
public:
exitbutton()
{}
void buttonact();
friend void exitbuttoninit();
}eb;
/*********************** MYEXIT.H over *********************************/

25

/*********************** MYRENDER.H ************************************/


class renderbutton:public buttons
{
public:
renderbutton(){}
static void render();
void buttonact();
friend void renderbuttoninit();
}rb;
//----------------------------------------------------------------------class renderexitbutton:public buttons
{
public:
renderexitbutton(){}
void disp();
int buttonact();
friend void renderbuttoninit();
}reb;
/********************* MYRENDER.H over *********************************/
/********************* MYOPT.H *****************************************/
class optionbutton
{
char *text;
int stat,x,y,data;
public:
optionbutton()
{
text=NULL;
}
int getstat()
{
return stat;
}
optionbutton(int x1,int y1,char *text1,int dat);
void draw();
void act();
};
//-----------------------------------------------------------------------class option:public dialog
{
static int recursivedraw;
optionbutton rd;
friend lines;
public:

26

option();
option(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],
char *textt,int idt[3]);
static int isrecursive()
{
return recursivedraw;
}

void disp();
}opt;
int option::recursivedraw=1;
//-----------------------------------------------------------------------class optionmenubutton:public buttons
{
public:
optionmenubutton(){}
void buttonact();
friend void optionmenubuttoninit();
}omb;
/***************** MYOPT.H over************************************/

MYMOUSE.H
/*************************MYMOUSE.H***********************************
union REGS in,out;
short range(int x,int y,int px,int py,int r);
class mouse //class for mouse fuctions
{
private:
int callmouse();
int mousehide();
public:
int mousemode;
void mouseinit();
void mousemax(int x1,int x2,int y1,int y2);
void mouseon()
{callmouse();}
void mouseoff()
{mousehide();}
void mouseposi(int &xpos,int &ypos,int &click );
//return latest coords & click (single look)
int pollmouse(int xcond,int ycond,int click);
//look for a click at a point (single look)
int pollmouse(int xcond,int ycond,int click,int w,int h);

27

int hovermouse(int x1,int y1,int w1,int h1);


//look for hover over an area (single look)
void mouseposi(int &xpos,int &ypos,int &click, int dummy);
//look for any click and return click type and coords //(polled) ; dummy
for overloading
void mouseclick(int &xnew,int &ynew,int c=LCLICK);
// find coords of a click (polled)
void mousemodes();
//update mousemode according to current pos
int ifclick();
//return any click anywhere
}m;
***************************************************************/
int mouse::callmouse()
{
in.x.ax=1;
//set interrupt value
int86(51,&in,&out); //call interrupt
return 1;
}
int mouse::mousehide()
{
in.x.ax=2;
int86(51,&in,&out);
return 1;
}
short range(int x,int y,int px,int py,int r)//if (x,y) is in +-r range of
{
//(px,py) short to decrease size
if( x > px-r && x < px+r && y > py-r && y < py+r)
return 1;
return 0;
}
void mouse::mouseinit()
{
in.x.ax=8;
in.x.cx=0;
in.x.dx=getmaxy();
int86(51,&in,&out);

// set max vertical horizontal movement

in.x.ax=7;
in.x.cx=0;
in.x.dx=getmaxx();
int86(51,&in,&out);
}
void mouse::mousemax(int x1,int x2,int y1,int y2)
{
in.x.ax=7;
in.x.cx=x1;
in.x.dx=x2;
int86(51,&in,&out);
in.x.ax=8;
in.x.cx=y1;
in.x.dx=y2;
int86(51,&in,&out);
}

28

int defaultclick;
//for giving default argument to mouseposi
void mouse::mouseposi(int &xpos,int &ypos,int &click =defaultclick )
{
//get coords and click
in.x.ax=3;
int86(51,&in,&out);
click=out.x.bx;
xpos=out.x.cx;
ypos=out.x.dx;
}
void mouse::mouseposi(int &xpos, int &ypos,int &c, int dummy)
{
int x1,y1,c1,flag=0;
do
{
in.x.ax=3;
int86(51,&in,&out);
switch (out.x.bx)
{
case RCLICK:
case LCLICK:
xpos=out.x.cx;
ypos=out.x.dx;
c=out.x.bx;
flag=1;
break;
}
}while(flag==0);
}
int mouse::pollmouse(int xcond,int ycond,int click)
{
//look for mouse click at a area
int x1,y1,c=0;
mouseposi (x1,y1,c);
if ( x1>xcond-3 && x1<xcond+3 && y1>ycond-3 && y1<ycond+3 && c==click)
{
return 1;
}
return 0;
}
int mouse::pollmouse(int xcond,int ycond,int click,int w,int h)
{
// look for mouse click at a area
int x1,y1,c=0;
mouseposi (x1,y1,c);
if ( x1>xcond-w/2 && x1<xcond+w/2 && y1>ycond-h/2
&& y1<ycond+h/2 && c==click)
{
return 1;
}
return 0;
}

29

void mouse::mouseclick(int &newx,int &newy,int c ) //default LCLICK . return


{
//coords of a click.c ==>required click
int x1,y1,c1;
do
{
mouseposi(x1,y1,c1);
if (c1==c)
{
newx=x1;
newy=y1;
}
}while(c1!=c);
}
int mouse::hovermouse(int x1,int y1,int w1=6,int h1=6)//(x1,y1) is the center
{ int x2,y2,w,h;
w=w1/2;
h=h1/2;
in.x.ax=3;
int86(51,&in,&out);
x2=out.x.cx;
y2=out.x.dx;
if (x1>x2-w && x1<x2+w && y1>y2-h && y1<y2+h)
{
return 1;
}
return 0;
}
int mouse::ifclick()
{
in.x.ax=3;
int86(51,&in,&out);
return out.x.bx;
}
void mouse::mousemodes()
{
int x1,y1;
in.x.ax=3;
int86(51,&in,&out);
x1=out.x.cx;
y1=out.x.dx;
if ( x1 > wx1 && x1 < wx2 && y1 > wy1 && y1 < wy2)
mousemode=work;
else if ( x1 > tmx1 && x1 < tmx2 && y1> tmy1 && y1 < tmy2)
mousemode=top_menu; //side bottom menu
else if ( x1 > bmx1 && x1 < bmx2 && y1> bmy1 && y1 < bmy2)
mousemode=bottom_menu; //side bottom menu
else if ( x1 > tbx1 && x1 < tbx2 && y1 > tby1 && y1 < tby2)
mousemode=topbar;
}

30

MYNODES.H
//wnode is macro in mydefine.h => #define wnode(i) ((nodes&)worknodes[(i)])
/****************** MYNODES.H *****************************************
class MyArray: public Array //to get reallocated function
{
public:
MyArray(int a,int b,int c):Array(a,b,c)
{}
void reallocate(int n)
{
Array::reallocate(n);
}
};
//---------------------------------------------------------------------------class nodes :public Queue
{
private:
int x,y,stat,prex,prey,prestat;
static int laste,activated,globalstat;
//laste->saves last node;
//activated->last elemet index for mouseact //globalstat->for mouseact management
int pahx,pahy;
//store pre x,y pos to prevent continuous
//change of state b/w active&hover
friend int findnode(int x,int y);//search and return 1 node(index) in
//5 pixel range, -1 if not found
friend nodes& latestnode();//return last added node
friend void savescene(char *fname,int sceneid,int newf);
//write node data to file
friend lines;
int numlines;
lines **cline;

//to allow manipulations


//num of lines per node
//all immidiately related lines

void addline( lines *l);


void deleteline( lines *l);
void xy (int x1,int y1); //save old coords & put new coords
void makenode(int x1, int y1);
void nodeact();
//do mouse actions
void drawnode();//called for updating status,calls recursions as needed
void drawnode1();
//draws the nodes
void drawnode(lines *l); //called only for 2nd level recursion
static int delnodeclick(int &newx,int &newy,int &node);
static int arraysize();
MyTime T_l,T_l1;

//T_l=> timer for locked mode

public:
nodes();
//default constructor
nodes(int dummy); //for creating dummy object without affecting laste

31

static int last() //return last nodes index


{return laste;}
void del_all_lines();

//delete all lines connected to a node

static void nodeinit(); //empty


static void newnode();
//new node mode
static void newnode(int x1,int y1); //to automatically make node at x1,y1
//(used by open dialog)
static void deletenode();
//delete mode, finds node itself
static void empty();
//to delete all existing nodes
static void mouseact();
//called from main
static void draw_all();
~nodes();
};
int nodes::laste=-1;
//no nodes
int nodes::activated=0;
int nodes::globalstat=open;
*********************** MYNODES.H over ******************************/
MyArray worknodes(0,0,1);//initially-0 space. lowermost index=0.
//if more than 1, new size= 2....
// contructors and destructors
nodes::nodes()//default contructor
{
prestat=open;
stat=globalstat=open;
laste++; //update lastelem index each time a new node is created
numlines=-1;
cline=new lines*[0];
}
nodes::nodes(int dummy) //for creating dummy object without affecting laste
{
dummy=0;
numlines=-1;
cline=new lines*[0];
}
nodes::~nodes()
{
delete [] cline;
}
// contructors and destructors over
void nodes::xy (int x1,int y1)
{
prex=x;
prey=y;
x=x1;
y=y1;
}

32

void nodes::nodeinit()
{}
int nodes::arraysize() //returns reference to the last added node;
{
return(worknodes.arraySize()-1);//-1 so that it is element index
}
void nodes::makenode(int x1, int y1) //init values and draw new node at coords
{
stat=globalstat=open; //prex,prey for drawnode1() compatability
x=x1;
y=y1;
prex=x;
prey=y;
drawnode1();
}
void nodes::newnode()
{
int x1=0,y1=0,c;
m.mousemax(wx1,wx2,wy1,wy2); //restrict movement if node is selected
if( laste< arraysize() )
worknodes.reallocate(laste+1);//remove vacant spaces
//reallocate takes actual size(1->n)
newnodeagain1: // to take care of lclick ouside work area
m.mouseposi(x1,y1,c,0); //look till a click is recieved
if (c==LCLICK ) //if left click, new node is created
{
if (m.mousemode==work)
{
worknodes.add(* (new nodes));
wnode(laste).makenode(x1,y1);
//laste updated by contructor
wnode(laste).stat=globalstat=open;
if(! (bioskey(_KEYBRD_SHIFTSTATUS) & 0x03))
//if shift is not pressed ,
//dont make another new node
nodebuttons::changemode(move_node);
else
delay(100);//to prevent continous nodes
//over the previous node
}
else

goto newnodeagain1;
}
else if(c==RCLICK)
nodebuttons::changemode(move_node);
m.mousemax(fullx1,fullx2,fully1,fully2); //remove movement restriction
}

33

void nodes::newnode(int x1,int y1)


{
worknodes.add(* (new nodes));
wnode(laste).makenode(x1,y1); //laste updated by contructor
wnode(laste).stat=globalstat=open;
}
int findnode(int x,int y) //search and return 1 node in 5 pixel range
{
int nx,ny;
//node's x & y
for (int i=0; i <= nodes::last() ;i++) //iterate though all nodes
{
nx=wnode(i).x;
ny=wnode(i).y;
if (range(x,y,nx,ny,5)) //if in range
{
return i;
//return element index
}
}
return -1;
}

//not found

int nodes::delnodeclick(int &newx,int &newy,int &node)


{
int x1,y1,c1,j,j1=-1;
do
{
m.mouseposi(x1,y1,c1);
node=j=findnode(x1,y1);
if (j != -1 )
{
if ( wnode(j).stat != del_hov && wnode(j).stat != locked)
//dont draw if updated or if locked
{
wnode(j).stat=globalstat=del_hov;
wnode(j).drawnode();
j1 = j;
j = -1;
}
}
else if (j1 != -1)
{
wnode(j1).stat=globalstat=open; //last hovered node
wnode(j1).drawnode();
j1=-1;
}
if (c1==LCLICK && wnode(node).stat != locked )
{
newx=x1;
newy=y1;
return LCLICK;
}
else if (c1 == RCLICK)

34

{
if (j1 != -1)
{
wnode(j1).stat=globalstat=open; //last hovered node
wnode(j1).drawnode();
j1=-1;
node=-1;
}
return RCLICK;
}
}while(1);
}
void nodes::deletenode()
{
if (laste != -1)// if a node exists
{
deleteagain:
int x1,y1,i,j;
j=delnodeclick(x1,y1,i);
if ( j == LCLICK)
{
if (i != -1) //if node found
{
m.mouseoff(); // to properly draw
setfillstyle(SOLID_FILL,0); //
setcolor(getbkcolor()); //erase previous node
pieslice(wnode(i).prex,wnode(i).prey,0,360,5);
//to ensure complete erase
setfillstyle(SOLID_FILL,0);// erase node from screen
setcolor(getbkcolor()); //
pieslice(wnode(i).x,wnode(i).y,0,360,5);//
m.mouseon(); //reset mouse
wnode(i).del_all_lines();
worknodes.detach(i); //detach and delete a node at click pos
laste--;
//one node deleted
if(! (bioskey(_KEYBRD_SHIFTSTATUS) & 0x03))
//if shift is not pressed ,exit delete mode
nodebuttons::changemode(move_node);
}

}
else if ( j == RCLICK) //if RCLICK anywhere
nodebuttons::changemode(move_node);//cancel deletemode
else
goto deleteagain;

else

35

{
nodebuttons::changemode(move_node);
h.display(H_no_del);
}
}
void nodes::empty()
{
m.mouseoff(); // to properly draw
while(laste>=0)
{
setfillstyle(SOLID_FILL,0);//
setcolor(getbkcolor()); //erase previous node for complete erase
pieslice(wnode(laste).prex,wnode(laste).prey,0,360,5);//
setfillstyle(SOLID_FILL,0);//
setcolor(getbkcolor());//erase node from screen
pieslice(wnode(laste).x,wnode(laste).y,0,360,5);//
wnode(laste).del_all_lines();
worknodes.detach(laste); //detach and delete a node at click pos.
laste--;
}
worknodes.reallocate(0);//reallocate to save space
m.mouseon();
//reset mouse
}
void nodes::drawnode(lines *l) //called only for 2nd level recursion
{
if(l!=NULL && option::isrecursive())
{
for (int i=0;i<=numlines;i++)
if(l!=cline[i] )
{
cline[i]->drawline(this);
//if any line updated in this node
//recur update automatically checked
}
}
drawnode1();
}

36

void nodes::drawnode()//called for updating status,decides and calls recursion


{
if(option::isrecursive() && stat==active)
{
for (int i=0;i<=numlines;i++)
cline[i]->drawline(this);
lines::reset_recurstat();
}
else
{
for (int i=0;i<=numlines;i++)
cline[i]->drawline();
//draw all related lines without any other changes
}
drawnode1();
}
void nodes::drawnode1()
{
m.mouseoff(); //turn off cursor to remove drawing errors
setlinestyle(SOLID_LINE,0,1);
setfillstyle(SOLID_FILL,0);
//
setcolor(getbkcolor());
//erase previous node
pieslice(prex,prey,0,360,5);
//
setcolor(getmaxcolor());
switch (stat)
{
case open:
setfillstyle(SOLID_FILL,BLACK);
setcolor(getmaxcolor());
pieslice(x,y,0,360,5);
break;
case active:
setcolor(getmaxcolor());
setfillstyle(SOLID_FILL,GREEN);
pieslice(x,y,0,360,5);
h.display(H_active);
break;
case locked:
setfillstyle(SOLID_FILL,RED);
pieslice(x,y,0,360,5);
break;
case hover:
setfillstyle(SOLID_FILL,LIGHTBLUE);
pieslice(x,y,0,360,5);
h.display(H_hover);
break;
case del_hov:
setfillstyle(SOLID_FILL,LIGHTRED);
pieslice(x,y,0,360,5);
break;

37

case linesel:
setfillstyle(SOLID_FILL,LIGHTGRAY);
pieslice(x,y,0,360,5);
break;
}
m.mouseon();//turn on mouse
}
void nodes::nodeact()
{
int prestat=stat; //save current stat for checking redraw
switch (stat)
{
case open:

case hover:

pahx=pahy=0; //reset reentry pos to initial


if (m.hovermouse(x,y))
stat=globalstat=hover;
break;
if (m.hovermouse(x,y)==0) //if not hovering now
stat=globalstat=open;
else if (m.pollmouse(x,y,RCLICK))
{
if (T_l1.status()==0 || (T_l1.status()==1 &&
T_l1.time() > 0.3))
{
T_l.start();
T_l1.stop();
stat=globalstat=locked;
}
}
else if(m.pollmouse(x,y,LCLICK) && !range(x,y,pahx,pahy,3)
&& globalstat!=active )
{
stat=globalstat=active;
m.mousemax(wx1,wx2,wy1,wy2);//restrict movement if node
//is selected
pahx=x;//save pos where it was clicked
pahy=y;//prevent reentry to hover continously from active
}
else if(globalstat!=active &&
(bioskey(_KEYBRD_SHIFTSTATUS) & 0x03) )
//if right or left shift was pressed
{
//check only for 0x01 and/or 0x02
stat=globalstat=linesel;
}
break;

case active:
int xa,ya,c=0;
m.mouseposi (xa,ya,c); //get new coords
xy(xa,ya);

38

if (c==LCLICK && !range(xa,ya,pahx,pahy,3) )


//if clicked again and if node has moved //from
activation pos
{
stat=globalstat=hover;
m.mousemax(fullx1,fullx2,fully1,fully2);
//remove movement restriction
pahx=x;//save pos where it was clicked
pahy=y;//prevent continously reentring
//active from hover
}
drawnode(); //update position
break;
case locked:
h.display(H_locked);
if(m.pollmouse(x,y,RCLICK))
{
if (T_l.status()==1 && T_l.time() > 0.3)
{
stat=globalstat=open;
T_l.stop();
T_l1.start();
}
}
break;
case linesel:
if (m.hovermouse(x,y)==0) //if not hovering now
stat=globalstat=open;
else if(m.pollmouse(x,y,LCLICK) &&
!range(x,y,pahx,pahy,3)&&globalstat!=active
&& (bioskey(_KEYBRD_SHIFTSTATUS) & 0x03) )
//if right or left shift was pressed
{
//check only for 0x01 and/or 0x02
lines::lineact(this);
stat=globalstat=open;
}
else if( m.hovermouse(x,y) &&
!(bioskey(_KEYBRD_SHIFTSTATUS) & 0x03) )
stat=globalstat=hover;
break;
}
if(prestat!=stat) // if status changes or is locked
{
prestat=stat;
drawnode();
}
}

39

void nodes::mouseact()
{
int i,x1,y1;
if( activated != -1 && wnode(activated).stat==active )
{
wnode(activated).nodeact();
}
else
{
//to redraw all when a node is deactiveted
if( activated != -1 && wnode(activated).stat==off)
{
draw_all();
activated = -1;//an node was released,
//so redraw everything
}
m.mouseposi(x1,y1);
i=findnode(x1,y1); //find the node required
if (i != -1)
// if found
{
wnode(i).nodeact();
if( wnode(i).stat==locked )
{
wnode(i).drawnode();
delay(100);
}
activated=i;
}

for (int j=0;j<=last();j++)


{
if( j==activated)
wnode(j).nodeact();//draw last activated node to
//off state
if( wnode(j).prestat == hover && wnode(j).stat==off)
wnode(j).drawnode();//force redraw of any node
//that was hovered
}

}
void nodes::draw_all()
{
for (int i=0;i<=laste;i++)
wnode(i).drawnode();
}

40

//-----------------------------line related----------------------------------void nodes::addline( lines *l)


{
if(numlines==-1)
{
delete [] cline;
cline= new lines*[1];
cline[0]=l;
numlines=0;
}
else
{
lines **temp=new lines*[numlines+2]; //(numlines+1)+1
for (int i=0;i<=numlines;i++)
temp[i]=cline[i];
temp[i]=l;
delete [] cline; //unallocate memory that was originally allocated
numlines++;
cline=temp;
}
}
void nodes::deleteline( lines *l)
{
if(numlines>0)
{
lines **temp=new lines*[numlines]; //(numlines-1)+1
for (int i=0,j=0;i<=numlines && j<=numlines-1;i++)
if( l != cline[i] )//if not the one to be deleted
temp[j++]=cline[i];
delete [] cline; //unallocate memory that was originally allocated
cline=temp;
numlines--;
}
else if(numlines==0)
{
delete [] cline;
cline= new lines*[0];
numlines--;
}
else
{
cout<<"deleteline Error 1";
getch();
}
}
void nodes::del_all_lines()
{
while(numlines>=0)
{
lines::del_line(cline[numlines]);
}
}

41

MYLINE.H
/*************************MYLINES.H *************************************
class lines:public Queue
{

static int arraysize();


int recurstat;

public:
int color;
nodes *p[2];//starting and ending nodes
lines()
{
p[0]=NULL;
p[1]=NULL;
recurstat=0;
}

static int num;


static void lineact(nodes *p1);
static void newline(int x1,int y1,int x2,int y2,int c);//to make lines automatically for open
static void del_line(lines *l);
static void empty();
static lines* findcommon(nodes*n1 , nodes*n2);
static void reset_recurstat();
void drawline();//non recursive draws & initial nodes
void drawline(nodes *n);//all recursive draw after 1st node
};
int lines::num=-1;
***************************************************************************/
MyArray conlinesArr(0,0,1);
int lines::arraysize() //returns reference to the last added node;
{
return(conlinesArr.arraySize()-1);
//-1 so that it can be used as element index
}
void lines::lineact(nodes *p1)
{
int no_lineflag=1;//1 if no common lines exist
if(nodes::last()>0) //if more than 1 node exists

42

{
m.mousemax(wx1,wx2,wy1,wy2);//restrict movement if node selected
nodes *p2=NULL;
int x,y,c=-1,i=-1,prei,j,k;
again_new_line:
while(p2==NULL)
{
m.mouseposi(x,y,c);
h.display(H_linenode);
i=findnode(x,y);
if(i!=-1)//if found
{
if(i!=prei &&&wnode(i)!=p1)//another node found
//& it is not the start node
{
m.mouseoff();
setcolor(getmaxcolor());
setfillstyle(SOLID_FILL,BLACK);//hover
pieslice(wnode(prei).x,wnode(prei).y,
0,360,5);
m.mouseon();
prei=i;
}
if(&wnode(i)!=p1)//if both nodes (start & end)
//are not the same
{
m.mouseoff();
setcolor(getmaxcolor());
setfillstyle(SOLID_FILL,LIGHTBLUE);//hover
pieslice(wnode(i).x,wnode(i).y,0,360,5);
m.mouseon();
if( findnode(x,y)!= -1 && c==LCLICK)
//if new node found and it is //not the
start node
{
p2=&wnode(i);
}
}

if (c==RCLICK)
goto newline_exit;
}

43

for(j=0;j<=p1->numlines;j++)//iterate through all


//lines to find common lines
for (k=0;k<=p2->numlines;k++)
if( p1->cline[j]==p2->cline[k] && p1->cline[j]!=NULL)
{
del_line(p1->cline[j]);//delete all common lines
no_lineflag=0;
}
if(p1 != NULL && p2!=NULL && no_lineflag==1)//if no common lines
//exist, make a new one
{
conlinesArr.add( * (new lines ) );
num++;
lines &latest=conline(num);
latest.p[0]=p1;
latest.p[1]=p2;
latest.p[0]->addline(&conline(num));//associate
//the nodes with this line
latest.p[1]->addline(&conline(num));
latest.color=linecolor::color;//currently selected
//color
latest.p[0]->drawnode1();
latest.p[1]->drawnode1();
latest.drawline();
}
if(bioskey(_KEYBRD_SHIFTSTATUS) & 0x03)//if right or
//left shift was pressed
{
p1=p2;
//use the last clicked node as the
//starting of next line
p2=NULL;
goto again_new_line;
}
}
newline_exit:
m.mousemax(fullx1,fullx2,fully1,fully2); //remove movement restriction
}

void lines::newline(int x1,int y1,int x2,int y2,int c)//to make lines


//automatically for open
{

nodes *p1=NULL,*p2=NULL;

44

int i=findnode(x1,y1);
if( i != -1 ) //if node found
{
p1=&wnode(i);
}
i=findnode(x2,y2);
if( i != -1 && p1!=&wnode(i))//if node found and it
//is not the start node
{
p2=&wnode(i);
}
if(p1 != NULL && p2!=NULL )//if no common lines exist, make a new one
{
if( num< arraysize() )
conlinesArr.reallocate(num+1); //remove vacant spaces
//reallocate takes actual size(1->n)
conlinesArr.add( * (new lines ) );
num++;
lines &latest=conline(num);
latest.p[0]=p1;
latest.p[1]=p2;
latest.p[0]->addline(&conline(num));
//associate the nodes with this line
latest.p[1]->addline(&conline(num));
latest.color=c; //currently selected color
latest.p[0]->drawnode();
latest.p[1]->drawnode();
latest.drawline();
}
}
void lines::del_line(lines *l)
{
if(l!=NULL&& num>=0)
{
m.mouseoff();
setcolor(getbkcolor());
line(l->p[0]->x,l->p[0]->y,l->p[1]->x,l->p[1]->y);//draw new line
m.mouseon();
l->p[0]->deleteline(l);
l->p[1]->deleteline(l);
for(int i=0;i<=num;i++)
if(l==&conline(i))
{
conlinesArr.detach(i);

45

num--;
break;

}
}
void lines::drawline() //non recursive draws
{
int x1=p[0]->x,y1=p[0]->y,x2=p[1]->x,y2=p[1]->y;
m.mouseoff();
setlinestyle(SOLID_LINE,0xFF,THICK_WIDTH);
setcolor(getbkcolor());
line(p[0]->prex,p[0]->prey,p[1]->prex,p[1]->prey);
//clear prev line
setlinestyle(SOLID_LINE,0xFF,NORM_WIDTH);
setcolor(color);
line(x1,y1,x2,y2);
//draw new line
setcolor(WHITE);
m.mouseon();
}
void lines::drawline(nodes *n)
{
if(recurstat==0)
{
recurstat=1;
drawline();

//only for recursive draws

//update this line

if(n==p[0] )
p[1]->drawnode(this); //update the othernodea also
else if(n==p[1] )
p[0]->drawnode(this);
}

void lines::empty()
{
m.mouseoff();
while(num>=0)
{
conlinesArr.detach(num);
num--;
}
conlinesArr.reallocate(0);
m.mouseon();
}
void lines::reset_recurstat()
{
for (int i=0;i<=num;i++)
conline(i).recurstat=0;

46

}
lines* lines::findcommon(nodes*n1 , nodes*n2)
{
for(int j=0;j<=n1->numlines;j++) //iterate through all lines
//to find common lines
for (int k=0;k<=n2->numlines;k++)
if( n1->cline[j]==n2->cline[k] && n1->cline[j]!=NULL)
return (n1->cline[j]);
return NULL;//if none found
}

MYLCOLOR.H
/************************* MYLCOLOR.H ****************************
class linecolor
{
int h,w;//height & width of each box;
int x,y,th,tw;//total height & width
public:
linecolor();
static int color;
void disp();
void act();
}lc;
int linecolor::color=WHITE;
*****************************************************************/
linecolor::linecolor()
{
x=tmx1;
y=bmy1-110;
tw=85;
th=85;
h=(th-1)/4;
w=(tw-1)/4;
}
void linecolor::disp()
{
m.mouseoff();
setcolor(WHITE);
setlinestyle(SOLID_FILL,0,NORM_WIDTH);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
if(color==i*4+j) //if currently selected color
setfillstyle(SOLID_FILL,i*4+j);

47

else
setfillstyle(CLOSE_DOT_FILL,i*4+j);
//all colours,one by one
bar(x+(i*w),y+(j*h),x+(i*w)+w,y+(j*h)+h);
rectangle(x+(i*w),y+(j*h),x+(i*w)+w,y+(j*h)+h);
}
setlinestyle(SOLID_FILL,0,NORM_WIDTH);
m.mouseon();
};
void linecolor::act()
{
if(m.mousemode==top_menu)
{
int x1=x,y1=y,c,cl=color;
int prex1=x1,prey1=y1,precl=color;
m.mouseposi(x1,y1,c);
if( range(x1,y1,x+42,y+42,42) )
{
int j=(x1-x)/20;//integer division rounds
//to nearest & smaller no. b/w 0 & 4
int k=(y1-y)/20;
if(range(x1,y1,x+(j*w)+9,y+(k*h)+9,9))//hovering over
//a color
{
if(precl!=cl)
{
m.mouseoff();
setfillstyle(SOLID_FILL,j*4+k);
bar(x+(j*w),y+(k*h),x+(j*w)+w,y+(k*h)+h);
rectangle(x+(j*w),y+(k*h),x+(j*w)+w,y+(k*h)+h);
prex1=x+(j*w);
prey1=y+(k*h);
precl=cl;
cl=j*4+k;
m.mouseon();
}
if(m.ifclick())
//select color
{
int x2=x + ( (color/4) * w);
int y2=y + ( (color%4) * h);
m.mouseoff();
setfillstyle(SOLID_FILL,BLACK);
bar(x2,y2,x2+w,y2+h); //clear existing

48

setfillstyle(CLOSE_DOT_FILL,color);
bar(x2,y2,x2+w,y2+h);
rectangle(x2,y2,x2+w,y2+h);
setfillstyle(SOLID_FILL,j*4+k);
bar(x+(j*w),y+(k*h),x+(j*w)+w,y+(k*h)+h);
rectangle(x+(j*w),y+(k*h),x+(j*w)+w,y+(k*h)+h);
m.mouseon();
color=j*4+k;
}
}
if(precl!=cl)
{
m.mouseoff();
setfillstyle(SOLID_FILL,BLACK);
bar(prex1,prey1,prex1+w,prey1+h);//clear existing
setfillstyle(CLOSE_DOT_FILL,precl);
bar(prex1,prey1,prex1+w,prey1+h);
rectangle(prex1,prey1,prex1+w,prey1+h);
m.mouseon();
precl=cl;
}
}
}

49

BU.H
/******************** BU.H *******************************
class buttons
{
protected:
int x1,y1,x2,y2,id,stat,prestat;//id is d same as the corresponding
//workmode stat= off/hover/active
char text[20];
void mouseover();
void buttonclick();
void button_active_draw();
friend nodes;
public:

buttons(){}
buttons(int x1t,int y1t,int x2t,int y2t,int idt,char textt[]);

void drawbutton();
void reset();//stat off,draw button
int getstat();
friend void buttoninit(); //calls all button inits
};
*********************************************************/
buttons::buttons(int x1t,int y1t,int x2t,int y2t,int idt,char textt[])
{
x1=x1t;
y1=y1t;
x2=x2t;
y2=y2t;
id=idt;
strcpy(text,textt);
}
void buttons::reset() //stat off,draw button
{
stat=off;
drawbutton();
}
int buttons::getstat()
{
return stat;
}
void buttons::button_active_draw()
{
int xmid=x1+(x2-x1)/2;
int ymid=y1+(y2-y1)/2;
int x3=xmid-1.2*textwidth(text)/2;
int y3=ymid-1.5*textheight(text)/2;
int x4=xmid+1.2*textwidth(text)/2;
int y4=ymid+0.5*textheight(text)/2.0 ;

50

setcolor(button_out_color);
setlinestyle(SOLID_LINE,0,3);
setfillstyle(XHATCH_FILL,button_out_color);
rectangle(x1,y1,x2,y2);
floodfill(x1+2,y1+2,button_out_color);
//outer
setcolor(BLUE);
setfillstyle(SOLID_FILL,button_in_color);
rectangle(x3,y3,x4,y4);
floodfill(x3+2,y3+2,BLUE);
setcolor(button_in_color);
rectangle(x3,y3,x4,y4);
setlinestyle(SOLID_LINE,0,1);
setcolor(button_act_text_color);
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy(x1+(x2-x1)/2,y1+(y2-y1)/2,text);
setcolor(WHITE);
}
void buttons::drawbutton() //refresh a button according to present stat
{
m.mouseoff(); // to properly draw
switch(stat)
{
case off:

if (prestat==active)
{
setcolor(BLUE);
setfillstyle(SOLID_FILL,BLACK);
rectangle(x1,y1,x2,y2);
floodfill(x1+2,y1+2,BLUE);
}
setcolor(WHITE);
setlinestyle(SOLID_LINE,0,3);
rectangle (x1,y1,x2,y2);
setlinestyle (SOLID_LINE,0,1);
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy(x1+(x2-x1)/2,y1+(y2-y1)/2,text);
break;

case active:
button_active_draw();
break;
case hover:

setcolor(YELLOW);
setlinestyle(SOLID_LINE,0,3);
rectangle (x1,y1,x2,y2);
setlinestyle (SOLID_LINE,0,1);
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy(x1+(x2-x1)/2,y1+(y2-y1)/2,text);
setcolor(WHITE);
break;

51

prestat=stat; //update prestat


m.mouseon(); //reset mouse
}
void buttons::mouseover() //sense when mouse is over a button
{
if (stat!=active)
{
if(m.hovermouse(x1+(x2-x1)/2,y1+(y2-y1)/2,x2-x1,y2-y1)) //look for hovering over button
stat=hover;
else
stat=off;
}
}
void buttons::buttonclick() //set-reset Lclicks
{
in.x.ax=3;
int86(51,&in,&out);
int click=out.x.bx;
if (click==LCLICK)
if (stat==active)
stat=off;
else
stat=active;
//set active stat for this one
}

#if !defined(__BUNB_h)
#include"BUNB.h"
#endif
void savebuttoninit();
void openbuttoninit();
void buttoninit()
{

nodebuttoninit(); //side bottom menu


savebuttoninit();
openbuttoninit();
exitbuttoninit();
renderbuttoninit();
optionmenubuttoninit();
//modebuttoninit();
//side top menu

52

BUNB.H
/******************* BUNB.H *****************************
class nodebuttons : public buttons //side bottom work buttons .only one active at a time
{
private:
static void reset_last_active();
static int lastactive;
static int mode;
public:
void buttonclick();
virtual void buttonact();
friend void nodebuttoninit();
static int getmode();
static void changemode(int to_mode);
//change mode,button stats and redraw
}nb[4]; //node buttons
int nodebuttons::lastactive=new_node; //will be correct after 1st click
int nodebuttons::mode=new_node;
********************************************************/
void nodebuttoninit()
{
nb[0].x1=bmx1;
nb[0].y1=190;
nb[0].x2=nb[0].x1+85;
nb[0].y2=nb[0].y1+40;
nb[0].id=new_node;
nb[0].prestat=hover; //for complete redraw 1st time
nb[0].stat=active; //initially active mode
strcpy(nb[0].text,"CREATE");
nb[0].drawbutton();
nb[1].x1=bmx1;
nb[1].y1=235;
nb[1].x2=nb[1].x1+85;
nb[1].y2=nb[1].y1+40;
nb[1].id=move_node;
nb[1].prestat=active; //for complete redraw 1st time
nb[1].stat=off;
strcpy(nb[1].text,"MOVE");
nb[1].drawbutton();
nb[2].x1=bmx1;
nb[2].y1=280;
nb[2].x2=nb[2].x1+85;
nb[2].y2=nb[2].y1+40;
nb[2].id=delete_node;
nb[2].prestat=active; //for complete redraw 1st time
nb[2].stat=off;
strcpy(nb[2].text,"DELETE");
nb[2].drawbutton();
}

53

int nodebuttons::getmode()
{
return mode;
}
void nodebuttons::buttonclick() // reset last active when aonther is clicked
{
in.x.ax=3;
int86(51,&in,&out);
int click=out.x.bx;
if (click==LCLICK)
{
nodebuttons::reset_last_active();//reset last active button to default
lastactive=id;
//update last active
stat=active;
//set active stat for this one
prestat=off;
}
}
void nodebuttons::changemode(int to_mode)
{
int from_mode=nodebuttons::mode; //save current active button
nodebuttons::mode=to_mode;
//update mode
nb[from_mode].prestat=nb[from_mode].stat; //update button modes
nb[from_mode].stat=off;
nb[to_mode].prestat=nb[to_mode].stat;
nb[to_mode].stat=active;
nb[from_mode].drawbutton(); //redraw buttons
nb[to_mode].drawbutton();
}
void nodebuttons::reset_last_active()
{
nb[nodebuttons::lastactive].prestat=active;
nb[nodebuttons::lastactive].stat=off;
//reset stat
nb[nodebuttons::lastactive].drawbutton(); //redraw to reflect change
}
void nodebuttons::buttonact() // main function calling
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if(id==new_node)
h.display(H_newnodeb);
else if( id==delete_node)
h.display(H_delnodeb);

54

if (stat==active)//if clicked
{
mode=id; //set workmode
//id is d same as the corresponding workmode
}

}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat

MYDIALOG .H
/************************************************************
class diagbutton:public buttons
{
public:
static int mode;
diagbutton(){} //for array
diagbutton(int x1t,int y1t,int x2t,int y2t,int idt,char textt[]);
void buttonact();
static void resetmode()
{mode=-1;
}
};
int diagbutton::mode=-1;
************************************************************/
diagbutton::diagbutton(int x1t,int y1t,int x2t,int y2t,int idt,char textt[])
{
x1=x1t;
y1=y1t;
x2=x2t;
y2=y2t;
strcpy(text,textt);
id=idt;
}
void diagbutton::buttonact()
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover)
//if hovering
{
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if (stat==active) //if clicked
{
mode=id;//set workmode
//id is the same as the corresponding workmode
}
}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat
}

55

/*********************** CLASS DIALOG ******************************


class dialog
{
int optionnum,numlines;
char heading[20],**line;
void far *buf;
protected:
int x1,y1,x2,y2;
diagbutton b[3];
public:
dialog()
{
line=NULL;
buf=NULL;

}
dialog(int x1t,int y1t,int x2t,int y2t,int optionnum,
char **buttontextt,char headingt[20],char *text,int idt[3]);
void show_diag();
void act_diag();
void clear_diag();

};
********************************************************************/

dialog::dialog(int x1t,int y1t,int x2t,int y2t,int optionnumt,


char **buttontextt,char headingt[20],char *text,int idt[3])
{
x1=x1t;
x2=x2t;
y1=y1t;
y2=y2t;
optionnum=optionnumt;
numlines=0; // default 1 line
for(int k=0;k<5;k++) //no data
strcpy(line[k]," ");
if(optionnum==1)
b[0]=diagbutton((x1+x2)/2-35,y2t-30,(x1+x2)/2+35,
y2t-10,idt[0],buttontextt[0]);
//centered if only one button
else
b[0]=diagbutton(x1t+10,y2t-30,x1t+80,y2t-10,
idt[0],buttontextt[0]); //atleaset one button
if(optionnum>1) //2 buttons
b[1]=diagbutton(x1t+90,y2t-30,x1t+170,y2t-10,
idt[1],buttontextt[1]);
if(optionnum>2)//3 buttons
b[2]=diagbutton(x1t+180,y2t-30,x1t+270,y2t-10,
idt[2],buttontextt[2]);
strcpy(heading,headingt);

56

//split lines
int i=0,j=0;
char word[20];
i=j=0;
do
{
for (j=0;text[i]!=' ' && i<strlen(text) ;i++,j++)
{
//copy one word
word[j]=text[i]; //copy a word
}
word[j]='\0';

//terminate string

i++;
if ( textwidth(line[numlines]) +
textwidth(word) < (x2-x1-10) )
{
// check if length is exceeded

}
else
{

strcat(line[numlines]," ");
strcat(line[numlines],word);
//if not exceeded, concatenate
//length limit reached
strcat(line[numlines+1]," ");
strcat(line[numlines+1],word);//add to nextline
++numlines;

}
}while( (i<strlen(text)) && (numlines<3) );
//till the end of the text or max lines reached
}
void dialog::show_diag()
{
m.mouseoff();
diagbutton::mode=-1;//reset previously selected button
buf=farmalloc ( imagesize(x1-1,y1-1,x2+1,y2+1) );
if (buf == NULL)
{
cout<< "null malloc\n";
getch();
}
getimage(x1-1,y1-1,x2+1,y2+1,buf); //savebackground
setcolor(BLUE);
//clear background
setfillstyle(SOLID_FILL,BLACK);
rectangle(x1,y1,x2,y2);
floodfill(x1+2,y1+2,BLUE);

57

setcolor(WHITE);
setlinestyle(SOLID_LINE,0,3); //draw outer line
rectangle(x1,y1,x2,y2);
setlinestyle(SOLID_LINE,0,1);
settextstyle(DEFAULT_FONT,0,2); //bigger size
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy((x1+x2)/2, y1+textheight(heading) , heading);
settextjustify(LEFT_TEXT,CENTER_TEXT);
settextstyle(DEFAULT_FONT,0,1);//default size
for (int i=0;i<=numlines;i++) //display the text
outtextxy(x1+10, y1+50+textheight("H")*2*i ,line[i]);
if(optionnum>0)
b[0].drawbutton();
if(optionnum>1) //2 buttons
b[1].drawbutton();
if(optionnum>2)//3 buttons
b[2].drawbutton();
}
void dialog::act_diag()
{
m.mouseon();
for(int i=0;i<optionnum;i++)
b[i].buttonact(); //check for button act till a button click
//use diagbutton::mode outside to decide on further action
}
void dialog::clear_diag()
{
for(int i=0;i<optionnum;i++)
b[i].reset();
if(buf!=NULL)
{
m.mouseoff();
putimage(x1-1,y1-1,buf,COPY_PUT); //restore previous image
m.mouseon();
}

farfree(buf);

58

MYFILE.H
/********************* MYFILE.H *******************************
class filediag:public dialog
{
protected:
public:

char oldfname[25]; //last used filename without extension


filediag();
filediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]);
void disp_diag();

};
***************************************************************/
filediag::filediag():dialog()
{
strcpy(oldfname,"");
}
filediag::filediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]):
dialog(x1t,y1t,x2t,y2t,optionnumt,buttontextt,headingt,textt,idt)
{
strcpy(oldfname,"");
}
void filediag::disp_diag()
{
char fname[25]="";
if ( strlen(oldfname)!=0 )
strcpy(fname,oldfname);
show_diag();
diagbutton::resetmode();
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x1+10,y1 + (y2-y1)*0.8+ textheight("F")/2 ,"File Name");
settextjustify(LEFT_TEXT,CENTER_TEXT);
rectangle(x1+textwidth("File Name")+15,y1+(y2-y1)*0.8, x2-30,
y1+(y2-y1)*0.8 + 18);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x1+textwidth("File Name")+18,y1 + (y2-y1)*0.8+
textheight("F")/2 ,fname);
settextjustify(LEFT_TEXT,CENTER_TEXT);
while(diagbutton::mode==-1)
{
if(kbhit())
{
if(strlen(fname)<20)

59

{
int c=getch();
if(c==8)
{
fname[strlen(fname)-1]='\0';

//backspace

//decrease one letter


}
else if(c==0)
//special char
getch();
//clear buffer of other chars
else if(c==13)
//enter
diagbutton::mode=ok; //any +ve result
else if(c==27)
//escape
diagbutton::mode=cancel;//any -ve result
else if( isalnum( (char)c ) )
{
int l=strlen(fname);
fname[l]=(char)c;
fname[l+1]='\0';
}
setfillstyle(SOLID_FILL,BLACK);
bar(x1+textwidth("File Name")+15,y1 + (y2-y1)*0.8 ,
x2-30, y1 + (y2-y1)*0.8 + 18);
rectangle(x1+textwidth("File Name")+15,y1 +
(y2-y1)*0.8, x2-30, y1 + (y2-y1)*0.8 + 18);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x1+textwidth("File Name")+18,y1 +
(y2-y1)*0.8+ textheight("F")/2 ,fname);
settextjustify(LEFT_TEXT,CENTER_TEXT);
}
else if(strlen(fname)==20)//to allow to delete last letter
{
int c=getch();
if(c==8)
//backspace
{
fname[strlen(fname)-1]='\0';
}
//decrease one letter
setfillstyle(SOLID_FILL,BLACK);
bar(x1+textwidth("File Name")+15,y1 + (y2-y1)*0.8 ,
x2-30, y1 + (y2-y1)*0.8 + 18);
rectangle(x1+textwidth("File Name")+15,y1 +
(y2-y1)*0.8 , x2-30, y1 + (y2-y1)*0.8 + 18);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x1+textwidth("File Name")+18,y1 +
(y2-y1)*0.8+ textheight("F")/2 ,fname);
settextjustify(LEFT_TEXT,CENTER_TEXT);
}
else
getch();//empty buffer
}
act_diag();

60

if(diagbutton::mode!=-1 && diagbutton::mode!=cancel &&


diagbutton::mode!=exitb && strlen(fname)==0 )
{
diagbutton::resetmode();
b[0].reset();
diagbutton::mode=-1;//do not save if name is empty
h.display(6);
}
}
strcpy(oldfname,fname);
clear_diag();
/*
NOTE:do this in overloaded function for actions
if (diagbutton::mode==<mode>) //if save selected
{
action to be taken
}
}

*/

MYSAVE.H
//#define iovar(var) (char*)&(var),sizeof(var) in mydefine.h
struct nodexy
{
int x,y;
}nxy;
struct linedat
{
int x1,y1,x2,y2,c;
}ld;
struct fileheader
{
int version,numscenes;
}fh;
struct sceneheader
{
int numnodes,numlines;
}sh;
#define VERSION 3 //to ensure that only the correct format is read

61

/************************************************************
File structure:
ver-num numscenes
numnodes numlines
x y
x y
x y
x1 y1 x2 y2
x1 y1 x2 y2
x1 y1 x2 y2
numnodes numlines
......
......
**************************************************************/
/*************************************************************
class savediag:public filediag
{
public:
static int firstsave;
savediag();
savediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,char **buttontextt,char
headingt[20],char *textt,int idt[3]);
friend void savefile(char *fname,int sceneid,int newf);
void disp_diag();
}dsave;
int savediag::firstsave=1; //1st save or not
***********************************************************/
savediag::savediag():filediag()
{
strcpy(oldfname,"");
}
savediag::savediag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]):
filediag(x1t,y1t,x2t,y2t,optionnumt,buttontextt,headingt,textt,idt)
{
strcpy(oldfname,"");
}
void savediag::disp_diag()
{
filediag::disp_diag();
if (diagbutton::mode==save || diagbutton::mode==ok)
{
//if save selected (->ok for ENTER key)
savefile(oldfname,scenedat::curscene,savediag::firstsave);//newfile
}
}

62

//-------------------for accessing save dialog from program-----------------/*************************************************************************


class savebutton:public diagbutton
{
public:
savebutton()
{}
void buttonact();
friend void savebuttoninit();
}sb;
*************************************************************************/
void savebutton::buttonact()
{
if(m.mousemode==topbar)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
h.display(H_save);
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if (stat==active) //if clicked
{
dsave.disp_diag();
mode=id; //set workmode
}
}
}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat
if (stat==active)
sb.reset();
diagbutton::resetmode();
}
void savebuttoninit()
{
sb.x1=tbx1;
sb.y1=tby1;
sb.x2=tbx1+50;
sb.y2=tby2;
sb.id=save;
sb.prestat=off; //for complete redraw 1st time
sb.stat=off;
strcpy(sb.text,"SAVE");
sb.drawbutton();
}
void initsavediag()
{
char *s[2]={"SAVE","CANCEL"};
int d[2]={save,cancel};
dsave=savediag(100,100,400,400,2,s,"SAVE","Enter File Name",d);
}
//------------------------- dialog over--------------------------------

63

//------------------------ save start---------------------------------void savescene(char *fname,int sceneid,int newf=0)


{
int scenes=1;
if( strstr(fname,".kdr")==NULL )//no extention
strcat(fname,".kdr");
if(newf==1)
remove(fname);//delete existing file
fstream f(fname,ios::in|ios::out);
if ( f.good() && newf || strcmpi(dsave.oldfname,fname)==0)//if new file
{
f.seekp(0,ios::beg);
scenes=1;
fh.version=VERSION;
fh.numscenes=1;
f.write( iovar(fh) );
savediag::firstsave=0;
}
if(!f.good())
{
cout<<"error-file not open";
getch();
}
else
{
//-------------skip to required scene
f.seekp(0,ios::beg);
f.seekg(0,ios::beg);
f.read( iovar(fh) );
if(fh.version==VERSION)
{
scenes= fh.numscenes; //if prev datat exists
//----------skip older scenes-----------------------------if(sceneid>=scenes)//new or current scene
{
if (sceneid==scenes+1)//next scene to be written
{
for(int i=1;i<=scenes ;i++)
{
f.read(iovar(sh)); //get no. of //nodes in next
scene
f.seekg( ( sh.numnodes*sizeof(nxy))+ (
sh.numlines*sizeof(ld) ),ios::cur );
}//skip all nodes in each scene
}

64

else if (sceneid==scenes)//update current scene


{
for(int i=1;i<scenes ;i++)
{
f.read(iovar(sh));
//get no. of nodes in next scene
f.seekg( ( sh.numnodes*sizeof(nxy))+
(sh.numlines*sizeof(ld))
,ios::cur);//skip all nodes in scene
}
}
//-------------skip older scenes-over-----------------------//---------------write required scene-----------------------sh.numnodes=nodes::last();
sh.numlines=lines::num;
f.write( iovar(sh) );
//write info about scene contents for access
for (int i=0;i<=nodes::last();i++)
{
nxy.x=wnode(i).x;
nxy.y=wnode(i).y;
f.write( iovar(nxy) );
}//write all nodes
for (i=0;i<=lines::num;i++)
{
ld.x1=conline(i).p[0]->x;
ld.y1=conline(i).p[0]->y;
ld.x2=conline(i).p[1]->x;
ld.y2=conline(i).p[1]->y;
ld.c =conline(i).color;
}

f.write( iovar(ld) );
//write all lines

f.close();
//---------------write required scene-over-----------------}
}
}
}
void savefile(char *fname,int sceneid=1,int newf=0) //save a particlar scene
{
if( strstr(fname,".kdr")==NULL )//no extention
strcat(fname,".kdr");
}

savescene(fname,sceneid,newf);

//------------------------- save over--------------------------------------

65

MYOPEN.H
/************************************************************
File structure:
ver-num numscenes
numnodes numlines
x y
x y
x y
x1 y1 x2 y2
x1 y1 x2 y2
x1 y1 x2 y2
numnodes numlines
......
......
**************************************************************/
//------------------------- dialog start-----------------------------/*******************************************************************
class opendiag:public filediag
{
public:
opendiag();
opendiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]);
friend void openfile(char *fname);
void disp_diag();
}dopen;
*****************************************************************/
opendiag::opendiag():filediag()
{
strcpy(oldfname,"");
}

opendiag::opendiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,


char **buttontextt,char headingt[20],char *textt,int idt[3]):
filediag(x1t,y1t,x2t,y2t,optionnumt,buttontextt,headingt,textt,idt)
{
strcpy(oldfname,"");
}
void opendiag::disp_diag()
{
filediag::disp_diag();
if (diagbutton::mode==open || diagbutton::mode==ok) //if open selected
{
//(->ok for ENTER key)
nodes::empty();

66

lines::empty();
m.mouseoff();
setfillstyle(SOLID_FILL,BLACK);
bar(wx1,wy1,wx2,wy2);
m.mouseon();
}

openfile(oldfname);

}
// for accessing save dialog from program
/**********************************************************************
class openbutton:public diagbutton
{
public:
openbutton(){}
void buttonact();
friend void openbuttoninit();
}ob;
***********************************************************************/
void openbutton::buttonact()
{
if(m.mousemode==topbar)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
h.display(H_open);
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if (stat==active) //if clicked
{
dopen.disp_diag();
mode=id; //set workmode
}
}
}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat
if (stat==active)
ob.reset();
diagbutton::resetmode();
}
void openbuttoninit()
{
ob.x1=tbx1+55;
ob.y1=tby1;
ob.x2=tbx1+105;
ob.y2=tby2;
ob.id=open;
ob.prestat=off; //for complete redraw 1st time
ob.stat=off;
strcpy(ob.text,"OPEN");

67

ob.drawbutton();
}
void initopendiag()
{
char *s[2]={"OPEN","CANCEL"};
int d[2]={open,cancel};
dopen=opendiag(100,100,400,400,2,s,"OPEN","Enter File Name",d);
}
//------------------------- dialog over-----------------------------//------------------------- open start------------------------------void openfile(char *fname)
{
int scenes=1;
if( strstr(fname,".kdr")==NULL )//no extention
strcat(fname,".kdr");
fstream f(fname,ios::in|ios::nocreate|ios::binary);
if(f.fail())
{
h.display(H_nofile);
}
else
{
//-------------skip to required scene
f.seekg(0,ios::beg);
if(f.read(iovar(fh)) && fh.version==VERSION )
{
scenes= fh.numscenes; //get no. of scenes
for (int i=1;i<=scenes && !f.eof();i++) //for all scenes
{
f.read( iovar(sh) );
for (int j=0;j<=sh.numnodes;j++)
{
f.read( iovar(nxy) );
nodes::newnode(nxy.x , nxy.y);
}

for (j=0;j<=sh.numlines;j++)
{
f.read( iovar(ld) );
lines::newline(ld.x1,ld.y1,ld.x2,ld.y2,ld.c);
}
// change to next scene
}

f.close();
}
}
//------------------------- open over---------------------------------

68

MYEXIT.H
/****************************************************************************
class exitdiag:public filediag
{
public:
exitdiag();
exitdiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]);
friend void exit(char *fname);
void disp_diag();
}dexit;
***************************************************************************/
exitdiag::exitdiag():filediag()
{
strcpy(oldfname,"");
}
exitdiag::exitdiag(int x1t,int y1t,int x2t,int y2t,int optionnumt,char **buttontextt,char headingt[20],char
*textt,int idt[3]):filediag(x1t,y1t,x2t,y2t,optionnumt,buttontextt,headingt,textt,idt)
{
strcpy(oldfname,"");
}
void exitdiag::disp_diag()
{
filediag::disp_diag();
if (diagbutton::mode==save || diagbutton::mode==ok) //if save selected
{
//(->ok for ENTER key)

savefile(oldfname,scenedat::curscene,savediag::firstsave);//newfile
exit(0);//Exit Program properly
}
else if(diagbutton::mode==exitb)
exit(0);//Exit Program properly

/**************************************************************************
class exitbutton:public diagbutton
{
public:
exitbutton()
{}
void buttonact();
friend void exitbuttoninit();
}eb;
*************************************************************************/
void exitbutton::buttonact()
{
if(m.mousemode==topbar)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering

69

}
}

buttonclick(); //(virtual)check for click on button.


//any click recieved here will be on the button
h.display(H_exit);
if (stat==active) //if clicked
{
dexit.disp_diag();
mode=id; //set workmode

}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat
if (stat==active)
eb.reset();
}
void exitbuttoninit()
{
eb.x1=tbx2-60;
eb.y1=tby1;
eb.x2=tbx2;
eb.y2=tby2;
eb.id=exitb;
eb.prestat=off; //for complete redraw 1st time
eb.stat=off;
strcpy(eb.text,"EXIT");
eb.drawbutton();
}
void initexitdiag()
{
char *s[3]={"SAVE","CANCEL","EXIT"};
int d[3]={save,cancel,exitb};
dexit=exitdiag(100,100,400,400,3,s,"EXIT?","Do you want to Save Before
Exit? All unsaved data will be lost.",d);
}

MYRENDER.H
/**********************************************************************
class renderbutton:public buttons
{
public:
renderbutton(){}
static void render();
void buttonact();
friend void renderbuttoninit();
}rb;
***********************************************************************/
void renderbutton::buttonact()

70

{
if(m.mousemode==bottom_menu)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if (stat==active) //if clicked
{
render();
}
}
}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat
if (stat==active)
rb.reset();
}
/**********************************************************************
class renderexitbutton:public buttons
{
public:
renderexitbutton(){}
void disp();
int buttonact();
friend void renderbuttoninit();
}reb;
******************************************************************/
int renderexitbutton::buttonact()
{
int e=0;
if(m.mousemode==bottom_menu)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
if (stat==active) //if clicked
{
e=1;
}

delay(750);

}
}
if (prestat!=stat)
drawbutton(); //redraw only if change in stat

71

if (stat==active)
reb.reset();
return e;
}
void renderbuttoninit()
{
rb.x1=bmx1;
rb.y1=bmy2-50;
rb.x2=bmx1+85;
rb.y2=bmy2-7;
rb.id=renderb;
rb.prestat=off; //for complete redraw 1st time
rb.stat=off;
strcpy(rb.text,"RENDER");
rb.drawbutton();
reb.x1=bmx1;
reb.y1=bmy2-50;
reb.x2=bmx1+85;
reb.y2=bmy2-7;
reb.id=renderbe;
reb.prestat=off; //for complete redraw 1st time
reb.stat=off;
strcpy(reb.text,"RETURN");
}
void renderbutton::render()
{
m.mouseoff();
setfillstyle(SOLID_FILL,BLACK);
bar(0,0,getmaxx(),getmaxy());
for(int i=0;i<=lines::num;i++)
conline(i).drawline();
m.mouseon();
delay(500);
reb.drawbutton();
while(reb.buttonact()==0);//wait till exit is selected
//redraw all work related stuff
nodes::draw_all();
sb.drawbutton();
ob.drawbutton();
eb.drawbutton();
omb.drawbutton();
lc.disp();
h.helpinit();
for (i=0;i<=2;i++)
nb[i].drawbutton();

72

MYOPT.H
/********************************************************************
class optionbutton
{
char *text;
int stat,x,y,data;
public:
optionbutton()
{
text=NULL;
}
int getstat()
{
return stat;
}
optionbutton(int x1,int y1,char *text1,int dat);
void draw();
void act();
};
*********************************************************************/
optionbutton::optionbutton(int x1,int y1,char *text1,int dat)
{
x=x1;
y=y1;
text=text1;
stat=dat;
}
void optionbutton::draw()
{
m.mouseoff();
setcolor(WHITE);
rectangle(x,y,x+10,y+10);
if(stat==1)
{
line(x,y,x+10,y+10);
line(x,y+10,x+10,y);//cross mark
}
else
{
setcolor(BLACK);
line(x,y,x+10,y+10);
line(x,y+10,x+10,y);//erase cross mark
setcolor(WHITE);
}
textsettingstype *t=NULL;
gettextsettings(t);//get current settings
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x+20,y,text);

73

settextjustify(t->horiz,t->vert);//restore old settings


m.mouseon();
}
void optionbutton::act()
{
if(m.hovermouse(x+5,y+5,5,6)) //if hovering
{
if(m.ifclick()==LCLICK)
{
if(stat==1)
stat=0;
else
stat=1;
draw();
delay(100);
}
}

/*******************************************************************
class option:public dialog
{
static int recursivedraw;
optionbutton rd;
friend lines;
public:
option();
option(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int idt[3]);
static int isrecursive()
{
return recursivedraw;
}

void disp();
}opt;
int option::recursivedraw=1;
*************************************************************************/
option::option():dialog(),rd()
{}
option::option(int x1t,int y1t,int x2t,int y2t,int optionnumt,
char **buttontextt,char headingt[20],char *textt,int
idt[3]):dialog(x1t,y1t,x2t,y2t,optionnumt,buttontextt,headingt,textt,idt)
{
rd=optionbutton(100+20,100+100,"Recursive Draw (Slower)",recursivedraw);
}

74

void option::disp()
{
char *s[2]={"OK"};
int d[1]={ok};
opt=option(100,100,410,400,1,s,"OPTIONS",
"Select performance options",d);
show_diag();
rd.draw();
while(diagbutton::mode!=ok)
{
rd.act();
if(rd.getstat()==1)
recursivedraw=1;
else
recursivedraw=0;
if(kbhit())
{
char ch=getch();
if (ch==13 || ch==27)//enter or esc
break;
}
act_diag();
}
clear_diag();
}
/****************************************************************
class optionmenubutton:public buttons
{
public:
optionmenubutton(){}
void buttonact();
friend void optionmenubuttoninit();
}omb;
**************************************************************/
void optionmenubutton::buttonact()
{
if(m.mousemode==topbar)
{
prestat=stat;
//store last recorded stat
mouseover();
//checks for hovering.updates stat
if (stat==hover) //if hovering
{
buttonclick(); //(virtual)check for click on button.
//any click recieved here will be on the button
h.display(H_option);

75

if (stat==active) //if clicked


{
opt.disp();
}
}

if (prestat!=stat)
drawbutton(); //redraw only if change in stat
if (stat==active)
omb.reset();
diagbutton::resetmode();
}
void optionmenubuttoninit()
{
omb.x1=tbx1+110;
omb.y1=tby1;
omb.x2=tbx1+180;
omb.y2=tby2;
omb.id=options;
omb.prestat=off; //for complete redraw 1st time
omb.stat=off;
strcpy(omb.text,"OPTIONS");
omb.drawbutton();
}

MYTIME.H
/************************** MYTIME.H ********************************
class MyTime
{
int stat;
double elapTicks;
clock_t Begin, End; //initialize Begin and End for the timer
public:
MyTime();
void start();
void stop();
int status();
float time();
};
********************************************************************/
MyTime::MyTime()
{
stat=0;
elapTicks=0;
End=0;
Begin=0;
}

76

void MyTime::start()
{
if (clock() == -1)
{
cout<<"time not available";
getch();
}
Begin = clock(); //start the timer
stat=1;
}
void MyTime::stop()
{
if (stat==1)
{
End = clock();
stat=0;
}
}

//stop the timer

int MyTime::status()
{
return stat;
}
float MyTime::time()
{
//the number of ticks from Begin to End
if (stat==1)
return ((clock() - Begin)/CLK_TCK); //currrent time - begin
else
return ((End - Begin)/CLK_TCK);

MYHELP.H
/**************************** MYHELP.H **************************************
class help
{
int x,y,h,now;
char *s[hstrnum]; //TODO at the end ,correct the value
public :
help();
void helpinit(); //can do only after init of graphics
void display(int code);
}h;
****************************************************************************/
void help::help()
{
for (int i=0;i<hstrnum;i++)
s[i]=helpstr[i];
}
void help::display(int code)//revert to older message
{
if(code == -2 )// not new message-> revert to old

77

{
if( pre != -1)
{
if (now != -1) //not empty
{
setcolor(BLACK); //erase old text
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x,y,s[now]);
}
setcolor(WHITE);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x,y,s[pre]);
now=pre;
pre =-1;

}
}
else if (now != code && code >=0)//not updated yet
{
if (now != H_empty) //not empty
{
setcolor(BLACK); //erase old text
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x,y,s[now]);
outtextxy(x,y,s[pre]);
}
setcolor(WHITE);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x,y,s[code]);
pre=now;
now=code;
}
}
void help::helpinit()
{
h = textheight("i");
x = 15;
y = getmaxy()- ( h/2.0 + 10 );
now= -1;
setcolor(WHITE);
setlinestyle(SOLID_LINE,0,3);
rectangle(x - 5, y - h/2.0 , x + textwidth( "Help :")+3 ,y+h+3);
settextjustify(LEFT_TEXT,TOP_TEXT);
outtextxy(x,y, "Help :");
}

x = x + textwidth( "Help :") + 7;

78

MYSTR.H
//all the help strings and their #define shortcuts for easy manipulation
#define hstrnum 12
char *helpstr[hstrnum]={ //correct the values in mystr when adding
"Click to create a new node",
//0 - new node
"Left click on a node to move it, Right click to immobilise (lock) it",
//1- not hovering or active
"Left click to release",
//2 - active node
"Right click to release lock",
//3 - mouse over locked
"Left click on a node to delete it, Right click to cancel mode",//4
"No nodes to delete",
//5
"Name cannot have zero length " ,
//6
"File does not exist",
//7
"select Second node",
//8
"Get the final image",
//9
"Create new node",
//10
"Delete existing node",
//11
"Save this file",
//12
"Open existing file",
//13
"Exit K-DRAW",
//14
"Set Performance Options"
//15
};
#define H_empty
-1
#define H_newnode 0 //** in main
#define H_hover 1 //** in drawnode
#define H_active 2 //** in drawnode
#define H_locked 3 //** in nodeact
#define H_delnode 4 //** in main
#define H_no_del 5 //** in mynodes nodes::deletenode()
#define H_savelength 6 //** in mysave.h->disp_diag
#define H_nofile 7 //** in myopen.h->openfile
#define H_linenode 8 //** in .lines::lineact(nodes *p1)
#define H_render 9 //** in renderbutton::buttonact()
#define H_newnodeb 10 //** in nodebuttons::buttonact()
#define H_delnodeb 11 //** in nodebuttons::buttonact()
#define H_save 12 //** in savebutton::buttonact()
#define H_open
13 //** in openbutton::buttonact()
#define H_exit 14 //** in exitbutton::buttonact()
#define H_option
15 //** in optionmenubutton::buttonact()

79

MYMISC.H
//all miscellaneous functions.
void memshow()//to give visual indicator of critical memory status
{
static int stat=0,prestat=stat;
if(prestat==RED && stat==YELLOW)
{
setfillstyle(SOLID_FILL,BLACK);
bar(600,30.1,getmaxx(),35);
}
prestat=stat;
if (farcoreleft()<2*imagesize(0,0,getmaxx(),getmaxy()) )
{
stat=RED;
outtextxy(600,33,"Memory low!!");
}
else if (farcoreleft()<4*imagesize(0,0,getmaxx(),getmaxy()) )
{
stat=YELLOW;
}
else
{
stat=GREEN;
}
if(stat!=prestat)
{
setfillstyle(SOLID_FILL,stat);
pieslice(610,20,0,360,10);
}
}
void welcomediag()
{
m.mouseoff();
int x1=100,y1=100,x2=400,y2=400;
const int numlines=4;
char *heading="K-DRAW";
char *line[numlines]={ "Welcome to K-DRAW.",
"Using K-DRAW you can",
"Draw and edit pictures (.KDR)",
"save and open them too!"};
setlinestyle(SOLID_LINE,0,3); //draw outer line
rectangle(x1,y1,x2,y2);
setlinestyle(SOLID_LINE,0,1);
settextstyle(DEFAULT_FONT,0,2); //bigger size

80

settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy((x1+x2)/2, y1+textheight(heading) , heading);
settextjustify(LEFT_TEXT,CENTER_TEXT);
settextstyle(DEFAULT_FONT,0,1);//default size
outtextxy((x1+x2)/2, y1+textheight(heading)+25 ,
"BY Kiran Rajmohan");
settextjustify(CENTER_TEXT,CENTER_TEXT);
for (int i=0;i<numlines;i++) //display the text
outtextxy((x1+x2)/2, y1+75+textheight("H")*3*i ,line[i]);
char t[2];
t[0]=254;//solid block
t[1]='\0';

for(i=0;i<120;i+=2)
{
delay(75);
outtextxy(x1+25+i*2,y2-50,t);
outtextxy(x1+25+i*2,y2-46,t);
outtextxy(x1+25+i*2,y2-43,t);
}
setfillstyle(SOLID_FILL,BLACK);
bar(x1-2,y1-2,x2+2,y2+2);
}

m.mouseon();

81

SCREEN SHOTS

Welcome screen

82

Initial screen

83

Drawing a house

84

Completed house before Render

85

Rendered House

86

Open dialog box

87

Save dialog box

88

Options Dialog box

89

Exit Dialog box

90

BIBLIOGRAPHY
The following books and websites were referred for syntax and techniques.

Computer Science C++ by Sumita Arora

www.lookuptables.com (for ascii equivalents)

http://electrosofts.com/cgraphics/mouse.html (reference for mouse )

91

You might also like