/* * This file contains the MVPaneClass 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" /* Global Variables for Panes */ HWND hCaptureWnd = 0; /* initially un-captured */ LPMV baseMV = 0; /* base of popup chain MV */ /* are we currently selecting? */ int selecting = FALSE; HWND hSelectCapture = 0; /**************************************************************************** ** FUNCTION: Pane_Register ** ** PURPOSE: Register the window class for the Pane ** ** COMMENTS: ** ** The MVPaneClass contains extra bytes for holding Pane data: ** ** - a LPMV (MediaView pointer) ** ** - a Pane type (scrolling, non-scrolling, or popup) ** ** - a parent hWnd ****************************************************************************/ BOOL Pane_Register(HANDLE hInstance) { WNDCLASS wc; /* create the Pane class */ wc.style = CS_DBLCLKS; wc.lpfnWndProc = PaneWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = EXTRA_PANE_SIZE; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = 0; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "MVPaneClass"; if (RegisterClass(&wc) == 0) return(FALSE); return(TRUE); } /**************************************************************************** ** FUNCTION: Pane_Create ** ** PURPOSE: Create a new Pane. ** ** COMMENTS: ** ** Use the Pane_Open call to set up the MediaView and the style. ** ****************************************************************************/ HWND Pane_Create(LPSTR szTitle, HWND hParent, HANDLE hInstance) { HWND hWnd; /* create the Pane window */ hWnd = CreateWindow( "MVPaneClass", szTitle, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, 0, hInstance, 0 ); if (hWnd == 0) return(0); /* make it initially invisible */ ShowWindow(hWnd, SW_HIDE); return(hWnd); } /**************************************************************************** ** FUNCTION: Pane_Open ** ** PURPOSE: Create a new Pane. ** ** COMMENTS: ** ** This call links the MediaView to the Pane and does an initial ** ** layout. ** ****************************************************************************/ int Pane_Open(HWND hWnd, HWND hParentWnd, LPMV lpMV, int type) { ERR err; extern int iKerningBoundary; /* bind the window handle to the MV */ if (!fMVSetWindow(lpMV, hWnd, &err)) return(err); /* store away the MV and the type */ SetPaneMV(hWnd, lpMV); SetPaneType(hWnd, type); /* * The Windows GetParent function will make the main window the parent * of the first Popup. We need the parent to be the base Pane, * so we track all of this outside Windows. */ SetPaneParent(hWnd, hParentWnd); /* set the dwData of the Callback to contain the MV pointer */ fMVSetHotspotCallback(lpMV, (MVCBPROC)Pane_HotspotCallback, lpMV, &err); /* turn on hotspot highlighting if appropriate */ fMVHighlightHotspots(lpMV, bShowHotspots, &err); /* if there is a Kerning Boundary set (from the command line), do it here */ if (iKerningBoundary) MVSetKerningBoundary(lpMV, iKerningBoundary); /* don't display partial lines */ MVHidePartialLines(lpMV, TRUE); return(0); } /**************************************************************************** ** FUNCTION: Pane_Close ** ** PURPOSE: Close the Pane. ** ** COMMENTS: ** ****************************************************************************/ void Pane_Close(HWND hWnd) { LPMV lpMV = GetPaneMV(hWnd); ERR err; HANDLE hHits = hMVGetHighlights(lpMV); /* undo any highlights */ if (hHits) { GlobalFree(hHits); hMVSetHighlights(lpMV, 0, FALSE, &err); } /* cean up the MV memory */ MVDelete(lpMV); /* clean up the hWnd */ SetPaneMV(hWnd, 0); return; } /**************************************************************************** ** FUNCTION: PaneWndProc ** ** PURPOSE: Process messages sent to the Pane. ** ** COMMENTS: ** ****************************************************************************/ long WINAPI PaneWndProc(hWnd, message, wParam, lParam) HWND hWnd; UINT message; WPARAM wParam; LPARAM lParam; { PAINTSTRUCT ps; HDC hDC; switch (message) { case WM_KEYDOWN: /* we only get here when a popup is in effect */ Pane_KeyDown(hWnd, wParam, lParam); break; case WM_LBUTTONDOWN: Pane_MouseLButtonDown(hWnd, wParam, lParam); break; case WM_LBUTTONUP: Pane_MouseLButtonUp(hWnd, wParam, lParam); break; case WM_LBUTTONDBLCLK: Pane_MouseDoubleClick(hWnd, wParam, lParam); break; case WM_MOUSEMOVE: Pane_MouseMove(hWnd, wParam, lParam); break; case WM_SIZE: /* Resizing and layout has already been done by the View */ break; case WM_HSCROLL: Pane_ScrollHorz(hWnd, wParam, lParam); break; case WM_VSCROLL: Pane_ScrollVert(hWnd, wParam, lParam); break; case WM_PAINT: hDC = BeginPaint (hWnd, &ps); Pane_Draw(hWnd, hDC, &(ps.rcPaint)); EndPaint (hWnd, &ps); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0); } /**************************************************************************** ** FUNCTION: Pane_Draw ** ** PURPOSE: Repaint the pane. ** COMMENTS: ** ****************************************************************************/ int Pane_Draw(HWND hWnd, HDC hDC, LPRECT lpR) { ERR err; RECT rect; LPMV lpMV = GetPaneMV(hWnd); if (lpMV == 0) return(ERR_FAILED); if (lpR == NULL) { GetClientRect (hWnd, &rect); lpR = ▭ } if (!fMVApplyToDC (lpMV, hDC, lpR, &err)) return(err); /* the non-scrolling region needs a border at the bottom */ if (GetPaneType(hWnd) == NSR_PANE && fMVHasSR(lpMV)) { MoveToEx(hDC, lpR->left, lpR->bottom-1, NULL); LineTo(hDC, lpR->right, lpR->bottom-1); } return(0); } /**************************************************************************** ** FUNCTION: Pane_Layout ** ** PURPOSE: Realize the Pane ... this does not actually paint, that ** ** is done handling the WM_PAINT message. ** ** COMMENTS: ** ** The doRealize flag is used to suppress the call to fMVRealize. ** ** A non-scrolling Pane will have already called this once to ** ** enable getting the horizontal layout size. Calling fmRealize ** ** again wouldn't hurt anything, but would be inefficient. ** ****************************************************************************/ void Pane_Layout(HWND hWnd, int doRealize) { LPMV lpMV = GetPaneMV(hWnd); ERR err; if (lpMV == 0) return; /* set up (or hide) the search hits for the Pane */ Pane_UpdateHits(lpMV); /* this does the MediaView layout of the subTopic */ if (doRealize) fMVRealize(lpMV, 0, (LPERR)&err); /* if it is a scrolling Pane, set the scroll bar ranges too */ if (GetPaneType(hWnd) == SR_PANE) Pane_ScrollRanges(lpMV, hWnd); return; } /**************************************************************************** ** FUNCTION: Pane_ScrollVert ** ** PURPOSE: handle vertical scrolling (these messages only come ** ** to a scrolling Pane. ** ** COMMENTS: ** ****************************************************************************/ void Pane_ScrollVert(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMV lpMV = GetPaneMV(hWnd); POINT pt; ERR err; int y; int yTop, yBottom; RECT rc; WORD code; WORD pos; /* make sure it is a scrolling Pane */ if (lpMV == 0 || GetPaneType(hWnd) != SR_PANE) return; code = GET_WM_VSCROLL_CODE(wParam, lParam); pos = GET_WM_VSCROLL_POS(wParam, lParam); switch (code) { case SB_TOP: case SB_BOTTOM: case SB_LINEUP: case SB_LINEDOWN: case SB_PAGEUP: case SB_PAGEDOWN: /* * MediaView returns the scroll pixels in pt. * Just set the scroll position and pass them to Windows. */ y = yMVScrollY(lpMV, &pt, &yTop, &yBottom, code, 0, &err); SetScrollPos (hWnd, SB_VERT, y, TRUE); ScrollWindow(hWnd, pt.x, pt.y, 0, 0); /* because we have turned on the MVHidePartialLines, it is * necesssary to repaint the Pane during scrolling. This code * does the minimum repaint. */ if( (code == SB_LINEUP) || (code == SB_PAGEUP) ) { GetClientRect(hWnd, &rc); rc.bottom = rc.top + yTop; InvalidateRect(hWnd, &rc, FALSE); UpdateWindow(hWnd); GetClientRect(hWnd, &rc); rc.top = rc.bottom - yBottom; ScrollWindow(hWnd, 0, yBottom, &rc, NULL); UpdateWindow(hWnd); } else if( (code == SB_LINEDOWN) || (code == SB_PAGEDOWN) ) { GetClientRect(hWnd, &rc); rc.top = rc.bottom - yBottom; InvalidateRect(hWnd, &rc, FALSE); UpdateWindow(hWnd); GetClientRect(hWnd, &rc); rc.bottom = rc.top + yTop; ScrollWindow(hWnd, 0, -yTop, &rc, NULL); UpdateWindow(hWnd); } break; case SB_THUMBPOSITION: /* * pt comes back empty in this case, but the MediaView has * done the proper layout. Redraw the window */ y = yMVScrollY(lpMV, &pt, &yTop, &yBottom, code, pos, (LPERR)&err); SetScrollPos(hWnd, SB_VERT, y, TRUE); RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE); break; case SB_THUMBTRACK: /* track thumb, but don't update the display until SB_THUMBPOSITION */ SetScrollPos (hWnd, SB_VERT, pos, TRUE); break; } } /**************************************************************************** ** FUNCTION: Pane_ScrollHorz ** ** PURPOSE: handle horizontal scrolling (these messages only come ** ** to the scrolling region. ** ** COMMENTS: ** ****************************************************************************/ void Pane_ScrollHorz(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMV lpMV = GetPaneMV(hWnd); POINT pt; int err; int x; WORD code; WORD pos; /* make sure it is a scrolling Pane */ if (lpMV == 0 || GetPaneType(hWnd) != SR_PANE) return; code = GET_WM_HSCROLL_CODE(wParam, lParam); pos = GET_WM_HSCROLL_POS(wParam, lParam); switch (code) { case SB_TOP: case SB_BOTTOM: case SB_LINEUP: case SB_LINEDOWN: case SB_PAGEUP: case SB_PAGEDOWN: /* * MediaView returns the scroll pixels in pt. * Just set the scroll position and pass them to Windows. */ x = xMVScrollX(lpMV, &pt, code, 0, (LPERR)&err); SetScrollPos (hWnd, SB_HORZ, x, TRUE); ScrollWindow(hWnd, pt.x, pt.y, 0, 0); break; case SB_THUMBPOSITION: /* * pt comes back empty in this case, but the MediaView has * done the proper layout. Redraw the window */ x = xMVScrollX(lpMV, &pt, code, pos, (LPERR)&err); SetScrollPos (hWnd, SB_HORZ, x, TRUE); RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE); break; case SB_THUMBTRACK: /* track thumb, but don't update the display until SB_THUMBPOSITION */ SetScrollPos (hWnd, SB_HORZ, pos, TRUE); break; } } /**************************************************************************** ** FUNCTION: Pane_ScrollRanges ** ** PURPOSE: Calculate the new scroll ranges ** ** COMMENTS: ** ****************************************************************************/ void Pane_ScrollRanges(LPMV lpMV, HWND hWnd) { POINT pt, oldpt; int x, y, dummy; /* remember the old positions */ x = xMVGetXScrollPos(lpMV); y = yMVGetYScrollPos(lpMV); /* remember current scrollbar information */ GetScrollRange(hWnd, SB_VERT, &dummy, &oldpt.y); GetScrollRange(hWnd, SB_HORZ, &dummy, &oldpt.x); /* have MediaView tell us the ranges, at pass them to Windows */ pt = ptMVGetScrollSizes(lpMV); SetScrollRange(hWnd, SB_VERT, 0, pt.y, FALSE); SetScrollRange(hWnd, SB_HORZ, 0, pt.x, FALSE); /* if the scrollbar state changed, the client area changed and the * layout must be redone. */ if (pt.x != oldpt.x || pt.y != oldpt.y) { ERR err; fMVRealize(lpMV, 0, (LPERR)&err); } /* Set the thumb position */ SetScrollPos(hWnd, SB_VERT, y, TRUE); SetScrollPos(hWnd, SB_HORZ, x, TRUE); } /**************************************************************************** ** FUNCTION: Pane_MouseMove ** ** PURPOSE: handle the changing of the cursor over hotspots ** ** COMMENTS: ** ****************************************************************************/ void Pane_MouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) { POINT pt; enum CONTENTTYPE eC; LPMV lpMV = GetPaneMV(hWnd); HINSTANCE hInst = GetPaneInstance(hWnd); ERR err; RECT rect; extern HCURSOR curT, curB, curE, curU, curArrow, curIbeam; if (lpMV == 0) return; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); /* if selecting, extend the selection. If we are not already in a * hotspot, don't allow the cursor to change if we cross into one. */ if (selecting) { /* if this is a SR and the mouse moves outside the window, scroll */ if (GetPaneType(hWnd) == SR_PANE) { GetClientRect(hWnd, &rect); if (pt.y < rect.top) Pane_ScrollVert(hWnd, SB_LINEUP, 0); else if (pt.y > rect.bottom) Pane_ScrollVert(hWnd, SB_LINEDOWN, 0); if (pt.x < rect.left) Pane_ScrollHorz(hWnd, SB_LINEUP, 0); else if (pt.x > rect.right) Pane_ScrollHorz(hWnd, SB_LINEDOWN, 0); } /* if over text, select characters up to this point */ if (GetCursor() == curIbeam) MVSelectPoint(lpMV, MVSEL_CHAR, pt, TRUE, (LPERR)&err); return; } /* * If we are positioned over a hotspot, set the cursor * according to the hotspot type. Otherwise, use the IBEAM over * text, or the ARROW over everything else. */ if (fMVOverHotspot(lpMV, pt, &eC)) { switch (eC) { case CONTENT_TEXT: SetCursor(curT); break; case CONTENT_BITMAP: SetCursor(curB); break; case CONTENT_WINDOW: SetCursor(curE); break; default: /* includes CONTENT_UNKNOWN */ SetCursor(curU); break; } } else { /* not a hot spot ... is it over text? */ if (eC == CONTENT_TEXT) SetCursor(curIbeam); else SetCursor(curArrow); } } /**************************************************************************** ** FUNCTION: Pane_MouseLButtonDown ** ** PURPOSE: handle mouse clicks ** ** COMMENTS: ** ** This is the routine that anchors a selection. It also handles ** ** clicks outside an active popup (who will have the mouse ** ** captured). ** ****************************************************************************/ void Pane_MouseLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { ERR err; LPMV lpMV = GetPaneMV(hWnd); HWND hOldWnd = hWnd; POINT pt; extern HCURSOR curIbeam; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); /* if there is a popup active, handle the click here */ if (hCaptureWnd != 0) { /* * returns an hWnd if processing continues, and may pass an * ancestor hWnd. Note that pt will have been adjusted for the new * Client coordinates. */ hWnd = Pane_PopupButtonDown(hWnd, wParam, &pt); } /* The popup window may have disappeared ... don't start selecting */ if (hWnd == 0) { selecting = FALSE; hSelectCapture = 0; return; } /* hWnd might have changed */ lpMV = GetPaneMV(hWnd); /* do not begin selecting unless we are over text */ if (GetCursor() != curIbeam) return; /* anchor the selection (arg 4 == FALSE means start) */ MVSelectPoint(lpMV, MVSEL_CHAR, pt, FALSE, (LPERR)&err); /* * Capture the mouse so that we can detect selections outside the Pane * and force scrolling. */ hSelectCapture = SetCapture(hWnd); selecting = TRUE; } /**************************************************************************** ** FUNCTION: Pane_MouseLButtonUp ** ** PURPOSE: handle mouse up ** ** COMMENTS: ** ** This is a completed "click", so tell MediaView. It also ** ** completes a selection, so process that too. ** ****************************************************************************/ void Pane_MouseLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam) { POINT pt; LPMV lpMV = GetPaneMV(hWnd); ERR err; extern HCURSOR curIbeam; if (lpMV == 0) return; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); /* mark the end of the selection */ if (selecting) { /* restore captured mouse and turn off the selection */ selecting = FALSE; ReleaseCapture(); if (hSelectCapture) SetCapture(hSelectCapture); MVSelectPoint(lpMV, MVSEL_CHAR, pt, TRUE, (LPERR)&err); } /* * If the click started outside the hotspot in text, the cursor * will be the IBEAM. This allows selection of hotspot text as * long as the selection starts outside the hotspot. If this * is really a hotspot click, then tell MediaView about it. */ if (GetCursor() != curIbeam) fMVClickPoint(lpMV, pt); } /**************************************************************************** ** FUNCTION: Pane_MouseDoubleClick ** ** PURPOSE: handle the double click (select a word) ** ** COMMENTS: ** ****************************************************************************/ void Pane_MouseDoubleClick(HWND hWnd, WPARAM wParam, LPARAM lParam) { POINT pt; LPMV lpMV = GetPaneMV(hWnd); ERR err; extern HCURSOR curIbeam; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); /* if we are over text, select the next word */ if (GetCursor() == curIbeam) { MVSelectPoint(lpMV, MVSEL_WORD, pt, FALSE, &err); MVSelectPoint(lpMV, MVSEL_WORD, pt, TRUE, &err); } } /**************************************************************************** ** FUNCTION: Pane_HotspotCallback ** ** PURPOSE: hotspot handler ** ** COMMENTS: ** ** LPMV is actually the Data pointer set by fMVSetHotspotCallback ** ** so theoretically it coudl be any application data. For this ** ** model it is the MV pointer for the Pane. ** ****************************************************************************/ void _export FAR PASCAL Pane_HotspotCallback( LPMV lpMV, /* the Pane MV pointer */ int ht, /* the hotspot type */ RECT rect, /* the rect of the hotspot (in the Pane) */ DWORD dwData) /* hotspot data: Hash code or string handle */ { VA va; HTITLE hTitle; HWND hWnd; if (lpMV == 0) return; switch (ht) { case HOTSPOT_STRING: Pane_HotspotString(lpMV, dwData); break; case HOTSPOT_HASH: /* a jump closes all open popups */ hWnd = Pane_CloseAllPopups(hwndMVGetWindow(lpMV)); /* this hWnd is the base Pane. Use its MV and update the source */ lpMV = GetPaneMV(hWnd); /* convert the hash data into a VA */ hTitle = hMVGetTitle(lpMV, NULL); va = vaConvertHash(hTitle, (HASH)dwData); /* in this model we handle the hotspot at the View level */ hWnd = GetParent(hwndMVGetWindow(lpMV)); if (!View_SetTopic(GetView(hWnd), va, 0, SET_FROM_OTHER)) return; break; case HOTSPOT_POPUPHASH: /* convert the hash data into a VA */ hTitle = hMVGetTitle(lpMV, NULL); va = vaConvertHash(hTitle, (HASH)dwData); if (!Pane_Popup(lpMV, &rect, va)) return; break; case HOTSPOT_UNKNOWN: default: /* handle unknown hotspots here */ break; } } /**************************************************************************** ** FUNCTION: Pane_SetAddress ** ** PURPOSE: Convert the HASH address into a VA and set the topic ** ** COMMENTS: ** ****************************************************************************/ int Pane_SetAddress(HWND hWnd, VA va, long scroll) { ERR err; LPMV lpMV = GetPaneMV(hWnd); int iSubTopic = GetPaneType(hWnd); /* for popups, prefer the scrolling region */ if (iSubTopic == POPUP_PANE) iSubTopic = SR_PANE; /* and set the address ... notice we retrieve the subTopic from the hWnd */ if (!fMVSetAddress(lpMV, va, iSubTopic, scroll, (LPERR)&err)) { /* the failure might have been because this is a popup that only * has a non-scrolling region. Try it again. */ if (GetPaneType(hWnd) == POPUP_PANE) { if (!fMVSetAddress(lpMV, va, NSR_PANE, scroll, (LPERR)&err)) return(err); } else return(err); } /* the display update is done from the view level (the calling routine) */ return(0); } /**************************************************************************** ** FUNCTION: Pane_Popup ** ** PURPOSE: manifest a topic in a POPUP window ** ** COMMENTS: ** ** Popups will cascade. If the mouse is clicked outside an active ** ** popup, this code will clean them up back to the window with the ** ** click. ** ****************************************************************************/ int Pane_Popup(LPMV lpParentMV, LPRECT lpR, VA va) { ERR err; HWND hParentWnd = hwndMVGetWindow(lpParentMV); LPMV lpMV; HWND hWnd; POINT pt, ptxy; int x, y, xLen, yLen; /* create the popup window */ hWnd = CreateWindow( "MVPaneClass", 0, WS_POPUP|WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParentWnd, 0, GetPaneInstance(hParentWnd), 0 ); if (hWnd == 0) return(FALSE); /* * The coordinates are relative to the parent window. * A popup needs to be positioned with Screen coordinates. */ RectClientToScreen(hParentWnd, lpR); /* guess at an initial size and placement so we can Realize the MV */ xLen = yLen = 400; x = lpR->left + (lpR->right - lpR->left) / 2; y = lpR->top + (lpR->bottom - lpR->top) / 2; ShowWindow(hWnd, SW_HIDE); MoveWindow(hWnd, x, y, xLen, yLen, FALSE); /* duplicate the parent MV and set the subTopic address */ if ((lpMV = lpMVDuplicate(lpParentMV, &err)) == 0) return(err); Pane_Open(hWnd, hParentWnd, lpMV, POPUP_PANE); Pane_SetAddress(hWnd, va, 0); /* don't allow magnification on popups ... since there * is no scrolling, the text might disappear. */ fMVSetMagnifier(lpMV, 100, &err); /* do the layout */ Pane_Layout(hWnd, TRUE); /* the Pane is Realized, so now we can get the real size */ pt = ptMVGetSize(lpMV); ptxy = Pane_PopupPosition(hParentWnd, x, y, pt.x, pt.y); MoveWindow(hWnd, ptxy.x, ptxy.y, pt.x, pt.y, TRUE); ShowWindow(hWnd, SW_SHOW); /* remember the base Pane MV */ if (hCaptureWnd == 0) baseMV = lpParentMV; /* popup windows need to process mouseClicks to see when to disappear */ SetCapture(hWnd); hCaptureWnd = hWnd; /* clear any selection int the parent MV */ fMVClearSelection(lpParentMV, &err); /* set the source window to show this topic */ MV_SourceUpdate(lpMV); return(TRUE); } /**************************************************************************** ** FUNCTION: Pane_CloseAllPopups ** ** PURPOSE: If any Popups are in effect, close them. ** ** COMMENTS: ** ****************************************************************************/ HWND Pane_CloseAllPopups(HWND hWnd) { while (hCaptureWnd) hWnd = Pane_UnPopup(hCaptureWnd); return(hWnd); } /**************************************************************************** ** FUNCTION: Pane_UnPopup ** ** PURPOSE: Clean up a popup window. ** ** COMMENTS: ** ** If the parent pane is also a popup, pass the mouse capture to it.** ****************************************************************************/ HWND Pane_UnPopup(HWND hWnd) { LPMV lpMV = GetPaneMV(hWnd); HWND hParentWnd = GetPaneParent(hWnd); if (GetPaneType(hParentWnd) == POPUP_PANE) { SetCapture(hParentWnd); hCaptureWnd = hParentWnd; } else { ReleaseCapture(); hCaptureWnd = 0; } /* cean up the Pane */ Pane_Close(hWnd); DestroyWindow(hWnd); return(hParentWnd); } /**************************************************************************** ** FUNCTION: Pane_PopupButtonDown ** ** PURPOSE: Handle ButtonDown in a popup window. ** ** COMMENTS: ** ** A click outside the popup closes the popup. There may be a ** ** chain of popups that need cleaning up down to the one getting ** ** the click. When called, the top Popup window has the ** ** mouse captured. ** ****************************************************************************/ HWND Pane_PopupButtonDown(HWND hWnd, WPARAM wParam, LPPOINT lpt) { HWND hParentWnd; HWND hTargetWnd; RECT rect; /* was the click inside this popup? */ ClientToScreen(hWnd, lpt); GetWindowRect(hCaptureWnd, &rect); hTargetWnd = WindowFromPoint(*lpt); if (hTargetWnd == hWnd) { MV_SourceUpdate(GetPaneMV(hWnd)); ScreenToClient(hWnd, lpt); return(hWnd); } /* or was it inside an embedded window in this popup? */ else if (PtInRect(&rect, *lpt)) goto sendClick; /* otherwise it was outside the popup */ else { /* No, pass the torch to the parent */ hParentWnd = Pane_UnPopup(hWnd); /* if Parent is a POPUP, have it process the click */ if (GetPaneType(hParentWnd) == POPUP_PANE) { /* Convert the point from screen to the parent's coord system */ ScreenToClient(hParentWnd, lpt); return(Pane_PopupButtonDown(hParentWnd, wParam, lpt)); } } /* the click is outside the popup chain */ ReleaseCapture(); hCaptureWnd = 0; MV_SourceUpdate(baseMV); /* The click was outside the popup chain. Was it inside the base Pane? */ if (hTargetWnd == hParentWnd) { ScreenToClient(hParentWnd, lpt); return(hParentWnd); } /* otherwise it is outside the Pane or in another application */ sendClick: ScreenToClient(hTargetWnd, lpt); /* hTargetWnd might be 0 if the click was on the desktop */ if (hTargetWnd) PostMessage(hTargetWnd, WM_LBUTTONDOWN, wParam, MAKELONG(lpt->x, lpt->y)); SetFocus(hTargetWnd); return(0); } /**************************************************************************** ** FUNCTION: Pane_PopupPosition ** ** PURPOSE: Calculate the best position for a popup window ** ** COMMENTS: ** ** Anchor it to the input x,y (the middle of the hotspot), but ** ** choose an orientation that keeps most of it on the screen. ** ** Note that x and y are already screen coordinates. ** ****************************************************************************/ POINT Pane_PopupPosition(HWND hWnd, int x, int y, int width, int length) { POINT pt; int screenX = GetSystemMetrics(SM_CXSCREEN); int screenY = GetSystemMetrics(SM_CYSCREEN); int Rslop, Bslop; /* how much goes off the screen to the right? */ Rslop = x + width - screenX; if (Rslop > 0 ) x -= width; /* if it still doesn't fit, center it on the screen */ if (x < 0) x = (screenX - width) / 2; /* how much goes off the screen to the bottom? */ Bslop = y + length - screenY; if (Bslop > 0 ) y -= length; /* if it still doesn't fit, center it on the screen */ if (y < 0) y = (screenY - length) / 2; /* and pass them back */ pt.x = x; pt.y = y; return(pt); } /**************************************************************************** ** FUNCTION: RectClientToScreen ** ** PURPOSE: ClientToScreen for both POINTs in the RECT ** ** COMMENTS: ** ****************************************************************************/ void RectClientToScreen(HWND hWnd, LPRECT lpR) { POINT pt; pt.x = lpR->left; pt.y = lpR->top; ClientToScreen(hWnd, &pt); lpR->left = pt.x; lpR->top = pt.y; pt.x = lpR->right; pt.y = lpR->bottom; ClientToScreen(hWnd, &pt); lpR->right = pt.x; lpR->bottom = pt.y; } /**************************************************************************** ** FUNCTION: Pane_UpdateHits ** ** PURPOSE: Calculate whether there is a search hits highlight ** ** handle for this MV and update the MV appropriately. ** ** COMMENTS: ** ****************************************************************************/ void Pane_UpdateHits(LPMV lpMV) { HANDLE hHits = hMVGetHighlights(lpMV); HANDLE hHighlights; int showHits; long topicNumber; ERR err; if (hHits) GlobalFree(hHits); showHits = View_GetHighlights(lpMV, &hHighlights); hHits = 0; if (showHits && hHighlights) { topicNumber = lMVTopicNumber(lpMV); hHits = HighlightsInTopic(hHighlights, topicNumber); } /* this will turn on/off the hits list if it is required */ hMVSetHighlights(lpMV, hHits, hHits != 0, &err); } /**************************************************************************** ** FUNCTION: Pane_CopySelection ** ** PURPOSE: If there is a selection, copy it to the clopboard. ** ** COMMENTS: ** ****************************************************************************/ BOOL Pane_CopySelection(LPMV lpMV) { ERR err; HANDLE hMem; /* is there an active selection? */ if (!fMVIsSelected(lpMV)) return(FALSE); /* MediaView allocates memory, but the clipboard will free it */ if ((hMem = hMVCopySelection(lpMV, &err)) != 0) { OpenClipboard(hwndMVGetWindow(lpMV)); EmptyClipboard(); SetClipboardData(CF_TEXT, hMem); CloseClipboard(); return(TRUE); } return(FALSE); } /**************************************************************************** ** FUNCTION: Pane_KeyDown ** ** PURPOSE: Process the keydown message. ** ** COMMENTS: ** ****************************************************************************/ void Pane_KeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { ERR err; LPMV lpMV = GetPaneMV(hWnd); switch (wParam) { case VK_TAB: /* Tabbing through hot spots */ fMVMoveFocus(lpMV, !(GetKeyState(VK_SHIFT) & 0x8000), &err); break; case VK_RETURN: /* "clicking" on a hot spot */ fMVClickFocus(lpMV, &err); break; /* text selection using keys */ case VK_UP: MVSelectKey(lpMV, MVKEY_UP, (GetKeyState(VK_SHIFT) & 0x8000), &err); break; case VK_DOWN: MVSelectKey(lpMV, MVKEY_DOWN, (GetKeyState(VK_SHIFT) & 0x8000), &err); break; case VK_LEFT: MVSelectKey(lpMV, MVKEY_LEFT, (GetKeyState(VK_SHIFT) & 0x8000), &err); break; case VK_RIGHT: MVSelectKey(lpMV, MVKEY_RIGHT, (GetKeyState(VK_SHIFT) & 0x8000),&err); break; case VK_HOME: MVSelectKey(lpMV, MVKEY_START, (GetKeyState(VK_SHIFT) & 0x8000),&err); break; case VK_END: MVSelectKey(lpMV, MVKEY_END, (GetKeyState(VK_SHIFT) & 0x8000), &err); break; /* scrolling using keys */ case VK_NEXT: Pane_ScrollVert(hWnd, SB_PAGEDOWN, 0); break; case VK_PRIOR: Pane_ScrollVert(hWnd, SB_PAGEUP, 0); break; /* if any popups are in effect, wind them back */ case VK_ESCAPE: Pane_CloseAllPopups(0); break; } } /**************************************************************************** ** FUNCTION: Pane_HotspotString ** ** PURPOSE: Process a hotspot string. ** ** COMMENTS: ** ** This is called by the HotspotCallback routine. This means that ** ** DS is not correct unless you declare this routine (or its ** ** caller as _loadds. String constants are relative to DS. ** ****************************************************************************/ int Pane_HotspotString(LPMV lpMV, DWORD dwData) { LPSTR lp; lp = (LPSTR)dwData; /* process string commands here ... for example, activate all Media Engines */ if (_fstrcmp(lp, "activate") == 0) MVActivate(lpMV, TRUE); return(0); }