/*
 ============================================================================
 xoblite -> an alternative shell based on Blackbox for Windows
 Copyright  2002-2005 Karl-Henrik Henriksson [qwilk]
 Copyright  2001-2004 The Blackbox for Windows Development Team
 http://xoblite.net/ - #bb4win on irc.freenode.net
 ============================================================================

  Blackbox for Windows is free software, released under the
  GNU General Public License (GPL version 2 or later), with an extension
  that allows linking of proprietary modules under a controlled interface.
  What this means is that plugins etc. are allowed to be released
  under any license the author wishes. Please note, however, that the
  original Blackbox gradient math code used in Blackbox for Windows
  is available under the BSD license.

  http://www.fsf.org/licenses/gpl.html
  http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
  http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  For additional license information, please read the included license.html

 ============================================================================
*/

#include "BBApi.h" 
#include "Settings.h" 
#include "BImage.h" 
#include <windows.h> 

int screenNumber = 0; // To be used in multimonitor setups (?)
static char szTemp[MAX_LINE_LENGTH];

bool coreReadingToBuffer = false;

//===========================================================================

Settings::Settings()
{
        ZeroMemory(&Toolbar, sizeof(StyleItem));
        ZeroMemory(&ToolbarLabel, sizeof(StyleItem));
        ZeroMemory(&ToolbarWindowLabel, sizeof(StyleItem));
        ZeroMemory(&ToolbarClock, sizeof(StyleItem));
        ZeroMemory(&ToolbarButton, sizeof(StyleItem));
        ZeroMemory(&ToolbarButtonPressed, sizeof(StyleItem));

        ZeroMemory(&MenuTitle, sizeof(StyleItem));
        ZeroMemory(&MenuFrame, sizeof(StyleItem));
        ZeroMemory(&MenuHilite, sizeof(StyleItem));
        ZeroMemory(&MenuIndicator, sizeof(StyleItem));

        ZeroMemory(&Slit, sizeof(StyleItem));

        ZeroMemory(&ActiveTask, sizeof(StyleItem));
        ZeroMemory(&InactiveTask, sizeof(StyleItem));
        ZeroMemory(&FlashingTask, sizeof(StyleItem));

        //====================

        menuFrameBulletColor = 0;
        menuFrameDisableColor = 0;

        menuHiliteBulletColor = 0;

        //====================

        borderWidth = 0;
        borderColor = 0;
        bevelWidth = 0;
        handleWidth = 0;
        frameWidth = 0;

        //====================

        bbrcFile[0] = 0;
        menuFile[0] = 0;
        plugrcFile[0] = 0;
        extrcFile[0] = 0;
        extrcDefaultFile[0] = 0;
        styleFile[0] = 0;
}

//===========================================================================

Settings::~Settings()
{
        DeleteStyleItems();
}

//===========================================================================

void Settings::DeleteStyleItems()
{
        if (Toolbar) delete Toolbar;
        if (ToolbarButton) delete ToolbarButton;
        if (ToolbarButtonPressed) delete ToolbarButtonPressed;
        if (ToolbarLabel) delete ToolbarLabel;
        if (ToolbarWindowLabel) delete ToolbarWindowLabel;
        if (ToolbarClock) delete ToolbarClock;

        if (MenuTitle) delete MenuTitle;
        if (MenuFrame) delete MenuFrame;
        if (MenuHilite) delete MenuHilite;
        if (MenuIndicator) delete MenuIndicator;

        if (Slit) delete Slit;

        if (ActiveTask) delete ActiveTask;
        if (InactiveTask) delete InactiveTask;
        if (FlashingTask) delete FlashingTask;
}

//===========================================================================

void Settings::ReadRCSettings()
{
        coreReadingToBuffer = true;

        char bbrc[MAX_PATH];
        strcpy(bbrc, bbrcPath()); // Save the blackbox.rc path so we don't have to call that function repeatedly...

        // Per screen settings (not yet fully supported)

        //====================

        // Slit settings
        sprintf(szTemp, "session.screen%d.slit.placement:", screenNumber);
        strcpy(slitPlacement, ReadString(bbrc, szTemp, "TopCenter"));

        sprintf(szTemp, "session.screen%d.slit.direction:", screenNumber);
        strcpy(slitDirection, ReadString(bbrc, szTemp, "Horizontal"));

        sprintf(szTemp, "session.screen%d.slit.onTop:", screenNumber);
        slitOnTop = ReadBool(bbrc, szTemp, false);

        sprintf(szTemp, "session.screen%d.slit.autoHide:", screenNumber);
        slitAutoHide = ReadBool(bbrc, szTemp, false);

        //====================

        // Toolbar settings
        sprintf(szTemp, "session.screen%d.toolbar.onTop:", screenNumber);
        toolbarOnTop = ReadBool(bbrc, szTemp, true);

        sprintf(szTemp, "session.screen%d.toolbar.autoHide:", screenNumber);
        toolbarAutoHide = ReadBool(bbrc, szTemp, false);

        sprintf(szTemp, "session.screen%d.toolbar.placement:", screenNumber);
        strcpy(toolbarPlacement, ReadString(bbrc, szTemp, "BottomCenter"));

        sprintf(szTemp, "session.screen%d.toolbar.widthPercent:", screenNumber);
        toolbarWidthPercent = ReadInt(bbrc, szTemp, 66);
        if (toolbarWidthPercent < 30) toolbarWidthPercent = 30;

        //====================

        // Other settings
        sprintf(szTemp, "session.screen%d.workspaces:", screenNumber);
        workspaces = ReadInt(bbrc, szTemp, 4);

        sprintf(szTemp, "session.screen%d.focusLastWindow:", screenNumber);
        focusLastWindow = ReadBool(bbrc, szTemp, false);

        sprintf(szTemp, "session.screen%d.windowPlacement:", screenNumber);
        strcpy(windowPlacement, ReadString(bbrc, szTemp, "ColSmartPlacement"));

        sprintf(szTemp, "session.screen%d.colPlacementDirection:", screenNumber);
        strcpy(colPlacementDirection, ReadString(bbrc, szTemp, "TopToBottom"));

        sprintf(szTemp, "session.screen%d.workspaceNames:", screenNumber);
        strcpy(workspaceNames, ReadString(bbrc, szTemp, "alpha,beta,gamma,delta"));

        sprintf(szTemp, "session.screen%d.focusNewWindows:", screenNumber);
        focusNewWindows = ReadBool(bbrc, szTemp, false);

        sprintf(szTemp, "session.screen%d.rowPlacementDirection:", screenNumber);
        strcpy(rowPlacementDirection, ReadString(bbrc, szTemp, "LeftToRight"));

        sprintf(szTemp, "session.screen%d.fullMaximization:", screenNumber);
        fullMaximization = ReadBool(bbrc, szTemp, true);

        sprintf(szTemp, "session.screen%d.strftimeFormat:", screenNumber);
        strcpy(strftimeFormat, ReadString(bbrc, szTemp, "%H:%M | %a %#d %b"));

        sprintf(szTemp, "session.screen%d.edgeSnapThreshold:", screenNumber);
        edgeSnapThreshold = ReadInt(bbrc, szTemp, 10);

        sprintf(szTemp, "session.screen%d.focusModel:", screenNumber);
        strcpy(focusModel, ReadString(bbrc, szTemp, "ClickToFocus"));

        //====================

        strcpy(styleFile, ReadString(bbrc, "session.styleFile:", ""));
        if (strchr(styleFile, '\"')) StrRemoveEncap(styleFile);
        if (strchr(styleFile, '$')) ReplaceShellFolders(styleFile);
        if (strchr(styleFile, '%')) ReplaceEnvVars(styleFile);

        //====================

        cacheLife = ReadInt(bbrc, "session.cacheLife:", 5);
        cacheMax = ReadInt(bbrc, "session.cacheMax:", 200);
        opaqueMove = ReadBool(bbrc, "session.opaqueMove:", false);
        doubleClickInterval = ReadInt(bbrc, "session.doubleClickInterval:", 250);
        autoRaiseDelay = ReadInt(bbrc, "session.autoRaiseDelay:", 250);

        //====================

        strcpy(menuFile, ReadString(bbrc, "session.menuFile:", "$Blackbox$\\menu.rc"));
        if (strchr(menuFile, '\"')) StrRemoveEncap(menuFile);
        if (strchr(menuFile, '$')) ReplaceShellFolders(menuFile);
        if (strchr(menuFile, '%')) ReplaceEnvVars(menuFile);
        if (!FileExists(menuFile))
        {
                // Check for menu.rc in the Blackbox and $UserAppData$\Blackbox directories...
                strcpy(menuFile, ConfigFileExists("menu.rc", NULL));
                if (!stricmp(menuFile, ""))
                {
                        // If not found, check for menurc in the same directories...
                        strcpy(menuFile, ConfigFileExists("menurc", NULL));
                        if (!stricmp(menuFile, ""))
                        {
                                // If still not found, create the default
                                // menu.rc in the Blackbox directory...
                                WriteDefaultMenu();
                                GetBlackboxPath(menuFile, sizeof(menuFile));
                                strcat(menuFile, "menu.rc");
                        }
                }

                // Finally, we save the menu.rc path to blackbox.rc...
                menuPath(menuFile);
        }

        //====================

        colorsPerChannel = ReadInt(bbrc, "session.colorsPerChannel:", 4);
        imageDither = ReadBool(bbrc, "session.imageDither:", false);

        coreReadingToBuffer = false;
}

//===========================================================================

void Settings::WriteDefaultRCSettings()
{
        DWORD retLength=0;
        char path[MAX_LINE_LENGTH];
        GetBlackboxPath(path, sizeof(path));
        strcat(path, "blackbox.rc");

        if (FileExists(path)) return;
        else
        {
                HANDLE f = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
                if (f)
                {
                        // Slit settings
                        strcpy(szTemp,
                                "session.screen0.slit.placement: TopCenter\r\n"
                                "session.screen0.slit.direction: Horizontal\r\n"
                                "session.screen0.slit.onTop: false\r\n"
                                "session.screen0.slit.autoHide: false\r\n");
                        WriteFile(f, szTemp, strlen(szTemp), &retLength, NULL);

                        // Toolbar settings
                        strcpy(szTemp,
                                "session.screen0.toolbar.onTop: true\r\n"
                                "session.screen0.toolbar.autoHide: false\r\n"
                                "session.screen0.toolbar.placement: BottomCenter\r\n"
                                "session.screen0.toolbar.widthPercent: 66\r\n");
                        WriteFile(f, szTemp, strlen(szTemp), &retLength, NULL);

                        // Other settings
                        strcpy(szTemp,
                                "session.screen0.workspaces: 4\r\n"
                                "session.screen0.focusLastWindow: false\r\n"
                                "session.screen0.windowPlacement: ColSmartPlacement\r\n"
                                "session.screen0.colPlacementDirection: TopToBottom\r\n"
                                "session.screen0.workspaceNames: alpha,beta,gamma,delta\r\n"
                                "session.screen0.focusNewWindows: false\r\n"
                                "session.screen0.rowPlacementDirection: LeftToRight\r\n"
                                "session.screen0.fullMaximization: true\r\n"
                                "session.screen0.strftimeFormat: %H:%M | %a %#d %b\r\n"
                                "session.screen0.edgeSnapThreshold: 10\r\n"
                                "session.screen0.focusModel: ClickToFocus\r\n");
                        WriteFile(f, szTemp, strlen(szTemp), &retLength, NULL);

                        // Global settings
                        strcpy(szTemp,
                                "session.styleFile: $Blackbox$\\styles\\x-ashes\r\n"
                                "session.cacheLife: 5\r\n"
                                "session.cacheMax: 200\r\n"
                                "session.opaqueMove: false\r\n"
                                "session.doubleClickInterval: 250\r\n"
                                "session.autoRaiseDelay: 250\r\n"
                                "session.menuFile: $Blackbox$\\menu.rc\r\n"
                                "session.colorsPerChannel: 4\r\n"
                                "session.imageDither: false\r\n");
                        WriteFile(f, szTemp, strlen(szTemp), &retLength, NULL);
                }
                CloseHandle(f);
        }
}

//===========================================================================

void Settings::ReadExtensionsRCSettings()
{
        coreReadingToBuffer = true;

        char temp[MAX_LINE_LENGTH], tempArea[MAX_LINE_LENGTH];

        // Please note that a parameter may be read from the default extensions.rc file
        // (extrcDefaultFile below) or the current extensions.rc file (extrcFile below)
        // depending on the purpose of the parameter, i.e. theme related parameters are
        // read from the current extensions.rc file while global parameters (e.g. preferred
        // editor) are read from the default extensions.rc file

        //========== theme specific settings ========================================
        
        toolbarHidden = ReadBool(extrcFile, "xoblite.toolbar.hidden:", false);
        toolbarSnapToEdges = ReadBool(extrcFile, "xoblite.toolbar.snapToEdges:", false);
        toolbarTransparencyAlpha = (BYTE)ReadInt(extrcFile, "xoblite.toolbar.transparency.alpha:", 255);

        //====================

        systembarHidden = ReadBool(extrcFile, "xoblite.systembar.hidden:", true);
        strcpy(systembarPlacement, ReadString(extrcFile, "xoblite.systembar.placement:", "DockedToToolbar"));
        systembarOnTop = ReadBool(extrcFile, "xoblite.systembar.onTop:", true);
        systembarSnapToEdges = ReadBool(extrcFile, "xoblite.systembar.snapToEdges:", false);
        systembarWidthPercent = ReadInt(extrcFile, "xoblite.systembar.widthPercent:", 66);
        if (systembarWidthPercent < 30) systembarWidthPercent = 30;
        systembarTooltipsDisabled = ReadBool(extrcFile, "xoblite.systembar.tooltips.disable:", false);
        systembarTransparencyAlpha = (BYTE)ReadInt(extrcFile, "xoblite.systembar.transparency.alpha:", 255);
        systembarFirstInSlit = ReadBool(extrcFile, "xoblite.systembar.firstInSlit:", false);
        systembarXobloonNotifications = ReadBool(extrcFile, "xoblite.systembar.xobloon.notifications:", true);

        //====================

        systrayHidden = ReadBool(extrcFile, "xoblite.systray.hidden:", false);
        systraySaturationValue = ReadInt(extrcFile, "xoblite.systray.saturation:", 30);
        systrayHueIntensity = ReadInt(extrcFile, "xoblite.systray.hue:", 100);

        //====================

        taskbarHidden = ReadBool(extrcFile, "xoblite.taskbar.hidden:", false);
        strcpy(temp, ReadString(extrcFile, "xoblite.taskbar.placement:", "Systembar"));
        {
                if (!stricmp(temp, "Toolbar")) taskbarOnToolbar = true;
                else taskbarOnToolbar = false;
        }
        strcpy(temp, ReadString(extrcFile, "xoblite.taskbar.mode:", "Bars+Icons"));
        {
                if (!stricmp(temp, "Icons")) taskbarMode = 2;
                else if (!stricmp(temp, "Bars+Icons")) taskbarMode = 3;
                else taskbarMode = 1;
        }
        taskbarCurrentOnly = ReadBool(extrcFile, "xoblite.taskbar.currentOnly:", false);
        taskbarFlashing = ReadBool(extrcFile, "xoblite.taskbar.flashing:", true);
        taskbarSaturationValue = ReadInt(extrcFile, "xoblite.taskbar.saturation:", systraySaturationValue);
        taskbarHueIntensity = ReadInt(extrcFile, "xoblite.taskbar.hue:", systrayHueIntensity);
        taskbarActiveSatHue = ReadBool(extrcFile, "xoblite.taskbar.active.SatHue:", false);
        taskbarInactiveBackground = ReadBool(extrcFile, "xoblite.taskbar.inactive.background:", false);

        //====================

        slitHidden = ReadBool(extrcFile, "xoblite.slit.hidden:", false);
        slitSnapToEdges = ReadBool(extrcFile, "xoblite.slit.snapToEdges:", false);
        slitTransparencyAlpha = (BYTE)ReadInt(extrcFile, "xoblite.slit.transparency.alpha:", 255);
        strcpy(slitPositioning, ReadString(extrcFile, "xoblite.slit.positioning:", "SideBySide"));

        //====================

        menuTransparencyAlpha = (BYTE)ReadInt(extrcFile, "xoblite.menu.transparency.alpha:", 255);
        menuSeparators = ReadBool(extrcFile, "xoblite.menu.separators:", true);

        //====================

        pluginsHidden = ReadBool(extrcFile, "xoblite.plugins.hidden:", false);
        autohideSpeed = ReadInt(extrcFile, "xoblite.autohide.speed:", 10);
        alternativeBullets = ReadBool(extrcFile, "xoblite.alternative.bullets:", false);
        forceFontShadows = ReadBool(extrcFile, "xoblite.force.font.shadows:", false);
        writeProtection = ReadBool(extrcFile, "xoblite.write.protection:", false);
        disableScriptSupport = ReadBool(extrcFile, "xoblite.disable.script.support:", false);

        strcpy(tempArea, ReadString(extrcFile, "xoblite.desktop.area:", "NotDefined"));
        if (!stricmp(tempArea, "NotDefined"))
        {
                desktopAreaNotDefined = true;
        }
        else
        {
                desktopAreaNotDefined = false;

                char left[10], top[10], right[10], bottom[10];
                LPSTR tokens[4];
                tokens[0] = left;
                tokens[1] = top;
                tokens[2] = right;
                tokens[3] = bottom;

                left[0] = top[0] = right[0] = bottom[0] = '\0';
                BBTokenize (tempArea, tokens, 3, bottom);

                desktopArea.left = atoi(left);
                desktopArea.top = atoi(top);
                desktopArea.right = atoi(right);
                desktopArea.bottom = atoi(bottom);
        }

        //========== global settings ================================================

        systrayDisabled = ReadBool(extrcDefaultFile, "xoblite.systray.disable:", false);

        //====================

        submenuDelay = ReadInt(extrcDefaultFile, "xoblite.submenu.delay:", 40);
        scrollSpeed = ReadInt(extrcDefaultFile, "xoblite.menu.scrollSpeed:", 10);
        wheelSpeed = ReadInt(extrcDefaultFile, "xoblite.menu.wheelSpeed:", 50);

        midclickStylesMenu = ReadBool(extrcDefaultFile, "xoblite.midclick.stylesMenu:", false);

        strcpy(stylesFolder, ReadString(extrcDefaultFile, "xoblite.stylesFolder:", "$Blackbox$\\styles"));
        if (strchr(stylesFolder, '\"')) StrRemoveEncap(stylesFolder);
        if (strchr(stylesFolder, '$')) ReplaceShellFolders(stylesFolder);
        if (strchr(stylesFolder, '%')) ReplaceEnvVars(stylesFolder);

        strcpy(themesFolder, ReadString(extrcDefaultFile, "xoblite.themesFolder:", "$Blackbox$\\themes"));
        if (strchr(themesFolder, '\"')) StrRemoveEncap(themesFolder);
        if (strchr(themesFolder, '$')) ReplaceShellFolders(themesFolder);
        if (strchr(themesFolder, '%')) ReplaceEnvVars(themesFolder);

        //====================

        strcpy(selectedTheme, ReadString(extrcDefaultFile, "xoblite.selected.theme:", "<Default>"));
        strcpy(pluginsRepository, ReadString(extrcDefaultFile, "xoblite.plugins.repository:", "http://xoblite.net/plugins.txt"));
        slimlineMetrics = ReadBool(extrcDefaultFile, "xoblite.slimline.metrics:", false);
        followActive = ReadBool(extrcDefaultFile, "xoblite.tasks.followActive:", true);
        disableRootCommands = ReadBool(extrcDefaultFile, "xoblite.disable.rootCommands:", false);
        runStartupApps = ReadBool(extrcDefaultFile, "xoblite.startup.programs:", true);

        strcpy(preferredEditor, ReadString(extrcDefaultFile, "xoblite.editor:", "notepad.exe"));
        if (strchr(preferredEditor, '$')) ReplaceShellFolders(preferredEditor);
        if (strchr(preferredEditor, '%')) ReplaceEnvVars(preferredEditor);

        strcpy(checkedForUpdates, ReadString(extrcDefaultFile, "xoblite.checked.for.updates:", "#001 / 2005-01-01"));

        debugLogging = ReadBool(extrcDefaultFile, "xoblite.debug:", false);

        //====================

        coreReadingToBuffer = false;
}

//===========================================================================

void Settings::WriteDefaultMenu()
{
        DWORD retLength=0;
        char temp[MAX_LINE_LENGTH];

        // NOTE: We do not need to check if the file exists or not, because if
        // it does not then there is no issue, and if it exists this function
        // is called from MenuMaker because the current menu file is
        // considered invalid (= it does not contain a [begin]), and the user
        // wants it replaced by the default menu

        HANDLE f = CreateFile(menuFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
        if (f)
        {
                strcpy(temp,
                        "[begin] ()\r\n"
                        "\t[exec] (explorer) {explorer.exe /e,c:\\}\r\n"
                        "\t[path] (start) {\"$StartMenu$\"|\"$CommonStartMenu$\"}\r\n"
                        "\t[submenu] (xoblite)\r\n"
                        "\t\t[exec] (about...) {$Blackbox$\\Blackbox.exe -about}\r\n"
                        "\t\t[submenu] (documentation)\r\n"
                        "\t\t\t[exec] (readme) {$Blackbox$\\docs\\readme.txt}\r\n"
                        "\t\t\t[exec] (online docs) {http://xoblite.net/docs/}\r\n"
                        "\t\t\t[exec] (license) {http://xoblite.net/license.html}\r\n"
                        "\t\t[end]\r\n"
                        "\t\t[config] (configuration)\r\n"
                        "\t\t[stylesmenu] (styles) {$Blackbox$\\styles}\r\n"
                        "\t\t[editstyle] (edit current style)\r\n"
                        "\t\t[editmenu] (edit menu.rc)\r\n");
                WriteFile(f, temp, strlen(temp), &retLength, NULL);
                strcpy(temp,
                        "\t\t[editextensions] (edit extensions.rc)\r\n"
                        "\t\t[editblackbox] (edit blackbox.rc)\r\n"
                        "\t\t[restart] (restart)\r\n"
                        "\t\t[reconfig] (reconfigure)\r\n"
                        "\t\t[exit] (quit)\r\n"
                        "\t[end]\r\n"
                        "\t[submenu] (shutdown menu)\r\n"
                        "\t\t[lockworkstation] (lock workstation)\r\n"
                        "\t\t[shutdown] (shutdown)\r\n"
                        "\t\t[reboot] (reboot)\r\n"
                        "\t\t[logoff] (log off)\r\n"
                        "\t\t[hibernate] (hibernate)\r\n"
                        "\t\t[suspend] (suspend)\r\n"
                        "\t[end]\r\n"
                        "[end]\r\n");
                WriteFile(f, temp, strlen(temp), &retLength, NULL);
        }

        CloseHandle(f);
}

//===========================================================================

void Settings::ReadStyleSettings()
{
        coreReadingToBuffer = true;
        char temp[MAX_LINE_LENGTH];

        // Should we use the new bb4nix 0.70 syntax?
        bool bb4nix070syntax;
        strcpy(temp, ReadString(styleFile, "menu.title.appearance:", "NotDefined"));
        if (!stricmp(temp, "NotDefined")) bb4nix070syntax = false;
        else bb4nix070syntax = true;

        DeleteStyleItems();

        //====================

        // Wildcard settings (not fully implemented yet...)
        strcpy(temp, ReadString(styleFile, "*.font:", "Tahoma"));
        strcpy(wildcardFont, ReadString(styleFile, "*font:", temp));
        strcpy(wildcardToolbarFont, ReadString(styleFile, "toolbar*font:", wildcardFont));
        strcpy(wildcardMenuFont, ReadString(styleFile, "menu*font:", wildcardFont));
//      strcpy(wildcardWindowFont, ReadString(styleFile, "window*font:", wildcardFont));

        strcpy(temp, ReadString(styleFile, "*.textColor:", "#b0b0b0"));
        strcpy(wildcardTextColorString, ReadString(styleFile, "*textColor:", temp));
        wildcardTextColor = GetColor(styleFile, "*textColor:", temp, NULL, false);

        if (bb4nix070syntax)
        {
                strcpy(temp, ReadString(styleFile, "*.alignment:", "Center"));
                strcpy(wildcardJustify, ReadString(styleFile, "*alignment:", temp));
        }
        else
        {
                strcpy(temp, ReadString(styleFile, "*.justify:", "Center"));
                strcpy(wildcardJustify, ReadString(styleFile, "*justify:", temp));
        }

        //====================

        // Miscellaneous resources

        // Border (can be drawn round all components)
        borderWidth = GetInt(styleFile, "borderWidth:", 1); // For all parent elements
        wildcardBorderWidth = GetInt(styleFile, "*.borderWidth:", 0);
        wildcardBorderWidth = GetInt(styleFile, "*borderWidth:", wildcardBorderWidth); // For all non-parent elements

        borderColor = GetColor(styleFile, "borderColor:", NULL, 0x000000, true);
        wildcardBorderColor = GetColor(styleFile, "*.borderColor:", NULL, borderColor, true);
        wildcardBorderColor = GetColor(styleFile, "*borderColor:", NULL, wildcardBorderColor, true);

        bevelWidth = GetInt(styleFile, "bevelWidth:", 1);
        marginWidth = GetInt(styleFile, "marginWidth:", 0);
        handleWidth = GetInt(styleFile, "handleWidth:", 5);

        // Width of the window frame (from version 0.61 on)
        // When not specified, frameWidth defaults to the value of bevelWidth
        frameWidth = GetInt(styleFile, "frameWidth:", bevelWidth);

        // This command is executed whenever the style is selected,
        // typically setting the wallpaper (e.g. using bsetroot)
        strcpy(rootCommand, ReadString(styleFile, "rootCommand:", ""));
        if (strchr(rootCommand, '$')) ReplaceShellFolders(rootCommand);

        //====================

        // Toolbar background
        Toolbar = new StyleItem;
        strcpy(toolbar, "Flat Gradient Vertical");
        appearancePointer = toolbar;
        Toolbar->Color = 0x303030;
        Toolbar->ColorTo = 0x000000;
        Toolbar->TextColor = wildcardTextColor;
        Toolbar->borderColor = wildcardBorderColor;
        Toolbar->borderWidth = borderWidth;
        strcpy(Toolbar->Font, wildcardToolbarFont);
        Toolbar->FontHeight = 12;
        ReadStyleElement(styleFile, Toolbar, "toolbar", bb4nix070syntax, true);

        if (slimlineMetrics && (Toolbar->FontHeight > 12)) Toolbar->FontHeight = 12;

        //====================

        // Toolbar workspace label
        ToolbarLabel = new StyleItem;
        strcpy(toolbarLabel, "parentrelative");
        appearancePointer = toolbarLabel;
        ToolbarLabel->Color = 0x303030;
        ToolbarLabel->ColorTo = 0x000000;
        ToolbarLabel->TextColor = Toolbar->TextColor;
        ToolbarLabel->borderColor = Toolbar->borderColor;
        ToolbarLabel->borderWidth = wildcardBorderWidth;
        strcpy(ToolbarLabel->Font, Toolbar->Font);
        ToolbarLabel->FontHeight = Toolbar->FontHeight;
        ReadStyleElement(styleFile, ToolbarLabel, "toolbar.label", bb4nix070syntax, true);

        if (slimlineMetrics && (ToolbarLabel->FontHeight > 12)) ToolbarLabel->FontHeight = 12;

        //====================

        // Toolbar window label
        if (bb4nix070syntax) strcpy(temp, ReadString(styleFile, "toolbar.windowLabel.appearance:", ""));
        else strcpy(temp, ReadString(styleFile, "toolbar.windowLabel:", ""));

        ToolbarWindowLabel = new StyleItem;

        if (strlen(temp))
        {
                strcpy(toolbarWindowLabel, "Sunken Gradient Vertical");
                appearancePointer = toolbarWindowLabel;
                ToolbarWindowLabel->Color = 0x000000;
                ToolbarWindowLabel->ColorTo = 0x202020;
                ToolbarWindowLabel->TextColor = Toolbar->TextColor;
                ToolbarWindowLabel->borderColor = Toolbar->borderColor;
                ToolbarWindowLabel->borderWidth = wildcardBorderWidth;
                strcpy(ToolbarWindowLabel->Font, Toolbar->Font);
                ToolbarWindowLabel->FontHeight = Toolbar->FontHeight;
                ReadStyleElement(styleFile, ToolbarWindowLabel, "toolbar.windowLabel", bb4nix070syntax, true);
        }
        else
        {
                // Use workspace label settings if window label
                // isn't defined (applicable to some 0.5x styles)
                strcpy(toolbarWindowLabel, toolbarLabel);
                CopyMemory(ToolbarWindowLabel, ToolbarLabel, sizeof(StyleItem));
        }

        if (slimlineMetrics && (ToolbarWindowLabel->FontHeight > 12)) ToolbarWindowLabel->FontHeight = 12;

        //====================

        // Toolbar clock
        ToolbarClock = new StyleItem;
        strcpy(toolbarClock, "parentrelative");
        appearancePointer = toolbarClock;
        ToolbarClock->Color = 0x303030;
        ToolbarClock->ColorTo = 0x000000;
        ToolbarClock->TextColor = Toolbar->TextColor;
        ToolbarClock->borderColor = Toolbar->borderColor;
        ToolbarClock->borderWidth = wildcardBorderWidth;
        strcpy(ToolbarClock->Font, Toolbar->Font);
        ToolbarClock->FontHeight = Toolbar->FontHeight;
        ReadStyleElement(styleFile, ToolbarClock, "toolbar.clock", bb4nix070syntax, true);

        if (slimlineMetrics && (ToolbarClock->FontHeight > 12)) ToolbarClock->FontHeight = 12;

        //====================

        // Toolbar text
        if (!strlen(ReadString(styleFile, "toolbar.textColor:", "")))
        {
                if (!strlen(ReadString(styleFile, "*textColor:", "")))
                {
                        if (ToolbarWindowLabel->parentRelative) Toolbar->TextColor = ToolbarWindowLabel->TextColor;
                        else if (ToolbarLabel->parentRelative) Toolbar->TextColor = ToolbarLabel->TextColor;
                        else if (ToolbarClock->parentRelative) Toolbar->TextColor = ToolbarClock->TextColor;
                        else Toolbar->TextColor = ToolbarWindowLabel->TextColor;
                }
                else Toolbar->TextColor = GetColor(styleFile, "*textColor:", NULL, wildcardTextColor, true);
        }
        else Toolbar->TextColor = GetColor(styleFile, "toolbar.textColor:", NULL, wildcardTextColor, true);

//      if (toolbarFontHeight > 12) Toolbar->FontHeight = toolbarFontHeight = 12;

        //====================

        // Toolbar buttons
        ToolbarButton = new StyleItem;
        strcpy(toolbarButton, "Flat Gradient Vertical");
        appearancePointer = toolbarButton;
        ToolbarButton->Color = 0x303030;
        ToolbarButton->ColorTo = 0x000000;
        ToolbarButton->borderColor = Toolbar->borderColor;
        ToolbarButton->borderWidth = wildcardBorderWidth;
        ReadStyleElement(styleFile, ToolbarButton, "toolbar.button", bb4nix070syntax, false);

        //====================

        // Toolbar button arrows
        if (bb4nix070syntax)
        {
                strcpy(temp, ReadString(styleFile, "toolbar.button.foregroundColor:", "#707070"));
                ToolbarButton->PicColor = GetColor(styleFile, "toolbar.button.picColor:", temp, NULL, false);
        }
        else ToolbarButton->PicColor = GetColor(styleFile, "toolbar.button.picColor:", NULL, 0x707070, true);

        //====================

        // Toolbar buttons in pressed state
        ToolbarButtonPressed = new StyleItem;
        strcpy(toolbarButtonPressed, "Flat Gradient Vertical");
        appearancePointer = toolbarButtonPressed;
        ToolbarButtonPressed->Color = 0x606060;
        ToolbarButtonPressed->ColorTo = 0x303030;
        ToolbarButtonPressed->borderColor = Toolbar->borderColor;
        ToolbarButtonPressed->borderWidth = wildcardBorderWidth;
        ReadStyleElement(styleFile, ToolbarButtonPressed, "toolbar.button.pressed", bb4nix070syntax, false);

        //====================

        // Toolbar button arrows in pressed state
        if (bb4nix070syntax)
        {
                strcpy(temp, ReadString(styleFile, "toolbar.button.pressed.foregroundColor:", "#707070"));
                ToolbarButtonPressed->PicColor = GetColor(styleFile, "toolbar.button.pressed.picColor:", temp, NULL, false);
        }
        else
        {
                if (strlen(ReadString(styleFile, "toolbar.button.pressed.picColor:", "")))
                        ToolbarButtonPressed->PicColor = GetColor(styleFile, "toolbar.button.pressed.picColor:", NULL, 0x707070, true);
                else
                        ToolbarButtonPressed->PicColor = ToolbarButton->PicColor;
        }

        //====================

        menuBorderColor = GetColor(styleFile, "menu.borderColor:", NULL, wildcardBorderColor, true);
        menuBorderWidth = ReadInt(styleFile, "menu.borderWidth:", borderWidth);

        // Menu titlebar
        MenuTitle = new StyleItem;
        strcpy(menuTitle, "Flat Gradient CrossDiagonal");
        appearancePointer = menuTitle;
        MenuTitle->Color = 0x000000;
        MenuTitle->ColorTo = 0x808080;
        MenuTitle->TextColor = wildcardTextColor;
        MenuTitle->borderColor = menuBorderColor;
        MenuTitle->borderWidth = menuBorderWidth;
        strcpy(MenuTitle->Font, wildcardMenuFont);
        MenuTitle->FontHeight = 12;
        ReadStyleElement(styleFile, MenuTitle, "menu.title", bb4nix070syntax, true);

        if (slimlineMetrics && (MenuTitle->FontHeight > 12)) MenuTitle->FontHeight = 12;

        //====================

        // Menu frame
        MenuFrame = new StyleItem;
        strcpy(menuFrame, "Flat Gradient Horizontal");
        appearancePointer = menuFrame;
        MenuFrame->Color = 0x404040;
        MenuFrame->ColorTo = 0x000000;
        MenuFrame->TextColor = wildcardTextColor;
        MenuFrame->borderColor = menuBorderColor;
        MenuFrame->borderWidth = menuBorderWidth;
        strcpy(MenuFrame->Font, wildcardMenuFont);
        MenuFrame->FontHeight = 12;
        ReadStyleElement(styleFile, MenuFrame, "menu.frame", bb4nix070syntax, true);

        menuFrameDisableColor = GetColor(styleFile, "menu.frame.disableColor:", "black", NULL, false);

        if (slimlineMetrics && (MenuFrame->FontHeight > 12)) MenuFrame->FontHeight = 12;

        //====================

        // Highlighted/active menu items
        MenuHilite = new StyleItem;
        strcpy(menuHilite, "Raised Gradient Vertical");
        appearancePointer = menuHilite;
        MenuHilite->Color = 0x303030;
        MenuHilite->ColorTo = 0x808080;
        MenuHilite->TextColor = MenuFrame->TextColor;
        MenuHilite->borderColor = MenuFrame->borderColor;
        MenuHilite->borderWidth = wildcardBorderWidth;
        strcpy(MenuHilite->Font, MenuFrame->Font);
        MenuHilite->FontHeight = MenuFrame->FontHeight;
        if (bb4nix070syntax) ReadStyleElement(styleFile, MenuHilite, "menu.active", bb4nix070syntax, true);
        else ReadStyleElement(styleFile, MenuHilite, "menu.hilite", bb4nix070syntax, true);

        if (MenuHilite->parentRelative)
        {
                MenuHilite->Color = MenuFrame->Color;
                MenuHilite->ColorTo = MenuFrame->ColorTo;
                MenuHilite->type = 255; // Quick'n'dirty hack to support menu.hilite being parentrelative (see GradientPainter::Paint and MenuMaker::MakePainter for more)
        }

        //====================

        // Submenu bullets
//      strcpy(menuBullet, ReadString(styleFile, "menu.bullet:", "Square"));
        strcpy(menuBullet, ReadString(styleFile, "menu.bullet:", "Triangle"));
        strcpy(menuBulletPosition, ReadString(styleFile, "menu.bullet.position:", "Right"));

        if (bb4nix070syntax)
        {
                COLORREF tempColor;
                tempColor = GetColor(styleFile, "menu.frame.foregroundColor:", NULL, MenuFrame->TextColor, true);
                menuFrameBulletColor = GetColor(styleFile, "menu.frame.bulletColor:", NULL, tempColor, true);
                tempColor = GetColor(styleFile, "menu.active.foregroundColor:", NULL, MenuHilite->TextColor, true);
                menuHiliteBulletColor = GetColor(styleFile, "menu.active.bulletColor:", NULL, tempColor, true);
        }
        else
        {
                menuFrameBulletColor = GetColor(styleFile, "menu.frame.bulletColor:", NULL, MenuFrame->TextColor, true);
                menuHiliteBulletColor = GetColor(styleFile, "menu.hilite.bulletColor:", NULL, MenuHilite->TextColor, true);
        }

        //====================

        Slit = new StyleItem;
        strcpy(slit, toolbar);
        appearancePointer = slit;
        Slit->Color = Toolbar->Color;
        Slit->ColorTo = Toolbar->ColorTo;
        Slit->borderColor = Toolbar->borderColor;
        Slit->borderWidth = Toolbar->borderWidth;
        ReadStyleElement(styleFile, Slit, "slit", bb4nix070syntax, false);

        //====================

        // Window style parameters are not used by nor cached by the core...

        //====================

        // Taskbar resources

        ActiveTask = new StyleItem;

        if (!ToolbarWindowLabel->parentRelative)
        {
                CopyMemory(ActiveTask, ToolbarWindowLabel, sizeof(StyleItem));
                if (ActiveTask->type == B_ELLIPTIC) activeTaskShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->Color, ToolbarWindowLabel->TextColor);
                else activeTaskShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->Color, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->TextColor);
        }
        else if (!ToolbarLabel->parentRelative)
        {
                CopyMemory(ActiveTask, ToolbarLabel, sizeof(StyleItem));
                if (ActiveTask->type == B_ELLIPTIC) activeTaskShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->ColorTo, ToolbarLabel->Color, ToolbarLabel->TextColor);
                else activeTaskShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->Color, ToolbarLabel->ColorTo, ToolbarLabel->TextColor);
        }
        else if (!ToolbarClock->parentRelative)
        {
                CopyMemory(ActiveTask, ToolbarClock, sizeof(StyleItem));
                if (ActiveTask->type == B_ELLIPTIC) activeTaskShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->ColorTo, ToolbarClock->Color, ToolbarClock->TextColor);
                else activeTaskShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->Color, ToolbarClock->ColorTo, ToolbarClock->TextColor);
        }
        else
        {
                CopyMemory(ActiveTask, Toolbar, sizeof(StyleItem));
                ActiveTask->TextColor = ToolbarWindowLabel->TextColor;
                if (ActiveTask->type == B_ELLIPTIC) activeTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->ColorTo, Toolbar->Color, ToolbarWindowLabel->TextColor);
                else activeTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
        }

        InactiveTask = new StyleItem;
        CopyMemory(InactiveTask, Toolbar, sizeof(StyleItem));

        if (ToolbarWindowLabel->parentRelative)
        {
                InactiveTask->TextColor = ToolbarWindowLabel->TextColor;
                inactiveTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
        }
        else if (ToolbarLabel->parentRelative)
        {
                InactiveTask->TextColor = ToolbarLabel->TextColor;
                inactiveTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarLabel->TextColor);
        }
        else if (ToolbarClock->parentRelative)
        {
                InactiveTask->TextColor = ToolbarClock->TextColor;
                inactiveTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarClock->TextColor);
        }
        else if (ToolbarButton->parentRelative)
        {
                InactiveTask->TextColor = ToolbarButton->PicColor;
                inactiveTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarButton->PicColor);
        }
        else
        {
                InactiveTask->TextColor = Toolbar->TextColor;
                inactiveTaskShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, Toolbar->TextColor);
        }

        //====================

        BYTE red, green, blue;
        FlashingTask = new StyleItem;

/*
        // Using the same colours as for the xobloon notifications...
        red = GetRValue(ActiveTask->Color);
        green = GetGValue(ActiveTask->Color);
        blue = GetBValue(ActiveTask->Color);
//      FlashingTask->Color = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//      FlashingTask->Color = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
        FlashingTask->Color = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//      FlashingTask->Color = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        red = GetRValue(ActiveTask->ColorTo);
        green = GetGValue(ActiveTask->ColorTo);
        blue = GetBValue(ActiveTask->ColorTo);
//      FlashingTask->ColorTo = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//      FlashingTask->ColorTo = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
        FlashingTask->ColorTo = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//      FlashingTask->ColorTo = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        red = GetRValue(ActiveTask->TextColor);
        green = GetGValue(ActiveTask->TextColor);
        blue = GetBValue(ActiveTask->TextColor);
//      FlashingTask->TextColor = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//      FlashingTask->TextColor = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
        FlashingTask->TextColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//      FlashingTask->TextColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        red = GetRValue(activeTaskShadowColor);
        green = GetGValue(activeTaskShadowColor);
        blue = GetBValue(activeTaskShadowColor);
//      flashingTaskShadowColor = RGB((BYTE)blue, (BYTE)red, (BYTE)green);
//      flashingTaskShadowColor = RGB((BYTE)green, (BYTE)blue, (BYTE)red);
        flashingTaskShadowColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
//      flashingTaskShadowColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
*/
        // Using an inverted variation of the xobloon notification colours...
        red = 0xff - GetRValue(ActiveTask->ColorTo);
        green = 0xff - GetGValue(ActiveTask->ColorTo);
        blue = 0xff - GetBValue(ActiveTask->ColorTo);
        FlashingTask->Color = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(ActiveTask->Color);
        green = 0xff - GetGValue(ActiveTask->Color);
        blue = 0xff - GetBValue(ActiveTask->Color);
        FlashingTask->ColorTo = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(ActiveTask->TextColor);
        green = 0xff - GetGValue(ActiveTask->TextColor);
        blue = 0xff - GetBValue(ActiveTask->TextColor);
        FlashingTask->TextColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(activeTaskShadowColor);
        green = 0xff - GetGValue(activeTaskShadowColor);
        blue = 0xff - GetBValue(activeTaskShadowColor);
        flashingTaskShadowColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
/*
        // Invert the inactive task button and border colours for the flashing button...
        red = 0xff - GetRValue(InactiveTask->ColorTo);
        green = 0xff - GetGValue(InactiveTask->ColorTo);
        blue = 0xff - GetBValue(InactiveTask->ColorTo);
//      FlashingTask->Color = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        FlashingTask->Color = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(InactiveTask->Color);
        green = 0xff - GetGValue(InactiveTask->Color);
        blue = 0xff - GetBValue(InactiveTask->Color);
//      FlashingTask->ColorTo = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        FlashingTask->ColorTo = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(InactiveTask->TextColor);
        green = 0xff - GetGValue(InactiveTask->TextColor);
        blue = 0xff - GetBValue(InactiveTask->TextColor);
//      FlashingTask->TextColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        FlashingTask->TextColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
        red = 0xff - GetRValue(inactiveTaskShadowColor);
        green = 0xff - GetGValue(inactiveTaskShadowColor);
        blue = 0xff - GetBValue(inactiveTaskShadowColor);
//      flashingTaskShadowColor = RGB((BYTE)red, (BYTE)green, (BYTE)blue);
        flashingTaskShadowColor = RGB((BYTE)blue, (BYTE)green, (BYTE)red);
*/
        //====================

        // Menu indicators for boolean items (introduced in xoblite bb1)
        MenuIndicator = new StyleItem;
        if (MenuHilite->parentRelative)
        {
                CopyMemory(MenuIndicator, MenuTitle, sizeof(StyleItem));
                strcpy(menuIndicator, menuTitle);
        }
        else
        {
                CopyMemory(MenuIndicator, MenuHilite, sizeof(StyleItem));
                strcpy(menuIndicator, menuHilite);
        }
        appearancePointer = menuIndicator;
        ReadStyleElement(styleFile, MenuIndicator, "menu.indicator", bb4nix070syntax, false);

        // Menu separators (introduced in xoblite bb2)
        if (bb4nix070syntax) menuSeparatorColor = GetColor(styleFile, "menu.separator.foregroundColor:", NULL, MenuFrame->TextColor, true);
        else menuSeparatorColor = GetColor(styleFile, "menu.separator.color:", NULL, MenuFrame->TextColor, true);

        // Text shadows (introduced in xoblite bb2)
        if (forceFontShadows)
        {
                MenuTitle->FontShadow = MenuFrame->FontShadow = MenuHilite->FontShadow = true;
                ToolbarLabel->FontShadow = ToolbarWindowLabel->FontShadow = ToolbarClock->FontShadow = true;
                ActiveTask->FontShadow = InactiveTask->FontShadow = true;
        }

        if (ToolbarLabel->parentRelative) toolbarLabelShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarLabel->TextColor);
        else toolbarLabelShadowColor = CreateShadowColor(ToolbarLabel, ToolbarLabel->Color, ToolbarLabel->ColorTo, ToolbarLabel->TextColor);
        if (ToolbarWindowLabel->parentRelative) toolbarWindowLabelShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarWindowLabel->TextColor);
        else toolbarWindowLabelShadowColor = CreateShadowColor(ToolbarWindowLabel, ToolbarWindowLabel->Color, ToolbarWindowLabel->ColorTo, ToolbarWindowLabel->TextColor);
        if (ToolbarClock->parentRelative) toolbarClockShadowColor = CreateShadowColor(Toolbar, Toolbar->Color, Toolbar->ColorTo, ToolbarClock->TextColor);
        else toolbarClockShadowColor = CreateShadowColor(ToolbarClock, ToolbarClock->Color, ToolbarClock->ColorTo, ToolbarClock->TextColor);

        menuTitleShadowColor = CreateShadowColor(MenuTitle, MenuTitle->Color, MenuTitle->ColorTo, MenuTitle->TextColor);
        menuFrameShadowColor = CreateShadowColor(MenuFrame, MenuFrame->Color, MenuFrame->ColorTo, MenuFrame->TextColor);
        if (MenuHilite->parentRelative) menuHiliteShadowColor = CreateShadowColor(MenuFrame, MenuFrame->Color, MenuFrame->ColorTo, MenuHilite->TextColor);
        else menuHiliteShadowColor = CreateShadowColor(MenuHilite, MenuHilite->Color, MenuHilite->ColorTo, MenuHilite->TextColor);

        //====================

        // Old style settings (for compatibility only - not for general use - pending for removal!)

        if (strlen(ReadString(styleFile, "menuFont:", "")))
        {
                strcpy(MenuFrame->Font, ReadString(styleFile, "menuFont:", MenuFrame->Font));
                CheckFontSubstitution(MenuFrame->Font);
        }

        if (strlen(ReadString(styleFile, "titleFont:", "")))
        {
                strcpy(MenuTitle->Font, ReadString(styleFile, "titleFont:", MenuTitle->Font));
                CheckFontSubstitution(MenuTitle->Font);
        }

        if (strlen(ReadString(styleFile, "menuJustify:", "")))
                strcpy(menuFrameJustify, ReadString(styleFile, "menuJustify:", menuFrameJustify));
        
        if (strlen(ReadString(styleFile, "titleJustify:", "")))
                strcpy(menuTitleJustify, ReadString(styleFile, "titleJustify:", menuTitleJustify));

        if (strlen(ReadString(styleFile, "menu.frame.highlightColor:", "")))
        {
                MenuHilite->Color = GetColor(styleFile, "menu.frame.highlightColor:", "#303030", NULL, false);
                MenuHilite->ColorTo = MenuHilite->Color;
        }

        if (strlen(ReadString(styleFile, "menu.frame.hiTextColor:", "")))
                MenuHilite->TextColor = GetColor(styleFile, "menu.frame.hiTextColor:", NULL, wildcardTextColor, true);

        if (strlen(ReadString(styleFile, "menu.bulletStyle:", "")))
                strcpy(menuBullet, ReadString(styleFile, "menu.bulletStyle:", menuBullet));

        if (strlen(ReadString(styleFile, "menu.bulletPosition:", "")))
                strcpy(menuBulletPosition, ReadString(styleFile, "menu.bulletPosition:", menuBulletPosition));

        //====================

        coreReadingToBuffer = false;
}

//===========================================================================

void Settings::ReadStyleElement(LPSTR styleFile, StyleItem* styleItem, LPSTR paramString, bool bb4nix070syntax, bool readFont)
{
        char temp[MAX_LINE_LENGTH], param[MAX_LINE_LENGTH];

        strcpy(param, paramString);
        int nLen = strlen(param);

        //====================

        // Appearance (solid/gradient, bevel type, etc)
        if (bb4nix070syntax) strcpy(&param[nLen], ".appearance:");
        else strcpy(&param[nLen], ":");
        strcpy(temp, ReadString(styleFile, param, appearancePointer));
        ParseItem(temp, styleItem);
        // Save appearance string (used by caching mechanism)
        strcpy(appearancePointer, temp);

        //====================

        // Border
        strcpy(&param[nLen], ".borderColor:");
        styleItem->borderColor = GetColor(styleFile, param, NULL, styleItem->borderColor, true);
        strcpy(&param[nLen], ".borderWidth:");
        styleItem->borderWidth = ReadInt(styleFile, param, styleItem->borderWidth);

        if (bb4nix070syntax)
        {
                if (IsInString(temp, "border"))
                {
                        styleItem->bordered = true;
                        if (styleItem->borderWidth == 0) styleItem->borderWidth = borderWidth;
                }
                else
                {
                        styleItem->bordered = false;
                        styleItem->borderWidth = 0;
                }
        }
        else
        {
                if (styleItem->borderWidth > 0) styleItem->bordered = true;
                else styleItem->bordered = false;
        }

        //====================

        // Margin
        strcpy(&param[nLen], ".marginWidth:");
        styleItem->marginWidth = GetInt(styleFile, param, marginWidth);

        //====================

        // Colours
/*
        // ##### VERSION 1: MIXING OF SYNTAXES NOT ALLOWED #####

        if (bb4nix070syntax)
        {
                if ((styleItem->type != B_SOLID) || ((styleItem->type == B_SOLID) && styleItem->interlaced))
                {
                        // Gradients or interlaced solids...
                        strcpy(&param[nLen], ".color1:");
                        styleItem->Color = GetColor(styleFile, param, NULL, styleItem->Color, true);
                        strcpy(&param[nLen], ".color2:");
                        styleItem->ColorTo = GetColor(styleFile, param, NULL, styleItem->ColorTo, true);
                }
                else
                {
                        // Non-interlaced solids...
                        // (also checking the erroneous "color" param
                        // for compatibility with flawed styles...)
                        COLORREF tempColor;
                        strcpy(&param[nLen], ".color:");
                        tempColor = GetColor(styleFile, param, NULL, styleItem->Color, true);
                        strcpy(&param[nLen], ".backgroundColor:");
                        styleItem->Color = GetColor(styleFile, param, NULL, tempColor, true);
                        styleItem->ColorTo = styleItem->Color;
                }
        }
        else
        {
                // The good old Blackbox 0.65 syntax... =]
                strcpy(&param[nLen], ".color:");
                styleItem->Color = GetColor(styleFile, param, NULL, styleItem->Color, true);
                strcpy(&param[nLen], ".colorTo:");
                styleItem->ColorTo = GetColor(styleFile, param, NULL, styleItem->ColorTo, true);
        }
*/
        // ##### VERSION 2: MIXING OF SYNTAXES ALLOWED #####

        COLORREF tempColor;

        strcpy(&param[nLen], ".backgroundColor:");
        tempColor = GetColor(styleFile, param, NULL, styleItem->Color, true);
        strcpy(&param[nLen], ".color1:");
        tempColor = GetColor(styleFile, param, NULL, tempColor, true);
        strcpy(&param[nLen], ".color:");
        styleItem->Color = GetColor(styleFile, param, NULL, tempColor, true);

        if (styleItem->type == B_SOLID) styleItem->ColorTo = styleItem->Color;
        else
        {
                strcpy(&param[nLen], ".color2:");
                tempColor = GetColor(styleFile, param, NULL, styleItem->ColorTo, true);
                strcpy(&param[nLen], ".colorTo:");
                styleItem->ColorTo = GetColor(styleFile, param, NULL, tempColor, true);
        }

        strcpy(&param[nLen], ".textColor:");
        styleItem->TextColor = GetColor(styleFile, param, NULL, styleItem->TextColor, true);
/*
        if (bb4nix070syntax)
        {
                // "menu.frame.foregroundColor -> bitmap color for checks and submenu-arrows"
                strcpy(&param[nLen], ".foregroundColor:");
                styleItem->foregroundColor = GetColor(styleFile, param, NULL, styleItem->TextColor, true);

                // "menu.frame.disabledColor -> disabled text color"
                strcpy(&param[nLen], ".disabledColor:");
                styleItem->foregroundColor = GetColor(styleFile, param, NULL, styleItem->TextColor, true);
        }
*/
        //====================

        if (readFont)
        {
                // Font name/size/weight/shadow
                strcpy(&param[nLen], ".font:");
                strcpy(temp, ReadString(styleFile, param, styleItem->Font));
                if (strchr(temp, '/'))
                {
                        ParseFontString(temp, styleItem);
                }
                else
                {
                        CheckFontSubstitution(temp);
                        strcpy(styleItem->Font, temp);

                        strcpy(&param[nLen], ".fontHeight:");
                        styleItem->FontHeight = ReadInt(styleFile, param, styleItem->FontHeight);

                        strcpy(&param[nLen], ".fontWeight:");
                        strcpy(temp, ReadString(styleFile, param, "Normal"));
                        if (IsInString(temp, "Bold")) styleItem->FontWeight = FW_BOLD;
                        else styleItem->FontWeight = FW_NORMAL;

                        if (IsInString(temp, "Shadow")) styleItem->FontShadow = true;
                        else styleItem->FontShadow = false;
                }

                //====================

                // Text alignment/justify
                if (bb4nix070syntax) strcpy(&param[nLen], ".alignment:");
                else strcpy(&param[nLen], ".justify:");
                strcpy(temp, ReadString(styleFile, param, wildcardJustify));
                if (IsInString(temp, "Left")) styleItem->Justify = DT_LEFT;
                else if (IsInString(temp, "Right")) styleItem->Justify = DT_RIGHT;
                else styleItem->Justify = DT_CENTER;
        }
}

//===========================================================================

COLORREF Settings::CreateShadowColor(StyleItem* styleItem, COLORREF color, COLORREF colorTo, COLORREF textColor)
{
        BYTE r = GetRValue(color);
        BYTE g = GetGValue(color);
        BYTE b = GetBValue(color);
        BYTE rto = GetRValue(colorTo);
        BYTE gto = GetGValue(colorTo);
        BYTE bto = GetBValue(colorTo);

        int rav, gav, bav;
        
        if (styleItem->type != B_SOLID)
        {
                rav = (r+rto) / 2;
                gav = (g+gto) / 2;
                bav = (b+bto) / 2;
        }
        else
        {
                rav = r;
                gav = g;
                bav = b;
        }

        if (rav < 0x10) rav = 0;
        else rav -= 0x10;
        if (gav < 0x10) gav = 0;
        else gav -= 0x10;
        if (bav < 0x10) bav = 0;
        else bav -= 0x10;

        return RGB((BYTE)rav, (BYTE)gav, (BYTE)bav);
}

//===========================================================================

void Settings::GetShellFolders()
{
        // Get the Blackbox folder path...
        GetBlackboxPath(SF_blackboxPath, MAX_PATH);
        // ...and remove the "\" at the end to be consistent with what SHGetFolderPath returns...
        SF_blackboxPath[strlen(SF_blackboxPath)-1] = 0;
/*
        SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 0, SF_startMenu);
        SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, SF_commonStartMenu);
        SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, SF_programFiles);
        SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, SF_desktop);
        SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, SF_userAppData);
*/
        SHGetSpecialFolderPath(NULL, SF_startMenu, CSIDL_PROGRAMS, 0);
        SHGetSpecialFolderPath(NULL, SF_commonStartMenu, CSIDL_COMMON_PROGRAMS, 0);
        SHGetSpecialFolderPath(NULL, SF_programFiles, CSIDL_PROGRAM_FILES, 0);
        SHGetSpecialFolderPath(NULL, SF_desktop, CSIDL_DESKTOPDIRECTORY, 0);
        SHGetSpecialFolderPath(NULL, SF_userAppData, CSIDL_APPDATA, 0);

        // Store the default theme path...
        strcpy(SF_currentThemePath, SF_blackboxPath); // Default theme
        usingDefaultTheme = true;

        // Find and store the path to the default extensions.rc file (some settings should always
        // be read from this file, e.g. preferred editor and AutoUpdate last checked date)
        extensionsrcPath();
        strcpy(extrcDefaultFile, extrcFile);
}

//===========================================================================

int Settings::GetInt(LPCSTR fp, LPCSTR szString, int szDefault)
{
        if (!coreReadingToBuffer && (!fp || !stricmp(fp, "") || !stricmp(fp, styleFile)))
        {
                if (!stricmp(szString, "borderWidth:")) return borderWidth;
                else if (!stricmp(szString, "bevelWidth:")) return bevelWidth;
                else if (!stricmp(szString, "handleWidth:")) return handleWidth;
                else if (!stricmp(szString, "frameWidth:")) return frameWidth;
                else if (!stricmp(szString, "toolbar.borderWidth:")) return Toolbar->borderWidth;
                else if (!stricmp(szString, "menu.borderWidth:")) return menuBorderWidth;
                else if (!stricmp(szString, "slit.borderWidth:")) return Slit->borderWidth;
                else if (!stricmp(szString, "toolbar.fontHeight:")) return Toolbar->FontHeight;
                else if (!stricmp(szString, "menu.title.fontHeight:")) return MenuTitle->FontHeight;
                else if (!stricmp(szString, "menu.frame.fontHeight:")) return MenuFrame->FontHeight;
        }

        //====================

        // If we can not find the value in the buffer, we fetch it from the file...
        LPSTR buffer = ReadValue(fp, szString, 0);
        if (!buffer) return szDefault;
        else
        {
                int value = 0;
                value = atoi(buffer);
                return value;
        }
}

//===========================================================================

LPSTR Settings::GetString(LPCSTR fp, LPCSTR szString, LPSTR szDefault)
{
        if (!coreReadingToBuffer && (!fp || !stricmp(fp, "") || !stricmp(fp, styleFile)))
        {
                //====================

                if (strchr(szString, '*')) // wildcard items
                {
                        if (!stricmp(szString, "*font:")) return wildcardFont;
                        else if (!stricmp(szString, "toolbar*font:")) return wildcardToolbarFont;
                        else if (!stricmp(szString, "menu*font:")) return wildcardMenuFont;
//                      else if (!stricmp(szString, "window*font:")) return wildcardWindowFont;
                        else if (!stricmp(szString, "*textColor:")) return wildcardTextColorString;
                        else if (!stricmp(szString, "*justify:")) return wildcardJustify;

                        else if (!stricmp(szString, "*.font:")) return wildcardFont;
                        else if (!stricmp(szString, "*.textColor:")) return wildcardTextColorString;
                        else if (!stricmp(szString, "*.justify:")) return wildcardJustify;
                }

                //====================

                else if (IsInString(szString, "toolbar")) // toolbar items
                {
                        if (!stricmp(szString, "toolbar:")) return toolbar;
                        else if (!stricmp(szString, "toolbar.label:")) return toolbarLabel;
                        else if (!stricmp(szString, "toolbar.windowLabel:")) return toolbarWindowLabel;
                        else if (!stricmp(szString, "toolbar.clock:")) return toolbarClock;
                        else if (!stricmp(szString, "toolbar.button:")) return toolbarButton;
                        else if (!stricmp(szString, "toolbar.button.pressed:")) return toolbarButtonPressed;
                        else if (!stricmp(szString, "toolbar.justify:")) return toolbarJustify;
                        else if (!stricmp(szString, "toolbar.font:")) return Toolbar->Font;
                }

                //====================

                else if (IsInString(szString, "menu."))
                {
                        if (szString[5] == 't') // menu title items
                        {
                                if (!stricmp(szString, "menu.title:")) return menuTitle;
                                else if (!stricmp(szString, "menu.title.font:")) return MenuTitle->Font;
                                else if (!stricmp(szString, "menu.title.justify:")) return menuTitleJustify;
                        }
                        else if (szString[5] == 'f') // menu frame items
                        {
                                if (!stricmp(szString, "menu.frame:")) return menuFrame;
                                else if (!stricmp(szString, "menu.frame.font:")) return MenuFrame->Font;
                                else if (!stricmp(szString, "menu.frame.justify:")) return menuFrameJustify;
                        }
                        else if (szString[5] == 'b') // menu bullet items
                        {
                                if (!stricmp(szString, "menu.bullet:")) return menuBullet;
                                else if (!stricmp(szString, "menu.bullet.position:")) return menuBulletPosition;
                        }
                        else if (!stricmp(szString, "menu.hilite:")) return menuHilite; // menu hilite items
                        else if (!stricmp(szString, "menu.indicator:")) return menuIndicator; // menu indicator items
                }

                //====================

                else if (IsInString(szString, "slit")) // slit items
                {
                        if (!stricmp(szString, "slit:")) return slit;
                }

                //====================

                // else if (IsInString(szString, "window.")) // window items
                // -> Window style parameters are not used by nor cached by the core...
        }

        //====================

        // If we can not find the value in the buffer, we fetch it from the file...
        LPSTR value = ReadValue(fp, szString, 0);
        if (value) return value;
        else return szDefault;
}

//===========================================================================

COLORREF Settings::GetColor(LPCSTR fp, LPCSTR szString, LPCSTR szDefault, COLORREF szDefaultRef, bool useDefaultRef)
{
        if (!coreReadingToBuffer && (!fp || !stricmp(fp, "") || !stricmp(fp, styleFile)))
        {
                //====================

                if (IsInString(szString, "toolbar."))
                {
                        if (szString[8] == 'c') // toolbar background and clock items
                        {
                                if (!stricmp(szString, "toolbar.color:")) return Toolbar->Color;
                                else if (!stricmp(szString, "toolbar.colorTo:")) return Toolbar->ColorTo;

                                else if (!stricmp(szString, "toolbar.clock.color:")) return ToolbarClock->Color;
                                else if (!stricmp(szString, "toolbar.clock.colorTo:")) return ToolbarClock->ColorTo;
                                else if (!stricmp(szString, "toolbar.clock.textColor:")) return ToolbarClock->TextColor;
                        }
                        if (szString[8] == 'l') // toolbar workspace label items
                        {
                                if (!stricmp(szString, "toolbar.label.color:")) return ToolbarLabel->Color;
                                else if (!stricmp(szString, "toolbar.label.colorTo:")) return ToolbarLabel->ColorTo;
                                else if (!stricmp(szString, "toolbar.label.textColor:")) return ToolbarLabel->TextColor;
                        }
                        if (szString[8] == 'w') // toolbar window label items
                        {
                                if (!stricmp(szString, "toolbar.windowLabel.color:")) return ToolbarWindowLabel->Color;
                                else if (!stricmp(szString, "toolbar.windowLabel.colorTo:")) return ToolbarWindowLabel->ColorTo;
                                else if (!stricmp(szString, "toolbar.windowLabel.textColor:")) return ToolbarWindowLabel->TextColor;
                        }
                        if (szString[8] == 'b') // toolbar button items + toolbar border
                        {
                                if (!stricmp(szString, "toolbar.button.color:")) return ToolbarButton->Color;
                                else if (!stricmp(szString, "toolbar.button.colorTo:")) return ToolbarButton->ColorTo;
                                else if (!stricmp(szString, "toolbar.button.picColor:")) return ToolbarButton->PicColor;

                                else if (!stricmp(szString, "toolbar.button.pressed.color:")) return ToolbarButtonPressed->Color;
                                else if (!stricmp(szString, "toolbar.button.pressed.colorTo:")) return ToolbarButtonPressed->ColorTo;
                                else if (!stricmp(szString, "toolbar.button.pressed.picColor:")) return ToolbarButtonPressed->PicColor;

                                else if (!stricmp(szString, "toolbar.borderColor:")) return Toolbar->borderColor;
                        }
                        else if (!stricmp(szString, "toolbar.textColor:")) return Toolbar->TextColor;
                }

                //====================

                else if (IsInString(szString, "menu."))
                {
                        if (szString[5] == 't') // menu title items
                        {
                                if (!stricmp(szString, "menu.title.color:")) return MenuTitle->Color;
                                else if (!stricmp(szString, "menu.title.colorTo:")) return MenuTitle->ColorTo;
                                else if (!stricmp(szString, "menu.title.textColor:")) return MenuTitle->TextColor;
                        }
                        else if (szString[5] == 'f') // menu frame items
                        {
                                if (!stricmp(szString, "menu.frame.color:")) return MenuFrame->Color;
                                else if (!stricmp(szString, "menu.frame.colorTo:")) return MenuFrame->ColorTo;
                                else if (!stricmp(szString, "menu.frame.textColor:")) return MenuFrame->TextColor;
                                else if (!stricmp(szString, "menu.frame.disableColor:")) return menuFrameDisableColor;
                                else if (!stricmp(szString, "menu.frame.bulletColor:")) return menuFrameBulletColor;
                        }
                        else if (szString[5] == 'h')  // menu hilite items
                        {
                                if (!stricmp(szString, "menu.hilite.color:")) return MenuHilite->Color;
                                else if (!stricmp(szString, "menu.hilite.colorTo:")) return MenuHilite->ColorTo;
                                else if (!stricmp(szString, "menu.hilite.textColor:")) return MenuHilite->TextColor;
                                else if (!stricmp(szString, "menu.hilite.bulletColor:")) return menuHiliteBulletColor;
                        }
                        else // menu indicator and separator items + menu border
                        {
                                if (!stricmp(szString, "menu.indicator.color:")) return MenuIndicator->Color;
                                else if (!stricmp(szString, "menu.indicator.colorTo:")) return MenuIndicator->ColorTo;
                                else if (!stricmp(szString, "menu.separator.color:")) return menuSeparatorColor;
                                else if (!stricmp(szString, "menu.borderColor:")) return menuBorderColor;
                        }
                }

                //====================

                if (IsInString(szString, "slit")) // slit items
                {
                        if (!stricmp(szString, "slit.color:")) return Slit->Color;
                        else if (!stricmp(szString, "slit.colorTo:")) return Slit->ColorTo;
                        else if (!stricmp(szString, "slit.borderColor:")) return Slit->borderColor;
                }

                //====================

                // else if (IsInString(szString, "window.")) // window items
                // -> Window style parameters are not used by nor cached by the core...

                //====================

                else if (!stricmp(szString, "borderColor:")) return borderColor;
        }

        //====================

        // If we could not find the value in
        // the buffer, we fetch it from the file...
        COLORREF value;
        char colorString[MAX_LINE_LENGTH];
        char tempString[MAX_LINE_LENGTH];
        char cr[4], cg[4], cb[4];

        LPSTR buffer;
        if (!fp || !stricmp(fp, "")) buffer = ReadValue(styleFile, szString, 0);
        else buffer = ReadValue(fp, szString, 0);
        if (buffer) strcpy(colorString, buffer);
        else
        {
                // If the requested parameter could not be
                // found in the file we use the default value...
                if (useDefaultRef) return szDefaultRef;
                else strcpy(colorString, szDefault);
        }

        //====================

        // Check if its a #RRGGBB type string...
        if (*colorString == '#') memmove(colorString, colorString+1, strlen(colorString));

        // Check if its an "rgb:12/ee/4c" type string...
        else if (colorString[3]== ':')
//      else if (strchr(colorString, ':'))
        {
                strcpy(tempString, Tokenize(colorString, colorString, ":"));
                strcpy(tempString, Tokenize(tempString, cr, "/"));
                strcpy(tempString, Tokenize(tempString, cg, "/"));
                strcpy(cb, tempString);

                strcpy(colorString, cr);
                if (strlen(cr)==1) strcat(colorString, cr);
                strcat(colorString, cg);
                if (strlen(cg)==1) strcat(colorString, cg);
                strcat(colorString, cb);
                if (strlen(cb)==1) strcat(colorString, cb);
        }

        // Check if its a pre-defined colour (e.g. "black")...
        else if (isalpha(*colorString))
        {
                value = ParseLiteralColor(colorString);
                if (value) return value;
        }

        //====================

        value = strtol(colorString, NULL, 16);
        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())

        return value;
}

//===========================================================================





syntax highlighting by

w e b c p p
web c plus plus