/*
 ============================================================================
 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 "MenuMaker.h" 

extern vector<Menu*> g_Menues;

extern Settings *pSettings;
extern PluginManager *pPluginManager;

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

MenuMaker::MenuMaker()
{
        m_pRoot = NULL;
        m_pDesktopMenu = NULL;
        m_pToolbarMenu = NULL;
        m_pSystembarMenu = NULL;
        m_pSlitMenu = NULL;
        m_pStylesMenu = NULL;
        m_pThemesMenu = NULL;
        m_pPluginMenu = NULL;

        m_pTitle = NULL;
        m_pEntry = NULL;
        m_pSelEntry = NULL;
        m_pBottom = NULL;

        m_hDefaultFont = 0;
        m_hEntryFont = 0;
}

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

MenuMaker::~MenuMaker()
{
        int i;

        if (m_pRoot)
        {
                int msgs[] = { BB_MENU, BB_HIDEMENU, 0 };
                SendMessage (GetBBWnd(), BB_UNREGISTERMESSAGE, (WPARAM)m_RootMenus[0]->GetWindow(), (LPARAM)msgs);
        }

        DeleteObject(m_hDefaultFont);
        DeleteObject(m_hEntryFont);

        delete m_pTitle;
        delete m_pEntry;
        delete m_pSelEntry;
        delete m_pBottom;

        // Delete all menu objects
        if (m_pRoot) delete m_pRoot;
        if (m_pDesktopMenu) delete m_pDesktopMenu;
        if (m_pToolbarMenu) delete m_pToolbarMenu;
        if (m_pSystembarMenu) delete m_pSystembarMenu;
        if (m_pSlitMenu) delete m_pSlitMenu;
        if (m_pStylesMenu) delete m_pStylesMenu;
        if (m_pThemesMenu) delete m_pThemesMenu;
        if (m_pPluginMenu) DelMenu(m_pPluginMenu);

        // Delete the painters that we have allocated
        for (i = 0; i < (int)m_Painters.size(); i++) delete m_Painters[i];
}

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

void MenuMaker::Initialize(HINSTANCE pMenuInst) 
{       
        hInst = pMenuInst;

        // Read menu configuration...
        ReadConfig();
        ParseMenu();

        // Assign a default root if not explicitly defined...
        if (!m_pRoot)
        {
                if (!m_RootMenus.empty()) m_pRoot = m_RootMenus[0];
        }

        if (m_pRoot)
        {
                int msgs[] = { BB_MENU, BB_HIDEMENU, 0 };
                SendMessage(GetBBWnd(), BB_REGISTERMESSAGE, (WPARAM) m_RootMenus[0]->GetWindow(), (LPARAM)msgs);
        }
}

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

void MenuMaker::ReadConfig()
{
        // menu.title configuration

        if (m_pTitle) delete m_pTitle;
        m_pTitle = MakePainter(pSettings->MenuTitle->Color, 
                pSettings->MenuTitle->ColorTo, 
                pSettings->MenuTitle->type, 
                pSettings->MenuTitle->interlaced, 
                pSettings->MenuTitle->bevelstyle, 
                pSettings->MenuTitle->bevelposition, 
                pSettings->bevelWidth);

        MenuItem::SetTitleAlignment(pSettings->MenuTitle->Justify);

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

        // menu.frame configuration

        if (m_pEntry) delete m_pEntry;
        m_pEntry = new Painter;

        MenuItem::SetAlignment(pSettings->MenuFrame->Justify);

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

        // menu.hilite (= selected item) configuration

        if (m_pSelEntry) delete m_pSelEntry;
        m_pSelEntry = MakePainter(pSettings->MenuHilite->Color, 
                pSettings->MenuHilite->ColorTo, 
                pSettings->MenuHilite->type, 
                pSettings->MenuHilite->interlaced, 
                pSettings->MenuHilite->bevelstyle,
                pSettings->MenuHilite->bevelposition, 
                pSettings->bevelWidth);

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

        // Menu bottom part
        if (m_pBottom) delete m_pBottom;
        m_pBottom = new Painter;

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

        // Menu bullet configuration
        if ((!stricmp(pSettings->menuBullet, "triangle")) || (!stricmp(pSettings->menuBullet, "arrow")))
                FolderItem::SetBulletStyle(BS_TRIANGLE);
        else if (!stricmp(pSettings->menuBullet, "square")) FolderItem::SetBulletStyle(BS_SQUARE);
        else if (!stricmp(pSettings->menuBullet, "diamond")) FolderItem::SetBulletStyle(BS_DIAMOND);
        else if (!stricmp(pSettings->menuBullet, "circle")) FolderItem::SetBulletStyle(BS_CIRCLE);
        else if (!stricmp(pSettings->menuBullet, "triple")) FolderItem::SetBulletStyle(BS_TRIPLE);
        else if (!stricmp(pSettings->menuBullet, "comment")) FolderItem::SetBulletStyle(BS_COMMENT);
        else if (!stricmp(pSettings->menuBullet, "grid")) FolderItem::SetBulletStyle(BS_GRID);
        else FolderItem::SetBulletStyle(BS_EMPTY);

        if (!stricmp(pSettings->menuBulletPosition, "LeftJustify")||!stricmp(pSettings->menuBulletPosition, "Left"))
        {
                FolderItem::SetBulletPosition(DT_LEFT);
                CommandItem::SetBulletPosition(DT_LEFT);
        }
        else
        {
                FolderItem::SetBulletPosition(DT_RIGHT);
                CommandItem::SetBulletPosition(DT_RIGHT);
        }

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

        // Miscellaneous configuration (bevels, border etc.)

        m_nBorderWidth = pSettings->menuBorderWidth;
        m_nBorderColor = pSettings->menuBorderColor;

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

        // Font handling...

        if (m_hDefaultFont) DeleteObject(m_hDefaultFont);
        if (strlen(pSettings->MenuTitle->Font)) m_hDefaultFont = CreateFont(pSettings->MenuTitle->FontHeight, 0, 0, 0, pSettings->MenuTitle->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, pSettings->MenuTitle->Font);
        else
        {
                LOGFONT logFont;
                SystemParametersInfo(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
                m_hDefaultFont = CreateFontIndirect(&logFont);
        }

        m_nSeparatorHeight = 6;

        if (m_hEntryFont) DeleteObject(m_hEntryFont);
        if (strlen(pSettings->MenuFrame->Font)) m_hEntryFont = CreateFont(pSettings->MenuFrame->FontHeight, 0, 0, 0, pSettings->MenuFrame->FontWeight, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, pSettings->MenuFrame->Font);
        else m_hEntryFont = m_hDefaultFont;

        // Set the font...
        m_pTitle->SetFont(m_hDefaultFont, pSettings->MenuTitle->TextColor);
        m_pEntry->SetFont(m_hEntryFont, pSettings->MenuFrame->TextColor);
        m_pSelEntry->SetFont(m_hEntryFont, pSettings->MenuHilite->TextColor);

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

        // Assign hard-coded variables...

        SIZE size;
        HDC fonthdc = CreateDC("DISPLAY", NULL, NULL, NULL);
/*
        HGDIOBJ oldDefaultfont = SelectObject(fonthdc, m_hDefaultFont);
        GetTextExtentPoint32(fonthdc, "TQkgfp/", 8, &size);
        if (!stricmp(pSettings->menuTitleFont, "nu")) size.cy = 7;
        if (pSettings->MenuTitle->bevelstyle != BEVEL_FLAT)
        {
                if (pSettings->MenuTitle->bevelposition == BEVEL2) m_nTitleHeight = size.cy + (2 * m_nBorderWidth) + 6;
                else m_nTitleHeight = size.cy + (2 * m_nBorderWidth) + 4;
        }
        else m_nTitleHeight = size.cy + (2 * m_nBorderWidth) + 2;
        int minTitleFontHeight = pSettings->MenuTitle->FontHeight + (2 * m_nBorderWidth);
        if (m_nTitleHeight < minTitleFontHeight) m_nTitleHeight = minTitleFontHeight;
        SelectObject(fonthdc, oldDefaultfont);
*/

        HGDIOBJ oldDefaultfont = SelectObject(fonthdc, m_hDefaultFont);
        if (!stricmp(pSettings->MenuTitle->Font, "nu")) size.cy = 7;
        else GetTextExtentPoint32(fonthdc, "TQkgfp/", 8, &size);

        if (!pSettings->slimlineMetrics && pSettings->MenuTitle->marginWidth != 0)
        {
                m_nTitleHeight = size.cy + (2 * pSettings->MenuTitle->marginWidth) + (2 * pSettings->MenuTitle->borderWidth);
        }
        else
        {
                if (pSettings->MenuTitle->bevelstyle != BEVEL_FLAT)
                {
                        if (pSettings->MenuTitle->bevelposition == BEVEL2) m_nTitleHeight = size.cy + 6;
                        else m_nTitleHeight = size.cy + 4;
                }
                else m_nTitleHeight = size.cy + 2;
                m_nTitleHeight += (2 * m_nBorderWidth);
        }
        int minTitleFontHeight = pSettings->MenuTitle->FontHeight + (2 * m_nBorderWidth);
        if (m_nTitleHeight < minTitleFontHeight) m_nTitleHeight = minTitleFontHeight;
        SelectObject(fonthdc, oldDefaultfont);

        //====================
/*
        HGDIOBJ oldEntryfont = SelectObject(fonthdc, m_hEntryFont);
        GetTextExtentPoint32(fonthdc, "TQkgfp/", 8, &size);
        if (!stricmp(pSettings->menuFrameFont, "nu")) size.cy = 7;
        if (pSettings->MenuHilite->bevelstyle != BEVEL_FLAT)
        {
                if (pSettings->MenuHilite->bevelposition == BEVEL2) m_nSubmenuHeight = size.cy + 4;
                else m_nSubmenuHeight = size.cy + 2;
        }
        else m_nSubmenuHeight = size.cy + 2;
        if (m_nSubmenuHeight < pSettings->MenuFrame->FontHeight) m_nSubmenuHeight = pSettings->MenuFrame->FontHeight;
        SelectObject(fonthdc, oldEntryfont);
*/

        HGDIOBJ oldEntryfont = SelectObject(fonthdc, m_hEntryFont);
        if (!stricmp(pSettings->MenuFrame->Font, "nu")) size.cy = 7;
        else GetTextExtentPoint32(fonthdc, "TQkgfp/", 8, &size);

        if (!pSettings->slimlineMetrics && pSettings->MenuFrame->marginWidth != 0)
        {
                m_nSubmenuHeight = size.cy + (2 * pSettings->MenuFrame->marginWidth);
        }
        else
        {
                if (pSettings->MenuHilite->bevelstyle != BEVEL_FLAT)
                {
                        if (pSettings->MenuHilite->bevelposition == BEVEL2) m_nSubmenuHeight = size.cy + 4;
                        else m_nSubmenuHeight = size.cy + 2;
                }
                else m_nSubmenuHeight = size.cy + 2;
                m_nSubmenuHeight += (2 * pSettings->MenuHilite->borderWidth);
        }
        if (m_nSubmenuHeight < pSettings->MenuFrame->FontHeight) m_nSubmenuHeight = pSettings->MenuFrame->FontHeight;
        SelectObject(fonthdc, oldEntryfont);

        DeleteDC(fonthdc);

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

//      if (m_nBorderWidth > 0) m_nBottomHeight = m_nBorderWidth - 1;
//      else m_nBottomHeight = 0;
        m_nBottomHeight = 0;

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

        int smallIndent = 3 + m_nBorderWidth;
        if (!pSettings->slimlineMetrics) smallIndent += pSettings->MenuFrame->marginWidth;
        int bulletIndent = 13 + m_nBorderWidth;
        if (!pSettings->slimlineMetrics) bulletIndent += pSettings->MenuFrame->marginWidth;

        if (!stricmp(pSettings->menuBullet, "empty"))
        {
                // If no bullet is used, we use equal left/right indents...
                // (using large indent to still fit bool indicators)
                MenuItem::SetIndent(bulletIndent);
                MenuItem::SetRightIndent(bulletIndent);
        }
        else if (!stricmp(pSettings->menuBulletPosition, "LeftJustify")||!stricmp(pSettings->menuBulletPosition, "Left"))
        {
                // If the bullet is on the left, we make the right indent smaller...
                MenuItem::SetIndent(bulletIndent);
                MenuItem::SetRightIndent(smallIndent);
        }
        else
        {
                // If the bullet is on the right, we make the left indent smaller...
                MenuItem::SetIndent(smallIndent);
                MenuItem::SetRightIndent(bulletIndent);
        }
}

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

void MenuMaker::ParseMenu()
{
        FILE *pMenu = FileOpen(pSettings->menuFile);

        // The menu configuration file is considered invalid if it does not contain a [begin]...
        if (!stricmp(ReadString(pSettings->menuFile, "[begin]", ""), ""))
        {
                FileClose(pMenu);

                char msg[MAX_LINE_LENGTH];
                strcpy(msg, pSettings->menuFile);
                strcat(msg,
                        "\n\nYour menu file does not seem to be valid.   \n\n"
                        "Do you want to create a new menu file with default items?   \n"
                        "(clicking \"No\" will open your current menu file for editing)   ");

                if (MessageBox(GetDesktopWindow(), msg, "xoblite", MB_YESNO | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
                {
                        pSettings->WriteDefaultMenu();
                }
                else PostMessage(GetBBWnd(), BB_EDITFILE, 1, 0); // Open the current menu file for editing...

                pMenu = FileOpen(pSettings->menuFile);
        }

        // Create the main menu
        m_pRoot = new Menu(hInst);
        ParseFolder(pMenu, m_pRoot);
        m_pRoot->Validate();
        m_RootMenus.insert(m_RootMenus.begin(), m_pRoot);

        // Create the workspaces menu
        m_pDesktopMenu = new DesktopMenu("Workspaces", this);
        m_RootMenus.insert(m_RootMenus.begin()+1, m_pDesktopMenu);

        // Create the toolbar menu
        m_pToolbarMenu = new ToolbarMenu("Toolbar", this);
        m_RootMenus.insert(m_RootMenus.begin()+2, m_pToolbarMenu);

        // Create the systembar menu
        m_pSystembarMenu = new SystembarMenu("Systembar", this);
        m_RootMenus.insert(m_RootMenus.begin()+3, m_pSystembarMenu);

        // Create the slit menu
        m_pSlitMenu = new SlitMenu("Slit", this);
        m_RootMenus.insert(m_RootMenus.begin()+4, m_pSlitMenu);

        // Create the styles menu
        m_pStylesMenu = new StylesMenu("Styles", this);
        m_RootMenus.insert(m_RootMenus.begin()+5, m_pStylesMenu);

        // Create the themes menu
        m_pThemesMenu = new ThemesMenu("Themes", this);
        m_RootMenus.insert(m_RootMenus.begin()+6, m_pThemesMenu);

        FileClose(pMenu);
}

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

void MenuMaker::ParseFolder(FILE *pMenu, Menu *pRoot)
{
        for(;;)
        {
                char szLineBuffer[MAX_LINE_LENGTH]="";

                if (!ReadNextCommand(pMenu, szLineBuffer, sizeof(szLineBuffer)))
                        break;
                if (!ParseLine(pMenu, pRoot, szLineBuffer))
                        break;
        }
}

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

bool MenuMaker::ParseLine(FILE *pMenu, Menu *pRoot, char *pszLine)
{
    char command[MAX_LINE_LENGTH]="", label[MAX_LINE_LENGTH]="", data[MAX_LINE_LENGTH]="";

        Painter* pPainter = m_pEntry;
        MenuItem* pMenuItem = NULL;

        // Check if the line is a valid config line (if it contains a [ it's considered ok)
        if (!strchr(pszLine, '['))
                return true;

        // Remove whitespaces at the beginning of the line
        while (*pszLine && isspace(*pszLine)) pszLine++;

        // Substitute any applivation environment variables, e.g. "$ProgramFiles$"
        if (strchr(pszLine, '$')) ReplaceShellFolders(pszLine);

        // Substitute any "%VAR%" for the VAR value if it's a real VAR
        if (strchr(pszLine, '%')) ReplaceEnvVars(pszLine);

        // Extract the command section from the string
        strcpy(data, Tokenize(pszLine, command, " "));

        // Check to see if the line contains a label tag (for [end] error protection)
        if (*data == '(')
        {
                strcpy(data, Tokenize(data, label, ")"));
                memmove(label, label+1, strlen(label));
        }

        // If the line contains a data tag, remove the { } encapsulation
        if (*data == '{') StrRemoveEncap(data);

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

        // If the line contains [begin] we create a title item...
        if (!stricmp(command, "[begin]"))
        {
                // If no menu title has been defined, display xoblite version...
                if (!stricmp(label, ""))
                {
                        strcpy(m_szHotListName, "xoblite ");
                        strcat(m_szHotListName, (LPSTR)GetBBVersion());
                }
                else strcpy(m_szHotListName, label);

                AddHeaderItem(m_pRoot, m_szHotListName);
                return true;
        }

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

        // If the line contains [submenu] we create a subfolder...
        else if (!stricmp(command, "[submenu]"))
        {
                Menu* pSub = new Menu(hInst);
                AddHeaderItem(pSub, strlen(data) ? data : label);
                ParseFolder(pMenu, pSub);
                pSub->Validate();
                
                pMenuItem = new FolderItem(pSub, label);
//              return true;
        }

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

        // If the line contains [end] we terminate the line parsing by returning false...
        else if (!stricmp(command, "[end]"))
        {
                AddBottomItem(pRoot);
                return false;
        }

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

        // If the line contains [include] we parse the file to be included...
        else if (!stricmp(command, "[include]"))
        {
                if (!FileExists(label))
                {
                        // If the file does not exist, display an error messagebox...
                        char message[MAX_LINE_LENGTH];
                        strcpy(message, "xoblite was unable to include...\n\n");
                        strcat(message, label);
                        strcat(message, "\n\n...into the menu. Please check your menu configuration file.   ");
                        MessageBox(GetBBWnd(), message, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                        // ...and insert a placeholder "error" item...
                        CreateMenuItem(pRoot, "[nop]", NULL, "[include failed]", false);
                        return true;
                }
                // ...otherwise open and parse the file
                FILE *pMenu = FileOpen(label);
                ParseFolder(pMenu, pRoot);
                FileClose(pMenu);
                return true;
        }

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

        // Check if the line is pointing to a dynamic folder...
        else if (!stricmp(command, "[path]"))
                pMenuItem = new SpecialFolder(data, this, label, 1);

        else if (!stricmp(command, "[stylesmenu]"))
                pMenuItem = new SpecialFolder(data, this, label, 0);

        else if (!stricmp(command, "[themesmenu]"))
                pMenuItem = new SpecialFolder(pSettings->themesFolder, this, label, 2);

        else if (!stricmp(command, "[stylesdir]"))
        {
                InsertFolder(pRoot, label, false, false);
                return true;
        }
        else if (!stricmp(command, "[stylestree]"))
        {
                InsertFolder(pRoot, label, true, false);
                return true;
        }

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

        // Check if the line is specifying a special item...
        else if (!stricmp(command, "[workspaces]"))
                pMenuItem = new FolderItem(new DesktopMenu(label ? label : "Workspaces", this), label ? label : "Workspaces");
        else if (!stricmp(command, "[tasks]"))
//              pMenuItem = new DesktopMenuItem("Tasks", this, 254);
                pMenuItem = new DesktopMenuItem("Icons", this, 255);
        else if (!stricmp(command, "[config]"))
                pMenuItem = new FolderItem(new ConfigMenu(label ? label : "Configuration", this), label ? label : "Configuration");

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

        // All other items: [exec] [separator] [nop] etc...
        else
        {
                CreateMenuItem(pRoot, command, data, label, false);
                return true;
        }

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

        // Finally, we add the new item to the menu...
        pMenuItem->SetHeight(m_nSubmenuHeight);
        pMenuItem->SetPainter(pPainter);
        pMenuItem->SetActivePainter(m_pSelEntry);
        pRoot->AddMenuItem(pMenuItem);

        return true;
}

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

void MenuMaker::AddHeaderItem(Menu* pMenu, LPSTR pszTitle)
{
        MenuItem* pHead = new TitleItem(pszTitle, MENU_HEADER);
        pHead->SetPainter(m_pTitle);
        pHead->SetHeight(m_nTitleHeight);
        pMenu->AddMenuItem(pHead);
}

void MenuMaker::AddBottomItem(Menu* pMenu)
{
        MenuItem* pMenuItem = new TitleItem("", MENU_NOP);
        pMenuItem->SetPainter(m_pBottom);
        pMenuItem->SetHeight(m_nBottomHeight);
        pMenu->AddMenuItem(pMenuItem);
}

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

void MenuMaker::InsertFolder(Menu *pMenu, LPSTR pszFolder, bool includeSubFolders, bool themesMenu)
{
        char tempPath[MAX_LINE_LENGTH];
        strcpy(tempPath, pszFolder);

        char pszPattern[MAX_LINE_LENGTH];
        long handle;
        _finddata_t found;
        MenuItem* pItem = NULL;
        char itemCmd[MAX_LINE_LENGTH];
        char itemTitle[MAX_LINE_LENGTH];
        bool directoryFound = false, itemFound = false;

    // First, we create a file search pattern by taking the path to the directory... 
    strcpy(pszPattern, tempPath);
    if (pszPattern[strlen(pszPattern)] != '\\') strcat(pszPattern, "\\");
    // ...and adding a wildcard pattern
    strcat(pszPattern, "*");

    // Using this pattern, we then search for items in the directory
        // and process them according to name, attributes etc.
    handle = _findfirst(pszPattern, &found);

        // First we look for any subfolders...
        if (includeSubFolders || themesMenu)
        {
                if (handle != -1) 
                {
                        do
                        {
                                // Skip hidden files...
                                if (strcmp(found.name, ".") == 0 || strcmp(found.name, "..") == 0 || (found.attrib & _A_HIDDEN))
                                        continue;
                                // Subfolders are created by adding a new SpecialFolder...
                                if (found.attrib & _A_SUBDIR)
                                {
                                        if (themesMenu)
                                        {
                                                // To get the full path to the file we copy the search
                                                // pattern, remove the wildcard and add the filename
                                                strcpy(itemCmd, pszPattern);
                                                itemCmd[strlen(itemCmd)-1] = '\0';
                                                strcat(itemCmd, found.name);

                                                // The title of the menu item is the name of the file
                                                strcpy(itemTitle, found.name);

                                                // Finally, we create the new menu item...
                                                CreateMenuItem(pMenu, "[theme]", itemCmd, itemTitle, IsInString(bbrcPath(), itemCmd));
                                        }
                                        else
                                        {
                                                // To get the full path to the folder we copy the search
                                                // pattern, remove the wildcard and add the folder name,
                                                // then add quotes to be on the safe side during further
                                                // processing if the path contains spaces...
                                                char dirPath[MAX_LINE_LENGTH];
                                                strcpy(dirPath,"\"");
                                                strcat(dirPath, pszPattern);
                                                dirPath[strlen(dirPath)-1] = '\0';
                                                strcat(dirPath, found.name);
                                                strcat(dirPath, "\"");
                                                pItem = new SpecialFolder(dirPath, this, found.name, 0);
                                                // ...and add the subfolder to the menu!
                                                pItem->SetHeight(m_nSubmenuHeight);
                                                pItem->SetPainter(m_pEntry);
                                                pItem->SetActivePainter(m_pSelEntry);
//                                              pItem->SetSortPriority(1);
                                                pMenu->AddMenuItem(pItem);

                                                directoryFound = true;
                                        }
                                }
                                else continue;
                        }
                        while(_findnext(handle, &found)==0);
                }
                _findclose(handle);

                // ...finally, we reinitialize the handle since
                // we're going to scan for normal items below...
                handle = _findfirst(pszPattern, &found);
        }

    if ((handle != -1) && !themesMenu) 
    {
                do
                {
                        // Skip hidden files...
                        if(strcmp(found.name, ".") == 0 || strcmp(found.name, "..") == 0 || (found.attrib & _A_HIDDEN))
                                continue;
                        // Skip subfolders...
                        if(found.attrib & _A_SUBDIR) 
                                continue;
                        else // Files (in this case style files)
                        {
                                // To get the full path to the file we copy the search
                                // pattern, remove the wildcard and add the filename
                                strcpy(itemCmd, pszPattern);
                                itemCmd[strlen(itemCmd)-1] = '\0';
                                strcat(itemCmd, found.name);

                                // The title of the menu item is the name of the file
                                strcpy(itemTitle, found.name);
                                // Remove the .style extension if found...
                                if (IsInString(itemTitle, ".style")) PathRemoveExtension(itemTitle);

                                // Finally, we create the new menu item...
                                CreateMenuItem(pMenu, "[style]", itemCmd, itemTitle, (!stricmp(itemCmd, pSettings->styleFile)));

                                itemFound = true;
                        }
                }
                while(_findnext(handle, &found)==0);
        }
    _findclose(handle);

        if (directoryFound && itemFound) CreateMenuItem(pMenu, "[separator]", NULL, NULL, false);

        pMenu->Sort(0,0);

/*
        if (includeSubFolders)
        {
                CreateMenuItem(pMenu, "[separator]", NULL, NULL, false);

                pItem = new SpecialFolder(pSettings->themesFolder, this, "Themes", 2);
                pItem->SetHeight(m_nSubmenuHeight);
                pItem->SetPainter(m_pEntry);
                pItem->SetActivePainter(m_pSelEntry);
//              pItem->SetSortPriority(1);
                pMenu->AddMenuItem(pItem);
        }
*/
}

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

Menu* MenuMaker::LoadFolder(LPSTR pszTitle, LPSTR pszFolder, int menuType)
{
        char folder[MAX_LINE_LENGTH], title[MAX_LINE_LENGTH];
        strcpy(folder, pszFolder);
        strcpy(title, pszTitle);
        
        long handle;
        _finddata_t found;
        MenuItem* pItem = NULL;
        char itemCmd[MAX_LINE_LENGTH], itemTitle[MAX_LINE_LENGTH], dirPath[MAX_LINE_LENGTH];
        bool directoryFound = false, itemFound = false;

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

        Menu* pMenu = new Menu(hInst);

        // First, we create the header (title) menu item...
        AddHeaderItem(pMenu, title);

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

        // If we're creating a [themesmenu] subfolder we add the default theme to the menu...
        if (menuType == 2)
        {
                char bbpath[MAX_LINE_LENGTH];
                GetBlackboxPath(bbpath, MAX_LINE_LENGTH);
                bbpath[strlen(bbpath)-1] = 0;
                CreateMenuItem(pMenu, "[theme]", bbpath, "<Default>", !IsInString(bbrcPath(), "themes"));
        }

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

        char folderToken[MAX_LINE_LENGTH], folderPattern[MAX_LINE_LENGTH];

        while (strlen(folder))
        {
                // Get the next folder path token from the input string...
                strcpy(folder, Tokenize(folder, folderToken, "|"));
                if (folderToken[0] == '\"') StrRemoveEncap(folderToken);

                // Does the folder path already contain a wildcard?
                LPSTR wildcardPointer = strchr(folderToken, '*');
                if (wildcardPointer != NULL)
                {
                        // If so, we use the folder path without alteration as search pattern...
                        strcpy(folderPattern, folderToken);
                        int i = (int)(wildcardPointer - folderToken);
                        folderToken[i] = '\0';
                }
                else
                {
                        // If not, we use the default "all files" search pattern...
                        if (folderToken[strlen(folderToken)] != '\\') strcat(folderToken, "\\");
                        strcpy(folderPattern, folderToken);
                        strcat(folderPattern, "*");
                }

                // Using this pattern, we then search for items in the directory
                // and process them according to name, attributes etc.
                handle = _findfirst(folderPattern, &found);

                if (handle != -1) 
                {
                        do
                        {
                                // Skip hidden files...
                                if (strcmp(found.name, ".") == 0 || strcmp(found.name, "..") == 0 || (found.attrib & _A_HIDDEN))
                                        continue;
                                // Subfolders are created by adding a new SpecialFolder...
                                if (found.attrib & _A_SUBDIR) 
                                {
                                        if (menuType == 2) // [themesmenu] items
                                        {
                                                // To get the full path to the file we copy
                                                // the folder path and add the filename...
                                                strcpy(itemCmd, folderToken);
                                                strcat(itemCmd, found.name);

                                                // The title of the menu item is the name of the file
                                                strcpy(itemTitle, found.name);

                                                // Finally, we create the new menu item...
                                                CreateMenuItem(pMenu, "[theme]", itemCmd, itemTitle, IsInString(bbrcPath(), itemCmd));
                                        }
                                        else
                                        {
                                                // To get the full path to the file we copy the folder path
                                                // and add the filename, then add quotes to be on the safe
                                                // side during further processing if the path contains spaces...
                                                strcpy(dirPath,"\"");
                                                strcat(dirPath, folderToken);
                                                strcat(dirPath, found.name);
                                                strcat(dirPath, "\"");

                                                pItem = new SpecialFolder(dirPath, this, found.name, menuType);
                                                pItem->SetHeight(m_nSubmenuHeight);
                                                pItem->SetPainter(m_pEntry);
                                                pItem->SetActivePainter(m_pSelEntry);
                                                pMenu->AddMenuItem(pItem);

                                                directoryFound = true;
                                        }
                                }
                                else
                                {
                                        if (menuType == 0) // [stylesmenu] items
                                        {
                                                if (IsInString(found.name, ".3dc")) continue;

                                                // To get the full path to the file we copy
                                                // the folder path and add the filename...
                                                strcpy(itemCmd, folderToken);
                                                strcat(itemCmd, found.name);

                                                // The title of the menu item is the name of the file
                                                strcpy(itemTitle, found.name);
                                                // Remove the .style extension if found...
                                                if (IsInString(itemTitle, ".style")) PathRemoveExtension(itemTitle);

                                                // Finally, we create the new menu item...
                                                CreateMenuItem(pMenu, "[style]", itemCmd, itemTitle, (!stricmp(itemCmd, pSettings->styleFile)));

                                                itemFound = true;
                                        }
                                        else if (menuType == 1) // [path] items
                                        {
                                                // To get the full path to the file we copy the folder path
                                                // and add the filename, then add quotes to be on the safe
                                                // side during further processing if the path contains spaces...
                                                strcpy(itemCmd, "\"");
                                                strcat(itemCmd, folderToken);
                                                strcat(itemCmd, found.name);
                                                strcat(itemCmd, "\"");

                                                // The title of the menu item is the name of the file,
                                                // minus .lnk if it's a symbolic link
                                                strcpy(itemTitle, found.name);
                                                if (IsInString(itemTitle, ".lnk")) PathRemoveExtension(itemTitle);

                                                // Finally, we create the new menu item...
                                                CreateMenuItem(pMenu, "[exec]", itemCmd, itemTitle, false);

                                                itemFound = true;
                                        }
                                }
                        }
                        while (_findnext(handle, &found)==0);
                }

                _findclose(handle);
        }

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

        if (directoryFound && itemFound) CreateMenuItem(pMenu, "[separator]", NULL, NULL, false);

        // When the search is completed, we sort
        // the items and add the bottom menu item...
        if (menuType == 2) pMenu->Sort(1,0);
        else pMenu->Sort(0,0);
        AddBottomItem(pMenu);
        pMenu->Validate();

        return pMenu;
}

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

void MenuMaker::Show(int index)
{
        m_RootMenus[index]->Show();
        SetFocus(m_RootMenus[index]->GetWindow());
}

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

void MenuMaker::Hide(int index)
{
        // Clear the "menu item editbox open" flag...
        pSettings->menuEditboxAlreadyActive = false;

        // Hide all menus...
        for (int i=0; i < (int)m_RootMenus.size(); i++)
        {
                if (m_RootMenus[i]->IsPinned())
                        m_RootMenus[i]->SetPinned(false);

                m_RootMenus[i]->Hide(HIDE_PARENTS);
                m_RootMenus[i]->Hide(HIDE_CHILDREN);
        }

//      if (pPluginManager) pPluginManager->Hide(); // Hide all plugin menus
        if (m_pPluginMenu)
        {
                m_pPluginMenu->Hide(HIDE_PARENTS);
                m_pPluginMenu->Hide(HIDE_CHILDREN);
                ShowWindow(m_pPluginMenu->GetWindow(), SW_HIDE);
        }
}

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

void MenuMaker::ShowRootMenu()
{
        m_pRoot->SetPinned(true);
        m_pRoot->Show();
}

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

void MenuMaker::ShowDesktopMenu()
{
        m_pDesktopMenu->SetPinned(true);
        m_pDesktopMenu->Show();
}

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

void MenuMaker::ShowToolbarMenu()
{
        m_pToolbarMenu->SetPinned(true);
        m_pToolbarMenu->Show();
}

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

void MenuMaker::ShowSystembarMenu()
{
        m_pSystembarMenu->SetPinned(true);
        m_pSystembarMenu->Show();
}

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

void MenuMaker::ShowSlitMenu()
{
        m_pSlitMenu->SetPinned(true);
        m_pSlitMenu->Show();
}

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

void MenuMaker::ShowStylesMenu()
{
        m_pStylesMenu->SetPinned(true);
        m_pStylesMenu->Show();
}

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

void MenuMaker::ShowThemesMenu()
{
        m_pThemesMenu->SetPinned(true);
        m_pThemesMenu->Show();
}

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

Painter* MenuMaker::MakePainter(DWORD dwColor, DWORD dwGradColor, int nType, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth)
{
        Painter* pNewPainter = NULL;

        if (nType == 255) // Quick'n'dirty hack to support menu.hilite being parentrelative (see Settings.cpp and GradientPainter::Paint for more)
                pNewPainter = new GradientPainter(dwColor, dwGradColor, nType, bInterlaced, bevelStyle, bevelPosition, bevelWidth);
        else
        {
//              if (dwColor != dwGradColor)
                        pNewPainter = new GradientPainter(dwColor, dwGradColor, nType, bInterlaced, bevelStyle, bevelPosition, bevelWidth);
//              else
//                      pNewPainter = new SolidPainter(dwColor);
        }

        return pNewPainter;
}

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

MenuItem* MenuMaker::CreateMenuItem(Menu *pMenu, char* pszCommand, char* pszArgument, char* pszTitle, bool isSelected)
{
        MenuItem *newMenuItem = NULL;

        if (pMenu)
        {
                if (!stricmp(pszCommand, "[separator]"))
                {
                        if (pSettings->menuSeparators)
                        {
                                newMenuItem = new TitleItem("", MENU_SEPARATOR);
                                newMenuItem->SetHeight(m_nSeparatorHeight);
                                newMenuItem->SetPainter(m_pEntry);

                                // Set a higher sort priority for [separator] items to make
                                // them sort before any regular menu items (i.e. between folders
                                // regular menu items)
                                newMenuItem->SetSortPriority(2);

                                pMenu->AddMenuItem(newMenuItem);
                        }
                }
                else if (!stricmp(pszCommand, "[nop]"))
                {
                        if (pszTitle == NULL) newMenuItem = new TitleItem("", MENU_NOP);
                        else newMenuItem = new TitleItem(pszTitle, MENU_NOP);
                        newMenuItem->SetHeight(m_nSubmenuHeight);
                        newMenuItem->SetPainter(m_pEntry);
                        pMenu->AddMenuItem(newMenuItem);
                }
                else if (!stricmp(pszCommand, "<edit-string>")) // Used by MakeMenuItemString
                {
                        char Cmd[MAX_LINE_LENGTH], init_string[MAX_LINE_LENGTH];
                        LPSTR tokens[2];
                        tokens[0] = Cmd;
                        tokens[1] = init_string;

                        Cmd[0] = init_string[0] = '\0';
                        BBTokenize (pszArgument, tokens, 1, init_string);

                        newMenuItem = new StringItem(pszTitle, Cmd, init_string);
                        newMenuItem->SetHeight(m_nSubmenuHeight);// + 4);
                        newMenuItem->SetPainter(m_pEntry);
                        newMenuItem->SetActivePainter(m_pSelEntry);
                        pMenu->AddMenuItem(newMenuItem);
                }
                else // [exec], <edit-int> (MakeMenuItemInt), etc
                {
                        newMenuItem = new CommandItem(pszCommand, pszArgument, pszTitle, isSelected);
                        newMenuItem->SetHeight(m_nSubmenuHeight);
                        newMenuItem->SetPainter(m_pEntry);
                        newMenuItem->SetActivePainter(m_pSelEntry);
                        pMenu->AddMenuItem(newMenuItem);
                }
        }

        return newMenuItem;
}

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





syntax highlighting by

w e b c p p
web c plus plus