NT4/private/windows/win4help/winhelp/hmessage.c
2020-09-30 17:12:29 +02:00

1820 lines
43 KiB
C

/*****************************************************************************
*
* HMESSAGE.C
*
* Copyright (C) Microsoft Corporation 1990 - 1994.
* All Rights reserved.
*
******************************************************************************
*
* Module Intent
*
* This module contains the helping procedures for the Windows functions
* used frequently (during user interaction) in Help.
*
*****************************************************************************/
#include "help.h"
#pragma hdrstop
#include "inc\printset.h"
#include "inc\hwproc.h"
#include "inc\winclass.h"
_subsystem( WINAPP );
#include "inc\cursor.h"
#include "resource.h"
#include "inc\navpriv.h"
#include "inc\bookmark.h"
#include <string.h>
#ifdef _DEBUG
#include "inc\fsdriver.h"
#include "inc\andriver.h"
#include "inc\btdriver.h"
#endif
/****************************************************************************
* *
* Defines *
* *
****************************************************************************/
#define CB_BORDER 2 // Width of the boarder we draw around note window
/*------------------------------------------------------------*\
| This will cause the pattern to be ORed with the destination.
\*------------------------------------------------------------*/
#define PATMERGE 0x00A000C9
/****************************************************************************
* *
* Prototypes *
* *
*****************************************************************************/
static BOOL STDCALL PaintShadowBackground(HWND, HDC);
static void STDCALL SetSrchHilite (HWND, WORD);
static void INLINE CaptureLock(QDE qde);
INLINE VOID STDCALL ClientRectToScreen(HWND hwnd, RECT *lprect);
#ifdef _DEBUG
VOID STDCALL VDebugAddButton(VOID);
#endif
/****************************************************************************
* *
* Variables *
* *
*****************************************************************************/
#define SHADOW_WIDTH 6
#define SHADOW_HEIGHT 6
static HCURSOR hcurWait;
static HCURSOR hcurHand;
static BOOL fRestoreFocus; // TRUE to restore focus to the caller
static BOOL fRequireDown; // Ignore the next upclick
void STDCALL CatchMouse(HWND hwnd)
{
HWND hwndCur;
HDE hde;
hwndCur = HwndGetEnv();
if (FSetEnv(hwnd) && (hde = HdeGetEnv()) != NULL)
CaptureLock(QdeFromGh(hde));
FSetEnv(hwndCur);
}
void STDCALL FreeMouse(HWND hwnd)
{
HWND hwndCur;
HDE hde;
hwndCur = HwndGetEnv();
if (FSetEnv(hwnd) && (hde = HdeGetEnv()) != NULL && IsCaptureLocked(hde))
ReleaseCaptureLock(hde);
FSetEnv(hwndCur);
}
static void INLINE CaptureLock(QDE qde)
{
qde->fSelectionFlags |= CAPTURE_LOCKED;
ASSERT(qde->hwnd);
SetCapture(qde->hwnd);
}
BOOL STDCALL HandleMouseInput(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hwndCur;
HDE hde;
HDC hdc;
BOOL fResult;
fResult = FALSE;
hwndCur = HwndGetEnv();
if (FSetEnv(hwnd) && (hde = HdeGetEnv()) != NULL) {
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
MouseInFrame(hde, &MAKEPOINTS(lParam), msg, wParam);
if ((hde = HdeGetEnv()) && IsCaptureLocked(hde))
fResult = IsSelected(QdeFromGh(hde));
RelHDC(hwnd, hde, hdc);
}
}
FSetEnv(hwndCur);
return fResult;
}
/*******************
-
- Name: NoteWndProc
*
* Purpose: Main window proc for the note (popup) window
*
* Arguments: Standard Windows proc
*
* Returns: Standard Windows proc
*
******************/
LRESULT EXPORT NoteWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
HDE hde;
HWND hwndCur;
RECT rct;
BOOL fSelected, fMask;
POINTS pts;
POINT pt;
BOOL fSeen = FALSE;
static HWND hwndEmbedded = NULL;
static BOOL fButtonsDown;
#define LEFT_DOWN 0x0001
#define RIGHT_DOWN 0x0002
switch(msg) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (IsWindowVisible(hwnd) && (hde = HdeGetEnv())) {
HDC hdcSave;
hdcSave= QdeFromGh(hde)->hdc;
SetPainting(hde, TRUE);
ASSERT(hwnd == HwndGetEnv());
SetHDC(hde, hdc);
GetClientRect(hwnd, &rct);
rct.top += CB_BORDER + 1;
rct.left += CB_BORDER + 1;
rct.right -= SHADOW_WIDTH + CB_BORDER;
rct.bottom -= SHADOW_HEIGHT + CB_BORDER;
IntersectClipRect(hdc, rct.left, rct.top, rct.right, rct.bottom);
RefreshHde(hde, &ps.rcPaint);
SetHDC(hde, hdcSave);
SetPainting(hde, FALSE);
}
EndPaint(hwnd, &ps);
break;
case WM_ERASEBKGND:
return PaintShadowBackground(hwnd, (HDC) wParam);
case WM_KILLFOCUS:
/*
* This message is sent when a message box is placed on top of the
* glossary box. For example in the case where we could not find the
* target of the glossary jump. This way we take the box down
* immediately.
*/
if ((hde = HdeGetEnv()) && IsCaptureLocked(hde))
FreeMouse(hwnd);
if (!fLockPopup) {
fButtonsDown= 0;
if (!hwndEmbedded)
// MUST BE SendMessage()! Required so that the popup will
// shut down before the jump.
SendMessage(hwnd, WM_CLOSE, 0, 0); // Shut down the note
}
break;
case WM_CLOSE:
FreeMouse(hwnd);
ShowNote(0, NULL, 1, FALSE);
break;
case WM_ACTIVATEAPP:
case WM_ACTIVATE:
// If we get deactivated, then close the popup
if (wParam == WA_INACTIVE && !fLockPopup) {
fButtonsDown = 0;
fRestoreFocus = FALSE;
PostMessage(hwnd, WM_CLOSE, 0, 0); // Shut down the note
}
break;
case WM_SETFOCUS:
CatchMouse(hwnd);
hwndEmbedded = NULL;
break;
case WM_KEYDOWN:
fKeyDownSeen = TRUE;
// Intentionally fall through
case WM_KEYUP:
if (msg == WM_KEYUP) {
if (!fKeyDownSeen)
break; // out of sequence
}
if ((wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_CAPITAL)) {
fKeyDownSeen = FALSE;
break;
}
FExecKey(hwnd, wParam, msg == WM_KEYDOWN);
if (msg == WM_KEYDOWN)
break; // don't dismiss on the down key
else
fKeyDownSeen = FALSE;
if ((wParam == VK_TAB) && !fKeyDown(VK_MENU))
break;
if (msg == WM_KEYUP && HdeGetEnv()) {
fButtonsDown= 0;
if (!fLockPopup)
PostMessage(hwnd, WM_CLOSE, 0, 0); // Shut down the note
}
break;
case WM_SYSKEYUP:
case WM_SYSKEYDOWN:
FExecKey(hwnd, wParam, msg == WM_SYSKEYDOWN);
#if 0
if (HdeGetEnv()) {
fButtonsDown= 0;
ShowNote(NULL, NULL, 1, FALSE);
FreeMouse(hwnd);
}
#endif
break;
// Mouse Handling Rules
//
// The note window has a more complicated policy for handling
// mouse events. This is because it captures the mouse whenever
// it has the input focus. That allows us to dismiss the note window
// at the next mouse click even when that click occurs outside the
// note window. Capturing the mouse makes that possible. However it
// also means that we have to process mouse clicks on behalf of
// embedded windows.
//
// Since we also want to allow text selection in note windows, we've
// changed the dismiss rule to keep the note window up so long as we
// have an active text selection. Note also that we dismiss on button
// up rather than button down.
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
POINTSTOPOINT(pt, MAKEPOINTS(lParam));
hwndCur = ChildWindowFromPoint(hwnd, pt);
fRequireDown = FALSE;
if (hwndCur && hwndCur != hwnd) {
int i;
for (i = 0; i < MAX_BUTTONS; i++) {
if (btndata[i].hwnd == hwndCur) {
hwndEmbedded = hwndCur;
FreeMouse(hwnd);
SendMessage(hwndEmbedded, msg, wParam, lParam);
// fButtonsDown |= (msg == WM_LBUTTONDOWN ||
// msg == WM_LBUTTONDBLCLK) ?
// LEFT_DOWN : RIGHT_DOWN;
return 0;
}
}
}
// intentionally fall through
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
fButtonsDown |= (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) ?
LEFT_DOWN : RIGHT_DOWN;
case WM_MOUSEMOVE:
HandleMouseInput(hwnd, msg, wParam, lParam);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (fRequireDown) {
fRequireDown = FALSE;
break;
}
fSelected = HandleMouseInput(hwnd, msg, wParam, lParam);
fMask= (msg == WM_LBUTTONUP)? LEFT_DOWN : RIGHT_DOWN;
if (!(fButtonsDown & fMask))
break;
else
fButtonsDown &= ~fMask;
#if 0
if (hwndEmbedded && msg == WM_LBUTTONUP) {
POINTSTOPOINT(pt, MAKEPOINTS(lParam));
if (hwndEmbedded == ChildWindowFromPoint(hwnd, pt)) {
fButtonsDown = 0;
FreeMouse(hwnd);
hwndCur = hwndEmbedded;
hwndEmbedded = NULL;
doBtnCmd(hwndCur);
break;
}
hwndEmbedded = NULL;
}
#endif
if (!fSelected && msg != WM_RBUTTONUP) {
fButtonsDown= 0;
if (!fLockPopup)
PostMessage(hwnd, WM_CLOSE, 0, 0); // Shut down the note
}
break;
case WM_TIMER:
hde = HdeGetEnvHwnd(hwnd);
if (hde)
{
DWORD dw;
dw = GetMessagePos();
pt.x = LOWORD(dw);
pt.y = HIWORD(dw);
ScreenToClient(hwnd, &pt);
hdc = GetAndSetHDC(hwnd, hde);
if (hdc)
{
pts.x = (SHORT) pt.x;
pts.y = (SHORT) pt.y;
MouseInFrame(hde, &pts, msg, wParam);
RelHDC(hwnd, hde, hdc);
}
}
break;
case WM_COMMAND:
fLockPopup = TRUE;
FreeMouse(hwnd);
if (LOWORD(wParam) != IDEMBED_BUTTON)
ExecMnuCommand(hwnd, wParam, lParam);
CatchMouse(hwnd);
fLockPopup = FALSE;
break;
case WM_SETCURSOR:
if ((LOWORD(lParam) == HTCLIENT) && (HdeGetEnvHwnd(hwnd)))
return 0L;
default:
// Everything else comes here
return(DefWindowProc(hwnd, msg, wParam, lParam));
break;
}
return(0L);
}
/*******************
-
- Name: PaintShadowBackground
*
* Purpose: Gives a window a shadow background
*
* Arguments: hwnd - window handle of window to add shadow
* hds - handle to display space (DC) for window
* wWidth - Width of the shadow
* height - Height of the shadow
* bFrame - if TRUE, a frame will be painted around "fake" window.
*
* Returns: TRUE iff the shadow is successfully created.
*
******************/
#ifndef NO_PRAGMAS
#pragma data_seg(".text", "CODE")
#endif
static const WORD rgwPatGray[] =
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA };
#ifndef NO_PRAGMAS
#pragma data_seg()
#endif
static BOOL STDCALL PaintShadowBackground(HWND hwnd, HDC hdc)
{
BOOL fStockBrush; // Whether hBrush is a stock object
HBRUSH hBrush;
HBRUSH hbrushTemp;
RECT rct;
RECT rcClient; // Will always be client rectangle
POINT pt;
HBITMAP hbmGray;
HPEN hpen;
COLORREF coBack; // background color to paint
/*
* First the background of the "fake" window is erased leaving the
* desktop where the shadow will be.
*/
GetClientRect(hwnd, &rcClient);
rct = rcClient;
rct.bottom = max(0, rct.bottom - SHADOW_HEIGHT);
rct.right = max(0, rct.right - SHADOW_WIDTH);
// we inherit the background color of the topic window which was active at
// the time the glossary was requested.
if (GetSysColor(COLOR_WINDOW) != RGB(255, 255, 255) ||
GetSysColor(COLOR_WINDOWTEXT) != 0 ||
GetHighContrastFlag())
coBack = GetSysColor(COLOR_WINDOW);
else if (fHelp == POPUP_HELP)
/*
* If we're a stand alone popup and the foreground and background
* window colors are the default and the high-contrast flag hasn't been
* set, then we use the same dithered yellow color that's used for the
* system-help proc4 window.
*/
coBack = RGB(255, 255, 238); // dithered yellow
else
coBack = (clrPopup != (COLORREF) -1) ? clrPopup :
(COLORREF) GetWindowLong(ahwnd[iCurWindow].hwndTopic, GTWW_COBACK);
if (coBack == coNIL)
coBack = GetSysColor(COLOR_WINDOW);
hBrush = CreateSolidBrush(coBack);
if (!hBrush)
return FALSE;
UnrealizeObject(hBrush);
pt.x = pt.y = 0;
ClientToScreen(hwnd, &pt);
SetBrushOrgEx(hdc, pt.x, pt.y, NULL);
FillRect(hdc, &rct, hBrush);
DeleteObject(hBrush);
// Next we create the "window" border
rct = rcClient;
rct.bottom = max(0, rct.bottom - SHADOW_HEIGHT);
rct.right = max(0, rct.right - SHADOW_WIDTH);
FrameRect(hdc, &rct, GetStockObject(BLACK_BRUSH));
InflateRect(&rct, -1, -1);
FrameRect(hdc, &rct, GetStockObject(LTGRAY_BRUSH));
// Now we create the brush for the the shadow
hBrush = 0;
if ((hbmGray = CreateBitmap(8, 8, 1, 1, rgwPatGray)) != NULL) {
hBrush = CreatePatternBrush(hbmGray);
DeleteObject(hbmGray);
fStockBrush = FALSE;
}
// If we cannot create the pattern brush, we try to use a black brush.
if (hBrush == 0) {
if (!(hBrush == GetStockObject(BLACK_BRUSH)))
return FALSE;
fStockBrush = TRUE;
}
SetROP2(hdc, R2_MASKPEN);
SetBkMode(hdc, TRANSPARENT);
if ((hpen = GetStockObject(NULL_PEN)) != 0)
SelectObject(hdc, hpen); // We do not care if this fails
hbrushTemp = SelectObject(hdc, hBrush); // or if this fails, since the
// paint behavior will be okay.
rct = rcClient; // Paint the right side rectangle
rct.top = rct.top + SHADOW_HEIGHT;
rct.left = max(0, rct.right - SHADOW_WIDTH);
PatBlt(hdc, rct.left, rct.top, rct.right - rct.left,
rct.bottom - rct.top, PATMERGE);
rct = rcClient; // Paint the bottom rectangle
rct.top = max(0, rct.bottom - SHADOW_HEIGHT);
rct.left = rct.left + SHADOW_WIDTH;
// Note overlap by one pixel!
rct.right = max(0, rct.right - SHADOW_WIDTH + 1);
PatBlt(hdc, rct.left, rct.top, rct.right - rct.left,
rct.bottom - rct.top, PATMERGE);
// Cleanup brush
if (hbrushTemp != NULL)
SelectObject(hdc, hbrushTemp);
if (!fStockBrush)
DeleteObject(hBrush);
return TRUE;
}
/*******************
-
- Name: ExecMnuCommand
*
* Purpose: Handle a menu selection
*
* Arguments: hwnd - Window handle of caller proc
* wParam, and lParam - wParam and lParam of the calling Windows proc.
*
* Returns: TRUE if it handled the event.
*
******************/
#pragma warning(disable:4113)
BOOL STDCALL ExecMnuCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
int iT;
TLP tlp;
FM fm;
#ifdef _DEBUG
DWORD wCheck;
#endif
#ifdef RAWHIDE
LA la;
RC rc;
HDE hde;
WORD wNavSrchCmd;
#endif
// Everything we do here requires that the dialogs be down.
if (LOWORD(wParam) != IDCANCEL)
if (!FDestroyDialogsHwnd(ahwnd[MAIN_HWND].hwndParent, FALSE))
return FALSE;
switch(LOWORD(wParam)) {
case HLPMENUFILEPRINT:
ASSERT(HdeGetEnv());
PrintHde(HdeGetEnv());
break;
case HLPMENUFILEPRINTSETUP:
DlgPrintSetup(hwnd);
/*------------------------------------------------------------*\
| This was possibly set, if print.setup was called by macro
\*------------------------------------------------------------*/
ClearMacroFlag();
break;
case HLPMENUEDITCOPY:
WaitCursor();
// Any OOM msgboxes are displayed within FCopyToClipboardHwnd itself
FCopyToClipboardHwnd(hwnd);
RemoveWaitCursor();
break;
case HLPMENUEDITCPYSPL:
{
HWND hwndTopic;
HDE hde;
QDE qde, qdeSelection;
hwndTopic= hwndNote? hwndNote : ahwnd[iCurWindow].hwndTopic;
qdeSelection= NULL;
if (!hwndNote) {
hde= HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTitle);
if (hde && FTopicHasNSR(hde)) {
qde= QdeFromGh(hde);
if (IsSelected(qde))
qdeSelection= qde;
}
}
if (!qdeSelection) {
hde = HdeGetEnvHwnd(hwndTopic);
if (hde && FTopicHasSR(hde)) {
qde= QdeFromGh(hde);
if (IsSelected(qde))
qdeSelection= qde;
}
}
WaitCursor();
if (qdeSelection) {
HDC hdc;
HANDLE hCopyText;
int err;
hdc= NULL;
if (!(qdeSelection->hdc))
qdeSelection->hdc = hdc = GetDC(hwndTopic);
hCopyText= hCopySelection(qdeSelection,
qdeSelection->vaStartMark, qdeSelection->vaEndMark,
qdeSelection->lichStartMark, qdeSelection->lichEndMark, &err);
if (hCopyText) {
if (OpenClipboard(hwnd)) {
EmptyClipboard();
SetClipboardData(CF_TEXT, hCopyText);
CloseClipboard();
}
else {
GlobalFree(hCopyText);
PostErrorMessage(wERRS_EXPORT);
}
}
#ifdef _DEBUG
else
OkMsgBox("Copy failed.");
#endif
if (hdc)
{
ReleaseDC(qdeSelection->hwnd, hdc);
qdeSelection->hdc= NULL;
}
}
else
FCopyToClipboardHwnd(hwnd);
RemoveWaitCursor();
break;
}
case HLPMENUFILEEXIT:
QuitHelp();
break;
case HLPMENUFILEOPEN:
fm = DlgOpenFile(hwnd, NULL, NULL);
/*------------------------------------------------------------*\
| This was possibly set, if file.open was called by macro
\*------------------------------------------------------------*/
ClearMacroFlag();
if (fm) {
FM fmCopy;
DestroyAllSecondarys(); // Close any existing secondary windows
szSavedKeyword[0] = '\0';
fmCopy = FmCopyFm(fm);
fDelayShow = TRUE; // REVIEW: necessary?
if (FReplaceHde("", &fm, NULL)) {
if (!hfsGid || !cntFlags.cCntItems) {
INT16 i = 0;
TopicGoto(fGOTO_ITO, (QV)&i);
}
else {
fNoQuit = FALSE;
FWinHelp(fmCopy, HELP_FINDER, 0);
}
}
fDelayShow = FALSE;
ASSERT(!fm);
RemoveFM(&fmCopy);
}
break;
case HLPMENUHELPABOUT:
CallDialog(ABOUTDLG, hwnd, (FARPROC) AboutDlg);
/*------------------------------------------------------------*\
| This was possibly set, if about was called by macro
\*------------------------------------------------------------*/
ClearMacroFlag();
break;
// Under WinHelp version 4.0, we no longer allow the help author to
// disable the Keep Help on Top menu.
case HLPMENUHELPONTOP:
case IDM_HELP_ON_TOP:
if (ahwnd[iCurWindow].fsOnTop == ONTOP_AUTHOREDON)
ahwnd[iCurWindow].fsOnTop = ONTOP_NOTSET;
else
ahwnd[iCurWindow].fsOnTop = ONTOP_AUTHOREDON;
SetWindowPos(ahwnd[iCurWindow].hwndParent,
(cntFlags.fsOnTop == ONTOP_FORCEON ||
(ahwnd[iCurWindow].fsOnTop & ONTOP_AUTHOREDON)) ?
HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
break;
case IDM_DISPLAY_HISTORY:
PostMessage(ahwnd[iCurWindow].hwndParent, MSG_ACTION, IFW_HISTORY, 1L);
break;
case IDM_FONTS_DEFAULT:
cntFlags.iFontAdjustment = 0;
GenerateMessage(MSG_REPAINT, TRUE, 0L);
break;
case IDM_FONTS_BIGGER:
cntFlags.iFontAdjustment = 4;
GenerateMessage(MSG_REPAINT, TRUE, 0L);
break;
case IDM_FONTS_SMALLER:
cntFlags.iFontAdjustment = -4;
GenerateMessage(MSG_REPAINT, TRUE, 0L);
break;
case IDM_ONTOP_DEFAULT:
cntFlags.fsOnTop = ONTOP_NOTSET;
ChangeOnTopState();
break;
case IDM_ONTOP_FORCEON:
cntFlags.fsOnTop = ONTOP_FORCEON;
ChangeOnTopState();
break;
case IDM_ONTOP_FORCEOFF:
cntFlags.fsOnTop = ONTOP_FORCEOFF;
ChangeOnTopState();
break;
case IDM_OVERRIDE_COLORS:
cntFlags.fOverColor = !cntFlags.fOverColor;
if (MessageBox((hwndAnimate ?
hwndAnimate : ahwnd[iCurWindow].hwndParent),
GetStringResource(sidRestartHelp),
pszCaption, MB_YESNO) == IDYES)
QuitHelp();
break;
case IDM_TOPIC_INFO:
CallDialog(IDD_DLG_TOPIC_INFO, hwndNote ?
hwndNote : ahwnd[iCurWindow].hwndParent, TopicInfoDlg);
break;
case IDM_ASK_FIRST:
fDebugState ^= fDEBUGASKFIRST;
#ifdef _DEBUG
CheckMenuItem(GetMenu(ahwnd[iCurWindow].hwndParent), IDM_ASK_FIRST,
(fDebugState & fDEBUGASKFIRST) ? MF_CHECKED : MF_UNCHECKED);
#endif
break;
case HLPMENU_SEARCH_CTX:
if (fHelp != POPUP_HELP)
CallDialog(IDDLG_GET_CTX, ahwnd[iCurWindow].hwndParent, SearchCtxDlg);
break;
case HLPMENUHELPHELP:
// If we are the help app (i.e. executed using WinHelp(), replace the
// current topic in the main window. If not then spawn a new copy of
// help to display HelpOnHelp
JumpHOH(HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic));
break;
case HLPMENUBOOKMARKMORE:
iT = CallDialog(BOOKMARKDLG, hwnd, (FARPROC)BookMarkDlg);
/*------------------------------------------------------------*\
| This was possibly set, if bookmark.more was called by macro
\*------------------------------------------------------------*/
ClearMacroFlag();
/*----------------------------------------------------------------------*\
| The dialog box has returned the index + 1, or 0 if canceled. |
\*----------------------------------------------------------------------*/
if ( iT == 0 )
break;
tlp = JumpToBkMk(HdeGetEnv(), iT - 1);
TopicGoto(fGOTO_TLP, (QV)&tlp);
break;
case MNUBOOKMARK1:
case MNUBOOKMARK2:
case MNUBOOKMARK3:
case MNUBOOKMARK4:
case MNUBOOKMARK5:
case MNUBOOKMARK6:
case MNUBOOKMARK7:
case MNUBOOKMARK8:
case MNUBOOKMARK9:
iT = LOWORD(wParam) - MNUBOOKMARK1;
tlp = JumpToBkMk(HdeGetEnv(), iT);
TopicGoto(fGOTO_TLP, (QV)&tlp);
break;
case HLPMENUBOOKMARKDEFINE:
CallDialog(DEFINEDLG, hwnd, (FARPROC)DefineDlg);
// This was possibly set, if bookmark.define was called by macro
ClearMacroFlag();
break;
case HLPMENUEDITANNOTATE:
EnableMenuItem(hmnuHelp, HLPMENUEDITANNOTATE,
(MF_DISABLED | MF_BYCOMMAND | MF_GRAYED));
if (FDisplayAnnoHde(HdeGetEnv()))
EnableMenuItem(hmnuHelp, HLPMENUEDITANNOTATE, (MF_ENABLED | MF_BYCOMMAND));
break;
#ifdef RAWHIDE
case HLPMENUSRCHHILITEON:
case HLPMENUSRCHHILITEOFF:
wNavSrchCmd = (LOWORD(wParam) == HLPMENUSRCHHILITEON) ? wNavSrchHiliteOn :
wNavSrchHiliteOff;
SetSrchHilite(ahwnd[iCurWindow].hwndTopic, wNavSrchCmd);
if (ahwnd[iCurWindow].hwndTitle)
SetSrchHilite(ahwnd[iCurWindow].hwndTitle, wNavSrchCmd);
break;
case HLPMENUSRCHDO:
if (RcCallSearch(HdeGetEnv(), hwnd) != rcSuccess)
{
// REVIEW: 05-Sep-1993 [ralphw] so, should we do anything here?
break;
}
/*
* We do a relayout here at the current topic position, by calling
* RESIZE, (Admittedly a bit of a hack) in case the topic we are in
* contains matches which should be hilighted.
*/
{
TLP tlpBogus;
/*
* tlpBogus is not used. The current values of the TLP in
* whatever DEs there are, are used.
*/
TopicGoto(fGOTO_TLP_RESIZEONLY, (QV)&tlpBogus);
}
break;
// FTUI menu commands
case HLPMENUSRCHFIRSTTOPIC:
case HLPMENUSRCHLASTTOPIC:
case HLPMENUSRCHPREVTOPIC:
case HLPMENUSRCHNEXTTOPIC:
case HLPMENUSRCHPREVMATCH:
case HLPMENUSRCHNEXTMATCH:
case HLPMENUSRCHCURRMATCH:
switch(LOWORD(wParam)) {
case HLPMENUSRCHFIRSTTOPIC:
wNavSrchCmd = wNavSrchFirstTopic;
break;
case HLPMENUSRCHLASTTOPIC:
wNavSrchCmd = wNavSrchLastTopic;
break;
case HLPMENUSRCHPREVTOPIC:
wNavSrchCmd = wNavSrchPrevTopic;
break;
case HLPMENUSRCHNEXTTOPIC:
wNavSrchCmd = wNavSrchNextTopic;
break;
case HLPMENUSRCHPREVMATCH:
wNavSrchCmd = wNavSrchPrevMatch;
break;
case HLPMENUSRCHNEXTMATCH:
wNavSrchCmd = wNavSrchNextMatch;
break;
case HLPMENUSRCHCURRMATCH:
wNavSrchCmd = wNavSrchCurrTopic;
break;
default:
NotReached();
break;
}
if ((hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic)) != NULL) {
/*
* Ensure that internal and visible focus is set to the main
* help window for all search operations.
*/
// REVIEW: [ralphw] I changed to allow in secondary windows. But
// does it work?
SetFocus(ahwnd[iCurWindow].hwndParent);
if ((rc = RcProcessNavSrchCmd(hde, wNavSrchCmd, (QLA) &la)) == rcSuccess)
{
TopicGoto(fGOTO_LA, (QV) &la);
}
else if (rc == rcFileChange) {
rc = RcResetCurrMatchFile(hde);
}
if (rc != rcSuccess) {
// Error
}
}
break;
#endif
#ifdef _DEBUG
case IDM_FRAMES:
fDebugState ^= fDEBUGFRAME;
wCheck = (fDebugState & fDEBUGFRAME) ? MF_CHECKED : MF_UNCHECKED;
CheckMenuItem(GetMenu(ahwnd[iCurWindow].hwndParent), IDM_FRAMES, wCheck);
InvalidateRect(ahwnd[iCurWindow].hwndTopic, NULL, TRUE);
break;
case IDM_MEM_USAGE:
{
char szBuf[256];
wsprintf(szBuf, "With bitmaps:\t%s bytes\r\n",
FormatNumber(lcHeapCheck()));
DiscardBitmapsHde(QdeFromGh(HdeGetEnv()));
wsprintf(szBuf + strlen(szBuf), "Without bitmaps:\t%s bytes\r\n",
FormatNumber(lcHeapCheck()));
ErrorQch(szBuf);
}
break;
case IDM_ADD_BUTTON:
VDebugAddButton();
break;
case IDM_DISCARD_BITMAPS:
DiscardBitmapsHde(QdeFromGh(HdeGetEnv()));
break;
case IDM_GENERATE_FTS:
if (!StartAnimation(sidCreatingFTS)) {
Error(wERRS_OOM, wERRA_RETURN);
break;
}
GenerateIndex(HdeGetEnv(), GetCurFilename(),
TOPIC_SEARCH | PHRASE_SEARCH | PHRASE_FEEDBACK | VECTOR_SEARCH
| WINHELP_INDEX | USE_VA_ADDR);
StopAnimation();
break;
case IDM_DO_FIND:
GenerateMessage(MSG_ACTION, IFW_FIND, 1);
break;
#endif // DEBUG
default:
MenuExecute(wParam);
break;
}
return TRUE;
}
/***************************************************************************
*
- Name: SetSrchHilite
-
* Purpose:
* Process theHLPMENUSRCHHILITEON & HLPMENUSRCHHILITEOFF requests for all
* DEs in the system.
*
* Arguments:
* hwnd = hwnd to be set (may be null)
* wCmd = command to be processed
*
* Returns:
* nothing
*
***************************************************************************/
VOID static STDCALL SetSrchHilite(HWND hwnd, WORD wCmd)
{
HDE hde;
HDC hdc;
if (hwnd) {
hde = HdeGetEnvHwnd (hwnd);
if (hde) {
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
#ifdef RAWHIDE
RcProcessNavSrchCmd(hde, wCmd, NULL);
#endif
InvalidateRect(hwnd, NULL, TRUE);
RelHDC(hwnd, hde, hdc);
}
}
}
}
/*******************
-
- Name: ShowNote
*
* Purpose: Show the note window when a definition hotspot has been
* clicked on.
*
* Arguments: FM fm file moniker of the file to display -- fmNil
* will use the current file.
* HDE hdeFrom The DE of the source of the note.
* LONG itohashctx either an ITO or a hash value.
* BOOL fShow FALSE if hiding the note window.
* fGOTO_ITO if itohashctx is an ITO,
* fGOTO_HASH if itohashctx is a hash value.
* fGOTO_CTX if itohashctx is a ctx
* Returns: Nothing.
*
******************/
static BOOL fShown; // Is the note window already shown?
#ifdef _DEBUG
extern int iEnvCur;
#endif
BOOL STDCALL ShowNote(FM fm, HDE hdeFrom, LONG itohashctx, BOOL fShow)
{
RECT rctHlp; // Client area of help window
RECT rcClient; // Client area of note window
RECT rctHotspot; // Rectangle containing hotspot
int width, height; // Size of the note window
int wOffset; // Offset so that hotspot is not hidden
HDE hde; // Display E... for layout
POINT pt; // Point for layout
POINT ptOrg; // Centre of hotspot area
POINT ptw; // Layout size of note window + shadow
static HWND hwndSave; // The parent DE's window when brought up
HWND hwndFrom; // The source DE's window
BOOL fReSized = FALSE; // Have we resized the window?
// Make certain we have the current screen resolution
if (!cxScreen)
GetScreenResolution();
// If we were called from a popup, then we need to flush the message queue so as
// to close the old popup.
if (hwndNote && fShow) {
/*
* We really, really, really want the current note window to be gone
* before we try to create this new one, or we'll end up with a huge
* flash on the screen as it resizes itself. We also don't want to
* end up in an infinite loop, hence the counter.
*/
int count = 0;
while (hwndNote && count < 100) {
count++;
FlushMessageQueue(0);
/*
* HACK: we have to give the desktop time to repaint or we'll end
* up picking up part of the previous popup in our shadow window. I
* tried calling RedrawWindow(NULL, ...) and UpdateWindow(NULL) to no
* effect. Sleep(0) didn't work, but Sleep(100) worked on a P90 on NT,
* and a 386/20 running Win95.
*/
Sleep(100);
}
fRequireDown = TRUE;
}
else
fRequireDown = FALSE;
if (!hwndNote) {
hwndNote = CreateWindowEx(WS_EX_TOPMOST, pchNote,
NULL,
WS_POPUP,
10, 10, 120, 120,
ahwnd[iCurWindow].hwndParent,
NULL, hInsNow, NULL);
if (fHelp == POPUP_HELP)
fRestoreFocus = TRUE;
}
if (!hwndNote) {
Error(wERRS_OOM_CREATE_NOTE, wERRA_RETURN);
return FALSE;
}
/* (kevynct)
* Destroy the note window.
* Note that when the note window is brought up, we save the current DE
* and set the environment to the note DE. When the note window is
* destroyed, we revert back to the original saved DE.
*/
if (!fShow) {
if (!fShown)
return TRUE;
/*
* If this is context sensitive help, then wait around for 10
* seconds and then go away. This gives good performance for multiple
* context sensitive help requests, while quickly freeing up memory if
* we are no longer used.
*/
if (fHelp == POPUP_HELP && !fAutoClose) {
fAutoClose = TRUE;
SetTimer(ahwnd[MAIN_HWND].hwndParent, ID_AUTO_CLOSE, NOTE_TIMEOUT,
NULL);
}
fShown = FALSE;
DestroyHde(HdeDefectEnv(hwndNote));
if (fRestoreFocus)
RestoreFocusToAppCaller();
DestroyWindow(hwndNote);
hwndNote = NULL;
if (fHelp != POPUP_HELP) {
FSetEnv(ahwnd[iCurWindow].hwndTopic);
SetFocus(ahwnd[iCurWindow].hwndParent);
}
#if 0
// REVIEW: why do we need to call EnableDisable after a popup?
if (FSetEnv(ahwnd[iCurWindow].hwndParent) &&
(hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndParent)) != NULL)
EnableDisable(hde, FALSE, iCurWindow);
#endif
return TRUE;
}
if (fHelp != POPUP_HELP) {
ToggleHotspots(FALSE);
hwndSave = HwndGetEnv();
if (hdeFrom != NULL)
hwndFrom = QdeFromGh(hdeFrom)->hwnd;
else
hwndFrom = hwndSave;
}
else {
hwndSave = NULL;
hwndFrom = NULL;
#ifdef _DEBUG
// ASSERT(iEnvCur == -1);
ASSERT(!hdeFrom);
#endif
}
/*
* Get the hotspot rectangle, and set the offset. DANGER: HDE is set
* if fm is fmNil. This is used later.
*/
if (!fm) {
hde = HdeGetEnv();
if (hdeFrom != NULL && !ptPopup.x)
RctLastHotspotHit(QdeFromGh(hdeFrom), &rctHotspot);
else
SetRectEmpty(&rctHotspot);
}
/*
* For interfile jumps (where RctLastHotspotHde will not have cached a
* hotspot) we establish a rectangle around the mouse cursor position to
* use. We also do this if for some reason we cannot retrieve the hotspot
* from the hdeFrom.
*/
if (ptPopup.x) {
ScreenToClient(hwndFrom, &ptPopup);
rctHotspot.top = ptPopup.y - 10;
rctHotspot.left = ptPopup.x - 25;
rctHotspot.bottom = ptPopup.y + 10;
rctHotspot.right = ptPopup.x + 25;
ptPopup.x = 0;
}
else if (fm || rctHotspot.right == 0 && rctHotspot.bottom == 0) {
if (fm)
hde = NULL;
GetCursorPos(&pt);
ScreenToClient(hwndFrom, &pt);
rctHotspot.top = pt.y - 10;
rctHotspot.left = pt.x - 25;
rctHotspot.bottom = pt.y + 10;
rctHotspot.right = pt.x + 25;
}
wOffset = RECT_HEIGHT(rctHotspot) / 2;
// Find the centre of the hotspot rectangle.
ptOrg.x = rctHotspot.left + RECT_WIDTH(rctHotspot) / 2;
ptOrg.y = rctHotspot.top + wOffset;
ClientToScreen(hwndFrom, (LPPOINT)&ptOrg);
// Set the point at which to layout the note window.
if (ptOrg.x < 0)
ptOrg.x = 0;
if (ptOrg.x > cxScreen)
ptOrg.x = cxScreen;
if (ptOrg.y < 0)
ptOrg.y = 0;
if (ptOrg.y > cyScreen)
ptOrg.y = cyScreen;
pt = ptOrg;
// Create and Enlist the DE for this note.
// Note: fm may be nil
hde = HdeCreate(&fm, fm ? NULL : hde, deNote);
RemoveFM(&fm);
if (!hde) {
DestroyWindow(hwndNote);
hwndNote = NULL;
return FALSE;
}
SetHdeHwnd(hde, hwndNote);
if (hde)
FEnlistEnv(hwndNote, hde);
else
return TRUE;
FSetEnv(hwndNote);
// Get the help client area rectangle in screen coordinates.
if (fHelp != POPUP_HELP) {
GetClientRect(ahwnd[iCurWindow].hwndParent, &rctHlp);
ClientRectToScreen(ahwnd[iCurWindow].hwndParent, &rctHlp);
}
else {
// Force a default parent size
SetRect(&rctHlp, 0, 0, 320, 240);
}
/*
* The width of the window will be the minimum of the window size + 15
* and 1/2 the screen width. The height of the window will be the height
* of the help window, up to a minimum height.
*/
width = min(RECT_WIDTH(rctHlp) + 15, cxScreen - 30);
width = max(width, MINNOTEWIDTH);
height = cyScreen - 4;
// Make sure the note doesn't go off-screen.
ReSize:
if ((cyScreen - pt.y) < (height + wOffset))
pt.y = max((pt.y - height - wOffset), 2 );
else
pt.y = min((pt.y + wOffset ), (cyScreen - height - 2) );
if (cxScreen / 2 < pt.x) // If pt.x is in right half of screen...
pt.x = min((int)(pt.x - (width/2)), cxScreen - width - 2);
else
pt.x = max((pt.x - (width / 2)), 2);
// Set the tentative (ie, not final) position for the note window.
SetWindowPos(hwndNote, NULL, pt.x, pt.y, width, height, SWP_NOZORDER);
GetClientRect(hwndNote, &rcClient);
/*
* Add space since we are drawing our own border on the client
* area and for the shadow on the right and the bottom.
*/
rcClient.top += CB_BORDER + 1;
rcClient.left += CB_BORDER + 1;
rcClient.right -= SHADOW_WIDTH + CB_BORDER;
rcClient.bottom -= SHADOW_HEIGHT + CB_BORDER;
SetSizeHdeQrct(hde, &rcClient, FALSE);
/* Fix for bug 59 (kevynct 90/05/23)
*
* Layout the topic for the note window. BEWARE! The final position
* of the note window is not yet set, so if there is a hotspot in the
* note topic, layout may think that the current mouse position touches
* the hotspot, even though the note window hotspot may be moved later;
* this will leave the cursor incorrectly set. We thus set the cursor to
* icurArrow AFTER the layout call (at the end of this function).
*
* Also note that the cursor is not reset when the note window goes
* away; the window regaining the capture is responsible for resetting
* the cursor.
*/
if (!Goto(hwndNote, (WORD) fShow, &itohashctx)) {
// REVIEW: this probably isn't sufficient for cleanup 22-Apr-1993 [ralphw]
fShown = TRUE;
ShowNote(0, NULL, 1, FALSE);
return FALSE;
}
/*
* Now that the note's topic is rendered, get its real layout size and
* resize the note window (taking shadow on the note window into account)
*/
ptw = PtGetLayoutSize(QdeFromGh(hde));
ptw.x += SHADOW_WIDTH;
ptw.y += SHADOW_HEIGHT;
width = min(ptw.x + 10, cxScreen - 30);
width = max(width, MINNOTEWIDTH);
height = min(ptw.y + 10, cyScreen - 4);
pt = ptOrg;
// Make sure the note doesn't go off-screen.
if ((cyScreen - pt.y) < (height + wOffset))
pt.y = max((pt.y - height - wOffset), 2);
else
pt.y = min((pt.y + wOffset), (cyScreen - height - 2));
if (cxScreen/2 < pt.x)
pt.x = min((pt.x - (width/2)), cxScreen - width - 2);
else
pt.x = max((pt.x - (width/2)), 2);
// Try once, and only once to make a reasonable size
if (!fReSized) {
// Check for an overly wide but short popup
if (height * 8 < width) {
width = height * 8;
height = min(RECT_HEIGHT(rctHlp), cyScreen - 4);
fReSized = TRUE;
goto ReSize;
}
// Check for an overly tall but narrow popup
else if (height > width && width < (cxScreen / 3) * 2) {
int oldHeight = height;
while (height > width && width < (cxScreen / 3) * 2) {
height -= 50;
width += 50;
}
height = oldHeight;
if (pt.x + width >= cxScreen && pt.x > cxScreen - width - 1)
pt.x = cxScreen - width - 1;
fReSized = TRUE;
goto ReSize;
}
}
SetWindowPos(hwndNote, NULL, pt.x, pt.y, width, height, SWP_NOZORDER);
/*
* Note that this sizing logic can be removed if we ever handle
* WM_SIZE messages in the note window procedrue.
*/
GetClientRect(hwndNote, &rcClient);
/*
* Add space since we are drawing our own border on the client
* area and for the shadow on the right and the bottom.
*/
rcClient.top += CB_BORDER + 1;
rcClient.left += CB_BORDER + 1;
rcClient.right -= SHADOW_WIDTH + CB_BORDER;
rcClient.bottom -= SHADOW_HEIGHT + CB_BORDER;
SetSizeHdeQrct(hde, &rcClient, FALSE);
fShown = TRUE;
SetForegroundWindow(hwndNote);
SetFocus(hwndNote);
ShowWindow(hwndNote, SW_SHOW);
FSetCursor(icurARROW);
return TRUE;
}
/*******************
-
- Name: CreateBrowseButtons
*
* Purpose: Creates browse next and browse prev buttons if needed
*
* Arguments: hwnd - parent window of the button
*
* Returns: Nothing.
*
******************/
#ifndef NO_PRAGMAS
#pragma data_seg(".text", "CODE")
#endif
const char txtBtnPrevious[] = "btn_previous";
const char txtBtnNext[] = "btn_next";
const char txtPrevMacro[] = "Prev()";
const char txtNextMacro[] = "Next()";
#ifndef NO_PRAGMAS
#pragma data_seg()
#endif
VOID STDCALL CreateBrowseButtons(HWND hwnd)
{
// if (ahwnd[iCurWindow].hwndParent != ahwnd[MAIN_HWND].hwndParent)
// return;
if (ahwnd[iCurWindow].hwndButtonPrev)
/* Note that we do not declare an error here. Given the way that macro
* messages get posted, it is possible to do the following in a single
* macro:
*
* - Jump to a secondary window, thereby creating it and thereby running
* the config section macros of the file, one of which, for this
* example is BrowseButtons().
* - Change focus back to the main window.
*
* with focus back at the main window, we receive the message to turn
* on browse buttons, which might already be there. That get's ignored
* >right here<.
*/
return;
ahwnd[iCurWindow].hwndButtonPrev = HwndAddButton(hwnd, IBF_STD, HashFromSz(txtBtnPrevious),
GetStringResource(sidPreviousButton), txtPrevMacro);
ahwnd[iCurWindow].hwndButtonNext = HwndAddButton(hwnd, IBF_STD, HashFromSz(txtBtnNext),
GetStringResource(sidNextButton), txtNextMacro);
}
/*******************
-
- Name: CreateCoreButtons
*
* Purpose: Creates core four buttons
*
* Arguments: hwnd - parent window of the button
*
* Returns: Nothing.
*
******************/
#ifndef NO_PRAGMAS
#pragma data_seg(".text", "CODE")
#endif
const char txtBtnContents[] = "btn_contents";
const char txtBtnSearch[] = "btn_search";
const char txtBtnBack[] = "btn_back";
const char txtBtnPrint[] = "btn_print";
// New to 4.0
const char txtBtnTopics[] = "btn_topics";
const char txtBtnMenu[] = "btn_menu";
const char txtBtnFind[] = "btn_find";
#ifndef NO_PRAGMAS
#pragma data_seg()
#endif
VOID STDCALL CreateCoreButtons(HWND hwnd, const WSMAG* pwsmag)
{
int iWindow = GetWindowIndex(hwnd);
// 4.0: Allow creation of buttons in secondary windows
if (pwsmag && pwsmag->wMax >= FWSMAG_FIRST_BUTTON &&
curHelpFileVersion >= wVersion40) {
NoDefButtons:
if (pwsmag->wMax & FWSMAG_WMAX_CONTENTS)
ahwnd[iWindow].hwndButtonContents = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnContents),
GetStringResource(sidContentsButton), "Contents()");
if (pwsmag->wMax & FWSMAG_WMAX_SEARCH)
/*
* Note that we used "Index" instead of "Search" for the
* button when this is a secondary window. We also assume the if
* a main window shut off all default buttons, then we'll have
* a .CNT file, and so we use Index in that case also.
*/
ahwnd[iWindow].hwndButtonSearch = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnSearch),
GetStringResource(sidINDEXBtn), "Search()");
if (pwsmag->wMax & FWSMAG_WMAX_FIND)
ahwnd[iWindow].hwndButtonFind = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnFind), GetStringResource(sidFindButton),
"Find()");
if (pwsmag->wMax & FWSMAG_WMAX_TOPICS)
ahwnd[iWindow].hwndButtonTopics = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnTopics), GetStringResource(sidFinder), "FD()");
if (pwsmag->wMax & FWSMAG_WMAX_BACK) {
ahwnd[iWindow].hwndButtonBack = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnBack), GetStringResource(sidBackButton),
"Back()");
RcBackInit(iWindow); // initialize the back stack
}
if (pwsmag->wMax & FWSMAG_WMAX_PRINT)
ahwnd[iWindow].hwndButtonPrint = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnPrint), GetStringResource(sidPrintButton),
"Print()");
if (pwsmag->wMax & FWSMAG_WMAX_MENU)
ahwnd[iWindow].hwndButtonMenu = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnMenu), GetStringResource(sidMenuButton),
"MU()");
if (pwsmag->wMax & FWSMAG_WMAX_BROWSE) {
ahwnd[iWindow].hwndButtonPrev = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnPrevious),
GetStringResource(sidPreviousButton), txtPrevMacro);
ahwnd[iWindow].hwndButtonNext = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnNext),
GetStringResource(sidNextButton), txtNextMacro);
}
return;
}
if (ahwnd[iCurWindow].hwndParent != ahwnd[MAIN_HWND].hwndParent)
return;
ahwnd[iWindow].hwndButtonPrev = NULL;
ahwnd[iWindow].hwndButtonNext = NULL;
/*
* 4.0: Check to see if this help file specifies a Topics button
* instead of the older Contents/Search buttons.
*/
if (curHelpFileVersion >= wVersion40) {
WSMAG wsmag;
int result = IWsmagFromHrgwsmagNsz(
HdeGetEnvHwnd(ahwnd[MAIN_HWND].hwndTopic), txtMain, &wsmag);
if (result >= 0) {
if (wsmag.wMax & FWSMAG_WMAX_NO_DEF_BTNS) {
pwsmag = &wsmag;
goto NoDefButtons;
}
}
}
ahwnd[iWindow].hwndButtonContents = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnContents),
GetStringResource(sidContentsButton), "Contents()");
{
QDE qde = HdeGetEnv();
ASSERT(qde);
ahwnd[iWindow].hwndButtonSearch = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnSearch),
/*
* Version 4 help files, or any help file associated with
* a .CNT file use an Index button instead of a Search button.
*/
GetStringResource((QDE_HHDR(qde).wVersionNo >= wVersion40 ?
sidINDEXBtn : sidSearchButton)),
"Search()");
}
// REVIEW: should we make Find a standard button?
ahwnd[iWindow].hwndButtonBack = HwndAddButton(hwnd, IBF_STD, HashFromSz(txtBtnBack),
GetStringResource(sidBackButton), "Back()");
ahwnd[iWindow].hwndButtonPrint = HwndAddButton(hwnd, IBF_STD, HashFromSz(txtBtnPrint),
GetStringResource(sidPrintButton), "Print()");
if (curHelpFileVersion == wVersion3_0) {
// WinHelp 3.0 files always had browse buttons.
ahwnd[iWindow].hwndButtonPrev = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnPrevious),
GetStringResource(sidPreviousButton), txtPrevMacro);
ahwnd[iWindow].hwndButtonNext = HwndAddButton(hwnd, IBF_STD,
HashFromSz(txtBtnNext),
GetStringResource(sidNextButton), txtNextMacro);
}
}
static HCURSOR hcurRestore;
void STDCALL WaitCursor(void)
{
if (!hcurWait)
hcurWait = LoadCursor(NULL, (LPSTR) IDC_WAIT);
hcurRestore = SetCursor(hcurWait);
}
void STDCALL RemoveWaitCursor(void) {
SetCursor(hcurRestore);
}
/*******************
**
** Name: FSetCursor
**
** Purpose: Set the cursor to the passed cursor.
**
** Arguments: icur - index of cursor desired.
**
** Returns: TRUE if successful.
**
*******************/
BOOL STDCALL FSetCursor(int icur)
{
switch(icur) {
case icurWAIT:
if (!hcurWait)
hcurWait = LoadCursor(NULL, (LPSTR) IDC_WAIT);
return (BOOL) SetCursor(hcurArrow);
case icurHAND:
if (!hcurHand)
hcurHand = LoadCursor(hInsNow, MAKEINTRESOURCE(IDCUR_HAND));
return (BOOL) SetCursor(hcurHand);
case icurIBEAM:
return (BOOL) SetCursor(hcurIBeam);
default:
case icurARROW:
// Arrow cursor loaded in FLoadResources()
return (BOOL) SetCursor(hcurArrow);
}
}
/*******************
-
- Name: GenerateMessage
*
* Purpose: Posts messages to the applications queue
*
* Arguments: wWhich - which message to generate
* wParam - message dependent data
* lParam - message dependent data
*
* Returns: 0L for the Posted messages; result of Sent messages
*
*******************/
LONG STDCALL _GenerateMessage(UINT wWhich, WPARAM wParam, LPARAM lParam)
{
if (wWhich > MSG_SEND) {
return SendMessage(ahwnd[iCurWindow].hwndParent, wWhich, wParam, lParam);
}
else {
#ifdef _DEBUG
BOOL f;
if (!(f = PostMessage(ahwnd[iCurWindow].hwndParent, wWhich, wParam, lParam )))
ErrorQch("Overflow in the message queue.");
return f;
#else
return PostMessage(ahwnd[iCurWindow].hwndParent, wWhich, wParam, lParam);
#endif
}
}
void STDCALL _PostErrorMessage(WPARAM msg)
{
#if defined(_DEBUG)
if (MessageBox(ahwnd[iCurWindow].hwndParent,
"Do you want to break into the debugger now?",
"_PostErrorMessage", MB_YESNO | MB_DEFBUTTON2) == IDYES)
DebugBreak();
#endif
if (!cPostErrorMessages)
PostMessage(ahwnd[iCurWindow].hwndParent, MSG_ERROR, msg, wERRA_RETURN);
else
cPostErrorMessages--;
}
/*******************
-
- Name:
- ClientRectToScreen(HWND, LPRECT)
*
* Purpose:
* This function takes a rectangle in client coordinates and converts
* to screen screen coordinates.
*
* Arguments:
* 2. lprect - pointer to client rect
*
* Returns;
* LPRECT - pointer to converted rectangle
*
******************/
INLINE VOID STDCALL ClientRectToScreen(HWND hwnd, RECT* lprect)
{
ClientToScreen(hwnd, (LPPOINT)&(lprect->left));
ClientToScreen(hwnd, (LPPOINT)&(lprect->right));
}