[CALC] Improvements and fixes for the numeric text output. CORE-8486
[reactos.git] / base / applications / calc / winmain.c
index c6723ba..db6e7b3 100644 (file)
@@ -1,12 +1,26 @@
-#include "calc.h"
+/*
+ * ReactOS Calc (main program)
+ *
+ * Copyright 2007-2017, Carlo Bramini
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
-#include <winbase.h>
-#include <wingdi.h>
-#include <winreg.h>
-#include <shellapi.h>
-#include <commctrl.h>
+#include "calc.h"
 
-#define HTMLHELP_PATH(_pt)  TEXT("%systemroot%\\Help\\calc.chm::") TEXT(_pt)
+#define HTMLHELP_PATH(_pt)  _T("%systemroot%\\Help\\calc.chm::") _T(_pt)
 
 #define MAKE_BITMASK4(_show_b16, _show_b10, _show_b8, _show_b2) \
     (((_show_b2)  << 0) | \
@@ -34,9 +48,9 @@
 #define BITMASK_OCT_MASK    0x02
 #define BITMASK_BIN_MASK    0x01
 
-#define CALC_CLR_RED        0x000000FF
-#define CALC_CLR_BLUE       0x00FF0000
-#define CALC_CLR_PURP       0x00FF00FF
+#define CALC_CLR_RED        RGB(0xFF, 0x00, 0x00)
+#define CALC_CLR_BLUE       RGB(0x00, 0x00, 0xFF)
+#define CALC_CLR_PURP       RGB(0xFF, 0x00, 0xFF)
 
 typedef struct {
     CHAR key; // Virtual key identifier
@@ -219,85 +233,125 @@ static const function_table_t function_table[] = {
     { IDC_BUTTON_LEFTPAR,  NO_CHAIN,              0, run_lpar,    NULL,        NULL,     NULL,     },
 };
 
+/* Sub-classing information for theming support */
+typedef struct{
+    BOOL    bHover;
+    WNDPROC oldProc;
+} BTNINFO,*LPBTNINFO;
+
+
 /*
-*/
+ * Global variable declaration
+ */
 
-calc_t calc;
+calc_t  calc;
 
-static void load_config(void)
+/* Hot-state info for theming support */
+BTNINFO BtnInfo[255];
+UINT    BtnCount;
+
+static void UpdateNumberIntl(void)
 {
+    /* Get current user defaults */
+    if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, calc.sDecimal, SIZEOF(calc.sDecimal)))
+        _tcscpy(calc.sDecimal, _T("."));
+
+    if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, calc.sThousand, SIZEOF(calc.sThousand)))
+        _tcscpy(calc.sThousand, _T(","));
+
+    /* get the string lengths */
+    calc.sDecimal_len = _tcslen(calc.sDecimal);
+    calc.sThousand_len = _tcslen(calc.sThousand);
+}
+
+static int LoadRegInt(LPCTSTR lpszApp, LPCTSTR lpszKey, int iDefault)
+{
+    HKEY  hKey;
+    int   iValue;
     DWORD tmp;
-    HKEY hKey;
-    
-    /* If no settings are found in the registry, then use the default options */
-    calc.layout = CALC_LAYOUT_STANDARD;
-    calc.usesep = FALSE;
 
-    /* Get the configuration based on what version of Windows that's being used */
-    if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Calc"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) 
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, lpszApp, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
     {
-        /* Try to load last selected layout */
-        tmp = sizeof(calc.layout);
-        if (RegQueryValueEx(hKey, TEXT("layout"), NULL, NULL, (LPBYTE)&calc.layout, &tmp) != ERROR_SUCCESS)
-            calc.layout = CALC_LAYOUT_STANDARD;
+        /* Try to load integer value */
+        tmp = sizeof(int);
 
-        /* Try to load last selected formatting option */
-        tmp = sizeof(calc.usesep);
-        if (RegQueryValueEx(hKey, TEXT("UseSep"), NULL, NULL, (LPBYTE)&calc.usesep, &tmp) != ERROR_SUCCESS)
-            calc.usesep = FALSE;
+        if (RegQueryValueEx(hKey, lpszKey, NULL, NULL, (LPBYTE)&iValue, &tmp) == ERROR_SUCCESS)
+            iDefault = iValue;
 
         /* close the key */
         RegCloseKey(hKey);
     }
 
-    /* memory is empty at startup */
-    calc.is_memory = FALSE;
+    return iDefault;
+}
 
-    /* empty these values */
-    calc.sDecimal[0] = TEXT('\0');
-    calc.sThousand[0] = TEXT('\0');
+static void SaveRegInt(LPCTSTR lpszApp, LPCTSTR lpszKey, int iValue)
+{
+    HKEY hKey;
 
-    /* try to open the registry */
-    if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\International"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+    if (RegCreateKeyEx(HKEY_CURRENT_USER, lpszApp, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) == ERROR_SUCCESS)
     {
-        /* get these values (ignore errors) */
-        tmp = sizeof(calc.sDecimal);
-        RegQueryValueEx(hKey, TEXT("sDecimal"), NULL, NULL, (LPBYTE)calc.sDecimal, &tmp);
-
-        tmp = sizeof(calc.sThousand);
-        RegQueryValueEx(hKey, TEXT("sThousand"), NULL, NULL, (LPBYTE)calc.sThousand, &tmp);
+        RegSetValueEx(hKey, lpszKey, 0, REG_DWORD, (const BYTE*)&iValue, sizeof(int));
 
         /* close the key */
         RegCloseKey(hKey);
     }
-    /* if something goes wrong, let's apply the defaults */
-    if (calc.sDecimal[0] == TEXT('\0'))
-        _tcscpy(calc.sDecimal, TEXT("."));
+}
 
-    if (calc.sThousand[0] == TEXT('\0'))
-        _tcscpy(calc.sThousand, TEXT(","));
+static void load_config(void)
+{
+    OSVERSIONINFO osvi;
 
-    /* get the string lengths */
-    calc.sDecimal_len = _tcslen(calc.sDecimal);
-    calc.sThousand_len = _tcslen(calc.sThousand);
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+    GetVersionEx(&osvi);
+
+    switch (osvi.dwPlatformId) {
+    case VER_PLATFORM_WIN32s:
+    case VER_PLATFORM_WIN32_WINDOWS:
+        /* Try to load last selected layout */
+        calc.layout = GetProfileInt(_T("SciCalc"), _T("layout"), CALC_LAYOUT_STANDARD);
+
+        /* Try to load last selected formatting option */
+        calc.usesep = (GetProfileInt(_T("SciCalc"), _T("UseSep"), FALSE)) ? TRUE : FALSE;
+        break;
+
+    default: /* VER_PLATFORM_WIN32_NT */
+        /* Try to load last selected layout */
+        calc.layout = LoadRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("layout"), CALC_LAYOUT_STANDARD);
+
+        /* Try to load last selected formatting option */
+        calc.usesep = (LoadRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("UseSep"), FALSE)) ? TRUE : FALSE;
+        break;
+    }
+
+    /* memory is empty at startup */
+    calc.is_memory = FALSE;
+
+    /* Get locale info for numbers */
+    UpdateNumberIntl();
 }
 
 static void save_config(void)
 {
-    HKEY hKey;
-    DWORD sepValue;
+    TCHAR buf[32];
+    OSVERSIONINFO osvi;
+
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+    GetVersionEx(&osvi);
+
+    switch (osvi.dwPlatformId) {
+    case VER_PLATFORM_WIN32s:
+    case VER_PLATFORM_WIN32_WINDOWS:
+        _stprintf(buf, _T("%lu"), calc.layout);
+        WriteProfileString(_T("SciCalc"), _T("layout"), buf);
+        WriteProfileString(_T("SciCalc"), _T("UseSep"), (calc.usesep==TRUE) ? _T("1") : _T("0"));
+        break;
 
-    if (RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Calc"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS)
-    {
-        return;
+    default: /* VER_PLATFORM_WIN32_NT */
+        SaveRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("layout"), calc.layout);
+        SaveRegInt(_T("SOFTWARE\\Microsoft\\Calc"), _T("UseSep"), calc.usesep);
+        break;
     }
-    
-    sepValue = (calc.usesep) ? 1 : 0;
-
-    RegSetValueEx(hKey, TEXT("layout"), 0, REG_DWORD, (const BYTE*)&calc.layout, sizeof(calc.layout));
-    RegSetValueEx(hKey, TEXT("UseSep"), 0, REG_DWORD, (const BYTE*)&sepValue, sizeof(sepValue));
-
-    RegCloseKey(hKey);
 }
 
 static LRESULT post_key_press(LPARAM lParam, WORD idc)
@@ -312,7 +366,7 @@ static LRESULT post_key_press(LPARAM lParam, WORD idc)
     if (!GetClassName(hCtlWnd, ClassName, SIZEOF(ClassName)))
         return 1;
 
-    if (!_tcscmp(ClassName, TEXT("Button"))) {
+    if (!_tcscmp(ClassName, WC_BUTTON)) {
         DWORD dwStyle = GetWindowLongPtr(hCtlWnd, GWL_STYLE) & 0xF;
 
         /* Set states for press/release, but only for push buttons */
@@ -439,22 +493,25 @@ static void update_lcd_display(HWND hwnd)
      * happen that separator is used between each digit.
      * Also added little additional space for dot and '\0'.
      */
-    TCHAR *tmp = (TCHAR *)alloca(sizeof(calc.buffer)*2+2*sizeof(TCHAR));
+    TCHAR tmp[MAX_CALC_SIZE * 2 + 2];
 
-    if (calc.buffer[0] == TEXT('\0'))
-        _tcscpy(tmp, TEXT("0"));
+    if (calc.buffer[0] == _T('\0'))
+        _tcscpy(tmp, _T("0"));
     else
         _tcscpy(tmp, calc.buffer);
-    /* add final '.' in decimal mode (if it's missing) */
-    if (calc.base == IDC_RADIO_DEC) {
-        if (_tcschr(tmp, TEXT('.')) == NULL)
-            _tcscat(tmp, TEXT("."));
+
+    /* Add final '.' in decimal mode (if it's missing), but
+     * only if it's a result: no append if it prints "ERROR".
+     */
+    if (calc.base == IDC_RADIO_DEC && !calc.is_nan) {
+        if (_tcschr(tmp, _T('.')) == NULL)
+            _tcscat(tmp, _T("."));
     }
     /* if separator mode is on, let's add an additional space */
     if (calc.usesep && !calc.sci_in && !calc.sci_out && !calc.is_nan) {
         /* go to the integer part of the string */
-        TCHAR *p = _tcschr(tmp, TEXT('.'));
-        TCHAR *e = _tcschr(tmp, TEXT('\0'));
+        TCHAR *p = _tcschr(tmp, _T('.'));
+        TCHAR *e = _tcschr(tmp, _T('\0'));
         int    n=0, t;
 
         if (p == NULL) p = e;
@@ -471,21 +528,21 @@ static void update_lcd_display(HWND hwnd)
             break;
         }
         while (--p > tmp) {
-            if (++n == t && *(p-1) != TEXT('-')) {
+            if (++n == t && *(p-1) != _T('-')) {
                 memmove(p+1, p, (e-p+1)*sizeof(TCHAR));
                 e++;
-                *p = TEXT(' ');
+                *p = _T(' ');
                 n = 0;
             }
         }
         /* if decimal mode, apply regional settings */
         if (calc.base == IDC_RADIO_DEC) {
             TCHAR *p = tmp;
-            TCHAR *e = _tcschr(tmp, TEXT('.'));
+            TCHAR *e = _tcschr(tmp, _T('.'));
 
             /* searching for thousands default separator */
             while (p < e) {
-                if (*p == TEXT(' ')) {
+                if (*p == _T(' ')) {
                     memmove(p+calc.sThousand_len, p+1, _tcslen(p)*sizeof(TCHAR));
                     memcpy(p, calc.sThousand, calc.sThousand_len*sizeof(TCHAR));
                     p += calc.sThousand_len;
@@ -497,7 +554,7 @@ static void update_lcd_display(HWND hwnd)
             memcpy(p, calc.sDecimal, calc.sDecimal_len*sizeof(TCHAR));
         }
     } else {
-        TCHAR *p = _tcschr(tmp, TEXT('.'));
+        TCHAR *p = _tcschr(tmp, _T('.'));
 
         /* update decimal point when usesep is false */
         if (p != NULL) {
@@ -514,9 +571,9 @@ static void update_parent_display(HWND hWnd)
     int   n = eval_parent_count();
 
     if (!n)
-        str[0] = TEXT('\0');
+        str[0] = _T('\0');
     else
-        _stprintf(str,TEXT("(=%d"), n);
+        _stprintf(str,_T("(=%d"), n);
     SendDlgItemMessage(hWnd, IDC_TEXT_PARENT, WM_SETTEXT, 0, (LPARAM)str);
 }
 
@@ -527,14 +584,14 @@ static void build_operand(HWND hwnd, DWORD idc)
     if (idc == IDC_BUTTON_DOT) {
         /* if dot is the first char, it's added automatically */
         if (calc.buffer == calc.ptr) {
-            *calc.ptr++ = TEXT('0');
-            *calc.ptr++ = TEXT('.');
-            *calc.ptr   = TEXT('\0');
+            *calc.ptr++ = _T('0');
+            *calc.ptr++ = _T('.');
+            *calc.ptr   = _T('\0');
             update_lcd_display(hwnd);
             return;
         }
         /* if pressed dot and it's already in the string, then return */
-        if (_tcschr(calc.buffer, TEXT('.')) != NULL)
+        if (_tcschr(calc.buffer, _T('.')) != NULL)
             return;
     }
     if (idc != IDC_STATIC) {
@@ -543,8 +600,8 @@ static void build_operand(HWND hwnd, DWORD idc)
     n = calc.ptr - calc.buffer;
     if (idc == IDC_BUTTON_0 && n == 0) {
         /* no need to put the dot because it's handled by update_lcd_display() */
-        calc.buffer[0] = TEXT('0');
-        calc.buffer[1] = TEXT('\0');
+        calc.buffer[0] = _T('0');
+        calc.buffer[1] = _T('\0');
         update_lcd_display(hwnd);
         return;
     }
@@ -560,12 +617,12 @@ static void build_operand(HWND hwnd, DWORD idc)
             if (idc != IDC_STATIC)
                 calc.esp = (calc.esp * 10 + (key2code[i].key-'0')) % LOCAL_EXP_SIZE;
             if (calc.ptr == calc.buffer)
-                _stprintf(calc.ptr, TEXT("0.e%+d"), calc.esp);
+                _stprintf(calc.ptr, _T("0.e%+d"), calc.esp);
             else {
                 /* adds the dot at the end if the number has no decimal part */
-                if (!_tcschr(calc.buffer, TEXT('.')))
-                    *calc.ptr++ = TEXT('.');
-                _stprintf(calc.ptr, TEXT("e%+d"), calc.esp);
+                if (!_tcschr(calc.buffer, _T('.')))
+                    *calc.ptr++ = _T('.');
+                _stprintf(calc.ptr, _T("e%+d"), calc.esp);
             }
             update_lcd_display(hwnd);
             return;
@@ -580,7 +637,7 @@ static void build_operand(HWND hwnd, DWORD idc)
             return;
         break;
     }
-    calc.ptr += _stprintf(calc.ptr, TEXT("%C"), key2code[i].key);
+    calc.ptr += _stprintf(calc.ptr, _T("%C"), key2code[i].key);
     update_lcd_display(hwnd);
 }
 
@@ -594,16 +651,21 @@ static void prepare_rpn_result(calc_number_t *rpn, TCHAR *buffer, int size, int
     prepare_rpn_result_2(rpn, buffer, size, base);
 }
 
-static void display_rpn_result(HWND hwnd, calc_number_t *rpn)
+static void set_rpn_result(HWND hwnd, calc_number_t *rpn)
 {
     calc.sci_in = FALSE;
     prepare_rpn_result(rpn, calc.buffer, SIZEOF(calc.buffer), calc.base);
     calc.ptr = calc.buffer + _tcslen(calc.buffer);
     update_lcd_display(hwnd);
-    calc.ptr = calc.buffer;
     update_parent_display(hwnd);
 }
 
+static void display_rpn_result(HWND hwnd, calc_number_t *rpn)
+{
+    set_rpn_result(hwnd, rpn);
+    calc.ptr = calc.buffer;
+}
+
 static int get_modifiers(HWND hwnd)
 {
     int modifiers = 0;
@@ -622,8 +684,8 @@ static void convert_text2number(calc_number_t *a)
     /* the operand is taken from the last input */
     if (calc.buffer == calc.ptr) {
         /* if pushed valued is ZERO then we should grab it */
-        if (!_tcscmp(calc.buffer, TEXT("0.")) ||
-            !_tcscmp(calc.buffer, TEXT("0")))
+        if (!_tcscmp(calc.buffer, _T("0.")) ||
+            !_tcscmp(calc.buffer, _T("0")))
             /* this zero is good for both integer and decimal */
             rpn_zero(a);
         else
@@ -817,7 +879,7 @@ static void update_n_stats_items(HWND hWnd, TCHAR *buffer)
 {
     unsigned int n = SendDlgItemMessage(hWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0); 
 
-    _stprintf(buffer, TEXT("n=%d"), n);
+    _stprintf(buffer, _T("n=%u"), n);
     SendDlgItemMessage(hWnd, IDC_TEXT_NITEMS, WM_SETTEXT, 0, (LPARAM)buffer);
 }
 
@@ -872,7 +934,7 @@ static char *ReadConversion(const char *formula)
 
     /* clear display content before proceeding */
     calc.ptr = calc.buffer;
-    calc.buffer[0] = TEXT('\0');
+    calc.buffer[0] = _T('\0');
 
     return str;
 }
@@ -916,10 +978,10 @@ static INT_PTR CALLBACK DlgStatProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         }
         break;
     case WM_CLOSE:
-        clean_stat_list();
         DestroyWindow(hWnd);
         return TRUE;
     case WM_DESTROY:
+        clean_stat_list();
         PostMessage(GetParent(hWnd), WM_CLOSE_STATS, 0, 0);
         return TRUE;
     case WM_INSERT_STAT:
@@ -969,11 +1031,14 @@ static void CopyMemToClipboard(void *ptr)
 
 static void handle_copy_command(HWND hWnd)
 {
-    TCHAR display[sizeof(calc.buffer)];
+    TCHAR display[MAX_CALC_SIZE];
+    UINT  n;
+
+    n = GetDlgItemText(hWnd, IDC_TEXT_OUTPUT, display, SIZEOF(display));
 
-    SendDlgItemMessage(hWnd, IDC_TEXT_OUTPUT, WM_GETTEXT, (WPARAM)SIZEOF(display), (LPARAM)display);
     if (calc.base == IDC_RADIO_DEC && _tcschr(calc.buffer, _T('.')) == NULL)
-        display[_tcslen(display)-calc.sDecimal_len] = TEXT('\0');
+        display[n - calc.sDecimal_len] = _T('\0');
+
     CopyMemToClipboard(display);
 }
 
@@ -987,7 +1052,7 @@ static char *ReadClipboard(void)
 
         if (hData != NULL) {
             fromClipboard = (char *)GlobalLock(hData);
-            if (strlen(fromClipboard))
+            if (fromClipboard[0])
                 buffer = _strupr(_strdup(fromClipboard));
             GlobalUnlock( hData );
         }
@@ -1033,10 +1098,12 @@ static char *handle_sequence_input(HWND hwnd, sequence_t *seq)
             }
         }
     }
-    seq->ptr = ptr;
+
     if (*ptr != '\0')
+    {
+        seq->ptr = ptr;
         PostMessage(hwnd, seq->wm_msg, 0, 0);
-    else {
+    else {
         free(seq->data);
         seq->data = seq->ptr = ptr = NULL;
     }
@@ -1167,7 +1234,7 @@ static void handle_context_menu(HWND hWnd, WPARAM wp, LPARAM lp)
         popup.rcMargins.left   = -1;
         popup.rcMargins.right  = -1;
         popup.idString = GetWindowLongPtr((HWND)wp, GWL_ID);
-        HtmlHelp((HWND)wp, HTMLHELP_PATH("/popups.txt"), HH_DISPLAY_TEXT_POPUP, (DWORD_PTR)&popup);
+        calc_HtmlHelp((HWND)wp, HTMLHELP_PATH("/popups.txt"), HH_DISPLAY_TEXT_POPUP, (DWORD_PTR)&popup);
     }
 #else
     (void)idm;
@@ -1199,14 +1266,58 @@ static void run_lpar(calc_number_t *c)
 static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
 {
     LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lp;
-    DWORD            dwStyle;
     UINT             dwText;
     TCHAR            text[64];
     int              dx, dy, len;
     SIZE             size;
     POINT            pt;
 
-    if(dis->CtlType == ODT_BUTTON) {
+    if(dis->CtlType == ODT_BUTTON)
+    {
+        HTHEME hTheme = NULL;
+        LPBTNINFO lpBtnInfo;
+
+        if (calc_IsAppThemed() && calc_IsThemeActive())
+            hTheme = calc_OpenThemeData(hWnd, L"Button");
+
+        if (hTheme)
+        {
+            int iState = 0;
+
+            if ((dis->itemState & ODS_DISABLED))
+                iState |= PBS_DISABLED;
+            if ((dis->itemState & ODS_SELECTED))
+                iState |= PBS_PRESSED;
+
+            lpBtnInfo = (LPBTNINFO)GetWindowLongPtr(dis->hwndItem, GWLP_USERDATA);
+            if (lpBtnInfo != NULL)
+            {
+                if (lpBtnInfo->bHover)
+                    iState |= PBS_HOT;
+            }
+
+            if (calc_IsThemeBackgroundPartiallyTransparent(hTheme, BP_PUSHBUTTON, iState))
+            {
+                calc_DrawThemeParentBackground(dis->hwndItem, dis->hDC, &dis->rcItem);
+            }
+
+            // Draw the frame around the control
+            calc_DrawThemeBackground(hTheme, dis->hDC, BP_PUSHBUTTON, iState, &dis->rcItem, NULL);
+
+            calc_CloseThemeData(hTheme);
+        } else {
+            /* default state: unpushed */
+            DWORD dwStyle = 0;
+
+            if ((dis->itemState & ODS_SELECTED))
+                dwStyle = DFCS_PUSHED;
+
+            DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle);
+        }
+
+        /* button text to write */
+        len = GetWindowText(dis->hwndItem, text, SIZEOF(text));
+
         /*
          * little exception: 1/x has different color
          * in standard and scientific modes
@@ -1222,21 +1333,20 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
                 break;
             }
         }
-        /* button text to write */
-        len = GetWindowText(dis->hwndItem, text, SIZEOF(text));
-        /* default state: unpushed & enabled */
-        dwStyle = 0;
+
+        /* No background, to avoid corruption of the texture */
+        SetBkMode(dis->hDC, TRANSPARENT);
+
+        /* Default state: enabled */
         dwText = 0;
         if ((dis->itemState & ODS_DISABLED))
             dwText = DSS_DISABLED;
-        if ((dis->itemState & ODS_SELECTED))
-            dwStyle = DFCS_PUSHED;
 
-        DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | dwStyle);
+        /* Draw the text in the button */
         GetTextExtentPoint32(dis->hDC, text, len, &size);
         dx = ((dis->rcItem.right-dis->rcItem.left) - size.cx) >> 1;
         dy = ((dis->rcItem.bottom-dis->rcItem.top) - size.cy) >> 1;
-        if ((dwStyle & DFCS_PUSHED)) {
+        if ((dis->itemState & ODS_SELECTED)) {
             dx++;
             dy++;
         }
@@ -1247,6 +1357,84 @@ static LRESULT CALLBACK SubclassButtonProc(HWND hWnd, WPARAM wp, LPARAM lp)
     return 1L;
 }
 
+static INT_PTR CALLBACK HotButtonProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+    LPBTNINFO lpBtnInfo = (LPBTNINFO)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+    TRACKMOUSEEVENT mouse_event;
+
+    switch (msg) {
+    case WM_MOUSEMOVE:
+        mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
+        mouse_event.dwFlags = TME_QUERY;
+        if (!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags & (TME_HOVER|TME_LEAVE)))
+        {
+            mouse_event.dwFlags = TME_HOVER|TME_LEAVE;
+            mouse_event.hwndTrack = hWnd;
+            mouse_event.dwHoverTime = 1;
+            TrackMouseEvent(&mouse_event);
+        }
+        break;
+
+    case WM_MOUSEHOVER:
+        lpBtnInfo->bHover = TRUE;
+        InvalidateRect(hWnd, NULL, FALSE);
+        break;
+
+    case WM_MOUSELEAVE:
+        lpBtnInfo->bHover = FALSE;
+        InvalidateRect(hWnd, NULL, FALSE);
+        break;
+    }
+
+    return CallWindowProc(lpBtnInfo->oldProc, hWnd, msg, wp, lp);
+}
+
+static BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)
+{
+    TCHAR szClass[64];
+
+    if (!GetClassName(hWnd, szClass, SIZEOF(szClass)))
+        return TRUE;
+
+    if (!_tcscmp(szClass, WC_BUTTON))
+    {
+        int *pnCtrls = (int *)lParam;
+        int nCtrls = *pnCtrls;
+
+        BtnInfo[nCtrls].oldProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+        BtnInfo[nCtrls].bHover  = FALSE;
+
+        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&BtnInfo[nCtrls]);
+        SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)HotButtonProc);
+
+        *pnCtrls = ++nCtrls;
+    }
+    return TRUE;
+}
+
+static INT_PTR CALLBACK OnSettingChange(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+    /* Check for user policy and area string valid */
+    if (wParam == 0 && lParam != 0)
+    {
+        LPTSTR lpArea = (LPTSTR)lParam;
+
+        /* Check if a parameter has been changed into the locale settings */
+        if (!_tcsicmp(lpArea, _T("intl")))
+        {
+            /* Re-load locale parameters */
+            UpdateNumberIntl();
+
+            /* Update text for decimal button */
+            SetDlgItemText(hWnd, IDC_BUTTON_DOT, calc.sDecimal);
+
+            /* Update text into the output display */
+            update_lcd_display(hWnd);
+        }
+    }
+    return 0;
+}
+
 static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
 {
     unsigned int x;
@@ -1258,9 +1446,13 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         return SubclassButtonProc(hWnd, wp, lp);
 
     case WM_INITDIALOG:
-        // For now, the Help dialog is disabled because of lacking of HTML Help support
+#ifdef DISABLE_HTMLHELP_SUPPORT
         EnableMenuItem(GetMenu(hWnd), IDM_HELP_HELP, MF_BYCOMMAND | MF_GRAYED);
+#endif
         calc.hWnd=hWnd;
+        /* Enumerate children and apply hover function */
+        BtnCount = 0;
+        EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&BtnCount);
 
 #ifdef USE_KEYBOARD_HOOK
         calc.hKeyboardHook=SetWindowsHookEx(
@@ -1285,8 +1477,8 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         /* remove keyboard focus */
         SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
         /* set our calc icon */
-        SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG)));
-        SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_SMALL)));
+        SendMessage(hWnd, WM_SETICON, ICON_BIG,   (LPARAM)calc.hBgIcon);
+        SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)calc.hSmIcon);
 
         /* Sets the state of the option to group digits */
         hMenu = GetSubMenu(GetMenu(hWnd), 1);
@@ -1321,7 +1513,7 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
     case WM_COMMAND:
         /*
          * if selection of category is changed, we must
-         * updatethe content of the "from/to" combo boxes.
+         * update the content of the "from/to" combo boxes.
          */
         if (wp == MAKEWPARAM(IDC_COMBO_CATEGORY, CBN_SELCHANGE)) {
             ConvAdjust(hWnd, SendDlgItemMessage(hWnd, IDC_COMBO_CATEGORY, CB_GETCURSEL, 0, 0));
@@ -1339,12 +1531,12 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
             TCHAR infotext[200];
             LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle));
             LoadString(calc.hInstance, IDS_AUTHOR, infotext, SIZEOF(infotext));
-            ShellAbout(hWnd, infotitle, infotext, (HICON)LoadIcon(calc.hInstance, MAKEINTRESOURCE(IDI_CALC_BIG)));
+            ShellAbout(hWnd, infotitle, infotext, calc.hBgIcon);
             return TRUE;
         }
         case IDM_HELP_HELP:
 #ifndef DISABLE_HTMLHELP_SUPPORT
-            HtmlHelp(hWnd, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC, (DWORD_PTR)NULL);
+            calc_HtmlHelp(hWnd, HTMLHELP_PATH("/general_information.htm"), HH_DISPLAY_TOPIC, (DWORD_PTR)NULL);
 #endif
             return TRUE;
         case IDM_VIEW_STANDARD:
@@ -1353,7 +1545,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 calc.layout = CALC_LAYOUT_STANDARD;
                 calc.action = IDM_VIEW_STANDARD;
                 DestroyWindow(hWnd);
-                save_config();
 
                 CheckMenuRadioItem(GetMenu(hWnd),
                     IDM_VIEW_STANDARD,
@@ -1368,7 +1559,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 calc.layout = CALC_LAYOUT_SCIENTIFIC;
                 calc.action = IDM_VIEW_SCIENTIFIC;
                 DestroyWindow(hWnd);
-                save_config();
 
                 CheckMenuRadioItem(GetMenu(hWnd),
                     IDM_VIEW_STANDARD,
@@ -1383,7 +1573,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 calc.layout = CALC_LAYOUT_CONVERSION;
                 calc.action = IDM_VIEW_CONVERSION;
                 DestroyWindow(hWnd);
-                save_config();
 
                 CheckMenuRadioItem(GetMenu(hWnd),
                     IDM_VIEW_STANDARD,
@@ -1431,7 +1620,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
             calc.usesep = (calc.usesep ? FALSE : TRUE);
             update_menu(hWnd);
             update_lcd_display(hWnd);
-            save_config();
             return TRUE;
         case IDC_BUTTON_CONVERT:
             ConvExecute(hWnd);
@@ -1540,6 +1728,7 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 {
                     PostMessage(hWnd, WM_COMMAND, IdcSim, 0);
                     CheckDlgButton(hWnd, IDC_CHECK_INV, BST_UNCHECKED);
+                    break;
                 }
             }
 
@@ -1575,9 +1764,9 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                     TCHAR *ptr;
 
                     calc.sci_in = FALSE;
-                    ptr = _tcschr(calc.ptr, TEXT('e'));
+                    ptr = _tcschr(calc.ptr, _T('e'));
                     if (ptr)
-                        *ptr = TEXT('\0');
+                        *ptr = _T('\0');
                     update_lcd_display(hWnd);
                 } else {
                     calc.esp /= 10;
@@ -1585,12 +1774,12 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 }
             } else
             if (calc.ptr != calc.buffer) {
-                *--calc.ptr = TEXT('\0');
-                if (!_tcscmp(calc.buffer, TEXT("-")) ||
-                    !_tcscmp(calc.buffer, TEXT("-0")) ||
-                    !_tcscmp(calc.buffer, TEXT("0"))) {
+                *--calc.ptr = _T('\0');
+                if (!_tcscmp(calc.buffer, _T("-")) ||
+                    !_tcscmp(calc.buffer, _T("-0")) ||
+                    !_tcscmp(calc.buffer, _T("0"))) {
                     calc.ptr = calc.buffer;
-                    calc.buffer[0] = TEXT('\0');
+                    calc.buffer[0] = _T('\0');
                 }
                 update_lcd_display(hWnd);
             }
@@ -1618,22 +1807,22 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                 calc.esp = 0-calc.esp;
                 build_operand(hWnd, IDC_STATIC);
             } else {
-                if (calc.is_nan || calc.buffer[0] == TEXT('\0'))
+                if (calc.is_nan || calc.buffer[0] == _T('\0'))
                     break;
 
-                if (calc.buffer[0] == TEXT('-')) {
+                if (calc.buffer[0] == _T('-')) {
                     /* make the number positive */
                     memmove(calc.buffer, calc.buffer+1, sizeof(calc.buffer)-1);
                     if (calc.buffer != calc.ptr)
                         calc.ptr--;
                 } else {
                     /* if first char is '0' and no dot, it isn't valid */
-                    if (calc.buffer[0] == TEXT('0') &&
-                        calc.buffer[1] != TEXT('.'))
+                    if (calc.buffer[0] == _T('0') &&
+                        calc.buffer[1] != _T('.'))
                         break;
                     /* make the number negative */
                     memmove(calc.buffer+1, calc.buffer, sizeof(calc.buffer)-1);
-                    calc.buffer[0] = TEXT('-');
+                    calc.buffer[0] = _T('-');
                     if (calc.buffer != calc.ptr)
                         calc.ptr++;
                 }
@@ -1696,14 +1885,20 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                     if (cb != NULL) {
                         convert_text2number(&calc.code);
                         cb(&calc.code);
-                        display_rpn_result(hWnd, &calc.code);
-//                      if (!(function_table[x].range & NO_CHAIN))
-//                          exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
+//                        display_rpn_result(hWnd, &calc.code);
+                        set_rpn_result(hWnd, &calc.code);
+
+                        if ((function_table[x].range & NO_CHAIN))
+                            calc.ptr = calc.buffer;
+
+//                        if (!(function_table[x].range & NO_CHAIN))
+//                            exec_infix2postfix(&calc.code, RPN_OPERATOR_NONE);
                         if (function_table[x].range & MODIFIER_INV)
                             SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
                         if (function_table[x].range & MODIFIER_HYP)
                             SendDlgItemMessage(hWnd, IDC_CHECK_HYP, BM_SETCHECK, 0, 0);
                     }
+                    break;
                 }
             }
             return TRUE;
@@ -1720,6 +1915,7 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         }
         break;
     case WM_CLOSE_STATS:
+        calc.hStatWnd = NULL;
         enable_allowed_controls(hWnd, calc.base);
         return TRUE;
     case WM_LOAD_STAT:
@@ -1749,6 +1945,7 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         calc.action = IDC_STATIC;
         DestroyWindow(hWnd);
         return TRUE;
+
     case WM_DESTROY:
         /* Get (x,y) position of the calculator */
         GetWindowRect(hWnd, &rc);
@@ -1775,6 +1972,13 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
     case WM_EXITMENULOOP:
         calc.is_menu_on = FALSE;
         break;
+
+    case WM_SETTINGCHANGE:
+        return OnSettingChange(hWnd, wp, lp);
+
+    case WM_THEMECHANGED:
+        InvalidateRect(hWnd, NULL, FALSE);
+        break;
     }
     return FALSE;
 }
@@ -1788,6 +1992,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
     MSG msg;
     DWORD dwLayout;
 
+    /* Initialize controls for theming & manifest support */
     InitCommonControls();
 
     calc.hInstance = hInstance;
@@ -1798,6 +2003,26 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
     load_config();
     start_rpn_engine();
 
+    HtmlHelp_Start(hInstance);
+
+    Theme_Start(hInstance);
+
+    calc.hBgIcon = LoadImage(
+                    hInstance,
+                    MAKEINTRESOURCE(IDI_CALC),
+                    IMAGE_ICON,
+                    GetSystemMetrics(SM_CXICON),
+                    GetSystemMetrics(SM_CYICON),
+                    0);
+
+    calc.hSmIcon = LoadImage(
+                    hInstance,
+                    MAKEINTRESOURCE(IDI_CALC),
+                    IMAGE_ICON,
+                    GetSystemMetrics(SM_CXSMICON),
+                    GetSystemMetrics(SM_CYSMICON),
+                    0);
+
     do {
         /* ignore hwnd: dialogs are already visible! */
         if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
@@ -1821,9 +2046,20 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
             TranslateMessage(&msg);
             DispatchMessage(&msg);
         }
+
+        save_config();
     } while (calc.action != IDC_STATIC);
 
+    if (calc.hBgIcon != NULL)
+        DestroyIcon(calc.hBgIcon);
+
+    if (calc.hSmIcon != NULL)
+        DestroyIcon(calc.hSmIcon);
+
     stop_rpn_engine();
 
+    Theme_Stop();
+    HtmlHelp_Stop();
+
     return 0;
 }