mirror of https://github.com/OpenTTD/OpenTTD
(svn r26024) [1.3] -Backport: number of prerequisites for key handling fixes/improvements
parent
c13d1d6362
commit
10fdf41107
|
@ -1498,7 +1498,7 @@ make_cflags_and_ldflags() {
|
|||
LDFLAGS="$LDFLAGS -Wl,--subsystem,windows"
|
||||
fi
|
||||
|
||||
LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32"
|
||||
LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32 -limm32"
|
||||
|
||||
if [ $cc_version -ge 44 ]; then
|
||||
LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++"
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -176,7 +176,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -233,7 +233,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -280,7 +280,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -176,7 +176,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -233,7 +233,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -280,7 +280,7 @@
|
|||
<Culture>0x0809</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -184,7 +184,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
@ -292,7 +292,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -392,7 +392,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -184,7 +184,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
@ -292,7 +292,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -392,7 +392,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -183,7 +183,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
@ -290,7 +290,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -389,7 +389,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -183,7 +183,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
@ -290,7 +290,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
|
@ -389,7 +389,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
AdditionalDependencies="winmm.lib ws2_32.lib imm32.lib libpng.lib zlibstat.lib lzo2.lib liblzma.lib libfreetype2.lib icuuc.lib icuin.lib icudt.lib icule.lib iculx.lib"
|
||||
LinkIncremental="0"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreDefaultLibraryNames="LIBCMT.lib"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "settings_type.h"
|
||||
#include "console_func.h"
|
||||
#include "rev.h"
|
||||
#include "video/video_driver.hpp"
|
||||
|
||||
#include "widgets/console_widget.h"
|
||||
|
||||
|
@ -184,6 +185,7 @@ struct IConsoleWindow : Window
|
|||
~IConsoleWindow()
|
||||
{
|
||||
_iconsole_mode = ICONSOLE_CLOSED;
|
||||
_video_driver->EditBoxLostFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,6 +217,9 @@ struct IConsoleWindow : Window
|
|||
delta = 0;
|
||||
}
|
||||
|
||||
/* If we have a marked area, draw a background highlight. */
|
||||
if (_iconsole_cmdline.marklength != 0) GfxFillRect(this->line_offset + delta + _iconsole_cmdline.markxoffs, this->height - this->line_height, this->line_offset + delta + _iconsole_cmdline.markxoffs + _iconsole_cmdline.marklength, this->height - 1, PC_DARK_RED);
|
||||
|
||||
DrawString(this->line_offset + delta, right, this->height - this->line_height, _iconsole_cmdline.buf, (TextColour)CC_COMMAND, SA_LEFT | SA_FORCE);
|
||||
|
||||
if (_focused_window == this && _iconsole_cmdline.caret) {
|
||||
|
@ -307,10 +312,70 @@ struct IConsoleWindow : Window
|
|||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
virtual void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
|
||||
{
|
||||
if (_iconsole_cmdline.InsertString(str, marked, caret, insert_location, replacement_end)) {
|
||||
IConsoleWindow::scroll = 0;
|
||||
IConsoleResetHistoryPos();
|
||||
this->SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char *GetFocusedText() const
|
||||
{
|
||||
return _iconsole_cmdline.buf;
|
||||
}
|
||||
|
||||
virtual const char *GetCaret() const
|
||||
{
|
||||
return _iconsole_cmdline.buf + _iconsole_cmdline.caretpos;
|
||||
}
|
||||
|
||||
virtual const char *GetMarkedText(size_t *length) const
|
||||
{
|
||||
if (_iconsole_cmdline.markend == 0) return NULL;
|
||||
|
||||
*length = _iconsole_cmdline.markend - _iconsole_cmdline.markpos;
|
||||
return _iconsole_cmdline.buf + _iconsole_cmdline.markpos;
|
||||
}
|
||||
|
||||
virtual Point GetCaretPosition() const
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
Point pt = {this->line_offset + delta + _iconsole_cmdline.caretxoffs, this->height - this->line_height};
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
virtual Rect GetTextBoundingRect(const char *from, const char *to) const
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
|
||||
Point p1 = GetCharPosInString(_iconsole_cmdline.buf, from, FS_NORMAL);
|
||||
Point p2 = from != to ? GetCharPosInString(_iconsole_cmdline.buf, from) : p1;
|
||||
|
||||
Rect r = {this->line_offset + delta + p1.x, this->height - this->line_height, this->line_offset + delta + p2.x, this->height};
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual const char *GetTextCharacterAtPosition(const Point &pt) const
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
|
||||
if (!IsInsideMM(pt.y, this->height - this->line_height, this->height)) return NULL;
|
||||
|
||||
return GetCharAtPosition(_iconsole_cmdline.buf, pt.x - delta);
|
||||
}
|
||||
|
||||
virtual void OnMouseWheel(int wheel)
|
||||
{
|
||||
this->Scroll(-wheel);
|
||||
}
|
||||
|
||||
virtual void OnFocusLost()
|
||||
{
|
||||
_video_driver->EditBoxLostFocus();
|
||||
}
|
||||
};
|
||||
|
||||
int IConsoleWindow::scroll = 0;
|
||||
|
|
|
@ -365,8 +365,8 @@ static inline T ROR(const T x, const uint8 n)
|
|||
* (since it will use hardware swapping if available).
|
||||
* Even though they should return uint16 and uint32, we get
|
||||
* warnings if we don't cast those (why?) */
|
||||
#define BSWAP32(x) ((uint32)Endian32_Swap(x))
|
||||
#define BSWAP16(x) ((uint16)Endian16_Swap(x))
|
||||
#define BSWAP32(x) ((uint32)CFSwapInt32(x))
|
||||
#define BSWAP16(x) ((uint16)CFSwapInt16(x))
|
||||
#elif defined(_MSC_VER)
|
||||
/* MSVC has intrinsics for swapping, resulting in faster code */
|
||||
#define BSWAP32(x) (_byteswap_ulong(x))
|
||||
|
|
15
src/gfx.cpp
15
src/gfx.cpp
|
@ -653,6 +653,21 @@ Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsiz
|
|||
return layout.GetCharPosition(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character from a string that is drawn at a specific position.
|
||||
* @param str String to test.
|
||||
* @param x Position relative to the start of the string.
|
||||
* @param start_fontsize Font size to start the text with.
|
||||
* @return Pointer to the character at the position or NULL if there is no character at the position.
|
||||
*/
|
||||
const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize)
|
||||
{
|
||||
if (x < 0) return NULL;
|
||||
|
||||
Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
|
||||
return layout.GetCharAtPosition(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw single character horizontally centered around (x,y)
|
||||
* @param c Character (glyph) to draw
|
||||
|
|
|
@ -71,6 +71,7 @@ extern Dimension _cur_resolution;
|
|||
extern Palette _cur_palette; ///< Current palette
|
||||
|
||||
void HandleKeypress(uint keycode, WChar key);
|
||||
void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL);
|
||||
void HandleCtrlChanged();
|
||||
void HandleMouseEvents();
|
||||
void CSleep(int milliseconds);
|
||||
|
@ -128,6 +129,7 @@ Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestio
|
|||
Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion);
|
||||
void LoadStringWidthTable(bool monospace = false);
|
||||
Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL);
|
||||
const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = FS_NORMAL);
|
||||
|
||||
void DrawDirtyBlocks();
|
||||
void SetDirtyBlocks(int left, int top, int right, int bottom);
|
||||
|
|
|
@ -735,6 +735,50 @@ Point Layouter::GetCharPosition(const char *ch) const
|
|||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character that is at a position.
|
||||
* @param x Position in the string.
|
||||
* @return Pointer to the character at the position or NULL if no character is at the position.
|
||||
*/
|
||||
const char *Layouter::GetCharAtPosition(int x) const
|
||||
{
|
||||
const ParagraphLayouter::Line *line = *this->Begin();;
|
||||
|
||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
||||
|
||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
||||
/* Not a valid glyph (empty). */
|
||||
if (run->GetGlyphs()[i] == 0xFFFF) continue;
|
||||
|
||||
int begin_x = (int)run->GetPositions()[i * 2];
|
||||
int end_x = (int)run->GetPositions()[i * 2 + 2];
|
||||
|
||||
if (IsInsideMM(x, begin_x, end_x)) {
|
||||
/* Found our glyph, now convert to UTF-8 string index. */
|
||||
size_t index = run->GetGlyphToCharMap()[i];
|
||||
|
||||
size_t cur_idx = 0;
|
||||
for (const char *str = this->string; *str != '\0'; ) {
|
||||
if (cur_idx == index) return str;
|
||||
|
||||
WChar c;
|
||||
size_t len = Utf8Decode(&c, str);
|
||||
#ifdef WITH_ICU
|
||||
/* ICU uses UTF-16 internally which means we need to account for surrogate pairs. */
|
||||
cur_idx += len < 4 ? 1 : 2;
|
||||
#else
|
||||
cur_idx++;
|
||||
#endif
|
||||
str += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a static font instance.
|
||||
*/
|
||||
|
|
|
@ -179,6 +179,7 @@ public:
|
|||
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
|
||||
Dimension GetBounds();
|
||||
Point GetCharPosition(const char *ch) const;
|
||||
const char *GetCharAtPosition(int x) const;
|
||||
|
||||
static void ResetFontCache(FontSize size);
|
||||
static void ResetLineCache();
|
||||
|
|
|
@ -2588,7 +2588,7 @@ struct IndustryCargoesWindow : public Window {
|
|||
delete lst;
|
||||
break;
|
||||
}
|
||||
int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? this->ind_cargo - NUM_INDUSTRYTYPES : -1;
|
||||
int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1;
|
||||
ShowDropDownList(this, lst, selected, WID_IC_CARGO_DROPDOWN, 0, true);
|
||||
break;
|
||||
}
|
||||
|
@ -2605,7 +2605,7 @@ struct IndustryCargoesWindow : public Window {
|
|||
delete lst;
|
||||
break;
|
||||
}
|
||||
int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? this->ind_cargo : -1;
|
||||
int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1;
|
||||
ShowDropDownList(this, lst, selected, WID_IC_IND_DROPDOWN, 0, true);
|
||||
break;
|
||||
}
|
||||
|
|
102
src/misc_gui.cpp
102
src/misc_gui.cpp
|
@ -764,6 +764,9 @@ void QueryString::DrawEditBox(const Window *w, int wid) const
|
|||
|
||||
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
|
||||
|
||||
/* If we have a marked area, draw a background highlight. */
|
||||
if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY);
|
||||
|
||||
DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW);
|
||||
bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid);
|
||||
if (focussed && tb->caret) {
|
||||
|
@ -774,6 +777,105 @@ void QueryString::DrawEditBox(const Window *w, int wid) const
|
|||
_cur_dpi = old_dpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current caret position.
|
||||
* @param w Window the edit box is in.
|
||||
* @param wid Widget index.
|
||||
* @return Top-left location of the caret, relative to the window.
|
||||
*/
|
||||
Point QueryString::GetCaretPosition(const Window *w, int wid) const
|
||||
{
|
||||
const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid);
|
||||
|
||||
assert((wi->type & WWT_MASK) == WWT_EDITBOX);
|
||||
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT);
|
||||
int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT;
|
||||
|
||||
int left = wi->pos_x + (rtl ? clearbtn_width : 0);
|
||||
int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1;
|
||||
|
||||
/* Clamp caret position to be inside out current width. */
|
||||
const Textbuf *tb = &this->text;
|
||||
int delta = min(0, (right - left) - tb->pixels - 10);
|
||||
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
|
||||
|
||||
Point pt = {left + WD_FRAMERECT_LEFT + tb->caretxoffs + delta, wi->pos_y + WD_FRAMERECT_TOP};
|
||||
return pt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bounding rectangle for a range of the query string.
|
||||
* @param w Window the edit box is in.
|
||||
* @param wid Widget index.
|
||||
* @param from Start of the string range.
|
||||
* @param to End of the string range.
|
||||
* @return Rectangle encompassing the string range, relative to the window.
|
||||
*/
|
||||
Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const
|
||||
{
|
||||
const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid);
|
||||
|
||||
assert((wi->type & WWT_MASK) == WWT_EDITBOX);
|
||||
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT);
|
||||
int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT;
|
||||
|
||||
int left = wi->pos_x + (rtl ? clearbtn_width : 0);
|
||||
int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1;
|
||||
|
||||
int top = wi->pos_y + WD_FRAMERECT_TOP;
|
||||
int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM;
|
||||
|
||||
/* Clamp caret position to be inside our current width. */
|
||||
const Textbuf *tb = &this->text;
|
||||
int delta = min(0, (right - left) - tb->pixels - 10);
|
||||
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
|
||||
|
||||
/* Get location of first and last character. */
|
||||
Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL);
|
||||
Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1;
|
||||
|
||||
Rect r = { Clamp(left + p1.x + delta + WD_FRAMERECT_LEFT, left, right), top, Clamp(left + p2.x + delta + WD_FRAMERECT_LEFT, left, right - WD_FRAMERECT_RIGHT), bottom };
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character that is rendered at a position.
|
||||
* @param w Window the edit box is in.
|
||||
* @param wid Widget index.
|
||||
* @param pt Position to test.
|
||||
* @return Pointer to the character at the position or NULL if no character is at the position.
|
||||
*/
|
||||
const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const
|
||||
{
|
||||
const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid);
|
||||
|
||||
assert((wi->type & WWT_MASK) == WWT_EDITBOX);
|
||||
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT);
|
||||
int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT;
|
||||
|
||||
int left = wi->pos_x + (rtl ? clearbtn_width : 0);
|
||||
int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1;
|
||||
|
||||
int top = wi->pos_y + WD_FRAMERECT_TOP;
|
||||
int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM;
|
||||
|
||||
if (!IsInsideMM(pt.y, top, bottom)) return NULL;
|
||||
|
||||
/* Clamp caret position to be inside our current width. */
|
||||
const Textbuf *tb = &this->text;
|
||||
int delta = min(0, (right - left) - tb->pixels - 10);
|
||||
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
|
||||
|
||||
return ::GetCharAtPosition(tb->buf, pt.x - delta - left);
|
||||
}
|
||||
|
||||
void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed)
|
||||
{
|
||||
const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid);
|
||||
|
|
|
@ -108,6 +108,14 @@ typedef unsigned int NSUInteger;
|
|||
#endif /* __LP64__ */
|
||||
#endif /* NSInteger */
|
||||
|
||||
#ifndef CGFLOAT_DEFINED
|
||||
#if __LP64__
|
||||
typedef double CGFloat;
|
||||
#else
|
||||
typedef float CGFloat;
|
||||
#endif /* __LP64__ */
|
||||
#endif /* CGFLOAT_DEFINED */
|
||||
|
||||
/* OS X SDK versions >= 10.5 have a non-const iconv. */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
|
||||
# define HAVE_NON_CONST_ICONV
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "window_func.h"
|
||||
#include "gfx_func.h"
|
||||
#include "querystring_gui.h"
|
||||
#include "video/video_driver.hpp"
|
||||
|
||||
#include "widgets/osk_widget.h"
|
||||
|
||||
|
@ -205,6 +206,7 @@ struct OskWindow : public Window {
|
|||
|
||||
virtual void OnFocusLost()
|
||||
{
|
||||
_video_driver->EditBoxLostFocus();
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -53,6 +53,41 @@ public:
|
|||
void DrawEditBox(const Window *w, int wid) const;
|
||||
void ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed);
|
||||
void HandleEditBox(Window *w, int wid);
|
||||
|
||||
Point GetCaretPosition(const Window *w, int wid) const;
|
||||
Rect GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const;
|
||||
const char *GetCharAtPosition(const Window *w, int wid, const Point &pt) const;
|
||||
|
||||
/**
|
||||
* Get the current text.
|
||||
* @return Current text.
|
||||
*/
|
||||
const char *GetText() const
|
||||
{
|
||||
return this->text.buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position of the caret in the text buffer.
|
||||
* @return Pointer to the caret in the text buffer.
|
||||
*/
|
||||
const char *GetCaret() const
|
||||
{
|
||||
return this->text.buf + this->text.caretpos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently marked text.
|
||||
* @param[out] length Length of the marked text.
|
||||
* @return Begining of the marked area or NULL if no text is marked.
|
||||
*/
|
||||
const char *GetMarkedText(size_t *length) const
|
||||
{
|
||||
if (this->text.markend == 0) return NULL;
|
||||
|
||||
*length = this->text.markend - this->text.markpos;
|
||||
return this->text.buf + this->text.markpos;
|
||||
}
|
||||
};
|
||||
|
||||
void ShowOnScreenKeyboard(Window *parent, int button);
|
||||
|
|
|
@ -67,7 +67,7 @@ const char *SoundDriver_Cocoa::Start(const char * const *parm)
|
|||
requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
|
||||
requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
|
||||
|
||||
MxInitialize(requestedDesc.mSampleRate);
|
||||
MxInitialize((uint)requestedDesc.mSampleRate);
|
||||
|
||||
/* Locate the default output audio unit */
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
|
|
148
src/textbuf.cpp
148
src/textbuf.cpp
|
@ -103,6 +103,7 @@ bool Textbuf::DeleteChar(uint16 keycode)
|
|||
this->UpdateStringIter();
|
||||
this->UpdateWidth();
|
||||
this->UpdateCaretPosition();
|
||||
this->UpdateMarkedText();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -115,6 +116,7 @@ void Textbuf::DeleteAll()
|
|||
memset(this->buf, 0, this->max_bytes);
|
||||
this->bytes = this->chars = 1;
|
||||
this->pixels = this->caretpos = this->caretxoffs = 0;
|
||||
this->markpos = this->markend = this->markxoffs = this->marklength = 0;
|
||||
this->UpdateStringIter();
|
||||
}
|
||||
|
||||
|
@ -138,11 +140,80 @@ bool Textbuf::InsertChar(WChar key)
|
|||
this->UpdateStringIter();
|
||||
this->UpdateWidth();
|
||||
this->UpdateCaretPosition();
|
||||
this->UpdateMarkedText();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a string into the text buffer. If maxwidth of the Textbuf is zero,
|
||||
* we don't care about the visual-length but only about the physical
|
||||
* length of the string.
|
||||
* @param str String to insert.
|
||||
* @param marked Replace the currently marked text with the new text.
|
||||
* @param caret Move the caret to this point in the insertion string.
|
||||
* @param insert_location Position at which to insert the string.
|
||||
* @param replacement_end Replace all characters from #insert_location up to this location with the new string.
|
||||
* @return True on successful change of Textbuf, or false otherwise.
|
||||
*/
|
||||
bool Textbuf::InsertString(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
|
||||
{
|
||||
uint16 insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos;
|
||||
if (insert_location != NULL) {
|
||||
insertpos = insert_location - this->buf;
|
||||
if (insertpos > this->bytes) return false;
|
||||
|
||||
if (replacement_end != NULL) {
|
||||
this->DeleteText(insertpos, replacement_end - this->buf, str == NULL);
|
||||
}
|
||||
} else {
|
||||
if (marked) this->DiscardMarkedText(str == NULL);
|
||||
}
|
||||
|
||||
if (str == NULL) return false;
|
||||
|
||||
uint16 bytes = 0, chars = 0;
|
||||
WChar c;
|
||||
for (const char *ptr = str; (c = Utf8Consume(&ptr)) != '\0';) {
|
||||
if (!IsValidChar(c, this->afilter)) break;
|
||||
|
||||
byte len = Utf8CharLen(c);
|
||||
if (this->bytes + bytes + len > this->max_bytes) break;
|
||||
if (this->chars + chars + 1 > this->max_chars) break;
|
||||
|
||||
bytes += len;
|
||||
chars++;
|
||||
|
||||
/* Move caret if needed. */
|
||||
if (ptr == caret) this->caretpos = insertpos + bytes;
|
||||
}
|
||||
|
||||
if (bytes == 0) return false;
|
||||
|
||||
if (marked) {
|
||||
this->markpos = insertpos;
|
||||
this->markend = insertpos + bytes;
|
||||
}
|
||||
|
||||
memmove(this->buf + insertpos + bytes, this->buf + insertpos, this->bytes - insertpos);
|
||||
memcpy(this->buf + insertpos, str, bytes);
|
||||
|
||||
this->bytes += bytes;
|
||||
this->chars += chars;
|
||||
if (!marked && caret == NULL) this->caretpos += bytes;
|
||||
assert(this->bytes <= this->max_bytes);
|
||||
assert(this->chars <= this->max_chars);
|
||||
this->buf[this->bytes - 1] = '\0'; // terminating zero
|
||||
|
||||
this->UpdateStringIter();
|
||||
this->UpdateWidth();
|
||||
this->UpdateCaretPosition();
|
||||
this->UpdateMarkedText();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard
|
||||
* and append this up to the maximum length (either absolute or screenlength). If maxlength
|
||||
|
@ -155,36 +226,55 @@ bool Textbuf::InsertClipboard()
|
|||
|
||||
if (!GetClipboardContents(utf8_buf, lengthof(utf8_buf))) return false;
|
||||
|
||||
uint16 bytes = 0, chars = 0;
|
||||
WChar c;
|
||||
for (const char *ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
|
||||
if (!IsValidChar(c, this->afilter)) break;
|
||||
return this->InsertString(utf8_buf, false);
|
||||
}
|
||||
|
||||
byte len = Utf8CharLen(c);
|
||||
if (this->bytes + bytes + len > this->max_bytes) break;
|
||||
if (this->chars + chars + 1 > this->max_chars) break;
|
||||
|
||||
bytes += len;
|
||||
chars++;
|
||||
/**
|
||||
* Delete a part of the text.
|
||||
* @param from Start of the text to delete.
|
||||
* @param to End of the text to delete.
|
||||
* @param update Set to true if the internal state should be updated.
|
||||
*/
|
||||
void Textbuf::DeleteText(uint16 from, uint16 to, bool update)
|
||||
{
|
||||
uint c = 0;
|
||||
const char *s = this->buf + from;
|
||||
while (s < this->buf + to) {
|
||||
Utf8Consume(&s);
|
||||
c++;
|
||||
}
|
||||
|
||||
if (bytes == 0) return false;
|
||||
/* Strip marked characters from buffer. */
|
||||
memmove(this->buf + from, this->buf + to, this->bytes - to);
|
||||
this->bytes -= to - from;
|
||||
this->chars -= c;
|
||||
|
||||
memmove(this->buf + this->caretpos + bytes, this->buf + this->caretpos, this->bytes - this->caretpos);
|
||||
memcpy(this->buf + this->caretpos, utf8_buf, bytes);
|
||||
/* Fixup caret if needed. */
|
||||
if (this->caretpos > from) {
|
||||
if (this->caretpos <= to) {
|
||||
this->caretpos = from;
|
||||
} else {
|
||||
this->caretpos -= to - from;
|
||||
}
|
||||
}
|
||||
|
||||
this->bytes += bytes;
|
||||
this->chars += chars;
|
||||
this->caretpos += bytes;
|
||||
assert(this->bytes <= this->max_bytes);
|
||||
assert(this->chars <= this->max_chars);
|
||||
this->buf[this->bytes - 1] = '\0'; // terminating zero
|
||||
if (update) {
|
||||
this->UpdateStringIter();
|
||||
this->UpdateCaretPosition();
|
||||
this->UpdateMarkedText();
|
||||
}
|
||||
}
|
||||
|
||||
this->UpdateStringIter();
|
||||
this->UpdateWidth();
|
||||
this->UpdateCaretPosition();
|
||||
/**
|
||||
* Discard any marked text.
|
||||
* @param update Set to true if the internal state should be updated.
|
||||
*/
|
||||
void Textbuf::DiscardMarkedText(bool update)
|
||||
{
|
||||
if (this->markend == 0) return;
|
||||
|
||||
return true;
|
||||
this->DeleteText(this->markpos, this->markend, update);
|
||||
this->markpos = this->markend = this->markxoffs = this->marklength = 0;
|
||||
}
|
||||
|
||||
/** Update the character iter after the text has changed. */
|
||||
|
@ -207,6 +297,17 @@ void Textbuf::UpdateCaretPosition()
|
|||
this->caretxoffs = this->chars > 1 ? GetCharPosInString(this->buf, this->buf + this->caretpos, FS_NORMAL).x : 0;
|
||||
}
|
||||
|
||||
/** Update pixel positions of the marked text area. */
|
||||
void Textbuf::UpdateMarkedText()
|
||||
{
|
||||
if (this->markend != 0) {
|
||||
this->markxoffs = GetCharPosInString(this->buf, this->buf + this->markpos, FS_NORMAL).x;
|
||||
this->marklength = GetCharPosInString(this->buf, this->buf + this->markend, FS_NORMAL).x - this->markxoffs;
|
||||
} else {
|
||||
this->markxoffs = this->marklength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text navigation with arrow keys left/right.
|
||||
* This defines where the caret will blink and the next character interaction will occur
|
||||
|
@ -342,6 +443,7 @@ void Textbuf::UpdateSize()
|
|||
this->caretpos = this->bytes - 1;
|
||||
this->UpdateStringIter();
|
||||
this->UpdateWidth();
|
||||
this->UpdateMarkedText();
|
||||
|
||||
this->UpdateCaretPosition();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ struct Textbuf {
|
|||
bool caret; ///< is the caret ("_") visible or not
|
||||
uint16 caretpos; ///< the current position of the caret in the buffer, in bytes
|
||||
uint16 caretxoffs; ///< the current position of the caret in pixels
|
||||
uint16 markpos; ///< the start position of the marked area in the buffer, in bytes
|
||||
uint16 markend; ///< the end position of the marked area in the buffer, in bytes
|
||||
uint16 markxoffs; ///< the start position of the marked area in pixels
|
||||
uint16 marklength; ///< the length of the marked area in pixels
|
||||
|
||||
explicit Textbuf(uint16 max_bytes, uint16 max_chars = UINT16_MAX);
|
||||
~Textbuf();
|
||||
|
@ -52,6 +56,7 @@ struct Textbuf {
|
|||
bool InsertClipboard();
|
||||
|
||||
bool InsertChar(uint32 key);
|
||||
bool InsertString(const char *str, bool marked, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL);
|
||||
|
||||
bool DeleteChar(uint16 keycode);
|
||||
bool MovePos(uint16 keycode);
|
||||
|
@ -61,14 +66,19 @@ struct Textbuf {
|
|||
bool HandleCaret();
|
||||
void UpdateSize();
|
||||
|
||||
void DiscardMarkedText(bool update = true);
|
||||
|
||||
private:
|
||||
StringIterator *char_iter;
|
||||
|
||||
bool CanDelChar(bool backspace);
|
||||
|
||||
void DeleteText(uint16 from, uint16 to, bool update);
|
||||
|
||||
void UpdateStringIter();
|
||||
void UpdateWidth();
|
||||
void UpdateCaretPosition();
|
||||
void UpdateMarkedText();
|
||||
};
|
||||
|
||||
#endif /* TEXTBUF_TYPE_H */
|
||||
|
|
|
@ -50,6 +50,11 @@ public:
|
|||
*/
|
||||
/* virtual */ bool AfterBlitterChange();
|
||||
|
||||
/**
|
||||
* An edit box lost the input focus. Abort character compositing if necessary.
|
||||
*/
|
||||
/* virtual */ void EditBoxLostFocus();
|
||||
|
||||
/** Return driver name
|
||||
* @return driver name
|
||||
*/
|
||||
|
@ -227,7 +232,17 @@ uint QZ_ListModes(OTTD_Point *modes, uint max_modes, CGDirectDisplayID display_i
|
|||
@end
|
||||
|
||||
/** Subclass of NSView to fix Quartz rendering and mouse awareness */
|
||||
@interface OTTD_CocoaView : NSView {
|
||||
@interface OTTD_CocoaView : NSView
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
|
||||
# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
|
||||
<NSTextInputClient, NSTextInput>
|
||||
# else
|
||||
<NSTextInputClient>
|
||||
# endif /* MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 */
|
||||
#else
|
||||
<NSTextInput>
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */
|
||||
{
|
||||
CocoaSubdriver *driver;
|
||||
NSTrackingRectTag trackingtag;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "../../blitter/factory.hpp"
|
||||
#include "../../fileio_func.h"
|
||||
#include "../../gfx_func.h"
|
||||
#include "../../window_func.h"
|
||||
#include "../../window_gui.h"
|
||||
|
||||
#import <sys/param.h> /* for MAXPATHLEN */
|
||||
|
||||
|
@ -57,7 +59,7 @@ static bool _cocoa_video_dialog = false;
|
|||
|
||||
CocoaSubdriver *_cocoa_subdriver = NULL;
|
||||
|
||||
static const NSString *OTTDMainLaunchGameEngine = @"ottdmain_launch_game_engine";
|
||||
static NSString *OTTDMainLaunchGameEngine = @"ottdmain_launch_game_engine";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -394,21 +396,12 @@ static CocoaSubdriver *QZ_CreateSubdriver(int width, int height, int bpp, bool f
|
|||
/* OSX 10.7 allows to toggle fullscreen mode differently */
|
||||
if (MacOSVersionIsAtLeast(10, 7, 0)) {
|
||||
ret = QZ_CreateWindowSubdriver(width, height, bpp);
|
||||
}
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)
|
||||
else {
|
||||
if (ret != NULL && fullscreen) ret->ToggleFullscreen();
|
||||
} else {
|
||||
ret = fullscreen ? QZ_CreateFullscreenSubdriver(width, height, bpp) : QZ_CreateWindowSubdriver(width, height, bpp);
|
||||
}
|
||||
#endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) */
|
||||
|
||||
if (ret != NULL) {
|
||||
/* We cannot set any fullscreen mode on OSX 10.7 when not compiled against SDK 10.7 */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
if (fullscreen) { ret->ToggleFullscreen(); }
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != NULL) return ret;
|
||||
if (!fallback) return NULL;
|
||||
|
||||
/* Try again in 640x480 windowed */
|
||||
|
@ -572,6 +565,22 @@ bool VideoDriver_Cocoa::AfterBlitterChange()
|
|||
return this->ChangeResolution(_screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* An edit box lost the input focus. Abort character compositing if necessary.
|
||||
*/
|
||||
void VideoDriver_Cocoa::EditBoxLostFocus()
|
||||
{
|
||||
if (_cocoa_subdriver != NULL) {
|
||||
if ([ _cocoa_subdriver->cocoaview respondsToSelector:@selector(inputContext) ] && [ [ _cocoa_subdriver->cocoaview performSelector:@selector(inputContext) ] respondsToSelector:@selector(discardMarkedText) ]) {
|
||||
[ [ _cocoa_subdriver->cocoaview performSelector:@selector(inputContext) ] performSelector:@selector(discardMarkedText) ];
|
||||
} else {
|
||||
[ [ NSInputManager currentInputManager ] markedTextAbandoned:_cocoa_subdriver->cocoaview ];
|
||||
}
|
||||
}
|
||||
/* Clear any marked string from the current edit box. */
|
||||
HandleTextInput(NULL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch asserts prior to initialization of the videodriver.
|
||||
*
|
||||
|
@ -757,6 +766,43 @@ void cocoaReleaseAutoreleasePool()
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Count the number of UTF-16 code points in a range of an UTF-8 string.
|
||||
* @param from Start of the range.
|
||||
* @param to End of the range.
|
||||
* @return Number of UTF-16 code points in the range.
|
||||
*/
|
||||
static NSUInteger CountUtf16Units(const char *from, const char *to)
|
||||
{
|
||||
NSUInteger i = 0;
|
||||
|
||||
while (from < to) {
|
||||
WChar c;
|
||||
size_t len = Utf8Decode(&c, from);
|
||||
i += len < 4 ? 1 : 2; // Watch for surrogate pairs.
|
||||
from += len;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance an UTF-8 string by a number of equivalent UTF-16 code points.
|
||||
* @param str UTF-8 string.
|
||||
* @param count Number of UTF-16 code points to advance the string by.
|
||||
* @return Advanced string pointer.
|
||||
*/
|
||||
static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
|
||||
{
|
||||
for (NSUInteger i = 0; i < count && *str != '\0'; ) {
|
||||
WChar c;
|
||||
size_t len = Utf8Decode(&c, str);
|
||||
i += len < 4 ? 1 : 2; // Watch for surrogates.
|
||||
str += len;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@implementation OTTD_CocoaView
|
||||
/**
|
||||
|
@ -852,6 +898,200 @@ void cocoaReleaseAutoreleasePool()
|
|||
if (_cocoa_subdriver != NULL) UndrawMouseCursor();
|
||||
_cursor.in_window = false;
|
||||
}
|
||||
|
||||
|
||||
/** Insert the given text at the given range. */
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return;
|
||||
|
||||
NSString *s = [ aString isKindOfClass:[ NSAttributedString class ] ] ? [ aString string ] : (NSString *)aString;
|
||||
|
||||
const char *insert_point = NULL;
|
||||
const char *replace_range = NULL;
|
||||
if (replacementRange.location != NSNotFound) {
|
||||
/* Calculate the part to be replaced. */
|
||||
insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), replacementRange.location);
|
||||
replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length);
|
||||
}
|
||||
|
||||
HandleTextInput(NULL, true);
|
||||
HandleTextInput([ s UTF8String ], false, NULL, insert_point, replace_range);
|
||||
}
|
||||
|
||||
/** Insert the given text at the caret. */
|
||||
- (void)insertText:(id)aString
|
||||
{
|
||||
[ self insertText:aString replacementRange:NSMakeRange(NSNotFound, 0) ];
|
||||
}
|
||||
|
||||
/** Set a new marked text and reposition the caret. */
|
||||
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return;
|
||||
|
||||
NSString *s = [ aString isKindOfClass:[ NSAttributedString class ] ] ? [ aString string ] : (NSString *)aString;
|
||||
|
||||
const char *utf8 = [ s UTF8String ];
|
||||
if (utf8 != NULL) {
|
||||
const char *insert_point = NULL;
|
||||
const char *replace_range = NULL;
|
||||
if (replacementRange.location != NSNotFound) {
|
||||
/* Calculate the part to be replaced. */
|
||||
NSRange marked = [ self markedRange ];
|
||||
insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), replacementRange.location + (marked.location != NSNotFound ? marked.location : 0u));
|
||||
replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length);
|
||||
}
|
||||
|
||||
/* Convert caret index into a pointer in the UTF-8 string. */
|
||||
const char *selection = Utf8AdvanceByUtf16Units(utf8, selRange.location);
|
||||
|
||||
HandleTextInput(utf8, true, selection, insert_point, replace_range);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set a new marked text and reposition the caret. */
|
||||
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
|
||||
{
|
||||
[ self setMarkedText:aString selectedRange:selRange replacementRange:NSMakeRange(NSNotFound, 0) ];
|
||||
}
|
||||
|
||||
/** Unmark the current marked text. */
|
||||
- (void)unmarkText
|
||||
{
|
||||
HandleTextInput(NULL, true);
|
||||
}
|
||||
|
||||
/** Get the caret position. */
|
||||
- (NSRange)selectedRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return NSMakeRange(NSNotFound, 0);
|
||||
|
||||
NSUInteger start = CountUtf16Units(_focused_window->GetFocusedText(), _focused_window->GetCaret());
|
||||
return NSMakeRange(start, 0);
|
||||
}
|
||||
|
||||
/** Get the currently marked range. */
|
||||
- (NSRange)markedRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return NSMakeRange(NSNotFound, 0);
|
||||
|
||||
size_t mark_len;
|
||||
const char *mark = _focused_window->GetMarkedText(&mark_len);
|
||||
if (mark != NULL) {
|
||||
NSUInteger start = CountUtf16Units(_focused_window->GetFocusedText(), mark);
|
||||
NSUInteger len = CountUtf16Units(mark, mark + mark_len);
|
||||
|
||||
return NSMakeRange(start, len);
|
||||
}
|
||||
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
|
||||
/** Is any text marked? */
|
||||
- (BOOL)hasMarkedText
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return NO;
|
||||
|
||||
size_t len;
|
||||
return _focused_window->GetMarkedText(&len) != NULL;
|
||||
}
|
||||
|
||||
/** Get a string corresponding to the given range. */
|
||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return nil;
|
||||
|
||||
NSString *s = [ NSString stringWithUTF8String:_focused_window->GetFocusedText() ];
|
||||
NSRange valid_range = NSIntersectionRange(NSMakeRange(0, [ s length ]), theRange);
|
||||
|
||||
if (actualRange != NULL) *actualRange = valid_range;
|
||||
if (valid_range.length == 0) return nil;
|
||||
|
||||
return [ [ [ NSAttributedString alloc ] initWithString:[ s substringWithRange:valid_range ] ] autorelease ];
|
||||
}
|
||||
|
||||
/** Get a string corresponding to the given range. */
|
||||
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
|
||||
{
|
||||
return [ self attributedSubstringForProposedRange:theRange actualRange:NULL ];
|
||||
}
|
||||
|
||||
/** Get the current edit box string. */
|
||||
- (NSAttributedString *)attributedString
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return [ [ [ NSAttributedString alloc ] initWithString:@"" ] autorelease ];
|
||||
|
||||
return [ [ [ NSAttributedString alloc ] initWithString:[ NSString stringWithUTF8String:_focused_window->GetFocusedText() ] ] autorelease ];
|
||||
}
|
||||
|
||||
/** Get the character that is rendered at the given point. */
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return NSNotFound;
|
||||
|
||||
NSPoint view_pt = [ self convertPoint:[ [ self window ] convertScreenToBase:thePoint ] fromView:nil ];
|
||||
|
||||
Point pt = { (int)view_pt.x, (int)[ self frame ].size.height - (int)view_pt.y };
|
||||
|
||||
const char *ch = _focused_window->GetTextCharacterAtPosition(pt);
|
||||
if (ch == NULL) return NSNotFound;
|
||||
|
||||
return CountUtf16Units(_focused_window->GetFocusedText(), ch);
|
||||
}
|
||||
|
||||
/** Get the bounding rect for the given range. */
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)aRange
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return NSMakeRect(0, 0, 0, 0);
|
||||
|
||||
/* Convert range to UTF-8 string pointers. */
|
||||
const char *start = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location);
|
||||
const char *end = aRange.length != 0 ? Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location + aRange.length) : start;
|
||||
|
||||
/* Get the bounding rect for the text range.*/
|
||||
Rect r = _focused_window->GetTextBoundingRect(start, end);
|
||||
NSRect view_rect = NSMakeRect(_focused_window->left + r.left, [ self frame ].size.height - _focused_window->top - r.bottom, r.right - r.left, r.bottom - r.top);
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
if ([ [ self window ] respondsToSelector:@selector(convertRectToScreen:) ]) {
|
||||
return [ [ self window ] convertRectToScreen:[ self convertRect:view_rect toView:nil ] ];
|
||||
}
|
||||
#endif
|
||||
|
||||
NSRect window_rect = [ self convertRect:view_rect toView:nil ];
|
||||
NSPoint origin = [ [ self window ] convertBaseToScreen:window_rect.origin ];
|
||||
return NSMakeRect(origin.x, origin.y, window_rect.size.width, window_rect.size.height);
|
||||
}
|
||||
|
||||
/** Get the bounding rect for the given range. */
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
return [ self firstRectForCharacterRange:aRange ];
|
||||
}
|
||||
|
||||
/** Get all string attributes that we can process for marked text. */
|
||||
- (NSArray*)validAttributesForMarkedText
|
||||
{
|
||||
return [ NSArray array ];
|
||||
}
|
||||
|
||||
/** Identifier for this text input instance. */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
|
||||
- (long)conversationIdentifier
|
||||
#else
|
||||
- (NSInteger)conversationIdentifier
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Invoke the selector if we implement it. */
|
||||
- (void)doCommandBySelector:(SEL)aSelector
|
||||
{
|
||||
if ([ self respondsToSelector:aSelector ]) [ self performSelector:aSelector ];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -60,11 +60,28 @@ enum RightMouseButtonEmulationState {
|
|||
static unsigned int _current_mods;
|
||||
static bool _tab_is_down;
|
||||
static bool _emulating_right_button;
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
static float _current_magnification;
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
static uint32 _tEvent;
|
||||
#endif
|
||||
|
||||
|
||||
/* Support for touch gestures is only available starting with the
|
||||
* 10.6 SDK, even if it says that support starts in fact with 10.5.2.
|
||||
* Replicate the needed stuff for older SDKs. */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5
|
||||
static const NSUInteger NSEventTypeMagnify = 30;
|
||||
static const NSUInteger NSEventTypeEndGesture = 20;
|
||||
|
||||
@interface NSEvent ()
|
||||
/* This message is valid for events of type NSEventTypeMagnify, on 10.5.2 or later */
|
||||
- (CGFloat)magnification WEAK_IMPORT_ATTRIBUTE;
|
||||
@end
|
||||
#endif
|
||||
|
||||
|
||||
static uint32 GetTick()
|
||||
{
|
||||
struct timeval tim;
|
||||
|
@ -255,8 +272,10 @@ static uint32 QZ_MapKey(unsigned short sym)
|
|||
return key;
|
||||
}
|
||||
|
||||
static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down)
|
||||
static bool QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down)
|
||||
{
|
||||
bool interpret_keys = true;
|
||||
|
||||
switch (keycode) {
|
||||
case QZ_UP: SB(_dirkeys, 1, 1, down); break;
|
||||
case QZ_DOWN: SB(_dirkeys, 3, 1, down); break;
|
||||
|
@ -275,6 +294,21 @@ static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL dow
|
|||
|
||||
if (down) {
|
||||
uint32 pressed_key = QZ_MapKey(keycode);
|
||||
|
||||
static bool console = false;
|
||||
|
||||
if (pressed_key == WKC_BACKQUOTE && unicode == 0) {
|
||||
if (!console) {
|
||||
/* Backquote is a dead key, require a double press for hotkey behaviour (i.e. console). */
|
||||
console = true;
|
||||
return true;
|
||||
} else {
|
||||
/* Second backquote, don't interpret as text input. */
|
||||
interpret_keys = false;
|
||||
}
|
||||
}
|
||||
console = false;
|
||||
|
||||
/* Don't handle normal characters if an edit box has the focus. */
|
||||
if (!EditBoxInGlobalFocus() || ((pressed_key & ~WKC_SPECIAL_KEYS) <= WKC_TAB) || IsInsideMM(pressed_key & ~WKC_SPECIAL_KEYS, WKC_F1, WKC_PAUSE + 1)) {
|
||||
HandleKeypress(pressed_key, unicode);
|
||||
|
@ -283,6 +317,8 @@ static void QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL dow
|
|||
} else {
|
||||
DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
|
||||
}
|
||||
|
||||
return interpret_keys;
|
||||
}
|
||||
|
||||
static void QZ_DoUnsidedModifiers(unsigned int newMods)
|
||||
|
@ -387,7 +423,6 @@ static bool QZ_PollEvent()
|
|||
|
||||
NSString *chars;
|
||||
NSPoint pt;
|
||||
NSText *fieldEditor;
|
||||
switch ([ event type ]) {
|
||||
case NSMouseMoved:
|
||||
case NSOtherMouseDragged:
|
||||
|
@ -504,17 +539,19 @@ static bool QZ_PollEvent()
|
|||
break;
|
||||
}
|
||||
|
||||
fieldEditor = [[ event window ] fieldEditor:YES forObject:nil ];
|
||||
[ fieldEditor setString:@"" ];
|
||||
[ fieldEditor interpretKeyEvents: [ NSArray arrayWithObject:event ] ];
|
||||
|
||||
chars = [ event characters ];
|
||||
if ([ chars length ] == 0) {
|
||||
QZ_KeyEvent([ event keyCode ], 0, YES);
|
||||
if (EditBoxInGlobalFocus()) {
|
||||
if (QZ_KeyEvent([ event keyCode ], 0, YES)) {
|
||||
[ _cocoa_subdriver->cocoaview interpretKeyEvents:[ NSArray arrayWithObject:event ] ];
|
||||
}
|
||||
} else {
|
||||
QZ_KeyEvent([ event keyCode ], [ chars characterAtIndex:0 ], YES);
|
||||
for (uint i = 1; i < [ chars length ]; i++) {
|
||||
QZ_KeyEvent(0, [ chars characterAtIndex:i ], YES);
|
||||
chars = [ event characters ];
|
||||
if ([ chars length ] == 0) {
|
||||
QZ_KeyEvent([ event keyCode ], 0, YES);
|
||||
} else {
|
||||
QZ_KeyEvent([ event keyCode ], [ chars characterAtIndex:0 ], YES);
|
||||
for (uint i = 1; i < [ chars length ]; i++) {
|
||||
QZ_KeyEvent(0, [ chars characterAtIndex:i ], YES);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -547,6 +584,29 @@ static bool QZ_PollEvent()
|
|||
_cursor.v_wheel -= (int)([ event deltaY ] * 5 * _settings_client.gui.scrollwheel_multiplier);
|
||||
break;
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
case NSEventTypeMagnify:
|
||||
/* Pinch open or close gesture. */
|
||||
_current_magnification += [ event magnification ] * 5.0f;
|
||||
|
||||
while (_current_magnification >= 1.0f) {
|
||||
_current_magnification -= 1.0f;
|
||||
_cursor.wheel++;
|
||||
HandleMouseEvents();
|
||||
}
|
||||
while (_current_magnification <= -1.0f) {
|
||||
_current_magnification += 1.0f;
|
||||
_cursor.wheel--;
|
||||
HandleMouseEvents();
|
||||
}
|
||||
break;
|
||||
|
||||
case NSEventTypeEndGesture:
|
||||
/* Gesture ended. */
|
||||
_current_magnification = 0.0f;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NSCursorUpdate:
|
||||
case NSMouseEntered:
|
||||
case NSMouseExited:
|
||||
|
|
|
@ -241,7 +241,7 @@ class FullscreenSubdriver: public CocoaSubdriver {
|
|||
* disable until a replacement can be found. */
|
||||
if (MacOSVersionIsAtLeast(10, 7, 0)) {
|
||||
this->window_buffer = NULL;
|
||||
this->window_pitch = NULL;
|
||||
this->window_pitch = 0;
|
||||
} else {
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
|
||||
this->window_buffer = CGDisplayBaseAddress(this->display_id);
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
#include "../../core/math_func.hpp"
|
||||
#include "../../gfx_func.h"
|
||||
|
||||
/* On some old versions of MAC OS this may not be defined.
|
||||
* Those versions generally only produce code for PPC. So it should be safe to
|
||||
* set this to 0. */
|
||||
#ifndef kCGBitmapByteOrder32Host
|
||||
#define kCGBitmapByteOrder32Host 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Important notice regarding all modifications!!!!!!!
|
||||
* There are certain limitations because the file is objective C++.
|
||||
|
@ -144,7 +151,7 @@ static CGColorSpaceRef QZ_GetCorrectColorSpace()
|
|||
/* Calculate total area we are blitting */
|
||||
uint32 blitArea = 0;
|
||||
for (int n = 0; n < dirtyRectCount; n++) {
|
||||
blitArea += dirtyRects[n].size.width * dirtyRects[n].size.height;
|
||||
blitArea += (uint32)(dirtyRects[n].size.width * dirtyRects[n].size.height);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -240,12 +247,12 @@ void WindowQuartzSubdriver::GetDeviceInfo()
|
|||
*/
|
||||
bool WindowQuartzSubdriver::ToggleFullscreen()
|
||||
{
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
[this->window toggleFullScreen:this->window];
|
||||
return true;
|
||||
#else
|
||||
if ([ this->window respondsToSelector:@selector(toggleFullScreen:) ]) {
|
||||
[ this->window performSelector:@selector(toggleFullScreen:) withObject:this->window ];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WindowQuartzSubdriver::SetVideoMode(int width, int height, int bpp)
|
||||
|
@ -280,15 +287,17 @@ bool WindowQuartzSubdriver::SetVideoMode(int width, int height, int bpp)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
|
||||
/* Add built in full-screen support when available (OS X 10.7 and higher)
|
||||
* This code actually compiles for 10.5 and later, but only makes sense in conjunction
|
||||
* with the quartz fullscreen support as found only in 10.7 and later
|
||||
*/
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
if ([this->window respondsToSelector:@selector(toggleFullScreen:)]) {
|
||||
/* Constants needed to build on pre-10.7 systems. Source: NSWindow documentation. */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
|
||||
/* Constants needed to build on pre-10.7 SDKs. Source: NSWindow documentation. */
|
||||
const int NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7;
|
||||
const int NSWindowFullScreenButton = 7;
|
||||
#endif
|
||||
|
||||
NSWindowCollectionBehavior behavior = [ this->window collectionBehavior ];
|
||||
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
|
@ -326,10 +335,10 @@ bool WindowQuartzSubdriver::SetVideoMode(int width, int height, int bpp)
|
|||
[ this->window setContentSize:contentRect.size ];
|
||||
|
||||
/* Ensure frame height - title bar height >= view height */
|
||||
contentRect.size.height = Clamp(height, 0, [ this->window frame ].size.height - 22 /* 22 is the height of title bar of window*/);
|
||||
contentRect.size.height = Clamp(height, 0, (int)[ this->window frame ].size.height - 22 /* 22 is the height of title bar of window*/);
|
||||
|
||||
if (this->cocoaview != nil) {
|
||||
height = contentRect.size.height;
|
||||
height = (int)contentRect.size.height;
|
||||
[ this->cocoaview setFrameSize:contentRect.size ];
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +523,7 @@ NSPoint WindowQuartzSubdriver::GetMouseLocation(NSEvent *event)
|
|||
{
|
||||
NSPoint pt;
|
||||
|
||||
if (event.window == nil) {
|
||||
if ( [ event window ] == nil) {
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
if ([ this->cocoaview respondsToSelector:@selector(convertRectFromScreen:) ]) {
|
||||
pt = [ this->cocoaview convertPoint:[ [ this->cocoaview window ] convertRectFromScreen:NSMakeRect([ event locationInWindow ].x, [ event locationInWindow ].y, 0, 0) ].origin fromView:nil ];
|
||||
|
@ -560,8 +569,8 @@ bool WindowQuartzSubdriver::WindowResized()
|
|||
|
||||
NSRect newframe = [ this->cocoaview frame ];
|
||||
|
||||
this->window_width = newframe.size.width;
|
||||
this->window_height = newframe.size.height;
|
||||
this->window_width = (int)newframe.size.width;
|
||||
this->window_height = (int)newframe.size.height;
|
||||
|
||||
/* Create Core Graphics Context */
|
||||
free(this->window_buffer);
|
||||
|
|
|
@ -73,6 +73,11 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* An edit box lost the input focus. Abort character compositing if necessary.
|
||||
*/
|
||||
virtual void EditBoxLostFocus() {}
|
||||
};
|
||||
|
||||
/** Base of the factory for the video drivers. */
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#include "../texteff.hpp"
|
||||
#include "../thread/thread.h"
|
||||
#include "../progress.h"
|
||||
#include "../window_gui.h"
|
||||
#include "../window_func.h"
|
||||
#include "win32_v.h"
|
||||
#include <windows.h>
|
||||
#include <imm.h>
|
||||
|
||||
/* Missing define in MinGW headers. */
|
||||
#ifndef MAPVK_VK_TO_CHAR
|
||||
|
@ -50,6 +52,9 @@ bool _window_maximize;
|
|||
uint _display_hz;
|
||||
uint _fullscreen_bpp;
|
||||
static Dimension _bck_resolution;
|
||||
#if !defined(WINCE) || _WIN32_WCE >= 0x400
|
||||
DWORD _imm_props;
|
||||
#endif
|
||||
|
||||
/** Whether the drawing is/may be done in a separate thread. */
|
||||
static bool _draw_threaded;
|
||||
|
@ -498,6 +503,152 @@ static LRESULT HandleCharMsg(uint keycode, WChar charcode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(WINCE) || _WIN32_WCE >= 0x400
|
||||
/** Should we draw the composition string ourself, i.e is this a normal IME? */
|
||||
static bool DrawIMECompositionString()
|
||||
{
|
||||
return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
|
||||
}
|
||||
|
||||
/** Set position of the composition window to the caret position. */
|
||||
static void SetCompositionPos(HWND hwnd)
|
||||
{
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
if (hIMC != NULL) {
|
||||
COMPOSITIONFORM cf;
|
||||
cf.dwStyle = CFS_POINT;
|
||||
|
||||
if (EditBoxInGlobalFocus()) {
|
||||
/* Get caret position. */
|
||||
Point pt = _focused_window->GetCaretPosition();
|
||||
cf.ptCurrentPos.x = _focused_window->left + pt.x;
|
||||
cf.ptCurrentPos.y = _focused_window->top + pt.y;
|
||||
} else {
|
||||
cf.ptCurrentPos.x = 0;
|
||||
cf.ptCurrentPos.y = 0;
|
||||
}
|
||||
ImmSetCompositionWindow(hIMC, &cf);
|
||||
}
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
}
|
||||
|
||||
/** Set the position of the candidate window. */
|
||||
static void SetCandidatePos(HWND hwnd)
|
||||
{
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
if (hIMC != NULL) {
|
||||
CANDIDATEFORM cf;
|
||||
cf.dwIndex = 0;
|
||||
cf.dwStyle = CFS_EXCLUDE;
|
||||
|
||||
if (EditBoxInGlobalFocus()) {
|
||||
Point pt = _focused_window->GetCaretPosition();
|
||||
cf.ptCurrentPos.x = _focused_window->left + pt.x;
|
||||
cf.ptCurrentPos.y = _focused_window->top + pt.y;
|
||||
if (_focused_window->window_class == WC_CONSOLE) {
|
||||
cf.rcArea.left = _focused_window->left;
|
||||
cf.rcArea.top = _focused_window->top;
|
||||
cf.rcArea.right = _focused_window->left + _focused_window->width;
|
||||
cf.rcArea.bottom = _focused_window->top + _focused_window->height;
|
||||
} else {
|
||||
cf.rcArea.left = _focused_window->left + _focused_window->nested_focus->pos_x;
|
||||
cf.rcArea.top = _focused_window->top + _focused_window->nested_focus->pos_y;
|
||||
cf.rcArea.right = cf.rcArea.left + _focused_window->nested_focus->current_x;
|
||||
cf.rcArea.bottom = cf.rcArea.top + _focused_window->nested_focus->current_y;
|
||||
}
|
||||
} else {
|
||||
cf.ptCurrentPos.x = 0;
|
||||
cf.ptCurrentPos.y = 0;
|
||||
SetRectEmpty(&cf.rcArea);
|
||||
}
|
||||
ImmSetCandidateWindow(hIMC, &cf);
|
||||
}
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
}
|
||||
|
||||
/** Handle WM_IME_COMPOSITION messages. */
|
||||
static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
|
||||
if (hIMC != NULL) {
|
||||
if (lParam & GCS_RESULTSTR) {
|
||||
/* Read result string from the IME. */
|
||||
LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0); // Length is always in bytes, even in UNICODE build.
|
||||
TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR));
|
||||
len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str, len);
|
||||
str[len / sizeof(TCHAR)] = '\0';
|
||||
|
||||
/* Transmit text to windowing system. */
|
||||
if (len > 0) {
|
||||
HandleTextInput(NULL, true); // Clear marked string.
|
||||
HandleTextInput(FS2OTTD(str));
|
||||
}
|
||||
SetCompositionPos(hwnd);
|
||||
|
||||
/* Don't pass the result string on to the default window proc. */
|
||||
lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
|
||||
}
|
||||
|
||||
if ((lParam & GCS_COMPSTR) && DrawIMECompositionString()) {
|
||||
/* Read composition string from the IME. */
|
||||
LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0); // Length is always in bytes, even in UNICODE build.
|
||||
TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR));
|
||||
len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len);
|
||||
str[len / sizeof(TCHAR)] = '\0';
|
||||
|
||||
if (len > 0) {
|
||||
static char utf8_buf[1024];
|
||||
convert_from_fs(str, utf8_buf, lengthof(utf8_buf));
|
||||
|
||||
/* Convert caret position from bytes in the input string to a position in the UTF-8 encoded string. */
|
||||
LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0);
|
||||
const char *caret = utf8_buf;
|
||||
for (const TCHAR *c = str; *c != '\0' && *caret != '\0' && caret_bytes > 0; c++, caret_bytes--) {
|
||||
/* Skip DBCS lead bytes or leading surrogates. */
|
||||
#ifdef UNICODE
|
||||
if (Utf16IsLeadSurrogate(*c)) {
|
||||
#else
|
||||
if (IsDBCSLeadByte(*c)) {
|
||||
#endif
|
||||
c++;
|
||||
caret_bytes--;
|
||||
}
|
||||
Utf8Consume(&caret);
|
||||
}
|
||||
|
||||
HandleTextInput(utf8_buf, true, caret);
|
||||
} else {
|
||||
HandleTextInput(NULL, true);
|
||||
}
|
||||
|
||||
lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
|
||||
}
|
||||
}
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
|
||||
return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
|
||||
}
|
||||
|
||||
/** Clear the current composition string. */
|
||||
static void CancelIMEComposition(HWND hwnd)
|
||||
{
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
/* Clear any marked string from the current edit box. */
|
||||
HandleTextInput(NULL, true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static bool DrawIMECompositionString() { return false; }
|
||||
static void SetCompositionPos(HWND hwnd) {}
|
||||
static void SetCandidatePos(HWND hwnd) {}
|
||||
static void CancelIMEComposition(HWND hwnd) {}
|
||||
|
||||
#endif /* !defined(WINCE) || _WIN32_WCE >= 0x400 */
|
||||
|
||||
static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static uint32 keycode = 0;
|
||||
|
@ -507,6 +658,10 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
switch (msg) {
|
||||
case WM_CREATE:
|
||||
SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
|
||||
SetCompositionPos(hwnd);
|
||||
#if !defined(WINCE) || _WIN32_WCE >= 0x400
|
||||
_imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case WM_ENTERSIZEMOVE:
|
||||
|
@ -633,6 +788,33 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
}
|
||||
|
||||
#if !defined(WINCE) || _WIN32_WCE >= 0x400
|
||||
case WM_INPUTLANGCHANGE:
|
||||
_imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
|
||||
break;
|
||||
|
||||
case WM_IME_SETCONTEXT:
|
||||
/* Don't show the composition window if we draw the string ourself. */
|
||||
if (DrawIMECompositionString()) lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
||||
break;
|
||||
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
SetCompositionPos(hwnd);
|
||||
if (DrawIMECompositionString()) return 0;
|
||||
break;
|
||||
|
||||
case WM_IME_COMPOSITION:
|
||||
return HandleIMEComposition(hwnd, wParam, lParam);
|
||||
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
/* Clear any pending composition string. */
|
||||
HandleTextInput(NULL, true);
|
||||
if (DrawIMECompositionString()) return 0;
|
||||
break;
|
||||
|
||||
case WM_IME_NOTIFY:
|
||||
if (wParam == IMN_OPENCANDIDATE) SetCandidatePos(hwnd);
|
||||
break;
|
||||
|
||||
#if !defined(UNICODE)
|
||||
case WM_IME_CHAR:
|
||||
if (GB(wParam, 8, 8) != 0) {
|
||||
|
@ -817,6 +999,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
|
||||
case WM_SETFOCUS:
|
||||
_wnd.has_focus = true;
|
||||
SetCompositionPos(hwnd);
|
||||
break;
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
|
@ -1172,3 +1355,10 @@ bool VideoDriver_Win32::AfterBlitterChange()
|
|||
{
|
||||
return AllocateDibSection(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen);
|
||||
}
|
||||
|
||||
void VideoDriver_Win32::EditBoxLostFocus()
|
||||
{
|
||||
CancelIMEComposition(_wnd.main_wnd);
|
||||
SetCompositionPos(_wnd.main_wnd);
|
||||
SetCandidatePos(_wnd.main_wnd);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
|
||||
/* virtual */ bool ClaimMousePointer();
|
||||
|
||||
/* virtual */ void EditBoxLostFocus();
|
||||
|
||||
/* virtual */ const char *GetName() const { return "win32"; }
|
||||
|
||||
bool MakeWindow(bool full_screen);
|
||||
|
|
140
src/window.cpp
140
src/window.cpp
|
@ -33,6 +33,7 @@
|
|||
#include "statusbar_gui.h"
|
||||
#include "error.h"
|
||||
#include "game/game.hpp"
|
||||
#include "video/video_driver.hpp"
|
||||
|
||||
/** Values for _settings_client.gui.auto_scrolling */
|
||||
enum ViewportAutoscrolling {
|
||||
|
@ -249,6 +250,89 @@ QueryString *Window::GetQueryString(uint widnum)
|
|||
return query != this->querystrings.End() ? query->second : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current input text if an edit box has the focus.
|
||||
* @return The currently focused input text or NULL if no input focused.
|
||||
*/
|
||||
/* virtual */ const char *Window::GetFocusedText() const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetText();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string at the caret if an edit box has the focus.
|
||||
* @return The text at the caret or NULL if no edit box is focused.
|
||||
*/
|
||||
/* virtual */ const char *Window::GetCaret() const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetCaret();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range of the currently marked input text.
|
||||
* @param[out] length Length of the marked text.
|
||||
* @return Pointer to the start of the marked text or NULL if no text is marked.
|
||||
*/
|
||||
/* virtual */ const char *Window::GetMarkedText(size_t *length) const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current caret position if an edit box has the focus.
|
||||
* @return Top-left location of the caret, relative to the window.
|
||||
*/
|
||||
/* virtual */ Point Window::GetCaretPosition() const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index);
|
||||
}
|
||||
|
||||
Point pt = {0, 0};
|
||||
return pt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bounding rectangle for a text range if an edit box has the focus.
|
||||
* @param from Start of the string range.
|
||||
* @param to End of the string range.
|
||||
* @return Rectangle encompassing the string range, relative to the window.
|
||||
*/
|
||||
/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to);
|
||||
}
|
||||
|
||||
Rect r = {0, 0, 0, 0};
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character that is rendered at a position by the focused edit box.
|
||||
* @param pt The position to test.
|
||||
* @return Pointer to the character at the position or NULL if no character is at the position.
|
||||
*/
|
||||
/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) {
|
||||
return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the window that has the focus
|
||||
|
@ -293,6 +377,8 @@ bool EditBoxInGlobalFocus()
|
|||
void Window::UnfocusFocusedWidget()
|
||||
{
|
||||
if (this->nested_focus != NULL) {
|
||||
if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus();
|
||||
|
||||
/* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
|
||||
this->nested_focus->SetDirty(this);
|
||||
this->nested_focus = NULL;
|
||||
|
@ -315,11 +401,20 @@ bool Window::SetFocusedWidget(int widget_index)
|
|||
|
||||
/* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
|
||||
this->nested_focus->SetDirty(this);
|
||||
if (this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus();
|
||||
}
|
||||
this->nested_focus = this->GetWidget<NWidgetCore>(widget_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when window looses focus
|
||||
*/
|
||||
void Window::OnFocusLost()
|
||||
{
|
||||
if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) _video_driver->EditBoxLostFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled/disabled status of a list of widgets.
|
||||
* By default, widgets are enabled.
|
||||
|
@ -823,7 +918,10 @@ Window::~Window()
|
|||
if (_last_scroll_window == this) _last_scroll_window = NULL;
|
||||
|
||||
/* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */
|
||||
if (_focused_window == this) _focused_window = NULL;
|
||||
if (_focused_window == this) {
|
||||
this->OnFocusLost();
|
||||
_focused_window = NULL;
|
||||
}
|
||||
|
||||
this->DeleteChildWindows();
|
||||
|
||||
|
@ -2299,9 +2397,14 @@ EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode)
|
|||
break;
|
||||
|
||||
case QueryString::ACTION_CLEAR:
|
||||
query->text.DeleteAll();
|
||||
this->SetWidgetDirty(wid);
|
||||
this->OnEditboxChanged(wid);
|
||||
if (query->text.bytes <= 1) {
|
||||
/* If already empty, unfocus instead */
|
||||
this->UnfocusFocusedWidget();
|
||||
} else {
|
||||
query->text.DeleteAll();
|
||||
this->SetWidgetDirty(wid);
|
||||
this->OnEditboxChanged(wid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2372,6 +2475,35 @@ void HandleCtrlChanged()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a text string at the cursor position into the edit box widget.
|
||||
* @param wid Edit box widget.
|
||||
* @param str Text string to insert.
|
||||
*/
|
||||
/* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
|
||||
{
|
||||
QueryString *query = this->GetQueryString(wid);
|
||||
if (query == NULL) return;
|
||||
|
||||
if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) {
|
||||
this->SetWidgetDirty(wid);
|
||||
this->OnEditboxChanged(wid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text input.
|
||||
* @param str Text string to input.
|
||||
* @param marked Is the input a marked composition string from an IME?
|
||||
* @param caret Move the caret to this point in the insertion string.
|
||||
*/
|
||||
void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
|
||||
{
|
||||
if (!EditBoxInGlobalFocus()) return;
|
||||
|
||||
_focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local counter that is incremented each time an mouse input event is detected.
|
||||
* The counter is used to stop auto-scrolling.
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "window_type.h"
|
||||
#include "company_type.h"
|
||||
#include "core/geometry_type.hpp"
|
||||
|
||||
Window *FindWindowById(WindowClass cls, WindowNumber number);
|
||||
Window *FindWindowByClass(WindowClass cls);
|
||||
|
@ -53,5 +54,6 @@ void DeleteWindowById(WindowClass cls, WindowNumber number, bool force = true);
|
|||
void DeleteWindowByClass(WindowClass cls);
|
||||
|
||||
bool EditBoxInGlobalFocus();
|
||||
Point GetCaretPosition();
|
||||
|
||||
#endif /* WINDOW_FUNC_H */
|
||||
|
|
|
@ -323,6 +323,13 @@ public:
|
|||
const QueryString *GetQueryString(uint widnum) const;
|
||||
QueryString *GetQueryString(uint widnum);
|
||||
|
||||
virtual const char *GetFocusedText() const;
|
||||
virtual const char *GetCaret() const;
|
||||
virtual const char *GetMarkedText(size_t *length) const;
|
||||
virtual Point GetCaretPosition() const;
|
||||
virtual Rect GetTextBoundingRect(const char *from, const char *to) const;
|
||||
virtual const char *GetTextCharacterAtPosition(const Point &pt) const;
|
||||
|
||||
void InitNested(const WindowDesc *desc, WindowNumber number = 0);
|
||||
void CreateNestedTree(const WindowDesc *desc, bool fill_nested = true);
|
||||
void FinishInitNested(const WindowDesc *desc, WindowNumber window_number = 0);
|
||||
|
@ -467,6 +474,7 @@ public:
|
|||
bool SetFocusedWidget(int widget_index);
|
||||
|
||||
EventState HandleEditBoxKey(int wid, WChar key, uint16 keycode);
|
||||
virtual void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end);
|
||||
|
||||
void HandleButtonClick(byte widget);
|
||||
int GetRowFromWidget(int clickpos, int widget, int padding, int line_height = -1) const;
|
||||
|
@ -559,10 +567,7 @@ public:
|
|||
*/
|
||||
virtual void OnFocus() {}
|
||||
|
||||
/**
|
||||
* Called when window looses focus
|
||||
*/
|
||||
virtual void OnFocusLost() {}
|
||||
virtual void OnFocusLost();
|
||||
|
||||
/**
|
||||
* A key has been pressed.
|
||||
|
|
Loading…
Reference in New Issue