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