📄 fakemenu.c
字号:
/*****************************************************************************
*
* FakeMenu.c
*
* Copyright (c) 1997 Microsoft Corporation. All rights reserved.
*
* This source code is only intended as a supplement to
* Microsoft Development Tools, q.v. for detailed
* information regarding the Microsoft samples programs.
*
* Abstract:
*
* Sample program to demonstrate how a program can display a
* popup window which does not deactivate its parent. This
* can be used for things like a magnifying glass window or
* a pseudo-menu.
*
*****************************************************************************/
#include "FakeMenu.h"
#define COMPILE_MULTIMON_STUBS
#include <multimon.h>
/*****************************************************************************
*
* Overview
*
* Normally, pop-up windows receive activation, resulting in the
* owner window being de-activated. To prevent the owner from
* being de-activated, the pop-up window should not receive
* activation.
*
* Since the pop-up window is not active, input messages are not
* delivered to the pop-up. Instead, the input messages must be
* explicitly inspected by the message loop.
*
* Our sample program illustrates how you can create a pop-up
* window that contains a selection of colors.
*
* Right-click in the window to change its background color
* via the fake menu popup. Observe
*
* - The caption of the main application window remains
* highlighted even though the fake-menu is "active".
*
* - The current fake-menu item highlight follows the mouse.
*
* - The keyboard arrows can be used to move the highlight,
* ESC cancels the fake-menu, Enter accepts the fake-menu.
*
* - The fake-menu appears on the correct monitor (for
* multiple-monitor systems).
*
*****************************************************************************/
HINSTANCE g_hinst; /* My hinstance */
HBRUSH g_hbrColor; /* The selected color */
/*****************************************************************************
*
* This is the array of predefined colors we put into the color
* picker.
*
*****************************************************************************/
#define CCLRPREDEF 16 /* 16 predefined colors */
const COLORREF c_rgclrPredef[CCLRPREDEF] = {
RGB(0x00, 0x00, 0x00), /* 0 = black */
RGB(0x80, 0x00, 0x00), /* 1 = maroon */
RGB(0x00, 0x80, 0x00), /* 2 = green */
RGB(0x80, 0x80, 0x00), /* 3 = olive */
RGB(0x00, 0x00, 0x80), /* 4 = navy */
RGB(0x80, 0x00, 0x80), /* 5 = purple */
RGB(0x00, 0x80, 0x80), /* 6 = teal */
RGB(0x80, 0x80, 0x80), /* 7 = gray */
RGB(0xC0, 0xC0, 0xC0), /* 8 = silver */
RGB(0xFF, 0x00, 0x00), /* 9 = red */
RGB(0x00, 0xFF, 0x00), /* A = lime */
RGB(0xFF, 0xFF, 0x00), /* B = yelow */
RGB(0x00, 0x00, 0xFF), /* C = blue */
RGB(0xFF, 0x00, 0xFF), /* D = fuchsia */
RGB(0x00, 0xFF, 0xFF), /* E = cyan */
RGB(0xFF, 0xFF, 0xFF), /* F = white */
};
/*****************************************************************************
*
* COLORPICKSTATE
*
* Structure that records the state of a color-picker pop-up.
*
* A pointer to this state information is kept in the GWLP_USERDATA
* window long.
*
* The iSel field is the index of the selected color, or the
* special value -1 to mean that no item is highlighted.
*
*****************************************************************************/
typedef struct COLORPICKSTATE {
BOOL fDone; /* Set when we should get out */
int iSel; /* Which color is selected? */
int iResult; /* Which color should be returned? */
HWND hwndOwner; /* Our owner window */
} COLORPICKSTATE, *PCOLORPICKSTATE;
#define CYCOLOR 16 /* Height of a single color pick */
#define CXFAKEMENU 100 /* Width of our fake menu */
/*****************************************************************************
*
* ColorPick_GetColorRect
*
* Returns the rectangle that encloses the specified color.
*
*****************************************************************************/
void
ColorPick_GetColorRect(LPRECT prc, int iColor)
{
/*
* Build the "menu" item rect.
*/
prc->left = 0;
prc->right = CXFAKEMENU;
prc->top = iColor * CYCOLOR;
prc->bottom = prc->top + CYCOLOR;
}
/*****************************************************************************
*
* ColorPick_OnCreate
*
* Stash away our state.
*
*****************************************************************************/
LRESULT
ColorPick_OnCreate(HWND hwnd, LPCREATESTRUCT pcs)
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)(pcs->lpCreateParams));
return 0;
}
/*****************************************************************************
*
* ColorPick_OnPaint
*
* Draw the color bars, and put a border around the selected
* color.
*
*****************************************************************************/
void
ColorPick_OnPaint(PCOLORPICKSTATE pcps, HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
if (hdc) {
RECT rcClient;
int iColor;
GetClientRect(hwnd, &rcClient);
/*
* For each of our predefined colors, draw it in a little
* rectangular region, leaving some border so the user can
* see if the item is highlighted or not.
*/
for (iColor = 0; iColor < CCLRPREDEF; iColor++) {
RECT rc;
HBRUSH hbr;
/*
* Build the "menu" item rect.
*/
ColorPick_GetColorRect(&rc, iColor);
/*
* If the item is highlighted, then draw a highlighted
* background.
*/
if (iColor == pcps->iSel) {
FillRect(hdc, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
}
/*
* Now shrink the rectangle by an edge and fill the
* rest with the color of the item itself.
*/
InflateRect(&rc, -GetSystemMetrics(SM_CXEDGE),
-GetSystemMetrics(SM_CYEDGE));
hbr = CreateSolidBrush(c_rgclrPredef[iColor]);
FillRect(hdc, &rc, hbr);
DeleteObject(hbr);
}
EndPaint(hwnd, &ps);
}
}
/*****************************************************************************
*
* ColorPick_ChangeSel
*
* Change the selection to the specified item.
*
*****************************************************************************/
void
ColorPick_ChangeSel(PCOLORPICKSTATE pcps, HWND hwnd, int iSel)
{
/*
* If the selection changed, then
* repaint the items that need repainting.
*/
if (pcps->iSel != iSel) {
RECT rc;
if (pcps->iSel >= 0) {
ColorPick_GetColorRect(&rc, pcps->iSel);
InvalidateRect(hwnd, &rc, TRUE);
}
pcps->iSel = iSel;
if (pcps->iSel >= 0) {
ColorPick_GetColorRect(&rc, pcps->iSel);
InvalidateRect(hwnd, &rc, TRUE);
}
}
}
/*****************************************************************************
*
* ColorPick_OnMouseMove
*
* Track the mouse to see if it is over any of our colors.
*
*****************************************************************************/
void
ColorPick_OnMouseMove(PCOLORPICKSTATE pcps, HWND hwnd, int x, int y)
{
int iSel;
if (x >= 0 && x < CXFAKEMENU &&
y >= 0 && y < CCLRPREDEF * CYCOLOR) {
iSel = y / CYCOLOR;
} else {
iSel = -1;
}
ColorPick_ChangeSel(pcps, hwnd, iSel);
}
/*****************************************************************************
*
* ColorPick_OnLButtonUp
*
* When the button comes up, we are done.
*
*****************************************************************************/
void
ColorPick_OnLButtonUp(PCOLORPICKSTATE pcps, HWND hwnd, int x, int y)
{
/*
* First track to the final location, in case the user
* moves the mouse REALLY FAST and immediately lets go.
*/
ColorPick_OnMouseMove(pcps, hwnd, x, y);
/*
* Set the result to the current selection.
*/
pcps->iResult = pcps->iSel;
/*
* And tell the message loop that we're done.
*/
pcps->fDone = TRUE;
}
/*****************************************************************************
*
* ColorPick_OnKeyDown
*
* If the ESC key is pressed, then abandon the fake menu.
*
* If the Enter key is pressed, then accept the current selection.
*
* If an arrow key is pressed, the move the selection.
*
*****************************************************************************/
void
ColorPick_OnKeyDown(PCOLORPICKSTATE pcps, HWND hwnd, WPARAM vk)
{
switch (vk) {
case VK_ESCAPE:
pcps->fDone = TRUE; /* Abandoned */
break;
case VK_RETURN:
pcps->iResult = pcps->iSel; /* Accept current selection */
pcps->fDone = TRUE;
break;
case VK_UP:
if (pcps->iSel > 0) {
ColorPick_ChangeSel(pcps, hwnd, pcps->iSel - 1);
} else {
ColorPick_ChangeSel(pcps, hwnd, CCLRPREDEF - 1);
}
break;
case VK_DOWN:
if (pcps->iSel + 1 < CCLRPREDEF) {
ColorPick_ChangeSel(pcps, hwnd, pcps->iSel + 1);
} else {
ColorPick_ChangeSel(pcps, hwnd, 0);
}
break;
}
}
/*****************************************************************************
*
* ColorPick_WndProc
*
* Window procedure for the color picker popup.
*
*****************************************************************************/
LRESULT CALLBACK
ColorPick_WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
PCOLORPICKSTATE pcps = (PCOLORPICKSTATE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch (uiMsg) {
case WM_CREATE:
return ColorPick_OnCreate(hwnd, (LPCREATESTRUCT)lParam);
case WM_MOUSEMOVE:
ColorPick_OnMouseMove(pcps, hwnd, (short)LOWORD(lParam),
(short)HIWORD(lParam));
break;
case WM_LBUTTONUP:
ColorPick_OnLButtonUp(pcps, hwnd, (short)LOWORD(lParam),
(short)HIWORD(lParam));
break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
ColorPick_OnKeyDown(pcps, hwnd, wParam);
break;
/*
* Do not activate when somebody clicks on me.
*/
case WM_MOUSEACTIVATE:
return MA_NOACTIVATE;
case WM_PAINT:
ColorPick_OnPaint(pcps, hwnd);
return 0;
}
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
/*****************************************************************************
*
* ColorPick_ChooseLocation
*
* Find a place to put the window so it won't go off the screen
* or straddle two monitors.
*
* x, y = location of mouse click (preferred upper-left corner)
* cx, cy = size of window being created
*
* We use the same logic that real menus use.
*
* - If (x, y) is too high or too far left, then slide onto screen.
* - Use (x, y) if all fits on the monitor.
* - If too low, then slide up.
* - If too far right, then flip left.
*
*****************************************************************************/
void
ColorPick_ChooseLocation(HWND hwnd, int x, int y, int cx, int cy, LPPOINT ppt)
{
HMONITOR hmon;
MONITORINFO minf;
/*
* First get the dimensions of the monitor that contains (x, y).
*/
ppt->x = x;
ppt->y = y;
hmon = MonitorFromPoint(*ppt, MONITOR_DEFAULTTONULL);
/*
* If (x, y) is not on any monitor, then use the monitor that
* the owner window is on.
*/
if (hmon == NULL) {
hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
}
minf.cbSize = sizeof(minf);
GetMonitorInfo(hmon, &minf);
/*
* Now slide things around until they fit.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -