Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextBox 、TextArea を異体字に対応 #1153

Open
wants to merge 1 commit into
base: v6_develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Siv3D/include/Siv3D/TextAreaEditState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ namespace s3d

Array<Glyph> glyphs;

Array<size_t> charIndices;

Array<std::pair<uint16, uint16>> glyphPositions;

struct ClipInfo
Expand Down
78 changes: 47 additions & 31 deletions Siv3D/src/Siv3D/SimpleGUI/SivSimpleGUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,13 @@ namespace s3d
const double width = Max(_width, MinTextBoxWidth);
const RectF region{ Arg::center = center, Max(width, MinTextBoxWidth), TextBoxHeight };

// グリフ
const auto glyphs = font.getGlyphs(text.text);

// グリフに対応する文字のインデックス
auto charIndices = font.getGlyphClusters(text.text, UseFallback::No, Ligature::No).map([](const auto& cluster) { return cluster.pos; });
charIndices.push_back(text.text.size());

// マウスカーソルを IBeam にする
if (enabled && Cursor::OnClientRect() && region.mouseOver())
{
Expand All @@ -841,18 +848,20 @@ namespace s3d
// カーソルの位置を計算する
{
const double posX = (Cursor::PosF().x - (region.x + 8));
size_t index = 0;
size_t index = text.text.size();
double pos = 0.0;

for (const auto& advance : font(text.text).getXAdvances())
for (size_t i = 0; i < glyphs.size(); ++i)
{
const double advance = glyphs[i].xAdvance;

if (posX <= (pos + (advance / 2)))
{
index = charIndices[i];
break;
}

pos += advance;
++index;
}

text.cursorPos = index;
Expand Down Expand Up @@ -912,15 +921,15 @@ namespace s3d
if ((0 < text.cursorPos)
&& (KeyLeft.down() || ((SecondsF{ 0.33 } < KeyLeft.pressedDuration()) && (SecondsF{ 0.06 } < text.leftPressStopwatch))))
{
--text.cursorPos;
text.cursorPos = *std::lower_bound(charIndices.rbegin(), charIndices.rend(), text.cursorPos - 1, std::greater{});
text.leftPressStopwatch.restart();
}

// [→] キー
if ((text.cursorPos < text.text.size())
&& (KeyRight.down() || ((SecondsF{ 0.33 } < KeyRight.pressedDuration()) && (SecondsF{ 0.06 } < text.rightPressStopwatch))))
{
++text.cursorPos;
text.cursorPos = *std::lower_bound(charIndices.begin(), charIndices.end(), text.cursorPos + 1);
text.rightPressStopwatch.restart();
}
}
Expand Down Expand Up @@ -979,22 +988,27 @@ namespace s3d
{
const ScopedCustomShader2D shader{ pixelShader };
Vec2 penPos = textPos;
const Array<Glyph> glyphs = font.getGlyphs(text.text);

for (auto&& [index, glyph] : Indexed(glyphs))
{
const double xAdvance = glyph.xAdvance;
const Vec2 glyphPos = (penPos + glyph.getOffset());

glyph.texture.draw(glyphPos, textColor);
penPos.x += xAdvance;

// テキストカーソルの位置の計算を計算する
if (text.active && (text.cursorPos == (index + 1)))
if (text.active && (text.cursorPos == charIndices[index]))
{
cursorPosX = penPos.x;
editingTextPos = penPos;
}

glyph.texture.draw(glyphPos, textColor);
penPos.x += xAdvance;
}

if (text.active && (text.cursorPos == text.text.size()))
{
cursorPosX = penPos.x;
editingTextPos = penPos;
}
}

Expand Down Expand Up @@ -1254,7 +1268,7 @@ namespace s3d
}

// テキストの描画位置のオフセットを決定する
if ((index + 1) == text.cursorPos)
if (text.charIndices[index + 1] == text.cursorPos)
{
const double d1 = ((penPos.y + fontHeight + newScrollY) - textRenderRegionBottomY);
const double d2 = (textRenderRegion.y - (penPos.y + newScrollY));
Expand Down Expand Up @@ -1342,7 +1356,7 @@ namespace s3d
}

// テキストカーソルの位置の計算を計算する
if (text.active && (text.cursorPos == (index + 1)))
if (text.active && (text.cursorPos == text.charIndices[index + 1]))
{
double yBegin = 0.0, yEnd = 0.0;

Expand Down Expand Up @@ -1456,11 +1470,11 @@ namespace s3d
# endif
) // [home]: 行頭へ
{
for (int32 i = (static_cast<int32>(text.cursorPos) - 1); 0 <= i; --i)
for (int32 i = (static_cast<int32>(std::lower_bound(text.charIndices.begin(), text.charIndices.end(), text.cursorPos) - text.charIndices.begin()) - 1); 0 <= i; --i)
{
if (text.glyphs[i].codePoint == '\n')
{
text.cursorPos = (i + 1);
text.cursorPos = text.charIndices[i + 1];
text.cursorStopwatch.restart();
text.refreshScroll = true;
break;
Expand Down Expand Up @@ -1490,7 +1504,7 @@ namespace s3d
# endif
) // [end]: 行末へ
{
for (size_t i = text.cursorPos; i <= text.text.size(); ++i)
for (size_t i = (std::lower_bound(text.charIndices.begin(), text.charIndices.end(), text.cursorPos) - text.charIndices.begin()); i <= text.glyphs.size(); ++i)
{
if (i == text.text.size())
{
Expand All @@ -1501,7 +1515,7 @@ namespace s3d
}
else if (text.glyphs[i].codePoint == '\n')
{
text.cursorPos = i;
text.cursorPos = text.charIndices[i];
text.cursorStopwatch.restart();
text.refreshScroll = true;
break;
Expand All @@ -1513,7 +1527,7 @@ namespace s3d
if ((0 < text.cursorPos)
&& (KeyLeft.down() || ((SecondsF{ 0.33 } < KeyLeft.pressedDuration()) && (SecondsF{ 0.06 } < text.leftPressStopwatch))))
{
--text.cursorPos;
text.cursorPos = *std::lower_bound(text.charIndices.rbegin(), text.charIndices.rend(), text.cursorPos - 1, std::greater{});
text.leftPressStopwatch.restart();
text.refreshScroll = true;
}
Expand All @@ -1522,20 +1536,21 @@ namespace s3d
if ((text.cursorPos < text.text.size())
&& (KeyRight.down() || ((SecondsF{ 0.33 } < KeyRight.pressedDuration()) && (SecondsF{ 0.06 } < text.rightPressStopwatch))))
{
++text.cursorPos;
text.cursorPos = *std::lower_bound(text.charIndices.begin(), text.charIndices.end(), text.cursorPos + 1);
text.rightPressStopwatch.restart();
text.refreshScroll = true;
}

// [↑] キーでテキストカーソルを上に移動させる
if (KeyUp.down() || ((SecondsF{ 0.33 } < KeyUp.pressedDuration()) && (SecondsF{ 0.06 } < text.upPressStopwatch)))
{
const int32 currentRow = (text.cursorPos ? text.glyphPositions[text.cursorPos - 1].first : 0);
const int32 currentColumn = (text.cursorPos ? text.glyphPositions[text.cursorPos - 1].second : 0);
const size_t index = (std::lower_bound(text.charIndices.begin(), text.charIndices.end(), text.cursorPos) - text.charIndices.begin());
const int32 currentRow = (index ? text.glyphPositions[index - 1].first : 0);
const int32 currentColumn = (index ? text.glyphPositions[index - 1].second : 0);

if (0 < currentRow)
{
for (int32 i = (static_cast<int32>(text.cursorPos) - 1); 0 <= i; --i)
for (int32 i = (static_cast<int32>(index) - 1); 0 <= i; --i)
{
if (i == 0)
{
Expand All @@ -1551,13 +1566,13 @@ namespace s3d
{
if ((row + 1) < currentRow)
{
text.cursorPos = (i + 1);
text.cursorPos = text.charIndices[i + 1];
break;
}

if (column <= currentColumn)
{
text.cursorPos = i;
text.cursorPos = text.charIndices[i];
break;
}
}
Expand All @@ -1571,13 +1586,14 @@ namespace s3d
// [↓] キーでテキストカーソルを下に移動させる
if (KeyDown.down() || ((SecondsF{ 0.33 } < KeyDown.pressedDuration()) && (SecondsF{ 0.06 } < text.downPressStopwatch)))
{
const size_t index = (std::lower_bound(text.charIndices.begin(), text.charIndices.end(), text.cursorPos) - text.charIndices.begin());
const int32 maxCursorIndex = static_cast<int32>(text.glyphPositions.size());
const int32 currentRow = (text.cursorPos ? text.glyphPositions[text.cursorPos - 1].first : 0);
const int32 currentColumn = (text.cursorPos ? text.glyphPositions[text.cursorPos - 1].second : 0);
const int32 currentRow = (index ? text.glyphPositions[index - 1].first : 0);
const int32 currentColumn = (index ? text.glyphPositions[index - 1].second : 0);

if (currentRow < (text.glyphPositions.back().first))
{
for (int32 i = (static_cast<int32>(text.cursorPos) + 1); i <= maxCursorIndex; ++i)
for (int32 i = (static_cast<int32>(index) + 1); i <= maxCursorIndex; ++i)
{
const auto& glyphPosition = text.glyphPositions[i - 1];
const int32 row = glyphPosition.first;
Expand All @@ -1587,20 +1603,20 @@ namespace s3d
{
if ((currentRow + 1) < row)
{
text.cursorPos = (i - 1);
text.cursorPos = text.charIndices[i - 1];
break;
}

if (currentColumn <= column)
{
text.cursorPos = i;
text.cursorPos = text.charIndices[i];
break;
}
}

if (i == maxCursorIndex)
{
text.cursorPos = maxCursorIndex;
text.cursorPos = text.text.size();
break;
}
}
Expand All @@ -1618,7 +1634,7 @@ namespace s3d
{
if (text.clipInfos)
{
text.cursorPos = text.clipInfos.front().index;
text.cursorPos = text.charIndices[text.clipInfos.front().index];
}

// 最後の行の文字をマーク
Expand Down Expand Up @@ -1663,7 +1679,7 @@ namespace s3d

if (rect.intersects(cursorPos))
{
text.cursorPos = (clipInfo.index + ((glyph.xAdvance / 2) <= (cursorPos.x - penPos.x)));
text.cursorPos = text.charIndices[clipInfo.index + ((glyph.xAdvance / 2) <= (cursorPos.x - penPos.x))];
text.cursorStopwatch.restart();
break;
}
Expand Down
4 changes: 4 additions & 0 deletions Siv3D/src/Siv3D/TextAreaEditState/SivTextAreaEditState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace s3d
cursorPos = 0;
scrollY = 0.0;
glyphs.clear();
charIndices.assign({ 0 });
resetStopwatches();
}

Expand All @@ -57,6 +58,9 @@ namespace s3d

glyphs = font.getGlyphs(text);

charIndices = font.getGlyphClusters(text, UseFallback::No, Ligature::No).map([](const auto& cluster) { return cluster.pos; });
charIndices.push_back(text.size());

for (auto& glyph : glyphs)
{
if (glyph.codePoint == U'\t')
Expand Down