1: /*
     2:  ============================================================================
     3:  xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
     4:  Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
     5:  Copyright © 2001-2004 The Blackbox for Windows Development Team
     6:  http://xoblite.net/ + https://github.com/xoblite/
     7:  ============================================================================
     8: 
     9:   Blackbox for Windows is free software, released under the
    10:   GNU General Public License (GPL version 2 or later), with an extension
    11:   that allows linking of proprietary modules under a controlled interface.
    12:   What this means is that plugins etc. are allowed to be released
    13:   under any license the author wishes. Please note, however, that the
    14:   original Blackbox gradient math code used in Blackbox for Windows
    15:   is available under the BSD license.
    16: 
    17:   http://www.fsf.org/licenses/gpl.html
    18:   http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
    19:   http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
    20: 
    21:   This program is distributed in the hope that it will be useful,
    22:   but WITHOUT ANY WARRANTY; without even the implied warranty of
    23:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    24:   GNU General Public License for more details.
    25: 
    26:   For additional license information, please read the included license.html.
    27: 
    28:  ============================================================================
    29: */
    30: 
    31: #include "Settings.h" 
    32: #include <shlobj.h> 
    33: #include <shlwapi.h> 
    34: #include <time.h> 
    35: #include <locale.h> 
    36: 
    37: #include <gdiplus.h> 
    38: using namespace Gdiplus;
    39: 
    40: /*
    41:     #######################################################################################
    42:     ###### BELOW: A FEW MORE STYLE RELATED "TODOs" FOR FURTHER STUDY/CONSIDERATION? #######
    43:     #######################################################################################
    44: 
    45:     ##### SHOULD handleHeight BE SAVED OR NOT? FAILSAFES IN CORE AND/OR PLUGIN? (ETC) #####
    46: 
    47:     window.handleHeight     - height of the window handle
    48: 
    49:     window.frame.focus.borderColor  - color of border around focused window
    50:     window.frame.unfocus.borderColor - color of border around unfocused window
    51:     window.frame.borderWidth    - border width around client window
    52: 
    53:     window.title.marginWidth    - space around and between buttons and labels
    54:     window.label.marginWidth    - space around text in labels
    55:     window.button.marginWidth   - space around bitmaps in buttons
    56: 
    57:     window.font         - text font
    58:     window.alignment    - alignment of text in labels
    59: 
    60: 
    61:     ******** menu.frame.bulletColor: ??? (check translation/mapping vs menu.frame.foregroundColor @ bb4nix)
    62:     ******** menu.active.bulletColor: ??? (check translation/mapping vs menu.active.foregroundColor @ bb4nix
    63: 
    64:     ...picColor: ???
    65: 
    66:     menu.title.foregroundColor  - bitmap color for e.g. close button
    67:     menu.frame.foregroundColor  - bitmap color for checks and submenu-arrows
    68:     menu.active.foregroundColor - bitmap color for checks and submenu-arrows
    69:     toolbar.button.foregroundColor  - bitmap color for buttons
    70: 
    71:     toolbar.font            - text font
    72:     toolbar.alignment       - text alignment for all labels
    73:     toolbar.marginWidth     - space around and between buttons and labels
    74: 
    75:     https://github.com/bradleythughes/blackbox/blob/master/data/README.style
    76: 
    77:     #######################################################################################
    78: */
    79: 
    80: 
    81: //===========================================================================
    82: 
    83: Settings::Settings()
    84: {
    85:     Wildcard = new StyleItem;
    86: 
    87:     Toolbar = new StyleItem;
    88:     ToolbarLabel = new StyleItem;
    89:     ToolbarWindowLabel = new StyleItem;
    90:     ToolbarClock = new StyleItem;
    91:     ToolbarButton = new StyleItem;
    92:     ToolbarButtonPressed = new StyleItem;
    93:     ToolbarBorder = new StyleItem;
    94: 
    95:     MenuTitle = new StyleItem;
    96:     MenuFrame = new StyleItem;
    97:     MenuActive = new StyleItem;
    98:     MenuGrip = new StyleItem;
    99:     MenuFrameBullet = new StyleItem;
   100:     MenuActiveBullet = new StyleItem;
   101:     MenuIndicator = new StyleItem;
   102:     MenuSeparator = new StyleItem;
   103:     MenuFrameBorder = new StyleItem;
   104: 
   105:     Dock = new StyleItem;
   106:     DockBorder = new StyleItem;
   107: 
   108:     ActiveTask = new StyleItem;
   109:     InactiveTask = new StyleItem;
   110:     FlashingTask = new StyleItem;
   111: 
   112:     Console = new StyleItem;
   113: 
   114:     WindowTitleFocus = new StyleItem;
   115:     WindowTitleUnfocus = new StyleItem;
   116:     WindowLabelFocus = new StyleItem;
   117:     WindowLabelUnfocus = new StyleItem;
   118:     WindowButtonFocus = new StyleItem;
   119:     WindowButtonUnfocus = new StyleItem;
   120:     WindowButtonPressed = new StyleItem;
   121:     WindowGripFocus = new StyleItem;
   122:     WindowGripUnfocus = new StyleItem;
   123:     WindowHandleFocus = new StyleItem;
   124:     WindowHandleUnfocus = new StyleItem;
   125: 
   126:     ExternalHardware = new StyleItem;
   127: 
   128:     InitStyleItems();
   129: 
   130:     //====================
   131: 
   132:     borderWidth = 0;
   133:     borderColor = 0;
   134: 
   135:     bevelWidth = 0;
   136:     handleHeight = 0;
   137:     frameWidth = 0;
   138: 
   139:     //====================
   140: 
   141:     bbrcFile[0] = 0;
   142:     xobrcFile[0] = 0;
   143:     xobrcDefaultFile[0] = 0;
   144: 
   145:     styleFile[0] = 0;
   146:     menuFile[0] = 0;
   147:     hotkeysFile[0] = 0;
   148:     pluginsFile[0] = 0;
   149: 
   150:     //====================
   151: 
   152:     designerModeEnabled = false;
   153:     selectedElement = Toolbar;
   154:     wallpaperPerWorkspaceSemaphore = false;
   155: 
   156:     currentWorkspace = lastWorkspace = 0;
   157: 
   158:     //====================
   159: 
   160:     ZeroMemory(&Statistics, sizeof(Statistics));
   161: }
   162: 
   163: //===========================================================================
   164: 
   165: Settings::~Settings()
   166: {
   167:     DestroyStyleItems();
   168: }
   169: 
   170: //===========================================================================
   171: // Functions: InitStyleItems -> InitStyleItem
   172: // Purpose: Initializes/re-initializes all StyleItems with default settings
   173: //===========================================================================
   174: 
   175: void Settings::InitStyleItems()
   176: {
   177: //  if (debugLogging) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"Entering InitStyleItems() ...");
   178: 
   179:     InitStyleItem(Wildcard);
   180: 
   181:     InitStyleItem(Toolbar);
   182:     InitStyleItem(ToolbarLabel);
   183:     InitStyleItem(ToolbarWindowLabel);
   184:     InitStyleItem(ToolbarClock);
   185:     InitStyleItem(ToolbarButton);
   186:     InitStyleItem(ToolbarButtonPressed);
   187:     InitStyleItem(ToolbarBorder);
   188: 
   189:     InitStyleItem(MenuTitle);
   190:     InitStyleItem(MenuFrame);
   191:     InitStyleItem(MenuActive);
   192:     InitStyleItem(MenuGrip);
   193:     InitStyleItem(MenuFrameBullet);
   194:     InitStyleItem(MenuActiveBullet);
   195:     InitStyleItem(MenuIndicator);
   196:     InitStyleItem(MenuSeparator);
   197:     InitStyleItem(MenuFrameBorder);
   198: 
   199:     InitStyleItem(Dock);
   200:     InitStyleItem(DockBorder);
   201: 
   202:     InitStyleItem(ActiveTask);
   203:     InitStyleItem(InactiveTask);
   204:     InitStyleItem(FlashingTask);
   205: 
   206:     InitStyleItem(Console);
   207: 
   208:     InitStyleItem(WindowTitleFocus);
   209:     InitStyleItem(WindowTitleUnfocus);
   210:     InitStyleItem(WindowLabelFocus);
   211:     InitStyleItem(WindowLabelUnfocus);
   212:     InitStyleItem(WindowButtonFocus);
   213:     InitStyleItem(WindowButtonUnfocus);
   214:     InitStyleItem(WindowButtonPressed);
   215:     InitStyleItem(WindowGripFocus);
   216:     InitStyleItem(WindowGripUnfocus);
   217:     InitStyleItem(WindowHandleFocus);
   218:     InitStyleItem(WindowHandleUnfocus);
   219: 
   220:     InitStyleItem(ExternalHardware);
   221: }
   222: 
   223: //====================
   224: 
   225: void Settings::InitStyleItem(StyleItem* styleItem)
   226: {
   227:     // ##################################################################################
   228:     // Below: COLOR_UNDEFINED is later used e.g. by ReadStyleElement() to detect if
   229:     // these colours have been read or calculated before... (i.e. inherited or otherwise)
   230:     // ##################################################################################
   231: 
   232:     if (styleItem->Image.bitmap)
   233:     {
   234: //      if (debugLogging) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)styleItem->Image.path);
   235:         DeleteObject(styleItem->Image.bitmap); // Note: We need to do this *before* we ZeroMemory as part of a re-initialization... :)
   236:     }
   237: 
   238:     ZeroMemory(styleItem, sizeof(StyleItem));
   239: 
   240:     styleItem->parentRelative = false;
   241:     styleItem->type = B_SOLID;
   242:     styleItem->bevelstyle = BEVEL_FLAT;
   243:     styleItem->bevelposition = BEVEL1;
   244:     styleItem->interlaced = false;
   245: 
   246:     styleItem->Color1 = styleItem->Color2 = 0x000000;
   247:     styleItem->Color3 = styleItem->Color4 = 0x000000;
   248:     styleItem->Color5 = styleItem->Color6 = styleItem->Color7 = styleItem->Color8 = 0x000000;
   249: 
   250:     styleItem->TextColor = styleItem->foregroundColor = 0xffffff;
   251:     styleItem->disabledColor = 0x888888;
   252: 
   253:     styleItem->ShadowColor = styleItem->OutlineColor = COLOR_UNDEFINED; // -> Not pre-defined, not yet calculated, not yet defined.
   254:     styleItem->FontOutline = styleItem->FontShadow = false;
   255:     
   256:     strcpy_s(styleItem->Font, sizeofArray(styleItem->Font), "Segoe UI");
   257:     styleItem->FontHeight = 15;
   258:     styleItem->FontWeight = FW_NORMAL;
   259:     styleItem->Justify = DT_CENTER;
   260: 
   261:     styleItem->marginWidth = 0;
   262: 
   263:     styleItem->borderColor = 0x000000;
   264:     styleItem->borderWidth = 0;
   265:     styleItem->bordered = false;
   266: 
   267:     styleItem->Image.path[0] = '\0';
   268:     styleItem->Image.mode = 0;
   269:     styleItem->Image.width = styleItem->Image.height = styleItem->Image.left = styleItem->Image.top = styleItem->Image.right = styleItem->Image.bottom = 0;
   270: 
   271:     styleItem->nVersion = CORE_SHELL_STYLEITEM; // -> "This StyleItem belongs to the core shell" (see also BBApi.cpp/h)
   272: }
   273: 
   274: //===========================================================================
   275: // Functions: DestroyStyleItems -> DestroyStyleItem
   276: // Purpose: Safely destroys all StyleItems (including members) upon exit
   277: //===========================================================================
   278: 
   279: void Settings::DestroyStyleItems()
   280: {
   281:     DestroyStyleItem(Wildcard);
   282: 
   283:     DestroyStyleItem(Toolbar);
   284:     DestroyStyleItem(ToolbarLabel);
   285:     DestroyStyleItem(ToolbarWindowLabel);
   286:     DestroyStyleItem(ToolbarClock);
   287:     DestroyStyleItem(ToolbarButton);
   288:     DestroyStyleItem(ToolbarButtonPressed);
   289:     DestroyStyleItem(ToolbarBorder);
   290: 
   291:     DestroyStyleItem(MenuTitle);
   292:     DestroyStyleItem(MenuFrame);
   293:     DestroyStyleItem(MenuActive);
   294:     DestroyStyleItem(MenuGrip);
   295:     DestroyStyleItem(MenuFrameBullet);
   296:     DestroyStyleItem(MenuActiveBullet);
   297:     DestroyStyleItem(MenuIndicator);
   298:     DestroyStyleItem(MenuSeparator);
   299:     DestroyStyleItem(MenuFrameBorder);
   300: 
   301:     DestroyStyleItem(Dock);
   302:     DestroyStyleItem(DockBorder);
   303: 
   304:     DestroyStyleItem(ActiveTask);
   305:     DestroyStyleItem(InactiveTask);
   306:     DestroyStyleItem(FlashingTask);
   307: 
   308:     DestroyStyleItem(Console);
   309: 
   310:     DestroyStyleItem(WindowTitleFocus);
   311:     DestroyStyleItem(WindowTitleUnfocus);
   312:     DestroyStyleItem(WindowLabelFocus);
   313:     DestroyStyleItem(WindowLabelUnfocus);
   314:     DestroyStyleItem(WindowButtonFocus);
   315:     DestroyStyleItem(WindowButtonUnfocus);
   316:     DestroyStyleItem(WindowButtonPressed);
   317:     DestroyStyleItem(WindowGripFocus);
   318:     DestroyStyleItem(WindowGripUnfocus);
   319:     DestroyStyleItem(WindowHandleFocus);
   320:     DestroyStyleItem(WindowHandleUnfocus);
   321: 
   322:     DestroyStyleItem(ExternalHardware);
   323: }
   324: 
   325: //====================
   326: 
   327: void Settings::DestroyStyleItem(StyleItem* styleItem)
   328: {
   329:     if (styleItem)
   330:     {
   331:         if (styleItem->Image.bitmap) DeleteObject(styleItem->Image.bitmap);
   332:         delete styleItem;
   333:     }
   334: }
   335: 
   336: //===========================================================================
   337: // Functions: CreateFileCache / DestroyFileCache
   338: // Purpose: ...
   339: //===========================================================================
   340: 
   341: LPSTR Settings::CreateFileCache(LPSTR path)
   342: {
   343:     char* cachedFilePtr;
   344: 
   345: //  FILE* f = fopen(path, "r");
   346:     FILE* f = NULL;
   347:     fopen_s(&f, path, "r");
   348: 
   349:     if (f)
   350:     {
   351:         // Allocate memory for the file cache...
   352:         fseek(f, 0, SEEK_END);
   353:         long nLen = ftell(f);
   354:         cachedFilePtr = (char*)malloc(nLen+2);
   355:         if (cachedFilePtr != NULL)
   356:         {
   357:             // Copy the contents of the file to the file cache...
   358:             fseek (f, 0, SEEK_SET);
   359:             int readLen = fread (cachedFilePtr, 1, nLen, f);
   360:             cachedFilePtr[readLen] = '\0';
   361:             cachedFilePtr[readLen+1] = EOF;
   362:         }
   363:         fclose(f);
   364:     }
   365:     else
   366:     {
   367:         // Create a dummy cache if the requested file does not exist...
   368:         cachedFilePtr = (char*)malloc(2);
   369:         if (cachedFilePtr != NULL)
   370:         {
   371:             cachedFilePtr[0] = '\0';
   372:             cachedFilePtr[1] = EOF;
   373:         }
   374:     }
   375: 
   376:     return cachedFilePtr;
   377: }
   378: 
   379: //====================
   380: 
   381: void Settings::DestroyFileCache(LPSTR cachedFilePtr)
   382: {
   383:     if (cachedFilePtr) free(cachedFilePtr);
   384:     cachedFilePtr = NULL;
   385: }
   386: 
   387: //===========================================================================
   388: // Function: WriteDefaultRCSettings
   389: // Purpose: ...
   390: //===========================================================================
   391: 
   392: void Settings::WriteDefaultRCSettings()
   393: {
   394:     DWORD retLength=0;
   395:     char path[MAX_LINE_LENGTH], szTemp[MAX_LINE_LENGTH];
   396:     GetBlackboxPath(path, sizeofArray(path));
   397:     strcat_s(path, sizeofArray(path), "xoblite.rc");
   398: 
   399:     if (FileExists(path)) return;
   400:     else
   401:     {
   402:         // Try to download the latest default xoblite.rc available online...
   403:         bool downloadSuccessful = DownloadFile("http://xoblite.net/defaults/xoblite.rc", path);
   404:         if (downloadSuccessful)
   405:         {
   406:             // ...and double-check that the downloaded file wasn't actually a 404 message... :)
   407:             strcpy_s(szTemp, sizeofArray(szTemp), ReadString(path, "404 Not Found", ""));
   408:             if (strnlen_s(szTemp, sizeofArray(szTemp)) > 0) downloadSuccessful = false;
   409:         }
   410: 
   411:         if (!downloadSuccessful)
   412:         {
   413:             // If the downloading above wasn't successful, we create a "fallback" non-populated xoblite.rc as a last resort...
   414:             HANDLE f = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
   415:             if (f)
   416:             {
   417:                 strcpy_s(szTemp, sizeofArray(szTemp),
   418:                     "! =========================================================================================\r\n"
   419:                     "! Note: This \"fallback\" blank configuration file will be dynamically populated over time...\r\n"
   420:                     "! =========================================================================================\r\n\r\n");
   421:                 WriteFile(f, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
   422:             }
   423:             CloseHandle(f);
   424:         }
   425: 
   426:         strcpy_s(bbrcFile, sizeofArray(bbrcFile), path); // Legacy blackbox.rc (for backwards compatibility)
   427:         strcpy_s(xobrcDefaultFile, sizeofArray(xobrcDefaultFile), path); // Default xoblite.rc (for universal settings)
   428:     }
   429: }
   430: 
   431: //===========================================================================
   432: // Function: ReadConfiguration
   433: // Purpose: ...
   434: //===========================================================================
   435: 
   436: void Settings::ReadConfiguration()
   437: {
   438:     char temp[MAX_LINE_LENGTH];
   439: 
   440:     // ======================================================================
   441:     // First, let's read any *legacy* syntax blackbox.rc settings,
   442:     // so we can use them as possible fallbacks later...
   443:     // ======================================================================
   444: 
   445:     bbrcCache = CreateFileCache(bbrcFile);
   446: 
   447:     strcpy_s(styleFile, sizeofArray(styleFile), GetString(NULL, bbrcCache, "session.styleFile:", ""));
   448:     strcpy_s(menuFile, sizeofArray(menuFile), GetString(NULL, bbrcCache, "session.menuFile:", "$Blackbox$\\menu.rc"));
   449: 
   450:     strcpy_s(toolbarPlacementString, sizeofArray(toolbarPlacementString), GetString(NULL, bbrcCache, "session.screen0.toolbar.placement:", "BottomCenter"));
   451:     toolbarHorizontalWidth = GetInt(NULL, bbrcCache, "session.screen0.toolbar.widthPercent:", 75);
   452:     toolbarOnTop = GetBool(NULL, bbrcCache, "session.screen0.toolbar.onTop:", true);
   453:     strcpy_s(toolbarClockFormat, sizeofArray(toolbarClockFormat), GetString(NULL, bbrcCache, "session.screen0.strftimeFormat:", "%H:%M | %a %#d %b"));
   454: 
   455:     strcpy_s(dockPlacementString, sizeofArray(dockPlacementString), GetString(NULL, bbrcCache, "session.screen0.slit.placement:", "Manual xC y50"));
   456:     strcpy_s(dockDirection, sizeofArray(dockDirection), GetString(NULL, bbrcCache, "session.screen0.slit.direction:", "Horizontal"));
   457:     dockOnTop = GetBool(NULL, bbrcCache, "session.screen0.slit.onTop:", false);
   458: 
   459:     numberOfWorkspaces = GetInt(NULL, bbrcCache, "session.screen0.workspaces:", 4);
   460:     strcpy_s(workspaceNames, sizeofArray(workspaceNames), GetString(NULL, bbrcCache, "session.screen0.workspaceNames:", "")); // Nowadays automatically named "Workspace #1" etc if not specified (the old default used to be alpha,beta,gamma,delta)
   461: 
   462:     // focusLastWindow = GetBool(NULL, bbrcCache, "session.screen0.focusLastWindow:", false);
   463:     // strcpy_s(windowPlacement, sizeofArray(windowPlacement), GetString(NULL, bbrcCache, "session.screen0.windowPlacement:", "ColSmartPlacement"));
   464:     // strcpy_s(colPlacementDirection, sizeofArray(colPlacementDirection), GetString(NULL, bbrcCache, "session.screen0.colPlacementDirection:", "TopToBottom"));
   465:     // focusNewWindows = GetBool(NULL, bbrcCache, "session.screen0.focusNewWindows:", false);
   466:     // strcpy_s(rowPlacementDirection, sizeofArray(rowPlacementDirection), GetString(NULL, bbrcCache, "session.screen0.rowPlacementDirection:", "LeftToRight"));
   467: 
   468:     // strcpy_s(focusModel, sizeofArray(focusModel), GetString(NULL, bbrcCache, "session.screen0.focusModel:", "ClickToFocus"));
   469:     // opaqueMove = GetBool(NULL, bbrcCache, "session.opaqueMove:", false);
   470:     // fullMaximization = GetBool(NULL, bbrcCache, "session.screen0.fullMaximization:", true);
   471: 
   472:     edgeSnapThreshold = GetInt(NULL, bbrcCache, "session.screen0.edgeSnapThreshold:", 10);
   473:     // doubleClickInterval = GetInt(NULL, bbrcCache, "session.doubleClickInterval:", 250);
   474:     // autoRaiseDelay = GetInt(NULL, bbrcCache, "session.autoRaiseDelay:", 250);
   475: 
   476:     DestroyFileCache(bbrcCache);
   477: 
   478:     // ======================================================================
   479: 
   480:     // ##### Next, we read all xoblite syntax settings from xoblite.rc! #####
   481:     // Please note that a parameter may be read from the *default* xoblite.rc file
   482:     // (xobrcDefaultCache below) or the *current theme* xoblite.rc file (xobrcCache below)
   483:     // depending on the purpose of the parameter, i.e. theme related parameters are
   484:     // read from the current theme's xoblite.rc file while universal parameters
   485:     // (e.g. preferred editor) are read from the default theme's xoblite.rc file
   486: 
   487:     // ======================================================================
   488:     //========== THEME SPECIFIC SETTINGS ====================================
   489:     // ======================================================================
   490: 
   491:     xobrcCache = CreateFileCache(xobrcFile); // -> The current theme's xoblite.rc!
   492: 
   493:     //====================
   494: 
   495:     strcpy_s(styleFile, sizeofArray(styleFile), GetString(NULL, bbrcCache, "xoblite.styleFile:", styleFile));
   496:     if (strchr(styleFile, '\"')) StrRemoveEncap(styleFile);
   497:     if (strchr(styleFile, '$')) ReplaceShellFolders(styleFile);
   498:     if (strchr(styleFile, '%')) ReplaceEnvVars(styleFile);
   499: 
   500:     //====================
   501: 
   502:     menuSeparators = GetBool(NULL, xobrcCache, "xoblite.menu.separators:", true);
   503:     menuRoundedCorners = GetBool(NULL, xobrcCache, "xoblite.menu.rounded:", false);
   504:     menuTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.menu.transparency.alpha:", 255);
   505:     menuTitleTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.menu.title.transparency.alpha:", menuTransparencyAlpha);
   506:     menuFrameTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.menu.frame.transparency.alpha:", menuTransparencyAlpha);
   507:     menuActiveTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.menu.active.transparency.alpha:", menuTransparencyAlpha);
   508:     menuGripTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.menu.grip.transparency.alpha:", menuTransparencyAlpha);
   509: 
   510:     //====================
   511: 
   512:     toolbarHidden = GetBool(NULL, xobrcCache, "xoblite.toolbar.hidden:", false);
   513:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.toolbar.placement:", toolbarPlacementString));
   514:     ParsePlacement(temp, &ToolbarPlacement);
   515:     toolbarVertical = GetBool(NULL, xobrcCache, "xoblite.toolbar.vertical:", false);
   516:     toolbarHorizontalWidth = GetInt(NULL, xobrcCache, "xoblite.toolbar.widthPercent:", toolbarHorizontalWidth); // -> Used prior to xoblite bb5, cf. width only as percentage in legacy *box...
   517:     toolbarHorizontalWidth = GetInt(NULL, xobrcCache, "xoblite.toolbar.horizontal.width:", toolbarHorizontalWidth); // -> Used by xoblite bb5 onwards, cf. adaptive parsing of width <> 100 etc...
   518:     if (toolbarHorizontalWidth < 30) toolbarHorizontalWidth = 30;
   519:     toolbarVerticalWidth = GetInt(NULL, xobrcCache, "xoblite.toolbar.vertical.width:", 0); // (If not specified, the vertical toolbar width is set automatically by xoblite.)
   520: //  if (toolbarVerticalWidth < 5) toolbarVerticalWidth = 5;
   521:     toolbarTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.toolbar.transparency.alpha:", 255);
   522:     toolbarLabelTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.toolbar.label.transparency.alpha:", toolbarTransparencyAlpha);
   523:     toolbarWindowLabelTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.toolbar.windowlabel.transparency.alpha:", toolbarTransparencyAlpha);
   524:     toolbarClockTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.toolbar.clock.transparency.alpha:", toolbarTransparencyAlpha);
   525:     toolbarButtonTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.toolbar.button.transparency.alpha:", toolbarTransparencyAlpha);
   526:     toolbarRoundedCorners = GetBool(NULL, xobrcCache, "xoblite.toolbar.rounded:", false);
   527:     toolbarOnTop = GetBool(NULL, xobrcCache, "xoblite.toolbar.onTop:", toolbarOnTop);
   528:     toolbarSnapToEdges = GetBool(NULL, xobrcCache, "xoblite.toolbar.snapToEdges:", false);
   529: 
   530:     toolbarLabelHidden = GetBool(NULL, xobrcCache, "xoblite.toolbar.label.hidden:", false);
   531:     toolbarDownUpButtonsHidden = GetBool(NULL, xobrcCache, "xoblite.toolbar.downup.buttons.hidden:", false);
   532:     toolbarLeftRightButtonsHidden = GetBool(NULL, xobrcCache, "xoblite.toolbar.leftright.buttons.hidden:", false);
   533:     toolbarClockHidden = GetBool(NULL, xobrcCache, "xoblite.toolbar.clock.hidden:", false);
   534:     toolbarAllowAsymmetry = GetBool(NULL, xobrcCache, "xoblite.toolbar.allow.asymmetry:", false);
   535: 
   536:     strcpy_s(toolbarLabelDLClickOverride, sizeofArray(toolbarLabelDLClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.label.dlclick.override:", ""));
   537:     strcpy_s(toolbarLabelRClickOverride, sizeofArray(toolbarLabelRClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.label.rclick.override:", ""));
   538:     strcpy_s(toolbarLabelMClickOverride, sizeofArray(toolbarLabelMClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.label.mclick.override:", ""));
   539:     strcpy_s(toolbarLabelX1ClickOverride, sizeofArray(toolbarLabelX1ClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.label.x1click.override:", ""));
   540:     strcpy_s(toolbarLabelX2ClickOverride, sizeofArray(toolbarLabelX2ClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.label.x2click.override:", ""));
   541: 
   542:     strcpy_s(toolbarClockDLClickOverride, sizeofArray(toolbarClockDLClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.clock.dlclick.override:", ""));
   543:     strcpy_s(toolbarClockRClickOverride, sizeofArray(toolbarClockRClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.clock.rclick.override:", ""));
   544:     strcpy_s(toolbarClockMClickOverride, sizeofArray(toolbarClockMClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.clock.mclick.override:", ""));
   545:     strcpy_s(toolbarClockX1ClickOverride, sizeofArray(toolbarClockX1ClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.clock.x1click.override:", ""));
   546:     strcpy_s(toolbarClockX2ClickOverride, sizeofArray(toolbarClockX2ClickOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.clock.x2click.override:", ""));
   547: 
   548:     strcpy_s(toolbarDownButtonOverride, sizeofArray(toolbarDownButtonOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.downbutton.override:", ""));
   549:     strcpy_s(toolbarUpButtonOverride, sizeofArray(toolbarUpButtonOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.upbutton.override:", ""));
   550:     strcpy_s(toolbarLeftButtonOverride, sizeofArray(toolbarLeftButtonOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.leftbutton.override:", ""));
   551:     strcpy_s(toolbarRightButtonOverride, sizeofArray(toolbarRightButtonOverride), GetString(NULL, xobrcCache, "xoblite.toolbar.rightbutton.override:", ""));
   552: 
   553:     //====================
   554: 
   555:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.taskbar.mode:", "Bars+Icons"));
   556:     {
   557:         if (!_stricmp(temp, "Bars")) taskbarMode = TASKBAR_MODE_BARS;
   558:         else if (!_stricmp(temp, "Bars+Icons")) taskbarMode = TASKBAR_MODE_BARSICONS;
   559:         else if (!_stricmp(temp, "Icons")) taskbarMode = TASKBAR_MODE_ICONS;
   560:         else taskbarMode = TASKBAR_MODE_HIDDEN; // -> Hide the taskbar, show the toolbar windowLabel instead...
   561:     }
   562:     taskbarMaxItems = GetInt(NULL, xobrcCache, "xoblite.taskbar.max.items:", 10); // ...no maximum if set to 0...
   563:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.taskbar.sorting:", "FollowActive"));
   564:     {
   565:         if (!_stricmp(temp, "LastUsed")) taskbarSorting = TASKBAR_SORT_BY_LAST_USED;
   566:         else if (!_stricmp(temp, "FollowActive")) taskbarSorting = TASKBAR_SORT_FOLLOW_ACTIVE;
   567:         else taskbarSorting = TASKBAR_SORT_DISABLED;
   568:     }
   569:     taskbarShowTaskWorkspace = GetBool(NULL, xobrcCache, "xoblite.taskbar.show.task.workspace:", true);
   570:     taskbarCurrentOnly = GetBool(NULL, xobrcCache, "xoblite.taskbar.currentOnly:", false);
   571:     taskbarFlashing = GetBool(NULL, xobrcCache, "xoblite.taskbar.flashing:", true);
   572:     taskbarSaturationValue = GetInt(NULL, xobrcCache, "xoblite.taskbar.saturation:", 30);
   573:     taskbarHueIntensity = GetInt(NULL, xobrcCache, "xoblite.taskbar.hue:", 100);
   574:     taskbarActiveSatHue = GetBool(NULL, xobrcCache, "xoblite.taskbar.active.SatHue:", false);
   575:     taskbarActiveTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.taskbar.active.transparency.alpha:", toolbarTransparencyAlpha);
   576: //  taskbarActiveLivePreview = GetBool(NULL, xobrcCache, "xoblite.taskbar.active.live.preview:", true);
   577:     taskbarActiveLivePreview = false; // Deprecated, kept until all related code has been removed
   578:     taskbarInactiveBackground = GetBool(NULL, xobrcCache, "xoblite.taskbar.inactive.background:", false);
   579:     taskbarPreviews = GetBool(NULL, xobrcCache, "xoblite.taskbar.previews:", true);
   580:     bool tempTooltips = GetBool(NULL, xobrcCache, "xoblite.toolbar.tooltips.disable:", false); // -> Used prior to xoblite bb5, parsed for backwards compatibility only...
   581:     taskbarTooltips = GetBool(NULL, xobrcCache, "xoblite.taskbar.tooltips:", !tempTooltips); // -> Used by xoblite bb5 onwards (cf. now used only by the taskbar, the systray has been removed, etc)
   582: 
   583:     //====================
   584: 
   585:     dockHidden = GetBool(NULL, xobrcCache, "xoblite.dock.hidden:", false);
   586:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.dock.placement:", dockPlacementString));
   587:     ParsePlacement(temp, &DockPlacement);
   588:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.dock.direction:", dockDirection)); // -> Used prior to xoblite bb5, parsed for backwards compatibility only...
   589:     {
   590:         if (!_stricmp(temp, "Vertical")) dockVertical = true;
   591:         else dockVertical = false;
   592:     }
   593:     dockVertical = GetBool(NULL, xobrcCache, "xoblite.dock.vertical:", dockVertical);
   594: 
   595:     dockSnapToEdges = GetBool(NULL, xobrcCache, "xoblite.dock.snapToEdges:", false);
   596:     dockTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.dock.transparency.alpha:", 255);
   597: 
   598:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.dock.positioning:", "")); // -> Used prior to xoblite bb5, parsed for backwards compatibility only...
   599:     if (!_stricmp(temp, "SideBySide")) dockPuzzlePositioning = false;
   600:     else dockPuzzlePositioning = true;
   601:     dockPuzzlePositioning = GetBool(NULL, xobrcCache, "xoblite.dock.puzzle.positioning:", dockPuzzlePositioning);
   602: 
   603:     dockOnTop = GetBool(NULL, xobrcCache, "xoblite.dock.onTop:", dockOnTop);
   604: 
   605:     //====================
   606: 
   607:     consoleHidden = GetBool(NULL, xobrcCache, "xoblite.console.hidden:", true);
   608:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.console.placement:", "Default"));
   609:     ParsePlacement(temp, &ConsolePlacement);
   610:     consoleMaximized = GetBool(NULL, xobrcCache, "xoblite.console.maximized:", true);
   611:     consoleMaximizedWidth = GetInt(NULL, xobrcCache, "xoblite.console.maximized.width:", 0);
   612:     consoleMaximizedMessages = GetInt(NULL, xobrcCache, "xoblite.console.maximized.messages:", 10);
   613:     if (consoleMaximizedMessages < 1) consoleMaximizedMessages = 1;
   614:     consoleRestoredWidth = GetInt(NULL, xobrcCache, "xoblite.console.restored.width:", 0);
   615:     consoleRestoredMessages = GetInt(NULL, xobrcCache, "xoblite.console.restored.messages:", 1);
   616:     if (consoleRestoredMessages < 1) consoleMaximizedMessages = 1;
   617:     consoleTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.console.transparency.alpha:", 85);
   618:     consoleDesktopMode = GetBool(NULL, xobrcCache, "xoblite.console.desktop.mode:", false);
   619:     consoleRoundedCorners = GetBool(NULL, xobrcCache, "xoblite.console.rounded:", true);
   620:     consolePadding = GetInt(NULL, xobrcCache, "xoblite.console.padding:", 0);
   621: 
   622:     StyleItem tempStyleItem;
   623:     ZeroMemory(&tempStyleItem, sizeof(StyleItem));
   624:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.console.font:", ""));
   625:     ParseFontString(temp, &tempStyleItem);
   626:     if (strnlen_s(tempStyleItem.Font, sizeofArray(tempStyleItem.Font)))
   627:     {
   628:         strcpy_s(consoleFont, sizeofArray(consoleFont), tempStyleItem.Font);
   629:         consoleFontHeight = tempStyleItem.FontHeight;
   630:         consoleFontWeight = tempStyleItem.FontWeight;
   631:         consoleFontDefined = true;
   632:     }
   633:     else consoleFontDefined = false;
   634: 
   635:     //====================
   636: 
   637:     desktopClockHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.clock.hidden:", true);
   638:     strcpy_s(desktopClockType, sizeofArray(desktopClockType), GetString(NULL, xobrcCache, "xoblite.desktop.clock.type:", "Regular"));
   639:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.clock.placement:", "Default"));
   640:     ParsePlacement(temp, &desktopClockPlacement);
   641:     desktopClockTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.desktop.clock.transparency.alpha:", 210);
   642: 
   643:     desktopWeekdayHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.weekday.hidden:", true);
   644:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.weekday.placement:", "Manual x-50 y-100"));
   645:     ParsePlacement(temp, &desktopWeekdayPlacement);
   646:     desktopWeekdayTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.desktop.weekday.transparency.alpha:", 210);
   647: 
   648:     desktopDateHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.date.hidden:", true);
   649:     strcpy_s(desktopDateFormat, sizeofArray(desktopDateFormat), GetString(NULL, xobrcCache, "xoblite.desktop.date.format:", "%B %#d %Y"));
   650:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.date.placement:", "Manual x-50 y-50"));
   651:     ParsePlacement(temp, &desktopDatePlacement);
   652:     desktopDateTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.desktop.date.transparency.alpha:", 105);
   653: 
   654:     desktopGreetingHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.greeting.hidden:", true);
   655:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.greeting.placement:", "Manual x-50 y-50"));
   656:     ParsePlacement(temp, &desktopGreetingPlacement);
   657:     desktopGreetingTransparencyAlpha = (BYTE)GetInt(NULL, xobrcCache, "xoblite.desktop.greeting.transparency.alpha:", 60);
   658: 
   659:     desktopWorkspaceIndicatorHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.indicator.hidden:", false);
   660: 
   661:     desktopBorderHidden = GetBool(NULL, xobrcCache, "xoblite.desktop.border.hidden:", true);
   662: 
   663:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.clock.font:", ""));
   664:     ParseFontString(temp, &tempStyleItem);
   665:     if (strnlen_s(tempStyleItem.Font, sizeofArray(tempStyleItem.Font)))
   666:     {
   667:         strcpy_s(desktopClockFont, sizeofArray(desktopClockFont), tempStyleItem.Font);
   668:         desktopClockFontHeight = tempStyleItem.FontHeight;
   669:         desktopClockFontWeight = tempStyleItem.FontWeight;
   670:         desktopClockFontDefined = true;
   671:     }
   672:     else desktopClockFontDefined = false;
   673: 
   674:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.weekday.font:", temp)); // -> Inherits desktop clock font if not specified
   675:     ParseFontString(temp, &tempStyleItem);
   676:     if (strnlen_s(tempStyleItem.Font, sizeofArray(tempStyleItem.Font)))
   677:     {
   678:         strcpy_s(desktopWeekdayFont, sizeofArray(desktopWeekdayFont), tempStyleItem.Font);
   679:         desktopWeekdayFontHeight = tempStyleItem.FontHeight;
   680:         desktopWeekdayFontWeight = tempStyleItem.FontWeight;
   681:         desktopWeekdayFontDefined = true;
   682:     }
   683:     else desktopWeekdayFontDefined = false;
   684: 
   685:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.date.font:", temp)); // -> Inherits desktop weekday font if not specified
   686:     ParseFontString(temp, &tempStyleItem);
   687:     if (strnlen_s(tempStyleItem.Font, sizeofArray(tempStyleItem.Font)))
   688:     {
   689:         strcpy_s(desktopDateFont, sizeofArray(desktopDateFont), tempStyleItem.Font);
   690:         desktopDateFontHeight = tempStyleItem.FontHeight;
   691:         desktopDateFontWeight = tempStyleItem.FontWeight;
   692:         desktopDateFontDefined = true;
   693:     }
   694:     else desktopDateFontDefined = false;
   695: 
   696:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.greeting.font:", temp)); // -> Inherits desktop date font if not specified
   697:     ParseFontString(temp, &tempStyleItem);
   698:     if (strnlen_s(tempStyleItem.Font, sizeofArray(tempStyleItem.Font)))
   699:     {
   700:         strcpy_s(desktopGreetingFont, sizeofArray(desktopGreetingFont), tempStyleItem.Font);
   701:         desktopGreetingFontHeight = tempStyleItem.FontHeight;
   702:         desktopGreetingFontWeight = tempStyleItem.FontWeight;
   703:         desktopGreetingFontDefined = true;
   704:     }
   705:     else desktopGreetingFontDefined = false;
   706: 
   707:     desktopWidgetColor = GetColor(NULL, xobrcCache, "xoblite.desktop.widget.color:", NULL, 0xffffff, true);
   708:     desktopClockColor = GetColor(NULL, xobrcCache, "xoblite.desktop.clock.color:", NULL, desktopWidgetColor, true);
   709:     desktopWeekdayColor = GetColor(NULL, xobrcCache, "xoblite.desktop.weekday.color:", NULL, desktopWidgetColor, true);
   710:     desktopDateColor = GetColor(NULL, xobrcCache, "xoblite.desktop.date.color:", NULL, desktopWidgetColor, true);
   711:     desktopGreetingColor = GetColor(NULL, xobrcCache, "xoblite.desktop.greeting.color:", NULL, desktopWidgetColor, true);
   712: 
   713:     wcscpy_s(desktopGreetingNight, sizeofArray(desktopGreetingNight), GetStringUnicode(NULL, xobrcCache, "xoblite.desktop.greeting.night:", L"Good night"));                    // 00-06 -> "Good night"
   714:     wcscpy_s(desktopGreetingMorning, sizeofArray(desktopGreetingMorning), GetStringUnicode(NULL, xobrcCache, "xoblite.desktop.greeting.morning:", L"Good morning"));            // 06-12 -> "Good morning"
   715:     wcscpy_s(desktopGreetingAfternoon, sizeofArray(desktopGreetingAfternoon), GetStringUnicode(NULL, xobrcCache, "xoblite.desktop.greeting.afternoon:", L"Good afternoon"));    // 12-18 -> "Good afternoon"
   716:     wcscpy_s(desktopGreetingEvening, sizeofArray(desktopGreetingEvening), GetStringUnicode(NULL, xobrcCache, "xoblite.desktop.greeting.evening:", L"Good evening"));            // 18-24 -> "Good evening"
   717: 
   718:     desktopDisableGDIplusForWidgets = GetBool(NULL, xobrcCache, "xoblite.desktop.widgets.disable.gdiplus:", true);
   719: 
   720:     strcpy_s(desktopRClickOverride, sizeofArray(desktopRClickOverride), GetString(NULL, xobrcCache, "xoblite.desktop.rclick.override:", ""));
   721:     strcpy_s(desktopMClickOverride, sizeofArray(desktopMClickOverride), GetString(NULL, xobrcCache, "xoblite.desktop.mclick.override:", ""));
   722:     strcpy_s(desktopX1ClickOverride, sizeofArray(desktopX1ClickOverride), GetString(NULL, xobrcCache, "xoblite.desktop.x1click.override:", ""));
   723:     strcpy_s(desktopX2ClickOverride, sizeofArray(desktopX2ClickOverride), GetString(NULL, xobrcCache, "xoblite.desktop.x2click.override:", ""));
   724: /*
   725:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, xobrcCache, "xoblite.desktop.area:", ""));
   726:     if (strnlen_s(temp, MAX_LINE_LENGTH) > 0)
   727:     {
   728:         desktopAreaDefined = true;
   729: 
   730:         char left[10], top[10], right[10], bottom[10];
   731:         LPSTR tokens[4];
   732:         tokens[0] = left;
   733:         tokens[1] = top;
   734:         tokens[2] = right;
   735:         tokens[3] = bottom;
   736: 
   737:         left[0] = top[0] = right[0] = bottom[0] = '\0';
   738:         BBTokenize(temp, tokens, 3, bottom);
   739: 
   740:         desktopArea.left = atoi(left);
   741:         desktopArea.top = atoi(top);
   742:         desktopArea.right = atoi(right);
   743:         desktopArea.bottom = atoi(bottom);
   744:     }
   745:     else desktopAreaDefined = false;
   746: */
   747:     //====================
   748: 
   749:     pluginsHidden = GetBool(NULL, xobrcCache, "xoblite.plugins.hidden:", false);
   750: 
   751:     //====================
   752: 
   753:     writeProtection = GetBool(NULL, xobrcCache, "xoblite.write.protection:", false);
   754: 
   755:     //====================
   756: 
   757:     DestroyFileCache(xobrcCache);
   758: 
   759:     // ======================================================================
   760:     //========== UNIVERSAL SETTINGS =========================================
   761:     // ======================================================================
   762: 
   763:     xobrcDefaultCache = CreateFileCache(xobrcDefaultFile); // -> The default xoblite.rc!
   764: 
   765:     //====================
   766: 
   767:     strcpy_s(stylesFolder, sizeofArray(stylesFolder), GetString(NULL, xobrcDefaultCache, "xoblite.stylesFolder:", "$Blackbox$\\styles"));
   768:     if (strchr(stylesFolder, '\"')) StrRemoveEncap(stylesFolder);
   769:     if (strchr(stylesFolder, '$')) ReplaceShellFolders(stylesFolder);
   770:     if (strchr(stylesFolder, '%')) ReplaceEnvVars(stylesFolder);
   771: 
   772:     strcpy_s(themesFolder, sizeofArray(themesFolder), GetString(NULL, xobrcDefaultCache, "xoblite.themesFolder:", "$Blackbox$\\themes"));
   773:     if (strchr(themesFolder, '\"')) StrRemoveEncap(themesFolder);
   774:     if (strchr(themesFolder, '$')) ReplaceShellFolders(themesFolder);
   775:     if (strchr(themesFolder, '%')) ReplaceEnvVars(themesFolder);
   776: 
   777:     strcpy_s(wallpapersFolder, sizeofArray(wallpapersFolder), GetString(NULL, xobrcDefaultCache, "xoblite.wallpapersFolder:", "$Blackbox$\\wallpapers"));
   778:     if (strchr(wallpapersFolder, '\"')) StrRemoveEncap(wallpapersFolder);
   779:     if (strchr(wallpapersFolder, '$')) ReplaceShellFolders(wallpapersFolder);
   780:     if (strchr(wallpapersFolder, '%')) ReplaceEnvVars(wallpapersFolder);
   781: 
   782:     enableSoundFX = GetBool(NULL, xobrcDefaultCache, "xoblite.sound.effects:", true);
   783:     strcpy_s(soundsFolder, sizeofArray(soundsFolder), GetString(NULL, xobrcDefaultCache, "xoblite.soundsFolder:", "$Blackbox$\\sounds"));
   784:     if (strchr(soundsFolder, '\"')) StrRemoveEncap(soundsFolder);
   785:     if (strchr(soundsFolder, '$')) ReplaceShellFolders(soundsFolder);
   786:     if (strchr(soundsFolder, '%')) ReplaceEnvVars(soundsFolder);
   787: 
   788:     strcpy_s(hotkeysFile, sizeofArray(hotkeysFile), GetString(NULL, xobrcDefaultCache, "xoblite.hotkeysFile:", "$Blackbox$\\hotkeys.rc"));
   789:     if (strchr(hotkeysFile, '\"')) StrRemoveEncap(hotkeysFile);
   790:     if (strchr(hotkeysFile, '$')) ReplaceShellFolders(hotkeysFile);
   791:     if (strchr(hotkeysFile, '%')) ReplaceEnvVars(hotkeysFile);
   792: 
   793:     strcpy_s(pluginsFile, sizeofArray(pluginsFile), GetString(NULL, xobrcDefaultCache, "xoblite.pluginsFile:", "$Blackbox$\\plugins.rc"));
   794:     if (strchr(pluginsFile, '\"')) StrRemoveEncap(pluginsFile);
   795:     if (strchr(pluginsFile, '$')) ReplaceShellFolders(pluginsFile);
   796:     if (strchr(pluginsFile, '%')) ReplaceEnvVars(pluginsFile);
   797: 
   798:     strcpy_s(selectedTheme, sizeofArray(selectedTheme), GetString(NULL, xobrcDefaultCache, "xoblite.selected.theme:", "[Default]"));
   799:     if (!_stricmp(selectedTheme, "<Default>")) strcpy_s(selectedTheme, sizeofArray(selectedTheme), "[Default]"); // (changed to avoid similarity to editable string/integer menu items, as it is also shown in the Themes menu)
   800: 
   801:     //====================
   802: 
   803:     strcpy_s(toolbarClockFormat, sizeofArray(toolbarClockFormat), GetString(NULL, xobrcDefaultCache, "xoblite.toolbar.strftimeFormat:", toolbarClockFormat));
   804: 
   805:     strcpy_s(menuFile, sizeofArray(menuFile), GetString(NULL, xobrcDefaultCache, "xoblite.menuFile:", menuFile));
   806:     if (strchr(menuFile, '\"')) StrRemoveEncap(menuFile);
   807:     if (strchr(menuFile, '$')) ReplaceShellFolders(menuFile);
   808:     if (strchr(menuFile, '%')) ReplaceEnvVars(menuFile);
   809:     if (!FileExists(menuFile))
   810:     {
   811:         // Check for menu.rc in the Blackbox and $UserAppData$\Blackbox directories...
   812:         strcpy_s(menuFile, sizeofArray(menuFile), ConfigFileExists("menu.rc", NULL));
   813:         if (!_stricmp(menuFile, ""))
   814:         {
   815:             // If not found, check for menurc in the same directories...
   816:             strcpy_s(menuFile, sizeofArray(menuFile), ConfigFileExists("menurc", NULL));
   817:             if (!_stricmp(menuFile, ""))
   818:             {
   819:                 // If still not found, create the default
   820:                 // menu.rc in the Blackbox directory...
   821:                 WriteDefaultMenu();
   822:             }
   823:         }
   824: 
   825:         // Finally, we save the newly configured menu.rc path...
   826:         menuPath(menuFile);
   827:     }
   828:     submenuDelay = GetInt(NULL, xobrcDefaultCache, "xoblite.submenu.delay:", 40);
   829: //  scrollSpeed = GetInt(NULL, xobrcDefaultCache, "xoblite.menu.scrollSpeed:", 10);
   830: //  wheelSpeed = GetInt(NULL, xobrcDefaultCache, "xoblite.menu.wheelSpeed:", 50);
   831: 
   832:     //====================
   833: 
   834:     numberOfWorkspaces = GetInt(NULL, xobrcDefaultCache, "xoblite.workspaces:", numberOfWorkspaces);
   835:     strcpy_s(workspaceNames, sizeofArray(workspaceNames), GetString(NULL, xobrcDefaultCache, "xoblite.workspaces.names:", workspaceNames));
   836:     mousewheelChanging = GetBool(NULL, xobrcDefaultCache, "xoblite.workspaces.mousewheel.changing:", false);
   837:     followActive = GetBool(NULL, xobrcDefaultCache, "xoblite.workspaces.followActive:", true);
   838:     wallpaperPerWorkspace = GetBool(NULL, xobrcDefaultCache, "xoblite.workspaces.wallpapers:", true);
   839: 
   840:     //====================
   841: 
   842:     strcpy_s(pluginsRepository, sizeofArray(pluginsRepository), GetString(NULL, xobrcDefaultCache, "xoblite.plugins.repository:", "http://xoblite.net/plugins.txt"));
   843: 
   844:     //====================
   845: 
   846:     doubleScaleHiDPI = GetBool(NULL, xobrcDefaultCache, "xoblite.double.scale:", true); // <- Deprecated, kept for backwards compatibility only, remapped to new integer scaling factor.
   847:     int legacyScalingFactor = 1;
   848:     if (doubleScaleHiDPI) legacyScalingFactor = 2;
   849:     scalingFactorHiDPI = GetInt(NULL, xobrcDefaultCache, "xoblite.hidpi.scaling.factor:", legacyScalingFactor); // <- New integer HiDPI scaling factor (1x-6x) for further flexibililty wrt ultra-high res screens
   850:     if (scalingFactorHiDPI < 1) scalingFactorHiDPI = 1; // Safeguard
   851:     if (scalingFactorHiDPI > 4) scalingFactorHiDPI = 4; // Safeguard
   852: 
   853:     multimonPlacements = GetBool(NULL, xobrcDefaultCache, "xoblite.multimonitor.placements:", false);
   854:     fullscreenDetection = GetBool(NULL, xobrcDefaultCache, "xoblite.fullscreen.detection:", false);
   855: 
   856:     disableRootCommands = GetBool(NULL, xobrcDefaultCache, "xoblite.disable.rootCommands:", false);
   857:     disableThemeFonts = GetBool(NULL, xobrcDefaultCache, "xoblite.disable.theme.fonts:", true);
   858:     disableScriptSupport = GetBool(NULL, xobrcDefaultCache, "xoblite.disable.script.support:", false);
   859: 
   860:     disableUnicodeParsing = GetBool(NULL, xobrcDefaultCache, "xoblite.disable.unicode.parsing:", false); // PRELIMINARY
   861: 
   862:     explorerHidden = GetBool(NULL, xobrcDefaultCache, "xoblite.explorer.hidden:", false);
   863: 
   864:     strcpy_s(timeDateLocale, sizeofArray(timeDateLocale), GetString(NULL, xobrcDefaultCache, "xoblite.toolbar.locale:", "")); // Old syntax (when used by the toolbar only)
   865:     strcpy_s(timeDateLocale, sizeofArray(timeDateLocale), GetString(NULL, xobrcDefaultCache, "xoblite.timedate.locale:", timeDateLocale)); // New syntax (when used by both toolbar and desktop)
   866: 
   867:     strcpy_s(preferredEditor, sizeofArray(preferredEditor), GetString(NULL, xobrcDefaultCache, "xoblite.editor:", "\"notepad.exe\""));
   868:     if (strchr(preferredEditor, '$')) ReplaceShellFolders(preferredEditor);
   869:     if (strchr(preferredEditor, '%')) ReplaceEnvVars(preferredEditor);
   870: 
   871:     strcpy_s(checkedForUpdates, sizeofArray(checkedForUpdates), GetString(NULL, xobrcDefaultCache, "xoblite.checked.for.updates:", "#001 / 2006-01-01"));
   872: 
   873:     //====================
   874: 
   875:     // fullMaximization = GetBool(NULL, xobrcDefaultCache, "xoblite.fullMaximization:", fullMaximization);
   876:     edgeSnapThreshold = GetInt(NULL, xobrcDefaultCache, "xoblite.edgeSnapThreshold:", edgeSnapThreshold);
   877:     // strcpy_s(focusModel, MAX_LINE_LENGTH, GetString(NULL, xobrcDefaultCache, "xoblite.focusModel:", focusModel));
   878: 
   879:     // opaqueMove = GetBool(NULL, xobrcDefaultCache, "xoblite.opaqueMove:", opaqueMove);
   880:     // doubleClickInterval = GetInt(NULL, xobrcDefaultCache, "xoblite.doubleClickInterval:", doubleClickInterval);
   881:     // autoRaiseDelay = GetInt(NULL, xobrcDefaultCache, "xoblite.autoRaiseDelay:", autoRaiseDelay);
   882: 
   883:     //====================
   884: 
   885:     debugLogging = GetBool(NULL, xobrcDefaultCache, "xoblite.debug:", false);
   886: 
   887:     //====================
   888: 
   889:     DestroyFileCache(xobrcDefaultCache);
   890: 
   891:     // ======================================================================
   892:     // ======================================================================
   893:     // ======================================================================
   894: /*
   895:     // Apply a few settings directly... (read: no better place to do it so we might as well do it here... ;))
   896:     SystemParametersInfo(SPI_SETACTIVEWNDTRKTIMEOUT, 0, (PVOID)autoRaiseDelay, SPIF_SENDCHANGE);
   897: 
   898:     if (!_stricmp(focusModel, "ClickToFocus"))
   899:     {
   900:         SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING, 0, (PVOID)false, SPIF_SENDCHANGE);
   901:         SystemParametersInfo(SPI_SETACTIVEWNDTRKZORDER, 0, (PVOID)false, SPIF_SENDCHANGE);
   902:     }
   903:     else if (!_stricmp(focusModel, "AutoRaiseSloppyFocus"))
   904:     {
   905:         SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING, 0, (PVOID)true, SPIF_SENDCHANGE);
   906:         SystemParametersInfo(SPI_SETACTIVEWNDTRKZORDER, 0, (PVOID)true, SPIF_SENDCHANGE);
   907:     }
   908:     else if (!_stricmp(focusModel, "SloppyFocus"))
   909:     {
   910:         SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING, 0, (PVOID)true, SPIF_SENDCHANGE);
   911:         SystemParametersInfo(SPI_SETACTIVEWNDTRKZORDER, 0, (PVOID)false, SPIF_SENDCHANGE);
   912:     }
   913: 
   914:     SystemParametersInfo(SPI_SETDOUBLECLICKTIME, doubleClickInterval, NULL, SPIF_SENDCHANGE);
   915:     SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, opaqueMove, NULL, SPIF_SENDCHANGE);
   916: */
   917: }
   918: 
   919: //===========================================================================
   920: // Function: WriteDefaultMenu
   921: // Purpose: ...
   922: //===========================================================================
   923: 
   924: void Settings::WriteDefaultMenu()
   925: {
   926:     DWORD retLength=0;
   927:     char temp[MAX_LINE_LENGTH];
   928: 
   929:     HANDLE f = CreateFile(menuFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
   930:     if (f)
   931:     {
   932:         strcpy_s(temp, MAX_LINE_LENGTH,
   933:             "[begin] ()\r\n"
   934:             "\t[exec] (Explorer) {explorer.exe /e,%SystemDrive%}\r\n"
   935:             "\t[submenu] (Start menu)\r\n"
   936:                 "\t\t[path] (Current user) {\"$StartMenu$\"}\r\n"
   937:                 "\t\t[path] (All users) {\"$CommonStartMenu$\"}\r\n"
   938:             "\t[end]\r\n"
   939:             "\t[submenu] (Shutdown menu)\r\n"
   940:                 "\t\t[lockworkstation] (Lock workstation)\r\n"
   941:                 "\t\t[separator]\r\n"
   942:                 "\t\t[standby] (Standby [sleep])\r\n"
   943:                 "\t\t[hibernate] (Hibernate [suspend])\r\n"
   944:                 "\t\t[separator]\r\n"
   945:                 "\t\t[logoff] (Log off)\r\n"
   946:                 "\t\t[reboot] (Restart [reboot])\r\n"
   947:                 "\t\t[shutdown] (Shutdown)\r\n"
   948:             "\t[end]\r\n"
   949:             "\t[separator]\r\n"
   950:             "\t[configuration] (xoblite)\r\n"
   951:             "[end] ()\r\n");
   952:         WriteFile(f, temp, strnlen_s(temp, MAX_LINE_LENGTH), &retLength, NULL);
   953:     }
   954: 
   955:     CloseHandle(f);
   956: 
   957:     GetBlackboxPath(menuFile, sizeofArray(menuFile));
   958:     strcat_s(menuFile, sizeofArray(menuFile), "menu.rc");
   959: }
   960: 
   961: //===========================================================================
   962: // Function: ReadStyle
   963: // Purpose: ...
   964: //===========================================================================
   965: 
   966: void Settings::ReadStyle()
   967: {
   968:     // ##################################################################################
   969:     // Sidenote: The ~messy inheritance between style elements, old wildcarding etc below
   970:     // is not an ideal situation, but legacy dependencies are tough to get rid of, so...
   971:     // ##################################################################################
   972: 
   973:     styleCache = CreateFileCache(styleFile);
   974:     if (styleCache == NULL) return;
   975: 
   976:     //====================
   977: 
   978:     char temp[MAX_LINE_LENGTH];
   979:     COLORREF tempColor;
   980:     bool bb4nix070syntax = false;
   981:     InitStyleItems(); // -> Resets all StyleItems back to a default state (including any applicable destroy/delete's)
   982: 
   983:     //====================
   984: 
   985:     // First, a few miscellaneous "style-wide" parameters...
   986: 
   987:     borderWidth = GetInt(NULL, styleCache, "borderWidth:", 0); // "For all parent elements" [?]
   988:     borderColor = GetColor(NULL, styleCache, "borderColor:", NULL, 0x000000, true);
   989: 
   990:     marginWidth = GetInt(NULL, styleCache, "marginWidth:", 0);
   991:     bevelWidth = GetInt(NULL, styleCache, "bevelWidth:", 1);
   992: 
   993:     handleHeight = GetInt(NULL, styleCache, "handleWidth:", 5); // ...often used?...
   994:     handleHeight = GetInt(NULL, styleCache, "handleHeight:", handleHeight); // ...more recent?... (and makes more sense of course!)
   995:     handleHeight = GetInt(NULL, styleCache, "window.handleHeight:", handleHeight); // ...bb4nix 0.70 syntax... (see https://raw.githubusercontent.com/bradleythughes/blackbox/master/data/README.style )
   996: 
   997:     // Width of the window frame (old parameter from bb4nix version 0.61+;
   998:     // when not specified, frameWidth defaults to the value of bevelWidth)
   999:     frameWidth = GetInt(NULL, styleCache, "frameWidth:", bevelWidth);
  1000: 
  1001:     // The "rootCommand" is executed whenever the style is selected,
  1002:     // typically setting a wallpaper... (e.g. using bsetbg or bsetroot)
  1003:     strcpy_s(rootCommand, sizeofArray(rootCommand), GetString(NULL, styleCache, "rootCommand:", ""));
  1004:     if (strchr(rootCommand, '$')) ReplaceShellFolders(rootCommand);
  1005:     if (strchr(rootCommand, '%')) ReplaceEnvVars(rootCommand);
  1006: 
  1007:     //====================
  1008: 
  1009:     // Wildcard settings... (nb. only a rudimentary top level implementation
  1010:     // due to the fact I *really* dislike the use of wildcards in styles... <sigh>)
  1011:     strcpy_s(wildcard, sizeofArray(wildcard), "Flat Solid");
  1012:     appearancePointer = wildcard;
  1013: 
  1014:     // First we fetch a few of the more common "non-dot" wildcards, e.g. *textColor...
  1015:     Wildcard->TextColor = GetColor(NULL, styleCache, "*textColor:", NULL, Wildcard->TextColor, true);
  1016: 
  1017:     strcpy_s(Wildcard->Font, sizeofArray(Wildcard->Font), GetString(NULL, styleCache, "*font:", Wildcard->Font));
  1018:     CheckFontSubstitution(Wildcard->Font);
  1019:     Wildcard->FontHeight = GetInt(NULL, styleCache, "*fontHeight:", Wildcard->FontHeight);
  1020: 
  1021:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "*alignment:", "Center"));
  1022:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "*justify:", temp));
  1023:     if (IsInString(temp, "Left")) Wildcard->Justify = DT_LEFT;
  1024:     else if (IsInString(temp, "Right")) Wildcard->Justify = DT_RIGHT;
  1025:     else Wildcard->Justify = DT_CENTER;
  1026: 
  1027:     Wildcard->borderWidth = GetInt(NULL, styleCache, "*borderWidth:", borderWidth); // "For all non-parent elements" [?]
  1028:     Wildcard->borderColor = GetColor(NULL, styleCache, "*borderColor:", NULL, borderColor, true);
  1029:     Wildcard->marginWidth = GetInt(NULL, styleCache, "*marginWidth:", marginWidth);
  1030: 
  1031:     // ...and use these as defaults for all "dotted" wildcards, e.g. *.textColor...
  1032:     ReadStyleElement(styleCache, Wildcard, "*", true);
  1033: 
  1034:     // Finally, a few odd birds thrown in just because I'm in a good mood... ;)
  1035:     strcpy_s(wildcardToolbarFont, sizeofArray(wildcardToolbarFont), GetString(NULL, styleCache, "toolbar*font:", Wildcard->Font));
  1036:     strcpy_s(wildcardMenuFont, sizeofArray(wildcardMenuFont), GetString(NULL, styleCache, "menu*font:", Wildcard->Font));
  1037:     strcpy_s(wildcardWindowFont, sizeofArray(wildcardWindowFont), GetString(NULL, styleCache, "window*font:", Wildcard->Font));
  1038: 
  1039:     //====================
  1040: 
  1041:     // Toolbar background
  1042:     strcpy_s(toolbar, sizeofArray(toolbar), "Flat Solid");
  1043:     appearancePointer = toolbar;
  1044:     CopyMemory(Toolbar, Wildcard, sizeof(StyleItem));
  1045:     Toolbar->Color = 0x000000;
  1046:     Toolbar->TextColor = 0xffffff;
  1047:     Toolbar->FontOutline = Toolbar->FontShadow = false;
  1048:     Toolbar->marginWidth = 1;
  1049:     Toolbar->borderWidth = borderWidth;
  1050:     strcpy_s(Toolbar->Font, sizeofArray(Toolbar->Font), wildcardToolbarFont);
  1051:     ReadStyleElement(styleCache, Toolbar, "toolbar", true);
  1052: 
  1053:     // If a console font is not defined in xoblite.rc, use the toolbar font as default...
  1054:     if (!consoleFontDefined)
  1055:     {
  1056:         strcpy_s(consoleFont, sizeofArray(consoleFont), Toolbar->Font);
  1057:         consoleFontHeight = Toolbar->FontHeight;
  1058:         consoleFontWeight = Toolbar->FontWeight;
  1059:     }
  1060: 
  1061:     if (Toolbar->ShadowY > Toolbar->marginWidth) Toolbar->ShadowY = Toolbar->marginWidth;
  1062: 
  1063:     //====================
  1064: 
  1065:     // Toolbar workspace label
  1066:     strcpy_s(toolbarLabel, sizeofArray(toolbarLabel), "ParentRelative");
  1067:     appearancePointer = toolbarLabel;
  1068:     CopyMemory(ToolbarLabel, Toolbar, sizeof(StyleItem));
  1069:     ToolbarLabel->FontOutline = ToolbarLabel->FontShadow = false;
  1070:     ToolbarLabel->borderWidth = Wildcard->borderWidth;
  1071:     ReadStyleElement(styleCache, ToolbarLabel, "toolbar.label", true);
  1072: 
  1073:     if (ToolbarLabel->ShadowY > ToolbarLabel->marginWidth) ToolbarLabel->ShadowY = ToolbarLabel->marginWidth;
  1074: 
  1075:     //====================
  1076: 
  1077:     // Toolbar window label
  1078:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "toolbar.windowLabel.appearance:", ""));
  1079:     if (!strnlen_s(temp, MAX_LINE_LENGTH)) strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "toolbar.windowLabel:", ""));
  1080: 
  1081:     if (strnlen_s(temp, MAX_LINE_LENGTH))
  1082:     {
  1083:         strcpy_s(toolbarWindowLabel, sizeofArray(toolbarWindowLabel), "Flat Solid");
  1084:         appearancePointer = toolbarWindowLabel;
  1085:         CopyMemory(ToolbarWindowLabel, Toolbar, sizeof(StyleItem));
  1086:         ToolbarWindowLabel->FontOutline = ToolbarWindowLabel->FontShadow = false;
  1087:         ToolbarWindowLabel->borderWidth = Wildcard->borderWidth;
  1088:         ToolbarWindowLabel->marginWidth = ToolbarLabel->marginWidth;
  1089:         ReadStyleElement(styleCache, ToolbarWindowLabel, "toolbar.windowLabel", true);
  1090:     }
  1091:     else
  1092:     {
  1093:         // Use workspace label settings if window label isn't defined... (applicable to some old 0.5x styles)
  1094:         strcpy_s(toolbarWindowLabel, sizeofArray(toolbarWindowLabel), toolbarLabel);
  1095:         CopyMemory(ToolbarWindowLabel, ToolbarLabel, sizeof(StyleItem));
  1096:     }
  1097: 
  1098:     if (ToolbarWindowLabel->ShadowY > ToolbarWindowLabel->marginWidth) ToolbarWindowLabel->ShadowY = ToolbarWindowLabel->marginWidth;
  1099: 
  1100:     //====================
  1101: 
  1102:     // Toolbar clock
  1103:     strcpy_s(toolbarClock, sizeofArray(toolbarClock), "ParentRelative");
  1104:     appearancePointer = toolbarClock;
  1105:     CopyMemory(ToolbarClock, Toolbar, sizeof(StyleItem));
  1106:     ToolbarClock->FontOutline = ToolbarClock->FontShadow = false;
  1107:     ToolbarClock->marginWidth = ToolbarLabel->marginWidth;
  1108:     ToolbarClock->borderWidth = Wildcard->borderWidth;
  1109:     ReadStyleElement(styleCache, ToolbarClock, "toolbar.clock", true);
  1110: 
  1111:     if (ToolbarClock->ShadowY > ToolbarClock->marginWidth) ToolbarClock->ShadowY = ToolbarClock->marginWidth;
  1112: 
  1113:     //====================
  1114: 
  1115:     // Toolbar text
  1116:     if (!strnlen_s(GetString(NULL, styleCache, "toolbar.textColor:", ""), MAX_LINE_LENGTH))
  1117:     {
  1118:         if (!strnlen_s(GetString(NULL, styleCache, "*textColor:", ""), MAX_LINE_LENGTH))
  1119:         {
  1120:             if (ToolbarWindowLabel->parentRelative) Toolbar->TextColor = ToolbarWindowLabel->TextColor;
  1121:             else if (ToolbarLabel->parentRelative) Toolbar->TextColor = ToolbarLabel->TextColor;
  1122:             else if (ToolbarClock->parentRelative) Toolbar->TextColor = ToolbarClock->TextColor;
  1123:             else Toolbar->TextColor = ToolbarWindowLabel->TextColor;
  1124:         }
  1125:         else Toolbar->TextColor = GetColor(NULL, styleCache, "*textColor:", NULL, Wildcard->TextColor, true);
  1126:     }
  1127:     else Toolbar->TextColor = GetColor(NULL, styleCache, "toolbar.textColor:", NULL, Wildcard->TextColor, true);
  1128: 
  1129: //  if (toolbarFontHeight > 12) Toolbar->FontHeight = toolbarFontHeight = 12;
  1130: 
  1131:     //====================
  1132: 
  1133:     // Toolbar buttons in non-pressed state...
  1134:     strcpy_s(toolbarButton, sizeofArray(toolbarButton), "Flat Solid");
  1135:     appearancePointer = toolbarButton;
  1136:     ToolbarButton->Color = 0x444444;
  1137:     ToolbarButton->PicColor = Toolbar->TextColor;
  1138:     ToolbarButton->borderColor = Toolbar->borderColor;
  1139:     ToolbarButton->borderWidth = Wildcard->borderWidth;
  1140:     ToolbarButton->marginWidth = 2;
  1141:     bb4nix070syntax = ReadStyleElement(styleCache, ToolbarButton, "toolbar.button", false);
  1142: 
  1143: //  tempColor = GetColor(NULL, styleCache, "toolbar.button.foregroundColor:", NULL, Toolbar->TextColor, true);
  1144: //  ToolbarButton->PicColor = GetColor(NULL, styleCache, "toolbar.button.picColor:", NULL, tempColor, true);
  1145: 
  1146:     //====================
  1147: 
  1148:     // Toolbar buttons in pressed state...
  1149:     strcpy_s(toolbarButtonPressed, sizeofArray(toolbarButtonPressed), "Flat Solid");
  1150:     appearancePointer = toolbarButtonPressed;
  1151:     CopyMemory(ToolbarButtonPressed, ToolbarButton, sizeof(StyleItem));
  1152:     ToolbarButtonPressed->Color = 0x222222;
  1153:     ToolbarButtonPressed->borderColor = Toolbar->borderColor;
  1154:     ToolbarButtonPressed->borderWidth = Wildcard->borderWidth;
  1155:     ToolbarButtonPressed->marginWidth = 2;
  1156:     bb4nix070syntax = ReadStyleElement(styleCache, ToolbarButtonPressed, "toolbar.button.pressed", false);
  1157: 
  1158: //  tempColor = GetColor(NULL, styleCache, "toolbar.button.pressed.foregroundColor:", NULL, ToolbarButton->PicColor, true);
  1159: //  ToolbarButtonPressed->PicColor = GetColor(NULL, styleCache, "toolbar.button.pressed.picColor:", NULL, tempColor, true);
  1160: 
  1161:     //====================
  1162: 
  1163:     // Toolbar gradient-style borders... (experimental from xoblite bb5 RC4)
  1164:     if (strnlen_s(GetString(NULL, styleCache, "toolbar.border.", ""), MAX_LINE_LENGTH)) // toolbar.border defined?
  1165:     {
  1166:         strcpy_s(toolbarBorder, sizeofArray(toolbarBorder), "");
  1167:         appearancePointer = toolbarBorder;
  1168:         ReadStyleElement(styleCache, ToolbarBorder, "toolbar.border", false);
  1169:     }
  1170:     else ToolbarBorder->parentRelative = true; // Disable toolbar gradient-style borders...
  1171: 
  1172:     //====================
  1173: 
  1174:     menuBorderColor = GetColor(NULL, styleCache, "menu.borderColor:", NULL, Wildcard->borderColor, true);
  1175:     menuBorderWidth = GetInt(NULL, styleCache, "menu.borderWidth:", borderWidth);
  1176: 
  1177:     // Menu title...
  1178:     strcpy_s(menuTitle, sizeofArray(menuTitle), "Flat Solid");
  1179:     appearancePointer = menuTitle;
  1180:     CopyMemory(MenuTitle, Wildcard, sizeof(StyleItem));
  1181:     MenuTitle->Color = 0x000000;
  1182:     MenuTitle->TextColor = Wildcard->TextColor;
  1183:     MenuTitle->borderColor = menuBorderColor;
  1184:     MenuTitle->borderWidth = menuBorderWidth;
  1185:     MenuTitle->marginWidth = marginWidth;
  1186:     strcpy_s(MenuTitle->Font, sizeofArray(MenuTitle->Font), wildcardMenuFont);
  1187:     MenuTitle->FontOutline = MenuTitle->FontShadow = false;
  1188:     ReadStyleElement(styleCache, MenuTitle, "menu.title", true);
  1189: 
  1190:     if (MenuTitle->ShadowY > MenuTitle->marginWidth) MenuTitle->ShadowY = MenuTitle->marginWidth;
  1191: 
  1192:     //====================
  1193: 
  1194:     // Menu frame...
  1195:     strcpy_s(menuFrame, sizeofArray(menuFrame), "Flat Solid");
  1196:     appearancePointer = menuFrame;
  1197:     CopyMemory(MenuFrame, MenuTitle, sizeof(StyleItem));
  1198:     MenuFrame->Color = 0x000000;
  1199:     MenuFrame->TextColor = Wildcard->TextColor;
  1200:     MenuFrame->borderColor = menuBorderColor;
  1201:     MenuFrame->borderWidth = menuBorderWidth;
  1202:     MenuFrame->marginWidth = marginWidth;
  1203:     strcpy_s(MenuFrame->Font, sizeofArray(MenuFrame->Font), wildcardMenuFont);
  1204:     MenuFrame->FontHeight = Wildcard->FontHeight;
  1205:     MenuFrame->Justify = Wildcard->Justify;
  1206:     MenuFrame->FontOutline = MenuFrame->FontShadow = false;
  1207:     ReadStyleElement(styleCache, MenuFrame, "menu.frame", true);
  1208: 
  1209:     tempColor = GetColor(NULL, styleCache, "menu.frame.foregroundColor:", NULL, MenuFrame->TextColor, true);
  1210:     MenuFrame->BulletColor = GetColor(NULL, styleCache, "menu.frame.bulletColor:", NULL, tempColor, true);
  1211: 
  1212:     // Optional menu frame gradient-style borders... (experimental from xoblite bb5 RC4)
  1213:     if (strnlen_s(GetString(NULL, styleCache, "menu.frame.border.", ""), MAX_LINE_LENGTH)) // menu.border defined?
  1214:     {
  1215:         strcpy_s(menuFrameBorder, sizeofArray(menuFrameBorder), "");
  1216:         appearancePointer = menuFrameBorder;
  1217:         ReadStyleElement(styleCache, MenuFrameBorder, "menu.frame.border", false);
  1218:     }
  1219:     else MenuFrameBorder->parentRelative = true; // Disable menu gradient-style borders...
  1220: 
  1221:     //====================
  1222: 
  1223:     // Highlighted/active menu items
  1224:     // (first parse any menu.hilite [classic syntax] settings, then any menu.active [0.70 syntax] settings,
  1225:     // i.e. the latter having priority if a parameter has been defined twice using both syntaxes...)
  1226:     strcpy_s(menuActive, sizeofArray(menuActive), "Flat Solid");
  1227:     appearancePointer = menuActive;
  1228:     CopyMemory(MenuActive, MenuFrame, sizeof(StyleItem));
  1229:     MenuActive->Color = MenuFrame->TextColor;
  1230:     MenuActive->TextColor = MenuFrame->Color;
  1231:     MenuActive->borderWidth = Wildcard->borderWidth;
  1232:     MenuActive->marginWidth = marginWidth;
  1233:     MenuActive->FontOutline = MenuActive->FontShadow = false;
  1234: //  strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "menu.active", ""));
  1235: //  if (strnlen_s(temp, MAX_LINE_LENGTH)) bb4nix070syntax = ReadStyleElement(styleCache, MenuActive, "menu.active", true);
  1236: //  else bb4nix070syntax = ReadStyleElement(styleCache, MenuActive, "menu.hilite", true);
  1237:     bb4nix070syntax = ReadStyleElement(styleCache, MenuActive, "menu.hilite", true); // Try looking for menu.hilite parameters first...
  1238:     bb4nix070syntax = ReadStyleElement(styleCache, MenuActive, "menu.active", true); // ...then overload menu.active on top of menu.hilite to allow for accidentally mixed syntax parameters... (yeah it does happen every now and then ;))
  1239: 
  1240:     MenuActive->BulletColor = GetColor(NULL, styleCache, "menu.hilite.bulletColor:", NULL, MenuActive->TextColor, true);
  1241:     tempColor = GetColor(NULL, styleCache, "menu.active.foregroundColor:", NULL, MenuActive->BulletColor, true);
  1242:     MenuActive->BulletColor = GetColor(NULL, styleCache, "menu.active.bulletColor:", NULL, tempColor, true);
  1243: 
  1244:     if (MenuActive->parentRelative)
  1245:     {
  1246:         MenuActive->type = B_PARENTRELATIVE;
  1247:         MenuActive->Color = MenuFrame->Color;
  1248:         MenuActive->ColorTo = MenuFrame->ColorTo;
  1249:     }
  1250: 
  1251:     if (MenuActive->ShadowY > MenuActive->marginWidth) MenuActive->ShadowY = MenuActive->marginWidth;
  1252: 
  1253:     //====================
  1254: 
  1255:     // Submenu bullet style+position for menu.frame and menu.active folder items... (nb. non-image bullet colours are parsed above for both of them)
  1256:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "menu.bullet:", "Triangle")); // -> Legacy style syntax (for backwards compatibility)
  1257:     strcpy_s(menuFrameBulletAsString, sizeofArray(menuFrameBulletAsString), GetString(NULL, styleCache, "menu.frame.bullet:", temp)); // -> Modern style syntax (for more flexibility)
  1258: 
  1259:     if (strchr(menuFrameBulletAsString, '.') || strchr(menuFrameBulletAsString, '\\')) // -> We detect whether a menu bullet image path has been specified by checking for an "only-in-a-path" character (. or \) in the style parameter string...
  1260:     {
  1261:         menuBullet = MENU_BULLET_IMAGE;
  1262: 
  1263:         if (strchr(menuFrameBulletAsString, '\"')) StrRemoveEncap(menuFrameBulletAsString);
  1264:         if (strchr(menuFrameBulletAsString, '$')) ReplaceShellFolders(menuFrameBulletAsString);
  1265:         if (strchr(menuFrameBulletAsString, '%')) ReplaceEnvVars(menuFrameBulletAsString);
  1266:         if (FileExists(menuFrameBulletAsString))
  1267:         {
  1268: //          strncpy(MenuFrameBullet->Image.path, menuFrameBulletAsString, MAX_PATH);
  1269:             strncpy_s(MenuFrameBullet->Image.path, sizeof(MenuFrameBullet->Image.path), menuFrameBulletAsString, _TRUNCATE);
  1270:             CreateElementImage(MenuFrameBullet);
  1271:         }
  1272: 
  1273:         // Below: A separate menu.active bullet image is optional, i.e. if not defined
  1274:         // the menu.bullet/menu.frame.bullet one is used also for menu.active bullets...
  1275:         strcpy_s(menuActiveBulletAsString, sizeofArray(menuActiveBulletAsString), GetString(NULL, styleCache, "menu.active.bullet:", menuFrameBulletAsString));
  1276:         if (strchr(menuActiveBulletAsString, '\"')) StrRemoveEncap(menuActiveBulletAsString);
  1277:         if (strchr(menuActiveBulletAsString, '$')) ReplaceShellFolders(menuActiveBulletAsString);
  1278:         if (strchr(menuActiveBulletAsString, '%')) ReplaceEnvVars(menuActiveBulletAsString);
  1279:         if (FileExists(menuActiveBulletAsString))
  1280:         {
  1281: //          strncpy(MenuActiveBullet->Image.path, menuActiveBulletAsString, MAX_PATH);
  1282:             strncpy_s(MenuActiveBullet->Image.path, sizeof(MenuActiveBullet->Image.path), menuActiveBulletAsString, _TRUNCATE);
  1283:             CreateElementImage(MenuActiveBullet);
  1284:         }
  1285:     }
  1286:     else if ((!_stricmp(menuFrameBulletAsString, "triangle")) || (!_stricmp(temp, "arrow"))) menuBullet = MENU_BULLET_TRIANGLE;
  1287:     else if (!_stricmp(menuFrameBulletAsString, "square")) menuBullet = MENU_BULLET_SQUARE;
  1288:     else if (!_stricmp(menuFrameBulletAsString, "diamond")) menuBullet = MENU_BULLET_DIAMOND;
  1289:     else if (!_stricmp(menuFrameBulletAsString, "circle")) menuBullet = MENU_BULLET_CIRCLE;
  1290:     else if (!_stricmp(menuFrameBulletAsString, "triple")) menuBullet = MENU_BULLET_TRIPLE;
  1291:     else if (!_stricmp(menuFrameBulletAsString, "comment")) menuBullet = MENU_BULLET_COMMENT;
  1292:     else if (!_stricmp(menuFrameBulletAsString, "grid")) menuBullet = MENU_BULLET_GRID;
  1293:     else if (!_stricmp(menuFrameBulletAsString, "quad")) menuBullet = MENU_BULLET_QUAD;
  1294:     else if (!_stricmp(menuFrameBulletAsString, "bitmap"))
  1295:     {
  1296:         // Unsupported: bbLean used to allow small bitmaps to be used as simple one-colour menu bullet "masks",
  1297:         // while xoblite nowadays support much more flexible ARGB images as frame/active bullets, see above.
  1298:         menuBullet = MENU_BULLET_TRIANGLE; // -> Fallback to triangle bullets...
  1299:     }
  1300:     else menuBullet = MENU_BULLET_EMPTY;
  1301: 
  1302:     strcpy_s(menuBulletPosition, sizeofArray(menuBulletPosition), GetString(NULL, styleCache, "menu.bullet.position:", "Right"));
  1303: 
  1304:     // Menu "indicators" for boolean items... (introduced in xoblite bb1)
  1305:     if (MenuActive->parentRelative)
  1306:     {
  1307:         CopyMemory(MenuIndicator, MenuTitle, sizeof(StyleItem));
  1308:         strcpy_s(menuIndicator, sizeofArray(menuIndicator), menuTitle);
  1309:     }
  1310:     else
  1311:     {
  1312:         CopyMemory(MenuIndicator, MenuActive, sizeof(StyleItem));
  1313:         strcpy_s(menuIndicator, sizeofArray(menuIndicator), menuActive);
  1314:     }
  1315:     appearancePointer = menuIndicator;
  1316:     ReadStyleElement(styleCache, MenuIndicator, "menu.indicator", false);
  1317: 
  1318:     // Menu separators... (originally introduced in xoblite bb2, later evolved further)
  1319: //  tempColor = GetColor(NULL, styleCache, "menu.separator.foregroundColor:", NULL, MenuFrame->TextColor, true);
  1320: //  MenuSeparator->Color = GetColor(NULL, styleCache, "menu.separator.color:", NULL, tempColor, true);
  1321: 
  1322:     strcpy_s(menuSeparator, sizeofArray(menuSeparator), "Flat Gradient MirrorHorizontal");
  1323:     appearancePointer = menuSeparator;
  1324:     CopyMemory(MenuSeparator, MenuFrame, sizeof(StyleItem));
  1325:     MenuSeparator->type = B_MIRRORHORIZONTAL;
  1326:     MenuSeparator->bevelstyle = BEVEL_FLAT;
  1327:     MenuSeparator->marginWidth = 1;
  1328: 
  1329:     if (!strnlen_s(GetString(NULL, styleCache, "menu.separator.appearance:", ""), MAX_LINE_LENGTH)) // No separator appearance defined -> Legacy separators mode
  1330:     {
  1331:         if (strnlen_s(GetString(NULL, styleCache, "menu.separator.shadowColor:", ""), MAX_LINE_LENGTH))
  1332:         {
  1333:             MenuSeparator->FontShadow = true;
  1334:             MenuSeparator->Color1 = MenuFrame->Color1;
  1335:             MenuSeparator->Color2 = GetColor(NULL, styleCache, "menu.separator.color:", NULL, MenuFrame->TextColor, true);
  1336:             MenuSeparator->ShadowColor = GetColor(NULL, styleCache, "menu.separator.shadowColor:", NULL, MenuFrame->Color, true);
  1337:             MenuSeparator->ShadowX = GetInt(NULL, styleCache, "menu.separator.shadowX:", 1);
  1338:             MenuSeparator->ShadowY = GetInt(NULL, styleCache, "menu.separator.shadowY:", 1);
  1339:         }
  1340:         else
  1341:         {
  1342:             MenuSeparator->Color1 = MenuFrame->Color1;
  1343:             tempColor = GetColor(NULL, styleCache, "menu.separator.foregroundColor:", NULL, MenuFrame->TextColor, true);
  1344:             MenuSeparator->Color2 = GetColor(NULL, styleCache, "menu.separator.color:", NULL, tempColor, true);
  1345:         }
  1346:     }
  1347:     else // Separator appearance defined -> Advanced separators mode (e.g. up to 8 colours etc)
  1348:     {
  1349:         MenuSeparator->Color1 = GetColor(NULL, styleCache, "menu.separator.foregroundColor:", NULL, MenuFrame->TextColor, true);
  1350:         MenuSeparator->Color2 = MenuSeparator->Color3 = MenuSeparator->Color4 = MenuSeparator->Color5 = MenuSeparator->Color6 = MenuSeparator->Color7 = MenuSeparator->Color8 = MenuSeparator->Color1;
  1351: //      ReadStyleElement(styleCache, MenuSeparator, "menu.separator", false);
  1352:         ReadStyleElement(styleCache, MenuSeparator, "menu.separator", true); // Note: Boolean true only in order to read shadowColor etc (normally part of the font related parsing)
  1353: 
  1354:         switch (MenuSeparator->type)
  1355:         {
  1356:             case B_SUPERHORIZONTAL:
  1357:             case B_SPLITHORIZONTAL:
  1358:             case B_MIRRORHORIZONTAL:
  1359:             case B_HORIZONTAL:
  1360:             case B_SOLID:
  1361:             case B_SPLITSOLID:
  1362:             {
  1363:                 break;
  1364:             }
  1365: 
  1366:             case B_SUPERVERTICAL: { MenuSeparator->type = B_SUPERHORIZONTAL; break; }
  1367:             case B_SPLITVERTICAL: { MenuSeparator->type = B_SPLITHORIZONTAL; break; }
  1368:             case B_VERTICAL: { MenuSeparator->type = B_HORIZONTAL; break; }
  1369: 
  1370:             default: { MenuSeparator->type = B_MIRRORHORIZONTAL; break; }
  1371:         }
  1372:     }
  1373: 
  1374:     if (MenuSeparator->ShadowX > 3) MenuSeparator->ShadowX = 3;
  1375:     else if (MenuSeparator->ShadowX < -3) MenuSeparator->ShadowX = -3;
  1376:     if (MenuSeparator->ShadowY > 3) MenuSeparator->ShadowY = 3;
  1377:     else if (MenuSeparator->ShadowY < -3) MenuSeparator->ShadowY = -3;
  1378: 
  1379:     //====================
  1380: 
  1381:     // Menu grip... (introduced in xoblite bb4 RC4)
  1382:     if (strnlen_s(GetString(NULL, styleCache, "menu.grip", ""), MAX_LINE_LENGTH)) // menu.grip defined?
  1383:     {
  1384:         strcpy_s(menuGrip, sizeofArray(menuGrip), "");
  1385:         appearancePointer = menuGrip;
  1386:         CopyMemory(MenuGrip, MenuTitle, sizeof(StyleItem));
  1387:         MenuGrip->marginWidth = MenuGrip->FontHeight = 0;
  1388:         MenuGrip->FontOutline = MenuGrip->FontShadow = false;
  1389:         ReadStyleElement(styleCache, MenuGrip, "menu.grip", true);
  1390: 
  1391: //      MenuGrip->parentRelative = false; // Enable menu grips...
  1392:         if (MenuGrip->ShadowY > MenuGrip->marginWidth) MenuGrip->ShadowY = MenuGrip->marginWidth;
  1393:     }
  1394:     else MenuGrip->parentRelative = true; // Disable menu grips...
  1395: 
  1396:     //====================
  1397: 
  1398:     // Dock...
  1399:     strcpy_s(dock, sizeofArray(dock), toolbar); // Default dock styling == Inherit toolbar styling
  1400:     appearancePointer = dock;
  1401:     CopyMemory(Dock, Toolbar, sizeof(StyleItem));
  1402:     ReadStyleElement(styleCache, Dock, "slit", false); // -> Backwards compatible with old slit.* style entries
  1403:     ReadStyleElement(styleCache, Dock, "dock", false);
  1404: 
  1405:     // Dock gradient-style borders... (experimental from xoblite bb5 RC4)
  1406:     if (strnlen_s(GetString(NULL, styleCache, "dock.border.", ""), MAX_LINE_LENGTH)) // dock.border defined?
  1407:     {
  1408:         strcpy_s(dockBorder, sizeofArray(dockBorder), "");
  1409:         appearancePointer = dockBorder;
  1410:         ReadStyleElement(styleCache, DockBorder, "dock.border", false);
  1411:     }
  1412:     else DockBorder->parentRelative = true; // Disable dock gradient-style borders...
  1413: 
  1414:     //====================
  1415: 
  1416:     // Taskbar active, non-active and flashing task buttons... (-> derived from other style elements, so also need to be updated dynamically on Designer Mode changes, hence the separate function)
  1417:     DeriveTaskbarStyle();
  1418: 
  1419:     //====================
  1420: 
  1421:     // Console...
  1422:     strcpy_s(console, sizeofArray(console), toolbar);
  1423:     appearancePointer = console;
  1424:     CopyMemory(Console, Toolbar, sizeof(StyleItem));
  1425:     Console->Color = 0x000000;
  1426:     Console->TextColor = 0xffffff;
  1427:     strcpy_s(Console->Font, sizeofArray(Console->Font), consoleFont);
  1428:     CheckFontSubstitution(Console->Font);
  1429:     Console->FontHeight = consoleFontHeight;
  1430:     Console->FontWeight = consoleFontWeight;
  1431:     Console->FontOutline = Console->FontShadow = false;
  1432:     ReadStyleElement(styleCache, Console, "console", true);
  1433: 
  1434:     Console->PicColor = GetColor(NULL, styleCache, "console.buttonColor:", NULL, Console->TextColor, true);
  1435: 
  1436:     //====================
  1437: 
  1438:     // Window title...
  1439:     strcpy_s(windowTitleFocus, sizeofArray(windowTitleFocus), toolbar);
  1440:     appearancePointer = windowTitleFocus;
  1441:     CopyMemory(WindowTitleFocus, Toolbar, sizeof(StyleItem));
  1442:     if (!ToolbarBorder->parentRelative) WindowTitleFocus->borderColor = ToolbarBorder->Color1; // -> Toolbar uses gradient borders, which are not (yet?) supported for WindowTitles, so let's use an approximation as default-if-not-defined borderColor...
  1443:     ReadStyleElement(styleCache, WindowTitleFocus, "window.title.focus", false);
  1444: 
  1445:     strcpy_s(windowTitleUnfocus, sizeofArray(windowTitleUnfocus), windowTitleFocus);
  1446:     appearancePointer = windowTitleUnfocus;
  1447:     CopyMemory(WindowTitleUnfocus, WindowTitleFocus, sizeof(StyleItem));
  1448:     ReadStyleElement(styleCache, WindowTitleUnfocus, "window.title.unfocus", false);
  1449: 
  1450:     // Window label...
  1451:     strcpy_s(windowLabelFocus, sizeofArray(windowLabelFocus), toolbarWindowLabel);
  1452:     appearancePointer = windowLabelFocus;
  1453:     CopyMemory(WindowLabelFocus, ToolbarWindowLabel, sizeof(StyleItem));
  1454:     strcpy_s(WindowLabelFocus->Font, wildcardWindowFont);
  1455:     ReadStyleElement(styleCache, WindowLabelFocus, "window.label.focus", true);
  1456: 
  1457:     strcpy_s(windowLabelUnfocus, sizeofArray(windowLabelUnfocus), windowLabelFocus);
  1458:     appearancePointer = windowLabelUnfocus;
  1459:     CopyMemory(WindowLabelUnfocus, WindowLabelFocus, sizeof(StyleItem));
  1460:     ReadStyleElement(styleCache, WindowLabelUnfocus, "window.label.unfocus", true);
  1461: 
  1462:     // Window buttons...
  1463:     strcpy_s(windowButtonFocus, sizeofArray(windowButtonFocus), toolbarButton);
  1464:     appearancePointer = windowButtonFocus;
  1465:     CopyMemory(WindowButtonFocus, ToolbarButton, sizeof(StyleItem));
  1466:     strcpy_s(WindowButtonFocus->Font, sizeofArray(WindowButtonFocus->Font), WindowLabelFocus->Font); // Since it can be of interest to have further "window" options, we create a hybrid of WindowButtonFocus colours etc and WindowLabelFocus font settings here...
  1467: //  CheckFontSubstitution(WindowButtonFocus->Font);
  1468:     WindowButtonFocus->FontHeight = WindowLabelFocus->FontHeight;
  1469:     WindowButtonFocus->FontWeight = WindowLabelFocus->FontWeight;
  1470:     WindowButtonFocus->TextColor = WindowButtonFocus->PicColor;
  1471:     WindowButtonFocus->FontOutline = WindowButtonFocus->FontShadow = false;
  1472:     ReadStyleElement(styleCache, WindowButtonFocus, "window.button.focus", false);
  1473: 
  1474:     strcpy_s(windowButtonUnfocus, sizeofArray(windowButtonUnfocus), windowButtonFocus);
  1475:     appearancePointer = windowButtonUnfocus;
  1476:     CopyMemory(WindowButtonUnfocus, WindowButtonFocus, sizeof(StyleItem));
  1477:     strcpy_s(WindowButtonUnfocus->Font, sizeofArray(WindowButtonUnfocus->Font), WindowLabelUnfocus->Font); // ...ditto above...
  1478: //  CheckFontSubstitution(WindowButtonUnfocus->Font);
  1479:     WindowButtonUnfocus->FontHeight = WindowLabelUnfocus->FontHeight;
  1480:     WindowButtonUnfocus->FontWeight = WindowLabelUnfocus->FontWeight;
  1481:     WindowButtonUnfocus->TextColor = WindowButtonUnfocus->PicColor;
  1482:     WindowButtonUnfocus->FontOutline = WindowButtonUnfocus->FontShadow = false;
  1483:     ReadStyleElement(styleCache, WindowButtonUnfocus, "window.button.unfocus", false);
  1484: 
  1485:     strcpy_s(windowButtonPressed, sizeofArray(windowButtonPressed), toolbarButtonPressed);
  1486:     appearancePointer = windowButtonPressed;
  1487:     CopyMemory(WindowButtonPressed, ToolbarButtonPressed, sizeof(StyleItem));
  1488:     strcpy_s(WindowButtonPressed->Font, sizeofArray(WindowButtonPressed->Font), WindowButtonFocus->Font); // ...ditto above...
  1489: //  CheckFontSubstitution(WindowButtonPressed->Font);
  1490:     WindowButtonPressed->FontHeight = WindowButtonFocus->FontHeight;
  1491:     WindowButtonPressed->FontWeight = WindowButtonFocus->FontWeight;
  1492:     WindowButtonPressed->TextColor = WindowButtonPressed->PicColor;
  1493:     WindowButtonPressed->FontOutline = WindowButtonPressed->FontShadow = false;
  1494:     ReadStyleElement(styleCache, WindowButtonPressed, "window.button.pressed", false);
  1495: 
  1496:     // Window grips...
  1497:     strcpy_s(windowGripFocus, sizeofArray(windowGripFocus), windowTitleFocus);
  1498:     appearancePointer = windowGripFocus;
  1499:     CopyMemory(WindowGripFocus, WindowTitleFocus, sizeof(StyleItem));
  1500:     ReadStyleElement(styleCache, WindowGripFocus, "window.grip.focus", false);
  1501: 
  1502:     strcpy_s(windowGripUnfocus, sizeofArray(windowGripUnfocus), windowGripFocus);
  1503:     appearancePointer = windowGripUnfocus;
  1504:     CopyMemory(WindowGripUnfocus, WindowGripFocus, sizeof(StyleItem));
  1505:     ReadStyleElement(styleCache, WindowGripUnfocus, "window.grip.unfocus", false);
  1506: 
  1507:     // Window handle...
  1508:     strcpy_s(windowHandleFocus, sizeofArray(windowHandleFocus), windowTitleFocus);
  1509:     appearancePointer = windowHandleFocus;
  1510:     CopyMemory(WindowHandleFocus, WindowTitleFocus, sizeof(StyleItem));
  1511:     ReadStyleElement(styleCache, WindowHandleFocus, "window.handle.focus", false);
  1512: 
  1513:     strcpy_s(windowHandleUnfocus, sizeofArray(windowHandleUnfocus), windowHandleFocus);
  1514:     appearancePointer = windowHandleUnfocus;
  1515:     CopyMemory(WindowHandleUnfocus, WindowHandleFocus, sizeof(StyleItem));
  1516:     ReadStyleElement(styleCache, WindowHandleUnfocus, "window.handle.unfocus", false);
  1517: 
  1518:     //====================
  1519: 
  1520:     // External RGB hardware... (used e.g. by plugins like xControlRGB-Corsair, xControlRGB-LIFX, etc)
  1521:     strcpy_s(externalHardware, sizeofArray(externalHardware), toolbarWindowLabel);
  1522:     appearancePointer = externalHardware;
  1523:     CopyMemory(ExternalHardware, ToolbarWindowLabel, sizeof(StyleItem));
  1524:     ReadStyleElement(styleCache, ExternalHardware, "hardware", false);
  1525: 
  1526:     //====================
  1527: 
  1528:     // Text shadows (introduced in xoblite bb2)
  1529: /*
  1530:     if (ToolbarLabel->parentRelative) toolbarLabelShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarLabel->TextColor);
  1531:     else toolbarLabelShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->Color, ToolbarLabel->ColorTo, ToolbarLabel->TextColor);
  1532:     if (ToolbarWindowLabel->parentRelative) toolbarWindowLabelShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
  1533:     else toolbarWindowLabelShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->Color, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->TextColor);
  1534:     if (ToolbarClock->parentRelative) toolbarClockShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarClock->TextColor);
  1535:     else toolbarClockShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->Color, ToolbarClock->ColorTo, ToolbarClock->TextColor);
  1536: 
  1537:     menuTitleShadowColor = CreateShadowColor(MenuTitle, MenuTitle->Color, MenuTitle->ColorTo, MenuTitle->TextColor);
  1538:     menuFrameShadowColor = CreateShadowColor(MenuFrame, MenuFrame->Color, MenuFrame->ColorTo, MenuFrame->TextColor);
  1539:     if (MenuActive->parentRelative) menuActiveShadowColor = CreateShadowColor(MenuFrame, MenuFrame->Color, MenuFrame->ColorTo, MenuActive->TextColor);
  1540:     else menuActiveShadowColor = CreateShadowColor(MenuActive, MenuActive->Color, MenuActive->ColorTo, MenuActive->TextColor);
  1541: */
  1542:     //====================
  1543: 
  1544:     // Finally, a few really old style settings... (nb. for legacy compatibility only -> not intended for general use today -> "pending removal at any time")
  1545: 
  1546:     if (strnlen_s(GetString(NULL, styleCache, "titleFont:", ""), MAX_LINE_LENGTH))
  1547:     {
  1548:         strcpy_s(MenuTitle->Font, sizeofArray(MenuTitle->Font), GetString(NULL, styleCache, "titleFont:", MenuTitle->Font));
  1549:         CheckFontSubstitution(MenuTitle->Font);
  1550:     }
  1551: 
  1552:     if (strnlen_s(GetString(NULL, styleCache, "menuFont:", ""), MAX_LINE_LENGTH))
  1553:     {
  1554:         strcpy_s(MenuFrame->Font, sizeofArray(MenuFrame->Font), GetString(NULL, styleCache, "menuFont:", MenuFrame->Font));
  1555:         CheckFontSubstitution(MenuFrame->Font);
  1556:     }
  1557: 
  1558:     if (strnlen_s(GetString(NULL, styleCache, "titleJustify:", ""), MAX_LINE_LENGTH))
  1559:     {
  1560:         strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "titleJustify:", ""));
  1561:         if (IsInString(temp, "Left")) MenuTitle->Justify = DT_LEFT;
  1562:         else if (IsInString(temp, "Right")) MenuTitle->Justify = DT_RIGHT;
  1563:         else if (IsInString(temp, "Center")) MenuTitle->Justify = DT_CENTER;
  1564:     }
  1565: 
  1566:     if (strnlen_s(GetString(NULL, styleCache, "menuJustify:", ""), MAX_LINE_LENGTH))
  1567:     {
  1568:         strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, "menuJustify:", ""));
  1569:         if (IsInString(temp, "Left")) MenuFrame->Justify = DT_LEFT;
  1570:         else if (IsInString(temp, "Right")) MenuFrame->Justify = DT_RIGHT;
  1571:         else if (IsInString(temp, "Center")) MenuFrame->Justify = DT_CENTER;
  1572:     }
  1573: 
  1574:     if (strnlen_s(GetString(NULL, styleCache, "menu.frame.highlightColor:", ""), MAX_LINE_LENGTH))
  1575:     {
  1576:         MenuActive->Color = GetColor(NULL, styleCache, "menu.frame.highlightColor:", "#303030", NULL, false);
  1577:         MenuActive->ColorTo = MenuActive->Color;
  1578:     }
  1579: 
  1580:     if (strnlen_s(GetString(NULL, styleCache, "menu.frame.hiTextColor:", ""), MAX_LINE_LENGTH))
  1581:         MenuActive->TextColor = GetColor(NULL, styleCache, "menu.frame.hiTextColor:", NULL, Wildcard->TextColor, true);
  1582: 
  1583:     if (strnlen_s(GetString(NULL, styleCache, "menu.bulletStyle:", ""), MAX_LINE_LENGTH))
  1584:         strcpy_s(menuFrameBulletAsString, sizeofArray(menuFrameBulletAsString), GetString(NULL, styleCache, "menu.bulletStyle:", menuFrameBulletAsString));
  1585: 
  1586:     if (strnlen_s(GetString(NULL, styleCache, "menu.bulletPosition:", ""), MAX_LINE_LENGTH))
  1587:         strcpy_s(menuBulletPosition, sizeofArray(menuBulletPosition), GetString(NULL, styleCache, "menu.bulletPosition:", menuBulletPosition));
  1588: 
  1589:     //====================
  1590: 
  1591:     // ###########################################################################################
  1592:     // ##### Below: xoblite bb5 introduces support for UI scaling for *HiDPI* displays!!! :D #####
  1593:     // ##### (i.e. user configurable "Regular scale" Non-HiDPI 1x / "Double scale" HiDPI 2x) #####
  1594:     // ###########################################################################################
  1595: 
  1596:     if (scalingFactorHiDPI > 1)
  1597:     {
  1598:         borderWidth *= scalingFactorHiDPI;
  1599:         menuBorderWidth *= scalingFactorHiDPI;
  1600:         bevelWidth *= scalingFactorHiDPI;
  1601:         marginWidth *= scalingFactorHiDPI;
  1602:         handleHeight *= scalingFactorHiDPI;
  1603:         frameWidth *= scalingFactorHiDPI;
  1604: 
  1605:         if (MenuTitle->FontHeight >= 2) MenuTitle->FontHeight *= scalingFactorHiDPI;
  1606:         MenuFrame->FontHeight *= scalingFactorHiDPI;
  1607:         MenuActive->FontHeight *= scalingFactorHiDPI;
  1608:         if (MenuGrip->FontHeight >= 2) MenuGrip->FontHeight *= scalingFactorHiDPI;
  1609:         Toolbar->FontHeight *= scalingFactorHiDPI;
  1610:         ToolbarLabel->FontHeight *= scalingFactorHiDPI;
  1611:         ToolbarWindowLabel->FontHeight *= scalingFactorHiDPI;
  1612:         ToolbarClock->FontHeight *= scalingFactorHiDPI;
  1613:         Console->FontHeight *= scalingFactorHiDPI;
  1614:         Dock->FontHeight *= scalingFactorHiDPI;
  1615:         WindowLabelFocus->FontHeight *= scalingFactorHiDPI;
  1616:         WindowLabelUnfocus->FontHeight *= scalingFactorHiDPI;
  1617: 
  1618:         if (MenuTitle->borderWidth > 0) MenuTitle->borderWidth *= scalingFactorHiDPI;
  1619:         if (MenuFrame->borderWidth > 0) MenuFrame->borderWidth *= scalingFactorHiDPI;
  1620:         if (MenuActive->borderWidth > 0) MenuActive->borderWidth *= scalingFactorHiDPI;
  1621:         if (MenuGrip->borderWidth > 0) MenuGrip->borderWidth *= scalingFactorHiDPI;
  1622:         if (MenuSeparator->borderWidth > 0) MenuSeparator->borderWidth *= scalingFactorHiDPI; // TBD
  1623:         if (Toolbar->borderWidth > 0) Toolbar->borderWidth *= scalingFactorHiDPI;
  1624:         if (ToolbarLabel->borderWidth > 0) ToolbarLabel->borderWidth *= scalingFactorHiDPI;
  1625:         if (ToolbarWindowLabel->borderWidth > 0) ToolbarWindowLabel->borderWidth *= scalingFactorHiDPI;
  1626:         if (ToolbarClock->borderWidth > 0) ToolbarClock->borderWidth *= scalingFactorHiDPI;
  1627:         if (ToolbarButton->borderWidth > 0) ToolbarButton->borderWidth *= scalingFactorHiDPI;
  1628:         if (ToolbarButtonPressed->borderWidth > 0) ToolbarButtonPressed->borderWidth *= scalingFactorHiDPI;
  1629:         if (Dock->borderWidth > 0) Dock->borderWidth *= scalingFactorHiDPI;
  1630:         if (WindowTitleFocus->borderWidth > 0) WindowTitleFocus->borderWidth *= scalingFactorHiDPI;
  1631:         if (WindowTitleUnfocus->borderWidth > 0) WindowTitleUnfocus->borderWidth *= scalingFactorHiDPI;
  1632:         if (WindowLabelFocus->borderWidth > 0) WindowLabelFocus->borderWidth *= scalingFactorHiDPI;
  1633:         if (WindowLabelUnfocus->borderWidth > 0) WindowLabelUnfocus->borderWidth *= scalingFactorHiDPI;
  1634:         if (WindowButtonFocus->borderWidth > 0) WindowButtonFocus->borderWidth *= scalingFactorHiDPI;
  1635:         if (WindowButtonUnfocus->borderWidth > 0) WindowButtonUnfocus->borderWidth *= scalingFactorHiDPI;
  1636:         if (WindowButtonPressed->borderWidth > 0) WindowButtonPressed->borderWidth *= scalingFactorHiDPI;
  1637:         if (WindowGripFocus->borderWidth > 0) WindowGripFocus->borderWidth *= scalingFactorHiDPI;
  1638:         if (WindowGripUnfocus->borderWidth > 0) WindowGripUnfocus->borderWidth *= scalingFactorHiDPI;
  1639:         if (WindowHandleFocus->borderWidth > 0) WindowHandleFocus->borderWidth *= scalingFactorHiDPI;
  1640:         if (WindowHandleUnfocus->borderWidth > 0) WindowHandleUnfocus->borderWidth *= scalingFactorHiDPI;
  1641: 
  1642:         if (MenuTitle->marginWidth > 0) MenuTitle->marginWidth *= scalingFactorHiDPI;
  1643:         if (MenuFrame->marginWidth > 0) MenuFrame->marginWidth *= scalingFactorHiDPI;
  1644:         if (MenuActive->marginWidth > 0) MenuActive->marginWidth *= scalingFactorHiDPI;
  1645:         if (MenuGrip->marginWidth > 0) MenuGrip->marginWidth *= scalingFactorHiDPI;
  1646:         if (MenuSeparator->marginWidth > 0) MenuSeparator->marginWidth *= scalingFactorHiDPI; // TBD
  1647:         if (Toolbar->marginWidth > 0) Toolbar->marginWidth *= scalingFactorHiDPI;
  1648:         if (ToolbarLabel->marginWidth > 0) ToolbarLabel->marginWidth *= scalingFactorHiDPI;
  1649:         if (ToolbarWindowLabel->marginWidth > 0) ToolbarWindowLabel->marginWidth *= scalingFactorHiDPI;
  1650:         if (ToolbarClock->marginWidth > 0) ToolbarClock->marginWidth *= scalingFactorHiDPI;
  1651:         if (ToolbarButton->marginWidth > 0) ToolbarButton->marginWidth *= scalingFactorHiDPI;
  1652:         if (ToolbarButtonPressed->marginWidth > 0) ToolbarButtonPressed->marginWidth *= scalingFactorHiDPI;
  1653:         if (Dock->marginWidth > 0) Dock->marginWidth *= scalingFactorHiDPI;
  1654:         if (WindowTitleFocus->marginWidth > 0) WindowTitleFocus->marginWidth *= scalingFactorHiDPI;
  1655:         if (WindowTitleUnfocus->marginWidth > 0) WindowTitleUnfocus->marginWidth *= scalingFactorHiDPI;
  1656:         if (WindowLabelFocus->marginWidth > 0) WindowLabelFocus->marginWidth *= scalingFactorHiDPI;
  1657:         if (WindowLabelUnfocus->marginWidth > 0) WindowLabelUnfocus->marginWidth *= scalingFactorHiDPI;
  1658:         if (WindowButtonFocus->marginWidth > 0) WindowButtonFocus->marginWidth *= scalingFactorHiDPI;
  1659:         if (WindowButtonUnfocus->marginWidth > 0) WindowButtonUnfocus->marginWidth *= scalingFactorHiDPI;
  1660:         if (WindowButtonPressed->marginWidth > 0) WindowButtonPressed->marginWidth *= scalingFactorHiDPI;
  1661:         if (WindowGripFocus->marginWidth > 0) WindowGripFocus->marginWidth *= scalingFactorHiDPI;
  1662:         if (WindowGripUnfocus->marginWidth > 0) WindowGripUnfocus->marginWidth *= scalingFactorHiDPI;
  1663:         if (WindowHandleFocus->marginWidth > 0) WindowHandleFocus->marginWidth *= scalingFactorHiDPI;
  1664:         if (WindowHandleUnfocus->marginWidth > 0) WindowHandleUnfocus->marginWidth *= scalingFactorHiDPI;
  1665: 
  1666:         // Note: ShadowX+ShadowY offsets are re-calculated adaptively in BBApi.cpp DrawTextWithEffects() instead!
  1667:     }
  1668: 
  1669:     //====================
  1670: 
  1671:     // ### 20210521: Moved to MenuCommon::Configure(), kept here just for short term reference... (to be deleted) ###
  1672: 
  1673:     // Calculate submenu gap for rounded corner menus...
  1674:     // (nb. dependence toward the HiDPI adjustments calculated above, so order is important)
  1675: //  if (MenuFrame->borderWidth > 0) submenuGap = (MenuFrame->borderWidth * 2); // Note: Use borderWidth*2 due to how menu borders overlap for non-rounded menus!
  1676: //  else if (MenuFrame->marginWidth > 0) submenuGap = MenuFrame->marginWidth;
  1677: //  else if (scalingFactorHiDPI > 1) submenuGap = scalingFactorHiDPI * 2;
  1678: //  else submenuGap = 2;
  1679: 
  1680:     //====================
  1681: /*
  1682:     if (debugLogging)
  1683:     {
  1684:         if (Toolbar->FontShadow) Log("Toolbar shadows enabled!", "");
  1685:         else if (ToolbarLabel->FontShadow) Log("ToolbarLabel shadows enabled!", "");
  1686:         else if (ToolbarWindowLabel->FontShadow) Log("ToolbarWindowLabel shadows enabled!", "");
  1687:         else if (ToolbarClock->FontShadow) Log("ToolbarClock shadows enabled!", "");
  1688:         else if (MenuTitle->FontShadow) Log("MenuTitle shadows enabled!", "");
  1689: 
  1690:         if (Toolbar->FontOutline) Log("Toolbar outlines enabled!", "");
  1691:         else if (ToolbarLabel->FontOutline) Log("ToolbarLabel outlines enabled!", "");
  1692:         else if (ToolbarWindowLabel->FontOutline) Log("ToolbarWindowLabel outlines enabled!", "");
  1693:         else if (ToolbarClock->FontOutline) Log("ToolbarClock outlines enabled!", "");
  1694:         else if (MenuTitle->FontOutline) Log("MenuTitle outlines enabled!", "");
  1695:     }
  1696: */
  1697:     //====================
  1698: 
  1699:     // Free memory allocated for the style buffer...
  1700:     DestroyFileCache(styleCache);
  1701: }
  1702: 
  1703: //===========================================================================
  1704: // Function: ReadStyleElement
  1705: // Purpose: Reads an entire style element from the memory cached style buffer
  1706: //===========================================================================
  1707: 
  1708: bool Settings::ReadStyleElement(LPSTR styleCache, StyleItem* styleItem, LPSTR paramString, bool readFont)
  1709: {
  1710:     char temp[MAX_LINE_LENGTH], param[MAX_LINE_LENGTH];
  1711:     bool bb4nix070syntax = false;
  1712: 
  1713:     strcpy_s(param, sizeofArray(param), paramString);
  1714:     int nLen = strnlen_s(param, sizeofArray(param));
  1715: 
  1716:     //====================
  1717: 
  1718:     // Appearance... (i.e. flat/raised/sunken, solid/gradient, bevel type, etc)
  1719:     // (Note: The appearance *string* is later used also by the style memory caching mechanism;
  1720:     // hence we need to save it for later here even if not further used by the StyleItem parser below.)
  1721:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".appearance:");
  1722:     if (strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH)) bb4nix070syntax = true;
  1723:     strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, appearancePointer));
  1724:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ":");
  1725:     strcpy_s(appearancePointer, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, temp));
  1726:     ParseItem(appearancePointer, styleItem);
  1727: 
  1728:     //====================
  1729: 
  1730:     // Below: Any previously existing bitmap for this particular element have already been destroyed through a prior call to InitStyleItems() from ReadStyle() above,
  1731:     // but we may have inherited a pointer to another element's bitmap as part of a CopyMemory of its StyleItem information, and hence it's OK to set it back to NULL here.
  1732:     styleItem->Image.bitmap = NULL;
  1733: 
  1734:     // Is an image to be used instead of a regular *box gradient? (nb. we perform this check first to be able to fallback to the latter if needed)
  1735:     if (styleItem->type == B_IMAGEFROMFILE)
  1736:     {
  1737:         if (strchr(appearancePointer, '\\'))
  1738:         {
  1739:             // -> Image path specified directly in .appearance... (nb. the backslash character is not otherwise used in regular *box style .appearance strings)
  1740: //          strncpy(styleItem->Image.path, appearancePointer, MAX_PATH);
  1741:             strncpy_s(styleItem->Image.path, sizeof(styleItem->Image.path), appearancePointer, _TRUNCATE);
  1742:         }
  1743:         else
  1744:         {
  1745:             // -> Image path specified in separate .image parameter...
  1746:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".image:");
  1747: //          strncpy(styleItem->Image.path, GetString(NULL, styleCache, param, ""), MAX_PATH);
  1748:             strncpy_s(styleItem->Image.path, sizeof(styleItem->Image.path), GetString(NULL, styleCache, param, ""), _TRUNCATE);
  1749: 
  1750: //          if (strchr(appearancePointer, '/'))
  1751: //          {
  1752: //              SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)strchr(appearancePointer, '/'));
  1753: //          }
  1754:         }
  1755:         styleItem->Image.path[sizeof(styleItem->Image.path)-1] = '\0'; // Failsafe
  1756: 
  1757:         if (strchr(styleItem->Image.path, '\"')) StrRemoveEncap((LPSTR)styleItem->Image.path);
  1758:         if (strchr(styleItem->Image.path, '$')) ReplaceShellFolders((LPSTR)styleItem->Image.path);
  1759:         if (strchr(styleItem->Image.path, '%')) ReplaceEnvVars((LPSTR)styleItem->Image.path);
  1760: 
  1761:         styleItem->Image.width = styleItem->Image.height = styleItem->Image.left = styleItem->Image.top = styleItem->Image.right = styleItem->Image.bottom = 0; // ### TEMPORARY HERE, TO BE MOVED INTO IF() BELOW ###
  1762: 
  1763:         // ...if so, let's check if the image file exists.. (and if not, fallback to a solid background)
  1764:         if (FileExists(styleItem->Image.path))
  1765:         {
  1766: //          if (debugLogging) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_WARNING_MESSAGE, (LPARAM)styleItem->Image.path);
  1767:             CreateElementImage(styleItem);
  1768: /*
  1769:             // Load the image using GDI+ to add support for JPG, PNG etc...
  1770:             // (nb. regular GDI LoadImage() only supports BMP images. GDI+ startup/shutdown is performed elsewhere here in MenuCommon.)
  1771:             wchar_t imagePathWC[MAX_PATH];
  1772:             MultiByteToWideChar(CP_ACP, 0, styleItem->Image.path, strnlen_s(styleItem->Image.path, sizeofArray(styleItem->Image.path))+1, imagePathWC, MAX_PATH);
  1773:             Bitmap* bitmap = new Bitmap(imagePathWC, FALSE);
  1774:             styleItem->Image.width = bitmap->GetWidth();
  1775:             styleItem->Image.height = bitmap->GetHeight();
  1776: //          SetRect(&menuImage->edges, 0, 0, 0, 0);
  1777:             if ((pf == PixelFormat32bppARGB) || (pf == PixelFormat32bppPARGB) || (pf == PixelFormat64bppARGB) || (pf == PixelFormat64bppPARGB)) styleItem->Image.argb = true;
  1778:             else styleItem->Image.argb = false;
  1779:             bitmap->GetHBITMAP(0, &styleItem->Image.bitmap); // Create our target GDI HBITMAP from the loaded GDI+ Bitmap...
  1780:             delete bitmap;
  1781: */
  1782:         }
  1783:         else styleItem->type = B_SOLID; // Fallback
  1784:     }
  1785: 
  1786:     //====================
  1787: 
  1788:     // Border...
  1789:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".borderColor:");
  1790:     styleItem->borderColor = GetColor(NULL, styleCache, param, NULL, styleItem->borderColor, true);
  1791:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".borderWidth:");
  1792:     styleItem->borderWidth = GetInt(NULL, styleCache, param, styleItem->borderWidth);
  1793: 
  1794:     if (bb4nix070syntax)
  1795:     {
  1796:         if (IsInString(appearancePointer, "border")) // If the border tag is set we always draw the border, regardless of whether borderWidth was explicitly defined or inherited...
  1797:         {
  1798:             styleItem->bordered = true;
  1799:         }
  1800:         else
  1801:         {
  1802:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".borderWidth:");
  1803:             if (strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH)) // If borderWidth was explicitly defined for this element we disregard the border tag... (i.e. "forgiving" parsing)
  1804:             {
  1805:                 styleItem->bordered = true;
  1806:             }
  1807: //          else // Do not draw the border if borderWidth was inherited and the border tag was not set...
  1808: //          {
  1809: //              styleItem->bordered = false;
  1810: //              styleItem->borderWidth = 0;
  1811: //          }
  1812:         }
  1813:     }
  1814:     else
  1815:     {
  1816:         if (styleItem->borderWidth > 0) styleItem->bordered = true;
  1817: //      else styleItem->bordered = false;
  1818:     }
  1819: 
  1820: //  if (IsInString(appearancePointer, "border")) styleItem->bordered = true;
  1821: //  else if (strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH)) styleItem->bordered = true;
  1822: 
  1823:     //====================
  1824: 
  1825:     // Margin...
  1826:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".marginWidth:");
  1827:     styleItem->marginWidth = GetInt(NULL, styleCache, param, styleItem->marginWidth);
  1828: 
  1829:     //====================
  1830: 
  1831:     // Colours...
  1832: 
  1833:     COLORREF tempColor;
  1834: 
  1835:     if (!strchr(appearancePointer, '\\') && IsInString(appearancePointer, "auto"))
  1836:     {
  1837:         COLORREF colorAutoPicked;
  1838:         int randomPixelX, randomPixelY;
  1839:         // srand((unsigned int)time(NULL)); // Provide a seed for pseudorandom number generation... (nb. this is already done in Blackbox.cpp, so not needed here!)
  1840: 
  1841:         RECT workArea;
  1842:         SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, SPIF_SENDCHANGE); // Get the dimensions of the screen's work area...
  1843:         int workAreaWidth = workArea.right - workArea.left;
  1844:         int workAreaHeight = workArea.bottom - workArea.top;
  1845: 
  1846:         HDC hdc = GetDC(GetDesktopWindow()); // Get the HDC of the Windows desktop window...
  1847: 
  1848:         for (int n = 1; n <= 8; n++)
  1849:         {
  1850:             randomPixelX = (rand() % workAreaWidth); // Select a random X position across the screen's work area width...
  1851:             randomPixelY = (rand() % workAreaHeight); // ..and a random Y position across the screen's work area height...
  1852:             colorAutoPicked = GetPixel(hdc, workArea.left+randomPixelX, workArea.top+randomPixelY); // Pick the colour of the pixel at the random X/Y position...
  1853:             if (colorAutoPicked == CLR_INVALID) continue; // Failsafe
  1854: 
  1855:             switch (n)
  1856:             {
  1857:                 // ...for each of the up to 8 colours per style element...
  1858:                 case 1: {styleItem->Color1 = colorAutoPicked; break; }
  1859:                 case 2: {styleItem->Color2 = colorAutoPicked; break; }
  1860:                 case 3: {styleItem->Color3 = colorAutoPicked; break; }
  1861:                 case 4: {styleItem->Color4 = colorAutoPicked; break; }
  1862:                 case 5: {styleItem->Color5 = colorAutoPicked; break; }
  1863:                 case 6: {styleItem->Color6 = colorAutoPicked; break; }
  1864:                 case 7: {styleItem->Color7 = colorAutoPicked; break; }
  1865:                 case 8: {styleItem->Color8 = colorAutoPicked; break; }
  1866:             }
  1867:         }
  1868: 
  1869:         ReleaseDC(NULL, hdc);
  1870:         DeleteDC(hdc);
  1871:     }
  1872:     else
  1873:     {
  1874:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".backgroundColor:");
  1875:         tempColor = GetColor(NULL, styleCache, param, NULL, styleItem->Color1, true);
  1876:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color1:");
  1877:         tempColor = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  1878:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color:");
  1879:         styleItem->Color1 = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  1880: 
  1881:         if (styleItem->type == B_SOLID) styleItem->Color2 = styleItem->Color1; // (...just in case, cf. legacy 2-colour API aspects?)
  1882:         else
  1883:         {
  1884:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color2:");
  1885:             tempColor = GetColor(NULL, styleCache, param, NULL, styleItem->Color2, true);
  1886:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".colorTo:");
  1887:             styleItem->Color2 = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  1888:         }
  1889: 
  1890:         if ((styleItem->type >= B_SPLITHORIZONTAL) && (styleItem->type < B_MIRRORHORIZONTAL)) // 4-colour split or 8-colour super gradient being used?
  1891:         {
  1892:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color.splitTo:");
  1893:             if (((styleItem->type == B_SPLITHORIZONTAL) || (styleItem->type == B_SPLITVERTICAL)) && strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH))
  1894:             {
  1895:                 // -> The style is using the fugly old
  1896:                 // 4-colour split gradient ".splitTo" syntax... :(
  1897: 
  1898:                 styleItem->Color3 = styleItem->Color2;
  1899:                 styleItem->Color2 = styleItem->Color1;
  1900: 
  1901:                 int sr, sg, sb;
  1902: 
  1903:                 sr = GetRValue(styleItem->Color2);
  1904:                 sg = GetGValue(styleItem->Color2);
  1905:                 sb = GetBValue(styleItem->Color2);
  1906:                 sr += sr >> 2;
  1907:                 sg += sg >> 2;
  1908:                 sb += sb >> 2;
  1909:                 if (sr>0xff) sr = 0xff;
  1910:                 if (sg>0xff) sg = 0xff;
  1911:                 if (sb>0xff) sb = 0xff;
  1912:                 styleItem->Color1 = RGB(sr,sg,sb);
  1913: 
  1914:                 sr  = GetRValue(styleItem->Color3);
  1915:                 sg = GetGValue(styleItem->Color3);
  1916:                 sb = GetBValue(styleItem->Color3);
  1917:                 sr += sr >> 4;
  1918:                 sg += sg >> 4;
  1919:                 sb += sb >> 4;
  1920:                 if (sr>0xff) sr = 0xff;
  1921:                 if (sg>0xff) sg = 0xff;
  1922:                 if (sb>0xff) sb = 0xff;
  1923:                 styleItem->Color4 = RGB(sr,sg,sb);
  1924: 
  1925:                 strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color.splitTo:");
  1926:                 styleItem->Color1 = GetColor(NULL, styleCache, param, NULL, styleItem->Color1, true);
  1927:                 strcpy_s(&param[nLen], (sizeof(param)-nLen), ".colorTo.splitTo:");
  1928:                 styleItem->Color4 = GetColor(NULL, styleCache, param, NULL, styleItem->Color4, true);
  1929:             }
  1930:             else
  1931:             {
  1932:                 // -> The style is using the more flexible newer .color1-4/8 syntax... :D
  1933: 
  1934:                 strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color3:");
  1935:                 styleItem->Color3 = GetColor(NULL, styleCache, param, NULL, styleItem->Color3, true);
  1936:                 strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color4:");
  1937:                 styleItem->Color4 = GetColor(NULL, styleCache, param, NULL, styleItem->Color4, true);
  1938: 
  1939:                 if (styleItem->type >= B_SUPERHORIZONTAL) // 8-colour super gradient being used...
  1940:                 {
  1941:                     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color5:");
  1942:                     styleItem->Color5 = GetColor(NULL, styleCache, param, NULL, styleItem->Color5, true);
  1943:                     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color6:");
  1944:                     styleItem->Color6 = GetColor(NULL, styleCache, param, NULL, styleItem->Color6, true);
  1945:                     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color7:");
  1946:                     styleItem->Color7 = GetColor(NULL, styleCache, param, NULL, styleItem->Color7, true);
  1947:                     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".color8:");
  1948:                     styleItem->Color8 = GetColor(NULL, styleCache, param, NULL, styleItem->Color8, true);
  1949:                 }
  1950:     /*
  1951:                 if (styleItem->type < B_SUPERHORIZONTAL) // 4-colour split gradient being used...
  1952:                 {
  1953:                     // Re-order the colours from "1234" to "2314"
  1954:                     // to allow for limited forward compatibility
  1955:                     // for MakeGradient (i.e. even if MakeGradient
  1956:                     // does not support 4 input colours it will
  1957:                     // fall back to a 2 input colour split gradient)
  1958: 
  1959:                     tempColor = styleItem->Color3;
  1960:                     styleItem->Color3 = styleItem->Color1;
  1961:                     styleItem->Color1 = styleItem->Color2;
  1962:                     styleItem->Color2 = tempColor;
  1963:                 }
  1964:                 else // 8-colour super gradient being used...
  1965:                 {
  1966:                     // ...for now, I won't bother trying to squeeze forward compatibility
  1967:                     // for MakeGradient into the mix in here as well... (at some point it just becomes ugly)
  1968:                 }
  1969:     */
  1970:             }
  1971:         }
  1972:     }
  1973: 
  1974:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".textColor:");
  1975:     styleItem->TextColor = GetColor(NULL, styleCache, param, NULL, styleItem->TextColor, true);
  1976: 
  1977: /*
  1978:     // #########################################################################
  1979:     // As the following colour parameters are (1) only used by a few StyleItems,
  1980:     // and (2) sometimes overloaded (menu.active/hilite), we do *not* parse them
  1981:     // here but manually in ReadStyle() for applicable items intstead, see above
  1982:     // #########################################################################
  1983:     // The following colour parameters are used interchangeably for similar things so let's parse them together...
  1984:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".foregroundColor:");
  1985:     if (styleItem->foregroundColor == COLOR_UNDEFINED) tempColor = GetColor(NULL, styleCache, param, NULL, styleItem->TextColor, true); // First read: Default value -> Same as TextColor
  1986:     else tempColor = GetColor(NULL, styleCache, param, NULL, styleItem->foregroundColor, true); // Subsequent reads: Default value -> Inherited value from previous set/read action
  1987:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".bulletColor:");
  1988:     tempColor = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  1989:     strcpy_s(&param[nLen], (sizeof(param)-nLen), ".picColor:");
  1990:     styleItem->foregroundColor = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  1991: */
  1992:     if (styleItem == MenuFrame)
  1993:     {
  1994:         // menu.frame.disabledColor -> Disabled text color (i.e. menu [nop] items)
  1995:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".disabledColor:");
  1996:         styleItem->disabledColor = GetColor(NULL, styleCache, param, NULL, styleItem->TextColor, true);
  1997:     }
  1998: 
  1999:     if ((styleItem == ToolbarButton) || (styleItem == ToolbarButtonPressed) ||
  2000:         (styleItem == WindowButtonFocus) || (styleItem == WindowButtonUnfocus) || (styleItem == WindowButtonPressed))
  2001:     {
  2002:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".foregroundColor:");
  2003:         tempColor = GetColor(NULL, styleCache, param, NULL, styleItem->PicColor, true);
  2004:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".picColor:");
  2005:         styleItem->PicColor = GetColor(NULL, styleCache, param, NULL, tempColor, true);
  2006:     }
  2007: 
  2008:     //====================
  2009: 
  2010:     // Font...
  2011:     if (readFont)
  2012:     {
  2013:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".font:");
  2014:         strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, styleItem->Font));
  2015: 
  2016:         if (strchr(temp, '/')) // -> The font was defined using a single .font: Font/Size/WeightFlags property, e.g. "Segoe UI/15/BoldShadow"
  2017:         {
  2018:             // ParseFontString(temp, styleItem); // Note: We can *not* use this BBAPI function here as it does not allow for the multi-pass parsing we may require here in Settings.
  2019: 
  2020:             // Extract the font...
  2021:             strcpy_s(temp, MAX_LINE_LENGTH, Tokenize(temp, styleItem->Font, "/"));
  2022:             CheckFontSubstitution(styleItem->Font);
  2023: 
  2024:             if (strnlen_s(temp, MAX_LINE_LENGTH))
  2025:             {
  2026:                 // Extract the font size...
  2027:                 char height[MAX_LINE_LENGTH];
  2028:                 strcpy_s(temp, MAX_LINE_LENGTH, Tokenize(temp, height, "/"));
  2029:                 if (atoi(height) > 0) styleItem->FontHeight = atoi(height);
  2030: 
  2031:                 if (strnlen_s(temp, MAX_LINE_LENGTH))
  2032:                 {
  2033:                     // Extract the font weight + any outline and/or shadow flags...
  2034:                     if (IsInString(temp, "Normal")) styleItem->FontWeight = FW_NORMAL;
  2035:                     if (IsInString(temp, "Bold")) styleItem->FontWeight = FW_BOLD;
  2036:                     if (IsInString(temp, "Outline")) styleItem->FontOutline = true;
  2037:                     if (IsInString(temp, "Shadow")) styleItem->FontShadow = true;
  2038:                 }
  2039:             }
  2040:         }
  2041:         else // -> The font was defined using separate properties, i.e. .font, .fontHeight, .fontWeight
  2042:         {
  2043:             CheckFontSubstitution(temp);
  2044:             strcpy_s(styleItem->Font, sizeofArray(styleItem->Font), temp);
  2045: 
  2046:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".fontHeight:");
  2047:             styleItem->FontHeight = GetInt(NULL, styleCache, param, styleItem->FontHeight);
  2048: 
  2049:             strcpy_s(&param[nLen], (sizeof(param)-nLen), ".fontWeight:");
  2050:             strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, "Normal"));
  2051:             if (IsInString(temp, "Bold")) styleItem->FontWeight = FW_BOLD;
  2052:             else styleItem->FontWeight = FW_NORMAL;
  2053: 
  2054:             if (IsInString(temp, "Outline")) styleItem->FontOutline = true;
  2055:             if (IsInString(temp, "Shadow")) styleItem->FontShadow = true;
  2056:         }
  2057: /*
  2058:         if (globalFontOverride)
  2059:         {
  2060:             // ##### Q: SHOULD WE ALSO ADD THE OPTION OF HAVING A GLOBAL FONT OVERRIDE? (READ: JUST AN IDEA, TO BE DECIDED...) #####
  2061:             strcpy_s(styleItem->Font, sizeofArray(styleItem->Font), globalFont);
  2062:             styleItem->FontHeight = globalFontHeight;
  2063:             // Note: We still allow style-defined font *weights* even if font+size override is used!
  2064:         }
  2065: */
  2066:         //====================
  2067: 
  2068:         // Text alignment/justify...
  2069:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".alignment:");
  2070:         strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, ""));
  2071:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".justify:");
  2072:         strcpy_s(temp, MAX_LINE_LENGTH, GetString(NULL, styleCache, param, temp));
  2073: 
  2074:         if (IsInString(temp, "Left")) styleItem->Justify = DT_LEFT;
  2075:         else if (IsInString(temp, "Right")) styleItem->Justify = DT_RIGHT;
  2076:         else if (IsInString(temp, "Center")) styleItem->Justify = DT_CENTER;
  2077:         // -> else use inherited alignment...
  2078: 
  2079:         //====================
  2080: 
  2081:         // Note#1: Font outlines and shadows can be automatically enabled using either the "Outline" and "Shadow" font tags respectively (see above),
  2082:         // or manually enabled and configured by specifying .outlineColor and/or .shadowColor for the given element.
  2083:         // Note#2: ...and due to this dependency, we also need to check for the latter *AFTER* having parsed the font properties above!
  2084: 
  2085:         // Font outlines...
  2086:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".outlineColor:");
  2087:         if (strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH))
  2088:         {
  2089:             // An outline colour *has* been specified and outlines should therefore be enabled...
  2090:             styleItem->FontOutline = true;
  2091:             styleItem->OutlineColor = GetColor(NULL, styleCache, param, NULL, styleItem->OutlineColor, true);
  2092:         }
  2093:         else if (styleItem->FontOutline && (styleItem->OutlineColor == COLOR_UNDEFINED))
  2094:         {
  2095:             // An outline colour has *not* been specified but the "Outline" font tag has been set, so let's calculate a default outline colour instead...
  2096:             styleItem->OutlineColor = CreateShadowColor(styleItem, styleItem->Color1, styleItem->Color2, styleItem->TextColor);
  2097:         }
  2098: 
  2099:         // Font shadows...
  2100:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".shadowColor:");
  2101:         if (strnlen_s(GetString(NULL, styleCache, param, ""), MAX_LINE_LENGTH))
  2102:         {
  2103:             // A shadow colour *has* been specified and shadows should therefore be enabled...
  2104:             styleItem->FontShadow = true;
  2105:             styleItem->ShadowColor = GetColor(NULL, styleCache, param, NULL, styleItem->ShadowColor, true);
  2106:         }
  2107:         else if (styleItem->FontShadow && (styleItem->ShadowColor == COLOR_UNDEFINED))
  2108:         {
  2109:             // A shadow colour has *not* been specified but the "Shadow" font tag has been set, so let's calculate a default shadow colour instead...
  2110:             if (styleItem->FontOutline) styleItem->ShadowColor = CreateShadowColor(styleItem, styleItem->Color1, styleItem->Color2, styleItem->OutlineColor);
  2111:             else styleItem->ShadowColor = CreateShadowColor(styleItem, styleItem->Color1, styleItem->Color2, styleItem->TextColor);
  2112:         }
  2113: 
  2114:         // Default text shadow offsets at non-HiDPI is 1 pixels to the right and below the text itself...
  2115:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".shadowX:");
  2116:         styleItem->ShadowX = GetInt(NULL, styleCache, param, 1);
  2117: //      if (styleItem->ShadowX > 2) styleItem->ShadowX = 2;
  2118: //      if (styleItem->ShadowX < -2) styleItem->ShadowX = -2;
  2119:         strcpy_s(&param[nLen], (sizeof(param)-nLen), ".shadowY:");
  2120:         styleItem->ShadowY = GetInt(NULL, styleCache, param, 1);
  2121: //      if (styleItem->ShadowY > 2) styleItem->ShadowY = 2;
  2122: //      if (styleItem->ShadowY < -2) styleItem->ShadowY = -2;
  2123:     }
  2124: 
  2125:     //====================
  2126: 
  2127:     return bb4nix070syntax;
  2128: }
  2129: 
  2130: //===========================================================================
  2131: 
  2132: void Settings::DeriveTaskbarStyle()
  2133: {
  2134:     // Taskbar active task button... (-> derived from other style elements)
  2135: 
  2136:     if (!ToolbarWindowLabel->parentRelative)
  2137:     {
  2138:         CopyMemory(ActiveTask, ToolbarWindowLabel, sizeof(StyleItem));
  2139:         if (ActiveTask->type == B_ELLIPTIC) ActiveTask->ShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->Color, ToolbarWindowLabel->TextColor);
  2140: //      else ActiveTask->ShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->Color, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->TextColor);
  2141:     }
  2142:     else if (!ToolbarLabel->parentRelative)
  2143:     {
  2144:         CopyMemory(ActiveTask, ToolbarLabel, sizeof(StyleItem));
  2145:         if (ActiveTask->type == B_ELLIPTIC) ActiveTask->ShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->ColorTo, ToolbarLabel->Color, ToolbarLabel->TextColor);
  2146: //      else ActiveTask->ShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->Color, ToolbarLabel->ColorTo, ToolbarLabel->TextColor);
  2147:     }
  2148:     else if (!ToolbarClock->parentRelative)
  2149:     {
  2150:         CopyMemory(ActiveTask, ToolbarClock, sizeof(StyleItem));
  2151:         if (ActiveTask->type == B_ELLIPTIC) ActiveTask->ShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->ColorTo, ToolbarClock->Color, ToolbarClock->TextColor);
  2152: //      else ActiveTask->ShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->Color, ToolbarClock->ColorTo, ToolbarClock->TextColor);
  2153:     }
  2154:     else
  2155:     {
  2156:         CopyMemory(ActiveTask, Toolbar, sizeof(StyleItem));
  2157:         ActiveTask->TextColor = ToolbarWindowLabel->TextColor;
  2158: //      ActiveTask->FontShadow = ToolbarWindowLabel->FontShadow;
  2159:         if (ActiveTask->type == B_ELLIPTIC) ActiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->ColorTo, Toolbar->Color, ToolbarWindowLabel->TextColor);
  2160:         else ActiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
  2161: //      ActiveTask->FontOutline = ToolbarWindowLabel->FontOutline;
  2162: //      ActiveTask->OutlineColor = ToolbarWindowLabel->OutlineColor;
  2163:     }
  2164: 
  2165:     if (ActiveTask->borderWidth > 1) ActiveTask->borderWidth = 1;
  2166: 
  2167:     //====================
  2168: 
  2169:     // Taskbar non-active task buttons... (-> derived from other style elements)
  2170: 
  2171:     CopyMemory(InactiveTask, Toolbar, sizeof(StyleItem));
  2172: 
  2173:     if (ToolbarWindowLabel->parentRelative)
  2174:     {
  2175:         InactiveTask->TextColor = ToolbarWindowLabel->TextColor;
  2176:         InactiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
  2177:     }
  2178:     else if (ToolbarLabel->parentRelative)
  2179:     {
  2180:         InactiveTask->TextColor = ToolbarLabel->TextColor;
  2181:         InactiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarLabel->TextColor);
  2182:     }
  2183:     else if (ToolbarClock->parentRelative)
  2184:     {
  2185:         InactiveTask->TextColor = ToolbarClock->TextColor;
  2186:         InactiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarClock->TextColor);
  2187:     }
  2188:     else if (ToolbarButton->parentRelative)
  2189:     {
  2190:         InactiveTask->TextColor = ToolbarButton->PicColor;
  2191:         InactiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarButton->PicColor);
  2192:     }
  2193:     else
  2194:     {
  2195:         InactiveTask->TextColor = Toolbar->TextColor;
  2196:         InactiveTask->ShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, Toolbar->TextColor);
  2197:     }
  2198: 
  2199:     if (InactiveTask->borderWidth > 1) InactiveTask->borderWidth = 1;
  2200: 
  2201:     //====================
  2202: 
  2203:     // Flashing task buttons... (-> inverted variations of the active task button colours)
  2204:     FlashingTask->Color = InvertColor(ActiveTask->ColorTo);
  2205:     FlashingTask->ColorTo = InvertColor(ActiveTask->Color);
  2206:     FlashingTask->Color3 = InvertColor(ActiveTask->Color4);
  2207:     FlashingTask->Color4 = InvertColor(ActiveTask->Color3);
  2208:     FlashingTask->TextColor = InvertColor(ActiveTask->TextColor);
  2209:     FlashingTask->ShadowColor = InvertColor(ActiveTask->ShadowColor);
  2210:     FlashingTask->OutlineColor = InvertColor(ActiveTask->OutlineColor);
  2211:     FlashingTask->borderColor = InvertColor(ActiveTask->borderColor);
  2212: }
  2213: 
  2214: //===========================================================================
  2215: 
  2216: COLORREF Settings::CreateShadowColor(StyleItem* styleItem, COLORREF color, COLORREF colorTo, COLORREF textColor)
  2217: {
  2218:     BYTE r = GetRValue(color);
  2219:     BYTE g = GetGValue(color);
  2220:     BYTE b = GetBValue(color);
  2221:     BYTE rto = GetRValue(colorTo);
  2222:     BYTE gto = GetGValue(colorTo);
  2223:     BYTE bto = GetBValue(colorTo);
  2224: 
  2225:     int rav, gav, bav;
  2226:     
  2227:     if (styleItem->type != B_SOLID)
  2228:     {
  2229:         rav = (r+rto) / 2;
  2230:         gav = (g+gto) / 2;
  2231:         bav = (b+bto) / 2;
  2232:     }
  2233:     else
  2234:     {
  2235:         rav = r;
  2236:         gav = g;
  2237:         bav = b;
  2238:     }
  2239: 
  2240:     if (rav < 0x10) rav = 0;
  2241:     else rav -= 0x10;
  2242:     if (gav < 0x10) gav = 0;
  2243:     else gav -= 0x10;
  2244:     if (bav < 0x10) bav = 0;
  2245:     else bav -= 0x10;
  2246: 
  2247:     return RGB((BYTE)rav, (BYTE)gav, (BYTE)bav);
  2248: }
  2249: 
  2250: //===========================================================================
  2251: 
  2252: COLORREF Settings::InvertColor(COLORREF color)
  2253: {
  2254:     red = 0xff - GetRValue(color);
  2255:     green = 0xff - GetGValue(color);
  2256:     blue = 0xff - GetBValue(color);
  2257:     return RGB((BYTE)blue, (BYTE)green, (BYTE)red);
  2258: }
  2259: 
  2260: //===========================================================================
  2261: 
  2262: COLORREF Settings::MixColors(COLORREF colorA, COLORREF colorB)
  2263: {
  2264:     BYTE rt = GetRValue(colorA);
  2265:     BYTE gt = GetGValue(colorA);
  2266:     BYTE bt = GetBValue(colorA);
  2267:     BYTE rb = GetRValue(colorB);
  2268:     BYTE gb = GetGValue(colorB);
  2269:     BYTE bb = GetBValue(colorB);
  2270: 
  2271:     int rav = (rt + rb) / 2;
  2272:     int gav = (gt + gb) / 2;
  2273:     int bav = (bt + bb) / 2;
  2274: 
  2275:     return RGB((BYTE)rav, (BYTE)gav, (BYTE)bav);
  2276: }
  2277: 
  2278: //===========================================================================
  2279: 
  2280: void Settings::GetShellFolders()
  2281: {
  2282:     // Get the Blackbox folder path...
  2283:     GetBlackboxPath(SF_blackboxPath, MAX_PATH);
  2284:     // ...and remove the "\" at the end to be consistent with what SHGetFolderPath returns...
  2285:     SF_blackboxPath[strnlen_s(SF_blackboxPath, sizeofArray(SF_blackboxPath))-1] = 0;
  2286: 
  2287:     // Fetch shell folders based on their CSIDLs
  2288:     // (see https://learn.microsoft.com/en-us/windows/win32/shell/csidl )
  2289:     // or using direct paths as applicable per item...
  2290:     SHGetSpecialFolderPath(NULL, SF_startMenu, CSIDL_PROGRAMS, 0);
  2291:     SHGetSpecialFolderPath(NULL, SF_commonStartMenu, CSIDL_COMMON_PROGRAMS, 0);
  2292: //  SHGetSpecialFolderPath(NULL, SF_programFiles, CSIDL_PROGRAM_FILES, 0);
  2293: //  SHGetSpecialFolderPath(NULL, SF_programFilesX86, CSIDL_PROGRAM_FILESX86, 0);
  2294:     strcpy_s(SF_programFiles, "%SystemDrive%\\Program Files");
  2295:     strcpy_s(SF_programFilesX86, "%SystemDrive%\\Program Files (x86)");
  2296:     SHGetSpecialFolderPath(NULL, SF_desktop, CSIDL_DESKTOPDIRECTORY, 0);
  2297:     SHGetSpecialFolderPath(NULL, SF_userProfile, CSIDL_PROFILE, 0);
  2298: //  SHGetSpecialFolderPath(NULL, SF_userAppData, CSIDL_APPDATA, 0);
  2299:     strcpy_s(SF_userAppData, sizeofArray(SF_userAppData), SF_userProfile);
  2300:     strcat_s(SF_userAppData, sizeofArray(SF_userAppData), "\\AppData");
  2301: 
  2302:     // Store the default theme path...
  2303:     strcpy_s(SF_currentThemePath, sizeofArray(SF_currentThemePath), SF_blackboxPath); // Default theme
  2304:     usingDefaultTheme = true;
  2305: 
  2306:     // Find and store the path to the default xoblite.rc file (some settings should always
  2307:     // be read from this file, e.g. preferred editor and AutoUpdate last checked date)
  2308:     bbrcPath();
  2309:     extensionsrcPath();
  2310:     strcpy_s(xobrcDefaultFile, sizeofArray(xobrcDefaultFile), xobrcFile);
  2311: }
  2312: 
  2313: //===========================================================================
  2314: 
  2315: bool Settings::GetBool(LPCSTR fp, LPSTR cachedFilePtr, LPCSTR szString, bool szDefault)
  2316: {
  2317:     // NULL/empty filepointers are not supported for ReadBool,
  2318:     // but since it is the only Read* function that does not
  2319:     // support them I have added a safeguard here to prevent
  2320:     // a borked plugin from crashing the core... <g>
  2321:     if (!cachedFilePtr && (!fp || !_stricmp(fp, ""))) return szDefault;
  2322: 
  2323:     //====================
  2324: 
  2325:     LPSTR buffer;
  2326:     if (cachedFilePtr && !fp)
  2327:     {
  2328:         // Look for the value in the file cache...
  2329:         buffer = GetValueFromCache(cachedFilePtr, szString);
  2330:     }
  2331:     else
  2332:     {
  2333:         // If we can not find the value in the cache, we fetch it from the file...
  2334:         buffer = ReadValue(fp, szString, 0);
  2335:     }
  2336: 
  2337:     if (buffer)
  2338:     {
  2339:         if (!_stricmp(buffer, "true")) return true;
  2340:         else if (!_stricmp(buffer, "false")) return false;
  2341:     }
  2342: 
  2343:     return szDefault;
  2344: }
  2345: 
  2346: //===========================================================================
  2347: 
  2348: int Settings::GetInt(LPCSTR fp, LPSTR cachedFilePtr, LPCSTR szString, int szDefault)
  2349: {
  2350:     if (!cachedFilePtr && (!fp || !_stricmp(fp, "") || !_stricmp(fp, styleFile)))
  2351:     {
  2352:         if (!_strnicmp(szString, "toolbar.", 8))
  2353:         {
  2354:             if (szString[8] == 'l') // toolbar label items
  2355:             {
  2356:                 if (!_stricmp(&szString[13], ".borderWidth:")) return ToolbarLabel->borderWidth;
  2357:                 else if (!_stricmp(&szString[13], ".marginWidth:")) return ToolbarLabel->marginWidth;
  2358:                 else if (!_stricmp(&szString[13], ".fontHeight:")) return ToolbarLabel->FontHeight;
  2359:             }
  2360:             else if (szString[8] == 'w') // toolbar windowLabel items
  2361:             {
  2362:                 if (!_stricmp(&szString[19], ".borderWidth:")) return ToolbarWindowLabel->borderWidth;
  2363:                 else if (!_stricmp(&szString[19], ".marginWidth:")) return ToolbarWindowLabel->marginWidth;
  2364:                 else if (!_stricmp(&szString[19], ".fontHeight:")) return ToolbarWindowLabel->FontHeight;
  2365:             }
  2366:             else if (szString[8] == 'c') // toolbar clock items
  2367:             {
  2368:                 if (!_stricmp(&szString[13], ".borderWidth:")) return ToolbarClock->borderWidth;
  2369:                 else if (!_stricmp(&szString[13], ".marginWidth:")) return ToolbarClock->marginWidth;
  2370:                 else if (!_stricmp(&szString[13], ".fontHeight:")) return ToolbarClock->FontHeight;
  2371:             }
  2372:             else // toolbar main items
  2373:             {
  2374:                 if (!_stricmp(&szString[7], ".borderWidth:")) return Toolbar->borderWidth;
  2375:                 else if (!_stricmp(&szString[7], ".marginWidth:")) return Toolbar->marginWidth;
  2376:                 else if (!_stricmp(&szString[7], ".fontHeight:")) return Toolbar->FontHeight;
  2377:             }
  2378:         }
  2379: 
  2380:         //====================
  2381: 
  2382:         else if (!_strnicmp(szString, "menu.", 5))
  2383:         {
  2384:             if (szString[5] == 't') // menu title items
  2385:             {
  2386:                 if (!_stricmp(&szString[10], ".borderWidth:")) return MenuTitle->borderWidth;
  2387:                 else if (!_stricmp(&szString[10], ".marginWidth:")) return MenuTitle->marginWidth;
  2388:                 else if (!_stricmp(&szString[10], ".fontHeight:")) return MenuTitle->FontHeight;
  2389:             }
  2390:             else if (szString[5] == 'f') // menu frame items
  2391:             {
  2392:                 if (!_stricmp(&szString[10], ".borderWidth:")) return MenuFrame->borderWidth;
  2393:                 else if (!_stricmp(&szString[10], ".marginWidth:")) return MenuFrame->marginWidth;
  2394:                 else if (!_stricmp(&szString[10], ".fontHeight:")) return MenuFrame->FontHeight;
  2395:             }
  2396:             else if (szString[5] == 'h' || szString[5] == 'a') // menu hilite/active items
  2397:             {
  2398:                 if (!_stricmp(&szString[11], ".borderWidth:")) return MenuActive->borderWidth;
  2399:                 else if (!_stricmp(&szString[11], ".marginWidth:")) return MenuActive->marginWidth;
  2400:                 else if (!_stricmp(&szString[11], ".fontHeight:")) return MenuActive->FontHeight;
  2401:             }
  2402:             else if (szString[5] == 'g') // menu grip items
  2403:             {
  2404:                 if (!_stricmp(&szString[9], ".borderWidth:")) return MenuGrip->borderWidth;
  2405:                 else if (!_stricmp(&szString[9], ".marginWidth:")) return MenuGrip->marginWidth;
  2406:                 else if (!_stricmp(&szString[9], ".fontHeight:")) return MenuGrip->FontHeight;
  2407:             }
  2408:             else if (!_stricmp(&szString[4], ".borderWidth:")) return menuBorderWidth;
  2409:         }
  2410: 
  2411:         //====================
  2412: 
  2413:         else if (!_strnicmp(szString, "dock.", 5) || !_strnicmp(szString, "slit.", 5))
  2414:         {
  2415:             if (!_stricmp(&szString[5], ".borderWidth:")) return Dock->borderWidth;
  2416:             else if (!_stricmp(&szString[5], ".marginWidth:")) return Dock->marginWidth;
  2417:         }
  2418: 
  2419:         //====================
  2420: 
  2421:         else if (!_strnicmp(szString, "window.", 7))
  2422:         {
  2423:             if (szString[7] == 't')
  2424:             {
  2425:                 if (szString[13] == 'f') // window title focus items
  2426:                 {
  2427:                     if (!_stricmp(&szString[18], ".borderWidth:")) return WindowTitleFocus->borderWidth;
  2428:                     else if (!_stricmp(&szString[18], ".marginWidth:")) return WindowTitleFocus->marginWidth;
  2429:                 }
  2430:                 else if (szString[13] == 'u') // window title unfocus items
  2431:                 {
  2432:                     if (!_stricmp(&szString[20], ".borderWidth:")) return WindowTitleUnfocus->borderWidth;
  2433:                     else if (!_stricmp(&szString[20], ".marginWidth:")) return WindowTitleUnfocus->marginWidth;
  2434:                 }
  2435:             }
  2436:             else if (szString[7] == 'l')
  2437:             {
  2438:                 if (szString[13] == 'f') // window label focus items
  2439:                 {
  2440:                     if (!_stricmp(&szString[18], ".borderWidth:")) return WindowLabelFocus->borderWidth;
  2441:                     else if (!_stricmp(&szString[18], ".marginWidth:")) return WindowLabelFocus->marginWidth;
  2442:                     else if (!_stricmp(&szString[18], ".fontHeight:")) return WindowLabelFocus->FontHeight;
  2443:                 }
  2444:                 else if (szString[13] == 'u') // window label unfocus items
  2445:                 {
  2446:                     if (!_stricmp(&szString[20], ".borderWidth:")) return WindowLabelUnfocus->borderWidth;
  2447:                     else if (!_stricmp(&szString[20], ".marginWidth:")) return WindowLabelUnfocus->marginWidth;
  2448:                     else if (!_stricmp(&szString[20], ".fontHeight:")) return WindowLabelUnfocus->FontHeight;
  2449:                 }
  2450:             }
  2451:             else if (szString[7] == 'b')
  2452:             {
  2453:                 if (szString[14] == 'f') // window button focus items
  2454:                 {
  2455:                     if (!_stricmp(&szString[19], ".borderWidth:")) return WindowButtonFocus->borderWidth;
  2456:                     else if (!_stricmp(&szString[19], ".marginWidth:")) return WindowButtonFocus->marginWidth;
  2457:                 }
  2458:                 else if (szString[14] == 'u') // window button unfocus items
  2459:                 {
  2460:                     if (!_stricmp(&szString[21], ".borderWidth:")) return WindowButtonUnfocus->borderWidth;
  2461:                     else if (!_stricmp(&szString[21], ".marginWidth:")) return WindowButtonUnfocus->marginWidth;
  2462:                 }
  2463:                 else if (szString[14] == 'p') // window button pressed items
  2464:                 {
  2465:                     if (!_stricmp(&szString[21], ".borderWidth:")) return WindowButtonPressed->borderWidth;
  2466:                     else if (!_stricmp(&szString[21], ".marginWidth:")) return WindowButtonPressed->marginWidth;
  2467:                 }
  2468:             }
  2469:             else if (szString[7] == 'g')
  2470:             {
  2471:                 if (szString[12] == 'f') // window grip focus items
  2472:                 {
  2473:                     if (!_stricmp(&szString[17], ".borderWidth:")) return WindowGripFocus->borderWidth;
  2474:                     else if (!_stricmp(&szString[17], ".marginWidth:")) return WindowGripFocus->marginWidth;
  2475:                 }
  2476:                 else if (szString[12] == 'u') // window grip unfocus items
  2477:                 {
  2478:                     if (!_stricmp(&szString[19], ".borderWidth:")) return WindowGripUnfocus->borderWidth;
  2479:                     else if (!_stricmp(&szString[19], ".marginWidth:")) return WindowGripUnfocus->marginWidth;
  2480:                 }
  2481:             }
  2482:             else if (szString[7] == 'h')
  2483:             {
  2484:                 if (!_stricmp(&szString[6], ".handleHeight:")) return handleHeight; // window handle height (special non-StyleItem parameter)
  2485:                 else if (szString[14] == 'f') // window handle focus items
  2486:                 {
  2487:                     if (!_stricmp(&szString[19], ".borderWidth:")) return WindowHandleFocus->borderWidth;
  2488:                     else if (!_stricmp(&szString[19], ".marginWidth:")) return WindowHandleFocus->marginWidth;
  2489:                 }
  2490:                 else if (szString[14] == 'u') // window handle unfocus items
  2491:                 {
  2492:                     if (!_stricmp(&szString[21], ".borderWidth:")) return WindowHandleUnfocus->borderWidth;
  2493:                     else if (!_stricmp(&szString[21], ".marginWidth:")) return WindowHandleUnfocus->marginWidth;
  2494:                 }
  2495:             }
  2496:         }
  2497: 
  2498:         //====================
  2499: 
  2500:         else if (!_stricmp(szString, "borderWidth:")) return borderWidth;
  2501:         else if (!_stricmp(szString, "bevelWidth:")) return bevelWidth;
  2502:         else if (!_stricmp(szString, "handleHeight:") || !_stricmp(szString, "handleWidth:")) return handleHeight;
  2503:         else if (!_stricmp(szString, "frameWidth:")) return frameWidth;
  2504: 
  2505:         else if (!_stricmp(szString, "dpi.scaling.factor:") || !_stricmp(szString, "hidpi.scaling.factor:")) return scalingFactorHiDPI;
  2506:     }
  2507: 
  2508:     //====================
  2509: 
  2510:     LPSTR buffer;
  2511:     if (cachedFilePtr && !fp)
  2512:     {
  2513:         // Look for the value in the buffered style file...
  2514:         buffer = GetValueFromCache(cachedFilePtr, szString);
  2515:     }
  2516: //  else if (!cachedFilePtr && !_stricmp(fp, "."))
  2517: //  {
  2518:         // ##### PROOF OF CONCEPT ONLY, HAVE NOT YET DECIDED IF THIS REALLY A GOOD IDEA... (read: there's value in separation of concerns as well!) #####
  2519: //      // Look for the value in the xoblite.rc file for the current theme... (== fp shortcut to allow plugins to read their settings from there for ease of use, easier portability, etc)
  2520: //      buffer = ReadValue(xobrcFile, szString, 0);
  2521: //  }
  2522:     else
  2523:     {
  2524:         // If we can not find the value in the buffer, we fetch it from the specified file... (== this could be any file)
  2525:         buffer = ReadValue(fp, szString, 0);
  2526:     }
  2527: 
  2528:     if (buffer)
  2529:     {
  2530:         int value = 0;
  2531:         value = atoi(buffer);
  2532:         return value;
  2533:     }
  2534:     
  2535:     return szDefault;
  2536: }
  2537: 
  2538: //===========================================================================
  2539: 
  2540: LPSTR Settings::GetString(LPCSTR fp, LPSTR cachedFilePtr, LPCSTR szString, LPSTR szDefault)
  2541: {
  2542:     if (!cachedFilePtr && (!fp || !_stricmp(fp, "") || !_stricmp(fp, styleFile)))
  2543:     {
  2544:         //====================
  2545: 
  2546:         if (strchr(szString, '*')) // wildcard items
  2547:         {
  2548:             if (!_stricmp(szString, "*font:")) return Wildcard->Font;
  2549:             else if (!_stricmp(szString, "toolbar*font:")) return wildcardToolbarFont;
  2550:             else if (!_stricmp(szString, "menu*font:")) return wildcardMenuFont;
  2551:             else if (!_stricmp(szString, "window*font:")) return wildcardWindowFont;
  2552:             else if (!_stricmp(szString, "*justify:") || !_stricmp(szString, "*alignment:")) return GetAlignmentAsString(Wildcard);
  2553: 
  2554:             else if (!_stricmp(szString, "*.font:")) return Wildcard->Font;
  2555:             else if (!_stricmp(szString, "*.justify:") || !_stricmp(szString, "*.alignment:")) return GetAlignmentAsString(Wildcard);
  2556:         }
  2557: 
  2558:         //====================
  2559: 
  2560:         else if (!_strnicmp(szString, "toolbar", 7)) // toolbar items
  2561:         {
  2562:             if (IsInString(szString, ".appearance:"))
  2563:             {
  2564:                 if (!_stricmp(&szString[7], ".appearance:")) return toolbar;
  2565:                 else if (!_stricmp(&szString[7], ".label.appearance:")) return toolbarLabel;
  2566:                 else if (!_stricmp(&szString[7], ".windowLabel.appearance:")) return toolbarWindowLabel;
  2567:                 else if (!_stricmp(&szString[7], ".clock.appearance:")) return toolbarClock;
  2568:                 else if (!_stricmp(&szString[7], ".button.appearance:")) return toolbarButton;
  2569:                 else if (!_stricmp(&szString[7], ".button.pressed.appearance:")) return toolbarButtonPressed;
  2570:             }
  2571:             else
  2572:             {
  2573:                 if (!_stricmp(&szString[7], ":")) return toolbar;
  2574:                 else if (!_stricmp(&szString[7], ".label:")) return toolbarLabel;
  2575:                 else if (!_stricmp(&szString[7], ".windowLabel:")) return toolbarWindowLabel;
  2576:                 else if (!_stricmp(&szString[7], ".clock:")) return toolbarClock;
  2577:                 else if (!_stricmp(&szString[7], ".button:")) return toolbarButton;
  2578:                 else if (!_stricmp(&szString[7], ".button.pressed:")) return toolbarButtonPressed;
  2579: 
  2580:                 else if (!_stricmp(&szString[7], ".font:")) return Toolbar->Font;
  2581:                 else if (!_stricmp(&szString[7], ".label.font:")) return ToolbarLabel->Font;
  2582:                 else if (!_stricmp(&szString[7], ".windowLabel.font:")) return ToolbarWindowLabel->Font;
  2583:                 else if (!_stricmp(&szString[7], ".clock.font:")) return ToolbarClock->Font;
  2584: 
  2585:                 else if (!_stricmp(&szString[7], ".alignment:") || !_stricmp(&szString[7], ".justify:")) return GetAlignmentAsString(Toolbar);
  2586:                 else if (!_stricmp(&szString[7], ".label.alignment:") || !_stricmp(&szString[7], ".label.justify:")) return GetAlignmentAsString(ToolbarLabel);
  2587:                 else if (!_stricmp(&szString[7], ".windowLabel.alignment:") || !_stricmp(&szString[7], ".windowLabel.justify:")) return GetAlignmentAsString(ToolbarWindowLabel);
  2588:                 else if (!_stricmp(&szString[7], ".clock.alignment:") || !_stricmp(&szString[7], ".clock.justify:")) return GetAlignmentAsString(ToolbarClock);
  2589:             }
  2590:         }
  2591: 
  2592:         //====================
  2593: 
  2594:         else if (!_strnicmp(szString, "menu.", 5))
  2595:         {
  2596:             if (szString[5] == 't') // menu title items
  2597:             {
  2598:                 if (!_stricmp(&szString[10], ":") || !_stricmp(&szString[10], ".appearance:")) return menuTitle;
  2599:                 else if (!_stricmp(&szString[10], ".font:")) return MenuTitle->Font;
  2600:                 else if (!_stricmp(&szString[10], ".alignment:") || !_stricmp(&szString[10], ".justify:")) return GetAlignmentAsString(MenuTitle);
  2601:             }
  2602:             else if (szString[5] == 'f') // menu frame items
  2603:             {
  2604:                 if (!_stricmp(&szString[10], ":") || !_stricmp(&szString[10], ".appearance:")) return menuFrame;
  2605:                 else if (!_stricmp(&szString[10], ".font:")) return MenuFrame->Font;
  2606:                 else if (!_stricmp(&szString[10], ".alignment:") || !_stricmp(&szString[10], ".justify:")) return GetAlignmentAsString(MenuFrame);
  2607:             }
  2608:             else if (szString[5] == 'b') // menu bullet items
  2609:             {
  2610:                 if (!_stricmp(&szString[11], ":") || !_stricmp(&szString[11], ".appearance:")) return menuFrameBulletAsString;
  2611:                 else if (!_stricmp(&szString[11], ".position:")) return menuBulletPosition;
  2612:             }
  2613:             else if (!_stricmp(&szString[4], ".active.appearance:") || !_stricmp(&szString[4], ".hilite:") || !_stricmp(&szString[4], ".active:")) return menuActive; // menu active/hilite items
  2614:             else if (!_stricmp(&szString[4], ".grip.appearance:") || !_stricmp(&szString[4], ".grip:")) return menuGrip; // menu grip items
  2615:             else if (!_stricmp(&szString[4], ".indicator.appearance:") || !_stricmp(&szString[4], ".indicator:")) return menuIndicator; // menu indicator items
  2616:         }
  2617: 
  2618:         //====================
  2619: 
  2620:         else if (!_strnicmp(szString, "dock", 4) || !_strnicmp(szString, "slit", 4))
  2621:         {
  2622:             if (!_stricmp(&szString[4], ":") || !_stricmp(&szString[4], ".appearance:")) return dock;
  2623:         }
  2624: 
  2625:         //====================
  2626: 
  2627:         else if (!_strnicmp(szString, "window.", 7))
  2628:         {
  2629:             if (szString[7] == 't')
  2630:             {
  2631:                 if (szString[13] == 'f') // window title focus items
  2632:                 {
  2633:                     if (!_stricmp(&szString[18], ":") || !_stricmp(&szString[18], ".appearance:")) return windowTitleFocus;
  2634:                 }
  2635:                 else if (szString[13] == 'u') // window title unfocus items
  2636:                 {
  2637:                     if (!_stricmp(&szString[20], ":") || !_stricmp(&szString[20], ".appearance:")) return windowTitleUnfocus;
  2638:                 }
  2639:             }
  2640:             else if (szString[7] == 'l')
  2641:             {
  2642:                 if (szString[13] == 'f') // window label focus items
  2643:                 {
  2644:                     if (!_stricmp(&szString[18], ":") || !_stricmp(&szString[18], ".appearance:")) return windowLabelFocus;
  2645:                     else if (!_stricmp(&szString[18], ".font:")) return WindowLabelFocus->Font;
  2646:                     else if (!_stricmp(&szString[18], ".alignment:") || !_stricmp(&szString[18], ".justify:")) return GetAlignmentAsString(WindowLabelFocus);
  2647:                 }
  2648:                 else if (szString[13] == 'u') // window label unfocus items
  2649:                 {
  2650:                     if (!_stricmp(&szString[20], ":") || !_stricmp(&szString[20], ".appearance:")) return windowLabelUnfocus;
  2651:                     else if (!_stricmp(&szString[20], ".font:")) return WindowLabelUnfocus->Font;
  2652:                     else if (!_stricmp(&szString[20], ".alignment:") || !_stricmp(&szString[20], ".justify:")) return GetAlignmentAsString(WindowLabelUnfocus);
  2653:                 }
  2654:             }
  2655:             else if (szString[7] == 'b')
  2656:             {
  2657:                 if (szString[14] == 'f') // window button focus items
  2658:                 {
  2659:                     if (!_stricmp(&szString[19], ":") || !_stricmp(&szString[19], ".appearance:")) return windowButtonFocus;
  2660:                 }
  2661:                 else if (szString[14] == 'u') // window button unfocus items
  2662:                 {
  2663:                     if (!_stricmp(&szString[21], ":") || !_stricmp(&szString[21], ".appearance:")) return windowButtonUnfocus;
  2664:                 }
  2665:                 else if (szString[14] == 'p') // window button pressed items
  2666:                 {
  2667:                     if (!_stricmp(&szString[21], ":") || !_stricmp(&szString[21], ".appearance:")) return windowButtonPressed;
  2668:                 }
  2669:             }
  2670:             else if (szString[7] == 'g')
  2671:             {
  2672:                 if (szString[12] == 'f') // window grip focus items
  2673:                 {
  2674:                     if (!_stricmp(&szString[17], ":") || !_stricmp(&szString[17], ".appearance:")) return windowGripFocus;
  2675:                 }
  2676:                 else if (szString[12] == 'u') // window grip unfocus items
  2677:                 {
  2678:                     if (!_stricmp(&szString[19], ":") || !_stricmp(&szString[19], ".appearance:")) return windowGripUnfocus;
  2679:                 }
  2680:             }
  2681:             else if (szString[7] == 'h')
  2682:             {
  2683:                 if (szString[14] == 'f') // window handle focus items
  2684:                 {
  2685:                     if (!_stricmp(&szString[19], ":") || !_stricmp(&szString[19], ".appearance:")) return windowHandleFocus;
  2686:                 }
  2687:                 else if (szString[14] == 'u') // window handle unfocus items
  2688:                 {
  2689:                     if (!_stricmp(&szString[21], ":") || !_stricmp(&szString[21], ".appearance:")) return windowHandleUnfocus;
  2690:                 }
  2691:             }
  2692:         }
  2693: 
  2694:         //====================
  2695: 
  2696:         else if (!_strnicmp(szString, "hardware", 8))
  2697:         {
  2698:             if (!_stricmp(&szString[8], ":") || !_stricmp(&szString[8], ".appearance:")) return externalHardware;
  2699:         }
  2700:     }
  2701: 
  2702:     //====================
  2703: 
  2704:     LPSTR buffer;
  2705:     if (cachedFilePtr && !fp)
  2706:     {
  2707:         // Look for the value in the buffered style file...
  2708:         buffer = GetValueFromCache(cachedFilePtr, szString);
  2709:     }
  2710:     else
  2711:     {
  2712:         // If we can not find the value in the buffer, we fetch it from the file...
  2713:         buffer = ReadValue(fp, szString, 0);
  2714:     }
  2715: 
  2716:     if (buffer) return buffer;
  2717:     
  2718:     return szDefault;
  2719: }
  2720: 
  2721: //===========================================================================
  2722: 
  2723: static wchar_t GetStringUnicodeBuffer[MAX_LINE_LENGTH];
  2724: 
  2725: LPWSTR Settings::GetStringUnicode(LPCSTR fp, LPSTR cachedFilePtr, LPCSTR szString, LPWSTR szDefault)
  2726: {
  2727:     // Workaround to support Unicode text strings within an otherwise (by legacy) ANSI centered codebase... (cf. similar logic in e.g. the Menu .cpp's)
  2728:     char stringANSI[MAX_LINE_LENGTH];
  2729:     strcpy_s(stringANSI, sizeofArray(stringANSI), GetString(fp, cachedFilePtr, szString, ""));
  2730:     stringANSI[sizeofArray(stringANSI)-1] = '\0'; // Just in case...
  2731:     if (strnlen_s(stringANSI, sizeofArray(stringANSI)) > 0)
  2732:     {
  2733:         MultiByteToWideChar(CP_UTF8, 0, stringANSI, strnlen_s(stringANSI, sizeofArray(stringANSI))+1, GetStringUnicodeBuffer, MAX_LINE_LENGTH);
  2734:         return GetStringUnicodeBuffer;
  2735:     }
  2736: 
  2737:     return szDefault;
  2738: }
  2739: 
  2740: //===========================================================================
  2741: 
  2742: COLORREF Settings::GetColor(LPCSTR fp, LPSTR cachedFilePtr, LPCSTR szString, LPCSTR szDefault, COLORREF szDefaultRef, bool useDefaultRef)
  2743: {
  2744:     if (!cachedFilePtr)
  2745:     {
  2746:         if (!fp || !_stricmp(fp, "") || !_stricmp(fp, styleFile))
  2747:         {
  2748:             char* ptr = NULL;
  2749:             StyleItem* si = NULL;
  2750: 
  2751:             //====================
  2752: 
  2753:             if (strchr(szString, '*')) // wildcard items
  2754:             {
  2755:                 if (!_stricmp(szString, "*.textColor:") || !_stricmp(szString, "*textColor:")) return Wildcard->TextColor;
  2756:             }
  2757: 
  2758:             //====================
  2759: 
  2760:             else if (!_strnicmp(szString, "toolbar", 7))
  2761:             {
  2762:                 if (!_strnicmp(&szString[7], ".clock", 6)) // toolbar clock items
  2763:                 {
  2764:                     ptr = (char*)&szString[13];
  2765:                     si = ToolbarClock;
  2766:                 }
  2767:                 else if (!_strnicmp(&szString[7], ".label", 6)) // toolbar label items
  2768:                 {
  2769:                     ptr = (char*)&szString[13];
  2770:                     si = ToolbarLabel;
  2771:                 }
  2772:                 else if (!_strnicmp(&szString[7], ".windowLabel", 12)) // toolbar windowLabel items
  2773:                 {
  2774:                     ptr = (char*)&szString[19];
  2775:                     si = ToolbarWindowLabel;
  2776:                 }
  2777:                 else if (!_strnicmp(&szString[7], ".button.pressed", 15)) // toolbar pressed button items
  2778:                 {
  2779:                     ptr = (char*)&szString[22];
  2780:                     si = ToolbarButtonPressed;
  2781:                 }
  2782:                 else if (!_strnicmp(&szString[7], ".button", 7)) // toolbar button items
  2783:                 {
  2784:                     ptr = (char*)&szString[14];
  2785:                     si = ToolbarButton;
  2786:                 }
  2787:                 else // toolbar items
  2788:                 {
  2789:                     ptr = (char*)&szString[7];
  2790:                     si = Toolbar;
  2791:                 }
  2792:             }
  2793: 
  2794:             //====================
  2795: 
  2796:             else if (!_strnicmp(szString, "menu", 4))
  2797:             {
  2798:                 if (!_strnicmp(&szString[4], ".title", 6)) // menu title items
  2799:                 {
  2800:                     ptr = (char*)&szString[10];
  2801:                     si = MenuTitle;
  2802:                 }
  2803:                 else if (!_strnicmp(&szString[4], ".frame", 6)) // menu frame items
  2804:                 {
  2805:                     if (!_stricmp(&szString[10], ".bulletColor:")) return MenuFrame->BulletColor;
  2806:                     else if (!_stricmp(&szString[10], ".disableColor:")) return MenuFrame->disabledColor;
  2807:                     ptr = (char*)&szString[10];
  2808:                     si = MenuFrame;
  2809:                 }
  2810:                 else if (!_strnicmp(&szString[4], ".hilite", 7) || !_strnicmp(&szString[4], ".active", 7)) // menu hilite/active items
  2811:                 {
  2812:                     if (!_stricmp(&szString[11], ".bulletColor:")) return MenuActive->BulletColor;
  2813:                     ptr = (char*)&szString[11];
  2814:                     si = MenuActive;
  2815:                 }
  2816:                 else if (!_strnicmp(&szString[4], ".indicator", 10)) // menu indicator
  2817:                 {
  2818:                     ptr = (char*)&szString[14];
  2819:                     si = MenuIndicator;
  2820:                 }
  2821:                 // menu separator items + menu border
  2822:                 else if (!_stricmp(&szString[4], ".separator.color:")) return MenuSeparator->Color;
  2823:                 else if (!_stricmp(&szString[4], ".borderColor:")) return menuBorderColor;
  2824:             }
  2825: 
  2826:             //====================
  2827: 
  2828:             else if (!_strnicmp(szString, "dock", 4) || !_strnicmp(szString, "slit", 4)) // dock items
  2829:             {
  2830:                 ptr = (char*)&szString[4];
  2831:                 si = Dock;
  2832:             }
  2833: 
  2834:             //====================
  2835: 
  2836:             else if (!_strnicmp(szString, "window", 6))
  2837:             {
  2838:                 if (!_strnicmp(&szString[6], ".title", 6))
  2839:                 {
  2840:                     if (!_strnicmp(&szString[12], ".focus", 6)) // window title focus items
  2841:                     {
  2842:                         ptr = (char*)&szString[18];
  2843:                         si = WindowTitleFocus;
  2844:                     }
  2845:                     else if (!_strnicmp(&szString[12], ".unfocus", 8)) // window title unfocus items
  2846:                     {
  2847:                         ptr = (char*)&szString[20];
  2848:                         si = WindowTitleUnfocus;
  2849:                     }
  2850:                 }
  2851:                 else if (!_strnicmp(&szString[6], ".label", 6))
  2852:                 {
  2853:                     if (!_strnicmp(&szString[12], ".focus", 6)) // window label focus items
  2854:                     {
  2855:                         ptr = (char*)&szString[18];
  2856:                         si = WindowLabelFocus;
  2857:                     }
  2858:                     else if (!_strnicmp(&szString[12], ".unfocus", 8)) // window label unfocus items
  2859:                     {
  2860:                         ptr = (char*)&szString[20];
  2861:                         si = WindowLabelUnfocus;
  2862:                     }
  2863:                 }
  2864:                 else if (!_strnicmp(&szString[6], ".button", 7))
  2865:                 {
  2866:                     if (!_strnicmp(&szString[13], ".focus", 6)) // window button focus items
  2867:                     {
  2868:                         ptr = (char*)&szString[19];
  2869:                         si = WindowButtonFocus;
  2870:                     }
  2871:                     else if (!_strnicmp(&szString[13], ".unfocus", 8)) // window button unfocus items
  2872:                     {
  2873:                         ptr = (char*)&szString[21];
  2874:                         si = WindowButtonUnfocus;
  2875:                     }
  2876:                     else if (!_strnicmp(&szString[13], ".pressed", 8)) // window button pressed items
  2877:                     {
  2878:                         ptr = (char*)&szString[21];
  2879:                         si = WindowButtonPressed;
  2880:                     }
  2881:                 }
  2882:                 else if (!_strnicmp(&szString[6], ".grip", 5))
  2883:                 {
  2884:                     if (!_strnicmp(&szString[11], ".focus", 6)) // window grip focus items
  2885:                     {
  2886:                         ptr = (char*)&szString[17];
  2887:                         si = WindowGripFocus;
  2888:                     }
  2889:                     else if (!_strnicmp(&szString[11], ".unfocus", 8)) // window grip unfocus items
  2890:                     {
  2891:                         ptr = (char*)&szString[19];
  2892:                         si = WindowGripUnfocus;
  2893:                     }
  2894:                 }
  2895:                 else if (!_strnicmp(&szString[6], ".handle", 7))
  2896:                 {
  2897:                     if (!_strnicmp(&szString[13], ".focus", 6)) // window handle focus items
  2898:                     {
  2899:                         ptr = (char*)&szString[19];
  2900:                         si = WindowHandleFocus;
  2901:                     }
  2902:                     else if (!_strnicmp(&szString[13], ".unfocus", 8)) // window handle unfocus items
  2903:                     {
  2904:                         ptr = (char*)&szString[21];
  2905:                         si = WindowHandleUnfocus;
  2906:                     }
  2907:                 }
  2908:             }
  2909: 
  2910:             //====================
  2911: 
  2912:             else if (!_strnicmp(szString, "hardware", 8)) // hardware items
  2913:             {
  2914:                 ptr = (char*)&szString[8];
  2915:                 si = ExternalHardware;
  2916:             }
  2917: 
  2918:             //====================
  2919: 
  2920:             if (ptr != NULL)
  2921:             {
  2922:                 if (!_stricmp(ptr, ".color:") || !_stricmp(ptr, ".color1:") || !_stricmp(ptr, ".backgroundColor:")) return si->Color;
  2923:                 else if (!_stricmp(ptr, ".colorTo:") || !_stricmp(ptr, ".color2:")) return si->ColorTo;
  2924:                 else if (!_stricmp(ptr, ".color3:")) return si->Color3;
  2925:                 else if (!_stricmp(ptr, ".color4:")) return si->Color4;
  2926:                 else if (!_stricmp(ptr, ".color5:")) return si->Color5;
  2927:                 else if (!_stricmp(ptr, ".color6:")) return si->Color6;
  2928:                 else if (!_stricmp(ptr, ".color7:")) return si->Color7;
  2929:                 else if (!_stricmp(ptr, ".color8:")) return si->Color8;
  2930: //              else if (!_stricmp(ptr, ".textColor:") || !_stricmp(ptr, ".foregroundColor:")) return si->TextColor;
  2931:                 else if (!_stricmp(ptr, ".textColor:")) return si->TextColor;
  2932:                 else if (!_stricmp(ptr, ".borderColor:")) return si->borderColor;
  2933: //              else if (!_stricmp(ptr, ".picColor:")) return si->PicColor;
  2934:                 else if (!_stricmp(ptr, ".picColor:") || !_stricmp(ptr, ".bulletColor:") || !_stricmp(ptr, ".foregroundColor:")) return si->foregroundColor;
  2935:             }
  2936: 
  2937:             //====================
  2938: 
  2939:             else if (!_stricmp(szString, "borderColor:")) return borderColor;
  2940:         }
  2941:     }
  2942: 
  2943:     //====================
  2944: 
  2945:     // If we could not find the value in
  2946:     // the buffer, we fetch it from the file...
  2947:     COLORREF value;
  2948:     char colorString[MAX_LINE_LENGTH];
  2949:     char tempString[MAX_LINE_LENGTH];
  2950:     char cr[4], cg[4], cb[4];
  2951: 
  2952:     //====================
  2953: 
  2954:     LPSTR buffer;
  2955:     if (cachedFilePtr && !fp)
  2956:     {
  2957:         // Look for the value in the buffered style file...
  2958:         buffer = GetValueFromCache(cachedFilePtr, szString);
  2959:     }
  2960:     else
  2961:     {
  2962:         // If we can not find the value in the buffer, we fetch it from the file...
  2963:         if (!fp || !_stricmp(fp, "")) buffer = ReadValue(styleFile, szString, 0);
  2964:         else buffer = ReadValue(fp, szString, 0);
  2965:     }
  2966: 
  2967:     if (buffer) strcpy_s(colorString, sizeofArray(colorString), buffer);
  2968:     else
  2969:     {
  2970:         // If the requested parameter could not be
  2971:         // found in the file we use the default value...
  2972:         if (useDefaultRef) return szDefaultRef;
  2973:         else strcpy_s(colorString, sizeofArray(colorString), szDefault);
  2974:     }
  2975: 
  2976:     //====================
  2977: 
  2978:     // Check if its a #RRGGBB type string...
  2979:     if (*colorString == '#') memmove(colorString, colorString+1, strnlen_s(colorString, sizeofArray(colorString)));
  2980: 
  2981:     // Check if its an "rgb:12/ee/4c" type string...
  2982:     else if (colorString[3]== ':')
  2983: //  else if (strchr(colorString, ':'))
  2984:     {
  2985:         strcpy_s(tempString, sizeofArray(tempString), Tokenize(colorString, colorString, ":"));
  2986:         strcpy_s(tempString, sizeofArray(tempString), Tokenize(tempString, cr, "/"));
  2987:         strcpy_s(tempString, sizeofArray(tempString), Tokenize(tempString, cg, "/"));
  2988:         strcpy_s(cb, sizeofArray(cb), tempString);
  2989: 
  2990:         strcpy_s(colorString, sizeofArray(colorString), cr);
  2991:         if (strnlen_s(cr, sizeofArray(cr))==1) strcat_s(colorString, sizeofArray(colorString), cr);
  2992:         strcat_s(colorString, sizeofArray(colorString), cg);
  2993:         if (strnlen_s(cg, sizeofArray(cg))==1) strcat_s(colorString, sizeofArray(colorString), cg);
  2994:         strcat_s(colorString, sizeofArray(colorString), cb);
  2995:         if (strnlen_s(cb, sizeofArray(cb))==1) strcat_s(colorString, sizeofArray(colorString), cb);
  2996:     }
  2997: 
  2998:     // Check if its a pre-defined colour (e.g. "black")...
  2999:     else if (isalpha(*colorString))
  3000:     {
  3001:         value = ParseLiteralColor(colorString);
  3002:         if (value) return value;
  3003:     }
  3004: 
  3005:     //====================
  3006: 
  3007:     value = strtol(colorString, NULL, 16);
  3008:     value = RGB(GetBValue(value), GetGValue(value), GetRValue(value));// Have to switch the R and B values around due to the anal way of handling #000000 colors (this is below near the RGB())
  3009: 
  3010:     return value;
  3011: }
  3012: 
  3013: //===========================================================================
  3014: 
  3015: static char valueFromCache[MAX_LINE_LENGTH+1];
  3016: 
  3017: LPSTR Settings::GetValueFromCache(LPSTR cachedFilePtr, LPCSTR szString)
  3018: {
  3019:     char* ptr = cachedFilePtr;
  3020:     char* ptr2 = cachedFilePtr;
  3021: 
  3022:     // Look for the requested keyword in the memory cache...
  3023:     for (;;)
  3024:     {
  3025:         ptr = StrStrI(ptr2, szString); // -> Case insensitive strstr (Win32 shlwapi.lib)
  3026:         if (ptr == NULL) return NULL;
  3027:         else if (!CheckForComment(cachedFilePtr, ptr)) break;
  3028:         ptr2 = ptr+1;
  3029:     }
  3030: 
  3031:     // We're only interested in the string after the keyword...
  3032:     ptr += strlen(szString); // Note: As we do not (currently at least) know the length of the szString we can not use strnlen_s here :(
  3033:     // Remove any initial space characters or tabs...
  3034:     ptr += strspn(ptr, " \t");
  3035:     // Copy the string while checking for end of line, end of file, or MS-DOS Ctrl-Z...
  3036:     ptr2 = ptr;
  3037:     for (int i=0; i<MAX_LINE_LENGTH; i++)
  3038:     {
  3039:         if ((ptr2[0] == '\n') || (ptr2[0] == EOF) || (ptr2[0] == 26))
  3040:         {
  3041:             valueFromCache[i] = '\0';
  3042:             break;
  3043:         }
  3044:         else
  3045:         {
  3046:             valueFromCache[i] = ptr2[0];
  3047:             ptr2++;
  3048:         }
  3049:     }
  3050: 
  3051:     valueFromCache[MAX_LINE_LENGTH-1] = '\0'; // Failsafe (in case the line is longer than the allowed maximum 4096 bytes)
  3052: 
  3053:     int nLen = strnlen_s(valueFromCache, sizeofArray(valueFromCache));
  3054:     if (nLen == 0) return NULL;
  3055: 
  3056:     // Remove any trailing space characters...
  3057:     while (nLen >0 && valueFromCache[nLen-1] == ' ') nLen--;
  3058:     valueFromCache[nLen] = '\0';
  3059: 
  3060:     return valueFromCache;
  3061: }
  3062: 
  3063: //====================
  3064: 
  3065: bool Settings::CheckForComment(LPSTR cachedFilePtr, LPSTR ptr)
  3066: {
  3067:     LPSTR ptr2 = ptr - 1;
  3068:     if (ptr2[0] == '.') return true; // Safeguard for e.g. "borderColor:" vs "toolbar.borderColor:"
  3069:     for (;;)
  3070:     {
  3071:         if ((ptr2[0] == '\n') || (ptr2[0] == EOF) || (ptr2[0] == 26)) return false;
  3072:         else if ((ptr2[0] == '!') || (ptr2[0] == '#')) return true;
  3073:         else if (ptr2 == cachedFilePtr) return false;
  3074:         else ptr2--;
  3075:     }
  3076: }
  3077: 
  3078: //===========================================================================
  3079: 
  3080: void Settings::UpdateAppearanceString(StyleItem* styleItem)
  3081: {
  3082:     if (styleItem->type == B_IMAGEFROMFILE) return;
  3083: 
  3084:     //====================
  3085: 
  3086:     // Update the cached appearance *string* for the specified element...
  3087:     // (nb. not included in the StyleItem definition but potentially used by
  3088:     //  e.g. plugins calling ReadString, so needs to reflect the latest changes
  3089:     // applied while using the style Designer Mode (see Broams.cpp)
  3090: 
  3091:     if (styleItem == Toolbar) appearancePointer = toolbar;
  3092:     else if (styleItem == ToolbarLabel) appearancePointer = toolbarLabel;
  3093:     else if (styleItem == ToolbarWindowLabel) appearancePointer = toolbarWindowLabel;
  3094:     else if (styleItem == ToolbarClock) appearancePointer = toolbarClock;
  3095:     else if (styleItem == ToolbarButton) appearancePointer = toolbarButton;
  3096:     else if (styleItem == ToolbarButtonPressed) appearancePointer = toolbarButtonPressed;
  3097:     else if (styleItem == MenuTitle) appearancePointer = menuTitle;
  3098:     else if (styleItem == MenuFrame) appearancePointer = menuFrame;
  3099:     else if (styleItem == MenuActive) appearancePointer = menuActive;
  3100:     else if (styleItem == MenuGrip) appearancePointer = menuGrip;
  3101:     else if (styleItem == MenuIndicator) appearancePointer = menuIndicator;
  3102:     else if (styleItem == Dock) appearancePointer = dock;
  3103:     else if (styleItem == Console) appearancePointer = console;
  3104:     else if (styleItem == WindowTitleFocus) appearancePointer = windowTitleFocus;
  3105:     else if (styleItem == WindowTitleUnfocus) appearancePointer = windowTitleUnfocus;
  3106:     else if (styleItem == WindowLabelFocus) appearancePointer = windowLabelFocus;
  3107:     else if (styleItem == WindowLabelUnfocus) appearancePointer = windowLabelUnfocus;
  3108:     else if (styleItem == WindowButtonFocus) appearancePointer = windowButtonFocus;
  3109:     else if (styleItem == WindowButtonUnfocus) appearancePointer = windowButtonUnfocus;
  3110:     else if (styleItem == WindowButtonPressed) appearancePointer = windowButtonPressed;
  3111:     else if (styleItem == WindowGripFocus) appearancePointer = windowGripFocus;
  3112:     else if (styleItem == WindowGripUnfocus) appearancePointer = windowGripUnfocus;
  3113:     else if (styleItem == WindowHandleFocus) appearancePointer = windowHandleFocus;
  3114:     else if (styleItem == WindowHandleUnfocus) appearancePointer = windowHandleUnfocus;
  3115:     else if (styleItem == ExternalHardware) appearancePointer = externalHardware;
  3116:     else return; // Failsafe
  3117: 
  3118:     //====================
  3119: 
  3120:     appearancePointer[0] = '\0';
  3121: 
  3122:     if (styleItem->type == B_PARENTRELATIVE || styleItem->parentRelative) strcat_s(appearancePointer, MAX_LINE_LENGTH, "ParentRelative");
  3123:     else
  3124:     {
  3125:         if (styleItem->bevelstyle == BEVEL_RAISED) strcat_s(appearancePointer, MAX_LINE_LENGTH, "Raised");
  3126:         else if (styleItem->bevelstyle == BEVEL_SUNKEN) strcat_s(appearancePointer, MAX_LINE_LENGTH, "Sunken");
  3127:         else strcat_s(appearancePointer, MAX_LINE_LENGTH, "Flat");
  3128: 
  3129:         if (styleItem->type == B_SOLID) strcat_s(appearancePointer, MAX_LINE_LENGTH, " Solid");
  3130:         else
  3131:         {
  3132:             strcat_s(appearancePointer, MAX_LINE_LENGTH, " Gradient");
  3133:             switch (styleItem->type)
  3134:             {
  3135:                 case B_HORIZONTAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Horizontal"); break; }
  3136:                 case B_VERTICAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Vertical"); break; }
  3137:                 case B_DIAGONAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Diagonal"); break; }
  3138:                 case B_CROSSDIAGONAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " CrossDiagonal"); break; }
  3139:                 case B_PIPECROSS: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Pipecross"); break; }
  3140:                 case B_ELLIPTIC: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Elliptic"); break; }
  3141:                 case B_RECTANGLE: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Rectangle"); break; }
  3142:                 case B_PYRAMID: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " Pyramid"); break; }
  3143:                 case B_MIRRORHORIZONTAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " MirrorHorizontal"); break; }
  3144:                 case B_MIRRORVERTICAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " MirrorVertical"); break; }
  3145:                 case B_SPLITSOLID: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " SplitSolid"); break; }
  3146:                 case B_SPLITHORIZONTAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " SplitHorizontal"); break; }
  3147:                 case B_SPLITVERTICAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " SplitVertical"); break; }
  3148:                 case B_SUPERHORIZONTAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " SuperHorizontal"); break; }
  3149:                 case B_SUPERVERTICAL: { strcat_s(appearancePointer, MAX_LINE_LENGTH, " SuperVertical"); break; }
  3150:                 default: break;
  3151:             }
  3152:         }
  3153: 
  3154:         if (styleItem->bevelstyle != BEVEL_FLAT)
  3155:         {
  3156:             if (styleItem->bevelposition == BEVEL2) strcat_s(appearancePointer, MAX_LINE_LENGTH, " Bevel2");
  3157:             else strcat_s(appearancePointer, MAX_LINE_LENGTH, " Bevel1");
  3158:         }
  3159: 
  3160:         if (styleItem->interlaced) strcat_s(appearancePointer, MAX_LINE_LENGTH, " Interlaced");
  3161:     }
  3162: }
  3163: 
  3164: //====================
  3165: 
  3166: char justifyLeft[5] = "Left", justifyCenter[7] = "Center", justifyRight[6] = "Right";
  3167: 
  3168: LPSTR Settings::GetAlignmentAsString(StyleItem* styleItem)
  3169: {
  3170:     if (styleItem->Justify == DT_LEFT) return justifyLeft;
  3171:     else if (styleItem->Justify == DT_RIGHT) return justifyRight;
  3172:     else return justifyCenter;
  3173: }
  3174: 
  3175: //===========================================================================
  3176: 
  3177: void Settings::ParsePlacement(LPSTR inputString, Placement* outputPlacement)
  3178: {
  3179: //  strncpy(outputPlacement->rcString, inputString, sizeof(outputPlacement->rcString)); // Save the .rc placement string, we might need it later...
  3180:     strncpy_s(outputPlacement->rcString, sizeof(outputPlacement->rcString), inputString, _TRUNCATE); // Save the .rc placement string, we might need it later...
  3181:     outputPlacement->rcString[sizeof(outputPlacement->rcString)-1] = '\0';
  3182: 
  3183:     //====================
  3184: 
  3185:     if (inputString[0] == 'M' || inputString[0] == 'm') // Manual positioning
  3186:     {
  3187:         char tempPlacement[MAX_LINE_LENGTH];
  3188:         strcpy_s(tempPlacement, sizeofArray(tempPlacement), inputString);
  3189: 
  3190:         char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH], token3[MAX_LINE_LENGTH];
  3191:         LPSTR tokens[2];
  3192:         tokens[0] = token1;
  3193:         tokens[1] = token2;
  3194: 
  3195:         token1[0] = token2[0] = token3[0] = '\0';
  3196:         BBTokenize (tempPlacement, tokens, 2, token3);
  3197: 
  3198:         outputPlacement->placement = PLACEMENT_MANUAL;
  3199: 
  3200:         if (token2[1] == 'C') // "xC" -> Use centered x positioning (nb. regardless of Manual y positioning, see below)
  3201:         {
  3202:             outputPlacement->centeredx = true;
  3203:             if (strnlen_s(token2, sizeofArray(token2)) > 2) outputPlacement->rcx = atoi(&token2[2]); // Any +/- offset from the centered position? (i.e. input string is longer than "xC")
  3204:             else outputPlacement->rcx = 0;
  3205:         }
  3206:         else
  3207:         {
  3208:             outputPlacement->centeredx = false;
  3209:             outputPlacement->rcx = atoi(&token2[1]); // E.g. "x10" (-> left relative positioning) or "x-10" (-> right relative positioning)
  3210:         }
  3211: 
  3212:         if (token3[1] == 'C') // "yC" -> Use centered y positioning (nb. regardless of Manual x positioning, see above)
  3213:         {
  3214:             outputPlacement->centeredy = true;
  3215:             if (strnlen_s(token3, sizeofArray(token3)) > 2) outputPlacement->rcy = atoi(&token3[2]); // Any +/- offset from the centered position? (i.e. input string is longer than "yC")
  3216:             else outputPlacement->rcy = 0;
  3217:         }
  3218:         else
  3219:         {
  3220:             outputPlacement->centeredy = false;
  3221:             outputPlacement->rcy = atoi(&token3[1]); // E.g. "y10" (-> top relative positioning) or "y-10" (-> bottom relative positioning)
  3222:         }
  3223: 
  3224:         return;
  3225:     }
  3226: 
  3227:     //====================
  3228: 
  3229:     if (inputString[0] == 'T' || inputString[0] == 't') // Vertical Top
  3230:     {
  3231:         if (inputString[3] == 'L') outputPlacement->placement = PLACEMENT_TOP_LEFT;
  3232:         else if (inputString[3] == 'C') outputPlacement->placement = PLACEMENT_TOP_CENTER;
  3233:         else if (inputString[3] == 'R') outputPlacement->placement = PLACEMENT_TOP_RIGHT;
  3234:     }
  3235: 
  3236:     //====================
  3237: 
  3238:     else if (inputString[0] == 'C' || inputString[0] == 'c') // Vertical Center
  3239:     {
  3240:         if (inputString[6] == 'L') outputPlacement->placement = PLACEMENT_CENTER_LEFT;
  3241:         if (inputString[6] == 'C') outputPlacement->placement = PLACEMENT_CENTER_CENTER;
  3242:         else if (inputString[6] == 'R') outputPlacement->placement = PLACEMENT_CENTER_RIGHT;
  3243:     }
  3244: 
  3245:     //====================
  3246: 
  3247:     else if (inputString[0] == 'B' || inputString[0] == 'b') // Vertical Bottom
  3248:     {
  3249:         if (inputString[6] == 'L') outputPlacement->placement = PLACEMENT_BOTTOM_LEFT;
  3250:         else if (inputString[6] == 'C') outputPlacement->placement = PLACEMENT_BOTTOM_CENTER;
  3251:         else if (inputString[6] == 'R') outputPlacement->placement = PLACEMENT_BOTTOM_RIGHT;
  3252:     }
  3253: 
  3254:     //====================
  3255: 
  3256:     else if (inputString[0] == 'D' || inputString[0] == 'd') // Default (used by the console)
  3257:     {
  3258:         outputPlacement->placement = PLACEMENT_DEFAULT;
  3259:     }
  3260: 
  3261:     //====================
  3262: 
  3263:     else if (inputString[0] == 'O' || inputString[0] == 'o') // OppositeToolbar (used by the dock)
  3264:     {
  3265:         outputPlacement->placement = PLACEMENT_OPPOSITE_TOOLBAR;
  3266:     }
  3267: 
  3268:     //====================
  3269: 
  3270:     else if (inputString[0] == 'N' || inputString[0] == 'n') // Next (used by e.g the toolbar broams)
  3271:     {
  3272:         if (outputPlacement->placement >= PLACEMENT_TOP_LEFT && outputPlacement->placement < PLACEMENT_BOTTOM_RIGHT) outputPlacement->placement++;
  3273:         else outputPlacement->placement = PLACEMENT_TOP_LEFT;
  3274:     }
  3275:     else if (inputString[0] == 'P' || inputString[0] == 'p') // Previous (used by e.g the toolbar broams)
  3276:     {
  3277:         if (outputPlacement->placement <= PLACEMENT_BOTTOM_RIGHT && outputPlacement->placement > PLACEMENT_TOP_LEFT) outputPlacement->placement--;
  3278:         else outputPlacement->placement = PLACEMENT_BOTTOM_RIGHT;
  3279:     }
  3280: 
  3281:     //====================
  3282: 
  3283:     else if (outputPlacement->placement < PLACEMENT_MANUAL || outputPlacement->placement > PLACEMENT_OPPOSITE_TOOLBAR)
  3284:     {
  3285:         // "Sanity check" failed, use default value...
  3286:         outputPlacement->placement = PLACEMENT_BOTTOM_CENTER;
  3287:     }
  3288: }
  3289: 
  3290: //===========================================================================
  3291: 
  3292: void Settings::PositionFromPlacement(Placement* inputPlacement)
  3293: {
  3294:     if (!multimonPlacements || (GetSystemMetrics(SM_CMONITORS) == 1)) // -> Multi-monitor placements disabled, or only one display monitor connected...
  3295:     {
  3296:         if (explorerHidden)
  3297:         {
  3298:             ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
  3299:             ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
  3300:             ScreenX = 0; // GetSystemMetrics(SM_XVIRTUALSCREEN);
  3301:             ScreenY = 0; // GetSystemMetrics(SM_YVIRTUALSCREEN);
  3302:         }
  3303:         else
  3304:         {
  3305:             RECT workArea;
  3306:             SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, SPIF_SENDCHANGE);
  3307:             ScreenWidth = workArea.right - workArea.left;
  3308:             ScreenHeight = workArea.bottom - workArea.top;
  3309:             ScreenX = workArea.left;
  3310:             ScreenY = workArea.top;
  3311:         }
  3312:     }
  3313:     else // -> Multi-monitor placements enabled, and more than one display monitor connected...
  3314:     {
  3315:         ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  3316:         ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  3317:         ScreenX = GetSystemMetrics(SM_XVIRTUALSCREEN);
  3318:         ScreenY = GetSystemMetrics(SM_YVIRTUALSCREEN);
  3319:     }
  3320: 
  3321:     //====================
  3322: 
  3323:     int tempPlacement = inputPlacement->placement;
  3324: 
  3325:     //====================
  3326: 
  3327:      // OppositeToolbar placement?
  3328: 
  3329:     if (tempPlacement == PLACEMENT_OPPOSITE_TOOLBAR)
  3330:     {
  3331:         switch (ToolbarPlacement.placement)
  3332:         {
  3333:             case PLACEMENT_TOP_LEFT:
  3334:             tempPlacement = PLACEMENT_BOTTOM_LEFT;
  3335:             break;
  3336:             case PLACEMENT_TOP_CENTER:
  3337:             tempPlacement = PLACEMENT_BOTTOM_CENTER;
  3338:             break;
  3339:             case PLACEMENT_TOP_RIGHT:
  3340:             tempPlacement = PLACEMENT_BOTTOM_RIGHT;
  3341:             break;
  3342: 
  3343:             case PLACEMENT_CENTER_LEFT:
  3344:             tempPlacement = PLACEMENT_CENTER_RIGHT;
  3345:             break;
  3346:             case PLACEMENT_CENTER_RIGHT:
  3347:             tempPlacement = PLACEMENT_CENTER_LEFT;
  3348:             break;
  3349: 
  3350:             case PLACEMENT_BOTTOM_LEFT:
  3351:             tempPlacement = PLACEMENT_TOP_LEFT;
  3352:             break;
  3353:             case PLACEMENT_BOTTOM_CENTER:
  3354:             tempPlacement = PLACEMENT_TOP_CENTER;
  3355:             break;
  3356:             case PLACEMENT_BOTTOM_RIGHT:
  3357:             tempPlacement = PLACEMENT_TOP_RIGHT;
  3358:             break;
  3359: 
  3360:             default:
  3361:             tempPlacement = PLACEMENT_CENTER_RIGHT;
  3362:         }
  3363:     }
  3364: 
  3365:     //====================
  3366: 
  3367:     switch (tempPlacement)
  3368:     {
  3369:         //====================
  3370: 
  3371:         case PLACEMENT_MANUAL:
  3372:         {
  3373:             // Centered placement for x or y requested?
  3374:             // (optionally with +/- offset from centered position through input rcx/rcy values, see ParsePlacement() above)
  3375:             if (inputPlacement->centeredx) inputPlacement->x = inputPlacement->rcx + (ScreenWidth - inputPlacement->width) / 2;
  3376:             else inputPlacement->x = inputPlacement->rcx;
  3377:             if (inputPlacement->centeredy) inputPlacement->y = inputPlacement->rcy + (ScreenHeight - inputPlacement->height) / 2;
  3378:             else inputPlacement->y = inputPlacement->rcy;
  3379: 
  3380:             // Negative coordinates -> Offset from the bottom right corner of the screen,
  3381:             // relative to bottom right corner of the window...
  3382:             if (inputPlacement->x < 0) inputPlacement->x = ScreenWidth + inputPlacement->x - inputPlacement->width;
  3383:             if (inputPlacement->y < 0) inputPlacement->y = ScreenHeight + inputPlacement->y - inputPlacement->height;
  3384: 
  3385:             // Make sure the window is inside the visible screen...
  3386:             int xmax = ScreenWidth - inputPlacement->width;
  3387:             int ymax = ScreenHeight - inputPlacement->height;
  3388:             if (inputPlacement->x < 0) inputPlacement->x = 0;
  3389:             if (inputPlacement->y < 0) inputPlacement->y = 0;
  3390:             if (inputPlacement->x > xmax) inputPlacement->x = xmax;
  3391:             if (inputPlacement->y > ymax) inputPlacement->y = ymax;
  3392:         }
  3393:         break;
  3394: 
  3395:         //====================
  3396: 
  3397:         case PLACEMENT_TOP_LEFT:
  3398:         {
  3399:             inputPlacement->x = 0;
  3400:             inputPlacement->y = 0;
  3401:         }
  3402:         break;
  3403: 
  3404:         //====================
  3405: 
  3406:         case PLACEMENT_TOP_CENTER:
  3407:         {
  3408:             inputPlacement->x = (ScreenWidth - inputPlacement->width) / 2;
  3409:             inputPlacement->y = 0;
  3410:         }
  3411:         break;
  3412: 
  3413:         //====================
  3414: 
  3415:         case PLACEMENT_TOP_RIGHT:
  3416:         {
  3417:             inputPlacement->x = ScreenWidth - inputPlacement->width;
  3418:             inputPlacement->y = 0;
  3419:         }
  3420:         break;
  3421: 
  3422:         //====================
  3423: 
  3424:         case PLACEMENT_BOTTOM_LEFT:
  3425:         {
  3426:             inputPlacement->x = 0;
  3427:             inputPlacement->y = ScreenHeight - inputPlacement->height;
  3428:         }
  3429:         break;
  3430: 
  3431:         //====================
  3432: 
  3433:         case PLACEMENT_BOTTOM_CENTER:
  3434:         {
  3435:             inputPlacement->x = (ScreenWidth - inputPlacement->width) / 2;
  3436:             inputPlacement->y = ScreenHeight - inputPlacement->height;
  3437:         }
  3438:         break;
  3439: 
  3440:         //====================
  3441: 
  3442:         case PLACEMENT_BOTTOM_RIGHT:
  3443:         {
  3444:             inputPlacement->x = ScreenWidth - inputPlacement->width;
  3445:             inputPlacement->y = ScreenHeight - inputPlacement->height;
  3446:         }
  3447:         break;
  3448: 
  3449:         //====================
  3450: 
  3451:         case PLACEMENT_CENTER_LEFT:
  3452:         {
  3453:             inputPlacement->x = 0;
  3454:             inputPlacement->y = (ScreenHeight - inputPlacement->height) / 2;
  3455:         }
  3456:         break;
  3457: 
  3458:         //====================
  3459: 
  3460:         case PLACEMENT_CENTER_CENTER:
  3461:         {
  3462:             inputPlacement->x = (ScreenWidth - inputPlacement->width) / 2;
  3463:             inputPlacement->y = (ScreenHeight - inputPlacement->height) / 2;
  3464:         }
  3465:         break;
  3466: 
  3467:         //====================
  3468: 
  3469:         case PLACEMENT_DEFAULT: // (used by the console)
  3470:         {
  3471:             inputPlacement->x = (ScreenWidth - inputPlacement->width) / 2;
  3472: //          inputPlacement->y = ScreenHeight - desktopArea.bottom - inputPlacement->height - inputPlacement->x;
  3473:             inputPlacement->y = ScreenHeight - inputPlacement->height - inputPlacement->x;
  3474:         }
  3475:         break;
  3476: 
  3477:         //====================
  3478: 
  3479:         default: // PLACEMENT_CENTER_RIGHT
  3480:         {
  3481:             inputPlacement->x = ScreenWidth - inputPlacement->width;
  3482:             inputPlacement->y = (ScreenHeight - inputPlacement->height) / 2;
  3483:         }
  3484:     }
  3485: 
  3486:     inputPlacement->x += ScreenX;
  3487:     inputPlacement->y += ScreenY;
  3488: }
  3489: 
  3490: //===========================================================================
  3491: 
  3492: void Settings::WritePlacement(Placement* inputPlacement)
  3493: {
  3494:     char outputString[255], outputX[5], outputY[5];
  3495: 
  3496:     switch (inputPlacement->placement)
  3497:     {
  3498:         //====================
  3499: 
  3500:         case PLACEMENT_MANUAL:
  3501:         {
  3502:             if (inputPlacement->centeredx) // -> Center relative x positioning
  3503:             {
  3504:                 if (inputPlacement->rcx != 0) sprintf_s(outputX, sizeofArray(outputX), "xC%d", inputPlacement->rcx);
  3505:                 else strcpy_s(outputX, sizeofArray(outputX), "xC");
  3506:             }
  3507:             else sprintf_s(outputX, sizeofArray(outputX), "x%d", inputPlacement->rcx); // -> Left/Right relative x positioning
  3508: 
  3509:             if (inputPlacement->centeredy) // -> Center relative y positioning
  3510:             {
  3511:                 if (inputPlacement->rcy != 0) sprintf_s(outputY, sizeofArray(outputY), "yC%d", inputPlacement->rcy);
  3512:                 else strcpy_s(outputY, sizeofArray(outputY), "yC");
  3513:             }
  3514:             else sprintf_s(outputY, sizeofArray(outputY), "y%d", inputPlacement->rcy); // -> Top/Bottom relative y positioning
  3515: 
  3516:             sprintf_s(outputString, sizeofArray(outputString), "Manual %s %s", outputX, outputY);
  3517:             break;
  3518:         }
  3519: 
  3520:         //====================
  3521: 
  3522:         case PLACEMENT_TOP_LEFT:            { strcpy_s(outputString, sizeofArray(outputString), "TopLeft"); break; }
  3523:         case PLACEMENT_TOP_CENTER:          { strcpy_s(outputString, sizeofArray(outputString), "TopCenter"); break; }
  3524:         case PLACEMENT_TOP_RIGHT:           { strcpy_s(outputString, sizeofArray(outputString), "TopRight"); break; }
  3525: 
  3526:         case PLACEMENT_CENTER_LEFT:         { strcpy_s(outputString, sizeofArray(outputString), "CenterLeft"); break; }
  3527:         case PLACEMENT_CENTER_CENTER:       { strcpy_s(outputString, sizeofArray(outputString), "CenterCenter");    break; }
  3528:         case PLACEMENT_CENTER_RIGHT:        { strcpy_s(outputString, sizeofArray(outputString), "CenterRight"); break; }
  3529: 
  3530:         case PLACEMENT_BOTTOM_LEFT:         { strcpy_s(outputString, sizeofArray(outputString), "BottomLeft"); break; }
  3531:         case PLACEMENT_BOTTOM_CENTER:       { strcpy_s(outputString, sizeofArray(outputString), "BottomCenter");    break; }
  3532:         case PLACEMENT_BOTTOM_RIGHT:        { strcpy_s(outputString, sizeofArray(outputString), "BottomRight"); break; }
  3533: 
  3534:         case PLACEMENT_OPPOSITE_TOOLBAR:    { strcpy_s(outputString, sizeofArray(outputString), "OppositeToolbar"); break; }
  3535: 
  3536:         case PLACEMENT_DEFAULT:             { strcpy_s(outputString, sizeofArray(outputString), "Default"); break; }
  3537: 
  3538:         //====================
  3539: 
  3540:         default:
  3541:         return;
  3542:     }
  3543: 
  3544: //  strncpy(inputPlacement->rcString, outputString, sizeof(inputPlacement->rcString)); // Save the new .rc placement string, we might need it later...
  3545:     strncpy_s(inputPlacement->rcString, sizeof(inputPlacement->rcString), outputString, _TRUNCATE); // Save the new .rc placement string, we might need it later...
  3546: 
  3547:     if (inputPlacement == &ToolbarPlacement) WriteString(xobrcFile, "xoblite.toolbar.placement:", outputString);
  3548:     else if (inputPlacement == &DockPlacement) WriteString(xobrcFile, "xoblite.dock.placement:", outputString);
  3549:     else if (inputPlacement == &ConsolePlacement) WriteString(xobrcFile, "xoblite.console.placement:", outputString);
  3550:     else if (inputPlacement == &desktopClockPlacement) WriteString(xobrcFile, "xoblite.desktop.clock.placement:", outputString);
  3551:     else if (inputPlacement == &desktopWeekdayPlacement) WriteString(xobrcFile, "xoblite.desktop.weekday.placement:", outputString);
  3552:     else if (inputPlacement == &desktopDatePlacement) WriteString(xobrcFile, "xoblite.desktop.date.placement:", outputString);
  3553:     else if (inputPlacement == &desktopGreetingPlacement) WriteString(xobrcFile, "xoblite.desktop.greeting.placement:", outputString);
  3554: }
  3555: 
  3556: //===========================================================================
  3557: 
  3558: void Settings::WriteStyle()
  3559: {
  3560:     time_t systemTime;
  3561:     struct tm localTime;
  3562:     time(&systemTime);
  3563:     localtime_s(&localTime, &systemTime);
  3564: 
  3565:     char filename[MAX_PATH], path[MAX_PATH];
  3566:     _locale_t timestampLocale = _create_locale(LC_TIME, "en-US"); // -> Always use en-US format for the saved style filename timestamp...
  3567:     _strftime_l(filename, MAX_PATH, "\\xDesigner_%Y_%m_%d_%H%M%S.style", &localTime, timestampLocale);
  3568:     _free_locale(timestampLocale);
  3569:     strcpy_s(path, sizeofArray(path), stylesFolder);
  3570:     strcat_s(path, sizeofArray(path), filename);
  3571: 
  3572:     if (FileExists(path)) return;
  3573:     else
  3574:     {
  3575:         HANDLE file = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  3576:         if (file)
  3577:         {
  3578:             char szTemp[MAX_LINE_LENGTH];
  3579:             DWORD retLength = 0;
  3580: 
  3581:             strcpy_s(szTemp, sizeofArray(szTemp), "! --------------------------------------------------\r\n\r\n");
  3582:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3583: 
  3584:             strcpy_s(szTemp, sizeofArray(szTemp), "style.name: <Auto-generated>\r\nstyle.author: <xoblite Designer mode>\r\nstyle.date: \r\nstyle.credits: \r\nstyle.comments: \r\nstyle.wallpaper: \r\n\r\n");
  3585:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3586: 
  3587:             strcpy_s(szTemp, sizeofArray(szTemp), "! ----------------------------- wallpaper ----------\r\n\r\n");
  3588:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3589: 
  3590:             sprintf_s(szTemp, sizeofArray(szTemp), "rootCommand: %s\r\n\r\n", rootCommand);
  3591:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3592: 
  3593:             strcpy_s(szTemp, sizeofArray(szTemp), "! ------------------------------- toolbar ----------\r\n\r\n");
  3594:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3595: 
  3596:             WriteStyleElement(file, Toolbar);
  3597:             if (!ToolbarBorder->parentRelative) WriteStyleElement(file, ToolbarBorder);
  3598:             WriteStyleElement(file, ToolbarLabel);
  3599:             WriteStyleElement(file, ToolbarWindowLabel);
  3600:             WriteStyleElement(file, ToolbarClock);
  3601:             WriteStyleElement(file, ToolbarButton);
  3602:             WriteStyleElement(file, ToolbarButtonPressed);
  3603: 
  3604:             strcpy_s(szTemp, sizeofArray(szTemp), "! ---------------------------------- menu ----------\r\n\r\n");
  3605:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3606: 
  3607:             WriteStyleElement(file, MenuTitle);
  3608:             WriteStyleElement(file, MenuFrame);
  3609:             if (!MenuFrameBorder->parentRelative) WriteStyleElement(file, MenuFrameBorder);
  3610:             WriteStyleElement(file, MenuActive);
  3611:             WriteStyleElement(file, MenuGrip);
  3612:             WriteStyleElement(file, MenuIndicator);
  3613:             WriteStyleElement(file, MenuSeparator);
  3614: //          sprintf_s(szTemp, sizeofArray(szTemp), "menu.separator.color: #%02x%02x%02x\r\n\r\n", GetRValue(MenuSeparator->Color), GetGValue(MenuSeparator->Color), GetBValue(MenuSeparator->Color));
  3615:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3616: 
  3617:             strcpy_s(szTemp, sizeofArray(szTemp), "menu.bullet: ");
  3618:             switch (menuBullet)
  3619:             {
  3620:                 case MENU_BULLET_TRIANGLE: { strcat_s(szTemp, sizeofArray(szTemp), "Triangle\r\n"); break; }
  3621:                 case MENU_BULLET_SQUARE: { strcat_s(szTemp, sizeofArray(szTemp), "Square\r\n"); break; }
  3622:                 case MENU_BULLET_DIAMOND: { strcat_s(szTemp, sizeofArray(szTemp), "Diamond\r\n"); break; }
  3623:                 case MENU_BULLET_CIRCLE: { strcat_s(szTemp, sizeofArray(szTemp), "Circle\r\n"); break; }
  3624:                 case MENU_BULLET_TRIPLE: { strcat_s(szTemp, sizeofArray(szTemp), "Triple\r\n"); break; }
  3625:                 case MENU_BULLET_COMMENT: { strcat_s(szTemp, sizeofArray(szTemp), "Comment\r\n"); break; }
  3626:                 case MENU_BULLET_GRID: { strcat_s(szTemp, sizeofArray(szTemp), "Grid\r\n"); break; }
  3627:                 case MENU_BULLET_QUAD: { strcat_s(szTemp, sizeofArray(szTemp), "Quad\r\n"); break; }
  3628:                 default: { strcat_s(szTemp, sizeofArray(szTemp), "Empty\r\n"); break; }
  3629:             }
  3630:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3631: 
  3632:             if (!_stricmp(menuBulletPosition, "right")) strcpy_s(szTemp, sizeofArray(szTemp), "menu.bullet.position: Right\r\n\r\n");
  3633:             else strcpy_s(szTemp, sizeofArray(szTemp), "menu.bullet.position: Left\r\n\r\n");
  3634:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3635: 
  3636:             strcpy_s(szTemp, sizeofArray(szTemp), "! ---------------------------------- dock ----------\r\n\r\n");
  3637:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3638: 
  3639:             WriteStyleElement(file, Dock);
  3640:             if (!DockBorder->parentRelative) WriteStyleElement(file, DockBorder);
  3641: 
  3642:             strcpy_s(szTemp, sizeofArray(szTemp), "! ------------------------------- console ----------\r\n\r\n");
  3643:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3644: 
  3645:             sprintf_s(szTemp, sizeofArray(szTemp), "console.color: #%02x%02x%02x\r\n", GetRValue(Console->Color), GetGValue(Console->Color), GetBValue(Console->Color));
  3646:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3647:             sprintf_s(szTemp, sizeofArray(szTemp), "console.textColor: #%02x%02x%02x\r\n", GetRValue(Console->TextColor), GetGValue(Console->TextColor), GetBValue(Console->TextColor));
  3648:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3649:             sprintf_s(szTemp, sizeofArray(szTemp), "console.buttonColor: #%02x%02x%02x\r\n", GetRValue(Console->PicColor), GetGValue(Console->PicColor), GetBValue(Console->PicColor));
  3650:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3651: 
  3652:             if ((scalingFactorHiDPI > 1) && (Console->FontHeight > 0)) sprintf_s(szTemp, sizeofArray(szTemp), "console.font: %s/%d/", Console->Font, (Console->FontHeight / scalingFactorHiDPI));
  3653:             else sprintf_s(szTemp, sizeofArray(szTemp), "console.font: %s/%d/", Console->Font, Console->FontHeight);
  3654:             if (Console->FontWeight == FW_BOLD) strcat_s(szTemp, sizeofArray(szTemp), "Bold\r\n\r\n");
  3655:             else strcat_s(szTemp, sizeofArray(szTemp), "Normal\r\n\r\n");
  3656:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3657: 
  3658:             strcpy_s(szTemp, sizeofArray(szTemp), "! -------------------------------- window ----------\r\n\r\n");
  3659:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3660: 
  3661:             WriteStyleElement(file, WindowTitleFocus);
  3662:             WriteStyleElement(file, WindowTitleUnfocus);
  3663:             WriteStyleElement(file, WindowLabelFocus);
  3664:             WriteStyleElement(file, WindowLabelUnfocus);
  3665:             WriteStyleElement(file, WindowButtonFocus);
  3666:             WriteStyleElement(file, WindowButtonUnfocus);
  3667:             WriteStyleElement(file, WindowButtonPressed);
  3668:             WriteStyleElement(file, WindowGripFocus);
  3669:             WriteStyleElement(file, WindowGripUnfocus);
  3670:             WriteStyleElement(file, WindowHandleFocus);
  3671:             WriteStyleElement(file, WindowHandleUnfocus);
  3672: 
  3673: //          sprintf_s(szTemp, sizeofArray(szTemp), "window.handleHeight: %d\r\n\r\n", (handleHeight/2));
  3674: //          WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3675: 
  3676: //          strcpy_s(szTemp, sizeofArray(szTemp), "! --------------------------------------------------\r\n\r\n");
  3677: //          WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3678: 
  3679: //          WriteStyleElement(file, ExternalHardware);
  3680: 
  3681:             strcpy_s(szTemp, sizeofArray(szTemp), "! --------------------------------------------------\r\n");
  3682:             WriteFile(file, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
  3683:         }
  3684:         CloseHandle(file);
  3685:     }
  3686: 
  3687:     char msg[MAX_LINE_LENGTH];
  3688:     sprintf_s(msg, sizeofArray(msg), "... style settings saved to %s .", path);
  3689:     SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
  3690: }
  3691: 
  3692: //===========================================================================
  3693: 
  3694: void Settings::WriteStyleElement(HANDLE file, StyleItem* styleItem)
  3695: {
  3696:     char styleElement[32], writeBuffer[MAX_LINE_LENGTH];
  3697:     DWORD retLength = 0;
  3698: 
  3699:     if (styleItem == Toolbar) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar");
  3700:     else if (styleItem == ToolbarBorder) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.border");
  3701:     else if (styleItem == ToolbarLabel) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.label");
  3702:     else if (styleItem == ToolbarWindowLabel) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.windowLabel");
  3703:     else if (styleItem == ToolbarClock) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.clock");
  3704:     else if (styleItem == ToolbarButton) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.button");
  3705:     else if (styleItem == ToolbarButtonPressed) strcpy_s(styleElement, sizeofArray(styleElement), "toolbar.button.pressed");
  3706:     else if (styleItem == MenuTitle) strcpy_s(styleElement, sizeofArray(styleElement), "menu.title");
  3707:     else if (styleItem == MenuFrame) strcpy_s(styleElement, sizeofArray(styleElement), "menu.frame");
  3708:     else if (styleItem == MenuFrameBorder) strcpy_s(styleElement, sizeofArray(styleElement), "menu.frame.border");
  3709:     else if (styleItem == MenuActive) strcpy_s(styleElement, sizeofArray(styleElement), "menu.active");
  3710:     else if (styleItem == MenuGrip) strcpy_s(styleElement, sizeofArray(styleElement), "menu.grip");
  3711:     else if (styleItem == MenuIndicator) strcpy_s(styleElement, sizeofArray(styleElement), "menu.indicator");
  3712:     else if (styleItem == MenuSeparator) strcpy_s(styleElement, sizeofArray(styleElement), "menu.separator");
  3713:     // else if (styleItem == Dock) strcpy_s(styleElement, sizeofArray(styleElement), "slit");
  3714:     else if (styleItem == Dock) strcpy_s(styleElement, sizeofArray(styleElement), "dock");
  3715:     else if (styleItem == DockBorder) strcpy_s(styleElement, sizeofArray(styleElement), "dock.border");
  3716:     else if (styleItem == WindowTitleFocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.title.focus");
  3717:     else if (styleItem == WindowTitleUnfocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.title.unfocus");
  3718:     else if (styleItem == WindowLabelFocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.label.focus");
  3719:     else if (styleItem == WindowLabelUnfocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.label.unfocus");
  3720:     else if (styleItem == WindowButtonFocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.button.focus");
  3721:     else if (styleItem == WindowButtonUnfocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.button.unfocus");
  3722:     else if (styleItem == WindowButtonPressed) strcpy_s(styleElement, sizeofArray(styleElement), "window.button.pressed");
  3723:     else if (styleItem == WindowGripFocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.grip.focus");
  3724:     else if (styleItem == WindowGripUnfocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.grip.unfocus");
  3725:     else if (styleItem == WindowHandleFocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.handle.focus");
  3726:     else if (styleItem == WindowHandleUnfocus) strcpy_s(styleElement, sizeofArray(styleElement), "window.handle.unfocus");
  3727:     else if (styleItem == ExternalHardware) strcpy_s(styleElement, sizeofArray(styleElement), "hardware");
  3728:     else return;
  3729: 
  3730:     //====================
  3731: 
  3732:     strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3733:     strcat_s(writeBuffer, sizeofArray(writeBuffer), ".appearance:");
  3734:     if (styleItem->type == B_PARENTRELATIVE || styleItem->parentRelative) strcat_s(writeBuffer, sizeofArray(writeBuffer), " ParentRelative");
  3735:     else
  3736:     {
  3737:         if ((styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) && (styleItem != ExternalHardware))
  3738:         {
  3739:             if (styleItem->bevelstyle == BEVEL_RAISED) strcat_s(writeBuffer, sizeofArray(writeBuffer), " Raised");
  3740:             else if (styleItem->bevelstyle == BEVEL_SUNKEN) strcat_s(writeBuffer, sizeofArray(writeBuffer), " Sunken");
  3741:             else strcat_s(writeBuffer, sizeofArray(writeBuffer), " Flat");
  3742:         }
  3743: 
  3744:         if (styleItem->type == B_SOLID) strcat_s(writeBuffer, sizeofArray(writeBuffer), " Solid");
  3745:         else
  3746:         {
  3747:             if ((styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) && (styleItem != ExternalHardware))
  3748:             {
  3749:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), " Gradient");
  3750:             }
  3751: 
  3752:             switch (styleItem->type)
  3753:             {
  3754:                 case B_HORIZONTAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Horizontal"); break; }
  3755:                 case B_VERTICAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Vertical"); break; }
  3756:                 case B_DIAGONAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Diagonal"); break; }
  3757:                 case B_CROSSDIAGONAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " CrossDiagonal"); break; }
  3758:                 case B_PIPECROSS: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Pipecross"); break; }
  3759:                 case B_ELLIPTIC: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Elliptic"); break; }
  3760:                 case B_RECTANGLE: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Rectangle"); break; }
  3761:                 case B_PYRAMID: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " Pyramid"); break; }
  3762:                 case B_MIRRORHORIZONTAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " MirrorHorizontal"); break; }
  3763:                 case B_MIRRORVERTICAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " MirrorVertical"); break; }
  3764:                 case B_SPLITSOLID: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " SplitSolid"); break; }
  3765:                 case B_SPLITHORIZONTAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " SplitHorizontal"); break; }
  3766:                 case B_SPLITVERTICAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " SplitVertical"); break; }
  3767:                 case B_SUPERHORIZONTAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " SuperHorizontal"); break; }
  3768:                 case B_SUPERVERTICAL: { strcat_s(writeBuffer, sizeofArray(writeBuffer), " SuperVertical"); break; }
  3769:                 default: break;
  3770:             }
  3771:         }
  3772: 
  3773:         if ((styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) && (styleItem != ExternalHardware))
  3774:         {
  3775:             if (styleItem->bevelstyle != BEVEL_FLAT)
  3776:             {
  3777:                 if (styleItem->bevelposition == BEVEL2) strcat_s(writeBuffer, sizeofArray(writeBuffer), " Bevel2");
  3778:                 else strcat_s(writeBuffer, sizeofArray(writeBuffer), " Bevel1");
  3779:             }
  3780: 
  3781:             if (styleItem->interlaced) strcat_s(writeBuffer, sizeofArray(writeBuffer), " Interlaced");
  3782:         }
  3783:     }
  3784:     strcat_s(writeBuffer, sizeofArray(writeBuffer), "\r\n");
  3785:     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3786: 
  3787:     //====================
  3788: 
  3789:     char colorString[10];
  3790: 
  3791:     if (styleItem->type != B_PARENTRELATIVE && !styleItem->parentRelative)
  3792:     {
  3793:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3794:         if (styleItem->type == B_SOLID) strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color:");
  3795:         else strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color1:");
  3796:         sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color1), GetGValue(styleItem->Color1), GetBValue(styleItem->Color1));
  3797:         strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3798:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3799: 
  3800:         if (styleItem->type != B_SOLID)
  3801:         {
  3802:             strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3803:             strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color2:");
  3804:             sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color2), GetGValue(styleItem->Color2), GetBValue(styleItem->Color2));
  3805:             strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3806:             WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3807: 
  3808:             if (styleItem->type == B_SPLITHORIZONTAL || styleItem->type == B_SPLITVERTICAL || styleItem->type == B_SUPERHORIZONTAL || styleItem->type == B_SUPERVERTICAL)
  3809:             {
  3810:                 strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3811:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color3:");
  3812:                 sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color3), GetGValue(styleItem->Color3), GetBValue(styleItem->Color3));
  3813:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3814:                 WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3815: 
  3816:                 strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3817:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color4:");
  3818:                 sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color4), GetGValue(styleItem->Color4), GetBValue(styleItem->Color4));
  3819:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3820:                 WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3821: 
  3822:                 if (styleItem->type == B_SUPERHORIZONTAL || styleItem->type == B_SUPERVERTICAL)
  3823:                 {
  3824:                     strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3825:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color5:");
  3826:                     sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color5), GetGValue(styleItem->Color5), GetBValue(styleItem->Color5));
  3827:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3828:                     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3829: 
  3830:                     strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3831:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color6:");
  3832:                     sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color6), GetGValue(styleItem->Color6), GetBValue(styleItem->Color6));
  3833:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3834:                     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3835: 
  3836:                     strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3837:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color7:");
  3838:                     sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color7), GetGValue(styleItem->Color7), GetBValue(styleItem->Color7));
  3839:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3840:                     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3841: 
  3842:                     strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3843:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), ".color8:");
  3844:                     sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->Color8), GetGValue(styleItem->Color8), GetBValue(styleItem->Color8));
  3845:                     strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3846:                     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3847:                 }
  3848:             }
  3849:         }
  3850:     }
  3851: 
  3852:     //====================
  3853: 
  3854:     if ((styleItem != ToolbarButton) && (styleItem != ToolbarButtonPressed) && (styleItem != MenuActive) && (styleItem != MenuIndicator) && (styleItem != MenuSeparator) && (styleItem != Dock) && 
  3855:         (styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) &&
  3856:         (styleItem != WindowTitleFocus) && (styleItem != WindowButtonFocus) && (styleItem != WindowGripFocus) && (styleItem != WindowHandleFocus) && (styleItem != WindowButtonPressed) &&
  3857:         (styleItem != WindowTitleUnfocus) && (styleItem != WindowButtonUnfocus) && (styleItem != WindowGripUnfocus) && (styleItem != WindowHandleUnfocus) &&
  3858:         (styleItem != ExternalHardware))
  3859:     {
  3860:         if ((scalingFactorHiDPI > 1) && (styleItem->FontHeight > 0)) sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.font: %s/%d/", styleElement, styleItem->Font, (styleItem->FontHeight / scalingFactorHiDPI));
  3861:         else sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.font: %s/%d/", styleElement, styleItem->Font, styleItem->FontHeight);
  3862:         if (styleItem->FontWeight == FW_BOLD) strcat_s(writeBuffer, sizeofArray(writeBuffer), "Bold\r\n");
  3863:         else strcat_s(writeBuffer, sizeofArray(writeBuffer), "Normal\r\n");
  3864:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3865: 
  3866:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3867:         strcat_s(writeBuffer, sizeofArray(writeBuffer), ".alignment: ");
  3868:         if (styleItem->Justify == DT_LEFT) strcat_s(writeBuffer, sizeofArray(writeBuffer), "Left\r\n");
  3869:         else if (styleItem->Justify == DT_RIGHT) strcat_s(writeBuffer, sizeofArray(writeBuffer), "Right\r\n");
  3870:         else strcat_s(writeBuffer, sizeofArray(writeBuffer), "Center\r\n");
  3871:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3872:     }
  3873: 
  3874:     if ((styleItem != ToolbarButton) && (styleItem != ToolbarButtonPressed) && (styleItem != MenuIndicator) && (styleItem != MenuSeparator) && (styleItem != Dock) &&
  3875:         (styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) &&
  3876:         (styleItem != WindowTitleFocus) && (styleItem != WindowButtonFocus) && (styleItem != WindowGripFocus) && (styleItem != WindowHandleFocus) && (styleItem != WindowButtonPressed) &&
  3877:         (styleItem != WindowTitleUnfocus) && (styleItem != WindowButtonUnfocus) && (styleItem != WindowGripUnfocus) && (styleItem != WindowHandleUnfocus) &&
  3878:         (styleItem != ExternalHardware))
  3879:     {
  3880:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3881:         strcat_s(writeBuffer, sizeofArray(writeBuffer), ".textColor:");
  3882:         sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->TextColor), GetGValue(styleItem->TextColor), GetBValue(styleItem->TextColor));
  3883:         strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3884:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3885: 
  3886:         if (styleItem->FontOutline)
  3887:         {
  3888:             strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3889:             strcat_s(writeBuffer, sizeofArray(writeBuffer), ".outlineColor:");
  3890:             sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->OutlineColor), GetGValue(styleItem->OutlineColor), GetBValue(styleItem->OutlineColor));
  3891:             strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3892:             WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3893:         }
  3894: 
  3895:         if (styleItem->FontShadow)
  3896:         {
  3897:             strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3898:             strcat_s(writeBuffer, sizeofArray(writeBuffer), ".shadowColor:");
  3899:             sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->ShadowColor), GetGValue(styleItem->ShadowColor), GetBValue(styleItem->ShadowColor));
  3900:             strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3901:             WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3902:         }
  3903:     }
  3904: 
  3905: //  if ((styleItem == MenuFrame) || (styleItem == MenuActive))
  3906:     if (styleItem == MenuFrame)
  3907:     {
  3908:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3909:         strcat_s(writeBuffer, sizeofArray(writeBuffer), ".disabledColor:");
  3910:         sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->disabledColor), GetGValue(styleItem->disabledColor), GetBValue(styleItem->disabledColor));
  3911:         strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3912:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3913:     }
  3914: 
  3915:     //====================
  3916: 
  3917:     if ((styleItem == ToolbarButton) || (styleItem == ToolbarButtonPressed) || (styleItem == WindowButtonFocus) || (styleItem == WindowButtonUnfocus) || (styleItem == WindowButtonPressed))
  3918:     {
  3919:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3920:         strcat_s(writeBuffer, sizeofArray(writeBuffer), ".picColor:");
  3921:         sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->PicColor), GetGValue(styleItem->PicColor), GetBValue(styleItem->PicColor));
  3922:         strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3923:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3924:     }
  3925: 
  3926:     if ((styleItem == MenuFrame) || (styleItem == MenuActive))
  3927:     {
  3928:         strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3929:         strcat_s(writeBuffer, sizeofArray(writeBuffer), ".bulletColor:");
  3930:         sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->BulletColor), GetGValue(styleItem->BulletColor), GetBValue(styleItem->BulletColor));
  3931:         strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3932:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3933:     }
  3934: 
  3935:     //====================
  3936: 
  3937:     if ((styleItem != MenuSeparator) && (styleItem != ToolbarBorder) && (styleItem != MenuFrameBorder) && (styleItem != DockBorder) && (styleItem != ExternalHardware))
  3938:     {
  3939:         if ((scalingFactorHiDPI > 1) && (styleItem->marginWidth > 0)) sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.marginWidth: %d\r\n", styleElement, (styleItem->marginWidth / scalingFactorHiDPI));
  3940:         else sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.marginWidth: %d\r\n", styleElement, styleItem->marginWidth);
  3941:         WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3942: 
  3943:         if (styleItem->type != B_PARENTRELATIVE && !styleItem->parentRelative)
  3944:         {
  3945:             if ((scalingFactorHiDPI > 1) && (styleItem->borderWidth > 0)) sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.borderWidth: %d\r\n", styleElement, (styleItem->borderWidth / scalingFactorHiDPI));
  3946:             else sprintf_s(writeBuffer, sizeofArray(writeBuffer), "%s.borderWidth: %d\r\n", styleElement, styleItem->borderWidth);
  3947:             WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3948: 
  3949:             if (styleItem->borderWidth > 0)
  3950:             {
  3951:                 strcpy_s(writeBuffer, sizeofArray(writeBuffer), styleElement);
  3952:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), ".borderColor:");
  3953:                 sprintf_s(colorString, sizeofArray(colorString), " #%02x%02x%02x\r\n", GetRValue(styleItem->borderColor), GetGValue(styleItem->borderColor), GetBValue(styleItem->borderColor));
  3954:                 strcat_s(writeBuffer, sizeofArray(writeBuffer), colorString);
  3955:                 WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3956:             }
  3957:         }
  3958:     }
  3959: 
  3960:     //====================
  3961: 
  3962:     strcpy_s(writeBuffer, sizeofArray(writeBuffer), "\r\n");
  3963:     WriteFile(file, writeBuffer, strnlen_s(writeBuffer, sizeofArray(writeBuffer)), &retLength, NULL);
  3964: }
  3965: 
  3966: //===========================================================================
  3967: