/*
 *  gui.h -- portable gui library, platform independent header
 */

#ifndef gui_H
#define gui_H

#include <setjmp.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <varargs.h>
#include <wchar.h>

#include "wstring.h"

/*
 *  user variables and functions
 */

extern const char *task_name;
extern void task_initialise(void);
extern void task_finalise(void);

/*
 *  #include gui_<platform>.h
 */

#ifdef riscos
  #include "gui_riscos.h"
#elif defined gtk
  #include "gui_gtk.h"
#else
  #error Unknown platform
#endif

/*
 *  main_<platform>.c
 */

extern char **gui_message;

extern int main(int argc, char *argv[]);
extern void gui_initialise(void);
extern void gui_event_loop(void);

/*
 *  window_<platform>.c
 */

#define gui_H_SCROLL_BAR 0x1
#define gui_V_SCROLL_BAR 0x2
#define gui_CLICK 1
#define gui_CLICK_MENU 2
#define gui_CLICK_RIGHT 3
#define gui_DRAG 4
#define gui_DRAG_RIGHT 5

extern gui_window_id gui_create_window(const unsigned int flags,
      char *title,
      const unsigned int width, const unsigned int height,
      void (*close_fn)(gui_window_id window_id),
      void (*redraw_fn)(gui_window_id window_id, unsigned int invalid[]),
      void (*click_fn)(gui_window_id window_id, unsigned int x, unsigned int y,
            unsigned int z),
      void (*resize_fn)(gui_window_id window_id, unsigned int width, unsigned int height),
      bool (*key_fn)(gui_window_id window_id, unsigned int key),
      void (*input_fn)(gui_window_id window_id, wchar_t key),
      void (*menu_fn)(gui_window_id window_id, unsigned int items[]),
      gui_menu_id menu,
      const char *bbar,
      const char *help);
extern void gui_remove_window(const gui_window_id window_id);
extern void gui_refresh_window(const gui_window_id window_id);
extern void gui_refresh_box(const gui_window_id window_id, unsigned int x0,
      unsigned int y0,
      unsigned int x1, unsigned int y1);
extern void gui_window_extent(const gui_window_id window_id,
      unsigned int width, unsigned int height);
extern void gui_fill(unsigned int colour, unsigned int x0, unsigned int y0,
      unsigned int x1, unsigned int y1);
extern void gui_move_box(const gui_window_id window_id, unsigned int x0, unsigned int y0,
      unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2);

/*
 *  dialog_<platform>.c
 */

extern void gui_start_dialog(char *title, unsigned int width,
      bool close, const char *help);
extern gui_window_id gui_create_dialog(void);
extern void ensure_dialog_space(void);
extern void gui_create_label(char *text, const char *help);
extern gui_gadget_id gui_create_text_box(char *text, const char *mask,
      const char *help);
extern gui_gadget_id gui_create_display_box(char *text, char *value,
      const char *help);
extern void gui_create_button(char *text, void (*click_fn)(gui_window_id window_id, gui_gadget_id gadget_id),
      const char *help);

/*
 *  textarea.c
 */

struct gui_ta;
struct gui_ta_content;
struct gui_ta_word;
struct gui_ta_style;
struct gui_ta_position;
struct gui_ta_selection;

struct gui_ta
{
  unsigned long width;
  unsigned long height;
  unsigned long contents;
  unsigned long styles;
  struct gui_ta_content *(*content)[];
  struct gui_ta_style *(*style)[];
};

struct gui_ta_content
{
  enum { CONTENT_SPACE, CONTENT_PARAGRAPH } type;
  unsigned long y0;
  unsigned long y1;
  unsigned long leading;
  unsigned long base;
  unsigned long words;
  enum { ALIGN_LEFT, ALIGN_CENTRE, ALIGN_RIGHT, ALIGN_FULL } align;
  struct gui_ta_word *(*word)[];
};

struct gui_ta_word
{
  signed long x;		/* real x coordinate */
  unsigned long lx;		/* left-align x coordinate */
  unsigned long y;		/* y coordinate */
  unsigned long width;		/* width of text */
  unsigned long style;		/* font style */
  int start : 1;		/* at start of a line */
  int end : 1;			/* at end of a line */
  signed long box_x0;		/* rubout box */
  signed long box_x1;
  wchar_t text[1];
};

#define gui_SIZEOF_GUI_TA_WORD(n) (offsetof(struct gui_ta_word, text) + (n) * sizeof(wchar_t))

struct gui_ta_position
{
  unsigned long content;
  unsigned long word;
  unsigned long offset;
  unsigned long x;
  unsigned long y;
};

struct gui_ta_selection
{
  struct gui_ta_position start;
  struct gui_ta_position end;
};

extern struct gui_ta *gui_ta(unsigned long width);
extern long gui_ta_add_space(struct gui_ta *doc, unsigned long height);
extern int gui_ta_add_paragraph(struct gui_ta *doc, unsigned long leading,
      unsigned long base, wchar_t *text, unsigned long style, unsigned long align);
extern unsigned long gui_ta_get_style(struct gui_ta *doc, unsigned long xsize,
      unsigned long ysize, unsigned long fcolour, unsigned long bcolour, char *font);
extern void gui_ta_render(struct gui_ta *doc, unsigned long x, unsigned long y,
      unsigned int invalid[], struct gui_ta_selection *sel);
extern void gui_ta_position_xy(struct gui_ta *doc, struct gui_ta_position *pos,
      signed long x, unsigned long y);
extern void gui_ta_reformat(struct gui_ta *doc, unsigned long width);
extern unsigned int gui_ta_reformat_paragraph(struct gui_ta *doc,
      struct gui_ta_content *con, unsigned long y, unsigned long width,
      unsigned long *y0_ret, unsigned long *y1_ret);
extern void gui_ta_insert_char(struct gui_ta *doc, struct gui_ta_position *pos,
      wchar_t text, gui_window_id window_id,
      unsigned long x_offset, unsigned long y_offset);
extern void gui_ta_insert_split(struct gui_ta *doc, struct gui_ta_position *pos,
      gui_window_id window_id, unsigned long x_offset, unsigned long y_offset);
extern void gui_ta_insert_newline(struct gui_ta *doc, struct gui_ta_position *pos,
      gui_window_id window_id, unsigned long x_offset, unsigned long y_offset);
extern void gui_ta_position_cwo(struct gui_ta *doc, struct gui_ta_position *pos);
extern void gui_ta_delete(struct gui_ta *doc, struct gui_ta_position *start,
      struct gui_ta_position *end, gui_window_id window_id,
      unsigned long x_offset, unsigned long y_offset);
extern void gui_ta_remove(struct gui_ta *doc);
extern void gui_ta_align(struct gui_ta *doc, unsigned int content, unsigned int align,
      gui_window_id window_id, unsigned int x_offset, unsigned int y_offset);
extern void gui_ta_export(struct gui_ta *doc, const char *path);

/*
 *  textarea_<platform>.c
 */

extern unsigned long gui_ta_text_width(struct gui_ta *doc, const wchar_t *text,
      unsigned long s);
extern void gui_ta_render_text(struct gui_ta *doc, wchar_t *text, unsigned long s,
      unsigned long x, unsigned long y, unsigned long box_x0,
      unsigned long box_y0, unsigned long box_x1, unsigned long box_y1,
      bool sel);
extern unsigned long gui_ta_position_x(struct gui_ta *doc, wchar_t *text, unsigned long s,
      signed long *x);
extern unsigned long gui_ta_position_o(struct gui_ta *doc, wchar_t *text, unsigned long s,
      unsigned long offset);
extern void gui_ta_caret(gui_window_id window_id, struct gui_ta *doc,
      struct gui_ta_position *pos, unsigned long x, unsigned long y);
extern void gui_ta_fill_style(struct gui_ta_style *style);
extern void gui_ta_empty_style(struct gui_ta_style *style);

/*
 *  messages.c
 */

extern char **gui_messages_read(const char *file_name);

/*
 *  menu_<platform>.c
 */

extern gui_menu_id gui_menu(unsigned int base, unsigned int items);
extern void gui_menu_attach(gui_menu_id menu, unsigned int item, gui_menu_id submenu);

/*
 *  log
 */

#ifdef DEBUG
  #define gui_log(fmt, args...) { fprintf(stdout, fmt, ## args); fflush(stdout); }
#else
  #define gui_log(fmt, args...) {}
#endif


#endif
