1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-10-05 19:18:01 +08:00
ULib/contrib/signer/window.cpp
stefanocasazza fc24169677 sync
2016-09-15 18:36:41 +02:00

328 lines
10 KiB
C++

/* window.cpp */
#include "window.h"
ATOM Window::WindowClassAtom;
HINSTANCE Window::AppInstance;
LRESULT CALLBACK Window::FirstWindowProcReflector(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
U_TRACE(2, "Window::FirstWindowProcReflector(%d,%d,%d,%d)", hwnd, uMsg, wParam, lParam)
Window* wnd = 0;
if (uMsg == WM_NCCREATE)
{
// This is the first message a window gets (so MSDN says anyway).
// Take this opportunity to "link" the HWND to the 'this' ptr, steering
// messages to the class instance's WindowProc().
wnd = (Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
// Set a backreference to this class instance in the HWND.
SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)(wnd));
// Set a new WindowProc now that we have the peliminaries done.
// We could instead simply do the contents of Window::WindowProcReflector
// in the 'else' clause below, but this way we eliminate an unnecessary 'if/else' on
// every message. Yeah, it's probably not worth the trouble.
SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR) &Window::WindowProcReflector);
// Finally, store the window handle in the class.
wnd->WindowHandle = hwnd;
}
else
{
// Should never get here.
U_ERROR("Unexpected windows message %u received too early in window initialization", uMsg);
}
return wnd->WindowProc(uMsg, wParam, lParam);
}
bool Window::Create(Window* parent, DWORD Style)
{
U_TRACE(2, "Window::Create(%p,%lld)", parent, Style)
// First register the window class, if we haven't already
if (registerWindowClass() == false) return false; // Registration failed
// Save our parent, we'll probably need it eventually.
Parent = parent;
// Create the window instance
WindowHandle = CreateWindowEx(
// Extended Style
0,
"MainWindowClass", // MAKEINTATOM(WindowClassAtom), // window class atom (name)
"Hello", // no title-bar string yet
// Style bits
Style,
// Default positions and size
CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
// Parent Window
(parent == 0 ? 0 : parent->GetHWND()),
// use class menu
0,
// The application instance
GetInstance(),
// The this ptr, which we'll use to set up the WindowProc reflection.
(LPVOID)this);
U_RETURN(WindowHandle != 0);
}
bool Window::registerWindowClass()
{
U_TRACE(2, "Window::registerWindowClass()")
if (WindowClassAtom == 0)
{
// We're not registered yet
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
// Some sensible style defaults
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
// Our default window procedure. This replaces itself
// on the first call with the simpler Window::WindowProcReflector().
wc.lpfnWndProc = Window::FirstWindowProcReflector;
// No class bytes
wc.cbClsExtra = 0;
// One pointer to REFLECTION_INFO in the extra window instance bytes
wc.cbWndExtra = 4;
// The app instance
wc.hInstance = GetInstance();
// Use a bunch of system defaults for the GUI elements
wc.hIcon = 0;
wc.hIconSm = 0;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
// No menu
wc.lpszMenuName = 0;
// We'll get a little crazy here with the class name
wc.lpszClassName = "MainWindowClass";
// All set, try to register
WindowClassAtom = RegisterClassEx(&wc);
if (WindowClassAtom == 0) U_RETURN(false); // Failed
}
// We're registered, or already were before the call,
// return success in either case.
U_RETURN(true);
}
bool Window::MessageLoop()
{
U_TRACE(2, "Window::MessageLoop()")
MSG msg;
while (GetMessage(&msg, 0, 0, 0) != 0 &&
GetMessage(&msg, 0, 0, 0) != -1)
{
if (!IsWindow(WindowHandle) ||
!IsDialogMessage(WindowHandle, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
U_RETURN(true);
}
void Window::CenterWindow()
{
U_TRACE(2, "Window::CenterWindow()")
POINT p;
RECT WindowRect, ParentRect;
int WindowWidth, WindowHeight;
// Get the window rectangle
WindowRect = GetWindowRect();
if (GetParent() == 0) ::GetWindowRect(GetDesktopWindow(), &ParentRect); // Center on desktop window
else ::GetClientRect(GetParent()->GetHWND(), &ParentRect); // Center on client area of parent
WindowWidth = WindowRect.right - WindowRect.left;
WindowHeight = WindowRect.bottom - WindowRect.top;
// Find center of area we're centering on
p.x = (ParentRect.right - ParentRect.left) / 2;
p.y = (ParentRect.bottom - ParentRect.top) / 2;
// Convert that to screen coords
if (GetParent() == 0) ClientToScreen(GetDesktopWindow(), &p);
else ClientToScreen(GetParent()->GetHWND(), &p);
// Calculate new top left corner for window
p.x -= WindowWidth / 2;
p.y -= WindowHeight / 2;
// And finally move the window
MoveWindow(p.x, p.y, WindowWidth, WindowHeight);
}
bool Window::SetDlgItemFont(int id, const TCHAR* fontname, int Pointsize, int Weight, bool Italic, bool Underline, bool Strikeout)
{
U_TRACE(2, "Window::SetDlgItemFont(%d,%S,%d,%d,%b,%b,%b)", id, fontname, Pointsize, Weight, Italic, Underline, Strikeout)
HWND ctrl = GetDlgItem(id);
if (ctrl == 0) U_RETURN(false); // Couldn't get that ID
// We need the DC for the point size calculation.
HDC hdc = GetDC(ctrl);
// Create the font. We have to keep it around until the dialog item
// goes away - basically until we're destroyed.
HFONT hfnt = CreateFont(-MulDiv(Pointsize, GetDeviceCaps(hdc, LOGPIXELSY), 72),
0, 0, 0, Weight,
Italic ? TRUE : FALSE,
Underline ? TRUE : FALSE,
Strikeout ? TRUE : FALSE,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname);
if (hfnt == 0) U_RETURN(false); // Font creation failed
// Set the new font, and redraw any text which was already in the item.
SendMessage(ctrl, WM_SETFONT, (WPARAM) hfnt, TRUE);
// Store the handle so that we can DeleteObject() it in dtor
Fonts.push_back(hfnt);
U_RETURN(true);
}
RECT Window::ScreenToClient(const RECT &r) const
{
U_TRACE(2, "Window::ScreenToClient(%p)", &r)
RECT ret;
POINT tl, br;
tl.y = r.top;
tl.x = r.left;
::ScreenToClient(GetHWND(), &tl);
br.y = r.bottom;
br.x = r.right;
::ScreenToClient(GetHWND(), &br);
ret.top = tl.y;
ret.left = tl.x;
ret.bottom = br.y;
ret.right = br.x;
return ret;
}
// initialization of the tooltip capability
void Window::ActivateTooltips()
{
U_TRACE(2, "Window::ActivateTooltips()")
if (TooltipHandle != 0) return; // already initialized
// create a window for the tool tips - will be invisible most of the time
if ((TooltipHandle = CreateWindowEx(0, (LPCTSTR) TOOLTIPS_CLASS, 0,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetHWND(),
0, GetInstance(), 0)) == 0)
{
char buffer[4096];
(void) write(2, buffer,
u__snprintf(buffer, sizeof(buffer),
U_CONSTANT_TO_PARAM("Warning: call to CreateWindowEx failed when initializing tooltips. Error = %8.8x\n"), GetLastError()));
return;
}
// must be topmost so that tooltips will display on top
SetWindowPos(TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// some of our tooltips are lengthy, and will disappear before they can be
// read with the default windows delay, so we set a long (30s) delay here.
SendMessage(TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM) MAKELONG(30000, 0));
}
// adds a tooltip to element 'target' in window 'win'
// note: text is limited to 80 chars (grumble)
void Window::AddTooltip(HWND target, HWND win, const char* text)
{
U_TRACE(2, "Window::AddTooltip(%d,%d,%S)", target, win, text)
if (!TooltipHandle) ActivateTooltips();
TOOLINFO ti;
memset((void*)&ti, 0, sizeof(ti));
ti.hwnd = win;
ti.cbSize = sizeof(ti);
ti.uId = (UINT_PTR)target;
ti.uFlags = TTF_IDISHWND | // add tool based on handle not ID
TTF_SUBCLASS; // tool is to subclass the window in order to automatically get mouse events
ti.lpszText = (LPTSTR)text; // pointer to text or string resource
SendMessage(TooltipHandle, (UINT)TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}
// this is the handler for TTN_GETDISPINFO notifications
BOOL Window::TooltipNotificationHandler(LPARAM lParam)
{
U_TRACE(2, "Window::TooltipNotificationHandler(%d)", lParam)
int ctrlID;
NMTTDISPINFO* dispinfo = (NMTTDISPINFO*)lParam;
if ((dispinfo->uFlags & TTF_IDISHWND) &&
((ctrlID = GetDlgCtrlID((HWND)dispinfo->hdr.idFrom)) != 0) &&
TooltipStrings.find(ctrlID))
{
// enable multiple lines
SendMessage(dispinfo->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, 450);
// this is quite ugly. Apparently even when using string resources
// the tooltip length still can't exceed 80 chars. So, we fetch the
// resource into our own buffer and use that
TCHAR buf[2048];
LoadString(GetInstance(), TooltipStrings.elem(), (LPTSTR)buf, (sizeof(buf) / sizeof(TCHAR)));
dispinfo->lpszText = buf;
// set this flag so that the control will not ask for this again
dispinfo->uFlags |= TTF_DI_SETITEM;
dispinfo->hinst = 0;
U_RETURN(TRUE);
}
U_RETURN(FALSE);
}
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* Window::dump(bool reset) const
{
*UObjectIO::os << "Parent " << Parent << '\n'
<< "WindowHandle " << WindowHandle << '\n'
<< "TooltipHandle " << TooltipHandle << '\n'
<< "Fonts (UVector<HFONT> " << (void*)&Fonts << ')';
if (reset)
{
UObjectIO::output();
return UObjectIO::buffer_output;
}
return 0;
}
#endif