/*
* TVision example: a simple text editor
*
* Written by Sergio Sigala <sergio@sigala.it>
* Modified by Max Okumoto <okumoto@ucsd.edu>
*/
#define Uses_MsgBox
#define Uses_TApplication
#define Uses_TBackground
#define Uses_TButton
#define Uses_TChDirDialog
#define Uses_TCheckBoxes
#define Uses_TDeskTop
#define Uses_TDialog
#define Uses_TEditWindow
#define Uses_TEditor
#define Uses_TFileDialog
#define Uses_THistory
#define Uses_TInputLine
#define Uses_TKeys
#define Uses_TLabel
#define Uses_TMenuBar
#define Uses_TMenuItem
#define Uses_TSItem
#define Uses_TStaticText
#define Uses_TStatusDef
#define Uses_TStatusItem
#define Uses_TStatusLine
#define Uses_TSubMenu
#include <tvision/tv.h>
#include <assert.h>
extern "C" {
#include <signal.h>
}
//new command codes; standard commands are defined in views.h
enum
{
cmAbout = 100,
cmShowClip
};
//main class of our application
class TVDemo: public TApplication
{
private:
TEditWindow *clipWindow;
static TDialog *createFindDialog();
static TDialog *createReplaceDialog();
static ushort doEditorDialog(int dialog, ...);
static ushort doExecute(TDialog *p, void *data);
static ushort doReplacePrompt(TPoint &cursor);
void aboutBox();
void cascade();
void changeDir();
void newFile();
void openFile(char *fileSpec);
void shell();
void showClipboard();
void tile();
public:
TVDemo();
static TMenuBar *initMenuBar(TRect r);
static TStatusLine *initStatusLine(TRect r);
virtual void handleEvent(TEvent& Event);
virtual void idle();
};
//constructor
TVDemo::TVDemo(): TProgInit(&TVDemo::initStatusLine, &TVDemo::initMenuBar,
&TVDemo::initDeskTop)
{
//Variable editorDialog is a function pointer used by TEditor objects to
//display various dialog boxes. The default editorDialog, defEditorDialog
//(implemented in editstat.cc), simply returns cmCancel. The following
//line replaces it with our version.
TEditor::editorDialog = doEditorDialog;
//create a clipboard
clipWindow = new TEditWindow(deskTop->getExtent(), 0, wnNoNumber);
if (clipWindow != 0)
{
//remember who is the clipboard; all editor istances will
//refer to this one when doing clipboard operations
TEditor::clipboard = (TEditor *) clipWindow->editor;
//put the clipboard in the background
clipWindow->hide();
deskTop->insert(clipWindow);
}
}
//shows the about dialog
void TVDemo::aboutBox()
{
TDialog *box = new TDialog(TRect(0, 0, 32, 11), "About");
box->insert(new TStaticText(TRect(1, 2, 1+30, 2+5),
"\003TVEDIT\n"
"\003A simple text editor\n\n"
"\003Ported from Turbo Pascal 6.0 by Sergio Sigala"));
box->insert(new TButton(TRect(11, 8, 11+10, 10), "O~K~", cmOK,
bfDefault));
box->options |= ofCentered;
executeDialog(box);
}
//moves all the windows in a cascade-like fashion
void TVDemo::cascade()
{
deskTop->cascade(deskTop->getExtent());
}
//changes the current working directory
void TVDemo::changeDir()
{
TView *d = validView(new TChDirDialog(0, cmChangeDir));
if (d != 0)
{
deskTop->execView(d);
destroy(d);
}
}
//creates a find dialog and then returns his address
TDialog *TVDemo::createFindDialog()
{
TInputLine *p;
TDialog *d = new TDialog(TRect(0, 0, 38, 12), "Find");
if (!d) return 0;
d->options |= ofCentered;
d->insert(p = new TInputLine(TRect(3, 3, 32, 4), 80));
d->insert(new TLabel(TRect(2, 2, 15, 3), "~T~ext to find", p));
d->insert(new THistory(TRect(32, 3, 35, 4), p, 10));
d->insert(new TCheckBoxes(TRect(3, 5, 35, 7),
new TSItem("~C~ase sensitive",
new TSItem("~W~hole words only", 0))));
d->insert(new TButton(TRect(14, 9, 24, 11), "O~K~", cmOK, bfDefault));
d->insert(new TButton(TRect(14+12, 9, 24+12, 11), "Cancel", cmCancel,
bfNormal));
d->selectNext(False);
return d;
}
//creates a replace dialog and then returns his address
TDialog *TVDemo::createReplaceDialog()
{
TInputLine *p;
TDialog *d = new TDialog(TRect(0, 0, 40, 16), "Replace");
if (!d) return 0;
d->options |= ofCentered;
d->insert(p = new TInputLine(TRect(3, 3, 34, 4), 80));
d->insert(new TLabel(TRect(2, 2, 15, 3), "~T~ext to find", p));
d->insert(new THistory(TRect(34, 3, 37, 4), p, 10));
d->insert(p = new TInputLine(TRect(3, 6, 34, 7), 80));
d->insert(new TLabel(TRect(2, 5, 12, 6), "~N~ew text", p));
d->insert(new THistory(TRect(34, 6, 37, 7), p, 11));
d->insert(new TCheckBoxes(TRect(3, 8, 37, 12),
new TSItem("~C~ase sensitive",
new TSItem("~W~hole words only",
new TSItem("~P~rompt on replace",
new TSItem("~R~eplace all", 0))))));
d->insert(new TButton(TRect(17, 13, 27, 15), "O~K~", cmOK, bfDefault));
d->insert(new TButton(TRect(28, 13, 38, 15), "Cancel", cmCancel,
bfNormal));
d->selectNext(False);
return d;
}
//This is a function used by TEditor objects to display various dialog boxes.
//Since dialog boxes are very application-dependent, a TEditor object does not
//display its own dialog boxes directly. Instead it controls them through this
//function.
ushort TVDemo::doEditorDialog(int dialog, ...)
{
va_list ap;
void *info = 0;
va_start(ap, dialog); //initializes the variable argument list
info = va_arg(ap, void *); //get first parameter (if any)
va_end(ap);
switch (dialog)
{
case edOutOfMemory:
return messageBox("Not enough memory for this operation",
mfError + mfOKButton);
case edReadError:
return messageBox(mfError + mfOKButton, "Error reading file %s", info);
case edWriteError:
return messageBox(mfError + mfOKButton, "Error writing file %s", info);
case edCreateError:
return messageBox(mfError + mfOKButton, "Error creating file %s",
info);
case edSaveModify:
return messageBox(mfInformation + mfYesNoCancel,
"%s has been modified. Save?", info);
case edSaveUntitled:
return messageBox("Save untitled file?",
mfInformation + mfYesNoCancel);
case edSaveAs:
return doExecute(new TFileDialog("*.*", "Save file as", "~N~ame",
fdOKButton, 101), info);
case edFind:
return doExecute(createFindDialog(), info);
case edSearchFailed:
return messageBox("Search string not found", mfError + mfOKButton);
case edReplace:
return doExecute(createReplaceDialog(), info);
case edReplacePrompt:
va_start(ap, dialog);
TPoint *cursor = va_arg(ap, TPoint *);
va_end(ap);
return doReplacePrompt(*cursor);
}
assert(0); /* what should the return value be if we fall through? */
return 0;
}
//executes a dialog in modal state; similar to TProgram::execute(), but this
//version is fully static
ushort TVDemo::doExecute(TDialog *p, void *data)
{
ushort result = cmCancel;
if (1) //validView(p))
{
if (data) p->setData(data);
result = deskTop->execView(p);
if (result != cmCancel && data) p->getData(data);
destroy(p);
}
return result;
}
ushort TVDemo::doReplacePrompt(TPoint &cursor)
{
TRect r(0, 2, 40, 9);
r.move((deskTop->size.x - r.b.x) / 2, 0);
TPoint lower = deskTop->makeGlobal(r.b);
if (cursor.y <= lower.y) r.move(0, (deskTop->size.y - r.b.y - 2));
return messageBoxRect(r, "Replace this occurence?",
mfYesNoCancel + mfInformation);
}
//handles application's events
void TVDemo::handleEvent(TEvent &event)
{
TApplication::handleEvent(event);
if (event.what == evCommand) switch (event.message.command)
{
case cmAbout:
aboutBox();
break;
case cmCascade:
cascade();
break;
case cmChDir:
changeDir();
break;
case cmDosShell:
shell();
break;
case cmNew:
newFile();
break;
case cmOpen:
openFile("*");
break;
case cmShowClip:
showClipboard();
break;
case cmTile:
tile();
break;
default:
return;
}
clearEvent(event);
}
//returns true if and only if the view at address `p' is tileable and visible
static Boolean isTileable(TView *p, void *)
{
if ((p->options & ofTileable) != 0 &&
(p->state & sfVisible) != 0) return True;
else return False;
}
//called when in idle state
void TVDemo::idle()
{
TApplication::idle();
if (deskTop->firstThat(isTileable, 0) != 0)
{
enableCommand(cmTile);
enableCommand(cmCascade);
}
else
{
disableCommand(cmSave);
disableCommand(cmSaveAs);
disableCommand(cmUndo);
disableCommand(cmCut);
disableCommand(cmCopy);
disableCommand(cmPaste);
disableCommand(cmClear);
disableCommand(cmFind);
disableCommand(cmReplace);
disableCommand(cmSearchAgain);
disableCommand(cmTile);
disableCommand(cmCascade);
}
}
//creates a new menu bar
TMenuBar *TVDemo::initMenuBar(TRect r)
{
TSubMenu& sub1 = *new TSubMenu("~\360~", 0, hcNoContext) +
*new TMenuItem("~A~bout...", cmAbout, kbNoKey, hcNoContext);
TSubMenu& sub2 = *new TSubMenu("~F~ile", 0, hcNoContext) +
*new TMenuItem("~O~pen...", cmOpen, kbF3, hcNoContext, "F3") +
*new TMenuItem("~N~ew", cmNew, kbNoKey, hcNoContext, "") +
*new TMenuItem("~S~ave", cmSave, kbF2, hcNoContext, "F2") +
*new TMenuItem("S~a~ve as...", cmSaveAs, kbNoKey, hcNoContext, "") +
newLine() +
*new TMenuItem("~C~hange dir...", cmChDir, kbNoKey, hcNoContext, "") +
*new TMenuItem("~D~OS shell", cmDosShell, kbNoKey, hcNoContext, "") +
*new TMenuItem("E~x~it", cmQuit, kbAltX, hcNoContext, "Alt-X");
TSubMenu& sub3 = *new TSubMenu("~E~dit", 0, hcNoContext) +
*new TMenuItem("~U~ndo", cmUndo, kbNoKey, hcNoContext, "") +
newLine() +
*new TMenuItem("Cu~t~", cmCut, kbShiftDel, hcNoContext, "Shift-Del") +
*new TMenuItem("~C~opy", cmCopy, kbCtrlIns, hcNoContext, "Ctrl-Ins") +
*new TMenuItem("~P~aste", cmPaste, kbShiftIns, hcNoContext, "Shift-Ins") +
*new TMenuItem("~S~how clipboard", cmShowClip, kbNoKey, hcNoContext, "") +
newLine() +
*new TMenuItem("~C~lear", cmClear, kbCtrlDel, hcNoContext, "Ctrl-Del");
TSubMenu& sub4 = *new TSubMenu("~S~earch", 0, hcNoContext) +
*new TMenuItem("~F~ind...", cmFind, kbNoKey, hcNoContext) +
*new TMenuItem("~R~eplace...", cmReplace, kbNoKey, hcNoContext) +
*new TMenuItem("~S~earch again", cmSearchAgain, kbNoKey, hcNoContext);
TSubMenu& sub5 = *new TSubMenu("~W~indows", 0, hcNoContext) +
*new TMenuItem("~S~ize/move", cmResize, kbCtrlF5, hcNoContext, "Ctrl-F5") +
*new TMenuItem("~Z~oom", cmZoom, kbF5, hcNoContext, "F5") +
*new TMenuItem("~N~ext", cmNext, kbF6, hcNoContext, "F6") +
*new TMenuItem("~P~revious", cmPrev, kbShiftF6, hcNoContext, "Shift-F6") +
*new TMenuItem("~C~lose", cmClose, kbAltF3, hcNoContext, "Alt-F3") +
*new TMenuItem("~T~ile", cmTile, kbNoKey, hcNoContext) +
*new TMenuItem("C~a~scade", cmCascade, kbNoKey, hcNoContext);
r.b.y = r.a.y + 1;
return new TMenuBar(r, sub1 + sub2 + sub3 + sub4 + sub5);
}
//creates a new status line
TStatusLine *TVDemo::initStatusLine(TRect r)
{
r.a.y = r.b.y - 1;
return new TStatusLine(r,
*new TStatusDef(0, 50) +
*new TStatusItem("~Alt-X~ Exit", kbAltX, cmQuit) +
*new TStatusItem("~F2~ Save", kbF2, cmSave) +
*new TStatusItem("~F3~ Open", kbF3, cmOpen) +
*new TStatusItem("~Alt-F3~ Close", kbAltF3, cmClose) +
*new TStatusItem("~F5~ Zoom", kbF5, cmZoom) +
*new TStatusItem("~F6~ Next", kbF6, cmNext) +
*new TStatusItem("~F10~ Menu", kbF10, cmMenu) +
*new TStatusItem("", kbCtrlF5, cmResize));
}
//Creates a new edit window, with no assigned file name.
//The window title will be `Untitled'.
void TVDemo::newFile()
{
TView *w = validView(new TEditWindow(deskTop->getExtent(), 0,
wnNoNumber));
if (w != 0) deskTop->insert(w);
}
//opens an existing file, whose file name is passed as a parameter
//in `fileSpec'
void TVDemo::openFile(char *fileSpec)
{
TFileDialog *d = (TFileDialog *) validView(new TFileDialog(fileSpec,
"Open a File", "~N~ame", fdOpenButton, 100));
if (d != 0 && deskTop->execView(d) != cmCancel)
{
char fileName[PATH_MAX];
d->getFileName(fileName);
TView *w = validView(new TEditWindow(deskTop->getExtent(),
fileName, wnNoNumber));
if (w != 0) deskTop->insert(w);
}
destroy(d);
}
void TVDemo::shell()
{
raise(SIGTSTP); //this line simulates a Ctrl-Z
}
//Shows the clipboard. The user can't really destroy the clipboard: every
//cmClose command will simply move the clipboard window in the background,
//by hiding it.
void TVDemo::showClipboard()
{
if (clipWindow != 0)
{
clipWindow->select();
clipWindow->show();
}
}
//moves all the windows in a tile-like fashion
void TVDemo::tile()
{
deskTop->tile(deskTop->getExtent());
}
int main()
{
TVDemo d;
d.run();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1