// infowind.c // // This file implements the info windows' menus, controls and events. // // by John D. de Boer #include "twist.h" #include "twindow.h" extern GlobalOpts Opt; extern void *Sel,*Was; extern IBNibRef Nib; int INFOWINDS; // the number of information windows currently open window *InfoWind[MAXINFOWINDS]; // the infomation windows static cursor Mitten; // the hyperlink cursor static bool Hand; // cursor is currently the hand const static int MARGIN = 8; // white margin around text box #define GenevaFontID (3) // static void SetFollowed(void *V) { if (VoidIsPers(V)) { Person *P=(Person *)V; P->followed=1; } if (VoidIsEvent(V)) { Event *E=(Event *)V; E->followed=1; } } static bool WasFollowed(void *V) { if (VoidIsPers(V)) { Person *P=(Person *)V; return P->followed; } if (VoidIsEvent(V)) { Event *E=(Event *)V; return E->followed; } return 0; } // Drawing content static void DrawInfoBox(window *W, const Rect *R) { InfoInfo *D; HIRect H; if (!W) return; D=W->appdata; if (!D) return; if (D->size!=Opt.size/* && !W->printing*/) { setTEsize(D->txn,0,D->info.len,Opt.size); D->size=Opt.size; } H=W->page; H.origin.y=0; TXNDrawObject(D->txn,&H,kTXNDrawItemAllMask); } static void DrawInfo(window *W) { InfoInfo *D; Rect R; if (!W) return; D=W->appdata; if (!D) return; GetWindowPortBounds(W->wmw,&R);//can be page again DrawInfoBox(W,&R); } static void PrintInfo(struct window *W, short PAGE) { InfoInfo *D; if (!W) return; D=W->appdata; if (!D) return; DrawInfo(W); } static void ColourLinks(window *W, bool Underline) { int i; InfoInfo *D; WindowPtr WP; colour Co; InfoLink L; if (!W) return; WP=W->wmw; D=W->appdata; if (!WP || !D) return; for (i=0;iinfo.links;i++) { L=(*(D->info.link))[i]; if (Underline) setTEstyle(D->txn,L.start,L.end,underline); setcolour(&Co,WasFollowed(L.link) ? purple : blue); setTEcolour(D->txn,L.start,L.end,&Co); } } static void CreateInfoTE(window *W) { InfoInfo *D; void *V; WindowPtr WP; if (!W) return; WP=W->wmw; D=W->appdata; if (!WP || !D) return; V=D->obj; if (!V) return; if (VoidIsPers(V)) { Person *P=(Person *)V; setwindowname(W,P->name); MakePersInfo(P,&(D->info)); } else { Event *E=(Event *)V; setwindowname(W,E->name); MakeEventInfo(E,&(D->info)); } D->txn=createtextobj(WP,D->info.text,D->info.len,D->info.tlen,Opt.size,MARGIN); D->size=Opt.size; ColourLinks(W,1); } // Utility static Person *TheAuthor(void *V) { if (!V || !VoidIsEvent(V)) return NULL; return ((Event *)V)->pers; } static void CopyInfo(InfoInfo *D) { OSStatus err; if (!D) return; TXNSelectAll(D->txn); err=TXNCopy(D->txn); err=TXNSetSelection(D->txn,0,0); } // Menus for the infomation window static MenuRef InfoMenu; static void InitInfoMenus(void) { OSStatus err; err=CreateMenuFromNib(Nib,CFSTR("info"),&InfoMenu); } static void SetUpInfoMenus(void) { SetUpFileMenu(); InsertMenu(InfoMenu,0); SetUpSizeMenu(); SetUpWindowMenu(); } static void AdjustInfoMenus(window *W) { InfoInfo *D; void *V; if (!W) return; D=W->appdata; if (!D) return; V=D->obj; if (!V) return; itemenable(InfoMenu,5,TheAuthor(V)!=NULL); AdjustFileMenu(W); AdjustSizeMenu(W); } static bool InfoCommand(window *W, UInt32 C) { InfoInfo *D; void *V; Person *Au; if (!W) return 0; D=W->appdata; if (!D) return 0; V=D->obj; switch (C) { case 'copy': CopyInfo(D); return 1; case 'InGo': Au=TheAuthor(V); if (!Au) return 1; Sel=Au; SwitchToTimeLine(); return 1; } return FileCommand(W,C); } // Contextual Menus static bool InfoPopup(window *W, point Pt) { if (!Sel) return 0; if (VoidIsPers(Sel)) return PersonPopup(W,Pt,1,1,0,1,Sel); if (VoidIsEvent(Sel)) return EventPopup(W,Pt,1,1,0,Sel); return 0; } // Window events static void *LinkClick(window *W, InfoInfo *D, point Pt) { OSStatus err; Point QD; /*HIPoint H;*/ UInt32 OFFSET,O2; int i; InfoLink L; if (!W || !D) return NULL; QD.h=Pt.x; QD.v= height(W->page) - Pt.y; err=TXNPointToOffset(D->txn,QD,&OFFSET); //H=Pt; H.y= height(W->page) - Pt.y; //err=TXNHIPointToOffset(D->txn,&H,&OFFSET); QD.h-= 1.5 * Opt.size; err=TXNPointToOffset(D->txn,QD,&O2); //H.x-= 1.5 * Opt.size; //err=TXNHIPointToOffset(D->txn,&H,&O2); if (OFFSET==O2) return NULL; // point is well to right of ragged edge for (i=0;iinfo.links;i++) { L=(*(D->info.link))[i]; if (L.start<=OFFSET && OFFSET<=L.end) return L.link; } return NULL; } static bool InfoContent(mouseclick *M) { window *W; InfoInfo *D; void *HL; long CONTEXTTIME; if (!M) return 0; W=M->wind; if (!W) return 0; D=W->appdata; if (!D) return 0; if (M->point.x >= right(W->page) - SCROLLTHICK) return 0; Was=Sel; Sel=D->obj; if (Sel!=Was) RedisplayAll(); CONTEXTTIME= TickCount() + GetDblTime(); HL=LinkClick(W,D,M->point); if (HL) { Sel=HL; SwitchToInfo(); return 1; } if (M->right) return InfoPopup(W,M->point); while (stilldown(M)) if (TickCount()>CONTEXTTIME) return InfoPopup(W,M->point); return 1; } static bool InfoDouble(mouseclick *M) { window *W; InfoInfo *D; if (!M) return 0; W=M->wind; if (!W) return 0; D=W->appdata; if (!D) return 0; if (M->point.x >= right(W->page) - SCROLLTHICK) return 0; Was=Sel; Sel=D->obj; if (Sel==Was) { SwitchToTimeLine(); return 1; } return InfoContent(M); } static void InfoGrow(window *W) { if (!W) return; } static bool TrackInfoMouse(mouseclick *M) { window *W; InfoInfo *D; bool Link; if (!M) return 0; W=M->wind; if (!W) return 0; D=W->appdata; if (!D) return 0; Link= pointinrect(M->point,W->page) && LinkClick(W,D,M->point); if (Link) { if (Hand) return 0; setcursor(Mitten); Hand=1; return 1; } if (!Hand) return 0; defaultcursor(); Hand=0; return 1; } // "Info" windows void InitInfoViews(void) { OSStatus err; INFOWINDS=0; InitInfoMenus(); Mitten=getcursor("201"); Hand=0; err=TXNInitTextension(NULL,0,0); } static int InfoIndex(window *W) { int i; for (i=0;i=0; } window *InfoWindOf(void *V) { int i; window *W; InfoInfo *D; for (i=0;iappdata; if (!D) continue; if (D->obj==V) return W; } return NULL; } static void OldInfoWindow(window *W) { InfoInfo *D; if (!W) return; D=W->appdata; if (!D) return; TXNDeleteObject(D->txn); PurgeInfoPara(&(D->info)); old(D); oldwindow(W); } static void CloseInfoWindow(window *W) { int i; if (!W) return; i=InfoIndex(W); if (i<0) return; defaultcursor(); OldInfoWindow(W); InfoWind[i]=InfoWind[--INFOWINDS]; } void CloseAllInfo(void) { while (INFOWINDS>0) CloseInfoWindow(InfoWind[0]); } static window *NewInfoWindow(void *V) { Rect R; window *W; InfoInfo *D; Point Pt; WindowPtr WP; if (!V) return NULL; W=customwindow("Historical Event",375,425,1); if (!W) return NULL; stackwindow(W,StackableWindows()); D=W->appdata=pointer(sizeof(InfoInfo)); D->obj=V; SetFollowed(V); InitInfoPara(&(D->info)); D->size=Opt.size; D->txn=NULL; CreateInfoTE(W); revealwindow(W); installmenus(W,NULL,&SetUpInfoMenus,&AdjustInfoMenus,&InfoCommand); installgrow(W,&InfoGrow,NULL); installpaint(W,&DrawInfo); installclick(W,&InfoContent,&CloseInfoWindow,&DrawInfo); installmousemove(W,&TrackInfoMouse); //installdouble(W,&InfoDouble); installprint(W,NULL,&PrintInfo); WP=W->wmw; if (!WP) { Pt.h=200; Pt.v=100; } else { GetWindowPortBounds(WP,&R); Pt.h= R.right + 5; Pt.v=R.top; localtoglobal(WP,&Pt); } OpenImage(V,Pt); return W; } static void AddInfoWindow(void *V) { window *W; if (!V) return; if (INFOWINDS>=MAXINFOWINDS) { beep(); return; } W=NewInfoWindow(V); if (!W) return; InfoWind[INFOWINDS++]=W; revealwindow(W); postwindowmenus(W); // don't know why, but this is necessary } // Opening information window for selection void SwitchToInfo(void) { int i; window *W; if (!Sel) return; W=InfoWindOf(Sel); if (W) revealwindow(W); else AddInfoWindow(Sel); for (i=0;i < INFOWINDS - 1;i++) ColourLinks(InfoWind[i],0); RedisplayAll(); }