// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

// canvas for Windows mode of MIDAS

// canvas31.h and canvas31.cc required major editing to convert from
// OWL 1.0 to OWL 2.0. Almost all the encapsulations that I provided for
// OWL 1.0 are replaced by Borland OWL 2.0 classes. This is not because
// the Borland classes are better (often they are demonstrably inferior, at
// least for our purposes) but because they are probably more robust than
// my versions.

#ifndef SMCANVAS31H
#define SMCANVAS31H

#include <list.h>

#include <owl\button.h>
#include <owl\dialog.h>
#include <owl\edit.h>
#include <owl\listbox.h>
#include <owl\point.h>
#include <owl\printer.h>
#include <owl\scrollba.h>
#include <owl\static.h>
#include <owl\gdiobjec.h>
#include <owl\window.h>
#include <DREstring.h>

#include <resource.h>

// define some typedefs so that at least some of the OWL 1.0 calls still work
typedef TWindow* PTWindow;
typedef TModule* PTModule;
typedef TApplication* PTApplication;

// we declare a bunch of routines that take away some of the drudgery of the
// Windows API 

extern int screen_position_left(HWND);
extern int screen_position_right(HWND);
extern int screen_position_top(HWND);
extern int screen_position_bottom(HWND);

inline int title_height(void)
  { return GetSystemMetrics(SM_CYCAPTION); }

inline int border_height(void)
  { return GetSystemMetrics(SM_CYBORDER); }

inline int border_width(void)
  { return GetSystemMetrics(SM_CXBORDER); }

inline int frame_height(void)
  { return GetSystemMetrics(SM_CYFRAME); }

inline int frame_width(void)
  { return GetSystemMetrics(SM_CXFRAME); }

inline int screen_width(void)
  { return GetSystemMetrics(SM_CXSCREEN); }

inline int screen_height(void)
  { return GetSystemMetrics(SM_CYSCREEN); }

inline boolean mouse_present(void)
  { return GetSystemMetrics(SM_MOUSEPRESENT); }

// calculate the width in pixels of a string in a window
inline int text_width(HWND hwnd, const char* cp)
  { return TWindowDC(hwnd).GetTextExtent(cp, strlen(cp)).cx; }

extern RECT global_rect;

inline HWND hwnd(PTWindow pt)
	 { return pt->HWindow; }

// other casts have to be handled in a similar clumsy manner
RECT& rect(HWND);

// now for a bunch of simple encapsulation classes. Borland should have
// provided these, but it is obvious that their ObjectWindows stuff was
// written by C programmers, not C++ ones

class popup;

// -------------------------------  listbox  ---------------------------
class listbox : public TListBox
{
public:
  listbox(PTWindow AParent, const int AnId, const int X,
	  const int Y, const int W, const int H, PTModule AModule = NULL);
  listbox(PTWindow AParent, const int ResourceId,
	  PTModule AModule = NULL);

  inline HWND window_handle(void)
    { return HWindow; }
  listbox& resize(const int w, const int h);
  listbox& move(const int x, const int y);
  inline listbox& show(const int param = SW_SHOWNORMAL)
    { Show(param); return *this; }
  inline listbox& hide(void)
	 { Show(SW_HIDE); return *this; }
  inline listbox& item(const char* cp)
	 { AddString((char*)cp); return *this; }
  inline listbox& clear(void)
    { ClearList(); return *this; }

  inline int width(void)
    { return Attr.W; }
  inline int height(void)
    { return Attr.H; }
  inline int x(void)
	 { return Attr.X; }
  inline int y(void)
    { return Attr.Y; }

};

// -----------------------------  popup  ---------------------------

// A popup is a window to which we can write. It is encapsulated within
// the win_surf class. A popup cannot be printed _per se_; only the
// win_surf class that encapsulates it can be printed. I have tried
// many ways of using the Borland OWL printer classes to try to
// print a popup directly, but they all fail with obscure exceptions
// in the Borland DLLs. This is a pity, because it would be much neater
// to use their classes (if only they would work).

class popup : public TWindow
{ friend class windows31;
  friend class windows_printer;

  boolean _inverted, _visible;
  int R, G, B, _w, _h;
  char name[20], classname[30];
  TBitmap* current_bitmap;
  TMemoryDC _memdc;

  void _copy_to_screen(void);
  void _copy_to_screen(const int, const int, const int , const int);

public:
  popup(const int r, const int g, const int b, const int w, const int h,
	PTWindow AParent, LPSTR ATitle, boolean is_visible = true, PTModule AModule = NULL);

  ~popup(void);

// If we try to init the bitmap in the constructor, it fails
  void init_bitmap(void);

  void font(TFont&);
  
  LPSTR GetClassName(void)
	 { return classname; }
  void GetWindowClass(WNDCLASS& AWndClass);
  inline HWND window_handle(void)
	 { return HWindow; }
  void copy_to_clipboard(void);
  popup& resize(const int w, const int h);
  popup& move(const int x, const int y);

  reveal(int, width, _w);
  reveal(int, height, _h);

  inline void show(const int param = SW_SHOW)
	 { Show(param); }
  inline void hide(void)
	 { Show(SW_HIDE); }

  inline popup& fgc(const TColor& clr = RGB(255, 255, 255))
	 { _memdc.SetTextColor(clr); return *this; }
  inline popup& bgc(const TColor& clr = RGB(0, 0, 0))
	 { _memdc.SetBkColor(clr); return *this; }
  inline int text_width(DREstring& s)
	 { return (_memdc.GetTextExtent(s, s.length()).cx); }
  inline int text_height(DREstring& s)
	 { return (_memdc.GetTextExtent(s, s.length()).cy); }
  popup& write(DREstring s, const int x = 0, const int y = 0);

  popup& update(void);
  popup& update(const int X, const int Y, const int W, const int H);

  inline popup& set_pen(const TPen& pen)
	 { _memdc.SelectObject(pen); return *this; }

  inline popup& moveto(const int x, const int y)
	 { _memdc.MoveTo(x, y); return *this; }

  inline popup& lineto(const int x, const int y)
	 { _memdc.LineTo(x, y); return *this; }

  inline popup& setpixel(const int x, const int y,
				 const TColor& clr = RGB(255, 255, 255))
	 { _memdc.SetPixel(x, y, clr); return *this; }

  inline boolean bitblt(const int xdest = 0, const int ydest = 0,
								const int w = -1,
								const int h = -1,
								const TDC& dc = NULL, const int xsrc = 0,
								const int ysrc = 0, DWORD rop = BLACKNESS)
  { ::BitBlt(_memdc, xdest, ydest, w == -1 ? width() : w,
				 h == -1 ? height() : h, dc, xsrc, ysrc, rop);
  }

  inline popup& clear(void)
  { bitblt();
	 return *this;
  }

  popup& invert(void);

// the Paint signature is different in OWL 2.0
  void Paint(TDC&, BOOL, TRect&);
  void EvSize(UINT, TSize&);

  void PrintPage(int, TRect&, unsigned);
  popup& print(void);

// declare the response table (OWL Programmers' Guide, p. 132)
  DECLARE_RESPONSE_TABLE(popup);
};

// class to print a popup
/* class popup_printout : public TPrintout
{ TWindow* window;
  TBitmap* bmp;

public:
  popup_printout(TWindow* twp, TBitmap* tbmp,
                 const char* title = "POPUP PRINT") :
   TPrintout(title),
    window(twp),
    bmp(tbmp)
    { }
  void PrintPage(int, TRect&, unsigned);
}; */


// a primary_button is simply a TButton in the right place
class primary_button : public TButton
{ static int _next_x, _next_y, _label_height;

public:
  primary_button(PTWindow AParent, int AnId, LPSTR AText, int W);
};


// ditto for secondary_buttons, but they are more complicated
class secondary_button : public TButton
{ static int _next_x, _next_y, _label_height;

public:
  secondary_button(PTWindow AParent, int AnId, LPSTR AText, int W);
  ~secondary_button(void);
};

// ************************** popup_menu ****************************

// a popup_menu is a modal dialogue; the reason for using a dialogue
// rather than a simple listbox is that a listbox is a dependent
// window and Microsoft provide no way to overide this behaviour and
// make a listbox independent.

class pmd : public TDialog
{ int _x, _y, _selected_index;
  TListBox* tlbp;
  TListBoxData* _data;

public:
  pmd(PTWindow AParent, const char* AName, const int x = 0, const int y = 0);
  ~pmd(void)
	 { delete tlbp;
		delete _data;
	 }

  pmd& item(const char*);
  pmd& selected(const int);
  int execute(void);
  void HandleListBoxMessage(void) /* = [ID_FIRST + ID_POPUP_MENU_LISTBOX]*/;
//  LRESULT HandleMessage(UINT msg);
  void SetupWindow(void);

  DECLARE_RESPONSE_TABLE(pmd);
};

// an edit control class

const int MAX_EDIT_CONTROL_SIZE = 4;
const int STATIC_TEXT_LENGTH = 32;

class edit_control : public TDialog
{ char* _label[MAX_EDIT_CONTROL_SIZE], *_value[MAX_EDIT_CONTROL_SIZE];
  int _x, _y, _n_controls;
  TEdit* edp[MAX_EDIT_CONTROL_SIZE];
  TStatic* stp[MAX_EDIT_CONTROL_SIZE];

// define a transfer buffer
  struct edit_transfer_buffer_struct
  { char buffer[MAX_EDIT_CONTROL_SIZE][32];
  };

  edit_transfer_buffer_struct _edit_transfer_buffer;

public:
  edit_control(PTWindow AParent, const char* AName, const int n_controls,
					const int len = STATIC_TEXT_LENGTH, const int x = 0, const int y = 0);
  ~edit_control(void);

  edit_control& label(const int n, const char*);
  edit_control& value(const int n, const char*);
  inline edit_control& value(const int n, DREstring st)
    { return value(n, (const char*)st); }
    
  inline edit_control& label(const int n, const int v)
    { return label(n, (const char*)DREstring10(v)); }
  inline edit_control& value(const int n, const int v)
    { return value(n, (const char*)DREstring10(v)); }

  inline const char* value(const int n)
	 { return _value[n - 1]; }

  int execute(void);
  void SetupWindow(void);
};

  class popup_menu
{
  class popup_menu_dialog : public TDialog
  { friend class popup_menu;

	 int _x, _y;
	 listbox* lbp;
	 LPSTR title;

  public:
	 popup_menu_dialog(PTWindow AParent, LPSTR AName, const int x,
							 const int y);
	 void HandleListBoxMessage(RTMessage) /* = [ID_FIRST + ID_POPUP_MENU_LISTBOX]*/;
	 LRESULT HandleMessage(UINT msg);
	 void SetupWindow(void) /* = [WM_FIRST + WM_INITDIALOG] */;
/*	 DECLARE_RESPONSE_TABLE(popup_menu_dialog);  */
  };

  glist items;
  TListBoxData* menu_list;
  TApplication* app;
  popup_menu_dialog* dp;

public:
  popup_menu(TWindow* AParent, LPSTR AName, const int ofsx = 0,
	     const int ofsy = 0);
  ~popup_menu(void);

  popup_menu& item(const char* cp);
  popup_menu& selected(const int n);   // wrt 1
  int execute(void);
};

// ************************** popup_slider ****************************

// a popup_slider is a modal dialogue; see "popup_menu" description
// for the reason

class popup_slider
{
  class popup_slider_dialog : public TDialog
  { friend class popup_slider;

    char* _unit;
    int _x, _y, _minval, _maxval, _curval;
    TScrollBar* sbp;
    TButton* ok;
    TStatic* staticp, *staticminp, *staticmaxp;
    LPSTR title;

  public:
    popup_slider_dialog(PTWindow AParent, LPSTR AName, const int x,
		      const int y, const int minval, const int maxval,
		      const int curval, char* unit);
	 void HandleOKMessage(UINT) /* = [ID_FIRST + ID_POPUP_SLIDER_BUTTON] */;
	 void HandleScrollBarMessage(UINT) /* = [ID_FIRST + ID_POPUP_SLIDER_SCROLLBAR] */;
	 void WMInitDialog(UINT) /* = [WM_FIRST + WM_INITDIALOG] */;

	 DECLARE_RESPONSE_TABLE(popup_slider_dialog);
  };

  PTApplication app;
  popup_slider_dialog* dp;

public:
  popup_slider(PTWindow AParent, LPSTR AName, const int ofsx = 0,
	     const int ofsy = 0, const int minval = 0,
	     const int maxval = 100, const int curval = 50,
	     char* unit = "%");
  ~popup_slider(void);

  int execute(void);
};

#endif
