/*
 * File:     hello.cc
 * Purpose:  Demo for wxWindows class library
 *
 *                       wxWindows 1.40
 * Copyright (c) 1993 Artificial Intelligence Applications Institute,
 *                   The University of Edinburgh
 *
 *                     Author: Julian Smart
 *                        Date: 18-4-93
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose is hereby granted without fee, provided
 * that the above copyright notice, author statement and this permission
 * notice appear in all copies of this software and related documentation.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
 * IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL THE ARTIFICIAL INTELLIGENCE APPLICATIONS INSTITUTE OR THE
 * UNIVERSITY OF EDINBURGH BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF
 * DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH
 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <windows.h> // Included only for using MS C/C++ precompiled headers
#include "wx.h"
#include "hello.h"

// Declare two frames
MyFrame   *frame = NULL;
wxFrame   *subframe = NULL;
wxMenuBar *menu_bar = NULL;
MyTimer   the_timer;
Bool      timer_on = FALSE;
wxBitmap  *test_bitmap = NULL;
wxIcon    *test_icon = NULL;

// This statement initialises the whole application
MyApp     myApp;

// For drawing lines in a canvas
float     xpos = -1;
float     ypos = -1;

// Must initialise these in OnInit, not statically
wxPen     *red_pen;
wxFont    *small_font;

float     zoom_factor = 1.0;

// The `main program' equivalent, creating the windows and returning the
// main frame
wxFrame *MyApp::OnInit(void)
{
  // Create a red pen
  red_pen = new wxPen("RED", 3, wxSOLID);

  // Create a small font
  small_font = new wxFont(10, wxSWISS, wxNORMAL, wxNORMAL);

  // Create the main frame window
  frame = new MyFrame(NULL, "Hello wxWindows", 0, 0, 400, 550);

  // Give it a status line
  frame->CreateStatusLine();

  // Give it an icon
  test_icon = new wxIcon("aiai_icn");
  frame->SetIcon(test_icon);

  // Make a menubar
  wxMenu *file_menu = new wxMenu;

  file_menu->Append(HELLO_LOAD_FILE, "&Load file");

  wxMenu *pullright_menu = new wxMenu;
  pullright_menu->Append(HELLO_TWIPS, "&Twips");
  pullright_menu->Append(HELLO_LOMETRIC, "&10th mm");
  pullright_menu->Append(HELLO_METRIC, "&Metric");
  pullright_menu->Append(HELLO_NORMAL, "&Normal size");
  pullright_menu->Append(HELLO_ZOOM, "&Zoom...");

  file_menu->Append(HELLO_SCALE, "&Scale picture", pullright_menu);

  file_menu->AppendSeparator();
  file_menu->Append(HELLO_PRINT, "&Print");
#ifdef wx_msw
  file_menu->Append(HELLO_PRINT_EPS, "Print to &EPS file");
  file_menu->Append(HELLO_COPY_MF, "&Copy metafile to clipboard");
#endif
  file_menu->AppendSeparator();
  file_menu->Append(HELLO_QUIT, "&Quit");

  wxMenu *timer_menu = new wxMenu;
  timer_menu->Append(HELLO_TIMER_ON, "Timer &on");
  timer_menu->Append(HELLO_TIMER_OFF, "Timer o&ff");

  wxMenu *cursor_menu = new wxMenu;
  cursor_menu->Append(wxCURSOR_ARROW, "Arrow");
  cursor_menu->Append(wxCURSOR_WAIT, "Wait");
  cursor_menu->Append(wxCURSOR_IBEAM, "Ibeam");
  cursor_menu->Append(wxCURSOR_CROSS, "Cross");
  cursor_menu->Append(wxCURSOR_SIZENWSE, "Size NWSE");
  cursor_menu->Append(wxCURSOR_SIZENESW, "Size NESW");
  cursor_menu->Append(wxCURSOR_SIZEWE, "Size WE");
  cursor_menu->Append(wxCURSOR_SIZENS, "Size NS");
  cursor_menu->Append(wxCURSOR_PENCIL, "Pencil");
  cursor_menu->Append(wxCURSOR_BULLSEYE, "Bullseye");
  cursor_menu->Append(wxCURSOR_MAGNIFIER, "Magnifier");
  cursor_menu->Append(wxCURSOR_HAND, "Hand");
  cursor_menu->Append(wxCURSOR_NO_ENTRY, "No Entry");
  cursor_menu->Append(wxCURSOR_CHAR, "Char");
  cursor_menu->Append(wxCURSOR_LEFT_BUTTON, "Left Button");
  cursor_menu->Append(wxCURSOR_RIGHT_BUTTON, "Right Button");
  cursor_menu->Append(wxCURSOR_MIDDLE_BUTTON, "Middle Button");
  cursor_menu->Append(wxCURSOR_QUESTION_ARROW, "Question arrow");
  cursor_menu->Append(wxCURSOR_SIZING, "Sizing");
  cursor_menu->Append(wxCURSOR_SPRAYCAN, "Spraycan");
  cursor_menu->Append(wxCURSOR_WATCH, "Watch");
  cursor_menu->Append(wxCURSOR_POINT_LEFT, "Point left");
  cursor_menu->Append(wxCURSOR_POINT_RIGHT, "Point right");
  cursor_menu->Append(wxCURSOR_PAINT_BRUSH, "Paint brush");

  wxMenu *help_menu = new wxMenu;
  help_menu->Append(HELLO_ABOUT, "&About");

  menu_bar = new wxMenuBar;

  menu_bar->Append(file_menu, "&File");
  menu_bar->Append(timer_menu, "&Timer");
  menu_bar->Append(cursor_menu, "&Cursor");
  menu_bar->Append(help_menu, "&Help");

  // Associate the menu bar with the frame
  frame->SetMenuBar(menu_bar);

  menu_bar->Enable(HELLO_TIMER_ON, TRUE);
  menu_bar->Enable(HELLO_TIMER_OFF, FALSE);

  // Make a panel
  frame->panel = new wxPanel(frame, 0, 0, 400, 250, wxBORDER);
  frame->panel->SetLabelPosition(wxVERTICAL);

  // Create some panel items

  (void)new wxButton(frame->panel, (wxFunction)&button_proc, "A button");

  (void)new wxText(frame->panel, NULL, "A text item", "Initial value",
                   -1, -1, 200);

  (void)new wxCheckBox(frame->panel, NULL, "A check box");

  frame->panel->NewLine();

  char *choice_strings[] = { "Julian", "Hattie", "Ken", "Dick" };

  wxChoice *choice = new wxChoice(frame->panel, NULL, "A choice item",
                     -1, -1, -1, -1, 4, choice_strings);
  choice->SetSelection(0);

  (void)new wxMessage(frame->panel, "Hello! A simple message");

  wxListBox *list = new wxListBox(frame->panel, (wxFunction)&list_proc, "A list",
                                  wxSINGLE, -1, -1, 100, 100);
  list->Append("Apple");
  list->Append("Pear");
  list->Append("Orange");
  list->Append("Banana");
  list->Append("Fruit");
  
  frame->panel->NewLine();

  (void)new wxSlider(frame->panel, NULL, "A slider",
                     40, 22, 101, 150);

  (void)new wxMultiText(frame->panel, (wxFunction)NULL, "Multiline text", "Some text");

  // Make a text window
  frame->text_window = new wxTextWindow(frame, 0, 250, 400, 250);

  // Make another frame, containing a canvas
  subframe = new wxFrame(NULL, "Canvas Frame", 300, 300, 400, 300);

  int width, height;
  subframe->GetClientSize(&width, &height);

  MyCanvas *canvas = new MyCanvas(subframe, 0, 0, width, height, wxRETAINED);
  wxCursor *cursor = new wxCursor(wxCURSOR_PENCIL);
  canvas->SetCursor(cursor);

  // Give it scrollbars: the virtual canvas is 20 * 50 = 1000 pixels in each direction
  canvas->SetScrollbars(20, 20, 50, 50, 4, 4);
  canvas->SetPen(red_pen);
  frame->canvas = canvas;

  frame->Show(TRUE);
  subframe->Show(TRUE);

  // Load a file into the text window
  frame->text_window->LoadFile("welcome.txt");
  frame->SetStatusText("Hello, wxWindows");

  // Return the main frame window
  return frame;
}

// Define my frame constructor
MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h):
  wxFrame(frame, title, x, y, w, h)
{
  panel = NULL;
  text_window = NULL;
}

// Intercept menu commands
void MyFrame::OnMenuCommand(int id)
{
  wxDC *dc = canvas->GetDC();
  switch (id)
  {
    case HELLO_LOAD_FILE:
    {
      char *s = wxFileSelector("Load text file", NULL, NULL, NULL, "*.txt");
      if (s)
        frame->text_window->LoadFile(s);
      break;
    }
    case HELLO_TWIPS:
    {
      dc->SetMapMode(MM_TWIPS);
      dc->Clear();
      Draw(*dc);
      break;
    }
    case HELLO_METRIC:
    {
      dc->SetMapMode(MM_METRIC);
      dc->Clear();
      Draw(*dc);
      break;
    }
    case HELLO_LOMETRIC:
    {
      dc->SetMapMode(MM_LOMETRIC);
      dc->Clear();
      Draw(*dc);
      break;
    }
    case HELLO_NORMAL:
    {
      dc->SetUserScale(1.0, 1.0);
      dc->SetMapMode(MM_TEXT);
      dc->Clear();
      Draw(*dc);
      break;
    }
    case HELLO_ZOOM:
    {
      char *zoom_factor_s = FloatToString(zoom_factor);
      zoom_factor_s = wxGetTextFromUser("Enter new zoom factor", "Input", zoom_factor_s);
      if (zoom_factor_s)
      {
        StringToFloat(zoom_factor_s, &zoom_factor);
        dc->SetUserScale(zoom_factor, zoom_factor);
        dc->Clear();
        Draw(*dc);
      }
      break;
    }
    case HELLO_QUIT:
    {
      OnClose();
      delete this;
      break;
    }
    case HELLO_PRINT:
    {
      wxDC dc(NULL, NULL, NULL);  // Defaults to EPS under UNIX,
                                  // normal Windows printing under Win 3.1
      if (dc.Ok())
      {
        dc.StartDoc("Hello printout");
        dc.StartPage();
        Draw(dc);
        dc.EndPage();
        dc.EndDoc();
      }
      break;
    }
#ifdef wx_msw
    case HELLO_PRINT_EPS:         // To use the special wxWindows EPS driver
                                  // under Windows 3.1, specify "PostScript"
    {
      wxDC dc(NULL, "PostScript", NULL);
      if (dc.Ok())
      {
        dc.StartDoc("Hello printout");
        dc.StartPage();
        Draw(dc, FALSE);
        dc.EndPage();
        dc.EndDoc();
      }
      break;
    }
    case HELLO_COPY_MF:
    {
      wxMetaFileDC dc;
      if (dc.Ok())
      {
        Draw(dc, FALSE);
        wxMetaFile *mf = dc.Close();
        if (mf)
        {
          Bool success = mf->SetClipboard();
          delete mf;
        }
      }
      break;
    }
#endif
    case HELLO_ABOUT:
    {
      (void)wxMessageBox("wxWindows GUI library demo Vsn 1.40\nAuthor: Julian Smart J.Smart@ed.ac.uk\nAIAI (c) 1993", "About wxHello");
      break;
    }
    case HELLO_TIMER_ON:
    {
      the_timer.Start(5000);
      timer_on = TRUE;
      menu_bar->Enable(HELLO_TIMER_ON, FALSE);
      menu_bar->Enable(HELLO_TIMER_OFF, TRUE);
      break;
    }
    case HELLO_TIMER_OFF:
    {
      the_timer.Stop();
      menu_bar->Enable(HELLO_TIMER_ON, TRUE);
      menu_bar->Enable(HELLO_TIMER_OFF, FALSE);
      break;
    }
    default:
    {
      wxCursor *cursor = new wxCursor(id);
      frame->canvas->SetCursor(cursor);
      break;
    }
  }
}

// Intercept menu item selection - only has an effect in Windows
void MyFrame::OnMenuSelect(int id)
{
  char *msg = NULL;
  switch (id)
  {
    case HELLO_LOAD_FILE:
      msg = "Load a text file";
      break;
    case HELLO_SCALE:
      msg = "Scale picture";
      break;
    case HELLO_TWIPS:
      msg = "Twips scale";
      break;
    case HELLO_METRIC:
      msg = "Metric scale (mm)";
      break;
    case HELLO_LOMETRIC:
      msg = "Metric scale (0.1 mm)";
      break;
    case HELLO_NORMAL:
      msg = "Pixel scale";
      break;
    case HELLO_ZOOM:
      msg = "Zoom by specified amount";
      break;
    case HELLO_QUIT:
      msg = "Quit program";
      break;
    case HELLO_PRINT:
      msg = "Print picture";
      break;
#ifdef wx_msw
    case HELLO_PRINT_EPS:
      msg = "Print to EPS file";
      break;
    case HELLO_COPY_MF:
      msg = "Copy metafile to clipboard";
      break;
#endif
    case -1:
      msg = "";
      break;
  }
  if (msg)
    frame->SetStatusText(msg);
}

// Size the subwindows when the frame is resized
void MyFrame::OnSize(int w, int h)
{
  if (panel && text_window)
  {
    int width, height;
    GetClientSize(&width, &height);
    panel->SetSize(0, 0, width, (int)(height/2));
    text_window->SetSize(0, (int)(height/2), width, (int)(height/2));
  }
}

void MyFrame::Draw(wxDC& dc, Bool draw_bitmaps)
{
  dc.SetFont(small_font);
  dc.SetPen(wxGREEN_PEN);
  dc.DrawLine(0, 0, 200, 200);
  dc.DrawLine(200, 0, 0, 200);

  dc.SetBrush(wxCYAN_BRUSH);
  dc.SetPen(wxRED_PEN);
  dc.DrawRectangle(100, 100, 100, 50);
  dc.DrawRoundedRectangle(150, 150, 100, 50);

  dc.SetClippingRegion(150, 150, 100, 50);
  dc.DrawText("This text should be clipped within the rectangle", 150, 170);
  dc.DestroyClippingRegion();

  dc.DrawEllipse(250, 250, 100, 50);

  dc.DrawSpline(50, 200, 50, 100, 200, 10);

  dc.DrawLine(50, 230, 200, 230);

  dc.DrawText("This is a test string", 50, 230);

  if (draw_bitmaps)
  {
    // The easy way to draw bitmaps, using icons
    dc.DrawIcon(test_icon, 250, 50);

/*  An alternative way to draw bitmaps.
    wxDC *temp_dc = dc.CreateCompatibleDC();
    temp_dc->SelectObject(test_bitmap);
    dc.Blit(250, 50, BITMAP_WIDTH, BITMAP_HEIGHT, temp_dc, 0, 0);
    delete temp_dc;
*/

  }
}

// Define a constructor for my canvas
MyCanvas::MyCanvas(wxFrame *frame, int x, int y, int w, int h, int style):
 wxCanvas(frame, x, y, w, h, style)
{
}

// Define the repainting behaviour
void MyCanvas::OnPaint(void)
{
  frame->Draw(*(GetDC()));
}

// This implements a tiny doodling program! Drag the mouse using
// the left button.
void MyCanvas::OnEvent(wxEvent& event)
{
  SetPen(wxBLACK_PEN);
  float x, y;
  event.Position(&x, &y);
  if (xpos > -1 && ypos > -1 && event.Dragging())
  {
    DrawLine(xpos, ypos, x, y);
  }
  xpos = x;
  ypos = y;
}

// Intercept character input
void MyCanvas::OnChar(int ch)
{
  char buf[2];
  buf[0] = (char)ch;
  buf[1] = 0;
  frame->SetStatusText(buf);
}

// Define the behaviour for the frame closing
// - must delete all frames except for the main one.
Bool MyFrame::OnClose(void)
{
  if (subframe)
    delete subframe;

  return TRUE;
}

// Gets some user input, and sets the status line
void button_proc(wxButton& but, wxEvent& event)
{
  int choice = wxMessageBox("Press OK to continue", "Try me", wxOK | wxCANCEL);

  if (choice == wxOK)
  {
    char *text = wxGetTextFromUser("Enter some text", "Text input", "");
    if (text)
    {
      (void)wxMessageBox(text, "Result", wxOK);

      frame->SetStatusText(text);
    }
  }
}

// Put some text into the text window
void list_proc(wxListBox& list, wxEvent& event)
{
  *(frame->text_window) << event.string;
}

void GenericOk(wxButton& but, wxEvent& event)
{
  wxDialogBox *dialog = (wxDialogBox *)but.GetParent();

  dialog->Show(FALSE);
}

// Timer notify proc
void MyTimer::Notify(void)
{
  *(frame->text_window) << "Timer went!" << "\n";
}
