]> git.saurik.com Git - wxWidgets.git/blob - demos/poem/wxpoem.cpp
GetBestFittingSize --> GetEffectiveMinSize
[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 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 #include "wxpoem.h"
29
30 #include "corner1.xpm"
31 #include "corner2.xpm"
32 #include "corner3.xpm"
33 #include "corner4.xpm"
34 #include "wxpoem.xpm"
35
36 #define buf_size 10000
37 #define DEFAULT_POETRY_DAT "wxpoem"
38 #define DEFAULT_POETRY_IND "wxpoem"
39 #define DEFAULT_CHAR_HEIGHT 18
40 #define DEFAULT_FONT "Swiss"
41 #define DEFAULT_X_POS 0
42 #define DEFAULT_Y_POS 0
43 #define BORDER_SIZE 30
44 #define THIN_LINE_BORDER 10
45 #define THICK_LINE_BORDER 16
46 #define THICK_LINE_WIDTH 2
47 #define SHADOW_OFFSET 1
48 #define X_SIZE 30
49 #define Y_SIZE 20
50
51 static wxChar *poem_buffer; // Storage for each poem
52 static wxChar line[150]; // Storage for a line
53 static int pages[30]; // For multipage poems -
54 // store the start of each page
55 static long last_poem_start = 0; // Start of last found poem
56 static long last_find = -1; // Point in file of last found
57 // search string
58 static bool search_ok = false; // Search was successful
59 static bool same_search = false; // Searching on same string
60
61 static long poem_index[600]; // Index of poem starts
62 static long nitems = 0; // Number of poems
63 static int char_height = DEFAULT_CHAR_HEIGHT; // Actual height
64 static int index_ptr = -1; // Pointer into index
65 static int poem_height, poem_width; // Size of poem
66 static int XPos; // Startup X position
67 static int YPos; // Startup Y position
68 static int pointSize = 12; // Font size
69
70 static wxChar *index_filename = NULL; // Index filename
71 static wxChar *data_filename = NULL; // Data filename
72 static wxChar error_buf[300]; // Error message buffer
73 static bool loaded_ok = false; // Poem loaded ok
74 static bool index_ok = false; // Index loaded ok
75
76 static bool paging = false; // Are we paging?
77 static int current_page = 0; // Currently viewed page
78
79 // Backing bitmap
80 wxBitmap *backingBitmap = NULL;
81
82 void PoetryError(wxChar *, wxChar *caption=_T("wxPoem Error"));
83 void PoetryNotify(wxChar *Msg, wxChar *caption=_T("wxPoem"));
84 void TryLoadIndex();
85 bool LoadPoem(wxChar *, long);
86 int GetIndex();
87 int LoadIndex(wxChar *);
88 bool Compile(void);
89 void FindMax(int *max_thing, int thing);
90
91 #if wxUSE_CLIPBOARD
92 #include "wx/dataobj.h"
93 #include "wx/clipbrd.h"
94 #endif
95
96 #ifdef __WXWINCE__
97 STDAPI_(__int64) CeGetRandomSeed();
98 #endif
99
100 IMPLEMENT_APP(MyApp)
101
102 MainWindow *TheMainWindow = NULL;
103
104 // Create the fonts
105 void MainWindow::CreateFonts()
106 {
107 m_normalFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxNORMAL);
108 m_boldFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxBOLD);
109 m_italicFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxITALIC, wxNORMAL);
110 }
111
112 BEGIN_EVENT_TABLE(MainWindow, wxFrame)
113 EVT_CLOSE(MainWindow::OnCloseWindow)
114 EVT_CHAR(MainWindow::OnChar)
115 EVT_MENU(wxID_ANY, MainWindow::OnPopup)
116 END_EVENT_TABLE()
117
118 MainWindow::MainWindow(wxFrame *frame, wxWindowID id, const wxString& title,
119 const wxPoint& pos, const wxSize& size, long style):
120 wxFrame(frame, id, title, pos, size, style)
121 {
122 m_corners[0] = m_corners[1] = m_corners[2] = m_corners[3] = NULL;
123
124 ReadPreferences();
125 CreateFonts();
126
127 SetIcon(wxpoem_xpm);
128
129 m_corners[0] = new wxIcon( corner1_xpm );
130 m_corners[1] = new wxIcon( corner2_xpm );
131 m_corners[2] = new wxIcon( corner3_xpm );
132 m_corners[3] = new wxIcon( corner4_xpm );
133 }
134
135 MainWindow::~MainWindow()
136 {
137 for (int i=0;i<4;i++)
138 {
139 if(m_corners[i])
140 {
141 delete m_corners[i];
142 }
143 }
144 }
145
146 // Read the poetry buffer, either for finding the size
147 // or for writing to a bitmap (not to the window directly,
148 // since that displays messily)
149 // If DrawIt is true, we draw, otherwise we just determine the
150 // size the window should be.
151 void MainWindow::ScanBuffer(wxDC *dc, bool DrawIt, int *max_x, int *max_y)
152 {
153 int i = pages[current_page];
154 int ch = -1;
155 int y = 0;
156 int j;
157 wxChar *line_ptr;
158 int curr_width = 0;
159 bool page_break = false;
160
161 int width = 0;
162 int height = 0;
163
164 if (DrawIt)
165 {
166 y = (*max_y - poem_height)/2;
167 width = *max_x;
168 height = *max_y;
169 }
170
171 if (DrawIt && wxColourDisplay())
172 {
173 dc->SetBrush(*wxLIGHT_GREY_BRUSH);
174 dc->SetPen(*wxGREY_PEN);
175 dc->DrawRectangle(0, 0, width, height);
176 dc->SetBackgroundMode(wxTRANSPARENT);
177 }
178
179 // See what ACTUAL char height is
180 if(m_normalFont)
181 dc->SetFont(*m_normalFont);
182 long xx;
183 long yy;
184 dc->GetTextExtent(_T("X"), &xx, &yy);
185 char_height = (int)yy;
186
187 if (current_page == 0)
188 {
189 m_title = wxEmptyString;
190 }
191 else if (!m_title.empty())
192 {
193 dc->SetFont(* m_boldFont);
194 dc->GetTextExtent(m_title, &xx, &yy);
195 FindMax(&curr_width, (int)xx);
196
197 if (DrawIt)
198 {
199 int x = (width - xx)/2;
200 dc->SetFont(* m_boldFont);
201
202 // Change text to BLACK!
203 dc->SetTextForeground(* wxBLACK);
204 dc->DrawText(m_title, x, y);
205 // Change text to WHITE!
206 dc->SetTextForeground(* wxWHITE);
207 dc->DrawText(m_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] = (wxChar)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(* m_boldFont);
262 line_ptr = line+3;
263
264 m_title = line_ptr;
265 m_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(* m_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(* m_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(* m_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(* m_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(* m_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(* m_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(*wxWHITE_PEN);
386 else
387 dc->SetPen(*wxBLACK_PEN);
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(*wxBLACK_PEN);
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 // Draw icons
402 dc->DrawIcon(* m_corners[0], 0, 0);
403 dc->DrawIcon(* m_corners[1], int(width-32), 0);
404
405 int y2 = height - 32;
406 int x2 = (width-32);
407 dc->DrawIcon(* m_corners[2], 0, y2);
408 dc->DrawIcon(* m_corners[3], x2, y2);
409 }
410 }
411
412 // Get an index (randomly generated) and load the poem
413 void MainWindow::GetIndexLoadPoem(void)
414 {
415 if (index_ok)
416 index_ptr = GetIndex();
417
418 if (index_ptr > -1)
419 loaded_ok = LoadPoem(data_filename, -1);
420 }
421
422 // Find the size of the poem and resize the window accordingly
423 void MainWindow::Resize(void)
424 {
425 wxClientDC dc(canvas);
426
427 // Get the poem size
428 ScanBuffer(& dc, false, &poem_width, &poem_height);
429 int x = poem_width + (2*BORDER_SIZE);
430 int y = poem_height + (2*BORDER_SIZE);
431
432 SetClientSize(x, y);
433
434 // In case client size isn't what we set it to...
435 int xx, yy;
436 GetClientSize(&xx, &yy);
437
438 wxMemoryDC memDC;
439 if (backingBitmap) delete backingBitmap;
440 backingBitmap = new wxBitmap(x, yy);
441 memDC.SelectObject(* backingBitmap);
442
443 memDC.Clear();
444 ScanBuffer(&memDC, true, &xx, &yy);
445 }
446
447 // Which is more?
448 void FindMax(int *max_thing, int thing)
449 {
450 if (thing > *max_thing)
451 *max_thing = thing;
452 }
453
454 // Next page/poem
455 void MainWindow::NextPage(void)
456 {
457 if (paging)
458 current_page ++;
459 else
460 {
461 current_page = 0;
462 GetIndexLoadPoem();
463 }
464 Resize();
465 }
466
467 // Previous page
468 void MainWindow::PreviousPage(void)
469 {
470 if (current_page > 0)
471 {
472 current_page --;
473 Resize();
474 }
475 }
476
477 // Search for a string
478 void MainWindow::Search(bool ask)
479 {
480 long position;
481
482 if (ask || m_searchString.empty())
483 {
484 wxString s = wxGetTextFromUser( _T("Enter search string"), _T("Search"), m_searchString);
485 if (!s.empty())
486 {
487 s.MakeLower();
488 m_searchString = s;
489 search_ok = true;
490 }
491 else
492 {
493 search_ok = false;
494 }
495 }
496 else
497 {
498 same_search = true;
499 search_ok = true;
500 }
501
502 if (!m_searchString.empty() && search_ok)
503 {
504 position = DoSearch();
505 if (position > -1)
506 {
507 loaded_ok = LoadPoem(data_filename, position);
508 Resize();
509 }
510 else
511 {
512 last_poem_start = 0;
513 PoetryNotify(_T("Search string not found."));
514 }
515 }
516 }
517
518 bool MyApp::OnInit()
519 {
520 poem_buffer = new wxChar[buf_size];
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->canvas = new MyCanvas(TheMainWindow);
544
545 if (argc > 1)
546 {
547 index_filename = wxStrcpy(new wxChar[wxStrlen(argv[1]) + 1], argv[1]);
548 data_filename = wxStrcpy(new wxChar[wxStrlen(argv[1]) + 1], argv[1]);
549 }
550 else
551 {
552 index_filename = _T(DEFAULT_POETRY_IND);
553 data_filename = _T(DEFAULT_POETRY_DAT);
554 }
555 TryLoadIndex();
556
557 TheMainWindow->GetIndexLoadPoem();
558 TheMainWindow->Resize();
559 TheMainWindow->Show(true);
560
561 return true;
562 }
563
564 int MyApp::OnExit()
565 {
566 if (backingBitmap)
567 delete backingBitmap;
568
569 delete[] poem_buffer;
570
571 return 0;
572 }
573
574 void MainWindow::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
575 {
576 WritePreferences();
577 this->Destroy();
578 }
579
580 void MainWindow::OnChar(wxKeyEvent& event)
581 {
582 canvas->OnChar(event);
583 }
584
585 BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
586 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
587 EVT_CHAR(MyCanvas::OnChar)
588 EVT_PAINT(MyCanvas::OnPaint)
589 END_EVENT_TABLE()
590
591 // Define a constructor for my canvas
592 MyCanvas::MyCanvas(wxFrame *frame):
593 wxWindow(frame, wxID_ANY)
594 {
595 m_popupMenu = new wxMenu;
596 m_popupMenu->Append(POEM_NEXT, _T("Next poem/page"));
597 m_popupMenu->Append(POEM_PREVIOUS, _T("Previous page"));
598 m_popupMenu->AppendSeparator();
599 m_popupMenu->Append(POEM_SEARCH, _T("Search"));
600 m_popupMenu->Append(POEM_NEXT_MATCH, _T("Next match"));
601 m_popupMenu->Append(POEM_COPY, _T("Copy to clipboard"));
602 m_popupMenu->Append(POEM_MINIMIZE, _T("Minimize"));
603 m_popupMenu->AppendSeparator();
604 m_popupMenu->Append(POEM_BIGGER_TEXT, _T("Bigger text"));
605 m_popupMenu->Append(POEM_SMALLER_TEXT, _T("Smaller text"));
606 m_popupMenu->AppendSeparator();
607 m_popupMenu->Append(POEM_ABOUT, _T("About wxPoem"));
608 m_popupMenu->AppendSeparator();
609 m_popupMenu->Append(POEM_EXIT, _T("Exit"));
610 }
611
612 MyCanvas::~MyCanvas()
613 {
614 // Note: this must be done before the main window/canvas are destroyed
615 // or we get an error (no parent window for menu item button)
616 delete m_popupMenu;
617 m_popupMenu = NULL;
618 }
619
620 // Define the repainting behaviour
621 void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
622 {
623 wxPaintDC dc(this);
624
625 if (backingBitmap)
626 {
627 int xx, yy;
628 TheMainWindow->GetClientSize(&xx, &yy);
629
630 dc.DrawBitmap(* backingBitmap, 0, 0);
631 #if 0
632 wxMemoryDC memDC;
633 memDC.SelectObject(* backingBitmap);
634 dc.Blit(0, 0, backingBitmap->GetWidth(), backingBitmap->GetHeight(), &memDC, 0, 0);
635 #endif
636 }
637 }
638
639 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
640 {
641 static int startPosX, startPosY, startFrameX, startFrameY;
642
643 long x, y;
644 event.GetPosition(&x, &y);
645
646 if (event.RightDown())
647 {
648 // Versions from wxWin 1.67 are probably OK
649 PopupMenu(m_popupMenu, (int)x, (int)y );
650 }
651 else if (event.LeftDown())
652 {
653 this->CaptureMouse();
654 int x1 = (int)x;
655 int y1 = (int)y;
656 ClientToScreen(&x1, &y1);
657 startPosX = x1;
658 startPosY = y1;
659 GetParent()->GetPosition(&startFrameX, &startFrameY);
660 }
661 else if (event.LeftUp())
662 {
663 if (GetCapture() == this) this->ReleaseMouse();
664 }
665 else if (event.Dragging() && event.LeftIsDown())
666 {
667 int x1 = (int)x;
668 int y1 = (int)y;
669 ClientToScreen(&x1, &y1);
670
671 int dX = x1 - startPosX;
672 int dY = y1 - startPosY;
673 GetParent()->Move(startFrameX + dX, startFrameY + dY);
674 }
675 }
676
677 // Process characters
678 void MyCanvas::OnChar(wxKeyEvent& event)
679 {
680 switch (event.GetKeyCode())
681 {
682 case 'n':
683 case 'N':
684 // Next match
685 TheMainWindow->Search(false);
686 break;
687
688 case 's':
689 case 'S':
690 // New search
691 TheMainWindow->Search(true);
692 break;
693
694 case WXK_SPACE:
695 case WXK_RIGHT:
696 case WXK_DOWN:
697 // Another poem
698 TheMainWindow->NextPage();
699 break;
700
701 case WXK_ESCAPE:
702 TheMainWindow->Close(true);
703 default:
704 break;
705 }
706 }
707
708 // Load index file
709 int LoadIndex(wxChar *file_name)
710 {
711 long data;
712 FILE *index_file;
713
714 wxChar buf[100];
715
716 if (file_name == NULL)
717 return 0;
718
719 wxSprintf(buf, _T("%s.idx"), file_name);
720
721 index_file = wxFopen(buf, _T("r"));
722 if (index_file == NULL)
723 return 0;
724
725 wxFscanf(index_file, _T("%ld"), &nitems);
726
727 for (int i = 0; i < nitems; i++)
728 {
729 wxFscanf(index_file, _T("%ld"), &data);
730 poem_index[i] = data;
731 }
732
733 fclose(index_file);
734
735 return 1;
736 }
737
738 // Get index
739 int GetIndex()
740 {
741 int indexn = (int)(rand() % nitems);
742
743 if ((indexn < 0) || (indexn > nitems))
744 { PoetryError(_T("No such poem!"));
745 return -1;
746 }
747 else
748 return indexn;
749 }
750
751 // Read preferences
752 void MainWindow::ReadPreferences()
753 {
754 #if wxUSE_RESOURCES
755 wxGetResource(_T("wxPoem"), _T("FontSize"), &pointSize);
756 wxGetResource(_T("wxPoem"), _T("X"), &XPos);
757 wxGetResource(_T("wxPoem"), _T("Y"), &YPos);
758 #endif
759 }
760
761 // Write preferences to disk
762 void MainWindow::WritePreferences()
763 {
764 #ifdef __WXMSW__
765 TheMainWindow->GetPosition(&XPos, &YPos);
766 #if wxUSE_RESOURCES
767 wxWriteResource(_T("wxPoem"), _T("FontSize"), pointSize);
768 wxWriteResource(_T("wxPoem"), _T("X"), XPos);
769 wxWriteResource(_T("wxPoem"), _T("Y"), YPos);
770 #endif
771 #endif
772 }
773
774 // Load a poem from given file, at given point in file.
775 // If position is > -1, use this for the position in the
776 // file, otherwise use index[index_ptr] to find the correct position.
777 bool LoadPoem(wxChar *file_name, long position)
778 {
779 // int j = 0;
780 // int indexn = 0;
781 wxChar buf[100];
782 long data;
783 FILE *data_file;
784
785 paging = false;
786 current_page = 0;
787
788 if (file_name == NULL)
789 {
790 wxSprintf(error_buf, _T("Error in Poem loading."));
791 PoetryError(error_buf);
792 return false;
793 }
794
795 wxSprintf(buf, _T("%s.dat"), file_name);
796 data_file = wxFopen(buf, _T("r"));
797
798 if (data_file == NULL)
799 {
800 wxSprintf(error_buf, _T("Data file %s not found."), buf);
801 PoetryError(error_buf);
802 return false;
803 }
804
805 if (position > -1)
806 data = position;
807 else
808 data = poem_index[index_ptr];
809
810 fseek(data_file, data, SEEK_SET);
811
812 int ch = 0;
813 int i = 0;
814 while ((ch != EOF) && (ch != '#'))
815 {
816 ch = getc(data_file);
817 // Add a linefeed so it will copy to the clipboard ok
818 if (ch == 10)
819 {
820 poem_buffer[i] = 13;
821 i++;
822 }
823
824 poem_buffer[i] = (wxChar)ch;
825 i ++;
826
827 if (i == buf_size)
828 {
829 wxSprintf(error_buf, _T("%s"), _T("Poetry buffer exceeded."));
830 PoetryError(error_buf);
831 return false;
832 }
833 }
834 fclose(data_file);
835 poem_buffer[i-1] = 0;
836 return true;
837 }
838
839 // Do the search
840 long MainWindow::DoSearch(void)
841 {
842 if (m_searchString.empty())
843 return false;
844
845 FILE *file;
846 size_t i = 0;
847 int ch = 0;
848 wxChar buf[100];
849 long find_start;
850 long previous_poem_start;
851
852 bool found = false;
853 size_t search_length = m_searchString.length();
854
855 if (same_search)
856 {
857 find_start = last_find + 1;
858 previous_poem_start = last_poem_start;
859 }
860 else
861 {
862 find_start = 0;
863 last_poem_start = 0;
864 previous_poem_start = -1;
865 }
866
867 if (data_filename)
868 wxSprintf(buf, _T("%s.dat"), data_filename);
869
870 file = wxFopen(buf, _T("r"));
871 if (! (data_filename && file))
872 {
873 wxSprintf(error_buf, _T("Poetry data file %s not found\n"), buf);
874 PoetryError(error_buf);
875 return false;
876 }
877
878 fseek(file, find_start, SEEK_SET);
879
880 while ((ch != EOF) && !found)
881 {
882 ch = getc(file);
883 ch = wxTolower(ch); // Make lower case
884
885 // Only match if we're looking at a different poem
886 // (no point in displaying the same poem again)
887 if ((ch == m_searchString[i]) && (last_poem_start != previous_poem_start))
888 {
889 if (i == 0)
890 last_find = ftell(file);
891 if (i == search_length-1)
892 found = true;
893 i ++;
894 }
895 else
896 {
897 i = 0;
898 }
899
900 if (ch == '#')
901 {
902 ch = getc(file);
903 last_poem_start = ftell(file);
904 }
905 }
906 fclose(file);
907 if (ch == EOF)
908 {
909 last_find = -1;
910 }
911
912 if (found)
913 {
914 return last_poem_start;
915 }
916
917 return -1;
918 }
919
920 // Set up poetry filenames, preferences, load the index
921 // Load index (or compile it if none found)
922 void TryLoadIndex()
923 {
924 index_ok = (LoadIndex(index_filename) != 0);
925 if (!index_ok || (nitems == 0))
926 {
927 PoetryError(_T("Index file not found; will compile new one"), _T("wxPoem"));
928 index_ok = Compile();
929 }
930 }
931
932 // Error message
933 void PoetryError(wxChar *msg, wxChar *caption)
934 {
935 wxMessageBox(msg, caption, wxOK|wxICON_EXCLAMATION);
936 }
937
938 // Notification (change icon to something appropriate!)
939 void PoetryNotify(wxChar *Msg, wxChar *caption)
940 {
941 wxMessageBox(Msg, caption, wxOK | wxICON_INFORMATION);
942 }
943
944 // Build up and save an index into the poetry data file, for
945 // rapid random access
946 bool Compile(void)
947 {
948 FILE *file;
949 int j;
950 int ch;
951 wxChar buf[100];
952
953 if (data_filename)
954 wxSprintf(buf, _T("%s.dat"), data_filename);
955
956 file = wxFopen(buf, _T("r"));
957 if (! (data_filename && file))
958 {
959 wxSprintf(error_buf, _T("Poetry data file %s not found\n"), buf);
960 PoetryError(error_buf);
961 return false;
962 }
963
964 nitems = 0;
965
966 // Do first one (?)
967 poem_index[nitems] = 0;
968 nitems ++;
969
970 // Do rest
971
972 do {
973 ch = getc(file);
974 if (ch == '#')
975 {
976 ch = getc(file);
977 long data;
978 data = ftell(file);
979 poem_index[nitems] = data;
980 nitems ++;
981 }
982 } while (ch != EOF);
983 fclose(file);
984
985 if (index_filename)
986 wxSprintf(buf, _T("%s.idx"), index_filename);
987
988 file = wxFopen(buf, _T("w"));
989 if (! (data_filename && file))
990 {
991 wxSprintf(error_buf, _T("Poetry index file %s cannot be created\n"), buf);
992 PoetryError(error_buf);
993 return false;
994 }
995
996 wxFprintf(file, _T("%ld\n\n"), nitems);
997 for (j = 0; j < nitems; j++)
998 wxFprintf(file, _T("%ld\n"), poem_index[j]);
999
1000 fclose(file);
1001 PoetryNotify(_T("Poetry index compiled."));
1002 return true;
1003 }
1004
1005 void MainWindow::OnPopup(wxCommandEvent& event)
1006 {
1007 switch (event.GetId())
1008 {
1009 case POEM_NEXT:
1010 // Another poem/page
1011 TheMainWindow->NextPage();
1012 break;
1013 case POEM_PREVIOUS:
1014 // Previous page
1015 TheMainWindow->PreviousPage();
1016 break;
1017 case POEM_SEARCH:
1018 // Search - with dialog
1019 TheMainWindow->Search(true);
1020 break;
1021 case POEM_NEXT_MATCH:
1022 // Search - without dialog (next match)
1023 TheMainWindow->Search(false);
1024 break;
1025 case POEM_MINIMIZE:
1026 TheMainWindow->Iconize(true);
1027 break;
1028 #if wxUSE_CLIPBOARD
1029 case POEM_COPY:
1030 wxTheClipboard->UsePrimarySelection();
1031 if (wxTheClipboard->Open())
1032 {
1033 static wxString s;
1034 s = poem_buffer;
1035 s.Replace( _T("@P"),wxEmptyString);
1036 s.Replace( _T("@A "),wxEmptyString);
1037 s.Replace( _T("@A"),wxEmptyString);
1038 s.Replace( _T("@T "),wxEmptyString);
1039 s.Replace( _T("@T"),wxEmptyString);
1040 wxTextDataObject *data = new wxTextDataObject( s.c_str() );
1041 if (!wxTheClipboard->SetData( data ))
1042 wxMessageBox(_T("Error while copying to the clipboard."));
1043 }
1044 else
1045 {
1046 wxMessageBox(_T("Error opening the clipboard."));
1047 }
1048 wxTheClipboard->Close();
1049 break;
1050 #endif
1051 case POEM_BIGGER_TEXT:
1052 pointSize ++;
1053 CreateFonts();
1054 TheMainWindow->Resize();
1055 break;
1056 case POEM_SMALLER_TEXT:
1057 if (pointSize > 2)
1058 {
1059 pointSize --;
1060 CreateFonts();
1061 TheMainWindow->Resize();
1062 }
1063 break;
1064 case POEM_ABOUT:
1065 (void)wxMessageBox(_T("wxPoem Version 1.1\nJulian Smart (c) 1995"),
1066 _T("About wxPoem"), wxOK, TheMainWindow);
1067 break;
1068 case POEM_EXIT:
1069 // Exit
1070 TheMainWindow->Close(true);
1071 break;
1072 default:
1073 break;
1074 }
1075 }