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