Implemented the More Windows... menu item for MDI.
This commit is contained in:
parent
a4b73d43cd
commit
f58d80d17f
|
@ -20,6 +20,12 @@
|
|||
|
||||
#define WM_MDICALCCHILDSCROLL 0x10AC /* this is exactly what Windows uses */
|
||||
|
||||
/* "More Windows..." definitions */
|
||||
#define MDI_MOREWINDOWSLIMIT 9 /* after this number of windows, a "More Windows..."
|
||||
option will appear under the Windows menu */
|
||||
#define MDI_IDC_LISTBOX 100
|
||||
#define MDI_IDS_MOREWINDOWS 13
|
||||
|
||||
extern LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam );
|
||||
|
||||
|
|
|
@ -46,3 +46,18 @@ BEGIN
|
|||
PUSHBUTTON "&No", 7, 304, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
|
||||
END
|
||||
|
||||
MDI_MOREWINDOWS DIALOG FIXED IMPURE 20, 20, 232, 122
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Select Window"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
BEGIN
|
||||
LISTBOX MDI_IDC_LISTBOX, 5, 7, 222, 90, WS_VSCROLL | WS_HSCROLL /* defined in mdi.h */
|
||||
DEFPUSHBUTTON "OK", IDOK, 75, 100, 35, 14
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 120, 100, 35, 14
|
||||
END
|
||||
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
MDI_IDS_MOREWINDOWS "&More Windows..." /* defined in mdi.h */
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "winuser.h"
|
||||
#include "winnls.h"
|
||||
#include "dlgs.h"
|
||||
#include "mdi.h"
|
||||
|
||||
/*
|
||||
* Everything that does not depend on language,
|
||||
|
|
304
windows/mdi.c
304
windows/mdi.c
|
@ -6,11 +6,64 @@
|
|||
* This file contains routines to support MDI (Multiple Document
|
||||
* Interface) features .
|
||||
*
|
||||
* Notes: Fairly complete implementation. Any volunteers for
|
||||
* "More windows..." stuff?
|
||||
*
|
||||
* Notes: Fairly complete implementation.
|
||||
* Also, Excel and WinWord do _not_ use MDI so if you're trying
|
||||
* to fix them look elsewhere.
|
||||
*
|
||||
* Notes on how the "More Windows..." is implemented:
|
||||
*
|
||||
* When we have more than 9 opened windows, a "More Windows..."
|
||||
* option appears in the "Windows" menu. Each child window has
|
||||
* a WND* associated with it, accesible via the children list of
|
||||
* the parent window. This WND* has a wIDmenu member, which reflects
|
||||
* the position of the child in the window list. For example, with
|
||||
* 9 child windows, we could have the following pattern:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Name of the child window pWndChild->wIDmenu
|
||||
* Doc1 5000
|
||||
* Doc2 5001
|
||||
* Doc3 5002
|
||||
* Doc4 5003
|
||||
* Doc5 5004
|
||||
* Doc6 5005
|
||||
* Doc7 5006
|
||||
* Doc8 5007
|
||||
* Doc9 5008
|
||||
*
|
||||
*
|
||||
* The "Windows" menu, as the "More windows..." dialog, are constructed
|
||||
* in this order. If we add a child, we would have the following list:
|
||||
*
|
||||
*
|
||||
* Name of the child window pWndChild->wIDmenu
|
||||
* Doc1 5000
|
||||
* Doc2 5001
|
||||
* Doc3 5002
|
||||
* Doc4 5003
|
||||
* Doc5 5004
|
||||
* Doc6 5005
|
||||
* Doc7 5006
|
||||
* Doc8 5007
|
||||
* Doc9 5008
|
||||
* Doc10 5009
|
||||
*
|
||||
* But only 5000 to 5008 would be displayed in the "Windows" menu. We want
|
||||
* the last created child to be in the menu, so we swap the last child with
|
||||
* the 9th... Doc9 will be accessible via the "More Windows..." option.
|
||||
*
|
||||
* Doc1 5000
|
||||
* Doc2 5001
|
||||
* Doc3 5002
|
||||
* Doc4 5003
|
||||
* Doc5 5004
|
||||
* Doc6 5005
|
||||
* Doc7 5006
|
||||
* Doc8 5007
|
||||
* Doc9 5009
|
||||
* Doc10 5008
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -30,6 +83,7 @@
|
|||
#include "struct32.h"
|
||||
#include "tweak.h"
|
||||
#include "debugtools.h"
|
||||
#include "dlgs.h"
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(mdi);
|
||||
|
||||
|
@ -45,6 +99,8 @@ static BOOL MDI_RestoreFrameMenu(WND *, HWND);
|
|||
|
||||
static LONG MDI_ChildActivate( WND*, HWND );
|
||||
|
||||
static HWND MDI_MoreWindowsDialog(WND*);
|
||||
static void MDI_SwapMenuItems(WND *, UINT, UINT);
|
||||
/* -------- Miscellaneous service functions ----------
|
||||
*
|
||||
* MDI_GetChildByID
|
||||
|
@ -134,15 +190,28 @@ static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
|
|||
/* set correct id */
|
||||
tmpWnd->wIDmenu--;
|
||||
|
||||
n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
|
||||
n = sprintf(buffer, "&%d ",index - clientInfo->idFirstChild);
|
||||
if (tmpWnd->text)
|
||||
lstrcpynA(buffer + n, tmpWnd->text, sizeof(buffer) - n );
|
||||
|
||||
/* change menu */
|
||||
/* change menu if the current child is to be shown in the
|
||||
* "Windows" menu
|
||||
*/
|
||||
if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
|
||||
ModifyMenuA(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
|
||||
index - 1 , buffer );
|
||||
WIN_ReleaseWndPtr(tmpWnd);
|
||||
}
|
||||
|
||||
/* We must restore the "More Windows..." option if there is enough child
|
||||
*/
|
||||
if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
|
||||
{
|
||||
char szTmp[50];
|
||||
LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
|
||||
|
||||
AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
|
||||
}
|
||||
retvalue = TRUE;
|
||||
END:
|
||||
WIN_ReleaseWndPtr(wndPtr);
|
||||
|
@ -248,9 +317,17 @@ static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
|
|||
|
||||
if( ci->nActiveChildren )
|
||||
{
|
||||
INT j = i - ci->nActiveChildren + 1;
|
||||
INT j;
|
||||
LPWSTR buffer = NULL;
|
||||
MENUITEMINFOW mii;
|
||||
INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
|
||||
|
||||
if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
|
||||
nbWindowsMenuItems = ci->nActiveChildren;
|
||||
else
|
||||
nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
|
||||
|
||||
j = i - nbWindowsMenuItems + 1;
|
||||
|
||||
for( ; i >= j ; i-- )
|
||||
{
|
||||
|
@ -355,6 +432,7 @@ static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
|
|||
SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
|
||||
}
|
||||
|
||||
if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
|
||||
/* this menu is needed to set a check mark in MDI_ChildActivate */
|
||||
if (ci->hWindowMenu != 0)
|
||||
AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
|
||||
|
@ -405,7 +483,29 @@ static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
|
|||
/* All MDI child windows have the WS_EX_MDICHILD style */
|
||||
wnd->dwExStyle |= WS_EX_MDICHILD;
|
||||
|
||||
/* If we have more than 9 windows, we must insert the new one at the
|
||||
* 9th position in order to see it in the "Windows" menu
|
||||
*/
|
||||
if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
|
||||
MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
|
||||
|
||||
MDI_MenuModifyItem(w ,hwnd);
|
||||
|
||||
/* Have we hit the "More Windows..." limit? If so, we must
|
||||
* add a "More Windows..." option
|
||||
*/
|
||||
if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
|
||||
{
|
||||
char szTmp[50];
|
||||
LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
|
||||
|
||||
ModifyMenuA(ci->hWindowMenu,
|
||||
ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
|
||||
MF_BYCOMMAND | MF_STRING,
|
||||
ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
|
||||
szTmp);
|
||||
}
|
||||
|
||||
if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
|
||||
ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
|
||||
else
|
||||
|
@ -540,6 +640,8 @@ static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
|
|||
|
||||
if( childPtr )
|
||||
{
|
||||
MDI_MenuDeleteItem(w_parent, child);
|
||||
|
||||
if( child == ci->hwndActiveChild )
|
||||
{
|
||||
MDI_SwitchActiveChild(parent, child, TRUE);
|
||||
|
@ -557,7 +659,6 @@ static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
|
|||
MDI_ChildActivate(w_parent, 0);
|
||||
}
|
||||
}
|
||||
MDI_MenuDeleteItem(w_parent, child);
|
||||
|
||||
WIN_ReleaseWndPtr(childPtr);
|
||||
|
||||
|
@ -621,8 +722,16 @@ static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
|
|||
(LPARAM)hWndChild);
|
||||
/* uncheck menu item */
|
||||
if( clientInfo->hWindowMenu )
|
||||
{
|
||||
WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
|
||||
|
||||
if (wPrevID < MDI_MOREWINDOWSLIMIT)
|
||||
CheckMenuItem( clientInfo->hWindowMenu,
|
||||
wndPrev->wIDmenu, 0);
|
||||
else
|
||||
CheckMenuItem( clientInfo->hWindowMenu,
|
||||
clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* set appearance */
|
||||
|
@ -650,9 +759,16 @@ static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
|
|||
|
||||
/* check menu item */
|
||||
if( clientInfo->hWindowMenu )
|
||||
CheckMenuItem( clientInfo->hWindowMenu,
|
||||
wndPtr->wIDmenu, MF_CHECKED);
|
||||
{
|
||||
/* The window to be activated must be displayed in the "Windows" menu */
|
||||
if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
|
||||
{
|
||||
MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
|
||||
MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
|
||||
}
|
||||
|
||||
CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
|
||||
}
|
||||
/* bring active child to the top */
|
||||
SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
|
||||
|
||||
|
@ -1349,9 +1465,16 @@ LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
|
|||
else
|
||||
{
|
||||
wndPtr = WIN_FindWndPtr(hwndMDIClient);
|
||||
childHwnd = MDI_GetChildByID(wndPtr,wParam );
|
||||
WIN_ReleaseWndPtr(wndPtr);
|
||||
ci = (MDICLIENTINFO*)wndPtr->wExtra;
|
||||
|
||||
if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
|
||||
/* User chose "More Windows..." */
|
||||
childHwnd = MDI_MoreWindowsDialog(wndPtr);
|
||||
else
|
||||
/* User chose one of the windows listed in the "Windows" menu */
|
||||
childHwnd = MDI_GetChildByID(wndPtr,wParam );
|
||||
|
||||
WIN_ReleaseWndPtr(wndPtr);
|
||||
if( childHwnd )
|
||||
SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
|
||||
(WPARAM16)childHwnd , 0L);
|
||||
|
@ -2170,3 +2293,162 @@ TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* "More Windows..." functionality
|
||||
*/
|
||||
|
||||
/* MDI_MoreWindowsDlgProc
|
||||
*
|
||||
* This function will process the messages sent to the "More Windows..."
|
||||
* dialog.
|
||||
* Return values: 0 = cancel pressed
|
||||
* HWND = ok pressed or double-click in the list...
|
||||
*
|
||||
*/
|
||||
|
||||
static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (iMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
WND *pWnd;
|
||||
UINT widest = 0;
|
||||
UINT length;
|
||||
UINT i;
|
||||
WND *pParentWnd = (WND *)lParam;
|
||||
MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
|
||||
HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
|
||||
|
||||
/* Fill the list, sorted by id... */
|
||||
for (i = 0; i < ci->nActiveChildren; i++)
|
||||
{
|
||||
|
||||
/* Find the window with the current ID */
|
||||
for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
|
||||
if (pWnd->wIDmenu == ci->idFirstChild + i)
|
||||
break;
|
||||
|
||||
SendMessageA(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
|
||||
SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
|
||||
length = strlen(pWnd->text);
|
||||
WIN_ReleaseWndPtr(pWnd);
|
||||
|
||||
if (length > widest)
|
||||
widest = length;
|
||||
}
|
||||
/* Make sure the horizontal scrollbar scrolls ok */
|
||||
SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
|
||||
|
||||
/* Set the current selection */
|
||||
SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
/* windows are sorted by menu ID, so we must return the
|
||||
* window associated to the given id
|
||||
*/
|
||||
HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
|
||||
UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
|
||||
WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
|
||||
|
||||
EndDialog(hDlg, pWnd->hwndSelf);
|
||||
return TRUE;
|
||||
}
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg, 0);
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
switch (HIWORD(wParam))
|
||||
{
|
||||
case LBN_DBLCLK:
|
||||
{
|
||||
/* windows are sorted by menu ID, so we must return the
|
||||
* window associated to the given id
|
||||
*/
|
||||
HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
|
||||
UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
|
||||
WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
|
||||
|
||||
EndDialog(hDlg, pWnd->hwndSelf);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* MDI_MoreWindowsDialog
|
||||
*
|
||||
* Prompts the user with a listbox containing the opened
|
||||
* documents. The user can then choose a windows and click
|
||||
* on OK to set the current window to the one selected, or
|
||||
* CANCEL to cancel. The function returns a handle to the
|
||||
* selected window.
|
||||
*/
|
||||
|
||||
static HWND MDI_MoreWindowsDialog(WND* wndPtr)
|
||||
{
|
||||
LPCVOID template;
|
||||
HRSRC hRes;
|
||||
HANDLE hDlgTmpl;
|
||||
|
||||
hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
|
||||
|
||||
if (hRes == 0)
|
||||
return 0;
|
||||
|
||||
hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
|
||||
|
||||
if (hDlgTmpl == 0)
|
||||
return 0;
|
||||
|
||||
template = LockResource( hDlgTmpl );
|
||||
|
||||
if (template == 0)
|
||||
return 0;
|
||||
|
||||
return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
|
||||
(LPDLGTEMPLATEA) template,
|
||||
wndPtr->hwndSelf,
|
||||
(DLGPROC) MDI_MoreWindowsDlgProc,
|
||||
(LPARAM) wndPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* MDI_SwapMenuItems
|
||||
*
|
||||
* Will swap the menu IDs for the given 2 positions.
|
||||
* pos1 and pos2 are menu IDs
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
|
||||
{
|
||||
WND *pWnd;
|
||||
|
||||
for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
|
||||
{
|
||||
if (pWnd->wIDmenu == pos1)
|
||||
pWnd->wIDmenu = pos2;
|
||||
else
|
||||
if (pWnd->wIDmenu == pos2)
|
||||
pWnd->wIDmenu = pos1;
|
||||
}
|
||||
|
||||
WIN_ReleaseWndPtr(pWnd);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue