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