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