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