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:
Aaron van Geffen 2021-08-20 12:31:03 +02:00 committed by GitHub
parent 65895bcab1
commit 7d0f7f9dba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 65 deletions

View File

@ -1451,4 +1451,9 @@ namespace OpenLoco::Gfx
}
return nullptr;
}
void setCurrentFontSpriteBase(int16_t value)
{
_currentFontSpriteBase = value;
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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

View File

@ -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;
}
}
}