Added George Tasker's forward slash fix to file dialog; added some consts to prntbase.h;
[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 IMPLEMENT_APP(MyApp)
141
142 MainWindow *TheMainWindow = NULL;
143
144 // Create the fonts
145 void CreateFonts()
146 {
147 NormalFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxNORMAL);
148 BoldFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxBOLD);
149 ItalicFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxITALIC, wxNORMAL);
150 }
151
152 BEGIN_EVENT_TABLE(MainWindow, wxFrame)
153 EVT_CLOSE(MainWindow::OnCloseWindow)
154 EVT_CHAR(MainWindow::OnChar)
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 #ifdef __WXMSW__
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 #ifdef __WXMSW__
251 if (ch == 13)
252 #else
253 if (ch == 10)
254 #endif
255 {
256 ch = -1;
257 i ++;
258 #ifdef __WXMSW__
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 HelpController = new wxHelpController();
594 HelpController->Initialize("wxpoem");
595
596 CreateFonts();
597
598 ReadPreferences();
599
600 // Seed the random number generator
601 time_t current_time;
602
603 (void)time(&current_time);
604 srand((unsigned int)current_time);
605
606 // randomize();
607 pages[0] = 0;
608
609 TheMainWindow = new MainWindow(NULL, -1, "wxPoem", wxPoint(XPos, YPos), wxSize(100, 100), wxCAPTION|wxMINIMIZE_BOX|wxSYSTEM_MENU);
610
611 #ifdef wx_x
612 TheMainWindow->SetIcon(Icon("wxpoem"));
613 #endif
614
615 TheMainWindow->canvas = new MyCanvas(TheMainWindow, -1, wxDefaultPosition, wxDefaultSize);
616
617 popupMenu = new wxMenu("", (wxFunction)PopupFunction);
618 popupMenu->Append(POEM_NEXT, "Next poem/page");
619 popupMenu->Append(POEM_PREVIOUS, "Previous page");
620 popupMenu->AppendSeparator();
621 popupMenu->Append(POEM_SEARCH, "Search");
622 popupMenu->Append(POEM_NEXT_MATCH, "Next match");
623 popupMenu->Append(POEM_COPY, "Copy to clipboard");
624 popupMenu->Append(POEM_MINIMIZE, "Minimize");
625 popupMenu->AppendSeparator();
626 popupMenu->Append(POEM_BIGGER_TEXT, "Bigger text");
627 popupMenu->Append(POEM_SMALLER_TEXT, "Smaller text");
628 popupMenu->AppendSeparator();
629 popupMenu->Append(POEM_ABOUT, "About wxPoem");
630 popupMenu->AppendSeparator();
631 popupMenu->Append(POEM_EXIT, "Exit");
632
633 if (argc > 1)
634 {
635 index_filename = copystring(argv[1]);
636 data_filename = copystring(argv[1]);
637 }
638 else
639 {
640 index_filename = DEFAULT_POETRY_IND;
641 data_filename = DEFAULT_POETRY_DAT;
642 }
643 TryLoadIndex();
644
645 #ifdef __WXMSW__
646 Corner1 = new wxIcon("icon_1");
647 Corner2 = new wxIcon("icon_2");
648 Corner3 = new wxIcon("icon_3");
649 Corner4 = new wxIcon("icon_4");
650 #endif
651 #if defined(__WXGTK__) || defined(__WXMOTIF__)
652 Corner1 = new wxIcon( corner1_xpm );
653 Corner2 = new wxIcon( corner2_xpm );
654 Corner3 = new wxIcon( corner3_xpm );
655 Corner4 = new wxIcon( corner4_xpm );
656 #endif
657
658 TheMainWindow->GetIndexLoadPoem();
659 TheMainWindow->Resize();
660 TheMainWindow->Show(TRUE);
661
662 return TRUE;
663 }
664
665 int MyApp::OnExit()
666 {
667 if (backingBitmap)
668 delete backingBitmap;
669 delete HelpController;
670 delete GreyPen;
671 delete DarkGreyPen;
672 delete WhitePen;
673
674 delete Corner1;
675 delete Corner2;
676 delete Corner3;
677 delete Corner4;
678
679 delete NormalFont;
680 delete BoldFont;
681 delete ItalicFont;
682 delete poem_buffer;
683
684 return 0;
685 }
686
687 void MainWindow::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
688 {
689 WritePreferences();
690 this->Destroy();
691 }
692
693 void MainWindow::OnChar(wxKeyEvent& event)
694 {
695 canvas->OnChar(event);
696 }
697
698 BEGIN_EVENT_TABLE(MyCanvas, wxPanel)
699 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
700 EVT_CHAR(MyCanvas::OnChar)
701 EVT_PAINT(MyCanvas::OnPaint)
702 END_EVENT_TABLE()
703
704 // Define a constructor for my canvas
705 MyCanvas::MyCanvas(wxFrame *frame, wxWindowID id, const wxPoint& pos, const wxSize& size):
706 wxPanel(frame, id, pos, size)
707 {
708 }
709
710 // Define the repainting behaviour
711 void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
712 {
713 wxPaintDC dc(this);
714
715 if (backingBitmap)
716 {
717 int xx, yy;
718 TheMainWindow->GetClientSize(&xx, &yy);
719
720 wxMemoryDC memDC;
721 memDC.SelectObject(* backingBitmap);
722 dc.Blit(0, 0, backingBitmap->GetWidth(), backingBitmap->GetHeight(), &memDC, 0, 0);
723 }
724 }
725
726 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
727 {
728 long x, y;
729 event.Position(&x, &y);
730 static int startPosX, startPosY, startFrameX, startFrameY;
731
732 event.Position(&x, &y);
733
734 if (event.RightDown())
735 {
736 // Versions from wxWin 1.67 are probably OK
737 PopupMenu(popupMenu, (int)x, (int)y );
738 }
739 else if (event.LeftDown())
740 {
741 this->CaptureMouse();
742 int x1 = (int)x;
743 int y1 = (int)y;
744 ClientToScreen(&x1, &y1);
745 startPosX = x1;
746 startPosY = y1;
747 GetParent()->GetPosition(&startFrameX, &startFrameY);
748 }
749 else if (event.LeftUp())
750 this->ReleaseMouse();
751 else if (event.Dragging() && event.LeftIsDown())
752 {
753 int x1 = (int)x;
754 int y1 = (int)y;
755 ClientToScreen(&x1, &y1);
756
757 int dX = x1 - startPosX;
758 int dY = y1 - startPosY;
759 GetParent()->Move(startFrameX + dX, startFrameY + dY);
760 }
761 }
762
763 // Process characters
764 void MyCanvas::OnChar(wxKeyEvent& event)
765 {
766 switch (event.KeyCode())
767 {
768 case 'n':
769 case 'N':
770 // Next match
771 TheMainWindow->Search(FALSE);
772 break;
773 case 's':
774 case 'S':
775 // New search
776 TheMainWindow->Search(TRUE);
777 break;
778 case WXK_SPACE:
779 // Another poem
780 TheMainWindow->NextPage();
781 break;
782 case 27:
783 TheMainWindow->Close(TRUE);
784 default:
785 break;
786 }
787 }
788
789 // Load index file
790 int LoadIndex(char *file_name)
791 {
792 long data;
793 FILE *index_file;
794
795 int i = 0;
796 char buf[100];
797
798 if (file_name)
799 sprintf(buf, "%s.idx", file_name);
800 if (! (file_name && (index_file = fopen(buf, "r"))))
801 return 0;
802 else
803 {
804 fscanf(index_file, "%ld", &nitems);
805
806 for (i = 0; i < nitems; i++)
807 {
808 fscanf(index_file, "%ld", &data);
809 poem_index[i] = data;
810 }
811 fclose(index_file);
812
813 return 1;
814 }
815 }
816
817 // Get index
818 int GetIndex()
819 {
820 int indexn = 0;
821
822 indexn = (int)(rand() % nitems);
823
824 if ((indexn < 0) || (indexn > nitems))
825 { PoetryError("No such poem!");
826 return -1;
827 }
828 else
829 return indexn;
830 }
831
832 // Read preferences
833 void ReadPreferences()
834 {
835 wxGetResource("wxPoem", "FontSize", &pointSize);
836 wxGetResource("wxPoem", "X", &XPos);
837 wxGetResource("wxPoem", "Y", &YPos);
838 }
839
840 // Write preferences to disk
841 void WritePreferences()
842 {
843 #ifdef __WXMSW__
844 TheMainWindow->GetPosition(&XPos, &YPos);
845 wxWriteResource("wxPoem", "FontSize", pointSize);
846 wxWriteResource("wxPoem", "X", XPos);
847 wxWriteResource("wxPoem", "Y", YPos);
848 #endif
849 }
850
851 // Load a poem from given file, at given point in file.
852 // If position is > -1, use this for the position in the
853 // file, otherwise use index[index_ptr] to find the correct position.
854 bool LoadPoem(char *file_name, long position)
855 {
856 int ch = 0;
857 int i = 0;
858 // int j = 0;
859 // int indexn = 0;
860 char buf[100];
861 long data;
862 FILE *data_file;
863
864 paging = FALSE;
865 current_page = 0;
866
867 if (file_name)
868 sprintf(buf, "%s.dat", file_name);
869
870 if (! (file_name && (data_file = fopen(buf, "r"))))
871 {
872 sprintf(error_buf, "Data file %s not found.", buf);
873 PoetryError(error_buf);
874 return FALSE;
875 }
876 else
877 {
878 if (position > -1)
879 data = position;
880 else
881 data = poem_index[index_ptr];
882
883 fseek(data_file, data, SEEK_SET);
884
885 ch = 0;
886 i = 0;
887 while ((ch != EOF) && (ch != '#'))
888 {
889 ch = getc(data_file);
890 // Add a linefeed so it will copy to the clipboard ok
891 if (ch == 10)
892 {
893 poem_buffer[i] = 13;
894 i++;
895 }
896
897 poem_buffer[i] = ch;
898 i ++;
899
900 if (i == buf_size)
901 {
902 sprintf(error_buf, "%s", "Poetry buffer exceeded.");
903 PoetryError(error_buf);
904 return FALSE;
905 }
906 }
907 fclose(data_file);
908 poem_buffer[i-1] = 0;
909 return TRUE;
910 }
911 }
912
913 // Do the search
914 long MainWindow::DoSearch(void)
915 {
916 if (!search_string)
917 return FALSE;
918
919 FILE *file;
920 long i = 0;
921 int ch = 0;
922 char buf[100];
923 long find_start;
924 long previous_poem_start;
925
926 bool found = FALSE;
927 int search_length = strlen(search_string);
928
929 if (same_search)
930 {
931 find_start = last_find + 1;
932 previous_poem_start = last_poem_start;
933 }
934 else
935 {
936 find_start = 0;
937 last_poem_start = 0;
938 previous_poem_start = -1;
939 }
940
941 if (data_filename)
942 sprintf(buf, "%s.dat", data_filename);
943
944 if (! (data_filename && (file = fopen(buf, "r"))))
945 {
946 sprintf(error_buf, "Poetry data file %s not found\n", buf);
947 PoetryError(error_buf);
948 return FALSE;
949 }
950
951 fseek(file, find_start, SEEK_SET);
952
953 while ((ch != EOF) && !found)
954 {
955 ch = getc(file);
956 ch |= 0x0020; // Make lower case
957
958 // Only match if we're looking at a different poem
959 // (no point in displaying the same poem again)
960 if ((ch == search_string[i]) && (last_poem_start != previous_poem_start))
961 {
962 if (i == 0)
963 last_find = ftell(file);
964 if (i == search_length-1)
965 found = TRUE;
966 i ++;
967 }
968 else
969 i = 0;
970
971 if (ch == '#')
972 {
973 ch = getc(file);
974 last_poem_start = ftell(file);
975 }
976 }
977 fclose(file);
978 if (ch == EOF)
979 last_find = -1;
980
981 if (found)
982 {
983 return last_poem_start;
984 }
985 else
986 return -1;
987 }
988
989 // Set up poetry filenames, preferences, load the index
990 // Load index (or compile it if none found)
991 void TryLoadIndex()
992 {
993 index_ok = LoadIndex(index_filename);
994 if (!index_ok || (nitems == 0))
995 {
996 PoetryError("Index file not found; will compile new one", "wxPoem");
997 index_ok = Compile();
998 }
999 }
1000
1001 // Error message
1002 void PoetryError(char *msg, char *caption)
1003 {
1004 wxMessageBox(msg, caption, wxOK|wxICON_EXCLAMATION);
1005 }
1006
1007 // Notification (change icon to something appropriate!)
1008 void PoetryNotify(char *Msg, char *caption)
1009 {
1010 wxMessageBox(Msg, caption, wxOK | wxICON_INFORMATION);
1011 }
1012
1013 // Build up and save an index into the poetry data file, for
1014 // rapid random access
1015 bool Compile(void)
1016 {
1017 FILE *file;
1018 long i = 0;
1019 int j;
1020 int ch = 0;
1021 char buf[100];
1022
1023 if (data_filename)
1024 sprintf(buf, "%s.dat", data_filename);
1025
1026 if (! (data_filename && (file = fopen(buf, "r"))))
1027 {
1028 sprintf(error_buf, "Poetry data file %s not found\n", buf);
1029 PoetryError(error_buf);
1030 return FALSE;
1031 }
1032
1033 nitems = 0;
1034
1035 // Do first one (?)
1036 poem_index[nitems] = 0;
1037 nitems ++;
1038
1039 // Do rest
1040 while (ch != EOF)
1041 {
1042 ch = getc(file);
1043 i ++;
1044 if (ch == '#')
1045 {
1046 ch = getc(file);
1047 long data;
1048 data = ftell(file);
1049 poem_index[nitems] = data;
1050 nitems ++;
1051 }
1052 }
1053 fclose(file);
1054
1055 if (index_filename)
1056 sprintf(buf, "%s.idx", index_filename);
1057 if (! (data_filename && (file = fopen(buf, "w"))))
1058 {
1059 sprintf(error_buf, "Poetry index file %s cannot be created\n", buf);
1060 PoetryError(error_buf);
1061 return FALSE;
1062 }
1063
1064 fprintf(file, "%ld\n\n", nitems);
1065 for (j = 0; j < nitems; j++)
1066 fprintf(file, "%ld\n", poem_index[j]);
1067
1068 fclose(file);
1069 PoetryNotify("Poetry index compiled.");
1070 return TRUE;
1071 }
1072
1073 void PopupFunction(wxMenu& /*menu*/, wxCommandEvent& event)
1074 {
1075 switch (event.GetId())
1076 {
1077 case POEM_NEXT:
1078 // Another poem/page
1079 TheMainWindow->NextPage();
1080 break;
1081 case POEM_PREVIOUS:
1082 // Previous page
1083 TheMainWindow->PreviousPage();
1084 break;
1085 case POEM_SEARCH:
1086 // Search - with dialog
1087 TheMainWindow->Search(TRUE);
1088 break;
1089 case POEM_NEXT_MATCH:
1090 // Search - without dialog (next match)
1091 TheMainWindow->Search(FALSE);
1092 break;
1093 case POEM_MINIMIZE:
1094 TheMainWindow->Iconize(TRUE);
1095 break;
1096 #ifdef __WXMSW__
1097 case POEM_COPY:
1098 // Copy current poem to the clipboard
1099 CopyToClipboard((HWND) TheMainWindow->GetHWND(), poem_buffer);
1100 break;
1101 #endif
1102 case POEM_COMPILE:
1103 // Compile index
1104 Compile();
1105 break;
1106 case POEM_BIGGER_TEXT:
1107 {
1108 pointSize ++;
1109 CreateFonts();
1110 TheMainWindow->Resize();
1111 break;
1112 }
1113 case POEM_SMALLER_TEXT:
1114 {
1115 if (pointSize > 2)
1116 {
1117 pointSize --;
1118 CreateFonts();
1119 TheMainWindow->Resize();
1120 }
1121 break;
1122 }
1123 case POEM_HELP_CONTENTS:
1124 {
1125 HelpController->LoadFile("wxpoem");
1126 HelpController->DisplayContents();
1127 break;
1128 }
1129 case POEM_ABOUT:
1130 {
1131 (void)wxMessageBox("wxPoem Version 1.1\nJulian Smart (c) 1995",
1132 "About wxPoem", wxOK, TheMainWindow);
1133 break;
1134 }
1135 case POEM_EXIT:
1136 // Exit
1137 TheMainWindow->Close(TRUE);
1138 break;
1139 default:
1140 break;
1141 }
1142 }