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