/*! ... */

#include "deu.h"
#include "d_misc.h"
#include "i_window.h"

/* maximum number of editing windows that can be open simultaneously */
#define MAX_WINDOWS   20

/* array containing the info for each window */
WindowInfo win_info[MAX_WINDOWS];


/*
   Initialise the info structures for the windows.
*/

void InitWindows(void)
{
  int i;

  for (i = 0; i < MAX_WINDOWS; i++)
    win_info[i].type = WINTYPE_NONE;
}


/*
   Create a new window (return -1 if this is not possible).
   The window is created, but not displayed.  RaiseWindow() must be called
   in order to display the window, after having registered the callbacks.
*/

int CreateNewWindow(int type, char *title /*! + menu definition */)
{
  int i;

  for (i = 0; i < MAX_WINDOWS; i++)
    if (win_info[i].type == WINTYPE_NONE)
      break;
  if (i >= MAX_WINDOWS)
    return -1; /* cannot open new window */
  win_info[i].type = type;
  win_info[i].width = 640;   /*! should be changed */
  win_info[i].height = 480;  /*! should be changed */
  win_info[i].title = title;
  /*! initialise the menu here... */
  win_info[i].action_callback = NULL;
  win_info[i].mousem_callback = NULL;
  win_info[i].redraw_callback = NULL;
  win_info[i].close_callback = NULL;

  /*! on a real windowing system, the window should be created here... */

  /* Note: the string "DEU:" or DEU_VER_NUM followed by a colon will be
     prepended to the title of each window (the title should be a file
     name, map name or object name). */
  return i;
}


/*
   Raise a window to the top of the window stack.
   This function should be called when the window is displayed for the first
   time or when the user switches to this window using an entry in the main
   menu (under DOS, this is the only way to switch to another window, since
   there is no window manager).
*/

void RaiseWindow(int win_num)
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to switch to an invalid window (%d)", win_num);
#endif

#if defined(DEU_GFX_X11)
  /*! XMapRaised(...); */
#else
  /* Under the X Window System, moving a window to the top of the stack will
     generate an Expose event for this window.  This is not the case for DOS
     graphics and this must be simulated by calling the redraw_callback
     function, otherwise nothing would be drawn in the window.
  */
  if (win_info[win_num].redraw_callback != NULL)
    win_info[win_num].redraw_callback(win_num);
#endif
}


/*
   Tell a window to redraw itself.
*/

void RedrawWindow(int win_num)
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to redraw an invalid window (%d)", win_num);
#endif

#if defined(DEU_GFX_X11)
  /* generate an Expose event that will be processed later */
  /*! XClearWindow(..., TRUE); */
#else
  /* Under the X Window System, clearing a window (with send_expose = TRUE)
     will generate an Expose event for this window.  This is not the case for
     DOS graphics and this must be simulated by calling the redraw_callback
     function, otherwise nothing would be drawn in the window.
  */
  if (win_info[win_num].redraw_callback != NULL)
    win_info[win_num].redraw_callback(win_num);
#endif
}


/*
   Close a window and destroy any data associated with it.
   Note: if a "close_callback" has been registered for this window and it
         returns FALSE when called, then the window is not closed (useful
         for confirmation when some edited data has not been saved).
*/

Bool CloseWindow(int win_num)
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to close an invalid window (%d)", win_num);
#endif
  /* call the close_callback and abort if it returns FALSE */
  if ((win_info[win_num].close_callback != NULL)
      && (win_info[win_num].close_callback(win_num) == FALSE))
    return FALSE;
  /* Note: the callback is responsible for freeing any structures that could
     have been allocated, like the level structure or current selection list
     for the map editor */

  /*! on a real windowing system, the window should be destroyed here... */

  /*! destroy the information associated with the menu bar */
  win_info[win_num].type = WINTYPE_NONE;
  return TRUE;
}


/*
   Register a callback function for redrawing the window.
   If this function is not defined for a window, then this window will always
   remain blank.
   Note: if a NULL pointer is given, the callback is disabled.
*/

void RegisterRedrawCB(int win_num, void (*redrawCB)(int window_num))
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to add a redraw_callback to an invalid window (%d)", win_num);
#endif
  win_info[win_num].redraw_callback = redrawCB;
}


/*
   Register a callback function for when the window is closed.
   Note: if a NULL pointer is given, the callback is disabled.
*/

void RegisterCloseCB(int win_num, Bool (*closeCB)(int window_num))
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to add a close_callback to an invalid window (%d)", win_num);
#endif
  win_info[win_num].close_callback = closeCB;
}


/*
   Register a callback function for actions (key pressed, mouse button
   pressed or mouse button released).
   Note: if a NULL pointer is given, the callback is disabled.
*/

void RegisterActionCB(int win_num, void (*actionCB)(int window_num, UInt16 key))
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to add an action_callback to an invalid window (%d)", win_num);
#endif
  win_info[win_num].action_callback = actionCB;
}


/*
   Register a callback function for mouse movements.  This should only be
   enabled for short periods of time (e.g. when drawing in rubber band mode).
   The new coordinates of the mouse pointer will be stored in the global
   variables PointerX and PointerY before this function is called.
   Note: if a NULL pointer is given, the callback is disabled.
*/

void RegisterMousemCB(int win_num, void (*mousemCB)(int window_num))
{
#ifdef DEBUG_WINDOWS
  if ((win_num < 0) || (win_num > MAX_WINDOWS)
      || (win_info[win_num].type == WINTYPE_NONE))
    ProgError("BUG: Trying to add a mousem_callback to an invalid window (%d)", win_num);
#endif
  win_info[win_num].mousem_callback = mousemCB;
}


/* end of file */
