mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-24 07:06:36 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e7246c1444 | ||
|
35b8e922d7 | ||
|
3090f70ee6 | ||
|
484e18a9af | ||
|
83d37a7c94 | ||
|
fc043af3a1 | ||
|
2ebd3f2cf3 | ||
|
ebab2ee188 |
@@ -1,14 +1,117 @@
|
|||||||
#include "GpSystemServices_Win32.h"
|
#include "GpSystemServices_Win32.h"
|
||||||
#include "GpMutex_Win32.h"
|
#include "GpMutex_Win32.h"
|
||||||
#include "GpThreadEvent_Win32.h"
|
#include "GpThreadEvent_Win32.h"
|
||||||
|
#include "GpWindows.h"
|
||||||
|
|
||||||
|
#include "IGpClipboardContents.h"
|
||||||
|
|
||||||
|
#include "UTF16.h"
|
||||||
|
#include "UTF8.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#pragma push_macro("CreateMutex")
|
#pragma push_macro("CreateMutex")
|
||||||
#ifdef CreateMutex
|
#ifdef CreateMutex
|
||||||
#undef CreateMutex
|
#undef CreateMutex
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern GpWindowsGlobals g_gpWindowsGlobals;
|
||||||
|
|
||||||
|
namespace GpSystemServices_Win32_Private
|
||||||
|
{
|
||||||
|
class RefCountedClipboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RefCountedClipboard();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~RefCountedClipboard();
|
||||||
|
|
||||||
|
void AddRef();
|
||||||
|
void DecRef();
|
||||||
|
|
||||||
|
unsigned int m_refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextClipboard : public RefCountedClipboard, public IGpClipboardContentsText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextClipboard(const uint8_t *utf8Text, size_t utf8Size);
|
||||||
|
~TextClipboard() override;
|
||||||
|
|
||||||
|
GpClipboardContentsType_t GetContentsType() const override;
|
||||||
|
void Destroy() override;
|
||||||
|
IGpClipboardContents *Clone() const override;
|
||||||
|
const uint8_t *GetBytes() const override;
|
||||||
|
size_t GetSize() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> m_utf8Text;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
RefCountedClipboard::RefCountedClipboard()
|
||||||
|
: m_refCount(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RefCountedClipboard::~RefCountedClipboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefCountedClipboard::AddRef()
|
||||||
|
{
|
||||||
|
m_refCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefCountedClipboard::DecRef()
|
||||||
|
{
|
||||||
|
unsigned int rc = --m_refCount;
|
||||||
|
if (rc == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextClipboard::TextClipboard(const uint8_t *utf8Text, size_t utf8Size)
|
||||||
|
{
|
||||||
|
m_utf8Text.resize(utf8Size);
|
||||||
|
if (utf8Size > 0)
|
||||||
|
memcpy(&m_utf8Text[0], utf8Text, utf8Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextClipboard::~TextClipboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GpClipboardContentsType_t TextClipboard::GetContentsType() const
|
||||||
|
{
|
||||||
|
return GpClipboardContentsTypes::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextClipboard::Destroy()
|
||||||
|
{
|
||||||
|
this->DecRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
IGpClipboardContents *TextClipboard::Clone() const
|
||||||
|
{
|
||||||
|
const_cast<TextClipboard*>(this)->AddRef();
|
||||||
|
return const_cast<TextClipboard*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *TextClipboard::GetBytes() const
|
||||||
|
{
|
||||||
|
if (m_utf8Text.size() == 0)
|
||||||
|
return nullptr;
|
||||||
|
return &m_utf8Text[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TextClipboard::GetSize() const
|
||||||
|
{
|
||||||
|
return m_utf8Text.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct GpSystemServices_Win32_ThreadStartParams
|
struct GpSystemServices_Win32_ThreadStartParams
|
||||||
{
|
{
|
||||||
GpSystemServices_Win32::ThreadFunc_t m_threadFunc;
|
GpSystemServices_Win32::ThreadFunc_t m_threadFunc;
|
||||||
@@ -34,6 +137,10 @@ GpSystemServices_Win32::GpSystemServices_Win32()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpSystemServices_Win32::~GpSystemServices_Win32()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int64_t GpSystemServices_Win32::GetTime() const
|
int64_t GpSystemServices_Win32::GetTime() const
|
||||||
{
|
{
|
||||||
SYSTEMTIME epochStart;
|
SYSTEMTIME epochStart;
|
||||||
@@ -171,6 +278,89 @@ bool GpSystemServices_Win32::AreFontResourcesSeekable() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGpClipboardContents *GpSystemServices_Win32::GetClipboardContents() const
|
||||||
|
{
|
||||||
|
IGpClipboardContents *cbObject = nullptr;
|
||||||
|
|
||||||
|
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||||
|
{
|
||||||
|
if (OpenClipboard(g_gpWindowsGlobals.m_hwnd))
|
||||||
|
{
|
||||||
|
HGLOBAL textHandle = GetClipboardData(CF_UNICODETEXT);
|
||||||
|
if (textHandle)
|
||||||
|
{
|
||||||
|
const wchar_t *str = static_cast<const wchar_t*>(GlobalLock(textHandle));
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
if (str[0] == 0)
|
||||||
|
cbObject = new GpSystemServices_Win32_Private::TextClipboard(nullptr, 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int bytesRequired = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (bytesRequired > 0)
|
||||||
|
{
|
||||||
|
std::vector<char> decodedText;
|
||||||
|
decodedText.resize(bytesRequired);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, str, -1, &decodedText[0], bytesRequired, nullptr, nullptr);
|
||||||
|
|
||||||
|
cbObject = new GpSystemServices_Win32_Private::TextClipboard(reinterpret_cast<const uint8_t*>(&decodedText[0]), decodedText.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalUnlock(textHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpSystemServices_Win32::SetClipboardContents(IGpClipboardContents *contents)
|
||||||
|
{
|
||||||
|
if (!contents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (contents->GetContentsType() == GpClipboardContentsTypes::kText)
|
||||||
|
{
|
||||||
|
IGpClipboardContentsText *textContents = static_cast<IGpClipboardContentsText*>(contents);
|
||||||
|
|
||||||
|
if (OpenClipboard(g_gpWindowsGlobals.m_hwnd))
|
||||||
|
{
|
||||||
|
if (EmptyClipboard())
|
||||||
|
{
|
||||||
|
int wcharsRequired = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<const char*>(textContents->GetBytes()), textContents->GetSize(), nullptr, 0);
|
||||||
|
|
||||||
|
std::vector<wchar_t> wideChars;
|
||||||
|
|
||||||
|
if (wcharsRequired)
|
||||||
|
{
|
||||||
|
wideChars.resize(wcharsRequired + 1);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<const char*>(textContents->GetBytes()), textContents->GetSize(), &wideChars[0], wcharsRequired);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wideChars.resize(1);
|
||||||
|
|
||||||
|
wideChars[wideChars.size() - 1] = static_cast<wchar_t>(0);
|
||||||
|
|
||||||
|
HGLOBAL textObject = GlobalAlloc(GMEM_MOVEABLE, wideChars.size() * sizeof(wchar_t));
|
||||||
|
if (textObject)
|
||||||
|
{
|
||||||
|
wchar_t *buffer = static_cast<wchar_t*>(GlobalLock(textObject));
|
||||||
|
memcpy(buffer, &wideChars[0], wideChars.size() * sizeof(wchar_t));
|
||||||
|
GlobalUnlock(textObject);
|
||||||
|
|
||||||
|
SetClipboardData(CF_UNICODETEXT, textObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GpSystemServices_Win32::SetTouchscreenSimulation(bool isTouchscreenSimulation)
|
void GpSystemServices_Win32::SetTouchscreenSimulation(bool isTouchscreenSimulation)
|
||||||
{
|
{
|
||||||
|
@@ -19,6 +19,7 @@ class GpSystemServices_Win32 final : public IGpSystemServices
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GpSystemServices_Win32();
|
GpSystemServices_Win32();
|
||||||
|
~GpSystemServices_Win32();
|
||||||
|
|
||||||
int64_t GetTime() const override;
|
int64_t GetTime() const override;
|
||||||
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
|
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
|
||||||
@@ -36,6 +37,8 @@ public:
|
|||||||
void SetTextInputEnabled(bool isEnabled) override;
|
void SetTextInputEnabled(bool isEnabled) override;
|
||||||
bool IsTextInputEnabled() const override;
|
bool IsTextInputEnabled() const override;
|
||||||
bool AreFontResourcesSeekable() const override;
|
bool AreFontResourcesSeekable() const override;
|
||||||
|
IGpClipboardContents *GetClipboardContents() const override;
|
||||||
|
void SetClipboardContents(IGpClipboardContents *contents) override;
|
||||||
|
|
||||||
void SetTouchscreenSimulation(bool isTouchscreenSimulation);
|
void SetTouchscreenSimulation(bool isTouchscreenSimulation);
|
||||||
|
|
||||||
|
@@ -15,8 +15,8 @@ android {
|
|||||||
}
|
}
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 7
|
versionCode 9
|
||||||
versionName "1.0.11"
|
versionName "1.0.13"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
ndkBuild {
|
ndkBuild {
|
||||||
arguments "APP_PLATFORM=android-16"
|
arguments "APP_PLATFORM=android-16"
|
||||||
|
@@ -290,6 +290,15 @@ bool GpSystemServices_Android::AreFontResourcesSeekable() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGpClipboardContents *GpSystemServices_Android::GetClipboardContents() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpSystemServices_Android::SetClipboardContents(IGpClipboardContents *contents)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
GpSystemServices_Android *GpSystemServices_Android::GetInstance()
|
GpSystemServices_Android *GpSystemServices_Android::GetInstance()
|
||||||
{
|
{
|
||||||
return &ms_instance;
|
return &ms_instance;
|
||||||
|
@@ -24,6 +24,8 @@ public:
|
|||||||
void SetTextInputEnabled(bool isEnabled) override;
|
void SetTextInputEnabled(bool isEnabled) override;
|
||||||
bool IsTextInputEnabled() const override;
|
bool IsTextInputEnabled() const override;
|
||||||
bool AreFontResourcesSeekable() const override;
|
bool AreFontResourcesSeekable() const override;
|
||||||
|
IGpClipboardContents *GetClipboardContents() const override;
|
||||||
|
void SetClipboardContents(IGpClipboardContents *contents) override;
|
||||||
|
|
||||||
void FlushTextInputEnabled();
|
void FlushTextInputEnabled();
|
||||||
|
|
||||||
|
@@ -55,6 +55,7 @@ DrawSurface *loadScreenRingSurface;
|
|||||||
|
|
||||||
void ReadInPrefs (void);
|
void ReadInPrefs (void);
|
||||||
void WriteOutPrefs (void);
|
void WriteOutPrefs (void);
|
||||||
|
void HandleSplashResolutionChange (void);
|
||||||
int main(int argc, const char **argv);
|
int main(int argc, const char **argv);
|
||||||
|
|
||||||
|
|
||||||
@@ -1137,17 +1138,28 @@ int gpAppMain()
|
|||||||
loadScreenRingSurface = nullptr;
|
loadScreenRingSurface = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool resolutionChanged = false;
|
||||||
|
|
||||||
if (!isPrefsLoaded)
|
if (!isPrefsLoaded)
|
||||||
{
|
{
|
||||||
WriteOutPrefs();
|
WriteOutPrefs();
|
||||||
|
|
||||||
FlushResolutionChange();
|
if (thisMac.isResolutionDirty)
|
||||||
|
{
|
||||||
|
resolutionChanged = true;
|
||||||
|
FlushResolutionChange();
|
||||||
|
}
|
||||||
|
|
||||||
ShowInitialLaunchDisclaimer();
|
ShowInitialLaunchDisclaimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushResolutionChange();
|
if (thisMac.isResolutionDirty)
|
||||||
|
resolutionChanged = true;
|
||||||
|
|
||||||
OpenMainWindow();
|
if (resolutionChanged)
|
||||||
|
HandleSplashResolutionChange();
|
||||||
|
else
|
||||||
|
OpenMainWindow();
|
||||||
|
|
||||||
if (isDoColorFade)
|
if (isDoColorFade)
|
||||||
PortabilityLayer::WindowManager::GetInstance()->SetWindowDesaturation(mainWindow, 1.0);
|
PortabilityLayer::WindowManager::GetInstance()->SetWindowDesaturation(mainWindow, 1.0);
|
||||||
|
@@ -44,15 +44,22 @@ void DoMarquee (void)
|
|||||||
if ((!theMarquee.active) || (theMarquee.paused))
|
if ((!theMarquee.active) || (theMarquee.paused))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DrawSurface *surface = mainWindow->GetDrawSurface();
|
theMarquee.step++;
|
||||||
const uint8_t *pattern = theMarquee.pats[theMarquee.index];
|
|
||||||
DrawMarquee(surface, pattern);
|
|
||||||
theMarquee.index++;
|
|
||||||
if (theMarquee.index >= kNumMarqueePats)
|
|
||||||
theMarquee.index = 0;
|
|
||||||
|
|
||||||
pattern = theMarquee.pats[theMarquee.index];
|
if (theMarquee.step >= theMarquee.interval)
|
||||||
DrawMarquee(surface, pattern);
|
{
|
||||||
|
DrawSurface *surface = mainWindow->GetDrawSurface();
|
||||||
|
const uint8_t *pattern = theMarquee.pats[theMarquee.index];
|
||||||
|
DrawMarquee(surface, pattern);
|
||||||
|
theMarquee.index++;
|
||||||
|
if (theMarquee.index >= kNumMarqueePats)
|
||||||
|
theMarquee.index = 0;
|
||||||
|
|
||||||
|
pattern = theMarquee.pats[theMarquee.index];
|
||||||
|
DrawMarquee(surface, pattern);
|
||||||
|
|
||||||
|
theMarquee.step = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------- StartMarquee
|
//-------------------------------------------------------------- StartMarquee
|
||||||
@@ -515,6 +522,8 @@ void InitMarquee (void)
|
|||||||
theMarquee.active = false;
|
theMarquee.active = false;
|
||||||
theMarquee.paused = false;
|
theMarquee.paused = false;
|
||||||
theMarquee.handled = false;
|
theMarquee.handled = false;
|
||||||
|
theMarquee.step = 0;
|
||||||
|
theMarquee.interval = 2;
|
||||||
gliderMarqueeUp = false;
|
gliderMarqueeUp = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
Pattern pats[kNumMarqueePats];
|
Pattern pats[kNumMarqueePats];
|
||||||
Rect bounds, handle;
|
Rect bounds, handle;
|
||||||
short index, direction, dist;
|
short index, direction, dist, step, interval;
|
||||||
Boolean active, paused, handled;
|
Boolean active, paused, handled;
|
||||||
} marquee;
|
} marquee;
|
||||||
|
|
||||||
|
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#define GP_BUILD_VERSION_MAJOR 1
|
#define GP_BUILD_VERSION_MAJOR 1
|
||||||
#define GP_BUILD_VERSION_MINOR 0
|
#define GP_BUILD_VERSION_MINOR 0
|
||||||
#define GP_BUILD_VERSION_UPDATE 11
|
#define GP_BUILD_VERSION_UPDATE 13
|
||||||
|
|
||||||
#define GP_APPLICATION_VERSION_STRING "1.0.11"
|
#define GP_APPLICATION_VERSION_STRING "1.0.13"
|
||||||
#define GP_APPLICATION_COPYRIGHT_STRING "2019-2020 Eric Lasota"
|
#define GP_APPLICATION_COPYRIGHT_STRING "2019-2021 Eric Lasota"
|
||||||
#define GP_APPLICATION_WEBSITE_STRING "https://github.com/elasota/Aerofoil"
|
#define GP_APPLICATION_WEBSITE_STRING "https://github.com/elasota/Aerofoil"
|
||||||
|
11
GpCommon/GpClipboardContentsType.h
Normal file
11
GpCommon/GpClipboardContentsType.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace GpClipboardContentsTypes
|
||||||
|
{
|
||||||
|
enum GpClipboardContentsType
|
||||||
|
{
|
||||||
|
kText,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef GpClipboardContentsTypes::GpClipboardContentsType GpClipboardContentsType_t;
|
16
GpCommon/IGpClipboardContents.h
Normal file
16
GpCommon/IGpClipboardContents.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "GpClipboardContentsType.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct IGpClipboardContents
|
||||||
|
{
|
||||||
|
virtual GpClipboardContentsType_t GetContentsType() const = 0;
|
||||||
|
virtual void Destroy() = 0;
|
||||||
|
virtual IGpClipboardContents *Clone() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IGpClipboardContentsText : public IGpClipboardContents
|
||||||
|
{
|
||||||
|
virtual const uint8_t *GetBytes() const = 0;
|
||||||
|
virtual size_t GetSize() const = 0; // In bytes
|
||||||
|
};
|
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
struct IGpMutex;
|
struct IGpMutex;
|
||||||
struct IGpThreadEvent;
|
struct IGpThreadEvent;
|
||||||
|
struct IGpClipboardContents;
|
||||||
|
|
||||||
struct IGpSystemServices
|
struct IGpSystemServices
|
||||||
{
|
{
|
||||||
@@ -34,4 +35,6 @@ public:
|
|||||||
virtual void SetTextInputEnabled(bool isEnabled) = 0;
|
virtual void SetTextInputEnabled(bool isEnabled) = 0;
|
||||||
virtual bool IsTextInputEnabled() const = 0;
|
virtual bool IsTextInputEnabled() const = 0;
|
||||||
virtual bool AreFontResourcesSeekable() const = 0;
|
virtual bool AreFontResourcesSeekable() const = 0;
|
||||||
|
virtual IGpClipboardContents *GetClipboardContents() const = 0;
|
||||||
|
virtual void SetClipboardContents(IGpClipboardContents *contents) = 0;
|
||||||
};
|
};
|
||||||
|
@@ -1202,6 +1202,12 @@ void GpDisplayDriverD3D11::Run()
|
|||||||
float pixelScaleX = 1.0f;
|
float pixelScaleX = 1.0f;
|
||||||
float pixelScaleY = 1.0f;
|
float pixelScaleY = 1.0f;
|
||||||
|
|
||||||
|
if (desiredWidth < 640)
|
||||||
|
desiredWidth = 640;
|
||||||
|
|
||||||
|
if (desiredHeight < 480)
|
||||||
|
desiredHeight = 480;
|
||||||
|
|
||||||
if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight, virtualWidth, virtualHeight, pixelScaleX, pixelScaleY))
|
if (m_properties.m_adjustRequestedResolutionFunc(m_properties.m_adjustRequestedResolutionFuncContext, desiredWidth, desiredHeight, virtualWidth, virtualHeight, pixelScaleX, pixelScaleY))
|
||||||
{
|
{
|
||||||
bool resizedOK = ResizeD3DWindow(m_osGlobals->m_hwnd, m_windowWidthPhysical, m_windowHeightPhysical, desiredWidth, desiredHeight, windowStyle, menus, logger);
|
bool resizedOK = ResizeD3DWindow(m_osGlobals->m_hwnd, m_windowWidthPhysical, m_windowHeightPhysical, desiredWidth, desiredHeight, windowStyle, menus, logger);
|
||||||
|
@@ -361,7 +361,7 @@ namespace PortabilityLayer
|
|||||||
|
|
||||||
const bool haveEvent = WaitForEvent(&evt, 1);
|
const bool haveEvent = WaitForEvent(&evt, 1);
|
||||||
|
|
||||||
if (window->IsHandlingTickEvents())
|
if (!haveEvent && window->IsHandlingTickEvents())
|
||||||
window->OnTick();
|
window->OnTick();
|
||||||
|
|
||||||
const int16_t selection = (filterFunc != nullptr) ? filterFunc(captureContext, this, haveEvent ? &evt : nullptr) : -1;
|
const int16_t selection = (filterFunc != nullptr) ? filterFunc(captureContext, this, haveEvent ? &evt : nullptr) : -1;
|
||||||
|
@@ -109,7 +109,8 @@ namespace PortabilityLayer
|
|||||||
uint8_t *bytes = static_cast<uint8_t*>(buf);
|
uint8_t *bytes = static_cast<uint8_t*>(buf);
|
||||||
const MMBlock *mmBlock = reinterpret_cast<const MMBlock*>(bytes - MMBlock::AlignedSize());
|
const MMBlock *mmBlock = reinterpret_cast<const MMBlock*>(bytes - MMBlock::AlignedSize());
|
||||||
|
|
||||||
free(bytes - MMBlock::AlignedSize() - mmBlock->m_offsetFromAllocLocation);
|
void *freeLoc = bytes - MMBlock::AlignedSize() - mmBlock->m_offsetFromAllocLocation;
|
||||||
|
free(freeLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
MMHandleBlock *MemoryManagerImpl::AllocHandle(size_t size)
|
MMHandleBlock *MemoryManagerImpl::AllocHandle(size_t size)
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "IGpDirectoryCursor.h"
|
#include "IGpDirectoryCursor.h"
|
||||||
#include "HostSuspendCallArgument.h"
|
#include "HostSuspendCallArgument.h"
|
||||||
#include "HostSuspendHook.h"
|
#include "HostSuspendHook.h"
|
||||||
|
#include "IGpClipboardContents.h"
|
||||||
#include "IGpCursor.h"
|
#include "IGpCursor.h"
|
||||||
#include "IGpDisplayDriver.h"
|
#include "IGpDisplayDriver.h"
|
||||||
#include "IGpFileSystem.h"
|
#include "IGpFileSystem.h"
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
#include "PLTimeTaggedVOSEvent.h"
|
#include "PLTimeTaggedVOSEvent.h"
|
||||||
#include "PLWidgets.h"
|
#include "PLWidgets.h"
|
||||||
|
|
||||||
|
#include "UTF8.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -688,6 +691,141 @@ WindowPtr PL_GetPutInFrontWindowPtr()
|
|||||||
return PortabilityLayer::WindowManager::GetInstance()->GetPutInFrontSentinel();
|
return PortabilityLayer::WindowManager::GetInstance()->GetPutInFrontSentinel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PLClipboardContentsText : public IGpClipboardContentsText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static PLClipboardContentsText *CreateFromMacRomanStr(const uint8_t *chars, size_t size);
|
||||||
|
|
||||||
|
GpClipboardContentsType_t GetContentsType() const override;
|
||||||
|
void Destroy() override;
|
||||||
|
IGpClipboardContents *Clone() const override;
|
||||||
|
const uint8_t *GetBytes() const override;
|
||||||
|
size_t GetSize() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PLClipboardContentsText(uint8_t *utf8Bytes, size_t size);
|
||||||
|
~PLClipboardContentsText();
|
||||||
|
|
||||||
|
uint8_t *m_utf8Bytes;
|
||||||
|
size_t m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PLClipboardContentsText *PLClipboardContentsText::CreateFromMacRomanStr(const uint8_t *chars, size_t length)
|
||||||
|
{
|
||||||
|
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
|
||||||
|
|
||||||
|
size_t numUTF8Bytes = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
uint8_t utf8Bytes[PortabilityLayer::UTF8Processor::kMaxEncodedBytes];
|
||||||
|
|
||||||
|
uint16_t codePoint = MacRoman::ToUnicode(chars[i]);
|
||||||
|
|
||||||
|
size_t numBytesEmitted = 0;
|
||||||
|
PortabilityLayer::UTF8Processor::EncodeCodePoint(utf8Bytes, numBytesEmitted, codePoint);
|
||||||
|
|
||||||
|
numUTF8Bytes += numBytesEmitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *utf8Bytes = nullptr;
|
||||||
|
|
||||||
|
if (numUTF8Bytes)
|
||||||
|
{
|
||||||
|
utf8Bytes = static_cast<uint8_t*>(mm->Alloc(numUTF8Bytes));
|
||||||
|
if (!utf8Bytes)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
numUTF8Bytes = 0;
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
uint16_t codePoint = MacRoman::ToUnicode(chars[i]);
|
||||||
|
|
||||||
|
size_t numBytesEmitted = 0;
|
||||||
|
PortabilityLayer::UTF8Processor::EncodeCodePoint(utf8Bytes + numUTF8Bytes, numBytesEmitted, codePoint);
|
||||||
|
|
||||||
|
numUTF8Bytes += numBytesEmitted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *storage = mm->Alloc(sizeof(PLClipboardContentsText));
|
||||||
|
if (!storage)
|
||||||
|
{
|
||||||
|
mm->Release(utf8Bytes);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new (storage) PLClipboardContentsText(utf8Bytes, numUTF8Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLClipboardContentsText::PLClipboardContentsText(uint8_t *utf8Bytes, size_t size)
|
||||||
|
: m_utf8Bytes(utf8Bytes)
|
||||||
|
, m_size(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PLClipboardContentsText::~PLClipboardContentsText()
|
||||||
|
{
|
||||||
|
PortabilityLayer::MemoryManager::GetInstance()->Release(m_utf8Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpClipboardContentsType_t PLClipboardContentsText::GetContentsType() const
|
||||||
|
{
|
||||||
|
return GpClipboardContentsTypes::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLClipboardContentsText::Destroy()
|
||||||
|
{
|
||||||
|
this->~PLClipboardContentsText();
|
||||||
|
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
IGpClipboardContents *PLClipboardContentsText::Clone() const
|
||||||
|
{
|
||||||
|
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
|
||||||
|
uint8_t *bytesCopy = nullptr;
|
||||||
|
if (m_size)
|
||||||
|
{
|
||||||
|
bytesCopy = static_cast<uint8_t*>(mm->Alloc(m_size));
|
||||||
|
if (!bytesCopy)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
memcpy(bytesCopy, m_utf8Bytes, m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *storage = mm->Alloc(sizeof(PLClipboardContentsText));
|
||||||
|
if (!storage)
|
||||||
|
{
|
||||||
|
if (bytesCopy)
|
||||||
|
mm->Release(bytesCopy);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new (storage) PLClipboardContentsText(bytesCopy, m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *PLClipboardContentsText::GetBytes() const
|
||||||
|
{
|
||||||
|
return m_utf8Bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PLClipboardContentsText::GetSize() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PL_CopyStringToClipboard(const uint8_t *chars, size_t length)
|
||||||
|
{
|
||||||
|
if (IGpClipboardContentsText *clipboardText = PLClipboardContentsText::CreateFromMacRomanStr(chars, length))
|
||||||
|
{
|
||||||
|
PLDrivers::GetSystemServices()->SetClipboardContents(clipboardText);
|
||||||
|
clipboardText->Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Window::Window()
|
Window::Window()
|
||||||
: m_surface(PortabilityLayer::QDPortType_Window)
|
: m_surface(PortabilityLayer::QDPortType_Window)
|
||||||
, m_wmX(0)
|
, m_wmX(0)
|
||||||
|
@@ -279,3 +279,5 @@ void PL_NotYetImplemented();
|
|||||||
void PL_NotYetImplemented_Minor();
|
void PL_NotYetImplemented_Minor();
|
||||||
void PL_NotYetImplemented_TODO(const char *category);
|
void PL_NotYetImplemented_TODO(const char *category);
|
||||||
void PL_Init();
|
void PL_Init();
|
||||||
|
|
||||||
|
void PL_CopyStringToClipboard(const uint8_t *chars, size_t length);
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "FontFamily.h"
|
#include "FontFamily.h"
|
||||||
#include "FontManager.h"
|
#include "FontManager.h"
|
||||||
|
#include "IGpClipboardContents.h"
|
||||||
#include "IGpSystemServices.h"
|
#include "IGpSystemServices.h"
|
||||||
#include "InputManager.h"
|
#include "InputManager.h"
|
||||||
#include "MacRomanConversion.h"
|
#include "MacRomanConversion.h"
|
||||||
@@ -9,14 +10,16 @@
|
|||||||
#include "RenderedFont.h"
|
#include "RenderedFont.h"
|
||||||
#include "GpRenderedFontMetrics.h"
|
#include "GpRenderedFontMetrics.h"
|
||||||
#include "ResolveCachingColor.h"
|
#include "ResolveCachingColor.h"
|
||||||
#include "TextPlacer.h"
|
|
||||||
#include "Rect2i.h"
|
#include "Rect2i.h"
|
||||||
|
#include "TextPlacer.h"
|
||||||
|
#include "UTF8.h"
|
||||||
|
|
||||||
#include "PLDrivers.h"
|
#include "PLDrivers.h"
|
||||||
#include "PLKeyEncoding.h"
|
#include "PLKeyEncoding.h"
|
||||||
#include "PLQDraw.h"
|
#include "PLQDraw.h"
|
||||||
#include "PLStandardColors.h"
|
#include "PLStandardColors.h"
|
||||||
#include "PLTimeTaggedVOSEvent.h"
|
#include "PLTimeTaggedVOSEvent.h"
|
||||||
|
#include "PLCore.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -36,7 +39,10 @@ namespace PortabilityLayer
|
|||||||
, m_caratTimer(0)
|
, m_caratTimer(0)
|
||||||
, m_isMultiLine(false)
|
, m_isMultiLine(false)
|
||||||
, m_isDraggingSelection(false)
|
, m_isDraggingSelection(false)
|
||||||
|
, m_isDraggingWords(false)
|
||||||
, m_dragSelectionStartChar(false)
|
, m_dragSelectionStartChar(false)
|
||||||
|
, m_doubleClickTime(0)
|
||||||
|
, m_doubleClickPoint(Point::Create(0, 0))
|
||||||
, m_scrollOffset(0, 0)
|
, m_scrollOffset(0, 0)
|
||||||
, m_characterFilter(nullptr)
|
, m_characterFilter(nullptr)
|
||||||
, m_characterFilterContext(nullptr)
|
, m_characterFilterContext(nullptr)
|
||||||
@@ -233,6 +239,8 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
const KeyDownStates *downStates = PortabilityLayer::InputManager::GetInstance()->GetKeys();
|
const KeyDownStates *downStates = PortabilityLayer::InputManager::GetInstance()->GetKeys();
|
||||||
const bool isShiftHeld = downStates->m_special.Get(GpKeySpecials::kLeftShift) || downStates->m_special.Get(GpKeySpecials::kRightShift);
|
const bool isShiftHeld = downStates->m_special.Get(GpKeySpecials::kLeftShift) || downStates->m_special.Get(GpKeySpecials::kRightShift);
|
||||||
|
const bool isWords = downStates->m_special.Get(GpKeySpecials::kLeftCtrl) || downStates->m_special.Get(GpKeySpecials::kRightCtrl);
|
||||||
|
const bool isCtrlHeld = downStates->m_special.Get(GpKeySpecials::kLeftCtrl) || downStates->m_special.Get(GpKeySpecials::kRightCtrl);
|
||||||
|
|
||||||
if (keyEvent.m_keyIDSubset == GpKeyIDSubsets::kSpecial)
|
if (keyEvent.m_keyIDSubset == GpKeyIDSubsets::kSpecial)
|
||||||
{
|
{
|
||||||
@@ -248,12 +256,12 @@ namespace PortabilityLayer
|
|||||||
}
|
}
|
||||||
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kLeftArrow)
|
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kLeftArrow)
|
||||||
{
|
{
|
||||||
HandleLeftArrow(keyEvent.m_repeatCount, isShiftHeld);
|
HandleLeftArrow(keyEvent.m_repeatCount, isShiftHeld, isWords);
|
||||||
return WidgetHandleStates::kDigested;
|
return WidgetHandleStates::kDigested;
|
||||||
}
|
}
|
||||||
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kRightArrow)
|
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kRightArrow)
|
||||||
{
|
{
|
||||||
HandleRightArrow(keyEvent.m_repeatCount, isShiftHeld);
|
HandleRightArrow(keyEvent.m_repeatCount, isShiftHeld, isWords);
|
||||||
return WidgetHandleStates::kDigested;
|
return WidgetHandleStates::kDigested;
|
||||||
}
|
}
|
||||||
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kDownArrow)
|
else if (keyEvent.m_key.m_specialKey == GpKeySpecials::kDownArrow)
|
||||||
@@ -277,6 +285,39 @@ namespace PortabilityLayer
|
|||||||
return WidgetHandleStates::kDigested;
|
return WidgetHandleStates::kDigested;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCtrlHeld && keyEvent.m_keyIDSubset == GpKeyIDSubsets::kASCII)
|
||||||
|
{
|
||||||
|
if (keyEvent.m_key.m_asciiChar == kCopyShortcutKey)
|
||||||
|
{
|
||||||
|
if (m_selStartChar != m_selEndChar)
|
||||||
|
HandleCopy();
|
||||||
|
return WidgetHandleStates::kDigested;
|
||||||
|
}
|
||||||
|
if (keyEvent.m_key.m_asciiChar == kCutShortcutKey)
|
||||||
|
{
|
||||||
|
if (m_selStartChar != m_selEndChar)
|
||||||
|
HandleCut();
|
||||||
|
return WidgetHandleStates::kDigested;
|
||||||
|
}
|
||||||
|
else if (keyEvent.m_key.m_asciiChar == kPasteShortcutKey)
|
||||||
|
{
|
||||||
|
HandlePaste(keyEvent.m_repeatCount);
|
||||||
|
return WidgetHandleStates::kDigested;
|
||||||
|
}
|
||||||
|
else if (keyEvent.m_key.m_asciiChar == kSelectAllShortcutKey)
|
||||||
|
{
|
||||||
|
m_selStartChar = 0;
|
||||||
|
m_selEndChar = m_length;
|
||||||
|
|
||||||
|
m_caratSelectionAnchor = CaratSelectionAnchor_Start;
|
||||||
|
m_caratScrollLocked = false;
|
||||||
|
AdjustScrollToCarat();
|
||||||
|
|
||||||
|
m_caratTimer = 0;
|
||||||
|
Redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
|
else if (evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
|
||||||
@@ -289,8 +330,17 @@ namespace PortabilityLayer
|
|||||||
|
|
||||||
if (m_rect.Contains(pt))
|
if (m_rect.Contains(pt))
|
||||||
{
|
{
|
||||||
|
const uint32_t doubleTime = 30; // PL_NotYetImplemented_TODO: Get this from the system settings
|
||||||
|
|
||||||
m_window->FocusWidget(this);
|
m_window->FocusWidget(this);
|
||||||
m_isDraggingSelection = true;
|
m_isDraggingSelection = true;
|
||||||
|
m_isDraggingWords = false;
|
||||||
|
if (evt.m_timestamp >= m_doubleClickTime && evt.m_timestamp - m_doubleClickTime <= doubleTime)
|
||||||
|
{
|
||||||
|
if (pt == m_doubleClickPoint)
|
||||||
|
m_isDraggingWords = true;
|
||||||
|
}
|
||||||
|
|
||||||
return HandleDragSelection(evt);
|
return HandleDragSelection(evt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -493,7 +543,7 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
bool isOutOfRange = false;
|
bool isOutOfRange = false;
|
||||||
m_caratScrollPosition.m_y -= lineGap;
|
m_caratScrollPosition.m_y -= lineGap;
|
||||||
caratChar = FindVerticalMovementCaratPos(m_caratScrollPosition, isOutOfRange);
|
caratChar = FindVerticalMovementCaratPos(m_caratScrollPosition, isOutOfRange, nullptr);
|
||||||
HandleKeyMoveCarat(caratChar, shiftHeld);
|
HandleKeyMoveCarat(caratChar, shiftHeld);
|
||||||
|
|
||||||
if (isOutOfRange)
|
if (isOutOfRange)
|
||||||
@@ -534,7 +584,7 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
bool isOutOfRange = false;
|
bool isOutOfRange = false;
|
||||||
m_caratScrollPosition.m_y += lineGap;
|
m_caratScrollPosition.m_y += lineGap;
|
||||||
caratChar = FindVerticalMovementCaratPos(m_caratScrollPosition, isOutOfRange);
|
caratChar = FindVerticalMovementCaratPos(m_caratScrollPosition, isOutOfRange, nullptr);
|
||||||
HandleKeyMoveCarat(caratChar, shiftHeld);
|
HandleKeyMoveCarat(caratChar, shiftHeld);
|
||||||
|
|
||||||
if (isOutOfRange)
|
if (isOutOfRange)
|
||||||
@@ -550,7 +600,7 @@ namespace PortabilityLayer
|
|||||||
Redraw();
|
Redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditboxWidget::HandleLeftArrow(const uint32_t numRepeatsRequested, bool shiftHeld)
|
void EditboxWidget::HandleLeftArrow(const uint32_t numRepeatsRequested, bool shiftHeld, bool wholeWords)
|
||||||
{
|
{
|
||||||
size_t caratChar = ResolveCaratChar();
|
size_t caratChar = ResolveCaratChar();
|
||||||
|
|
||||||
@@ -559,7 +609,13 @@ namespace PortabilityLayer
|
|||||||
if (!shiftHeld && m_selStartChar != m_selEndChar)
|
if (!shiftHeld && m_selStartChar != m_selEndChar)
|
||||||
m_selEndChar = m_selStartChar;
|
m_selEndChar = m_selStartChar;
|
||||||
else if (caratChar > 0)
|
else if (caratChar > 0)
|
||||||
HandleKeyMoveCarat(caratChar - 1, shiftHeld);
|
{
|
||||||
|
size_t spanLength = 1;
|
||||||
|
if (wholeWords)
|
||||||
|
spanLength = IdentifySpanLength(caratChar - 1, SpanScanDirection_Left);
|
||||||
|
|
||||||
|
HandleKeyMoveCarat(caratChar - spanLength, shiftHeld);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_caratScrollLocked = false;
|
m_caratScrollLocked = false;
|
||||||
@@ -624,8 +680,92 @@ namespace PortabilityLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditboxWidget::HandleCopy()
|
||||||
|
{
|
||||||
|
if (m_selStartChar == m_selEndChar)
|
||||||
|
return;
|
||||||
|
|
||||||
void EditboxWidget::HandleRightArrow(const uint32_t numRepeatsRequested, bool shiftHeld)
|
PL_CopyStringToClipboard(m_chars + m_selStartChar, m_selEndChar - m_selStartChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditboxWidget::HandleCut()
|
||||||
|
{
|
||||||
|
HandleCopy();
|
||||||
|
HandleBackspace(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditboxWidget::HandlePaste(size_t repeatCount)
|
||||||
|
{
|
||||||
|
IGpClipboardContents *clipboardContents = PLDrivers::GetSystemServices()->GetClipboardContents();
|
||||||
|
|
||||||
|
if (clipboardContents == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (clipboardContents->GetContentsType() != GpClipboardContentsTypes::kText)
|
||||||
|
{
|
||||||
|
clipboardContents->Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IGpClipboardContentsText *textContents = static_cast<IGpClipboardContentsText*>(clipboardContents);
|
||||||
|
const size_t utf8Size = textContents->GetSize();
|
||||||
|
const uint8_t *utf8Bytes = textContents->GetBytes();
|
||||||
|
|
||||||
|
size_t numCodePoints = 0;
|
||||||
|
for (size_t i = 0; i < utf8Size; )
|
||||||
|
{
|
||||||
|
uint32_t codePoint = 0;
|
||||||
|
size_t numDigested = 0;
|
||||||
|
if (!UTF8Processor::DecodeCodePoint(utf8Bytes + i, utf8Size - i, numDigested, codePoint))
|
||||||
|
{
|
||||||
|
clipboardContents->Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += numDigested;
|
||||||
|
numCodePoints++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
|
||||||
|
uint8_t *decodedChars = static_cast<uint8_t*>(mm->Alloc(numCodePoints));
|
||||||
|
|
||||||
|
if (!decodedChars)
|
||||||
|
{
|
||||||
|
clipboardContents->Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
numCodePoints = 0;
|
||||||
|
for (size_t i = 0; i < utf8Size; )
|
||||||
|
{
|
||||||
|
uint32_t codePoint = 0;
|
||||||
|
size_t numDigested = 0;
|
||||||
|
if (!UTF8Processor::DecodeCodePoint(utf8Bytes + i, utf8Size - i, numDigested, codePoint))
|
||||||
|
{
|
||||||
|
clipboardContents->Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codePoint > 0xffff || !MacRoman::FromUnicode(decodedChars[numCodePoints], static_cast<uint16_t>(codePoint)))
|
||||||
|
decodedChars[numCodePoints] = '?';
|
||||||
|
|
||||||
|
numCodePoints++;
|
||||||
|
|
||||||
|
i += numDigested;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is extremely suboptimal due to the embedded redraw...
|
||||||
|
for (size_t i = 0; i < repeatCount; i++)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < numCodePoints; j++)
|
||||||
|
HandleCharacter(decodedChars[j], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mm->Release(decodedChars);
|
||||||
|
clipboardContents->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditboxWidget::HandleRightArrow(const uint32_t numRepeatsRequested, bool shiftHeld, bool wholeWords)
|
||||||
{
|
{
|
||||||
size_t caratChar = ResolveCaratChar();
|
size_t caratChar = ResolveCaratChar();
|
||||||
|
|
||||||
@@ -634,7 +774,13 @@ namespace PortabilityLayer
|
|||||||
if (!shiftHeld && m_selStartChar != m_selEndChar)
|
if (!shiftHeld && m_selStartChar != m_selEndChar)
|
||||||
m_selStartChar = m_selEndChar;
|
m_selStartChar = m_selEndChar;
|
||||||
else if (caratChar < m_length)
|
else if (caratChar < m_length)
|
||||||
HandleKeyMoveCarat(caratChar + 1, shiftHeld);
|
{
|
||||||
|
size_t spanLength = 1;
|
||||||
|
if (wholeWords)
|
||||||
|
spanLength = IdentifySpanLength(caratChar, SpanScanDirection_Right);
|
||||||
|
|
||||||
|
HandleKeyMoveCarat(caratChar + spanLength, shiftHeld);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_caratScrollLocked = false;
|
m_caratScrollLocked = false;
|
||||||
@@ -645,12 +791,15 @@ namespace PortabilityLayer
|
|||||||
Redraw();
|
Redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t EditboxWidget::FindVerticalMovementCaratPos(const Vec2i &desiredPos, bool &isOutOfRange) const
|
size_t EditboxWidget::FindVerticalMovementCaratPos(const Vec2i &desiredPos, bool &isOutOfRange, CaratCharacterAlignment *optOutAlignment) const
|
||||||
{
|
{
|
||||||
Vec2i basePoint = Vec2i(0, 0);
|
Vec2i basePoint = Vec2i(0, 0);
|
||||||
|
|
||||||
if (desiredPos.m_y < basePoint.m_y)
|
if (desiredPos.m_y < basePoint.m_y)
|
||||||
{
|
{
|
||||||
|
if (optOutAlignment)
|
||||||
|
*optOutAlignment = CaratCharacterAlignment_Start;
|
||||||
|
|
||||||
isOutOfRange = true;
|
isOutOfRange = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -658,6 +807,7 @@ namespace PortabilityLayer
|
|||||||
PortabilityLayer::TextPlacer placer(basePoint, m_rect.Width(), GetRenderedFont(), GetString());
|
PortabilityLayer::TextPlacer placer(basePoint, m_rect.Width(), GetRenderedFont(), GetString());
|
||||||
|
|
||||||
bool foundLine = false;
|
bool foundLine = false;
|
||||||
|
bool foundChar = false;
|
||||||
size_t caratChar = 0;
|
size_t caratChar = 0;
|
||||||
|
|
||||||
PortabilityLayer::GlyphPlacementCharacteristics characteristics;
|
PortabilityLayer::GlyphPlacementCharacteristics characteristics;
|
||||||
@@ -675,34 +825,96 @@ namespace PortabilityLayer
|
|||||||
if (desiredPos.m_x <= 0)
|
if (desiredPos.m_x <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (characteristics.m_character != '\r')
|
if (characteristics.m_character == '\r')
|
||||||
caratChar++;
|
break;
|
||||||
|
|
||||||
|
caratChar++;
|
||||||
|
|
||||||
if (characteristics.m_glyphStartPos.m_x <= desiredPos.m_x && characteristics.m_glyphEndPos.m_x > desiredPos.m_x)
|
if (characteristics.m_glyphStartPos.m_x <= desiredPos.m_x && characteristics.m_glyphEndPos.m_x > desiredPos.m_x)
|
||||||
{
|
{
|
||||||
int32_t distanceToEnd = characteristics.m_glyphEndPos.m_x - desiredPos.m_x;
|
int32_t distanceToEnd = characteristics.m_glyphEndPos.m_x - desiredPos.m_x;
|
||||||
int32_t distanceToStart = desiredPos.m_x - characteristics.m_glyphStartPos.m_x;
|
int32_t distanceToStart = desiredPos.m_x - characteristics.m_glyphStartPos.m_x;
|
||||||
|
|
||||||
|
foundChar = true;
|
||||||
|
|
||||||
if (distanceToStart <= distanceToEnd)
|
if (distanceToStart <= distanceToEnd)
|
||||||
|
{
|
||||||
|
if (optOutAlignment)
|
||||||
|
*optOutAlignment = CaratCharacterAlignment_BeforeChar;
|
||||||
|
|
||||||
caratChar = characteristics.m_characterIndex;
|
caratChar = characteristics.m_characterIndex;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (optOutAlignment)
|
||||||
|
*optOutAlignment = CaratCharacterAlignment_AfterChar;
|
||||||
|
|
||||||
caratChar = characteristics.m_characterIndex + 1;
|
caratChar = characteristics.m_characterIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!foundChar)
|
||||||
|
{
|
||||||
|
if (optOutAlignment)
|
||||||
|
*optOutAlignment = CaratCharacterAlignment_EndOfLine;
|
||||||
|
}
|
||||||
|
|
||||||
if (foundLine)
|
if (foundLine)
|
||||||
{
|
{
|
||||||
isOutOfRange = false;
|
isOutOfRange = false;
|
||||||
return caratChar;
|
return caratChar;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
isOutOfRange = true;
|
{
|
||||||
return m_length;
|
isOutOfRange = true;
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditboxWidget::ExpandSelectionToWords(size_t rootChar, size_t &outStartChar, size_t &outEndChar)
|
||||||
|
{
|
||||||
|
assert(rootChar < m_length);
|
||||||
|
|
||||||
|
CharacterCategory charCategory = CategorizeCharacter(m_chars[rootChar]);
|
||||||
|
|
||||||
|
if (charCategory == CharacterCategory_LineBreak)
|
||||||
|
{
|
||||||
|
outStartChar = rootChar;
|
||||||
|
outEndChar = rootChar;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t selStart = rootChar;
|
||||||
|
size_t selEnd = rootChar + 1;
|
||||||
|
|
||||||
|
while (selStart > 0)
|
||||||
|
{
|
||||||
|
CharacterCategory candidateCategory = CategorizeCharacter(m_chars[selStart - 1]);
|
||||||
|
if (candidateCategory != charCategory)
|
||||||
|
break;
|
||||||
|
|
||||||
|
selStart--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (selEnd < m_length)
|
||||||
|
{
|
||||||
|
CharacterCategory candidateCategory = CategorizeCharacter(m_chars[selEnd]);
|
||||||
|
if (candidateCategory != charCategory)
|
||||||
|
break;
|
||||||
|
|
||||||
|
selEnd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
outStartChar = selStart;
|
||||||
|
outEndChar = selEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Handles adjustment of the selection range and anchor when the carat is moved with shift held
|
// Handles adjustment of the selection range and anchor when the carat is moved with shift held
|
||||||
void EditboxWidget::HandleKeyMoveCarat(size_t newPos, bool shiftHeld)
|
void EditboxWidget::HandleKeyMoveCarat(size_t newPos, bool shiftHeld)
|
||||||
{
|
{
|
||||||
@@ -749,13 +961,67 @@ namespace PortabilityLayer
|
|||||||
paragraph = -((-relativeY + (linegap - 1)) / linegap);
|
paragraph = -((-relativeY + (linegap - 1)) / linegap);
|
||||||
|
|
||||||
bool isOutOfRange = false;
|
bool isOutOfRange = false;
|
||||||
const size_t caratPos = FindVerticalMovementCaratPos(Vec2i(relativePoint.m_x, paragraph * linegap), isOutOfRange);
|
CaratCharacterAlignment cca;
|
||||||
|
const size_t caratPos = FindVerticalMovementCaratPos(Vec2i(relativePoint.m_x, paragraph * linegap), isOutOfRange, &cca);
|
||||||
|
|
||||||
if (mouseEvent.m_eventType == GpMouseEventTypes::kDown)
|
if (mouseEvent.m_eventType == GpMouseEventTypes::kDown)
|
||||||
{
|
{
|
||||||
m_dragSelectionStartChar = caratPos;
|
if (m_isDraggingWords)
|
||||||
m_selStartChar = caratPos;
|
{
|
||||||
m_selEndChar = caratPos;
|
FindVerticalMovementCaratPos(Vec2i(relativePoint.m_x, paragraph * linegap), isOutOfRange, &cca);
|
||||||
|
|
||||||
|
bool hasRootChar = false;
|
||||||
|
size_t rootChar = 0;
|
||||||
|
|
||||||
|
switch (cca)
|
||||||
|
{
|
||||||
|
case CaratCharacterAlignment_Start:
|
||||||
|
if (m_length > 0)
|
||||||
|
{
|
||||||
|
hasRootChar = true;
|
||||||
|
rootChar = caratPos;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CaratCharacterAlignment_AfterChar:
|
||||||
|
assert(caratPos >= 1);
|
||||||
|
hasRootChar = true;
|
||||||
|
rootChar = caratPos - 1;
|
||||||
|
break;
|
||||||
|
case CaratCharacterAlignment_BeforeChar:
|
||||||
|
hasRootChar = true;
|
||||||
|
rootChar = caratPos;
|
||||||
|
break;
|
||||||
|
case CaratCharacterAlignment_EndOfLine:
|
||||||
|
if (m_length > 0 && (caratPos == 0 || m_chars[caratPos - 1] != '\r'))
|
||||||
|
{
|
||||||
|
hasRootChar = true;
|
||||||
|
rootChar = caratPos - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasRootChar)
|
||||||
|
{
|
||||||
|
size_t startChar, endChar;
|
||||||
|
ExpandSelectionToWords(rootChar, startChar, endChar);
|
||||||
|
|
||||||
|
m_dragSelectionStartChar = startChar;
|
||||||
|
m_dragSelectionEndChar = endChar;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dragSelectionStartChar = caratPos;
|
||||||
|
m_dragSelectionEndChar = caratPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dragSelectionStartChar = caratPos;
|
||||||
|
m_dragSelectionEndChar = caratPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selStartChar = m_dragSelectionStartChar;
|
||||||
|
m_selEndChar = m_dragSelectionEndChar;
|
||||||
m_caratSelectionAnchor = CaratSelectionAnchor_End;
|
m_caratSelectionAnchor = CaratSelectionAnchor_End;
|
||||||
|
|
||||||
m_caratTimer = 0;
|
m_caratTimer = 0;
|
||||||
@@ -763,17 +1029,40 @@ namespace PortabilityLayer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (caratPos < m_dragSelectionStartChar)
|
size_t selExpandMin = caratPos;
|
||||||
|
size_t selExpandMax = caratPos;
|
||||||
|
|
||||||
|
if (m_isDraggingWords && (caratPos < m_dragSelectionStartChar || caratPos > m_dragSelectionEndChar))
|
||||||
|
{
|
||||||
|
size_t rootChar = 0;
|
||||||
|
if (caratPos < m_dragSelectionStartChar)
|
||||||
|
rootChar = caratPos;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(caratPos > m_dragSelectionEndChar);
|
||||||
|
rootChar = caratPos - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandSelectionToWords(rootChar, selExpandMin, selExpandMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selExpandMin < m_dragSelectionStartChar)
|
||||||
{
|
{
|
||||||
m_caratSelectionAnchor = CaratSelectionAnchor_Start;
|
m_caratSelectionAnchor = CaratSelectionAnchor_Start;
|
||||||
m_selStartChar = caratPos;
|
m_selStartChar = selExpandMin;
|
||||||
m_selEndChar = m_dragSelectionStartChar;
|
m_selEndChar = m_dragSelectionEndChar;
|
||||||
|
}
|
||||||
|
else if (selExpandMax > m_dragSelectionEndChar)
|
||||||
|
{
|
||||||
|
m_caratSelectionAnchor = CaratSelectionAnchor_End;
|
||||||
|
m_selEndChar = selExpandMax;
|
||||||
|
m_selStartChar = m_dragSelectionStartChar;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_caratSelectionAnchor = CaratSelectionAnchor_End;
|
m_caratSelectionAnchor = CaratSelectionAnchor_End;
|
||||||
m_selEndChar = caratPos;
|
|
||||||
m_selStartChar = m_dragSelectionStartChar;
|
m_selStartChar = m_dragSelectionStartChar;
|
||||||
|
m_selEndChar = m_dragSelectionEndChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
AdjustScrollToCarat();
|
AdjustScrollToCarat();
|
||||||
@@ -788,6 +1077,10 @@ namespace PortabilityLayer
|
|||||||
|
|
||||||
m_caratScrollLocked = false;
|
m_caratScrollLocked = false;
|
||||||
m_isDraggingSelection = false;
|
m_isDraggingSelection = false;
|
||||||
|
|
||||||
|
m_doubleClickTime = evt.m_timestamp;
|
||||||
|
m_doubleClickPoint = pt;
|
||||||
|
|
||||||
return WidgetHandleStates::kDigested;
|
return WidgetHandleStates::kDigested;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -986,6 +1279,52 @@ namespace PortabilityLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t EditboxWidget::IdentifySpanLength(size_t startChar, SpanScanDirection scanDirection) const
|
||||||
|
{
|
||||||
|
assert(startChar < m_length);
|
||||||
|
|
||||||
|
CharacterCategory contiguousCategory = CategorizeCharacter(m_chars[startChar]);
|
||||||
|
size_t spanLength = 1;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (scanDirection == SpanScanDirection_Left && (startChar + 1 - spanLength) == 0)
|
||||||
|
break;
|
||||||
|
if (scanDirection == SpanScanDirection_Right && startChar + spanLength == m_length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
size_t nextCharPos = startChar;
|
||||||
|
if (scanDirection == SpanScanDirection_Left)
|
||||||
|
nextCharPos -= spanLength;
|
||||||
|
else if (scanDirection == SpanScanDirection_Right)
|
||||||
|
nextCharPos += spanLength;
|
||||||
|
|
||||||
|
const CharacterCategory thisCategory = CategorizeCharacter(m_chars[nextCharPos]);
|
||||||
|
|
||||||
|
if (thisCategory != contiguousCategory)
|
||||||
|
{
|
||||||
|
// If span starts with whitespace, it can continue to the next category, otherwise stop
|
||||||
|
if (contiguousCategory == CharacterCategory_Whitespace)
|
||||||
|
contiguousCategory = thisCategory;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spanLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spanLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditboxWidget::CharacterCategory EditboxWidget::CategorizeCharacter(uint8_t character)
|
||||||
|
{
|
||||||
|
const CharacterCategorySpan *ccs = gs_characterCategorySpans;
|
||||||
|
while (character > ccs->m_lastCharacterPosInclusive)
|
||||||
|
ccs++;
|
||||||
|
|
||||||
|
return ccs->m_category;
|
||||||
|
}
|
||||||
|
|
||||||
FontFamily *EditboxWidget::GetFontFamily() const
|
FontFamily *EditboxWidget::GetFontFamily() const
|
||||||
{
|
{
|
||||||
return PortabilityLayer::FontManager::GetInstance()->GetSystemFont(12, FontFamilyFlag_None);
|
return PortabilityLayer::FontManager::GetInstance()->GetSystemFont(12, FontFamilyFlag_None);
|
||||||
@@ -1015,4 +1354,42 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
m_capacity = std::min<size_t>(255, capacity);
|
m_capacity = std::min<size_t>(255, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EditboxWidget::CharacterCategorySpan EditboxWidget::gs_characterCategorySpans[] =
|
||||||
|
{
|
||||||
|
{ 0x20, EditboxWidget::CharacterCategory_Whitespace },
|
||||||
|
{ 0x2f, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0x39, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0x40, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0x5a, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0x60, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0x7a, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0x7e, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0x7f, EditboxWidget::CharacterCategory_Whitespace },
|
||||||
|
{ 0x9f, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xa6, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xa7, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xad, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xaf, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xb4, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xb5, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xb8, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xb9, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xbc, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xbf, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xc3, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xc4, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xc9, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xca, EditboxWidget::CharacterCategory_Whitespace },
|
||||||
|
{ 0xcf, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xd7, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xd9, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xdd, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xdf, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xe4, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xef, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xf0, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
{ 0xf5, EditboxWidget::CharacterCategory_AlphaNumeric },
|
||||||
|
{ 0xff, EditboxWidget::CharacterCategory_Punctuation },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -42,12 +42,40 @@ namespace PortabilityLayer
|
|||||||
static const unsigned int kCaratBlinkRate = 20;
|
static const unsigned int kCaratBlinkRate = 20;
|
||||||
static const unsigned int kMouseScrollRate = 20;
|
static const unsigned int kMouseScrollRate = 20;
|
||||||
|
|
||||||
|
enum SpanScanDirection
|
||||||
|
{
|
||||||
|
SpanScanDirection_Left,
|
||||||
|
SpanScanDirection_Right,
|
||||||
|
};
|
||||||
|
|
||||||
enum CaratSelectionAnchor
|
enum CaratSelectionAnchor
|
||||||
{
|
{
|
||||||
CaratSelectionAnchor_Start,
|
CaratSelectionAnchor_Start,
|
||||||
CaratSelectionAnchor_End
|
CaratSelectionAnchor_End
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CharacterCategory
|
||||||
|
{
|
||||||
|
CharacterCategory_AlphaNumeric,
|
||||||
|
CharacterCategory_Whitespace,
|
||||||
|
CharacterCategory_LineBreak,
|
||||||
|
CharacterCategory_Punctuation,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharacterCategorySpan
|
||||||
|
{
|
||||||
|
uint8_t m_lastCharacterPosInclusive;
|
||||||
|
CharacterCategory m_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CaratCharacterAlignment
|
||||||
|
{
|
||||||
|
CaratCharacterAlignment_Start, // Before the start of the text
|
||||||
|
CaratCharacterAlignment_AfterChar, // Carat is after the character that was clicked
|
||||||
|
CaratCharacterAlignment_BeforeChar, // Carat is before the character that was clicked
|
||||||
|
CaratCharacterAlignment_EndOfLine, // Carat is at the end of a line
|
||||||
|
};
|
||||||
|
|
||||||
void OnTick() override;
|
void OnTick() override;
|
||||||
void Redraw();
|
void Redraw();
|
||||||
|
|
||||||
@@ -57,13 +85,17 @@ namespace PortabilityLayer
|
|||||||
|
|
||||||
void HandleUpArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
void HandleUpArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
||||||
void HandleDownArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
void HandleDownArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
||||||
void HandleLeftArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
void HandleLeftArrow(const uint32_t numRepeatsRequested, bool shiftHeld, bool wholeWords);
|
||||||
void HandleRightArrow(const uint32_t numRepeatsRequested, bool shiftHeld);
|
void HandleRightArrow(const uint32_t numRepeatsRequested, bool shiftHeld, bool wholeWords);
|
||||||
|
|
||||||
void HandleHome(bool shiftHeld);
|
void HandleHome(bool shiftHeld);
|
||||||
void HandleEnd(bool shiftHeld);
|
void HandleEnd(bool shiftHeld);
|
||||||
|
void HandleCopy();
|
||||||
|
void HandleCut();
|
||||||
|
void HandlePaste(size_t repeatCount);
|
||||||
|
|
||||||
size_t FindVerticalMovementCaratPos(const Vec2i &desiredPos, bool &isOutOfRange) const;
|
size_t FindVerticalMovementCaratPos(const Vec2i &desiredPos, bool &isOutOfRange, CaratCharacterAlignment *optOutAlignment) const;
|
||||||
|
void ExpandSelectionToWords(size_t caratPos, size_t &outStartChar, size_t &outEndChar);
|
||||||
void HandleKeyMoveCarat(size_t newPos, bool shiftHeld);
|
void HandleKeyMoveCarat(size_t newPos, bool shiftHeld);
|
||||||
|
|
||||||
WidgetHandleState_t HandleDragSelection(const TimeTaggedVOSEvent &evt);
|
WidgetHandleState_t HandleDragSelection(const TimeTaggedVOSEvent &evt);
|
||||||
@@ -75,6 +107,8 @@ namespace PortabilityLayer
|
|||||||
size_t ResolveCaratChar() const;
|
size_t ResolveCaratChar() const;
|
||||||
void AdjustScrollToCarat();
|
void AdjustScrollToCarat();
|
||||||
void AdjustScrollToTextBounds();
|
void AdjustScrollToTextBounds();
|
||||||
|
size_t IdentifySpanLength(size_t startChar, SpanScanDirection scanDirection) const;
|
||||||
|
static CharacterCategory CategorizeCharacter(uint8_t character);
|
||||||
|
|
||||||
PortabilityLayer::FontFamily *GetFontFamily() const;
|
PortabilityLayer::FontFamily *GetFontFamily() const;
|
||||||
PortabilityLayer::RenderedFont *GetRenderedFont() const;
|
PortabilityLayer::RenderedFont *GetRenderedFont() const;
|
||||||
@@ -94,11 +128,22 @@ namespace PortabilityLayer
|
|||||||
bool m_hasFocus;
|
bool m_hasFocus;
|
||||||
bool m_isMultiLine;
|
bool m_isMultiLine;
|
||||||
bool m_isDraggingSelection;
|
bool m_isDraggingSelection;
|
||||||
|
bool m_isDraggingWords;
|
||||||
size_t m_dragSelectionStartChar;
|
size_t m_dragSelectionStartChar;
|
||||||
|
size_t m_dragSelectionEndChar;
|
||||||
|
uint32_t m_doubleClickTime;
|
||||||
|
Point m_doubleClickPoint;
|
||||||
|
|
||||||
uint16_t m_caratTimer;
|
uint16_t m_caratTimer;
|
||||||
|
|
||||||
CharacterFilterCallback_t m_characterFilter;
|
CharacterFilterCallback_t m_characterFilter;
|
||||||
void *m_characterFilterContext;
|
void *m_characterFilterContext;
|
||||||
|
|
||||||
|
static const CharacterCategorySpan gs_characterCategorySpans[];
|
||||||
|
|
||||||
|
static const int kCopyShortcutKey = 'C';
|
||||||
|
static const int kCutShortcutKey = 'X';
|
||||||
|
static const int kPasteShortcutKey = 'V';
|
||||||
|
static const int kSelectAllShortcutKey = 'A';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -11,5 +11,7 @@ namespace PortabilityLayer
|
|||||||
static void EncodeCodePoint(uint8_t *characters, size_t &outCharactersEmitted, uint32_t codePoint);
|
static void EncodeCodePoint(uint8_t *characters, size_t &outCharactersEmitted, uint32_t codePoint);
|
||||||
|
|
||||||
static bool DecodeToMacRomanPascalStr(const uint8_t *inChars, size_t inSize, uint8_t *outChars, size_t maxOutSize, size_t &outSize);
|
static bool DecodeToMacRomanPascalStr(const uint8_t *inChars, size_t inSize, uint8_t *outChars, size_t maxOutSize, size_t &outSize);
|
||||||
|
|
||||||
|
static const unsigned int kMaxEncodedBytes = 4;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user