wxWidgets/demos/poem/wxpoem.cpp
2002-05-14 13:53:48 +00:00

1157 lines
28 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: wxpoem.cpp
// Purpose: A small C++ program which displays a random poem on
// execution. It also allows search for poems containing a
// string.
// It requires winpoem.dat and creates winpoem.idx.
// Original version (WinPoem) written in 1994.
// This has not been rewritten in a long time so
// beware, inelegant code!
// Author: Julian Smart
// Created: 12/12/98
// RCS-ID: $Id$
// Copyright: (c) 1998 Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
#pragma implementation "wxpoem.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/help.h"
#include "wxpoem.h"
#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXX11__)
#include "corner1.xpm"
#include "corner2.xpm"
#include "corner3.xpm"
#include "corner4.xpm"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef __WINDOWS__
#include <windows.h>
#ifdef DrawText
#undef DrawText
#endif
#endif
#define buf_size 10000
#define DEFAULT_POETRY_DAT "wxpoem"
#define DEFAULT_POETRY_IND "wxpoem"
#define DEFAULT_CHAR_HEIGHT 18
#define DEFAULT_FONT "Swiss"
#define DEFAULT_X_POS 0
#define DEFAULT_Y_POS 0
#define BORDER_SIZE 30
#define THIN_LINE_BORDER 10
#define THICK_LINE_BORDER 16
#define THICK_LINE_WIDTH 2
#define SHADOW_OFFSET 1
#define X_SIZE 30
#define Y_SIZE 20
static char *poem_buffer; // Storage for each poem
static char line[150]; // Storage for a line
static char title[150]; // Remember the title
static char *search_string = NULL; // The search string
static int pages[30]; // For multipage poems -
// store the start of each page
static long last_poem_start = 0; // Start of last found poem
static long last_find = -1; // Point in file of last found
// search string
static bool search_ok = FALSE; // Search was successful
static bool same_search = FALSE; // Searching on same string
static long poem_index[600]; // Index of poem starts
static long nitems = 0; // Number of poems
static int char_height = DEFAULT_CHAR_HEIGHT; // Actual height
static int index_ptr = -1; // Pointer into index
static int poem_height, poem_width; // Size of poem
static int XPos; // Startup X position
static int YPos; // Startup Y position
static int pointSize = 12; // Font size
static char *index_filename = NULL; // Index filename
static char *data_filename = NULL; // Data filename
static char error_buf[300]; // Error message buffer
static bool loaded_ok = FALSE; // Poem loaded ok
static bool index_ok = FALSE; // Index loaded ok
static bool paging = FALSE; // Are we paging?
static int current_page = 0; // Currently viewed page
wxIcon *Corner1 = NULL;
wxIcon *Corner2 = NULL;
wxIcon *Corner3 = NULL;
wxIcon *Corner4 = NULL;
// Fonts
wxFont *NormalFont = NULL;
wxFont *BoldFont = NULL;
wxFont *ItalicFont = NULL;
// Pens
wxPen *GreyPen = NULL;
wxPen *DarkGreyPen = NULL;
wxPen *WhitePen = NULL;
// Backing bitmap
wxBitmap *backingBitmap = NULL;
void PoetryError(char *, char *caption="wxPoem Error");
void PoetryNotify(char *Msg, char *caption="wxPoem");
void TryLoadIndex();
bool LoadPoem(char *, long);
int GetIndex();
int LoadIndex(char *);
bool Compile(void);
void WritePreferences();
void ReadPreferences();
void FindMax(int *max_thing, int thing);
void CreateFonts();
#ifdef __WXMSW__
void CopyToClipboard(HWND, char *);
#endif
wxMenu *popupMenu = NULL;
#if wxUSE_HELP
wxHelpController *HelpController = NULL;
#endif // wxUSE_HELP
IMPLEMENT_APP(MyApp)
MainWindow *TheMainWindow = NULL;
// Create the fonts
void CreateFonts()
{
NormalFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxNORMAL);
BoldFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxNORMAL, wxBOLD);
ItalicFont = wxTheFontList->FindOrCreateFont(pointSize, wxSWISS, wxITALIC, wxNORMAL);
}
BEGIN_EVENT_TABLE(MainWindow, wxFrame)
EVT_CLOSE(MainWindow::OnCloseWindow)
EVT_CHAR(MainWindow::OnChar)
EVT_MENU(-1, MainWindow::OnPopup)
END_EVENT_TABLE()
MainWindow::MainWindow(wxFrame *frame, wxWindowID id, const wxString& title,
const wxPoint& pos, const wxSize& size, long style):
wxFrame(frame, id, title, pos, size, style)
{
}
MainWindow::~MainWindow()
{
// Note: this must be done before the main window/canvas are destroyed
// or we get an error (no parent window for menu item button)
delete popupMenu;
popupMenu = NULL;
}
// Read the poetry buffer, either for finding the size
// or for writing to a bitmap (not to the window directly,
// since that displays messily)
// If DrawIt is true, we draw, otherwise we just determine the
// size the window should be.
void MainWindow::ScanBuffer(wxDC *dc, bool DrawIt, int *max_x, int *max_y)
{
int i = pages[current_page];
int ch = -1;
int x = 10;
int y = 0;
int j;
char *line_ptr;
int curr_width = 0;
bool page_break = FALSE;
int width = 0;
int height = 0;
if (DrawIt)
{
y = (*max_y - poem_height)/2;
width = *max_x;
height = *max_y;
}
if (DrawIt && wxColourDisplay())
{
dc->SetBrush(*wxLIGHT_GREY_BRUSH);
dc->SetPen(*GreyPen);
dc->DrawRectangle(0, 0, width, height);
dc->SetBackgroundMode(wxTRANSPARENT);
}
// See what ACTUAL char height is
dc->SetFont(* NormalFont);
long xx;
long yy;
dc->GetTextExtent("X", &xx, &yy);
char_height = (int)yy;
if (current_page == 0)
title[0] = 0;
else if (title[0] != 0)
{
dc->SetFont(* BoldFont);
dc->GetTextExtent(title, &xx, &yy);
FindMax(&curr_width, (int)xx);
if (DrawIt)
{
x = (width - xx)/2;
dc->SetFont(* BoldFont);
// Change text to BLACK!
dc->SetTextForeground(* wxBLACK);
dc->DrawText(title, x, y);
// Change text to WHITE!
dc->SetTextForeground(* wxWHITE);
dc->DrawText(title, x-SHADOW_OFFSET, y-SHADOW_OFFSET);
}
y += char_height;
y += char_height;
}
while (ch != 0 && !page_break)
{
j = 0;
#if defined(__WXMSW__) || defined(__WXMAC__)
while (((ch = poem_buffer[i]) != 13) && (ch != 0))
#else
while (((ch = poem_buffer[i]) != 10) && (ch != 0))
#endif
{
line[j] = ch;
j ++;
i ++;
}
#if defined(__WXMSW__) || defined(__WXMAC__)
if (ch == 13)
#else
if (ch == 10)
#endif
{
ch = -1;
i ++;
#if defined(__WXMSW__) || defined(__WXMAC__)
// Add another to skip the linefeed
i ++;
#endif
// If a single newline on its own, put a space in
if (j == 0)
{
line[j] = ' ';
j ++;
line[j] = 0;
}
}
if (j > 0)
{
line[j] = 0;
if (line[0] == '@')
{
switch (line[1])
{
case 'P':
paging = TRUE;
page_break = TRUE;
break;
case 'T':
dc->SetFont(* BoldFont);
line_ptr = line+3;
strcpy(title, line_ptr);
strcat(title, " (cont'd)");
dc->GetTextExtent(line_ptr, &xx, &yy);
FindMax(&curr_width, (int)xx);
if (DrawIt)
{
x = (width - xx)/2;
dc->SetFont(* BoldFont);
// Change text to BLACK!
dc->SetTextForeground(* wxBLACK);
dc->DrawText(line_ptr, x, y);
// Change text to WHITE!
dc->SetTextForeground(* wxWHITE);
dc->DrawText(line_ptr, x-SHADOW_OFFSET, y-SHADOW_OFFSET);
dc->SetTextForeground(* wxWHITE);
}
break;
case 'A':
line_ptr = line+3;
dc->SetFont(* ItalicFont);
dc->GetTextExtent(line_ptr, &xx, &yy);
FindMax(&curr_width, (int)xx);
if (DrawIt)
{
x = (width - xx)/2;
dc->SetTextForeground(* wxBLACK);
dc->DrawText(line_ptr, x, y);
}
break;
// Default: just ignore this line
default:
y -= char_height;
}
}
else
{
dc->SetFont(* NormalFont);
dc->GetTextExtent(line, &xx, &yy);
FindMax(&curr_width, (int)xx);
if (DrawIt)
{
int x = (int)((width - xx)/2.0);
dc->SetFont(* NormalFont);
dc->SetTextForeground(* wxBLACK);
dc->DrawText(line, x, y);
}
}
}
y += char_height;
}
// Write (cont'd)
if (page_break)
{
char *cont = "(cont'd)";
dc->SetFont(* NormalFont);
dc->GetTextExtent(cont, &xx, &yy);
FindMax(&curr_width, (int)xx);
if (DrawIt)
{
int x = (int)((width - xx)/2.0);
dc->SetFont(* NormalFont);
dc->SetTextForeground(* wxBLACK);
dc->DrawText(cont, x, y);
}
y += 2*char_height;
}
*max_x = (int)curr_width;
*max_y = (int)(y-char_height);
if (page_break)
pages[current_page+1] = i;
else
paging = FALSE;
if (DrawIt)
{
// Draw dark grey thick border
if (wxColourDisplay())
{
dc->SetBrush(*wxGREY_BRUSH);
dc->SetPen(*wxGREY_PEN);
// Left side
dc->DrawRectangle(0, 0, THIN_LINE_BORDER, height);
// Top side
dc->DrawRectangle(THIN_LINE_BORDER, 0, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
// Right side
dc->DrawRectangle(width-THIN_LINE_BORDER, THIN_LINE_BORDER, width, height-THIN_LINE_BORDER);
// Bottom side
dc->DrawRectangle(THIN_LINE_BORDER, height-THIN_LINE_BORDER, width-THIN_LINE_BORDER, height);
}
// Draw border
// Have grey background, plus 3-d border -
// One black rectangle.
// Inside this, left and top sides - dark grey. Bottom and right -
// white.
// Change pen to black
dc->SetPen(*wxBLACK_PEN);
dc->DrawLine(THIN_LINE_BORDER, THIN_LINE_BORDER, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
dc->DrawLine(width-THIN_LINE_BORDER, THIN_LINE_BORDER, width-THIN_LINE_BORDER, height-THIN_LINE_BORDER);
dc->DrawLine(width-THIN_LINE_BORDER, height-THIN_LINE_BORDER, THIN_LINE_BORDER, height-THIN_LINE_BORDER);
dc->DrawLine(THIN_LINE_BORDER, height-THIN_LINE_BORDER, THIN_LINE_BORDER, THIN_LINE_BORDER);
// Right and bottom white lines - 'grey' (black!) if
// we're running on a mono display.
if (wxColourDisplay())
dc->SetPen(*WhitePen);
else
dc->SetPen(*DarkGreyPen);
dc->DrawLine(width-THICK_LINE_BORDER, THICK_LINE_BORDER,
width-THICK_LINE_BORDER, height-THICK_LINE_BORDER);
dc->DrawLine(width-THICK_LINE_BORDER, height-THICK_LINE_BORDER,
THICK_LINE_BORDER, height-THICK_LINE_BORDER);
// Left and top grey lines
dc->SetPen(*DarkGreyPen);
dc->DrawLine(THICK_LINE_BORDER, height-THICK_LINE_BORDER,
THICK_LINE_BORDER, THICK_LINE_BORDER);
dc->DrawLine(THICK_LINE_BORDER, THICK_LINE_BORDER,
width-THICK_LINE_BORDER, THICK_LINE_BORDER);
//#ifdef __WXMSW__
// Draw icons
dc->DrawIcon(* Corner1, 0, 0);
dc->DrawIcon(* Corner2, int(width-32), 0);
int y2 = height - 32;
int x2 = (width-32);
dc->DrawIcon(* Corner3, 0, y2);
dc->DrawIcon(* Corner4, x2, y2);
//#endif
}
}
// Get an index (randomly generated) and load the poem
void MainWindow::GetIndexLoadPoem(void)
{
if (index_ok)
index_ptr = GetIndex();
if (index_ptr > -1)
loaded_ok = LoadPoem(data_filename, -1);
}
// Find the size of the poem and resize the window accordingly
void MainWindow::Resize(void)
{
wxClientDC dc(canvas);
// Get the poem size
ScanBuffer(& dc, FALSE, &poem_width, &poem_height);
int x = poem_width + (2*BORDER_SIZE);
int y = poem_height + (2*BORDER_SIZE);
SetClientSize(x, y);
// In case client size isn't what we set it to...
int xx, yy;
GetClientSize(&xx, &yy);
wxMemoryDC memDC;
if (backingBitmap) delete backingBitmap;
backingBitmap = new wxBitmap(x, yy);
memDC.SelectObject(* backingBitmap);
memDC.Clear();
TheMainWindow->ScanBuffer(&memDC, TRUE, &xx, &yy);
}
// Which is more?
void FindMax(int *max_thing, int thing)
{
if (thing > *max_thing)
*max_thing = thing;
}
// Next page/poem
void MainWindow::NextPage(void)
{
if (paging)
current_page ++;
else
{
current_page = 0;
GetIndexLoadPoem();
}
Resize();
}
// Previous page
void MainWindow::PreviousPage(void)
{
if (current_page > 0)
{
current_page --;
Resize();
}
}
// Search for a string
void MainWindow::Search(bool ask)
{
long position;
if (ask || !search_string)
{
wxString s = wxGetTextFromUser("Enter search string", "Search", (const char*) search_string);
if (s != "")
{
if (search_string) delete[] search_string;
search_string = copystring(s);
search_ok = TRUE;
} else search_ok = FALSE;
}
else
{
same_search = TRUE;
search_ok = TRUE;
}
if (search_string && search_ok)
{
position = DoSearch();
if (position > -1)
{
loaded_ok = LoadPoem(data_filename, position);
Resize();
}
else
{
last_poem_start = 0;
PoetryNotify("Search string not found.");
}
}
}
// Copy a string to the clipboard
#ifdef __WXMSW__
void CopyToClipboard(HWND handle, char *s)
{
int length = strlen(s);
HANDLE hGlobalMemory = GlobalAlloc(GHND, (DWORD) length + 1);
if (hGlobalMemory)
{
#ifdef __WINDOWS_386__
LPSTR lpGlobalMemory = MK_FP32(GlobalLock(hGlobalMemory));
#else
LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory);
#endif
int i, j = 0;
for (i = 0; i < length; i ++)
{
if (s[i] == '@')
{
i++;
switch (s[i])
{
case 'P':
break;
case 'T':
case 'A':
default:
i ++;
break;
}
}
else
{
lpGlobalMemory[j] = s[i];
j ++;
}
}
GlobalUnlock(hGlobalMemory);
OpenClipboard(handle);
EmptyClipboard();
SetClipboardData(CF_TEXT, hGlobalMemory);
CloseClipboard();
}
}
#endif
bool MyApp::OnInit()
{
poem_buffer = new char[buf_size];
GreyPen = new wxPen("LIGHT GREY", THICK_LINE_WIDTH, wxSOLID);
DarkGreyPen = new wxPen("GREY", THICK_LINE_WIDTH, wxSOLID);
WhitePen = new wxPen("WHITE", THICK_LINE_WIDTH, wxSOLID);
#if wxUSE_HELP
HelpController = new wxHelpController();
HelpController->Initialize("wxpoem");
#endif // wxUSE_HELP
CreateFonts();
ReadPreferences();
// Seed the random number generator
time_t current_time;
(void)time(&current_time);
srand((unsigned int)current_time);
// randomize();
pages[0] = 0;
TheMainWindow = new MainWindow(NULL, 500, "wxPoem", wxPoint(XPos, YPos), wxSize(100, 100), wxCAPTION|wxMINIMIZE_BOX|wxSYSTEM_MENU);
#ifdef wx_x
TheMainWindow->SetIcon(Icon("wxpoem"));
#endif
TheMainWindow->canvas = new MyCanvas(TheMainWindow, 501, wxDefaultPosition, wxDefaultSize);
popupMenu = new wxMenu;
popupMenu->Append(POEM_NEXT, "Next poem/page");
popupMenu->Append(POEM_PREVIOUS, "Previous page");
popupMenu->AppendSeparator();
popupMenu->Append(POEM_SEARCH, "Search");
popupMenu->Append(POEM_NEXT_MATCH, "Next match");
popupMenu->Append(POEM_COPY, "Copy to clipboard");
popupMenu->Append(POEM_MINIMIZE, "Minimize");
popupMenu->AppendSeparator();
popupMenu->Append(POEM_BIGGER_TEXT, "Bigger text");
popupMenu->Append(POEM_SMALLER_TEXT, "Smaller text");
popupMenu->AppendSeparator();
popupMenu->Append(POEM_ABOUT, "About wxPoem");
popupMenu->AppendSeparator();
popupMenu->Append(POEM_EXIT, "Exit");
if (argc > 1)
{
index_filename = copystring(argv[1]);
data_filename = copystring(argv[1]);
}
else
{
index_filename = DEFAULT_POETRY_IND;
data_filename = DEFAULT_POETRY_DAT;
}
TryLoadIndex();
#ifdef __WXMSW__
Corner1 = new wxIcon("icon_1");
Corner2 = new wxIcon("icon_2");
Corner3 = new wxIcon("icon_3");
Corner4 = new wxIcon("icon_4");
#endif
#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXX11__)
Corner1 = new wxIcon( corner1_xpm );
Corner2 = new wxIcon( corner2_xpm );
Corner3 = new wxIcon( corner3_xpm );
Corner4 = new wxIcon( corner4_xpm );
#endif
TheMainWindow->GetIndexLoadPoem();
TheMainWindow->Resize();
TheMainWindow->Show(TRUE);
return TRUE;
}
int MyApp::OnExit()
{
if (backingBitmap)
delete backingBitmap;
#if wxUSE_HELP
delete HelpController;
#endif // wxUSE_HELP
delete GreyPen;
delete DarkGreyPen;
delete WhitePen;
delete Corner1;
delete Corner2;
delete Corner3;
delete Corner4;
// Causes crash since they're deleted by the global font list
#if 0
delete NormalFont;
delete BoldFont;
delete ItalicFont;
#endif
delete[] poem_buffer;
if (search_string)
delete[] search_string;
return 0;
}
void MainWindow::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
{
WritePreferences();
this->Destroy();
}
void MainWindow::OnChar(wxKeyEvent& event)
{
canvas->OnChar(event);
}
BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
EVT_CHAR(MyCanvas::OnChar)
EVT_PAINT(MyCanvas::OnPaint)
END_EVENT_TABLE()
// Define a constructor for my canvas
MyCanvas::MyCanvas(wxFrame *frame, wxWindowID id, const wxPoint& pos, const wxSize& size):
wxWindow(frame, id, pos, size)
{
}
// Define the repainting behaviour
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
if (backingBitmap)
{
int xx, yy;
TheMainWindow->GetClientSize(&xx, &yy);
dc.DrawBitmap(* backingBitmap, 0, 0);
#if 0
wxMemoryDC memDC;
memDC.SelectObject(* backingBitmap);
dc.Blit(0, 0, backingBitmap->GetWidth(), backingBitmap->GetHeight(), &memDC, 0, 0);
#endif
}
}
void MyCanvas::OnMouseEvent(wxMouseEvent& event)
{
static int startPosX, startPosY, startFrameX, startFrameY;
long x, y;
event.GetPosition(&x, &y);
if (event.RightDown())
{
// Versions from wxWin 1.67 are probably OK
PopupMenu(popupMenu, (int)x, (int)y );
}
else if (event.LeftDown())
{
this->CaptureMouse();
int x1 = (int)x;
int y1 = (int)y;
ClientToScreen(&x1, &y1);
startPosX = x1;
startPosY = y1;
GetParent()->GetPosition(&startFrameX, &startFrameY);
}
else if (event.LeftUp())
this->ReleaseMouse();
else if (event.Dragging() && event.LeftIsDown())
{
int x1 = (int)x;
int y1 = (int)y;
ClientToScreen(&x1, &y1);
int dX = x1 - startPosX;
int dY = y1 - startPosY;
GetParent()->Move(startFrameX + dX, startFrameY + dY);
}
}
// Process characters
void MyCanvas::OnChar(wxKeyEvent& event)
{
switch (event.KeyCode())
{
case 'n':
case 'N':
// Next match
TheMainWindow->Search(FALSE);
break;
case 's':
case 'S':
// New search
TheMainWindow->Search(TRUE);
break;
case WXK_SPACE:
// Another poem
TheMainWindow->NextPage();
break;
case 27:
TheMainWindow->Close(TRUE);
default:
break;
}
}
// Load index file
int LoadIndex(char *file_name)
{
long data;
FILE *index_file;
int i = 0;
char buf[100];
if (file_name)
sprintf(buf, "%s.idx", file_name);
if (! (file_name && (index_file = fopen(buf, "r"))))
return 0;
else
{
fscanf(index_file, "%ld", &nitems);
for (i = 0; i < nitems; i++)
{
fscanf(index_file, "%ld", &data);
poem_index[i] = data;
}
fclose(index_file);
return 1;
}
}
// Get index
int GetIndex()
{
int indexn = 0;
indexn = (int)(rand() % nitems);
if ((indexn < 0) || (indexn > nitems))
{ PoetryError("No such poem!");
return -1;
}
else
return indexn;
}
// Read preferences
void ReadPreferences()
{
wxGetResource("wxPoem", "FontSize", &pointSize);
wxGetResource("wxPoem", "X", &XPos);
wxGetResource("wxPoem", "Y", &YPos);
}
// Write preferences to disk
void WritePreferences()
{
#ifdef __WXMSW__
TheMainWindow->GetPosition(&XPos, &YPos);
wxWriteResource("wxPoem", "FontSize", pointSize);
wxWriteResource("wxPoem", "X", XPos);
wxWriteResource("wxPoem", "Y", YPos);
#endif
}
// Load a poem from given file, at given point in file.
// If position is > -1, use this for the position in the
// file, otherwise use index[index_ptr] to find the correct position.
bool LoadPoem(char *file_name, long position)
{
int ch = 0;
int i = 0;
// int j = 0;
// int indexn = 0;
char buf[100];
long data;
FILE *data_file;
paging = FALSE;
current_page = 0;
if (file_name)
sprintf(buf, "%s.dat", file_name);
if (! (file_name && (data_file = fopen(buf, "r"))))
{
sprintf(error_buf, "Data file %s not found.", buf);
PoetryError(error_buf);
return FALSE;
}
else
{
if (position > -1)
data = position;
else
data = poem_index[index_ptr];
fseek(data_file, data, SEEK_SET);
ch = 0;
i = 0;
while ((ch != EOF) && (ch != '#'))
{
ch = getc(data_file);
// Add a linefeed so it will copy to the clipboard ok
if (ch == 10)
{
poem_buffer[i] = 13;
i++;
}
poem_buffer[i] = ch;
i ++;
if (i == buf_size)
{
sprintf(error_buf, "%s", "Poetry buffer exceeded.");
PoetryError(error_buf);
return FALSE;
}
}
fclose(data_file);
poem_buffer[i-1] = 0;
return TRUE;
}
}
// Do the search
long MainWindow::DoSearch(void)
{
if (!search_string)
return FALSE;
FILE *file;
long i = 0;
int ch = 0;
char buf[100];
long find_start;
long previous_poem_start;
bool found = FALSE;
int search_length = strlen(search_string);
if (same_search)
{
find_start = last_find + 1;
previous_poem_start = last_poem_start;
}
else
{
find_start = 0;
last_poem_start = 0;
previous_poem_start = -1;
}
if (data_filename)
sprintf(buf, "%s.dat", data_filename);
if (! (data_filename && (file = fopen(buf, "r"))))
{
sprintf(error_buf, "Poetry data file %s not found\n", buf);
PoetryError(error_buf);
return FALSE;
}
fseek(file, find_start, SEEK_SET);
while ((ch != EOF) && !found)
{
ch = getc(file);
ch |= 0x0020; // Make lower case
// Only match if we're looking at a different poem
// (no point in displaying the same poem again)
if ((ch == search_string[i]) && (last_poem_start != previous_poem_start))
{
if (i == 0)
last_find = ftell(file);
if (i == search_length-1)
found = TRUE;
i ++;
}
else
i = 0;
if (ch == '#')
{
ch = getc(file);
last_poem_start = ftell(file);
}
}
fclose(file);
if (ch == EOF)
last_find = -1;
if (found)
{
return last_poem_start;
}
else
return -1;
}
// Set up poetry filenames, preferences, load the index
// Load index (or compile it if none found)
void TryLoadIndex()
{
index_ok = (LoadIndex(index_filename) != 0);
if (!index_ok || (nitems == 0))
{
PoetryError("Index file not found; will compile new one", "wxPoem");
index_ok = Compile();
}
}
// Error message
void PoetryError(char *msg, char *caption)
{
wxMessageBox(msg, caption, wxOK|wxICON_EXCLAMATION);
}
// Notification (change icon to something appropriate!)
void PoetryNotify(char *Msg, char *caption)
{
wxMessageBox(Msg, caption, wxOK | wxICON_INFORMATION);
}
// Build up and save an index into the poetry data file, for
// rapid random access
bool Compile(void)
{
FILE *file;
long i = 0;
int j;
int ch = 0;
char buf[100];
if (data_filename)
sprintf(buf, "%s.dat", data_filename);
if (! (data_filename && (file = fopen(buf, "r"))))
{
sprintf(error_buf, "Poetry data file %s not found\n", buf);
PoetryError(error_buf);
return FALSE;
}
nitems = 0;
// Do first one (?)
poem_index[nitems] = 0;
nitems ++;
// Do rest
while (ch != EOF)
{
ch = getc(file);
i ++;
if (ch == '#')
{
ch = getc(file);
long data;
data = ftell(file);
poem_index[nitems] = data;
nitems ++;
}
}
fclose(file);
if (index_filename)
sprintf(buf, "%s.idx", index_filename);
if (! (data_filename && (file = fopen(buf, "w"))))
{
sprintf(error_buf, "Poetry index file %s cannot be created\n", buf);
PoetryError(error_buf);
return FALSE;
}
fprintf(file, "%ld\n\n", nitems);
for (j = 0; j < nitems; j++)
fprintf(file, "%ld\n", poem_index[j]);
fclose(file);
PoetryNotify("Poetry index compiled.");
return TRUE;
}
void MainWindow::OnPopup(wxCommandEvent& event)
{
switch (event.GetId())
{
case POEM_NEXT:
// Another poem/page
TheMainWindow->NextPage();
break;
case POEM_PREVIOUS:
// Previous page
TheMainWindow->PreviousPage();
break;
case POEM_SEARCH:
// Search - with dialog
TheMainWindow->Search(TRUE);
break;
case POEM_NEXT_MATCH:
// Search - without dialog (next match)
TheMainWindow->Search(FALSE);
break;
case POEM_MINIMIZE:
TheMainWindow->Iconize(TRUE);
break;
#ifdef __WXMSW__
case POEM_COPY:
// Copy current poem to the clipboard
CopyToClipboard((HWND) TheMainWindow->GetHWND(), poem_buffer);
break;
#endif
case POEM_COMPILE:
// Compile index
Compile();
break;
case POEM_BIGGER_TEXT:
{
pointSize ++;
CreateFonts();
TheMainWindow->Resize();
break;
}
case POEM_SMALLER_TEXT:
{
if (pointSize > 2)
{
pointSize --;
CreateFonts();
TheMainWindow->Resize();
}
break;
}
case POEM_HELP_CONTENTS:
{
#if wxUSE_HELP
HelpController->LoadFile("wxpoem");
HelpController->DisplayContents();
#endif // wxUSE_HELP
break;
}
case POEM_ABOUT:
{
(void)wxMessageBox("wxPoem Version 1.1\nJulian Smart (c) 1995",
"About wxPoem", wxOK, TheMainWindow);
break;
}
case POEM_EXIT:
// Exit
TheMainWindow->Close(TRUE);
break;
default:
break;
}
}