openclonk/src/gui/C4FileSelDlg.cpp

646 lines
21 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
// file selection dialogs
#include "C4Include.h"
#include "gui/C4FileSelDlg.h"
#include "graphics/C4GraphicsResource.h" // only for single use of ::GraphicsResource.fctOKCancel below...
#include "C4Version.h"
#include "graphics/C4Draw.h"
#ifdef _WIN32
#ifndef _WIN32_IE
#define _WIN32_IE 0x0400
#endif
#undef MK_ALT
#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))
{
if (szFilename) sFilename.Copy(szFilename); else sFilename.Clear();
}
C4FileSelDlg::ListItem::~ListItem()
{
}
// ---------------------------------------------------
// 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)
{
StdStrBuf sLabel; if (szFilename) sLabel.Ref(::GetFilename(szFilename)); else sLabel.Ref(LoadResStr("IDS_CTL_NONE"));
if (szFilename && fTruncateExtension)
{
sLabel.Copy();
char *szFilename = sLabel.GrabPointer();
RemoveExtension(szFilename);
sLabel.Take(szFilename);
}
rcBounds.Hgt = ::GraphicsResource.TextFont.GetLineHeight();
UpdateSize();
C4GUI::ComponentAligner caMain(GetContainedClientRect(),0,0);
int32_t iHeight = caMain.GetInnerHeight();
if (fCheckbox)
{
pCheck = new C4GUI::CheckBox(caMain.GetFromLeft(iHeight), nullptr, false);
if (fGrayed) pCheck->SetEnabled(false);
AddElement(pCheck);
pKeyCheck = new C4KeyBinding(C4KeyCodeEx(K_SPACE), "FileSelToggleFileActive", KEYSCOPE_Gui,
new C4GUI::ControlKeyCB<ListItem>(*this, &ListItem::UserToggleCheck), C4CustomKey::PRIO_Ctrl);
}
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);
}
C4FileSelDlg::DefaultListItem::~DefaultListItem()
{
if (pKeyCheck) delete pKeyCheck;
}
void C4FileSelDlg::DefaultListItem::UpdateOwnPos()
{
BaseClass::UpdateOwnPos();
if (!pLbl) return;
C4GUI::ComponentAligner caMain(GetContainedClientRect(),0,0);
caMain.GetFromLeft(caMain.GetInnerHeight()*(1+!!pCheck));
pLbl->SetBounds(caMain.GetAll());
}
bool C4FileSelDlg::DefaultListItem::IsChecked() const
{
return pCheck ? pCheck->GetChecked() : false;
}
void C4FileSelDlg::DefaultListItem::SetChecked(bool fChecked)
{
// store new state in checkbox
if (pCheck) pCheck->SetChecked(fChecked);
}
bool C4FileSelDlg::DefaultListItem::UserToggleCheck()
{
// toggle if possible
if (pCheck && !IsGrayed())
{
pCheck->ToggleCheck(true);
return true;
}
return false;
}
// ---------------------------------------------------
// 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)
{
sTitle.Copy(szTitle);
// key bindings
pKeyRefresh = new C4KeyBinding(C4KeyCodeEx(K_F5), "FileSelReload", KEYSCOPE_Gui,
new C4GUI::DlgKeyCB<C4FileSelDlg>(*this, &C4FileSelDlg::KeyRefresh), C4CustomKey::PRIO_CtrlOverride);
pKeyEnterOverride = new C4KeyBinding(C4KeyCodeEx(K_RETURN), "FileSelConfirm", KEYSCOPE_Gui,
new C4GUI::DlgKeyCB<C4FileSelDlg>(*this, &C4FileSelDlg::KeyEnter), C4CustomKey::PRIO_CtrlOverride);
if (fInitElements) InitElements();
sPath.Copy(szRootPath);
}
void C4FileSelDlg::InitElements()
{
UpdateSize();
CStdFont *pUseFont = &(::GraphicsResource.TextFont);
// 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)
{
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());
}
// 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)
{
caUpperArea.ExpandLeft(C4GUI_DefDlgIndent);
pSelectionInfoBox = new C4GUI::TextWindow(caUpperArea.GetAll());
pSelectionInfoBox->SetDecoration(true, true, nullptr, true);
}
// 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();
}
C4FileSelDlg::~C4FileSelDlg()
{
delete [] pLocations;
if (pSelCallback) delete pSelCallback;
delete pKeyEnterOverride;
delete pKeyRefresh;
}
void C4FileSelDlg::OnLocationComboFill(C4GUI::ComboBox_FillCB *pFiller)
{
// Add all locations
for (int32_t i=0; i<iLocationCount; ++i)
pFiller->AddEntry(pLocations[i].sName.getData(), i);
}
bool C4FileSelDlg::OnLocationComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection)
{
SetCurrentLocation(idNewSelection, true);
// No text change by caller; text alread changed by SetCurrentLocation
return true;
}
void C4FileSelDlg::SetPath(const char *szNewPath, bool fRefresh)
{
sPath.Copy(szNewPath);
if (fRefresh && IsShown()) UpdateFileList();
}
void C4FileSelDlg::OnShown()
{
BaseClass::OnShown();
// load files
UpdateFileList();
}
void C4FileSelDlg::UserClose(bool fOK)
{
if (!fOK || pSelection)
{
// allow OK only if something is sth is selected
Close(fOK);
}
else
{
GetScreen()->ShowErrorMessage(LoadResStr("IDS_ERR_PLEASESELECTAFILEFIRST"));
}
}
void C4FileSelDlg::OnClosed(bool fOK)
{
if (fOK && pSelection && pSelCallback)
pSelCallback->OnFileSelected(pSelection->GetFilename());
// base call: Might delete dlg
BaseClass::OnClosed(fOK);
}
void C4FileSelDlg::OnSelDblClick(class C4GUI::Element *pEl)
{
// item double-click: confirms with this file in single mode; toggles selection in multi mode
if (IsMultiSelection())
{
ListItem *pItem = static_cast<ListItem *>(pEl);
pItem->UserToggleCheck();
}
else
UserClose(true);
}
C4FileSelDlg::ListItem *C4FileSelDlg::CreateListItem(const char *szFilename)
{
// Default list item
if (szFilename)
return new DefaultListItem(szFilename, !!GetFileMask(), IsMultiSelection(), IsItemGrayed(szFilename), GetFileItemIcon());
else
return new DefaultListItem(nullptr, false, IsMultiSelection(), false, GetFileItemIcon());
}
void C4FileSelDlg::UpdateFileList()
{
BeginFileListUpdate();
// reload files
C4GUI::Element *pEl;
while ((pEl = pFileListBox->GetFirst())) delete pEl;
// 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())
{
pFileListBox->AddElement(CreateListItem(nullptr));
}
// 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();
}
void C4FileSelDlg::UpdateSelection()
{
// 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)
{
// 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);
}
}
void C4FileSelDlg::SetSelection(const char *szNewSelection, bool fFilenameOnly)
{
// check all selected definitions
for (ListItem *pFileItem = static_cast<ListItem *>(pFileListBox->GetFirst()); pFileItem; pFileItem = static_cast<ListItem *>(pFileItem->GetNext()))
{
const char *szFileItemFilename = pFileItem->GetFilename();
if (fFilenameOnly) szFileItemFilename = GetFilename(szFileItemFilename);
pFileItem->SetChecked(SIsModule(szNewSelection, szFileItemFilename));
}
}
StdStrBuf C4FileSelDlg::GetSelection(const char *szFixedSelection, bool fFilenameOnly) const
{
StdStrBuf sResult;
if (!IsMultiSelection())
{
// get single selected file for single selection dlg
if (pSelection) sResult.Copy(fFilenameOnly ? GetFilename(pSelection->GetFilename()) : pSelection->GetFilename());
}
else
{
// force fixed selection first
if (szFixedSelection) sResult.Append(szFixedSelection);
// get ';'-separated list for multi selection dlg
for (ListItem *pFileItem = static_cast<ListItem *>(pFileListBox->GetFirst()); pFileItem; pFileItem = static_cast<ListItem *>(pFileItem->GetNext()))
if (pFileItem->IsChecked())
{
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))
{
if (sResult.getLength()) sResult.AppendChar(';');
sResult.Append(szAppendFilename);
}
}
}
return sResult;
}
void C4FileSelDlg::AddLocation(const char *szName, const char *szPath)
{
// 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);
}
void C4FileSelDlg::AddCheckedLocation(const char *szName, const char *szPath)
{
// 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);
}
int32_t C4FileSelDlg::GetCurrentLocationIndex() const
{
return iCurrentLocationIndex;
}
void C4FileSelDlg::SetCurrentLocation(int32_t idx, bool fRefresh)
{
// 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);
}
// ---------------------------------------------------
// C4PlayerSelDlg
C4PlayerSelDlg::C4PlayerSelDlg(C4FileSel_BaseCB *pSelCallback)
: C4FileSelDlg(Config.General.UserDataPath, LoadResStr("IDS_MSG_SELECTPLR"), pSelCallback)
{
}
// ---------------------------------------------------
// C4DefinitionSelDlg
C4DefinitionSelDlg::C4DefinitionSelDlg(C4FileSel_BaseCB *pSelCallback, const char *szFixedSelection)
: C4FileSelDlg(Config.General.UserDataPath, FormatString(LoadResStr("IDS_MSG_SELECT"), LoadResStr("IDS_DLG_DEFINITIONS")).getData(), pSelCallback)
{
if (szFixedSelection) sFixedSelection.Copy(szFixedSelection);
}
void C4DefinitionSelDlg::OnShown()
{
// base call: load file list
C4FileSelDlg::OnShown();
// initial selection
if (sFixedSelection) SetSelection(sFixedSelection.getData(), true);
}
bool C4DefinitionSelDlg::IsItemGrayed(const char *szFilename) const
{
// cannot change initial selection
if (!sFixedSelection) return false;
return SIsModule(sFixedSelection.getData(), GetFilename(szFilename));
}
bool C4DefinitionSelDlg::SelectDefinitions(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection)
{
// let the user select definitions by showing a modal selection dialog
C4DefinitionSelDlg *pDlg = new C4DefinitionSelDlg(nullptr, pSelection->getData());
bool fResult;
if ((fResult = pOnScreen->ShowModalDlg(pDlg, false)))
{
pSelection->Copy(pDlg->GetSelection(pSelection->getData(), true));
}
delete pDlg;
return fResult;
}
// ---------------------------------------------------
// C4PortraitSelDlg::ListItem
C4PortraitSelDlg::ListItem::ListItem(const char *szFilename) : C4FileSelDlg::ListItem(szFilename)
, fError(false), fLoaded(false)
{
CStdFont *pUseFont = &(::GraphicsResource.MiniFont);
// determine label text
StdStrBuf sDisplayLabel;
if (szFilename)
{
sDisplayLabel.Copy(::GetFilename(szFilename));
::RemoveExtension(&sDisplayLabel);
}
else
{
sDisplayLabel.Ref(LoadResStr("IDS_MSG_NOPORTRAIT"));
}
// insert linebreaks into label text
int32_t iLineHgt = std::max<int32_t>(pUseFont->BreakMessage(sDisplayLabel.getData(), ImagePreviewSize-6, &sFilenameLabelText, false), 1);
// set size
SetBounds(C4Rect(0,0,ImagePreviewSize,ImagePreviewSize+iLineHgt));
}
void C4PortraitSelDlg::ListItem::Load()
{
if (sFilename)
{
// 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))
{
// image loaded. Can only be put into facet by main thread, because those operations aren't thread safe
fLoaded = true;
fLoadError = false;
}
SrcGrp.Close();
fError = fLoadError;
}
}
void C4PortraitSelDlg::ListItem::DrawElement(C4TargetFacet &cgo)
{
// Scale down newly loaded image?
if (fLoaded)
{
fLoaded = false;
if (!fctImage.CopyFromSfcMaxSize(fctLoadedImage.GetFace(), ImagePreviewSize))
fError = true;
fctLoadedImage.GetFace().Clear();
fctLoadedImage.Clear();
}
// Draw picture
CStdFont *pUseFont = &(::GraphicsResource.MiniFont);
C4Facet cgoPicture(cgo.Surface, cgo.TargetX+rcBounds.x, cgo.TargetY+rcBounds.y, ImagePreviewSize, ImagePreviewSize);
if (fError || !sFilename)
{
C4Facet &fctNoneImg = ::GraphicsResource.fctOKCancel;
fctNoneImg.Draw(cgoPicture.Surface, cgoPicture.X+(cgoPicture.Wdt-fctNoneImg.Wdt)/2, cgoPicture.Y+(cgoPicture.Hgt-fctNoneImg.Hgt)/2, 1,0);
}
else
{
if (!fctImage.Surface)
{
// not loaded yet
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);
}
else
{
fctImage.Draw(cgoPicture);
}
}
// draw filename
pDraw->TextOut(sFilenameLabelText.getData(), *pUseFont, 1.0f, cgo.Surface, cgoPicture.X+rcBounds.Wdt/2, cgoPicture.Y+cgoPicture.Hgt, C4GUI_MessageFontClr, ACenter, false);
}
// ---------------------------------------------------
// C4PortraitSelDlg::LoaderThread
void C4PortraitSelDlg::LoaderThread::ClearLoadItems()
{
// stop thread so list can be accessed
Stop();
// clear list
LoadItems.clear();
}
void C4PortraitSelDlg::LoaderThread::AddLoadItem(ListItem *pItem)
{
// not to be called when thread is running!
assert(!IsStarted());
LoadItems.push_back(pItem);
}
void C4PortraitSelDlg::LoaderThread::Execute()
{
// list empty?
if (!LoadItems.size())
{
// then we're done!
SignalStop();
return;
}
// load one item at the time
ListItem *pLoadItem = LoadItems.front();
pLoadItem->Load();
LoadItems.erase(LoadItems.begin());
}
// ---------------------------------------------------
// C4PortraitSelDlg
C4PortraitSelDlg::C4PortraitSelDlg(C4FileSel_BaseCB *pSelCallback)
: C4FileSelDlg(Config.General.SystemDataPath, FormatString(LoadResStr("IDS_MSG_SELECT"), LoadResStr("IDS_TYPE_PORTRAIT")).getData(), pSelCallback, false)
{
char path[_MAX_PATH+1];
// add common picture locations
StdStrBuf strLocation;
SCopy(Config.General.UserDataPath, path, _MAX_PATH); TruncateBackslash(path);
strLocation.Format("%s %s", C4ENGINECAPTION, LoadResStr("IDS_TEXT_USERPATH"));
AddLocation(strLocation.getData(), path);
SCopy(Config.General.SystemDataPath, path, _MAX_PATH); TruncateBackslash(path);
strLocation.Format("%s %s", C4ENGINECAPTION, LoadResStr("IDS_TEXT_PROGRAMDIRECTORY"));
AddCheckedLocation(strLocation.getData(), path);
#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());
#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);
}
void C4PortraitSelDlg::OnClosed(bool fOK)
{
// remember location
Config.Startup.LastPortraitFolderIdx = GetCurrentLocationIndex();
// inherited
C4FileSelDlg::OnClosed(fOK);
}
C4FileSelDlg::ListItem *C4PortraitSelDlg::CreateListItem(const char *szFilename)
{
// use own list item type
ListItem *pNew = new ListItem(szFilename);;
// schedule image loading
ImageLoader.AddLoadItem(pNew);
return pNew;
}
void C4PortraitSelDlg::BeginFileListUpdate()
{
// new file list. Stop loading current
ImageLoader.ClearLoadItems();
}
void C4PortraitSelDlg::EndFileListUpdate()
{
#if USE_BACKGROUND_THREAD_LOAD
// Begin loading images
ImageLoader.Start();
#endif
}
void C4PortraitSelDlg::OnIdle()
{
#if !USE_BACKGROUND_THREAD_LOAD
// no multithreading? Workaround for image loading then...
static int32_t i = 0;
if (!(i++%10)) ImageLoader.Execute();
#endif
}
bool C4PortraitSelDlg::SelectPortrait(C4GUI::Screen *pOnScreen, StdStrBuf *pSelection)
{
// let the user select a portrait by showing a modal selection dialog
C4PortraitSelDlg *pDlg = new C4PortraitSelDlg(nullptr);
bool fResult;
if ((fResult = pOnScreen->ShowModalDlg(pDlg, false)))
{
pSelection->Take(pDlg->GetSelection(nullptr, false));
}
delete pDlg;
return fResult;
}