home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d8xx
/
d832
/
term.lha
/
Term
/
term-3.1-Source.lha
/
termTextBuffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-19
|
43KB
|
1,821 lines
/*
** termTextBuffer.c
**
** Support routines for the text buffer.
**
** Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
** All Rights Reserved
*/
#include "termGlobal.h"
/* Gadget ID codes. */
enum { GAD_SCROLLER,GAD_UP,GAD_DOWN };
/* Menu ID codes. */
enum { MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_CLOSEBUF,MEN_QUITBUF };
/* Gadget ID codes. */
enum { GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };
/* A handy macro to determine the length of a string. */
#define LINE_WIDTH(s) (s)[-1]
/* The dimensions of the scroller images. */
#define ARROW_WIDTH 18
#define ARROW_HEIGHT 11
STATIC struct NewMenu BufferMenu[] =
{
{ NM_TITLE, NULL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_SEARCH},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_REPEAT},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_GOTO},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_CLOSEBUF},
{ NM_ITEM, NM_BARLABEL, 0 , 0, 0, (APTR)0},
{ NM_ITEM, NULL, 0 , 0, 0, (APTR)MEN_QUITBUF},
{ NM_END, 0, 0 , 0, 0, (APTR)0}
};
/* Some private data (render info & window). */
STATIC struct Window *BufferWindow;
STATIC struct Screen *BufferScreen;
STATIC struct RastPort *BPort;
STATIC APTR BufferVisualInfo;
STATIC LONG NumBufferLines,
NumBufferColumns,
LastTopLine;
STATIC BYTE BufferTerminated;
STATIC WORD LocalTextFontWidth,
LocalTextFontHeight,
LocalTextFontBase;
STATIC struct TextAttr LocalTextFont;
STATIC UBYTE LocalTextFontName[MAX_FILENAME_LENGTH];
STATIC struct TextAttr LocalUserFont;
STATIC UBYTE LocalUserFontName[MAX_FILENAME_LENGTH];
STATIC LONG CurrentLine,
DisplayedLines;
STATIC struct SearchInfo *BufferSearchInfo;
STATIC struct Gadget *Scroller,
*UpArrow,
*DownArrow;
STATIC struct Image *UpImage,
*DownImage;
STATIC UWORD *BufferLineWidths,
*BufferLineOffsets,
*BufferColumnOffsets;
/* DeleteScroller(VOID):
*
* Delete scroller and arrow objects.
*/
STATIC VOID
DeleteScroller(VOID)
{
if(Scroller)
{
DisposeObject(Scroller);
Scroller = NULL;
}
if(UpArrow)
{
DisposeObject(UpArrow);
UpArrow = NULL;
}
if(DownArrow)
{
DisposeObject(DownArrow);
DownArrow = NULL;
}
if(UpImage)
{
DisposeObject(UpImage);
UpImage = NULL;
}
if(DownImage)
{
DisposeObject(DownImage);
DownImage = NULL;
}
}
/* CreateScroller(LONG Height):
*
* Create scroller and arrow objects.
*/
STATIC BYTE __regargs
CreateScroller(LONG Height)
{
struct DrawInfo *DrawInfo;
BYTE Result = FALSE;
if(DrawInfo = GetScreenDrawInfo(BufferScreen))
{
if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
SYSIA_Size, SYSISIZE_MEDRES,
SYSIA_Which, UPIMAGE,
SYSIA_DrawInfo, DrawInfo,
TAG_DONE))
{
if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
SYSIA_Size, SYSISIZE_MEDRES,
SYSIA_Which, DOWNIMAGE,
SYSIA_DrawInfo, DrawInfo,
TAG_DONE))
{
LONG ScrollerHeight,LeftEdge;
ScrollerHeight = Height - 2 * ARROW_HEIGHT;
LeftEdge = BufferScreen -> Width - ARROW_WIDTH;
if(Scroller = NewObject(NULL,"propgclass",
GA_ID, GAD_SCROLLER,
GA_Top, 0,
GA_Left, LeftEdge,
GA_Width, ARROW_WIDTH,
GA_Height, ScrollerHeight,
GA_Immediate, TRUE,
GA_FollowMouse, TRUE,
GA_RelVerify, TRUE,
PGA_Freedom, FREEVERT,
PGA_NewLook, TRUE,
PGA_Visible, 1,
PGA_Total, 1,
TAG_DONE))
{
STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };
if(UpArrow = NewObject(NULL,"buttongclass",
GA_ID, GAD_UP,
GA_Image, UpImage,
GA_Left, LeftEdge,
GA_Top, ScrollerHeight,
GA_Height, ARROW_HEIGHT,
GA_Width, ARROW_WIDTH,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
GA_Previous, Scroller,
ICA_TARGET, ICTARGET_IDCMP,
ICA_MAP, ArrowMappings,
TAG_DONE))
{
if(DownArrow = NewObject(NULL,"buttongclass",
GA_ID, GAD_DOWN,
GA_Image, DownImage,
GA_Left, LeftEdge,
GA_Top, ScrollerHeight + ARROW_HEIGHT,
GA_Height, ARROW_HEIGHT,
GA_Width, ARROW_WIDTH,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
GA_Previous, UpArrow,
ICA_TARGET, ICTARGET_IDCMP,
ICA_MAP, ArrowMappings,
TAG_DONE))
Result = TRUE;
}
}
}
}
FreeScreenDrawInfo(BufferScreen,DrawInfo);
}
if(!Result)
DeleteScroller();
return(Result);
}
/* GetSearchString(STRPTR Buffer):
*
* Prompt user for a string to search the buffer for.
*/
STATIC BYTE
GetSearchString(STRPTR Buffer)
{
struct Gadget *GadgetList = NULL;
struct Gadget *GadgetArray[GAD_CANCEL + 1];
struct Window *PanelWindow;
UBYTE OtherBuffer[256];
BYTE Success = FALSE;
strcpy(OtherBuffer,Buffer);
if(CreateAllGetsGadgets(FALSE,FALSE,0,OtherBuffer,LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),GadgetArray,&GadgetList,BufferVisualInfo,BufferScreen))
{
if(PanelWindow = OpenWindowTags(NULL,
WA_Left, (BufferScreen -> Width - SZ_GetWindowWidth()) / 2,
WA_Top, (BufferScreen -> Height - SZ_GetWindowHeight()) / 2,
WA_Width, SZ_GetWindowWidth(),
WA_Height, SZ_GetWindowHeight(),
WA_Activate, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_RMBTrap, TRUE,
WA_CustomScreen, BufferScreen,
WA_IDCMP, IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_GADGETDOWN | BUTTONIDCMP | STRINGIDCMP,
WA_Title, LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),
TAG_DONE))
{
struct IntuiMessage *Massage;
ULONG IClass,Code;
struct Gadget *Gadget;
BYTE Terminated = FALSE;
ULONG SignalSet;
STRPTR String;
AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
GT_RefreshWindow(PanelWindow,NULL);
ActiveGadget = NULL;
String = SZ_GetString(GadgetArray[GAD_STRING]);
while(!Terminated)
{
SignalSet = Wait(PORTMASK(PanelWindow -> UserPort) | SIG_TOFRONT | SIG_KILL);
if(SignalSet & SIG_TOFRONT);
BumpWindow(PanelWindow);
if(SignalSet & SIG_KILL)
{
BufferTerminated = TRUE;
Terminated = TRUE;
}
if(SignalSet & PORTMASK(PanelWindow -> UserPort))
{
while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
{
IClass = Massage -> Class;
Code = Massage -> Code;
Gadget = (struct Gadget *)Massage -> IAddress;
GT_ReplyIMsg(Massage);
if(IClass == IDCMP_VANILLAKEY)
KeySelect(GadgetArray,GAD_CANCEL,Code,PanelWindow,&Gadget,&IClass,&Code);
if(IClass == IDCMP_RAWKEY && Code == HELP_CODE)
DisplayBeep(PanelWindow -> WScreen);
if(IClass == IDCMP_GADGETDOWN)
{
if((Gadget -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
ActiveGadget = Gadget;
}
if(IClass == IDCMP_ACTIVEWINDOW && ActiveGadget)
ActivateGadget(ActiveGadget,PanelWindow,NULL);
if(IClass == IDCMP_CLOSEWINDOW)
Terminated = TRUE;
if(IClass == IDCMP_GADGETUP)
{
switch(Gadget -> GadgetID)
{
case GAD_OK:
case GAD_STRING:
if(String[0])
{
strcpy(Buffer,String);
Success = TRUE;
}
case GAD_CANCEL:
Terminated = TRUE;
break;
}
}
}
}
}
RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
CloseWindow(PanelWindow);
}
}
FreeGadgets(GadgetList);
return(Success);
}
/* PrintLine(STRPTR Buffer,LONG LineNumber):
*
* Print a line at a given line number in the displayed area.
*/
STATIC VOID
PrintLine(STRPTR Buffer,LONG LineNumber)
{
WORD Length = Buffer[-1];
/* Print the text. */
if(Length)
{
Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);
if(Length > NumBufferColumns)
Text(BPort,Buffer,NumBufferColumns);
else
Text(BPort,Buffer,Length);
}
/* The line doesn't exactly fill the displayed line,
* so erase the remaining columns.
*/
if(Length < BufferLineWidths[LineNumber])
ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[NumBufferColumns - Length],LocalTextFontHeight,0x00);
BufferLineWidths[LineNumber] = Length;
}
/* RedrawScreen(LONG FirstLine):
*
* Redraw the contents of the entire screen and return the
* number of lines actually drawn.
*/
STATIC LONG
RedrawScreen(LONG FirstLine)
{
LONG i,Last,Line = 0,Result;
ObtainSemaphore(BufferSemaphore);
/* Determine last line to display. */
if((Last = FirstLine + NumBufferLines) >= Lines)
Last = Lines;
Result = Last - FirstLine;
if(LastTopLine != -1)
{
LONG Delta = FirstLine - LastTopLine;
if(ABS(Delta) < NumBufferLines)
{
/* No change? */
if(!Delta)
{
ReleaseSemaphore(BufferSemaphore);
return(Result);
}
else
{
LastTopLine = FirstLine;
/* Scrolled up? */
if(Delta < 0)
{
for(i = NumBufferLines - 1 ; i > -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],0xC0);
Last = FirstLine - Delta;
}
else
{
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
/* Scrolled down. */
ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],0xC0);
FirstLine += NumBufferLines - Delta;
Line = NumBufferLines - Delta;
}
}
}
else
LastTopLine = FirstLine;
}
else
LastTopLine = FirstLine;
if(BufferLines)
{
for(i = FirstLine ; i < Last ; i++)
PrintLine(BufferLines[i],Line++);
}
ReleaseSemaphore(BufferSemaphore);
/* We didn't fill the whole screen, so clear the rest. */
if(Result < NumBufferLines)
{
WORD i;
for(i = Result ; i < NumBufferLines ; i++)
BufferLineWidths[i] = 0;
ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[Line],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Line],0x00);
}
return(Result);
}
/* MarkArea(LONG Column,LONG Line,LONG Length):
*
* Mark an area in the term Buffer window.
*/
STATIC VOID
MarkArea(LONG Column,LONG Line,LONG Length)
{
STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;
if(OldColumn != -1)
ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,0x50);
if(Column != -1)
{
if(OldColumn != Column || OldLine != Line || OldLength != Length)
ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,0x50);
}
OldColumn = Column;
OldLine = Line;
OldLength = Length;
}
/* BufferClipPage(struct BlockMarker *Marker):
*
* Send the marked area to the clipboard.
*/
STATIC VOID __inline
BufferClipPage(struct BlockMarker *Marker)
{
if(BufferLines)
{
struct IFFHandle *Handle;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
{
InitIFFasClip(Handle);
if(!OpenIFF(Handle,IFFF_WRITE))
{
if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
{
if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
{
LONG Lines = Marker -> LastLine - Marker -> FirstLine - 1,
i;
if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);
WriteChunkBytes(Handle,"\n",1);
if(Lines > 0)
{
for(i = 0 ; i < Lines ; i++)
{
if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));
WriteChunkBytes(Handle,"\n",1);
}
}
if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
else
WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);
WriteChunkBytes(Handle,"\n",1);
PopChunk(Handle);
}
PopChunk(Handle);
}
CloseIFF(Handle);
}
CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
}
FreeIFF(Handle);
}
}
}
/* BufferClip(VOID):
*
* Start buffer marking process.
*/
STATIC VOID
BufferClip(VOID)
{
struct BlockMarker *Marker;
LONG FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
FirstY = BufferWindow -> MouseY / LocalTextFontHeight;
if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,CurrentLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
{
struct IntuiMessage *Massage;
ULONG Code,IClass;
BYTE Done = FALSE,Aborted = FALSE;
LONG PlusX = LocalTextFontWidth - 1,
MouseX,MouseY,
Delta = 0;
ReportMouse(TRUE,BufferWindow);
while(!Done)
{
WaitPort(BufferWindow -> UserPort);
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
{
IClass = Massage -> Class;
Code = Massage -> Code;
MouseX = Massage -> MouseX;
MouseY = Massage -> MouseY;
ReplyMsg(Massage);
if(IClass == IDCMP_INACTIVEWINDOW)
{
Done = Aborted = TRUE;
break;
}
if(IClass == IDCMP_INTUITICKS && Delta != 0)
{
if(BufferLines)
{
if((Delta > 0 && CurrentLine + NumBufferLines < Lines) || (Delta < 0 && CurrentLine > 0))
{
if(Delta < 0)
{
WORD i;
for(i = NumBufferLines - 1 ; i > -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
if(DisplayedLines)
ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],0xC0);
BufferLineWidths[0] = NumBufferColumns;
PrintLine(BufferLines[--CurrentLine],0);
}
else
{
WORD i;
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
if(DisplayedLines)
ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],0xC0);
BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
PrintLine(BufferLines[CurrentLine + NumBufferLines],NumBufferLines - 1);
CurrentLine++;
}
Marker -> Top += Delta;
Marker -> LastY -= Delta;
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
}
else
Delta = 0;
}
}
if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
{
BM_Draw(Marker,Marker -> Unselect);
Done = TRUE;
break;
}
if(IClass == IDCMP_MOUSEMOVE)
{
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);
if(MouseY < 1)
{
if(CurrentLine > 0)
Delta = -1;
}
else
{
if(MouseY >= BufferWindow -> Height - 1 && CurrentLine + NumBufferLines < Lines)
Delta = 1;
}
while(Delta)
{
MouseX = Window -> MouseX;
MouseY = Window -> MouseY;
if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
break;
else
{
if(BufferLines)
{
if((Delta > 0 && CurrentLine + NumBufferLines < Lines) || (Delta < 0 && CurrentLine > 0))
{
if(Delta < 0)
{
WORD i;
for(i = NumBufferLines - 1 ; i > -Delta ; i--)
BufferLineWidths[i] = BufferLineWidths[i + Delta];
if(DisplayedLines)
ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],0xC0);
BufferLineWidths[0] = NumBufferColumns;
PrintLine(BufferLines[--CurrentLine],0);
}
else
{
WORD i;
for(i = Delta ; i < NumBufferLines ; i++)
BufferLineWidths[i - Delta] = BufferLineWidths[i];
if(DisplayedLines)
ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],0xC0);
BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
PrintLine(BufferLines[CurrentLine + NumBufferLines],NumBufferLines - 1);
CurrentLine++;
}
Marker -> Top += Delta;
Marker -> LastY -= Delta;
BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
else
break;
}
else
break;
}
}
Delta = 0;
}
}
}
ReportMouse(FALSE,BufferWindow);
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
ReplyMsg(Massage);
if(!Aborted)
{
if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
{
SetWait(BufferWindow);
if(Marker -> FirstColumn == Marker -> Width)
{
Marker -> FirstLine++;
Marker -> FirstColumn = 0;
}
if(Marker -> LastColumn == 0)
{
Marker -> LastLine--;
Marker -> LastColumn = Marker -> Width;
}
if(Marker -> FirstLine <= Marker -> LastLine)
{
if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
{
if(BufferLines)
{
if(Marker -> FirstLine == Marker -> LastLine)
SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
else
BufferClipPage(Marker);
}
}
}
ClrWait(BufferWindow);
}
}
FreeVec(Marker);
}
}
/* StartBufferSearch(BYTE NewSearchString):
*
* Search the buffer for a string.
*/
STATIC VOID
StartBufferSearch(BYTE NewSearchString)
{
STATIC UBYTE SearchBuffer[256];
BYTE StartSearch = TRUE;
BlockWindow(BufferWindow);
if(NewSearchString || !SearchBuffer[0])
{
if(GetSearchString(SearchBuffer))
{
if(SearchBuffer[0])
{
if(BufferSearchInfo)
DeleteSearchInfo(BufferSearchInfo);
BufferSearchInfo = CreateSearchInfo(SearchBuffer);
}
else
StartSearch = FALSE;
}
else
StartSearch = FALSE;
}
else
{
if(!BufferSearchInfo)
BufferSearchInfo = CreateSearchInfo(SearchBuffer);
}
if(StartSearch && BufferSearchInfo)
{
if(Lines)
{
LONG LineNumber;
ObtainSemaphore(BufferSemaphore);
LineNumber = SearchTextBuffer(BufferSearchInfo);
ReleaseSemaphore(BufferSemaphore);
if(LineNumber == -1)
{
BlockWindows();
MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);
ReleaseWindows();
FlushMsg(BufferWindow);
BufferSearchInfo -> FoundY = -1;
MarkArea(-1,-1,-1);
}
else
{
if(LineNumber < CurrentLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(CurrentLine = LineNumber);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
else
{
if(LineNumber > CurrentLine + DisplayedLines - 1)
{
MarkArea(-1,-1,-1);
if(LineNumber >= Lines - NumBufferLines)
{
LONG NewCurrentLine;
if((NewCurrentLine = Lines - NumBufferLines) < 0)
NewCurrentLine = 0;
if(CurrentLine != NewCurrentLine)
DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
}
else
DisplayedLines = RedrawScreen(CurrentLine = LineNumber);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
}
MarkArea(BufferSearchInfo -> FoundX,LineNumber - CurrentLine,BufferSearchInfo -> PatternWidth);
}
}
else
MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
}
ReleaseWindow(BufferWindow);
}
/* LaunchBuffer():
*
* Launch the buffer process.
*/
BYTE
LaunchBuffer()
{
/* Is the buffer process already running? */
if(BufferProcess)
{
/* Tell it to bring its screen to the front. */
Signal(BufferProcess,SIG_TOFRONT);
/* Return success. */
return(TRUE);
}
else
{
struct MsgPort *ReplyPort;
BYTE Result = FALSE;
/* Create reply port. */
if(ReplyPort = CreateMsgPort())
{
struct Message *Message;
/* Create startup message. */
if(Message = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
{
Message -> mn_ReplyPort = ReplyPort;
Message -> mn_Length = sizeof(struct Message);
/* Launc the buffer process. */
if(BufferProcess = (struct Process *)CreateNewProcTags(
NP_Entry, BufferServer,
NP_Name, "term buffer process",
NP_Priority, 0,
NP_StackSize, 8192,
NP_WindowPtr, -1,
TAG_END))
{
/* Send the startup message. */
PutMsg(&BufferProcess -> pr_MsgPort,Message);
/* Wait for reply. */
WaitPort(ReplyPort);
/* Pick up the reply. */
GetMsg(ReplyPort);
/* Is the process still running? */
if(BufferProcess)
Result = TRUE;
}
/* Free the startup message. */
FreeVec(Message);
}
/* Delete the reply port. */
DeleteMsgPort(ReplyPort);
}
/* Return the result. */
return(Result);
}
}
/* TerminateBuffer():
*
* Terminate the buffer process.
*/
VOID
TerminateBuffer()
{
if(BufferProcess)
{
Forbid();
Signal(BufferProcess,SIG_KILL);
SetSignal(0,SIG_HANDSHAKE);
Wait(SIG_HANDSHAKE);
Permit();
}
LastTopLine = -1;
}
/* BufferServer():
*
* Asynchronous task to display the data stored in the
* scrollback display buffer.
*/
VOID __saveds
BufferServer()
{
struct ColorSpec ColorSpec[3];
ULONG SignalSet;
struct IntuiMessage *Massage;
ULONG IClass,Code,Qualifier,LastQualifier = NULL;
UBYTE Char,LastChar = 0;
LONG MouseX,MouseY,LastWidth = 0;
UBYTE PercentBuffer[80];
struct Menu *BufferMenuStrip;
LONG Width;
ULONG DisplayMode;
struct Rectangle DisplayClip;
struct DimensionInfo DimensionInfo;
UWORD SomeColour,CharCount,Height;
struct TextFont *LocalFont;
struct Message *StartupMessage;
struct MsgPort *StartupPort = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
struct TagItem *TagList;
/* Wait for startup message. */
WaitPort(StartupPort);
StartupMessage = GetMsg(StartupPort);
/* Reset top line index. */
LastTopLine = -1;
/* Clone the global font data. */
LocalTextFontWidth = TextFontWidth;
LocalTextFontHeight = TextFontHeight;
LocalTextFontBase = TextFontBase;
memcpy(&LocalTextFont,&TextAttr,sizeof(struct TextAttr));
LocalTextFont . ta_Name = LocalTextFontName;
strcpy(LocalTextFontName,TextAttr . ta_Name);
memcpy(&LocalUserFont,&UserFont,sizeof(struct TextAttr));
LocalUserFont . ta_Name = LocalUserFontName;
strcpy(LocalUserFontName,UserFont . ta_Name);
/* Up and running... */
BufferTerminated = FALSE;
/* Set up the startup colours for our buffer screen. */
ColorSpec[0] . ColorIndex = 0;
ColorSpec[0] . Red = (Config -> ScreenConfig -> Colours[0] >> 8) & 0xF;
ColorSpec[0] . Green = (Config -> ScreenConfig -> Colours[0] >> 4) & 0xF;
ColorSpec[0] . Blue = (Config -> ScreenConfig -> Colours[0] ) & 0xF;
switch(Config -> ScreenConfig -> ColourMode)
{
case COLOUR_EIGHT:
SomeColour = Config -> ScreenConfig -> Colours[7];
break;
case COLOUR_SIXTEEN:
SomeColour = Config -> ScreenConfig -> Colours[15];
break;
case COLOUR_AMIGA:
case COLOUR_MONO:
SomeColour = Config -> ScreenConfig -> Colours[1];
break;
}
ColorSpec[1] . ColorIndex = 1;
ColorSpec[1] . Red = (SomeColour >> 8) & 0xF;
ColorSpec[1] . Green = (SomeColour >> 4) & 0xF;
ColorSpec[1] . Blue = (SomeColour ) & 0xF;
ColorSpec[2] . ColorIndex = -1;
/* We'll use a fixed screen width, only the
* height is adapted from the main screen.
*/
DisplayMode = Config -> ScreenConfig -> DisplayMode;
if(Screen)
{
Width = Screen -> Width - (ARROW_WIDTH + 1);
if((CharCount = Width / LocalTextFontWidth) > BUFFER_LINE_WIDTH)
CharCount = BUFFER_LINE_WIDTH;
}
else
CharCount = BUFFER_LINE_WIDTH;
Width = CharCount * LocalTextFontWidth + ARROW_WIDTH + 1;
/* Get the mode dimension info. */
if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
{
/* Is the screen width smaller than the
* minimum screen mode width?
*/
if(Width < DimensionInfo . MinRasterWidth)
{
/* Use default modes. */
if((DisplayMode & LACE) || ((DisplayMode & MONITOR_ID_MASK) == A2024_MONITOR_ID))
DisplayMode = HIRESLACE_KEY;
else
DisplayMode = HIRES_KEY;
}
}
if(LocalFont = OpenFont(&LocalTextFont))
{
/* Inquire the text overscan dimensions. */
if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
{
/* Centre the buffer screen. */
if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
{
LONG Differ = ((DisplayClip . MaxX - DisplayClip . MinX + 1) - (Width)) / 2;
DisplayClip . MinX += Differ;
DisplayClip . MaxX -= Differ;
}
/* Open a single bitplane clone of the main screen. */
if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
SA_Title, LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
SA_Depth, 1,
SA_DClip, &DisplayClip,
SA_DisplayID, DisplayMode,
SA_Font, &LocalUserFont,
SA_Behind, TRUE,
SA_AutoScroll, TRUE,
SA_Colors, ColorSpec,
TAG_END))
{
if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
{
LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);
if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
{
if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
GTMN_TextAttr, &LocalUserFont,
GTMN_NewLookMenus, TRUE,
TAG_DONE))
{
WORD TitleOffset,Len;
Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;
Len = strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT));
TitleOffset = TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),Len) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4;
/* Open a cute window on our buffer screen. */
if(BufferWindow = OpenWindowTags(NULL,
WA_Top, BufferScreen -> BarHeight + 2,
WA_Left, 0,
WA_Width, BufferScreen -> Width,
WA_Height, Height * LocalTextFontHeight,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_SmartRefresh,FALSE,
WA_CustomScreen,BufferScreen,
WA_RMBTrap, TRUE,
WA_NewLookMenus,TRUE,
WA_RptQueue, 1,
WA_IDCMP, IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE,
TAG_DONE))
{
if(BufferLineWidths = (UWORD *)AllocVec(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth),MEMF_ANY | MEMF_CLEAR))
{
UWORD Index;
WORD i;
BufferLineOffsets = &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight];
BufferColumnOffsets = &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight];
for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight ; i++)
{
BufferLineOffsets[i] = Index;
Index += LocalTextFontHeight;
}
for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth ; i++)
{
BufferColumnOffsets[i] = Index;
Index += LocalTextFontWidth;
}
if(CreateScroller(BufferWindow -> Height))
{
/* Signal our father process that
* we're running.
*/
ReplyMsg(StartupMessage);
StartupMessage = NULL;
SetMenuStrip(BufferWindow,BufferMenuStrip);
AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);
Restart: BPort = BufferWindow -> RPort;
SetFont(BPort,LocalFont);
/* Determine maximum dimensions of
* the buffer screen (in rows and
* columns).
*/
NumBufferColumns = (BufferWindow -> Width - (ARROW_WIDTH + 1)) / LocalTextFontWidth;
NumBufferLines = BufferWindow -> Height / LocalTextFontHeight;
/* Bring the screen to the front. */
BumpWindow(BufferWindow);
/* Set the drawing pens for the window. */
SetAPen(BPort,1);
SetBPen(BPort,0);
SetDrMd(BPort,JAM2);
/* Initial creation of the buffer display. */
DisplayedLines = RedrawScreen(CurrentLine = 0);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top, 0,
PGA_Total, Lines,
PGA_Visible, NumBufferLines,
TAG_DONE);
BufferWindow -> Flags &= ~WFLG_RMBTRAP;
do
{
/* Show where we are. */
if(Lines)
{
LONG Width;
SetAPen(BufferScreen -> BarLayer -> rp,0);
SetBPen(BufferScreen -> BarLayer -> rp,1);
SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
if(LocaleBase)
SPrintf(PercentBuffer,"%lD/%lD (%ld%%)",CurrentLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (CurrentLine + DisplayedLines)) / Lines);
else
SPrintf(PercentBuffer,"%ld/%ld (%ld%%)",CurrentLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (CurrentLine + DisplayedLines)) / Lines);
Len = strlen(PercentBuffer);
Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
if(LastWidth > Width)
{
SetAPen(BufferScreen -> BarLayer -> rp,1);
RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
}
LastWidth = Width;
}
SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));
/* Leave the town? */
if(SignalSet & SIG_KILL)
BufferTerminated = TRUE;
/* Bring our window to the front. */
if(SignalSet & SIG_TOFRONT)
BumpWindow(BufferWindow);
/* We've got one more line in the
* buffer.
*/
if(SignalSet & SIG_UPDATE)
{
ObtainSemaphore(BufferSemaphore);
if(BufferLines)
{
if(Lines - CurrentLine > DisplayedLines && DisplayedLines < NumBufferLines)
{
LONG i = CurrentLine + DisplayedLines;
do
PrintLine(BufferLines[i++],DisplayedLines++);
while(DisplayedLines < NumBufferLines);
}
}
ReleaseSemaphore(BufferSemaphore);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Total, Lines,
PGA_Visible, NumBufferLines,
TAG_DONE);
}
/* The contents of the buffer have moved
* up a line.
*/
if(SignalSet & SIG_MOVEUP)
{
LastTopLine++;
DisplayedLines = RedrawScreen(CurrentLine);
}
/* Process the incoming window
* input.
*/
while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
{
IClass = Massage -> Class;
Code = Massage -> Code;
Qualifier = Massage -> Qualifier;
MouseX = Massage -> MouseX;
MouseY = Massage -> MouseY;
TagList = (struct TagItem *)Massage -> IAddress;
/* This hack is necessary to obtain the
* character codes generated for the cursor
* keys. A control or alternate qualifier
* would spoil the result (i.e. we would
* not get a valid key code).
*/
Massage -> Qualifier = NULL;
Char = KeyConvert(Massage,NULL,NULL);
/* Just in case anybody needs it... */
Massage -> Qualifier = Qualifier;
ReplyMsg((struct Message *)Massage);
if(IClass == IDCMP_IDCMPUPDATE)
{
switch(GetTagData(GA_ID,0,TagList))
{
case GAD_UP:
if(CurrentLine > 0)
{
CurrentLine--;
MarkArea(-1,-1,-1);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
DisplayedLines = RedrawScreen(CurrentLine);
}
break;
case GAD_DOWN:
if(CurrentLine + NumBufferLines < Lines)
{
CurrentLine++;
MarkArea(-1,-1,-1);
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
DisplayedLines = RedrawScreen(CurrentLine);
}
break;
}
}
if(IClass == IDCMP_MOUSEMOVE || IClass == IDCMP_GADGETDOWN || IClass == IDCMP_GADGETUP)
{
LONG Position;
GetAttr(PGA_Top,Scroller,&Position);
if(Position != CurrentLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(CurrentLine = Position);
}
}
if(IClass == IDCMP_RAWKEY)
{
if(Code == HELP_CODE)
GuideDisplay(CONTEXT_TEXTBUFFER);
if(LastChar)
{
if((Code & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
{
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
}
if(LastChar = Char)
{
/* Use the numeric keypad keys to
* move through the buffer.
*/
if(Qualifier & IEQUALIFIER_NUMERICPAD)
{
/* Remove the numpad qualifier. */
Qualifier &= ~IEQUALIFIER_NUMERICPAD;
switch(Char - '0')
{
/* Jump to bottom. */
case 1: Char = CDN;
Qualifier |= IEQUALIFIER_CONTROL;
break;
/* Jump to top. */
case 7: Char = CUP;
Qualifier |= IEQUALIFIER_CONTROL;
break;
/* Move one page down. */
case 3: Char = CDN;
Qualifier |= IEQUALIFIER_LSHIFT;
break;
/* Move one page up. */
case 9: Char = CUP;
Qualifier |= IEQUALIFIER_LSHIFT;
break;
/* Move one line down. */
case 2: Char = CDN;
break;
/* Move one line up. */
case 8: Char = CUP;
break;
}
}
/* Check cursor keys. */
switch(Char)
{
/* Scroll the buffer up. */
case CUP:
if(Qualifier & IEQUALIFIER_CONTROL)
{
MarkArea(-1,-1,-1);
if(CurrentLine)
{
DisplayedLines = RedrawScreen(CurrentLine = 0);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
break;
}
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
LONG NewCurrentLine;
if((NewCurrentLine = CurrentLine - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(NewCurrentLine != CurrentLine)
{
DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
break;
}
if(CurrentLine)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(--CurrentLine);
}
break;
/* Scroll the buffer down. */
case CDN:
if(Qualifier & IEQUALIFIER_CONTROL)
{
LONG NewCurrentLine;
if((NewCurrentLine = Lines - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(CurrentLine != NewCurrentLine)
{
DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
break;
}
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
LONG NewCurrentLine;
if((NewCurrentLine = CurrentLine + (2 * NumBufferLines)) > Lines)
NewCurrentLine = Lines;
if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
NewCurrentLine = 0;
MarkArea(-1,-1,-1);
if(NewCurrentLine != CurrentLine)
{
DisplayedLines = RedrawScreen(CurrentLine = NewCurrentLine);
LastChar = 0;
SetGadgetAttrs(Scroller,BufferWindow,NULL,
PGA_Top,CurrentLine,
TAG_DONE);
}
break;
}
if(CurrentLine + NumBufferLines < Lines)
{
MarkArea(-1,-1,-1);
DisplayedLines = RedrawScreen(++CurrentLine);
}
break;
}
LastQualifier = Qualifier;
}
else
LastQualifier = NULL;
continue;
}
/* User hit a mouse button. */
if(IClass == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX))
{
MarkArea(-1,-1,-1);
/* Reasonable dimensions? */
if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
{
ObtainSemaphore(BufferSemaphore);
BufferClip();
LastTopLine = CurrentLine;
ReleaseSemaphore(BufferSemaphore);
if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
Signal(ThisProcess,SIG_CLIP);
break;
}
}
if(IClass == IDCMP_MENUPICK)
{
struct MenuItem *MenuItem;
while(Code != MENUNULL)
{
MenuItem = ItemAddress(BufferMenuStrip,Code);
switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
{
case MEN_SEARCH:
StartBufferSearch(TRUE);
break;
case MEN_REPEAT:
StartBufferSearch(FALSE);
break;
case MEN_GOTO:
if(Window)
BumpWindow(Window);
break;
case MEN_QUITBUF:
case MEN_CLOSEBUF:
BufferTerminated = TRUE;
break;
case MEN_CLEARBUF_CONTENTS:
if(Lines)
{
BlockWindows();
BlockWindow(BufferWindow);
if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
FreeBuffer();
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
goto Restart;
}
else
{
if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
{
FreeBuffer();
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
goto Restart;
}
}
ReleaseWindow(BufferWindow);
ReleaseWindows();
FlushMsg(BufferWindow);
}
break;
}
Code = MenuItem -> NextSelect;
}
}
}
}
while(!BufferTerminated);
RemoveGList(BufferWindow,Scroller,(UWORD)-1);
DeleteScroller();
}
FreeVec(BufferLineWidths);
}
if(Window)
BumpWindow(Window);
MarkArea(-1,-1,-1);
ScreenToBack(BufferScreen);
BufferWindow -> Flags |= WFLG_RMBTRAP;
ClearMenuStrip(BufferWindow);
CloseWindow(BufferWindow);
}
}
FreeMenus(BufferMenuStrip);
}
FreeVisualInfo(BufferVisualInfo);
}
CloseScreen(BufferScreen);
}
}
CloseFont(LocalFont);
}
/* Release the search buffer data. */
if(BufferSearchInfo)
{
DeleteSearchInfo(BufferSearchInfo);
BufferSearchInfo = NULL;
}
Forbid();
BufferProcess = NULL;
if(StartupMessage)
ReplyMsg(StartupMessage);
else
Signal(ThisProcess,SIG_HANDSHAKE);
}