AEROGLASS kept me busy for many days...
It is a major step forward into my 64-bit translation of GDImage, because many fondamentals have been done:
- Child controls anchor within a window.
- Completion of text and image sprite objects.
- Alphablending.
- Mouse handling.
- User callback to monitor the GDImage control messages.
- Gradient paint of the main window.
- Easy support of Windows theme.
- Screen capture.
Project code source:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <bitset>
using namespace std;
#include <Commctrl.h>
#include <vector>
#pragma comment(lib, "D:\\VS2010\\GDImage64.lib")
#pragma comment(lib, "D:\\VS2010\\GDImage32.lib")
#include "GDImage.h"
//Apply WinXP theme
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#define long_proc typedef long (__stdcall *zProc)
const wchar_t *$Background = L"Background";
#define IDC_STATUSBAR 100
#define IDC_CTRL 101
#define IDC_STA_Help 102
#define IDC_BTN_FIT2GLASS 103
#define IDC_BTN_CHECK 104
// Warning each overlay object must have a UNIQUE IDENTIFIER
#define ID_OBJECT_TEXT 9
#define ID_FIRST ID_OBJECT_TEXT
#define ID_OBJECT_SPRITE 10
#define ID_AERO_GLASS 11
#define ID_LIGHT 12
#define ID_TWIN 13
#define ID_BRUSH 14
#define ID_LAST ID_BRUSH
const wchar_t *BUTTON = L"BUTTON";
// Global variable
HINSTANCE g_hInst; // Current instance
// Declaration of the functions being used in this module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MyCallBack(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ScreenCaptureToBackground(IN HWND hParent);
vector<HBITMAP> g_hBitmap;
HFONT zDefaultFont() {
static HFONT hDefault;
if (hDefault == 0) { hDefault = (HFONT) GetStockObject(ANSI_VAR_FONT); }
return hDefault;
}
void zSetCTLFont(IN HWND hCtrl, IN HFONT hFont) {
SendMessage(hCtrl, WM_SETFONT, (WPARAM) hFont, 0);
}
long RND (IN long nMin, IN long nMax) {
return ((rand() * (nMax - nMin + 1) / RAND_MAX)) + nMin;
}
HFONT CaptionFont() {
LOGFONT lf = {0};
static HFONT CaptionFont;
if (CaptionFont == 0) {
lf.lfHeight = 8;
lf.lfWidth = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = OUT_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
lf.lfWeight = 700;
wcscpy_s(lf.lfFaceName, L"MS Sans Serif");
CaptionFont = CreateFontIndirect(&lf);
}
return CaptionFont;
}
void GetSpriteFromFile(IN HWND hCtrl) {
RECT rc;
long K, x = 0, y = 0, bmW = 0, bmH = 0;
if (g_hBitmap.size() == 0) { g_hBitmap.resize(4); }
g_hBitmap[0] = ZI_CreateBitmapFromFile(L"aero.png", bmW, bmH);
g_hBitmap[1] = ZI_CreateBitmapFromFile(L"light.png", bmW, bmH);
g_hBitmap[2] = ZI_CreateBitmapFromFile(L"twin.png", bmW, bmH);
g_hBitmap[3] = ZI_CreateBitmapFromFile(L"paintbrush.png", bmW, bmH);
GetClientRect(hCtrl, &rc);
// Use random location to draw the sprites
long UB = (long) g_hBitmap.size();
for (K = 0; K < UB; ++K) {
x = RND(0, rc.right); y = RND(0, rc.bottom);
ZD_DrawBitmapToCtrl(hCtrl, x, y, g_hBitmap[K], 0xFFFFFFFF, ID_OBJECT_SPRITE + K + 1, ZS_VISIBLE);
}
// Add a label for each of the sprite that will be shown on the status bar,
// and anchor them to scroll together with the background.
// Note: ZD_SetObjectLocked is meant to enable/disable user interaction on sprite.
ZD_SetObjectImageLabel(ID_AERO_GLASS, L"Aero glass");
ZD_SetObjectScroll(ID_AERO_GLASS, TRUE);
ZD_SetObjectImageLabel(ID_LIGHT, L"Light");
ZD_SetObjectScroll(ID_LIGHT, TRUE);
ZD_SetObjectImageLabel(ID_TWIN, L"Twin");
ZD_SetObjectScroll(ID_TWIN, TRUE);
ZD_SetObjectImageLabel(ID_BRUSH, L"Paint brush");
ZD_SetObjectScroll(ID_BRUSH, TRUE);
}
void AddChildControls (IN HWND hWnd) {
HWND hCtrl;
wstring sLabel;
// ******************************************************************************
// Helper function to create A GDImage control (with automatic scrollbar support)
// ------------------------------------------------------------------------------
hCtrl = ZI_CreateWindow(hWnd, 10, 10, 580, 400, (HMENU) IDC_CTRL);
// Set the correct anchor property
ZI_SetAnchorMode(hCtrl, ANCHOR_HEIGHT_WIDTH);
// We use a callback to monitor the GDImage control messages
// Create a WM_LBUTTONDOWN event
ZI_EventMessage((LONG_PTR) MyCallBack, WM_LBUTTONDOWN, TRUE);
// Create a WM_RBUTTONDOWN event
ZI_EventMessage((LONG_PTR) MyCallBack, WM_RBUTTONDOWN, TRUE);
// Create a WM_KEYDOWN event
ZI_EventMessage((LONG_PTR) MyCallBack, WM_KEYDOWN, TRUE);
// Create a WM_MOUSEMOVE event
ZI_EventMessage((LONG_PTR) MyCallBack, WM_MOUSEMOVE, TRUE);
// We capture the desktop to set the image background
ScreenCaptureToBackground(hWnd);
// Add the sprites
GetSpriteFromFile(hCtrl);
// Draw overlayed text in a GDImage Control
// ******************************************************************************
// Require the use of True Type Font name (TTF).
// This type of overlay doesn't alter the image shown in the background.
// ------------------------------------------------------------------------------
// Draw Text overlay
// Note: because this is the last object it is drawn on top of z-order
ZD_DrawTextToCtrl(GetDlgItem(hWnd, IDC_CTRL), L"GDImage Aero Glass", 20, 20, ZD_ColorARGB(200,RGB(250,250,255)),
L"Times New Roman", 40, // The font size in pixel
ID_OBJECT_TEXT, // The unique object ID
ZS_VISIBLE, // Show overlay
1, // shadow effect (offset in pixel)
NULL);
ZD_SetObjectScroll(ID_OBJECT_TEXT, TRUE);
// ******************************************************************************
// Create static help comment
// ------------------------------------------------------------------------------
sLabel = L"\n\nMouse use:\n\nLeft button\nto drag the object.\n\nRight button\ncusor coordinates.\n\n"
L"You can create events to monitor the message flow.\n___________\n\nKeyboard input:\n\n"
L"You can use all navigation keys.\n\nAltogether with SHIFT or CTRL or CTRL+SHIFT for faster move.";
CreateWindowEx(0, L"STATIC", (WCHAR*) sLabel.c_str(), WS_CHILD | WS_VISIBLE | SS_CENTER,
740 - (7 + 120 + 8), 10, 120, 340, hWnd, (HMENU) IDC_STA_Help, zInstance(), NULL);
zSetCTLFont(GetDlgItem(hWnd, IDC_STA_Help), CaptionFont());
// Set the correct anchor property
ZI_SetAnchorMode(GetDlgItem(hWnd, IDC_STA_Help), ANCHOR_RIGHT);
// ******************************************************************************
// Create the "Center" button
// ------------------------------------------------------------------------------
CreateWindowEx(0, BUTTON, L"Fit sprites to glass", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
740 - (7 + 120 + 8), 390, 120, 22, hWnd, (HMENU) IDC_BTN_FIT2GLASS, zInstance(), NULL);
zSetCTLFont(GetDlgItem(hWnd, IDC_BTN_FIT2GLASS), zDefaultFont());
// Set the correct anchor property
ZI_SetAnchorMode(GetDlgItem(hWnd, IDC_BTN_FIT2GLASS), ANCHOR_BOTTOM_RIGHT);
CreateWindowEx(0, BUTTON, L"Glue sprites together", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER,
740 - (7 + 120 + 8), 361, 120, 22, hWnd, (HMENU) IDC_BTN_CHECK, zInstance(), NULL);
zSetCTLFont(GetDlgItem(hWnd, IDC_BTN_CHECK), zDefaultFont());
// Set the correct anchor property
ZI_SetAnchorMode(GetDlgItem(hWnd, IDC_BTN_CHECK), ANCHOR_BOTTOM_RIGHT);
// ******************************************************************************
// Create the status bar
// ------------------------------------------------------------------------------
hCtrl = CreateWindowEx(0, L"msctls_statusbar32", L"", WS_CHILD | WS_VISIBLE | SBARS_TOOLTIPS | SBARS_SIZEGRIP,
0, 423, 740, 23, hWnd, (HMENU) IDC_STATUSBAR, zInstance(), NULL);
zSetCTLFont(hCtrl, zDefaultFont());
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Declaration of local variables
MSG msg;
int nRet = 0;
int IsInitialized = 0;
WNDCLASSEX wcx;
WCHAR szWindowClass[] = L"ZMAIN";
wstring sCaption;
sCaption = L"Aeroglass - GDImage ";
if (sizeof(LONG_PTR) == 8) {
sCaption += L"64-bit"; }
else {
sCaption += L"32-bit";
}
// Register the main window class
wcx.cbSize = sizeof(WNDCLASSEX);
IsInitialized = GetClassInfoEx(hInstance, szWindowClass, &wcx);
if (!IsInitialized) {
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = szWindowClass;
wcx.hIconSm = wcx.hIcon;
if (RegisterClassEx(&wcx)) { IsInitialized = -1; }
}
if (IsInitialized) {
nRet = ZI_LoadDLL (L"");
g_hInst = hInstance; // Stocke le handle d'instance dans la variable globale
UINT dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
UINT dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
RECT rc;
SetRect(&rc, 0, 0, 740, 443);
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
int x = max((GetSystemMetrics(SM_CXSCREEN) - rc.right - rc.left) / 2, 0);
int y = max((GetSystemMetrics(SM_CYSCREEN) - rc.bottom - rc.top) / 2, 0);
HWND hWnd = CreateWindowEx(
dwExStyle, // Optional window styles.
szWindowClass, // Window class
(WCHAR*) sCaption.c_str(), // Window text
dwStyle, // Window style
x, y, rc.right - rc.left, rc.bottom - rc.top,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hWnd) {
// Populate the window with all child controls
AddChildControls(hWnd);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
SetFocus(GetDlgItem(hWnd, IDC_CTRL));
// Main message loop
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
nRet = (int) msg.wParam;
}
}
return nRet;
}
// Main winproc
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
int wmId = 0, wmEvent = 0;
PAINTSTRUCT ps; RECT rc; HWND hCtrl = 0;
WCHAR sFullName[MAX_PATH] = {0};
MINMAXINFO* MinMax;
wstring sLabel;
HPEN hPen = 0, OldPen = 0;
long K = 0, x = 0, y = 0, UB = 0, xCurrentScroll = 0, yCurrentScroll = 0, BoundWidthGlass = 0, BoundHeightGlass = 0,
BoundWidth = 0, BoundHeight = 0, xGlass = 0, yGlass = 0;
switch (uMsg) {
case WM_GETMINMAXINFO: // Set minimum/maximum dialog size
MinMax = (MINMAXINFO*) lParam;
SetRect(&rc, 0, 0, 740, 443);
AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE) ; // Adjust Window To True Requested Size
MinMax->ptMinTrackSize.x = rc.right - rc.left;
MinMax->ptMinTrackSize.y = rc.bottom - rc.top;
return 0;
case WM_CTLCOLORSTATIC:
switch(GetDlgCtrlID((HWND) lParam)) {
case IDC_STA_Help:
SetTextColor((HDC) wParam, RGB(2,77,220));
SetBkMode((HDC) wParam, TRANSPARENT);
// Use a custom background for the help control
GetClientRect(GetDlgItem(hWnd, IDC_STA_Help), &rc);
ZI_GradientPaintDC((HDC) wParam, 0, 0, rc.right, rc.bottom, RGB(228,227,255), RGB(188,187,211));
hPen = CreatePen(0, 1, RGB(128,128,192));
OldPen = (HPEN) SelectObject((HDC) wParam, hPen);
SelectObject((HDC) wParam, GetStockObject(NULL_BRUSH));
RoundRect((HDC) wParam, 0, 0, rc.right, rc.bottom, 8, 8);
SelectObject((HDC) wParam, OldPen);
DeleteObject(hPen);
return 0;
case IDC_BTN_CHECK:
SetBkMode((HDC) wParam, TRANSPARENT);
// Use a custom background for the Check control
GetClientRect(GetDlgItem(hWnd, IDC_BTN_CHECK), &rc);
ZI_GradientPaintDC((HDC) wParam, 0, 0, rc.right, rc.bottom, RGB(179,178,198), RGB(176,175,196));
SelectObject((HDC) wParam, GetStockObject(NULL_BRUSH));
return 0;
}
break;
case WM_SIZE:
if (wParam != SIZE_MINIMIZED) {
// Move Status bar
hCtrl = GetDlgItem(hWnd, IDC_STATUSBAR);
if (hCtrl) { SendMessage(hCtrl, uMsg, wParam, lParam); }
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Process menu command
switch (wmId) {
case IDC_BTN_FIT2GLASS:
hCtrl = GetDlgItem(hWnd, IDC_CTRL);
GetClientRect(hCtrl, &rc);
xCurrentScroll = (long) ZI_GetProperty(hCtrl, ZI_Horizontal);
yCurrentScroll = (long) ZI_GetProperty(hCtrl, ZI_Vertical);
// ID_AERO_GLASS
ZD_GetObjectBound(ID_AERO_GLASS, BoundWidthGlass, BoundHeightGlass);
xGlass = max((rc.right - BoundWidthGlass) / 2 + xCurrentScroll, 0);
yGlass = max((rc.bottom - BoundHeightGlass) / 2 + yCurrentScroll, 0);
ZD_SetObjectXY(ID_AERO_GLASS, xGlass, yGlass, ZD_DRAW_DEFERRED); // Move, without immediate redraw
// ID_OBJECT_TEXT
ZD_GetObjectBound(ID_OBJECT_TEXT, BoundWidth, BoundHeight);
x = xGlass + max((BoundWidthGlass - BoundWidth) / 2, 0);
y = yGlass + 10; // max((BoundHeightGlass& - BoundHeight) \ 2, 0)
ZD_SetObjectXY(ID_OBJECT_TEXT, x, y, ZD_DRAW_DEFERRED); // Move, without immediate redraw
// ID_LIGHT
ZD_GetObjectBound(ID_LIGHT, BoundWidth, BoundHeight);
x = (long) (xGlass + BoundWidthGlass - (BoundWidth * 0.56f));
y = (long) (yGlass - (BoundHeight / 3.0f));
ZD_SetObjectXY(ID_LIGHT, x, y, ZD_DRAW_DEFERRED); // Move, without immediate redraw
// ID_TWIN
ZD_GetObjectBound(ID_TWIN, BoundWidth, BoundHeight);
x = xGlass - 20;
y = (long) (yGlass + BoundHeightGlass - (BoundHeight * 0.95f));
ZD_SetObjectXY(ID_TWIN, x, y, ZD_DRAW_DEFERRED); // Move, without immediate redraw
// ID_BRUSH
ZD_GetObjectBound(ID_BRUSH, BoundWidth, BoundHeight);
x = (long) (xGlass + max((BoundWidthGlass - BoundWidth * 0.95f) / 2, 0));
y = (long) (yGlass + max((BoundHeightGlass - BoundHeight * 1.10f) / 2, 0));
ZD_SetObjectXY(ID_BRUSH, x, y, ZD_DRAW_DEFERRED); // Move, without immediate redraw
// Request GDImage to update the control display to show the changes
ZI_UpdateWindow(hCtrl, 0);
break;
}
return 0;
case WM_ERASEBKGND:
GetClientRect (hWnd, &rc);
ZI_GradientPaintDC((HDC) wParam, 0, 0, rc.right, rc.bottom, RGB(228,227,227), RGB(168,167,191));
return 1;
case WM_PAINT:
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
UB = (long) g_hBitmap.size();
for (K = 0; K < UB; ++K) {
DeleteObject(g_hBitmap[K]);
}
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void ScreenCaptureToBackground(IN HWND hParent) {
long SysXRes = GetSystemMetrics(SM_CXSCREEN);
long SysYRes = GetSystemMetrics(SM_CYSCREEN);
HWND hCtrl = GetDlgItem(hParent, IDC_CTRL);
ZI_CreateImageBackground(hCtrl, SysXRes, SysYRes);
HWND hDeskTop = GetDesktopWindow();
HDC hDCSrce = GetWindowDC(hDeskTop);
BitBlt(ZI_GetDC(hCtrl), 0, 0, SysXRes, SysYRes, hDCSrce, 0, 0, SRCCOPY);
ReleaseDC(hDeskTop, hDCSrce);
}
LRESULT CALLBACK MyCallBack(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
LRESULT nRet = 0; // Do not stop the event processing in GDImage
RECT rc;
long ObjectID = 0, x = 0, y = 0, x1 = 0, y1 = 0, x2Div2 = 0, y2Div2 = 0, BoundWidth = 0, BoundHeight = 0, useWidth = 0, useHeight = 0,
UseStep = 0, xCapture = 0, yCapture = 0, Dx = 0, Dy = 0, xCurrentScroll = 0, yCurrentScroll = 0, ID;
wstring sMsg, sLabel;
HWND hParent = GetParent(hWnd);
if (hWnd == GetDlgItem(hParent, IDC_CTRL)) { // In case we use the same callback for several GDImage control
// make sure that we handle the good one.
switch (uMsg) {
case WM_LBUTTONDOWN:
ObjectID = ZI_MouseOverObjectID();
if (ObjectID == GetDlgCtrlID(hWnd)) {
sLabel = $Background; }
else {
sLabel = ZD_GetObjectImageLabel(ObjectID);
}
sMsg = L"WM_LBUTTONDOWN on object "; sMsg += STRL$(ObjectID); sMsg += L" >", sMsg += sLabel; sMsg += L"<";
SetWindowText(GetDlgItem(hParent, IDC_STATUSBAR), (WCHAR*) sMsg.c_str());
break;
case WM_RBUTTONDOWN:
ObjectID = ZI_MouseOverObjectID();
if (ObjectID == GetDlgCtrlID(hWnd)) {
sLabel = $Background; }
else {
sLabel = ZD_GetObjectImageLabel(ObjectID);
}
sMsg = L"WM_RBUTTONDOWN on object "; sMsg += STRL$(ObjectID); sMsg += L" >";
sMsg += sLabel; sMsg += L"< at location "; sMsg += STRL$(LOWORD(lParam)); sMsg += L","; sMsg += STRL$(HIWORD(lParam));
SetWindowText(GetDlgItem(hParent, IDC_STATUSBAR), (WCHAR*) sMsg.c_str());
break;
case WM_MOUSEMOVE:
ObjectID = ZI_GetMovingSpriteID();
if (ObjectID) {
// Does ID_BTN_CHECK is checked ?
if (SendMessage(GetDlgItem(GetParent(hWnd), IDC_BTN_CHECK), BM_GETCHECK, 0, 0)) {
x = LOWORD(lParam); y = HIWORD(lParam);
xCurrentScroll = (long) ZI_GetProperty(hWnd, ZI_Horizontal);
yCurrentScroll = (long) ZI_GetProperty(hWnd, ZI_Vertical);
ZD_GetObjectXY(ObjectID, x1, y1);
ZD_GetObjectXYcapture(ObjectID, xCapture, yCapture);
Dx = (x - xCapture + xCurrentScroll) - x1;
Dy = (y - yCapture + yCurrentScroll) - y1;
for (ID = ID_FIRST; ID <= ID_LAST; ++ID) {
if (ID != ObjectID) {
ZD_GetObjectXY(ID, x, y);
// Add the DX,DY offset
ZD_SetObjectXY(ID, x + Dx, y + Dy, ZD_DRAW_DEFERRED); // Move, without immediate redraw
}
}
// Note: The display's refresh is yeld by the default GDImage WM_MOUSE event
}
}
break;
case WM_KEYDOWN:
ObjectID = ZI_GetObjectFocusID();
if (ObjectID) {
ZD_GetObjectXY(ObjectID, x, y);
x1 = x; // Make a copy to keep the orignal x location unchanged
y1 = y; // Make a copy to keep the orignal y location unchanged
// Check accelerator keys to compute the step range
if (ZI_IsCtrlKeyPressed()) {
UseStep = 4; if (ZI_IsShiftKeyPressed()) { UseStep = 16; }
}
else if (ZI_IsShiftKeyPressed()) {
UseStep = 2; }
else {
UseStep = 1;
}
if (ZD_GetObjectScroll(ObjectID)) { // if (object scroll with the bitmap background
// Get the size of the bitmap background
ZI_GetBitmapSize(ZI_GetBMP(GetDlgItem(hParent, IDC_CTRL)), useWidth, useHeight); }
else {
// Get the control client size
GetClientRect(GetDlgItem(hParent, IDC_CTRL), &rc);
useWidth = rc.right; useHeight = rc.bottom;
}
// Get the sprite object size
ZD_GetObjectBound(ObjectID, BoundWidth, BoundHeight);
x2Div2 = BoundWidth / 2; y2Div2 = BoundHeight / 2;
switch (wParam) {
case VK_HOME:
x1 = 0;
break;
case VK_END:
x1 = max(useWidth - BoundWidth, 0);
break;
case VK_PRIOR:
y1 = 0;
break;
case VK_NEXT:
y1 = max(useHeight - BoundHeight, 0);
break;
case VK_LEFT:
case VK_NUMPAD4:
if (x1 > -x2Div2) { x1 = max(x1 - UseStep, -x2Div2); }
break;
case VK_UP:
case VK_NUMPAD8:
if (y1 > -y2Div2) { y1 = max(y1 - UseStep, -y2Div2); }
break;
case VK_RIGHT:
case VK_NUMPAD6:
if (x1 < useWidth - x2Div2) { x1 = min(x1 + UseStep, useWidth - x2Div2); }
break;
case VK_DOWN:
case VK_NUMPAD2:
if (y1 < useHeight - y2Div2) {
y1 = min(y1 + UseStep, useHeight - y2Div2);
}
break;
}
if ((x != x1) || (y != y1)) {
x = x1; y = y1; ZD_SetObjectXY(ObjectID, x1, y1, TRUE);
}
sMsg = L"Object "; sMsg += STRL$(ObjectID); sMsg += L" coordinates";
sMsg += STRL$(x); sMsg += L","; sMsg += STRL$(y);
SetWindowText(GetDlgItem(hParent, IDC_STATUSBAR), (WCHAR*) sMsg.c_str());
}
break;
}
}
return nRet;
}
The attached ZIP file comprise only the 64-bit version.