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