aboutsummaryrefslogtreecommitdiff
path: root/mp/src/vgui2/vgui_controls/FileOpenDialog.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/vgui2/vgui_controls/FileOpenDialog.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/vgui2/vgui_controls/FileOpenDialog.cpp')
-rw-r--r--mp/src/vgui2/vgui_controls/FileOpenDialog.cpp3402
1 files changed, 1701 insertions, 1701 deletions
diff --git a/mp/src/vgui2/vgui_controls/FileOpenDialog.cpp b/mp/src/vgui2/vgui_controls/FileOpenDialog.cpp
index 8a1af699..ebe5eb0c 100644
--- a/mp/src/vgui2/vgui_controls/FileOpenDialog.cpp
+++ b/mp/src/vgui2/vgui_controls/FileOpenDialog.cpp
@@ -1,1701 +1,1701 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implementation of vgui generic open file dialog
-//
-// $NoKeywords: $
-//===========================================================================//
-
-
-#define PROTECTED_THINGS_DISABLE
-
-#if !defined( _X360 ) && defined( WIN32 )
-#include "winlite.h"
-#include <shellapi.h>
-#elif defined( POSIX )
-#include <stdlib.h>
-#define _stat stat
-#define _wcsnicmp wcsncmp
-#elif defined( _X360 )
-#else
-#error
-#endif
-
-#undef GetCurrentDirectory
-#include "filesystem.h"
-#include <sys/stat.h>
-
-#include "tier1/utldict.h"
-#include "tier1/utlstring.h"
-
-#include <vgui/IScheme.h>
-#include <vgui/ISurface.h>
-#include <vgui/ISystem.h>
-#include <KeyValues.h>
-#include <vgui/IVGui.h>
-#include <vgui/ILocalize.h>
-#include <vgui/IInput.h>
-
-#include <vgui_controls/FileOpenDialog.h>
-
-#include <vgui_controls/Button.h>
-#include <vgui_controls/ComboBox.h>
-#include <vgui_controls/ImagePanel.h>
-#include <vgui_controls/InputDialog.h>
-#include <vgui_controls/Label.h>
-#include <vgui_controls/ListPanel.h>
-#include <vgui_controls/TextEntry.h>
-#include <vgui_controls/ImageList.h>
-#include <vgui_controls/MenuItem.h>
-#include <vgui_controls/Tooltip.h>
-
-#if defined( _X360 )
-#include "xbox/xbox_win32stubs.h"
-#undef GetCurrentDirectory
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include <tier0/memdbgon.h>
-
-using namespace vgui;
-
-static int s_nLastSortColumn = 0;
-
-static int ListFileNameSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- NOTE_UNUSED( pPanel );
-
- bool dir1 = item1.kv->GetInt("directory") == 1;
- bool dir2 = item2.kv->GetInt("directory") == 1;
-
- // if they're both not directories of files, return if dir1 is a directory (before files)
- if (dir1 != dir2)
- {
- return dir1 ? -1 : 1;
- }
-
- const char *string1 = item1.kv->GetString("text");
- const char *string2 = item2.kv->GetString("text");
-
- // YWB: Mimic windows behavior where filenames starting with numbers are sorted based on numeric part
- int num1 = Q_atoi( string1 );
- int num2 = Q_atoi( string2 );
-
- if ( num1 != 0 &&
- num2 != 0 )
- {
- if ( num1 < num2 )
- return -1;
- else if ( num1 > num2 )
- return 1;
- }
-
- // Push numbers before everything else
- if ( num1 != 0 )
- {
- return -1;
- }
-
- // Push numbers before everything else
- if ( num2 != 0 )
- {
- return 1;
- }
-
- return Q_stricmp( string1, string2 );
-}
-
-static int ListBaseStringSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *fieldName )
-{
- bool dir1 = item1.kv->GetInt("directory") == 1;
- bool dir2 = item2.kv->GetInt("directory") == 1;
-
- // if they're both not directories of files, return if dir1 is a directory (before files)
- if (dir1 != dir2)
- {
- return -1;
- }
-
- const char *string1 = item1.kv->GetString(fieldName);
- const char *string2 = item2.kv->GetString(fieldName);
- int cval = Q_stricmp(string1, string2);
- if ( cval == 0 )
- {
- // Use filename to break ties
- return ListFileNameSortFunc( pPanel, item1, item2 );
- }
-
- return cval;
-}
-
-static int ListBaseIntegerSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *fieldName )
-{
- bool dir1 = item1.kv->GetInt("directory") == 1;
- bool dir2 = item2.kv->GetInt("directory") == 1;
-
- // if they're both not directories of files, return if dir1 is a directory (before files)
- if (dir1 != dir2)
- {
- return -1;
- }
-
- int i1 = item1.kv->GetInt(fieldName);
- int i2 = item2.kv->GetInt(fieldName);
- if ( i1 == i2 )
- {
- // Use filename to break ties
- return ListFileNameSortFunc( pPanel, item1, item2 );
- }
-
- return ( i1 < i2 ) ? -1 : 1;
-}
-
-static int ListBaseInteger64SortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *lowfield, char const *highfield )
-{
- bool dir1 = item1.kv->GetInt("directory") == 1;
- bool dir2 = item2.kv->GetInt("directory") == 1;
-
- // if they're both not directories of files, return if dir1 is a directory (before files)
- if (dir1 != dir2)
- {
- return dir1 ? -1 : 1;
- }
-
- uint32 l1 = item1.kv->GetInt(lowfield);
- uint32 h1 = item1.kv->GetInt(highfield);
- uint32 l2 = item2.kv->GetInt(lowfield);
- uint32 h2 = item2.kv->GetInt(highfield);
- uint64 i1 = (uint64)( (uint64)l1 | ( (uint64)h1 << 32 ) );
- uint64 i2 = (uint64)( (uint64)l2 | ( (uint64)h2 << 32 ) );
-
- if ( i1 == i2 )
- {
- // Use filename to break ties
- return ListFileNameSortFunc( pPanel, item1, item2 );
- }
-
- return ( i1 < i2 ) ? -1 : 1;
-}
-
-
-static int ListFileSizeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- return ListBaseIntegerSortFunc( pPanel, item1, item2, "filesizeint" );
-}
-
-static int ListFileModifiedSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- // NOTE: Backward order to get most recent files first
- return ListBaseInteger64SortFunc( pPanel, item2, item1, "modifiedint_low", "modifiedint_high" );
-}
-static int ListFileCreatedSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- // NOTE: Backward order to get most recent files first
- return ListBaseInteger64SortFunc( pPanel, item2, item1, "createdint_low", "createdint_high" );
-}
-static int ListFileAttributesSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- return ListBaseStringSortFunc( pPanel, item1, item2, "attributes" );
-}
-static int ListFileTypeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
-{
- return ListBaseStringSortFunc( pPanel, item1, item2, "type" );
-}
-
-
-
-namespace vgui
-{
-
-class FileCompletionMenu : public Menu
-{
-public:
- FileCompletionMenu(Panel *parent, const char *panelName) : Menu(parent, panelName)
- {
- }
-
- // override it so it doesn't request focus
- virtual void SetVisible(bool state)
- {
- Panel::SetVisible(state);
- }
-
-};
-
-
-//-----------------------------------------------------------------------------
-// File completion edit text entry
-//-----------------------------------------------------------------------------
-class FileCompletionEdit : public TextEntry
-{
- DECLARE_CLASS_SIMPLE( FileCompletionEdit, TextEntry );
-
-public:
- FileCompletionEdit(Panel *parent);
- ~FileCompletionEdit();
-
- int AddItem(const char *itemText, KeyValues *userData);
- int AddItem(const wchar_t *itemText, KeyValues *userData);
- void DeleteAllItems();
- int GetItemCount();
- int GetItemIDFromRow(int row);
- int GetRowFromItemID(int itemID);
- virtual void PerformLayout();
- void OnSetText(const wchar_t *newtext);
- virtual void OnKillFocus();
- void HideMenu(void);
- void ShowMenu(void);
- virtual void OnKeyCodeTyped(KeyCode code);
- MESSAGE_FUNC_INT( OnMenuItemHighlight, "MenuItemHighlight", itemID );
-
-private:
- FileCompletionMenu *m_pDropDown;
-};
-
-
-
-FileCompletionEdit::FileCompletionEdit(Panel *parent) : TextEntry(parent, NULL)
-{
- m_pDropDown = new FileCompletionMenu(this, NULL);
- m_pDropDown->AddActionSignalTarget(this);
-}
-
-FileCompletionEdit::~FileCompletionEdit()
-{
- delete m_pDropDown;
-}
-
-int FileCompletionEdit::AddItem(const char *itemText, KeyValues *userData)
-{
- // when the menu item is selected it will send the custom message "SetText"
- return m_pDropDown->AddMenuItem(itemText, new KeyValues("SetText", "text", itemText), this, userData);
-}
-int FileCompletionEdit::AddItem(const wchar_t *itemText, KeyValues *userData)
-{
- // add the element to the menu
- // when the menu item is selected it will send the custom message "SetText"
- KeyValues *kv = new KeyValues("SetText");
- kv->SetWString("text", itemText);
-
- // get an ansi version for the menuitem name
- char ansi[128];
- g_pVGuiLocalize->ConvertUnicodeToANSI(itemText, ansi, sizeof(ansi));
- return m_pDropDown->AddMenuItem(ansi, kv, this, userData);
-}
-
-void FileCompletionEdit::DeleteAllItems()
-{
- m_pDropDown->DeleteAllItems();
-}
-
-int FileCompletionEdit::GetItemCount()
-{
- return m_pDropDown->GetItemCount();
-}
-
-int FileCompletionEdit::GetItemIDFromRow(int row)
-{
- // valid from [0, GetItemCount)
- return m_pDropDown->GetMenuID(row);
-}
-
-int FileCompletionEdit::GetRowFromItemID(int itemID)
-{
- int i;
- for (i=0;i<GetItemCount();i++)
- {
- if (m_pDropDown->GetMenuID(i) == itemID)
- return i;
- }
- return -1;
-}
-
-void FileCompletionEdit::PerformLayout()
-{
- BaseClass::PerformLayout();
-
- m_pDropDown->PositionRelativeToPanel( this, Menu::DOWN, 0 );
-
- // reset the width of the drop down menu to be the width of this edit box
- m_pDropDown->SetFixedWidth(GetWide());
- m_pDropDown->ForceCalculateWidth();
-}
-
-void FileCompletionEdit::OnSetText(const wchar_t *newtext)
-{
- // see if the combobox text has changed, and if so, post a message detailing the new text
- wchar_t wbuf[255];
- GetText( wbuf, 254 );
-
- if ( wcscmp(wbuf, newtext) )
- {
- // text has changed
- SetText(newtext);
-
- // fire off that things have changed
- PostActionSignal(new KeyValues("TextChanged", "text", newtext));
- Repaint();
- }
-}
-
-void FileCompletionEdit::OnKillFocus()
-{
- HideMenu();
- BaseClass::OnKillFocus();
-}
-
-void FileCompletionEdit::HideMenu(void)
-{
- // hide the menu
- m_pDropDown->SetVisible(false);
-}
-
-void FileCompletionEdit::ShowMenu(void)
-{
- // reset the dropdown's position
- m_pDropDown->InvalidateLayout();
-
- // make sure we're at the top of the draw order (and therefore our children as well)
- // this important to make sure the menu will be drawn in the foreground
- MoveToFront();
-
- // reset the drop down
- m_pDropDown->ClearCurrentlyHighlightedItem();
-
- // limit it to only 6
- if (m_pDropDown->GetItemCount() > 6)
- {
- m_pDropDown->SetNumberOfVisibleItems(6);
- }
- else
- {
- m_pDropDown->SetNumberOfVisibleItems(m_pDropDown->GetItemCount());
- }
- // show the menu
- m_pDropDown->SetVisible(true);
-
- Repaint();
-}
-
-void FileCompletionEdit::OnKeyCodeTyped(KeyCode code)
-{
- if ( code == KEY_DOWN )
- {
- if (m_pDropDown->GetItemCount() > 0)
- {
- int menuID = m_pDropDown->GetCurrentlyHighlightedItem();
- int row = -1;
- if ( menuID == -1 )
- {
- row = m_pDropDown->GetItemCount() - 1;
- }
- else
- {
- row = GetRowFromItemID(menuID);
- }
- row++;
- if (row == m_pDropDown->GetItemCount())
- {
- row = 0;
- }
- menuID = GetItemIDFromRow(row);
- m_pDropDown->SetCurrentlyHighlightedItem(menuID);
- return;
- }
- }
- else if ( code == KEY_UP )
- {
- if (m_pDropDown->GetItemCount() > 0)
- {
- int menuID = m_pDropDown->GetCurrentlyHighlightedItem();
- int row = -1;
- if ( menuID == -1 )
- {
- row = 0;
- }
- else
- {
- row = GetRowFromItemID(menuID);
- }
- row--;
- if ( row < 0 )
- {
- row = m_pDropDown->GetItemCount() - 1;
- }
- menuID = GetItemIDFromRow(row);
- m_pDropDown->SetCurrentlyHighlightedItem(menuID);
- return;
- }
- }
- else if ( code == KEY_ESCAPE )
- {
- if ( m_pDropDown->IsVisible() )
- {
- HideMenu();
- return;
- }
- }
- BaseClass::OnKeyCodeTyped(code);
- return;
-}
-
-void FileCompletionEdit::OnMenuItemHighlight( int itemID )
-{
- char wbuf[80];
- if ( m_pDropDown->IsValidMenuID(itemID) )
- {
- m_pDropDown->GetMenuItem(itemID)->GetText(wbuf, 80);
- }
- else
- {
- wbuf[0] = 0;
- }
- SetText(wbuf);
- RequestFocus();
- GotoTextEnd();
-}
-
-
-} // namespace vgui
-
-
-//-----------------------------------------------------------------------------
-// Dictionary of start dir contexts
-//-----------------------------------------------------------------------------
-static CUtlDict< CUtlString, unsigned short > s_StartDirContexts;
-
-struct ColumnInfo_t
-{
- char const *columnName;
- char const *columnText;
- int startingWidth;
- int minWidth;
- int maxWidth;
- int flags;
- SortFunc *pfnSort;
- Label::Alignment alignment;
-};
-
-static ColumnInfo_t g_ColInfo[] =
-{
- { "text", "#FileOpenDialog_Col_Name", 175, 20, 10000, ListPanel::COLUMN_UNHIDABLE, &ListFileNameSortFunc , Label::a_west },
- { "filesize", "#FileOpenDialog_Col_Size", 100, 20, 10000, 0, &ListFileSizeSortFunc , Label::a_east },
- { "type", "#FileOpenDialog_Col_Type", 150, 20, 10000, 0, &ListFileTypeSortFunc , Label::a_west },
- { "modified", "#FileOpenDialog_Col_DateModified", 125, 20, 10000, 0, &ListFileModifiedSortFunc , Label::a_west },
-// { "created", "#FileOpenDialog_Col_DateCreated", 125, 20, 10000, ListPanel::COLUMN_HIDDEN, &ListFileCreatedSortFunc , Label::a_west },
- { "attributes", "#FileOpenDialog_Col_Attributes", 50, 20, 10000, ListPanel::COLUMN_HIDDEN, &ListFileAttributesSortFunc , Label::a_west },
-};
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-FileOpenDialog::FileOpenDialog(Panel *parent, const char *title, bool bOpenOnly, KeyValues* pContextKeyValues ) :
- Frame( parent, "FileOpenDialog" )
-{
- m_DialogType = bOpenOnly ? FOD_OPEN : FOD_SAVE;
- Init( title, pContextKeyValues );
-}
-
-
-FileOpenDialog::FileOpenDialog( Panel *parent, const char *title, FileOpenDialogType_t type, KeyValues *pContextKeyValues ) :
- Frame( parent, "FileOpenDialog" )
-{
- m_DialogType = type;
- Init( title, pContextKeyValues );
-}
-
-void FileOpenDialog::Init( const char *title, KeyValues *pContextKeyValues )
-{
- m_bFileSelected = false;
- SetTitle(title, true);
- SetMinimizeButtonVisible(false);
-
-#ifdef POSIX
- Q_strncpy(m_szLastPath, "/", sizeof( m_szLastPath ) );
-#else
- Q_strncpy(m_szLastPath, "c:\\", sizeof( m_szLastPath ) );
-#endif
-
- m_pContextKeyValues = pContextKeyValues;
-
- // Get the list of available drives and put them in a menu here.
- // Start with the directory we are in.
- m_pFullPathEdit = new ComboBox(this, "FullPathEdit", 6, false);
- m_pFullPathEdit->GetTooltip()->SetTooltipFormatToSingleLine();
-
- // list panel
- m_pFileList = new ListPanel(this, "FileList");
- for ( int i = 0; i < ARRAYSIZE( g_ColInfo ); ++i )
- {
- const ColumnInfo_t& info = g_ColInfo[ i ];
-
- m_pFileList->AddColumnHeader( i, info.columnName, info.columnText, info.startingWidth, info.minWidth, info.maxWidth, info.flags );
- m_pFileList->SetSortFunc( i, info.pfnSort );
- m_pFileList->SetColumnTextAlignment( i, info.alignment );
- }
-
- m_pFileList->SetSortColumn( s_nLastSortColumn );
- m_pFileList->SetMultiselectEnabled( false );
-
- // file name edit box
- m_pFileNameEdit = new FileCompletionEdit(this);
- m_pFileNameEdit->AddActionSignalTarget(this);
-
- m_pFileTypeCombo = new ComboBox( this, "FileTypeCombo", 6, false );
-
- switch ( m_DialogType )
- {
- case FOD_OPEN:
- m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this );
- break;
- case FOD_SAVE:
- m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Save", this );
- break;
- case FOD_SELECT_DIRECTORY:
- m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Select", this );
- m_pFileTypeCombo->SetVisible( false );
- break;
- }
-
- m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this );
- m_pFolderUpButton = new Button( this, "FolderUpButton", "", this );
- m_pFolderUpButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_Up" );
- m_pNewFolderButton = new Button( this, "NewFolderButton", "", this );
- m_pNewFolderButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_NewFolder" );
- m_pOpenInExplorerButton = new Button( this, "OpenInExplorerButton", "", this );
-
-#if defined ( OSX )
- m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInFinderButton" );
-#elif defined ( POSIX )
- m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInDesktopManagerButton" );
-#else // Assume Windows / Explorer
- m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInExplorerButton" );
-#endif
-
- Label *lookIn = new Label( this, "LookInLabel", "#FileOpenDialog_Look_in" );
- Label *fileName = new Label( this, "FileNameLabel",
- ( m_DialogType != FOD_SELECT_DIRECTORY ) ? "#FileOpenDialog_File_name" : "#FileOpenDialog_Directory_Name" );
-
- m_pFolderIcon = new ImagePanel(NULL, "FolderIcon");
-
- // set up the control's initial positions
- SetSize( 600, 260 );
-
- int nFileEditLeftSide = ( m_DialogType != FOD_SELECT_DIRECTORY ) ? 84 : 100;
- int nFileNameWidth = ( m_DialogType != FOD_SELECT_DIRECTORY ) ? 72 : 82;
-
- m_pFullPathEdit->SetBounds(67, 32, 310, 24);
- m_pFolderUpButton->SetBounds(362, 32, 24, 24);
- m_pNewFolderButton->SetBounds(392, 32, 24, 24);
- m_pOpenInExplorerButton->SetBounds(332, 32, 24, 24);
- m_pFileList->SetBounds(10, 60, 406, 130);
- m_pFileNameEdit->SetBounds( nFileEditLeftSide, 194, 238, 24);
- m_pFileTypeCombo->SetBounds( nFileEditLeftSide, 224, 238, 24);
- m_pOpenButton->SetBounds(336, 194, 74, 24);
- m_pCancelButton->SetBounds(336, 224, 74, 24);
- lookIn->SetBounds(10, 32, 55, 24);
- fileName->SetBounds(10, 194, nFileNameWidth, 24);
-
- // set autolayout parameters
- m_pFullPathEdit->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_RIGHT, 67, 32, -100, 0 );
- m_pFileNameEdit->SetAutoResize( Panel::PIN_BOTTOMLEFT, Panel::AUTORESIZE_RIGHT, nFileEditLeftSide, -42, -104, 0 );
- m_pFileTypeCombo->SetAutoResize( Panel::PIN_BOTTOMLEFT, Panel::AUTORESIZE_RIGHT, nFileEditLeftSide, -12, -104, 0 );
- m_pFileList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 10, 60, -10, -70 );
-
- m_pFolderUpButton->SetPinCorner( Panel::PIN_TOPRIGHT, -40, 32 );
- m_pNewFolderButton->SetPinCorner( Panel::PIN_TOPRIGHT, -10, 32 );
- m_pOpenInExplorerButton->SetPinCorner( Panel::PIN_TOPRIGHT, -70, 32 );
- m_pOpenButton->SetPinCorner( Panel::PIN_BOTTOMRIGHT, -16, -42 );
- m_pCancelButton->SetPinCorner( Panel::PIN_BOTTOMRIGHT, -16, -12 );
- lookIn->SetPinCorner( Panel::PIN_TOPLEFT, 10, 32 );
- fileName->SetPinCorner( Panel::PIN_BOTTOMLEFT, 10, -42 );
-
- // label settings
- lookIn->SetContentAlignment(Label::a_west);
- fileName->SetContentAlignment(Label::a_west);
-
- lookIn->SetAssociatedControl(m_pFullPathEdit);
- fileName->SetAssociatedControl(m_pFileNameEdit);
-
- if ( m_DialogType != FOD_SELECT_DIRECTORY )
- {
- Label *fileType = new Label(this, "FileTypeLabel", "#FileOpenDialog_File_type");
- fileType->SetBounds(10, 224, 72, 24);
- fileType->SetPinCorner( Panel::PIN_BOTTOMLEFT, 10, -12 );
- fileType->SetContentAlignment(Label::a_west);
- fileType->SetAssociatedControl( m_pFileTypeCombo );
- }
-
- // set tab positions
- GetFocusNavGroup().SetDefaultButton(m_pOpenButton);
-
- m_pFileNameEdit->SetTabPosition(1);
- m_pFileTypeCombo->SetTabPosition(2);
- m_pOpenButton->SetTabPosition(3);
- m_pCancelButton->SetTabPosition(4);
- m_pFullPathEdit->SetTabPosition(5);
- m_pFileList->SetTabPosition(6);
-
- m_pOpenButton->SetCommand( ( m_DialogType != FOD_SELECT_DIRECTORY ) ? new KeyValues( "OnOpen" ) : new KeyValues( "SelectFolder" ) );
- m_pCancelButton->SetCommand( "CloseModal" );
- m_pFolderUpButton->SetCommand( new KeyValues( "OnFolderUp" ) );
- m_pNewFolderButton->SetCommand( new KeyValues( "OnNewFolder" ) );
- m_pOpenInExplorerButton->SetCommand( new KeyValues( "OpenInExplorer" ) );
-
- SetSize( 600, 384 );
-
- m_nStartDirContext = s_StartDirContexts.InvalidIndex();
-
- // Set our starting path to the current directory
- char pLocalPath[255];
- g_pFullFileSystem->GetCurrentDirectory( pLocalPath , 255 );
- if ( !pLocalPath[0] || ( IsOSX() && V_strlen(pLocalPath) <= 2 ) )
- {
- const char *pszHomeDir = getenv( "HOME" );
- V_strcpy_safe( pLocalPath, pszHomeDir );
- }
-
- SetStartDirectory( pLocalPath );
-
- // Because these call through virtual functions, we can't issue them in the constructor, so we post a message to ourselves instead!!
- PostMessage( GetVPanel(), new KeyValues( "PopulateFileList" ) );
- PostMessage( GetVPanel(), new KeyValues( "PopulateDriveList" ) );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-FileOpenDialog::~FileOpenDialog()
-{
- s_nLastSortColumn = m_pFileList->GetSortColumn();
- if ( m_pContextKeyValues )
- {
- m_pContextKeyValues->deleteThis();
- m_pContextKeyValues = NULL;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Apply scheme settings
-//-----------------------------------------------------------------------------
-void FileOpenDialog::ApplySchemeSettings(IScheme *pScheme)
-{
- BaseClass::ApplySchemeSettings(pScheme);
- m_pFolderIcon->SetImage(scheme()->GetImage("resource/icon_folder", false));
- m_pFolderUpButton->AddImage(scheme()->GetImage("resource/icon_folderup", false), -3);
- m_pNewFolderButton->AddImage( scheme()->GetImage("resource/icon_newfolder", false), -3 );
- m_pOpenInExplorerButton->AddImage( scheme()->GetImage("resource/icon_play_once", false), -3 );
-
- ImageList *imageList = new ImageList(false);
- imageList->AddImage(scheme()->GetImage("resource/icon_file", false));
- imageList->AddImage(scheme()->GetImage("resource/icon_folder", false));
- imageList->AddImage(scheme()->GetImage("resource/icon_folder_selected", false));
-
- m_pFileList->SetImageList(imageList, true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Prevent default button ('select') from getting triggered
-// when selecting directories. Instead, open the directory
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnKeyCodeTyped(KeyCode code)
-{
- if ( m_DialogType == FOD_SELECT_DIRECTORY && code == KEY_ENTER )
- {
- OnOpen();
- }
- else
- {
- BaseClass::OnKeyCodeTyped( code );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void FileOpenDialog::PopulateDriveList()
-{
- char fullpath[MAX_PATH * 4];
- char subDirPath[MAX_PATH * 4];
- GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
- Q_strncpy(subDirPath, fullpath, sizeof( subDirPath ) );
-
- m_pFullPathEdit->DeleteAllItems();
-
-#ifdef WIN32
- // populate the drive list
- char buf[512];
- int len = system()->GetAvailableDrives(buf, 512);
- char *pBuf = buf;
- for (int i=0; i < len / 4; i++)
- {
- m_pFullPathEdit->AddItem(pBuf, NULL);
-
- // is this our drive - add all subdirectories
- if (!_strnicmp(pBuf, fullpath, 2))
- {
- int indent = 0;
- char *pData = fullpath;
- while (*pData)
- {
- if ( *pData == CORRECT_PATH_SEPARATOR )
- {
- if (indent > 0)
- {
- memset(subDirPath, ' ', indent);
- memcpy(subDirPath+indent, fullpath, pData-fullpath);
- subDirPath[indent+pData-fullpath] = 0;
-
- m_pFullPathEdit->AddItem(subDirPath, NULL);
- }
- indent += 2;
- }
- pData++;
- }
- }
- pBuf += 4;
- }
-#else
- m_pFullPathEdit->AddItem("/", NULL);
-
- char *pData = fullpath;
- int indent = 0;
- while (*pData)
- {
- if (*pData == '/' && ( pData[1] != '\0' ) )
- {
- if (indent > 0)
- {
- memset(subDirPath, ' ', indent);
- memcpy(subDirPath+indent, fullpath, pData-fullpath);
- subDirPath[indent+pData-fullpath] = 0;
-
- m_pFullPathEdit->AddItem(subDirPath, NULL);
- }
- indent += 2;
- }
- pData++;
- }
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Delete self on close
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnClose()
-{
- s_nLastSortColumn = m_pFileList->GetSortColumn();
- if ( !m_bFileSelected )
- {
- KeyValues *pKeyValues = new KeyValues( "FileSelectionCancelled" );
- PostActionSignal( pKeyValues );
- m_bFileSelected = true;
- }
-
- m_pFileNameEdit->SetText("");
- m_pFileNameEdit->HideMenu();
-
- if ( vgui::input()->GetAppModalSurface() == GetVPanel() )
- {
- input()->SetAppModalSurface(NULL);
- }
-
- BaseClass::OnClose();
-}
-
-void FileOpenDialog::OnFolderUp()
-{
- MoveUpFolder();
- OnOpen();
-}
-
-void FileOpenDialog::OnInputCompleted( KeyValues *data )
-{
- if ( m_hInputDialog.Get() )
- {
- delete m_hInputDialog.Get();
- }
-
- input()->SetAppModalSurface( m_SaveModal );
- m_SaveModal = 0;
-
- NewFolder( data->GetString( "text" ) );
- OnOpen();
-}
-
-void FileOpenDialog::OnInputCanceled()
-{
- input()->SetAppModalSurface( m_SaveModal );
- m_SaveModal = 0;
-}
-
-void FileOpenDialog::OnNewFolder()
-{
- if ( m_hInputDialog.Get() )
- delete m_hInputDialog.Get();
-
- m_hInputDialog = new InputDialog( this, "#FileOpenDialog_NewFolder_InputTitle", "#FileOpenDialog_NewFolderPrompt", "#FileOpenDialog_NewFolder_DefaultName" );
- if ( m_hInputDialog.Get() )
- {
- m_SaveModal = input()->GetAppModalSurface();
-
- KeyValues *pContextKeyValues = new KeyValues( "NewFolder" );
- m_hInputDialog->SetSmallCaption( true );
- m_hInputDialog->SetMultiline( false );
- m_hInputDialog->DoModal( pContextKeyValues );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Opens the current file/folder in explorer
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnOpenInExplorer()
-{
- char pCurrentDirectory[MAX_PATH];
- GetCurrentDirectory( pCurrentDirectory, sizeof(pCurrentDirectory) );
-#if !defined( _X360 ) && defined( WIN32 )
- ShellExecute( NULL, NULL, pCurrentDirectory, NULL, NULL, SW_SHOWNORMAL );
-#elif defined( OSX )
- char szCmd[ MAX_PATH * 2];
- Q_snprintf( szCmd, sizeof(szCmd), "/usr/bin/open \"%s\"", pCurrentDirectory );
- ::system( szCmd );
-#elif defined( LINUX )
- char szCmd[ MAX_PATH * 2 ];
- Q_snprintf( szCmd, sizeof(szCmd), "xdg-open \"%s\" &", pCurrentDirectory );
- ::system( szCmd );
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Handle for button commands
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnCommand(const char *command)
-{
- if (!stricmp(command, "Cancel"))
- {
- Close();
- }
- else
- {
- BaseClass::OnCommand(command);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Sets the start directory context (and resets the start directory in the process)
-//-----------------------------------------------------------------------------
-void FileOpenDialog::SetStartDirectoryContext( const char *pStartDirContext, const char *pDefaultDir )
-{
- bool bUseCurrentDirectory = true;
- if ( pStartDirContext )
- {
- m_nStartDirContext = s_StartDirContexts.Find( pStartDirContext );
- if ( m_nStartDirContext == s_StartDirContexts.InvalidIndex() )
- {
- m_nStartDirContext = s_StartDirContexts.Insert( pStartDirContext, pDefaultDir );
- bUseCurrentDirectory = ( pDefaultDir == NULL );
- }
- else
- {
- bUseCurrentDirectory = false;
- }
- }
- else
- {
- m_nStartDirContext = s_StartDirContexts.InvalidIndex();
- }
-
- if ( !bUseCurrentDirectory )
- {
- SetStartDirectory( s_StartDirContexts[m_nStartDirContext].Get() );
- }
- else
- {
- // Set our starting path to the current directory
- char pLocalPath[255];
- g_pFullFileSystem->GetCurrentDirectory( pLocalPath, 255 );
- SetStartDirectory( pLocalPath );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the starting directory of the file search.
-//-----------------------------------------------------------------------------
-void FileOpenDialog::SetStartDirectory( const char *dir )
-{
- m_pFullPathEdit->SetText(dir);
-
- // ensure it's validity
- ValidatePath();
-
- // Store this in the start directory list
- if ( m_nStartDirContext != s_StartDirContexts.InvalidIndex() )
- {
- char pDirBuf[MAX_PATH];
- GetCurrentDirectory( pDirBuf, sizeof(pDirBuf) );
- s_StartDirContexts[ m_nStartDirContext ] = pDirBuf;
- }
-
- PopulateDriveList();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Add filters for the drop down combo box
-//-----------------------------------------------------------------------------
-void FileOpenDialog::AddFilter( const char *filter, const char *filterName, bool bActive, const char *pFilterInfo )
-{
- KeyValues *kv = new KeyValues("item");
- kv->SetString( "filter", filter );
- kv->SetString( "filterinfo", pFilterInfo );
- int itemID = m_pFileTypeCombo->AddItem(filterName, kv);
- if ( bActive )
- {
- m_pFileTypeCombo->ActivateItem(itemID);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Activate the dialog
-//-----------------------------------------------------------------------------
-void FileOpenDialog::DoModal( bool bUnused )
-{
- m_bFileSelected = false;
- m_pFileNameEdit->RequestFocus();
- BaseClass::DoModal();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the directory this is currently in
-//-----------------------------------------------------------------------------
-void FileOpenDialog::GetCurrentDirectory(char *buf, int bufSize)
-{
- // get the text from the text entry
- m_pFullPathEdit->GetText(buf, bufSize);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the last selected file name
-//-----------------------------------------------------------------------------
-void FileOpenDialog::GetSelectedFileName(char *buf, int bufSize)
-{
- m_pFileNameEdit->GetText(buf, bufSize);
-}
-
-
-//-----------------------------------------------------------------------------
-// Creates a new folder
-//-----------------------------------------------------------------------------
-void FileOpenDialog::NewFolder( char const *folderName )
-{
- char pCurrentDirectory[MAX_PATH];
- GetCurrentDirectory( pCurrentDirectory, sizeof(pCurrentDirectory) );
-
- char pFullPath[MAX_PATH];
- char pNewFolderName[MAX_PATH];
- Q_strncpy( pNewFolderName, folderName, sizeof(pNewFolderName) );
- int i = 2;
- do
- {
- Q_MakeAbsolutePath( pFullPath, sizeof(pFullPath), pNewFolderName, pCurrentDirectory );
- if ( !g_pFullFileSystem->FileExists( pFullPath, NULL ) &&
- !g_pFullFileSystem->IsDirectory( pFullPath, NULL ) )
- {
- g_pFullFileSystem->CreateDirHierarchy( pFullPath, NULL );
- m_pFileNameEdit->SetText( pNewFolderName );
- return;
- }
-
- Q_snprintf( pNewFolderName, sizeof(pNewFolderName), "%s%d", folderName, i );
- ++i;
- } while ( i <= 999 );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Move the directory structure up
-//-----------------------------------------------------------------------------
-void FileOpenDialog::MoveUpFolder()
-{
- char fullpath[MAX_PATH * 4];
- GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
-
- Q_StripLastDir( fullpath, sizeof( fullpath ) );
- // append a trailing slash
- Q_AppendSlash( fullpath, sizeof( fullpath ) );
-
- SetStartDirectory(fullpath);
- PopulateFileList();
- InvalidateLayout();
- Repaint();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Validate that the current path is valid
-//-----------------------------------------------------------------------------
-void FileOpenDialog::ValidatePath()
-{
- char fullpath[MAX_PATH * 4];
- GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
- Q_RemoveDotSlashes( fullpath );
-
- // when statting a directory on Windows, you want to include
- // the terminal slash exactly when you are statting a root
- // directory. PKMN.
-#ifdef _WIN32
- if ( Q_strlen( fullpath ) != 3 )
- {
- Q_StripTrailingSlash( fullpath );
- }
-#endif
- // cleanup the path, we format tabs into the list to make it pretty in the UI
- Q_StripPrecedingAndTrailingWhitespace( fullpath );
-
- struct _stat buf;
- if ( ( 0 == _stat( fullpath, &buf ) ) &&
- ( 0 != ( buf.st_mode & S_IFDIR ) ) )
- {
- Q_AppendSlash( fullpath, sizeof( fullpath ) );
- Q_strncpy(m_szLastPath, fullpath, sizeof(m_szLastPath));
- }
- else
- {
- // failed to load file, use the previously successful path
- }
-
- m_pFullPathEdit->SetText(m_szLastPath);
- m_pFullPathEdit->GetTooltip()->SetText(m_szLastPath);
-}
-
-#ifdef WIN32
-const char *GetAttributesAsString( DWORD dwAttributes )
-{
- static char out[ 256 ];
- out[ 0 ] = 0;
- if ( dwAttributes & FILE_ATTRIBUTE_ARCHIVE )
- {
- Q_strncat( out, "A", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_COMPRESSED )
- {
- Q_strncat( out, "C", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY )
- {
- Q_strncat( out, "D", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_HIDDEN )
- {
- Q_strncat( out, "H", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_READONLY )
- {
- Q_strncat( out, "R", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_SYSTEM )
- {
- Q_strncat( out, "S", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- if ( dwAttributes & FILE_ATTRIBUTE_TEMPORARY )
- {
- Q_strncat( out, "T", sizeof( out ), COPY_ALL_CHARACTERS );
- }
- return out;
-}
-
-const char *GetFileTimetamp( FILETIME ft )
-{
- SYSTEMTIME local;
- FILETIME localFileTime;
- FileTimeToLocalFileTime( &ft, &localFileTime );
- FileTimeToSystemTime( &localFileTime, &local );
-
- static char out[ 256 ];
-
- bool am = true;
- WORD hour = local.wHour;
- if ( hour >= 12 )
- {
- am = false;
- // 12:42 pm displays as 12:42 pm
- // 13:42 pm displays as 1:42 pm
- if ( hour > 12 )
- {
- hour -= 12;
- }
- }
- Q_snprintf( out, sizeof( out ), "%d/%02d/%04d %d:%02d %s",
- local.wMonth,
- local.wDay,
- local.wYear,
- hour,
- local.wMinute,
- am ? "AM" : "PM" // TODO: Localize this?
- );
- return out;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: Fill the filelist with the names of all the files in the current directory
-//-----------------------------------------------------------------------------
-#define MAX_FILTER_LENGTH 255
-void FileOpenDialog::PopulateFileList()
-{
- // clear the current list
- m_pFileList->DeleteAllItems();
-
- FileFindHandle_t findHandle;
- char pszFileModified[64];
-
- // get the current directory
- char currentDir[MAX_PATH * 4];
- char dir[MAX_PATH * 4];
- char filterList[MAX_FILTER_LENGTH+1];
- GetCurrentDirectory(currentDir, sizeof(dir));
-
- KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
- if (combokv)
- {
- Q_strncpy(filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH);
- }
- else
- {
- // add wildcard for search
- Q_strncpy(filterList, "*\0", MAX_FILTER_LENGTH);
- }
-
-
- char *filterPtr = filterList;
- KeyValues *kv = new KeyValues("item");
-
- if ( m_DialogType != FOD_SELECT_DIRECTORY )
- {
- while ((filterPtr != NULL) && (*filterPtr != 0))
- {
- // parse the next filter in the list.
- char curFilter[MAX_FILTER_LENGTH];
- curFilter[0] = 0;
- int i = 0;
- while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
- {
- ++filterPtr;
- }
- while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
- {
- curFilter[i++] = *(filterPtr++);
- }
- curFilter[i] = 0;
-
- if (curFilter[0] == 0)
- {
- break;
- }
-
- Q_snprintf( dir, MAX_PATH*4, "%s%s", currentDir, curFilter );
-
- // Open the directory and walk it, loading files
- const char *pszFileName = g_pFullFileSystem->FindFirst( dir, &findHandle );
- while ( pszFileName )
- {
- if ( !g_pFullFileSystem->FindIsDirectory( findHandle )
- || !IsOSX()
- || ( IsOSX() && g_pFullFileSystem->FindIsDirectory( findHandle ) && Q_stristr( pszFileName, ".app" ) ) )
- {
- char pFullPath[MAX_PATH];
- Q_snprintf( pFullPath, MAX_PATH, "%s%s", currentDir, pszFileName );
-
- // add the file to the list
- kv->SetString( "text", pszFileName );
-
- kv->SetInt( "image", 1 );
-
- IImage *image = surface()->GetIconImageForFullPath( pFullPath );
-
- if ( image )
- {
- kv->SetPtr( "iconImage", (void *)image );
- }
-
- kv->SetInt("imageSelected", 1);
- kv->SetInt("directory", 0);
-
- kv->SetString( "filesize", Q_pretifymem( g_pFullFileSystem->Size( pFullPath ), 0, true ) );
- Q_FixSlashes( pFullPath );
- wchar_t fileType[ 80 ];
- g_pFullFileSystem->GetFileTypeForFullPath( pFullPath, fileType, sizeof( fileType ) );
- kv->SetWString( "type", fileType );
-
- kv->SetString( "attributes", g_pFullFileSystem->IsFileWritable( pFullPath )? "" : "R" );
-
- long fileModified = g_pFullFileSystem->GetFileTime( pFullPath );
- g_pFullFileSystem->FileTimeToString( pszFileModified, sizeof( pszFileModified ), fileModified );
- kv->SetString( "modified", pszFileModified );
-
-// kv->SetString( "created", GetFileTimetamp( findData.ftCreationTime ) );
-
- m_pFileList->AddItem(kv, 0, false, false);
- }
-
- pszFileName = g_pFullFileSystem->FindNext( findHandle );
- }
- g_pFullFileSystem->FindClose( findHandle );
- }
- }
-
- // find all the directories
- GetCurrentDirectory( dir, sizeof(dir) );
- Q_strncat(dir, "*", sizeof( dir ), COPY_ALL_CHARACTERS);
-
- const char *pszFileName = g_pFullFileSystem->FindFirst( dir, &findHandle );
- while ( pszFileName )
- {
- if ( pszFileName[0] != '.' && g_pFullFileSystem->FindIsDirectory( findHandle )
- && ( !IsOSX() || ( IsOSX() && !Q_stristr( pszFileName, ".app" ) ) ) )
- {
- char pFullPath[MAX_PATH];
- Q_snprintf( pFullPath, MAX_PATH, "%s%s", currentDir, pszFileName );
-
- kv->SetString("text", pszFileName );
- kv->SetPtr( "iconImage", (void *)NULL );
- kv->SetInt("image", 2);
- kv->SetInt("imageSelected", 3);
- kv->SetInt("directory", 1);
-
- kv->SetString( "filesize", "" );
- kv->SetString( "type", "#FileOpenDialog_FileType_Folder" );
-
- kv->SetString( "attributes", g_pFullFileSystem->IsFileWritable( pFullPath )? "" : "R" );
-
- long fileModified = g_pFullFileSystem->GetFileTime( pFullPath );
- g_pFullFileSystem->FileTimeToString( pszFileModified, sizeof( pszFileModified ), fileModified );
- kv->SetString( "modified", pszFileModified );
-
-// kv->SetString( "created", GetFileTimetamp( findData.ftCreationTime ) );
-
- m_pFileList->AddItem( kv, 0, false, false );
- }
-
- pszFileName = g_pFullFileSystem->FindNext( findHandle );
- }
- g_pFullFileSystem->FindClose( findHandle );
-
- kv->deleteThis();
- m_pFileList->SortList();
-}
-
-
-//-----------------------------------------------------------------------------
-// Does the specified extension match something in the filter list?
-//-----------------------------------------------------------------------------
-bool FileOpenDialog::ExtensionMatchesFilter( const char *pExt )
-{
- KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
- if ( !combokv )
- return true;
-
- char filterList[MAX_FILTER_LENGTH+1];
- Q_strncpy( filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH );
-
- char *filterPtr = filterList;
- while ((filterPtr != NULL) && (*filterPtr != 0))
- {
- // parse the next filter in the list.
- char curFilter[MAX_FILTER_LENGTH];
- curFilter[0] = 0;
- int i = 0;
- while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
- {
- ++filterPtr;
- }
- while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
- {
- curFilter[i++] = *(filterPtr++);
- }
- curFilter[i] = 0;
-
- if (curFilter[0] == 0)
- break;
-
- if ( !Q_stricmp( curFilter, "*" ) || !Q_stricmp( curFilter, "*.*" ) )
- return true;
-
- // FIXME: This isn't exactly right, but tough cookies;
- // it assumes the first two characters of the filter are *.
- Assert( curFilter[0] == '*' && curFilter[1] == '.' );
- if ( !Q_stricmp( &curFilter[2], pExt ) )
- return true;
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-// Choose the first non *.* filter in the filter list
-//-----------------------------------------------------------------------------
-void FileOpenDialog::ChooseExtension( char *pExt, int nBufLen )
-{
- pExt[0] = 0;
-
- KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
- if ( !combokv )
- return;
-
- char filterList[MAX_FILTER_LENGTH+1];
- Q_strncpy( filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH );
-
- char *filterPtr = filterList;
- while ((filterPtr != NULL) && (*filterPtr != 0))
- {
- // parse the next filter in the list.
- char curFilter[MAX_FILTER_LENGTH];
- curFilter[0] = 0;
- int i = 0;
- while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
- {
- ++filterPtr;
- }
- while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
- {
- curFilter[i++] = *(filterPtr++);
- }
- curFilter[i] = 0;
-
- if (curFilter[0] == 0)
- break;
-
- if ( !Q_stricmp( curFilter, "*" ) || !Q_stricmp( curFilter, "*.*" ) )
- continue;
-
- // FIXME: This isn't exactly right, but tough cookies;
- // it assumes the first two characters of the filter are *.
- Assert( curFilter[0] == '*' && curFilter[1] == '.' );
- Q_strncpy( pExt, &curFilter[1], nBufLen );
- break;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Saves the file to the start dir context
-//-----------------------------------------------------------------------------
-void FileOpenDialog::SaveFileToStartDirContext( const char *pFullPath )
-{
- if ( m_nStartDirContext == s_StartDirContexts.InvalidIndex() )
- return;
-
- char pPath[MAX_PATH];
- pPath[0] = 0;
- Q_ExtractFilePath( pFullPath, pPath, sizeof(pPath) );
- s_StartDirContexts[ m_nStartDirContext ] = pPath;
-}
-
-
-//-----------------------------------------------------------------------------
-// Posts a file selected message
-//-----------------------------------------------------------------------------
-void FileOpenDialog::PostFileSelectedMessage( const char *pFileName )
-{
- m_bFileSelected = true;
-
- // open the file!
- KeyValues *pKeyValues = new KeyValues( "FileSelected", "fullpath", pFileName );
- KeyValues *pFilterKeys = m_pFileTypeCombo->GetActiveItemUserData();
- const char *pFilterInfo = pFilterKeys ? pFilterKeys->GetString( "filterinfo", NULL ) : NULL;
- if ( pFilterInfo )
- {
- pKeyValues->SetString( "filterinfo", pFilterInfo );
- }
- if ( m_pContextKeyValues )
- {
- pKeyValues->AddSubKey( m_pContextKeyValues );
- m_pContextKeyValues = NULL;
- }
- PostActionSignal( pKeyValues );
- CloseModal();
-}
-
-
-//-----------------------------------------------------------------------------
-// Selects the current folder
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnSelectFolder()
-{
- ValidatePath();
-
- // construct a file path
- char pFileName[MAX_PATH];
- GetSelectedFileName( pFileName, sizeof( pFileName ) );
-
- Q_StripTrailingSlash( pFileName );
-
- if ( !stricmp(pFileName, "..") )
- {
- MoveUpFolder();
-
- // clear the name text
- m_pFileNameEdit->SetText("");
- return;
- }
-
- if ( !stricmp(pFileName, ".") )
- {
- // clear the name text
- m_pFileNameEdit->SetText("");
- return;
- }
-
- // Compute the full path
- char pFullPath[MAX_PATH * 4];
- if ( !Q_IsAbsolutePath( pFileName ) )
- {
- GetCurrentDirectory(pFullPath, sizeof(pFullPath) - MAX_PATH);
- strcat( pFullPath, pFileName );
- if ( !pFileName[0] )
- {
- Q_StripTrailingSlash( pFullPath );
- }
- }
- else
- {
- Q_strncpy( pFullPath, pFileName, sizeof(pFullPath) );
- }
-
- if ( g_pFullFileSystem->FileExists( pFullPath ) )
- {
- // open the file!
- SaveFileToStartDirContext( pFullPath );
- PostFileSelectedMessage( pFullPath );
- return;
- }
-
- PopulateDriveList();
- PopulateFileList();
- InvalidateLayout();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Handle the open button being pressed
-// checks on what has changed and acts accordingly
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnOpen()
-{
- ValidatePath();
-
- // construct a file path
- char pFileName[MAX_PATH];
- GetSelectedFileName( pFileName, sizeof( pFileName ) );
-
- int nLen = Q_strlen( pFileName );
- bool bSpecifiedDirectory = ( pFileName[nLen-1] == '/' || pFileName[nLen-1] == '\\' ) && (!IsOSX() || ( IsOSX() && !Q_stristr( pFileName, ".app" ) ) );
- Q_StripTrailingSlash( pFileName );
-
- if ( !stricmp(pFileName, "..") )
- {
- MoveUpFolder();
-
- // clear the name text
- m_pFileNameEdit->SetText("");
- return;
- }
-
- if ( !stricmp(pFileName, ".") )
- {
- // clear the name text
- m_pFileNameEdit->SetText("");
- return;
- }
-
- // Compute the full path
- char pFullPath[MAX_PATH * 4];
- if ( !Q_IsAbsolutePath( pFileName ) )
- {
- GetCurrentDirectory(pFullPath, sizeof(pFullPath) - MAX_PATH);
- Q_AppendSlash( pFullPath, sizeof( pFullPath ) );
- strcat(pFullPath, pFileName);
- if ( !pFileName[0] )
- {
- Q_StripTrailingSlash( pFullPath );
- }
- }
- else
- {
- Q_strncpy( pFullPath, pFileName, sizeof(pFullPath) );
- }
-
- Q_StripTrailingSlash( pFullPath );
-
- // when statting a directory on Windows, you want to include
- // the terminal slash exactly when you are statting a root
- // directory. PKMN.
-#ifdef _WIN32
- if ( Q_strlen( pFullPath ) == 2 )
- {
- Q_AppendSlash( pFullPath, Q_ARRAYSIZE( pFullPath ) );
- }
-#endif
-
-
- // If the name specified is a directory, then change directory
- if ( g_pFullFileSystem->IsDirectory( pFullPath, NULL ) &&
- ( !IsOSX() || ( IsOSX() && !Q_stristr( pFullPath, ".app" ) ) ) )
- {
- // it's a directory; change to the specified directory
- if ( !bSpecifiedDirectory )
- {
- Q_AppendSlash( pFullPath, Q_ARRAYSIZE( pFullPath ) );
- }
- SetStartDirectory( pFullPath );
-
- // clear the name text
- m_pFileNameEdit->SetText("");
- m_pFileNameEdit->HideMenu();
-
- PopulateDriveList();
- PopulateFileList();
- InvalidateLayout();
- return;
- }
- else if ( bSpecifiedDirectory )
- {
- PopulateDriveList();
- PopulateFileList();
- InvalidateLayout();
- return;
- }
-
- // Append suffix of the first filter that isn't *.*
- char extension[512];
- Q_ExtractFileExtension( pFullPath, extension, sizeof(extension) );
- if ( !ExtensionMatchesFilter( extension ) )
- {
- ChooseExtension( extension, sizeof(extension) );
- Q_SetExtension( pFullPath, extension, sizeof(pFullPath) );
- }
-
- if ( g_pFullFileSystem->FileExists( pFullPath ) )
- {
- // open the file!
- SaveFileToStartDirContext( pFullPath );
- PostFileSelectedMessage( pFullPath );
- return;
- }
-
- // file not found
- if ( ( m_DialogType == FOD_SAVE ) && pFileName[0] )
- {
- // open the file!
- SaveFileToStartDirContext( pFullPath );
- PostFileSelectedMessage( pFullPath );
- return;
- }
-
- PopulateDriveList();
- PopulateFileList();
- InvalidateLayout();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: using the file edit box as a prefix, create a menu of all possible files
-//-----------------------------------------------------------------------------
-void FileOpenDialog::PopulateFileNameCompletion()
-{
- char buf[80];
- m_pFileNameEdit->GetText(buf, 80);
- wchar_t wbuf[80];
- m_pFileNameEdit->GetText(wbuf, 80);
- int bufLen = wcslen(wbuf);
-
- // delete all items before we check if there's even a string
- m_pFileNameEdit->DeleteAllItems();
-
- // no string at all - don't show even bother showing it
- if (bufLen == 0)
- {
- m_pFileNameEdit->HideMenu();
- return;
- }
-
- // what files use current string as a prefix?
- int nCount = m_pFileList->GetItemCount();
- int i;
- for ( i = 0 ; i < nCount ; i++ )
- {
- KeyValues *kv = m_pFileList->GetItem(m_pFileList->GetItemIDFromRow(i));
- const wchar_t *wszString = kv->GetWString("text");
- if ( !_wcsnicmp(wbuf, wszString, bufLen) )
- {
- m_pFileNameEdit->AddItem(wszString, NULL);
- }
- }
-
- // if there are any items - show the menu
- if ( m_pFileNameEdit->GetItemCount() > 0 )
- {
- m_pFileNameEdit->ShowMenu();
- }
- else
- {
- m_pFileNameEdit->HideMenu();
- }
-
- m_pFileNameEdit->InvalidateLayout();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Handle an item in the list being selected
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnItemSelected()
-{
- // make sure only one item is selected
- if (m_pFileList->GetSelectedItemsCount() != 1)
- {
- m_pFileNameEdit->SetText("");
- }
- else
- {
- // put the file name into the text edit box
- KeyValues *data = m_pFileList->GetItem(m_pFileList->GetSelectedItem(0));
- m_pFileNameEdit->SetText(data->GetString("text"));
- }
-
- InvalidateLayout();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Handle an item in the Drive combo box being selected
-//-----------------------------------------------------------------------------
-void FileOpenDialog::OnTextChanged(KeyValues *kv)
-{
- Panel *pPanel = (Panel *) kv->GetPtr("panel", NULL);
-
- // first check which control had its text changed!
- if (pPanel == m_pFullPathEdit)
- {
- m_pFileNameEdit->HideMenu();
- m_pFileNameEdit->SetText("");
- OnOpen();
- }
- else if (pPanel == m_pFileNameEdit)
- {
- PopulateFileNameCompletion();
- }
- else if (pPanel == m_pFileTypeCombo)
- {
- m_pFileNameEdit->HideMenu();
- PopulateFileList();
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implementation of vgui generic open file dialog
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#define PROTECTED_THINGS_DISABLE
+
+#if !defined( _X360 ) && defined( WIN32 )
+#include "winlite.h"
+#include <shellapi.h>
+#elif defined( POSIX )
+#include <stdlib.h>
+#define _stat stat
+#define _wcsnicmp wcsncmp
+#elif defined( _X360 )
+#else
+#error
+#endif
+
+#undef GetCurrentDirectory
+#include "filesystem.h"
+#include <sys/stat.h>
+
+#include "tier1/utldict.h"
+#include "tier1/utlstring.h"
+
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui/ISystem.h>
+#include <KeyValues.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IInput.h>
+
+#include <vgui_controls/FileOpenDialog.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui_controls/InputDialog.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/ImageList.h>
+#include <vgui_controls/MenuItem.h>
+#include <vgui_controls/Tooltip.h>
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#undef GetCurrentDirectory
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+static int s_nLastSortColumn = 0;
+
+static int ListFileNameSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ NOTE_UNUSED( pPanel );
+
+ bool dir1 = item1.kv->GetInt("directory") == 1;
+ bool dir2 = item2.kv->GetInt("directory") == 1;
+
+ // if they're both not directories of files, return if dir1 is a directory (before files)
+ if (dir1 != dir2)
+ {
+ return dir1 ? -1 : 1;
+ }
+
+ const char *string1 = item1.kv->GetString("text");
+ const char *string2 = item2.kv->GetString("text");
+
+ // YWB: Mimic windows behavior where filenames starting with numbers are sorted based on numeric part
+ int num1 = Q_atoi( string1 );
+ int num2 = Q_atoi( string2 );
+
+ if ( num1 != 0 &&
+ num2 != 0 )
+ {
+ if ( num1 < num2 )
+ return -1;
+ else if ( num1 > num2 )
+ return 1;
+ }
+
+ // Push numbers before everything else
+ if ( num1 != 0 )
+ {
+ return -1;
+ }
+
+ // Push numbers before everything else
+ if ( num2 != 0 )
+ {
+ return 1;
+ }
+
+ return Q_stricmp( string1, string2 );
+}
+
+static int ListBaseStringSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *fieldName )
+{
+ bool dir1 = item1.kv->GetInt("directory") == 1;
+ bool dir2 = item2.kv->GetInt("directory") == 1;
+
+ // if they're both not directories of files, return if dir1 is a directory (before files)
+ if (dir1 != dir2)
+ {
+ return -1;
+ }
+
+ const char *string1 = item1.kv->GetString(fieldName);
+ const char *string2 = item2.kv->GetString(fieldName);
+ int cval = Q_stricmp(string1, string2);
+ if ( cval == 0 )
+ {
+ // Use filename to break ties
+ return ListFileNameSortFunc( pPanel, item1, item2 );
+ }
+
+ return cval;
+}
+
+static int ListBaseIntegerSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *fieldName )
+{
+ bool dir1 = item1.kv->GetInt("directory") == 1;
+ bool dir2 = item2.kv->GetInt("directory") == 1;
+
+ // if they're both not directories of files, return if dir1 is a directory (before files)
+ if (dir1 != dir2)
+ {
+ return -1;
+ }
+
+ int i1 = item1.kv->GetInt(fieldName);
+ int i2 = item2.kv->GetInt(fieldName);
+ if ( i1 == i2 )
+ {
+ // Use filename to break ties
+ return ListFileNameSortFunc( pPanel, item1, item2 );
+ }
+
+ return ( i1 < i2 ) ? -1 : 1;
+}
+
+static int ListBaseInteger64SortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2, char const *lowfield, char const *highfield )
+{
+ bool dir1 = item1.kv->GetInt("directory") == 1;
+ bool dir2 = item2.kv->GetInt("directory") == 1;
+
+ // if they're both not directories of files, return if dir1 is a directory (before files)
+ if (dir1 != dir2)
+ {
+ return dir1 ? -1 : 1;
+ }
+
+ uint32 l1 = item1.kv->GetInt(lowfield);
+ uint32 h1 = item1.kv->GetInt(highfield);
+ uint32 l2 = item2.kv->GetInt(lowfield);
+ uint32 h2 = item2.kv->GetInt(highfield);
+ uint64 i1 = (uint64)( (uint64)l1 | ( (uint64)h1 << 32 ) );
+ uint64 i2 = (uint64)( (uint64)l2 | ( (uint64)h2 << 32 ) );
+
+ if ( i1 == i2 )
+ {
+ // Use filename to break ties
+ return ListFileNameSortFunc( pPanel, item1, item2 );
+ }
+
+ return ( i1 < i2 ) ? -1 : 1;
+}
+
+
+static int ListFileSizeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ return ListBaseIntegerSortFunc( pPanel, item1, item2, "filesizeint" );
+}
+
+static int ListFileModifiedSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ // NOTE: Backward order to get most recent files first
+ return ListBaseInteger64SortFunc( pPanel, item2, item1, "modifiedint_low", "modifiedint_high" );
+}
+static int ListFileCreatedSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ // NOTE: Backward order to get most recent files first
+ return ListBaseInteger64SortFunc( pPanel, item2, item1, "createdint_low", "createdint_high" );
+}
+static int ListFileAttributesSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ return ListBaseStringSortFunc( pPanel, item1, item2, "attributes" );
+}
+static int ListFileTypeSortFunc(ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ return ListBaseStringSortFunc( pPanel, item1, item2, "type" );
+}
+
+
+
+namespace vgui
+{
+
+class FileCompletionMenu : public Menu
+{
+public:
+ FileCompletionMenu(Panel *parent, const char *panelName) : Menu(parent, panelName)
+ {
+ }
+
+ // override it so it doesn't request focus
+ virtual void SetVisible(bool state)
+ {
+ Panel::SetVisible(state);
+ }
+
+};
+
+
+//-----------------------------------------------------------------------------
+// File completion edit text entry
+//-----------------------------------------------------------------------------
+class FileCompletionEdit : public TextEntry
+{
+ DECLARE_CLASS_SIMPLE( FileCompletionEdit, TextEntry );
+
+public:
+ FileCompletionEdit(Panel *parent);
+ ~FileCompletionEdit();
+
+ int AddItem(const char *itemText, KeyValues *userData);
+ int AddItem(const wchar_t *itemText, KeyValues *userData);
+ void DeleteAllItems();
+ int GetItemCount();
+ int GetItemIDFromRow(int row);
+ int GetRowFromItemID(int itemID);
+ virtual void PerformLayout();
+ void OnSetText(const wchar_t *newtext);
+ virtual void OnKillFocus();
+ void HideMenu(void);
+ void ShowMenu(void);
+ virtual void OnKeyCodeTyped(KeyCode code);
+ MESSAGE_FUNC_INT( OnMenuItemHighlight, "MenuItemHighlight", itemID );
+
+private:
+ FileCompletionMenu *m_pDropDown;
+};
+
+
+
+FileCompletionEdit::FileCompletionEdit(Panel *parent) : TextEntry(parent, NULL)
+{
+ m_pDropDown = new FileCompletionMenu(this, NULL);
+ m_pDropDown->AddActionSignalTarget(this);
+}
+
+FileCompletionEdit::~FileCompletionEdit()
+{
+ delete m_pDropDown;
+}
+
+int FileCompletionEdit::AddItem(const char *itemText, KeyValues *userData)
+{
+ // when the menu item is selected it will send the custom message "SetText"
+ return m_pDropDown->AddMenuItem(itemText, new KeyValues("SetText", "text", itemText), this, userData);
+}
+int FileCompletionEdit::AddItem(const wchar_t *itemText, KeyValues *userData)
+{
+ // add the element to the menu
+ // when the menu item is selected it will send the custom message "SetText"
+ KeyValues *kv = new KeyValues("SetText");
+ kv->SetWString("text", itemText);
+
+ // get an ansi version for the menuitem name
+ char ansi[128];
+ g_pVGuiLocalize->ConvertUnicodeToANSI(itemText, ansi, sizeof(ansi));
+ return m_pDropDown->AddMenuItem(ansi, kv, this, userData);
+}
+
+void FileCompletionEdit::DeleteAllItems()
+{
+ m_pDropDown->DeleteAllItems();
+}
+
+int FileCompletionEdit::GetItemCount()
+{
+ return m_pDropDown->GetItemCount();
+}
+
+int FileCompletionEdit::GetItemIDFromRow(int row)
+{
+ // valid from [0, GetItemCount)
+ return m_pDropDown->GetMenuID(row);
+}
+
+int FileCompletionEdit::GetRowFromItemID(int itemID)
+{
+ int i;
+ for (i=0;i<GetItemCount();i++)
+ {
+ if (m_pDropDown->GetMenuID(i) == itemID)
+ return i;
+ }
+ return -1;
+}
+
+void FileCompletionEdit::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pDropDown->PositionRelativeToPanel( this, Menu::DOWN, 0 );
+
+ // reset the width of the drop down menu to be the width of this edit box
+ m_pDropDown->SetFixedWidth(GetWide());
+ m_pDropDown->ForceCalculateWidth();
+}
+
+void FileCompletionEdit::OnSetText(const wchar_t *newtext)
+{
+ // see if the combobox text has changed, and if so, post a message detailing the new text
+ wchar_t wbuf[255];
+ GetText( wbuf, 254 );
+
+ if ( wcscmp(wbuf, newtext) )
+ {
+ // text has changed
+ SetText(newtext);
+
+ // fire off that things have changed
+ PostActionSignal(new KeyValues("TextChanged", "text", newtext));
+ Repaint();
+ }
+}
+
+void FileCompletionEdit::OnKillFocus()
+{
+ HideMenu();
+ BaseClass::OnKillFocus();
+}
+
+void FileCompletionEdit::HideMenu(void)
+{
+ // hide the menu
+ m_pDropDown->SetVisible(false);
+}
+
+void FileCompletionEdit::ShowMenu(void)
+{
+ // reset the dropdown's position
+ m_pDropDown->InvalidateLayout();
+
+ // make sure we're at the top of the draw order (and therefore our children as well)
+ // this important to make sure the menu will be drawn in the foreground
+ MoveToFront();
+
+ // reset the drop down
+ m_pDropDown->ClearCurrentlyHighlightedItem();
+
+ // limit it to only 6
+ if (m_pDropDown->GetItemCount() > 6)
+ {
+ m_pDropDown->SetNumberOfVisibleItems(6);
+ }
+ else
+ {
+ m_pDropDown->SetNumberOfVisibleItems(m_pDropDown->GetItemCount());
+ }
+ // show the menu
+ m_pDropDown->SetVisible(true);
+
+ Repaint();
+}
+
+void FileCompletionEdit::OnKeyCodeTyped(KeyCode code)
+{
+ if ( code == KEY_DOWN )
+ {
+ if (m_pDropDown->GetItemCount() > 0)
+ {
+ int menuID = m_pDropDown->GetCurrentlyHighlightedItem();
+ int row = -1;
+ if ( menuID == -1 )
+ {
+ row = m_pDropDown->GetItemCount() - 1;
+ }
+ else
+ {
+ row = GetRowFromItemID(menuID);
+ }
+ row++;
+ if (row == m_pDropDown->GetItemCount())
+ {
+ row = 0;
+ }
+ menuID = GetItemIDFromRow(row);
+ m_pDropDown->SetCurrentlyHighlightedItem(menuID);
+ return;
+ }
+ }
+ else if ( code == KEY_UP )
+ {
+ if (m_pDropDown->GetItemCount() > 0)
+ {
+ int menuID = m_pDropDown->GetCurrentlyHighlightedItem();
+ int row = -1;
+ if ( menuID == -1 )
+ {
+ row = 0;
+ }
+ else
+ {
+ row = GetRowFromItemID(menuID);
+ }
+ row--;
+ if ( row < 0 )
+ {
+ row = m_pDropDown->GetItemCount() - 1;
+ }
+ menuID = GetItemIDFromRow(row);
+ m_pDropDown->SetCurrentlyHighlightedItem(menuID);
+ return;
+ }
+ }
+ else if ( code == KEY_ESCAPE )
+ {
+ if ( m_pDropDown->IsVisible() )
+ {
+ HideMenu();
+ return;
+ }
+ }
+ BaseClass::OnKeyCodeTyped(code);
+ return;
+}
+
+void FileCompletionEdit::OnMenuItemHighlight( int itemID )
+{
+ char wbuf[80];
+ if ( m_pDropDown->IsValidMenuID(itemID) )
+ {
+ m_pDropDown->GetMenuItem(itemID)->GetText(wbuf, 80);
+ }
+ else
+ {
+ wbuf[0] = 0;
+ }
+ SetText(wbuf);
+ RequestFocus();
+ GotoTextEnd();
+}
+
+
+} // namespace vgui
+
+
+//-----------------------------------------------------------------------------
+// Dictionary of start dir contexts
+//-----------------------------------------------------------------------------
+static CUtlDict< CUtlString, unsigned short > s_StartDirContexts;
+
+struct ColumnInfo_t
+{
+ char const *columnName;
+ char const *columnText;
+ int startingWidth;
+ int minWidth;
+ int maxWidth;
+ int flags;
+ SortFunc *pfnSort;
+ Label::Alignment alignment;
+};
+
+static ColumnInfo_t g_ColInfo[] =
+{
+ { "text", "#FileOpenDialog_Col_Name", 175, 20, 10000, ListPanel::COLUMN_UNHIDABLE, &ListFileNameSortFunc , Label::a_west },
+ { "filesize", "#FileOpenDialog_Col_Size", 100, 20, 10000, 0, &ListFileSizeSortFunc , Label::a_east },
+ { "type", "#FileOpenDialog_Col_Type", 150, 20, 10000, 0, &ListFileTypeSortFunc , Label::a_west },
+ { "modified", "#FileOpenDialog_Col_DateModified", 125, 20, 10000, 0, &ListFileModifiedSortFunc , Label::a_west },
+// { "created", "#FileOpenDialog_Col_DateCreated", 125, 20, 10000, ListPanel::COLUMN_HIDDEN, &ListFileCreatedSortFunc , Label::a_west },
+ { "attributes", "#FileOpenDialog_Col_Attributes", 50, 20, 10000, ListPanel::COLUMN_HIDDEN, &ListFileAttributesSortFunc , Label::a_west },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+FileOpenDialog::FileOpenDialog(Panel *parent, const char *title, bool bOpenOnly, KeyValues* pContextKeyValues ) :
+ Frame( parent, "FileOpenDialog" )
+{
+ m_DialogType = bOpenOnly ? FOD_OPEN : FOD_SAVE;
+ Init( title, pContextKeyValues );
+}
+
+
+FileOpenDialog::FileOpenDialog( Panel *parent, const char *title, FileOpenDialogType_t type, KeyValues *pContextKeyValues ) :
+ Frame( parent, "FileOpenDialog" )
+{
+ m_DialogType = type;
+ Init( title, pContextKeyValues );
+}
+
+void FileOpenDialog::Init( const char *title, KeyValues *pContextKeyValues )
+{
+ m_bFileSelected = false;
+ SetTitle(title, true);
+ SetMinimizeButtonVisible(false);
+
+#ifdef POSIX
+ Q_strncpy(m_szLastPath, "/", sizeof( m_szLastPath ) );
+#else
+ Q_strncpy(m_szLastPath, "c:\\", sizeof( m_szLastPath ) );
+#endif
+
+ m_pContextKeyValues = pContextKeyValues;
+
+ // Get the list of available drives and put them in a menu here.
+ // Start with the directory we are in.
+ m_pFullPathEdit = new ComboBox(this, "FullPathEdit", 6, false);
+ m_pFullPathEdit->GetTooltip()->SetTooltipFormatToSingleLine();
+
+ // list panel
+ m_pFileList = new ListPanel(this, "FileList");
+ for ( int i = 0; i < ARRAYSIZE( g_ColInfo ); ++i )
+ {
+ const ColumnInfo_t& info = g_ColInfo[ i ];
+
+ m_pFileList->AddColumnHeader( i, info.columnName, info.columnText, info.startingWidth, info.minWidth, info.maxWidth, info.flags );
+ m_pFileList->SetSortFunc( i, info.pfnSort );
+ m_pFileList->SetColumnTextAlignment( i, info.alignment );
+ }
+
+ m_pFileList->SetSortColumn( s_nLastSortColumn );
+ m_pFileList->SetMultiselectEnabled( false );
+
+ // file name edit box
+ m_pFileNameEdit = new FileCompletionEdit(this);
+ m_pFileNameEdit->AddActionSignalTarget(this);
+
+ m_pFileTypeCombo = new ComboBox( this, "FileTypeCombo", 6, false );
+
+ switch ( m_DialogType )
+ {
+ case FOD_OPEN:
+ m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this );
+ break;
+ case FOD_SAVE:
+ m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Save", this );
+ break;
+ case FOD_SELECT_DIRECTORY:
+ m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Select", this );
+ m_pFileTypeCombo->SetVisible( false );
+ break;
+ }
+
+ m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this );
+ m_pFolderUpButton = new Button( this, "FolderUpButton", "", this );
+ m_pFolderUpButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_Up" );
+ m_pNewFolderButton = new Button( this, "NewFolderButton", "", this );
+ m_pNewFolderButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_NewFolder" );
+ m_pOpenInExplorerButton = new Button( this, "OpenInExplorerButton", "", this );
+
+#if defined ( OSX )
+ m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInFinderButton" );
+#elif defined ( POSIX )
+ m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInDesktopManagerButton" );
+#else // Assume Windows / Explorer
+ m_pOpenInExplorerButton->GetTooltip()->SetText( "#FileOpenDialog_ToolTip_OpenInExplorerButton" );
+#endif
+
+ Label *lookIn = new Label( this, "LookInLabel", "#FileOpenDialog_Look_in" );
+ Label *fileName = new Label( this, "FileNameLabel",
+ ( m_DialogType != FOD_SELECT_DIRECTORY ) ? "#FileOpenDialog_File_name" : "#FileOpenDialog_Directory_Name" );
+
+ m_pFolderIcon = new ImagePanel(NULL, "FolderIcon");
+
+ // set up the control's initial positions
+ SetSize( 600, 260 );
+
+ int nFileEditLeftSide = ( m_DialogType != FOD_SELECT_DIRECTORY ) ? 84 : 100;
+ int nFileNameWidth = ( m_DialogType != FOD_SELECT_DIRECTORY ) ? 72 : 82;
+
+ m_pFullPathEdit->SetBounds(67, 32, 310, 24);
+ m_pFolderUpButton->SetBounds(362, 32, 24, 24);
+ m_pNewFolderButton->SetBounds(392, 32, 24, 24);
+ m_pOpenInExplorerButton->SetBounds(332, 32, 24, 24);
+ m_pFileList->SetBounds(10, 60, 406, 130);
+ m_pFileNameEdit->SetBounds( nFileEditLeftSide, 194, 238, 24);
+ m_pFileTypeCombo->SetBounds( nFileEditLeftSide, 224, 238, 24);
+ m_pOpenButton->SetBounds(336, 194, 74, 24);
+ m_pCancelButton->SetBounds(336, 224, 74, 24);
+ lookIn->SetBounds(10, 32, 55, 24);
+ fileName->SetBounds(10, 194, nFileNameWidth, 24);
+
+ // set autolayout parameters
+ m_pFullPathEdit->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_RIGHT, 67, 32, -100, 0 );
+ m_pFileNameEdit->SetAutoResize( Panel::PIN_BOTTOMLEFT, Panel::AUTORESIZE_RIGHT, nFileEditLeftSide, -42, -104, 0 );
+ m_pFileTypeCombo->SetAutoResize( Panel::PIN_BOTTOMLEFT, Panel::AUTORESIZE_RIGHT, nFileEditLeftSide, -12, -104, 0 );
+ m_pFileList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 10, 60, -10, -70 );
+
+ m_pFolderUpButton->SetPinCorner( Panel::PIN_TOPRIGHT, -40, 32 );
+ m_pNewFolderButton->SetPinCorner( Panel::PIN_TOPRIGHT, -10, 32 );
+ m_pOpenInExplorerButton->SetPinCorner( Panel::PIN_TOPRIGHT, -70, 32 );
+ m_pOpenButton->SetPinCorner( Panel::PIN_BOTTOMRIGHT, -16, -42 );
+ m_pCancelButton->SetPinCorner( Panel::PIN_BOTTOMRIGHT, -16, -12 );
+ lookIn->SetPinCorner( Panel::PIN_TOPLEFT, 10, 32 );
+ fileName->SetPinCorner( Panel::PIN_BOTTOMLEFT, 10, -42 );
+
+ // label settings
+ lookIn->SetContentAlignment(Label::a_west);
+ fileName->SetContentAlignment(Label::a_west);
+
+ lookIn->SetAssociatedControl(m_pFullPathEdit);
+ fileName->SetAssociatedControl(m_pFileNameEdit);
+
+ if ( m_DialogType != FOD_SELECT_DIRECTORY )
+ {
+ Label *fileType = new Label(this, "FileTypeLabel", "#FileOpenDialog_File_type");
+ fileType->SetBounds(10, 224, 72, 24);
+ fileType->SetPinCorner( Panel::PIN_BOTTOMLEFT, 10, -12 );
+ fileType->SetContentAlignment(Label::a_west);
+ fileType->SetAssociatedControl( m_pFileTypeCombo );
+ }
+
+ // set tab positions
+ GetFocusNavGroup().SetDefaultButton(m_pOpenButton);
+
+ m_pFileNameEdit->SetTabPosition(1);
+ m_pFileTypeCombo->SetTabPosition(2);
+ m_pOpenButton->SetTabPosition(3);
+ m_pCancelButton->SetTabPosition(4);
+ m_pFullPathEdit->SetTabPosition(5);
+ m_pFileList->SetTabPosition(6);
+
+ m_pOpenButton->SetCommand( ( m_DialogType != FOD_SELECT_DIRECTORY ) ? new KeyValues( "OnOpen" ) : new KeyValues( "SelectFolder" ) );
+ m_pCancelButton->SetCommand( "CloseModal" );
+ m_pFolderUpButton->SetCommand( new KeyValues( "OnFolderUp" ) );
+ m_pNewFolderButton->SetCommand( new KeyValues( "OnNewFolder" ) );
+ m_pOpenInExplorerButton->SetCommand( new KeyValues( "OpenInExplorer" ) );
+
+ SetSize( 600, 384 );
+
+ m_nStartDirContext = s_StartDirContexts.InvalidIndex();
+
+ // Set our starting path to the current directory
+ char pLocalPath[255];
+ g_pFullFileSystem->GetCurrentDirectory( pLocalPath , 255 );
+ if ( !pLocalPath[0] || ( IsOSX() && V_strlen(pLocalPath) <= 2 ) )
+ {
+ const char *pszHomeDir = getenv( "HOME" );
+ V_strcpy_safe( pLocalPath, pszHomeDir );
+ }
+
+ SetStartDirectory( pLocalPath );
+
+ // Because these call through virtual functions, we can't issue them in the constructor, so we post a message to ourselves instead!!
+ PostMessage( GetVPanel(), new KeyValues( "PopulateFileList" ) );
+ PostMessage( GetVPanel(), new KeyValues( "PopulateDriveList" ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+FileOpenDialog::~FileOpenDialog()
+{
+ s_nLastSortColumn = m_pFileList->GetSortColumn();
+ if ( m_pContextKeyValues )
+ {
+ m_pContextKeyValues->deleteThis();
+ m_pContextKeyValues = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Apply scheme settings
+//-----------------------------------------------------------------------------
+void FileOpenDialog::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ m_pFolderIcon->SetImage(scheme()->GetImage("resource/icon_folder", false));
+ m_pFolderUpButton->AddImage(scheme()->GetImage("resource/icon_folderup", false), -3);
+ m_pNewFolderButton->AddImage( scheme()->GetImage("resource/icon_newfolder", false), -3 );
+ m_pOpenInExplorerButton->AddImage( scheme()->GetImage("resource/icon_play_once", false), -3 );
+
+ ImageList *imageList = new ImageList(false);
+ imageList->AddImage(scheme()->GetImage("resource/icon_file", false));
+ imageList->AddImage(scheme()->GetImage("resource/icon_folder", false));
+ imageList->AddImage(scheme()->GetImage("resource/icon_folder_selected", false));
+
+ m_pFileList->SetImageList(imageList, true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Prevent default button ('select') from getting triggered
+// when selecting directories. Instead, open the directory
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnKeyCodeTyped(KeyCode code)
+{
+ if ( m_DialogType == FOD_SELECT_DIRECTORY && code == KEY_ENTER )
+ {
+ OnOpen();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void FileOpenDialog::PopulateDriveList()
+{
+ char fullpath[MAX_PATH * 4];
+ char subDirPath[MAX_PATH * 4];
+ GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
+ Q_strncpy(subDirPath, fullpath, sizeof( subDirPath ) );
+
+ m_pFullPathEdit->DeleteAllItems();
+
+#ifdef WIN32
+ // populate the drive list
+ char buf[512];
+ int len = system()->GetAvailableDrives(buf, 512);
+ char *pBuf = buf;
+ for (int i=0; i < len / 4; i++)
+ {
+ m_pFullPathEdit->AddItem(pBuf, NULL);
+
+ // is this our drive - add all subdirectories
+ if (!_strnicmp(pBuf, fullpath, 2))
+ {
+ int indent = 0;
+ char *pData = fullpath;
+ while (*pData)
+ {
+ if ( *pData == CORRECT_PATH_SEPARATOR )
+ {
+ if (indent > 0)
+ {
+ memset(subDirPath, ' ', indent);
+ memcpy(subDirPath+indent, fullpath, pData-fullpath);
+ subDirPath[indent+pData-fullpath] = 0;
+
+ m_pFullPathEdit->AddItem(subDirPath, NULL);
+ }
+ indent += 2;
+ }
+ pData++;
+ }
+ }
+ pBuf += 4;
+ }
+#else
+ m_pFullPathEdit->AddItem("/", NULL);
+
+ char *pData = fullpath;
+ int indent = 0;
+ while (*pData)
+ {
+ if (*pData == '/' && ( pData[1] != '\0' ) )
+ {
+ if (indent > 0)
+ {
+ memset(subDirPath, ' ', indent);
+ memcpy(subDirPath+indent, fullpath, pData-fullpath);
+ subDirPath[indent+pData-fullpath] = 0;
+
+ m_pFullPathEdit->AddItem(subDirPath, NULL);
+ }
+ indent += 2;
+ }
+ pData++;
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete self on close
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnClose()
+{
+ s_nLastSortColumn = m_pFileList->GetSortColumn();
+ if ( !m_bFileSelected )
+ {
+ KeyValues *pKeyValues = new KeyValues( "FileSelectionCancelled" );
+ PostActionSignal( pKeyValues );
+ m_bFileSelected = true;
+ }
+
+ m_pFileNameEdit->SetText("");
+ m_pFileNameEdit->HideMenu();
+
+ if ( vgui::input()->GetAppModalSurface() == GetVPanel() )
+ {
+ input()->SetAppModalSurface(NULL);
+ }
+
+ BaseClass::OnClose();
+}
+
+void FileOpenDialog::OnFolderUp()
+{
+ MoveUpFolder();
+ OnOpen();
+}
+
+void FileOpenDialog::OnInputCompleted( KeyValues *data )
+{
+ if ( m_hInputDialog.Get() )
+ {
+ delete m_hInputDialog.Get();
+ }
+
+ input()->SetAppModalSurface( m_SaveModal );
+ m_SaveModal = 0;
+
+ NewFolder( data->GetString( "text" ) );
+ OnOpen();
+}
+
+void FileOpenDialog::OnInputCanceled()
+{
+ input()->SetAppModalSurface( m_SaveModal );
+ m_SaveModal = 0;
+}
+
+void FileOpenDialog::OnNewFolder()
+{
+ if ( m_hInputDialog.Get() )
+ delete m_hInputDialog.Get();
+
+ m_hInputDialog = new InputDialog( this, "#FileOpenDialog_NewFolder_InputTitle", "#FileOpenDialog_NewFolderPrompt", "#FileOpenDialog_NewFolder_DefaultName" );
+ if ( m_hInputDialog.Get() )
+ {
+ m_SaveModal = input()->GetAppModalSurface();
+
+ KeyValues *pContextKeyValues = new KeyValues( "NewFolder" );
+ m_hInputDialog->SetSmallCaption( true );
+ m_hInputDialog->SetMultiline( false );
+ m_hInputDialog->DoModal( pContextKeyValues );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Opens the current file/folder in explorer
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnOpenInExplorer()
+{
+ char pCurrentDirectory[MAX_PATH];
+ GetCurrentDirectory( pCurrentDirectory, sizeof(pCurrentDirectory) );
+#if !defined( _X360 ) && defined( WIN32 )
+ ShellExecute( NULL, NULL, pCurrentDirectory, NULL, NULL, SW_SHOWNORMAL );
+#elif defined( OSX )
+ char szCmd[ MAX_PATH * 2];
+ Q_snprintf( szCmd, sizeof(szCmd), "/usr/bin/open \"%s\"", pCurrentDirectory );
+ ::system( szCmd );
+#elif defined( LINUX )
+ char szCmd[ MAX_PATH * 2 ];
+ Q_snprintf( szCmd, sizeof(szCmd), "xdg-open \"%s\" &", pCurrentDirectory );
+ ::system( szCmd );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle for button commands
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the start directory context (and resets the start directory in the process)
+//-----------------------------------------------------------------------------
+void FileOpenDialog::SetStartDirectoryContext( const char *pStartDirContext, const char *pDefaultDir )
+{
+ bool bUseCurrentDirectory = true;
+ if ( pStartDirContext )
+ {
+ m_nStartDirContext = s_StartDirContexts.Find( pStartDirContext );
+ if ( m_nStartDirContext == s_StartDirContexts.InvalidIndex() )
+ {
+ m_nStartDirContext = s_StartDirContexts.Insert( pStartDirContext, pDefaultDir );
+ bUseCurrentDirectory = ( pDefaultDir == NULL );
+ }
+ else
+ {
+ bUseCurrentDirectory = false;
+ }
+ }
+ else
+ {
+ m_nStartDirContext = s_StartDirContexts.InvalidIndex();
+ }
+
+ if ( !bUseCurrentDirectory )
+ {
+ SetStartDirectory( s_StartDirContexts[m_nStartDirContext].Get() );
+ }
+ else
+ {
+ // Set our starting path to the current directory
+ char pLocalPath[255];
+ g_pFullFileSystem->GetCurrentDirectory( pLocalPath, 255 );
+ SetStartDirectory( pLocalPath );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the starting directory of the file search.
+//-----------------------------------------------------------------------------
+void FileOpenDialog::SetStartDirectory( const char *dir )
+{
+ m_pFullPathEdit->SetText(dir);
+
+ // ensure it's validity
+ ValidatePath();
+
+ // Store this in the start directory list
+ if ( m_nStartDirContext != s_StartDirContexts.InvalidIndex() )
+ {
+ char pDirBuf[MAX_PATH];
+ GetCurrentDirectory( pDirBuf, sizeof(pDirBuf) );
+ s_StartDirContexts[ m_nStartDirContext ] = pDirBuf;
+ }
+
+ PopulateDriveList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Add filters for the drop down combo box
+//-----------------------------------------------------------------------------
+void FileOpenDialog::AddFilter( const char *filter, const char *filterName, bool bActive, const char *pFilterInfo )
+{
+ KeyValues *kv = new KeyValues("item");
+ kv->SetString( "filter", filter );
+ kv->SetString( "filterinfo", pFilterInfo );
+ int itemID = m_pFileTypeCombo->AddItem(filterName, kv);
+ if ( bActive )
+ {
+ m_pFileTypeCombo->ActivateItem(itemID);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activate the dialog
+//-----------------------------------------------------------------------------
+void FileOpenDialog::DoModal( bool bUnused )
+{
+ m_bFileSelected = false;
+ m_pFileNameEdit->RequestFocus();
+ BaseClass::DoModal();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the directory this is currently in
+//-----------------------------------------------------------------------------
+void FileOpenDialog::GetCurrentDirectory(char *buf, int bufSize)
+{
+ // get the text from the text entry
+ m_pFullPathEdit->GetText(buf, bufSize);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the last selected file name
+//-----------------------------------------------------------------------------
+void FileOpenDialog::GetSelectedFileName(char *buf, int bufSize)
+{
+ m_pFileNameEdit->GetText(buf, bufSize);
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new folder
+//-----------------------------------------------------------------------------
+void FileOpenDialog::NewFolder( char const *folderName )
+{
+ char pCurrentDirectory[MAX_PATH];
+ GetCurrentDirectory( pCurrentDirectory, sizeof(pCurrentDirectory) );
+
+ char pFullPath[MAX_PATH];
+ char pNewFolderName[MAX_PATH];
+ Q_strncpy( pNewFolderName, folderName, sizeof(pNewFolderName) );
+ int i = 2;
+ do
+ {
+ Q_MakeAbsolutePath( pFullPath, sizeof(pFullPath), pNewFolderName, pCurrentDirectory );
+ if ( !g_pFullFileSystem->FileExists( pFullPath, NULL ) &&
+ !g_pFullFileSystem->IsDirectory( pFullPath, NULL ) )
+ {
+ g_pFullFileSystem->CreateDirHierarchy( pFullPath, NULL );
+ m_pFileNameEdit->SetText( pNewFolderName );
+ return;
+ }
+
+ Q_snprintf( pNewFolderName, sizeof(pNewFolderName), "%s%d", folderName, i );
+ ++i;
+ } while ( i <= 999 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Move the directory structure up
+//-----------------------------------------------------------------------------
+void FileOpenDialog::MoveUpFolder()
+{
+ char fullpath[MAX_PATH * 4];
+ GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
+
+ Q_StripLastDir( fullpath, sizeof( fullpath ) );
+ // append a trailing slash
+ Q_AppendSlash( fullpath, sizeof( fullpath ) );
+
+ SetStartDirectory(fullpath);
+ PopulateFileList();
+ InvalidateLayout();
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Validate that the current path is valid
+//-----------------------------------------------------------------------------
+void FileOpenDialog::ValidatePath()
+{
+ char fullpath[MAX_PATH * 4];
+ GetCurrentDirectory(fullpath, sizeof(fullpath) - MAX_PATH);
+ Q_RemoveDotSlashes( fullpath );
+
+ // when statting a directory on Windows, you want to include
+ // the terminal slash exactly when you are statting a root
+ // directory. PKMN.
+#ifdef _WIN32
+ if ( Q_strlen( fullpath ) != 3 )
+ {
+ Q_StripTrailingSlash( fullpath );
+ }
+#endif
+ // cleanup the path, we format tabs into the list to make it pretty in the UI
+ Q_StripPrecedingAndTrailingWhitespace( fullpath );
+
+ struct _stat buf;
+ if ( ( 0 == _stat( fullpath, &buf ) ) &&
+ ( 0 != ( buf.st_mode & S_IFDIR ) ) )
+ {
+ Q_AppendSlash( fullpath, sizeof( fullpath ) );
+ Q_strncpy(m_szLastPath, fullpath, sizeof(m_szLastPath));
+ }
+ else
+ {
+ // failed to load file, use the previously successful path
+ }
+
+ m_pFullPathEdit->SetText(m_szLastPath);
+ m_pFullPathEdit->GetTooltip()->SetText(m_szLastPath);
+}
+
+#ifdef WIN32
+const char *GetAttributesAsString( DWORD dwAttributes )
+{
+ static char out[ 256 ];
+ out[ 0 ] = 0;
+ if ( dwAttributes & FILE_ATTRIBUTE_ARCHIVE )
+ {
+ Q_strncat( out, "A", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_COMPRESSED )
+ {
+ Q_strncat( out, "C", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ Q_strncat( out, "D", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_HIDDEN )
+ {
+ Q_strncat( out, "H", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_READONLY )
+ {
+ Q_strncat( out, "R", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_SYSTEM )
+ {
+ Q_strncat( out, "S", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ if ( dwAttributes & FILE_ATTRIBUTE_TEMPORARY )
+ {
+ Q_strncat( out, "T", sizeof( out ), COPY_ALL_CHARACTERS );
+ }
+ return out;
+}
+
+const char *GetFileTimetamp( FILETIME ft )
+{
+ SYSTEMTIME local;
+ FILETIME localFileTime;
+ FileTimeToLocalFileTime( &ft, &localFileTime );
+ FileTimeToSystemTime( &localFileTime, &local );
+
+ static char out[ 256 ];
+
+ bool am = true;
+ WORD hour = local.wHour;
+ if ( hour >= 12 )
+ {
+ am = false;
+ // 12:42 pm displays as 12:42 pm
+ // 13:42 pm displays as 1:42 pm
+ if ( hour > 12 )
+ {
+ hour -= 12;
+ }
+ }
+ Q_snprintf( out, sizeof( out ), "%d/%02d/%04d %d:%02d %s",
+ local.wMonth,
+ local.wDay,
+ local.wYear,
+ hour,
+ local.wMinute,
+ am ? "AM" : "PM" // TODO: Localize this?
+ );
+ return out;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill the filelist with the names of all the files in the current directory
+//-----------------------------------------------------------------------------
+#define MAX_FILTER_LENGTH 255
+void FileOpenDialog::PopulateFileList()
+{
+ // clear the current list
+ m_pFileList->DeleteAllItems();
+
+ FileFindHandle_t findHandle;
+ char pszFileModified[64];
+
+ // get the current directory
+ char currentDir[MAX_PATH * 4];
+ char dir[MAX_PATH * 4];
+ char filterList[MAX_FILTER_LENGTH+1];
+ GetCurrentDirectory(currentDir, sizeof(dir));
+
+ KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
+ if (combokv)
+ {
+ Q_strncpy(filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH);
+ }
+ else
+ {
+ // add wildcard for search
+ Q_strncpy(filterList, "*\0", MAX_FILTER_LENGTH);
+ }
+
+
+ char *filterPtr = filterList;
+ KeyValues *kv = new KeyValues("item");
+
+ if ( m_DialogType != FOD_SELECT_DIRECTORY )
+ {
+ while ((filterPtr != NULL) && (*filterPtr != 0))
+ {
+ // parse the next filter in the list.
+ char curFilter[MAX_FILTER_LENGTH];
+ curFilter[0] = 0;
+ int i = 0;
+ while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
+ {
+ ++filterPtr;
+ }
+ while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
+ {
+ curFilter[i++] = *(filterPtr++);
+ }
+ curFilter[i] = 0;
+
+ if (curFilter[0] == 0)
+ {
+ break;
+ }
+
+ Q_snprintf( dir, MAX_PATH*4, "%s%s", currentDir, curFilter );
+
+ // Open the directory and walk it, loading files
+ const char *pszFileName = g_pFullFileSystem->FindFirst( dir, &findHandle );
+ while ( pszFileName )
+ {
+ if ( !g_pFullFileSystem->FindIsDirectory( findHandle )
+ || !IsOSX()
+ || ( IsOSX() && g_pFullFileSystem->FindIsDirectory( findHandle ) && Q_stristr( pszFileName, ".app" ) ) )
+ {
+ char pFullPath[MAX_PATH];
+ Q_snprintf( pFullPath, MAX_PATH, "%s%s", currentDir, pszFileName );
+
+ // add the file to the list
+ kv->SetString( "text", pszFileName );
+
+ kv->SetInt( "image", 1 );
+
+ IImage *image = surface()->GetIconImageForFullPath( pFullPath );
+
+ if ( image )
+ {
+ kv->SetPtr( "iconImage", (void *)image );
+ }
+
+ kv->SetInt("imageSelected", 1);
+ kv->SetInt("directory", 0);
+
+ kv->SetString( "filesize", Q_pretifymem( g_pFullFileSystem->Size( pFullPath ), 0, true ) );
+ Q_FixSlashes( pFullPath );
+ wchar_t fileType[ 80 ];
+ g_pFullFileSystem->GetFileTypeForFullPath( pFullPath, fileType, sizeof( fileType ) );
+ kv->SetWString( "type", fileType );
+
+ kv->SetString( "attributes", g_pFullFileSystem->IsFileWritable( pFullPath )? "" : "R" );
+
+ long fileModified = g_pFullFileSystem->GetFileTime( pFullPath );
+ g_pFullFileSystem->FileTimeToString( pszFileModified, sizeof( pszFileModified ), fileModified );
+ kv->SetString( "modified", pszFileModified );
+
+// kv->SetString( "created", GetFileTimetamp( findData.ftCreationTime ) );
+
+ m_pFileList->AddItem(kv, 0, false, false);
+ }
+
+ pszFileName = g_pFullFileSystem->FindNext( findHandle );
+ }
+ g_pFullFileSystem->FindClose( findHandle );
+ }
+ }
+
+ // find all the directories
+ GetCurrentDirectory( dir, sizeof(dir) );
+ Q_strncat(dir, "*", sizeof( dir ), COPY_ALL_CHARACTERS);
+
+ const char *pszFileName = g_pFullFileSystem->FindFirst( dir, &findHandle );
+ while ( pszFileName )
+ {
+ if ( pszFileName[0] != '.' && g_pFullFileSystem->FindIsDirectory( findHandle )
+ && ( !IsOSX() || ( IsOSX() && !Q_stristr( pszFileName, ".app" ) ) ) )
+ {
+ char pFullPath[MAX_PATH];
+ Q_snprintf( pFullPath, MAX_PATH, "%s%s", currentDir, pszFileName );
+
+ kv->SetString("text", pszFileName );
+ kv->SetPtr( "iconImage", (void *)NULL );
+ kv->SetInt("image", 2);
+ kv->SetInt("imageSelected", 3);
+ kv->SetInt("directory", 1);
+
+ kv->SetString( "filesize", "" );
+ kv->SetString( "type", "#FileOpenDialog_FileType_Folder" );
+
+ kv->SetString( "attributes", g_pFullFileSystem->IsFileWritable( pFullPath )? "" : "R" );
+
+ long fileModified = g_pFullFileSystem->GetFileTime( pFullPath );
+ g_pFullFileSystem->FileTimeToString( pszFileModified, sizeof( pszFileModified ), fileModified );
+ kv->SetString( "modified", pszFileModified );
+
+// kv->SetString( "created", GetFileTimetamp( findData.ftCreationTime ) );
+
+ m_pFileList->AddItem( kv, 0, false, false );
+ }
+
+ pszFileName = g_pFullFileSystem->FindNext( findHandle );
+ }
+ g_pFullFileSystem->FindClose( findHandle );
+
+ kv->deleteThis();
+ m_pFileList->SortList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Does the specified extension match something in the filter list?
+//-----------------------------------------------------------------------------
+bool FileOpenDialog::ExtensionMatchesFilter( const char *pExt )
+{
+ KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
+ if ( !combokv )
+ return true;
+
+ char filterList[MAX_FILTER_LENGTH+1];
+ Q_strncpy( filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH );
+
+ char *filterPtr = filterList;
+ while ((filterPtr != NULL) && (*filterPtr != 0))
+ {
+ // parse the next filter in the list.
+ char curFilter[MAX_FILTER_LENGTH];
+ curFilter[0] = 0;
+ int i = 0;
+ while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
+ {
+ ++filterPtr;
+ }
+ while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
+ {
+ curFilter[i++] = *(filterPtr++);
+ }
+ curFilter[i] = 0;
+
+ if (curFilter[0] == 0)
+ break;
+
+ if ( !Q_stricmp( curFilter, "*" ) || !Q_stricmp( curFilter, "*.*" ) )
+ return true;
+
+ // FIXME: This isn't exactly right, but tough cookies;
+ // it assumes the first two characters of the filter are *.
+ Assert( curFilter[0] == '*' && curFilter[1] == '.' );
+ if ( !Q_stricmp( &curFilter[2], pExt ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Choose the first non *.* filter in the filter list
+//-----------------------------------------------------------------------------
+void FileOpenDialog::ChooseExtension( char *pExt, int nBufLen )
+{
+ pExt[0] = 0;
+
+ KeyValues *combokv = m_pFileTypeCombo->GetActiveItemUserData();
+ if ( !combokv )
+ return;
+
+ char filterList[MAX_FILTER_LENGTH+1];
+ Q_strncpy( filterList, combokv->GetString("filter", "*"), MAX_FILTER_LENGTH );
+
+ char *filterPtr = filterList;
+ while ((filterPtr != NULL) && (*filterPtr != 0))
+ {
+ // parse the next filter in the list.
+ char curFilter[MAX_FILTER_LENGTH];
+ curFilter[0] = 0;
+ int i = 0;
+ while ((filterPtr != NULL) && ((*filterPtr == ',') || (*filterPtr == ';') || (*filterPtr <= ' ')))
+ {
+ ++filterPtr;
+ }
+ while ((filterPtr != NULL) && (*filterPtr != ',') && (*filterPtr != ';') && (*filterPtr > ' '))
+ {
+ curFilter[i++] = *(filterPtr++);
+ }
+ curFilter[i] = 0;
+
+ if (curFilter[0] == 0)
+ break;
+
+ if ( !Q_stricmp( curFilter, "*" ) || !Q_stricmp( curFilter, "*.*" ) )
+ continue;
+
+ // FIXME: This isn't exactly right, but tough cookies;
+ // it assumes the first two characters of the filter are *.
+ Assert( curFilter[0] == '*' && curFilter[1] == '.' );
+ Q_strncpy( pExt, &curFilter[1], nBufLen );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves the file to the start dir context
+//-----------------------------------------------------------------------------
+void FileOpenDialog::SaveFileToStartDirContext( const char *pFullPath )
+{
+ if ( m_nStartDirContext == s_StartDirContexts.InvalidIndex() )
+ return;
+
+ char pPath[MAX_PATH];
+ pPath[0] = 0;
+ Q_ExtractFilePath( pFullPath, pPath, sizeof(pPath) );
+ s_StartDirContexts[ m_nStartDirContext ] = pPath;
+}
+
+
+//-----------------------------------------------------------------------------
+// Posts a file selected message
+//-----------------------------------------------------------------------------
+void FileOpenDialog::PostFileSelectedMessage( const char *pFileName )
+{
+ m_bFileSelected = true;
+
+ // open the file!
+ KeyValues *pKeyValues = new KeyValues( "FileSelected", "fullpath", pFileName );
+ KeyValues *pFilterKeys = m_pFileTypeCombo->GetActiveItemUserData();
+ const char *pFilterInfo = pFilterKeys ? pFilterKeys->GetString( "filterinfo", NULL ) : NULL;
+ if ( pFilterInfo )
+ {
+ pKeyValues->SetString( "filterinfo", pFilterInfo );
+ }
+ if ( m_pContextKeyValues )
+ {
+ pKeyValues->AddSubKey( m_pContextKeyValues );
+ m_pContextKeyValues = NULL;
+ }
+ PostActionSignal( pKeyValues );
+ CloseModal();
+}
+
+
+//-----------------------------------------------------------------------------
+// Selects the current folder
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnSelectFolder()
+{
+ ValidatePath();
+
+ // construct a file path
+ char pFileName[MAX_PATH];
+ GetSelectedFileName( pFileName, sizeof( pFileName ) );
+
+ Q_StripTrailingSlash( pFileName );
+
+ if ( !stricmp(pFileName, "..") )
+ {
+ MoveUpFolder();
+
+ // clear the name text
+ m_pFileNameEdit->SetText("");
+ return;
+ }
+
+ if ( !stricmp(pFileName, ".") )
+ {
+ // clear the name text
+ m_pFileNameEdit->SetText("");
+ return;
+ }
+
+ // Compute the full path
+ char pFullPath[MAX_PATH * 4];
+ if ( !Q_IsAbsolutePath( pFileName ) )
+ {
+ GetCurrentDirectory(pFullPath, sizeof(pFullPath) - MAX_PATH);
+ strcat( pFullPath, pFileName );
+ if ( !pFileName[0] )
+ {
+ Q_StripTrailingSlash( pFullPath );
+ }
+ }
+ else
+ {
+ Q_strncpy( pFullPath, pFileName, sizeof(pFullPath) );
+ }
+
+ if ( g_pFullFileSystem->FileExists( pFullPath ) )
+ {
+ // open the file!
+ SaveFileToStartDirContext( pFullPath );
+ PostFileSelectedMessage( pFullPath );
+ return;
+ }
+
+ PopulateDriveList();
+ PopulateFileList();
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the open button being pressed
+// checks on what has changed and acts accordingly
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnOpen()
+{
+ ValidatePath();
+
+ // construct a file path
+ char pFileName[MAX_PATH];
+ GetSelectedFileName( pFileName, sizeof( pFileName ) );
+
+ int nLen = Q_strlen( pFileName );
+ bool bSpecifiedDirectory = ( pFileName[nLen-1] == '/' || pFileName[nLen-1] == '\\' ) && (!IsOSX() || ( IsOSX() && !Q_stristr( pFileName, ".app" ) ) );
+ Q_StripTrailingSlash( pFileName );
+
+ if ( !stricmp(pFileName, "..") )
+ {
+ MoveUpFolder();
+
+ // clear the name text
+ m_pFileNameEdit->SetText("");
+ return;
+ }
+
+ if ( !stricmp(pFileName, ".") )
+ {
+ // clear the name text
+ m_pFileNameEdit->SetText("");
+ return;
+ }
+
+ // Compute the full path
+ char pFullPath[MAX_PATH * 4];
+ if ( !Q_IsAbsolutePath( pFileName ) )
+ {
+ GetCurrentDirectory(pFullPath, sizeof(pFullPath) - MAX_PATH);
+ Q_AppendSlash( pFullPath, sizeof( pFullPath ) );
+ strcat(pFullPath, pFileName);
+ if ( !pFileName[0] )
+ {
+ Q_StripTrailingSlash( pFullPath );
+ }
+ }
+ else
+ {
+ Q_strncpy( pFullPath, pFileName, sizeof(pFullPath) );
+ }
+
+ Q_StripTrailingSlash( pFullPath );
+
+ // when statting a directory on Windows, you want to include
+ // the terminal slash exactly when you are statting a root
+ // directory. PKMN.
+#ifdef _WIN32
+ if ( Q_strlen( pFullPath ) == 2 )
+ {
+ Q_AppendSlash( pFullPath, Q_ARRAYSIZE( pFullPath ) );
+ }
+#endif
+
+
+ // If the name specified is a directory, then change directory
+ if ( g_pFullFileSystem->IsDirectory( pFullPath, NULL ) &&
+ ( !IsOSX() || ( IsOSX() && !Q_stristr( pFullPath, ".app" ) ) ) )
+ {
+ // it's a directory; change to the specified directory
+ if ( !bSpecifiedDirectory )
+ {
+ Q_AppendSlash( pFullPath, Q_ARRAYSIZE( pFullPath ) );
+ }
+ SetStartDirectory( pFullPath );
+
+ // clear the name text
+ m_pFileNameEdit->SetText("");
+ m_pFileNameEdit->HideMenu();
+
+ PopulateDriveList();
+ PopulateFileList();
+ InvalidateLayout();
+ return;
+ }
+ else if ( bSpecifiedDirectory )
+ {
+ PopulateDriveList();
+ PopulateFileList();
+ InvalidateLayout();
+ return;
+ }
+
+ // Append suffix of the first filter that isn't *.*
+ char extension[512];
+ Q_ExtractFileExtension( pFullPath, extension, sizeof(extension) );
+ if ( !ExtensionMatchesFilter( extension ) )
+ {
+ ChooseExtension( extension, sizeof(extension) );
+ Q_SetExtension( pFullPath, extension, sizeof(pFullPath) );
+ }
+
+ if ( g_pFullFileSystem->FileExists( pFullPath ) )
+ {
+ // open the file!
+ SaveFileToStartDirContext( pFullPath );
+ PostFileSelectedMessage( pFullPath );
+ return;
+ }
+
+ // file not found
+ if ( ( m_DialogType == FOD_SAVE ) && pFileName[0] )
+ {
+ // open the file!
+ SaveFileToStartDirContext( pFullPath );
+ PostFileSelectedMessage( pFullPath );
+ return;
+ }
+
+ PopulateDriveList();
+ PopulateFileList();
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: using the file edit box as a prefix, create a menu of all possible files
+//-----------------------------------------------------------------------------
+void FileOpenDialog::PopulateFileNameCompletion()
+{
+ char buf[80];
+ m_pFileNameEdit->GetText(buf, 80);
+ wchar_t wbuf[80];
+ m_pFileNameEdit->GetText(wbuf, 80);
+ int bufLen = wcslen(wbuf);
+
+ // delete all items before we check if there's even a string
+ m_pFileNameEdit->DeleteAllItems();
+
+ // no string at all - don't show even bother showing it
+ if (bufLen == 0)
+ {
+ m_pFileNameEdit->HideMenu();
+ return;
+ }
+
+ // what files use current string as a prefix?
+ int nCount = m_pFileList->GetItemCount();
+ int i;
+ for ( i = 0 ; i < nCount ; i++ )
+ {
+ KeyValues *kv = m_pFileList->GetItem(m_pFileList->GetItemIDFromRow(i));
+ const wchar_t *wszString = kv->GetWString("text");
+ if ( !_wcsnicmp(wbuf, wszString, bufLen) )
+ {
+ m_pFileNameEdit->AddItem(wszString, NULL);
+ }
+ }
+
+ // if there are any items - show the menu
+ if ( m_pFileNameEdit->GetItemCount() > 0 )
+ {
+ m_pFileNameEdit->ShowMenu();
+ }
+ else
+ {
+ m_pFileNameEdit->HideMenu();
+ }
+
+ m_pFileNameEdit->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle an item in the list being selected
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnItemSelected()
+{
+ // make sure only one item is selected
+ if (m_pFileList->GetSelectedItemsCount() != 1)
+ {
+ m_pFileNameEdit->SetText("");
+ }
+ else
+ {
+ // put the file name into the text edit box
+ KeyValues *data = m_pFileList->GetItem(m_pFileList->GetSelectedItem(0));
+ m_pFileNameEdit->SetText(data->GetString("text"));
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle an item in the Drive combo box being selected
+//-----------------------------------------------------------------------------
+void FileOpenDialog::OnTextChanged(KeyValues *kv)
+{
+ Panel *pPanel = (Panel *) kv->GetPtr("panel", NULL);
+
+ // first check which control had its text changed!
+ if (pPanel == m_pFullPathEdit)
+ {
+ m_pFileNameEdit->HideMenu();
+ m_pFileNameEdit->SetText("");
+ OnOpen();
+ }
+ else if (pPanel == m_pFileNameEdit)
+ {
+ PopulateFileNameCompletion();
+ }
+ else if (pPanel == m_pFileTypeCombo)
+ {
+ m_pFileNameEdit->HideMenu();
+ PopulateFileList();
+ }
+}