home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / demos / poem / wxpoem.cpp < prev    next >
C/C++ Source or Header  |  2002-05-17  |  30KB  |  1,157 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        wxpoem.cpp
  3. // Purpose:     A small C++ program which displays a random poem on
  4. //              execution. It also allows search for poems containing a
  5. //              string.
  6. //              It requires winpoem.dat and creates winpoem.idx.
  7. //              Original version (WinPoem) written in 1994.
  8. //              This has not been rewritten in a long time so
  9. //              beware, inelegant code!
  10. // Author:      Julian Smart
  11. // Created:     12/12/98
  12. // RCS-ID:      $Id: wxpoem.cpp,v 1.7 2002/05/14 13:53:48 JS Exp $
  13. // Copyright:   (c) 1998 Julian Smart
  14. // Licence:     wxWindows licence
  15. /////////////////////////////////////////////////////////////////////////////
  16.  
  17. #ifdef __GNUG__
  18. #pragma implementation "wxpoem.h"
  19. #endif
  20.  
  21. // For compilers that support precompilation, includes "wx.h".
  22. #include "wx/wxprec.h"
  23.  
  24. #ifdef __BORLANDC__
  25. #pragma hdrstop
  26. #endif
  27.  
  28. #ifndef WX_PRECOMP
  29. #include "wx/wx.h"
  30. #endif
  31.  
  32. #include "wx/help.h"
  33.  
  34. #include "wxpoem.h"
  35.  
  36. #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXX11__)
  37. #include "corner1.xpm"
  38. #include "corner2.xpm"
  39. #include "corner3.xpm"
  40. #include "corner4.xpm"
  41. #endif
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <time.h>
  47.  
  48. #ifdef __WINDOWS__
  49. #include <windows.h>
  50. #ifdef DrawText
  51. #undef DrawText
  52. #endif
  53. #endif
  54.  
  55. #define         buf_size 10000
  56. #define         DEFAULT_POETRY_DAT "wxpoem"
  57. #define         DEFAULT_POETRY_IND "wxpoem"
  58. #define         DEFAULT_CHAR_HEIGHT 18
  59. #define         DEFAULT_FONT "Swiss"
  60. #define         DEFAULT_X_POS 0
  61. #define         DEFAULT_Y_POS 0
  62. #define         BORDER_SIZE 30
  63. #define         THIN_LINE_BORDER 10
  64. #define         THICK_LINE_BORDER 16
  65. #define         THICK_LINE_WIDTH 2
  66. #define         SHADOW_OFFSET 1
  67. #define         X_SIZE 30
  68. #define         Y_SIZE 20
  69.  
  70. static char     *poem_buffer;          // Storage for each poem
  71. static char     line[150];                      // Storage for a line
  72. static char     title[150];                     // Remember the title
  73. static char     *search_string = NULL;          // The search string
  74. static int      pages[30];                      // For multipage poems -
  75.                                                 // store the start of each page
  76. static long     last_poem_start = 0;            // Start of last found poem
  77. static long     last_find = -1;                 // Point in file of last found
  78.                                                 // search string
  79. static bool     search_ok = FALSE;              // Search was successful
  80. static bool     same_search = FALSE;            // Searching on same string
  81.  
  82. static long     poem_index[600];                     // Index of poem starts
  83. static long     nitems = 0;                     // Number of poems
  84. static int      char_height = DEFAULT_CHAR_HEIGHT; // Actual height
  85. static int      index_ptr = -1;                 // Pointer into index
  86. static int      poem_height, poem_width;        // Size of poem
  87. static int      XPos;                           // Startup X position
  88. static int      YPos;                           // Startup Y position
  89. static int      pointSize = 12;                 // Font size
  90.  
  91. static char     *index_filename = NULL;            // Index filename
  92. static char     *data_filename = NULL;             // Data filename
  93. static char     error_buf[300];                 // Error message buffer
  94. static bool     loaded_ok = FALSE;              // Poem loaded ok
  95. static bool     index_ok = FALSE;               // Index loaded ok
  96.  
  97. static bool     paging = FALSE;                 // Are we paging?
  98. static int      current_page = 0;               // Currently viewed page
  99.  
  100. wxIcon          *Corner1 = NULL;
  101. wxIcon          *Corner2 = NULL;
  102. wxIcon          *Corner3 = NULL;
  103. wxIcon          *Corner4 = NULL;
  104.  
  105. // Fonts
  106. wxFont          *NormalFont = NULL;
  107. wxFont          *BoldFont = NULL;
  108. wxFont          *ItalicFont = NULL;
  109.  
  110. // Pens
  111. wxPen           *GreyPen = NULL;
  112. wxPen           *DarkGreyPen = NULL;
  113. wxPen           *WhitePen = NULL;
  114.  
  115. // Backing bitmap
  116. wxBitmap        *backingBitmap = NULL;
  117.  
  118. void            PoetryError(char *, char *caption="wxPoem Error");
  119. void            PoetryNotify(char *Msg, char *caption="wxPoem");
  120. void            TryLoadIndex();
  121. bool            LoadPoem(char *, long);
  122. int             GetIndex();
  123. int             LoadIndex(char *);
  124. bool            Compile(void);
  125. void            WritePreferences();
  126. void            ReadPreferences();
  127. void            FindMax(int *max_thing, int thing);
  128. void            CreateFonts();
  129. #ifdef __WXMSW__
  130. void            CopyToClipboard(HWND, char *);
  131. #endif
  132.  
  133. wxMenu    *popupMenu = NULL;
  134.  
  135. #if wxUSE_HELP
  136.     wxHelpController *HelpController = NULL;
  137. #endif // wxUSE_HELP
  138.  
  139. IMPLEMENT_APP(MyApp)
  140.  
  141. MainWindow *TheMainWindow = NULL;
  142.  
  143. // Create the fonts
  144. void CreateFonts()
  145. {
  146.   NormalFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxNORMAL);
  147.   BoldFont =   wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxBOLD);
  148.   ItalicFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxITALIC, wxNORMAL);
  149. }
  150.  
  151. BEGIN_EVENT_TABLE(MainWindow, wxFrame)
  152.     EVT_CLOSE(MainWindow::OnCloseWindow)
  153.     EVT_CHAR(MainWindow::OnChar)
  154.     EVT_MENU(-1, MainWindow::OnPopup)
  155. END_EVENT_TABLE()
  156.  
  157. MainWindow::MainWindow(wxFrame *frame, wxWindowID id, const wxString& title,
  158.    const wxPoint& pos, const wxSize& size, long style):
  159.   wxFrame(frame, id, title, pos, size, style)
  160. {
  161. }
  162.  
  163. MainWindow::~MainWindow()
  164. {
  165.   // Note: this must be done before the main window/canvas are destroyed
  166.   // or we get an error (no parent window for menu item button)
  167.   delete popupMenu;
  168.   popupMenu = NULL;
  169. }
  170.  
  171. // Read the poetry buffer, either for finding the size
  172. // or for writing to a bitmap (not to the window directly,
  173. // since that displays messily)
  174. // If DrawIt is true, we draw, otherwise we just determine the
  175. // size the window should be.
  176. void MainWindow::ScanBuffer(wxDC *dc, bool DrawIt, int *max_x, int *max_y)
  177. {
  178.     int i = pages[current_page];
  179.     int ch = -1;
  180.     int x = 10;
  181.     int y = 0;
  182.     int j;
  183.     char *line_ptr;
  184.     int curr_width = 0;
  185.     bool page_break = FALSE;
  186.  
  187.     int width = 0;
  188.     int height = 0;
  189.  
  190.     if (DrawIt)
  191.     {
  192.       y = (*max_y - poem_height)/2;
  193.       width = *max_x;
  194.       height = *max_y;
  195.     }
  196.  
  197.     if (DrawIt && wxColourDisplay())
  198.     {
  199.       dc->SetBrush(*wxLIGHT_GREY_BRUSH);
  200.       dc->SetPen(*GreyPen);
  201.       dc->DrawRectangle(0, 0, width, height);
  202.       dc->SetBackgroundMode(wxTRANSPARENT);
  203.     }
  204.  
  205.     // See what ACTUAL char height is
  206.     dc->SetFont(* NormalFont);
  207.     long xx;
  208.     long yy;
  209.     dc->GetTextExtent("X", &xx, &yy);
  210.     char_height = (int)yy;
  211.  
  212.     if (current_page == 0)
  213.       title[0] = 0;
  214.     else if (title[0] != 0)
  215.     {
  216.        dc->SetFont(* BoldFont);
  217.        dc->GetTextExtent(title, &xx, &yy);
  218.        FindMax(&curr_width, (int)xx);
  219.  
  220.        if (DrawIt)
  221.        {
  222.          x = (width - xx)/2;
  223.          dc->SetFont(* BoldFont);
  224.  
  225.          // Change text to BLACK!
  226.          dc->SetTextForeground(* wxBLACK);
  227.          dc->DrawText(title, x, y);
  228.          // Change text to WHITE!
  229.          dc->SetTextForeground(* wxWHITE);
  230.          dc->DrawText(title, x-SHADOW_OFFSET, y-SHADOW_OFFSET);
  231.        }
  232.        y += char_height;
  233.        y += char_height;
  234.     }
  235.  
  236.     while (ch != 0 && !page_break)
  237.     {
  238.         j = 0;
  239. #if defined(__WXMSW__) || defined(__WXMAC__)
  240.         while (((ch = poem_buffer[i]) != 13) && (ch != 0))
  241. #else
  242.         while (((ch = poem_buffer[i]) != 10) && (ch != 0))
  243. #endif
  244.         {
  245.             line[j] = ch;
  246.             j ++;
  247.             i ++;
  248.         }
  249.  
  250. #if defined(__WXMSW__) || defined(__WXMAC__)
  251.         if (ch == 13)
  252. #else
  253.         if (ch == 10)
  254. #endif
  255.         {
  256.             ch = -1;
  257.             i ++;
  258. #if defined(__WXMSW__) || defined(__WXMAC__)
  259.             // Add another to skip the linefeed
  260.             i ++;
  261. #endif
  262.             // If a single newline on its own, put a space in
  263.             if (j == 0)
  264.             {
  265.               line[j] = ' ';
  266.               j ++;
  267.               line[j] = 0;
  268.             }
  269.         }
  270.  
  271.         if (j > 0)
  272.         {
  273.           line[j] = 0;
  274.           if (line[0] == '@')
  275.           {
  276.             switch (line[1])
  277.             {
  278.               case 'P':
  279.                 paging = TRUE;
  280.                 page_break = TRUE;
  281.                 break;
  282.  
  283.               case 'T':
  284.                 dc->SetFont(* BoldFont);
  285.                 line_ptr = line+3;
  286.  
  287.                 strcpy(title, line_ptr);
  288.                 strcat(title, " (cont'd)");
  289.  
  290.                 dc->GetTextExtent(line_ptr, &xx, &yy);
  291.                 FindMax(&curr_width, (int)xx);
  292.  
  293.                 if (DrawIt)
  294.                 {
  295.                   x = (width - xx)/2;
  296.                   dc->SetFont(* BoldFont);
  297.  
  298.                   // Change text to BLACK!
  299.                   dc->SetTextForeground(* wxBLACK);
  300.                   dc->DrawText(line_ptr, x, y);
  301.  
  302.                   // Change text to WHITE!
  303.                   dc->SetTextForeground(* wxWHITE);
  304.                   dc->DrawText(line_ptr, x-SHADOW_OFFSET, y-SHADOW_OFFSET);
  305.                   dc->SetTextForeground(* wxWHITE);
  306.                 }
  307.                 break;
  308.  
  309.               case 'A':
  310.                 line_ptr = line+3;
  311.                 dc->SetFont(* ItalicFont);
  312.  
  313.                 dc->GetTextExtent(line_ptr, &xx, &yy);
  314.                 FindMax(&curr_width, (int)xx);
  315.  
  316.                 if (DrawIt)
  317.                 {
  318.                   x = (width - xx)/2;
  319.                   dc->SetTextForeground(* wxBLACK);
  320.                   dc->DrawText(line_ptr, x, y);
  321.                 }
  322.                 break;
  323.  
  324.               // Default: just ignore this line
  325.               default:
  326.                 y -= char_height;
  327.             }
  328.            }
  329.            else
  330.            {
  331.               dc->SetFont(* NormalFont);
  332.  
  333.               dc->GetTextExtent(line, &xx, &yy);
  334.               FindMax(&curr_width, (int)xx);
  335.  
  336.               if (DrawIt)
  337.               {
  338.                 int x = (int)((width - xx)/2.0);
  339.                 dc->SetFont(* NormalFont);
  340.                 dc->SetTextForeground(* wxBLACK);
  341.                 dc->DrawText(line, x, y);
  342.               }
  343.            }
  344.         }
  345.         y += char_height;
  346.     }
  347.  
  348.     // Write (cont'd)
  349.     if (page_break)
  350.     {
  351.        char *cont = "(cont'd)";
  352.  
  353.        dc->SetFont(* NormalFont);
  354.  
  355.        dc->GetTextExtent(cont, &xx, &yy);
  356.        FindMax(&curr_width, (int)xx);
  357.        if (DrawIt)
  358.        {
  359.          int x = (int)((width - xx)/2.0);
  360.          dc->SetFont(* NormalFont);
  361.          dc->SetTextForeground(* wxBLACK);
  362.          dc->DrawText(cont, x, y);
  363.        }
  364.        y += 2*char_height;
  365.     }
  366.  
  367.     *max_x = (int)curr_width;
  368.     *max_y = (int)(y-char_height);
  369.  
  370.     if (page_break)
  371.       pages[current_page+1] = i;
  372.     else
  373.       paging = FALSE;
  374.  
  375.     if (DrawIt)
  376.     {
  377.       // Draw dark grey thick border
  378.       if (wxColourDisplay())
  379.       {
  380.         dc->SetBrush(*wxGREY_BRUSH);
  381.         dc->SetPen(*wxGREY_PEN);
  382.  
  383.         // Left side
  384.         dc->DrawRectangle(0, 0, THIN_LINE_BORDER, height);
  385.         // Top side
  386.         dc->DrawRectangle(THIN_LINE_BORDER, 0, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
  387.         // Right side
  388.         dc->DrawRectangle(width-THIN_LINE_BORDER, THIN_LINE_BORDER, width, height-THIN_LINE_BORDER);
  389.         // Bottom side
  390.         dc->DrawRectangle(THIN_LINE_BORDER, height-THIN_LINE_BORDER, width-THIN_LINE_BORDER, height);
  391.       }
  392.       // Draw border
  393.       // Have grey background, plus 3-d border -
  394.       // One black rectangle.
  395.       // Inside this, left and top sides - dark grey. Bottom and right -
  396.       // white.
  397.  
  398.       // Change pen to black
  399.       dc->SetPen(*wxBLACK_PEN);
  400.       dc->DrawLine(THIN_LINE_BORDER, THIN_LINE_BORDER, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
  401.       dc->DrawLine(width-THIN_LINE_BORDER, THIN_LINE_BORDER, width-THIN_LINE_BORDER, height-THIN_LINE_BORDER);
  402.       dc->DrawLine(width-THIN_LINE_BORDER, height-THIN_LINE_BORDER, THIN_LINE_BORDER, height-THIN_LINE_BORDER);
  403.       dc->DrawLine(THIN_LINE_BORDER, height-THIN_LINE_BORDER, THIN_LINE_BORDER, THIN_LINE_BORDER);
  404.  
  405.       // Right and bottom white lines - 'grey' (black!) if
  406.       // we're running on a mono display.
  407.       if (wxColourDisplay())
  408.         dc->SetPen(*WhitePen);
  409.       else
  410.         dc->SetPen(*DarkGreyPen);
  411.  
  412.       dc->DrawLine(width-THICK_LINE_BORDER, THICK_LINE_BORDER,
  413.                    width-THICK_LINE_BORDER, height-THICK_LINE_BORDER);
  414.       dc->DrawLine(width-THICK_LINE_BORDER, height-THICK_LINE_BORDER,
  415.                    THICK_LINE_BORDER, height-THICK_LINE_BORDER);
  416.  
  417.       // Left and top grey lines
  418.       dc->SetPen(*DarkGreyPen);
  419.       dc->DrawLine(THICK_LINE_BORDER, height-THICK_LINE_BORDER,
  420.                    THICK_LINE_BORDER, THICK_LINE_BORDER);
  421.       dc->DrawLine(THICK_LINE_BORDER, THICK_LINE_BORDER,
  422.                    width-THICK_LINE_BORDER, THICK_LINE_BORDER);
  423.  
  424. //#ifdef __WXMSW__
  425.       // Draw icons
  426.       dc->DrawIcon(* Corner1, 0, 0);
  427.       dc->DrawIcon(* Corner2, int(width-32), 0);
  428.  
  429.       int y2 = height - 32;
  430.       int x2 = (width-32);
  431.       dc->DrawIcon(* Corner3, 0, y2);
  432.       dc->DrawIcon(* Corner4, x2, y2);
  433. //#endif
  434.     }
  435. }
  436.  
  437. // Get an index (randomly generated) and load the poem
  438. void MainWindow::GetIndexLoadPoem(void)
  439. {
  440.     if (index_ok)
  441.       index_ptr = GetIndex();
  442.  
  443.     if (index_ptr > -1)
  444.       loaded_ok = LoadPoem(data_filename, -1);
  445. }
  446.  
  447. // Find the size of the poem and resize the window accordingly
  448. void MainWindow::Resize(void)
  449. {
  450.     wxClientDC dc(canvas);
  451.  
  452.     // Get the poem size
  453.     ScanBuffer(& dc, FALSE, &poem_width, &poem_height);
  454.     int x = poem_width + (2*BORDER_SIZE);
  455.     int y = poem_height + (2*BORDER_SIZE);
  456.  
  457.     SetClientSize(x, y);
  458.  
  459.     // In case client size isn't what we set it to...
  460.     int xx, yy;
  461.     GetClientSize(&xx, &yy);
  462.  
  463.     wxMemoryDC memDC;
  464.     if (backingBitmap) delete backingBitmap;
  465.     backingBitmap = new wxBitmap(x, yy);
  466.     memDC.SelectObject(* backingBitmap);
  467.  
  468.     memDC.Clear();
  469.     TheMainWindow->ScanBuffer(&memDC, TRUE, &xx, &yy);
  470. }
  471.  
  472. // Which is more?
  473. void FindMax(int *max_thing, int thing)
  474. {
  475.   if (thing > *max_thing)
  476.     *max_thing = thing;
  477. }
  478.  
  479. // Next page/poem
  480. void MainWindow::NextPage(void)
  481. {
  482.   if (paging)
  483.     current_page ++;
  484.   else
  485.   {
  486.     current_page = 0;
  487.     GetIndexLoadPoem();
  488.   }
  489.   Resize();
  490. }
  491.  
  492. // Previous page
  493. void MainWindow::PreviousPage(void)
  494. {
  495.   if (current_page > 0)
  496.   {
  497.     current_page --;
  498.     Resize();
  499.   }
  500. }
  501.  
  502. // Search for a string
  503. void MainWindow::Search(bool ask)
  504. {
  505.   long position;
  506.  
  507.   if (ask || !search_string)
  508.   {
  509.     wxString s = wxGetTextFromUser("Enter search string", "Search", (const char*) search_string);
  510.     if (s != "")
  511.     {
  512.       if (search_string) delete[] search_string;
  513.       search_string = copystring(s);
  514.       search_ok = TRUE;
  515.     } else search_ok = FALSE;
  516.   }
  517.   else
  518.   {
  519.     same_search = TRUE;
  520.     search_ok = TRUE;
  521.   }
  522.  
  523.   if (search_string && search_ok)
  524.   {
  525.     position = DoSearch();
  526.     if (position > -1)
  527.     {
  528.        loaded_ok = LoadPoem(data_filename, position);
  529.        Resize();
  530.     }
  531.     else
  532.     {
  533.       last_poem_start = 0;
  534.       PoetryNotify("Search string not found.");
  535.     }
  536.   }
  537. }
  538.  
  539. // Copy a string to the clipboard
  540. #ifdef __WXMSW__
  541. void CopyToClipboard(HWND handle, char *s)
  542. {
  543.   int length = strlen(s);
  544.   HANDLE hGlobalMemory = GlobalAlloc(GHND, (DWORD) length + 1);
  545.   if (hGlobalMemory)
  546.   {
  547. #ifdef __WINDOWS_386__
  548.     LPSTR lpGlobalMemory = MK_FP32(GlobalLock(hGlobalMemory));
  549. #else
  550.     LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory);
  551. #endif
  552.     int i, j = 0;
  553.     for (i = 0; i < length; i ++)
  554.     {
  555.       if (s[i] == '@')
  556.       {
  557.         i++;
  558.         switch (s[i])
  559.         {
  560.           case 'P':
  561.             break;
  562.           case 'T':
  563.           case 'A':
  564.           default:
  565.             i ++;
  566.             break;
  567.         }
  568.       }
  569.       else
  570.       {
  571.         lpGlobalMemory[j] = s[i];
  572.         j ++;
  573.       }
  574.     }
  575.  
  576.     GlobalUnlock(hGlobalMemory);
  577.     OpenClipboard(handle);
  578.     EmptyClipboard();
  579.     SetClipboardData(CF_TEXT, hGlobalMemory);
  580.     CloseClipboard();
  581.   }
  582. }
  583. #endif
  584.  
  585. bool MyApp::OnInit()
  586. {
  587.   poem_buffer = new char[buf_size];
  588.  
  589.   GreyPen = new wxPen("LIGHT GREY", THICK_LINE_WIDTH, wxSOLID);
  590.   DarkGreyPen = new wxPen("GREY", THICK_LINE_WIDTH, wxSOLID);
  591.   WhitePen = new wxPen("WHITE", THICK_LINE_WIDTH, wxSOLID);
  592.  
  593. #if wxUSE_HELP
  594.   HelpController = new wxHelpController();
  595.   HelpController->Initialize("wxpoem");
  596. #endif // wxUSE_HELP
  597.  
  598.   CreateFonts();
  599.  
  600.   ReadPreferences();
  601.  
  602.   // Seed the random number generator
  603.   time_t current_time;
  604.  
  605.   (void)time(¤t_time);
  606.   srand((unsigned int)current_time);
  607.  
  608. //    randomize();
  609.   pages[0] = 0;
  610.  
  611.   TheMainWindow = new MainWindow(NULL, 500, "wxPoem", wxPoint(XPos, YPos), wxSize(100, 100), wxCAPTION|wxMINIMIZE_BOX|wxSYSTEM_MENU);
  612.  
  613. #ifdef wx_x
  614.   TheMainWindow->SetIcon(Icon("wxpoem"));
  615. #endif
  616.  
  617.   TheMainWindow->canvas = new MyCanvas(TheMainWindow, 501, wxDefaultPosition, wxDefaultSize);
  618.  
  619.   popupMenu = new wxMenu;
  620.   popupMenu->Append(POEM_NEXT, "Next poem/page");
  621.   popupMenu->Append(POEM_PREVIOUS, "Previous page");
  622.   popupMenu->AppendSeparator();
  623.   popupMenu->Append(POEM_SEARCH, "Search");
  624.   popupMenu->Append(POEM_NEXT_MATCH, "Next match");
  625.   popupMenu->Append(POEM_COPY, "Copy to clipboard");
  626.   popupMenu->Append(POEM_MINIMIZE, "Minimize");
  627.   popupMenu->AppendSeparator();
  628.   popupMenu->Append(POEM_BIGGER_TEXT, "Bigger text");
  629.   popupMenu->Append(POEM_SMALLER_TEXT, "Smaller text");
  630.   popupMenu->AppendSeparator();
  631.   popupMenu->Append(POEM_ABOUT, "About wxPoem");
  632.   popupMenu->AppendSeparator();
  633.   popupMenu->Append(POEM_EXIT, "Exit");
  634.  
  635.   if (argc > 1)
  636.   {
  637.     index_filename = copystring(argv[1]);
  638.     data_filename = copystring(argv[1]);
  639.   }
  640.   else
  641.   {
  642.     index_filename = DEFAULT_POETRY_IND;
  643.     data_filename = DEFAULT_POETRY_DAT;
  644.   }
  645.   TryLoadIndex();
  646.  
  647. #ifdef __WXMSW__
  648.   Corner1 = new wxIcon("icon_1");
  649.   Corner2 = new wxIcon("icon_2");
  650.   Corner3 = new wxIcon("icon_3");
  651.   Corner4 = new wxIcon("icon_4");
  652. #endif
  653. #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXX11__)
  654.   Corner1 = new wxIcon( corner1_xpm );
  655.   Corner2 = new wxIcon( corner2_xpm );
  656.   Corner3 = new wxIcon( corner3_xpm );
  657.   Corner4 = new wxIcon( corner4_xpm );
  658. #endif
  659.  
  660.   TheMainWindow->GetIndexLoadPoem();
  661.   TheMainWindow->Resize();
  662.   TheMainWindow->Show(TRUE);
  663.  
  664.   return TRUE;
  665. }
  666.  
  667. int MyApp::OnExit()
  668. {
  669.   if (backingBitmap)
  670.     delete backingBitmap;
  671. #if wxUSE_HELP
  672.   delete HelpController;
  673. #endif // wxUSE_HELP
  674.   delete GreyPen;
  675.   delete DarkGreyPen;
  676.   delete WhitePen;
  677.  
  678.   delete Corner1;
  679.   delete Corner2;
  680.   delete Corner3;
  681.   delete Corner4;
  682.  
  683.   // Causes crash since they're deleted by the global font list
  684. #if 0
  685.   delete NormalFont;
  686.   delete BoldFont;
  687.   delete ItalicFont;
  688. #endif
  689.  
  690.   delete[] poem_buffer;
  691.   if (search_string)
  692.     delete[] search_string;
  693.  
  694.   return 0;
  695. }
  696.  
  697. void MainWindow::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
  698. {
  699.   WritePreferences();
  700.   this->Destroy();
  701. }
  702.  
  703. void MainWindow::OnChar(wxKeyEvent& event)
  704. {
  705.     canvas->OnChar(event);
  706. }
  707.  
  708. BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
  709.     EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
  710.     EVT_CHAR(MyCanvas::OnChar)
  711.     EVT_PAINT(MyCanvas::OnPaint)
  712. END_EVENT_TABLE()
  713.  
  714. // Define a constructor for my canvas
  715. MyCanvas::MyCanvas(wxFrame *frame, wxWindowID id, const wxPoint& pos, const wxSize& size):
  716.  wxWindow(frame, id, pos, size)
  717. {
  718. }
  719.  
  720. // Define the repainting behaviour
  721. void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
  722. {
  723.     wxPaintDC dc(this);
  724.  
  725.     if (backingBitmap)
  726.     {
  727.         int xx, yy;
  728.         TheMainWindow->GetClientSize(&xx, &yy);
  729.  
  730.         dc.DrawBitmap(* backingBitmap, 0, 0);
  731. #if 0        
  732.         wxMemoryDC memDC;
  733.         memDC.SelectObject(* backingBitmap);
  734.         dc.Blit(0, 0, backingBitmap->GetWidth(), backingBitmap->GetHeight(), &memDC, 0, 0);
  735. #endif
  736.   }
  737. }
  738.  
  739. void MyCanvas::OnMouseEvent(wxMouseEvent& event)
  740. {
  741.   static int startPosX, startPosY, startFrameX, startFrameY;
  742.  
  743.   long x, y;
  744.   event.GetPosition(&x, &y);
  745.  
  746.   if (event.RightDown())
  747.   {
  748.     // Versions from wxWin 1.67 are probably OK
  749.     PopupMenu(popupMenu, (int)x, (int)y );
  750.   }
  751.   else if (event.LeftDown())
  752.   {
  753.     this->CaptureMouse();
  754.     int x1 = (int)x;
  755.     int y1 = (int)y;
  756.     ClientToScreen(&x1, &y1);
  757.     startPosX = x1;
  758.     startPosY = y1;
  759.     GetParent()->GetPosition(&startFrameX, &startFrameY);
  760.   }
  761.   else if (event.LeftUp())
  762.     this->ReleaseMouse();
  763.   else if (event.Dragging() && event.LeftIsDown())
  764.   {
  765.     int x1 = (int)x;
  766.     int y1 = (int)y;
  767.     ClientToScreen(&x1, &y1);
  768.  
  769.     int dX = x1 - startPosX;
  770.     int dY = y1 - startPosY;
  771.     GetParent()->Move(startFrameX + dX, startFrameY + dY);
  772.   }
  773. }
  774.  
  775. // Process characters
  776. void MyCanvas::OnChar(wxKeyEvent& event)
  777. {
  778.   switch (event.KeyCode())
  779.   {
  780.     case 'n':
  781.     case 'N':
  782.       // Next match
  783.       TheMainWindow->Search(FALSE);
  784.       break;
  785.     case 's':
  786.     case 'S':
  787.       // New search
  788.       TheMainWindow->Search(TRUE);
  789.       break;
  790.     case WXK_SPACE:
  791.       // Another poem
  792.       TheMainWindow->NextPage();
  793.       break;
  794.     case 27:
  795.       TheMainWindow->Close(TRUE);
  796.     default:
  797.        break;
  798.    }
  799.  }
  800.  
  801. // Load index file
  802. int LoadIndex(char *file_name)
  803. {
  804.     long data;
  805.     FILE *index_file;
  806.  
  807.     int i = 0;
  808.     char buf[100];
  809.  
  810.     if (file_name)
  811.       sprintf(buf, "%s.idx", file_name);
  812.     if (! (file_name && (index_file = fopen(buf, "r"))))
  813.       return 0;
  814.     else
  815.     {
  816.       fscanf(index_file, "%ld", &nitems);
  817.  
  818.       for (i = 0; i < nitems; i++)
  819.       {
  820.         fscanf(index_file, "%ld", &data);
  821.         poem_index[i] = data;
  822.       }
  823.       fclose(index_file);
  824.  
  825.       return 1;
  826.     }
  827. }
  828.  
  829. // Get index
  830. int GetIndex()
  831. {
  832.     int indexn = 0;
  833.  
  834.     indexn = (int)(rand() % nitems);
  835.  
  836.     if ((indexn < 0) || (indexn > nitems))
  837.     { PoetryError("No such poem!");
  838.       return -1;
  839.     }
  840.     else
  841.       return indexn;
  842. }
  843.  
  844. // Read preferences
  845. void ReadPreferences()
  846. {
  847.   wxGetResource("wxPoem", "FontSize", &pointSize);
  848.   wxGetResource("wxPoem", "X", &XPos);
  849.   wxGetResource("wxPoem", "Y", &YPos);
  850. }
  851.  
  852. // Write preferences to disk
  853. void WritePreferences()
  854. {
  855. #ifdef __WXMSW__
  856.   TheMainWindow->GetPosition(&XPos, &YPos);
  857.   wxWriteResource("wxPoem", "FontSize", pointSize);
  858.   wxWriteResource("wxPoem", "X", XPos);
  859.   wxWriteResource("wxPoem", "Y", YPos);
  860. #endif
  861. }
  862.  
  863. // Load a poem from given file, at given point in file.
  864. // If position is > -1, use this for the position in the
  865. // file, otherwise use index[index_ptr] to find the correct position.
  866. bool LoadPoem(char *file_name, long position)
  867. {
  868.     int ch = 0;
  869.     int i = 0;
  870. //    int j = 0;
  871. //    int indexn = 0;
  872.     char buf[100];
  873.     long data;
  874.     FILE *data_file;
  875.  
  876.     paging = FALSE;
  877.     current_page = 0;
  878.  
  879.     if (file_name)
  880.       sprintf(buf, "%s.dat", file_name);
  881.  
  882.     if (! (file_name && (data_file = fopen(buf, "r"))))
  883.     {
  884.       sprintf(error_buf, "Data file %s not found.", buf);
  885.       PoetryError(error_buf);
  886.       return FALSE;
  887.     }
  888.     else
  889.     {
  890.       if (position > -1)
  891.         data = position;
  892.       else
  893.         data = poem_index[index_ptr];
  894.  
  895.       fseek(data_file, data, SEEK_SET);
  896.  
  897.       ch = 0;
  898.       i = 0;
  899.       while ((ch != EOF) && (ch != '#'))
  900.       {
  901.         ch = getc(data_file);
  902.         // Add a linefeed so it will copy to the clipboard ok
  903.         if (ch == 10)
  904.         {
  905.           poem_buffer[i] = 13;
  906.           i++;
  907.         }
  908.  
  909.         poem_buffer[i] = ch;
  910.         i ++;
  911.  
  912.         if (i == buf_size)
  913.         {
  914.            sprintf(error_buf, "%s", "Poetry buffer exceeded.");
  915.            PoetryError(error_buf);
  916.            return FALSE;
  917.         }
  918.       }
  919.       fclose(data_file);
  920.       poem_buffer[i-1] = 0;
  921.       return TRUE;
  922.   }
  923. }
  924.  
  925. // Do the search
  926. long MainWindow::DoSearch(void)
  927. {
  928.     if (!search_string)
  929.       return FALSE;
  930.  
  931.     FILE *file;
  932.     long i = 0;
  933.     int ch = 0;
  934.     char buf[100];
  935.     long find_start;
  936.     long previous_poem_start;
  937.  
  938.     bool found = FALSE;
  939.     int search_length = strlen(search_string);
  940.  
  941.     if (same_search)
  942.     {
  943.       find_start = last_find + 1;
  944.       previous_poem_start = last_poem_start;
  945.     }
  946.     else
  947.     {
  948.       find_start = 0;
  949.       last_poem_start = 0;
  950.       previous_poem_start = -1;
  951.     }
  952.  
  953.     if (data_filename)
  954.       sprintf(buf, "%s.dat", data_filename);
  955.  
  956.     if (! (data_filename && (file = fopen(buf, "r"))))
  957.     {
  958.       sprintf(error_buf, "Poetry data file %s not found\n", buf);
  959.       PoetryError(error_buf);
  960.       return FALSE;
  961.     }
  962.  
  963.     fseek(file, find_start, SEEK_SET);
  964.  
  965.     while ((ch != EOF) && !found)
  966.     {
  967.         ch = getc(file);
  968.         ch |= 0x0020;   // Make lower case
  969.  
  970.         // Only match if we're looking at a different poem
  971.         // (no point in displaying the same poem again)
  972.         if ((ch == search_string[i]) && (last_poem_start != previous_poem_start))
  973.         {
  974.           if (i == 0)
  975.             last_find = ftell(file);
  976.           if (i == search_length-1)
  977.             found = TRUE;
  978.           i ++;
  979.         }
  980.         else
  981.           i = 0;
  982.  
  983.         if (ch == '#')
  984.         {
  985.             ch = getc(file);
  986.               last_poem_start = ftell(file);
  987.         }
  988.     }
  989.     fclose(file);
  990.     if (ch == EOF)
  991.       last_find = -1;
  992.  
  993.     if (found)
  994.     {
  995.       return last_poem_start;
  996.     }
  997.     else
  998.       return -1;
  999. }
  1000.  
  1001. // Set up poetry filenames, preferences, load the index
  1002. // Load index (or compile it if none found)
  1003. void TryLoadIndex()
  1004. {
  1005.   index_ok = (LoadIndex(index_filename) != 0);
  1006.   if (!index_ok || (nitems == 0))
  1007.   {
  1008.       PoetryError("Index file not found; will compile new one", "wxPoem");
  1009.       index_ok = Compile();
  1010.   }
  1011. }
  1012.  
  1013. // Error message
  1014. void PoetryError(char *msg, char *caption)
  1015. {
  1016.   wxMessageBox(msg, caption, wxOK|wxICON_EXCLAMATION);
  1017. }
  1018.  
  1019. // Notification (change icon to something appropriate!)
  1020. void PoetryNotify(char *Msg, char *caption)
  1021. {
  1022.   wxMessageBox(Msg, caption, wxOK | wxICON_INFORMATION);
  1023. }
  1024.  
  1025. // Build up and save an index into the poetry data file, for
  1026. // rapid random access
  1027. bool Compile(void)
  1028. {
  1029.     FILE *file;
  1030.     long i = 0;
  1031.     int j;
  1032.     int ch = 0;
  1033.     char buf[100];
  1034.  
  1035.     if (data_filename)
  1036.       sprintf(buf, "%s.dat", data_filename);
  1037.  
  1038.     if (! (data_filename && (file = fopen(buf, "r"))))
  1039.     {
  1040.       sprintf(error_buf, "Poetry data file %s not found\n", buf);
  1041.       PoetryError(error_buf);
  1042.       return FALSE;
  1043.     }
  1044.  
  1045.     nitems = 0;
  1046.  
  1047.     // Do first one (?)
  1048.     poem_index[nitems] = 0;
  1049.     nitems ++;
  1050.  
  1051.     // Do rest
  1052.     while (ch != EOF)
  1053.     {
  1054.         ch = getc(file);
  1055.         i ++;
  1056.         if (ch == '#')
  1057.         {
  1058.             ch = getc(file);
  1059.             long data;
  1060.             data = ftell(file);
  1061.             poem_index[nitems] = data;
  1062.             nitems ++;
  1063.         }
  1064.     }
  1065.     fclose(file);
  1066.  
  1067.     if (index_filename)
  1068.       sprintf(buf, "%s.idx", index_filename);
  1069.     if (! (data_filename && (file = fopen(buf, "w"))))
  1070.     {
  1071.       sprintf(error_buf, "Poetry index file %s cannot be created\n", buf);
  1072.       PoetryError(error_buf);
  1073.       return FALSE;
  1074.     }
  1075.  
  1076.     fprintf(file, "%ld\n\n", nitems);
  1077.     for (j = 0; j < nitems; j++)
  1078.       fprintf(file, "%ld\n", poem_index[j]);
  1079.  
  1080.     fclose(file);
  1081.     PoetryNotify("Poetry index compiled.");
  1082.     return TRUE;
  1083. }
  1084.  
  1085. void MainWindow::OnPopup(wxCommandEvent& event)
  1086. {
  1087.   switch (event.GetId())
  1088.   {
  1089.      case POEM_NEXT:
  1090.        // Another poem/page
  1091.        TheMainWindow->NextPage();
  1092.        break;
  1093.      case POEM_PREVIOUS:
  1094.        // Previous page
  1095.        TheMainWindow->PreviousPage();
  1096.        break;
  1097.      case POEM_SEARCH:
  1098.        // Search - with dialog
  1099.        TheMainWindow->Search(TRUE);
  1100.        break;
  1101.      case POEM_NEXT_MATCH:
  1102.        // Search - without dialog (next match)
  1103.        TheMainWindow->Search(FALSE);
  1104.        break;
  1105.      case POEM_MINIMIZE:
  1106.        TheMainWindow->Iconize(TRUE);
  1107.        break;
  1108. #ifdef __WXMSW__
  1109.      case POEM_COPY:
  1110.        // Copy current poem to the clipboard
  1111.        CopyToClipboard((HWND) TheMainWindow->GetHWND(), poem_buffer);
  1112.        break;
  1113. #endif
  1114.      case POEM_COMPILE:
  1115.        // Compile index
  1116.        Compile();
  1117.        break;
  1118.      case POEM_BIGGER_TEXT:
  1119.      {
  1120.        pointSize ++;
  1121.        CreateFonts();
  1122.        TheMainWindow->Resize();
  1123.        break;
  1124.      }
  1125.      case POEM_SMALLER_TEXT:
  1126.      {
  1127.        if (pointSize > 2)
  1128.        {
  1129.          pointSize --;
  1130.          CreateFonts();
  1131.          TheMainWindow->Resize();
  1132.        }
  1133.        break;
  1134.      }
  1135.      case POEM_HELP_CONTENTS:
  1136.      {
  1137. #if wxUSE_HELP
  1138.        HelpController->LoadFile("wxpoem");
  1139.        HelpController->DisplayContents();
  1140. #endif // wxUSE_HELP
  1141.        break;
  1142.      }
  1143.      case POEM_ABOUT:
  1144.      {
  1145.        (void)wxMessageBox("wxPoem Version 1.1\nJulian Smart (c) 1995",
  1146.                           "About wxPoem", wxOK, TheMainWindow);
  1147.        break;
  1148.      }
  1149.      case POEM_EXIT:
  1150.        // Exit
  1151.        TheMainWindow->Close(TRUE);
  1152.        break;
  1153.      default:
  1154.        break;
  1155.   }
  1156. }
  1157.