mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-14 03:59:36 +00:00
Redo file prompts with in-game UI
This commit is contained in:
@@ -88,7 +88,7 @@ namespace PortabilityLayer
|
||||
ArrayView<const DialogItem> GetItems() const override;
|
||||
void SetItemVisibility(unsigned int itemIndex, bool isVisible) override;
|
||||
|
||||
int16_t ExecuteModal(DialogFilterFunc_t filterFunc) override;
|
||||
int16_t ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc) override;
|
||||
|
||||
bool ReplaceWidget(unsigned int itemIndex, Widget *widget) override;
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace PortabilityLayer
|
||||
|
||||
static void MakeStringSubstitutions(uint8_t *outStr, const uint8_t *inStr, const DialogTextSubstitutions *substitutions);
|
||||
|
||||
int16_t ExecuteModalInDarkenStack(DialogFilterFunc_t filterFunc);
|
||||
int16_t ExecuteModalInDarkenStack(void *captureContext, DialogFilterFunc_t filterFunc);
|
||||
|
||||
Window *m_window;
|
||||
DialogItem *m_items;
|
||||
@@ -334,20 +334,20 @@ namespace PortabilityLayer
|
||||
}
|
||||
}
|
||||
|
||||
int16_t DialogImpl::ExecuteModal(DialogFilterFunc_t filterFunc)
|
||||
int16_t DialogImpl::ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc)
|
||||
{
|
||||
Window *exclWindow = this->GetWindow();
|
||||
|
||||
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
|
||||
|
||||
int16_t result = ExecuteModalInDarkenStack(filterFunc);
|
||||
int16_t result = ExecuteModalInDarkenStack(captureContext, filterFunc);
|
||||
|
||||
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t DialogImpl::ExecuteModalInDarkenStack(DialogFilterFunc_t filterFunc)
|
||||
int16_t DialogImpl::ExecuteModalInDarkenStack(void *captureContext, DialogFilterFunc_t filterFunc)
|
||||
{
|
||||
Window *window = this->GetWindow();
|
||||
Widget *capturingWidget = nullptr;
|
||||
@@ -362,7 +362,7 @@ namespace PortabilityLayer
|
||||
if (window->IsHandlingTickEvents())
|
||||
window->OnTick();
|
||||
|
||||
const int16_t selection = filterFunc(this, haveEvent ? &evt : nullptr);
|
||||
const int16_t selection = (filterFunc != nullptr) ? filterFunc(captureContext, this, haveEvent ? &evt : nullptr) : -1;
|
||||
|
||||
if (selection >= 0)
|
||||
return selection;
|
||||
@@ -371,7 +371,7 @@ namespace PortabilityLayer
|
||||
{
|
||||
if (capturingWidget != nullptr)
|
||||
{
|
||||
const WidgetHandleState_t state = capturingWidget->ProcessEvent(evt);
|
||||
const WidgetHandleState_t state = capturingWidget->ProcessEvent(captureContext, evt);
|
||||
|
||||
if (state != WidgetHandleStates::kDigested)
|
||||
capturingWidget = nullptr;
|
||||
@@ -398,7 +398,7 @@ namespace PortabilityLayer
|
||||
{
|
||||
Widget *widget = this->m_items[i].GetWidget();
|
||||
|
||||
const WidgetHandleState_t state = widget->ProcessEvent(evt);
|
||||
const WidgetHandleState_t state = widget->ProcessEvent(captureContext, evt);
|
||||
|
||||
if (state == WidgetHandleStates::kActivated)
|
||||
return static_cast<int16_t>(i + 1);
|
||||
@@ -621,7 +621,7 @@ namespace PortabilityLayer
|
||||
|
||||
private:
|
||||
|
||||
static int16_t AlertFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
static int16_t AlertFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
|
||||
static DialogManagerImpl ms_instance;
|
||||
};
|
||||
@@ -706,7 +706,7 @@ namespace PortabilityLayer
|
||||
return dialog;
|
||||
}
|
||||
|
||||
int16_t DialogManagerImpl::AlertFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
int16_t DialogManagerImpl::AlertFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -767,7 +767,7 @@ namespace PortabilityLayer
|
||||
if (!dialog)
|
||||
return 0;
|
||||
|
||||
int16_t hit = dialog->ExecuteModal(DialogManagerImpl::AlertFilter);
|
||||
int16_t hit = dialog->ExecuteModal(nullptr, DialogManagerImpl::AlertFilter);
|
||||
dialog->Destroy();
|
||||
|
||||
return hit;
|
||||
|
||||
680
PortabilityLayer/FileBrowserUI.cpp
Normal file
680
PortabilityLayer/FileBrowserUI.cpp
Normal file
@@ -0,0 +1,680 @@
|
||||
#include "FileBrowserUI.h"
|
||||
|
||||
#include "DialogManager.h"
|
||||
#include "PLButtonWidget.h"
|
||||
#include "FileManager.h"
|
||||
#include "FontFamily.h"
|
||||
#include "GpApplicationName.h"
|
||||
#include "GpBuildVersion.h"
|
||||
#include "GpRenderedFontMetrics.h"
|
||||
#include "HostFileSystem.h"
|
||||
#include "HostDirectoryCursor.h"
|
||||
#include "HostSystemServices.h"
|
||||
#include "IGpFont.h"
|
||||
#include "WindowManager.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "PLStandardColors.h"
|
||||
#include "RenderedFont.h"
|
||||
#include "ResolveCachingColor.h"
|
||||
#include "WindowDef.h"
|
||||
#include "MacRomanConversion.h"
|
||||
|
||||
#include "PLArrayView.h"
|
||||
#include "PLControlDefinitions.h"
|
||||
#include "PLCore.h"
|
||||
#include "PLDialogs.h"
|
||||
#include "PLEditboxWidget.h"
|
||||
#include "PLKeyEncoding.h"
|
||||
#include "PLQDraw.h"
|
||||
#include "PLScrollBarWidget.h"
|
||||
#include "PLSysCalls.h"
|
||||
#include "PLTimeTaggedVOSEvent.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static const int kOkayButton = 1;
|
||||
static const int kCancelButton = 2;
|
||||
static const int kFileList = 3;
|
||||
static const int kFileListScrollBar = 4;
|
||||
static const int kFileNameEditBox = 5;
|
||||
static const int kFileBrowserUIOpenDialogTemplateID = 2001;
|
||||
static const int kFileBrowserUISaveDialogTemplateID = 2002;
|
||||
static const int kFileBrowserUIOverwriteDialogTemplateID = 2003;
|
||||
static const int kFileBrowserUIBadNameDialogTemplateID = 2004;
|
||||
|
||||
static const int kOverwriteNoButton = 1;
|
||||
static const int kOverwriteYesButton = 2;
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
class FileBrowserUIImpl
|
||||
{
|
||||
public:
|
||||
FileBrowserUIImpl();
|
||||
~FileBrowserUIImpl();
|
||||
|
||||
static void PubScrollBarCallback(void *captureContext, Widget *control, int part);
|
||||
static bool PubEditBoxCharFilter(void *context, uint8_t ch);
|
||||
static int16_t PubFileBrowserUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
static int16_t PubPopUpAlertUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
|
||||
bool AppendName(const char *name, size_t nameLength);
|
||||
void SortNames();
|
||||
void DrawFileList();
|
||||
|
||||
void CaptureFileListDrag();
|
||||
void SetScrollOffset(int32_t offset);
|
||||
uint16_t GetScrollCapacity() const;
|
||||
|
||||
void SetUIComponents(Window *window, DrawSurface *surface, const Rect &fileListRect, EditboxWidget *editBox);
|
||||
|
||||
PLPasStr GetSelectedFileName() const;
|
||||
|
||||
static int16_t PopUpAlert(const Rect &rect, int dialogResID, const DialogTextSubstitutions *substitutions);
|
||||
|
||||
private:
|
||||
typedef PascalStr<255> NameStr_t;
|
||||
void ScrollBarCallback(Widget *control, int part);
|
||||
int16_t FileBrowserUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
int16_t PopUpAlertUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
|
||||
static bool NameSortPred(const NameStr_t &a, const NameStr_t &b);
|
||||
|
||||
int m_offset;
|
||||
int m_selectedIndex;
|
||||
int32_t m_scrollOffset;
|
||||
int32_t m_fontSpacing;
|
||||
THandle<NameStr_t> m_names;
|
||||
size_t m_numNames;
|
||||
DrawSurface *m_surface;
|
||||
Window *m_window;
|
||||
EditboxWidget *m_editBox;
|
||||
Rect m_rect;
|
||||
|
||||
Point m_doubleClickPos;
|
||||
uint32_t m_doubleClickTime;
|
||||
bool m_haveFirstClick;
|
||||
};
|
||||
|
||||
FileBrowserUIImpl::FileBrowserUIImpl()
|
||||
: m_offset(0)
|
||||
, m_surface(nullptr)
|
||||
, m_window(nullptr)
|
||||
, m_editBox(nullptr)
|
||||
, m_rect(Rect::Create(0, 0, 0, 0))
|
||||
, m_selectedIndex(-1)
|
||||
, m_scrollOffset(0)
|
||||
, m_fontSpacing(1)
|
||||
, m_numNames(0)
|
||||
, m_doubleClickPos(Point::Create(0, 0))
|
||||
, m_doubleClickTime(0)
|
||||
, m_haveFirstClick(false)
|
||||
{
|
||||
}
|
||||
|
||||
FileBrowserUIImpl::~FileBrowserUIImpl()
|
||||
{
|
||||
m_names.Dispose();
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::PubScrollBarCallback(void *captureContext, Widget *control, int part)
|
||||
{
|
||||
static_cast<FileBrowserUIImpl*>(captureContext)->ScrollBarCallback(control, part);
|
||||
}
|
||||
|
||||
int16_t FileBrowserUIImpl::PubFileBrowserUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
{
|
||||
return static_cast<FileBrowserUIImpl*>(context)->FileBrowserUIFilter(dialog, evt);
|
||||
}
|
||||
|
||||
int16_t FileBrowserUIImpl::PubPopUpAlertUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
{
|
||||
return static_cast<FileBrowserUIImpl*>(context)->PopUpAlertUIFilter(dialog, evt);
|
||||
}
|
||||
|
||||
bool FileBrowserUIImpl::PubEditBoxCharFilter(void *context, uint8_t ch)
|
||||
{
|
||||
uint16_t unicodeChar = MacRoman::ToUnicode(ch);
|
||||
|
||||
return HostFileSystem::GetInstance()->ValidateFilePathUnicodeChar(unicodeChar);
|
||||
}
|
||||
|
||||
bool FileBrowserUIImpl::AppendName(const char *name, size_t nameLen)
|
||||
{
|
||||
MemoryManager *mm = MemoryManager::GetInstance();
|
||||
if (!m_names)
|
||||
{
|
||||
m_names = THandle<NameStr_t>(mm->AllocHandle(0));
|
||||
if (!m_names)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t oldSize = m_names.MMBlock()->m_size;
|
||||
|
||||
if (!mm->ResizeHandle(m_names.MMBlock(), oldSize + sizeof(NameStr_t)))
|
||||
return false;
|
||||
|
||||
(*m_names)[m_numNames++] = NameStr_t(nameLen, name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::SortNames()
|
||||
{
|
||||
if (!m_names)
|
||||
return;
|
||||
|
||||
NameStr_t *names = *m_names;
|
||||
|
||||
std::sort(names, names + m_numNames, NameSortPred);
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::DrawFileList()
|
||||
{
|
||||
if (!m_names.MMBlock())
|
||||
return;
|
||||
|
||||
PortabilityLayer::RenderedFont *font = GetApplicationFont(12, PortabilityLayer::FontFamilyFlags::FontFamilyFlag_Bold, true);
|
||||
|
||||
GpRenderedFontMetrics metrics = font->GetMetrics();
|
||||
int32_t spacing = metrics.m_linegap;
|
||||
int32_t glyphOffset = (metrics.m_linegap + metrics.m_ascent) / 2;
|
||||
|
||||
Rect itemRect = Rect::Create(m_rect.top, m_rect.left, m_rect.top + spacing, m_rect.right);
|
||||
itemRect.top -= m_scrollOffset;
|
||||
itemRect.bottom -= m_scrollOffset;
|
||||
|
||||
ResolveCachingColor blackColor = StdColors::Black();
|
||||
ResolveCachingColor whiteColor = StdColors::White();
|
||||
ResolveCachingColor focusColor = RGBAColor::Create(153, 153, 255, 255);
|
||||
|
||||
m_surface->FillRect(m_rect, whiteColor);
|
||||
|
||||
for (size_t i = 0; i < m_numNames; i++)
|
||||
{
|
||||
if (m_selectedIndex >= 0 && static_cast<size_t>(m_selectedIndex) == i)
|
||||
{
|
||||
Rect focusRect = itemRect.Intersect(m_rect);
|
||||
if (focusRect.IsValid())
|
||||
m_surface->FillRect(focusRect, focusColor);
|
||||
}
|
||||
|
||||
Point itemStringPoint = Point::Create(itemRect.left + 2, itemRect.top + glyphOffset);
|
||||
m_surface->DrawStringConstrained(itemStringPoint, (*m_names)[i].ToShortStr(), m_rect, blackColor, font);
|
||||
|
||||
itemRect.top += spacing;
|
||||
itemRect.bottom += spacing;
|
||||
}
|
||||
|
||||
m_fontSpacing = spacing;
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::CaptureFileListDrag()
|
||||
{
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::SetScrollOffset(int32_t offset)
|
||||
{
|
||||
m_scrollOffset = offset;
|
||||
DrawFileList();
|
||||
}
|
||||
|
||||
uint16_t FileBrowserUIImpl::GetScrollCapacity() const
|
||||
{
|
||||
int32_t boxHeight = m_rect.Height();
|
||||
int32_t overCapacity = (static_cast<int32_t>(m_numNames) * m_fontSpacing - boxHeight);
|
||||
|
||||
if (overCapacity < 0)
|
||||
return 0;
|
||||
else
|
||||
return static_cast<uint16_t>(overCapacity);
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::SetUIComponents(Window *window, DrawSurface *surface, const Rect &rect, EditboxWidget *editbox)
|
||||
{
|
||||
m_surface = surface;
|
||||
m_rect = rect;
|
||||
m_window = window;
|
||||
m_editBox = editbox;
|
||||
}
|
||||
|
||||
PLPasStr FileBrowserUIImpl::GetSelectedFileName() const
|
||||
{
|
||||
if (m_selectedIndex < 0)
|
||||
return PSTR("");
|
||||
else
|
||||
return (*m_names)[m_selectedIndex].ToShortStr();
|
||||
}
|
||||
|
||||
void FileBrowserUIImpl::ScrollBarCallback(Widget *control, int part)
|
||||
{
|
||||
const int pageStepping = 5;
|
||||
|
||||
switch (part)
|
||||
{
|
||||
case kControlUpButtonPart:
|
||||
control->SetState(control->GetState() - m_fontSpacing);
|
||||
break;
|
||||
case kControlDownButtonPart:
|
||||
control->SetState(control->GetState() + m_fontSpacing);
|
||||
break;
|
||||
case kControlPageUpPart:
|
||||
control->SetState(control->GetState() - pageStepping * m_fontSpacing);
|
||||
break;
|
||||
case kControlPageDownPart:
|
||||
control->SetState(control->GetState() + pageStepping * m_fontSpacing);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
SetScrollOffset(control->GetState());
|
||||
}
|
||||
|
||||
int16_t FileBrowserUIImpl::FileBrowserUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
{
|
||||
bool handledIt = false;
|
||||
int16_t hit = -1;
|
||||
|
||||
if (!evt)
|
||||
return -1;
|
||||
|
||||
Window *window = dialog->GetWindow();
|
||||
DrawSurface *surface = window->GetDrawSurface();
|
||||
|
||||
if (evt->IsKeyDownEvent())
|
||||
{
|
||||
switch (PackVOSKeyCode(evt->m_vosEvent.m_event.m_keyboardInputEvent))
|
||||
{
|
||||
case PL_KEY_SPECIAL(kEnter):
|
||||
case PL_KEY_NUMPAD_SPECIAL(kEnter):
|
||||
{
|
||||
Widget *okayButton = dialog->GetItems()[kOkayButton - 1].GetWidget();
|
||||
|
||||
if (okayButton->IsEnabled())
|
||||
{
|
||||
okayButton->SetHighlightStyle(kControlButtonPart, true);
|
||||
PLSysCalls::Sleep(8);
|
||||
okayButton->SetHighlightStyle(kControlButtonPart, false);
|
||||
|
||||
hit = kOkayButton;
|
||||
handledIt = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PL_KEY_SPECIAL(kEscape):
|
||||
{
|
||||
Widget *cancelButton = dialog->GetItems()[kCancelButton - 1].GetWidget();
|
||||
|
||||
cancelButton->SetHighlightStyle(kControlButtonPart, true);
|
||||
PLSysCalls::Sleep(8);
|
||||
cancelButton->SetHighlightStyle(kControlButtonPart, false);
|
||||
|
||||
hit = kCancelButton;
|
||||
handledIt = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
handledIt = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (evt->IsLMouseDownEvent())
|
||||
{
|
||||
Point mousePt = m_window->MouseToLocal(evt->m_vosEvent.m_event.m_mouseInputEvent);
|
||||
bool haveDoubleClick = false;
|
||||
|
||||
if (m_rect.Contains(mousePt))
|
||||
{
|
||||
if (m_haveFirstClick)
|
||||
{
|
||||
const uint32_t doubleTime = 30; // PL_NotYetImplemented_TODO: Get this from the system settings
|
||||
|
||||
if (mousePt == m_doubleClickPos && evt->m_timestamp - m_doubleClickTime < doubleTime)
|
||||
haveDoubleClick = true;
|
||||
}
|
||||
|
||||
if (!haveDoubleClick)
|
||||
{
|
||||
m_haveFirstClick = true;
|
||||
m_doubleClickPos = mousePt;
|
||||
m_doubleClickTime = evt->m_timestamp;
|
||||
|
||||
const TimeTaggedVOSEvent *rcvEvt = evt;
|
||||
|
||||
TimeTaggedVOSEvent evtHolder;
|
||||
for (;;)
|
||||
{
|
||||
if (rcvEvt)
|
||||
{
|
||||
if (rcvEvt->m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
|
||||
{
|
||||
mousePt = m_window->MouseToLocal(rcvEvt->m_vosEvent.m_event.m_mouseInputEvent);
|
||||
if (mousePt != m_doubleClickPos)
|
||||
m_haveFirstClick = false;
|
||||
|
||||
if (m_rect.Contains(mousePt))
|
||||
{
|
||||
int32_t selection = (mousePt.v - m_rect.top + m_scrollOffset) / m_fontSpacing;
|
||||
|
||||
if (selection < 0 || static_cast<size_t>(selection) >= m_numNames)
|
||||
selection = -1;
|
||||
|
||||
if (selection >= 0)
|
||||
{
|
||||
if (selection != m_selectedIndex)
|
||||
{
|
||||
m_selectedIndex = selection;
|
||||
|
||||
dialog->GetItems()[kOkayButton - 1].GetWidget()->SetEnabled(selection >= 0);
|
||||
|
||||
DrawFileList();
|
||||
}
|
||||
|
||||
if (m_editBox)
|
||||
{
|
||||
PLPasStr nameStr = (*m_names)[m_selectedIndex].ToShortStr();
|
||||
m_editBox->SetString(nameStr);
|
||||
m_editBox->SetSelection(0, nameStr.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rcvEvt->IsLMouseUpEvent())
|
||||
break;
|
||||
}
|
||||
|
||||
if (WaitForEvent(&evtHolder, 1))
|
||||
rcvEvt = &evtHolder;
|
||||
else
|
||||
rcvEvt = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (haveDoubleClick && m_selectedIndex >= 0)
|
||||
{
|
||||
handledIt = true;
|
||||
hit = kOkayButton;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handledIt)
|
||||
return -1;
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
int16_t FileBrowserUIImpl::PopUpAlertUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt)
|
||||
{
|
||||
bool handledIt = false;
|
||||
int16_t hit = -1;
|
||||
|
||||
if (!evt)
|
||||
return -1;
|
||||
|
||||
Window *window = dialog->GetWindow();
|
||||
DrawSurface *surface = window->GetDrawSurface();
|
||||
|
||||
if (evt->IsKeyDownEvent())
|
||||
{
|
||||
switch (PackVOSKeyCode(evt->m_vosEvent.m_event.m_keyboardInputEvent))
|
||||
{
|
||||
case PL_KEY_SPECIAL(kEnter):
|
||||
case PL_KEY_NUMPAD_SPECIAL(kEnter):
|
||||
{
|
||||
Widget *okayButton = dialog->GetItems()[kOkayButton - 1].GetWidget();
|
||||
|
||||
if (okayButton->IsEnabled())
|
||||
{
|
||||
okayButton->SetHighlightStyle(kControlButtonPart, true);
|
||||
PLSysCalls::Sleep(8);
|
||||
okayButton->SetHighlightStyle(kControlButtonPart, false);
|
||||
|
||||
hit = kOkayButton;
|
||||
handledIt = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
handledIt = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handledIt)
|
||||
return -1;
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool FileBrowserUIImpl::NameSortPred(const NameStr_t &a, const NameStr_t &b)
|
||||
{
|
||||
const size_t lenA = a.Length();
|
||||
const size_t lenB = b.Length();
|
||||
|
||||
const size_t shorterLength = std::min(lenA, lenB);
|
||||
|
||||
int comparison = memcmp(a.UnsafeCharPtr(), b.UnsafeCharPtr(), shorterLength);
|
||||
if (comparison > 0)
|
||||
return false;
|
||||
|
||||
if (comparison < 0)
|
||||
return true;
|
||||
|
||||
return lenA < lenB;
|
||||
}
|
||||
|
||||
int16_t FileBrowserUIImpl::PopUpAlert(const Rect &rect, int dialogResID, const DialogTextSubstitutions *substitutions)
|
||||
{
|
||||
PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance();
|
||||
Dialog *dialog = dialogManager->LoadDialogFromTemplate(dialogResID, rect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), substitutions);
|
||||
|
||||
const PortabilityLayer::DialogItem &firstItem = *dialog->GetItems().begin();
|
||||
Rect itemRect = firstItem.GetWidget()->GetRect();
|
||||
|
||||
PortabilityLayer::ButtonWidget::DrawDefaultButtonChrome(itemRect, dialog->GetWindow()->GetDrawSurface());
|
||||
|
||||
int16_t hit = 0;
|
||||
do
|
||||
{
|
||||
hit = dialog->ExecuteModal(nullptr, PubPopUpAlertUIFilter);
|
||||
} while (hit != kOkayButton && hit != kCancelButton);
|
||||
|
||||
dialog->Destroy();
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool FileBrowserUI::Prompt(Mode mode, VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText)
|
||||
{
|
||||
int dialogID = 0;
|
||||
if (mode == Mode_Open)
|
||||
dialogID = kFileBrowserUIOpenDialogTemplateID;
|
||||
else if (mode == Mode_Save)
|
||||
dialogID = kFileBrowserUISaveDialogTemplateID;
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
FileBrowserUIImpl uiImpl;
|
||||
|
||||
// Enumerate files
|
||||
PortabilityLayer::HostFileSystem *fs = PortabilityLayer::HostFileSystem::GetInstance();
|
||||
PortabilityLayer::HostDirectoryCursor *dirCursor = fs->ScanDirectory(dirID);
|
||||
|
||||
if (!dirCursor)
|
||||
return false;
|
||||
|
||||
const char *fileName;
|
||||
while (dirCursor->GetNext(fileName))
|
||||
{
|
||||
size_t nameLength = strlen(fileName);
|
||||
|
||||
if (nameLength < 4)
|
||||
continue;
|
||||
|
||||
const char *nameExt = fileName + (nameLength - 4);
|
||||
|
||||
if (!memcmp(nameExt, ".gpf", 4))
|
||||
{
|
||||
if (!uiImpl.AppendName(fileName, nameLength - 4))
|
||||
{
|
||||
dirCursor->Destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uiImpl.SortNames();
|
||||
|
||||
dirCursor->Destroy();
|
||||
|
||||
const int scrollBarWidth = 16;
|
||||
const Rect windowRect = Rect::Create(0, 0, 272, 450);
|
||||
|
||||
PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(windowRect, PortabilityLayer::WindowStyleFlags::kAlert, true, 0, 0, PSTR(""));
|
||||
|
||||
PortabilityLayer::ResolveCachingColor blackColor = StdColors::Black();
|
||||
PortabilityLayer::RenderedFont *font = GetApplicationFont(12, PortabilityLayer::FontFamilyFlag_Bold, true);
|
||||
PortabilityLayer::RenderedFont *fontLight = GetApplicationFont(8, PortabilityLayer::FontFamilyFlag_None, true);
|
||||
|
||||
int16_t verticalPoint = 16 + font->GetMetrics().m_ascent;
|
||||
int16_t horizontalOffset = 16;
|
||||
const int16_t spacing = 12;
|
||||
|
||||
PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance();
|
||||
|
||||
DialogTextSubstitutions substitutions(promptText);
|
||||
Dialog *dialog = dialogManager->LoadDialogFromTemplate(dialogID, windowRect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), &substitutions);
|
||||
|
||||
Window *window = dialog->GetWindow();
|
||||
|
||||
DrawSurface *surface = window->GetDrawSurface();
|
||||
|
||||
const PortabilityLayer::DialogItem &firstItem = *dialog->GetItems().begin();
|
||||
Rect itemRect = firstItem.GetWidget()->GetRect();
|
||||
|
||||
PortabilityLayer::ButtonWidget::DrawDefaultButtonChrome(itemRect, surface);
|
||||
|
||||
// Get item rects
|
||||
const Rect fileListRect = dialog->GetItems()[kFileList - 1].GetWidget()->GetRect();
|
||||
const Rect scrollBarRect = dialog->GetItems()[kFileListScrollBar - 1].GetWidget()->GetRect();
|
||||
|
||||
EditboxWidget *editbox = nullptr;
|
||||
if (mode == Mode_Save)
|
||||
{
|
||||
editbox = static_cast<EditboxWidget*>(dialog->GetItems()[kFileNameEditBox - 1].GetWidget());
|
||||
editbox->SetCharacterFilter(&uiImpl, FileBrowserUIImpl::PubEditBoxCharFilter);
|
||||
editbox->SetCapacity(31);
|
||||
editbox->SetString(initialFileName);
|
||||
|
||||
dialog->GetWindow()->FocusWidget(editbox);
|
||||
}
|
||||
|
||||
// Draw file list frame
|
||||
surface->FrameRect(fileListRect.Inset(-1, -1), blackColor);
|
||||
|
||||
// Draw initial stuff
|
||||
uiImpl.SetUIComponents(dialog->GetWindow(), surface, fileListRect, editbox);
|
||||
uiImpl.DrawFileList();
|
||||
|
||||
PortabilityLayer::ScrollBarWidget *scrollBar = nullptr;
|
||||
|
||||
{
|
||||
PortabilityLayer::WidgetBasicState state;
|
||||
state.m_rect = scrollBarRect;
|
||||
state.m_refConstant = 0;
|
||||
state.m_window = nullptr;
|
||||
state.m_max = uiImpl.GetScrollCapacity();
|
||||
state.m_state = 0;
|
||||
state.m_defaultCallback = FileBrowserUIImpl::PubScrollBarCallback;
|
||||
scrollBar = PortabilityLayer::ScrollBarWidget::Create(state, nullptr);
|
||||
}
|
||||
|
||||
dialog->ReplaceWidget(kFileListScrollBar - 1, scrollBar);
|
||||
|
||||
window->DrawControls();
|
||||
|
||||
int16_t hit = 0;
|
||||
|
||||
Window *exclWindow = dialog->GetWindow();
|
||||
|
||||
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
|
||||
|
||||
do
|
||||
{
|
||||
hit = dialog->ExecuteModal(&uiImpl, FileBrowserUIImpl::PubFileBrowserUIFilter);
|
||||
|
||||
if (hit == kFileListScrollBar)
|
||||
uiImpl.SetScrollOffset(scrollBar->GetState());
|
||||
|
||||
if (hit == kOkayButton && mode == Mode_Save)
|
||||
{
|
||||
HostFileSystem *fs = HostFileSystem::GetInstance();
|
||||
|
||||
EditboxWidget *editBox = static_cast<EditboxWidget*>(dialog->GetItems()[kFileNameEditBox - 1].GetWidget());
|
||||
|
||||
PLPasStr nameStr = editBox->GetString();
|
||||
if (nameStr.Length() == 0 || !fs->ValidateFilePath(nameStr.Chars(), nameStr.Length()))
|
||||
{
|
||||
PortabilityLayer::HostSystemServices::GetInstance()->Beep();
|
||||
FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIBadNameDialogTemplateID, nullptr);
|
||||
hit = -1;
|
||||
}
|
||||
else if (PortabilityLayer::FileManager::GetInstance()->FileExists(dirID, nameStr))
|
||||
{
|
||||
DialogTextSubstitutions substitutions(nameStr);
|
||||
|
||||
PortabilityLayer::HostSystemServices::GetInstance()->Beep();
|
||||
int16_t subHit = FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIOverwriteDialogTemplateID, &substitutions);
|
||||
|
||||
if (subHit == kOverwriteNoButton)
|
||||
hit = -1;
|
||||
}
|
||||
}
|
||||
} while (hit != kOkayButton && hit != kCancelButton);
|
||||
|
||||
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
|
||||
|
||||
bool confirmed = false;
|
||||
PLPasStr uiFileName;
|
||||
|
||||
if (hit == kOkayButton)
|
||||
{
|
||||
if (mode == Mode_Open)
|
||||
{
|
||||
uiFileName = uiImpl.GetSelectedFileName();
|
||||
confirmed = true;
|
||||
}
|
||||
else if (mode == Mode_Save)
|
||||
{
|
||||
uiFileName = editbox->GetString();
|
||||
confirmed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (confirmed)
|
||||
{
|
||||
if (uiFileName.Length() > pathCapacity)
|
||||
confirmed = false;
|
||||
}
|
||||
|
||||
if (confirmed)
|
||||
{
|
||||
memcpy(path, uiFileName.Chars(), uiFileName.Length());
|
||||
outPathLength = uiFileName.Length();
|
||||
}
|
||||
|
||||
dialog->Destroy();
|
||||
|
||||
return confirmed;
|
||||
}
|
||||
}
|
||||
20
PortabilityLayer/FileBrowserUI.h
Normal file
20
PortabilityLayer/FileBrowserUI.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "VirtualDirectory.h"
|
||||
|
||||
class PLPasStr;
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
class FileBrowserUI
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
Mode_Save,
|
||||
Mode_Open,
|
||||
};
|
||||
|
||||
static bool Prompt(Mode mode, VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText);
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "FileManager.h"
|
||||
|
||||
#include "FileBrowserUI.h"
|
||||
#include "HostFileSystem.h"
|
||||
#include "HostMemoryBuffer.h"
|
||||
#include "MemReaderStream.h"
|
||||
@@ -33,8 +35,8 @@ namespace PortabilityLayer
|
||||
PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override;
|
||||
PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override;
|
||||
|
||||
bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName) override;
|
||||
bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) override;
|
||||
bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) override;
|
||||
bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) override;
|
||||
|
||||
static FileManagerImpl *GetInstance();
|
||||
|
||||
@@ -174,18 +176,18 @@ namespace PortabilityLayer
|
||||
return RawOpenFileFork(dirID, filename, ".gpa", permission, ignoreMeta, createDisposition, outStream);
|
||||
}
|
||||
|
||||
bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName)
|
||||
bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText)
|
||||
{
|
||||
ExtendedFileName_t extFN;
|
||||
if (!ConstructFilename(extFN, initialFileName, ""))
|
||||
return false;
|
||||
|
||||
return PortabilityLayer::HostFileSystem::GetInstance()->PromptSaveFile(dirID, path, outPathLength, pathCapacity, extFN);
|
||||
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Save, dirID, path, outPathLength, pathCapacity, initialFileName, promptText);
|
||||
}
|
||||
|
||||
bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity)
|
||||
bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText)
|
||||
{
|
||||
return PLSysCalls::PromptOpenFile(dirID, path, outPathLength, pathCapacity);
|
||||
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Open, dirID, path, outPathLength, pathCapacity, PSTR(""), promptText);
|
||||
}
|
||||
|
||||
FileManagerImpl *FileManagerImpl::GetInstance()
|
||||
|
||||
@@ -35,8 +35,8 @@ namespace PortabilityLayer
|
||||
virtual PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0;
|
||||
virtual PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0;
|
||||
|
||||
virtual bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName) = 0;
|
||||
virtual bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) = 0;
|
||||
virtual bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) = 0;
|
||||
virtual bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) = 0;
|
||||
|
||||
static FileManager *GetInstance();
|
||||
};
|
||||
|
||||
@@ -20,9 +20,8 @@ namespace PortabilityLayer
|
||||
virtual bool DeleteFile(VirtualDirectory_t virtualDirectory, const char *path, bool &existed) = 0;
|
||||
virtual HostDirectoryCursor *ScanDirectory(VirtualDirectory_t virtualDirectory) = 0;
|
||||
|
||||
virtual bool PromptSaveFile(VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) = 0;
|
||||
virtual bool PromptOpenFile(VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity) = 0;
|
||||
virtual bool ValidateFilePath(const char *path, size_t pathLen) const = 0;
|
||||
virtual bool ValidateFilePathUnicodeChar(uint32_t ch) const = 0;
|
||||
|
||||
static HostFileSystem *GetInstance();
|
||||
static void SetInstance(HostFileSystem *instance);
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace PortabilityLayer
|
||||
{
|
||||
}
|
||||
|
||||
WidgetHandleState_t ButtonWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t ButtonWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (!m_visible || !m_enabled)
|
||||
return WidgetHandleStates::kIgnored;
|
||||
@@ -240,7 +240,7 @@ namespace PortabilityLayer
|
||||
|
||||
if (m_rect.Contains(pt))
|
||||
{
|
||||
if (Capture(pt, nullptr) == RegionIDs::kNone)
|
||||
if (Capture(captureContext, pt, nullptr) == RegionIDs::kNone)
|
||||
return WidgetHandleStates::kDigested;
|
||||
else
|
||||
return WidgetHandleStates::kActivated;
|
||||
@@ -264,7 +264,7 @@ namespace PortabilityLayer
|
||||
DrawControl(m_window->GetDrawSurface());
|
||||
}
|
||||
|
||||
int16_t ButtonWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback)
|
||||
int16_t ButtonWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
if (!m_enabled || !m_visible)
|
||||
return 0;
|
||||
|
||||
@@ -30,10 +30,10 @@ namespace PortabilityLayer
|
||||
void SetString(const PLPasStr &str) override;
|
||||
PLPasStr GetString() const override;
|
||||
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override;
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
|
||||
void OnEnabledChanged() override;
|
||||
void OnStateChanged() override;
|
||||
int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback) override;
|
||||
int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) override;
|
||||
void SetHighlightStyle(int16_t style, bool enabled) override;
|
||||
|
||||
static void DrawDefaultButtonChrome(const Rect &rect, DrawSurface *surface);
|
||||
|
||||
@@ -14,7 +14,7 @@ class PLPasStr;
|
||||
struct Control;
|
||||
struct Dialog;
|
||||
|
||||
typedef int16_t(*DialogFilterFunc_t)(Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
typedef int16_t(*DialogFilterFunc_t)(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
|
||||
|
||||
struct DialogTextSubstitutions
|
||||
{
|
||||
@@ -39,7 +39,7 @@ struct Dialog
|
||||
|
||||
virtual void SetItemVisibility(unsigned int itemIndex, bool isVisible) = 0;
|
||||
|
||||
virtual int16_t ExecuteModal(DialogFilterFunc_t filterFunc) = 0;
|
||||
virtual int16_t ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc) = 0;
|
||||
|
||||
virtual bool ReplaceWidget(unsigned int itemIndex, PortabilityLayer::Widget *widget) = 0;
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace PortabilityLayer
|
||||
, m_isDraggingSelection(false)
|
||||
, m_dragSelectionStartChar(false)
|
||||
, m_scrollOffset(0, 0)
|
||||
, m_characterFilter(nullptr)
|
||||
, m_characterFilterContext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -121,17 +123,17 @@ namespace PortabilityLayer
|
||||
m_length = len;
|
||||
memcpy(m_chars, str.UChars(), len);
|
||||
|
||||
if (m_selStartChar > len)
|
||||
m_selStartChar = len;
|
||||
if (m_selEndChar > len)
|
||||
m_selEndChar = len;
|
||||
|
||||
if (m_window)
|
||||
{
|
||||
DrawSurface *surface = m_window->GetDrawSurface();
|
||||
|
||||
DrawControl(surface);
|
||||
}
|
||||
|
||||
if (m_selStartChar > len)
|
||||
m_selStartChar = len;
|
||||
if (m_selEndChar > len)
|
||||
m_selEndChar = len;
|
||||
}
|
||||
|
||||
PLPasStr EditboxWidget::GetString() const
|
||||
@@ -166,7 +168,7 @@ namespace PortabilityLayer
|
||||
Redraw();
|
||||
}
|
||||
|
||||
WidgetHandleState_t EditboxWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t EditboxWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (m_isDraggingSelection)
|
||||
return HandleDragSelection(evt);
|
||||
@@ -200,6 +202,12 @@ namespace PortabilityLayer
|
||||
resolvedChar = MacRoman::FromUnicode(ch, keyEvent.m_key.m_unicodeChar);
|
||||
}
|
||||
|
||||
if (resolvedChar)
|
||||
{
|
||||
if (m_characterFilter)
|
||||
resolvedChar = m_characterFilter(m_characterFilterContext, ch);
|
||||
}
|
||||
|
||||
if (resolvedChar)
|
||||
{
|
||||
if (ch >= 0x20 && ch <= 0x7e)
|
||||
@@ -979,4 +987,15 @@ namespace PortabilityLayer
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void EditboxWidget::SetCharacterFilter(void *context, CharacterFilterCallback_t callback)
|
||||
{
|
||||
m_characterFilterContext = context;
|
||||
m_characterFilter = callback;
|
||||
}
|
||||
|
||||
void EditboxWidget::SetCapacity(size_t capacity)
|
||||
{
|
||||
m_capacity = std::min<size_t>(255, capacity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace PortabilityLayer
|
||||
class EditboxWidget final : public WidgetSpec<EditboxWidget>
|
||||
{
|
||||
public:
|
||||
typedef bool (*CharacterFilterCallback_t)(void *context, uint8_t character);
|
||||
|
||||
EditboxWidget(const WidgetBasicState &state);
|
||||
~EditboxWidget();
|
||||
|
||||
@@ -23,7 +25,7 @@ namespace PortabilityLayer
|
||||
void GainFocus() override;
|
||||
void LoseFocus() override;
|
||||
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override;
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
|
||||
|
||||
Rect GetExpandedRect() const override;
|
||||
|
||||
@@ -33,6 +35,9 @@ namespace PortabilityLayer
|
||||
|
||||
void SetMultiLine(bool isMultiLine);
|
||||
|
||||
void SetCharacterFilter(void *context, CharacterFilterCallback_t callback);
|
||||
void SetCapacity(size_t capacity);
|
||||
|
||||
private:
|
||||
static const unsigned int kCaratBlinkRate = 20;
|
||||
static const unsigned int kMouseScrollRate = 20;
|
||||
@@ -92,5 +97,8 @@ namespace PortabilityLayer
|
||||
size_t m_dragSelectionStartChar;
|
||||
|
||||
uint16_t m_caratTimer;
|
||||
|
||||
CharacterFilterCallback_t m_characterFilter;
|
||||
void *m_characterFilterContext;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace PortabilityLayer
|
||||
surface->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);
|
||||
}
|
||||
|
||||
WidgetHandleState_t IconWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t IconWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (!m_visible || !m_enabled)
|
||||
return WidgetHandleStates::kIgnored;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace PortabilityLayer
|
||||
|
||||
void DrawControl(DrawSurface *surface) override;
|
||||
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override;
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
|
||||
|
||||
private:
|
||||
THandle<PixMapImpl> m_iconImage;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace PortabilityLayer
|
||||
return true;
|
||||
}
|
||||
|
||||
WidgetHandleState_t InvisibleWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t InvisibleWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (!m_visible || !m_enabled)
|
||||
return WidgetHandleStates::kIgnored;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace PortabilityLayer
|
||||
|
||||
bool Init(const WidgetBasicState &state, const void *additionalData) override;
|
||||
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override;
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
|
||||
|
||||
private:
|
||||
bool m_clickable;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace PortabilityLayer
|
||||
return true;
|
||||
}
|
||||
|
||||
WidgetHandleState_t PopupMenuWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t PopupMenuWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (evt.IsLMouseDownEvent())
|
||||
{
|
||||
@@ -49,7 +49,7 @@ namespace PortabilityLayer
|
||||
|
||||
if (this->m_rect.Contains(Point::Create(localPoint.m_x, localPoint.m_y)))
|
||||
{
|
||||
int16_t part = Capture(Point::Create(localPoint.m_x, localPoint.m_y), nullptr);
|
||||
int16_t part = Capture(captureContext, Point::Create(localPoint.m_x, localPoint.m_y), nullptr);
|
||||
if (part >= 1)
|
||||
return WidgetHandleStates::kActivated;
|
||||
else
|
||||
@@ -60,7 +60,7 @@ namespace PortabilityLayer
|
||||
return WidgetHandleStates::kIgnored;
|
||||
}
|
||||
|
||||
int16_t PopupMenuWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback)
|
||||
int16_t PopupMenuWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
MenuManager *mm = PortabilityLayer::MenuManager::GetInstance();
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace PortabilityLayer
|
||||
|
||||
bool Init(const WidgetBasicState &state, const void *additionalData) override;
|
||||
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt);
|
||||
int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback);
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt);
|
||||
int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
|
||||
void DrawControl(DrawSurface *surface) override;
|
||||
|
||||
void OnStateChanged() override;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "PLTimeTaggedVOSEvent.h"
|
||||
#include "ResolveCachingColor.h"
|
||||
|
||||
#include "PLRegions.h"
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
ScrollBarWidget::ScrollBarWidget(const WidgetBasicState &state)
|
||||
@@ -15,14 +17,30 @@ namespace PortabilityLayer
|
||||
, m_laneCapacity(0)
|
||||
, m_isActive(false)
|
||||
, m_activePart(0)
|
||||
, m_callback(state.m_defaultCallback)
|
||||
{
|
||||
}
|
||||
|
||||
WidgetHandleState_t ScrollBarWidget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t ScrollBarWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
if (!m_visible || !m_enabled)
|
||||
return WidgetHandleStates::kIgnored;
|
||||
|
||||
if (evt.IsLMouseDownEvent())
|
||||
{
|
||||
const Point pt = m_window->MouseToLocal(evt.m_vosEvent.m_event.m_mouseInputEvent);
|
||||
|
||||
if (m_rect.Contains(pt))
|
||||
{
|
||||
if (Capture(captureContext, pt, m_callback) == RegionIDs::kNone)
|
||||
return WidgetHandleStates::kDigested;
|
||||
else
|
||||
return WidgetHandleStates::kActivated;
|
||||
}
|
||||
else
|
||||
return WidgetHandleStates::kIgnored;
|
||||
}
|
||||
|
||||
return WidgetHandleStates::kIgnored;
|
||||
}
|
||||
|
||||
@@ -279,19 +297,19 @@ namespace PortabilityLayer
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ScrollBarWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback)
|
||||
int16_t ScrollBarWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
int part = ResolvePart(pos);
|
||||
if (!part)
|
||||
return 0;
|
||||
|
||||
if (part == kControlIndicatorPart)
|
||||
return CaptureIndicator(pos, callback);
|
||||
return CaptureIndicator(captureContext, pos, callback);
|
||||
else
|
||||
return CaptureScrollSegment(pos, part, callback);
|
||||
return CaptureScrollSegment(captureContext, pos, part, callback);
|
||||
}
|
||||
|
||||
int16_t ScrollBarWidget::CaptureScrollSegment(const Point &pos, int part, WidgetUpdateCallback_t callback)
|
||||
int16_t ScrollBarWidget::CaptureScrollSegment(void *captureContext, const Point &pos, int part, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
int tickDelay = 15;
|
||||
|
||||
@@ -308,7 +326,7 @@ namespace PortabilityLayer
|
||||
if (ticksUntilIterate == 0)
|
||||
{
|
||||
if (m_isActive)
|
||||
IterateScrollSegment(part, callback);
|
||||
IterateScrollSegment(captureContext, part, callback);
|
||||
|
||||
ticksUntilIterate = tickDelay;
|
||||
}
|
||||
@@ -349,7 +367,7 @@ namespace PortabilityLayer
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ScrollBarWidget::CaptureIndicator(const Point &pos, WidgetUpdateCallback_t callback)
|
||||
int16_t ScrollBarWidget::CaptureIndicator(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
const bool isHorizontal = IsHorizontal();
|
||||
|
||||
@@ -428,10 +446,10 @@ namespace PortabilityLayer
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBarWidget::IterateScrollSegment(int part, WidgetUpdateCallback_t callback)
|
||||
void ScrollBarWidget::IterateScrollSegment(void *captureContext, int part, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
if (callback != nullptr)
|
||||
callback(this, part);
|
||||
callback(captureContext, this, part);
|
||||
}
|
||||
|
||||
int ScrollBarWidget::ResolvePart(const Point &point) const
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace PortabilityLayer
|
||||
bool Init(const WidgetBasicState &state, const void *additionalData) override;
|
||||
|
||||
void OnEnabledChanged() override;
|
||||
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override;
|
||||
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
|
||||
void DrawControl(DrawSurface *surface) override;
|
||||
|
||||
void SetState(int16_t state) override;
|
||||
@@ -24,7 +24,7 @@ namespace PortabilityLayer
|
||||
void SetMin(int32_t v) override;
|
||||
void SetMax(int32_t v) override;
|
||||
|
||||
int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback) override;
|
||||
int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) override;
|
||||
|
||||
int ResolvePart(const Point &point) const override;
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace PortabilityLayer
|
||||
|
||||
static void DrawBeveledBox(DrawSurface *surface, const Rect &rect);
|
||||
|
||||
int16_t CaptureScrollSegment(const Point &pos, int part, WidgetUpdateCallback_t callback);
|
||||
int16_t CaptureIndicator(const Point &pos, WidgetUpdateCallback_t callback);
|
||||
void IterateScrollSegment(int part, WidgetUpdateCallback_t callback);
|
||||
int16_t CaptureScrollSegment(void *captureContext, const Point &pos, int part, WidgetUpdateCallback_t callback);
|
||||
int16_t CaptureIndicator(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
|
||||
void IterateScrollSegment(void *captureContext, int part, WidgetUpdateCallback_t callback);
|
||||
|
||||
int32_t m_min;
|
||||
int32_t m_max;
|
||||
@@ -51,5 +51,7 @@ namespace PortabilityLayer
|
||||
|
||||
bool m_isActive;
|
||||
int m_activePart;
|
||||
|
||||
WidgetUpdateCallback_t m_callback;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -175,63 +175,4 @@ namespace PLSysCalls
|
||||
AnimationManager::GetInstance()->TickPlayers(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
static void PromptOpenFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue)
|
||||
{
|
||||
bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptOpenFile(static_cast<PortabilityLayer::VirtualDirectory_t>(args[0].m_int), static_cast<char*>(args[1].m_pointer), *static_cast<size_t*>(args[2].m_pointer), args[3].m_uint);
|
||||
returnValue->m_uint = (result ? 1 : 0);
|
||||
}
|
||||
|
||||
bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity)
|
||||
{
|
||||
PortabilityLayer::HostSuspendCallArgument cbArgs[4];
|
||||
cbArgs[0].m_int = static_cast<int32_t>(dirID);
|
||||
cbArgs[1].m_pointer = path;
|
||||
cbArgs[2].m_pointer = &outPathLength;
|
||||
cbArgs[3].m_size = pathCapacity;
|
||||
|
||||
PortabilityLayer::HostSuspendCallArgument cbReturnValue;
|
||||
|
||||
PortabilityLayer::HostSuspendCallArgument dispatchArgs[3];
|
||||
dispatchArgs[0].m_functionPtr = PromptOpenFileCallback;
|
||||
dispatchArgs[1].m_constPointer = cbArgs;
|
||||
dispatchArgs[2].m_pointer = &cbReturnValue;
|
||||
|
||||
PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr);
|
||||
|
||||
return cbReturnValue.m_uint != 0;
|
||||
}
|
||||
|
||||
static void PromptSaveFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue)
|
||||
{
|
||||
bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptSaveFile(
|
||||
static_cast<PortabilityLayer::VirtualDirectory_t>(args[0].m_int),
|
||||
static_cast<char*>(args[1].m_pointer),
|
||||
*static_cast<size_t*>(args[2].m_pointer),
|
||||
args[3].m_uint,
|
||||
static_cast<const char*>(args[4].m_constPointer));
|
||||
|
||||
returnValue->m_uint = (result ? 1 : 0);
|
||||
}
|
||||
|
||||
bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName)
|
||||
{
|
||||
PortabilityLayer::HostSuspendCallArgument cbArgs[5];
|
||||
cbArgs[0].m_int = static_cast<int32_t>(virtualDirectory);
|
||||
cbArgs[1].m_pointer = path;
|
||||
cbArgs[2].m_pointer = &outPathLength;
|
||||
cbArgs[3].m_size = pathCapacity;
|
||||
cbArgs[3].m_constPointer = initialFileName;
|
||||
|
||||
PortabilityLayer::HostSuspendCallArgument cbReturnValue;
|
||||
|
||||
PortabilityLayer::HostSuspendCallArgument dispatchArgs[3];
|
||||
dispatchArgs[0].m_functionPtr = PromptSaveFileCallback;
|
||||
dispatchArgs[1].m_constPointer = cbArgs;
|
||||
dispatchArgs[2].m_pointer = &cbReturnValue;
|
||||
|
||||
PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr);
|
||||
|
||||
return cbReturnValue.m_uint != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,4 @@
|
||||
namespace PLSysCalls
|
||||
{
|
||||
void Sleep(uint32_t ticks);
|
||||
bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity);
|
||||
bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName);
|
||||
}
|
||||
|
||||
@@ -13,17 +13,18 @@ namespace PortabilityLayer
|
||||
, m_max(0)
|
||||
, m_state(0)
|
||||
, m_enabled(true)
|
||||
, m_defaultCallback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
WidgetHandleState_t Widget::ProcessEvent(const TimeTaggedVOSEvent &evt)
|
||||
WidgetHandleState_t Widget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
|
||||
{
|
||||
(void)evt;
|
||||
|
||||
return WidgetHandleStates::kIgnored;
|
||||
}
|
||||
|
||||
int16_t Widget::Capture(const Point &pos, WidgetUpdateCallback_t callback)
|
||||
int16_t Widget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -64,6 +65,11 @@ namespace PortabilityLayer
|
||||
OnEnabledChanged();
|
||||
}
|
||||
|
||||
bool Widget::IsEnabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void Widget::SetState(int16_t state)
|
||||
{
|
||||
m_state = state;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace PortabilityLayer
|
||||
|
||||
typedef WidgetHandleStates::WidgetHandleState WidgetHandleState_t;
|
||||
|
||||
typedef void (*WidgetUpdateCallback_t)(Widget *control, int part);
|
||||
typedef void (*WidgetUpdateCallback_t)(void *captureContext, Widget *control, int part);
|
||||
|
||||
struct WidgetBasicState
|
||||
{
|
||||
@@ -40,6 +40,8 @@ namespace PortabilityLayer
|
||||
int16_t m_state;
|
||||
int16_t m_resID;
|
||||
bool m_enabled;
|
||||
|
||||
WidgetUpdateCallback_t m_defaultCallback;
|
||||
};
|
||||
|
||||
class Widget
|
||||
@@ -47,8 +49,8 @@ namespace PortabilityLayer
|
||||
public:
|
||||
virtual bool Init(const WidgetBasicState &state, const void *additionalData) = 0;
|
||||
virtual void Destroy() = 0;
|
||||
virtual WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt);
|
||||
virtual int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback);
|
||||
virtual WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt);
|
||||
virtual int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
|
||||
virtual void DrawControl(DrawSurface *surface);
|
||||
|
||||
virtual void SetMin(int32_t v);
|
||||
@@ -58,6 +60,7 @@ namespace PortabilityLayer
|
||||
void Resize(uint16_t width, uint16_t height);
|
||||
|
||||
void SetEnabled(bool enabled);
|
||||
bool IsEnabled() const;
|
||||
virtual void SetState(int16_t state);
|
||||
int16_t GetState() const;
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
<ClInclude Include="DialogManager.h" />
|
||||
<ClInclude Include="DisplayDeviceManager.h" />
|
||||
<ClInclude Include="EllipsePlotter.h" />
|
||||
<ClInclude Include="FileBrowserUI.h" />
|
||||
<ClInclude Include="FileManager.h" />
|
||||
<ClInclude Include="FilePermission.h" />
|
||||
<ClInclude Include="FilePos.h" />
|
||||
@@ -303,6 +304,7 @@
|
||||
<ClCompile Include="DialogManager.cpp" />
|
||||
<ClCompile Include="DisplayDeviceManager.cpp" />
|
||||
<ClCompile Include="EllipsePlotter.cpp" />
|
||||
<ClCompile Include="FileBrowserUI.cpp" />
|
||||
<ClCompile Include="FileManager.cpp" />
|
||||
<ClCompile Include="FontFamily.cpp" />
|
||||
<ClCompile Include="FontManager.cpp" />
|
||||
|
||||
@@ -459,6 +459,9 @@
|
||||
<ClInclude Include="HostLogDriver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileBrowserUI.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CFileStream.cpp">
|
||||
@@ -731,5 +734,8 @@
|
||||
<ClCompile Include="HostInputDriver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileBrowserUI.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user