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