--- /dev/null
+/*
+* PROJECT: ReactOS Character Map
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: base/applications/charmap/MainWindow.cpp
+* PURPOSE: Implements the main dialog window
+* COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+*/
+
+
+#include "precomp.h"
+#include "MainWindow.h"
+
+
+/* DATA *****************************************************/
+
+#define ID_ABOUT 0x1
+
+HINSTANCE g_hInstance = NULL;
+
+
+/* PUBLIC METHODS **********************************************/
+
+CCharMapWindow::CCharMapWindow(void) :
+ m_hMainWnd(NULL),
+ m_hStatusBar(NULL),
+ m_CmdShow(0),
+ m_hRichEd(NULL),
+ m_GridView(nullptr)
+{
+ m_GridView = new CGridView();
+}
+
+CCharMapWindow::~CCharMapWindow(void)
+{
+}
+
+bool
+CCharMapWindow::Create(_In_ HINSTANCE hInst,
+ _In_ int nCmdShow)
+{
+ INITCOMMONCONTROLSEX icex;
+ CAtlStringW szAppName;
+ int Ret = 1;
+
+ // Store the instance
+ g_hInstance = hInst;
+ m_CmdShow = nCmdShow;
+
+ // Initialize common controls
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Load the application name
+ if (szAppName.LoadStringW(g_hInstance, IDS_TITLE))
+ {
+ // Initialize the main window
+ if (Initialize(szAppName, nCmdShow))
+ {
+ // Run the application
+ Ret = Run();
+
+ // Uninitialize the main window
+ Uninitialize();
+ }
+ }
+
+ return (Ret == 0);
+}
+
+
+
+/* PRIVATE METHODS **********************************************/
+
+bool
+CCharMapWindow::Initialize(_In_z_ LPCTSTR lpCaption,
+ _In_ int nCmdShow)
+{
+ // The dialog has a rich edit text box
+ m_hRichEd = LoadLibraryW(L"riched20.DLL");
+ if (m_hRichEd == NULL) return false;
+
+ return !!(CreateDialogParamW(g_hInstance,
+ MAKEINTRESOURCE(IDD_CHARMAP),
+ NULL,
+ DialogProc,
+ (LPARAM)this));
+}
+
+void
+CCharMapWindow::Uninitialize(void)
+{
+ if (m_hRichEd)
+ FreeLibrary(m_hRichEd);
+}
+
+int
+CCharMapWindow::Run(void)
+{
+ MSG Msg;
+
+ // Pump the message queue
+ while (GetMessageW(&Msg, NULL, 0, 0) != 0)
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }
+
+ return 0;
+}
+
+void
+CCharMapWindow::UpdateStatusBar(_In_ bool InMenuLoop)
+{
+ SendMessageW(m_hStatusBar,
+ SB_SIMPLE,
+ (WPARAM)InMenuLoop,
+ 0);
+}
+
+bool
+CCharMapWindow::CreateStatusBar(void)
+{
+ int StatWidths[] = { 110, -1 }; // widths of status bar
+ bool bRet = FALSE;
+
+ // Create the status bar
+ m_hStatusBar = CreateWindowExW(0,
+ STATUSCLASSNAME,
+ NULL,
+ WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
+ 0, 0, 0, 0,
+ m_hMainWnd,
+ (HMENU)IDD_STATUSBAR,
+ g_hInstance,
+ NULL);
+ if (m_hStatusBar)
+ {
+ // Create the sections
+ bRet = (SendMessageW(m_hStatusBar,
+ SB_SETPARTS,
+ sizeof(StatWidths) / sizeof(int),
+ (LPARAM)StatWidths) != 0);
+
+ // Set the status bar for multiple parts output
+ SendMessage(m_hStatusBar, SB_SIMPLE, (WPARAM)FALSE, (LPARAM)0);
+ }
+
+ return bRet;
+}
+
+bool
+CCharMapWindow::StatusBarLoadString(_In_ HWND hStatusBar,
+ _In_ INT PartId,
+ _In_ HINSTANCE hInstance,
+ _In_ UINT uID)
+{
+ CAtlStringW szMessage;
+ bool bRet = false;
+
+ // Load the string from the resource
+ if (szMessage.LoadStringW(hInstance, uID))
+ {
+ // Display it on the status bar
+ bRet = (SendMessageW(hStatusBar,
+ SB_SETTEXT,
+ (WPARAM)PartId,
+ (LPARAM)szMessage.GetBuffer()) != 0);
+ }
+
+ return bRet;
+}
+
+BOOL
+CCharMapWindow::OnCreate(_In_ HWND hDlg)
+{
+ m_hMainWnd = hDlg;
+
+ if (!CreateStatusBar())
+ return FALSE;
+
+ if (!m_GridView->Create(hDlg))
+ return FALSE;
+
+ // Load an 'about' option into the system menu
+ HMENU hSysMenu;
+ hSysMenu = GetSystemMenu(m_hMainWnd, FALSE);
+ if (hSysMenu != NULL)
+ {
+ CAtlStringW AboutText;
+ if (AboutText.LoadStringW(IDS_ABOUT))
+ {
+ AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenuW(hSysMenu, MF_STRING, ID_ABOUT, AboutText);
+ }
+ }
+
+ // Add all the fonts to the
+ if (!CreateFontComboBox())
+ return FALSE;
+
+ // Configure Richedit control for sending notification changes.
+ DWORD evMask;
+ evMask = SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_GETEVENTMASK, 0, 0);
+ evMask |= ENM_CHANGE;
+ SendDlgItemMessage(hDlg, IDC_TEXTBOX, EM_SETEVENTMASK, 0, (LPARAM)evMask);
+
+ // Display the window according to the user request
+ ShowWindow(m_hMainWnd, m_CmdShow);
+
+ return TRUE;
+}
+
+BOOL
+CCharMapWindow::OnSize(void)
+{
+ RECT rcClient, rcStatus;
+ INT lvHeight, iStatusHeight;
+
+ // Resize the status bar
+ SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
+
+ // Get the statusbar rect and save the height
+ GetWindowRect(m_hStatusBar, &rcStatus);
+ iStatusHeight = rcStatus.bottom - rcStatus.top;
+
+ // Get the full client rect
+ GetClientRect(m_hMainWnd, &rcClient);
+
+ // Calculate the remaining height for the treeview
+ lvHeight = rcClient.bottom - iStatusHeight;
+
+ // Resize the device view
+ //m_GridView->OnSize(0,
+ // iToolHeight,
+ // rcClient.right,
+ // lvHeight);
+
+ return TRUE;
+}
+
+BOOL
+CCharMapWindow::OnNotify(_In_ LPARAM lParam)
+{
+ LPNMHDR NmHdr = (LPNMHDR)lParam;
+ LRESULT Ret = 0;
+
+ switch (NmHdr->code)
+ {
+ case NM_RCLICK:
+ {
+ break;
+ }
+
+ case NM_DBLCLK:
+ case NM_RETURN:
+ {
+ break;
+ }
+ }
+
+ return Ret;
+}
+
+BOOL
+CCharMapWindow::OnContext(_In_ LPARAM lParam)
+{
+ return 0;// m_GridView->OnContextMenu(lParam);
+}
+
+BOOL
+CCharMapWindow::OnCommand(_In_ WPARAM wParam,
+ _In_ LPARAM /*lParam*/)
+{
+ LRESULT RetCode = 0;
+ WORD Msg;
+
+ // Get the message
+ Msg = LOWORD(wParam);
+
+ switch (Msg)
+ {
+ case IDC_CHECK_ADVANCED:
+ break;
+
+ default:
+ // We didn't handle it
+ RetCode = -1;
+ break;
+ }
+
+ return RetCode;
+}
+
+BOOL
+CCharMapWindow::OnDestroy(void)
+{
+ // Clear the user data pointer
+ SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
+
+ // Break the message loop
+ PostQuitMessage(0);
+
+ return TRUE;
+}
+
+INT_PTR CALLBACK
+CCharMapWindow::DialogProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT Msg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ CCharMapWindow *This;
+ LRESULT RetCode = 0;
+
+ // Get the object pointer from window context
+ This = (CCharMapWindow *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (This == NULL)
+ {
+ // Check that this isn't a create message
+ if (Msg != WM_INITDIALOG)
+ {
+ // Don't handle null info pointer
+ return FALSE;
+ }
+ }
+
+ switch (Msg)
+ {
+ case WM_INITDIALOG:
+ {
+ // Get the object pointer from the create param
+ This = (CCharMapWindow *)lParam;
+
+ // Store the pointer in the window's global user data
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)This);
+
+ // Call the create handler
+ return This->OnCreate(hwndDlg);
+ }
+
+ case WM_SIZE:
+ {
+ return This->OnSize();
+ }
+
+ case WM_NOTIFY:
+ {
+ return This->OnNotify(lParam);
+ }
+
+ case WM_CONTEXTMENU:
+ {
+ return This->OnContext(lParam);
+ }
+
+ case WM_COMMAND:
+ {
+ return This->OnCommand(wParam, lParam);
+ }
+
+ case WM_SYSCOMMAND:
+ switch (wParam)
+ {
+ case ID_ABOUT:
+ // Apportion blame
+ MessageBoxW(This->m_hMainWnd,
+ L"ReactOS Character Map\r\nCopyright Ged Murphy 2015",
+ L"About",
+ MB_OK | MB_APPLMODAL);
+ break;
+ }
+ break;
+
+ case WM_ENTERMENULOOP:
+ {
+ This->UpdateStatusBar(true);
+ return TRUE;
+ }
+
+ case WM_EXITMENULOOP:
+ {
+ This->UpdateStatusBar(false);
+ return TRUE;
+ }
+
+ case WM_CLOSE:
+ {
+ // Destroy the main window
+ return DestroyWindow(hwndDlg);
+ }
+
+
+ case WM_DESTROY:
+ {
+ // Call the destroy handler
+ return This->OnDestroy();
+ }
+ }
+
+ return FALSE;
+}
+
+struct EnumFontParams
+{
+ CCharMapWindow *This;
+ HWND hCombo;
+};
+
+int
+CALLBACK
+CCharMapWindow::EnumDisplayFont(ENUMLOGFONTEXW *lpelfe,
+ NEWTEXTMETRICEXW *lpntme,
+ DWORD FontType,
+ LPARAM lParam)
+{
+ EnumFontParams *Params = (EnumFontParams *)lParam;
+ LPWSTR pszName = lpelfe->elfLogFont.lfFaceName;
+
+ /* Skip rotated font */
+ if (pszName[0] == L'@') return 1;
+
+ /* make sure font doesn't already exist in our list */
+ if (SendMessageW(Params->hCombo,
+ CB_FINDSTRINGEXACT,
+ 0,
+ (LPARAM)pszName) == CB_ERR)
+ {
+ INT idx;
+ idx = (INT)SendMessageW(Params->hCombo,
+ CB_ADDSTRING,
+ 0,
+ (LPARAM)pszName);
+
+ /* record the font's attributes (Fixedwidth and Truetype) */
+ BOOL fFixed = (lpelfe->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ? TRUE : FALSE;
+ BOOL fTrueType = (lpelfe->elfLogFont.lfOutPrecision == OUT_STROKE_PRECIS) ? TRUE : FALSE;
+
+ /* store this information in the list-item's userdata area */
+ SendMessageW(Params->hCombo,
+ CB_SETITEMDATA,
+ idx,
+ MAKEWPARAM(fFixed, fTrueType));
+ }
+
+ return 1;
+}
+
+
+bool
+CCharMapWindow::CreateFontComboBox()
+{
+ HWND hCombo;
+ hCombo = GetDlgItem(m_hMainWnd, IDC_FONTCOMBO);
+
+ NONCLIENTMETRICSW NonClientMetrics;
+ NonClientMetrics.cbSize = sizeof(NONCLIENTMETRICSW);
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
+ sizeof(NONCLIENTMETRICSW),
+ &NonClientMetrics,
+ 0);
+
+ // Get a handle to the font
+ HFONT GuiFont;
+ GuiFont = CreateFontIndirectW(&NonClientMetrics.lfMessageFont);
+
+ // Set the font used in the combo box
+ SendMessageW(hCombo,
+ WM_SETFONT,
+ (WPARAM)GuiFont,
+ 0);
+
+ // Set the fonts which we want to enumerate
+ LOGFONTW FontsToEnum;
+ ZeroMemory(&FontsToEnum, sizeof(LOGFONTW));
+ FontsToEnum.lfCharSet = DEFAULT_CHARSET;
+
+ // Set the params we want to pass to the callback
+ EnumFontParams Params;
+ Params.This = this;
+ Params.hCombo = hCombo;
+
+ // Get a DC for combo box
+ HDC hdc;
+ hdc = GetDC(hCombo);
+
+ // Enumerate all the fonts
+ int ret;
+ ret = EnumFontFamiliesExW(hdc,
+ &FontsToEnum,
+ (FONTENUMPROCW)EnumDisplayFont,
+ (LPARAM)&Params,
+ 0);
+
+ ReleaseDC(hCombo, hdc);
+ DeleteObject(GuiFont);
+
+ // Select the first item in the list
+ SendMessageW(hCombo,
+ CB_SETCURSEL,
+ 0,
+ 0);
+
+ return (ret == 1);
+}
\ No newline at end of file