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