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