/* * This file contains the ViewClass code for the sample browser. */ #include #include #include #include #include #include #include "ctl3d.h" /* MediaView Include Files */ #include #include /* Application Include Files */ #include "mvui.h" #include "view.h" #include "pane.h" #include "resrc1.h" #include "proto.h" /**************************************************************************** ** FUNCTION: View_Register ** ** PURPOSE: Register the MVViewClass ** ** COMMENTS: ** ****************************************************************************/ BOOL View_Register(HANDLE hInstance) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = ViewWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = EXTRA_VIEW_SIZE; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = 0; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "MVViewClass"; if (RegisterClass(&wc) == 0) return(FALSE); } /**************************************************************************** ** FUNCTION: View_Create ** ** PURPOSE: create the 2 windows in a view (non-scrolling, ** ** scrolling). ** ** COMMENTS: ** ****************************************************************************/ BOOL View_Create(LPVIEW lpView, HWND hMainWnd, HWND hFP, HANDLE hInstance) { _fmemset(lpView, 0, sizeof(VIEW)); /* create the view window */ lpView->hView = CreateWindow( "MVViewClass", "View", WS_CHILD|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hFP, /* make it a CHILD of the faceplate */ 0, hInstance, 0 ); /* create scrolling and non-scrolling regions */ if (!(lpView->hNSR = Pane_Create("Non-Scrolling Region", lpView->hView, hInstance))) return(FALSE); if (!(lpView->hSR = Pane_Create("Scrolling Region", lpView->hView, hInstance))) return(FALSE); lpView->isOpen = FALSE; View_Init(lpView); return(TRUE); } /**************************************************************************** ** FUNCTION: ViewWndProc ** ** PURPOSE: Handle top level messages to the View window ** ** COMMENTS: ** ****************************************************************************/ long WINAPI ViewWndProc(hWnd, message, wParam, lParam) HWND hWnd; UINT message; WPARAM wParam; LPARAM lParam; { extern HCURSOR curArrow; switch (message) { case WM_KEYDOWN: hWnd = GetFocus(); break; case WM_SIZE: View_Layout(GetView(hWnd)); break; case WM_MOUSEMOVE: /* * if we get this message, it is because the mouse is * in a region of the View that has no Pane (View is bigger * than the sum of the Panes. Be sure to set the cursor back to * the arrow. */ SetCursor(curArrow); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); } /**************************************************************************** ** FUNCTION: View_Open ** ** PURPOSE: Open the title and pass all of the necessary information ** ** to the children (Panes). ** ** ARGUMENTS: ** ** RETURNS: 0 if successful, or a MediaView error code ** ** COMMENTS: ** ** This routine opens a title, then creates an MV structure ** ** and binds it to each of a scrolling and non-scrolling regions ** ** (Panes) by doing a Pane_Open on each one. ** ****************************************************************************/ int View_Open(LPSTR szTitlePath, LPVIEW lpView) { ERR err; HTITLE hTitle; LPMV lpMV; /* Open the title */ if ((hTitle = TitleOpen(szTitlePath)) == 0) return(ERR_FAILED); lpView->hTitle = hTitle; /* allocate an MV for the View and assign the title */ if ((lpMV = lpMVNew(&err)) == 0) return(err); if (!fMVSetTitle(lpMV, hTitle, szTitlePath, &err)) { View_Close(lpView); return(err); } /* Give the MV access to the internal filesystem of the title */ lpView->hFileSys = (HANDLE)TitleGetInfo(hTitle, TTLINF_FILESYS, 0, 0); MVSetFileSystem(lpMV, lpView->hFileSys); /* load the group list for this title */ if ((lpView->lpGroups = MV_LoadGroups(szTitlePath, "GROUPS", "group")) == 0) { ErrorMsg("Cannot Find MVP file.", "Error"); } /* load the keyword index groups for this title */ else if ((lpView->lpKeyIndex = MV_LoadGroups(szTitlePath, "KEYINDEX", "keyword")) == 0) { ErrorMsg("Cannot Find MVP file.", "Error"); } /* and give the MV access to the font table of the title */ lpView->hFont = (HANDLE)TitleGetInfo(hTitle, TTLINF_FONTTABLE, 0, 0); hMVSetFontTable(lpMV, lpView->hFont); /* and bind the MV to the scrolling region pane */ if (Pane_Open(lpView->hSR, lpView->hView, lpMV, SR_PANE) != 0) return(ERR_FAILED); /* now set up the MV for the non-scrolling region */ if ((lpMV = lpMVDuplicate(lpMV, &err)) == 0) { View_Close(lpView); return(err); } if (Pane_Open(lpView->hNSR, lpView->hView, lpMV, NSR_PANE) != 0) { View_Close(lpView); return(ERR_FAILED); } SetView(lpView->hView, lpView); lpView->isOpen = TRUE; lpView->isInitial = TRUE; lpView->iIndex = -1; /* if there is a Popup in effect, get rid of it */ Pane_CloseAllPopups(0); /* set the whole View to the Contents topic */ View_Contents(lpView); /* default to a white brush for painting Search highlights */ lpView->hHitBrush = CreateSolidBrush(RGB(255,255,255)); return(0); } /**************************************************************************** ** FUNCTION: View_Close ** ** PURPOSE: Close the View. This includes closing each of the ** ** associated Panes, freeing the font table memory, and closing ** ** the Title. ** ** COMMENTS: ** ****************************************************************************/ void View_Close(LPVIEW lpView) { /* is the view really open? */ if (!lpView->isOpen) return; if (lpView->hTopicList) TopicListDestroy(lpView->hTopicList); /* cleanup things that are open or allocated */ Pane_Close(lpView->hSR); Pane_Close(lpView->hNSR); TitleClose(lpView->hTitle); DeleteObject(lpView->hHitBrush); lpView->isOpen = FALSE; lpView->lpGroups = MV_FreeGroups(lpView->lpGroups); lpView->lpKeyIndex = MV_FreeGroups(lpView->lpKeyIndex); if (lpView->hWordWheel) WordWheelClose(lpView->hWordWheel); lpView->hWordWheel = 0; lpView->iIndex = -1; /* this may go away when we do inter-file jumps */ MV_CleanupHistory(); MV_FreePrintMarks(); return; } /**************************************************************************** ** FUNCTION: View_Layout ** ** PURPOSE: Layout the topic in the View. This includes figuring out ** ** how the window needs to be sized and the SR and NSR regions ** ** laid out. ** ** COMMENTS: ** ****************************************************************************/ int View_Layout(LPVIEW lpView) { int err; LPMV lpMVsr, lpMVnsr; POINT ptNSR; RECT rect; int x, y, yNSR; /* has the View been opened? */ if (lpView == 0 || !lpView->isOpen) return(ERR_FAILED); /* get the MV pointers for each Pane */ lpMVsr = GetPaneMV(lpView->hSR); lpMVnsr = GetPaneMV(lpView->hNSR); /* get the size of the View window */ GetClientRect(lpView->hView, &rect); x = rect.right - rect.left; y = rect.bottom - rect.top; yNSR = 0; /* * If the window is minimized, or if either dimension goes to 0, * don't bother to Lay it out. Furthermore, things break if you do ... * the Pane size goes to 0 and the MediaView ptGetMVSize call pins to 0. */ if (x == 0 || y == 0) return(0); /* turn off updates until all the screen work is done */ SendMessage(lpView->hView, WM_SETREDRAW, FALSE, 0); /* layout the NSR */ if (fMVHasNSR(lpMVsr)) { /* * We cannot get the NSR size without doing a layout (Realize) first. * Let the NSR use up what it needs of the client rectangle, then * allocate the rest to the SR. */ fMVRealize(lpMVnsr, &rect, (LPERR)&err); ptNSR = ptMVGetSize(lpMVnsr); yNSR = min(y, ptNSR.y); MoveWindow(lpView->hNSR, 0, 0, x, yNSR, TRUE); /* * the NSR layout needs to supress the Realize in Pane_Layout, * hence the FALSE argument. */ Pane_Layout(lpView->hNSR, FALSE); ShowWindow(lpView->hNSR, SW_SHOW); } else ShowWindow(lpView->hNSR, SW_HIDE); /* size the scrolling region, allowing for a possible NSR */ if (fMVHasSR(lpMVsr)) { MoveWindow(lpView->hSR, 0, yNSR, x, y - yNSR, TRUE); /* the TRUE argument causes the fMVRealize to happen */ Pane_Layout(lpView->hSR, TRUE); ShowWindow(lpView->hSR, SW_SHOW); } else ShowWindow(lpView->hSR, SW_HIDE); /* force the repainting now */ SendMessage(lpView->hView, WM_SETREDRAW, TRUE, 0); InvalidateRect(lpView->hView, 0, TRUE); return(0); } /**************************************************************************** ** FUNCTION: View_Init ** ** PURPOSE: setup initial sizes on SR and NSR Panes ** ** COMMENTS: ** ****************************************************************************/ void View_Init(LPVIEW lpView) { int nsrH = 0; int x, y; RECT rect; GetClientRect(GetParent(lpView->hView), &rect); x = rect.right - rect.left; y = rect.bottom - rect.top; nsrH = y / 5; ShowScrollBar(lpView->hNSR, SB_BOTH, FALSE); MoveWindow(lpView->hNSR, 0, 0, x, nsrH, TRUE); MoveWindow(lpView->hSR, 0, nsrH, x, y - nsrH, TRUE); } /**************************************************************************** ** FUNCTION: View_SetTopic ** ** PURPOSE: Given a VA (address), set the view to that topic ** ** COMMENTS: ** ** Setting the topic at the view level keeps the Scrolling and ** ** non-Scrolling Panes in synch. ** ****************************************************************************/ BOOL View_SetTopic(LPVIEW lpView, VA va, long scroll, int source) { /* Topic Exit ... do any specialized handling for topic exit */ if (!lpView->isInitial && source != SET_FROM_PRINT && source != SET_FROM_SOURCE) View_TopicExit(lpView, source); lpView->isInitial = FALSE; /* jump to the new topic */ Pane_SetAddress(lpView->hNSR, va, scroll); Pane_SetAddress(lpView->hSR, va, scroll); /* and update the display */ View_Layout(lpView); /* Topic Entry ... do any specialized handling for topic entry */ if (source != SET_FROM_PRINT && source != SET_FROM_PRINT && source != SET_FROM_SOURCE) View_TopicEntry(lpView); /* if the source window is active, set its title to the Topic title */ if (lpView->lpApp->showSource && source != SET_FROM_SOURCE) MV_SourceUpdate(View_ValidMV(lpView)); return(TRUE); } /**************************************************************************** ** FUNCTION: View_Contents ** ** PURPOSE: Set the view to the contents topic. ** ** COMMENTS: ** ****************************************************************************/ void View_Contents(LPVIEW lpView) { VA va; if (!lpView->isOpen) return; /* get the VA of the Contents topic */ va = vaGetContents(lpView->hTitle); /* set the address; this will also do the layout */ View_SetTopic(lpView, va, 0, SET_FROM_OTHER); } /**************************************************************************** ** FUNCTION: View_HotspotHighlights ** ** PURPOSE: Set hotspot highlighting for the View ** ** COMMENTS: ** ****************************************************************************/ void View_HotspotHighlights(LPVIEW lpView, int OnOff) { ERR err; /* set hotspot highlighting for each Pane */ fMVHighlightHotspots(GetPaneMV(lpView->hSR), OnOff, &err); fMVHighlightHotspots(GetPaneMV(lpView->hNSR), OnOff, &err); } /**************************************************************************** ** FUNCTION: View_TextColor ** ** PURPOSE: Set the text color for all of the panes ** ** COMMENTS: ** ****************************************************************************/ void View_TextColor(LPVIEW lpView, COLORREF color) { /* set the text color in both panes */ MVSetTextColor(GetPaneMV(lpView->hSR), color); MVSetTextColor(GetPaneMV(lpView->hNSR), color); /* force the repainting */ View_Layout(lpView); } /**************************************************************************** ** FUNCTION: View_TopicEntry ** ** PURPOSE: Things to do upon topic entry. ** ** COMMENTS: ** ****************************************************************************/ int View_TopicEntry(LPVIEW lpView) { LPMV lpMV = View_ValidMV(lpView); int statusP, statusN; /* * Any topic entry code goes here. For instance, * the application could use topic entry data (! footnote) * which would be retrieved here with the hMVGetData call. */ /* * determine whether there are any Next or Prev topics in the group * and grey out the UI appropriately. */ statusP = (addrMVGetPrev(lpMV) != addrNil); statusN = (addrMVGetNext(lpMV) != addrNil); UI_UpdateEnable(statusP, statusN); return(0); } /**************************************************************************** ** FUNCTION: View_TopicExit ** ** PURPOSE: Things to do upon topic exit. ** ** COMMENTS: ** ****************************************************************************/ int View_TopicExit(LPVIEW lpView, int source) { /* add the topic to the history list */ MV_AddToHistory(lpView, source); return(0); } /**************************************************************************** ** FUNCTION: View_NextPrev ** ** PURPOSE: Jump to the next or previous topic in the browse group ** ** COMMENTS: ** ****************************************************************************/ BOOL View_NextPrev(LPVIEW lpView, int type) { LPMV lpMV = View_ValidMV(lpView); ADDR addr; VA va; /* if there is a Next or Prev, jump to it */ if (type == IDC_NEXT) { if ((addr = addrMVGetNext(lpMV)) == addrNil) return(FALSE); } else { if ((addr = addrMVGetPrev(lpMV)) == addrNil) return(FALSE); } /* we have an address, convert to a VA and set the topic */ va = vaConvertAddr(lpView->hTitle, addr); View_SetTopic(lpView, va, 0, SET_FROM_OTHER); return(TRUE); } /**************************************************************************** ** FUNCTION: View_GetHighlights ** ** PURPOSE: Trace the MV back to the View and get search highlight ** ** information. ** ** COMMENTS: ** ****************************************************************************/ BOOL View_GetHighlights(LPMV lpMV, LPHANDLE lpHdl) { LPVIEW lpView; HWND hWnd = hwndMVGetWindow(lpMV); ERR err; /* walk back to get the underlying view */ while (GetPaneType(hWnd) == POPUP_PANE) hWnd = GetPaneParent(hWnd); hWnd = GetPaneParent(hWnd); lpView = GetView(hWnd); /* set the brush for Search highlights */ hMVSetHighlightLook(lpMV, lpView->hHitBrush, R2_XORPEN, &err); /* retrieve the highlight info from the View */ *lpHdl = lpView->hHighlights; return(lpView->showHits); } /**************************************************************************** ** FUNCTION: View_CopyTopic ** ** PURPOSE: Copy the text of the topic to the clipboard. ** ** COMMENTS: ** ** The clipboard takes control of the memory handle and will ** ** free it appropriately. ** ****************************************************************************/ int View_CopyTopic(LPVIEW lpV) { HANDLE hMem; /* copy the information to the clipboard */ hMem = View_GetWholeTopic(lpV); OpenClipboard(lpV->hView); EmptyClipboard(); SetClipboardData(CF_TEXT, hMem); CloseClipboard(); return(0); } /**************************************************************************** ** FUNCTION: View_GetWholeTopic ** ** PURPOSE: Get the text of all of the subTopics into one buffer. ** ** COMMENTS: ** ** If there are other subTopics, this routine needs to handle ** ** all of them. ** ****************************************************************************/ HANDLE View_GetWholeTopic(LPVIEW lpV) { HANDLE hMemSR = 0; HANDLE hMemNSR = 0; LPSTR lpSR, lpNSR; LPMV lpMVsr = GetPaneMV(lpV->hSR); LPMV lpMVnsr = GetPaneMV(lpV->hNSR); long len = 0; ERR err; /* get both the SR and NSR regions (if they exist) */ if (fMVHasSR(lpMVsr)) hMemSR = hMVCopyMedia(lpMVsr, &err); if (fMVHasNSR(lpMVnsr)) hMemNSR = hMVCopyMedia(lpMVnsr, &err); /* 3 cases ... only SR, only NSR, both */ if (hMemSR && !hMemNSR) return(hMemSR); if (hMemNSR && !hMemSR) return(hMemNSR); /* otherwise, coalesce them into one block of memory */ lpNSR = GlobalLock(hMemNSR); len = _fstrlen(lpNSR); lpSR = GlobalLock(hMemSR); len += _fstrlen(lpSR); hMemNSR = GlobalReAlloc(hMemNSR, len+1, GHND); _fstrcat(lpNSR, lpSR); /* free the SR memory. The NSR memory will be owned by the clipboard */ GlobalFree(hMemSR); return(hMemNSR); } /**************************************************************************** ** FUNCTION: View_CopySelection ** ** PURPOSE: See if either of the Panes can copy a selection to the ** ** clipboard. ** ** COMMENTS: ** ****************************************************************************/ BOOL View_CopySelection(LPVIEW lpV) { /* see if either subTopic has a selection */ if (Pane_CopySelection(GetPaneMV(lpV->hSR))) return(TRUE); if (Pane_CopySelection(GetPaneMV(lpV->hNSR))) return(TRUE); return(FALSE); } /**************************************************************************** ** FUNCTION: View_KeyDown ** ** PURPOSE: Process the keydown message. ** ** clipboard. ** ** COMMENTS: ** ** Determine which Pane it applies to and pass it on. ** ****************************************************************************/ void View_KeyDown(LPVIEW lpV, HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMV lpMv; if (!lpV->isOpen) return; /* give the Scrolling region preference */ lpMv = GetPaneMV(lpV->hSR); if (fMVHasSR(lpMv)) Pane_KeyDown(lpV->hSR, wParam, lParam); else Pane_KeyDown(lpV->hNSR, wParam, lParam); } /**************************************************************************** ** FUNCTION: View_ValidMV ** ** PURPOSE: Get a valid MV pointer from the View ** ** COMMENTS: ** ****************************************************************************/ LPMV View_ValidMV(LPVIEW lpV) { /* * In order to get a valid VA from MediaView, we need to use * a "valid" lpMV. This means that we ask with an lpMV for * a subTopic that actually exists (use hSR if it has a scrolling * region, etc.). We are guaranteed that we have at least one * subTopic (sometimes both). */ if (fMVHasSR(GetPaneMV(lpV->hSR))) return(GetPaneMV(lpV->hSR)); else return(GetPaneMV(lpV->hNSR)); } /**************************************************************************** ** FUNCTION: View_SetMagnifier ** ** PURPOSE: Set the magnification factor for the View. ** ** COMMENTS: ** ** fMVSetMagnifier destroys the VA in the lpMV, so we need to save ** ** it around the calls. ****************************************************************************/ int View_SetMagnifier(LPVIEW lpV, int mag) { ERR err = 0; VA va; int subTopic; long scroll; LPMV lpMV; /* remember the VA */ lpMV = View_ValidMV(lpV); MVGetAddress(lpMV, &va, &subTopic, &scroll); /* set the magnifier */ if (fMVSetMagnifier(GetPaneMV(lpV->hNSR), mag, &err)) if (fMVSetMagnifier(GetPaneMV(lpV->hSR), mag, &err)) View_Layout(lpV); /* reset the address */ View_SetTopic(lpV, va, scroll, SET_FROM_WORKAROUND); return(err); } /**************************************************************************** ** FUNCTION: View_GetMagnifier ** ** PURPOSE: Get the magnification factor for the view ** ** COMMENTS: ** ****************************************************************************/ int View_GetMagnifier(LPVIEW lpV) { int mag; mag = iMVGetMagnifier(GetPaneMV(lpV->hNSR)); return(mag); } /**************************************************************************** ** FUNCTION: View_GetCharStyles ** ** PURPOSE: Display the charracter styles for thhis view. ** ** COMMENTS: ** ****************************************************************************/ int View_GetCharStyles(LPVIEW lpV, HWND hWnd) { int i; int numCharStyles; ERR err; char szStyleName[STYLESIZE+1]; LOGFONT lf; /* for each character style ... note that they are 1 based */ numCharStyles = iCharStyleCount(lpV->hFont, &err); for (i = 0; i < numCharStyles; ++i) { if (fGetCharStyle(lpV->hFont, /* the View font table */ &i, /* Character Style number */ szStyleName, /* returns the Style Name */ &lf, /* returned font information */ 0, 0, 0, 0, &err) == FALSE) return(err); SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szStyleName); } return(0); } /**************************************************************************** ** FUNCTION: View_SetCharStyles ** ** PURPOSE: Use the Format common dialog to change the character ** ** style. ** COMMENTS: ** ****************************************************************************/ int View_SetCharStyles(LPVIEW lpV, HWND hWnd) { ERR err; char szStyleName[STYLESIZE+1]; LOGFONT lf; int selNumber; CHOOSEFONT cf; BYTE bMoreAttr; RGBTRIPLE RGBfore, RGBback; int iSubSuper; /* get the selected style name */ selNumber = (int)SendMessage(hWnd, LB_GETCURSEL, 0, 0); SendMessage(hWnd, LB_GETTEXT, selNumber, (long)(LPSTR)szStyleName); /* get the font information (-1 says get it by name) */ selNumber = -1; if (fGetCharStyle(lpV->hFont, /* the View font table */ &selNumber, /* Character Style number (by reference) */ szStyleName, /* the Style Name */ &lf, /* returned font information */ &RGBfore, /* current forground color */ &RGBback, /* current background color */ &iSubSuper, /* sub-script/super-script */ &bMoreAttr, /* additional attributes */ &err) == FALSE) /* set up the CHOOSEFONT for the common dialog */ memset(&cf, 0, sizeof(CHOOSEFONT)); cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = hWnd; cf.lpLogFont = &lf; cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT; cf.nFontType = SCREEN_FONTTYPE; cf.rgbColors = RGB(RGBfore.rgbtRed, RGBfore.rgbtGreen, RGBfore.rgbtBlue); /* if there is a font, tell MediaView about it */ if (ChooseFont(&cf)) { /* convert COLORREF back to RGBTRIPLE */ RGBfore.rgbtRed = GetRValue(cf.rgbColors); RGBfore.rgbtGreen = GetGValue(cf.rgbColors); RGBfore.rgbtBlue = GetBValue(cf.rgbColors); /* Change the style. selNumber is set from the Get call */ if (fSetCharStyle(lpV->hFont, /* the View font table */ selNumber, /* Character Style number (by value) */ NULL, /* the Style Name */ &lf, /* returned font information */ &RGBfore, /* text color */ NULL, NULL, &bMoreAttr, /* additional attributes */ &err) == FALSE) return(err); /* Redo the display. This is a special case ... MediaView keeps * a font table cache that will not get updated until we either * change address or UnRealize the MV structure. */ MVUnrealize(GetPaneMV(lpV->hNSR)); MVUnrealize(GetPaneMV(lpV->hSR)); View_Layout(lpV); } else { /* don't exit the dialog */ return((int)CommDlgExtendedError()); } return(0); } /**************************************************************************** ** FUNCTION: View_GroupEntry ** ** PURPOSE: Things to do each time a group is entered. ** ** COMMENTS: ** ** This routine is never actually called, but exists to demonstrate ** ** how an application can determine what groups the current topic ** ** belongs to. ****************************************************************************/ int View_GroupEntry(LPVIEW lpV) { LPGROUPUI lpG = lpV->lpGroups; HTLIST htList; long count, i; long topicNumber = lMVTopicNumber(View_ValidMV(lpV)); while (lpG && lpG->title) { /* is the current topic in this group? */ htList = TopicListLoad(lpV->hTitle, lpG->name); /* for each topic number in the group */ count = TopicListLength(lpV->hTopicList); for (i = 0; i < count; ++i) { if (topicNumber == TopicListLookup(lpV->hTopicList, i)) break; } /* did we find it? */ if (i != count) { /* * yes ... the current topic is in this group. * Insert code here. */ ;;;; } /* next group */ } return(0); }