/*
** $VER: gui.c 1.1 (04 Jun 1996)
**
** (C) Copyright 1996 Marius Gröger
**     All Rights Reserved
**
** $HISTORY:
**
** 04 Jun 1996 : 001.001 :  sometimes a GUI group wouldn't be closed
** 25 Apr 1996 : 001.000 :  created
*/

#define DEBUG 0

/*F*/ /* includes */

#include <clib/alib_protos.h>
#include <clib/utility_protos.h>
#include <pragmas/utility_pragmas.h>
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>
#include <clib/intuition_protos.h>
#include <pragmas/intuition_pragmas.h>
#include <clib/gadtools_protos.h>
#include <pragmas/gadtools_pragmas.h>
#include <clib/icon_protos.h>
#include <pragmas/icon_pragmas.h>
#include <clib/locale_protos.h>
#include <pragmas/locale_pragmas.h>
#include <gtlayout/gtlayout.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <workbench/startup.h>
#include <utility/tagitem.h>
#define AsmPools
#include <pools/pool_lib.h>

#if (USE_EXTREADARGS != 0)
#include <extrdargs.h>
#endif

#include "compiler.h"
#include "debug.h"
#define CATCOMP_NUMBERS
#include "locale.h"
#include "sana2meter.h"
#include "constdata.h"

#include <strings.h>
#include <stddef.h>
/*E*/

/*F*/ /* private symbols */
/*E*/
/*F*/ /* exported symbols */
PUBLIC BOOL preparemenu(GD gd);
PUBLIC VOID checkmenu(GD gd);
PUBLIC VOID updategui(GD gd, BOOL complete);
PUBLIC VOID closegui(GD gd);
PUBLIC BOOL opengui(GD gd);
PUBLIC BOOL dowindow(GD gd, DoWindowCtrl *ctrl);
/*E*/
/*F*/ /* imported symbols */
IMPORT ASM STRPTR GetString(REG(a0) struct LocaleInfo *li, REG(d0) LONG stringNum);
IMPORT VOID saveconfig(GD gd);
IMPORT VOID message(GD gd, LONG title, LONG body, LONG button, ...);
IMPORT VOID *allocpvec(GD gd, ULONG len);
IMPORT VOID freepvec(GD gd, VOID *mem);
IMPORT VOID *allocppvec(GD gd, ULONG len);
IMPORT VOID freeppvec(GD gd, VOID *mem);
/*E*/

/*F*/ /* intervals */
PUBLIC const ULONG intervals[] =
{
   {  1 },
   {  2 },
   {  3 },
   {  4 },
   {  5 },
   { 10 },
   { 20 },
   { 30 },
   { 40 },
   { 50 },
   { 60 }
};
/*E*/
/*F*/ /* aging values */
PUBLIC const ULONG agings[] =
{
   {  0 },
   { 10 },
   { 20 },
   { 30 },
   { 40 },
   { 50 }
};
/*E*/
/*F*/ /* menu data structures */
PRIVATE const struct NewMenu menu[] =
{
   NM_TITLE, (STRPTR)MENU_PROJECT,          NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_SAVECONFIG,       NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)NM_BARLABEL,           NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_ABOUT,            NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)NM_BARLABEL,           NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_QUIT,             NULL, 0,                      0, NULL,
   NM_TITLE, (STRPTR)MENU_SETTINGS,         NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_UPDATE,           NULL, 0,                      0, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH1,         NULL, CHECKIT,               ~1, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH2,         NULL, CHECKIT,               ~2, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH3,         NULL, CHECKIT,               ~4, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH4,         NULL, CHECKIT,               ~8, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH5,         NULL, CHECKIT,              ~16, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH10,        NULL, CHECKIT,              ~32, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH20,        NULL, CHECKIT,              ~64, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH30,        NULL, CHECKIT,             ~128, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH40,        NULL, CHECKIT,             ~256, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH50,        NULL, CHECKIT,             ~512, NULL,
   NM_SUB,   (STRPTR)MENU_REFRESH60,        NULL, CHECKIT,            ~1024, NULL,
   NM_ITEM,  (STRPTR)MENU_CPSAGING,         NULL, 0,                      0, NULL,
   NM_SUB,   (STRPTR)MENU_AGING0,           NULL, CHECKIT,               ~1, NULL,
   NM_SUB,   (STRPTR)MENU_AGING10,          NULL, CHECKIT,               ~2, NULL,
   NM_SUB,   (STRPTR)MENU_AGING20,          NULL, CHECKIT,               ~4, NULL,
   NM_SUB,   (STRPTR)MENU_AGING30,          NULL, CHECKIT,               ~8, NULL,
   NM_SUB,   (STRPTR)MENU_AGING40,          NULL, CHECKIT,              ~16, NULL,
   NM_SUB,   (STRPTR)MENU_AGING50,          NULL, CHECKIT,              ~32, NULL,
   NM_ITEM,  (STRPTR)NM_BARLABEL,           NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_JUMP,             NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)NM_BARLABEL,           NULL, 0,                      0, NULL,
   NM_ITEM,  (STRPTR)MENU_STAYFRONT,        NULL, CHECKIT|MENUTOGGLE,     0, NULL,
   NM_ITEM,  (STRPTR)NM_BARLABEL,           NULL, 0,                      0, NULL,
   NM_END
};

#define FIRST_REFRESH_ITEM 8

#define FIRST_AGING_ITEM 20

#define STAYFRONT_ITEM 29

/*E*/

/*F*/ PUBLIC BOOL dowindow(GD gd, DoWindowCtrl *ctrl)
{
   struct IntuiMessage *im;
   ULONG qualifier;
   ULONG class;
   UWORD code;
   struct Gadget *gadget;
   BOOL running = TRUE;
   PD pd = gd->gd_Public;

   *ctrl = DOWCTRL_NOP;

   while(im = GT_GetIMsg(gd->gd_Handle->Window->UserPort))
   {
      class     = im->Class;
      code      = im->Code;
      qualifier = im->Qualifier;
      gadget    = im->IAddress;

      GT_ReplyIMsg(im);

      LT_HandleInput(gd->gd_Handle, qualifier, &class, &code, &gadget);

      switch(class)
      {
         case IDCMP_CLOSEWINDOW:
             running = FALSE;
         break;

         case IDCMP_MENUPICK:
         {
            UWORD n_menu, n_item, n_subitem;
            struct MenuItem *it;

            while(it = ItemAddress(gd->gd_Menu, code))
            {
               n_menu = MENUNUM(code);
               n_item = ITEMNUM(code);
               n_subitem = SUBNUM(code);

               if (n_menu == 0)
               {
                  if (n_item == 0)
                     saveconfig(gd);
                  else
                  if (n_item == 2)
                  {
                     message(gd, REQ_ABOUT_TITLE, REQ_ABOUT_BODY, REQ_ABOUT_BUTTON,
                        VERSION, REVISION, CPUTXT, EMAIL_AUTHOR);
                  }
                  else
                  if (n_item == 4)
                     running = FALSE;
               }
               else if (n_menu == 1)
               {
                  if (n_item == 0)
                  {
                     gd->gd_Refresh = gd->gd_time.tv_secs = intervals[n_subitem];
                     AbortIO((struct IORequest*)&pd->pd_TReq);
                  }
                  else
                  if (n_item == 1)
                  {
                     gd->gd_CPSAging = agings[n_subitem];
                     gd->gd_CPSAgingComp = 100 - gd->gd_CPSAging;
                  }
                  else
                  if (n_item == 3)
                  {
                     if (NextPubScreen(gd->gd_Handle->Screen, gd->gd_Public->pd_Pubscreen))
                        *ctrl = DOWCTRL_REOPEN | DOWCTRL_SHOWWINDOW;
                  }
                  else
                  if (n_item == 5)
                  {
                     if ((gd->gd_StayFront = ((it->Flags & CHECKED) != 0)))
                        WindowToFront(gd->gd_Handle->Window);
                  }
                  else
                  if (n_item >= 7)
                  {
                     struct GlobalDevData *gdd;

                     if (gdd = (struct GlobalDevData *)GTMENUITEM_USERDATA(it))
                     {
                        gdd->gd_Active = ((it->Flags & CHECKED) != 0);
                        *ctrl = DOWCTRL_UPDATE;
                     }
                  }
               }
               else if (n_menu >= 2)
               {
                  struct Watch *w;

                  if (w = (struct Watch *)GTMENUITEM_USERDATA(it))
                  {
                     if (it->Flags & CHECKED)
                        w->w_Flags |= WF_ACTIVE;
                     else
                        w->w_Flags &= ~WF_ACTIVE;
                     *ctrl = DOWCTRL_UPDATE;
                  }
               }
               code = it->NextSelect;
            }
         }
         break;

         case IDCMP_GADGETUP:
         break;
      }
   }

   return running;
}
/*E*/

/*F*/ PUBLIC BOOL preparemenu(GD gd)
{
   struct NewMenu *nm;
   struct Watch *w;
   ULONG i, ss;
   BOOL rc = TRUE;
   struct GlobalDevData *gdd;
   WORD extraitems;

   /* calculate the number of additional menu items for display control */
   extraitems = 0;

   /* device selection */
   extraitems += gd->gd_NumDevices;

   SCANDEVS(gdd, &gd->gd_Devices)
   {
      /* Menu Title */
      extraitems += 1;
      /* Std. DeviceQuery+Stats */
      extraitems += NUM_STDWATCHES;
      /* SpecialStats */
      extraitems += gdd->gd_ValidSpecialStats;
      /* Type-Tracking */
      extraitems += gdd->gd_NumTT * (NUM_TTWATCHES + 1);
   }

   if (gd->gd_NewMenu = allocpvec(gd, sizeof(menu) + extraitems*sizeof(struct NewMenu)))
   {
      CopyMem((void*)menu, (void*)gd->gd_NewMenu, sizeof(menu));

      for (nm = gd->gd_NewMenu; nm->nm_Type != NM_END; ++nm)
      {
         STRPTR p;

         if ((nm->nm_Label != NM_BARLABEL) && !(menu->nm_Type & NM_IGNORE))
         {
            p = GetString(&gd->gd_LocaleInfo, (LONG)nm->nm_Label);
            if (p[1] == '\0')
            {
               nm->nm_CommKey = p;
               nm->nm_Label = p+2;
            }
            else
               nm->nm_Label = p;
         }
      }

      gd->gd_DevSelStart = nm;

      SCANDEVS(gdd, &gd->gd_Devices)
      {
         nm->nm_Type = NM_ITEM;
         nm->nm_UserData = (APTR)gdd;
         nm->nm_Label = gdd->gd_Title;
         nm->nm_Flags = CHECKIT|MENUTOGGLE;
         nm->nm_CommKey = NULL;
         ++nm;
      }

      gd->gd_WatchStart = nm;

      SCANDEVS(gdd, &gd->gd_Devices)
      {
         /* Menu Title */
         nm->nm_Type = NM_TITLE;
         nm->nm_Label = gdd->gd_Title;
         ++nm;

         /* Std. DeviceQuery+Stats */
         for (i=0, w = gdd->gd_StdWatches; i<NUM_STDWATCHES; ++nm, ++i, ++w)
         {
            nm->nm_Type = NM_ITEM;
            nm->nm_UserData = (APTR)w;
            nm->nm_Label = w->w_Label;
            nm->nm_Flags = CHECKIT|MENUTOGGLE;
            nm->nm_CommKey = NULL;
         }
         /* SpecialStats */
         for(ss = gdd->gd_ValidSpecialStats; ss; --ss, ++nm, ++w)
         {
            nm->nm_Type = NM_ITEM;
            nm->nm_UserData = (APTR)w;
            nm->nm_Label = w->w_Label;
            nm->nm_Flags = CHECKIT|MENUTOGGLE;
            nm->nm_CommKey = NULL;
         }

         /* Type-Tracking */
         for (w=gdd->gd_TrackWatches; w->w_Link.mln_Succ; w=(struct Watch*)w->w_Link.mln_Succ, ++nm)
         {
            if (w->w_Flags & WF_FIRSTTT)
            {
               nm->nm_Type = NM_ITEM;
               nm->nm_Label = w->w_TrackType->tt_Label;
               nm->nm_CommKey = NULL;
               nm->nm_Flags = 0;
               nm->nm_UserData = NULL;
               ++nm;
            }
            nm->nm_Type = NM_SUB;
            nm->nm_Label = w->w_Label;
            nm->nm_CommKey = NULL;
            nm->nm_Flags = CHECKIT|MENUTOGGLE;
            nm->nm_UserData = (APTR)w;
         }
      }
      nm->nm_Type = NM_END;
   }
   else rc = TRUE;

   return rc;
}
/*E*/
/*F*/PUBLIC VOID checkmenu(GD gd)
{
   struct NewMenu *nm;
   struct Watch *w;
   struct GlobalDevData *gdd;
   int i;

   for (i=0, nm = gd->gd_NewMenu + FIRST_REFRESH_ITEM; i<NUM_REFRESHS; ++nm, ++i)
   {
      if (intervals[i] == gd->gd_Refresh)
         nm->nm_Flags |= CHECKED;
      else
         nm->nm_Flags &= ~CHECKED;
   }

   for (i=0, nm = gd->gd_NewMenu + FIRST_AGING_ITEM; i<NUM_AGINGS; ++nm, ++i)
   {
      if (agings[i] == gd->gd_CPSAging)
         nm->nm_Flags |= CHECKED;
      else
         nm->nm_Flags &= ~CHECKED;
   }

   nm = gd->gd_NewMenu + STAYFRONT_ITEM;
   if (gd->gd_StayFront)
      nm->nm_Flags |= CHECKED;
   else
      nm->nm_Flags &= ~CHECKED;

   for (i=gd->gd_NumDevices, nm = gd->gd_DevSelStart; i; ++nm, --i)
   {
      if (gdd = (struct GlobalDevData*)nm->nm_UserData)
      {
         if (gdd->gd_Active)
            nm->nm_Flags |= CHECKED;
         else
            nm->nm_Flags &= ~CHECKED;
      }
   }

   for (nm = gd->gd_WatchStart; nm->nm_Type != NM_END; ++nm)
   {
      if (w = (struct Watch*)nm->nm_UserData)
      {
         if (w->w_Flags & WF_OFF)
            nm->nm_Flags |= NM_ITEMDISABLED;

         if (w->w_Flags & WF_ACTIVE)
            nm->nm_Flags |= CHECKED;
         else
            nm->nm_Flags &= ~CHECKED;
      }
   }
   return ;
}
/*E*/

/*F*/ PUBLIC VOID updategui(GD gd, BOOL complete)
{
   struct GlobalDevData *gdd;
   struct Watch *w;

   if (complete)
   {
      SCANDEVS(gdd, &gd->gd_Devices)
      {
         SCANWATCHES(w, &gdd->gd_Watches)
         {
            if (w->w_Flags & WF_ACTIVE)
            {
               LT_SetAttributes(gd->gd_Handle, w->w_ID,
                                       GTNM_Number, *(w->w_Value),
                                       TAG_DONE);
            }
         }
      }
   }
   else
   {
      SCANDEVS(gdd, &gd->gd_Devices)
      {
         SCANWATCHES(w, &gdd->gd_Watches)
         {
            if ((w->w_Flags & (WF_ACTIVE | WF_STATIC)) == WF_ACTIVE)
            {
               LT_SetAttributes(gd->gd_Handle, w->w_ID,
                                       GTNM_Number, *(w->w_Value),
                                       TAG_DONE);
            }
         }
      }
   }

   if (gd->gd_StayFront)
      WindowToFront(gd->gd_Handle->Window);

   return ;
}
/*E*/
/*F*/PUBLIC VOID closegui(GD gd)
{
   if (gd->gd_Handle)
   {
      gd->gd_Left = gd->gd_Handle->Window->LeftEdge;
      gd->gd_Top = gd->gd_Handle->Window->TopEdge;

      LT_DeleteHandle(gd->gd_Handle);
      gd->gd_Handle = NULL;
   }
   if (gd->gd_Menu)
   {
      LT_DisposeMenu(gd->gd_Menu);
      gd->gd_Menu = NULL;
   }
   return ;
}
/*E*/
/*F*/ PUBLIC BOOL opengui(GD gd)
{
   struct GlobalDevData *gdd;
   struct PublicData *pd = gd->gd_Public;
   BOOL rc = FALSE, vgroup;
   int i;
   struct Watch *w;
   STRPTR windowtitle = "SANA2Meter";
   LONG error;

   if (gd->gd_Handle = LT_CreateHandleTags(NULL,
                                 LH_AutoActivate,FALSE,
                                 LH_UserData, gd,
                                 LAHN_MenuGlyphs, TRUE,
                                 gd->gd_CustomFont ? LH_Font : TAG_IGNORE, &pd->pd_Font,
                                 pd->pd_Pubscreen[0] ? LAHN_PubScreenName : TAG_IGNORE, pd->pd_Pubscreen,
                                 TAG_DONE))
   {
      i = 0;
      LT_New(gd->gd_Handle, LA_Type, HORIZONTAL_KIND, TAG_DONE);
      if (gd->gd_NumActives == 0)
      {
         LT_New(gd->gd_Handle, LA_Type, TEXT_KIND,
                        GTTX_Text, GetString(&gd->gd_LocaleInfo, TXT_INACTIVE),
                        TAG_DONE);
      }
      else
      {
         SCANDEVS(gdd, &gd->gd_Devices)
         {
            if (gdd->gd_Active)
            {
               if (gd->gd_NumActives == 1) windowtitle = gdd->gd_Title;
               vgroup = FALSE;
               LT_New(gd->gd_Handle, LA_Type, VERTICAL_KIND,
                                     (gd->gd_NumActives > 1) ?
                                             LA_LabelText : TAG_IGNORE, gdd->gd_Title,
                                     TAG_DONE);
               SCANWATCHES(w, &gdd->gd_Watches)
               {
                  if ((w->w_Flags & WF_FIRSTTT) && (w->w_TrackType->tt_Flags & TTF_ACTIVE))
                  {
                     if (vgroup) {
                        LT_EndGroup(gd->gd_Handle);
                     }
                     LT_New(gd->gd_Handle, LA_Type, VERTICAL_KIND, LA_LabelText, w->w_TrackType->tt_Label, TAG_DONE);
                     vgroup = TRUE;
                  }

                  if (w->w_Flags & WF_ACTIVE)
                  {
                     if (!vgroup)
                     {
                        vgroup = TRUE;
                        LT_New(gd->gd_Handle, LA_Type, VERTICAL_KIND, TAG_DONE);
                     }
                     LT_New(gd->gd_Handle, LA_Type, NUMBER_KIND,
                                           LA_LabelText, w->w_Label,
                                           /*w->w_Format ? GTNM_Format : TAG_IGNORE, w->w_Format,*/
                                           LA_ID, w->w_ID = ++i,
                                           LA_NoKey, TRUE,
                                           LA_Chars, 9,
                                           w->w_Value ? GTNM_Number : TAG_IGNORE, *(w->w_Value),
                                           LA_ExtraSpace, -1,
                                           (GadToolsBase->lib_Version == 39) ?
                                                TAG_IGNORE : GTNM_Justification, GTJ_RIGHT,
                                           TAG_DONE);
                  }
               }
               if (vgroup) {
                  LT_EndGroup(gd->gd_Handle);
               }
               LT_EndGroup(gd->gd_Handle);
            }
         }
      }
      LT_EndGroup(gd->gd_Handle);

      checkmenu(gd);
      if (gd->gd_Menu = LT_NewMenuTemplate(gd->gd_Handle->Screen, NULL,
                                           gd->gd_Handle->AmigaGlyph,
                                           gd->gd_Handle->CheckGlyph,
                                           &error, gd->gd_NewMenu))
      {
         if (LT_Build(gd->gd_Handle, LAWN_Title,        windowtitle,
                                     LAWN_IDCMP,        IDCMP_CLOSEWINDOW,
                                     LAWN_SmartZoom,    TRUE,
                                     LAWN_Menu,         gd->gd_Menu,
                                     LAWN_Left,         gd->gd_Left,
                                     LAWN_Top,          gd->gd_Top,
                                     WA_Activate,       gd->gd_Inactive ? FALSE : TRUE,
                                     WA_DepthGadget,    TRUE,
                                     WA_DragBar,        TRUE,
                                     WA_CloseGadget,    TRUE,
                                     TAG_DONE))
         {
            ULONG pen = gd->gd_Handle->DrawInfo->dri_Pens[HIGHLIGHTTEXTPEN];

            if (gd->gd_ToBack)
            {
               WindowToBack(gd->gd_Handle->Window);
               gd->gd_ToBack = 0;
            }
            gd->gd_Inactive = 0;

            if (gd->gd_NumActives != 0)
            {
               SCANDEVS(gdd, &gd->gd_Devices)
               {
                  SCANWATCHES(w, &gdd->gd_Watches)
                  {
                     if (w->w_Flags & WF_ACTIVE)
                        LT_SetAttributes(gd->gd_Handle, w->w_ID, GTNM_FrontPen, pen, TAG_DONE);
                  }
               }
            }
            rc = TRUE;
         }
         else message(gd, REQ_ERROR_TITLE, REQ_ERROR_NOGUI, REQ_ERROR_QUITBUTTON);
      }
      else
      {
         message(gd, REQ_ERROR_TITLE, REQ_ERROR_NOGUI, REQ_ERROR_QUITBUTTON);
      }
   }
   else message(gd, REQ_ERROR_TITLE, REQ_ERROR_NOGUI, REQ_ERROR_QUITBUTTON);

   return rc;
}
/*E*/

