openclonk/src/gui/C4FileSelDlg.cpp

644 lines
21 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
2009-05-08 13:28:41 +00:00
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
2009-05-08 13:28:41 +00:00
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
2009-05-08 13:28:41 +00:00
*/
// file selection dialogs
#include "C4Include.h"
#include "gui/C4FileSelDlg.h"
2009-05-08 13:28:41 +00:00
#include "C4Version.h"
#include "graphics/C4Draw.h"
#include "graphics/C4GraphicsResource.h" // only for single use of ::GraphicsResource.fctOKCancel below...
2009-05-08 13:28:41 +00:00
#ifdef _WIN32
2009-08-26 12:41:29 +00:00
#ifndef _WIN32_IE
2009-05-08 13:28:41 +00:00
#define _WIN32_IE 0x0400
2009-08-26 12:41:29 +00:00
#endif
2013-04-01 10:48:02 +00:00
#undef MK_ALT
2009-05-08 13:28:41 +00:00
#include <shlobj.h>
#ifndef CSIDL_MYPICTURES
#define CSIDL_MYPICTURES 0x0027
#endif
#endif
// def 1 if gfx loading works in background thread. Right now, it doesn't
// C4Group and C4Surface just don't like it
// So for now, the loading will be done in 1/10 of the frames in OnIdle of the dialog
#define USE_BACKGROUND_THREAD_LOAD 0
// ---------------------------------------------------
// C4FileSelDlg::ListItem
C4FileSelDlg::ListItem::ListItem(const char *szFilename) : C4GUI::Control(C4Rect(0,0,0,0))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (szFilename) sFilename.Copy(szFilename); else sFilename.Clear();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4FileSelDlg::ListItem::~ListItem() = default;
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4FileSelDlg::DefaultListItem
C4FileSelDlg::DefaultListItem::DefaultListItem(const char *szFilename, bool fTruncateExtension, bool fCheckbox, bool fGrayed, C4GUI::Icons eIcon)
: C4FileSelDlg::ListItem(szFilename), pLbl(nullptr), pCheck(nullptr), pKeyCheck(nullptr), fGrayed(fGrayed)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sLabel; if (szFilename) sLabel.Ref(::GetFilename(szFilename)); else sLabel.Ref(LoadResStr("IDS_CTL_NONE"));
if (szFilename && fTruncateExtension)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sLabel.Copy();
char *szFilename = sLabel.GrabPointer();
RemoveExtension(szFilename);
sLabel.Take(szFilename);
2010-03-28 18:58:01 +00:00
}
rcBounds.Hgt = ::GraphicsResource.TextFont.GetLineHeight();
2009-05-08 13:28:41 +00:00
UpdateSize();
C4GUI::ComponentAligner caMain(GetContainedClientRect(),0,0);
int32_t iHeight = caMain.GetInnerHeight();
if (fCheckbox)
2010-03-28 18:58:01 +00:00
{
pCheck = new C4GUI::CheckBox(caMain.GetFromLeft(iHeight), nullptr, false);
2009-05-08 13:28:41 +00:00
if (fGrayed) pCheck->SetEnabled(false);
AddElement(pCheck);
pKeyCheck = new C4KeyBinding(C4KeyCodeEx(K_SPACE), "FileSelToggleFileActive", KEYSCOPE_Gui,
2010-03-28 18:58:01 +00:00
new C4GUI::ControlKeyCB<ListItem>(*this, &ListItem::UserToggleCheck), C4CustomKey::PRIO_Ctrl);
}
2009-05-08 13:28:41 +00:00
C4GUI::Icon *pIco = new C4GUI::Icon(caMain.GetFromLeft(iHeight), eIcon);
AddElement(pIco);
pLbl = new C4GUI::Label(sLabel.getData(), caMain.GetAll(), ALeft, fGrayed ? C4GUI_CheckboxDisabledFontClr : C4GUI_CheckboxFontClr);
AddElement(pLbl);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4FileSelDlg::DefaultListItem::~DefaultListItem()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (pKeyCheck) delete pKeyCheck;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::DefaultListItem::UpdateOwnPos()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BaseClass::UpdateOwnPos();
if (!pLbl) return;
C4GUI::ComponentAligner caMain(GetContainedClientRect(),0,0);
caMain.GetFromLeft(caMain.GetInnerHeight()*(1+!!pCheck));
pLbl->SetBounds(caMain.GetAll());
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4FileSelDlg::DefaultListItem::IsChecked() const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return pCheck ? pCheck->GetChecked() : false;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::DefaultListItem::SetChecked(bool fChecked)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// store new state in checkbox
if (pCheck) pCheck->SetChecked(fChecked);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4FileSelDlg::DefaultListItem::UserToggleCheck()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// toggle if possible
if (pCheck && !IsGrayed())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCheck->ToggleCheck(true);
return true;
}
2010-03-28 18:58:01 +00:00
return false;
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4FileSelDlg
C4FileSelDlg::C4FileSelDlg(const char *szRootPath, const char *szTitle, C4FileSel_BaseCB *pSelCallback, bool fInitElements)
: C4GUI::Dialog(Clamp(C4GUI::GetScreenWdt()*2/3+10, 300,600), Clamp(C4GUI::GetScreenHgt()*2/3+10, 220,500), szTitle, false),
pLocationComboBox(nullptr), pFileListBox(nullptr), pSelectionInfoBox(nullptr), btnOK(nullptr), pLocations(nullptr), iLocationCount(0), pSelection(nullptr), pSelCallback(pSelCallback)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sTitle.Copy(szTitle);
// key bindings
pKeyRefresh = new C4KeyBinding(C4KeyCodeEx(K_F5), "FileSelReload", KEYSCOPE_Gui,
2010-03-28 18:58:01 +00:00
new C4GUI::DlgKeyCB<C4FileSelDlg>(*this, &C4FileSelDlg::KeyRefresh), C4CustomKey::PRIO_CtrlOverride);
2009-05-08 13:28:41 +00:00
pKeyEnterOverride = new C4KeyBinding(C4KeyCodeEx(K_RETURN), "FileSelConfirm", KEYSCOPE_Gui,
2010-03-28 18:58:01 +00:00
new C4GUI::DlgKeyCB<C4FileSelDlg>(*this, &C4FileSelDlg::KeyEnter), C4CustomKey::PRIO_CtrlOverride);
2009-05-08 13:28:41 +00:00
if (fInitElements) InitElements();
sPath.Copy(szRootPath);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::InitElements()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
UpdateSize();
CStdFont *pUseFont = &(::GraphicsResource.TextFont);
2009-05-08 13:28:41 +00:00
// main calcs
bool fHasOptions = HasExtraOptions();
C4GUI::ComponentAligner caMain(GetClientRect(), 0,0, true);
C4Rect rcOptions;
C4GUI::ComponentAligner caButtonArea(caMain.GetFromBottom(C4GUI_ButtonAreaHgt, 2*C4GUI_DefButton2Wdt+4*C4GUI_DefButton2HSpace),C4GUI_DefButton2HSpace,(C4GUI_ButtonAreaHgt-C4GUI_ButtonHgt)/2);
if (fHasOptions) rcOptions = caMain.GetFromBottom(pUseFont->GetLineHeight() + 2*C4GUI_DefDlgSmallIndent);
C4GUI::ComponentAligner caUpperArea(caMain.GetAll(), C4GUI_DefDlgIndent, C4GUI_DefDlgIndent, true);
// create file selection area
if (iLocationCount)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4GUI::ComponentAligner caLocations(caUpperArea.GetFromTop(C4GUI::ComboBox::GetDefaultHeight() + 2*C4GUI_DefDlgSmallIndent), C4GUI_DefDlgIndent,C4GUI_DefDlgSmallIndent, false);
StdStrBuf sText(LoadResStr("IDS_TEXT_LOCATION"));
AddElement(new C4GUI::Label(sText.getData(), caLocations.GetFromLeft(pUseFont->GetTextWidth(sText.getData())), ALeft));
pLocationComboBox = new C4GUI::ComboBox(caLocations.GetAll());
pLocationComboBox->SetComboCB(new C4GUI::ComboBox_FillCallback<C4FileSelDlg>(this, &C4FileSelDlg::OnLocationComboFill, &C4FileSelDlg::OnLocationComboSelChange));
pLocationComboBox->SetText(pLocations[0].sName.getData());
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create file selection area
bool fHasPreview = HasPreviewArea();
pFileListBox = new C4GUI::ListBox(fHasPreview ? caUpperArea.GetFromLeft(caUpperArea.GetWidth()/2) : caUpperArea.GetAll(), GetFileSelColWidth());
pFileListBox ->SetSelectionChangeCallbackFn(new C4GUI::CallbackHandler<C4FileSelDlg>(this, &C4FileSelDlg::OnSelChange));
pFileListBox ->SetSelectionDblClickFn(new C4GUI::CallbackHandler<C4FileSelDlg>(this, &C4FileSelDlg::OnSelDblClick));
if (fHasPreview)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
caUpperArea.ExpandLeft(C4GUI_DefDlgIndent);
pSelectionInfoBox = new C4GUI::TextWindow(caUpperArea.GetAll());
pSelectionInfoBox->SetDecoration(true, true, nullptr, true);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create button area
C4GUI::Button *btnAbort = new C4GUI::CancelButton(caButtonArea.GetFromRight(C4GUI_DefButton2Wdt));
btnOK = new C4GUI::OKButton(caButtonArea.GetFromRight(C4GUI_DefButton2Wdt));
// add components in tab order
if (pLocationComboBox) AddElement(pLocationComboBox);
AddElement(pFileListBox);
if (pSelectionInfoBox) AddElement(pSelectionInfoBox);
if (fHasOptions) AddExtraOptions(rcOptions);
AddElement(btnOK);
AddElement(btnAbort);
SetFocus(pFileListBox, false);
// no selection yet
UpdateSelection();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4FileSelDlg::~C4FileSelDlg()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete [] pLocations;
if (pSelCallback) delete pSelCallback;
delete pKeyEnterOverride;
delete pKeyRefresh;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::OnLocationComboFill(C4GUI::ComboBox_FillCB *pFiller)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Add all locations
for (int32_t i=0; i<iLocationCount; ++i)
pFiller->AddEntry(pLocations[i].sName.getData(), i);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4FileSelDlg::OnLocationComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SetCurrentLocation(idNewSelection, true);
// No text change by caller; text alread changed by SetCurrentLocation
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::SetPath(const char *szNewPath, bool fRefresh)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sPath.Copy(szNewPath);
if (fRefresh && IsShown()) UpdateFileList();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::OnShown()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BaseClass::OnShown();
// load files
UpdateFileList();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::UserClose(bool fOK)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (!fOK || pSelection)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// allow OK only if something is sth is selected
Close(fOK);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
GetScreen()->ShowErrorMessage(LoadResStr("IDS_ERR_PLEASESELECTAFILEFIRST"));
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::OnClosed(bool fOK)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (fOK && pSelection && pSelCallback)
pSelCallback->OnFileSelected(pSelection->GetFilename());
// base call: Might delete dlg
BaseClass::OnClosed(fOK);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::OnSelDblClick(class C4GUI::Element *pEl)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// item double-click: confirms with this file in single mode; toggles selection in multi mode
if (IsMultiSelection())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ListItem *pItem = static_cast<ListItem *>(pEl);
pItem->UserToggleCheck();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
UserClose(true);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4FileSelDlg::ListItem *C4FileSelDlg::CreateListItem(const char *szFilename)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Default list item
if (szFilename)
return new DefaultListItem(szFilename, !!GetFileMask(), IsMultiSelection(), IsItemGrayed(szFilename), GetFileItemIcon());
else
return new DefaultListItem(nullptr, false, IsMultiSelection(), false, GetFileItemIcon());
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::UpdateFileList()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BeginFileListUpdate();
// reload files
C4GUI::Element *pEl;
2010-01-25 04:00:59 +00:00
while ((pEl = pFileListBox->GetFirst())) delete pEl;
2009-05-08 13:28:41 +00:00
// file items
StdStrBuf sSearch;
const char *szFileMask = GetFileMask();
for (DirectoryIterator iter(sPath.getData()); *iter; ++iter)
if (!szFileMask || WildcardListMatch(szFileMask, *iter))
pFileListBox->AddElement(CreateListItem(*iter));
// none-item?
if (HasNoneItem())
2010-03-28 18:58:01 +00:00
{
pFileListBox->AddElement(CreateListItem(nullptr));
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// list now done
EndFileListUpdate();
// path into title
const char *szPath = sPath.getData();
SetTitle(*szPath ? FormatString("%s [%s]", sTitle.getData(), szPath).getData() : sTitle.getData());
// initial no-selection
UpdateSelection();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::UpdateSelection()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// update selection from list
pSelection = static_cast<ListItem *>(pFileListBox->GetSelectedItem());
// OK button only available if selection
// SetEnabled would look a lot better here, but it doesn't exist yet :(
// selection preview, if enabled
if (pSelectionInfoBox)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// default empty
pSelectionInfoBox->ClearText(false);
if (!pSelection) { pSelectionInfoBox->UpdateHeight(); return; }
// add selection description
if (pSelection->GetFilename())
pSelectionInfoBox->AddTextLine(pSelection->GetFilename(), &::GraphicsResource.TextFont, C4GUI_MessageFontClr, true, false);
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::SetSelection(const char *szNewSelection, bool fFilenameOnly)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check all selected definitions
for (ListItem *pFileItem = static_cast<ListItem *>(pFileListBox->GetFirst()); pFileItem; pFileItem = static_cast<ListItem *>(pFileItem->GetNext()))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const char *szFileItemFilename = pFileItem->GetFilename();
if (fFilenameOnly) szFileItemFilename = GetFilename(szFileItemFilename);
pFileItem->SetChecked(SIsModule(szNewSelection, szFileItemFilename));
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4FileSelDlg::GetSelection(const char *szFixedSelection, bool fFilenameOnly) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sResult;
if (!IsMultiSelection())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get single selected file for single selection dlg
if (pSelection) sResult.Copy(fFilenameOnly ? GetFilename(pSelection->GetFilename()) : pSelection->GetFilename());
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// force fixed selection first
if (szFixedSelection) sResult.Append(szFixedSelection);
2010-04-01 21:08:06 +00:00
// get ';'-separated list for multi selection dlg
2009-05-08 13:28:41 +00:00
for (ListItem *pFileItem = static_cast<ListItem *>(pFileListBox->GetFirst()); pFileItem; pFileItem = static_cast<ListItem *>(pFileItem->GetNext()))
if (pFileItem->IsChecked())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const char *szAppendFilename = pFileItem->GetFilename();
if (fFilenameOnly) szAppendFilename = GetFilename(szAppendFilename);
// prevent adding entries twice (especially those from the fixed selection list)
if (!SIsModule(sResult.getData(), szAppendFilename))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (sResult.getLength()) sResult.AppendChar(';');
sResult.Append(szAppendFilename);
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return sResult;
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::AddLocation(const char *szName, const char *szPath)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to list
int32_t iNewLocCount = iLocationCount+1;
Location *pNewLocations = new Location[iNewLocCount];
for (int32_t i=0; i<iLocationCount; ++i) pNewLocations[i] = pLocations[i];
pNewLocations[iLocationCount].sName.Copy(szName);
pNewLocations[iLocationCount].sPath.Copy(szPath);
delete [] pLocations; pLocations = pNewLocations; iLocationCount = iNewLocCount;
// first location? Then set path to this
if (iLocationCount == 1) SetPath(szPath, false);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::AddCheckedLocation(const char *szName, const char *szPath)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check location
// path must exit
if (!szPath || !*szPath) return;
if (!DirectoryExists(szPath)) return;
// path must not be in list yet
for (int32_t i=0; i<iLocationCount; ++i)
if (ItemIdentical(szPath, pLocations[i].sPath.getData()))
return;
// OK; add it!
AddLocation(szName, szPath);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4FileSelDlg::GetCurrentLocationIndex() const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return iCurrentLocationIndex;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4FileSelDlg::SetCurrentLocation(int32_t idx, bool fRefresh)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if (!Inside<int32_t>(idx, 0,iLocationCount)) return;
// update ComboBox-text
iCurrentLocationIndex = idx;
if (pLocationComboBox) pLocationComboBox->SetText(pLocations[idx].sName.getData());
// set new path
SetPath(pLocations[idx].sPath.getData(), fRefresh);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4PlayerSelDlg
C4PlayerSelDlg::C4PlayerSelDlg(C4FileSel_BaseCB *pSelCallback)
2010-03-28 18:58:01 +00:00
: C4FileSelDlg(Config.General.UserDataPath, LoadResStr("IDS_MSG_SELECTPLR"), pSelCallback)
{
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4DefinitionSelDlg
C4DefinitionSelDlg::C4DefinitionSelDlg(C4FileSel_BaseCB *pSelCallback, const char *szFixedSelection)
2010-03-28 18:58:01 +00:00
: C4FileSelDlg(Config.General.UserDataPath, FormatString(LoadResStr("IDS_MSG_SELECT"), LoadResStr("IDS_DLG_DEFINITIONS")).getData(), pSelCallback)
{
2009-05-08 13:28:41 +00:00
if (szFixedSelection) sFixedSelection.Copy(szFixedSelection);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4DefinitionSelDlg::OnShown()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// base call: load file list
C4FileSelDlg::OnShown();
// initial selection
if (sFixedSelection) SetSelection(sFixedSelection.getData(), true);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4DefinitionSelDlg::IsItemGrayed(const char *szFilename) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// cannot change initial selection
if (!sFixedSelection) return false;
return SIsModule(sFixedSelection.getData(), GetFilename(szFilename));
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4DefinitionSelDlg::SelectDefinitions(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// let the user select definitions by showing a modal selection dialog
C4DefinitionSelDlg *pDlg = new C4DefinitionSelDlg(nullptr, pSelection->getData());
2009-05-08 13:28:41 +00:00
bool fResult;
2010-01-25 04:00:59 +00:00
if ((fResult = pOnScreen->ShowModalDlg(pDlg, false)))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pSelection->Copy(pDlg->GetSelection(pSelection->getData(), true));
2010-03-28 18:58:01 +00:00
}
delete pDlg;
2009-05-08 13:28:41 +00:00
return fResult;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4PortraitSelDlg::ListItem
C4PortraitSelDlg::ListItem::ListItem(const char *szFilename) : C4FileSelDlg::ListItem(szFilename)
2010-03-28 18:58:01 +00:00
, fError(false), fLoaded(false)
{
CStdFont *pUseFont = &(::GraphicsResource.MiniFont);
2009-05-08 13:28:41 +00:00
// determine label text
StdStrBuf sDisplayLabel;
if (szFilename)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sDisplayLabel.Copy(::GetFilename(szFilename));
::RemoveExtension(&sDisplayLabel);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sDisplayLabel.Ref(LoadResStr("IDS_MSG_NOPORTRAIT"));
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// insert linebreaks into label text
int32_t iLineHgt = std::max<int32_t>(pUseFont->BreakMessage(sDisplayLabel.getData(), ImagePreviewSize-6, &sFilenameLabelText, false), 1);
2009-05-08 13:28:41 +00:00
// set size
SetBounds(C4Rect(0,0,ImagePreviewSize,ImagePreviewSize+iLineHgt));
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::ListItem::Load()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (sFilename)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
fLoaded = false;
// load image file
C4Group SrcGrp;
StdStrBuf sParentPath;
GetParentPath(sFilename.getData(), &sParentPath);
bool fLoadError = true;
if (SrcGrp.Open(sParentPath.getData()))
if (fctLoadedImage.Load(SrcGrp, ::GetFilename(sFilename.getData()), C4FCT_Full, C4FCT_Full, false, 0))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// image loaded. Can only be put into facet by main thread, because those operations aren't thread safe
fLoaded = true;
fLoadError = false;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
SrcGrp.Close();
fError = fLoadError;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::ListItem::DrawElement(C4TargetFacet &cgo)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Scale down newly loaded image?
if (fLoaded)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fLoaded = false;
if (!fctImage.CopyFromSfcMaxSize(fctLoadedImage.GetFace(), ImagePreviewSize))
fError = true;
fctLoadedImage.GetFace().Clear();
fctLoadedImage.Clear();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Draw picture
CStdFont *pUseFont = &(::GraphicsResource.MiniFont);
2009-05-08 13:28:41 +00:00
C4Facet cgoPicture(cgo.Surface, cgo.TargetX+rcBounds.x, cgo.TargetY+rcBounds.y, ImagePreviewSize, ImagePreviewSize);
if (fError || !sFilename)
2010-03-28 18:58:01 +00:00
{
C4Facet &fctNoneImg = ::GraphicsResource.fctOKCancel;
2009-05-08 13:28:41 +00:00
fctNoneImg.Draw(cgoPicture.Surface, cgoPicture.X+(cgoPicture.Wdt-fctNoneImg.Wdt)/2, cgoPicture.Y+(cgoPicture.Hgt-fctNoneImg.Hgt)/2, 1,0);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (!fctImage.Surface)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// not loaded yet
2011-10-03 14:30:18 +00:00
pDraw->TextOut(LoadResStr("IDS_PRC_INITIALIZE"), ::GraphicsResource.MiniFont, 1.0f, cgo.Surface, cgoPicture.X+cgoPicture.Wdt/2, cgoPicture.Y+(cgoPicture.Hgt-::GraphicsResource.MiniFont.GetLineHeight())/2, C4GUI_StatusFontClr, ACenter, false);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fctImage.Draw(cgoPicture);
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// draw filename
2011-10-03 14:30:18 +00:00
pDraw->TextOut(sFilenameLabelText.getData(), *pUseFont, 1.0f, cgo.Surface, cgoPicture.X+rcBounds.Wdt/2, cgoPicture.Y+cgoPicture.Hgt, C4GUI_MessageFontClr, ACenter, false);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4PortraitSelDlg::LoaderThread
void C4PortraitSelDlg::LoaderThread::ClearLoadItems()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// stop thread so list can be accessed
Stop();
// clear list
LoadItems.clear();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::LoaderThread::AddLoadItem(ListItem *pItem)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// not to be called when thread is running!
assert(!IsStarted());
LoadItems.push_back(pItem);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::LoaderThread::Execute()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// list empty?
if (!LoadItems.size())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// then we're done!
SignalStop();
return;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load one item at the time
ListItem *pLoadItem = LoadItems.front();
pLoadItem->Load();
LoadItems.erase(LoadItems.begin());
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ---------------------------------------------------
// C4PortraitSelDlg
C4PortraitSelDlg::C4PortraitSelDlg(C4FileSel_BaseCB *pSelCallback)
: C4FileSelDlg(Config.General.SystemDataPath, FormatString(LoadResStr("IDS_MSG_SELECT"), LoadResStr("IDS_TYPE_PORTRAIT")).getData(), pSelCallback, false)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char path[_MAX_PATH+1];
// add common picture locations
StdStrBuf strLocation;
SCopy(Config.General.UserDataPath, path, _MAX_PATH); TruncateBackslash(path);
2009-05-08 13:28:41 +00:00
strLocation.Format("%s %s", C4ENGINECAPTION, LoadResStr("IDS_TEXT_USERPATH"));
AddLocation(strLocation.getData(), path);
SCopy(Config.General.SystemDataPath, path, _MAX_PATH); TruncateBackslash(path);
2009-05-08 13:28:41 +00:00
strLocation.Format("%s %s", C4ENGINECAPTION, LoadResStr("IDS_TEXT_PROGRAMDIRECTORY"));
AddCheckedLocation(strLocation.getData(), path);
2009-05-08 13:28:41 +00:00
#ifdef _WIN32
wchar_t wpath[MAX_PATH+1];
if (SHGetSpecialFolderPathW(nullptr, wpath, CSIDL_PERSONAL, false)) AddCheckedLocation(LoadResStr("IDS_TEXT_MYDOCUMENTS"), StdStrBuf(wpath).getData());
if (SHGetSpecialFolderPathW(nullptr, wpath, CSIDL_MYPICTURES, false)) AddCheckedLocation(LoadResStr("IDS_TEXT_MYPICTURES"), StdStrBuf(wpath).getData());
if (SHGetSpecialFolderPathW(nullptr, wpath, CSIDL_DESKTOPDIRECTORY, false)) AddCheckedLocation(LoadResStr("IDS_TEXT_DESKTOP"), StdStrBuf(wpath).getData());
2009-05-08 13:28:41 +00:00
#endif
#ifdef __APPLE__
AddCheckedLocation(LoadResStr("IDS_TEXT_HOME"), getenv("HOME"));
#else
AddCheckedLocation(LoadResStr("IDS_TEXT_HOMEFOLDER"), getenv("HOME"));
#endif
#ifndef _WIN32
sprintf(path, "%s%c%s", getenv("HOME"), (char)DirectorySeparator, (const char *)"Desktop");
AddCheckedLocation(LoadResStr("IDS_TEXT_DESKTOP"), path);
#endif
// build dialog
InitElements();
// select last location
SetCurrentLocation(Config.Startup.LastPortraitFolderIdx, false);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::OnClosed(bool fOK)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// remember location
Config.Startup.LastPortraitFolderIdx = GetCurrentLocationIndex();
// inherited
C4FileSelDlg::OnClosed(fOK);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4FileSelDlg::ListItem *C4PortraitSelDlg::CreateListItem(const char *szFilename)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// use own list item type
ListItem *pNew = new ListItem(szFilename);;
// schedule image loading
ImageLoader.AddLoadItem(pNew);
return pNew;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::BeginFileListUpdate()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// new file list. Stop loading current
ImageLoader.ClearLoadItems();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::EndFileListUpdate()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
#if USE_BACKGROUND_THREAD_LOAD
// Begin loading images
ImageLoader.Start();
#endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4PortraitSelDlg::OnIdle()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
#if !USE_BACKGROUND_THREAD_LOAD
// no multithreading? Workaround for image loading then...
static int32_t i = 0;
if (!(i++%10)) ImageLoader.Execute();
#endif
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4PortraitSelDlg::SelectPortrait(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// let the user select a portrait by showing a modal selection dialog
C4PortraitSelDlg *pDlg = new C4PortraitSelDlg(nullptr);
2009-05-08 13:28:41 +00:00
bool fResult;
2010-01-25 04:00:59 +00:00
if ((fResult = pOnScreen->ShowModalDlg(pDlg, false)))
2010-03-28 18:58:01 +00:00
{
pSelection->Take(pDlg->GetSelection(nullptr, false));
2010-03-28 18:58:01 +00:00
}
delete pDlg;
2009-05-08 13:28:41 +00:00
return fResult;
2010-03-28 18:58:01 +00:00
}