Finish PromptBrowseWindow's prepare draw function (#1118)
* Implement loadFileDetails (0x00446E87) * Implement the rest of prepareDraw (0x00445C8F) * Rename file_entry to FileEntry; apply code style * Remove superfluous hooks for the browse window
This commit is contained in:
parent
65895bcab1
commit
7d0f7f9dba
|
@ -1451,4 +1451,9 @@ namespace OpenLoco::Gfx
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setCurrentFontSpriteBase(int16_t value)
|
||||
{
|
||||
_currentFontSpriteBase = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,4 +247,6 @@ namespace OpenLoco::Gfx
|
|||
std::optional<Gfx::Context> clipContext(const Gfx::Context& src, const Ui::Rect& newRect);
|
||||
|
||||
G1Element* getG1Element(uint32_t id);
|
||||
|
||||
void setCurrentFontSpriteBase(int16_t value);
|
||||
}
|
||||
|
|
|
@ -774,7 +774,6 @@ void OpenLoco::Interop::registerHooks()
|
|||
Ui::ProgressBar::registerHooks();
|
||||
Map::TileManager::registerHooks();
|
||||
Map::AnimationManager::registerHooks();
|
||||
Ui::Windows::PromptBrowse::registerHooks();
|
||||
Ui::Windows::TextInput::registerHooks();
|
||||
Ui::Windows::ToolTip::registerHooks();
|
||||
Ui::Windows::Vehicle::registerHooks();
|
||||
|
|
|
@ -254,7 +254,6 @@ namespace OpenLoco::Ui::Windows
|
|||
};
|
||||
bool open(browse_type type, char* path, const char* filter, const char* title);
|
||||
void handleInput(uint32_t charCode, uint32_t keyCode);
|
||||
void registerHooks();
|
||||
}
|
||||
|
||||
namespace PromptOkCancel
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct file_entry
|
||||
struct FileEntry
|
||||
{
|
||||
private:
|
||||
static constexpr uint8_t flag_directory = 1 << 4;
|
||||
|
@ -59,24 +59,24 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
char filename[0x140 - 0x2C]{};
|
||||
|
||||
public:
|
||||
file_entry()
|
||||
FileEntry()
|
||||
{
|
||||
}
|
||||
|
||||
file_entry(const std::string_view& p, bool isDirectory)
|
||||
FileEntry(const std::string_view& p, bool isDirectory)
|
||||
{
|
||||
p.copy(filename, sizeof(filename) - 1, 0);
|
||||
flags = isDirectory ? flag_directory : 0;
|
||||
}
|
||||
|
||||
constexpr bool is_directory() const
|
||||
constexpr bool isDirectory() const
|
||||
{
|
||||
return flags & flag_directory;
|
||||
}
|
||||
|
||||
std::string_view get_name() const
|
||||
std::string_view getName() const
|
||||
{
|
||||
if (!is_directory())
|
||||
if (!isDirectory())
|
||||
{
|
||||
auto end = std::strchr(filename, '.');
|
||||
if (end != nullptr)
|
||||
|
@ -89,7 +89,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(file_entry) == 0x140);
|
||||
static_assert(sizeof(FileEntry) == 0x140);
|
||||
|
||||
enum widx
|
||||
{
|
||||
|
@ -118,16 +118,18 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
static WindowEventList _events;
|
||||
static loco_global<uint8_t, 0x009D9D63> _type;
|
||||
static loco_global<browse_file_type, 0x009DA284> _fileType;
|
||||
static loco_global<uint8_t, 0x009DA285> _9DA285;
|
||||
static loco_global<char[512], 0x009DA084> _displayFolderBuffer;
|
||||
static loco_global<char[256], 0x009D9D64> _title;
|
||||
static loco_global<char[32], 0x009D9E64> _filter;
|
||||
static loco_global<char[512], 0x009D9E84> _directory;
|
||||
static loco_global<char[512], 0x0112CC04> _stringFormatBuffer;
|
||||
static loco_global<int16_t, 0x009D1084> _numFiles;
|
||||
static loco_global<file_entry*, 0x0050AEA4> _files;
|
||||
static loco_global<FileEntry*, 0x0050AEA4> _files;
|
||||
|
||||
static Ui::TextInput::InputSession inputSession;
|
||||
|
||||
static std::vector<file_entry> _newFiles;
|
||||
static std::vector<FileEntry> _newFiles;
|
||||
|
||||
static void onClose(Window* window);
|
||||
static void onResize(Window* window);
|
||||
|
@ -146,9 +148,9 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
static void upOneLevel();
|
||||
static void appendDirectory(const char* to_append);
|
||||
static void processFileForLoadSave(Window* window);
|
||||
static void processFileForDelete(Window* self, file_entry& entry);
|
||||
static void processFileForDelete(Window* self, FileEntry& entry);
|
||||
static void refreshDirectoryList();
|
||||
static void sub_446E87(Window* self);
|
||||
static void loadFileDetails(Window* self);
|
||||
static bool filenameContainsInvalidChars();
|
||||
|
||||
// 0x00445AB9
|
||||
|
@ -209,7 +211,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
window->row_height = 11;
|
||||
window->var_85A = -1;
|
||||
|
||||
addr<0x009DA285, uint8_t>() = 0;
|
||||
_9DA285 = 0;
|
||||
|
||||
auto& widget = window->widgets[widx::text_filename];
|
||||
inputSession.calculateTextOffset(widget.width());
|
||||
|
@ -240,14 +242,20 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
return false;
|
||||
}
|
||||
|
||||
// 0x00447174
|
||||
static void freeFileDetails()
|
||||
{
|
||||
call(0x00447174);
|
||||
}
|
||||
|
||||
// 0x0044647C
|
||||
static void onClose(Window*)
|
||||
{
|
||||
_newFiles = {};
|
||||
_numFiles = 0;
|
||||
_files = (file_entry*)-1;
|
||||
_files = (FileEntry*)-1;
|
||||
|
||||
call(0x00447174);
|
||||
freeFileDetails();
|
||||
}
|
||||
|
||||
// 0x004467F6
|
||||
|
@ -300,12 +308,12 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
|
||||
Audio::playSound(Audio::SoundId::clickDown, self->x + (self->width / 2));
|
||||
|
||||
file_entry entry = _files[index];
|
||||
FileEntry entry = _files[index];
|
||||
|
||||
// Clicking a directory, with left mouse button?
|
||||
if (Input::state() == Input::State::scrollLeft && entry.is_directory())
|
||||
if (Input::state() == Input::State::scrollLeft && entry.isDirectory())
|
||||
{
|
||||
appendDirectory(entry.get_name().data());
|
||||
appendDirectory(entry.getName().data());
|
||||
self->invalidate();
|
||||
return;
|
||||
}
|
||||
|
@ -314,7 +322,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
if (Input::state() == Input::State::scrollLeft)
|
||||
{
|
||||
// Copy the selected filename without extension to text input buffer.
|
||||
inputSession.buffer = entry.get_name();
|
||||
inputSession.buffer = entry.getName();
|
||||
inputSession.cursorPosition = inputSession.buffer.length();
|
||||
self->invalidate();
|
||||
|
||||
|
@ -342,7 +350,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
return;
|
||||
|
||||
self->var_85A = index;
|
||||
sub_446E87(self);
|
||||
loadFileDetails(self);
|
||||
self->invalidate();
|
||||
}
|
||||
|
||||
|
@ -402,11 +410,39 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
self->widgets[widx::parent_button].left = self->width - 26;
|
||||
self->widgets[widx::parent_button].right = self->width - 3;
|
||||
|
||||
// Resume the original prepare_draw routine beyond the widget repositioning.
|
||||
registers regs;
|
||||
regs.edi = X86Pointer(buffer);
|
||||
regs.esi = X86Pointer(self);
|
||||
call(0x00445D91, regs);
|
||||
// Get width of the base 'Folder:' string
|
||||
auto args = FormatArguments::common(StringIds::empty);
|
||||
char folderBuffer[256]{};
|
||||
StringManager::formatString(folderBuffer, StringIds::window_browse_folder, &args);
|
||||
Gfx::setCurrentFontSpriteBase(Font::medium_bold);
|
||||
const auto folderLabelWidth = Gfx::getStringWidth(folderBuffer);
|
||||
|
||||
// We'll ensure the folder width does not reach the parent button.
|
||||
const uint16_t maxWidth = self->widgets[widx::parent_button].left - folderLabelWidth - 10;
|
||||
strncpy(&_displayFolderBuffer[0], &_directory[0], 512);
|
||||
uint16_t folderWidth = Gfx::getStringWidth(_displayFolderBuffer);
|
||||
|
||||
// If the folder already fits, we're done.
|
||||
if (folderWidth <= maxWidth)
|
||||
return;
|
||||
|
||||
char* relativeDirectory = &_directory[0];
|
||||
do
|
||||
{
|
||||
// If we're omitting part of the folder, prepend ellipses.
|
||||
if (relativeDirectory != &_directory[0])
|
||||
strncpy(&_displayFolderBuffer[0], "...", 512);
|
||||
|
||||
// Seek the next directory separator token.
|
||||
while (*relativeDirectory != '\0' && *relativeDirectory != fs::path::preferred_separator)
|
||||
relativeDirectory++;
|
||||
|
||||
// Use the truncated directory name in the buffer.
|
||||
strncat(&_displayFolderBuffer[0], relativeDirectory, 512);
|
||||
|
||||
// Prepare for the next pass, if needed.
|
||||
relativeDirectory++;
|
||||
} while (Gfx::getStringWidth(_displayFolderBuffer) > maxWidth);
|
||||
}
|
||||
|
||||
static void setCommonArgsStringptr(const char* buffer)
|
||||
|
@ -425,7 +461,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
|
||||
window->draw(context);
|
||||
|
||||
auto folder = (const char*)0x9DA084;
|
||||
auto folder = &_displayFolderBuffer[0];
|
||||
setCommonArgsStringptr(folder);
|
||||
Gfx::drawString_494B3F(*context, window->x + 3, window->y + window->widgets[widx::parent_button].top + 6, 0, StringIds::window_browse_folder, _commonFormatArgs);
|
||||
|
||||
|
@ -433,7 +469,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
if (selectedIndex != -1)
|
||||
{
|
||||
auto& selectedFile = _files[selectedIndex];
|
||||
if (!selectedFile.is_directory())
|
||||
if (!selectedFile.isDirectory())
|
||||
{
|
||||
const auto& widget = window->widgets[widx::scrollview];
|
||||
|
||||
|
@ -441,7 +477,7 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
auto x = window->x + widget.right + 3;
|
||||
auto y = window->y + 45;
|
||||
|
||||
_nameBuffer = selectedFile.get_name();
|
||||
_nameBuffer = selectedFile.getName();
|
||||
setCommonArgsStringptr(_nameBuffer.c_str());
|
||||
Gfx::drawStringCentredClipped(
|
||||
*context,
|
||||
|
@ -632,14 +668,14 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
|
||||
// Draw the folder icon
|
||||
auto x = 1;
|
||||
if (file.is_directory())
|
||||
if (file.isDirectory())
|
||||
{
|
||||
Gfx::drawImage(&context, x, y, ImageIds::icon_folder);
|
||||
x += 14;
|
||||
}
|
||||
|
||||
// Copy name to our work buffer
|
||||
_nameBuffer = file.get_name();
|
||||
_nameBuffer = file.getName();
|
||||
|
||||
// Draw the name
|
||||
setCommonArgsStringptr(_nameBuffer.c_str());
|
||||
|
@ -765,12 +801,12 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
}
|
||||
}
|
||||
|
||||
std::sort(_newFiles.begin(), _newFiles.end(), [](const file_entry& a, const file_entry& b) -> bool {
|
||||
if (!a.is_directory() && b.is_directory())
|
||||
std::sort(_newFiles.begin(), _newFiles.end(), [](const FileEntry& a, const FileEntry& b) -> bool {
|
||||
if (!a.isDirectory() && b.isDirectory())
|
||||
return false;
|
||||
if (a.is_directory() && !b.is_directory())
|
||||
if (a.isDirectory() && !b.isDirectory())
|
||||
return true;
|
||||
return a.get_name() < b.get_name();
|
||||
return a.getName() < b.getName();
|
||||
});
|
||||
|
||||
_numFiles = (int16_t)_newFiles.size();
|
||||
|
@ -818,28 +854,6 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
refreshDirectoryList();
|
||||
}
|
||||
|
||||
void registerHooks()
|
||||
{
|
||||
registerHook(
|
||||
0x00445AB9,
|
||||
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
|
||||
auto result = open(
|
||||
(browse_type)regs.al,
|
||||
(char*)regs.ecx,
|
||||
(const char*)regs.edx,
|
||||
(const char*)regs.ebx);
|
||||
regs.eax = result ? 1 : 0;
|
||||
return 0;
|
||||
});
|
||||
|
||||
registerHook(
|
||||
0x00446E62,
|
||||
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
|
||||
appendDirectory((char*)regs.ebp);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
// 0x00446F1D
|
||||
static bool filenameContainsInvalidChars()
|
||||
{
|
||||
|
@ -950,17 +964,17 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
}
|
||||
|
||||
// 0x004466CA
|
||||
static void processFileForDelete(Window* self, file_entry& entry)
|
||||
static void processFileForDelete(Window* self, FileEntry& entry)
|
||||
{
|
||||
// Create full path to target file.
|
||||
fs::path path = fs::u8path(&_directory[0]) / std::string(entry.get_name());
|
||||
fs::path path = fs::u8path(&_directory[0]) / std::string(entry.getName());
|
||||
|
||||
// Append extension to filename.
|
||||
path += getExtensionFromFileType(_fileType);
|
||||
|
||||
// Copy directory and filename to buffer.
|
||||
char* buffer_2039 = const_cast<char*>(StringManager::getString(StringIds::buffer_2039));
|
||||
strncpy(&buffer_2039[0], entry.get_name().data(), 512);
|
||||
strncpy(&buffer_2039[0], entry.getName().data(), 512);
|
||||
|
||||
FormatArguments args{};
|
||||
args.push(StringIds::buffer_2039);
|
||||
|
@ -985,11 +999,37 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
|
|||
}
|
||||
|
||||
// 0x00446E87
|
||||
// TODO: only called by this window -- implement.
|
||||
static void sub_446E87(Window* self)
|
||||
static void loadFileDetails(Window* self)
|
||||
{
|
||||
registers regs;
|
||||
regs.esi = X86Pointer(self);
|
||||
call(0x00446E87, regs);
|
||||
freeFileDetails();
|
||||
|
||||
_9DA285 = 0;
|
||||
if (self->var_85A == -1)
|
||||
return;
|
||||
|
||||
FileEntry& entry = _files[self->var_85A];
|
||||
if (entry.isDirectory())
|
||||
return;
|
||||
|
||||
// Create full path to target file.
|
||||
fs::path path = fs::u8path(&_directory[0]) / std::string(entry.getName());
|
||||
|
||||
// Append extension to filename.
|
||||
path += getExtensionFromFileType(_fileType);
|
||||
|
||||
// Copy path to buffer.
|
||||
loco_global<char[512], 0x0112CE04> savePath;
|
||||
strncpy(&savePath[0], path.u8string().c_str(), 512);
|
||||
|
||||
// Load save game or scenario info.
|
||||
switch (_fileType)
|
||||
{
|
||||
case browse_file_type::saved_game:
|
||||
call(0x00442403);
|
||||
break;
|
||||
case browse_file_type::landscape:
|
||||
call(0x00442AFC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue