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