
/* Terminality - a portable terminal handling library
 * Copyright (C) 1998-2002, Emil Mikulic.
 * This is LGPL - look at COPYING.LIB
 */

/* $Id: gui.h,v 1.15 2002/07/26 01:39:40 darkmoon Exp $ */

/* Project:     Terminality/GUI
 * File:	gui.h
 * Author:      Emil Mikulic & Michal Safranek
 * Description: Create interface for the Terminality GUI
 */

#ifndef __GUI_H
#define __GUI_H

#include <tn.h>
#include <extra.h>

#include <list.h>
#include <xmem.h>
#include <register.h>
#include <elements.h>
#include <keyhndl.h>

#include <stdarg.h>
#include <string.h>

// localHandle class for local keyhandlers
class localHandle {
public:
	localHandle();
	~localHandle();
	int bind(key k, key (*fce)(key, element_type, void *), int overwrite);
	/*
	 * Short notes about key binding:
	 * You can bind to *any* key except KEY_NOTHING. KEY_NOTHING is reserved
	 * value and therefore can't be bound. Second exception is binding to
	 * KEY_SUPERVISE. (if enabled) KEY_SUPERVISE grants access to *all* keys
	 * so be careful when binding KS to sth like 'return KEY_NOTHING;' :P
	 *
	 * Also keep in mind that keys are stored in (sth like) linked list and
	 * for each key we must 'travel' whole list ... the more keys you register
	 * the more instructions you'll waste.
	 */
	int unbind(key k);
	void removeall();
protected:
	tn_list *local_keys;
	key keyhandler(key k, element_type type);
};


// menuItem class for keeping menu items
class menuItem {
friend class menu;
	char *name;
	int id;
public:

	menuItem();
	menuItem(char *n, int i);
	virtual ~menuItem();
};



// a menu separator line
class menuSeparator : public menuItem {
public:
	menuSeparator() : menuItem("-", -1) {};
	~menuSeparator() {};
};

// the actual menu class
class menu : public localHandle {
protected:
	tn_list *item;	// list of menuitems
	int count;	// how many are there?
	int current;	// currently selected item
	int scroll;	// scrolling for longer menus
	int width;	// widest item's width
	int height;	// height of menu
	int reg_id;	// register_add() id
public:
	bool visible; 		// Visibility of this object
	bool fixed_colors; 	// Disables color updates
	int x, y;		// (x,y) position of menu
	color	FRAME, CORNER, ITEM, ITEM_BG, 
		SELECTED_ITEM, SELECTED_ITEM_BG,
		SCROLL, FRAME_BG;

	menu(menuItem *i, ...);	// initialise list
	~menu();

	// get size of list
	int size(void) const { return count; };

	// draw menu
	void draw(void) const;

	// get choice and return it
	int getchoice(void);

	// set height
	int setheight(int h);

	// Change color scheme
	void change_scheme(void);
};



// hMenuItem class for keeping horizontal menu items
class hMenuItem {
friend class hMenu;
	char *name;
	int id;
	int x;
public:

	hMenuItem(char *n, int xx, int i);
	~hMenuItem();
};



// the actual hotizontal menu class
class hMenu : public localHandle {
protected:
	tn_list *item;	// list of menuitems
	int count;	// how many are there?
	int current;	// currently selected item
	bool active;	// active menu? (are we inside getchoice() ?)
	int reg_id;	// register_add() id

public:
	bool visible;		// Visibility of this object
	bool fixed_colors;	// Disables color updates
	int y;			// (x,y) position of menu
	color	ITEM, ITEM_BG, SELECTED_ITEM,
		SELECTED_ITEM_BG, BACKGROUND;

	hMenu(hMenuItem *i, ...);
	~hMenu();

	// get size of list
	int size(void) const { return count; };

	// draw menu
	void draw(void) const;

	// get choice and return it
	int getchoice(void);

	// Change color scheme
	void change_scheme(void);
};



// input (object) form element
class formObject : public localHandle {
protected:
	element_type type_id;
public:
	void (*onchange)(element_type, void *); // on-change handler
	// It's meaningful only for: check, radio, textbox, textarea
	bool visible; // Visibility of this object
	bool fixed_colors; // Disables color updates

	// Empty constructor/destructor
	formObject() { type_id = Unknown; onchange = NULL; };
	virtual ~formObject() {};

	// Pure virtual routines
	virtual void draw(void) = 0;
	virtual int getnb(void) = 0;

	// 0 - edit box
	// >0 - button, id is given
	virtual int getid(void) { return 0; };

	// Change color scheme
	virtual void change_scheme(void) = 0;

	// Get type of element
	int gettype(void){ return type_id; };
};



/* Checkbox elements */
typedef enum {
	CB_left, CB_check, CB_right, CB_label
} checkbox_element;



// checkbox input class
class checkbox : public formObject {
protected:
	int x, y, width;
	bool focus;
	char *label;
public:
	bool selected;
	char LBOX_CHR, RBOX_CHR, CHECK_CHECKED_CHR, CHECK_UNCHECKED_CHR;
	color	BACKGROUND, LABEL, LABEL_BG, CHECK, CHECK_BG, BOX, BOX_BG,
		SELECTED_LABEL, SELECTED_LABEL_BG, SELECTED_CHECK,
		SELECTED_CHECK_BG, SELECTED_BOX, SELECTED_BOX_BG;

	void (*spc_handle)(int); // On-space handle

	// Plain constructor
	checkbox() { label=NULL; };

	// Construct checkbox at <x,y>
	checkbox(const int xx, const int yy, bool sel);

	// Construct checkbox at <x,y> using <s> for a buffer
	checkbox(const int xx, const int yy, bool sel, const char *s);

	// Construct checkbox at <x,y> using <s> for a buffer, label's width <w>
	checkbox(const int xx, const int yy, bool sel, const char *s,
		const int w);

	// Destroy checkbox
	virtual ~checkbox();

	// Non-blocking get function
	virtual int getnb(void);

	// Blocking get (cannot be aborted)
	bool get(void);

	// Draw checkbox
	virtual void draw(void);

	// Change color scheme
	virtual void change_scheme(void);

protected:
	// Checkbox elements
	virtual void element(const checkbox_element el);
};



// radio group class (needed by radio button)
class radioGroup {
private:
	tn_list *members;
public:
	int selected_id;

	// Constructor
	radioGroup();

	// Add a button to list
	void add(class radio *me);

	// Fix buttons after change
	void fixup(int id);

	// Destructor
	~radioGroup();
};



// radio button class
class radio : public checkbox {
friend class radioGroup;
protected:
	class radioGroup *rgroup;
	int radio_id; // radio's id
public:

	// Construct radio at <x,y>
	radio(class radioGroup *rg, const int id, const int xx, const int yy,
		bool sel);

	// Construct radio at <x,y> using <s> for a buffer
	radio(class radioGroup *rg, const int id, const int xx, const int yy,
		bool sel, const char *s);

	// Construct radio at <x,y> using <s> for a buffer, label's width <w>
	radio(class radioGroup *rg, const int id, const int xx, const int yy,
		bool sel, const char *s, const int w);

	// Destroy radio
	~radio();

	// Non-blocking get function
	virtual int getnb(void);

	// Blocking get (cannot be aborted)
	bool get(void);

	// Draw radio
	virtual void draw(void);

	// Return rGroup ptr
	class radioGroup* getrgroup(void){ return rgroup; };
};



/* Textbox elements */
typedef enum { 
	TB_begin, TB_middle, TB_char, TB_end
} textbox_element;



// textbox input class
class textbox : public formObject {
protected:
	int x, y, width;
	int pos, count;
	bool focus;
	int maxlength;	// max characters
	int scroll;	// current scroll-position

public:
	char *buf;	// buffer holding text
	char *charmap;	// character map - limits entry
	char BEG_CHR, MID_CHR, END_CHR;		// characters
	char BEG_MORE_CHR, END_MORE_CHR;	// characters

	color	TEXT, TEXT_BG, SPACE, SPACE_BG, FRAME, FRAME_BG,
		SELECTED_TEXT, SELECTED_TEXT_BG, SELECTED_SPACE,
		SELECTED_SPACE_BG, SELECTED_FRAME, SELECTED_FRAME_BG;

	// Construct textbox at <x,y> holding <w> characters, maxlength <w>
	textbox(const int xx, const int yy, const int w);

	// Construct textbox at <x,y> using <s> for a buffer, maxl. <strlen(s)>
	textbox(const int xx, const int yy, const char *s);

	// Construct padded textbox at <x,y> using <s> for a buffer, maxl. <w>
	textbox(const int xx, const int yy, const char *s, const int w);

	// Construct textbox at <x,y> holding <w> characters, maxlength <m>
	textbox(const int xx, const int yy, const int w, const int m);

	// Construct padded textbox at <x,y> using <s> for a buffer, maxl. <m>
	textbox(const int xx, const int yy, const char *s, const int w,
		const int m);

	// Destroy textbox
	~textbox();

	// Non-blocking get function
	virtual int getnb(void);

	// Blocking get (cannot be aborted)
	char *get(void);

	// Draw textbox in its current state
	virtual void draw(void);

	// Set tb's content
	int set_buf(char *buffer);

	// Change color scheme
	void change_scheme(void);

protected:
	// Textbox elements
	virtual void element(const textbox_element el);
};



/* Textarea elements */
typedef enum { 
	TA_begin, TA_middle, TA_char, TA_end
} textarea_element;



// textarea input class
class textarea : public formObject {
protected:
	int x, y, width, height;
	int posx, posy, count;
	bool focus;

public:
	char *buf;	// buffer holding text
	char *charmap;	// character map - limits entry
	char BEG_CHR, MID_CHR, END_CHR;	// characters

	color	TEXT, TEXT_BG, SPACE, SPACE_BG, FRAME, FRAME_BG,
		SELECTED_TEXT, SELECTED_TEXT_BG, SELECTED_SPACE,
		SELECTED_SPACE_BG, SELECTED_FRAME, SELECTED_FRAME_BG;

	// Construct textarea at <x,y> width <w> height <h>
	textarea(const int xx, const int yy, const int w, const int h);

	// Construct textarea at <x,y> width <w> height <h> with content <s>
	textarea(const int xx, const int yy, const int w, const int h,
		const char *s);

	// Destroy textarea
	~textarea();

	// Non-blocking get function
	virtual int getnb(void);

	// Blocking get (cannot be aborted)
	char *get(void);

	// Draw textarea in its current state
	virtual void draw(void);

	// Set ta's content
	int set_buf(char *buffer);

	// Change color scheme
	void change_scheme(void);

protected:
	// Textarea elements
	virtual void element(const textarea_element el);
};



// static form decoration
class formStatic {
public:
	bool visible;		// Visibility of this object
	bool fixed_colors;	// Disables color updates

	// Empty constructor/destructor
	formStatic() {};
	virtual ~formStatic() {};

	// Put virtual drawing routine
	virtual void draw(void) = 0;

	// Change color scheme
	virtual void change_scheme(void) = 0;
};



// static text
class staticLabel : public formStatic {
	int x, y;
	char *s;

public:
	color fg, bg;

	// Initialise
	staticLabel(int xx, int yy, char *str);

	// Initialise
	staticLabel(int xx, int yy, char *str, color f, color b);

	// Destructor
	virtual ~staticLabel();

	// Drawing routine
	virtual void draw(void);

	// Change color scheme
	virtual void change_scheme(void);

	// Change label
	void set_label(char *buf);
};



// progress bar
class progressBar : public formStatic {
	int x, y, w, h;
	int max, cur, adv, low_mid, mid_hi;

public:
	color bg, none, low, mid, hi, perc;
	bool show_perc, alt_clr;
	chtype chr_none, chr_low, chr_mid, chr_hi;

	// Initialise
	progressBar(int xx, int yy, int ww, int hh);

	// Initialise
	progressBar(int xx, int yy, int ww, int hh, color _b, color _n,
		color _l, color _m, color _h, color _p);

	// Destructor
	virtual ~progressBar();

	// Drawing routine
	virtual void draw(void);

	// Change color scheme
	virtual void change_scheme(void);

	// Advance progress
	int advance(void);

	// Set units per advance
	int setadv(int units);

	// Set max units
	int setmax(int units);

	// Set current units
	int setcur(int units);

	// Set percents
	int setperc(int f, int s);

private:
	// Set color by percent
	void color_by_perc(int c, int m);

	// Set char by percent
	chtype *char_by_perc(int c, int m);
};



// button
class button : public formObject {
	int x, y, w, h, id;
	char *s;
	bool focus;

public:
	bool dflt;
	color	TEXT, SEL_TEXT, DEF_TEXT, SEL_DEF_TEXT, TL,
		SELECTED_TL, BR, SELECTED_BR, BACKGROUND;

	// Create button
	button(int xx, int yy, int ww, int hh, const char *str, int _id);

	// Destructor
	~button();

	// Get type of object
	virtual int getid(void);

	// Draw button
	virtual void draw(void);

	// Get choice
	virtual int getnb(void);

	// Change color scheme
	virtual void change_scheme(void);
};



// form - a way of keeping lots of widgets together
class form {
	// Lists of form elements
	tn_list *objDyn;
	tn_list *objStatic;
	bool draw_frame;
	int reg_id;	// register_add() id

public:
	bool visible;		// Visibility of this object
	bool fixed_colors;	// Disables color updates
	bool remember_id;	// Enables 'remembering' of position in form
	int last_id; // last active id for 'remembering' - use for setting initial
				 // active element
	
	int x, y, w, h;	// Form anatomy

	// Colors
	color BACKGROUND, BR, TL;

	// Constructor
	form(int xx, int yy, int ww, int hh);

	// Destructor
	virtual ~form();

	// Add dynamic element
	void addobject(formObject *obj);

	// Add static element
	void addstatic(formStatic *obj);

	// Turn on/off form's frame
	void frame(bool shw);

	// Draw form
	void draw(void);

	// Run the form (until a button is hit)
	int run(void);

	// Change color scheme
	void change_scheme(void);

private:
	// Find next visible object
	int find_next_visible(int id);

	// Find previous visible object
	int find_prev_visible(int id);
};


class listing;

// listingItem class for keeping listing items
class listingItem {
protected:
	tn_list *items, *colors;
	char *heading;
	bool separator; // Is this listingSeparator?
	friend class listing; // Not ideal one, but sufficient.

public:
	bool visible; // Visibility of this object
	bool fixed_colors; // Disables color updates
	int x, w;
	color	ITEM, ITEM_BG, EMPTY, EMPTY_BG, HEADING, HEADING_BG, MORE,
		MORE_BG, SELECTED_ITEM, SELECTED_ITEM_BG, SELECTED_EMPTY,
		SELECTED_EMPTY_BG, SELECTED_MORE, SELECTED_MORE_BG;
	char MORE_CHR;

	// constructors
	listingItem();
	listingItem(int xx, int ww, char *hding);
	listingItem(int xx, int ww, char *hding, tn_list *itms);
	listingItem(int xx, int ww, char *hding, tn_list *itms, tn_list *clrs);
	/* clrs: color[4] - ITEM, SELECTED_ITEM, ITEM_BG, SELECTED_ITEM_BG */

	// get size of 'items'
	int size(void) const;

	// draw (possibly <selected>) <n>th item on x,<y>
	// C(more?"with":"without") 'more data' flag
	virtual void draw(int n, int y, bool selected, bool more);

	// destructor
	virtual ~listingItem();

	// Change color scheme
	virtual void change_scheme(void);
};



// a listing separation
class listingSeparator : public listingItem {
public:
	// constructors
	listingSeparator(int xx);
	listingSeparator(int xx, tn_list *clrs);
	listingSeparator(int xx, char sep);
	listingSeparator(int xx, char sep, tn_list *clrs);
	~listingSeparator();
};



// the actual listing class
class listing : public localHandle {
protected:
	tn_list *items;
	int count;
	int current;
	int scroll;
	key (*handle)(key, void *, int);
	int reg_id; // register_add() id

public:
	bool visible; // Visibility of this object
	bool fixed_colors; // Disables color updates
	int x, y, w, h;
	bool more;
	color BACKGROUND;

	listing(int xx, int yy, int ww, int hh, listingItem *i, ...);
	listing(listingItem *i, ...);
	~listing();

	// draw listing
	void draw(void) const;

	// run it
	int run(void);

	// set keypress handle
	void set_handle(key (*fce)(key, void *, int));

	// set default keypress handle
	void default_handle(void);

	// Change color scheme
	void change_scheme(void);

	// Update element count
	void update_count(void);

	// Get element count
	int get_count(void);
};



// 'Custom' object class
class custom {
protected:
	void (*draw_handle)(void);
	void (*chsch_handle)(void);
	int reg_id;
public:
	bool visible;
	bool fixed_colors;

	custom(void (*dh)(void), void (*ch)(void));
	~custom();
	void draw(void);
	void change_scheme(void);
};


// textview class
class textview : public localHandle{
protected:
	tn_list *content;	// content of the textview
	int scroll;	// how many lines was scrolled out?
	int hscroll; // how many chars was scrolled out?
	int maxchars; // Longest line
	int x, y, w, h; // (x,y) position of TW, (w,h) size of TW
	int reg_id; // register_add() id
public:
	color BG, FG;
	bool horiz_scroll; // Horiz. scroll enabled?
	bool beeps; // Beeping enabled?
	bool fixed_colors;

	textview(int xx, int yy, int ww, int hh);
	textview(int xx, int yy, int ww, int hh, char *cont);
	virtual ~textview();
	virtual void draw(void);
	int run(void);
	void set_content(char *str);
	int import_file(char *fname);
	virtual void change_scheme(void);
};

// textview in window
class winTextview : public textview{
private:
	char *title;
public:
	color LF, DF; // Window's frame colors
	
	winTextview(int xx, int yy, int ww, int hh, char *tit);
	winTextview(int xx, int yy, int ww, int hh, char *tit, char *cont);
	~winTextview();
	void draw(void);
	void change_scheme(void);
};

#endif

