#include <stdio.h>
#include <unistd.h>
#include <gpm.h>
#include <linux/keyboard.h>
#include <ncurses.h>

#define WIDTH 30
#define HEIGHT 10
#define MOVE_DONE 99

int startx = 0;
int starty = 0;

char *choices[] = { "Wahl 1",
                    "Wahl 2",
                    "Wahl 3",
                    "Wahl 4",
                    "Ende",
                  };

/*Anzahl der Menüs zum Auswählen*/
int n_choices = sizeof(choices) / sizeof(char *);

void print_menu(WINDOW *menu_win, int highlight);

int my_handler(Gpm_Event *event, void *data)
{
  int choice = -1;
  /*Eine Art Mouseover-Effekt*/
  if(event->type & GPM_MOVE) /*Maus wurde bewegt?*/
    {
      choice = report_choice(event->x, event->y); /*Wenn ja wo?*/
/*Liefert die Funktion report_choice -1 zurück dann wars außerhalb*/
      if(choice == -1)
          return 0; /*Kein Auswahl*/
      else
          return MOVE_DONE + choice;
    }
  if(event->type & GPM_DOWN)
    {
       choice = report_choice(event->x, event->y);
       if(choice == -1)
           return 0; /*Bedeutet für Gpm_Wgetch() weitermachen*/
       else
           return choice;
    }
  return 0;
}

int main()
{
  Gpm_Connect conn;
  int c, choice = -1;
  WINDOW *menu_win;
/*Standartausgabe auf richtigem Terminal eingestellt?*/
  if(!isatty(STDOUT_FILENO))
    {
       printf("Filedeskriptor stdout ist nicht für das Terminal eingestellt");
       exit(1);
    }

  conn.eventMask = ~0;   /*Alle Mausereignisse*/
  conn.defaultMask = 0;   /*nix davon an gpm*/
  conn.minMod = 0;         /*Keine Taste muss gedrückt werden*/
  conn.maxMod = ~0;      /*....aber es dürfen dennoch alle gedrückt werden*/

  if(Gpm_Open(&conn, 0) == -1){
        printf("Kann keine Verbindung zum Maus-Server herstellen\n");
        exit(0);
       }

  initscr();      /*curses initialisieren*/
  clear();        /*Bildschirm löschen*/
  noecho();     /*keine Zeichen ausgeben*/
  cbreak();      /*Zeilenpufferung ausschalten*/
  startx = (80 - WIDTH) / 2;
  starty = (24 - HEIGHT) / 2;

  menu_win = newwin(HEIGHT, WIDTH, starty, startx);
/*Zeichne neues Fenster und heben Auswahl 1 "Wahl1" hervor*/
  print_menu(menu_win, 1);

  gpm_handler = my_handler; /*Maushandler einrichten*/
  gpm_visiblepointer = 1;   /*Mauszeiger immer sichtbar*/

  while((c = Gpm_Wgetch(menu_win)) != EOF) /*EOF = -1*/
    {
      if(c != -1 && gpm_hflag)
        {
           if(c > MOVE_DONE) /*Wurde ein Menü Ausgewählt?*/
              {
                choice = c - MOVE_DONE; /*Bsp. "Wahl 2" -> 101-99=2*/
 /*Menü neu ausgeben mit neuer  Hervorhebung*/
                print_menu(menu_win, choice);
                continue; /*Und weiter...........*/
              }
           else
              { /*Was haben wir Ausgewählt?*/
                mvprintw(23, 1,
                  "Ihre Wahl ist : %d. Auswahl \"%10s\"", c, choices[c - 1]);
                refresh();
                if(c == n_choices) /*Haben wir ENDE angeklickt?*/
                    break; /*Und tschüss........*/
                print_menu(menu_win, c); /*Fenster neu zeichnen*/
              }
        }
    }
  Gpm_Close();
  endwin(); /*Ende curses.......*/

  return 0;
}

/* "Zeichne" Menü*/
void print_menu(WINDOW *menu_win, int highlight)
{
  int x, y, i;

  x = 2;
  y = 2;
/*Ein Rahmen um das Fenster zeichnen*/
  box(menu_win, 0, 0);
/*Für die Hervorhebung des Mouseover-Effekt*/
  for(i = 0; i < n_choices; ++i)
   {
      if(highlight == i + 1)
        {
          wattron(menu_win, A_REVERSE|A_BOLD); /*Hervorhebung für Auswahl an*/
          mvwprintw(menu_win, y, x, "%s", choices[i]); /*Auswahl mit Hervorhebung
                                                                                         ausgeben*/
          wattroff(menu_win, A_REVERSE|A_BOLD); /*Hervorhebung für Auswahl
                                                                                        wieder aus*/
        }
      else/*Auswahl ausgeben ohne Hervorhebung*/
         mvwprintw(menu_win, y, x, "%s", choices[i]);
      ++y; /*Nächste Zeile*/
    }
  wrefresh(menu_win); /*Zum Schluss Fenster neu Zeichnen*/
}

/*Gibt Ihre Auswahl zurück, wird in der Funktion my_handler aufgerufen*/
int report_choice(int mouse_x, int mouse_y)
{
  int i,j, choice;

  i = startx + 2; /*+2 da String "Wahl n" 2Spalten vom Rand entfernt beginnt*/
  j = starty + 3; /*+3 da String "Wahl n" 3 Zeilen unter Top beginnt*/

  for(choice = 0; choice < n_choices; ++choice)
/*Wir testen alle Möglichkeiten durch*/
    if(mouse_y == j + choice && mouse_x >= i &&
        mouse_x <= i + strlen(choices[choice]))
            break;

  if(choice == n_choices)
     return -1; /*Nix passiert*/
  else
     return (choice + 1); /*...oder neue Position der Auswahl zurückgeben*/
}