/*  MENU.C   SwissBetty: Unit für ein Menü im LPC2220 */

#include "StdTypes.h"
#include "LPC22xx.h"
#include "setup.h"
#include "events.h"
#include "menu.h"
#include "gdi.h"

#if !defined (GCC)
#pragma thumb
#endif

RCST* CurrentMenu;
bool  isEditing;

/*-------------------*/
  /* hier kommen die gewünschten Menüs als #include rein */

#include "BettyMenu.inc"
#include "ADCMenu.inc"
#include "Appfinder.inc"


/*-------------------*/



/**************************************/
/* ein Menü setzen oder abfragen      */
/* Argument: 0 = nur abfragen         */
/**************************************/

RCST* GetSetMenu (RCST* aMenu)
{ RCST* temp;

  temp = CurrentMenu;
  if (aMenu) CurrentMenu = aMenu;
  return temp;
}

/**************************************/
/* Ereignisse an das Menü weitergeben */
/**************************************/

word DispatchEvent (word aEvent)
{ word w;

  if (aEvent==idMenuClear)
  { CurrentMenu = 0;
    return 0;
  }

  if (aEvent==idMenuSelect1)
  {  CurrentMenu = &Betty_Mainmenu;       /* Menü selektieren */
     if (CurrentMenu->OnEvent)            /* Menü initialisieren */
     { w = idMenuInit;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       w = idMenuRedraw;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       return 0;
     }
  }

  if (aEvent==idMenuSelect2)
  {  CurrentMenu = &ADCsee_Mainmenu;      /* Menü selektieren */
     if (CurrentMenu->OnEvent)            /* Menü initialisieren */
     { w = idMenuInit;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       w = idMenuRedraw;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       return 0;
     }
  }

  if (aEvent==idMenuSelect3)
  {  CurrentMenu = &Appfinder_Mainmenu;   /* Menü selektieren */
     if (CurrentMenu->OnEvent)            /* Menü initialisieren */
     { w = idMenuInit;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       w = idMenuRedraw;
       CurrentMenu->OnEvent(CurrentMenu, &w);
       return 0;
     }
  }



  /*
    hier können dann weitere Menüs eingefügt werden
  */



  if (!CurrentMenu) return 0;
  w = aEvent;
  if ((aEvent >= tastMin)&&(aEvent <= tastMax))
    { if (CurrentMenu->OnKey)
      CurrentMenu->OnKey(CurrentMenu, &w);
    }
  else
    { if (CurrentMenu->OnEvent)
      CurrentMenu->OnEvent(CurrentMenu, &w);
    }

 /* hier kann ggf. eine Behandlung nicht erledigter
    Events (w ungleich 0) erfolgen */


  if (DirtyPages)  ScrBlt();
  return w;
}


/*******************************************************/
/* Umrechnen lokaler Koordinaten in Screen-Koordinaten */
/*******************************************************/
void LocalToScreen (RCST* PItem, RECT* R)
{ int x, y;
  while (PItem->Owner)
  { PItem = PItem->Owner;
    x = PItem->R.left;
    y = PItem->R.top;
    R->left   = R->left   + x;
    R->top    = R->top    + y;
    R->right  = R->right  + x;
    R->bottom = R->bottom + y;
  }
}

/*****************************************/
/* umrandet das RECT in Penfarbe         */
/*****************************************/
void Umrande (RECT* Pr, int mode)
{ POINT GA, GB, GC, GD;
  GA.X = Pr->left;  GA.Y = Pr->top;
  GB.X = Pr->right; GB.Y = Pr->top;
  GC.X = Pr->right; GC.Y = Pr->bottom;
  GD.X = Pr->left;  GD.Y = Pr->bottom;
  DrawLine(GA,GB,mode);
  DrawLine(GB,GC,mode);
  DrawLine(GC,GD,mode);
  DrawLine(GD,GA,mode);
}


/*****************************************/
/* ermittelt, ob MenuItem den Focus hat  */
/*****************************************/
bool Ich_selected (RCST* self)
{ RCST** Pr;
  RCST* Tmp;

  if (self->Owner)
  { Pr = (RCST**) self->Owner->Data;
    Tmp = *Pr;
    return ((long)Tmp == (long)self);
  }
  return FALSE;
}

/*****************************************/
/* Hervorhebung des fokussierten         */
/* Dialog-Elementes oder nicht           */
/*****************************************/

void Hervorhebung(RECT* Pr, bool selected)
{ if (selected)
      CgFillRect(Pr, ltgr);
  else
      CgFillRect(Pr, white);
}



/****************************************************************************************
   Panel-Standard-Prozedur
   Tastendrücke verarbeiten. Zuerst wird dem fokussierten Element (so es ein solches gibt)
   den Tastendruck angeboten. Wird er von diesem Element ignoriert, dann versucht der
   PanelKeyHandler damit zu navigieren, d.h. das dem Tastendruck am ehesten entsprechende
   Element ermitteln, selbiges fokussieren und das bisherige und das neue Fokussierte neu
   zeichnen
 ****************************************************************************************/

void PanelKeyHandler (RCST *self, word *aKey)
{ RCST** P;
  RCST* Focussed;
  RCST* Tem;
  RCST* Kandidat;
  RCST* Kandi2;
  int mitteX, mitteY;
  int minX, maxX, minY, maxY;

  P = (RCST**) self->Data;
  Focussed = *P;

  /* wenn es noch gar keinen fokussierten Member gibt, dann nehmen wir den erstbesten */
  if (!Focussed)
  { *P = 0;
    Tem = self->Members;
    while (Tem)
    { if (Tem->Flags & canFocus)
      { *P = Tem;
        goto der_erstbeste;
      }
      else Tem = Tem->danach;
    }

    isEditing = 0;  /* ohne Fokussierbaren gibt es nix zu editieren! */
    return;         /* und ohne Fokussierbaren gibt es auch sonst nichts zu tun! */

    der_erstbeste:
    Focussed = Tem;
  }


  /* Taste an den fokussierten Member weiterleiten */
  if (Focussed->OnKey) Focussed->OnKey(Focussed, aKey);

  /* wenn Taste erledigt, dann raus hier */
  if (! *aKey) return;

  /* So. die Taste ist noch nicht erledigt, also müssen wir es selber tun */

  mitteX = Focussed->R.left + (Focussed->R.right - Focussed->R.left) / 2;
  mitteY = Focussed->R.top  + (Focussed->R.bottom - Focussed->R.top) / 2;

  Kandidat = 0;
  Kandi2   = 0;

  switch (*aKey)
  { case idRechtsTaste:
     { minX = Focussed->R.right;
       Tem = self->Members;
       while (Tem)
       { if (Tem->Flags & canFocus)              /* fokussierbar muß es sein */
         { if (Tem->R.left > minX)               /* linke Seite muß rechts vom aktuellen liegen */
	   { Kandi2 = Tem;
	     if ((Tem->R.top < mitteY) && (Tem->R.bottom > mitteY))
             { if (!Kandidat) Kandidat = Tem;
	       else { if (Tem->R.left < Kandidat->R.left) Kandidat = Tem; }
	     }
	   }
	 }
	 Tem = Tem->danach;
       }
       if (!Kandidat) Kandidat = Kandi2;
       break;
     }

    case idLinksTaste:
     { maxX = Focussed->R.left;
       Tem = self->Members;
       while (Tem)
       { if (Tem->Flags & canFocus)              /* fokussierbar muß es sein */
         { if (Tem->R.right < maxX)              /* rechte Seite muß links vom aktuellen liegen */
	   { Kandi2 = Tem;
	     if ((Tem->R.top < mitteY) && (Tem->R.bottom > mitteY))
             { if (!Kandidat) Kandidat = Tem;
	       else { if (Tem->R.left > Kandidat->R.left) Kandidat = Tem; }
             }
	   }
	 }
	 Tem = Tem->danach;
       }
       if (!Kandidat) Kandidat = Kandi2;
       break;
     }

    case idRaufTaste:
     { maxY = Focussed->R.top;
       Tem = self->Members;
       while (Tem)
       { if (Tem->Flags & canFocus)
         { if (Tem->R.top < maxY)
	   { Kandi2 = Tem;
	     if ((Tem->R.left < mitteX) && (Tem->R.right > mitteX))
              { if (!Kandidat) Kandidat = Tem;
                else { if (Tem->R.top > Kandidat->R.top) Kandidat = Tem; }
	      }
	   }
	 }
	 Tem = Tem->danach;
       }
       if (!Kandidat) Kandidat = Kandi2;
       break;
     }

    case idRunterTaste:
     { minY = Focussed->R.bottom;
       Tem = self->Members;
       while (Tem)
       { if (Tem->Flags & canFocus)
         { if (Tem->R.top > minY)
	   { Kandi2 = Tem;
	     if ((Tem->R.left < mitteX) && (Tem->R.right > mitteX))
             { if (!Kandidat) Kandidat = Tem;
               else { if (Tem->R.top < Kandidat->R.top) Kandidat = Tem; }
	     }
	   }
	 }
	 Tem = Tem->danach;
       }
       if (!Kandidat) Kandidat = Kandi2;
       break;
     }
  }
  if (!Kandidat) return;    /* wenn sich keiner gefunden hat, dann raus hier! */
  *P = Kandidat;            /* ab jetzt ist der Kandidat der Fokussierte */
  Focussed->Draw(Focussed); /* war fokussiert und ist es nicht mehr */
  Kandidat->Draw(Kandidat); /* ist jetzt fokussiert */
  *aKey = 0;
}




/****************************************************************************************
  Panel-Standard-Ereignishandler
  Ereignisse:
   a) idMenuInit:   wird zuerst selbst verarbeitet
   b) alle anderen: Ereignis wird einfach an alle Subviews weitergegeben
 ****************************************************************************************/

void PanelEventHandler (RCST* self, word *aEvent)
{ RCST* Tem;
  RCST** P;

  Tem = self->Members;

  if (*aEvent == idMenuInit)
   { isEditing = 0;                /* Editor ggf. rücksetzen */
     P = (RCST**) self->Data;
     *P = 0;
     while (Tem)  /* wir suchen den ersten Fokussierbaren */
     { if (Tem->Flags & canFocus) goto setfocussed;
       else  Tem = Tem->danach;
     }
    setfocussed: *P = Tem;
   }
  if (*aEvent==idMenuRedraw)
  { self->Draw(self);
    *aEvent = 0;
    return;
  }

  while (Tem)
  { if (Tem->OnEvent) Tem->OnEvent(Tem, aEvent);
    Tem = Tem->danach;
  }
}




/****************************************************************************************
 Panel-Standard-Prozedur
 Panel zeichnen und alle darin enthaltenen Objekte sich zeichnen lassen
 ****************************************************************************************/

const int modetafel[5] = { white, ltgr, dkgr, black, invert };

void PanelDrawProc (RCST* self)
{ RECT  R;
  RCST* Tem;
  byte  mode;

  mode = modetafel[self->Flags & 3];
  R = self->R;
  LocalToScreen(self,&R);
  if (self->Flags & opaque)  CgFillRect (&R, mode);
  if (self->Flags & debrect) Umrande(&R, black);

  Tem = self->Members;
  while (Tem)
  { Tem->Draw(Tem);
    Tem = Tem->danach;
  }
}


/*********************************************/
/* zeichnet einen Knopf mit Text drin,       */
/* falls es Members gibt, werden diese       */
/* auch gezeichnet (z.B.Icons).              */
/* Der eigene Clientbereich wird von links   */
/* beginnend um den von den Members belegten */
/* Bereich reduziert.                        */
/*********************************************/

void ButtonDrawProc (RCST* self)
{ RECT BR;
  RCST* Tmp;
  PFONT aFont;
  int i, j, k;
  char* P;
  bool bin_selected;

  aFont = Get_Font(idf_Helv_14B);

  bin_selected = Ich_selected(self);
  BR = self->R;
  LocalToScreen (self, &BR);
  Hervorhebung(&BR, bin_selected);
  if (self->Flags & opaque)
  { if (self->Flags & debrect) Umrande(&BR, black);
  }
  else Umrande(&BR, ltgr);

  Tmp = self->Members;
  if (Tmp)
  { i = 0;
    while (Tmp)
    { Tmp->Draw(Tmp);
      j = Tmp->R.right;
      if (j>i) i = j;
      Tmp = Tmp->danach;
    }
    BR.left = BR.left + i;
  }

  P = (char*) self->Data;

  i = BR.left;
  k = BR.top;
  if (self->Flags & center)
  { i = StringWidth (P, aFont);
    j = BR.right - BR.left;
    if (i > j) i = j;
    j = (j-i) >> 1;
    i = BR.left + j;
    j = Get_dY(aFont);
    k = BR.bottom - BR.top;
    if (j > k) j = k;
    k = (k - j) >> 1;
    k = BR.top + k;
  }
  CgStr_at (i, k, P, black | idf_Helv_14B);
}


/****************************************/
/* eine einfache Messagebox             */
/****************************************/

const RECT MbxRR = { 0, 30, 127, 156};
const RECT MbxRC = { 2, 32, 125, 154};


void Messagebox (char* Caption, char* Message)
{ PFONT aFont;
  int i, j, x, y, sw;
  RECT  R;
  char* Pa;

  Umrande ((RECT*)&MbxRR, dkgr);
  R = MbxRC;
  CgFillRect (&R, white);

  x = R.left + 2;
  y = R.top + 2;

  aFont = Get_Font(idf_Helv_14B);
  sw = StringWidth (Caption, aFont);
  i = R.right - R.left;
  i = (i - sw) >> 1;
  CgStr_at (x+i, y, Caption, black | idf_Helv_14B);
  y = y + Get_dY(aFont) + 2;

  aFont = Get_Font(idf_Helv_14);
  i = x;
  j = R.right - 2 - Get_dX(aFont,'-');
  Pa = Message;
  while (*Pa)
  { i += CgCh_at(i, y, *Pa++, black | idf_Helv_14);
    if (i >= j)
    { CgCh_at(i, y, '-', black | idf_Helv_14);
      i = x;
      y = y + Get_dY(aFont);
    }
  }
  ScrBlt();
}
