MAG Disk (Jun 1990) : source / OpenWindows.c

#include "PopUpMenu.h"

/* these must be declared here in this silly way (lattice 5.0 bug) */
IMPORT UWORD  chip GhostPattern[];
IMPORT WORD   far  NormalPattern[];
IMPORT struct Image chip MyAmigaKeyImage[];
IMPORT struct Image far MySubItemImage[];


/****************************************
 * OpenMenuWindow()                     *
 *					*
 * Input:				*
 *   none				*
 * Output:				*
 *   return    - TRUE if window opened. *
 ****************************************/

BOOL OpenMenuWindow(MenuTop)
  WORD MenuTop;
{
/*
  IMPORT UWORD far GhostPattern[2];
  IMPORT UWORD far NormalPattern[2];
*/
  IMPORT struct Window	*const ActiveWindow;
  IMPORT struct Menu	*const Menues;
  IMPORT struct Screen	*const Screen;
  IMPORT struct RastPort      Rp;     /* Screens RastPort */
  IMPORT struct WindowData    MenuWindow;
  IMPORT const UWORD	     MenuFontSize;

  WORD	MenuWidth     = 0;
  WORD	MenuHeight    = BORDERSIZE + 1;

 /****************************************
  * Find width & height of window needed *
  ****************************************/
  {
    struct Menu *MenuPtr = Menues;

    do {
      UWORD Length;

      Length = TextLength(&Rp,MenuPtr->MenuName,Mystrlen(MenuPtr->MenuName));
      if (MenuPtr->Width > Length)
	Length = MenuPtr->Width;
      if (Length > MenuWidth)
	MenuWidth = Length;
      MenuHeight += MenuFontSize;
    }
    while ((MenuPtr = MenuPtr->NextMenu) != NULL);

    MenuWidth  += (2 * BORDERSIZE + 1);
  }
 /************************************
  * Position window on screen (Left) *
  ************************************/
  {
    WORD MenuLeft = Screen->MouseX - ((UWORD)MenuWidth / 2);

    if (MenuLeft < 0)
      MenuLeft = 0;
    if (MenuLeft + MenuWidth > Screen->Width)
      MenuLeft = Screen->Width - MenuWidth;

    MenuWindow.LeftEdge  = MenuLeft;
    MenuWindow.Width	 = MenuWidth;
  }
 /***********************************
  * Position window on screen (Top) *
  ***********************************/
  {
    if (MenuTop > MenuHeight) /* menues has changed */
      MenuTop = 0;
    MenuTop  = Screen->MouseY - (MenuFontSize / 2) - MenuTop;

    if (MenuTop < 0)
      MenuTop = 0;
    if (MenuTop + MenuHeight > Screen->Height)
      MenuTop = Screen->Height - MenuHeight;

    MenuWindow.TopEdge	 = MenuTop;
    MenuWindow.Height	 = MenuHeight;
  }
 /*******************************
  * Open window with right size *
  *******************************/

  if (BuildBitMap(&MenuWindow) == FALSE)
    return (FALSE);

 /**********************
  * Fill in all menues *
  **********************/
  {
    const LONG	 MenuLeft = MenuWindow.LeftEdge + BORDERSIZE;
    struct Menu *MenuPtr  = Menues;

    do {
      MenuTop += MenuFontSize;

      SetAPen(&Rp,(LONG)ActiveWindow->DetailPen);
      Move(&Rp,MenuLeft,(LONG)MenuTop - 1);
      Text(&Rp,MenuPtr->MenuName,Mystrlen(MenuPtr->MenuName));

      /* Ghostitem ? */
      if (NOT (MenuPtr->Flags & MENUENABLED)) {
	SetAfPt(&Rp, GhostPattern, 1);
	SetAPen(&Rp,(LONG)ActiveWindow->BlockPen);
	RectFill(&Rp,MenuLeft,
		     (LONG)(MenuTop - MenuFontSize + BORDERSIZE),
		     (LONG)(MenuWindow.RightEdge - BORDERSIZE),
		     (LONG)MenuTop);
	SetAfPt(&Rp,NormalPattern,1);
      }
    }
    while ((MenuPtr = MenuPtr->NextMenu) != NULL);
  }

  return (TRUE);
}

/**************************************************************
 * OpenItemWindow(ItemWindow,ParentWindow,TopPos,WindowType)  *
 *							      *
 * Input:						      *
 *   ItemWindow   - Window to open.			      *
 *   ParentWindow -					      *
 *   TopPos	  - Top position for new window.	      *
 *   WindowType   - ITEMWINDOW or SUBWINDOW		      *
 * Output:						      *
 *   none						      *
 **************************************************************/
VOID OpenItemWindow(ItemWindow,ParentWindow,TopPos,WindowType)
  struct WindowData  *const ItemWindow;
  struct WindowData  *const ParentWindow;
  const WORD TopPos;
  const UWORD WindowType;
{
  IMPORT struct Screen	   *const Screen;
  IMPORT struct WindowData  MenuWindow;
  IMPORT const WORD  MouseX;

  struct WindowSize  Size;

 /****************************************
  * Find width & height of window needed *
  ****************************************/
  {
    struct MenuItem  *Item = ItemWindow->Items;

    Size.Left  = WORD_MAX;
    Size.Top   = WindowType; /* (ITEMWINDOW -> TopPos >= 0), SUBWINDOW -> no limit */
    Size.Right = Size.Bottom = WORD_MIN;

    do {
      CheckItemSize(&Size,Item,(LONG)Item->ItemFill);
      if ((Item->Flags & HIGHFLAGS) == HIGHIMAGE)
	CheckItemSize(&Size,Item,(LONG)Item->SelectFill); /* check highlighted */
    }
    while (Item = Item->NextItem);
  }
 /**********************************************
  * Position window on screen (left)           *
  * Possible positions: 		       *
  *   1. At real position (a'la intuition).    *
  *   2. At right side of parent.	       *
  *   3. At left side of parent.	       *
  *   4. On the side that covers parent least. *
  **********************************************/
  {
    WORD  WindowLeft;
    WORD  LeftValue   = Size.Left - BORDERSIZE;
    UWORD WindowWidth = Size.Right - LeftValue + BORDERSIZE;
    WORD  LeftPos2    = ParentWindow->LeftEdge - WindowWidth + 7;
    WORD  MaxLeft     = Screen->Width - WindowWidth;

    if ((WindowType == ITEMWINDOW) OR
	((WindowLeft = ParentWindow->LeftEdge + LeftValue) > MaxLeft) OR
	(WindowLeft < 0))
      WindowLeft = ParentWindow->RightEdge - 7;

    if (WindowLeft > MaxLeft)
      if (LeftPos2 > MaxLeft - WindowLeft)
	WindowLeft = (LeftPos2 > 0) ? LeftPos2 : 0;
      else
	WindowLeft = MaxLeft;

    if (WindowLeft + WindowWidth < ParentWindow->LeftEdge + 7)
      WindowWidth = ParentWindow->LeftEdge + 7 - WindowLeft;

    ItemWindow->LeftEdge  = WindowLeft;
    ItemWindow->LeftValue = LeftValue - WindowLeft;
    ItemWindow->Width	  = WindowWidth;
  }
 /***********************************
  * Position Window on screen (Top) *
  ***********************************/
  {
    WORD  TopValue     = Size.Top - BORDERSIZE;
    WORD  WindowTop    = TopPos + TopValue;
    UWORD WindowHeight = Size.Bottom - TopValue  + BORDERSIZE;

    if (WindowTop + WindowHeight > Screen->Height)
      WindowTop = Screen->Height - WindowHeight;
    if (WindowTop < 0)
      WindowTop = 0;

    ItemWindow->TopEdge   = WindowTop;
    ItemWindow->TopValue  = TopValue - WindowTop;
    ItemWindow->Height	  = WindowHeight;
  }

  if (BuildBitMap(ItemWindow) == FALSE)
    return;

  DrawAllItems(ItemWindow);
}

/****************************************
 * DrawAllItems(ItemWindow)             *
 *					*
 * Input:				*
 *   ItemWindow  - Window to draw into. *
 *					*
 * Output				*
 *   none				*
 ****************************************/
VOID DrawAllItems(ItemWindow)
  struct WindowData *const ItemWindow;
{
  struct MenuItem *Item = ItemWindow->Items;

  ClearWindow(ItemWindow);

  do
    DrawMenuItem(Item, ItemWindow, ITEMFILL, DONTCLEAROLD);
  while ((Item = Item->NextItem) != NULL);
}

/****************************************************************************
 * DrawMenuItem(Item, ItemWindow, Mode, Clear)                              *
 *									    *
 * Input:								    *
 *   Item -	  Item to draw. 					    *
 *   ItemWindow - Data about window to draw item into			    *
 *   Mode -	  ITEMFILL = Draw Item					    *
 *		  SELECTFILL = Draw selected item (if any)                  *
 *   Clear -	  Clear position before drawing  (Only used with HighImage) *
 * OUTPUT								    *
 *   none								    *
 ****************************************************************************/

VOID DrawMenuItem(Item,ItemWindow,Mode,Clear)
  struct MenuItem *const Item;
  struct WindowData  *const ItemWindow;
  const UWORD Mode;
  const BOOL   Clear;
{
/*
  IMPORT UWORD far GhostPattern[2];
  IMPORT UWORD far NormalPattern[2];
  IMPORT struct Image far MyAmigaKeyImage[2];
  IMPORT struct Image far MySubItemImage[2];
*/

  IMPORT struct RastPort Rp;
  IMPORT struct Window	*const ActiveWindow;
  IMPORT struct Screen	*const Screen;
  IMPORT const BOOL  ScreenType;

  union FillTypes Fill;
  const LONG Left = Item->LeftEdge - ItemWindow->LeftValue;
  const LONG Right = Left + Item->Width - 1;
  const LONG Top = Item->TopEdge - ItemWindow->TopValue;
  const LONG Bottom = Top + Item->Height - 1;

  /* Find what to Draw */
  if (!(Fill.APTR = (Mode == SELECTFILL) ? Item->SelectFill : Item->ItemFill))
    return;  /* nothing to draw */

  SetAPen(&Rp, (LONG)(ActiveWindow->BlockPen));
  SetDrMd(&Rp, JAM1);

  if (Clear)
    /* Erase whay may already be here */
    RectFill(&Rp, Left, Top, Right, Bottom);

  /* Now, draw the item itself -- depending on the Flag value, it    */
  /* could be either an Image or an IntuiText */

  if (Item->Flags & ITEMTEXT)
    PrintIText(&Rp, Fill.IText, Left, Top);
  else
    DrawImage(&Rp,  Fill.Image, Left, Top);

  /* If the item is checkmarked, draw the checkmark. */

  if ((Item->Flags & (CHECKIT | CHECKED)) == (CHECKIT | CHECKED))
    DrawImage(&Rp, ActiveWindow->CheckMark, Left, Top);

  /* If the item has a commandkey, or a subitem */
  {
    const LONG ItemTop	= Top + ((Item->Flags & ITEMTEXT) ?
					 Fill.IText->TopEdge:
					 Fill.Image->TopEdge);

    if (Item->Flags & COMMSEQ) {
      const LONG KeyLeft = Right - Rp.TxWidth;

      DrawImage(&Rp, &MyAmigaKeyImage[ScreenType],KeyLeft, ItemTop);

      Move(&Rp, KeyLeft, ItemTop + Rp.TxHeight - 2);
      SetAPen(&Rp, (LONG)(ActiveWindow->DetailPen));
      Text(&Rp,&Item->Command,1);
    }

    if (Item->SubItem)
      DrawImage(&Rp,&MySubItemImage[ScreenType],Right,ItemTop);
  }

  /* If the ITEMENABLED flag is not set, "ghost" the item. */

  if (!(Item->Flags & ITEMENABLED)) {
    SetAfPt(&Rp, GhostPattern, 1);
    SetAPen(&Rp, (LONG)(ActiveWindow->BlockPen));
    RectFill(&Rp, Left, Top, Right, Bottom);
    SetAfPt(&Rp, NormalPattern, 1);
  }
}

/****************************************
 * BuildBitMap(Window)  - OpenWindow    *
 *					*
 * Input:				*
 *   Window    - Window to open.	*
 * Output:				*
 *   return    - TRUE if window opened. *
 ****************************************/
BOOL BuildBitMap(Window)
  struct WindowData *const Window;
{
  IMPORT struct Screen	 *const Screen;
  IMPORT struct RastPort Rp;

  const LONG WindowWidth  = Window->Width;
  const LONG WindowHeight = Window->Height;

  /* is window to big for screen ? */

  if ((WindowWidth > Screen->Width) OR
      (WindowHeight > Screen->Height))
    return (FALSE);

  Window->RightEdge = Window->LeftEdge + WindowWidth  - 1;
  Window->Bottom    = Window->TopEdge  + WindowHeight - 1;

  /* init bitmap */
  {
    const ULONG Depth = Screen->BitMap.Depth;
    UWORD i;

    InitBitMap(&Window->Bm,Depth,WindowWidth,WindowHeight);

    /* allocate raster for all bitplanes */

    for (i = 0; i < Depth; i++)
      if ((Window->Bm.Planes[i] = AllocRaster(WindowWidth,WindowHeight)) == NULL) {
	RemoveBitMap(Window);
	return(FALSE);
      }
  }

  Window->BitMapOk = TRUE;

  /* make window visible */
  SwapBits(Window);

  ClearWindow(Window);

  return (TRUE);
}

/*********************************
 * ClearWindow(window)           *
 *				 *
 * Input:			 *
 *   Window   - Window to clear. *
 * OutPut:			 *
 *   none			 *
 *********************************/
VOID ClearWindow(Window)
  struct WindowData *const Window;
{
  IMPORT struct RastPort Rp;
  IMPORT struct Window *const ActiveWindow;

  /* window should look like intuitionmenues */
  SetDrMd(&Rp, JAM1);

  SetAPen(&Rp,(LONG)ActiveWindow->BlockPen);
  SetOPen(&Rp,(LONG)ActiveWindow->DetailPen);

  RectFill(&Rp,(LONG)Window->LeftEdge,
	       (LONG)Window->TopEdge,
	       (LONG)Window->RightEdge,
	       (LONG)Window->Bottom);
  BNDRYOFF(&Rp);
}

/******************************
 * CloseItemWindow(Window)    *
 *			      *
 *INPUT 		      *
 *  Window - Window to close. *
 *OUTPUT		      *
 *  none		      *
 ******************************/
VOID CloseItemWindow(Window)
  struct WindowData *const Window;
{
  if (Window->BitMapOk) {
    /* remove window from screen */
    SwapBits(Window);

    /* remove all bitplanes */
    RemoveBitMap(Window);
  }
}

/****************************************************************************
 * RemoveBitMap(Window) - Remove allocated rasters in the BitMap structure. *
 *									    *
 * Input:								    *
 *   Window   - Window with bitmap-					    *
 * Output:								    *
 *   none								    *
 ****************************************************************************/
VOID RemoveBitMap(Window)
  struct WindowData *const Window;
{
  struct BitMap *const Bm = &Window->Bm;
  UWORD  i;

  /* remove all allocated rasters */
  for (i = 0; i < Bm->Depth; i++)
    if (Bm->Planes[i])
      FreeRaster(Bm->Planes[i],(LONG)Window->Width,(LONG)Window->Height);

  Window->BitMapOk = FALSE;
}