1445 lines
42 KiB
C++
1445 lines
42 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "bagel/hodjnpodj/hnplibs/stdafx.h"
|
|
#include "bagel/hodjnpodj/hnplibs/rules.h"
|
|
#include "bagel/hodjnpodj/hnplibs/button.h"
|
|
#include "bagel/hodjnpodj/globals.h"
|
|
#include "bagel/boflib/sound.h"
|
|
//
|
|
|
|
namespace Bagel {
|
|
namespace HodjNPodj {
|
|
|
|
#define BUILD_FOR_DLL false
|
|
#define COLOR_BUTTONS true
|
|
|
|
#define SCROLL_PIECES 6 // number of mid-scroll segments
|
|
#define SCROLL_SPEC ".\\art\\lscroll.bmp" // path for scroll DIB on disk
|
|
#define SCROLL_TOP_SPEC ".\\art\\lscrollt.bmp" // path for scroll's top section DIB on disk
|
|
#define SCROLL_BOT_SPEC ".\\art\\lscrollb.bmp" // path for scroll's bottom section DIB on disk
|
|
#define SCROLL_MID_SPEC ".\\art\\lscrollm.bmp" // path for scroll's middle section DIB on disk
|
|
|
|
#define BUTTON_DY 15 // offset for Okay button from scroll base
|
|
|
|
#define SCROLL_STRIP_WIDTH 10 // width of scroll middle to reveal per interval
|
|
#define SCROLL_STRIP_DELAY 1000 // delay to wait after each partial scroll unfurling
|
|
|
|
#define TEXT_BUFFER_SIZE 1024 // # characters in the text input buffer
|
|
#define TEXT_LEFT_MARGIN 55 // left margin offset for display of text
|
|
#define TEXT_TOP_MARGIN 5 // top margin offset for display of text
|
|
#define TEXT_BOTTOM_MARGIN 20 // bottom margin offset for display of text
|
|
#define TEXT_WIDTH 435 // width of text display area
|
|
#define TEXT_MORE_DX 120 // offset of "more" indicator from right margin
|
|
#define TEXT_MORE_DY 10 // offset of "more" indicator bottom of scroll
|
|
#define MORE_TEXT_BLURB "[ More ]" // actual text to display for "more" indicator
|
|
#define MORE_TEXT_LENGTH 8 // # characters in "more" indicator string
|
|
#define TEXT_NEWLINE '\\' // character that indicates enforced line break
|
|
|
|
LRESULT PrefHookProc(int, WPARAM, LPARAM); // keyboard hook procedure definition
|
|
static FARPROC pKbdHook = nullptr; // pointer to hook procedure
|
|
static HHOOK hKbdHook = nullptr; // handle for hook procedure
|
|
|
|
static CRules *pRulesDialog = nullptr; // pointer to our rules dialog box
|
|
static CWnd *pParentWnd = nullptr; // parent window pointer
|
|
|
|
static CColorButton *pOKButton = nullptr; // OKAY button on scroll
|
|
|
|
static CDibDoc *pScrollTopDIB = nullptr, // DIB for scroll top section
|
|
*pScrollMidDIB = nullptr, // DIB for scroll mid section
|
|
*pScrollBotDIB = nullptr; // DIB for scroll bottom section
|
|
|
|
static CBitmap *pScrollTopBitmap = nullptr, // bitmap for scroll top section
|
|
*pScrollTopBitmapOld = nullptr, // bitmap previously mapped to top section context
|
|
*pScrollMidBitmap = nullptr, // bitmap for scroll mid section
|
|
*pScrollMidBitmapOld = nullptr, // bitmap previously mapped to mid section context
|
|
*pScrollBotBitmap = nullptr, // bitmap for scroll bottom section
|
|
*pScrollBotBitmapOld = nullptr; // bitmap previously mapped to bottom section context
|
|
|
|
static CBitmap *pScrollTopMask = nullptr, // mask for scroll top section bitmap
|
|
*pScrollTopMaskOld = nullptr, // bitmap previously mapped to top mask context
|
|
*pScrollMidMask = nullptr, // mask for scroll mid section bitmap
|
|
*pScrollMidMaskOld = nullptr, // bitmap previously mapped to mid mask context
|
|
*pScrollBotMask = nullptr, // mask for scroll bottom section bitmap
|
|
*pScrollBotMaskOld = nullptr; // bitmap previously mapped to bottom mask context
|
|
|
|
static CBitmap *pScrollBitmap = nullptr, // bitmap for an entirely blank scroll
|
|
*pScrollBitmapOld = nullptr, // bitmap previously mapped to the scroll context
|
|
*pBackgroundBitmap = nullptr, // bitmap containing the background for the scroll
|
|
*pBackgroundBitmapOld = nullptr, // bitmap previously mapped to the background context
|
|
*pWorkBitmap = nullptr, // bitmap containing the work area for the scroll
|
|
*pWorkBitmapOld = nullptr; // bitmap previously mapped to the work area context
|
|
|
|
static CPalette *pScrollPalette = nullptr, // palette used for the scroll
|
|
*pScrollPalOld = nullptr, // previous palette mapped to scroll context
|
|
*pBackgroundPalOld = nullptr, // previous palette mapped to background context
|
|
*pScrollTopPalOld = nullptr, // previous palette mapped to top context
|
|
*pScrollMidPalOld = nullptr, // previous palette mapped to middle context
|
|
*pScrollBotPalOld = nullptr, // previous palette mapped to bottom context
|
|
*pScrollTopMaskPalOld = nullptr, // previous palette mapped to top mask context
|
|
*pScrollMidMaskPalOld = nullptr, // previous palette mapped to middle mask context
|
|
*pScrollBotMaskPalOld = nullptr, // previous palette mapped to bottom mask context
|
|
*pWorkPalOld = nullptr; // previous palette mapped to work area context
|
|
|
|
static CDC *pScrollDC = nullptr, // device context for the scroll bitmap
|
|
*pBackgroundDC = nullptr, // device context for the background bitmap
|
|
*pScrollTopDC = nullptr, // device context for the top section bitmap
|
|
*pScrollMidDC = nullptr, // device context for the middle section bitmap
|
|
*pScrollBotDC = nullptr, // device context for the bottom section bitmap
|
|
*pScrollTopMaskDC = nullptr, // device context for the top mask bitmap
|
|
*pScrollMidMaskDC = nullptr, // device context for the middle section bitmap
|
|
*pScrollBotMaskDC = nullptr, // device context for the bottom section bitmap
|
|
*pWorkDC = nullptr; // device context for the work area bitmap
|
|
|
|
static CFont *pFont = nullptr; // font to use for displaying rules text
|
|
static char chPathName[128]; // buffer to hold path name of the rules file
|
|
static CFile *pHelpFile = nullptr; // the rules file
|
|
static uint32 nHelpFileSize = 0; // size of rules file
|
|
static int nHelpPage = 0; // current page of rules text
|
|
static uint32 dwHelpPagePosition[100]; // position of each page (# chars from file start)
|
|
static bool dwHelpPageEOL[100]; // whether page starts with enforced line break
|
|
static bool bHelpEOF = false; // whether end-of-file has been reached
|
|
static int tabstop = 20 + TEXT_LEFT_MARGIN;// pixels per tab stop
|
|
|
|
static const char *pSoundPath = nullptr; // path spec for rules narration
|
|
static CSound *pNarrative = nullptr; // sound object
|
|
|
|
static bool first_time = true;
|
|
static bool bActiveWindow = false; // whether our window is active
|
|
static bool bBruteForce = false; // whether we can be clever
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRules dialog
|
|
|
|
BEGIN_MESSAGE_MAP(CRules, CDialog)
|
|
//{{AFX_MSG_MAP(CRules)
|
|
ON_WM_CREATE()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_PAINT()
|
|
ON_WM_SHOWWINDOW()
|
|
ON_WM_SIZE()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_NCMOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_DESTROY()
|
|
ON_WM_ACTIVATE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
bool CRules::SetupKeyboardHook() {
|
|
HINSTANCE hInst;
|
|
|
|
pRulesDialog = this; // retain pointer to our dialog box
|
|
|
|
hInst = AfxGetInstanceHandle(); // get our application instance
|
|
|
|
hKbdHook = SetWindowsHookEx(WH_KEYBOARD, PrefHookProc, hInst, GetCurrentTask());
|
|
|
|
if (hKbdHook == nullptr) // plug in our keyboard hook
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CRules::RemoveKeyboardHook() {
|
|
if (m_bKeyboardHook) {
|
|
UnhookWindowsHookEx(hKbdHook); // unhook our keyboard procedure
|
|
FreeProcInstance(pKbdHook); // release our procedure pointer
|
|
}
|
|
|
|
pKbdHook = nullptr;
|
|
|
|
pRulesDialog = nullptr;
|
|
hKbdHook = nullptr;
|
|
m_bKeyboardHook = false;
|
|
}
|
|
|
|
LRESULT PrefHookProc(int code, WPARAM wParam, LPARAM lParam) {
|
|
if (code < 0) // required to punt to next hook
|
|
return (CallNextHookEx((HHOOK) pKbdHook, code, wParam, lParam));
|
|
|
|
if (lParam & 0xA0000000) // ignore ALT and key release
|
|
return false;
|
|
|
|
if (bActiveWindow)
|
|
switch (wParam) { // process only the keys we are looking for
|
|
case VK_UP: // ... letting the default dialog procedure
|
|
case VK_NUMPAD8: // ... deal with all the rest
|
|
case VK_PRIOR: // go to previous page of text
|
|
if (nHelpPage > 0)
|
|
(*pRulesDialog).UpdateScroll(nHelpPage - 1);
|
|
return true;
|
|
case VK_DOWN: // go to next page of text
|
|
case VK_NUMPAD2:
|
|
case VK_NEXT:
|
|
if (!bHelpEOF)
|
|
(*pRulesDialog).UpdateScroll(nHelpPage + 1);
|
|
return true;
|
|
case VK_HOME: // go to first page of text
|
|
if (nHelpPage > 0)
|
|
(*pRulesDialog).UpdateScroll(0);
|
|
return true;
|
|
case VK_END: // go to last page of text
|
|
while (!bHelpEOF) {
|
|
(*pRulesDialog).UpdateScroll(nHelpPage + 1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
CRules::CRules(CWnd *pParent, const char *pszPathName,
|
|
CPalette *pPalette, const char *pszSoundPath)
|
|
: CDialog(CRules::IDD, pParent) {
|
|
Common::strcpy_s(chPathName, pszPathName); // retain path to rules file on disk
|
|
pScrollPalette = pPalette; // retain palette to be used
|
|
pParentWnd = nullptr; // retain parent window pointer
|
|
pSoundPath = pszSoundPath; // retain path to sound file on disk
|
|
|
|
//{{AFX_DATA_INIT(CRules)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
|
|
void CRules::DoDataExchange(CDataExchange* pDX) {
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CRules)
|
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRules message handlers
|
|
|
|
void CRules::OnOK() {
|
|
ClearDialogImage();
|
|
CDialog::EndDialog(IDC_RULES_OKAY);
|
|
}
|
|
|
|
|
|
void CRules::OnCancel() {
|
|
ClearDialogImage();
|
|
CDialog::OnCancel();
|
|
}
|
|
|
|
|
|
void CRules::OnDestroy() {
|
|
bool bUpdateNeeded;
|
|
HCURSOR hNewCursor = nullptr;
|
|
CWinApp *pMyApp;
|
|
|
|
pMyApp = AfxGetApp();
|
|
hNewCursor = (*pMyApp).LoadStandardCursor(IDC_ARROW);
|
|
//if (hNewCursor != nullptr);
|
|
SetCursor(hNewCursor);
|
|
|
|
// Free the objects
|
|
delete pNarrative;
|
|
pNarrative = nullptr;
|
|
delete pOKButton;
|
|
pOKButton = nullptr;
|
|
delete pFont;
|
|
pFont = nullptr;
|
|
|
|
(*pHelpFile).Close(); // close and release the rules file
|
|
delete pHelpFile;
|
|
pHelpFile = nullptr;
|
|
|
|
if (pBackgroundBitmap != nullptr) {
|
|
bUpdateNeeded = (*pParentWnd).GetUpdateRect(nullptr, false);
|
|
if (bUpdateNeeded)
|
|
(*pParentWnd).ValidateRect(nullptr);
|
|
}
|
|
|
|
if (!bBruteForce) {
|
|
ReleaseCompatibleContext(pWorkDC, pWorkBitmap, pWorkBitmapOld, pWorkPalOld);
|
|
ReleaseCompatibleContext(pScrollDC, pScrollBitmap, pScrollBitmapOld, pScrollPalOld);
|
|
ReleaseCompatibleContext(pBackgroundDC, pBackgroundBitmap, pBackgroundBitmapOld, pBackgroundPalOld);
|
|
ReleaseCompatibleContext(pScrollMidDC, pScrollMidBitmap, pScrollMidBitmapOld, pScrollMidPalOld);
|
|
ReleaseCompatibleContext(pScrollMidMaskDC, pScrollMidMask, pScrollMidMaskOld, pScrollMidMaskPalOld);
|
|
}
|
|
|
|
if (m_bKeyboardHook) // remove keyboard hook, if present
|
|
RemoveKeyboardHook();
|
|
|
|
CDialog::OnDestroy();
|
|
}
|
|
|
|
|
|
bool CRules::OnInitDialog() {
|
|
CWnd *pButton; // pointer to the OKAY button
|
|
CRect myRect; // rectangle that holds the button location
|
|
int x, y, dx, dy; // used for calculating positioning info
|
|
bool bSuccess;
|
|
|
|
CDialog::OnInitDialog(); // do basic dialog initialization
|
|
|
|
if (pParentWnd == nullptr) // get our parent window
|
|
pParentWnd = ((CWnd *) this)->GetParent(); // ... as passed to us or inquired about
|
|
|
|
(*pParentWnd).GetWindowRect(&myRect);
|
|
x = myRect.left + (((myRect.right - myRect.left) - ScrollRect.right) >> 1);
|
|
y = myRect.top + (((myRect.bottom - myRect.top) - ScrollRect.bottom) >> 1);
|
|
MoveWindow(x, y, ScrollRect.right, ScrollRect.bottom); // center the dialog box on the parent
|
|
|
|
pButton = GetDlgItem((int) GetDefID()); // get the window for the okay button
|
|
ASSERT(pButton != nullptr); // ... and verify we have it
|
|
(*pButton).GetWindowRect(&myRect); // get the button's position and size
|
|
|
|
dx = myRect.right - myRect.left; // calculate where to place the button
|
|
x = (ScrollRect.right - dx) >> 1; // ... centered at the bottom edge
|
|
dy = myRect.bottom - myRect.top;
|
|
y = ScrollRect.bottom - dy - BUTTON_DY;
|
|
|
|
(*pButton).MoveWindow(x, y, dx, dy); // reposition the button
|
|
OkayRect.SetRect(x, y, x + dx, y + dy);
|
|
|
|
#if COLOR_BUTTONS
|
|
pOKButton = new CColorButton(); // build a color QUIT button to let us exit
|
|
ASSERT(pOKButton != nullptr);
|
|
(*pOKButton).SetPalette(pScrollPalette); // set the palette to use
|
|
bSuccess = (*pOKButton).SetControl((int) GetDefID(), this); // tie to the dialog control
|
|
ASSERT(bSuccess);
|
|
#endif
|
|
|
|
if (pSoundPath != nullptr)
|
|
pNarrative = new CSound(this, pSoundPath, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE);
|
|
|
|
m_bKeyboardHook = SetupKeyboardHook(); // establish keyboard hook
|
|
|
|
first_time = true;
|
|
|
|
return true; // return true unless focused on a control
|
|
}
|
|
|
|
|
|
void CRules::OnActivate(unsigned int nState, CWnd *pWndOther, bool bMinimized) {
|
|
bool bUpdateNeeded;
|
|
|
|
switch (nState) {
|
|
case WA_INACTIVE:
|
|
bActiveWindow = false;
|
|
break;
|
|
case WA_ACTIVE:
|
|
case WA_CLICKACTIVE:
|
|
bActiveWindow = true;
|
|
bUpdateNeeded = GetUpdateRect(nullptr, false);
|
|
if (bUpdateNeeded)
|
|
InvalidateRect(nullptr, false);
|
|
}
|
|
}
|
|
|
|
|
|
void CRules::OnPaint() {
|
|
CPaintDC dc(this); // device context for painting
|
|
CPalette *pPalOld = nullptr;
|
|
CDibDoc *pDibDoc;
|
|
|
|
ShowWaitCursor(); // put up the hourglass cursor
|
|
|
|
if (pScrollPalette != nullptr) { // map in our palette
|
|
pPalOld = dc.SelectPalette(pScrollPalette, false);
|
|
dc.RealizePalette(); // .. and make the system use it
|
|
}
|
|
|
|
if (first_time) { // unfurl scroll visually
|
|
first_time = false; // ... but only if this is the first time
|
|
UnfurlScroll(&dc); // ... we are updating the screen
|
|
ReleaseCompatibleContext(pScrollTopDC, pScrollTopBitmap, pScrollTopBitmapOld, pScrollTopPalOld);
|
|
ReleaseCompatibleContext(pScrollBotDC, pScrollBotBitmap, pScrollBotBitmapOld, pScrollBotPalOld);
|
|
ReleaseCompatibleContext(pScrollTopMaskDC, pScrollTopMask, pScrollTopMaskOld, pScrollTopMaskPalOld);
|
|
ReleaseCompatibleContext(pScrollBotMaskDC, pScrollBotMask, pScrollBotMaskOld, pScrollBotMaskPalOld);
|
|
if (pNarrative != nullptr)
|
|
// Play the narration
|
|
(*pNarrative).play();
|
|
|
|
} else if (bBruteForce) { // need to paint directly to screen
|
|
pDibDoc = LoadScrollDIB(SCROLL_SPEC, nullptr);
|
|
if (pDibDoc != nullptr) {
|
|
PaintScrollDIB(&dc, pDibDoc);
|
|
delete pDibDoc;
|
|
}
|
|
WritePage(&dc, nHelpPage);
|
|
UpdateMore(&dc); // update the "more" indicator
|
|
} else
|
|
dc.BitBlt( // update the screen with just the
|
|
0, 0, // ... current page of text
|
|
ScrollRect.right,
|
|
ScrollRect.bottom,
|
|
pScrollDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
|
|
if (pScrollPalette != nullptr) // map out our palette
|
|
dc.SelectPalette(pPalOld, false);
|
|
|
|
DoArrowCursor(); // return to an arrow cursor
|
|
}
|
|
|
|
|
|
bool CRules::OnEraseBkgnd(CDC *pDC) {
|
|
return true; // do not automatically erase background to white
|
|
}
|
|
|
|
|
|
void CRules::ClearDialogImage() {
|
|
delete pOKButton;
|
|
pOKButton = nullptr;
|
|
if (pBackgroundBitmap != nullptr)
|
|
ValidateRect(nullptr);
|
|
RefreshBackground();
|
|
}
|
|
|
|
|
|
void CRules::RefreshBackground() {
|
|
CDC *pDC;
|
|
CPalette *pPalOld = nullptr;
|
|
|
|
if (pBackgroundBitmap == nullptr)
|
|
return;
|
|
|
|
pDC = GetDC(); // get a context for our window
|
|
|
|
if (pScrollPalette != nullptr) { // map in our palette
|
|
pPalOld = (*pDC).SelectPalette(pScrollPalette, false);
|
|
(*pDC).RealizePalette(); // .. and make the system use it
|
|
}
|
|
|
|
(*pDC).BitBlt( // repaint the background as it was
|
|
0,
|
|
0,
|
|
ScrollRect.right,
|
|
ScrollRect.bottom,
|
|
pBackgroundDC,
|
|
0,
|
|
0,
|
|
SRCCOPY);
|
|
|
|
if (pScrollPalette != nullptr) // map out our palette
|
|
(*pDC).SelectPalette(pPalOld, false);
|
|
|
|
ReleaseDC(pDC); // release the context
|
|
}
|
|
|
|
|
|
void CRules::UnfurlScroll(CDC *pDC) {
|
|
int i, j, k, h;
|
|
int scroll_delta;
|
|
CRect dstRect, dst2Rect;
|
|
CDibDoc *pDibDoc;
|
|
|
|
if (!bBruteForce)
|
|
bBruteForce = !CreateWorkAreas(pDC); // create our work areas
|
|
if (bBruteForce) {
|
|
ReleaseCompatibleContext(pWorkDC, pWorkBitmap, pWorkBitmapOld, pWorkPalOld);
|
|
ReleaseCompatibleContext(pScrollDC, pScrollBitmap, pScrollBitmapOld, pScrollPalOld);
|
|
ReleaseCompatibleContext(pBackgroundDC, pBackgroundBitmap, pBackgroundBitmapOld, pBackgroundPalOld);
|
|
ReleaseCompatibleContext(pScrollMidDC, pScrollMidBitmap, pScrollMidBitmapOld, pScrollMidPalOld);
|
|
ReleaseCompatibleContext(pScrollMidMaskDC, pScrollMidMask, pScrollMidMaskOld, pScrollMidMaskPalOld);
|
|
pDibDoc = LoadScrollDIB(SCROLL_SPEC, nullptr);
|
|
if (pDibDoc != nullptr) {
|
|
PaintScrollDIB(pDC, pDibDoc);
|
|
delete pDibDoc;
|
|
}
|
|
WritePage(pDC, 0);
|
|
UpdateMore(pDC);
|
|
ScrollTopCurlRect = ScrollTopRect;
|
|
ScrollBotCurlRect = ScrollBotRect;
|
|
ScrollBotCurlRect.top += ScrollTopCurlRect.bottom + ScrollMidRect.bottom * SCROLL_PIECES;
|
|
ScrollBotCurlRect.bottom += ScrollTopCurlRect.bottom + ScrollMidRect.bottom * SCROLL_PIECES;
|
|
return;
|
|
}
|
|
|
|
(*pBackgroundDC).BitBlt( // save the entire background
|
|
0, 0,
|
|
ScrollRect.right,
|
|
ScrollRect.bottom,
|
|
pDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
|
|
(*pScrollDC).BitBlt( // copy background to scroll context
|
|
0, 0, // ... so we can construct the scroll
|
|
ScrollRect.right, // ... on top of it in a masked manner
|
|
ScrollRect.bottom,
|
|
pDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
|
|
// setup the top part of the scroll
|
|
|
|
ScrollTopCurlRect = ScrollTopRect; // record where we're putting the top curl
|
|
|
|
(*pScrollDC).BitBlt( // mask out where the top curl goes
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pScrollTopMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollTopMaskDC).BitBlt( // invert the top curl mask
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
(*pScrollTopDC).BitBlt( // remove transparent area from top curl
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pScrollTopMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollTopMaskDC).BitBlt( // restore top curl mask
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
(*pScrollDC).BitBlt( // paint top curl into the scroll
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pScrollTopDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
|
|
// setup the middle portion of the scroll
|
|
|
|
dstRect = ScrollMidRect; // setup initial destination for a
|
|
dstRect.top += ScrollTopRect.bottom; // ... mid section strip of the scroll
|
|
dstRect.bottom += ScrollTopRect.bottom;
|
|
|
|
(*pScrollMidMaskDC).BitBlt( // invert the mid section mask
|
|
0, 0,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
(*pScrollMidDC).BitBlt( // mask out transparent part of mid section
|
|
0, 0,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
pScrollMidMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollMidMaskDC).BitBlt( // reset the mid section mask
|
|
0, 0,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
for (i = 0; i < SCROLL_PIECES; i++) { // build the scroll's mid section srip-wise
|
|
(*pScrollDC).BitBlt(
|
|
dstRect.left, // mask out where the image will go
|
|
dstRect.top + ScrollMidRect.bottom * i,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
pScrollMidMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollDC).BitBlt( // paint in the mid section image
|
|
dstRect.left,
|
|
dstRect.top + ScrollMidRect.bottom * i,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
pScrollMidDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
}
|
|
|
|
// setup the bottom part of the scroll
|
|
|
|
dstRect.top += ScrollMidRect.bottom * SCROLL_PIECES; // record where the bottom curl goes
|
|
dstRect.bottom = dstRect.top + ScrollBotRect.bottom;
|
|
ScrollBotCurlRect = dstRect;
|
|
|
|
(*pScrollDC).BitBlt( // mask out where the bottom curl image goes
|
|
dstRect.left,
|
|
dstRect.top,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pScrollBotMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollBotMaskDC).BitBlt( // invert the bottom curl mask
|
|
0, 0,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
(*pScrollBotDC).BitBlt( // mask out transparent part of curl
|
|
0, 0,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pScrollBotMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollBotMaskDC).BitBlt( // reset the mask
|
|
0, 0,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
nullptr,
|
|
0, 0,
|
|
DSTINVERT);
|
|
|
|
(*pScrollDC).BitBlt( // paint in the bottom curl
|
|
dstRect.left,
|
|
dstRect.top,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pScrollBotDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
|
|
// write the first page of text
|
|
|
|
WritePage(pScrollDC, 0); // construct first page of text
|
|
|
|
// now display what we built, making the scroll look like it is unfurlinf from top
|
|
// ... and bottom, by increasing the display of the middle section and moving the
|
|
// ... top and bottom curls further away
|
|
|
|
j = (ScrollMidRect.bottom * SCROLL_PIECES) / SCROLL_STRIP_WIDTH; // number of times to update display
|
|
k = (ScrollMidRect.bottom * SCROLL_PIECES) % SCROLL_STRIP_WIDTH; // residual not displayed after main loop
|
|
h = j & 0x1; // whether there is a dangling odd pixel row
|
|
|
|
j = (j >> 1) + h + ((k > 0) ? 1 : 0); // revise loop count based on residual & dangle
|
|
|
|
scroll_delta = SCROLL_STRIP_WIDTH; // current width of the strip to display
|
|
|
|
dstRect.left = 0;
|
|
dstRect.right = ScrollRect.right;
|
|
dstRect.top = (ScrollRect.bottom - (ScrollTopRect.bottom + ScrollBotRect.bottom)) >> 1;
|
|
dstRect.bottom = dstRect.top + ScrollTopRect.bottom + ScrollBotRect.bottom;
|
|
|
|
for (i = 0; i <= j; i++) { // do each segment in turn
|
|
|
|
dst2Rect = dstRect;
|
|
|
|
(*pWorkDC).BitBlt( // splat in the background for top curl
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pBackgroundDC,
|
|
dst2Rect.left,
|
|
dst2Rect.top,
|
|
SRCCOPY);
|
|
|
|
(*pWorkDC).BitBlt( // mask out where the top curl goes
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pScrollTopMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pWorkDC).BitBlt( // insert the top curl background
|
|
0, 0,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pScrollTopDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
|
|
if (i == 0) { // if first time, just paint curl to display
|
|
(*pDC).BitBlt(
|
|
dst2Rect.left,
|
|
dst2Rect.top,
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom,
|
|
pWorkDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
} else {
|
|
(*pWorkDC).BitBlt( // ... otherwise paint in a new piece of
|
|
dst2Rect.left, // ... the middle section
|
|
ScrollTopRect.bottom,
|
|
dst2Rect.right,
|
|
scroll_delta,
|
|
pScrollDC,
|
|
dst2Rect.left,
|
|
dst2Rect.top + ScrollTopRect.bottom,
|
|
SRCCOPY);
|
|
(*pDC).BitBlt( // ... then paint it and the curl, thus
|
|
dst2Rect.left, // ... causing the top to seemingly unfurl
|
|
dst2Rect.top, // ... by one more strip
|
|
ScrollTopRect.right,
|
|
ScrollTopRect.bottom + scroll_delta,
|
|
pWorkDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
}
|
|
|
|
dst2Rect.top = dstRect.bottom - ScrollBotRect.bottom - scroll_delta;
|
|
dst2Rect.bottom = dstRect.bottom;
|
|
|
|
if ((i == 0) || ((i == 1) && (h == 1))) { // if first time or doing last iteration
|
|
(*pWorkDC).BitBlt( // ... just paint in the bottom curl
|
|
0, 0,
|
|
dst2Rect.right,
|
|
scroll_delta,
|
|
pDC,
|
|
dst2Rect.left,
|
|
dst2Rect.top,
|
|
SRCCOPY);
|
|
} else { //
|
|
(*pWorkDC).BitBlt(
|
|
0, 0,
|
|
dst2Rect.right,
|
|
scroll_delta,
|
|
pScrollDC,
|
|
dst2Rect.left,
|
|
dst2Rect.top,
|
|
SRCCOPY);
|
|
}
|
|
|
|
(*pWorkDC).BitBlt(
|
|
0,
|
|
scroll_delta,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pBackgroundDC,
|
|
ScrollBotRect.left,
|
|
dst2Rect.top + scroll_delta,
|
|
SRCCOPY);
|
|
|
|
(*pWorkDC).BitBlt(
|
|
0,
|
|
scroll_delta,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pScrollBotMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pWorkDC).BitBlt(
|
|
0,
|
|
scroll_delta,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom,
|
|
pScrollBotDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
|
|
(*pDC).BitBlt(
|
|
ScrollBotRect.left,
|
|
dst2Rect.top,
|
|
ScrollBotRect.right,
|
|
ScrollBotRect.bottom + scroll_delta,
|
|
pWorkDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
|
|
if ((j == 0) && (h == 1)) {
|
|
dstRect.top -= scroll_delta >> 1;
|
|
dstRect.bottom += scroll_delta >> 1;
|
|
} else {
|
|
dstRect.top -= scroll_delta;
|
|
dstRect.bottom += scroll_delta;
|
|
}
|
|
|
|
if ((i == j - 1) && (k != 0)) {
|
|
scroll_delta = k >> 1;
|
|
dstRect.top += SCROLL_STRIP_WIDTH - scroll_delta;
|
|
dstRect.bottom -= SCROLL_STRIP_WIDTH - scroll_delta;
|
|
|
|
}
|
|
}
|
|
|
|
UpdateMore(pDC);
|
|
}
|
|
|
|
|
|
void CRules::UpdateScroll(int nPage) {
|
|
int i;
|
|
CRect dstRect;
|
|
CDC *pDC;
|
|
CPalette *pPalOld = nullptr;
|
|
|
|
if (bBruteForce) {
|
|
nHelpPage = nPage;
|
|
InvalidateRect(nullptr, false);
|
|
return;
|
|
}
|
|
|
|
pDC = GetDC();
|
|
|
|
if (pScrollPalette != nullptr) { // map in our palette
|
|
pPalOld = (*pDC).SelectPalette(pScrollPalette, false);
|
|
(*pDC).RealizePalette(); // .. and make the system use it
|
|
}
|
|
|
|
dstRect = ScrollMidRect; // setup initial destination for blts
|
|
dstRect.top += ScrollTopRect.bottom;
|
|
dstRect.bottom += ScrollTopRect.bottom;
|
|
|
|
for (i = 0; i < SCROLL_PIECES; i++) { // repaint the scroll midsection artwork
|
|
(*pScrollDC).BitBlt( // ... mask out where artwork goes
|
|
dstRect.left,
|
|
dstRect.top + ScrollMidRect.bottom * i,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
pScrollMidMaskDC,
|
|
0, 0,
|
|
SRCAND);
|
|
|
|
(*pScrollDC).BitBlt( // ... paint in the scroll artwork
|
|
dstRect.left,
|
|
dstRect.top + ScrollMidRect.bottom * i,
|
|
ScrollMidRect.right,
|
|
ScrollMidRect.bottom,
|
|
pScrollMidDC,
|
|
0, 0,
|
|
SRCPAINT);
|
|
}
|
|
|
|
WritePage(pScrollDC, nPage); // construct the new page of text
|
|
|
|
(*pDC).BitBlt( // paint the result to the sceen
|
|
TEXT_LEFT_MARGIN,
|
|
ScrollTopRect.bottom + TEXT_TOP_MARGIN,
|
|
TEXT_WIDTH,
|
|
(SCROLL_PIECES * ScrollMidRect.bottom) - TEXT_TOP_MARGIN - 1,
|
|
pScrollDC,
|
|
TEXT_LEFT_MARGIN,
|
|
ScrollTopRect.bottom + TEXT_TOP_MARGIN,
|
|
SRCCOPY);
|
|
|
|
UpdateMore(pDC); // update the "more" indicator
|
|
|
|
if (pScrollPalette != nullptr) // map out our palette
|
|
(*pDC).SelectPalette(pPalOld, false);
|
|
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
|
|
void CRules::WritePage(CDC *pDC, int nPage) {
|
|
int i, n, x, y;
|
|
unsigned int nCropped = 0;
|
|
unsigned int nCount = 0;
|
|
char chInBuf[TEXT_BUFFER_SIZE];
|
|
CFont *pFontOld = nullptr;
|
|
CSize textInfo;
|
|
bool bEOL, bEOF;
|
|
TEXTMETRIC fontMetrics;
|
|
|
|
nHelpPage = nPage;
|
|
bEOF = bHelpEOF = false;
|
|
|
|
(*pHelpFile).SeekToBegin();
|
|
|
|
if ((nHelpPage == 0) && (nPage == 0)) {
|
|
dwHelpPagePosition[nHelpPage] = (*pHelpFile).GetPosition();
|
|
bEOL = dwHelpPageEOL[nHelpPage] = true;
|
|
} else {
|
|
(*pHelpFile).Seek(dwHelpPagePosition[nPage], CFile::begin);
|
|
bEOL = dwHelpPageEOL[nHelpPage];
|
|
}
|
|
|
|
dwHelpPagePosition[nHelpPage + 1] = dwHelpPagePosition[nHelpPage];
|
|
|
|
pFontOld = (*pDC).SelectObject(pFont);
|
|
|
|
(*pDC).GetTextMetrics(&fontMetrics);
|
|
|
|
(*pDC).SetBkMode(TRANSPARENT);
|
|
|
|
i = 0;
|
|
n = 1;
|
|
x = TEXT_LEFT_MARGIN;
|
|
y = ScrollTopRect.bottom + TEXT_TOP_MARGIN;
|
|
|
|
while (true) {
|
|
try_again:
|
|
if (i >= (int) nCount) {
|
|
if (bEOF)
|
|
break;
|
|
dwHelpPagePosition[nHelpPage + 1] += i + nCropped;
|
|
nCount = (*pHelpFile).Read(&chInBuf, TEXT_BUFFER_SIZE);
|
|
if (nCount < TEXT_BUFFER_SIZE)
|
|
bEOF = true;
|
|
i = 0;
|
|
n = 1;
|
|
nCropped = 0;
|
|
}
|
|
|
|
if (bEOL &&
|
|
((chInBuf[i] == '\r') ||
|
|
(chInBuf[i] == '\n'))) {
|
|
i += 1;
|
|
goto try_again;
|
|
}
|
|
|
|
if (!bEOL &&
|
|
((chInBuf[i] == ' ') ||
|
|
(chInBuf[i] == '\t'))) {
|
|
i += 1;
|
|
goto try_again;
|
|
}
|
|
|
|
bEOL = false;
|
|
|
|
while (true) {
|
|
if (i + n > (int) nCount) {
|
|
n = nCount - i;
|
|
if (bEOF)
|
|
break;
|
|
dwHelpPagePosition[nHelpPage + 1] += i + nCropped;
|
|
strncpy(&chInBuf[0], &chInBuf[i], n);
|
|
nCount = (*pHelpFile).Read(&chInBuf[n], TEXT_BUFFER_SIZE - n);
|
|
nCount += n;
|
|
if (nCount < TEXT_BUFFER_SIZE)
|
|
bEOF = true;
|
|
i = 0;
|
|
n = 1;
|
|
nCropped = 0;
|
|
}
|
|
|
|
if (chInBuf[i + n - 1] == '\r') {
|
|
crop_byte:
|
|
Common::copy(&chInBuf[i + n], chInBuf + nCount, &chInBuf[i + n - 1]);
|
|
nCount -= 1;
|
|
nCropped += 1;
|
|
continue;
|
|
}
|
|
|
|
if (chInBuf[i + n - 1] == '\n') {
|
|
if ((n > 1) &&
|
|
((chInBuf[i + n - 2] == ' ') ||
|
|
(chInBuf[i + n - 2] == '-')))
|
|
goto crop_byte;
|
|
else
|
|
chInBuf[i + n - 1] = ' ';
|
|
}
|
|
|
|
if (chInBuf[i + n - 1] == TEXT_NEWLINE) {
|
|
bEOL = true;
|
|
n -= 1;
|
|
break;
|
|
}
|
|
|
|
textInfo = (*pDC).GetTextExtent(&chInBuf[i], n);
|
|
if (textInfo.cx > TEXT_WIDTH - TEXT_LEFT_MARGIN) {
|
|
if ((chInBuf[i + n - 1] != ' ') &&
|
|
(chInBuf[i + n - 1] != '\t'))
|
|
while (n > 0) {
|
|
n -= 1;
|
|
if (strchr(" \t,;:-", chInBuf[i + n - 1]) != nullptr)
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
n += 1;
|
|
}
|
|
// (*pDC).TextOut(x,y,(const char *) &chInBuf[i],n);
|
|
(*pDC).TabbedTextOut(x, y, (const char *) &chInBuf[i], n, 1, &tabstop, 0);
|
|
if (chInBuf[i + n] == '\r')
|
|
i += 2;
|
|
else if (chInBuf[i + n] == TEXT_NEWLINE)
|
|
i += 1;
|
|
i += n;
|
|
n = 1;
|
|
y += fontMetrics.tmHeight;
|
|
if (y - ScrollTopRect.bottom > (SCROLL_PIECES * ScrollMidRect.bottom) - TEXT_BOTTOM_MARGIN)
|
|
break;
|
|
}
|
|
|
|
(*pDC).SelectObject(pFontOld);
|
|
|
|
dwHelpPagePosition[nPage + 1] += i + nCropped;
|
|
dwHelpPageEOL[nPage + 1] = bEOL;
|
|
|
|
while (true) {
|
|
if (i >= (int) nCount) {
|
|
if (bEOF)
|
|
break;
|
|
nCount = (*pHelpFile).Read(&chInBuf, TEXT_BUFFER_SIZE);
|
|
if (nCount < TEXT_BUFFER_SIZE)
|
|
bEOF = true;
|
|
i = 0;
|
|
n = 1;
|
|
}
|
|
|
|
if (bEOL &&
|
|
((chInBuf[i] == '\r') ||
|
|
(chInBuf[i] == '\n') ||
|
|
(chInBuf[i] == TEXT_NEWLINE))) {
|
|
i += 1;
|
|
dwHelpPagePosition[nHelpPage + 1] += 1;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
if (bEOF && (i >= (int) nCount))
|
|
bHelpEOF = true;
|
|
|
|
(*pDC).SelectObject(pFontOld);
|
|
|
|
}
|
|
|
|
|
|
void CRules::UpdateMore(CDC *pDC) {
|
|
int x, y, dx, dy;
|
|
CFont *pFontOld = nullptr;
|
|
TEXTMETRIC fontMetrics;
|
|
CSize textInfo;
|
|
|
|
pFontOld = (*pDC).SelectObject(pFont);
|
|
|
|
(*pDC).GetTextMetrics(&fontMetrics);
|
|
|
|
(*pDC).SetBkMode(TRANSPARENT);
|
|
|
|
x = ScrollRect.right - TEXT_MORE_DX;
|
|
y = ((ScrollTopRect.bottom - fontMetrics.tmHeight) >> 1) +
|
|
TEXT_MORE_DY - 3;
|
|
textInfo = (*pDC).GetTextExtent(MORE_TEXT_BLURB, MORE_TEXT_LENGTH);
|
|
dx = textInfo.cx;
|
|
dy = fontMetrics.tmHeight;
|
|
|
|
if (nHelpPage == 0)
|
|
(*pDC).BitBlt(
|
|
x,
|
|
y,
|
|
dx,
|
|
dy,
|
|
pScrollDC,
|
|
x,
|
|
y,
|
|
SRCCOPY);
|
|
else
|
|
(*pDC).TextOut(x, y, MORE_TEXT_BLURB, MORE_TEXT_LENGTH);
|
|
|
|
y = ScrollRect.bottom -
|
|
ScrollBotRect.bottom +
|
|
((ScrollBotRect.bottom - fontMetrics.tmHeight) >> 1) -
|
|
TEXT_MORE_DY;
|
|
|
|
if (bHelpEOF)
|
|
(*pDC).BitBlt(
|
|
x,
|
|
y,
|
|
dx,
|
|
dy,
|
|
pScrollDC,
|
|
x,
|
|
y,
|
|
SRCCOPY);
|
|
else
|
|
(*pDC).TextOut(x, y, MORE_TEXT_BLURB, MORE_TEXT_LENGTH);
|
|
|
|
(*pDC).SelectObject(pFontOld);
|
|
}
|
|
|
|
|
|
void CRules::OnShowWindow(bool bShow, unsigned int nStatus) {
|
|
CDialog::OnShowWindow(bShow, nStatus);
|
|
|
|
// TODO: Add your message handler code here
|
|
|
|
}
|
|
|
|
|
|
void CRules::OnSize(unsigned int nType, int cx, int cy) {
|
|
CDialog::OnSize(nType, cx, cy);
|
|
|
|
// TODO: Add your message handler code here
|
|
|
|
}
|
|
|
|
|
|
int CRules::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
|
bool bSuccess;
|
|
int dxDIB, dyDIB;
|
|
|
|
pHelpFile = new CFile();
|
|
ASSERT(pHelpFile != nullptr);
|
|
bSuccess = (*pHelpFile).Open(chPathName, CFile::modeRead | CFile::typeBinary, nullptr);
|
|
ASSERT(bSuccess);
|
|
if (!bSuccess)
|
|
return -1;
|
|
nHelpFileSize = (*pHelpFile).GetLength();
|
|
|
|
AddFontResource("msserif.fon");
|
|
pFont = new CFont();
|
|
ASSERT(pFont != nullptr);
|
|
bSuccess = (*pFont).CreateFont(16, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, OUT_RASTER_PRECIS, 0, PROOF_QUALITY, FF_ROMAN, "MS Sans Serif");
|
|
ASSERT(bSuccess);
|
|
|
|
if ((GetFreeSpace(0) >= (unsigned long) 1000000) &&
|
|
(GlobalCompact((unsigned long) 1000000) >= (unsigned long) 750000)) {
|
|
pScrollTopDIB = LoadScrollDIB(SCROLL_TOP_SPEC, &ScrollTopRect);
|
|
pScrollMidDIB = LoadScrollDIB(SCROLL_MID_SPEC, &ScrollMidRect);
|
|
pScrollBotDIB = LoadScrollDIB(SCROLL_BOT_SPEC, &ScrollBotRect);
|
|
if ((pScrollTopDIB == nullptr) ||
|
|
(pScrollMidDIB == nullptr) ||
|
|
(pScrollBotDIB == nullptr))
|
|
bBruteForce = true;
|
|
else
|
|
bBruteForce = false;
|
|
if (bBruteForce) {
|
|
if (pScrollTopDIB != nullptr)
|
|
delete pScrollTopDIB;
|
|
if (pScrollMidDIB != nullptr)
|
|
delete pScrollMidDIB;
|
|
if (pScrollBotDIB != nullptr)
|
|
delete pScrollBotDIB;
|
|
pScrollTopDIB = nullptr;
|
|
pScrollMidDIB = nullptr;
|
|
pScrollBotDIB = nullptr;
|
|
}
|
|
} else
|
|
bBruteForce = true;
|
|
|
|
if (bBruteForce) {
|
|
dxDIB = 501;
|
|
dyDIB = 395;
|
|
ScrollTopRect.SetRect(0, 0, 501, 48);
|
|
ScrollMidRect.SetRect(0, 0, 501, 50);
|
|
ScrollBotRect.SetRect(0, 0, 501, 47);
|
|
} else {
|
|
dxDIB = ScrollTopRect.right;
|
|
dyDIB = ScrollTopRect.bottom +
|
|
(ScrollMidRect.bottom * SCROLL_PIECES) +
|
|
ScrollBotRect.bottom;
|
|
}
|
|
|
|
ScrollRect.SetRect(0, 0, dxDIB, dyDIB);
|
|
|
|
if (CDialog::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool CRules::CreateWorkAreas(CDC *pDC) {
|
|
bool bSuccess;
|
|
CRect WorkRect;
|
|
|
|
pScrollTopBitmap = CreateScrollBitmap(pDC, pScrollTopDIB, pScrollPalette);
|
|
delete pScrollTopDIB;
|
|
pScrollMidBitmap = CreateScrollBitmap(pDC, pScrollMidDIB, pScrollPalette);
|
|
delete pScrollMidDIB;
|
|
pScrollBotBitmap = CreateScrollBitmap(pDC, pScrollBotDIB, pScrollPalette);
|
|
delete pScrollBotDIB;
|
|
if ((pScrollTopBitmap == nullptr) ||
|
|
(pScrollMidBitmap == nullptr) ||
|
|
(pScrollBotBitmap == nullptr))
|
|
return false;
|
|
|
|
pScrollTopDC = SetupCompatibleContext(pDC, pScrollTopBitmap, pScrollTopBitmapOld, pScrollPalette, pScrollTopPalOld);
|
|
pScrollMidDC = SetupCompatibleContext(pDC, pScrollMidBitmap, pScrollMidBitmapOld, pScrollPalette, pScrollMidPalOld);
|
|
pScrollBotDC = SetupCompatibleContext(pDC, pScrollBotBitmap, pScrollBotBitmapOld, pScrollPalette, pScrollBotPalOld);
|
|
if ((pScrollTopDC == nullptr) ||
|
|
(pScrollMidDC == nullptr) ||
|
|
(pScrollBotDC == nullptr))
|
|
return false;
|
|
|
|
pScrollBitmap = new CBitmap();
|
|
if (pScrollBitmap == nullptr)
|
|
return false;
|
|
bSuccess = (*pScrollBitmap).CreateCompatibleBitmap(pDC, ScrollRect.right, ScrollRect.bottom);
|
|
if (!bSuccess)
|
|
return false;
|
|
pScrollDC = SetupCompatibleContext(pDC, pScrollBitmap, pScrollBitmapOld, pScrollPalette, pScrollPalOld);
|
|
if (pScrollDC == nullptr)
|
|
return false;
|
|
|
|
pBackgroundBitmap = new CBitmap();
|
|
if (pBackgroundBitmap == nullptr)
|
|
return false;
|
|
bSuccess = (*pBackgroundBitmap).CreateCompatibleBitmap(pDC, ScrollRect.right, ScrollRect.bottom);
|
|
if (!bSuccess)
|
|
return false;
|
|
pBackgroundDC = SetupCompatibleContext(pDC, pBackgroundBitmap, pBackgroundBitmapOld, pScrollPalette, pBackgroundPalOld);
|
|
if (pBackgroundDC == nullptr)
|
|
return false;
|
|
|
|
WorkRect.UnionRect(&ScrollTopRect, &ScrollMidRect);
|
|
WorkRect.UnionRect(&WorkRect, &ScrollBotRect);
|
|
WorkRect.bottom += SCROLL_STRIP_WIDTH;
|
|
|
|
pWorkBitmap = new CBitmap();
|
|
if (pWorkBitmap == nullptr)
|
|
return false;
|
|
bSuccess = (*pWorkBitmap).CreateCompatibleBitmap(pDC, WorkRect.right, WorkRect.bottom);
|
|
if (!bSuccess)
|
|
return false;
|
|
pWorkDC = SetupCompatibleContext(pDC, pWorkBitmap, pWorkBitmapOld, pScrollPalette, pWorkPalOld);
|
|
if (pWorkDC == nullptr)
|
|
return false;
|
|
|
|
pScrollTopMask = new CBitmap();
|
|
pScrollMidMask = new CBitmap();
|
|
pScrollBotMask = new CBitmap();
|
|
if ((pScrollTopMask == nullptr) ||
|
|
(pScrollMidMask == nullptr) ||
|
|
(pScrollBotMask == nullptr))
|
|
return false;
|
|
pScrollTopMaskDC = SetupMask(pDC, pScrollTopDC, pScrollTopMask, pScrollTopMaskOld, &ScrollTopRect);
|
|
pScrollMidMaskDC = SetupMask(pDC, pScrollMidDC, pScrollMidMask, pScrollMidMaskOld, &ScrollMidRect);
|
|
pScrollBotMaskDC = SetupMask(pDC, pScrollBotDC, pScrollBotMask, pScrollBotMaskOld, &ScrollBotRect);
|
|
if ((pScrollTopMaskDC == nullptr) ||
|
|
(pScrollMidMaskDC == nullptr) ||
|
|
(pScrollBotMaskDC == nullptr))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
CDC *CRules::SetupMask(CDC *pDC, CDC *pBitmapDC, CBitmap *pMask, CBitmap * &pMaskOld, CRect *pRect) {
|
|
CDC *pNewDC = nullptr;
|
|
|
|
(*pMask).CreateBitmap((*pRect).right, (*pRect).bottom, 1, 1, nullptr);
|
|
|
|
pNewDC = new CDC();
|
|
|
|
if ((pNewDC != nullptr) &&
|
|
(*pNewDC).CreateCompatibleDC(pDC)) {
|
|
pMaskOld = (*pNewDC).SelectObject(pMask);
|
|
if (pMaskOld != nullptr) {
|
|
(*pNewDC).BitBlt(
|
|
0, 0,
|
|
(*pRect).right,
|
|
(*pRect).bottom,
|
|
pBitmapDC,
|
|
0, 0,
|
|
SRCCOPY);
|
|
return (pNewDC);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
CDC *CRules::SetupCompatibleContext(CDC *pDC, CBitmap *pBitmap,
|
|
CBitmap * &pBitmapOld, CPalette *pPalette, CPalette * &pPalOld) {
|
|
CDC *pNewDC = nullptr;
|
|
|
|
pNewDC = new CDC();
|
|
|
|
if ((pDC != nullptr) &&
|
|
(pNewDC != nullptr) &&
|
|
(*pNewDC).CreateCompatibleDC(pDC)) {
|
|
if (pPalette)
|
|
pPalOld = (*pNewDC).SelectPalette(pPalette, false);
|
|
else
|
|
pPalOld = nullptr;
|
|
(*pNewDC).RealizePalette();
|
|
pBitmapOld = (*pNewDC).SelectObject(pBitmap);
|
|
if (pBitmapOld != nullptr)
|
|
return (pNewDC);
|
|
}
|
|
|
|
delete pNewDC;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
void CRules::ReleaseCompatibleContext(CDC *&pDC, CBitmap * &pBitmap, CBitmap *pBitmapOld, CPalette *pPalOld) {
|
|
if (pBitmapOld != nullptr) {
|
|
(*pDC).SelectObject(pBitmapOld);
|
|
pBitmapOld = nullptr;
|
|
}
|
|
|
|
if (pPalOld != nullptr) {
|
|
(*pDC).SelectPalette(pPalOld, false);
|
|
pPalOld = nullptr;
|
|
}
|
|
|
|
if (pBitmap != nullptr) {
|
|
(*pBitmap).DeleteObject();
|
|
delete pBitmap;
|
|
pBitmap = nullptr;
|
|
}
|
|
|
|
if (pDC != nullptr) {
|
|
(*pDC).DeleteDC();
|
|
delete pDC;
|
|
pDC = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
CDibDoc *CRules::LoadScrollDIB(const char *pszPathName, CRect *pRect) {
|
|
bool bSuccess;
|
|
HDIB hDIB;
|
|
int dxDIB, dyDIB;
|
|
CDibDoc *pDibDoc = nullptr;
|
|
// CPalette *pPalette = nullptr;
|
|
// CBitmap *pBitmap = nullptr;
|
|
|
|
pDibDoc = new CDibDoc();
|
|
ASSERT(pDibDoc != nullptr);
|
|
|
|
bSuccess = (*pDibDoc).OpenDocument(pszPathName);
|
|
ASSERT(bSuccess);
|
|
hDIB = (*pDibDoc).GetHDIB();
|
|
ASSERT(hDIB != nullptr);
|
|
|
|
dxDIB = (int) DIBWidth(hDIB);
|
|
dyDIB = (int) DIBHeight(hDIB);
|
|
|
|
|
|
if (pRect != nullptr)
|
|
(*pRect).SetRect(0, 0, dxDIB, dyDIB);
|
|
|
|
return (pDibDoc);
|
|
}
|
|
|
|
|
|
bool CRules::PaintScrollDIB(CDC *pDC, CDibDoc *pDibDoc) {
|
|
bool bSuccess;
|
|
HDIB hDIB;
|
|
int dxDIB, dyDIB;
|
|
CRect myRect;
|
|
|
|
hDIB = (*pDibDoc).GetHDIB();
|
|
ASSERT(hDIB != nullptr);
|
|
|
|
dxDIB = (int) DIBWidth(hDIB);
|
|
dyDIB = (int) DIBHeight(hDIB);
|
|
|
|
|
|
myRect.SetRect(0, 0, dxDIB, dyDIB);
|
|
|
|
bSuccess = PaintDIB((*pDC).m_hDC, myRect, hDIB, myRect, pScrollPalette);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
CBitmap *CRules::CreateScrollBitmap(CDC *pDC, CDibDoc *pDibDoc, CPalette *pPalette) {
|
|
HDIB hDIB;
|
|
CBitmap *pBitmap = nullptr;
|
|
|
|
hDIB = (*pDibDoc).GetHDIB();
|
|
ASSERT(hDIB != nullptr);
|
|
|
|
pBitmap = ConvertDIB(pDC, hDIB, pPalette);
|
|
|
|
return pBitmap;
|
|
}
|
|
|
|
|
|
void CRules::OnLButtonDown(unsigned int nFlags, CPoint point) {
|
|
if (!bActiveWindow)
|
|
return;
|
|
|
|
if (ScrollTopCurlRect.PtInRect(point) && (nHelpPage != 0))
|
|
UpdateScroll(nHelpPage - 1);
|
|
else if (ScrollBotCurlRect.PtInRect(point) && !bHelpEOF)
|
|
UpdateScroll(nHelpPage + 1);
|
|
|
|
OnMouseMove(nFlags, point);
|
|
|
|
CDialog::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
|
|
void CRules::OnMouseMove(unsigned int nFlags, CPoint point) {
|
|
HCURSOR hNewCursor = nullptr;
|
|
CWinApp *pMyApp;
|
|
|
|
if (!bActiveWindow)
|
|
return;
|
|
|
|
pMyApp = AfxGetApp();
|
|
|
|
if (OkayRect.PtInRect(point))
|
|
hNewCursor = (*pMyApp).LoadStandardCursor(IDC_ARROW);
|
|
else if (ScrollTopCurlRect.PtInRect(point)) {
|
|
if (nHelpPage == 0)
|
|
hNewCursor = (*pMyApp).LoadCursor(IDC_RULES_INVALID);
|
|
else
|
|
hNewCursor = (*pMyApp).LoadCursor(IDC_RULES_ARROWUP);
|
|
} else if (ScrollBotCurlRect.PtInRect(point)) {
|
|
if (bHelpEOF)
|
|
hNewCursor = (*pMyApp).LoadCursor(IDC_RULES_INVALID);
|
|
else
|
|
hNewCursor = (*pMyApp).LoadCursor(IDC_RULES_ARROWDN);
|
|
} else
|
|
hNewCursor = (*pMyApp).LoadStandardCursor(IDC_ARROW);
|
|
|
|
//if (hNewCursor != nullptr);
|
|
SetCursor(hNewCursor);
|
|
|
|
CDialog::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
|
|
bool CRules::OnSetCursor(CWnd *pWnd, unsigned int nHitTest, unsigned int message) {
|
|
if ((*pWnd).m_hWnd == (*this).m_hWnd)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
void CRules::ShowWaitCursor() {
|
|
CWinApp *pMyApp;
|
|
|
|
pMyApp = AfxGetApp();
|
|
|
|
(*pMyApp).BeginWaitCursor();
|
|
}
|
|
|
|
|
|
void CRules::DoArrowCursor() {
|
|
CWinApp *pMyApp;
|
|
|
|
pMyApp = AfxGetApp();
|
|
|
|
(*pMyApp).EndWaitCursor();
|
|
}
|
|
|
|
} // namespace HodjNPodj
|
|
} // namespace Bagel
|