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