#include "Globals.h" char InvBuf[]= {CSI,'7',0x6d,NULL,CSI,'0',0x6d}; char Inv[]= {CSI,'7',0x6d,NULL}; char Norm[]= {CSI,'0',0x6d,NULL}; struct LineItem *InvItem; void MovedMouse(x,y) /*The mouse was moved! Record its new position*/ int x,y; { LastX=PtrX; LastY=PtrY; PtrY=(prefs.DS) ? (y/16)+1 : (y/8)+1; PtrX=(x/8)+1; } HandleButton(Seconds,Micros) /*Handle a button press*/ int Seconds,Micros; { int status; static int LastSeconds=1,LastMicros=1,DoubClicked=FALSE; static UBYTE ButtonX,ButtonY; /*If the user double-clicked (the mouse button), start or modify*/ /*a highlighted block*/ if(DoubleClick(LastSeconds,LastMicros,Seconds,Micros) && PtrY==ButtonY && !DoubClicked) { PtrX=ButtonX; PtrY=ButtonY; DoubClicked=TRUE; HandleInvs(); BLastX=PtrX; } else /*Otherwise, just move the cursor accordingly*/ if(PtrY > 0 && PtrY <= SCRNHEIGHT) { ButtonX=PtrX; ButtonY=PtrY; DoubClicked=FALSE; if(PtrY != InvY && InvsMode > NOINV) /*End text highlighting*/ EndLineInvs(); /*if the cursor is moved to a new line*/ if(PtrY-CurY < 0) /*move the cursor to a new line*/ status=MoveBack(-(PtrY-CurY)); else status=MoveForward(PtrY-CurY); if(status==FALSE) return(FALSE); if(PtrX > MaxX(CurrentItem)) /*Move the cursor to a new*/ CurX=MaxX(CurrentItem); /*X position*/ else if(PtrX < MinX(CurrentItem)) CurX=MinX(CurrentItem); else CurX=PtrX; PlotCursor(CurX,PtrY); } LastSeconds=Seconds; LastMicros=Micros; } void HandleInvs() /*Handle a modification or creation of a highlighted block*/ { if(InvsMode==NOINV) if(PtrX >= MinX(CurrentItem) && PtrX <= MaxX(CurrentItem)) HandleLineInvs(); else HandleBlockInvs(); else if(InvsMode > NOINV) HandleLineInvs(); /*Highlighting on one line*/ else HandleBlockInvs(); /*Block highlighting*/ } HandleBlockInvs() /*Handle the inverse of a block of lines*/ { int X,Y; if(InvsMode==NOINV) /*If nothing is highlighted*/ { InvY=EndIY=CurY; WriteConsole(Inv,-1); PlotCursor(1,CurY); PrintItem(CurrentItem); WriteConsole(Norm,-1); EndIItem=StartIItem=(struct LineItem *)CurrentItem; PlotCursor(MinX(CurrentItem),CurY); InvsMode=BLOCK_PENDING; return(TRUE); } if(InvsMode==BLOCK_PENDING) /*If one line is highlighted*/ { if(StartIItem == CurrentItem) /*Same line? End highlighting*/ { EndBlockInvs(); return(TRUE); } else /*Else, highlight a block (up or down, depending)*/ if(IsAfter(CurrentItem,StartIItem)) /*down*/ { EndIItem=(struct LineItem *)CurrentItem; if((Y=IsOnScreen(StartIItem->NextItem))) { PlotCursor(1,Y); RvsBlock(StartIItem->NextItem,EndIItem); } else { PlotCursor(1,1); RvsBlock(FirstScrnItem,EndIItem); } EndIY=CurY=PtrY; InvsMode=BLOCK_DOWN; PlotCursor(MinX(EndIItem),CurY); } else /*up*/ if(IsBefore(CurrentItem,StartIItem)) { EndIItem=(struct LineItem *)CurrentItem; EndIY=CurY; if( (Y=IsOnScreen(StartIItem->PrevItem)) ) RvsBlock(EndIItem,StartIItem->PrevItem); else RvsBlock(EndIItem,ScrnBtm); PlotCursor(MinX(EndIItem),EndIY); InvsMode=BLOCK_UP; } return(TRUE); } if(InvsMode == BLOCK_DOWN) /*If highlighting is down*/ { if((IsAfter(CurrentItem,EndIItem)) && CurrentItem != EndIItem) { /*Highlight more*/ if( (Y=IsOnScreen(EndIItem->NextItem))) { PlotCursor(1,Y); RvsBlock(EndIItem->NextItem,CurrentItem); } else { PlotCursor(1,1); RvsBlock(FirstScrnItem,CurrentItem); } EndIY=CurY=PtrY; EndIItem=(struct LineItem *)CurrentItem; PlotCursor(MinX(EndIItem),IsOnScreen(CurrentItem)); } if((IsBefore(CurrentItem,EndIItem)) && CurrentItem != EndIItem) { /*Unhighlight some*/ if(IsBefore(CurrentItem,StartIItem)) { EndBlockInvs(FALSE); return(TRUE); } EndIY=Y=CurY; X=CurX; PlotCursor(CurX,CurY+1); NormBlock(CurrentItem->NextItem,EndIItem); PlotCursor(X,Y); EndIItem=(struct LineItem *)CurrentItem; } } else /*The higlighting goes up*/ { if((IsBefore(CurrentItem,EndIItem)) && CurrentItem != EndIItem) { /*Highlight*/ EndIY=Y=CurY; if( (Y=IsOnScreen(EndIItem->PrevItem)) ) RvsBlock(CurrentItem,EndIItem->PrevItem); else RvsBlock(CurrentItem,ScrnBtm); PlotCursor(MinX(CurrentItem),IsOnScreen(CurrentItem)); EndIItem=(struct LineItem *)CurrentItem; } /*Normalize*/ if((IsAfter(CurrentItem,EndIItem)) && CurrentItem != EndIItem) { if((CurrentItem==StartIItem)||(IsAfter(CurrentItem,StartIItem))) { EndBlockInvs(); return(TRUE); } Y=CurY; PlotCursor(CurX,EndIY); NormBlock(EndIItem,CurrentItem->PrevItem); EndIItem=(struct LineItem *)CurrentItem; PlotCursor(MinX(CurrentItem),IsOnScreen(CurrentItem)); EndIY=CurY; } } } void NormIt(Start,End,Start_y) /*Un-highlight an area on screen*/ struct LineItem *Start,*End; int Start_y; { struct LineItem *CurItem; CurItem=(struct LineItem *)Start; WriteConsole(Norm,-1); PlotCursor(1,Start_y); CurY--; while(CurItem != End->NextItem) /*Go down the screen*/ { PlotCursor(1,CurY+1); PrintItem(CurItem); CurItem=(struct LineItem *)CurItem->NextItem; } } void NormBlock(Start,End) /*Unhighlight a block of text, keeping it to*/ struct LineItem *Start,*End; /*what is on screen currently*/ { int beg_y,end_y,old_y,old_x; old_y=CurY; old_x=CurX; if((beg_y=IsOnScreen(Start))) /*If 'Start' is on the screen*/ if((end_y=IsOnScreen(End))) /*If 'End' is on screen*/ NormIt(Start,End,beg_y); /*Normalize a block in the normal way*/ else NormIt(Start,ScrnBtm,beg_y);/*Normalize from 'Start' to end of screen*/ else if(IsBefore(Start,FirstScrnItem)) /*If 'Start' is above the screen*/ if(IsAfter(End,ScrnBtm)) /*and 'End' is below it*/ NormIt(FirstScrnItem,ScrnBtm,1); /*Unhighlight the whole screen*/ else if((IsOnScreen(End))) /*If the end is on the screen*/ NormIt(FirstScrnItem,End,1); /*Unhighlight from top to End*/ /*That's it (any other possibilities cause nothing to happen)*/ PlotCursor(old_x,old_y); } void RvsBlock(Start,End) /*Highlight a block*/ struct LineItem *Start,*End; { struct LineItem *CurItem; int y; CurItem=(struct LineItem *)Start; /*Start at the start*/ WriteConsole(Inv,-1); /*Activate inversed text*/ CurY--; while(CurItem != End->NextItem) /*Go through list*/ { if(y=IsOnScreen(CurItem)) /*Only do lines on screen*/ { PlotCursor(1,y); PrintItem(CurItem); } CurItem=(struct LineItem *)CurItem->NextItem; } WriteConsole(Norm,-1); } void EndBlockInvs() /*End the highlight of a block of lines*/ { struct WhichOne which; FindStartEnd(StartIItem,EndIItem,&which); NormBlock(which.Start,which.End); PlotCursor(MinX(CurrentItem),CurY); InvsMode=NOINV; } HandleLineInvs() /*Handle the inverse of individual characters*/ { int NewEnd; if(PtrX < MinX(CurrentItem)) PtrX=MinX(CurrentItem); else if(PtrX > MaxX(CurrentItem)) PtrX=MaxX(CurrentItem); if(InvsMode==NOINV) /*If nothing is highlighted, start highlighting*/ { InvBuf[3]=CurrentItem->Text[PosInText(CurrentItem->Level)]; WriteConsole(InvBuf,7); StartChar=EndChar=PosInText(CurrentItem->Level); PlotCursor(CurX,CurY); InvsMode=LINE_PENDING; InvY=CurY; InvItem=(struct LineItem *)CurrentItem; return(TRUE); } if(InvsMode==LINE_PENDING) /*If one character only*/ { if(PtrX == BLastX) /*Same character? Cancel highlighting*/ { EndLineInvs(); return(TRUE); } if(PtrX > BLastX) /*After the character*/ { EndChar=PosInText(InvItem->Level); PlotCursor(BLastX,CurY); RvsText(StartChar,EndChar); CurX=CurX+EndChar-StartChar; InvsMode=LINE_FWD; PlotCursor(CurX,CurY); return(TRUE); } if(PtrX < BLastX) /*Before the character*/ { EndChar=PosInText(InvItem->Level); RvsText(EndChar,StartChar-1); PlotCursor(PtrX,CurY); InvsMode=LINE_BACK; } return(TRUE); } else if(InvsMode==LINE_FWD) /*Left to right highlighting*/ { if(PtrX > BLastX) /*Forward (highlight more)*/ { NewEnd=PtrX-MinX(InvItem); PlotCursor(EndChar+MinX(InvItem),CurY); RvsText(EndChar,NewEnd); CurX=NewEnd+MinX(InvItem); PlotCursor(CurX,CurY); EndChar=NewEnd; } if(PtrX < BLastX) /*Backward (un-highlight)*/ if(PtrX-MinX(InvItem)<=StartChar) EndLineInvs(); else { NewEnd=PtrX-MinX(InvItem); NormText(NewEnd+1,EndChar); PlotCursor(CurX,CurY); EndChar=NewEnd; } } else /*Right to left highlighting*/ { if(PtrX < BLastX) /*Backward (highlight more)*/ { NewEnd=PtrX-MinX(InvItem); RvsText(NewEnd+1,EndChar); PlotCursor(CurX,CurY); EndChar=NewEnd; } if(PtrX > BLastX) /*Forward (un-highlight some)*/ if(PtrX-MinX(InvItem)>=StartChar) EndLineInvs(); else { NewEnd=PtrX-MinX(InvItem)-1; PlotCursor(EndChar+MinX(InvItem),CurY); NormText(EndChar,NewEnd); CurX=NewEnd+MinX(InvItem); EndChar=NewEnd; PlotCursor(CurX+1,CurY); } } } void RvsText(Start,End) /*Highlight a block of text*/ int Start,End; { char Buffer[80]; int c,l; strcpy(Buffer,Inv); l=strlen(Buffer); for(c=l; c-l < End-Start+1 ; c++) { Buffer[c]=InvItem->Text[c+Start-l]; } Buffer[c]=0; strcat(Buffer,Norm); WriteConsole(Inv,-1); WriteConsole(Buffer,c); WriteConsole(Norm,-1); } MoveBack(Number) /*Move back in the item list a specified number of times*/ int Number; { int c; for(c=0;cPrevItem==NULL) return(FALSE); else CurrentItem=(struct LineItem *)CurrentItem->PrevItem; } return(TRUE); } MoveForward(Number) /*Move forward in the item list a specifiecd*/ int Number; /*number of times*/ { int c; struct LineItem *OrigItem; OrigItem=(struct LineItem *)CurrentItem; for(c=0;cNextItem==NULL) { CurrentItem=(struct LineItem *)OrigItem; return(FALSE); } else CurrentItem=(struct LineItem *)CurrentItem->NextItem; } return(TRUE); } void EndLineInvs() /*End text inverse*/ { if(StartChar < EndChar) NormText(StartChar,EndChar); else NormText(EndChar,StartChar); InvsMode=NOINV; } void NormText(Start,End) /*Un-reverse text*/ int Start,End; { int TempX,c; char Buffer[80]; for(c=Start;c<=End;c++) Buffer[c-Start]=InvItem->Text[c]; Buffer[c-Start]=0; TempX=CurX; PlotCursor(MinX(InvItem)+Start,InvY); WriteConsole(Buffer,-1); PlotCursor(TempX,InvY); } HandleDelBlock() /*Delete a block of lines*/ { struct WhichOne which; struct LineItem *temp; BOOL stat; /*If you're deleting everything, just call New*/ if((StartIItem->PrevItem==NULL && EndIItem->NextItem==NULL) || (StartIItem->NextItem==NULL && EndIItem->PrevItem==NULL)) { NewAll(); return(TRUE); } /*Otherwise, find the true start and end and delete the block*/ FindStartEnd(StartIItem,EndIItem,&which); if(which.Start->NextItem != NULL && which.Start->NextItem->cont && !which.Start->cont && which.Start==which.End) /*TRUE==parent*/ return(FALSE); InvsMode=NOINV; /*Find the end (last child)*/ if(which.End->NextItem->cont && (which.Start!=which.End)) { temp=(struct LineItem *)which.End->PrevItem; stat=FALSE; while(temp!=which.Start) { if(!temp->cont) stat=TRUE; temp=(struct LineItem *)temp->PrevItem; } if(stat) which.End=(struct LineItem *)FindNextNonCont(which.End); } DelBlock(which.Start,which.End,IsOnScreen(which.Start), IsOnScreen(which.End)); return(TRUE); } /*When dealing with highlighted blocks, it is not guaranteed that*/ /*StartIItem comes before EndIItem in the linked list. This function*/ /*sorts out which is which and puts each pointer in an appropriate*/ /*space in a WhichOne structure (created especially for this function)*/ /*A kludge, I know. But 'Liner's grown up around this technique. It*/ /*would take more work than it is worth to change it*/ void FindStartEnd(Start,End,which) struct LineItem *Start,*End; struct WhichOne *which; { if(IsBefore(Start,End)) { which->Start=(struct LineItem *)Start; which->End=(struct LineItem *)End; } else { which->Start=(struct LineItem *)End; which->End=(struct LineItem *)Start; } } void DelBlock(Start,End,StartY,EndY) /*Delete a block of lines*/ struct LineItem *Start,*End; int StartY,EndY; { int TOS; if(!Start->cont) { Start=(struct LineItem *)FindPrevNonCont(Start); End=(struct LineItem *)FindNextNonCont(End); } StartY=IsOnScreen(Start); EndY=IsOnScreen(End); if(!StartY) /*If the start of the inversed block isn't on*/ { /*the screen, put it on the screen and then delete*/ FirstScrnItem=CurrentItem=(struct LineItem *)Start; PrintItemList(Start,(StartY=1)); } if(!EndY) /*Handle when the end isn't on screen*/ EndY=SCRNHEIGHT; if(Start==FirstScrnItem) TOS=TRUE; else TOS=FALSE; if(Start->PrevItem == NULL) /*If there is nothing before 'Start'*/ { /*Make 'End' the start of everything*/ CurrentItem=FirstItem=FirstScrnItem= (struct LineItem *)End->NextItem; CurrentItem->PrevItem=NULL; RemItem(CurrentItem); AddItem(CurrentItem); TOS=FALSE; } else if(End->NextItem==NULL) /*If 'End' is the end of everything, make*/ { /*'Start'->PrevItem the start of everything*/ CurrentItem=LastItem= (struct LineItem *)Start->PrevItem; LastItem->NextItem=NULL; if(Start==FirstScrnItem) { FirstScrnItem=ScrnBtm=(struct LineItem *)CurrentItem; StartY=1; } else StartY--; TOS=FALSE; } else { CurrentItem=Start->PrevItem->NextItem=(struct LineItem *) End->NextItem; End->NextItem->PrevItem= (struct LineItem *)Start->PrevItem; } if(TOS) /*If the Start was at the top of the screen...*/ CurrentItem=FirstScrnItem=(struct LineItem *)End->NextItem; /*Free the deleted block's memory*/ FreeListMem(Start,End); /*Update some ItemNumbers*/ RemItem(CurrentItem); AddItem(CurrentItem); BackSearchRefresh(CurrentItem); PrintItemList(CurrentItem,StartY); PlotCursor(MinX(CurrentItem),StartY); } void FreeListMem(Start,End) /*Free several Items at once*/ struct LineItem *Start,*End; { struct LineItem *Item,*Next; Next=(struct LineItem *)Start; do { Item=(struct LineItem *)Next; Next=(struct LineItem *)Item->NextItem; RemItem(Item); if(Item->PrevItem !=NULL) Item->PrevItem->NextItem=(struct LineItem *)Item->NextItem; if(Item->NextItem != NULL) Item->NextItem->PrevItem=(struct LineItem *)Item->PrevItem; FreeMem(Item,sizeof(struct LineItem)); } while(Item != End && Next != NULL); } void DelTextBlock() /*Delete the highlighted text*/ { int c,Start,End,len; char Buffer[2]; if(StartChar < EndChar) /*Find the start of the highlighted block*/ { Start=StartChar; End=EndChar; } else { Start=EndChar; End=StartChar; } len=strlen(InvItem->Text); for(c=0;c <= len-End; c++) InvItem->Text[c+Start]=InvItem->Text[c+End+1]; PlotCursor(1,InvY); Buffer[0]=CSI; Buffer[1]=0x4b; WriteConsole(Buffer,2); PrintItem(InvItem); PlotCursor(MinX(InvItem)+Start,InvY); InvsMode=NOINV; } CancelLineInvs() /*Cancel an inversed text section*/ { if(NOINV == InvsMode) return(FALSE); else if(InvsMode > NOINV) EndLineInvs(); } CancelInvs() /*Cancel inversed text or lines*/ { if(NOINV == InvsMode) return(FALSE); else if(InvsMode > NOINV) EndLineInvs(); else EndBlockInvs(); return(TRUE); } DelInvs() /*Delete the highlighted block or text*/ { if(InvsMode==NULL) return(FALSE); if(InvsMode > NOINV) DelTextBlock(); else HandleDelBlock(); return(TRUE); } void TitleError(string) /*Display 'string' in the title bar*/ char *string; { DisplayBeep(Screen); ErrorInTitle = TRUE; SetWindowTitles(Window,-1,string); } void TitleErrorCancel() /*Set the title bar text to normal (with the */ { /*current filename in the title bar*/ static char Title[85]; strcpy(Title,ScreenTitle); if(FileName[0]) strncat(Title,FileName,65); else strcat(Title,"Untitled"); if(Modified==TRUE) /*If the outline has been modified*/ Title[0]='*'; /*Put a '*' before "'Liner"*/ ErrorInTitle = FALSE; SetWindowTitles(Window,-1,Title); } void BackSearchRefresh(Base) /*Do a refresh of ItemNumbers by searching*/ struct LineItem *Base; /*back through the item list*/ { struct LineItem *Work,Dummy; Dummy.PrevItem=(struct LineItem *)Base->PrevItem; Dummy.NextItem=(struct LineItem *)Base->NextItem; for(Dummy.Level=Base->Level;Dummy.Level > 0;Dummy.Level--) if((Work=(struct LineItem *)FindPrev(&Dummy))!=NULL) { RemItem(Work); AddItem(Work); } } /*End of mouse.c*/