/////////////////////////////////////////////////////////////////////////
// $Id: gui.h 14131 2021-02-07 16:16:06Z vruppert $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2002-2021  The Bochs Project
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

#ifndef BX_GUI_H
#define BX_GUI_H

#include "gui/siminterface.h"

// header bar and status bar stuff
#define BX_HEADER_BAR_Y 32

#define BX_MAX_PIXMAPS 17
#define BX_MAX_HEADERBAR_ENTRIES 12

// align pixmaps towards left or right side of header bar
#define BX_GRAVITY_LEFT 10
#define BX_GRAVITY_RIGHT 11

#define BX_MAX_STATUSITEMS 10

// gui dialog capabilities
#define BX_GUI_DLG_FLOPPY       0x01
#define BX_GUI_DLG_CDROM        0x02
#define BX_GUI_DLG_SNAPSHOT     0x04
#define BX_GUI_DLG_RUNTIME      0x08
#define BX_GUI_DLG_USER         0x10
#define BX_GUI_DLG_SAVE_RESTORE 0x20
#define BX_GUI_DLG_ALL          0x3F

// text mode blink feature
#define BX_TEXT_BLINK_MODE      0x01
#define BX_TEXT_BLINK_TOGGLE    0x02
#define BX_TEXT_BLINK_STATE     0x04

// modifier keys
#define BX_MOD_KEY_SHIFT        0x01
#define BX_MOD_KEY_CTRL         0x02
#define BX_MOD_KEY_ALT          0x04
#define BX_MOD_KEY_CAPS         0x08

// mouse capture toggle feature
#define BX_MT_KEY_CTRL          0x01
#define BX_MT_KEY_ALT           0x02
#define BX_MT_KEY_F10           0x04
#define BX_MT_KEY_F12           0x08
#define BX_MT_MBUTTON           0x10
#define BX_MT_LBUTTON           0x20
#define BX_MT_RBUTTON           0x40

#define BX_GUI_MT_CTRL_MB       (BX_MT_KEY_CTRL | BX_MT_MBUTTON)
#define BX_GUI_MT_CTRL_LRB      (BX_MT_KEY_CTRL | BX_MT_LBUTTON | BX_MT_RBUTTON)
#define BX_GUI_MT_CTRL_F10      (BX_MT_KEY_CTRL | BX_MT_KEY_F10)
#define BX_GUI_MT_F12           (BX_MT_KEY_F12)
#define BX_GUI_MT_CTRL_ALT      (BX_MT_KEY_CTRL | BX_MT_KEY_ALT)

typedef struct {
  Bit16u  start_address;
  Bit8u   cs_start;
  Bit8u   cs_end;
  Bit16u  line_offset;
  Bit16u  line_compare;
  Bit8u   h_panning;
  Bit8u   v_panning;
  bool line_graphics;
  bool split_hpanning;
  Bit8u   blink_flags;
  Bit8u   actl_palette[16];
} bx_vga_tminfo_t;

typedef struct {
  Bit16u bpp, pitch;
  Bit8u red_shift, green_shift, blue_shift;
  Bit8u is_indexed, is_little_endian;
  unsigned long red_mask, green_mask, blue_mask;
  bool snapshot_mode;
} bx_svga_tileinfo_t;


BOCHSAPI_MSVCONLY Bit8u reverse_bitorder(Bit8u);

BOCHSAPI extern class bx_gui_c *bx_gui;

#if BX_SUPPORT_X86_64
  #define BOCHS_WINDOW_NAME "Bochs x86-64 emulator, http://bochs.sourceforge.net/"
#else
  #define BOCHS_WINDOW_NAME "Bochs x86 emulator, http://bochs.sourceforge.net/"
#endif

// The bx_gui_c class provides data and behavior that is common to
// all guis.  Each gui implementation will override the abstract methods.
class BOCHSAPI bx_gui_c : public logfunctions {
public:
  bx_gui_c (void);
  virtual ~bx_gui_c ();
  // Define the following functions in the module for your particular GUI
  // (x.cc, win32.cc, ...)
  virtual void specific_init(int argc, char **argv, unsigned header_bar_y) = 0;
  virtual void text_update(Bit8u *old_text, Bit8u *new_text,
                          unsigned long cursor_x, unsigned long cursor_y,
                          bx_vga_tminfo_t *tm_info) = 0;
  virtual void graphics_tile_update(Bit8u *tile, unsigned x, unsigned y) = 0;
  virtual void handle_events(void) = 0;
  virtual void flush(void) = 0;
  virtual void clear_screen(void) = 0;
  virtual bool palette_change(Bit8u index, Bit8u red, Bit8u green, Bit8u blue) = 0;
  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0, unsigned fwidth=0, unsigned bpp=8) = 0;
  virtual unsigned create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) = 0;
  virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) = 0;
  virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id) = 0;
  virtual void show_headerbar(void) = 0;
  virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)  = 0;
  virtual int set_clipboard_text(char *snapshot, Bit32u len) = 0;
  virtual void mouse_enabled_changed_specific (bool val) = 0;
  virtual void exit(void) = 0;
  // new graphics API methods (compatibility mode in gui.cc)
  virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info);
  virtual Bit8u *graphics_tile_get(unsigned x, unsigned y, unsigned *w, unsigned *h);
  virtual void graphics_tile_update_in_place(unsigned x, unsigned y, unsigned w, unsigned h);
  // new text update API
  virtual void set_font(bool lg) {}
  virtual void draw_char(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
                         Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
                         bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs) {}
  // optional gui methods (stubs or default code in gui.cc)
  virtual void statusbar_setitem_specific(int element, bool active, bool w) {}
  virtual void set_tooltip(unsigned hbar_id, const char *tip) {}
  // set_display_mode() changes the mode between the configuration interface
  // and the simulation.  This is primarily intended for display libraries
  // which have a full-screen mode such as SDL or term.  The display mode is
  // set to DISP_MODE_CONFIG before displaying any configuration menus,
  // for panics that requires user input, when entering the debugger, etc.  It
  // is set to DISP_MODE_SIM when the Bochs simulation resumes.  The
  // enum is defined in gui/siminterface.h.
  virtual void set_display_mode (disp_mode_t newmode) { /* default=no action*/ }
  // These are only needed for the term gui. For all other guis they will
  // have no effect.
  // returns 32-bit bitmask in which 1 means the GUI should handle that signal
  virtual Bit32u get_sighandler_mask () {return 0;}
  // called when registered signal arrives
  virtual void sighandler (int sig) {}
#if BX_USE_IDLE_HACK
  // this is called from the CPU model when the HLT instruction is executed.
  virtual void sim_is_idle(void) {}
#endif
  virtual void show_ips(Bit32u ips_count);
  virtual void beep_on(float frequency);
  virtual void beep_off();
  virtual void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp);
  virtual void set_mouse_mode_absxy(bool mode) {}
#if BX_USE_GUI_CONSOLE
  virtual void set_console_edit_mode(bool mode) {}
#endif

  // The following function(s) are defined already, and your
  // GUI code calls them
  static void key_event(Bit32u key);
  static void set_text_charmap(Bit8u *fbuffer);
  static void set_text_charbyte(Bit16u address, Bit8u data);
  static Bit8u get_mouse_headerbar_id();

  void init(int argc, char **argv, unsigned max_xres, unsigned max_yres,
            unsigned x_tilesize, unsigned y_tilesize);
  void cleanup(void);
  void draw_char_common(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
                        Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
                        bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs);
  void text_update_common(Bit8u *old_text, Bit8u *new_text,
                          Bit16u cursor_address, bx_vga_tminfo_t *tm_info);
  void graphics_tile_update_common(Bit8u *tile, unsigned x, unsigned y);
  bx_svga_tileinfo_t *graphics_tile_info_common(bx_svga_tileinfo_t *info);
  Bit8u* get_snapshot_buffer(void) {return snapshot_buffer;}
  bool palette_change_common(Bit8u index, Bit8u red, Bit8u green, Bit8u blue);
  void update_drive_status_buttons(void);
  static void     mouse_enabled_changed(bool val);
  int register_statusitem(const char *text, bool auto_off=0);
  void unregister_statusitem(int id);
  void statusbar_setitem(int element, bool active, bool w=0);
  static void init_signal_handlers();
  static void toggle_mouse_enable(void);
  bool mouse_toggle_check(Bit32u key, bool pressed);
  const char* get_toggle_info(void);
  Bit8u get_modifier_keys(void);
  Bit8u set_modifier_keys(Bit8u modifier, bool pressed);
  bool parse_user_shortcut(const char *val);
#if BX_DEBUGGER && BX_DEBUGGER_GUI
  void init_debug_dialog(void);
  void close_debug_dialog(void);
#endif
#if BX_USE_GUI_CONSOLE
  bool has_gui_console(void) {return console.present;}
  bool console_running(void) {return console.running;}
  void console_refresh(bool force);
  void console_key_enq(Bit8u key);
  int bx_printf(const char *s);
  char* bx_gets(char *s, int size);
#else
  bool has_gui_console(void) {return 0;}
  bool console_running(void) {return 0;}
  void console_refresh(bool force) {}
  void console_key_enq(Bit8u key) {}
#endif
  bool has_command_mode(void) {return command_mode.present;}
  bool command_mode_active(void) {return command_mode.active;}
  void set_command_mode(bool active);
  void set_fullscreen_mode(bool active) {fullscreen_mode = active;}
  // marklog handler without button, called in gui command mode
  static void marklog_handler(void);

protected:
  // And these are defined and used privately in gui.cc
  // header bar button handlers
  static void floppyA_handler(void);
  static void floppyB_handler(void);
  static void cdrom1_handler(void);
  static void reset_handler(void);
  static void power_handler(void);
  static void copy_handler(void);
  static void paste_handler(void);
  static void snapshot_handler(void);
  static void config_handler(void);
  static void userbutton_handler(void);
  static void save_restore_handler(void);
  // process clicks on the "classic" Bochs headerbar
  void headerbar_click(int x);
  // snapshot helper functions
  static void make_text_snapshot(char **snapshot, Bit32u *length);
  static Bit32u set_snapshot_mode(bool mode);
  // status bar LED timer
  static void led_timer_handler(void *);
  void led_timer(void);
#if BX_USE_GUI_CONSOLE
  void console_init(void);
  void console_cleanup(void);
#else
  void console_cleanup(void) {}
#endif

  // header bar buttons
  bool floppyA_status;
  bool floppyB_status;
  bool cdrom1_status;
  unsigned floppyA_bmap_id, floppyA_eject_bmap_id, floppyA_hbar_id;
  unsigned floppyB_bmap_id, floppyB_eject_bmap_id, floppyB_hbar_id;
  unsigned cdrom1_bmap_id, cdrom1_eject_bmap_id, cdrom1_hbar_id;
  unsigned power_bmap_id,    power_hbar_id;
  unsigned reset_bmap_id,    reset_hbar_id;
  unsigned copy_bmap_id, copy_hbar_id;
  unsigned paste_bmap_id, paste_hbar_id;
  unsigned snapshot_bmap_id, snapshot_hbar_id;
  unsigned config_bmap_id, config_hbar_id;
  unsigned mouse_bmap_id, nomouse_bmap_id, mouse_hbar_id;
  unsigned user_bmap_id, user_hbar_id;
  unsigned save_restore_bmap_id, save_restore_hbar_id;
  // the "classic" Bochs headerbar
  unsigned bx_headerbar_entries;
  struct {
    unsigned bmap_id;
    unsigned xdim;
    unsigned ydim;
    unsigned xorigin;
    unsigned alignment;
    void (*f)(void);
  } bx_headerbar_entry[BX_MAX_HEADERBAR_ENTRIES];
  // text charmap
  Bit8u vga_charmap[0x2000];
  bool charmap_updated;
  bool char_changed[256];
  // status bar items
  unsigned statusitem_count;
  int led_timer_index;
  struct {
    bool in_use;
    char text[8];
    bool active;
    bool mode; // read/write
    bool auto_off;
    Bit8u counter;
  } statusitem[BX_MAX_STATUSITEMS];
  // display mode
  disp_mode_t disp_mode;
  // new graphics API (with compatibility mode)
  bool new_gfx_api;
  Bit16u host_xres;
  Bit16u host_yres;
  Bit16u host_pitch;
  Bit8u host_bpp;
  Bit8u *framebuffer;
  // new text update API
  bool new_text_api;
  Bit16u cursor_address;
  bx_vga_tminfo_t tm_info;
  // maximum guest display size and tile size
  unsigned max_xres;
  unsigned max_yres;
  unsigned x_tilesize;
  unsigned y_tilesize;
  // current guest display settings
  bool guest_textmode;
  Bit8u   guest_fwidth;
  Bit8u   guest_fheight;
  Bit16u  guest_xres;
  Bit16u  guest_yres;
  Bit8u   guest_bpp;
  // graphics snapshot
  bool snapshot_mode;
  Bit8u *snapshot_buffer;
  struct {
    Bit8u blue;
    Bit8u green;
    Bit8u red;
    Bit8u reserved;
  } palette[256];
  // modifier keys
  Bit8u keymodstate;
  // mouse toggle setup
  Bit8u toggle_method;
  Bit32u toggle_keystate;
  char mouse_toggle_text[20];
  // userbutton shortcut
  Bit32u user_shortcut[4];
  int user_shortcut_len;
  bool user_shortcut_error;
  // gui dialog capabilities
  Bit32u dialog_caps;
#if BX_USE_GUI_CONSOLE
  struct {
    bool present;
    bool running;
    Bit8u *screen;
    Bit8u *oldscreen;
    Bit8u saved_fwidth;
    Bit8u saved_fheight;
    Bit16u saved_xres;
    Bit16u saved_yres;
    Bit8u  saved_bpp;
    Bit8u saved_palette[32];
    Bit8u saved_charmap[0x2000];
    unsigned cursor_x;
    unsigned cursor_y;
    Bit16u cursor_addr;
    bx_vga_tminfo_t tminfo;
    Bit8u keys[16];
    Bit8u n_keys;
  } console;
#endif
  // command mode
  struct {
    bool present;
    bool active;
  } command_mode;
  bool fullscreen_mode;
  Bit32u marker_count;
};


// Add this macro in the class declaration of each GUI, to define all the
// required virtual methods.  Example:
//
//    class bx_rfb_gui_c : public bx_gui_c {
//    public:
//      bx_rfb_gui_c (void) {}
//      DECLARE_GUI_VIRTUAL_METHODS()
//    };
// Then, each method must be defined later in the file.
#define DECLARE_GUI_VIRTUAL_METHODS()                                       \
virtual void specific_init(int argc, char **argv,                           \
                           unsigned header_bar_y);                          \
virtual void text_update(Bit8u *old_text, Bit8u *new_text,                  \
                  unsigned long cursor_x, unsigned long cursor_y,           \
                  bx_vga_tminfo_t *tm_info);                                \
virtual void graphics_tile_update(Bit8u *tile, unsigned x, unsigned y);     \
virtual void handle_events(void);                                           \
virtual void flush(void);                                                   \
virtual void clear_screen(void);                                            \
virtual bool palette_change(Bit8u index, Bit8u red, Bit8u green, Bit8u blue); \
virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0,   \
                          unsigned fwidth=0, unsigned bpp=8);               \
virtual unsigned create_bitmap(const unsigned char *bmap,                   \
                               unsigned xdim, unsigned ydim);               \
virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment,     \
                                  void (*f)(void));                         \
virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id);            \
virtual void show_headerbar(void);                                          \
virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes);              \
virtual int set_clipboard_text(char *snapshot, Bit32u len);                 \
virtual void mouse_enabled_changed_specific(bool val);                  \
virtual void exit(void);                                                    \
/* end of DECLARE_GUI_VIRTUAL_METHODS */

#define DECLARE_GUI_NEW_VIRTUAL_METHODS()                                   \
virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info);   \
virtual Bit8u *graphics_tile_get(unsigned x, unsigned y,                    \
                             unsigned *w, unsigned *h);                     \
virtual void graphics_tile_update_in_place(unsigned x, unsigned y,          \
                                       unsigned w, unsigned h);
/* end of DECLARE_GUI_NEW_VIRTUAL_METHODS */

#define BX_KEY_PRESSED  0x00000000
#define BX_KEY_RELEASED 0x80000000

#define BX_KEY_UNHANDLED 0x10000000

enum {
  BX_KEY_CTRL_L,
  BX_KEY_SHIFT_L,

  BX_KEY_F1,
  BX_KEY_F2,
  BX_KEY_F3,
  BX_KEY_F4,
  BX_KEY_F5,
  BX_KEY_F6,
  BX_KEY_F7,
  BX_KEY_F8,
  BX_KEY_F9,
  BX_KEY_F10,
  BX_KEY_F11,
  BX_KEY_F12,

  BX_KEY_CTRL_R,
  BX_KEY_SHIFT_R,
  BX_KEY_CAPS_LOCK,
  BX_KEY_NUM_LOCK,
  BX_KEY_ALT_L,
  BX_KEY_ALT_R,

  BX_KEY_A,
  BX_KEY_B,
  BX_KEY_C,
  BX_KEY_D,
  BX_KEY_E,
  BX_KEY_F,
  BX_KEY_G,
  BX_KEY_H,
  BX_KEY_I,
  BX_KEY_J,
  BX_KEY_K,
  BX_KEY_L,
  BX_KEY_M,
  BX_KEY_N,
  BX_KEY_O,
  BX_KEY_P,
  BX_KEY_Q,
  BX_KEY_R,
  BX_KEY_S,
  BX_KEY_T,
  BX_KEY_U,
  BX_KEY_V,
  BX_KEY_W,
  BX_KEY_X,
  BX_KEY_Y,
  BX_KEY_Z,

  BX_KEY_0,
  BX_KEY_1,
  BX_KEY_2,
  BX_KEY_3,
  BX_KEY_4,
  BX_KEY_5,
  BX_KEY_6,
  BX_KEY_7,
  BX_KEY_8,
  BX_KEY_9,

  BX_KEY_ESC,

  BX_KEY_SPACE,
  BX_KEY_SINGLE_QUOTE,
  BX_KEY_COMMA,
  BX_KEY_PERIOD,
  BX_KEY_SLASH,

  BX_KEY_SEMICOLON,
  BX_KEY_EQUALS,

  BX_KEY_LEFT_BRACKET,
  BX_KEY_BACKSLASH,
  BX_KEY_RIGHT_BRACKET,
  BX_KEY_MINUS,
  BX_KEY_GRAVE,

  BX_KEY_BACKSPACE,
  BX_KEY_ENTER,
  BX_KEY_TAB,

  BX_KEY_LEFT_BACKSLASH,
  BX_KEY_PRINT,
  BX_KEY_SCRL_LOCK,
  BX_KEY_PAUSE,

  BX_KEY_INSERT,
  BX_KEY_DELETE,
  BX_KEY_HOME,
  BX_KEY_END,
  BX_KEY_PAGE_UP,
  BX_KEY_PAGE_DOWN,

  BX_KEY_KP_ADD,
  BX_KEY_KP_SUBTRACT,
  BX_KEY_KP_END,
  BX_KEY_KP_DOWN,
  BX_KEY_KP_PAGE_DOWN,
  BX_KEY_KP_LEFT,
  BX_KEY_KP_RIGHT,
  BX_KEY_KP_HOME,
  BX_KEY_KP_UP,
  BX_KEY_KP_PAGE_UP,
  BX_KEY_KP_INSERT,
  BX_KEY_KP_DELETE,
  BX_KEY_KP_5,

  BX_KEY_UP,
  BX_KEY_DOWN,
  BX_KEY_LEFT,
  BX_KEY_RIGHT,

  BX_KEY_KP_ENTER,
  BX_KEY_KP_MULTIPLY,
  BX_KEY_KP_DIVIDE,

  BX_KEY_WIN_L,
  BX_KEY_WIN_R,
  BX_KEY_MENU,

  BX_KEY_ALT_SYSREQ,
  BX_KEY_CTRL_BREAK,

  BX_KEY_INT_BACK,
  BX_KEY_INT_FORWARD,
  BX_KEY_INT_STOP,
  BX_KEY_INT_MAIL,
  BX_KEY_INT_SEARCH,
  BX_KEY_INT_FAV,
  BX_KEY_INT_HOME,

  BX_KEY_POWER_MYCOMP,
  BX_KEY_POWER_CALC,
  BX_KEY_POWER_SLEEP,
  BX_KEY_POWER_POWER,
  BX_KEY_POWER_WAKE,

  BX_KEY_NBKEYS
};
// If you add BX_KEYs, don't forget this:
// - the last entry must be BX_KEY_NBKEYS
// - upate the scancodes table in the file iodev/scancodes.cc
// - update the bx_key_symbol table in the file gui/keymap.cc


/////////////// GUI plugin support

// Define macro to supply gui plugin code.  This macro is called once in GUI to
// supply the plugin initialization methods.  Since it is nearly identical for
// each gui module, the macro is easier to maintain than pasting the same code
// in each one.
//
// Each gui should declare a class pointer called "theGui" which is derived
// from bx_gui_c, before calling this macro.  For example, the SDL port
// says:
//   static bx_sdl_gui_c *theGui;

#define IMPLEMENT_GUI_PLUGIN_CODE(gui_name)                             \
  PLUGIN_ENTRY_FOR_GUI_MODULE(gui_name)                                 \
  {                                                                     \
    if (mode == PLUGIN_INIT) {                                          \
      genlog->info("installing %s module as the Bochs GUI", #gui_name); \
      theGui = new bx_##gui_name##_gui_c ();                            \
      bx_gui = theGui;                                                  \
    } else if (mode == PLUGIN_PROBE) {                                  \
      return (int)PLUGTYPE_GUI;                                         \
    }                                                                   \
    return(0); /* Success */                                            \
  }

#endif
