/* XRACER (C) 1999-2000 Richard W.M. Jones <rich@annexia.org> and other AUTHORS
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: menu.c,v 1.6 2000/03/12 12:58:54 rich Exp $
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#include <GL/glut.h>

#include "xracer.h"
#include "xracer-mode.h"
#include "xracer-text.h"
#include "xracer-log.h"
#include "xracer-menu.h"
#include "xracer-game.h"

static const struct xrMenu *menu; /* Current menu structure. */

static int posn = 0;		/* Current cursor position in screen. */

static void *font = 0;		/* Standard font. */
static int height = 0;		/* Font height. */
static void *small_font = 0;	/* Small font for footnote. */
static int small_height = 0;	/* Height of small font. */

/* Mode structure. */
static void start_mode (const void *args);
static void end_mode (void);
static void display (void);
static int keyboard (unsigned char key, int x, int y);
static int special (int special, int x, int y);

static struct xrMode mode = {
  name: "menu",
  start_mode: start_mode,
  end_mode: end_mode,
  display: display,
  keyboard: keyboard,
  special: special
};

/* Program-level menu initialization. */
void
xrMenuInit ()
{
  /* Select a font for drawing menus in. */
  font = xrTextFindFont ("crillee", 24);
  xrLogAssert (font != 0);

  small_font = xrTextFindFont ("crillee", 14);
  xrLogAssert (small_font != 0);

  height = xrTextGetHeight (font);
  small_height = xrTextGetHeight (small_font);
}

/* Enter this menu. */
void
xrEnterMenu (const struct xrMenu *_menu, const void *args)
{
  menu = _menu;
  xrEnterMode (&mode, args);
  if (menu->name) xrLog (LOG_DEBUG, "enter menu mode: %s", menu->name);
}

static void
start_mode (const void *args)
{
  posn = 0;
  if (menu->start_menu) menu->start_menu (args);
}

static void
end_mode ()
{
  if (menu->end_menu) menu->end_menu ();
}

static void
display ()
{
  int width, total_height, total_width, i, items_x, items_y;

  /* Clear display buffers. */
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* Any background display. */
  if (menu->display_background) menu->display_background ();

  /* Switch to orthographic projection. */
  glMatrixMode (GL_PROJECTION);
  glPushMatrix ();
  glLoadIdentity ();
  glOrtho (0, (GLdouble) xrWidth, 0, (GLdouble) xrHeight, 0, 1000);
  glMatrixMode (GL_MODELVIEW);
  glPushMatrix ();
  glLoadIdentity ();

  /* Enable alpha blending for text. */
  glEnable (GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  /* Display the header. */
  if (menu->title)
    {
      width = xrTextGetWidth (font, menu->title);
      xrTextPuts (font, menu->title, (xrWidth - width) / 2, xrHeight * 1/5);
    }

  /* Work out the overall size of the menu items. */
  total_height = menu->nr_items * height;
  total_width = 0;
  for (i = 0; i < menu->nr_items; ++i)
    {
      width = xrTextGetWidth (font, menu->items[i]);
      if (width > total_width)
	total_width = width;
    }

  /* Where are we going to put the menu items? */
  items_x = (xrWidth - total_width) / 2;
  items_y = (xrHeight - total_height) / 2;

  /* Display the menu items. */
  for (i = 0; i < menu->nr_items; ++i)
    {
      xrTextPuts (font, menu->items[i], items_x, items_y + i * height);
    }

  /* Display the cursor. */
  xrTextPuts (font, ">", items_x - 32, items_y + posn * height);

  /* Display the footer. */
  if (menu->footer)
    {
      width = xrTextGetWidth (small_font, menu->footer);
      xrTextPuts (small_font, menu->footer,
		  (xrWidth - width) / 2, xrHeight * 9/10);
    }

  glDisable (GL_BLEND);

  /* Restore matrices. */
  glMatrixMode (GL_MODELVIEW);
  glPopMatrix ();
  glMatrixMode (GL_PROJECTION);
  glPopMatrix ();
}

static int
keyboard (unsigned char key, int x, int y)
{
  switch (key)
    {
    case '\n':
    case '\r':
    case ' ':
      menu->actions[posn] ();
      return 1;
    }

  return 0;
}

static int
special (int special, int x, int y)
{
  switch (special)
    {
    case GLUT_KEY_UP:
      if (posn > 0)
	posn--;
      return 1;
    case GLUT_KEY_DOWN:
      if (posn < menu->nr_items-1)
	posn++;
      return 1;
    }
  return 0;
}
