[CALC] Add theming support, requires Windows XP or later. CORE-13343
[reactos.git] / base / applications / calc / winmain.c
index 589a453..fceb41f 100644 (file)
@@ -1,10 +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 "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) | \
@@ -32,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
@@ -164,6 +180,8 @@ static const WORD operator_codes[] = {
     IDC_BUTTON_MULT,    // RPN_OPERATOR_MULT
     IDC_BUTTON_DIV,     // RPN_OPERATOR_DIV
     IDC_BUTTON_MOD,     // RPN_OPERATOR_MOD
+    IDC_BUTTON_XeY,     // RPN_OPERATOR_POW
+    IDC_BUTTON_XrY,     // RPN_OPERATOR_SQR
 };
 
 typedef void (*rpn_callback1)(calc_number_t *);
@@ -178,8 +196,6 @@ typedef struct {
     rpn_callback1   inv_hyp;
 } function_table_t;
 
-static void run_pow(calc_number_t *number);
-static void run_sqr(calc_number_t *number);
 static void run_fe(calc_number_t *number);
 static void run_dat_sta(calc_number_t *number);
 static void run_mp(calc_number_t *c);
@@ -203,60 +219,73 @@ static const function_table_t function_table[] = {
     { IDC_BUTTON_LN,   MODIFIER_INV,              1, rpn_ln,      rpn_exp,     NULL,     NULL      },
     { IDC_BUTTON_LOG,  MODIFIER_INV,              1, rpn_log,     rpn_exp10,   NULL,     NULL      },
     { IDC_BUTTON_NF,   0,                         1, rpn_fact,    NULL,        NULL,     NULL      },
-    { IDC_BUTTON_AVE,  0,                         0, rpn_ave,     NULL,        NULL,     NULL      },
-    { IDC_BUTTON_SUM,  0,                         0, rpn_sum,     NULL,        NULL,     NULL      },
+    { IDC_BUTTON_AVE,  MODIFIER_INV,              0, rpn_ave,     rpn_ave2,    NULL,     NULL      },
+    { IDC_BUTTON_SUM,  MODIFIER_INV,              0, rpn_sum,     rpn_sum2,    NULL,     NULL      },
     { IDC_BUTTON_S,    MODIFIER_INV,              0, rpn_s_m1,    rpn_s,       NULL,     NULL      },
-    { IDC_BUTTON_XeY,  MODIFIER_INV,              1, run_pow,     run_sqr,     NULL,     NULL      },
     { IDC_BUTTON_SQRT, MODIFIER_INV,              1, rpn_sqrt,    NULL,        NULL,     NULL      },
     { IDC_BUTTON_DMS,  MODIFIER_INV,              1, rpn_dec2dms, rpn_dms2dec, NULL,     NULL      },
     { IDC_BUTTON_FE,   0,                         1, run_fe,      NULL,        NULL,     NULL      },
     { IDC_BUTTON_DAT,  0,                         1, run_dat_sta, NULL,        NULL,     NULL,     },
-    { IDC_BUTTON_MP,   MODIFIER_INV,              1, run_mp,      run_mm,      NULL,     NULL,     },
-    { IDC_BUTTON_MS,   MODIFIER_INV,              1, run_ms,      run_mw,      NULL,     NULL,     },
+    { IDC_BUTTON_MP,   MODIFIER_INV|NO_CHAIN,     1, run_mp,      run_mm,      NULL,     NULL,     },
+    { IDC_BUTTON_MS,   MODIFIER_INV|NO_CHAIN,     1, run_ms,      run_mw,      NULL,     NULL,     },
     { IDC_BUTTON_CANC, NO_CHAIN,                  0, run_canc,    NULL,        NULL,     NULL,     },
     { IDC_BUTTON_RIGHTPAR, NO_CHAIN,              1, run_rpar,    NULL,        NULL,     NULL,     },
     { 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;
+/* Hot-state info for theming support */
+BTNINFO BtnInfo[255];
+UINT    BtnCount;
 
 static void load_config(void)
 {
-    TCHAR buf[32];
     DWORD tmp;
-#if _WIN32_WINNT >= 0x0500
     HKEY hKey;
-#endif
+    
+    /* 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) 
+    {
+        /* 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 last selected layout */
-    GetProfileString(TEXT("SciCalc"), TEXT("layout"), TEXT("0"), buf, SIZEOF(buf));
-    if (_stscanf(buf, TEXT("%lu"), &calc.layout) != 1)
-        calc.layout = CALC_LAYOUT_STANDARD;
+        /* 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;
 
-    /* Try to load last selected formatting option */
-    GetProfileString(TEXT("SciCalc"), TEXT("UseSep"), TEXT("0"), buf, SIZEOF(buf));
-    if (_stscanf(buf, TEXT("%lu"), &tmp) != 1)
-        calc.usesep = FALSE;
-    else
-        calc.usesep = (tmp == 1) ? TRUE : FALSE;
+        /* close the key */
+        RegCloseKey(hKey);
+    }
 
     /* memory is empty at startup */
     calc.is_memory = FALSE;
 
-#if _WIN32_WINNT >= 0x0500
     /* empty these values */
     calc.sDecimal[0] = TEXT('\0');
     calc.sThousand[0] = TEXT('\0');
 
     /* try to open the registry */
-    if (RegOpenKeyEx(HKEY_CURRENT_USER, 
-                     TEXT("Control Panel\\International"),
-                     0,
-                     KEY_QUERY_VALUE,
-                     &hKey) == ERROR_SUCCESS) {
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\International"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+    {
         /* get these values (ignore errors) */
         tmp = sizeof(calc.sDecimal);
         RegQueryValueEx(hKey, TEXT("sDecimal"), NULL, NULL, (LPBYTE)calc.sDecimal, &tmp);
@@ -277,20 +306,24 @@ static void load_config(void)
     /* get the string lengths */
     calc.sDecimal_len = _tcslen(calc.sDecimal);
     calc.sThousand_len = _tcslen(calc.sThousand);
-#else
-    /* acquire regional settings */
-    calc.sDecimal_len  = GetProfileString(TEXT("intl"), TEXT("sDecimal"), TEXT("."), calc.sDecimal, SIZEOF(calc.sDecimal));
-    calc.sThousand_len = GetProfileString(TEXT("intl"), TEXT("sThousand"), TEXT(","), calc.sThousand, SIZEOF(calc.sThousand));
-#endif
 }
 
 static void save_config(void)
 {
-    TCHAR buf[32];
+    HKEY hKey;
+    DWORD sepValue;
 
-    _stprintf(buf, TEXT("%lu"), calc.layout);
-    WriteProfileString(TEXT("SciCalc"), TEXT("layout"), buf);
-    WriteProfileString(TEXT("SciCalc"), TEXT("UseSep"), (calc.usesep==TRUE) ? TEXT("1") : TEXT("0"));
+    if (RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Calc"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS)
+    {
+        return;
+    }
+    
+    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)
@@ -305,7 +338,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 */
@@ -428,7 +461,7 @@ KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
 static void update_lcd_display(HWND hwnd)
 {
     /*
-     * muliply size of calc.buffer by 2 because it may
+     * multiply size of calc.buffer by 2 because it may
      * happen that separator is used between each digit.
      * Also added little additional space for dot and '\0'.
      */
@@ -657,7 +690,33 @@ static void update_menu(HWND hwnd)
     HMENU        hMenu = GetSubMenu(GetMenu(hwnd), 1);
     unsigned int x;
 
-    for (x=0; x<SIZEOF(upd); x++) {
+    /* Sets the state of the layout in the menu based on the configuration file */
+    if (calc.layout == CALC_LAYOUT_SCIENTIFIC)
+    {
+        CheckMenuRadioItem(GetMenu(hwnd),
+                           IDM_VIEW_STANDARD,
+                           IDM_VIEW_CONVERSION,
+                           IDM_VIEW_SCIENTIFIC,
+                           MF_BYCOMMAND);
+    }
+    else if (calc.layout == CALC_LAYOUT_CONVERSION)
+    {
+        CheckMenuRadioItem(GetMenu(hwnd),
+                           IDM_VIEW_STANDARD,
+                           IDM_VIEW_CONVERSION,
+                           IDM_VIEW_CONVERSION,
+                           MF_BYCOMMAND);
+    }
+    else
+    {
+        CheckMenuRadioItem(GetMenu(hwnd),
+                           IDM_VIEW_STANDARD,
+                           IDM_VIEW_CONVERSION,
+                           IDM_VIEW_STANDARD,
+                           MF_BYCOMMAND);
+    }
+
+    for (x=3; x<SIZEOF(upd); x++) {
         if (*(upd[x].sel) != upd[x].idc) {
             CheckMenuItem(hMenu, upd[x].idm, MF_BYCOMMAND|MF_UNCHECKED);
             SendMessage((HWND)GetDlgItem(hwnd,upd[x].idc),BM_SETCHECK,FALSE,0L);
@@ -900,15 +959,18 @@ static INT_PTR CALLBACK DlgStatProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
     return FALSE;
 }
 
-static WPARAM idm_2_idc(int idm)
+static BOOL idm_2_idc(int idm, WPARAM *pIdc)
 {
     int x;
 
     for (x=0; x<SIZEOF(upd); x++) {
         if (upd[x].idm == idm)
-            break;
+        {
+            *pIdc = (WPARAM)(upd[x].idc);
+            return TRUE;
+        }
     }
-    return (WPARAM)(upd[x].idc);
+    return FALSE;
 }
 
 static void CopyMemToClipboard(void *ptr)
@@ -1095,19 +1157,9 @@ static statistic_t *upload_stat_number(int n)
     return p;
 }
 
-static void run_pow(calc_number_t *number)
-{
-    exec_infix2postfix(number, RPN_OPERATOR_POW);
-}
-
-static void run_sqr(calc_number_t *number)
-{
-    exec_infix2postfix(number, RPN_OPERATOR_SQR);
-}
-
 static void run_fe(calc_number_t *number)
 {
-    calc.sci_out = ((calc.sci_out == TRUE) ? FALSE : TRUE);
+    calc.sci_out = ((calc.sci_out != FALSE) ? FALSE : TRUE);
 }
 
 static void handle_context_menu(HWND hWnd, WPARAM wp, LPARAM lp)
@@ -1141,7 +1193,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;
@@ -1173,14 +1225,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
@@ -1196,21 +1292,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++;
         }
@@ -1221,17 +1316,79 @@ 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 DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
 {
     unsigned int x;
     RECT         rc;
+    HMENU        hMenu;
 
     switch (msg) {
     case WM_DRAWITEM:
         return SubclassButtonProc(hWnd, wp, lp);
 
     case WM_INITDIALOG:
+#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(
@@ -1256,8 +1413,13 @@ 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);
+        CheckMenuItem(hMenu, IDM_VIEW_GROUP, (calc.usesep ? MF_CHECKED : MF_UNCHECKED));
+
         /* update text for decimal button */
         SendDlgItemMessage(hWnd, IDC_BUTTON_DOT, WM_SETTEXT, (WPARAM)0, (LPARAM)calc.sDecimal);
         /* Fill combo box for conversion */
@@ -1300,30 +1462,63 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
             SetFocus(GetDlgItem(hWnd, IDC_BUTTON_FOCUS));
         switch (LOWORD(wp)) {
         case IDM_HELP_ABOUT:
-            DialogBox(calc.hInstance,MAKEINTRESOURCE(IDD_DIALOG_ABOUT), hWnd, AboutDlgProc);
+        {
+            TCHAR infotitle[100];
+            TCHAR infotext[200];
+            LoadString(calc.hInstance, IDS_CALC_NAME, infotitle, SIZEOF(infotitle));
+            LoadString(calc.hInstance, IDS_AUTHOR, infotext, SIZEOF(infotext));
+            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:
-            calc.layout = CALC_LAYOUT_STANDARD;
-            calc.action = IDM_VIEW_STANDARD;
-            DestroyWindow(hWnd);
-            save_config();
+            if (calc.layout != CALC_LAYOUT_STANDARD)
+            {
+                calc.layout = CALC_LAYOUT_STANDARD;
+                calc.action = IDM_VIEW_STANDARD;
+                DestroyWindow(hWnd);
+                save_config();
+
+                CheckMenuRadioItem(GetMenu(hWnd),
+                    IDM_VIEW_STANDARD,
+                    IDM_VIEW_CONVERSION,
+                    IDM_VIEW_STANDARD,
+                    MF_BYCOMMAND);
+            }
             return TRUE;
         case IDM_VIEW_SCIENTIFIC:
-            calc.layout = CALC_LAYOUT_SCIENTIFIC;
-            calc.action = IDM_VIEW_SCIENTIFIC;
-            DestroyWindow(hWnd);
-            save_config();
+            if (calc.layout != CALC_LAYOUT_SCIENTIFIC)
+            {
+                calc.layout = CALC_LAYOUT_SCIENTIFIC;
+                calc.action = IDM_VIEW_SCIENTIFIC;
+                DestroyWindow(hWnd);
+                save_config();
+
+                CheckMenuRadioItem(GetMenu(hWnd),
+                    IDM_VIEW_STANDARD,
+                    IDM_VIEW_CONVERSION,
+                    IDM_VIEW_SCIENTIFIC,
+                    MF_BYCOMMAND);
+            }
             return TRUE;
         case IDM_VIEW_CONVERSION:
-            calc.layout = CALC_LAYOUT_CONVERSION;
-            calc.action = IDM_VIEW_CONVERSION;
-            DestroyWindow(hWnd);
-            save_config();
+            if (calc.layout != CALC_LAYOUT_CONVERSION)
+            {
+                calc.layout = CALC_LAYOUT_CONVERSION;
+                calc.action = IDM_VIEW_CONVERSION;
+                DestroyWindow(hWnd);
+                save_config();
+
+                CheckMenuRadioItem(GetMenu(hWnd),
+                    IDM_VIEW_STANDARD,
+                    IDM_VIEW_CONVERSION,
+                    IDM_VIEW_CONVERSION,
+                    MF_BYCOMMAND);
+            }
             return TRUE;
         case IDM_VIEW_HEX:
         case IDM_VIEW_DEC:
@@ -1336,8 +1531,15 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         case IDM_VIEW_DWORD:
         case IDM_VIEW_WORD:
         case IDM_VIEW_BYTE:
-            SendMessage(hWnd, WM_COMMAND, idm_2_idc(LOWORD(wp)), 0);
-            return TRUE;
+        {
+            WPARAM idc;
+            if(idm_2_idc(LOWORD(wp), &idc))
+            {
+                SendMessage(hWnd, WM_COMMAND, idc, 0);
+                return TRUE;
+            }
+            return FALSE;
+        }
         case IDM_EDIT_COPY:
             handle_copy_command(hWnd);
             return TRUE;
@@ -1446,17 +1648,29 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         case IDC_BUTTON_LSH:
         case IDC_BUTTON_RSH:
         case IDC_BUTTON_EQU:
+        case IDC_BUTTON_XeY:
+        case IDC_BUTTON_XrY:
             if (calc.is_nan) break;
             /*
-             * LSH button holds the RSH function too with INV modifier,
-             * but since it's a two operand operator, it must be handled here.
+             * LSH and XeY buttons hold also the RSH and XrY functions with INV modifier,
+             * but since they are two operand operators, they must be handled here.
              */
-            if (LOWORD(wp) == IDC_BUTTON_LSH &&
-                (get_modifiers(hWnd) & MODIFIER_INV)) {
-                PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED), 0);
-                SendDlgItemMessage(hWnd, IDC_CHECK_INV, BM_SETCHECK, 0, 0);
-                break;
+            if ((get_modifiers(hWnd) & MODIFIER_INV))
+            {
+                WPARAM IdcSim = IDC_STATIC;
+
+                switch (LOWORD(wp)) {
+                case IDC_BUTTON_LSH: IdcSim = MAKEWPARAM(IDC_BUTTON_RSH, BN_CLICKED); break;
+                case IDC_BUTTON_XeY: IdcSim = MAKEWPARAM(IDC_BUTTON_XrY, BN_CLICKED); break;
+                }
+
+                if (IdcSim != IDC_STATIC)
+                {
+                    PostMessage(hWnd, WM_COMMAND, IdcSim, 0);
+                    CheckDlgButton(hWnd, IDC_CHECK_INV, BST_UNCHECKED);
+                }
             }
+
             for (x=0; x<SIZEOF(operator_codes); x++) {
                 if (LOWORD(wp) == operator_codes[x]) {
                     convert_text2number(&calc.code);
@@ -1583,7 +1797,6 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
         case IDC_BUTTON_SIN:
         case IDC_BUTTON_COS:
         case IDC_BUTTON_TAN:
-        case IDC_BUTTON_XeY:
         case IDC_BUTTON_MS:
             for (x=0; x<SIZEOF(function_table); x++) {
                 if (LOWORD(wp) == function_table[x].idc) {
@@ -1612,8 +1825,8 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
                         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);
+//                      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)
@@ -1664,6 +1877,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);
@@ -1690,6 +1904,10 @@ static INT_PTR CALLBACK DlgMainProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
     case WM_EXITMENULOOP:
         calc.is_menu_on = FALSE;
         break;
+
+    case WM_THEMECHANGED:
+        InvalidateRect(hWnd, NULL, FALSE);
+        break;
     }
     return FALSE;
 }
@@ -1703,6 +1921,9 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
     MSG msg;
     DWORD dwLayout;
 
+    /* Initialize controls for theming & manifest support */
+    InitCommonControls();
+
     calc.hInstance = hInstance;
 
     calc.x_coord = -1;
@@ -1711,12 +1932,31 @@ 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)
             dwLayout = IDD_DIALOG_SCIENTIFIC;
-        else
-        if (calc.layout == CALC_LAYOUT_CONVERSION)
+        else if (calc.layout == CALC_LAYOUT_CONVERSION)
             dwLayout = IDD_DIALOG_CONVERSION;
         else
             dwLayout = IDD_DIALOG_STANDARD;
@@ -1737,7 +1977,16 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
         }
     } 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;
 }