685aded8fd
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11142 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1150 lines
28 KiB
C++
1150 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__)
|
|
#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 ++;
|
|
#ifdef __WXMSW__
|
|
// 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(¤t_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__)
|
|
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;
|
|
|
|
delete NormalFont;
|
|
delete BoldFont;
|
|
delete ItalicFont;
|
|
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);
|
|
|
|
wxMemoryDC memDC;
|
|
memDC.SelectObject(* backingBitmap);
|
|
dc.Blit(0, 0, backingBitmap->GetWidth(), backingBitmap->GetHeight(), &memDC, 0, 0);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|