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