"Fossies" - the Fresh Open Source Software Archive

Member "netmapr-1.9c/netmapr.c" (14 Dec 2009, 276230 Bytes) of package /linux/privat/old/netmapr-1.9c.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "netmapr.c" see the Fossies "Dox" file reference documentation.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 #include <stdio.h>
    2 #include <stdarg.h>
    3 #include <stdlib.h>
    4 #include <string.h>
    5 #include <time.h>
    6 #include <sys/time.h>
    7 #include <sys/types.h>
    8 #include <unistd.h>
    9 
   10 #include <math.h>
   11 
   12 #include <SDL.h>
   13 #include <SDL_ttf.h>
   14 #include <SDL_keysym.h>
   15 
   16 #include "savepng.h"
   17 #include "netmapr.h"
   18 #include "constants.h"
   19 
   20 SDL_Surface *screen, *buffer;
   21 SDL_Surface *emptyimg;
   22 SDL_Surface *icon;
   23 SDL_Event event;
   24 int isevent;
   25 
   26 char svgbuf[BUFLEN];
   27 FILE *svgfile;
   28 
   29 TTF_Font *font[MAXLETTERHEIGHT];
   30 
   31 SDL_Color white = { 255, 255, 255, USECOLOUR};
   32 SDL_Color black = { 0, 0, 0, USECOLOUR};
   33 SDL_Color red = { 255, 0, 0, USECOLOUR};
   34 SDL_Color green = { 0, 255, 0, USECOLOUR};
   35 SDL_Color blue = { 0, 0, 255, USECOLOUR};
   36 SDL_Color blue2 = { 0, 0, 70, USECOLOUR};
   37 SDL_Color yellow = { 255, 255, 0, USECOLOUR};
   38 SDL_Color cyan = { 0, 255, 255, USECOLOUR};
   39 SDL_Color purple = { 255, 0, 255, USECOLOUR};
   40 SDL_Color grey = { 90, 90, 90, USECOLOUR};
   41 SDL_Color grey2 = { 70, 70, 70, USECOLOUR};
   42 SDL_Color grey3 = { 50, 50, 50, USECOLOUR};
   43 SDL_Color grey4 = { 30, 30, 30, USECOLOUR};
   44 
   45 SDL_Color statusbarcolour = { 255, 255, 255, 0 };
   46 
   47 SDL_Surface *searchbg;
   48 int searchflash = 0;
   49 int searchcounter = 0;
   50 int searchticks = 0;
   51 int oldsearchticks = 0;
   52 
   53 int errorflash = 0;
   54 int errorcounter = 0;
   55 int errorticks = 0;
   56 int olderrorticks = 0;
   57 
   58 int infoflash = 0;
   59 int infocounter = 0;
   60 int infoticks = 0;
   61 int oldinfoticks = 0;
   62 
   63 SDL_Color gridhigh = {255, 255, 255, 0};
   64 SDL_Color gridmiddle = {90, 90, 90, 0};
   65 SDL_Color gridlow = {50, 50, 50, 0};
   66 
   67 SDL_Cursor *normalmouse;
   68 SDL_Cursor *objmouse;
   69 SDL_Cursor *textmouse;
   70 
   71 
   72 int linemask[MAXLINESTYLE][LINESTYLESIZE];
   73 
   74 xy_t fillstack[MAXFILLSTACK];
   75 int fillstackptr = 0;
   76 
   77 /* screen "viewpane" position */
   78 int screenx = 0;
   79 int screeny = 0;
   80 
   81 int thingdrawn[MAXOBJECTS + MAXLINKS];
   82 
   83 SDL_Color fgcol;
   84 SDL_Color objfillcol;
   85 Uint8 defthickness = 1;
   86 Uint8 defstyle = LS_SOLID;
   87 Uint8 defarrow = 0;
   88 
   89 int modified = FALSE;
   90 int readonly = FALSE;
   91 int needtocalc = FALSE;
   92 
   93 int maplistpos = 0; /* scroll position in map list */
   94 
   95 int copyfrom = -1;
   96 int copymap = -1;
   97 int copytype = T_MAP;
   98 
   99 int searchmap = 0;
  100 int searchtob = 0;
  101 int searchwrap = FALSE;
  102 char searchtext[BUFLEN];
  103 
  104 int grid = TRUE;
  105 int gridsize = 15;
  106 int gridsizelist[] = {0, 10, 15, 20};
  107 int gridsizeindex = 1;
  108 int gridsizenum = 4;
  109 SDL_Color gridcol = {192, 192, 192, 0 };
  110 
  111 int oldshowflows = FALSE;
  112 int showflows = FALSE;
  113 
  114 int shortcut[] = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8 };
  115 int shortcutnum = 10;
  116 
  117 int matchtype = 0;
  118 
  119 int numobjtypes = 0;
  120 int numletters = 0;
  121 int numbuttons = 0;
  122 int nummaps = 1;
  123 
  124 int history[MAXHISTORY];
  125 int numhistory = 0;
  126 
  127 int children[MAXCHILDREN];
  128 int numchildren = 0;
  129 
  130 
  131 char currentfilename[BUFLEN];
  132 int state = S_NONE; 
  133 SDL_Surface *shadow = NULL; /* for object moves */
  134 SDL_Surface *bg = NULL; /* background for temp images*/
  135 int *linebg;  /* background for temp lines */
  136 int bgx,bgy;
  137 int bgw,bgh;
  138 int xoff,yoff;
  139 SDL_Rect temparea;
  140 char statustext[BUFLEN];
  141 char oldstatustext[BUFLEN];
  142 int rollover = FALSE;
  143 int oldmousepos = -1;
  144 int mousepos = 0;
  145 int oldselection = -1;
  146 int dontpaste = FALSE;
  147 
  148 SDL_Surface *toolbg;
  149 SDL_Surface *toolhilite;
  150 
  151 int curmap = 0;
  152 
  153 int startx,starty;
  154 int textanchor;
  155 char text[BUFLEN];
  156 int startobj,endobj;
  157 int updateheight;
  158 char * textpos; // new
  159 
  160 char progdir[BUFLEN];
  161 
  162 int shift;
  163 int autoload = FALSE;
  164 
  165 int main (int argc, char **argv) {
  166     int done;
  167     int c;
  168     int c2;
  169     int mod = FALSE;
  170     int tmod;
  171     int o;  
  172     Uint32 oldticks = 0;
  173     Uint32 ticks;
  174     int doubleclick = FALSE;
  175     int n,found,delmap;
  176     int mx,my,mb;
  177 
  178     if (argc >= 2) {
  179         int i;
  180         strcpy(text, argv[1]);
  181         /* cope with spaces in filenames */
  182         for (i = 2; i < argc; i++) {
  183             strcat(text, " ");
  184             strcat(text, argv[i]);
  185         }
  186         autoload = TRUE;
  187     }
  188 
  189     if (getenv("NETMAPRDIR") != NULL) {
  190         strncpy(progdir, getenv("NETMAPRDIR"), BUFLEN);
  191     } else {
  192         strcpy(progdir, "/usr/local/share/netmapr");
  193     }
  194 
  195     if (strstr(argv[0], "view")) {
  196         readonly = TRUE;
  197     }
  198 
  199     /*
  200     if (readonly) {
  201         printf("Starting netmapr viewer v%s...\n", VERSION);
  202     } else {
  203         printf("Starting netmapr v%s...\n", VERSION);
  204     }
  205     */
  206 
  207 
  208 
  209     if (initgraphics()) {
  210         printf("Error initialising graphics.\n");
  211         exit(1);
  212     }
  213     atexit(cleanup);
  214 
  215     SDL_EnableUNICODE(1);
  216 
  217 
  218     if (autoload) {
  219         loadmap();
  220         strcpy(text, "");
  221         textpos = text;
  222     }
  223 
  224 
  225     if (readonly) {
  226         sprintf(statustext, "Welcome to netmapr viewer v%s.  Author:  rob@nethack.net", VERSION);
  227     } else {
  228         sprintf(statustext, "Welcome to netmapr v%s.  Author:  rob@nethack.net", VERSION);
  229     }
  230     strcpy(oldstatustext,statustext);
  231     drawscreen();
  232 
  233     /* main loop */
  234     done = 0;
  235 
  236     while (!done) {
  237         /* fade search result indicator */
  238         if (searchflash > 0) {
  239             searchticks = SDL_GetTicks();
  240             if (searchticks - oldsearchticks >= SEARCHFLASHSPEED) {
  241                 searchflash--;
  242                 /* show the found object */
  243                 switch (state) {
  244                     case S_SAVING:
  245                     case S_LOADING:
  246                     case S_FGCOL:
  247                     case S_MAPNAMING:
  248                     case S_CREATETELE:
  249                     case S_REALLYQUIT:
  250                     case S_FILLCOL:
  251                     case S_SEARCH:
  252                         break;
  253                     default:
  254                         drawsearchflash();
  255                         break;
  256                 }
  257 
  258                 oldsearchticks = searchticks;
  259             }
  260         }
  261         /* fade error panel */
  262         if (errorflash > 0) {
  263             errorticks = SDL_GetTicks();
  264             if (errorticks - olderrorticks >= ERRORFLASHSPEED) {
  265                 errorflash--;
  266                 drawstatusbar();
  267 
  268                 olderrorticks = errorticks;
  269             }
  270         }
  271         /* fade info panel */
  272         if (infoflash > 0) {
  273             infoticks = SDL_GetTicks();
  274             if (infoticks - oldinfoticks >= INFOFLASHSPEED) {
  275                 /* don't fade this if we're in a mode where the user
  276                    has to do something special */ 
  277                 switch (state) {
  278                     case S_MATCHX:
  279                     case S_MATCHY:
  280                     case S_MATCHSIZE:
  281                     case S_CREATETELE:
  282                     case S_CHANGEOBJECT:
  283                     case S_DRAWFLOW:
  284                         break;
  285                     default:
  286                         infoflash--;
  287                         break;
  288                 }
  289                 drawstatusbar();
  290 
  291                 oldinfoticks = infoticks;
  292             }
  293         }
  294         /* check for input */
  295         //while (SDL_PollEvent(&event)) {
  296         isevent = TRUE;
  297         if (infoflash || errorflash || searchflash) {
  298             if (!SDL_PollEvent(&event)) isevent = FALSE;
  299         } else {
  300             if (!SDL_WaitEvent(&event)) isevent = FALSE;
  301         }
  302 
  303         while (isevent) {
  304             switch (event.type) {
  305                 case SDL_VIDEORESIZE:
  306                     /* set screen size */
  307                     screen = SDL_SetVideoMode(event.resize.w > MINSCREENX ? event.resize.w : MINSCREENX,
  308                                       event.resize.h > MINSCREENY ? event.resize.h : MINSCREENY,
  309                                   //map[curmap].bpp, SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_RESIZABLE);
  310                                   map[curmap].bpp, SDL_SWSURFACE|SDL_RESIZABLE);
  311                     SDL_FreeSurface(buffer);
  312                     buffer = SDL_CreateRGBSurface(SDL_SWSURFACE,screen->w - SIDEBARW,screen->h - STATUSH,
  313                         screen->format->BitsPerPixel, screen->format->Rmask,
  314                         screen->format->Gmask,screen->format->Bmask,
  315                         screen->format->Amask);
  316                     calcmapdimensions();
  317                     drawscreen();
  318                     break;
  319                 case SDL_MOUSEBUTTONDOWN:
  320                     searchflash = 0;
  321                     if (isonxscrollbar(event.button.x, event.button.y)) {
  322                         /* middle of the screen goes to where we clicked */
  323                         screenx = (((double)event.button.x / (double)(screen->w - SIDEBARW)) * map[curmap].width)
  324                               - ((screen->w - SIDEBARW)/2);
  325 
  326                         validatescreenpos();
  327                         drawxscrollbar();
  328                         changestate(S_XSCROLL);
  329                     } else if (isonyscrollbar(event.button.x, event.button.y)) {
  330                         /* middle of the screen goes to where we clicked */
  331                         screeny = (((double)event.button.y / (double)(screen->h - STATUSH - SBSIZE)) * map[curmap].height)
  332                               - ((screen->h - STATUSH - SBSIZE)/2);
  333 
  334                         validatescreenpos();
  335                         drawyscrollbar();
  336                         changestate(S_YSCROLL);
  337                     } else if (isonmap(event.button.x, event.button.y)) {
  338                         event.button.x += screenx;
  339                         event.button.y += screeny;
  340                         if (state == S_NONE) {
  341                             mod = SDL_GetModState();
  342                             if ((event.button.button == SDL_BUTTON_LEFT) && ((mod & KMOD_SHIFT))) {
  343                                 /* centre map on clicked position */
  344                                 screenx = event.button.x -  ((screen->w - SIDEBARW)/2);
  345                                 screeny = event.button.y -  ((screen->h - STATUSH)/2);
  346                                 validatescreenpos();
  347                                 drawmap(TRUE);
  348                             } else if ((event.button.button == SDL_BUTTON_LEFT) && ((mod & KMOD_CTRL) == 0)) {
  349                                 /* is there a selected link? if so check for it first */
  350                                 if ((map[curmap].selecteditemtype == T_LINK) && (map[curmap].selecteditem != -1) && 
  351                                     (isonlinkdst(map[curmap].selecteditem, event.button.x,event.button.y)) ) {
  352                                     
  353                                     map[curmap].curlink = map[curmap].selecteditem;
  354                                     startlinkdstmove(event.button.x, event.button.y);
  355                                 } else if ((map[curmap].selecteditemtype == T_LINK) && (map[curmap].selecteditem != -1) &&
  356                                     (isonlinksrc(map[curmap].selecteditem, event.button.x,event.button.y)) ) {
  357                                     map[curmap].curlink = map[curmap].selecteditem;
  358                                     startlinksrcmove(event.button.x, event.button.y);
  359                                 } else if ( ((map[curmap].selecteditemtype == T_LINK)  || (map[curmap].selecteditemtype == T_LINKPOINT))
  360                                     && (map[curmap].selecteditem != -1) &&
  361                                     (isonlinkpoint(map[curmap].selecteditem, event.button.x,event.button.y) != -1) ) {
  362                                     map[curmap].curlink = map[curmap].selecteditem;
  363                                     map[curmap].curlinkpoint = isonlinkpoint(map[curmap].selecteditem, event.button.x,event.button.y); 
  364                                     startlinkpointmove(event.button.x, event.button.y);
  365                                 } else {
  366                                     // move/select object 
  367                                     o = thingat(event.button.x, event.button.y);
  368                                     if (o != -1) {
  369                                         switch (map[curmap].thing[o].type) {
  370                                             case T_OBJECT:
  371                                                 map[curmap].curobj = map[curmap].thing[o].id;
  372                                                 startobjmove(event.button.x,event.button.y);
  373                                                 break;
  374                                             case T_LINK:
  375                                                 map[curmap].curlink = map[curmap].thing[o].id;
  376                                                 startlinkmove(event.button.x, event.button.y);
  377                                                 break;
  378                                             case T_TEXT:
  379                                                 map[curmap].curtext = map[curmap].thing[o].id;
  380                                                 starttextmove(event.button.x, event.button.y);
  381                                                 break;
  382                                         }
  383                                     } else {
  384                                         /* just clear the status text */
  385                                         sprintf(statustext, "Ready.");
  386                                         drawstatusbar();
  387                                     }
  388                                 }
  389                             } else if ((event.button.button == SDL_BUTTON_MIDDLE) ||
  390                                    ((event.button.button == SDL_BUTTON_LEFT) && (mod & KMOD_CTRL))) {
  391                                     // if we're over an object, start drawing a new link
  392                                     o = objat(event.button.x, event.button.y);
  393                                     if (o != -1) {
  394                                         map[curmap].curobj = o;
  395                                         startlink(event.button.x,event.button.y);
  396                                     }
  397                             } else if (event.button.button == SDL_BUTTON_RIGHT) {
  398                                 // resize text
  399                                 o = textat(event.button.x, event.button.y);
  400                                 if (o != -1) {
  401                                     map[curmap].curtext = o;
  402                                     startresizetext(event.button.x,event.button.y);
  403                                 } else {
  404                                     // resize object 
  405                                     o = objat(event.button.x, event.button.y);
  406                                     if (o != -1) {
  407                                         map[curmap].curobj = o;
  408                                         startresize(event.button.x,event.button.y);
  409                                     }
  410                                 }
  411 
  412 
  413                                 /*
  414                                 // resize object 
  415                                 o = objat(event.button.x, event.button.y);
  416                                 if (o != -1) {
  417                                     map[curmap].curobj = o;
  418                                     startresize(event.button.x,event.button.y);
  419                                 } else {
  420                                     // resize text
  421                                     o = textat(event.button.x, event.button.y);
  422                                     if (o != -1) {
  423                                         map[curmap].curtext = o;
  424                                         startresizetext(event.button.x,event.button.y);
  425                                     } 
  426                                 }
  427                                 */
  428                             } else if (event.button.button == SDL_BUTTON_WHEELUP) {
  429                                 int amt;
  430 
  431                                 tmod = SDL_GetModState();
  432                                 if ((mod & KMOD_SHIFT)) {
  433                                     amt = (map[curmap].numthings / MULTIRAISENUM);
  434                                 } else amt = 1;
  435 
  436                                 if (map[curmap].selecteditem != -1) {
  437                                     /* raise the selected object */
  438                                     raiseselected(amt);
  439                                 }
  440                             } else if (event.button.button == SDL_BUTTON_WHEELDOWN) {
  441                                 int amt;
  442 
  443                                 tmod = SDL_GetModState();
  444                                 if ((mod & KMOD_SHIFT)) {
  445                                     amt = (map[curmap].numthings / MULTIRAISENUM);
  446                                 } else amt = 1;
  447 
  448                                 if (map[curmap].selecteditem != -1) {
  449                                     /* lower the selected object */
  450                                     lowerselected(amt);
  451                                 }
  452                             }
  453                         } /* end if state = none */
  454                     } else if (isonobox(event.button.x, event.button.y)) {
  455                         int amt = 1;
  456 
  457                         tmod = SDL_GetModState();
  458                         if ((mod & KMOD_SHIFT)) {
  459                             amt = 4;
  460                         }
  461 
  462                         if (event.button.button == SDL_BUTTON_WHEELUP) {
  463                             scrollobox(-amt);
  464                         } else if (event.button.button == SDL_BUTTON_WHEELDOWN) {
  465                             scrollobox(amt);
  466                         }
  467                     }
  468                     break;
  469                 case SDL_MOUSEBUTTONUP:
  470                     searchflash = 0;
  471                     mod = SDL_GetModState();
  472                     if ((event.button.button == SDL_BUTTON_LEFT) && ((mod & KMOD_CTRL) == 0)) {
  473                         ticks = SDL_GetTicks();
  474                         if ((ticks - oldticks) <= DOUBLECLICKTHRES) {
  475                             doubleclick = TRUE;
  476                         } else {
  477                             doubleclick = FALSE;
  478                         }
  479                         oldticks = ticks;
  480 
  481                         if ((state == S_XSCROLL) || (state == S_YSCROLL)) {
  482                             changestate(S_NONE);
  483                             drawmap(TRUE);
  484                         } else if (state == S_EDITTEXT) {
  485                             endtextedit();
  486                         } else if (state == S_TYPETEXT) {
  487                             endtext();
  488                         } else if (isonmap(event.button.x, event.button.y)) {
  489                             event.button.x += screenx;
  490                             event.button.y += screeny;
  491                             if (state != S_REALLYQUIT) {
  492                                 //if ((doubleclick) && (objat(event.button.x, event.button.y) == map[curmap].selecteditem)) { 
  493                                 if (doubleclick) {
  494                                     o = objat(event.button.x, event.button.y);
  495 
  496                                     /* only works on an object */
  497                                     //if (map[curmap].selecteditem != -1) {
  498                                     if (o != -1) {
  499                                         /* can't create a new child via double click */
  500                                         if (map[curmap].obj[o].child != -1) {
  501                                             changestate(S_NONE);
  502                                             drillto(map[curmap].obj[o].child);
  503                                         } else {
  504                                             seterror(255);
  505                                             sprintf(statustext, "Cannot drill down - object has no children (use drill tool to create one).");
  506                                             map[curmap].selecteditem = -1;
  507                                             changestate(S_NONE);
  508                                             drawmap(TRUE);
  509                                         }
  510                                     } else {
  511                                         o = textat(event.button.x, event.button.y);
  512                                         if (o != -1) {
  513                                             startedittext(o);
  514                                         }
  515                                     }
  516                                 } 
  517                             }
  518                             if (state == S_NONE) {
  519                                 if (map[curmap].selecteditem != -1) {
  520                                     map[curmap].selecteditem = -1;
  521                                     map[curmap].selecteditemtype = T_EMPTY;
  522                                     sprintf(statustext,"Objects/lines deselected.\n"); 
  523                                     drawmap(TRUE);
  524                                 }
  525                             } else if (state == S_DRAWFLOW) {
  526                                 int clickedtype = -1;
  527                                 o = textat(event.button.x, event.button.y);
  528                                 if (o == -1) {
  529                                     o = objat(event.button.x, event.button.y);
  530                                     if (o == -1) {
  531                                         o = getlinkat(event.button.x, event.button.y);
  532                                         if (o != -1) {
  533                                             clickedtype = T_LINK;
  534                                         }
  535                                     } else {
  536                                         clickedtype = T_OBJECT;
  537                                     }
  538                                 } else {
  539                                     clickedtype = T_TEXT;
  540                                 }
  541                                 if (clickedtype == -1) {
  542                                     /* reset to old showflows value */
  543                                     changestate(S_NONE);
  544                                     drawmap(TRUE);
  545                                 } else {
  546                                     toggleflow(o, clickedtype);
  547                                     if (isflow(o, clickedtype)) {
  548                                         setinfo(255);
  549                                         sprintf(statustext, "%s #%d traffic flow status = TRUE.", typedesc[clickedtype], o);
  550                                     } else {
  551                                         setinfo(255);
  552                                         sprintf(statustext, "%s #%d traffic flow status = FALSE.", typedesc[clickedtype], o);
  553                                     }
  554                                     drawmap(TRUE);
  555                                 }
  556                             } else if (state == S_REALLYQUIT) {
  557                                 o = getyn(event.button.x-screenx, event.button.y-screeny);
  558                                 if (o == YES) {
  559                                     done = TRUE;
  560                                 } else {
  561                                     changestate(S_NONE);
  562                                     drawmap(TRUE);
  563                                 }
  564                             } else if (state == S_MATCHSIZE) {
  565                                 if (matchtype == T_OBJECT) {
  566                                     o = objat(event.button.x, event.button.y);
  567                                     if (o == -1) {
  568                                         changestate(S_NONE);
  569                                         sprintf(statustext, "Size match mode aborted.");
  570                                         drawstatusbar();
  571                                     } else {
  572                                         int n;
  573                                         /* resize selected item to match one which was clicked */
  574                                         map[curmap].obj[map[curmap].selecteditem].w = map[curmap].obj[o].w;
  575                                         map[curmap].obj[map[curmap].selecteditem].h = map[curmap].obj[o].h;
  576                                         /* adjust offsets on all links to/from object */
  577                                         for (n = 0; n < map[curmap].numlinks; n++) {
  578                                             if (map[curmap].olink[n].srcobj == map[curmap].selecteditem) {
  579                                                 map[curmap].olink[n].srcxoff = (map[curmap].obj[o].w / 2);
  580                                                 map[curmap].olink[n].srcyoff = (map[curmap].obj[o].h / 2);
  581                                             }
  582                                             if (map[curmap].olink[n].dstobj == map[curmap].selecteditem) {
  583                                                 map[curmap].olink[n].dstxoff = (map[curmap].obj[o].w / 2);
  584                                                 map[curmap].olink[n].dstyoff = (map[curmap].obj[o].h / 2);
  585                                             }
  586                                         }
  587                                         changestate(S_NONE);
  588                                         sprintf(statustext, "Object #%d resized to match object #%d.",map[curmap].selecteditem,o);
  589                                         drawmap(TRUE);
  590                                     }
  591                                 } else if (matchtype == T_TEXT) {
  592                                     o = textat(event.button.x, event.button.y);
  593                                     if (o == -1) {
  594                                         changestate(S_NONE);
  595                                         sprintf(statustext, "Size match mode aborted.");
  596                                         drawstatusbar();
  597                                     } else {
  598                                         int tw,th;
  599                                         /* resize selected text to match one which was clicked */
  600                                         map[curmap].textob[map[curmap].selecteditem].h = map[curmap].textob[o].h;
  601                                         TTF_SizeText(font[map[curmap].textob[o].h], map[curmap].textob[map[curmap].selecteditem].text, &tw,&th);
  602                                         map[curmap].textob[map[curmap].selecteditem].w = tw;
  603                                         /* adjust offsets on all links to/from object */
  604                                         changestate(S_NONE);
  605                                         sprintf(statustext, "Text #%d resized to match text #%d.",map[curmap].selecteditem,o);
  606                                         drawmap(TRUE);
  607                                     }
  608                                 }
  609                             } else if (state == S_MATCHX) {
  610                                 if (matchtype == T_OBJECT) {
  611                                     o = objat(event.button.x, event.button.y);
  612                                     if (o == -1) {
  613                                         changestate(S_NONE);
  614                                         sprintf(statustext, "X position match mode aborted.");
  615                                         drawstatusbar();
  616                                     } else {
  617                                         /* move selected item to match one which was clicked */
  618                                         /* match middle of objects! */
  619                                         map[curmap].obj[map[curmap].selecteditem].x = 
  620                                             (map[curmap].obj[o].x + (map[curmap].obj[o].w/2)) 
  621                                             - 
  622                                             (map[curmap].obj[map[curmap].selecteditem].w/2);
  623                                         changestate(S_NONE);
  624                                         sprintf(statustext, "Object #%d X relocated to match object #%d.",map[curmap].selecteditem,o);
  625                                         drawmap(TRUE);
  626                                     }
  627                                 } else if (matchtype == T_TEXT) {
  628                                     o = textat(event.button.x, event.button.y);
  629                                     if (o == -1) {
  630                                         changestate(S_NONE);
  631                                         sprintf(statustext, "X position match mode aborted.");
  632                                         drawstatusbar();
  633                                     } else {
  634                                         /* move selected item to match one which was clicked */
  635                                         /* match middle of text */
  636                                         map[curmap].textob[map[curmap].selecteditem].x = 
  637                                             (map[curmap].textob[o].x + (map[curmap].textob[o].w/2)) 
  638                                             - 
  639                                             (map[curmap].textob[map[curmap].selecteditem].w/2);
  640                                         /* validate */
  641                                         if (map[curmap].textob[map[curmap].selecteditem].x < 1) map[curmap].textob[map[curmap].selecteditem].x = 1;
  642                                         if (map[curmap].textob[map[curmap].selecteditem].x + map[curmap].textob[map[curmap].selecteditem].w > map[curmap].width) map[curmap].textob[map[curmap].selecteditem].x = map[curmap].width - map[curmap].textob[map[curmap].selecteditem].w;
  643 
  644                                         changestate(S_NONE);
  645                                         sprintf(statustext, "Text #%d X relocated to match text #%d.",map[curmap].selecteditem,o);
  646                                         drawmap(TRUE);
  647                                     }
  648                                 }
  649                             } else if (state == S_MATCHY) {
  650                                 if (matchtype == T_OBJECT) {
  651                                     o = objat(event.button.x, event.button.y);
  652                                     if (o == -1) {
  653                                         changestate(S_NONE);
  654                                         sprintf(statustext, "Y position match mode aborted.");
  655                                         drawstatusbar();
  656                                     } else {
  657                                         /* move selected item to match one which was clicked */
  658                                         map[curmap].obj[map[curmap].selecteditem].y = 
  659                                             (map[curmap].obj[o].y + (map[curmap].obj[o].h / 2))
  660                                             - 
  661                                             map[curmap].obj[map[curmap].selecteditem].h/2;
  662                                         changestate(S_NONE);
  663                                         sprintf(statustext, "Object #%d Y relocated to match object #%d.",map[curmap].selecteditem,o);
  664                                         drawmap(TRUE);
  665                                     }
  666                                 } else if (matchtype == T_TEXT) {
  667                                     o = textat(event.button.x, event.button.y);
  668                                     if (o == -1) {
  669                                         changestate(S_NONE);
  670                                         sprintf(statustext, "Y position match mode aborted.");
  671                                         drawstatusbar();
  672                                     } else {
  673                                         int curh, copyh;
  674                                         
  675                                         curh = TTF_FontHeight(font[map[curmap].textob[map[curmap].selecteditem].h]);
  676                                         copyh = TTF_FontHeight(font[map[curmap].textob[o].h]);
  677                                         /* move selected item to match one which was clicked */
  678                                         map[curmap].textob[map[curmap].selecteditem].y = 
  679                                             (map[curmap].textob[o].y + (copyh / 2))
  680                                             - 
  681                                             (curh / 2);
  682 
  683 
  684                                         /* validate */
  685                                         if (map[curmap].textob[map[curmap].selecteditem].y < 1) map[curmap].textob[map[curmap].selecteditem].y = 1;
  686                                         if (map[curmap].textob[map[curmap].selecteditem].y + curh > map[curmap].height) map[curmap].textob[map[curmap].selecteditem].y = map[curmap].height - curh - 1;
  687 
  688                                         /* match middle of text */
  689                                         changestate(S_NONE);
  690                                         sprintf(statustext, "Text #%d Y relocated to match text #%d.",map[curmap].selecteditem,o);
  691                                         drawmap(TRUE);
  692                                     }
  693                                 }
  694                             } else if (state == S_OBJMOVING) {
  695                                 /* has mouse actually moved? */
  696                                 if ((event.button.x == startx) && (event.button.y == starty)) {
  697                                     /* select the object */
  698                                     map[curmap].selecteditem = map[curmap].curobj;
  699                                     map[curmap].selecteditemtype = T_OBJECT;
  700                                     changestate(S_NONE);
  701                                     sprintf(statustext, "Object #%d (%s) selected.\n",map[curmap].selecteditem, objtype[map[curmap].obj[map[curmap].selecteditem].type].name);
  702                                     drawmap(TRUE);
  703                                 } else {
  704                                     // actually move the object 
  705                                     if (!endobjmove(event.button.x, event.button.y)) {
  706                                         sprintf(statustext, "Object #%d moved to (%d,%d).\n",map[curmap].curobj,event.button.x, event.button.y);
  707                                     }
  708                                     changestate(S_NONE);
  709                                     drawmap(TRUE);
  710                 
  711                                 }
  712                             } else if (state == S_LINKMOVING) {
  713                                 /* has mouse actually moved? */
  714                                 if ((event.button.x - screenx == startx) && (event.button.y - screeny == starty)) {
  715                                     /* select the link */
  716                                     map[curmap].selecteditem = map[curmap].curlink;
  717                                     map[curmap].selecteditemtype = T_LINK;
  718                                     changestate(S_NONE);
  719                                     sprintf(statustext,"Link #%d selected.\n",map[curmap].selecteditem);
  720                                     drawmap(TRUE);
  721                                 } else {
  722                                     // actually move the link 
  723                                     endlinkmove(event.button.x, event.button.y);
  724                                     changestate(S_NONE);
  725                                     sprintf(statustext,"Link #%d moved to (%d,%d).\n",map[curmap].curlink,event.button.x, event.button.y);
  726                                     drawmap(TRUE);
  727                                 }
  728                             } else if (state == S_LINKPOINTMOVE) {
  729                                 /* has mouse actually moved? */
  730                                 if ((event.button.x == startx) && (event.button.y == starty)) {
  731                                     /* select the link point */
  732                                     map[curmap].selecteditem = map[curmap].curlink;
  733                                     map[curmap].selecteditemtype = T_LINKPOINT;
  734                                     map[curmap].selectedlinkpoint = map[curmap].curlinkpoint;
  735                                     changestate(S_NONE);
  736                                     sprintf(statustext,"Link #%d point #%d selected.\n",map[curmap].selecteditem,map[curmap].selectedlinkpoint);
  737                                     drawmap(TRUE);
  738                                 } else {
  739                                     // actually move the link 
  740                                     endlinkpointmove(event.button.x, event.button.y);
  741                                     changestate(S_NONE);
  742                                     drawmap(TRUE);
  743                                 }
  744                             } else if (state == S_TEXTMOVING) {
  745                                 /* has mouse actually moved? */
  746                                 if ((event.button.x == startx) && (event.button.y == starty)) {
  747                                     /* select the object */
  748                                     map[curmap].selecteditem = map[curmap].curtext;
  749                                     map[curmap].selecteditemtype = T_TEXT;
  750                                     changestate(S_NONE);
  751                                     sprintf(statustext,"Text item #%d selected.\n",map[curmap].selecteditem);
  752                                     drawmap(TRUE);
  753                                 } else {
  754                                     // actually move the text 
  755                                     if (!endtextmove(event.button.x, event.button.y)) {
  756                                         sprintf(statustext,"Text item #%d moved to (%d,%d).\n",map[curmap].curtext,event.button.x, event.button.y);
  757                                     }
  758                                     changestate(S_NONE);
  759                                     drawmap(TRUE);
  760                 
  761                                 }
  762                             } else if (state == S_LINKSRCMOVE) {
  763                                 // actually move the link src endpoint
  764                                 endlinksrcmove(event.button.x, event.button.y);
  765                                 changestate(S_NONE);
  766                                 drawmap(TRUE);
  767                             } else if (state == S_LINKDSTMOVE) {
  768                                 // actually move the link dst endpoint
  769                                 endlinkdstmove(event.button.x, event.button.y);
  770                                 changestate(S_NONE);
  771                                 drawmap(TRUE);
  772                             } else if (state == S_ADDOBJ) {
  773                                 /* create a new object */
  774                                 createobject(map[curmap].selectedtype, event.button.x, event.button.y);
  775                                 drawmap(TRUE);
  776                                 changestate(S_NONE);
  777                             } else if (state == S_ADDTEXT) {
  778                                 /* start listening for text input */
  779                                 startx = event.button.x;
  780                                 starty = event.button.y;
  781                                 textanchor = objat(event.button.x,event.button.y);
  782                                 if (textanchor != -1) {
  783                                     startx = map[curmap].obj[textanchor].x;
  784                                     starty = map[curmap].obj[textanchor].y + map[curmap].obj[textanchor].h+3;
  785                                 }
  786                                 updateheight = DEFTEXTH;
  787 
  788                                 strcpy(text, "");
  789                                 textpos = text;
  790     
  791                                 bg = NULL;
  792                                 updatetextcursor();
  793     
  794                                 changestate(S_TYPETEXT);
  795                             } else if (state == S_FILLCOL) {
  796                                 getcolor(screen, event.button.x, event.button.y, &objfillcol);
  797                                 objfillcol.unused |= USECOLOUR; /* clear NOCOLOUR flag */
  798                                 if (map[curmap].selecteditem != -1) {
  799                                     if (map[curmap].selecteditemtype == T_OBJECT) {
  800                                         map[curmap].obj[map[curmap].selecteditem].fillcol = objfillcol;
  801                                         map[curmap].obj[map[curmap].selecteditem].fillcol.unused |= USECOLOUR;
  802                                         sprintf(statustext, "Fill colour of object #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, objfillcol.r,objfillcol.g,objfillcol.b);
  803                                     } else {
  804                                         sprintf(statustext, "Fill colour selected: R=%d,G=%d,B=%d",objfillcol.r,objfillcol.g,objfillcol.b);
  805                                     }
  806                                 } else {
  807                                     sprintf(statustext, "Fill colour selected: R=%d,G=%d,B=%d",objfillcol.r,objfillcol.g,objfillcol.b);
  808                                 }
  809                                 changestate(S_NONE);
  810                                 drawmap(TRUE);
  811                             } else if (state == S_FGCOL) {
  812                                 getcolor(screen, event.button.x, event.button.y, &fgcol);
  813                                 if (map[curmap].selecteditem != -1) {
  814                                     int flow = isflow(map[curmap].selecteditem, map[curmap].selecteditemtype);
  815                                     if (map[curmap].selecteditemtype == T_LINK) {
  816                                         map[curmap].olink[map[curmap].selecteditem].col = fgcol;
  817                                         if (flow) {
  818                                             map[curmap].olink[map[curmap].selecteditem].col.unused |= ISFLOW;
  819                                         }
  820                                         sprintf(statustext, "Colour of link #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, fgcol.r,fgcol.g,fgcol.b);
  821                                     } else if (map[curmap].selecteditemtype == T_TEXT) {
  822                                         map[curmap].textob[map[curmap].selecteditem].c = fgcol;
  823                                         if (flow) {
  824                                             map[curmap].textob[map[curmap].selecteditem].c.unused |= ISFLOW;
  825                                         }
  826                                         sprintf(statustext, "Colour of text item #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, fgcol.r,fgcol.g,fgcol.b);
  827                                     } else {
  828                                         sprintf(statustext, "Foreground colour selected: R=%d,G=%d,B=%d",fgcol.r,fgcol.g,fgcol.b);
  829                                     }
  830                                 } else {
  831                                     sprintf(statustext, "Foreground colour selected: R=%d,G=%d,B=%d",fgcol.r,fgcol.g,fgcol.b);
  832                                 }
  833                                 changestate(S_NONE);
  834                                 drawmap(TRUE);
  835                             } else if (state == S_CREATETELE) {
  836                                 int pos;
  837 
  838                                 if (event.button.y >= 50) {
  839                                     pos = (event.button.y - 50) / (DEFTEXTH*2);
  840                                     pos--;
  841                                     if (pos == -1) {
  842                                         map[curmap].obj[map[curmap].selecteditem].child = pos;
  843                                         sprintf(statustext, "Map link removed.");
  844                                         strcpy(oldstatustext, statustext);
  845                                         setmod(TRUE);
  846                                         changestate(S_NONE);
  847                                         drawmap(TRUE);
  848                                     } else if ((pos+maplistpos) <= (nummaps-1)) {
  849                                         if ((map[curmap].selecteditem != -1) && (map[curmap].selecteditemtype == T_OBJECT)) {
  850                                             if ((pos+maplistpos) != curmap) {
  851                                                 map[curmap].obj[map[curmap].selecteditem].child = pos + maplistpos;
  852                                                 sprintf(statustext, "Map link created.");
  853                                                 strcpy(oldstatustext, statustext);
  854                                                 setmod(TRUE);
  855                                                 changestate(S_NONE);
  856                                                 drawmap(TRUE);
  857                                             } else {
  858                                                 seterror(255);
  859                                                 sprintf(statustext, "ERROR: Cannot link to current map!");
  860                                                 drawstatusbar();
  861                                             }
  862                                         }
  863                                     } else { /* mouse is not over a map name */
  864                                         sprintf(statustext, "Map link creation cancelled.");
  865                                         changestate(S_NONE);
  866                                         drawmap(TRUE);
  867                                     }
  868                                 } else {
  869                                     sprintf(statustext, "Map link creation cancelled.");
  870                                     changestate(S_NONE);
  871                                     drawmap(TRUE);
  872                                 }
  873                             }
  874 
  875                         } else if (isonobox(event.button.x, event.button.y)) {
  876                             int tempx,tempy;
  877 
  878                             tempx = (event.button.x - obox.x) / (obox.gridsize+3);
  879                             tempy = (event.button.y - obox.y) / (obox.gridsize+3);
  880                             if (state == S_CHANGEOBJECT) {
  881                                 int seltype;
  882                                 seltype = tempy*obox.gridrowlen + tempx + (obox.pos*3);
  883                                 if (seltype >= numobjtypes) seltype = numobjtypes-1;
  884                                 if (map[curmap].selecteditemtype != T_OBJECT) {
  885                                     seterror(255);
  886                                     sprintf(statustext, "ERROR: Must select an object to change the type of!");
  887                                     drawstatusbar();
  888                                 } else if (map[curmap].selecteditem == -1) {
  889                                     seterror(255);
  890                                     sprintf(statustext, "ERROR: Must select an object to change the type of!");
  891                                     drawstatusbar();
  892                                 } else {
  893                                     sprintf(statustext, "Object #%d type changed from '%s' to '%s'.", map[curmap].selecteditem, objtype[map[curmap].obj[map[curmap].selecteditem].type].name, objtype[seltype].name);
  894                                     map[curmap].obj[map[curmap].selecteditem].type = seltype;
  895                                     state = S_NONE;
  896                                     drawtoolbox();
  897                                     drawmap(TRUE);
  898                                 }
  899                             } else {
  900                                 map[curmap].selectedtype = tempy*obox.gridrowlen + tempx + (obox.pos*3);
  901                                 if (map[curmap].selectedtype >= numobjtypes) map[curmap].selectedtype = numobjtypes-1;
  902                                 sprintf(statustext,"Object type '%s' selected.\n",objtype[map[curmap].selectedtype].name);
  903                             }
  904                             drawstatusbar();
  905 
  906                             drawobox();
  907                             SDL_UpdateRect(screen, obox.x, obox.y, obox.width,obox.height);
  908                         } else if (isongoback(event.button.x, event.button.y)) {
  909                             /* go back */
  910                             goback();
  911                         } else if (isonmapname(event.button.x, event.button.y)) {
  912                             /* rename current map */
  913                             startx = 1;
  914                             starty = ((screen->h - STATUSH)/2)-2;
  915                             bg = NULL;
  916                             strcpy(text, map[curmap].name);
  917                             textpos = &text[strlen(text)];
  918                             changestate(S_MAPNAMING);
  919                             drawmap(TRUE);
  920                             break;
  921                         } else if (isonmapboxchildren(event.button.x, event.button.y)) {
  922                             if ((state != S_XSCROLL) && (state != S_YSCROLL)) {
  923                                 int pos;
  924                                 int th;
  925 
  926                                 /* calculate pixel size of mapbox text */
  927                                 th = TTF_FontHeight(font[MAPBOXTEXTHEIGHT]);
  928                                 /* change to child */
  929                                 pos = (event.button.y - (mapbox.y+(th*2)+1)) / th;
  930                                 /* adjust for offset if not a special value */
  931                                 pos += mapbox.offset;
  932                                 if (pos >= numchildren) {
  933                                     seterror(255);
  934                                     sprintf(statustext, "ERROR: Invalid child map %d (max is %d).",pos,numchildren);
  935                                     drawstatusbar();
  936                                 } else {
  937                                     drillto(children[pos]);
  938                                 }
  939                             }
  940                             break;
  941                         } else if (isontoolbox(event.button.x, event.button.y)) {
  942                             int tempx,tempy, selection;
  943                             int boxy;
  944 
  945                             tempx = (event.button.x - toolbox.x) / (toolbox.gridsize+3);
  946                             tempy = (event.button.y - toolbox.y) / (toolbox.gridsize+3);
  947 
  948                             boxy = toolbox.y + (tempy*(toolbox.gridsize+3));
  949 
  950                             /* are we in a colour selection state? */
  951                             if (state == S_FGCOL) {
  952                                 /* set fgcol to black */
  953                                 fgcol = black;
  954                                 sprintf(statustext, "Foreground colour selected: R=0,G=0,B=0");
  955                                 changestate(S_NONE);
  956                                 drawmap(TRUE);
  957                                 break;
  958                             } else if (state == S_FILLCOL) {
  959                                 /* set bgcol to 'nothing' */
  960                                 objfillcol = black;
  961                                 objfillcol.unused &= ~(USECOLOUR);
  962                                 if (map[curmap].selecteditem != -1) {
  963                                     if (map[curmap].selecteditemtype == T_OBJECT) {
  964                                         map[curmap].obj[map[curmap].selecteditem].fillcol = black;
  965                                         map[curmap].obj[map[curmap].selecteditem].fillcol.unused &= ~(USECOLOUR);
  966                                         sprintf(statustext, "Fill colour of object #%d removed.", map[curmap].selecteditem);
  967                                     } else {
  968                                         sprintf(statustext, "Fill colour removed.");
  969                                     }
  970                                 } else {
  971                                     sprintf(statustext, "Fill colour removed.");
  972                                 }
  973                                 changestate(S_NONE);
  974                                 drawmap(TRUE);
  975                                 break;
  976                             }
  977   
  978                             selection = tempy*toolbox.gridrowlen + tempx;
  979                             switch (selection) {
  980                                 case TB_POINTER:
  981                                     /* special case - update sbar */
  982                                     sprintf(statustext, "Selection mode entered.");
  983                                     drawstatusbar();
  984                                     changestate(S_NONE);
  985                                     map[curmap].curobj = -1;
  986                                      break;
  987                                 case TB_ADDOBJ:
  988                                     changestate(S_ADDOBJ);
  989                                     if (map[curmap].selectedtype < 0) map[curmap].selectedtype = 0;
  990                                     break;
  991                                 case TB_ADDTEXT:
  992                                     changestate(S_ADDTEXT);
  993                                     break;
  994                                 case TB_COPY:
  995                                     copy();
  996                                     break;
  997                                 case TB_FLOW:
  998                                     if (showflows) {
  999                                         setinfo(255);
 1000                                         showflows = FALSE;
 1001                                         sprintf(statustext, "Traffic flows hidden.");
 1002                                     } else {
 1003                                         setinfo(255);
 1004                                         sprintf(statustext, "Traffic flows displayed.");
 1005                                         showflows = TRUE;
 1006                                     } 
 1007                                     drawtoolbox();
 1008                                     drawmap(TRUE);
 1009                                     break;
 1010                                 case TB_GRID:
 1011                                     togglegrid();
 1012                                     drawmap(TRUE);
 1013                                     break;
 1014                                 case TB_NEW:
 1015                                     if (readonly) {
 1016                                         seterror(255);
 1017                                         sprintf(statustext, "Cannot delete maps in read-only mode.");
 1018                                         drawstatusbar();
 1019                                         break;
 1020     
 1021                                     }
 1022                                     tmod = SDL_GetModState();
 1023                                     if (!(mod & KMOD_SHIFT)) {
 1024                                         seterror(255);
 1025                                         sprintf(statustext, "Must hold down SHIFT to start new project (avoids accidental loss of data)!");
 1026                                         drawstatusbar();
 1027                                         break;
 1028                                     }
 1029                                     initvars();
 1030                                     changestate(S_NONE);
 1031                                     setinfo(255);
 1032                                     sprintf(statustext, "All maps cleared.");
 1033                                     sprintf(oldstatustext, statustext);
 1034                                     
 1035                                     drawmap(TRUE);
 1036                                     break;
 1037                                 case TB_LINESTYLE:
 1038                                     if (map[curmap].selecteditemtype == T_LINK) {
 1039                                         if (map[curmap].selecteditem != -1) {
 1040                                             int si = map[curmap].selecteditem;
 1041                                             /* TODO: add arrow */
 1042                                             /* where are we? */
 1043                                             if (event.button.y <= (boxy + 9)) {
 1044                                                 /* clear thickness */
 1045                                                 map[curmap].olink[si].style &= 0xFFFF00;
 1046                                                 /* set to default */
 1047                                                 map[curmap].olink[si].style |= defthickness;
 1048                                             } else if (event.button.y <= (boxy + 19)) {
 1049                                                 /* clear style */
 1050                                                 map[curmap].olink[si].style &= 0xFF00FF;
 1051                                                 /* set to default */
 1052                                                 map[curmap].olink[si].style |= (defstyle << 8);
 1053                                             } else {
 1054                                                 /* clear arrow */
 1055                                                 map[curmap].olink[si].style &= 0x00FFFF;
 1056                                                 /* set to default */
 1057                                                 map[curmap].olink[si].style |= (defarrow << 16);
 1058                                             }
 1059                                             setmod(TRUE);
 1060                                             drawmap(TRUE);
 1061                                         } else {
 1062                                             seterror(255);
 1063                                             sprintf(statustext, "No link selected!");
 1064                                         } 
 1065                                     } else {
 1066                                         seterror(255);
 1067                                         sprintf(statustext, "No link selected!");
 1068                                     }
 1069                                     drawstatusbar();
 1070                                     break;
 1071                                 case TB_MATCHSIZE:
 1072                                     if (map[curmap].selecteditem != -1) {
 1073                                         switch (map[curmap].selecteditemtype) {
 1074                                             case T_OBJECT:
 1075                                             case T_TEXT:
 1076                                                 matchtype = map[curmap].selecteditemtype;
 1077                                                 changestate(S_MATCHSIZE);
 1078                                                 drawmap(TRUE);
 1079                                                 break;
 1080                                         }
 1081                                     }
 1082                                     break;
 1083                                 case TB_MATCHPOS:
 1084                                     if (map[curmap].selecteditem != -1) {
 1085                                         switch (map[curmap].selecteditemtype) {
 1086                                             case T_OBJECT:
 1087                                             case T_TEXT:
 1088                                                 matchtype = map[curmap].selecteditemtype;
 1089                                                 changestate(S_MATCHX);
 1090                                                 drawmap(TRUE);
 1091                                                 break;
 1092                                         }
 1093                                     }
 1094                                     break;
 1095                                 case TB_PASTE:
 1096                                     paste();
 1097                                     break;
 1098                                 case TB_FGCOL:
 1099                                     /* change selected item to match fgcol */
 1100                                     if (map[curmap].selecteditem != -1) {
 1101                                         int flow = isflow(map[curmap].selecteditem, map[curmap].selecteditemtype);
 1102                                         if (map[curmap].selecteditemtype == T_LINK) {
 1103                                             map[curmap].olink[map[curmap].selecteditem].col = fgcol;
 1104                                             /* maintain flow attribute */
 1105                                             if (flow) {
 1106                                                 map[curmap].olink[map[curmap].selecteditem].col.unused |= ISFLOW;
 1107                                             }
 1108                                             setmod(TRUE);
 1109                                             sprintf(statustext, "Colour of link #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, fgcol.r,fgcol.g,fgcol.b);
 1110                                         } else if (map[curmap].selecteditemtype == T_TEXT) {
 1111                                             map[curmap].textob[map[curmap].selecteditem].c = fgcol;
 1112                                             /* maintain flow attribute */
 1113                                             if (flow) {
 1114                                                 map[curmap].textob[map[curmap].selecteditem].c.unused |= ISFLOW;
 1115                                             }
 1116                                             setmod(TRUE);
 1117                                             sprintf(statustext, "Colour of text item #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, fgcol.r,fgcol.g,fgcol.b);
 1118                                         } else {
 1119                                             seterror(255);
 1120                                             sprintf(statustext, "No object selected! (use RMB to select new foreground colour)");
 1121                                         }
 1122                                     } else {
 1123                                         seterror(255);
 1124                                         sprintf(statustext, "No object selected! (use RMB to select new foreground colour)");
 1125                                     }
 1126                                     drawmap(TRUE);
 1127                                     break;
 1128                                 case TB_FILLCOL:
 1129                                     if (map[curmap].selecteditem != -1) {
 1130                                         if (map[curmap].selecteditemtype == T_OBJECT) {
 1131                                             map[curmap].obj[map[curmap].selecteditem].fillcol = objfillcol;
 1132                                             map[curmap].obj[map[curmap].selecteditem].fillcol.unused = objfillcol.unused;
 1133                                             setmod(TRUE);
 1134                                             if (objfillcol.unused & USECOLOUR) {
 1135                                                 sprintf(statustext, "Fill colour of object #%d changed to R=%d,G=%d,B=%d",map[curmap].selecteditem, objfillcol.r,objfillcol.g,objfillcol.b);
 1136                                             } else {
 1137                                                 sprintf(statustext, "Fill colour of object #%d removed.",map[curmap].selecteditem);
 1138                                             }
 1139                                         } else {
 1140                                             seterror(255);
 1141                                             sprintf(statustext, "No object selected! (use RMB to select new fill colour)");
 1142                                         }
 1143                                     } else {
 1144                                         seterror(255);
 1145                                         sprintf(statustext, "No object selected! (use RMB to select new fill colour)");
 1146                                     }
 1147                                     drawmap(TRUE);
 1148                                     break;
 1149                                 case TB_DELETEMAP:
 1150                                     /* safety - must hold down SHIFT to delete maps */
 1151 
 1152                                     if (readonly) {
 1153                                         seterror(255);
 1154                                         sprintf(statustext, "Cannot delete maps in read-only mode.");
 1155                                         drawstatusbar();
 1156                                         break;
 1157     
 1158                                     }
 1159                                     tmod = SDL_GetModState();
 1160                                     if (!(mod & KMOD_SHIFT)) {
 1161                                         seterror(255);
 1162                                         sprintf(statustext, "Must hold down SHIFT to delete maps (avoids accidental loss of data)!");
 1163                                         drawstatusbar();
 1164                                         break;
 1165                                     }
 1166                                     if (curmap == 0) {
 1167                                         seterror(255);
 1168                                         sprintf(statustext, "Cannot delete toplevel map!");
 1169                                         drawstatusbar();
 1170                                         break;
 1171                                     }
 1172                                     delmap = curmap;
 1173                                     /* any children in curent map? */
 1174                                     found = FALSE;
 1175                                     for (n = 0; n < map[delmap].numobjects; n++) {
 1176                                         if (map[delmap].obj[n].child != -1) {
 1177                                             found = TRUE;
 1178                                             break;
 1179                                         }
 1180                                     }
 1181                                     if (found) {
 1182                                         seterror(255);
 1183                                         sprintf(statustext, "Cannot delete a map with children.");
 1184                                         drawstatusbar();
 1185                                         break;
 1186                                     }
 1187                                     /* shuffle numbers on all other objects */
 1188                                     for (n = 0; n < nummaps; n++) {
 1189                                         int o;
 1190                                         for (o = 0; o < map[n].numobjects; o++) {
 1191                                             if (map[n].obj[o].child == delmap) {
 1192                                                 map[n].obj[o].child = -1;
 1193                                             } else if (map[n].obj[o].child > delmap) {
 1194                                                 map[n].obj[o].child--;
 1195                                             }
 1196                                         }
 1197                                     }
 1198                                     /* move all higher maps down by one */
 1199                                     for (n = delmap; n < (nummaps-1); n++) {
 1200                                         map[n] = map[n+1];
 1201                                     }
 1202                                     nummaps--;
 1203                                     /* move far enough back to avoid all occurences of this map */
 1204                                     found = FALSE;
 1205                                     for (n = 0; n < (numhistory-1); n++) {
 1206                                         if (history[n+1] == delmap) {
 1207                                             if (history[n] > delmap) {
 1208                                                 changemap(history[n] - 1);
 1209                                             } else {
 1210                                                 changemap(history[n]);
 1211                                             }
 1212                                             numhistory = n+1;
 1213                                             found = TRUE;
 1214                                             break;
 1215                                         }
 1216                                     }
 1217                                     if (!found) {
 1218                                         goback();
 1219                                         setinfo(255);
 1220                                         sprintf(statustext, "Deleted map #%d.\n",delmap);
 1221                                     }
 1222                                     /* fix history array */
 1223                                     for (n = 0; n < numhistory; n++) {
 1224                                         if (history[n] > delmap) {
 1225                                             history[n]--;
 1226                                         }
 1227                                     }
 1228                                     drawmap(TRUE);
 1229                                     break;
 1230                                 case TB_CREATETELE:
 1231                                     if ((map[curmap].selecteditemtype == T_OBJECT) && (map[curmap].selecteditem != -1)) {
 1232                                         setinfo(255);
 1233                                         sprintf(statustext,"Select destination map to link to...");
 1234                                         changestate(S_CREATETELE);
 1235                                         drawmap(TRUE);
 1236                                     } else {
 1237                                         seterror(255);
 1238                                         sprintf(statustext,"Cannot create map link - no object selected!");
 1239                                         drawstatusbar();
 1240                                     }
 1241                                     break;
 1242 
 1243                                 case TB_DRILLDOWN:
 1244                                     if ((map[curmap].selecteditemtype == T_OBJECT) && (map[curmap].selecteditem != -1)) {
 1245                                         drillto(map[curmap].obj[map[curmap].selecteditem].child);
 1246                                     } else {
 1247                                         seterror(255);
 1248                                         sprintf(statustext,"Cannot drill down - no object selected!");
 1249                                         drawstatusbar();
 1250                                     }
 1251                                     break;
 1252                                 case TB_SAVE:
 1253                                     startx = 1;
 1254                                     starty = ((screen->h - STATUSH)/2)-2;
 1255                                     bg = NULL;
 1256                                     strcpy(text, currentfilename);
 1257                                     textpos = &text[strlen(text)];
 1258                                     changestate(S_SAVING);
 1259                                     drawmap(TRUE);
 1260                                     break;
 1261                                 case TB_LOAD:
 1262                                     startx = 1;
 1263                                     starty = ((screen->h - STATUSH)/2)-2;
 1264                                     bg = NULL;
 1265                                     strcpy(text, currentfilename);
 1266                                     textpos = &text[strlen(text)];
 1267                                     changestate(S_LOADING);
 1268                                     drawmap(TRUE);
 1269                                     break;
 1270                                 
 1271                             }
 1272                             drawtoolbox();
 1273                         } /* end if is on map */
 1274                     } else if ((event.button.button == SDL_BUTTON_MIDDLE) ||
 1275                            ((event.button.button == SDL_BUTTON_LEFT) && (mod & KMOD_CTRL))) {
 1276                         if (state == S_DRAWLINK) {
 1277                             // finish drawing link
 1278                             o = objat(event.button.x + screenx, event.button.y + screeny);
 1279                             if ((o != -1) && (o != startobj)) {
 1280                                 endobj = o;
 1281                                 endlink(event.button.x,event.button.y);
 1282                                 changestate(S_NONE);
 1283                                 drawmap(TRUE);
 1284                             } else {
 1285                                 pasteline(screen,linebg);
 1286                                 sprintf(statustext,"Aborting link #%d.\n", map[curmap].numlinks);
 1287                                 drawstatusbar();
 1288                             }
 1289                             changestate(S_NONE);
 1290                         } else if (state == S_NONE) {
 1291                             /* are we on a link? if so, add a point to it */
 1292                             o = getlinkat(event.button.x + screenx, event.button.y + screeny);
 1293                             if (o != -1) {
 1294                                 addlinkpoint(o, event.button.x+screenx, event.button.y+screeny);
 1295                                 /* select the link */
 1296                                 map[curmap].selecteditemtype = T_LINK;
 1297                                 map[curmap].selecteditem = o;
 1298                                 drawmap(TRUE);
 1299                             } 
 1300                         }
 1301 
 1302 
 1303 
 1304                     } else if (event.button.button == SDL_BUTTON_RIGHT) {
 1305                         if (state == S_RESIZING) {
 1306                             // end resize 
 1307                             endresize(event.button.x, event.button.y);
 1308                             changestate(S_NONE);
 1309                             drawmap(TRUE);
 1310                         } else if (state == S_TEXTRESIZING) {
 1311                             // end text resize 
 1312                             endtextresize(event.button.x, event.button.y);
 1313                             changestate(S_NONE);
 1314                         } 
 1315                         /* check for right click on toolbox */ 
 1316                         if (isontoolbox(event.button.x, event.button.y)) {
 1317                             int tempx,tempy, selection,boxy;
 1318 
 1319                             tempx = (event.button.x - toolbox.x) / (toolbox.gridsize+3);
 1320                             tempy = (event.button.y - toolbox.y) / (toolbox.gridsize+3);
 1321                             boxy = toolbox.y + (tempy*(toolbox.gridsize+3));
 1322                             selection = tempy*toolbox.gridrowlen + tempx;
 1323                             switch (selection) {
 1324                                 case TB_ADDOBJ:
 1325                                     if (map[curmap].selecteditemtype != T_OBJECT) {
 1326                                         seterror(255);
 1327                                         sprintf(statustext, "Must select an object to change the type of first!");
 1328                                         drawstatusbar();
 1329                                     } else if (map[curmap].selecteditem == -1) {
 1330                                         seterror(255);
 1331                                         sprintf(statustext, "Must select an object to change the type of first!");
 1332                                         drawstatusbar();
 1333                                     } else {
 1334                                         changestate(S_CHANGEOBJECT);
 1335                                     }
 1336                                     break;
 1337                                 case TB_ADDTEXT:
 1338                                     if (state == S_NONE) {
 1339                                         if (    (map[curmap].selecteditemtype == T_TEXT) &&
 1340                                             (map[curmap].selecteditem != -1) ){
 1341                                             startedittext(map[curmap].selecteditem);
 1342                                         } else {
 1343                                             seterror(255);
 1344                                             sprintf(statustext, "Cannot edit text - no text item selected!");
 1345                                             drawstatusbar();
 1346                                         }
 1347                                     }
 1348                                     break;
 1349                                 case TB_GRID:
 1350                                     changegridsize();
 1351                                     drawmap(TRUE);
 1352                                     break;
 1353                                 case TB_FLOW:
 1354                                     oldshowflows = showflows;
 1355                                     showflows = TRUE;
 1356                                     drawtoolbox();
 1357                                     changestate(S_DRAWFLOW);
 1358                                     drawmap(TRUE);
 1359                                     break;
 1360                                 case TB_FGCOL:
 1361                                     changestate(S_FGCOL);
 1362                                     drawmap(TRUE);
 1363                                     break;
 1364                                 case TB_FILLCOL:
 1365                                     changestate(S_FILLCOL);
 1366                                     drawmap(TRUE);
 1367                                     break;
 1368                                 case TB_MATCHPOS: /* match y */
 1369                                     if (map[curmap].selecteditem != -1) {
 1370                                         switch (map[curmap].selecteditemtype) {
 1371                                             case T_OBJECT:
 1372                                             case T_TEXT:
 1373                                                 matchtype = map[curmap].selecteditemtype;
 1374                                                 changestate(S_MATCHY);
 1375                                                 drawmap(TRUE);
 1376                                                 break;
 1377                                         }
 1378                                     }
 1379                                     break;
 1380                                 case TB_LINESTYLE:
 1381                                     /* figure out where in the box we are */
 1382                                     if (event.button.y <= (boxy + 9)) {
 1383                                         changelinethickness(1);
 1384                                     } else if (event.button.y <= (boxy + 19)) {
 1385                                         changelinestyle(1);
 1386                                     } else {
 1387                                         changelinearrow(1);
 1388                                     }
 1389                                     drawstatusbar();
 1390                                     break;
 1391                             }
 1392                         }
 1393                     }
 1394                     break;
 1395                 case SDL_MOUSEMOTION:
 1396                     switch (state) {
 1397                         case S_OBJMOVING:
 1398                             updatemoveshadow(event.button.x, event.button.y);
 1399                             break;
 1400                         case S_RESIZING:
 1401                             updateresizeshadow(event.button.x, event.button.y);
 1402                             break;
 1403                         case S_DRAWLINK:
 1404                             updatelinkshadow(event.button.x, event.button.y);
 1405                             break;
 1406                         case S_TEXTMOVING:
 1407                             updatetextshadow(event.button.x, event.button.y);
 1408                             break;
 1409                         case S_TEXTRESIZING:
 1410                             updateresizetextshadow(event.button.x, event.button.y);
 1411                             break;
 1412                         case S_LINKPOINTMOVE:
 1413                             updatelinkpointshadow(event.button.x, event.button.y);
 1414                             break;
 1415                         case S_NONE:
 1416                             /* has mouse moved since last time? */
 1417                             mousepos = getmousepos(event.button.x, event.button.y);
 1418                             if ((mousepos != oldmousepos ) || (mousepos== MP_TOOLBOX)) {
 1419                                 /* rollovers */
 1420                                 if (mousepos == MP_TOOLBOX) {
 1421                                     SDL_Rect area;
 1422                                     int tempx,tempy, selection;
 1423                                     int boxy;
 1424 
 1425                                     if (!rollover) strcpy(oldstatustext, statustext);
 1426                                     rollover = TRUE;
 1427 
 1428                                     /* determine which button we're over */
 1429                                     tempx = (event.button.x - toolbox.x) / (toolbox.gridsize+3);
 1430                                     tempy = (event.button.y - toolbox.y) / (toolbox.gridsize+3);
 1431 
 1432                                     boxy = toolbox.y + (tempy*(toolbox.gridsize+3));
 1433                                     
 1434                                     selection = tempy*toolbox.gridrowlen + tempx;
 1435                                     /* replace old button */
 1436                                     if (toolbg != NULL) {
 1437                                         SDL_Rect area;
 1438 
 1439 
 1440                                         if (oldselection >= 0) {
 1441                                             if (dontpaste == FALSE) {
 1442                                                 area.x = toolbox.x + ((oldselection % 3 )*(toolbox.gridsize+3));
 1443                                                 area.y = toolbox.y + ((oldselection / 3)*(toolbox.gridsize+3));
 1444                                                 area.w = toolbox.gridsize;
 1445                                                 area.h = toolbox.gridsize;
 1446                                                 SDL_BlitSurface(toolbg, NULL, screen, &area);
 1447                                                 SDL_UpdateRect(screen, area.x, area.y, area.w, area.h);
 1448                                             } else {
 1449                                                 dontpaste = FALSE;
 1450                                             }
 1451                                         }
 1452                                         SDL_FreeSurface(toolbg);
 1453                                         toolbg = NULL;
 1454                                     }
 1455                                     /* copy background of this button */
 1456                                     if (selection <= TB_SAVE) {
 1457                                         toolbg = SDL_CreateRGBSurface(SDL_SWSURFACE,toolbox.gridsize+3, toolbox.gridsize+3,
 1458                                             screen->format->BitsPerPixel, screen->format->Rmask,
 1459                                             screen->format->Gmask,screen->format->Bmask,
 1460                                             screen->format->Amask);
 1461                                         area.x = toolbox.x + ((selection % 3 )*(toolbox.gridsize+3));
 1462                                         area.y = toolbox.y + ((selection / 3)*(toolbox.gridsize+3));
 1463                                         area.w = toolbox.gridsize+1;
 1464                                         area.h = toolbox.gridsize+1;
 1465                                         SDL_BlitSurface(screen,&area, toolbg, 0);
 1466 
 1467                                         /* draw highlight */
 1468                                         if (selection == TB_LINESTYLE) {
 1469                                             SDL_Rect sarea;
 1470 
 1471                                             if (event.button.y <= (boxy + 9)) {
 1472                                                 sarea.x = 0;
 1473                                                 sarea.y = 0;
 1474                                                 sarea.w = toolbox.gridsize;
 1475                                                 sarea.h = 11;
 1476                                                 area.h = 11;
 1477                                                 area.y += 1;
 1478                                             } else if (event.button.y <= (boxy + 19)) {
 1479                                                 sarea.x = 0;
 1480                                                 sarea.y = 0;
 1481                                                 sarea.w = toolbox.gridsize;
 1482                                                 sarea.h = 10;
 1483                                                 area.h = 10;
 1484                                                 area.y += 12;
 1485                                             } else {
 1486                                                 sarea.x = 0;
 1487                                                 sarea.y = 0;
 1488                                                 sarea.w = toolbox.gridsize;
 1489                                                 sarea.h = 8;
 1490                                                 area.h = 8;
 1491                                                 area.y += 21;
 1492                                             }
 1493                                             SDL_BlitSurface(toolhilite, &sarea, screen, &area);
 1494                                         }  else {
 1495                                             SDL_BlitSurface(toolhilite, NULL, screen, &area);
 1496                                         }
 1497 
 1498                                         SDL_UpdateRect(screen, area.x, area.y, area.w, area.h);
 1499                                     }
 1500 
 1501                                     if (selection != oldselection) {
 1502                                         switch (selection) {
 1503                                             case TB_POINTER:
 1504                                                 sprintf(statustext, "LMB = Enter object selection mode");
 1505                                                 drawstatusbar();
 1506                                                 break;
 1507                                             case TB_ADDOBJ:
 1508                                                 sprintf(statustext, "LMB = Add an object to the map, RMB = Change object type");
 1509                                                 drawstatusbar();
 1510                                                 break;
 1511                                             case TB_ADDTEXT:
 1512                                                 sprintf(statustext, "LMB (on map) = Add text to the map, LMB (on object) = Add text to an object");
 1513                                                 drawstatusbar();
 1514                                                 break;
 1515                                             case TB_COPY:
 1516                                                 sprintf(statustext, "LMB = Copy the current object/text/map");
 1517                                                 drawstatusbar();
 1518                                                 break;
 1519                                             case TB_PASTE:
 1520                                                 sprintf(statustext, "LMB = Paste the current copy buffer");
 1521                                                 drawstatusbar();
 1522                                                 break;
 1523                                             case TB_GRID:
 1524                                                 sprintf(statustext, "LMB = Toggle grid on/off, RMB = Change grid size");
 1525                                                 drawstatusbar();
 1526                                                 break;
 1527                                             case TB_FGCOL:
 1528                                                 sprintf(statustext, "LMB = Apply default foreground colour to current selection, RMB = Change default foreground colour");
 1529                                                 drawstatusbar();
 1530                                                 break;
 1531                                             case TB_FILLCOL:
 1532                                                 sprintf(statustext, "LMB = Apply default fill colour to current selection, RMB = Change default fill colour");
 1533                                                 drawstatusbar();
 1534                                                 break;
 1535                                             case TB_LINESTYLE:
 1536                                                 if (event.button.y <= (boxy + 9)) {
 1537                                                     sprintf(statustext, "LMB = Apply default thickness to current line, RMB = Change default line thickness");
 1538                                                 } else if (event.button.y <= (boxy + 19)) {
 1539                                                     sprintf(statustext, "LMB = Apply default style to current line, RMB = Change default line style");
 1540                                                 } else {
 1541                                                     sprintf(statustext, "LMB = Apply default arrowhead type to current line, RMB = Change default arrowhead type");
 1542                                                 }
 1543                                                 drawstatusbar();
 1544                                                 break;
 1545                                             case TB_MATCHSIZE:
 1546                                                 sprintf(statustext, "LMB = Match size of current selection to next item clicked");
 1547                                                 drawstatusbar();
 1548                                                 break;
 1549                                             case TB_MATCHPOS:
 1550                                                 sprintf(statustext, "LMB = Match horizontal position of currently selected item to next item clicked, RMB = match vertical position");
 1551                                                 drawstatusbar();
 1552                                                 break;
 1553                                             case TB_FLOW:
 1554                                                 sprintf(statustext, "LMB = Toggle display of traffic flows, RMB = Enter traffic flow definition mode");
 1555                                                 drawstatusbar();
 1556                                                 break;
 1557                                             case TB_DRILLDOWN:
 1558                                                 sprintf(statustext, "LMB = Drill down to create new map under current object");
 1559                                                 drawstatusbar();
 1560                                                 break;
 1561                                             case TB_CREATETELE:
 1562                                                 sprintf(statustext, "LMB = Set destination map for when current object is double-clicked");
 1563                                                 drawstatusbar();
 1564                                                 break;
 1565                                             case TB_DELETEMAP:
 1566                                                 sprintf(statustext, "LMB = Delete current map (hold down SHIFT to confirm)");
 1567                                                 drawstatusbar();
 1568                                                 break;
 1569                                             case TB_NEW:
 1570                                                 sprintf(statustext, "LMB = Delete ALL maps and start a fresh project (hold SHIFT to confirm)");
 1571                                                 drawstatusbar();
 1572                                                 break;
 1573                                             case TB_LOAD:
 1574                                                 sprintf(statustext, "LMB = Load a new map");
 1575                                                 drawstatusbar();
 1576                                                 break;
 1577                                             case TB_SAVE:
 1578                                                 sprintf(statustext, "LMB = Save the current map to disk (will automatically export based on extensions of BMP/PNG/SVG)");
 1579                                                 drawstatusbar();
 1580                                                 break;
 1581                                             default:
 1582                                                 break;
 1583                                         }
 1584                                     }
 1585                                     oldselection = selection;
 1586                                 } else if (mousepos == MP_MAPBOXNAME) {
 1587                                     if (!rollover) strcpy(oldstatustext, statustext);
 1588                                     rollover = TRUE;
 1589                                     sprintf(statustext, "LMB = Rename the current map.");
 1590                                     drawstatusbar();
 1591                                 } else if (mousepos == MP_MAPBOXCHILDREN) {
 1592                                     if (!rollover) strcpy(oldstatustext, statustext);
 1593                                     rollover = TRUE;
 1594                                     sprintf(statustext, "LMB = Drill down into a submap (blue text indicates maps already in the map history).");
 1595                                     drawstatusbar();
 1596                                 } else if (mousepos == MP_OBJECTBOX) {
 1597                                     if (!rollover) strcpy(oldstatustext, statustext);
 1598                                     rollover = TRUE;
 1599                                     sprintf(statustext, "LMB = Select a new object type.");
 1600                                     drawstatusbar();
 1601                                 } else {
 1602                                     strcpy(statustext, oldstatustext);
 1603                                     strcpy(oldstatustext, "");
 1604                                     drawstatusbar();
 1605                                     rollover = FALSE;
 1606                                 }
 1607                             }
 1608                             oldmousepos = mousepos;
 1609                             break;
 1610                                 
 1611                     }
 1612                     /* scrollbar drags */
 1613                     mb = SDL_GetMouseState(&mx,&my);
 1614                     //if (isonxscrollbar(mx,my)) {
 1615                     if (state == S_XSCROLL) {
 1616                         if (mb & SDL_BUTTON(1)) { /* if lmb is depressed */ 
 1617                             screenx = (((double)event.button.x / (double)(screen->w - SIDEBARW)) * map[curmap].width)
 1618                                   - ((screen->w - SIDEBARW)/2);
 1619 
 1620                             validatescreenpos();
 1621                             drawxscrollbar();
 1622                         }
 1623                     }
 1624                     //if (isonyscrollbar(mx,my)) {
 1625                     if (state == S_YSCROLL) {
 1626                         if (mb & SDL_BUTTON(1)) { /* if lmb is depressed */ 
 1627                             screeny = (((double)event.button.y / (double)(screen->h - STATUSH - SBSIZE)) * map[curmap].height)
 1628                                   - ((screen->h - STATUSH - SBSIZE)/2);
 1629 
 1630                             validatescreenpos();
 1631                             drawyscrollbar();
 1632                         }
 1633                     }
 1634                     break;
 1635                 case SDL_QUIT:
 1636                     if (modified) {
 1637                         strcpy(text, "Changes not saved - really quit?");
 1638                             changestate(S_REALLYQUIT);
 1639                         drawmap(TRUE);
 1640                     } else {
 1641                         done = TRUE;
 1642                     }
 1643                     break;
 1644                 case SDL_VIDEOEXPOSE:
 1645                     /* redraw screen */
 1646                     drawscreen();
 1647                     break;
 1648                 case SDL_KEYDOWN:
 1649                     c = event.key.keysym.unicode & 0x7F;
 1650                     c2 = event.key.keysym.sym;
 1651                     mod = SDL_GetModState();
 1652                     /* state independant */
 1653                     if (mod & KMOD_SHIFT) {
 1654                         if ((c >= 'a') && (c <= 'z')) {
 1655                             c -= 32;
 1656                         } else if (c == '1') {
 1657                             c = '!';
 1658                         } else if (c == '2') {
 1659                             c = '@';
 1660                         } else if (c == '3') {
 1661                             c = '#';
 1662                         } else if (c == '4') {
 1663                             c = '$';
 1664                         } else if (c == '5') {
 1665                             c = '%';
 1666                         } else if (c == '6') {
 1667                             c = '^';
 1668                         } else if (c == '7') {
 1669                             c = '&';
 1670                         } else if (c == '8') {
 1671                             c = '*';
 1672                         } else if (c == '9') {
 1673                             c = '(';
 1674                         } else if (c == '0') {
 1675                             c = ')';
 1676                         } else if (c == '-') {
 1677                             c = '_';
 1678                         } else if (c == '=') {
 1679                             c = '+';
 1680                         } else if (c == '\\') {
 1681                             c = '|';
 1682                         } else if (c == ';') {
 1683                             c = ':';
 1684                         } else if (c == '\'') {
 1685                             c = '"';
 1686                         } else if (c == ',') {
 1687                             c = '<';
 1688                         } else if (c == '.') {
 1689                             c = '>';
 1690                         } else if (c == '/') {
 1691                             c = '?';
 1692                         }
 1693                     }
 1694                     /* state dependant */
 1695                     if ((state == S_TYPETEXT) || (state == S_SAVING) || (state == S_LOADING) || (state == S_MAPNAMING) || (state == S_EDITTEXT) || (state == S_SEARCH)) {
 1696                         if ((c2 == 'u') && (mod & KMOD_CTRL)) {
 1697                             // delete from start to text pos
 1698                             strcpy(text, textpos);
 1699                             //text[0] = '\0';
 1700                             textpos = text;
 1701                             updatetextcursor();
 1702                         } else if ((c2 == 'k') && (mod & KMOD_CTRL)) {
 1703                             // delete from here to end
 1704                             *textpos = '\0';
 1705                             updatetextcursor();
 1706                         } else if ((c2 == 'a') && (mod & KMOD_CTRL)) {
 1707                             // go to start of text
 1708                             textpos = text;
 1709                             updatetextcursor();
 1710                         } else if ((c2 == 'e') && (mod & KMOD_CTRL)) {
 1711                             // go to end of text
 1712                             textpos = &text[strlen(text)];
 1713                             updatetextcursor();
 1714                         } else if ((c >= FIRSTLET) && (c <= LASTLET)) {
 1715                             // add onto end of text
 1716                             char temptext[2];
 1717                             char endbit[BUFLEN];
 1718                             // remember from here until end
 1719                             if (textpos) {
 1720                                 strcpy(endbit, textpos);
 1721                             } else {
 1722                                 endbit[0] = '\0';
 1723                             }
 1724                             // end here
 1725                             *textpos = '\0';
 1726                             // append char
 1727                             sprintf(temptext, "%c", c);
 1728                             strcat(text, temptext);
 1729                             // move cursor to end of appended bit
 1730                             textpos = &text[strlen(text)];
 1731                             // append end bit
 1732                             if (strlen(endbit) > 0) {
 1733                                 strcat(text, endbit);
 1734                             }
 1735                             //
 1736                             updatetextcursor();
 1737                         } else if (c2 == SDLK_LEFT) {
 1738                             // move cursor
 1739                             if (textpos != text) textpos--;
 1740                             updatetextcursor();
 1741                         } else if (c2 == SDLK_RIGHT) {
 1742                             if (textpos != &text[strlen(text)]) textpos++;
 1743                             updatetextcursor();
 1744                         } else if ((c2 == SDLK_ESCAPE) ||  
 1745                               ((c2 == 'g') && (mod & KMOD_CTRL)) ) {
 1746                             sprintf(statustext, "Aborted.");
 1747                             changestate(S_NONE);
 1748                             drawmap(TRUE);
 1749                         } else if (c == ' ') {
 1750                             // add onto end of text
 1751                             char endbit[BUFLEN];
 1752                             // remember from here until end
 1753                             strcpy(endbit, textpos);
 1754                             // end here
 1755                             *textpos = '\0';
 1756                             // append char
 1757                             strcat(text, " ");
 1758                             // move cursor to end of appended bit
 1759                             textpos = &text[strlen(text)];
 1760                             // append end bit
 1761                             strcat(text, endbit);
 1762                             updatetextcursor();
 1763                         } else if (c2 == SDLK_BACKSPACE) {
 1764                             // remove last charater
 1765                             if (textpos != text) {
 1766                                 strcpy(textpos-1, textpos);
 1767                             }
 1768                             //text[strlen(text)-1] = '\0';
 1769                             textpos--;
 1770                             updatetextcursor();
 1771                         } else if (c == 13) { /* enter */
 1772                             if (state == S_TYPETEXT) {
 1773                                 endtext();
 1774                             } else if (state == S_EDITTEXT) {
 1775                                 endtextedit();
 1776                             } else if (state == S_SAVING) {
 1777                                 savemap();
 1778                                 changestate(S_NONE);
 1779                                 drawmap(TRUE);
 1780                             } else if (state == S_LOADING) {
 1781                                 loadmap();
 1782                                 changestate(S_NONE);
 1783                                 drawmap(TRUE);
 1784                             } else if (state == S_SEARCH) {
 1785                                 changestate(S_NONE);
 1786                                 if (dosearch()) {
 1787                                     seterror(255);
 1788                                     sprintf(statustext, "Not found: '%s'",searchtext);
 1789                                     setsearchflash(0);
 1790                                 } else {
 1791                                     setinfo(255);
 1792                                     sprintf(statustext, "Found '%s' in text object #%d (map '%s')",searchtext, map[curmap].selecteditem, map[curmap].name);
 1793                                     setsearchflash(255);
 1794                                 }
 1795                                 drawmap(TRUE);
 1796                             } else if (state == S_MAPNAMING) {
 1797                                 /* rename map */
 1798                                 strcpy(map[curmap].name,text);
 1799                                 changestate(S_NONE);
 1800                                 setinfo(255);
 1801                                 sprintf(statustext, "Map #%d renamed to '%s'.",curmap,map[curmap].name);
 1802                                 drawmap(TRUE);
 1803                             }
 1804                         }
 1805                     } else {
 1806                         if (c2 == SDLK_HOME) {
 1807                             screenx = 0;
 1808                             screeny = 0;
 1809                             drawmap(TRUE);
 1810                         }
 1811                         if (c2 == SDLK_END) {
 1812                             screenx = map[curmap].width - (screen->w-SIDEBARW);
 1813                             screeny = map[curmap].height - (screen->h-STATUSH);
 1814                             drawmap(TRUE);
 1815                         }
 1816                         if (c == 'a') {  /* add map[curmap].object */
 1817                             if (state == S_NONE) {
 1818                                 changestate(S_ADDOBJ);
 1819                             }
 1820                         }
 1821                         if (c == '/') {  /* search/find */
 1822                             if (state == S_NONE) {
 1823                                 startx = 1;
 1824                                 starty = ((screen->h-STATUSH)/2)-2;
 1825                                 bg = NULL;
 1826                                 strcpy(text, "");
 1827                                 textpos = text;
 1828                                 changestate(S_SEARCH);
 1829                                 drawmap(TRUE);
 1830                             }
 1831                         }
 1832                         if (c == 'n') { /* find next */
 1833                             changestate(S_NONE);
 1834                             if (dosearchnext()) {
 1835                                 seterror(255);
 1836                                 sprintf(statustext, "Not foundnext: '%s'",searchtext);
 1837                                 setsearchflash(0);
 1838                             } else {
 1839                                 setinfo(255);
 1840                                 sprintf(statustext, "Foundnext %s'%s' in text object #%d (map '%s')",searchwrap ? "(wrapped) " : "",searchtext, map[curmap].selecteditem, map[curmap].name);
 1841                                 setsearchflash(255);
 1842                             }
 1843                             drawmap(TRUE);
 1844                         }
 1845                         if (c == 'm') {  /* modify object type */
 1846                             if (state == S_NONE) {
 1847                                 changestate(S_CHANGEOBJECT);
 1848                             }
 1849                         }
 1850                         if (c == 't') {  /* add text */
 1851                             if (state == S_NONE) {
 1852                                 changestate(S_ADDTEXT);
 1853                             }
 1854                         }
 1855                         if ((c == 'e') || (c2 == SDLK_F2)) {  /* edit current text */
 1856                             if (state == S_NONE) {
 1857                                 if (    (map[curmap].selecteditemtype == T_TEXT) &&
 1858                                     (map[curmap].selecteditem != -1) ){
 1859                                     startedittext(map[curmap].selecteditem);
 1860                                 } else {
 1861                                     seterror(255);
 1862                                     sprintf(statustext, "Cannot edit text - no text item selected!");
 1863                                     drawstatusbar();
 1864                                 }
 1865                             }
 1866                         }
 1867                         if (c == 's') { /* save */
 1868                             startx = 1;
 1869                             starty = ((screen->h-STATUSH)/2)-2;
 1870                             bg = NULL;
 1871                             strcpy(text, currentfilename);
 1872                             textpos = &text[strlen(text)];
 1873                             changestate(S_SAVING);
 1874                             drawmap(TRUE);
 1875                         } 
 1876                         if ((c == 'l') || (c == 'o')) { /* load, open */
 1877                             startx = 1;
 1878                             starty = ((screen->h-STATUSH)/2)-2;
 1879                             bg = NULL;
 1880                             strcpy(text, currentfilename);
 1881                             textpos = &text[strlen(text)];
 1882                             changestate(S_LOADING);
 1883                             drawmap(TRUE);
 1884                         }
 1885                         if ((c == ',') || (c == 'q')) { /* scroll object box up */
 1886                             if (state == S_CREATETELE) {
 1887                                 scrollmaplist(-1);
 1888                             } else {
 1889                                 scrollobox(-1);
 1890                             }
 1891                         }
 1892                         if ((c == '.') || (c == 'w')) { /* scroll object box down */
 1893                             if (state == S_CREATETELE) {
 1894                                 scrollmaplist(1);
 1895                             } else {
 1896                                 scrollobox(1);
 1897                             }
 1898                         }
 1899                         if ((c == '<') || (c == 'Q')) { /* scroll object box up */
 1900                             if (state == S_CREATETELE) {
 1901                                 scrollmaplist(-20);
 1902                             } else {
 1903                                 scrollobox(-OBOXPAGESIZE);
 1904                             }
 1905                         }
 1906                         if ((c == '>') || (c == 'W')) { /* scroll object box down */
 1907                             if (state == S_CREATETELE) {
 1908                                 scrollmaplist(20);
 1909                             } else {
 1910                                 scrollobox(OBOXPAGESIZE);
 1911                             }
 1912                         }
 1913                         if (c == 'x') {
 1914                             if (map[curmap].selecteditem != -1) {
 1915                                 switch (map[curmap].selecteditemtype) {
 1916                                     case T_OBJECT:
 1917                                     case T_TEXT:
 1918                                         matchtype = map[curmap].selecteditemtype;
 1919                                         changestate(S_MATCHX);
 1920                                         drawmap(TRUE);
 1921                                         break;
 1922                                 }
 1923                             }
 1924                         }
 1925                         if (c == 'y') {
 1926                             if (map[curmap].selecteditem != -1) {
 1927                                 switch (map[curmap].selecteditemtype) {
 1928                                     case T_OBJECT:
 1929                                     case T_TEXT:
 1930                                         matchtype = map[curmap].selecteditemtype;
 1931                                         changestate(S_MATCHY);
 1932                                         drawmap(TRUE);
 1933                                         break;
 1934                                 }
 1935                             }
 1936                         }
 1937                         if (c == 'b') {
 1938                             if (map[curmap].selecteditem != -1) {
 1939                                 switch (map[curmap].selecteditemtype) {
 1940                                     case T_OBJECT:
 1941                                     case T_TEXT:
 1942                                         matchtype = map[curmap].selecteditemtype;
 1943                                         changestate(S_MATCHSIZE);
 1944                                         drawmap(TRUE);
 1945                                         break;
 1946                                 }
 1947                             }
 1948                         }
 1949                         if (c == 'g') { /* toggle snap-to-grid */
 1950                             togglegrid();
 1951                             drawtoolbox();
 1952                         }
 1953                         if (c == ';') { /* change gridsize */
 1954                             changegridsize();
 1955                             drawmap(TRUE);
 1956                         }
 1957                         if (c == 'c') { /* copy */
 1958                             copy();
 1959                         }
 1960                         if (c == 'd') {  /* drill down */
 1961                             if (state == S_NONE) {
 1962                                 if ((map[curmap].selecteditemtype == T_OBJECT) && (map[curmap].selecteditem != -1)) {
 1963                                     drillto(map[curmap].obj[map[curmap].selecteditem].child);
 1964                                 } else {
 1965                                     seterror(255);
 1966                                     sprintf(statustext,"Cannot drill down - no object selected!");
 1967                                     drawstatusbar();
 1968                                 }
 1969                             } else {
 1970                                 seterror(255);
 1971                                 sprintf(statustext,"Cannot drill down in state %d.",state);
 1972                                 drawstatusbar();
 1973                             }
 1974                         }
 1975                         if (c == 'f') {
 1976                             if (showflows) {
 1977                                 showflows = FALSE;
 1978                                 setinfo(255);
 1979                                 sprintf(statustext, "Traffic flows hidden.");
 1980                             } else {
 1981                                 setinfo(255);
 1982                                 sprintf(statustext, "Traffic flows displayed.");
 1983                                 showflows = TRUE;
 1984                             } 
 1985                             drawtoolbox();
 1986                             drawmap(TRUE);
 1987                         }
 1988                         if ((c == 'p') || (c == 'v')) { /* paste */
 1989                             paste();
 1990                         }
 1991                         /* keyboard shortcuts */
 1992                         if ((c >= '0') && (c <= '9')) {
 1993                             int mx,my;
 1994                             int onum;
 1995     
 1996                             onum = c - '0';
 1997             
 1998                             SDL_GetMouseState(&mx, &my);
 1999                             if (isonobox(mx, my)) {
 2000                                 int seltype, tempx, tempy;
 2001                                 /* define shortcut */
 2002                                 tempx = (mx - obox.x) / (obox.gridsize+3);
 2003                                 tempy = (my - obox.y) / (obox.gridsize+3);
 2004                                 seltype = tempy*obox.gridrowlen + tempx + (obox.pos*3);
 2005 
 2006                                 shortcut[onum] = seltype;
 2007                                 setinfo(255);
 2008                                 sprintf(statustext,"Shortcut key '%c' set to '%s'.\n",c, objtype[seltype].name);
 2009                                 drawstatusbar();
 2010                                 drawobox();
 2011                             } else {
 2012                                 /* select shortcut */
 2013                                 int fitx, fity, fit;
 2014                                 /* select object */
 2015                                 map[curmap].selectedtype = shortcut[onum];
 2016                                 /* these two should never happen... */
 2017                                 if (map[curmap].selectedtype < 0 ) map[curmap].selectedtype = 0;
 2018                                 if (map[curmap].selectedtype >= numobjtypes) map[curmap].selectedtype = numobjtypes-1;
 2019                                 /* ensure that object is visible */
 2020                                 fitx = (obox.width / obox.gridsize);
 2021                                 fity = ((obox.height+3) / obox.gridsize);
 2022                                 fit = fitx * fity;
 2023 
 2024                                 /* scroll object box to make it visible */
 2025                                 while (shortcut[onum] < (obox.pos*fitx)) {
 2026                                     obox.pos--;
 2027                                 }
 2028                                 while (shortcut[onum] > ((obox.pos*fitx) + fit)) {
 2029                                     obox.pos++;
 2030                                 }
 2031 
 2032                                 sprintf(statustext,"Object type shortcut #%d ('%s') selected.\n",onum, objtype[map[curmap].selectedtype].name);
 2033                                 drawstatusbar();
 2034                                 drawobox();
 2035                                 SDL_UpdateRect(screen, obox.x, obox.y, obox.width,obox.height);
 2036                             }
 2037                         }
 2038                         if (c2 == SDLK_BACKSPACE) { 
 2039                             goback();
 2040                         }
 2041                         if (c2 == SDLK_PAGEUP) { 
 2042                             scrollobox(-OBOXPAGESIZE);
 2043                         }
 2044                         if (c2 == SDLK_PAGEDOWN) { 
 2045                             scrollobox(OBOXPAGESIZE);
 2046                         }
 2047                         if (c2 == SDLK_DELETE) { 
 2048                             if (map[curmap].selecteditem != -1) {
 2049                                 if (map[curmap].selecteditemtype == T_LINKPOINT) {
 2050                                     int i;
 2051                                     for (i = map[curmap].selectedlinkpoint; i < (map[curmap].olink[map[curmap].selecteditem].npoints-1); i++) {
 2052                                         map[curmap].olink[map[curmap].selecteditem].point[i].x = map[curmap].olink[map[curmap].selecteditem].point[i+1].x;
 2053                                         map[curmap].olink[map[curmap].selecteditem].point[i].y = map[curmap].olink[map[curmap].selecteditem].point[i+1].y;
 2054                                     }
 2055                                     map[curmap].olink[map[curmap].selecteditem].npoints--;
 2056 
 2057                                     /* move selection to next point on same line */
 2058                                     if (map[curmap].olink[map[curmap].selecteditem].npoints > 0) {
 2059                                         if (map[curmap].selectedlinkpoint >= map[curmap].olink[map[curmap].selecteditem].npoints) {
 2060                                             map[curmap].selectedlinkpoint = map[curmap].olink[map[curmap].selecteditem].npoints-1;
 2061                                         }
 2062                                     } else {
 2063                                         /* deselect point (leave link selected) */
 2064                                         map[curmap].selectedlinkpoint = -1;
 2065                                         map[curmap].selecteditemtype = T_LINK;
 2066                                     }
 2067                                     
 2068                                     sprintf(statustext, "Deleted link #%d point #%d.",map[curmap].selecteditem,map[curmap].selectedlinkpoint);
 2069                                     drawmap(TRUE);
 2070                                 } else {
 2071                                     deletething(map[curmap].selecteditem,map[curmap].selecteditemtype);
 2072                                 }
 2073                             }
 2074                         }
 2075                         if (map[curmap].selecteditem != -1) {
 2076                             if (c == ']') {  /* raise */
 2077                                 int amt;
 2078 
 2079                                 tmod = SDL_GetModState();
 2080                                 if ((tmod & KMOD_SHIFT)) {
 2081                                     amt = (map[curmap].numthings / MULTIRAISENUM);
 2082                                 } else amt = 1;
 2083 
 2084                                 /* raise the selected map[curmap].object */
 2085                                 raiseselected(amt);
 2086                             }
 2087                             if (c == '[') {  /* lower */
 2088                                 int amt;
 2089 
 2090                                 tmod = SDL_GetModState();
 2091                                 if ((tmod & KMOD_SHIFT)) {
 2092                                     amt = (map[curmap].numthings / MULTIRAISENUM);
 2093                                 } else amt = 1;
 2094 
 2095                                 /* lower the selected map[curmap].object */
 2096                                 lowerselected(amt);
 2097                             }
 2098                             if (c == '{') {  /* lower by lots */
 2099                                 int amt = (map[curmap].numthings / MULTIRAISENUM);
 2100                                 lowerselected(amt);
 2101                             }
 2102                             if (c == '}') {  /* raise by lots */
 2103                                 int amt = (map[curmap].numthings / MULTIRAISENUM);
 2104                                 raiseselected(amt);
 2105                             }
 2106                         }
 2107                     }
 2108                     break;
 2109             }
 2110     
 2111             if (infoflash || errorflash) {
 2112                 if (!SDL_PollEvent(&event)) isevent = FALSE;
 2113             } else {
 2114                 isevent = FALSE;
 2115             }
 2116         }
 2117         
 2118     } /* end main loop */
 2119 
 2120     return 0;
 2121 }
 2122 
 2123 void addlinkpoint(int linkid, int x, int y) {
 2124     int pos;
 2125     int i;
 2126 
 2127     pos = findpointpos(&map[curmap].olink[linkid],x,y);
 2128 
 2129     map[curmap].olink[linkid].npoints++;
 2130 
 2131     /* shuffle points from that point upwards */
 2132     for (i = (map[curmap].olink[linkid].npoints-1);i > pos ; i--) {
 2133         map[curmap].olink[linkid].point[i] = map[curmap].olink[linkid].point[i-1];
 2134     }
 2135 
 2136     map[curmap].olink[linkid].point[pos].x = x;
 2137     map[curmap].olink[linkid].point[pos].y = y;
 2138 
 2139     setmod(TRUE);
 2140     sprintf(statustext, "Point added to link #%d at position %d,%d.",linkid, x, y);
 2141 }
 2142 
 2143 int addvector(vectorimg_t *vimg, int type, int x1, int y1, int x2, int y2, SDL_Color *c, SDL_Color *fc) {
 2144 
 2145     if ((vimg->vnum + 1) >= MAXVECTORSPERIMAGE) return TRUE;
 2146     vimg->vector[vimg->vnum].type = type;
 2147     vimg->vector[vimg->vnum].x1 = x1;
 2148     vimg->vector[vimg->vnum].y1 = y1;
 2149     vimg->vector[vimg->vnum].x2 = x2;
 2150     vimg->vector[vimg->vnum].y2 = y2;
 2151     vimg->vector[vimg->vnum].c.r = c->r;
 2152     vimg->vector[vimg->vnum].c.g = c->g;
 2153     vimg->vector[vimg->vnum].c.b = c->b;
 2154     vimg->vector[vimg->vnum].c.unused = 0;
 2155     if (fc == NULL) {
 2156         vimg->vector[vimg->vnum].fc.r = 0;
 2157         vimg->vector[vimg->vnum].fc.g = 0;
 2158         vimg->vector[vimg->vnum].fc.b = 0;
 2159         vimg->vector[vimg->vnum].fc.unused = 0;
 2160     } else {
 2161         vimg->vector[vimg->vnum].fc.r = fc->r;
 2162         vimg->vector[vimg->vnum].fc.g = fc->g;
 2163         vimg->vector[vimg->vnum].fc.b = fc->b;
 2164         vimg->vector[vimg->vnum].fc.unused = fc->unused;
 2165     }
 2166     vimg->vnum = vimg->vnum + 1;
 2167 
 2168     return FALSE;
 2169 }
 2170 
 2171 void calcmapdimensions(void) {
 2172     int thismaxx,thismaxy; /* used to calculate map size */
 2173     int maxx = -1,maxy = -1; /* used to calculate map size */
 2174     int i;
 2175 
 2176     /* draw all map[curmap].objects links  etc*/
 2177     for (i = 0; i < map[curmap].numthings; i++) {
 2178         if (map[curmap].thing[i].type == T_OBJECT) {
 2179             /* calculate max map size */
 2180             thismaxx = map[curmap].obj[map[curmap].thing[i].id].x + map[curmap].obj[map[curmap].thing[i].id].w;
 2181             thismaxy = map[curmap].obj[map[curmap].thing[i].id].y + map[curmap].obj[map[curmap].thing[i].id].h;
 2182             if (thismaxx > maxx) maxx = thismaxx;
 2183             if (thismaxy > maxy) maxy = thismaxy;
 2184         } else if (map[curmap].thing[i].type == T_LINK) {
 2185             int p;
 2186             thismaxx = -1;
 2187             thismaxy = -1;
 2188             for (p = 0; p < map[curmap].olink[map[curmap].thing[i].id].npoints; p++) {
 2189                 if (map[curmap].olink[map[curmap].thing[i].id].point[p].x > thismaxx) 
 2190                     thismaxx = map[curmap].olink[map[curmap].thing[i].id].point[p].x;
 2191                 if (map[curmap].olink[map[curmap].thing[i].id].point[p].y > thismaxy) 
 2192                     thismaxy = map[curmap].olink[map[curmap].thing[i].id].point[p].y;
 2193             }
 2194             /* calculate max map size */
 2195             if (thismaxx > maxx) maxx = thismaxx;
 2196             if (thismaxy > maxy) maxy = thismaxy;
 2197         } else if (map[curmap].thing[i].type == T_TEXT) {
 2198             /* calculate max map size */
 2199             thismaxx = map[curmap].textob[map[curmap].thing[i].id].x + map[curmap].textob[map[curmap].thing[i].id].w;
 2200             thismaxy = map[curmap].textob[map[curmap].thing[i].id].y + map[curmap].textob[map[curmap].thing[i].id].h;
 2201             if (thismaxx > maxx) maxx = thismaxx;
 2202             if (thismaxy > maxy) maxy = thismaxy;
 2203         } else {
 2204             printf("WARNING: Thing #%d has unknown type %d!\n",i,map[curmap].thing[i].type);
 2205         }
 2206     }
 2207 
 2208     /* set map dimensions - automatically grow/shrink to be a bit bigger than required size */
 2209     if (maxx <= (map[curmap].width - 300)) map[curmap].width = maxx + 100;
 2210     if (maxy <= (map[curmap].height - 300)) map[curmap].height = maxx + 100;
 2211     if (maxx+200 > map[curmap].width) map[curmap].width = maxx + 200;
 2212     if (maxy+200 > map[curmap].height) map[curmap].height = maxy + 200;
 2213 
 2214     /* make sure map is always at least as big as the visible screen size */
 2215     if (map[curmap].width < screen->w - SIDEBARW) map[curmap].width = screen->w - SIDEBARW;
 2216     if (map[curmap].height < screen->h - STATUSH) map[curmap].height = screen->h - STATUSH;
 2217 
 2218 
 2219 
 2220     /* determine position of sidebar */
 2221     obox.x = screen->w - SIDEBARW;
 2222     obox.y = ((screen->h / 4) * 3) - 10;
 2223     obox.width = SIDEBARW;
 2224     obox.height = screen->h - obox.y;
 2225     obox.bgcol = black;
 2226     obox.gridbgcol = grey;
 2227     obox.gridcol = grey;
 2228     obox.gridsize = 30;
 2229     obox.gridrowlen = SIDEBARW / obox.gridsize;
 2230 
 2231     toolbox.x = screen->w - SIDEBARW;
 2232     toolbox.y = 0;
 2233     toolbox.width = SIDEBARW;
 2234     toolbox.height = screen->h / 3;
 2235     toolbox.bgcol = black;
 2236     toolbox.gridsize = 30;
 2237     toolbox.gridrowlen = SIDEBARW / toolbox.gridsize;
 2238 
 2239     mapbox.x = screen->w - SIDEBARW;
 2240     mapbox.y = toolbox.y+toolbox.height+10;
 2241     mapbox.width = SIDEBARW;
 2242     mapbox.height = obox.y - mapbox.y - 20;
 2243     mapbox.offset = 0;
 2244 
 2245 }
 2246 
 2247 int setgridsize(int size) {
 2248     int n;
 2249     for (n = 0; n < gridsizenum; n++) {
 2250         if (gridsizelist[n] == size) {
 2251             gridsizeindex = n;
 2252             gridsize = gridsizelist[n];
 2253             return FALSE;
 2254         }
 2255     }
 2256 
 2257     return TRUE;
 2258 }
 2259 
 2260 void changegridsize(void) {
 2261     if (++gridsizeindex >= gridsizenum) {
 2262         gridsizeindex = 0;
 2263     }
 2264     gridsize = gridsizelist[gridsizeindex];
 2265     setinfo(255);
 2266     sprintf(statustext, "Grid size set to %d.", gridsize);
 2267 }
 2268 
 2269 void changelinearrow(int changeby) {
 2270 
 2271     if ((changeby < 0) && (defarrow == 0)) {
 2272         defarrow = AP_BOTH;
 2273     } else {
 2274         defarrow += changeby;
 2275     }
 2276 
 2277     /* wrap around */
 2278     if (defarrow > AP_BOTH) defarrow = 0;
 2279 
 2280     /* change arrow style on currently selected line */
 2281     if (map[curmap].selecteditemtype == T_LINK) {
 2282         if (map[curmap].selecteditem != -1) {
 2283             map[curmap].olink[map[curmap].selecteditem].style &= 0x00ffff;
 2284             map[curmap].olink[map[curmap].selecteditem].style |= (defarrow << 16);
 2285             setmod(TRUE);
 2286             drawmap(TRUE);
 2287         }
 2288     }
 2289 
 2290     /* redraw toolbox */
 2291     drawtoolbox();
 2292 }
 2293 
 2294 void changelinestyle(int changeby) {
 2295     if ((changeby < 0) && (defstyle == 0)) {
 2296         defstyle = MAXLINESTYLE - 1;
 2297     } else {
 2298         defstyle += changeby;
 2299     }
 2300     /* wrap around */
 2301     if (defstyle >= MAXLINESTYLE) defstyle = 0;
 2302 
 2303     /* change line style of currently selected line */
 2304     if (map[curmap].selecteditemtype == T_LINK) {
 2305         if (map[curmap].selecteditem != -1) {
 2306             map[curmap].olink[map[curmap].selecteditem].style &= 0xff00ff;
 2307             map[curmap].olink[map[curmap].selecteditem].style |= (defstyle << 8);
 2308             setmod(TRUE);
 2309             drawmap(TRUE);
 2310         }
 2311     }
 2312 
 2313     /* redraw toolbox */
 2314     drawtoolbox();
 2315 }
 2316 
 2317 void changelinethickness(int changeby) {
 2318     defthickness += changeby;
 2319     /* wrap around */
 2320     if (defthickness <= 0) defthickness = 5;
 2321     if (defthickness > 5) defthickness = 1;
 2322 
 2323     /* change thickness of currently selected line */
 2324     if (map[curmap].selecteditemtype == T_LINK) {
 2325         if (map[curmap].selecteditem != -1) {
 2326             map[curmap].olink[map[curmap].selecteditem].style &= 0xffff00;
 2327             map[curmap].olink[map[curmap].selecteditem].style |= defthickness;
 2328             setmod(TRUE);
 2329             drawmap(TRUE);
 2330         }
 2331     }
 2332 
 2333     /* redraw toolbox */
 2334     drawtoolbox();
 2335 }
 2336 
 2337 void changemap(int newmap) {
 2338     map[newmap].selecteditem = -1;
 2339     map[newmap].selecteditemtype = -1;
 2340     /*map[newmap].selectedtype = map[curmap].selectedtype; */
 2341     curmap = newmap;
 2342 }
 2343 
 2344 void changestate(int newstate) {
 2345     int oldstate;
 2346 
 2347     oldstate = state;
 2348     /* can't do most things in readonly mode */
 2349     if (readonly) {
 2350         switch (newstate) {
 2351             case S_NONE:
 2352             case S_LOADING:
 2353             case S_REALLYQUIT:
 2354                 break;
 2355             default:
 2356                 newstate = S_NONE;
 2357                 break;
 2358         }
 2359     }
 2360     if (newstate != state) {
 2361         if (oldstate == S_DRAWFLOW) {
 2362             showflows = oldshowflows;
 2363         }
 2364         if ((state == S_ADDOBJ) || (state == S_ADDTEXT)) {
 2365             /* change mouse back to normal */
 2366             SDL_SetCursor(normalmouse);
 2367         }
 2368         if (newstate == S_ADDOBJ) SDL_SetCursor(objmouse);
 2369         if (newstate == S_ADDTEXT) SDL_SetCursor(textmouse);
 2370 
 2371         state = newstate;
 2372         if (oldstate == S_DRAWFLOW) {
 2373             drawmap(TRUE);
 2374         }
 2375         drawtoolbox();
 2376         switch (state) {
 2377             case S_NONE:
 2378                 //sprintf(statustext,"Selection mode enabled.\n"); fflush(STDOUT);
 2379                 if (oldstate == S_DRAWFLOW) {
 2380                     sprintf(statustext,"Traffic flow definition complete.");
 2381                 }
 2382                 break;
 2383             case S_ADDOBJ:
 2384                 sprintf(statustext,"Object creation mode enabled.\n"); 
 2385                 break;
 2386             case S_CHANGEOBJECT:
 2387                 setinfo(255);
 2388                 sprintf(statustext,"Object type modification mode enabled - select new object type...\n"); 
 2389                 break;
 2390             case S_ADDTEXT:
 2391                 sprintf(statustext,"Text creation mode entered.\n"); 
 2392                 break;
 2393             case S_TYPETEXT:
 2394                 sprintf(statustext,"Text entry mode entered.\n"); 
 2395                 break;
 2396             case S_EDITTEXT:
 2397                 sprintf(statustext,"Text edit mode entered.\n"); 
 2398                 break;
 2399             case S_MATCHSIZE:
 2400                 setinfo(255);
 2401                 sprintf(statustext,"Size-matching mode entered - select object to copy size from...\n"); 
 2402                 break;
 2403             case S_MATCHX:
 2404                 setinfo(255);
 2405                 sprintf(statustext,"X-matching mode entered - select item to align with...\n"); 
 2406                 break;
 2407             case S_MATCHY:
 2408                 setinfo(255);
 2409                 sprintf(statustext,"Y-matching mode entered - select item to align with...\n"); 
 2410                 break;
 2411             case S_DRAWFLOW:
 2412                 setinfo(255);
 2413                 sprintf(statustext,"Traffic flow definition mode entered - select items...\n"); 
 2414                 break;
 2415             case S_MAPNAMING:
 2416                 sprintf(statustext,"Map rename mode entered.\n"); 
 2417                 break;
 2418             case S_SEARCH:
 2419                 sprintf(statustext,"Search mode entered.\n"); 
 2420                 break;
 2421             case S_SAVING:
 2422                 sprintf(statustext,"Save mode entered.\n"); 
 2423                 break;
 2424             case S_LOADING:
 2425                 sprintf(statustext,"Load mode entered.\n"); 
 2426                 break;
 2427             case S_XSCROLL:
 2428                 sprintf(statustext,"Scrolling horizontally...\n"); 
 2429                 break;
 2430             case S_YSCROLL:
 2431                 sprintf(statustext,"Scrolling vertically...\n"); 
 2432                 break;
 2433         }
 2434         drawstatusbar();
 2435     }
 2436 }
 2437 
 2438 void cleanup(void) {
 2439     int i;
 2440     SDL_FreeCursor(textmouse);
 2441     SDL_FreeCursor(objmouse);
 2442     for (i = 1; i < MAXLETTERHEIGHT; i++) {
 2443         TTF_CloseFont(font[i]);
 2444     }
 2445     TTF_Quit();
 2446     SDL_EnableUNICODE(0);
 2447     SDL_Quit();
 2448 }
 2449 
 2450 void copy(void) {
 2451     if (map[curmap].selecteditem == -1) {
 2452         /* copy entire map */
 2453         copytype = T_MAP;
 2454         copyfrom = -1;
 2455         copymap = curmap;
 2456         sprintf(statustext,"Map %d ('%s') set as copy source.",curmap, map[curmap].name);
 2457         drawstatusbar();
 2458     } else {
 2459         if (map[curmap].selecteditemtype == T_OBJECT) {
 2460             copytype = T_OBJECT;
 2461             copymap = curmap;
 2462             copyfrom = map[curmap].selecteditem;
 2463             sprintf(statustext,"Object %d set as copy source.",copyfrom);
 2464             drawstatusbar();
 2465         } else if (map[curmap].selecteditemtype == T_TEXT) {
 2466             copytype = T_TEXT;
 2467             copymap = curmap;
 2468             copyfrom = map[curmap].selecteditem;
 2469             sprintf(statustext,"Text %d ('%s') set as copy source.",copyfrom, map[curmap].textob[copyfrom].text);
 2470             drawstatusbar();
 2471         }
 2472     }
 2473 }
 2474 
 2475 int createobject(int type, int x, int y) {
 2476     map[curmap].obj[map[curmap].numobjects].type = type;
 2477     map[curmap].obj[map[curmap].numobjects].w = objtype[type].defw;
 2478     map[curmap].obj[map[curmap].numobjects].h = objtype[type].defh;
 2479     if ((x + map[curmap].obj[map[curmap].numobjects].w) >= map[curmap].width) {
 2480         x = map[curmap].width - map[curmap].obj[map[curmap].numobjects].w - 1;
 2481     }
 2482     if ((y + map[curmap].obj[map[curmap].numobjects].h) >= map[curmap].height) {
 2483         y = map[curmap].height - map[curmap].obj[map[curmap].numobjects].h - 1;
 2484     }
 2485 
 2486     /* adjust for grid */
 2487     if (grid) {
 2488         x = x - (x % gridsize);
 2489         y = y - (y % gridsize);
 2490     }
 2491 
 2492     map[curmap].obj[map[curmap].numobjects].x = x;
 2493     map[curmap].obj[map[curmap].numobjects].y = y;
 2494 
 2495     map[curmap].obj[map[curmap].numobjects].child = -1;
 2496     map[curmap].obj[map[curmap].numobjects].fillcol.unused &= ~ISFLOW; /* not a flow */
 2497 
 2498     setmod(TRUE);
 2499     sprintf(statustext,"Object #%d (%s) created at (%d,%d).\n",map[curmap].numobjects, objtype[type].name, x, y);
 2500     drawstatusbar();
 2501 
 2502 
 2503     /* add to 'thing' list */
 2504     map[curmap].thing[map[curmap].numthings].type = T_OBJECT;
 2505     map[curmap].thing[map[curmap].numthings].id = map[curmap].numobjects;
 2506 
 2507     map[curmap].numobjects++;
 2508     map[curmap].numthings++;
 2509 
 2510 
 2511     return 0;
 2512 }
 2513 
 2514 void copyline(SDL_Surface *screen,int x1, int y1, int x2, int y2, int *lbuf) {
 2515     int deltax, deltay;
 2516     int numpixels;
 2517     int d;
 2518     int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
 2519     int i;
 2520     int x;
 2521     int y;
 2522     SDL_Color bgcol;
 2523 
 2524     /* store coords */
 2525     lbuf[0] = x1;
 2526     lbuf[1] = y1;
 2527     lbuf[2] = x2;
 2528     lbuf[3] = y2;
 2529 
 2530     deltax = (x2 - x1);
 2531     if (deltax < 0) deltax = -deltax;
 2532     deltay = (y2 - y1);
 2533     if (deltay < 0) deltay = -deltay;
 2534 
 2535     if (deltax >= deltay) {
 2536         numpixels = deltax + 1;
 2537         d = (deltay*2) - deltax;
 2538         dinc1 = deltay << 1;
 2539         dinc2 = (deltay-deltax) << 1;
 2540         xinc1 = 1;
 2541         xinc2 = 1;
 2542         yinc1 = 0;
 2543         yinc2 = 1;
 2544     } else {
 2545         numpixels = deltay + 1;
 2546         d = (deltax*2) - deltay;
 2547         dinc1 = deltax << 1;
 2548         dinc2 = (deltax - deltay) << 1;
 2549         xinc1 = 0;
 2550         xinc2 = 1;
 2551         yinc1 = 1;
 2552         yinc2 = 1;
 2553     }
 2554 
 2555     if (x1 > x2) {
 2556         xinc1 = - xinc1;
 2557         xinc2 = - xinc2;
 2558     }
 2559     if (y1 > y2) {
 2560         yinc1 = - yinc1;
 2561         yinc2 = - yinc2;
 2562     }
 2563 
 2564     x = x1; y = y1;
 2565 
 2566     for (i = 0; i < numpixels; i++) {
 2567         getcolor(screen, x, y, &bgcol);
 2568         lbuf[i+4] = SDL_MapRGB(screen->format, bgcol.r, bgcol.g, bgcol.b);
 2569 
 2570         if (d < 0) {
 2571             d += dinc1;
 2572             x += xinc1;
 2573             y += yinc1;
 2574         } else {
 2575             d += dinc2;
 2576             x += xinc2;
 2577             y += yinc2;
 2578         }
 2579     }
 2580     
 2581 }
 2582 
 2583 void deletething(int id, int type) {
 2584     int i;
 2585     int found;
 2586 
 2587 
 2588     if (type == T_LINK) {
 2589         /* remove the link*/
 2590         deletelink(id);
 2591     } else if (type == T_TEXT) {
 2592         deletetext(id);
 2593     } else if (type == T_OBJECT) {
 2594         /* remove any links connecting to this map[curmap].object */
 2595         found = 0;
 2596         while (found >= 0 ) {
 2597             found = -1;
 2598             for (i = 0; i < map[curmap].numlinks; i++) {
 2599                 if ((map[curmap].olink[i].srcobj == id) || (map[curmap].olink[i].dstobj == id)) {
 2600                     found = i;
 2601                     break;
 2602                 }
 2603             }
 2604             if (found >= 0) {
 2605                 deletelink(found);
 2606             }
 2607         }
 2608 
 2609         /* remove any text anchored to this map[curmap].object */
 2610         found = 0;
 2611         while (found >= 0 ) {
 2612             found = -1;
 2613             for (i = 0; i < map[curmap].numtext; i++) {
 2614                 if (map[curmap].textob[i].anchor == id) {
 2615                     found = i;
 2616                     break;
 2617                 }
 2618             }
 2619             if (found >= 0) {
 2620                 deletetext(found);
 2621             }
 2622         }
 2623         /* remove the map[curmap].object */
 2624         deleteobject(id);
 2625         /* shuffle ids on any link referencing this object */
 2626         for (i = 0; i < map[curmap].numlinks; i++) {
 2627             if (map[curmap].olink[i].srcobj > id) {
 2628                 map[curmap].olink[i].srcobj--;
 2629             }
 2630             if (map[curmap].olink[i].dstobj > id) {
 2631                 map[curmap].olink[i].dstobj--;
 2632             }
 2633         }
 2634         /* shuffle ids on any text referencing this object */
 2635         for (i = 0; i < map[curmap].numtext; i++) {
 2636             if (map[curmap].textob[i].anchor > id) {
 2637                 map[curmap].textob[i].anchor--;
 2638             }
 2639         }
 2640     }
 2641     setmod(TRUE);
 2642     map[curmap].selecteditem = -1;
 2643     map[curmap].selecteditemtype = -1;
 2644     drawmap(TRUE);
 2645 }
 2646 
 2647 void deletelink(int linkid) {
 2648     int i;
 2649     int n;
 2650     int found;
 2651 
 2652 
 2653     for (i = linkid; i < (map[curmap].numlinks-1); i++) {
 2654         map[curmap].olink[i] = map[curmap].olink[i+1];
 2655     }
 2656     map[curmap].numlinks--;
 2657     /* shuffle thing # */
 2658     for (n = 0; n < map[curmap].numthings; n++) {
 2659         /* mark for deletion */
 2660         if ((map[curmap].thing[n].id == linkid) && (map[curmap].thing[n].type == T_LINK)) {
 2661             map[curmap].thing[n].id = -1;
 2662         }
 2663         /* shuffle id */
 2664         if ((map[curmap].thing[n].id > linkid) && (map[curmap].thing[n].type == T_LINK)) {
 2665             map[curmap].thing[n].id--;
 2666         }
 2667     }
 2668 
 2669     found = -1;
 2670     for (n = 0; n < map[curmap].numthings; n++) {
 2671         if ((map[curmap].thing[n].type == T_LINK) && (map[curmap].thing[n].id == -1)) {
 2672             found = n;
 2673         }
 2674     }
 2675 
 2676     if (found != -1) {
 2677         // remove the thing 
 2678         for (n = found; n < (map[curmap].numthings-1); n++) {
 2679             map[curmap].thing[n] = map[curmap].thing[n+1];
 2680         }
 2681         map[curmap].numthings--;
 2682     } else {
 2683         seterror(255);
 2684         sprintf(statustext,"Can't find matching thing for link #%d!\n",linkid);
 2685     }
 2686 
 2687     setmod(TRUE);
 2688     sprintf(statustext,"Deleted link #%d.\n",linkid);
 2689     drawstatusbar();
 2690 
 2691 }
 2692 
 2693 
 2694 void deleteobject(int oid) {
 2695     int i;
 2696     int n;
 2697     int found;
 2698 
 2699     for (i = oid; i < (map[curmap].numobjects-1); i++) {
 2700         map[curmap].obj[i] = map[curmap].obj[i+1];
 2701     }
 2702     map[curmap].numobjects--;
 2703     /* shuffle thing # */
 2704     for (n = 0; n < map[curmap].numthings; n++) {
 2705         if ((map[curmap].thing[n].id == oid) && (map[curmap].thing[n].type == T_OBJECT)) {
 2706             map[curmap].thing[n].id = -1;
 2707         }
 2708         if ((map[curmap].thing[n].id > oid) && (map[curmap].thing[n].type == T_OBJECT)) {
 2709             map[curmap].thing[n].id--;
 2710         }
 2711     }
 2712 
 2713     found = -1;
 2714     for (n = 0; n < map[curmap].numthings; n++) {
 2715         if ((map[curmap].thing[n].type == T_OBJECT) && (map[curmap].thing[n].id == -1 )) {
 2716             found = n;
 2717         }
 2718     }
 2719 
 2720     if (found != -1) {
 2721         // remove the thing 
 2722         for (n = found; n < (map[curmap].numthings-1); n++) {
 2723             map[curmap].thing[n] = map[curmap].thing[n+1];
 2724         }
 2725         map[curmap].numthings--;
 2726     } else {
 2727         seterror(255);
 2728         sprintf(statustext,"Can't find matching thing for object #%d!\n",oid);
 2729     }
 2730     
 2731     setmod(TRUE);
 2732     sprintf(statustext,"Deleted object #%d.\n",oid);
 2733     drawstatusbar();
 2734 
 2735 
 2736 }
 2737 
 2738 void deletetext(int textid) {
 2739     int i;
 2740     int n;
 2741     int found;
 2742 
 2743 
 2744     for (i = textid; i < (map[curmap].numtext-1); i++) {
 2745         map[curmap].textob[i] = map[curmap].textob[i+1];
 2746     }
 2747     map[curmap].numtext--;
 2748     /* shuffle thing # */
 2749     for (n = 0; n < map[curmap].numthings; n++) {
 2750         /* mark for deletion */
 2751         if ((map[curmap].thing[n].id == textid) && (map[curmap].thing[n].type == T_TEXT)) {
 2752             map[curmap].thing[n].id = -1;
 2753         }
 2754         /* shuffle id */
 2755         if ((map[curmap].thing[n].id > textid) && (map[curmap].thing[n].type == T_TEXT)) {
 2756             map[curmap].thing[n].id--;
 2757         }
 2758     }
 2759 
 2760     found = -1;
 2761     for (n = 0; n < map[curmap].numthings; n++) {
 2762         if ((map[curmap].thing[n].type == T_TEXT) && (map[curmap].thing[n].id == -1)) {
 2763             found = n;
 2764         }
 2765     }
 2766 
 2767     if (found != -1) {
 2768         // remove the thing 
 2769         for (n = found; n < (map[curmap].numthings-1); n++) {
 2770             map[curmap].thing[n] = map[curmap].thing[n+1];
 2771         }
 2772         map[curmap].numthings--;
 2773     } else {
 2774         seterror(255);
 2775         sprintf(statustext,"Can't find matching thing for text item #%d!\n",textid);
 2776     }
 2777 
 2778     setmod(TRUE);
 2779     sprintf(statustext,"Deleted text item #%d.\n",textid);
 2780     drawstatusbar();
 2781 
 2782 }
 2783 
 2784 
 2785 
 2786 void adjustendpoint(SDL_Surface *screen, int *adjx, int *adjy, double x1, double y1, double x2, double y2, int arrowstyle, int arrowpos ) {
 2787     int middlex, middley;
 2788     int deltax, deltay;
 2789     int numpixels;
 2790     int d;
 2791     int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
 2792     int i,n;
 2793     int x;
 2794     int y;
 2795     int tempx,tempy;
 2796     int o,oldo;
 2797     SDL_Surface *temps;
 2798     int arrowthickness;
 2799 
 2800     arrowthickness = (arrowstyle & 0x0000ff);
 2801 
 2802 
 2803     /* calculate where the arrowpoint should go - follow the line until
 2804        we're not on an object */
 2805 
 2806     if (arrowpos == AP_END) {
 2807         /* temporarily reverse endpoints  */
 2808         tempx = x1;
 2809         tempy = y1;
 2810         x1 = x2;
 2811         y1 = y2;
 2812         x2 = tempx;
 2813         y2 = tempy;
 2814     }
 2815 
 2816     deltax = (x2 - x1);
 2817     if (deltax < 0) deltax = -deltax;
 2818     deltay = (y2 - y1);
 2819     if (deltay < 0) deltay = -deltay;
 2820 
 2821     if (deltax >= deltay) {
 2822         numpixels = deltax + 1;
 2823         d = (deltay*2) - deltax;
 2824         dinc1 = deltay << 1;
 2825         dinc2 = (deltay-deltax) << 1;
 2826         xinc1 = 1;
 2827         xinc2 = 1;
 2828         yinc1 = 0;
 2829         yinc2 = 1;
 2830     } else {
 2831         numpixels = deltay + 1;
 2832         d = (deltax*2) - deltay;
 2833         dinc1 = deltax << 1;
 2834         dinc2 = (deltax - deltay) << 1;
 2835         xinc1 = 0;
 2836         xinc2 = 1;
 2837         yinc1 = 1;
 2838         yinc2 = 1;
 2839     }
 2840 
 2841     if (x1 > x2) {
 2842         xinc1 = - xinc1;
 2843         xinc2 = - xinc2;
 2844     }
 2845     if (y1 > y2) {
 2846         yinc1 = - yinc1;
 2847         yinc2 = - yinc2;
 2848     }
 2849 
 2850     x = x1; y = y1;
 2851 
 2852     middlex = -1;
 2853     middley = -1;
 2854 
 2855 
 2856     /*
 2857     temps = SDL_CreateRGBSurface(SDL_SWSURFACE,10,10,
 2858         screen->format->BitsPerPixel, screen->format->Rmask,
 2859         screen->format->Gmask,screen->format->Bmask,
 2860         screen->format->Amask);
 2861     */
 2862     
 2863     temps = NULL;
 2864     o = -1;
 2865     oldo = -99;
 2866 
 2867     for (i = 0; i < numpixels; i++) {
 2868         o = objat(x,y);
 2869         if (o == -1) {
 2870             middlex = x;
 2871             middley = y;
 2872             break;
 2873         } else {
 2874             int ox,oy;
 2875             SDL_Color tempc;
 2876 
 2877             if (o != oldo) {
 2878                 if (oldo == -99) {
 2879                     SDL_Rect area;
 2880                     int tid;
 2881 
 2882                     temps = SDL_CreateRGBSurface(SDL_SWSURFACE,map[curmap].obj[o].w+3, map[curmap].obj[o].h+3,
 2883                         screen->format->BitsPerPixel, screen->format->Rmask,
 2884                         screen->format->Gmask,screen->format->Bmask,
 2885                         screen->format->Amask);
 2886                     area.x = map[curmap].obj[o].x;
 2887                     area.y = map[curmap].obj[o].y;
 2888                     area.w = map[curmap].obj[o].w;
 2889                     area.h = map[curmap].obj[o].h;
 2890 
 2891                     /* have we already drawn the object? */
 2892                     /* get thingid of this object */
 2893                     tid = -1;
 2894                     for (n = 0; n < map[curmap].numthings; n++) {
 2895                         if (    (map[curmap].thing[n].id == o) && 
 2896                             (map[curmap].thing[n].type == T_OBJECT) ) { 
 2897                             tid = n;
 2898                             break;  
 2899                         }
 2900                     }
 2901 
 2902                     /* FIXME: drawobject is too slow here!!! */
 2903                     /* but we can't just blit from the screen, in case
 2904                        the object hasn't been drawn yet */
 2905 
 2906 
 2907                     drawobject(temps, &map[curmap].obj[o], FALSE, TRUE);
 2908 
 2909 
 2910 /*
 2911                     if (tid == -1) {
 2912                         drawobject(temps, &map[curmap].obj[o], FALSE);
 2913                     } else if (thingdrawn[tid] == FALSE) {
 2914                         drawobject(temps, &map[curmap].obj[o], FALSE);
 2915                     } else {
 2916                         SDL_BlitSurface(screen, &area, temps, NULL);
 2917                     }
 2918 */
 2919                     oldo = o;
 2920                 } else {
 2921                     if (temps != NULL) {
 2922                         SDL_FreeSurface(temps);
 2923                         temps = NULL;
 2924                     }
 2925                     middlex = x;
 2926                     middley = y;
 2927                     break;
 2928                 }
 2929             }
 2930             /* we can start drawing if we're on the object but on a transparent bit */
 2931             ox = x - map[curmap].obj[o].x;
 2932             oy = y - map[curmap].obj[o].y;
 2933 
 2934             getcolor(temps, ox + arrowthickness - 1, oy + arrowthickness -1, &tempc);
 2935             if (    (tempc.r == map[curmap].bgcol.r) &&
 2936                 (tempc.g == map[curmap].bgcol.g) &&
 2937                 (tempc.b == map[curmap].bgcol.b)) { 
 2938                 /* free temporary surface */
 2939                 SDL_FreeSurface(temps);
 2940                 temps = NULL;
 2941 
 2942                 middlex = x;
 2943                 middley = y;
 2944                 break;
 2945             }
 2946         }
 2947 
 2948         if (d < 0) {
 2949             d += dinc1;
 2950             x += xinc1;
 2951             y += yinc1;
 2952         } else {
 2953             d += dinc2;
 2954             x += xinc2;
 2955             y += yinc2;
 2956         }
 2957     }
 2958 
 2959 
 2960     if (temps != NULL) {
 2961         SDL_FreeSurface(temps);
 2962         temps = NULL;
 2963     }
 2964     *adjx = middlex;
 2965     *adjy = middley;
 2966 }
 2967 
 2968 int dosearch(void) {
 2969     int i;
 2970     int m;
 2971     
 2972     /* fill in search text */
 2973     strcpy(searchtext, text);
 2974 
 2975     /* reset search point */
 2976     searchmap = 0;
 2977     searchtob = 0;
 2978     searchwrap = FALSE;
 2979 
 2980     /* go through each text object until we find what we're looking for */
 2981     for (m = 0; m < nummaps; m++) { /* for each map */
 2982         for (i = 0; i < map[m].numtext; i++) { /* for each text object */
 2983             /* does it contain the search string? */
 2984             if (strstr(map[m].textob[i].text, searchtext)) {
 2985                 drillto(m);
 2986 
 2987                 map[m].selecteditemtype = T_TEXT;
 2988                 map[m].selecteditem = i;
 2989 
 2990                 searchmap = m;
 2991                 searchtob = i;
 2992                 return FALSE;
 2993             }
 2994         }
 2995     }
 2996 
 2997     return TRUE;
 2998 }
 2999 
 3000 int dosearchnext(void) {
 3001     int i = -1;
 3002     int firsttime = TRUE;
 3003     int m;
 3004     int numtextfound = 0;
 3005     
 3006     /* go through each text object until we find what we're looking for */
 3007     for (m = searchmap; ; m++) { /* for each map */
 3008 
 3009 
 3010         if (m >= nummaps) { 
 3011             m = 0;
 3012             searchwrap = TRUE;
 3013         }
 3014 
 3015         if ((m == searchmap) && (numtextfound == 0) && (!firsttime)) {
 3016             /* no text objects exist */
 3017             return TRUE;
 3018         }
 3019 
 3020         if ((firsttime) && (m == searchmap)) {
 3021             i = searchtob+1;
 3022             firsttime = FALSE;
 3023         } else {
 3024             i = 0;
 3025         }
 3026 
 3027 
 3028 
 3029         for (; i < map[m].numtext; i++) { /* for each text object */
 3030 
 3031             /* back to start - not found */
 3032             if ((m == searchmap) && (i == searchtob)) {
 3033                 searchwrap = FALSE;
 3034                 return TRUE;
 3035             } 
 3036 
 3037             /* does it contain the search string? */
 3038             if (strstr(map[m].textob[i].text, searchtext)) {
 3039                 drillto(m);
 3040                 map[m].selecteditemtype = T_TEXT;
 3041                 map[m].selecteditem = i;
 3042 
 3043                 searchmap = m;
 3044                 searchtob = i;
 3045                 searchwrap = FALSE;
 3046                 return FALSE;
 3047             }
 3048         }
 3049         numtextfound += (map[m].numtext);
 3050 
 3051 
 3052     }
 3053 
 3054     return TRUE;
 3055 }
 3056 
 3057 
 3058 void drawarrowhead(SDL_Surface *screen, double x1, double y1, double x2, double y2, SDL_Color c, int arrowstyle, int arrowpos) {
 3059     double angle;
 3060     int arrowpointx,arrowpointy;
 3061     int arrowend1x,arrowend1y;
 3062     int arrowend2x,arrowend2y;
 3063     int middlex, middley;
 3064     int arrowlength = 5;
 3065     int arrowthickness;
 3066 
 3067     arrowthickness = (arrowstyle & 0x0000ff);
 3068 
 3069     /* calculate arrow length based on line length 
 3070        line length > 40 means arrow length is 5,
 3071        otherwise it's 3 */
 3072     //if (numpixels > 40) {
 3073     //  arrowlength = 5;
 3074     //} else {
 3075     arrowlength = 3;
 3076     //}
 3077     /* adjust for line thickness */
 3078     arrowlength = arrowlength + arrowthickness - 1;
 3079 
 3080     /* calculate angle of line */
 3081     angle = atan2(y2-y1,x2-x1);
 3082 
 3083     if (arrowpos == AP_START) {
 3084         middlex = x1;
 3085         middley = y1;
 3086     } else {
 3087         middlex = x2;
 3088         middley = y2;
 3089     }
 3090 
 3091     if (arrowpos == AP_END) {
 3092         angle += M_PI;
 3093         //if (angle > 360) angle -= 360;
 3094     } 
 3095     angle = -angle;
 3096 
 3097     /* original arrowhead is:
 3098      *
 3099      *          / (5,-5)
 3100      *         /
 3101      *  (0,0) <
 3102      *         \
 3103      *          \ (5,5)
 3104      */
 3105 
 3106     /* rotate arrowhead */
 3107     arrowpointx = 0;
 3108     arrowpointy = 0;
 3109     arrowend1x = (arrowlength * cos(angle)) + (-arrowlength * sin(angle));
 3110     arrowend1y = (-arrowlength * sin(angle)) + (-arrowlength * cos(angle));
 3111     arrowend2x = (arrowlength * cos(angle)) + (arrowlength * sin(angle));
 3112     arrowend2y = (-arrowlength * sin(angle)) + (arrowlength * cos(angle));
 3113 
 3114 
 3115     /* translate arrowhead into position */
 3116     arrowpointx = middlex;
 3117     arrowpointy = middley;
 3118     arrowend1x += middlex;
 3119     arrowend1y += middley;
 3120     arrowend2x += middlex;
 3121     arrowend2y += middley;
 3122 
 3123     /* get rid of the 'linestyle' and 'arrow' parts of arrowstyle to 
 3124      * (respectively) make sure the arrow looks okay and 
 3125      * avoid an infinite loop! */
 3126     arrowstyle &= 0x0000ff;
 3127     
 3128     drawline(screen, arrowpointx, arrowpointy, arrowend1x, arrowend1y, c, arrowstyle);
 3129     drawline(screen, arrowpointx, arrowpointy, arrowend2x, arrowend2y, c, arrowstyle);
 3130 }
 3131 
 3132 void drawarrowheadSVG(double x1, double y1, double x2, double y2, SDL_Color c, int arrowstyle, int arrowpos) {
 3133     double angle;
 3134     int arrowpointx,arrowpointy;
 3135     int arrowend1x,arrowend1y;
 3136     int arrowend2x,arrowend2y;
 3137     int middlex, middley;
 3138     int arrowlength = 5;
 3139     int arrowthickness;
 3140 
 3141     arrowthickness = (arrowstyle & 0x0000ff);
 3142 
 3143 
 3144     //if (numpixels > 40) {
 3145     //  arrowlength = 5;
 3146     //} else {
 3147     arrowlength = 3;
 3148     //}
 3149     /* adjust for line thickness */
 3150     arrowlength = arrowlength + arrowthickness - 1;
 3151 
 3152     /* calculate angle of line */
 3153     angle = atan2(y2-y1,x2-x1);
 3154 
 3155     if (arrowpos == AP_START) {
 3156         middlex = x1;
 3157         middley = y1;
 3158     } else {
 3159         middlex = x2;
 3160         middley = y2;
 3161     }
 3162 
 3163 
 3164     if (arrowpos == AP_END) {
 3165         angle += M_PI;
 3166         //if (angle > 360) angle -= 360;
 3167     } 
 3168     angle = -angle;
 3169 
 3170     /* original arrowhead is:
 3171      *
 3172      *          / (5,-5)
 3173      *         /
 3174      *  (0,0) <
 3175      *         \
 3176      *          \ (5,5)
 3177      */
 3178 
 3179     /* rotate arrowhead */
 3180     arrowpointx = 0;
 3181     arrowpointy = 0;
 3182     arrowend1x = (arrowlength * cos(angle)) + (-arrowlength * sin(angle));
 3183     arrowend1y = (-arrowlength * sin(angle)) + (-arrowlength * cos(angle));
 3184     arrowend2x = (arrowlength * cos(angle)) + (arrowlength * sin(angle));
 3185     arrowend2y = (-arrowlength * sin(angle)) + (arrowlength * cos(angle));
 3186 
 3187 
 3188     /* translate arrowhead into position */
 3189     arrowpointx = middlex;
 3190     arrowpointy = middley;
 3191     arrowend1x += middlex;
 3192     arrowend1y += middley;
 3193     arrowend2x += middlex;
 3194     arrowend2y += middley;
 3195 
 3196     /* get rid of the 'linestyle' and 'arrow' parts of arrowstyle to 
 3197      * (respectively) make sure the arrow looks okay and 
 3198      * avoid an infinite loop! */
 3199     arrowstyle &= 0x000000ff;
 3200     
 3201     sprintf(svgbuf,"<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" style=\"stroke:rgb(%d,%d,%d);stroke-width:%d; \"/>\n", arrowpointx, arrowpointy, arrowend1x, arrowend1y,c.r,c.g,c.b, arrowstyle );
 3202     fprintf(svgfile, svgbuf);
 3203     sprintf(svgbuf,"<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" style=\"stroke:rgb(%d,%d,%d);stroke-width:%d; \"/>\n", arrowpointx, arrowpointy, arrowend2x, arrowend2y,c.r,c.g,c.b, arrowstyle );
 3204     fprintf(svgfile, svgbuf);
 3205 }
 3206 
 3207 void lerp(int *newx, int *newy, int ax, int ay, int bx, int by, float t) {
 3208     *newx = ax + (bx - ax) * t;
 3209     *newy = ay + (by - ay) * t;
 3210 }
 3211 
 3212 void drawbezier(SDL_Surface *screen, int x1, int y1,
 3213         int x2,int y2,
 3214         int x3,int y3,
 3215         int x4,int y4,
 3216         SDL_Color c) {
 3217     int i;
 3218     float t;
 3219     int abx,aby,bcx,bcy,cdx,cdy;
 3220     int abbcx,abbcy,bccdx,bccdy;
 3221     int newx,newy;
 3222     int oldx,oldy;
 3223 
 3224     oldx = x1;
 3225     oldy = y1;
 3226 
 3227     for (i = 0; i < BEZIERQUALITY; i++) {
 3228         t = (float)i / (float)(BEZIERQUALITY - 1);
 3229 
 3230         lerp(&abx,&aby, x1, y1, x2, y2, t);
 3231         lerp(&bcx,&bcy, x2, y2, x3, y3, t);
 3232         lerp(&cdx,&cdy, x3, y3, x4, y4, t);
 3233         lerp(&abbcx,&abbcy, abx, aby, bcx, bcy, t);
 3234         lerp(&bccdx,&bccdy, bcx, bcy, cdx, cdy, t);
 3235         lerp(&newx,&newy, abbcx, abbcy, bccdx, bccdy, t);
 3236 
 3237         drawline(screen, oldx, oldy, newx, newy, c, 1);
 3238         oldx = newx;
 3239         oldy = newy;
 3240     }
 3241  
 3242 }
 3243         
 3244 
 3245 void drawbox(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c, SDL_Color *fc) {
 3246     if (fc != NULL) {
 3247         if (fc->unused & USECOLOUR) {
 3248             /* fill */
 3249             if (((x2 - x1) >= 2) && ((y2 - y1) >= 2)) {
 3250                 int y;
 3251                 for (y = (y1+1) ; y <= (y2-1); y++) {
 3252                     drawline(screen, x1+1, y, x2-1,y,*fc,1);
 3253                 }
 3254             }
 3255         } 
 3256     }
 3257     drawline(screen,x1,y1,x2,y1,c,1);
 3258     drawline(screen,x1,y1,x1,y2,c,1);
 3259     drawline(screen,x1,y2,x2,y2,c,1);
 3260     drawline(screen,x2,y1,x2,y2,c,1);
 3261 }
 3262 
 3263 void drawellipsepoints(SDL_Surface *screen, int x1, int y1, int x, int y, SDL_Color c) {
 3264     drawpixel(screen, x1 + x, y1 + y, c);
 3265     drawpixel(screen, x1 - x, y1 + y, c);
 3266     drawpixel(screen, x1 - x, y1 - y, c);
 3267     drawpixel(screen, x1 + x, y1 - y, c);
 3268 }
 3269 
 3270 void drawellipse(SDL_Surface *screen, int x1, int y1, int xr, int yr, SDL_Color c) {
 3271     double x,y;
 3272     double xc,yc;
 3273     double ee;
 3274     double twoas, twobs;
 3275     double stoppingx,stoppingy;
 3276 
 3277     twoas = 2 * xr * xr;
 3278     twobs = 2 * yr * yr;
 3279 
 3280     /* first set */
 3281     x = xr;
 3282     y = 0;
 3283     xc = yr * yr * (1 - 2*xr);
 3284     yc = xr * xr;
 3285     ee = 0;
 3286     stoppingx = twobs * xr;
 3287     stoppingy = 0;
 3288     while (stoppingx >= stoppingy) {
 3289         drawellipsepoints(screen, x1, y1, x,y, c);
 3290         y++;
 3291         stoppingy += twoas;
 3292         ee += yc;
 3293         yc += twoas;
 3294         if ((2*ee + xc) > 0) {
 3295             x--;
 3296             stoppingx -= twobs;
 3297             ee += xc;
 3298             xc += twobs;
 3299         }
 3300     }
 3301 
 3302 
 3303     /* second set */
 3304     x = 0;
 3305     y = yr;
 3306     xc = yr * yr;
 3307     yc = xr * xr * (1 - 2*yr);
 3308     ee = 0;
 3309     stoppingx = 0;
 3310     stoppingy = twoas * yr;
 3311     while (stoppingx <= stoppingy) {
 3312         drawellipsepoints(screen, x1, y1, x,y, c);
 3313         x++;
 3314         stoppingx += twobs;
 3315         ee += xc;
 3316         xc += twobs;
 3317         if ((2*ee + yc) > 0) {
 3318             y--;
 3319             stoppingy -= twoas;
 3320             ee += yc;
 3321             yc += twoas;
 3322         }
 3323     }
 3324 
 3325 }
 3326 
 3327 void drawflowbox(SDL_Surface *dest, int oid, int otype) {
 3328     int x1,y1,x2,y2;
 3329     int i;
 3330     int ls = 10;
 3331 
 3332     switch (otype) {
 3333         case T_OBJECT:
 3334             x1 = map[curmap].obj[oid].x;
 3335             y1 = map[curmap].obj[oid].y;
 3336             x2 = map[curmap].obj[oid].x + map[curmap].obj[oid].w;
 3337             y2 = map[curmap].obj[oid].y + map[curmap].obj[oid].h;
 3338             drawbox(dest, x1, y1, x2, y2, blue, NULL);
 3339             break;
 3340         case T_LINK:
 3341             x1 = map[curmap].obj[map[curmap].olink[oid].srcobj].x + map[curmap].olink[oid].srcxoff;
 3342             y1 = map[curmap].obj[map[curmap].olink[oid].srcobj].y + map[curmap].olink[oid].srcyoff;
 3343             x2 = map[curmap].obj[map[curmap].olink[oid].dstobj].x + map[curmap].olink[oid].dstxoff;
 3344             y2 = map[curmap].obj[map[curmap].olink[oid].dstobj].y + map[curmap].olink[oid].dstyoff;
 3345             drawbox(dest, x1-ls, y1-ls, x1+ls, y1+ls, blue, &blue);
 3346             drawbox(dest, x2-ls, y2-ls, x2+ls, y2+ls, blue, &blue);
 3347             for (i = 0; i < map[curmap].olink[oid].npoints; i++) {
 3348                 x1 = map[curmap].olink[oid].point[i].x;
 3349                 y1 = map[curmap].olink[oid].point[i].y;
 3350                 drawbox(dest, x1-ls, y1-ls, x1+ls, y1+ls, blue, &blue);
 3351             }
 3352             break;
 3353         case T_TEXT:
 3354             if (map[curmap].textob[oid].anchor == -1) {
 3355                 x1 = map[curmap].textob[oid].x;
 3356                 y1 = map[curmap].textob[oid].y;
 3357             } else {
 3358                 x1 = map[curmap].textob[oid].x + map[curmap].obj[map[curmap].textob[oid].anchor].x;
 3359                 y1 = map[curmap].textob[oid].y + map[curmap].obj[map[curmap].textob[oid].anchor].y;
 3360             }
 3361             x2 = x1 + map[curmap].textob[oid].w;
 3362             y2 = y1 + map[curmap].textob[oid].h;
 3363             drawbox(dest, x1, y1, x2, y2, blue, NULL);
 3364             break;
 3365         default:
 3366             return;
 3367     }
 3368 }
 3369 
 3370 void drawcolorchart(SDL_Surface *dest) {
 3371     int x,y;
 3372     //int i;
 3373     SDL_Color c;
 3374     int speed;
 3375     int finished = FALSE;
 3376     int size = 18;
 3377 
 3378 
 3379     int mode = 1;
 3380 
 3381     c.r = 0;
 3382     c.g = 0;
 3383     c.b = 0;
 3384     c.unused = USECOLOUR;
 3385 
 3386     speed = 24 ;
 3387 
 3388     for (y = 0; (y < (map[curmap].height-size)) && (!finished); y+= size) {
 3389         for (x = 0; (x < (map[curmap].width-size)) && (!finished); x+= size) {
 3390             drawbox(dest,x,y,x+(size-1),y+(size-1),black, &c);
 3391             /* fill box */
 3392             /*for (i = 1; i <= (size-2); i++) {
 3393                 drawline(dest, x+1, y+i, x+(size-2), y+i, c,1);
 3394             }*/
 3395             /* change color */
 3396 
 3397             if (mode == 1) {
 3398                 if (c.b + speed > 255) {
 3399                     c.b = 0;
 3400                     if (c.g + speed > 255) {
 3401                         c.g = 0;
 3402                         if (c.r + speed > 255) {
 3403                             c.r = 255 - speed;
 3404                             c.g = 255 - speed;
 3405                             c.b = 255 - speed;
 3406                             mode = 2;
 3407                         } else c.r += speed;
 3408                     } else c.g += speed;
 3409                 } else c.b += speed;
 3410             } else {
 3411                 if (c.r-speed <= 0) finished = TRUE;
 3412                 if (c.g-speed <= 0) finished = TRUE;
 3413                 if (c.b-speed <= 0) finished = TRUE;
 3414                 c.r -= speed;
 3415                 c.g -= speed;
 3416                 c.b -= speed;
 3417             }
 3418 
 3419             if (c.r >= 240)  c.r = 255;
 3420             if (c.g >= 240)  c.g = 255;
 3421             if (c.b >= 240)  c.b = 255;
 3422         }
 3423     }
 3424     SDL_Flip(screen);
 3425 }
 3426 
 3427 int findpointpos(link_t *l, int px, int py) {
 3428     int i;
 3429     int x,y,x2,y2;
 3430     int pos = 0;
 3431 
 3432     x = map[curmap].obj[l->srcobj].x + l->srcxoff;
 3433     y = map[curmap].obj[l->srcobj].y + l->srcyoff;
 3434 
 3435     for (i = 0; i < l->npoints; i++) {
 3436         x2 = l->point[i].x;
 3437         y2 = l->point[i].y;
 3438         
 3439         if (isonline(px, py, x, y, x2, y2)) {
 3440             return pos;
 3441         }
 3442         pos++;
 3443 
 3444         x = x2;
 3445         y = y2;
 3446     }
 3447 
 3448     /* draw line to final map[curmap].object */ 
 3449     x2 = map[curmap].obj[l->dstobj].x + l->dstxoff;
 3450     y2 = map[curmap].obj[l->dstobj].y + l->dstyoff;
 3451 
 3452     return pos;
 3453 }
 3454 
 3455 void drawline(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c, int linestyle) {
 3456     int deltax, deltay;
 3457     int numpixels;
 3458     int d;
 3459     int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
 3460     int i;
 3461     int x;
 3462     int y;
 3463     int xx,yy;
 3464     int maskcount = 0;
 3465     int maskindex = 0;
 3466     Uint8 arrow,style, thickness;
 3467 
 3468     arrow =     (linestyle & (0x00ff0000)) >> 16;
 3469     style =     (linestyle & (0x0000ff00)) >> 8;
 3470     thickness = (linestyle & (0x000000ff));
 3471 
 3472 
 3473     deltax = (x2 - x1);
 3474     if (deltax < 0) deltax = -deltax;
 3475     deltay = (y2 - y1);
 3476     if (deltay < 0) deltay = -deltay;
 3477 
 3478     if (deltax >= deltay) {
 3479         numpixels = deltax + 1;
 3480         d = (deltay*2) - deltax;
 3481         dinc1 = deltay << 1;
 3482         dinc2 = (deltay-deltax) << 1;
 3483         xinc1 = 1;
 3484         xinc2 = 1;
 3485         yinc1 = 0;
 3486         yinc2 = 1;
 3487     } else {
 3488         numpixels = deltay + 1;
 3489         d = (deltax*2) - deltay;
 3490         dinc1 = deltax << 1;
 3491         dinc2 = (deltax - deltay) << 1;
 3492         xinc1 = 0;
 3493         xinc2 = 1;
 3494         yinc1 = 1;
 3495         yinc2 = 1;
 3496     }
 3497 
 3498     if (x1 > x2) {
 3499         xinc1 = - xinc1;
 3500         xinc2 = - xinc2;
 3501     }
 3502     if (y1 > y2) {
 3503         yinc1 = - yinc1;
 3504         yinc2 = - yinc2;
 3505     }
 3506 
 3507     x = x1; y = y1;
 3508 
 3509     maskcount = 0;
 3510     maskindex = 0;
 3511     for (i = 0; i < numpixels; i++) {
 3512 
 3513         if (linemask[style][maskindex] == 1) {
 3514             /* plot point */
 3515             for (yy = 0; yy < thickness ; yy++) {
 3516                 for (xx = 0; xx < thickness ; xx++) {
 3517                     drawpixel(screen,x+xx,y+yy,c);
 3518                 }
 3519             }
 3520         }
 3521 
 3522         /* increment mask count */
 3523         if (++maskcount >= thickness) {
 3524             maskcount = 0;
 3525             /* increment mask index */
 3526             maskindex++;
 3527             if (maskindex >= LINESTYLESIZE) {
 3528                 maskindex = 0;
 3529             }
 3530             if (linemask[style][maskindex] == -1) maskindex = 0;
 3531         }
 3532         
 3533 
 3534         if (d < 0) {
 3535             d += dinc1;
 3536             x += xinc1;
 3537             y += yinc1;
 3538         } else {
 3539             d += dinc2;
 3540             x += xinc2;
 3541             y += yinc2;
 3542         }
 3543     }
 3544 
 3545     /* draw arrowheads if required */
 3546     if (arrow) {
 3547         if ((arrow == AP_START) || (arrow == AP_END)) {
 3548             drawarrowhead(screen, x1, y1, x2, y2, c, linestyle, arrow);
 3549         } else if (arrow == AP_BOTH) {
 3550             drawarrowhead(screen, x1, y1, x2, y2, c, linestyle, AP_START);
 3551             drawarrowhead(screen, x1, y1, x2, y2, c, linestyle, AP_END);
 3552         }
 3553     }
 3554 }
 3555 
 3556 
 3557 void drawlink(SDL_Surface *dest, link_t *l) {
 3558     int i;
 3559     int x,y,x2,y2;
 3560     int arrow;
 3561     int adjx,adjy;
 3562     int flow;
 3563 
 3564     flow = l->col.unused & ISFLOW;
 3565 
 3566     x = map[curmap].obj[l->srcobj].x + l->srcxoff - screenx;
 3567     y = map[curmap].obj[l->srcobj].y + l->srcyoff - screeny;
 3568     arrow = (l->style & 0x00ff0000) >> 16;
 3569 
 3570     for (i = 0; i < l->npoints; i++) {
 3571         x2 = l->point[i].x - screenx;
 3572         y2 = l->point[i].y - screeny;
 3573 
 3574         /* if this is the first point and the line is of 
 3575            type "arrowhead at start" then draw an arrow */
 3576     
 3577         if (  (i == 0) &&
 3578               ((arrow == AP_START) || (arrow == AP_BOTH))
 3579            ) {
 3580             int tempstyle;
 3581             tempstyle = l->style & (0xff00ffff);
 3582             tempstyle |= (AP_START << 16);
 3583         
 3584             /* adjust start point */
 3585             if (flow) {
 3586                 adjx = x;
 3587                 adjy = y;
 3588             } else {
 3589                 adjustendpoint(dest, &adjx, &adjy, x,y,x2,y2,l->style, AP_START);
 3590             }
 3591             drawline(dest, adjx,adjy,x2,y2, l->col,tempstyle);
 3592         } else {
 3593             /* clear the "arrowhead" part of these */
 3594             adjx = x;
 3595             adjy = y;
 3596             drawline(dest, adjx,adjy,x2,y2, l->col,l->style & 0xff00ffff);
 3597         }
 3598 
 3599         x = x2;
 3600         y = y2;
 3601     }
 3602 
 3603     /* draw line to final map[curmap].object */ 
 3604     x2 = map[curmap].obj[l->dstobj].x + l->dstxoff - screenx;
 3605     y2 = map[curmap].obj[l->dstobj].y + l->dstyoff - screeny;
 3606 
 3607     /* adjust end */
 3608     if (l->npoints >= 1) {
 3609         if ( (arrow == AP_END) || (arrow == AP_BOTH)) {
 3610             int tempstyle;
 3611             tempstyle = l->style & (0xff00ffff);
 3612             tempstyle |= (AP_END << 16);
 3613 
 3614             if (!flow) {
 3615                 adjustendpoint(dest, &adjx, &adjy, x,y,x2,y2,l->style & 0xff00ffff, AP_END);
 3616                 x2 = adjx ; y2 = adjy;
 3617             }
 3618         
 3619             drawline(dest, x,y,x2,y2, l->col,tempstyle);
 3620         } else {
 3621             /* clear the "arrowhead" part of these */
 3622             drawline(dest, x,y,x2,y2, l->col,l->style & 0xff00ffff);
 3623         }
 3624     } else {
 3625         /* adjust start */
 3626         if (!flow) {
 3627                 if ((arrow == AP_START) || (arrow == AP_BOTH)) {
 3628                 adjustendpoint(dest, &adjx, &adjy, x,y,x2,y2,l->style & 0xff00ffff, AP_START);
 3629                 x = adjx ; y = adjy;
 3630             }
 3631         }
 3632         /* adjust end */
 3633         if (!flow) {
 3634                 if ((arrow == AP_END) || (arrow == AP_BOTH)) {
 3635                 adjustendpoint(dest, &adjx, &adjy, x,y,x2,y2,l->style & 0xff00ffff, AP_END);
 3636                 x2 = adjx ; y2 = adjy;
 3637             }
 3638         }
 3639         drawline(dest, x,y,x2,y2, l->col,l->style);
 3640     }
 3641 }
 3642 
 3643 void drawlinkSVG(link_t *l) {
 3644     int i;
 3645     int x,y,x2,y2;
 3646     int width;
 3647     char temp[BUFLEN];
 3648     char dasharray[BUFLEN];
 3649     int linestyle;
 3650     int cur,old;
 3651     int count;
 3652     int first;
 3653     int arrow;
 3654     int adjx,adjy;
 3655     int flow;
 3656 
 3657     x = map[curmap].obj[l->srcobj].x + l->srcxoff;
 3658     y = map[curmap].obj[l->srcobj].y + l->srcyoff;
 3659 
 3660     flow = l->col.unused & ISFLOW;
 3661 
 3662     /* get attributes */
 3663     width     = l->style & 0x000000ff;
 3664     linestyle = (l->style & 0x0000ff00) >> 8;
 3665     arrow     = (l->style & 0x00ff0000) >> 16;
 3666 
 3667     old = linemask[linestyle][0];
 3668     count = 1;
 3669     first = 1;
 3670 
 3671     sprintf(dasharray, "stroke-dasharray:");
 3672     for (i = 0; linemask[linestyle][i] != -1; i++) {
 3673         cur = linemask[linestyle][i];
 3674         //sprintf(temp, "[%d]", cur);
 3675         //strcat(dasharray, temp);
 3676         if (cur == old) {
 3677             count++;
 3678         } else {
 3679             if (first) {
 3680                 sprintf(temp, "%d", count*width);
 3681                 first = 0;
 3682             } else {
 3683                 sprintf(temp, ",%d", count*width);
 3684             }
 3685             count = 1;
 3686             strcat(dasharray, temp);
 3687             old = cur;
 3688         }
 3689     }
 3690 
 3691     if (first == 1) {
 3692         /* don't need dash-array */
 3693         strcpy(dasharray, "");
 3694     } else {
 3695         sprintf(temp, ",%d", count*width);
 3696         strcat(dasharray, temp);
 3697     }
 3698 
 3699 
 3700     for (i = 0; i < l->npoints; i++) {
 3701         x2 = l->point[i].x;
 3702         y2 = l->point[i].y;
 3703 
 3704         
 3705         sprintf(svgbuf,"<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" style=\"stroke:rgb(%d,%d,%d);stroke-width:%d; %s;\"/>\n", x, y, x2, y2,l->col.r,l->col.g,l->col.b, width ,dasharray);
 3706         fprintf(svgfile, svgbuf);
 3707 
 3708         /* draw arrowhead if required */
 3709         if (  (i == 0) &&
 3710               ((arrow == AP_START) || (arrow == AP_BOTH))
 3711            ) {
 3712             int tempstyle;
 3713             tempstyle = l->style & (0xff00ffff);
 3714             tempstyle |= (AP_START << 16);
 3715 
 3716             if (flow) {
 3717                 adjx = x;
 3718                 adjy = y;
 3719             } else {
 3720                 adjustendpoint(screen, &adjx, &adjy, x,y,x2,y2,l->style, AP_START);
 3721             }
 3722         
 3723             drawarrowheadSVG(adjx,adjy,x2,y2, l->col,tempstyle, arrow);
 3724         } 
 3725 
 3726         x = x2;
 3727         y = y2;
 3728     }
 3729 
 3730     /* draw line to final map[curmap].object */ 
 3731     x2 = map[curmap].obj[l->dstobj].x + l->dstxoff;
 3732     y2 = map[curmap].obj[l->dstobj].y + l->dstyoff;
 3733 
 3734     /* draw arrow if required */
 3735     if (l->npoints >= 1) {
 3736         if ( (arrow == AP_END) || (arrow == AP_BOTH)) {
 3737             int tempstyle;
 3738             tempstyle = l->style & (0xff00ffff);
 3739             tempstyle |= (AP_END << 16);
 3740         
 3741             if (!flow) {
 3742                 adjustendpoint(screen, &adjx, &adjy, x,y,x2,y2,l->style, AP_END);
 3743                 x2 = adjx;
 3744                 y2 = adjy;
 3745             }
 3746             drawarrowheadSVG(x,y,x2,y2, l->col,tempstyle, AP_END);
 3747         }
 3748     } else {
 3749         /* adjust start point too */
 3750 
 3751         if ( (arrow == AP_START) || (arrow == AP_BOTH)) {
 3752             int tempstyle;
 3753             tempstyle = l->style & (0xff00ffff);
 3754             tempstyle |= (AP_START << 16);
 3755 
 3756             if (!flow) {
 3757                 adjustendpoint(screen, &adjx, &adjy, x,y,x2,y2,l->style, AP_START);
 3758                 x = adjx;
 3759                 y = adjy;
 3760             }
 3761 
 3762             drawarrowheadSVG(x,y,x2,y2, l->col,tempstyle, AP_START);
 3763         }
 3764         if ( (arrow == AP_END) || (arrow == AP_BOTH)) {
 3765             int tempstyle;
 3766             tempstyle = l->style & (0xff00ffff);
 3767             tempstyle |= (AP_END << 16);
 3768 
 3769             if (!flow) {
 3770                 adjustendpoint(screen, &adjx, &adjy, x,y,x2,y2,l->style, AP_END);
 3771                 x2 = adjx;
 3772                 y2 = adjy;
 3773             }
 3774 
 3775             drawarrowheadSVG(x,y,x2,y2, l->col,tempstyle, AP_END);
 3776         }
 3777     }
 3778 
 3779 
 3780 
 3781     sprintf(svgbuf,"<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" style=\"stroke:rgb(%d,%d,%d);stroke-width:%d; %s;\"/>\n", x, y, x2, y2,l->col.r,l->col.g,l->col.b, width ,dasharray);
 3782     fprintf(svgfile, svgbuf);
 3783 }
 3784 
 3785 
 3786 void drawobject(SDL_Surface *dest, mapobject_t *o, int doublebuffer, int adjust) {
 3787     SDL_Surface *temps;
 3788     SDL_Rect area;
 3789     Uint32 bgcol;
 3790     int testing = 0;
 3791 
 3792     /* create temp surface */
 3793     if (testing) {
 3794         printf("About to create surface...");
 3795         fflush(STDOUT);
 3796     }
 3797     if (doublebuffer) {
 3798         temps = SDL_CreateRGBSurface(SDL_SWSURFACE,o->w+3, o->h+3,
 3799             screen->format->BitsPerPixel, screen->format->Rmask,
 3800             screen->format->Gmask,screen->format->Bmask,
 3801             screen->format->Amask);
 3802     } else {
 3803         temps = dest;
 3804     }
 3805 
 3806     bgcol = SDL_MapRGB(temps->format, map[curmap].bgcol.r,map[curmap].bgcol.g,map[curmap].bgcol.b);
 3807     SDL_FillRect(temps, NULL, bgcol);
 3808 
 3809     /* draw onto temp surface */
 3810     if (testing) {
 3811         printf("About to drawvector ...");
 3812         fflush(STDOUT);
 3813     }
 3814     if (o->fillcol.unused & USECOLOUR) {
 3815         drawvector(temps, &objtype[o->type].vimg, 0, 0, o->w, o->h, NULL, &o->fillcol);
 3816     } else {
 3817         drawvector(temps, &objtype[o->type].vimg, 0, 0, o->w, o->h, NULL, NULL);
 3818     }
 3819 
 3820     /* set transparent colour on temp surface */
 3821     if (testing) {
 3822         printf("About to setcolour ...");
 3823         fflush(STDOUT);
 3824     }
 3825     SDL_SetColorKey(temps, SDL_SRCCOLORKEY|SDL_RLEACCEL, bgcol);
 3826 
 3827     /* blit to screen */
 3828     if (doublebuffer) {
 3829         area.x = o->x;
 3830         area.y = o->y;
 3831         if (adjust) {
 3832             area.x -= screenx;
 3833             area.y -= screeny;
 3834         }
 3835         area.w = o->w;
 3836         area.h = o->h;
 3837         if (testing) {
 3838             printf("About to blitsurface ...");
 3839             fflush(STDOUT);
 3840         }
 3841         SDL_BlitSurface(temps, 0, dest, &area);
 3842         SDL_FreeSurface(temps);
 3843         temps = NULL;
 3844     } else {
 3845         SDL_UpdateRect(temps, 0, 0, o->w, o->h);
 3846     }
 3847 
 3848     if (testing) {
 3849         printf("About to return ...");
 3850         fflush(STDOUT);
 3851     }
 3852 
 3853 }
 3854 
 3855 void drawobjectSVG(SDL_Surface *dest, mapobject_t *o, int doublebuffer) {
 3856     static int gnum = 0;
 3857 
 3858     /* create SVG group */
 3859     sprintf(svgbuf, "<g id=\"object%d\" >\n", gnum);
 3860     fprintf(svgfile, svgbuf);
 3861 
 3862     if (o->fillcol.unused & USECOLOUR) {
 3863         drawvectorSVG(&objtype[o->type].vimg, o->x, o->y, o->w, o->h, NULL, &o->fillcol);
 3864     } else {
 3865         drawvectorSVG(&objtype[o->type].vimg, o->x, o->y, o->w, o->h, NULL, NULL);
 3866     }
 3867 
 3868     sprintf(svgbuf, "</g>\n");
 3869     fprintf(svgfile, svgbuf);
 3870     gnum++;
 3871 
 3872 }
 3873 
 3874 void drawpixel(SDL_Surface *screen, int x, int y, SDL_Color c) {
 3875     Uint32 color = SDL_MapRGB(screen->format, c.r, c.g, c.b);
 3876 
 3877     if ((x < 0) || (y < 0) || (x >= screen->w) || (y >= screen->h)) {
 3878     return;
 3879     }
 3880 
 3881     /*if ( SDL_MUSTLOCK(screen) ) {
 3882         if ( SDL_LockSurface(screen) < 0 ) {
 3883             return;
 3884         }
 3885     }*/
 3886     switch (screen->format->BytesPerPixel) {
 3887         case 1: { /* Assuming 8-bpp */
 3888             Uint8 *bufp;
 3889 
 3890             bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
 3891             *bufp = color;
 3892         }
 3893         break;
 3894 
 3895         case 2: { /* Probably 15-bpp or 16-bpp */
 3896             Uint16 *bufp;
 3897 
 3898             bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
 3899             *bufp = color;
 3900         }
 3901         break;
 3902 
 3903         case 3: { /* Slow 24-bpp mode, usually not used */
 3904             Uint8 *bufp;
 3905 
 3906             bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
 3907             if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {
 3908                 bufp[0] = color;
 3909                 bufp[1] = color >> 8;
 3910                 bufp[2] = color >> 16;
 3911             } else {
 3912                 bufp[2] = color;
 3913                 bufp[1] = color >> 8;
 3914                 bufp[0] = color >> 16;
 3915             }
 3916         }
 3917         break;
 3918 
 3919         case 4: { /* Probably 32-bpp */
 3920             Uint32 *bufp;
 3921 
 3922             bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
 3923             *bufp = color;
 3924         }
 3925         break;
 3926     }
 3927     /*
 3928     if ( SDL_MUSTLOCK(screen) ) {
 3929         SDL_UnlockSurface(screen);
 3930     }
 3931     */
 3932     //SDL_UpdateRect(screen, x, y, 1, 1);
 3933 }
 3934 
 3935 void drawmap(int wantdecs) {
 3936     int i;
 3937     int testing = 0;
 3938     SDL_Rect area;
 3939     Uint32 fillcol;
 3940     int txoff,tyoff;
 3941     int anchoreditem;
 3942     int x,y;
 3943 
 3944     for (i = 0; i < map[curmap].numthings; i++) {
 3945         thingdrawn[i] = FALSE;
 3946     }
 3947 
 3948     if ((state == S_SAVING) || (state == S_LOADING) || (state == S_MAPNAMING) || (state == S_SEARCH)) {
 3949         /* show text entry screen */
 3950         showfiledialog();
 3951         return;
 3952     }
 3953 
 3954     if ((state == S_FGCOL) || (state == S_FILLCOL)) {
 3955         drawcolorchart(screen);
 3956         return;
 3957     }
 3958 
 3959     if (state == S_CREATETELE) {
 3960         drawmaplist(screen);
 3961         return;
 3962     }
 3963 
 3964     if (state == S_REALLYQUIT) {
 3965         drawyn(text);
 3966         return;
 3967     }
 3968 
 3969     if (testing) {
 3970         printf("START DRAWMAP\n"); fflush(STDOUT);
 3971     }
 3972 
 3973     /* clear map */
 3974     fillcol = SDL_MapRGB(buffer->format, map[curmap].bgcol.r,map[curmap].bgcol.g,map[curmap].bgcol.b);
 3975     SDL_FillRect(buffer, NULL, fillcol);
 3976 
 3977     /* draw grid */
 3978     if (gridsize != 0) {
 3979         for (x = 0; x < screen->w - SIDEBARW; x += (gridsize*2)) {
 3980             drawline(buffer,x,0,x,(screen->h - STATUSH), gridcol, (LS_BIGDASH << 8) | 1);
 3981             if ((x+gridsize) < screen->w - SIDEBARW) {
 3982                 drawline(buffer,x+gridsize,0,x+gridsize,(screen->h - DEFTEXTH-2), gridcol, (LS_DOTTED << 8) | 1);
 3983             }
 3984         }
 3985 
 3986         for (y = 0; y < screen->h - STATUSH; y += (gridsize*2)) {
 3987             drawline(buffer,0,y,screen->w - SIDEBARW, y,gridcol, (LS_BIGDASH << 8) | 1);
 3988             if ((y+gridsize) < (screen->h - STATUSH)) {
 3989                 drawline(buffer,0,y+gridsize,screen->w - SIDEBARW, y+gridsize,gridcol, (LS_DOTTED << 8) | 1);
 3990             }
 3991         }
 3992     }
 3993 
 3994     if (testing) {
 3995         printf("DRAWING THINGS \n"); fflush(STDOUT);
 3996     }
 3997 
 3998 
 3999     /* draw all map[curmap].objects links  etc*/
 4000     for (i = 0; i < map[curmap].numthings; i++) {
 4001         if (map[curmap].thing[i].type == T_OBJECT) {
 4002             if (testing) { printf("Drawing thing #%d (%d, %s)\n",i,map[curmap].thing[i].id,objtype[map[curmap].obj[map[curmap].thing[i].id].type].name); fflush(STDOUT); } 
 4003             if (!isflow(map[curmap].thing[i].id, T_OBJECT)) {
 4004                 drawobject(buffer, &map[curmap].obj[map[curmap].thing[i].id], TRUE, TRUE);
 4005                 thingdrawn[i] = TRUE;
 4006             } 
 4007         } else if (map[curmap].thing[i].type == T_LINK) {
 4008             if (testing) { printf ("Drawing thing #%d (%d, link)\n",i,map[curmap].thing[i].id); fflush(STDOUT); }
 4009             if (!isflow(map[curmap].thing[i].id, T_LINK)) {
 4010                 drawlink(buffer, &map[curmap].olink[map[curmap].thing[i].id]);
 4011                 thingdrawn[i] = TRUE;
 4012             }
 4013 
 4014         } else if (map[curmap].thing[i].type == T_TEXT) {
 4015             if (testing) { printf ("Drawing thing #%d (%d, text)\n",i,map[curmap].thing[i].id); fflush(STDOUT); } 
 4016             if (!isflow(map[curmap].thing[i].id, T_TEXT)) {
 4017                 drawtext(buffer, &map[curmap].textob[map[curmap].thing[i].id], TRUE);
 4018                 thingdrawn[i] = TRUE;
 4019             }
 4020         } else {
 4021             printf("WARNING: Thing #%d has unknown type %d!\n",i,map[curmap].thing[i].type);
 4022             thingdrawn[i] = TRUE;
 4023         }
 4024     }
 4025 
 4026     /* show traffic flows (these should be on top of everything else) */
 4027     if (showflows) {
 4028         for (i = 0; i < map[curmap].numthings; i++) {
 4029             if (map[curmap].thing[i].type == T_OBJECT) {
 4030                 if (isflow(map[curmap].thing[i].id, T_OBJECT)) {
 4031                     drawobject(buffer, &map[curmap].obj[map[curmap].thing[i].id], TRUE, TRUE);
 4032                     if (state == S_DRAWFLOW) drawflowbox(buffer, map[curmap].thing[i].id, T_OBJECT);
 4033                     thingdrawn[i] = TRUE;
 4034                 }
 4035             } else if (map[curmap].thing[i].type == T_LINK) {
 4036                 if (isflow(map[curmap].thing[i].id, T_LINK)) {
 4037                     drawlink(buffer, &map[curmap].olink[map[curmap].thing[i].id]);
 4038                     if (state == S_DRAWFLOW) drawflowbox(buffer, map[curmap].thing[i].id, T_LINK);
 4039                     thingdrawn[i] = TRUE;
 4040                 }
 4041             } else if (map[curmap].thing[i].type == T_TEXT) {
 4042                 if (isflow(map[curmap].thing[i].id, T_TEXT)) {
 4043                     drawtext(buffer, &map[curmap].textob[map[curmap].thing[i].id], TRUE);
 4044                     if (state == S_DRAWFLOW) drawflowbox(buffer, map[curmap].thing[i].id, T_TEXT);
 4045                     thingdrawn[i] = TRUE;
 4046                 }
 4047             } 
 4048         }
 4049     }
 4050 
 4051     if (testing) {
 4052         printf("FINISHED THINGS \n"); fflush(STDOUT);
 4053     }
 4054 
 4055     if (testing) {
 4056         printf("DRAWING HIGHLIGHT\n"); fflush(STDOUT);
 4057     }
 4058 
 4059     /* highlight the selected map[curmap].object */
 4060     /* by drawing boxes in its corners */
 4061     if (map[curmap].selecteditem != -1) {
 4062         if (map[curmap].selecteditemtype == T_OBJECT) {
 4063             int n;
 4064 
 4065             /* 10% of map[curmap].object's size */
 4066             area.w = map[curmap].obj[map[curmap].selecteditem].w / OBJSELHANDLEPCT;
 4067             area.h = map[curmap].obj[map[curmap].selecteditem].h / OBJSELHANDLEPCT;
 4068             if (area.w < 2) area.w = 2;
 4069             if (area.h < 2) area.h = 2;
 4070 
 4071             fillcol = SDL_MapRGB(buffer->format, 0, 0, 0);
 4072 
 4073             /* top left */
 4074             area.x = map[curmap].obj[map[curmap].selecteditem].x - screenx; 
 4075             area.y = map[curmap].obj[map[curmap].selecteditem].y - screeny;
 4076             SDL_FillRect(buffer, &area, fillcol);
 4077             /* top right */
 4078             area.x = map[curmap].obj[map[curmap].selecteditem].x + map[curmap].obj[map[curmap].selecteditem].w - area.w - screenx; 
 4079             area.y = map[curmap].obj[map[curmap].selecteditem].y - screeny;
 4080             SDL_FillRect(buffer, &area, fillcol);
 4081             /* bottom left */
 4082             area.x = map[curmap].obj[map[curmap].selecteditem].x - screenx; 
 4083             area.y = map[curmap].obj[map[curmap].selecteditem].y + map[curmap].obj[map[curmap].selecteditem].h - area.h - screeny;
 4084             SDL_FillRect(buffer, &area, fillcol);
 4085             /* bottom right */
 4086             area.x = map[curmap].obj[map[curmap].selecteditem].x + map[curmap].obj[map[curmap].selecteditem].w - area.w - screenx; 
 4087             area.y = map[curmap].obj[map[curmap].selecteditem].y + map[curmap].obj[map[curmap].selecteditem].h - area.h - screeny;
 4088             SDL_FillRect(buffer, &area, fillcol);
 4089 
 4090             /* Also highlight any text anchored to this object */
 4091             for (n = 0; n < map[curmap].numtext; n++) {
 4092                 if (map[curmap].textob[n].anchor == map[curmap].selecteditem) {
 4093                     int th;
 4094 
 4095                     /* calculate text's height */
 4096                     th = TTF_FontHeight(font[map[curmap].textob[n].h]);
 4097 
 4098                     /* 10% of text's size */
 4099                     area.w = map[curmap].textob[n].w / OBJSELHANDLEPCT;
 4100                     area.h = th / OBJSELHANDLEPCT;
 4101                     if (area.w < 2) area.w = 2;
 4102                     if (area.h < 2) area.h = 2;
 4103 
 4104                     anchoreditem = map[curmap].textob[n].anchor;
 4105                     if (anchoreditem == -1) {
 4106                         txoff = 0;
 4107                         tyoff = 0;
 4108                     } else {
 4109                         txoff = map[curmap].obj[anchoreditem].x;
 4110                         tyoff = map[curmap].obj[anchoreditem].y;
 4111                     }
 4112 
 4113                     fillcol = SDL_MapRGB(buffer->format, 0, 255, 0);
 4114 
 4115                     /* top left */
 4116                     area.x = map[curmap].textob[n].x + txoff - screenx;  
 4117                     area.y = map[curmap].textob[n].y + tyoff - screeny;
 4118                     SDL_FillRect(buffer, &area, fillcol);
 4119                     /* top right */
 4120                     area.x = map[curmap].textob[n].x +txoff + map[curmap].textob[n].w - area.w - screenx; 
 4121                     area.y = map[curmap].textob[n].y + tyoff - screeny;
 4122                     SDL_FillRect(buffer, &area, fillcol);
 4123                     /* bottom left */
 4124                     area.x = map[curmap].textob[n].x +txoff - screenx; 
 4125                     area.y = map[curmap].textob[n].y + tyoff + th - area.h - screeny;
 4126                     SDL_FillRect(buffer, &area, fillcol);
 4127                     /* bottom right */
 4128                     area.x = map[curmap].textob[n].x+txoff + map[curmap].textob[n].w - area.w - screenx; 
 4129                     area.y = map[curmap].textob[n].y +tyoff+ th - area.h - screeny;
 4130                     SDL_FillRect(buffer, &area, fillcol);
 4131                 }
 4132             }
 4133 
 4134         } else if (map[curmap].selecteditemtype == T_TEXT) {
 4135             int th;
 4136 
 4137             /* calculate text's height */
 4138             th = TTF_FontHeight(font[map[curmap].textob[map[curmap].selecteditem].h]);
 4139 
 4140             /* 10% of text's size */
 4141             area.w = map[curmap].textob[map[curmap].selecteditem].w / OBJSELHANDLEPCT;
 4142             area.h = th / OBJSELHANDLEPCT;
 4143             if (area.w < 2) area.w = 2;
 4144             if (area.h < 2) area.h = 2;
 4145 
 4146             anchoreditem = map[curmap].textob[map[curmap].selecteditem].anchor;
 4147             if (anchoreditem == -1) {
 4148                 txoff = 0;
 4149                 tyoff = 0;
 4150             } else {
 4151                 txoff = map[curmap].obj[anchoreditem].x;
 4152                 tyoff = map[curmap].obj[anchoreditem].y;
 4153             }
 4154 
 4155             fillcol = SDL_MapRGB(buffer->format, 0, 0, 0);
 4156 
 4157             /* top left */
 4158             area.x = map[curmap].textob[map[curmap].selecteditem].x + txoff - screenx; 
 4159             area.y = map[curmap].textob[map[curmap].selecteditem].y + tyoff - screeny;
 4160             SDL_FillRect(buffer, &area, fillcol);
 4161             /* top right */
 4162             area.x = map[curmap].textob[map[curmap].selecteditem].x +txoff + map[curmap].textob[map[curmap].selecteditem].w - area.w - screenx; 
 4163             area.y = map[curmap].textob[map[curmap].selecteditem].y + tyoff - screeny;
 4164             SDL_FillRect(buffer, &area, fillcol);
 4165             /* bottom left */
 4166             area.x = map[curmap].textob[map[curmap].selecteditem].x +txoff - screenx; 
 4167             area.y = map[curmap].textob[map[curmap].selecteditem].y + tyoff + th - area.h - screeny;
 4168             SDL_FillRect(buffer, &area, fillcol);
 4169             /* bottom right */
 4170             area.x = map[curmap].textob[map[curmap].selecteditem].x+txoff + map[curmap].textob[map[curmap].selecteditem].w - area.w - screenx; 
 4171             area.y = map[curmap].textob[map[curmap].selecteditem].y +tyoff+ th - area.h - screeny;
 4172             SDL_FillRect(buffer, &area, fillcol);
 4173 
 4174             /* if this text is anchored, highlight the map[curmap].object which it is anchored to */
 4175             if (anchoreditem != -1) {
 4176                 area.w = map[curmap].obj[anchoreditem].w / OBJSELHANDLEPCT;
 4177                 area.h = map[curmap].obj[anchoreditem].h / OBJSELHANDLEPCT;
 4178                 if (area.w < 2) area.w = 2;
 4179                 if (area.h < 2) area.h = 2;
 4180 
 4181                 fillcol = SDL_MapRGB(buffer->format, 0, 255, 0);
 4182 
 4183                 /* top left */
 4184                 area.x = map[curmap].obj[anchoreditem].x - screenx; 
 4185                 area.y = map[curmap].obj[anchoreditem].y - screeny;
 4186                 SDL_FillRect(buffer, &area, fillcol);
 4187                 /* top right */
 4188                 area.x = map[curmap].obj[anchoreditem].x + map[curmap].obj[anchoreditem].w - area.w - screenx; 
 4189                 area.y = map[curmap].obj[anchoreditem].y - screeny;
 4190                 SDL_FillRect(buffer, &area, fillcol);
 4191                 /* bottom left */
 4192                 area.x = map[curmap].obj[anchoreditem].x - screenx; 
 4193                 area.y = map[curmap].obj[anchoreditem].y + map[curmap].obj[anchoreditem].h - area.h - screeny;
 4194                 SDL_FillRect(buffer, &area, fillcol);
 4195                 /* bottom right */
 4196                 area.x = map[curmap].obj[anchoreditem].x + map[curmap].obj[anchoreditem].w - area.w - screenx; 
 4197                 area.y = map[curmap].obj[anchoreditem].y + map[curmap].obj[anchoreditem].h - area.h - screeny;
 4198                 SDL_FillRect(buffer, &area, fillcol);
 4199             }
 4200 
 4201         } else if (map[curmap].selecteditemtype == T_LINK) {
 4202             /* 10% of map[curmap].object's size */
 4203             area.w = LINESELHANDLESIZE;
 4204             area.h = LINESELHANDLESIZE;
 4205 
 4206             fillcol = SDL_MapRGB(buffer->format, 0, 0, 0);
 4207 
 4208             /* start of line */
 4209             area.x = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].srcobj].x + map[curmap].olink[map[curmap].selecteditem].srcxoff - (LINESELHANDLESIZE/2) - screenx;
 4210             area.y = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].srcobj].y + map[curmap].olink[map[curmap].selecteditem].srcyoff - (LINESELHANDLESIZE/2) - screeny;
 4211             SDL_FillRect(buffer, &area, fillcol);
 4212             /* end of line */
 4213             area.x = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].dstobj].x + map[curmap].olink[map[curmap].selecteditem].dstxoff -  (LINESELHANDLESIZE/2) - screenx;
 4214             area.y = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].dstobj].y + map[curmap].olink[map[curmap].selecteditem].dstyoff -  (LINESELHANDLESIZE/2) - screeny;
 4215             SDL_FillRect(buffer, &area, fillcol);
 4216 
 4217             /* points on the line */
 4218             for (i = 0; i < map[curmap].olink[map[curmap].selecteditem].npoints; i++) {
 4219                 area.x = map[curmap].olink[map[curmap].selecteditem].point[i].x - (LINESELHANDLESIZE/2) - screenx;
 4220                 area.y = map[curmap].olink[map[curmap].selecteditem].point[i].y - (LINESELHANDLESIZE/2) - screeny;
 4221                 SDL_FillRect(buffer, &area, fillcol);
 4222             }
 4223         } else if (map[curmap].selecteditemtype == T_LINKPOINT) {
 4224             /* highlight the line in green */
 4225             /* 10% of map[curmap].object's size */
 4226             area.w = LINESELHANDLESIZE;
 4227             area.h = LINESELHANDLESIZE;
 4228 
 4229             fillcol = SDL_MapRGB(buffer->format, 0, 255, 0);
 4230 
 4231             /* start of line */
 4232             area.x = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].srcobj].x + map[curmap].olink[map[curmap].selecteditem].srcxoff - (LINESELHANDLESIZE/2) - screenx;
 4233             area.y = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].srcobj].y + map[curmap].olink[map[curmap].selecteditem].srcyoff - (LINESELHANDLESIZE/2) - screeny;
 4234             SDL_FillRect(buffer, &area, fillcol);
 4235             /* end of line */
 4236             area.x = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].dstobj].x + map[curmap].olink[map[curmap].selecteditem].dstxoff -  (LINESELHANDLESIZE/2) - screenx;
 4237             area.y = map[curmap].obj[map[curmap].olink[map[curmap].selecteditem].dstobj].y + map[curmap].olink[map[curmap].selecteditem].dstyoff -  (LINESELHANDLESIZE/2) - screeny;
 4238             SDL_FillRect(buffer, &area, fillcol);
 4239 
 4240             /* points on the line */
 4241             for (i = 0; i < map[curmap].olink[map[curmap].selecteditem].npoints; i++) {
 4242                 if (i == map[curmap].selectedlinkpoint) {
 4243                     fillcol = SDL_MapRGB(buffer->format, 0, 0, 0);
 4244                 } else {
 4245                     fillcol = SDL_MapRGB(buffer->format, 0, 255, 0);
 4246                 }
 4247                 area.x = map[curmap].olink[map[curmap].selecteditem].point[i].x - (LINESELHANDLESIZE/2) - screenx;
 4248                 area.y = map[curmap].olink[map[curmap].selecteditem].point[i].y - (LINESELHANDLESIZE/2) - screeny;
 4249                 SDL_FillRect(buffer, &area, fillcol);
 4250             }
 4251         }
 4252     }
 4253 
 4254     /* blit buffer to screen */
 4255     SDL_BlitSurface(buffer, 0, screen,0);
 4256 
 4257     if (testing) {
 4258         printf("START MAPBOX\n"); fflush(STDOUT);
 4259     }
 4260     drawmapbox();
 4261 
 4262     /* draw status bar */
 4263     if (wantdecs) {
 4264         if (testing) {
 4265             printf("START STATUSBAR\n"); fflush(STDOUT);
 4266         }
 4267         drawstatusbar();
 4268     }
 4269 
 4270     if (testing) {
 4271         printf("FLIP\n"); fflush(STDOUT);
 4272     }
 4273 
 4274     if (wantdecs) {
 4275         /* draw scrollbars, if required */
 4276         if (map[curmap].width > (screen->w - SIDEBARW)) {
 4277             drawxscrollbar();
 4278         }
 4279         if (map[curmap].height > (screen->h - STATUSH)) {
 4280             drawyscrollbar();
 4281         }
 4282     }
 4283 
 4284     /* calculate mapdimensions if diagram has been modified */
 4285     if (needtocalc) {
 4286         calcmapdimensions();
 4287         needtocalc = FALSE;
 4288     }
 4289 
 4290     /* flip */
 4291     SDL_Flip(screen);
 4292     //SDL_UpdateRect(screen, 0, 0, map[curmap].width, map[curmap].height);
 4293 }
 4294 
 4295 void drawxscrollbar(void) {
 4296     int barw;
 4297     double barx;
 4298 
 4299     barx = ((double)screenx / (double)map[curmap].width) * (screen->w - SIDEBARW - SBSIZE);
 4300 
 4301     /* scrollbar outline */
 4302     drawbox(screen, 0, screen->h - STATUSH - SBSIZE, 
 4303             screen->w - SIDEBARW - SBSIZE, screen->h - STATUSH - 1, blue2 , &blue2);
 4304 
 4305     /* screen position */
 4306     barw = (((double)(screen->w - SIDEBARW - SBSIZE) / (double)map[curmap].width) * (screen->w - SIDEBARW - SBSIZE));
 4307     if (barx+barw > (screen->w - SIDEBARW-SBSIZE)) barw = screen->w - SIDEBARW - SBSIZE - barx;
 4308 
 4309     drawbox(screen, barx, screen->h - STATUSH - SBSIZE+1, 
 4310             barx + barw, screen->h - STATUSH - 2, blue , &blue);
 4311 
 4312     SDL_UpdateRect(screen, 0,screen->h - STATUSH - SBSIZE,  screen->w, SBSIZE);
 4313 }
 4314 
 4315 void drawyscrollbar(void) {
 4316     int barh;
 4317     double bary;
 4318 
 4319     bary = ((double)screeny / (double)map[curmap].height) * (screen->h - STATUSH - SBSIZE);
 4320 
 4321     /* scrollbar outline */
 4322     drawbox(screen, screen->w - SIDEBARW - SBSIZE, 0, 
 4323             screen->w - SIDEBARW - 2, screen->h - STATUSH - SBSIZE - 1, blue2, &blue2);
 4324 
 4325     /* screen position */
 4326     barh = (((double)(screen->h - STATUSH - SBSIZE) / (double)map[curmap].height) * (screen->h - STATUSH - SBSIZE));
 4327     if (bary+barh > (screen->h - STATUSH - SBSIZE)) barh = screen->h - STATUSH - SBSIZE - bary;
 4328 
 4329     drawbox(screen, screen->w - SIDEBARW - SBSIZE+1, bary, 
 4330             screen->w - SIDEBARW - 3, bary + barh, blue , &blue);
 4331 
 4332     SDL_UpdateRect(screen, screen->w - SIDEBARW - SBSIZE, 0, SBSIZE, screen->h - STATUSH - SBSIZE - 1);
 4333 }
 4334 
 4335 void validatescreenpos(void) {
 4336     if (screenx + (screen->w - SIDEBARW) > map[curmap].width) {
 4337         screenx = map[curmap].width - (screen->w - SIDEBARW);
 4338     }
 4339     if (screenx < 0) screenx = 0;
 4340 
 4341     if (screeny + (screen->h - STATUSH) > map[curmap].height) {
 4342         screeny = map[curmap].height - (screen->h - STATUSH);
 4343     }
 4344     if (screeny < 0) screeny = 0;
 4345 }
 4346 
 4347 void drawsearchflash(void) {
 4348     SDL_Surface *temps;
 4349     SDL_Rect area;
 4350     int txoff,tyoff;
 4351     int anchoreditem;
 4352 
 4353 
 4354     if (!searchflash) {
 4355         return;
 4356     }
 4357     /* highlight the object just found in a search */
 4358     if (map[curmap].selecteditem != -1) {
 4359         if (map[curmap].selecteditemtype == T_TEXT) {
 4360             int th;
 4361 
 4362             /* calculate text's height */
 4363             th = TTF_FontHeight(font[map[curmap].textob[map[curmap].selecteditem].h]);
 4364 
 4365             area.w = map[curmap].textob[map[curmap].selecteditem].w;
 4366             area.h = th;
 4367 
 4368