/* > C.Wimp-Funct                                                            */

/*****************************************************************************
*                                                                            *
* Hulp routines voor de window omgeving. Deze bestaan uit:                   *
*                                                                            * 
*   - Memory management routines (aanvragen geheugen / vrijgeven / debug)    *
*   - String routines (dynamisch string copy/update)                         *
*   - Wimp routines (High level window redraw enz.)                          *
*   - Help systeem (Help systeem dat in elk programma verwerkt kan worden)   *
*   - Printer driver routines (aansturen RiscOs printer driver)              *
*                                                                            *
* (C) Bernard Rutgrink 1991                                                  *
*                                                                            *
*****************************************************************************/

#ifndef __system_io
#define __system_io
#endif
#define FILEHANDLE int

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#include <limits.h>
#include <time.h>

#include "alarm.h"
#include "swis.h"
#include "wimp.h"
#include "wimpt.h"
#include "werr.h"
#include "dbox.h"
#include "dboxQuery.h"
#include "visdelay.h"
#include "os.h"
#include "bbc.h"
#include "heap.h"
#include "sprite.h"
#include "font.h"
#include "colourtran.h"
#include "res.h"
#include "template.h"
#include "txtedit.h"

#include "Wimp-Funct.h"

#define MAX_ALLOC          4096

#define HELP_TEKST_TITEL   0    /* Icon nr. van titel icon help_tekst window */
#define HELP_TEKST_OK      18   /* Icon nr. van OK icon in help_tekst window */
#define HELP_TEKST_VAN     1    /* Eerste icon voor helptekst                */
#define HELP_TEKST_TOT     18   /* Laatste icon voor helptekst               */
#define HELP_TEKST_LENGTE  44   /* Lengte van helptekst icons in karakters   */

#define HELP_MENU_VAN      0    /* Eerste helpmenu icon                      */
#define HELP_MENU_TOT      13   /* Laatste helpmenu icon                     */

#define PRINT_FONT         "Corpus.Medium"  /* Printer font                  */
#define PRINT_FONT_SIZE    12 * 16          /* Printer font-size             */

struct helpstr {
   char *label;
   char *tekst;
   struct helpstr *volgende;
};
static struct helpstr *helpteksten;
static int memory_count = 0;

#define MAX_TXT_WINDOWS     256

static txtedit_state *txt_state_array[MAX_TXT_WINDOWS];
static char **txt_text_array[MAX_TXT_WINDOWS];

/*****************************************************************************
*                                                                            *
*                       Memory management routines                           *
*                       --------------------------                           *
*                                                                            *
* Indien de DEBUG flag staat, wordt een speciale DEBUG malloc en free        *
* gebruikt. Deze controleren of het geheugen gebied toevallig wordt over-    *
* schreven. Als dit zo is, wordt er een fout melding bij 'free' gegeven      *
*                                                                            *
*****************************************************************************/

#ifndef DEBUG


/******************************** alloc_mem **********************************
*                                                                            *
*  Description: Vraag geheugen aan m.b.v. heap_alloc. Als er geen geheugen   *
*               meer is, geef dan een error.                                 *
*                                                                            *
*  Parameters:  size_t size                  Aantal aan te vragen bytes      *
*                                                                            *
*  Returns:     void *                       Pointer naar geheugen           *
*                                                                            *
*  Other Info:  Als er geen geheugen meer is, dan wordt de NULL pointer      *
*               terug gegeven (er wordt eerst een error gegeven). Er wordt   *
*               een interne teller bij gehouden die aangeeft hoeveel keer    *
*               er geheugen is aangevraagd.                                  *
*                                                                            * 
*****************************************************************************/

void *alloc_mem(size_t size,int line,char *file)
{
   void *pointer;

   pointer = heap_alloc(size);

   if (pointer == NULL)
   {
      werr(TRUE,"Fatal error: Unable to claim %d bytes of memory (line %d file %s)",size,line,file);
   }
   else
   {
      memory_count++;

   }
   return(pointer);
}

/******************************* free_mem ************************************
*                                                                            *
*  Description: Geef het aangegevraagde geheugen weer vrij                   *
*                                                                            *
*  Parameters:  void *pointer                Pointer naar vrij te geven      *
*                                            geheugen gebied.                *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Als de pointer NULL is, wordt geen geheugen vrij gegeven en  *
*               ook geen error gegenereerd. De interne teller wordt verlaagd *
*                                                                            * 
*****************************************************************************/

void free_mem(void *pointer)
{
   if (pointer != NULL)
   {
      heap_free(pointer);

      memory_count--;
   }
}

#else

#define RND(x)       (((x)+sizeof (int)-1)/sizeof (int))
#define CHECK1       0x12345678
#define CHECK2       0x9abcdef0

static int *alloc_adres[MAX_ALLOC];
static int alloc_line[MAX_ALLOC];
static char *alloc_file[MAX_ALLOC];

void *alloc_mem(size_t size,int line,char *file)
{
   static BOOL first = TRUE;
   int *ptr = heap_alloc(size+12);
   int tel;

   if (first == TRUE)
   {
      for (tel = 0; tel < MAX_ALLOC; tel++)
      {
         alloc_adres[tel] = NULL;
         alloc_line[tel]  = 0;
         alloc_file[tel]  = NULL;
      }
      first = FALSE;
   }

   if (ptr == NULL)
   {                            
      werr(TRUE,"Fatal error: Unable to claim %d bytes of memory (line %d file %s)",size,line,file);
   }
   else
   {
      memory_count++;

      ptr[0] = size;
      ptr[1] = CHECK1;
      ptr[2 + RND(size)] = CHECK2;

      for (tel = 0; tel < MAX_ALLOC && alloc_adres[tel] != NULL; tel++);
      if (tel < MAX_ALLOC)
      {
         alloc_adres[tel] = (int *)ptr + 2;
         alloc_line[tel] = line;
         alloc_file[tel] = heap_alloc(strlen(file) + 1);
         strcpy(alloc_file[tel],file);
      }
   }

   return ( ptr + 2 );
}

static void check_mem(int *ptr)
{
   if (ptr[1] != CHECK1 || ptr[2 + RND(ptr[0])] != CHECK2)
   {
      int tel;

      werr(TRUE,"Alloc space overwritten at location %x\n",ptr);
      for (tel = 0; tel < MAX_ALLOC && alloc_adres[tel]!=(int *)ptr; tel++);
      if (tel < MAX_ALLOC && alloc_adres[tel] == (int *)ptr)
      {
         werr(TRUE,"Claimed at %d in file %s\n",alloc_line[tel],alloc_file[tel]);
      }
   }
}

void free_mem(void *ptr1)
{
   int tel;

   if (ptr1 != NULL)
   {
      check_mem((int *)ptr1 - 2);
      heap_free((int *)ptr1 - 2);
      for (tel = 0; tel < MAX_ALLOC && alloc_adres[tel] != (int *)ptr1; tel++);
      if (tel < MAX_ALLOC && alloc_adres[tel] == (int *)ptr1)
      {
         heap_free(alloc_file[tel]);
         alloc_file[tel]  = NULL;
         alloc_adres[tel] = NULL;
         alloc_line[tel]  = 0;
      }
      memory_count--;
   }
}

#endif

/**************************** check_memory_alloc *****************************
*                                                                            *
*  Description: Kijk of de interne 'alloc' teller '0' is. Deze routine kan   *
*               gebruikt worden om te kijken of al het aangevraagde geheugen *
*               ook wordt vrij gegeven.                                      *
*                                                                            *
*  Parameters:  void                                                         *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Er wordt een error gegeven als de teller niet 0 is. Deze     *
*               routine kan b.v. als allerlaatste worden aangeroepen.        *
*                                                                            * 
*****************************************************************************/

void check_memory_alloc(void)
{
   char tmpbuf[256];
   int  tel;

   if (memory_count != 0)
   {
      sprintf(tmpbuf,"Memory alloc/free not equal, missing %d",memory_count);
      werr(FALSE,tmpbuf);

#ifdef DEBUG
      for (tel = 0; tel < MAX_ALLOC; tel++)
      {
         if (alloc_adres[tel] != NULL)
         {
            sprintf(tmpbuf,"Allocated at line %d file %s (points to %p)",
                    alloc_line[tel],alloc_file[tel],alloc_adres[tel]);
            werr(FALSE,tmpbuf);
         }
      }
#endif

   }
}

/*****************************************************************************
*                                                                            *
*                            String routines                                 *
*                            ---------------                                 *
*                                                                            *
*****************************************************************************/

/*************************** strcpy_mem **************************************
*                                                                            *
*  Description: Deze routine is hetzelfde als strcpy, maar er wordt direct   *
*               geheugen voor de string aangevraagd.                         *
*                                                                            *
*  Parameters:  char **destin                Pointer naar destiantion        *
*               char *source                 De te kopieren string           *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Als er geen geheugen meer is, wordt een error gegenereerd    *
*                                                                            * 
*****************************************************************************/

void _strcpy_mem(char **destin,char *source,int line,char *file)
{
   if (source != NULL)
   {
      *destin = alloc_mem(strlen(source) + 1,line,file);
      strcpy(*destin,source);
   }
   else
   {
      *destin = NULL;
   }
}

/***************************** strupd_mem ************************************
*                                                                            *
*  Description: String update. Een al 'beschreven' string wordt ge-update    *
*               Dit wordt dynamisch gedaan. Het oude geheugen wordt vrij     *
*               gegeven en er wordt niet geheugen aangevraagd. Hierin wordt  *
*               de nieuwe string gekopierd.                                  *
*                                                                            *
*  Parameters:  char **old                   Pointer karakter pointer old str*
*               char *new                    Pointer naar wat het moet       *
*                                            worden                          *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Als er geen geheugen meer is, wordt een error gegenereerd    *
*                                                                            * 
*****************************************************************************/

void _strupd_mem(char **old,char *new,int line,char *file)
{
   if (*old != NULL)
   {
      free_mem(*old);
      *old = NULL;
   }
   if (new != NULL)
   {
      *old = alloc_mem(strlen(new) + 1,line,file);
      strcpy(*old,new);
   }
}

/*****************************************************************************
*                                                                            *
*                            Window routines                                 *
*                            ---------------                                 *
*                                                                            *
*****************************************************************************/

void wimp_force_redraw_easy(wimp_w handle,int x0,int y0,int x1,int y1)
{
   wimp_redrawstr block;

   block.w = handle;
   block.box.x0=x0;
   block.box.y0=y0;
   block.box.x1=x1;
   block.box.y1=y1;
   wimpt_complain(wimp_force_redraw(&block));
}

void wimp_force_redraw_window_easy(wimp_w handle)
{
   wimp_wstate block1;
   wimp_redrawstr block2;

   wimpt_complain(wimp_get_wind_state(handle,&block1));
   block2.w = handle;
   block2.box.x0 = block1.o.x;
   block2.box.y0 = block1.o.y - (block1.o.box.y1 - block1.o.box.y0);
   block2.box.x1 = block1.o.x + (block1.o.box.x1 - block1.o.box.x0);
   block2.box.y1 = block1.o.y;
   wimpt_complain(wimp_force_redraw(&block2));
}

void wimp_set_icon_text_easy(wimp_w handle,wimp_i icon,const char *pointer)
{
   wimp_icreate buffer;
   wimp_i temp;

   wimpt_complain(wimp_get_icon_info(handle,icon,&buffer.i));
   wimpt_complain(wimp_delete_icon(handle,icon));
   if ((buffer.i.flags & wimp_INDIRECT) == 0)
      strcpy(buffer.i.data.text,pointer);
   else
      strncpy(buffer.i.data.indirecttext.buffer,pointer,
              buffer.i.data.indirecttext.bufflen);
   buffer.w = handle;
   wimpt_complain(wimp_create_icon(&buffer,&temp));
   wimp_force_redraw((wimp_redrawstr *)&buffer);
}

char *wimp_get_icon_text_easy(wimp_w handle,wimp_i icon)
{
   wimp_icreate buffer;

   wimpt_complain(wimp_get_icon_info(handle,icon,&buffer.i));
   if ((buffer.i.flags & wimp_INDIRECT) == 0)
      return(buffer.i.data.text);
   else
      return(buffer.i.data.indirecttext.buffer);
}

void wimp_front_window_easy(wimp_w handle)
{
   wimp_wstate state;

   wimpt_complain(wimp_get_wind_state(handle,&state));
   state.o.behind = -1;
   wimpt_complain(wimp_open_wind(&state.o));
}

void wimp_set_caret_pos_easy(wimp_w handle,wimp_i icon,int index)
{
   wimp_caretstr block;

   block.w = handle;
   block.i = icon;
   block.x = 0;
   block.y = 0;
   block.height = -1;
   block.index = index;
   wimpt_complain(wimp_set_caret_pos(&block));
}

void wimp_select_icon_easy(wimp_w handle,wimp_i icon)
{
   wimpt_complain(wimp_set_icon_state(handle,icon,wimp_ISELECTED,0));
}

BOOL wimp_icon_selected(wimp_w handle,wimp_i icon)
{
   wimp_icreate buffer;

   wimpt_complain(wimp_get_icon_info(handle,icon,&buffer.i));
   return (((buffer.i.flags & (1 << 21)) == 0) ? FALSE : TRUE);
}

void wimp_flash_icon_easy(wimp_w handle,wimp_i icon,int aantal)
{
   int tijd;
   int teller;

   tijd=alarm_timenow();
   for (teller=0; teller<=aantal; teller++)
   {
      wimp_select_icon_easy(handle,icon);
      while (alarm_timedifference(tijd,alarm_timenow()) < 3);
      tijd=alarm_timenow();
   }
}

void wimp_search_selected_icons(wimp_w handle,wimp_i *results)
{
   wimp_which_block block;

   block.window = handle;
   block.bit_mask = wimp_ISELECTED;
   block.bit_set  = wimp_ISELECTED;
   wimpt_complain(wimp_which_icon(&block,results));
}

void wimp_delete_icons(wimp_w handle)
{
   wimp_which_block block;
   int results[200];
   int teller;

   block.window = handle;
   block.bit_mask = 0;
   block.bit_set  = 0;
   wimpt_complain(wimp_which_icon(&block,results));
   teller = 0;
   while (results[teller] != -1)
      wimpt_complain(wimp_delete_icon(handle,results[teller++]));
}

void wimp_close_menu()
{
   wimpt_complain(os_swi2(Wimp_CreateMenu,0,-1));
}

int wimp_create_icon_easy(int handle,int x0,int y0,int x1,int y1,int flag,
                          char c0,char c1,char *tekst)
{
   wimp_icreate block;
   wimp_i ihandle;

   block.w = handle;
   block.i.box.x0 = x0;
   block.i.box.y0 = y0;
   block.i.box.x1 = x1;
   block.i.box.y1 = y1;
   block.i.flags = flag + (c0 << 24) + (c1 << 28);
   if ((flag & wimp_INDIRECT) != 0) {
      block.i.data.indirecttext.buffer = tekst;
      block.i.data.indirecttext.validstring = (char *)-1;
      block.i.data.indirecttext.bufflen = 254;
   }
   else 
      strcpy(block.i.data.text,tekst);
   wimpt_complain(wimp_create_icon(&block,&ihandle));
   return(ihandle);
}

void wimp_mouse_to(int xpos,int ypos)
{
   char buffer[5];
   os_regset reg;

   buffer[0] = 3;
   buffer[1] = (xpos&0x00ff);
   buffer[2] = (xpos&0xff00) >> 8;
   buffer[3] = (ypos&0x00ff);
   buffer[4] = (ypos&0xff00) >> 8;
   reg.r[0] = 21;
   reg.r[1] = (int)&buffer;
   os_swix(OS_Word,&reg);
}

void wimp_set_icon_flag_easy(wimp_w handle,wimp_i icon,int keep_same,int set)
{
   wimp_icreate buffer;
   wimp_i temp;

   wimpt_complain(wimp_get_icon_info(handle,icon,&buffer.i));
   wimpt_complain(wimp_delete_icon(handle,icon));
   buffer.i.flags = buffer.i.flags & keep_same;
   buffer.i.flags = buffer.i.flags | set;
   buffer.w = handle;
   wimpt_complain(wimp_create_icon(&buffer,&temp));
   wimp_force_redraw((wimp_redrawstr *)&buffer);
}

/*********************** wimp_move_template_window ***************************
*                                                                            *
*  Description: Zorg ervoor dat twee dezelfde windows niet over elkaar       *
*               worden gezet. Verschuif daarom het window in de template-    *
*               file                                                         *
*                                                                            *
*  Parameters:  const char *name             Naam van het window             *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Er wordt vanuit gegaan dat het window met de opgegeven naam  *
*               bestaat. Bestaat hij niet, dan wordt er niets gedaan         *
*                                                                            * 
*****************************************************************************/
    
void wimp_move_template_window(const char *naam)
{
   static int horizontaal = 16;
   static int verticaal   = -32;
   wimp_wind *block;

   block = template_syshandle((char *)naam);
   if (block != NULL)
   {
      if (block->box.x1 + horizontaal > mode_x_res() || 
          block->box.x0 + horizontaal < 0)
      {
         horizontaal = -horizontaal;
      }
      if (block->box.y1 + verticaal > mode_y_res() ||
          block->box.y0 + verticaal < 0)
      {
         verticaal = -verticaal;
      }
      block->box.x0 += horizontaal;
      block->box.x1 += horizontaal;
      block->box.y0 += verticaal;
      block->box.y1 += verticaal;
   }
}

/*********************** wimp_centre_template_window *************************
*                                                                            *
*  Description: Zorg ervoor dat een window uit de template file gecentreerd  *
*               op t.o.v. de huidige scherm coordinaten. Het window zal de   *
*               volgende keer dus midden op het scherm ge-opend worden.      *
*                                                                            *
*  Parameters:  const char *name             Naam van het window             *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Er wordt vanuit gegaan dat het window met de opgegeven naam  *
*               bestaat. Bestaat hij niet, dan wordt er niets gedaan.        *
*                                                                            * 
*****************************************************************************/
    
void wimp_centre_template_window(const char *naam)
{
   int x_midden;
   int y_midden;
   int lengte;
   int breedte;
   wimp_wind *block;

   block = template_syshandle((char *)naam);
   if (block != NULL)
   {
      x_midden = mode_x_res() / 2;
      y_midden = mode_y_res() / 2;
      lengte   = block->box.x1 - block->box.x0;
      breedte  = block->box.y1 - block->box.y0;
      block->box.x0 = x_midden - (lengte / 2);
      block->box.y0 = y_midden - (breedte / 2);
      block->box.x1 = block->box.x0 + lengte;
      block->box.y1 = block->box.y0 + breedte;
   }
}

int mode_var(int varnum)
{
   int mode;
   int value;
   int dummy;

   wimpt_checkmode();
   mode = wimpt_mode();
   os_swi3r(OS_ReadModeVariable,mode,varnum,dummy,&dummy,&dummy,&value);

   return ( value );
}

int mode_x_res(void)
{
   return ((mode_var(11) + 1) << mode_var(4));
}

int mode_y_res(void)
{
   return ((mode_var(12) + 1) << mode_var(5));
}

/*****************************************************************************
*                                                                            *
*                         Help system routines                               *
*                         --------------------                               *
*                                                                            *
*                                                                            *
*  Syntax beschrijving 'help' file                                           *
*  -------------------------------                                           *
*                                                                            *
*  nivo          [0-9]                                                       *
*  woord         [A-Za-z0-9]*                                                *
*  tekst         ({woord}|" ")*                                              *
*                                                                            *
*  label         ":"{nivo}{woord}\n\n                                        *
*  link          ">"{nivo}\n\n                                               *
*  helptekst     {tekst}\n\n                                                 *
*                                                                            *
*                                                                            *
*  help          ({label}({link}|{helptekst}))*                              *
*                                                                            *
*****************************************************************************/


/************************* help_splits_bij_spatie ****************************
*                                                                            *
*  Description: Hulp routine die een regel splitst bij een spatie of een '-' *
*                                                                            *
*  Parameters:  char *string                 De regel                        *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Interne routine                                              *
*                                                                            * 
*****************************************************************************/

void help_splits_bij_spatie(char *string)
{
   int lengte;

   lengte = strlen(string);
   while (string[lengte] != ' ' && string[lengte] != '-' && lengte > 0)
      lengte--;
   string[lengte + 1] = '\0';
}

/*************************** zoek_help_item **********************************
*                                                                            *
*  Description: Zoekt in de help-gegevens naar een bepaald 'help-item'       *
*                                                                            *
*  Parameters:  char *item                   Het te zoeken item              *
*                                                                            *
*  Returns:     struct helpstr *             Pointer naar de gevonden help-  *
*                                            structure.                      *
*                                                                            *
*  Other Info:  Als het item niet gevonden wordt, dan wordt er een wimp-     *
*               error gegenereerd. De pointer NULL wordt terug gegeven.      *
*               Interne routine.                                             *
*                                                                            * 
*****************************************************************************/

struct helpstr *zoek_help_item(char *item)
{
   BOOL gevonden = FALSE;
   struct helpstr *pointer;

   pointer = helpteksten;
   while (pointer != NULL && gevonden == FALSE)
   {
      if (strcmp(pointer->label,item) == 0)
      {
         gevonden = TRUE;
      }
      else
      {
         pointer = pointer->volgende;
      }
   }

   if (pointer == NULL)
   {
      werr(FALSE,"Something has gone wrong with the help system");
   }
   return(pointer);
}

/***************************** show_help_tekst *******************************
*                                                                            *
*  Description: Popup window met help-teksten bij bepaald item               *
*                                                                            *
*  Parameters:  struct helpstr *pointer      Pointer naar de 'help-tekst'    *
*                                                                            *
*  Returns:     BOOL                         Gesloten door CloseIcon         *
*                                                                            *
*  Other Info:  Interne routine                                              *
*                                                                            * 
*****************************************************************************/

BOOL show_help_tekst(struct helpstr *pointer)
{
   BOOL stay = TRUE;
   dbox help_tekst;
   int  icon = HELP_TEKST_VAN;
   int  van  = 0;
   char buffer[4096];

   help_tekst = dbox_new("help_tekst");
   if (help_tekst == NULL)
   {
      werr(FALSE,"Window not found in template");
   }
   else
   {
      dbox_setfield(help_tekst,HELP_TEKST_TITEL,&pointer->label[1]);
      while (van < strlen(pointer->tekst))
      {
         strncpy(buffer,&pointer->tekst[van],HELP_TEKST_LENGTE);
         buffer[HELP_TEKST_LENGTE] = '\0';
         if (strlen(buffer) == HELP_TEKST_LENGTE)
         {
            help_splits_bij_spatie(buffer);
         }
         dbox_setfield(help_tekst,icon++,buffer);
         van = van + strlen(buffer);
      }
      while (icon <= HELP_TEKST_TOT)
      {
         dbox_setfield(help_tekst,icon++,"");
      }
      dbox_show(help_tekst);
      icon = dbox_fillin(help_tekst);
      dbox_dispose(&help_tekst);
      stay = (icon == HELP_TEKST_OK);
   }
   return(stay);
}

/**************************** help_system_handler ****************************
*                                                                            *
*  Description: Handler routine voor het help-menu                           *
*                                                                            *
*  Parameters:  dbox menu                    Pointer naar dbox               *
*               void *handle                 level van menu                  *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Interne routine                                              *
*                                                                            * 
*****************************************************************************/

void help_system_handler(dbox menu,void *handle)
{
   struct helpstr *pointer;
   int itemnr;
   int  *level;
   char item[40];
   char buffer[40];
   BOOL stay;

   level = handle;
   itemnr = dbox_get(menu);
   if (itemnr >= HELP_MENU_VAN && itemnr <= HELP_MENU_TOT) {
      dbox_getfield(menu,itemnr,item,40);
      sprintf(buffer,"%1d%s",(int)level,item);
      pointer = zoek_help_item(buffer);
      if (pointer != NULL) {
         stay = TRUE;
         if (pointer->tekst[0] != '>')
            stay = show_help_tekst(pointer);
         else
            show_help_menu((int)pointer->tekst[1] - '0');
      }
   }
   else {
      if (dbox_persist() == FALSE)
         dbox_dispose(&menu);
   }
}

/***************************** show_help_menu ********************************
*                                                                            *
*  Description: Laat het menu-window zien van een bepaald level. Het help    *
*               systeem moet worden aangeroepen met show_help_menu(0)        *
*                                                                            *
*  Parameters:  int level                    level van menu                  *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Geen                                                         *
*                                                                            * 
*****************************************************************************/

void show_help_menu(int level)
{
   struct helpstr *pointer;
   int    teller;
   int    handle;
   dbox   help_menu;

   help_menu = dbox_new("help_menu");
   if (help_menu == NULL)
      werr(FALSE,"Window not found in template");
   else {
      handle = dbox_syshandle(help_menu);
      pointer = helpteksten;
      teller = HELP_MENU_VAN;
      while (pointer != NULL) {
         if (pointer->label[0] == level + '0')
         {
            wimp_set_icon_flag_easy(handle,teller,0x0ff0ffb,(1 << 2) + (7 << 24) + (1 << 28) + (9 << 12));      /* Icon border,zwart,grijs,menu */
            wimp_set_icon_text_easy(handle,teller,&pointer->label[1]);
            teller++;
         }
         pointer = pointer->volgende;
      }
      while (teller <= HELP_MENU_TOT)
      {
         wimp_set_icon_text_easy(handle,teller,"");
         wimp_set_icon_flag_easy(handle,teller,0x0ff0ffb,(0 << 2) + (1 <<24) + (1 << 28) + (0 << 12));          /* Icon not border,grijs,grijs,never */
         teller++;
      }
      dbox_eventhandler(help_menu,help_system_handler,(int *)level);
      dbox_showstatic(help_menu);
      if (level == 0)
         wimp_move_template_window("help_menu");
   }
}

/************************* init_help_system **********************************
*                                                                            *
*  Description: Initialiseer het help systeem. Deze routine mg maar n keer *
*               worden aangeroepen. Hij moet worden aangeroepen na res_init  *
*               Er wordt in de applicatie directory gekeken naar de file     *
*               'Help'. Deze file moet aan het help-system formaat voldoen.  *
*                                                                            *
*  Parameters:  void                                                         *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Geen                                                         *
*                                                                            * 
*****************************************************************************/

void init_help_system(void)
{
   struct helpstr *pointer;
   char filename[256];
   char buffer[4096];
   char hulp[4096];
   FILE *file;

   helpteksten = NULL;
   res_findname("Help",filename);
   file = fopen(filename,"r");
   while (feof(file) == 0)
   {
      fgets(buffer,4095,file);
      buffer[strlen(buffer) - 1] = '\0';
      if (buffer[0] == ':') {
         strcpy(hulp,&buffer[1]);
         if (helpteksten == NULL)
         {
            helpteksten = alloc_mem(sizeof(struct helpstr),__LINE__,__FILE__);
            pointer = helpteksten;
         }
         else
         {
            pointer->volgende = alloc_mem(sizeof(struct helpstr),__LINE__,__FILE__);
            pointer = pointer->volgende;
         }
         strcpy_mem(&pointer->label,hulp);
         pointer->tekst    = NULL;
         pointer->volgende = NULL;
      }
      else
      {
         if (strcmp(buffer,"") != 0)
         {
            if (pointer->tekst == NULL)
               strcpy_mem(&pointer->tekst,buffer);
            else
               strupd_mem(&pointer->tekst,buffer);
         }
      }
   }
   fclose(file);
}

/*********************** exit_help_system ************************************
*                                                                            *
*  Description: Routine die zorgt dat al het aangevraagde geheugen wordt     *
*               vrij-gegeven.                                                *
*                                                                            *
*  Parameters:  void                                                         *
*                                                                            *
*  Returns:     void                                                         *
*                                                                            *
*  Other Info:  Geen                                                         *
*                                                                            * 
*****************************************************************************/

void exit_help_system(void)
{
   struct helpstr *pointer1;
   struct helpstr *pointer2;

   pointer1 = helpteksten;
   while (pointer1 != NULL) {
      free_mem(pointer1->label);
      free_mem(pointer1->tekst);
      pointer2 = pointer1;
      pointer1 = pointer1->volgende;
      free_mem(pointer2);
   }
   helpteksten = NULL;
}

/*****************************************************************************
*                                                                            *
*                       Printer driver routines                              *
*                       -----------------------                              *
*                                                                            *
*****************************************************************************/

os_error *PrintAbortJob(int filehandle)
{
   os_regset reg;
   os_error  *err;
                  
   reg.r[0] = filehandle;
   err = os_swix(PDriver_AbortJob,&reg);
   return(err);
}

os_error *PrintEndJob(int filehandle)
{
   os_regset reg;
   os_error  *err;
                  
   reg.r[0] = filehandle;
   err = os_swix(PDriver_EndJob,&reg);
   return(err);
}

os_error *PrintCancelJob(int filehandle)
{
   os_regset reg;
   os_error  *err;
                  
   reg.r[0] = filehandle;
   err = os_swix(PDriver_CancelJob,&reg);
   return(err);
}

os_error *PrintSelectJob(int filehandle,const char *titel,int *prev_filehandle)
{
   os_regset reg;
   os_error  *err;

   titel = titel;               
   reg.r[0] = filehandle;
   reg.r[1] = 0;
   err  = os_swix(PDriver_SelectJob,&reg);
   *prev_filehandle = reg.r[0];
   return(err);
}

os_error *PrintPageSize(int *xsize,int *ysize,
                   int *left,int *bottom,int *right,int *top)
{
   os_regset reg;
   os_error  *err;

   err = os_swix(PDriver_PageSize,&reg);
   *xsize  = reg.r[1];
   *ysize  = reg.r[2];
   *left   = reg.r[3];
   *bottom = reg.r[4];
   *right  = reg.r[5];
   *top    = reg.r[6];
   return(err);
}

os_error *PrintDrawPage(int copies,int pagenum,int *rectangle,int *id,int *more)
{
   os_regset reg;
   os_error  *err;

   reg.r[0] = copies;
   reg.r[1]=(int)rectangle;
   reg.r[2]=pagenum;
   reg.r[3]=0;
   err = os_swix(PDriver_DrawPage,&reg);
   *more = reg.r[0];
   *id = reg.r[2];
   return(err);
}
   
os_error *PrintGiveRectangle(int id,int *rectangle,int *dimentions,int *pos)
{
   os_regset reg;
   os_error  *err;

   reg.r[0] = id;
   reg.r[1] = (int)rectangle;
   reg.r[2] = (int)dimentions;
   reg.r[3] = (int)pos;
   err = os_swix(PDriver_GiveRectangle,&reg);
   return(err);
}

os_error *PrintGetRectangle(int *buf,int *id,int *more)
{
   os_regset reg;
   os_error  *err;

   reg.r[1]=(int)buf;
   err = os_swix(PDriver_GetRectangle,&reg);
   *more = reg.r[0];
   *id = reg.r[2];
   return(err);
}

os_error *PrintGetResolution(int *xres,int *yres)
{
   os_regset reg;
   os_error  *err;

   err = os_swix(PDriver_Info,&reg);
   *xres = reg.r[1];
   *yres = reg.r[2];
   return(err);
}

int ConvertToPoint(int os_unit)
{
   int output;
  
   font_converttopoints(os_unit,os_unit,&output,&output);
   return(output);
}

int ConvertToOS(int point)
{
   int output;

   font_converttoos(point,point,&output,&output);
   return(output);
}

BOOL check_printer_driver(void)
{
   os_error *err;
   int      dummy;

   err = PrintPageSize(&dummy,&dummy,&dummy,&dummy,&dummy,&dummy);
   if (err != NULL) {
      werr(FALSE,"Printer driver not installed");
      return(FALSE);
   }
   return(TRUE);
}

/*************************************************************************
 Error afvang van escape tijdens het printen. Er is een globale variabele
 waarin het filenummer van de huidige print job wordt gezet. Na het drukken
 van escape wordt deze job 'aborted'. Na het printen van de job, moet de
 error handler weer verwijderd worden. Na de error wordt een longjump naar
 'jmp_main' uitgevoerd. Deze moet naar de main poll lus wijzen.
**************************************************************************/

typedef void SignalHandler(int);
FILE *print_job;
static SignalHandler *print_handler;
extern jmp_buf jmp_main;
extern void pdriver_release_error(void);


void print_error(int signal)
{
   signal = signal;
   pdriver_release_error();
   PrintAbortJob(print_job->__file);
   fclose(print_job);
   werr(FALSE,"Printing aborted");
   longjmp(jmp_main,0);
}

void pdriver_error_init(FILE *filehandle)
{
   print_job = filehandle;
   print_handler = signal(SIGINT,print_error);
}

void pdriver_release_error(void)
{
   signal(SIGINT,print_handler);
}

FILE *pdriver_fileptr;
int  pdriver_filehandle;
int  pdriver_oldfilehandle;

/******************************* pdriver_start_job ***************************
*                                                                            *
*  Description: Algemene routine voor het starten van een print job. Deze    *
*               routine moet aangeroepen worden als er begonnen moet worden  *
*               met printen. Na AL het print werk, moet de routine           *
*               pdriver_end_job worden aangeroepen.                          *
*                                                                            *
*  Parameters:  geen                                                         *
*                                                                            *
*  Returns:     BOOL                               True als gelukt is        *
*                                                                            *
*  Other Info:  De hourglass wordt niet aan gezet                            *
*                                                                            * 
*****************************************************************************/

BOOL pdriver_start_job(void)
{          
   os_error *err;

   pdriver_fileptr = fopen("Printer:","wb");
   if (pdriver_fileptr == NULL)
   {
      werr(FALSE,"Unable to open printer output. Is the 'SystemDevices' module unplugged?");
      return( FALSE );
   }
   pdriver_filehandle = (pdriver_fileptr)->__file;
   pdriver_error_init(pdriver_fileptr);
   err = PrintSelectJob(pdriver_filehandle,NULL,&pdriver_oldfilehandle);
   if (err != NULL)
   {
      fclose(pdriver_fileptr);
      print_error(SIGINT);
      return( FALSE );
   }
   return ( TRUE );
}

BOOL pdriver_end_job(void)
{
   os_error *err;

   err = PrintEndJob(pdriver_filehandle);
   if (err != NULL)
   {
      fclose(pdriver_fileptr);
      print_error(SIGINT);
      return(FALSE);
   }
   fclose(pdriver_fileptr);
   PrintSelectJob(pdriver_oldfilehandle,NULL,&pdriver_oldfilehandle);
   pdriver_release_error();

   return ( TRUE );
}

int pdriver_get_type(void)
{
   os_regset reg;

   if (os_swix(PDriver_Info,&reg) != NULL)
   {
      reg.r[0] = -1;
   }
   else
   {
      reg.r[0] = reg.r[0] >> 16;
   }
   return( reg.r[0] );
}

/******************************** print_page *********************************
*                                                                            *
*  Description: Algemene print-pagina routine. Deze routine zorgt ervoor dat *
*               de gegevens voor de printer driver goed worden ge-           *
*               initialiseerd. Hierna wordt de pagina geprint. De routine    *
*               die de gegevens op het scherm zet wordt als parameter mee-   *
*               gegeven. Een pagina ligt tussen de coordinaten 0,0 en        *
*               1280,1900. Hiertussen moet de 'teken' routine alle gegevens  *
*               zetten om de op papier te krijgen.                           *
*                                                                            *
*  Parameters:  BOOL (*draw_info)(void *,int *)    Bouw scherm op routine    *
*               int *pointer                       Pointer die meegegeven    *
*                                                  moet worden aan de bouw-  *
*                                                  scherm op routine.        *
*               int *page                          Pointer naar pagina num.  *
*                                                                            *
*  Returns:     BOOL                               True als printen gelukt is*
*                                                                            *
*  Other Info:  Het pagina nummer wordt meegegeven aan de opbouw routine.    *
*               Het pagina nummer wordt niet automatisch opgehoogd.          *
*               De routine pdriver_start_job moet zijn aangeroepen voordat   *
*               er geprint kan worden.                                       *
*                                                                            * 
*****************************************************************************/

BOOL print_page(BOOL (*draw_info)(void *,int *),void *pointer,int *page)
{
   wimp_paletteword voorgrond;
   wimp_paletteword achtergrond;
   font font_handle;
   os_error *err;
   BOOL done;
   int  dimentions[5];
   int  bounds[5];
   int  recbuf[5];
   int  pos[2];
   int  page_xsize;
   int  page_ysize;
   int  page_left;
   int  page_right;
   int  page_bottom;
   int  page_top;
   int  more;
   int  max;
   int  id;

   err = PrintPageSize(&page_xsize,&page_ysize,&page_left,&page_bottom,&page_right,&page_top);
   voorgrond.word   = 0x00000000;
   achtergrond.word = 0xffffff00;
   max           = 8;
   dimentions[0] = 0x10000;
   dimentions[1] = 0;
   dimentions[2] = 0;
   dimentions[3] = 0x10000;
   bounds[0]     = 0;
   bounds[1]     = 0;
   bounds[2]     = 1280;
   bounds[3]     = 1900;
   pos[1]        = page_top - ConvertToPoint(bounds[3] - bounds[1]);
   pos[0]        = page_left + (page_right - page_left) / 2 - (ConvertToPoint(bounds[2] - bounds[0])) / 2;


   err = PrintGiveRectangle(1,bounds,dimentions,pos);
   if (err != NULL)
   {
      print_error(SIGINT);
      return(FALSE);
   }
   err = PrintDrawPage(1,1,recbuf,&id,&more);
   if (err != NULL)
   {
      print_error(SIGINT);
      return(FALSE);
   }
   while (more != 0 )
   {
      err = os_swi6(ColourTrans_SetGCOL,0xffffff00,0,0,0x80,0,0);
      err = os_swi6(ColourTrans_SetGCOL,0x00000000,0,0,0x00,0,0);
      bbc_clg();
      wimpt_noerr(font_find(PRINT_FONT,PRINT_FONT_SIZE,PRINT_FONT_SIZE,0,0,&font_handle));
      wimpt_noerr(colourtran_setfontcolours(&font_handle,&achtergrond,&voorgrond,&max));
      done = (*draw_info)((void *) pointer,(int *) page);
      wimpt_noerr(font_lose(font_handle));
      err = PrintGetRectangle(recbuf,&id,&more);
      if (err != NULL)
      {
         print_error(SIGINT);
         return(FALSE);
      }
   }
   return(TRUE);
}

void print_demo(int bounds[])
{
   int x0;
   int y0;

   x0 = (bounds[0] + bounds[2]) / 2 - 10*16;
   y0 = (bounds[1] + bounds[3]) / 2;
   bbc_move(x0,y0);
   printf("Demonstration version\n");
}

/*****************************************************************************
*                                                                            *
*                       Edit window management routines                      *
*                       -------------------------------                      *
*                                                                            *
* De volgende routines zorgen ervoor dat 'strings' met behulp van edit       *
* windows ge-edit kunnen worden. Als identificatie van de 'string' wordt de  *
* pointer naar deze 'string' gebruikt. Deze mag dus tijdens het editen niet  *
* veranderen. LET DUS OP BIJ HET VRIJ GEVEN VAN GEHEUGEN. ALS ER EDIT        *
* WINDOW's OPEN ZIJN, SLUIT DEZE DAN.                                        *
*                                                                            *
*****************************************************************************/

char *txt_copy_text(txt t)
{
   int dot_at;
   int max;
   char *text;

   dot_at = txt_dot(t);
   max    = txt_size(t);
   text   = alloc_mem(max + 2,__LINE__,__FILE__);

   txt_setcharoptions(t,txt_DISPLAY,FALSE);
   txt_setdot(t,0);
   txt_charsatdot(t,text,&max);
   txt_setdot(t,dot_at);
   txt_setcharoptions(t,txt_DISPLAY,TRUE);

   /** Maak er een string van een verwijder laatste returns          **/

   max = txt_size(t);
   text[max--] = '\0';
   while (max > 0 && text[max] == '\n' && text[max - 1] == '\n')
   {
      text[max--] = '\0';
   }

   return ( text );
}

BOOL text_window_save_handler(char *filename,txtedit_state *state,void *handle)
{
#ifdef DEMO
   return ( FALSE );
#else
   return ( TRUE );
#endif
}

void text_window_close_handler(char *name,txtedit_state *state,void *handle)
{
   int tel;

   /** Binairy fix in o.txtedit (uit risc_oslib gehaald), laden op 10000  **/
   /** Op geheugen adres 13be8 staat BEQ 13cc8 dit wordt B 13cc8.         **/
   /** Nu moeten we echter met de hand het window weghalen.               **/

   for (tel = 0; tel < MAX_TXT_WINDOWS && txt_state_array[tel] != state; tel++);
   if (txt_state_array[tel] == state)
   {
      free_mem(*txt_text_array[tel]);
      *txt_text_array[tel] = txt_copy_text(txt_state_array[tel]->t);
      txt_dispose(&txt_state_array[tel]->t);        
      txt_state_array[tel] = NULL;
      txt_text_array[tel] = NULL;
   }
}

void close_text_window(char **string)
{
   int tel;

   for (tel = 0; tel < MAX_TXT_WINDOWS && txt_text_array[tel] != string; tel++);
   if (txt_text_array[tel] == string)
   {
      free_mem(*txt_text_array[tel]);
      *txt_text_array[tel] = txt_copy_text(txt_state_array[tel]->t);
      txt_dispose(&txt_state_array[tel]->t);        
      txt_state_array[tel] = NULL;
      txt_text_array[tel] = NULL;
   }
}

void open_text_window(char **string,char *name)
{
   int tel;

   /** Kijk eerst of deze toevallig al ge-edit wordt. Als dit het geval is **/
   /** haal dit window dan naar voren                                      **/

   for (tel = 0; tel < MAX_TXT_WINDOWS && txt_text_array[tel] != string; tel++);
   if (txt_text_array[tel] == string)
   {
      wimp_front_window_easy(txt_syshandle(txt_state_array[tel]->t));
   }
   else
   {
      for (tel = 0; tel < MAX_TXT_WINDOWS && txt_state_array[tel] != NULL; tel++);
      if (tel < MAX_TXT_WINDOWS)
      {
         txt_state_array[tel] = txtedit_install(txt_new(name));
         txt_text_array[tel] = string;
         if (txt_state_array[tel] != NULL)
         {
            strcpy(txt_state_array[tel]->filename,name);
            txt_show(txt_state_array[tel]->t);
            txt_replaceatend(txt_state_array[tel]->t,0,*string,strlen(*string));
         }
      }
   }
}

void init_edit_windows(void)
{
   int tel;

   for (tel = 0; tel < MAX_TXT_WINDOWS; tel++)
   {
      txt_state_array[tel] = NULL;
      txt_text_array[tel] = NULL;
   }
   txtedit_register_close_handler(text_window_close_handler,NULL);
   txtedit_register_save_handler(text_window_save_handler,NULL);
}

