/* pane.c - This file contains the multi-pane handling routines. * * Copyright (c) 1991-, Microsoft Corporation. * All rights reserved. */ #include "packager.h" #include #include "dialogs.h" //#define OLESVR_SUPPORT /* enable support for OLE server files */ #define DRAG_EMBED 2 // Ctrl + Drag #define DRAG_LINK 6 // Ctrl + Shift + Drag static HBRUSH hbrBlack; // Black brush static HCURSOR hcurSplit; static HWND hwndDesc; static HWND hwndInsertIcon = NULL; static HWND hwndView = NULL; static INT cxBorder; // WS_BORDER border width static INT cyBorder; static INT cxFudge = 0; // Fudge factors for good appearance static INT cyFudge = 0; static INT cxMinWidth; static INT cxView; static INT cxSplit; // Splitter bar width static INT cxPict; static INT cxDesc; static INT cxInsertIcon; static INT cxMin[CCHILDREN]; static INT cyHeight; static INT xSplit = 0; static CHAR szButton[] = "button"; static CHAR szStatic[] = "static"; static CHAR szPaneClass[] = "PaneClass"; static CHAR szSubtitleClass[] = "SubTitleClass"; static CHAR szDescription[CBMESSAGEMAX]; static CHAR szView[CBMESSAGEMAX]; static CHAR szPicture[CBMESSAGEMAX]; static CHAR szInsertIcon[CBMESSAGEMAX]; static CHAR szDropFile[CBPATHMAX]; static BOOL fHScrollEnable = FALSE; static BOOL fVScrollEnable = FALSE; static BOOL MakeWindows(VOID); static INT GetTextLen(HDC hdc, LPSTR lpstr); static VOID RecalibrateScroll(INT iPane, DWORD lParam); static VOID Undo(INT iPane); static VOID CalcWindows(BOOL fFirst); static INT Constrain(INT x, INT right); static VOID CopyOther(VOID); /* InitPaneClasses() - Do application "global" initialization. * * This function registers the window classes used by the application. * Returns: TRUE if successful. */ BOOL InitPaneClasses( VOID ) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = SubtitleWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszMenuName = MAKEINTRESOURCE(ID_APPLICATION); wc.lpszClassName = szSubtitleClass; if (!RegisterClass(&wc)) return FALSE; wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = PaneWndProc; wc.cbClsExtra = 0; // Reserve space for the item specific data handle wc.cbWndExtra = sizeof(LPVOID); wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szPaneClass; if (!RegisterClass(&wc)) return FALSE; return TRUE; } /* InitPanes() - Handles the instance-specific initialization. * * This function creates the main application window. * Returns: TRUE if successful. */ BOOL InitPanes( VOID ) { LOGFONT lf; CHARSETINFO csinfo; LCID lcid = GetThreadLocale(); DWORD dwCp = GetACP(); hbrBlack = GetStockObject(BLACK_BRUSH); hcurSplit = LoadCursor(ghInst, MAKEINTRESOURCE(SPLIT)); gcxIcon = GetSystemMetrics(SM_CXICON); gcyIcon = GetSystemMetrics(SM_CYICON); SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE); SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, &gcxArrange, FALSE); SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, &gcyArrange, FALSE); // ANSI app needs to make sure it has the right charset for text rendering if (TranslateCharsetInfo(&dwCp, &csinfo, TCI_SRCCODEPAGE)) lf.lfCharSet = (BYTE) csinfo.ciCharset; // Lock down font size to 8 point size since we won't adjust window size lf.lfHeight = -MulDiv(8, giYppli, 72); lf.lfWidth = 0; ghfontTitle = CreateFontIndirect(&lf); if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_CHINESE || PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_JAPANESE) lf.lfWeight = FW_NORMAL; else lf.lfWeight = FW_BOLD; ghfontChild = CreateFontIndirect(&lf); if (!(ghfontTitle || ghfontChild)) { if (ghfontTitle) DeleteObject(ghfontTitle); return FALSE; } LoadString(ghInst, IDS_CONTENT, gszCaption[CONTENT], CBMESSAGEMAX); LoadString(ghInst, IDS_VIEW, szView, CBMESSAGEMAX); LoadString(ghInst, IDS_DESCRIPTION, szDescription, CBMESSAGEMAX); LoadString(ghInst, IDS_PICTURE, szPicture, CBMESSAGEMAX); LoadString(ghInst, IDS_APPEARANCE, gszCaption[APPEARANCE], CBMESSAGEMAX); LoadString(ghInst, IDS_INSERTICON, szInsertIcon, CBMESSAGEMAX); // Create the window panes if (!MakeWindows()) return FALSE; CalcWindows(TRUE); // Give the focus to the content pane PostMessage(ghwndPane[CONTENT], WM_LBUTTONDOWN, 0, 0L); return TRUE; } /* EndPaneInstance() - Instance-specific termination code. */ VOID EndPanes( VOID ) { if (ghfontTitle) DeleteObject(ghfontTitle); if (ghfontChild) DeleteObject(ghfontChild); } /* MakeWindows() - Make the window panes. */ static BOOL MakeWindows( VOID ) { if (ghwndBar[CONTENT] = CreateWindow(szSubtitleClass, gszCaption[CONTENT], WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, ghwndFrame, NULL, ghInst, NULL)) { hwndView = CreateWindow(szStatic, szView, WS_CHILD | WS_VISIBLE | SS_LEFT | SS_CENTERIMAGE, 0, 0, 0, 0, ghwndBar[CONTENT], NULL, ghInst, NULL); hwndDesc = CreateWindow(szButton, szDescription, WS_CHILD | BS_AUTORADIOBUTTON | WS_VISIBLE | WS_GROUP, 0, 0, 0, 0, ghwndBar[CONTENT], (HMENU)IDM_DESC, ghInst, NULL); ghwndPict = CreateWindow(szButton, szPicture, WS_CHILD | BS_AUTORADIOBUTTON | WS_VISIBLE, 0, 0, 0, 0, ghwndBar[CONTENT], (HMENU)IDM_PICT, ghInst, NULL); if (hwndView && hwndDesc && ghwndPict) { // Use the appropriate dialog font SendMessage(ghwndBar[CONTENT], WM_SETFONT, (WPARAM)ghfontChild, TRUE); SendMessage(hwndView, WM_SETFONT, (WPARAM)ghfontChild, TRUE); SendMessage(hwndDesc, WM_SETFONT, (WPARAM)ghfontChild, TRUE); SendMessage(ghwndPict, WM_SETFONT, (WPARAM)ghfontChild, TRUE); CheckRadioButton(ghwndBar[CONTENT], IDM_PICT, IDM_DESC, IDM_DESC); EnableWindow(ghwndPict, FALSE); } else { goto Error; } } else { goto Error; } if (ghwndBar[APPEARANCE] = CreateWindow(szSubtitleClass, gszCaption[APPEARANCE], WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, ghwndFrame, NULL, ghInst, NULL)) { hwndInsertIcon = CreateWindow(szButton, szInsertIcon, WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 0, 0, 0, 0, ghwndBar[APPEARANCE], (HMENU)IDM_INSERTICON, ghInst, NULL); if (hwndInsertIcon) { SendMessage(ghwndBar[APPEARANCE], WM_SETFONT, (WPARAM)ghfontChild, TRUE); SendMessage(hwndInsertIcon, WM_SETFONT, (WPARAM)ghfontChild, TRUE); } else { goto Error; } } else { goto Error; } ghwndPane[APPEARANCE] = CreateWindowEx(WS_EX_CLIENTEDGE, szPaneClass, NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, ghwndFrame, NULL, ghInst, NULL); ghwndPane[CONTENT] = CreateWindowEx(WS_EX_CLIENTEDGE, szPaneClass, NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, ghwndFrame, NULL, ghInst, NULL); if (!ghwndPane[APPEARANCE] || !ghwndPane[CONTENT]) goto Error; EnableScrollBar(ghwndPane[APPEARANCE], SB_HORZ, ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[APPEARANCE], SB_VERT, ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[CONTENT], SB_HORZ, ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[CONTENT], SB_VERT, ESB_DISABLE_BOTH); DragAcceptFiles(ghwndPane[CONTENT], TRUE); return TRUE; Error: if (ghwndBar[CONTENT]) { if (hwndView) DestroyWindow(hwndView); if (hwndDesc) DestroyWindow(hwndDesc); if (ghwndPict) DestroyWindow(ghwndPict); DestroyWindow(ghwndBar[CONTENT]); } if (ghwndBar[APPEARANCE]) { if (hwndInsertIcon) DestroyWindow(hwndInsertIcon); DestroyWindow(ghwndBar[APPEARANCE]); } if (ghwndPane[APPEARANCE]) DestroyWindow(ghwndPane[APPEARANCE]); if (ghwndPane[CONTENT]) DestroyWindow(ghwndPane[CONTENT]); return FALSE; } /* SubtitleWndProc() - "Appearance" and "Content" bar window procedure. */ LRESULT CALLBACK SubtitleWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps; RECT rcCaption; INT iPane; iPane = (hWnd == ghwndBar[CONTENT]); switch (msg) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_INSERTICON: Raise(APPEARANCE); DeletePane(APPEARANCE, FALSE); if (gptyUndo[APPEARANCE] != ICON) glpobj[APPEARANCE] = IconCreateFromFile(""); else glpobj[APPEARANCE] = IconClone(glpobjUndo[APPEARANCE]); if (glpobj[APPEARANCE]) gpty[APPEARANCE] = ICON; if (glpobj[APPEARANCE] && IconDialog(glpobj[APPEARANCE])) { InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); Dirty(); } else { IconDelete(glpobj[APPEARANCE]); gpty[APPEARANCE] = NOTHING; glpobj[APPEARANCE] = NULL; SendMessage(ghwndPane[APPEARANCE], WM_COMMAND, IDM_UNDO, 0); } break; case IDM_DESC: if (!IsDlgButtonChecked(ghwndBar[CONTENT], IDM_DESC)) CheckRadioButton(ghwndBar[CONTENT], IDM_PICT, IDM_DESC, IDM_DESC); if (fHScrollEnable) EnableScrollBar(ghwndPane[iPane], SB_HORZ, ESB_DISABLE_BOTH); if (fVScrollEnable) EnableScrollBar(ghwndPane[iPane], SB_VERT, ESB_DISABLE_BOTH); InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); goto defProcess; case IDM_PICT: if (!IsDlgButtonChecked(ghwndBar[CONTENT], IDM_PICT) && IsWindowEnabled(GetDlgItem(ghwndBar[CONTENT], IDM_PICT))) CheckRadioButton(ghwndBar[CONTENT], IDM_PICT, IDM_DESC, IDM_PICT); if (fHScrollEnable) EnableScrollBar(ghwndPane[iPane], SB_HORZ, ESB_ENABLE_BOTH); if (fVScrollEnable) EnableScrollBar(ghwndPane[iPane], SB_VERT, ESB_ENABLE_BOTH); InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); // Fall through default: defProcess: if (GetTopWindow(ghwndFrame) != ghwndPane[iPane]) { if (gbDBCS) { /* 4-Oct-93 #2701 v-katsuy */ //win31#1203: 12/26/92:fixing Focus Line Scroll //delete Focus Rect on another pane InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); } BringWindowToTop(ghwndPane[iPane]); InvalidateRect(ghwndBar[APPEARANCE], NULL, TRUE); InvalidateRect(ghwndBar[CONTENT], NULL, TRUE); if (LOWORD(wParam) == IDM_PICT || LOWORD(wParam) == IDM_DESC) UpdateWindow(ghwndPane[CONTENT]); } } break; case WM_LBUTTONDOWN: if (GetTopWindow(ghwndFrame) != ghwndPane[iPane]) SendMessage(ghwndPane[iPane], WM_LBUTTONDOWN, 0, 0); break; case WM_PAINT: { HFONT hfontOld; GetClientRect(hWnd, &rcCaption); BeginPaint(hWnd, &ps); if (GetTopWindow(ghwndFrame) == ghwndPane[iPane]) { SetTextColor(ps.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetBkColor(ps.hdc, GetSysColor(COLOR_HIGHLIGHT)); } else { SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW)); } hfontOld = SelectObject(ps.hdc, ghfontChild); rcCaption.left += cxFudge; DrawText(ps.hdc, gszCaption[iPane], -1, &rcCaption, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP); SelectObject(ps.hdc, hfontOld); EndPaint(hWnd, &ps); } break; case WM_SIZE: if (iPane == APPEARANCE) { if (hwndInsertIcon) { GetClientRect(hWnd, &rcCaption); SetWindowPos(hwndInsertIcon, 0, rcCaption.right - cxInsertIcon, cyFudge, 0, 0, SWP_NOSIZE | SWP_NOZORDER); InvalidateRect(ghwndBar[APPEARANCE], NULL, TRUE); } } else { if (hwndView) { BOOL bChinese = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE; GetClientRect(hWnd, &rcCaption); SetWindowPos(hwndView, 0, bChinese ? rcCaption.right - cxDesc - cxPict - cxView - 15 : rcCaption.right - cxDesc - cxPict - cxView, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(hwndDesc, 0, rcCaption.right - cxDesc - cxPict, cyFudge, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(ghwndPict, 0, rcCaption.right - cxPict, cyFudge, 0, 0, SWP_NOSIZE | SWP_NOZORDER); InvalidateRect(ghwndBar[CONTENT], NULL, TRUE); } } break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0L; } static INT GetTextLen( HDC hdc, LPSTR lpstr ) { SIZE Size; GetTextExtentPoint32(hdc, lpstr, lstrlen(lpstr), &Size); return Size.cx + (cxFudge * 2); } LRESULT CALLBACK PaneWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { BOOL fFocus; LPVOID lpobjTemp; PAINTSTRUCT ps; RECT rc; CHAR szFile[CBPATHMAX]; INT iOld; INT iPane; INT iPos; INT Max; INT Min; INT nBar; iPane = (hwnd == ghwndPane[CONTENT]); switch (msg) { case WM_HSCROLL: case WM_VSCROLL: // If not the content pane in picture mode, break if (gpty[iPane] == PICTURE && iPane == CONTENT && !IsDlgButtonChecked(ghwndBar[CONTENT], IDM_PICT)) break; // Can't scroll anything but cmd line and picture if (gpty[iPane] != PICTURE && gpty[iPane] != CMDLINK) break; nBar = (msg == WM_HSCROLL ? SB_HORZ : SB_VERT); iOld = iPos = GetScrollPos(hwnd, nBar); switch (LOWORD(wParam)) { case SB_LINEUP: iPos--; break; case SB_LINEDOWN: iPos++; break; case SB_PAGEUP: case SB_PAGEDOWN: GetClientRect(hwnd, &rc); if (LOWORD(wParam) == SB_PAGEUP) iPos -= (rc.bottom - rc.top + 1); else iPos += (rc.bottom - rc.top + 1); break; case SB_THUMBPOSITION: iPos = (INT)HIWORD(wParam); break; } // Make sure that iPos is in the range GetScrollRange(hwnd, nBar, &Min, &Max); if (iPos < Min) iPos = Min; if (iPos > Max) iPos = Max; SetScrollPos(hwnd, nBar, iPos, TRUE); if (msg == WM_HSCROLL) ScrollWindow(hwnd, iOld - iPos, 0, NULL, NULL); else ScrollWindow(hwnd, 0, iOld - iPos, NULL, NULL); UpdateWindow(hwnd); break; case WM_LBUTTONDOWN: if (GetTopWindow(ghwndFrame) != hwnd) { BringWindowToTop(hwnd); InvalidateRect(ghwndBar[APPEARANCE], NULL, TRUE); InvalidateRect(ghwndBar[CONTENT], NULL, TRUE); InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); } break; case WM_PAINT: GetClientRect(hwnd, &rc); BeginPaint(hwnd, &ps); if (fFocus = (ghwndPane[iPane] == GetTopWindow(ghwndFrame))) { SetTextColor(ps.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetBkColor(ps.hdc, GetSysColor(COLOR_HIGHLIGHT)); } else { SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW)); } switch (gpty[iPane]) { case CMDLINK: CmlDraw(glpobj[iPane], ps.hdc, &rc, GetScrollPos(hwnd, SB_HORZ), fFocus); break; case PEMBED: EmbDraw(glpobj[iPane], ps.hdc, &rc, fFocus); break; case ICON: IconDraw(glpobj[iPane], ps.hdc, &rc, fFocus, 0, 0); break; case PICTURE: PicDraw(glpobj[iPane], ps.hdc, &rc, GetScrollPos(hwnd, SB_HORZ), GetScrollPos(hwnd, SB_VERT), hwnd == ghwndPane[APPEARANCE] || IsDlgButtonChecked(ghwndBar[CONTENT], IDM_PICT), fFocus); break; default: FillRect(ps.hdc, &rc, ghbrBackground); break; } EndPaint(hwnd, &ps); break; case WM_FIXSCROLL: GetClientRect(hwnd, &rc); lParam = ((DWORD)rc.bottom << 16) | (DWORD)rc.right; // Fall through case WM_SIZE: if (gpty[iPane] == PICTURE || gpty[iPane] == CMDLINK) RecalibrateScroll(iPane, (DWORD)lParam); break; case WM_DESTROY: DeletePane(iPane, TRUE); break; case WM_DROPFILES: { BYTE bKeyState = 0; // Retrieve the file name DragQueryFile((HANDLE)wParam, 0, szDropFile, CBPATHMAX); DragFinish((HANDLE)wParam); // We got dropped on, so bring ourselves to the top BringWindowToTop(ghwndFrame); BringWindowToTop(hwnd); // See what the user wants us to do bKeyState = ((GetKeyState(VK_SHIFT) < 0) << 2) | ((GetKeyState(VK_CONTROL) < 0) << 1) | ((GetKeyState(VK_MENU) < 0)); switch (bKeyState) { case DRAG_LINK: PostMessage(hwnd, WM_COMMAND, IDM_LINKFILE, 0L); break; case DRAG_EMBED: default: PostMessage(hwnd, WM_COMMAND, IDM_EMBEDFILE, 0L); break; } break; } case WM_LBUTTONDBLCLK: // Alt + Double Click = Properties if (gpty[iPane] == PICTURE && GetKeyState(VK_MENU) < 0) { wParam = IDM_LINKS; } else { if (gpty[iPane] == PEMBED) { // // If the server is a OLE server, we want to activate in // OLE fashion. But from users perspective it should not // look like an object. So for non-objects double-click // implies show the server. We should try to do the same // thing while editing ole server files. // wParam = IDD_EDIT; } else { wParam = IDD_PLAY; } } msg = WM_COMMAND; lParam = 0; // Fall through case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_COPY: case IDM_CUT: switch (gpty[iPane]) { case PICTURE: PicCopy(glpobj[iPane]); default: if (iPane == APPEARANCE) CopyOther(); break; } if (LOWORD(wParam) == IDM_COPY) break; // Fall through to delete the selection case IDM_CLEAR: DeletePane(iPane, FALSE); break; case IDM_LINKS: { LONG objtype; OleQueryType(((LPPICT)glpobj[iPane])->lpObject, &objtype); if (objtype == OT_LINK) DialogBoxAfterBlock(MAKEINTRESOURCE(DTPROP), ghwndPane[iPane], fnProperties); break; } case IDM_LINKFILE: if(SUCCEEDED(StringCchCopy(szFile, ARRAYSIZE(szFile), szDropFile))) { wParam = IDM_PASTELINK; goto CreateFromFile; } break; case IDM_EMBEDFILE: if(SUCCEEDED(StringCchCopy(szFile, ARRAYSIZE(szFile), szDropFile))) { wParam = IDM_PASTE; goto CreateFromFile; } break; case IDM_PASTE: case IDM_PASTELINK: // Try to paste a file name from the File Manager if (iPane == CONTENT) { HANDLE hdata; LPSTR lpstrFile; if (IsClipboardFormatAvailable(gcfFileName)) { if (!OpenClipboard(ghwndFrame)) break; if (!(hdata = GetClipboardData(gcfFileName)) || !(lpstrFile = GlobalLock(hdata))) { CloseClipboard(); break; } StringCchCopy(szFile, ARRAYSIZE(szFile), lpstrFile); GlobalUnlock(hdata); CloseClipboard(); CreateFromFile: #ifdef OLESVR_SUPPORT if (IsOleServerDoc (szFile)) { lpobjTemp = PicFromFile((wParam == IDM_PASTE), szFile); if (!lpobjTemp) { ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED); break; } goto StuffNewObject; } else { #endif DeletePane(CONTENT, FALSE); if (wParam == IDM_PASTE) { if (glpobj[CONTENT] = EmbCreate(szFile)) gpty[CONTENT] = PEMBED; } else { if (glpobj[CONTENT] = CmlCreateFromFilename(szFile, TRUE)) gpty[CONTENT] = CMDLINK; } #ifdef OLESVR_SUPPORT } #endif InvalidateRect(ghwndPane[CONTENT], NULL, TRUE); Dirty(); if (!gpty[APPEARANCE]) { if (glpobj[APPEARANCE] = IconCreateFromFile(szFile)) { gpty[APPEARANCE] = ICON; InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); } } break; } } // Not a file name, try to paste an OLE object if (!(lpobjTemp = PicPaste(LOWORD(wParam) == IDM_PASTE, gszCaption[iPane]))) { ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED); break; } #ifdef OLESVR_SUPPORT StuffNewObject: #endif DeletePane(iPane, FALSE); glpobj[iPane] = lpobjTemp; gpty[iPane] = PICTURE; SendMessage(ghwndPane[iPane], WM_FIXSCROLL, 0, 0L); InvalidateRect(ghwndPane[iPane], NULL, TRUE); Dirty(); if (iPane == CONTENT) { EnableWindow(ghwndPict, TRUE); if (!gpty[APPEARANCE]) { if (glpobj[APPEARANCE] = IconCreateFromObject( ((LPPICT)glpobj[iPane])->lpObject)) { gpty[APPEARANCE] = ICON; InvalidateRect(ghwndPane[APPEARANCE], NULL, TRUE); } } } Dirty(); break; case IDD_EDIT: /* Edit the icon form */ case IDD_PLAY: switch (gpty[iPane]) { case CMDLINK: CmlActivate(glpobj[iPane]); break; case PEMBED: EmbActivate(glpobj[iPane], LOWORD(wParam)); break; case PICTURE: PicActivate(glpobj[iPane], LOWORD(wParam)); break; default: break; } break; case IDD_UPDATE: /* Update the (link) object */ if (gpty[iPane] == PICTURE) PicUpdate(glpobj[iPane]); break; case IDD_FREEZE: /* Make the object static */ if (gpty[iPane] == PICTURE) PicFreeze(glpobj[iPane]); break; case IDD_CHANGE: if (gpty[iPane] == PICTURE) PicChangeLink(glpobj[iPane]); break; case IDM_UNDO: Undo(iPane); break; case IDD_AUTO: /* Change the (link) update options */ case IDD_MANUAL: if (gpty[iPane] == PICTURE && !PicSetUpdateOptions(glpobj[iPane], LOWORD(wParam))) break; case IDM_LINKDONE: /* The link update has completed */ PostMessage(ghwndError, WM_REDRAW, 0, 0L); break; default: break; } break; default: return (DefWindowProc(hwnd, msg, wParam, lParam)); } return 0; } LRESULT CALLBACK SplitterFrame( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { RECT rc; switch (msg) { case WM_SIZE: if (wParam != SIZEICONIC && ghwndBar[APPEARANCE]) { GetClientRect(hWnd, &rc); // Make sure the splitter bar is still valid xSplit = Constrain(xSplit, rc.right); CalcWindows(FALSE); // Invalidate the splitter bar, forcing a repaint rc.left = xSplit - cxSplit / 2 - cxBorder; rc.right = xSplit + cxSplit / 2 + cxBorder; InvalidateRect(hWnd, &rc, TRUE); } break; case WM_PAINT: { PAINTSTRUCT ps; RECT rcBlack; BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rc); SetRect(&rcBlack, xSplit - cxSplit / 2 - cxBorder, rc.top, xSplit + cxSplit / 2 + cxBorder, rc.top + cyHeight + cyBorder); FillRect(ps.hdc, &rcBlack, hbrBlack); SetRect(&rcBlack, xSplit - cxSplit / 2 - cxBorder, rc.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1, xSplit + cxSplit / 2 + cxBorder, rc.bottom); FillRect(ps.hdc, &rcBlack, hbrBlack); EndPaint(hWnd, &ps); break; } case WM_GETMINMAXINFO: { LPPOINT rgpt = (LPPOINT)lParam; rgpt[3].x = cxMinWidth; rgpt[3].y = cyHeight * 6; break; } case WM_LBUTTONDOWN: { MSG msg1; INT x; INT y; INT dy; HDC hdc; HCURSOR hcurOld; if (IsIconic(hWnd)) break; x = LOWORD(lParam); GetClientRect(hWnd, &rc); y = 0; dy = rc.bottom; // Constrain the splitter bar... x = Constrain(x, rc.right); hdc = GetDC(hWnd); // split bar loop PatBlt(hdc, x - cxSplit / 2, y, cxSplit, dy, PATINVERT); SetCapture(hWnd); hcurOld = SetCursor(hcurSplit); while (GetMessage(&msg1, NULL, 0, 0)) { if (msg1.message >= WM_MOUSEFIRST && msg1.message <= WM_MOUSELAST) { if (msg1.message == WM_LBUTTONUP || msg1.message == WM_LBUTTONDOWN) break; if (msg1.message == WM_MOUSEMOVE) { ScreenToClient(hWnd, &msg1.pt); x = Constrain(x, rc.right); // erase old PatBlt(hdc, x - cxSplit / 2, y, cxSplit, dy, PATINVERT); // put down new x = Constrain(msg1.pt.x, rc.right); PatBlt(hdc, x - cxSplit / 2, y, cxSplit, dy, PATINVERT); } } else { DispatchMessage(&msg1); } } SetCursor(hcurOld); ReleaseCapture(); // Constrain the splitter bar... x = Constrain(x, rc.right); // erase old PatBlt(hdc, x - cxSplit / 2, y, cxSplit, dy, PATINVERT); ReleaseDC(hWnd, hdc); if (msg1.wParam != VK_ESCAPE) { xSplit = x; CalcWindows(FALSE); InvalidateRect(ghwndBar[APPEARANCE], NULL, TRUE); InvalidateRect(ghwndBar[CONTENT], NULL, TRUE); } break; } default: return FALSE; } return TRUE; } VOID DeletePane( INT iPane, BOOL fDeleteUndo ) { // Delete the last Undo object if (glpobjUndo[iPane]) DeletePaneObject(glpobjUndo[iPane], gptyUndo[iPane]); // If we don't wish to keep an undo, delete the object too! if (fDeleteUndo) { DeletePaneObject(glpobj[iPane], gpty[iPane]); gptyUndo[iPane] = NOTHING; glpobjUndo[iPane] = NULL; } else { gptyUndo[iPane] = gpty[iPane]; glpobjUndo[iPane] = glpobj[iPane]; } // Handle the buttons and such if (gpty[iPane] == PICTURE || gpty[iPane] == CMDLINK) { CHAR szUndoName[CBMESSAGEMAX]; EnableScrollBar(ghwndPane[iPane], SB_HORZ, ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[iPane], SB_VERT, ESB_DISABLE_BOTH); if (gpty[iPane] == PICTURE) { if (iPane == CONTENT) { CheckRadioButton(ghwndBar[CONTENT], IDM_PICT, IDM_DESC, IDM_DESC); EnableWindow(ghwndPict, FALSE); } // If the Undo object isn't deleted already, rename it if (!fDeleteUndo) { if(SUCCEEDED(StringCchPrintf(szUndoName, ARRAYSIZE(szUndoName), szUndo, gszCaption[iPane]))) { OleRename(((LPPICT)glpobjUndo[iPane])->lpObject, szUndoName); } } } } glpobj[iPane] = NULL; gpty[iPane] = NOTHING; if (IsWindow(ghwndPane[iPane])) InvalidateRect(ghwndPane[iPane], NULL, TRUE); } static VOID RecalibrateScroll( INT iPane, DWORD lParam ) { INT cxDel; INT cyDel; BOOL bDesc = FALSE; LPPICT lppict = (LPPICT)glpobj[iPane]; // Compute the amount of scrolling possible cxDel = lppict->rc.right - lppict->rc.left - (INT)(lParam & 0xffff); cyDel = lppict->rc.bottom - lppict->rc.top - (INT)(lParam >> 16); // Normalize the scroll bar lengths if (cxDel < 0) cxDel = 0; if (cyDel < 0) cyDel = 0; if (iPane == CONTENT) { bDesc = IsDlgButtonChecked(ghwndBar[iPane], IDM_DESC); fHScrollEnable = cxDel; fVScrollEnable = cyDel; } EnableScrollBar(ghwndPane[iPane], SB_HORZ, (cxDel && !bDesc) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[iPane], SB_VERT, (cyDel && !bDesc) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH); // Ensure that the thumb is at a meaningful position if (GetScrollPos(ghwndPane[iPane], SB_HORZ) > cxDel) SetScrollPos(ghwndPane[iPane], SB_HORZ, cxDel, TRUE); if (GetScrollPos(ghwndPane[iPane], SB_VERT) > cyDel) SetScrollPos(ghwndPane[iPane], SB_VERT, cyDel, TRUE); } static VOID Undo( INT iPane ) { DWORD ot; LPPICT lppict; LPVOID lpobjTemp; INT ptyTemp; if (gpty[iPane] == PICTURE) { lppict = glpobj[iPane]; // Close the old object if (lppict->lpObject) { OleQueryType(lppict->lpObject, &ot); if (ot != OT_STATIC) Error(OleClose(lppict->lpObject)); } OleRename(lppict->lpObject, gszTemp); } if (gptyUndo[iPane] == PICTURE) { lppict = glpobjUndo[iPane]; // Try to reconnect the new object if it's a link if (lppict->lpObject) { OleQueryType(lppict->lpObject, &ot); if (ot == OT_LINK && Error(OleReconnect(lppict->lpObject))) ErrorMessage(E_FAILED_TO_RECONNECT_OBJECT); } OleRename(lppict->lpObject, gszCaption[iPane]); } if (gpty[iPane] == PICTURE) { CHAR szUndoName[CBMESSAGEMAX]; lppict = glpobj[iPane]; if(SUCCEEDED(StringCchPrintf(szUndoName, ARRAYSIZE(szUndoName), szUndo, gszCaption[iPane]))) { OleRename(lppict->lpObject, szUndoName); } } // Handle the buttons and enable/disable scroll bars // Going from picture to non-picture, disable all special things if (gptyUndo[iPane] != PICTURE && gpty[iPane] == PICTURE) { if (iPane == CONTENT) { CheckRadioButton(ghwndBar[CONTENT], IDM_PICT, IDM_DESC, IDM_DESC); EnableWindow(ghwndPict, FALSE); } EnableScrollBar(ghwndPane[iPane], SB_HORZ, ESB_DISABLE_BOTH); EnableScrollBar(ghwndPane[iPane], SB_VERT, ESB_DISABLE_BOTH); } if (gptyUndo[iPane] == PICTURE || gptyUndo[iPane] == CMDLINK) { SendMessage(ghwndPane[iPane], WM_FIXSCROLL, 0, 0L); if (gptyUndo[iPane] == PICTURE) { // Going from non-picture to picture, enable button if (gpty[iPane] != PICTURE && iPane == CONTENT) EnableWindow(ghwndPict, TRUE); } } lpobjTemp = glpobj[iPane]; glpobj[iPane] = glpobjUndo[iPane]; glpobjUndo[iPane] = lpobjTemp; ptyTemp = gpty[iPane]; gpty[iPane] = gptyUndo[iPane]; gptyUndo[iPane] = ptyTemp; InvalidateRect(ghwndPane[iPane], NULL, TRUE); Dirty(); } static VOID CalcWindows( BOOL fFirst ) { if (fFirst) { // Figure out the length of the text strings, and all dimensions HDC hdc = GetWindowDC(ghwndFrame); if (hdc) { cxBorder = GetSystemMetrics(SM_CXBORDER); cyBorder = GetSystemMetrics(SM_CYBORDER); cxFudge = cxBorder * 2; cyFudge = cyBorder * 2; cxSplit = cxBorder * 4; if (gbDBCS) { /* #3963 13-Dec-93 v-katsuy */ /* ORIGINALBUG! Window width calculated for just "&Picture". * This width should be calculate * [Radiobutton] + [Text](not include '&'). */ CHAR szTemp[CBMESSAGEMAX]; LPSTR lpText, lpTemp; for (lpText = szPicture, lpTemp = szTemp; *lpText; ) { if (*lpText == '&') lpText++; else *lpTemp++ = *lpText++; } *lpTemp = 0; cxPict = GetTextLen(hdc, szTemp) + cxFudge * 2 + GetSystemMetrics(SM_CXSIZE); // for radiobutton for (lpText = szDescription, lpTemp = szTemp; *lpText; ) { if (*lpText == '&') lpText++; else *lpTemp++ = *lpText++; } *lpTemp = 0; cxDesc = GetTextLen(hdc, szTemp) + GetSystemMetrics(SM_CXSIZE); // for radiobutton } else { cxPict = GetTextLen(hdc, szPicture) + cxFudge * 2; cxDesc = GetTextLen(hdc, szDescription); } cxView = GetTextLen(hdc, szView); cxInsertIcon = GetTextLen(hdc, szInsertIcon) + cxFudge; cxMin[CONTENT] = cxPict + cxDesc + cxView + GetTextLen(hdc, gszCaption[CONTENT]) + cxFudge; cxMin[APPEARANCE] = cxInsertIcon + GetTextLen(hdc, gszCaption[APPEARANCE]) + cxFudge; cyHeight = GetSystemMetrics(SM_CYMENU) + cyFudge * 2; ReleaseDC(ghwndFrame, hdc); cxMinWidth = cxMin[APPEARANCE] + cxMin[CONTENT] + cxSplit + GetSystemMetrics(SM_CXFRAME) + cxFudge; // Compute all the window sizes that we can SetWindowPos(ghwndFrame, 0, 0, 0, cxMinWidth + cxFudge * 20, cxMinWidth * 7 / 18, SWP_NOMOVE | SWP_NOZORDER); SetWindowPos(hwndInsertIcon, 0, 0, 0, cxInsertIcon - cxFudge, GetSystemMetrics(SM_CYMENU), SWP_NOMOVE | SWP_NOZORDER); SetWindowPos(hwndView, 0, 0, 0, cxView, cyHeight - cyFudge, SWP_NOMOVE | SWP_NOZORDER); SetWindowPos(ghwndPict, 0, 0, 0, (cxPict - cxFudge) << 1, GetSystemMetrics(SM_CYMENU), SWP_NOMOVE | SWP_NOZORDER); SetWindowPos(hwndDesc, 0, 0, 0, cxDesc, GetSystemMetrics(SM_CYMENU), SWP_NOMOVE | SWP_NOZORDER); } } else { RECT rc; GetClientRect(ghwndFrame, &rc); // Move the windows to the appropriate locations SetWindowPos(ghwndBar[APPEARANCE], 0, 0, 0, xSplit - cxSplit / 2 - cxBorder, cyHeight, SWP_NOZORDER); SetWindowPos(ghwndBar[CONTENT], 0, xSplit + cxSplit / 2 + cxBorder, 0, rc.right - (xSplit + cxSplit / 2) + 1 - cxBorder, cyHeight, SWP_NOZORDER); SetWindowPos(ghwndPane[APPEARANCE], 0, -cxBorder, cyHeight, cxBorder + xSplit - cxSplit / 2, rc.bottom + cyBorder - cyHeight, SWP_NOZORDER); SetWindowPos(ghwndPane[CONTENT], 0, xSplit + cxSplit / 2, cyHeight, cxBorder + rc.right - (xSplit + cxSplit / 2) + 1, rc.bottom + cyBorder - cyHeight, SWP_NOZORDER); } } static INT Constrain( INT x, INT right ) { // Constrain the splitter bar... if (x < cxMin[APPEARANCE] + cxSplit / 2 - 1) return cxMin[APPEARANCE] + cxSplit / 2 - 1; else if (x > (right - cxMin[CONTENT] - cxSplit / 2 + 1)) return right - cxMin[CONTENT] - cxSplit / 2 + 1; return x; } /* CopyOther() - Copies the picture in appearance pane * * Returns: none */ static VOID CopyOther( VOID ) { HANDLE hdata; if (OpenClipboard(ghwndFrame)) { Hourglass(TRUE); EmptyClipboard(); if (hdata = GetMF()) SetClipboardData(CF_METAFILEPICT, hdata); CloseClipboard(); Hourglass(FALSE); } } VOID DeletePaneObject( LPVOID lpobj, INT objType ) { switch (objType) { case CMDLINK: CmlDelete(lpobj); break; case PEMBED: EmbDelete(lpobj); break; case ICON: IconDelete(lpobj); break; case PICTURE: PicDelete(lpobj); break; } }