Skip to content

Instantly share code, notes, and snippets.

@oyakodon
Created December 28, 2017 06:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oyakodon/2bfef80f0a241970afd0de9ea7918ff6 to your computer and use it in GitHub Desktop.
Save oyakodon/2bfef80f0a241970afd0de9ea7918ff6 to your computer and use it in GitHub Desktop.
スクロールできるテキスト表示 / Siv3D, C++
#include <Siv3D.hpp>
/// <summary>
/// スクロールできるテキスト表示を提供します。
/// </summary>
class ScrollTextBox
{
private:
/// <summary>
/// フォント
/// </summary>
const Font font = Font(12);
/// <summary>
/// 改行区切りのテキスト配列
/// </summary>
Array<String> textArray;
/// <summary>
/// 表示エリア
/// </summary>
Rect textBox;
/// <summary>
/// 枠とのスペース
/// </summary>
const Point offset;
/// <summary>
/// 現在の行数
/// </summary>
int line = 0;
/// <summary>
/// 表示行数
/// </summary>
int m_line_height;
/// <summary>
/// マウスカーソルが箱の外に合ってもキーボード・マウス入力に反応させるかどうか
/// </summary>
bool m_enableOutside;
/// <summary>
/// 可視かどうか
/// </summary>
bool m_visible;
public:
/// <summary>
/// スクロールできるテキスト表示を提供します。
/// </summary>
/// <param name="text">表示するテキスト(改行区切り)</param>
/// <param name="pos">描画位置</param>
/// <param name="size">描画サイズ</param>
/// <param name="offset_">枠から文字までのスペース</param>
ScrollTextBox(const String& text, const Point& pos, const Point& size, int offset_ = 5) : offset(Point(offset_, offset_))
{
m_enableOutside = false;
m_visible = true;
setText(text);
setSize(size);
setPos(pos);
}
/// <summary>
/// 描画するテキストを設定します。
/// </summary>
void setText(const String& text)
{
textArray = Array<String>(text.split(L'\n'));
}
/// <summary>
/// 描画サイズを設定します。
/// </summary>
void setSize(const Point& size)
{
textBox.setSize(size);
m_line_height = (textBox.h - offset.x * 2) / font.height;
if (textArray.size() < m_line_height)
{
m_line_height = textArray.size();
}
}
/// <summary>
/// 描画位置を設定します。
/// </summary>
void setPos(const Point& pos)
{
textBox.setPos(pos);
}
/// <summary>
/// マウスカーソルが箱の外に合ってもキーボード・マウス入力に反応させるかどうかを設定します。
/// </summary>
void setEnableOutside(bool value)
{
m_enableOutside = value;
}
/// <summary>
/// 可視かどうかを設定します。
/// </summary>
void setVisible(bool value)
{
m_visible = value;
}
/// <summary>
/// 描画と入力を更新します。(メインループ内で1回呼び出してください)
/// </summary>
bool update()
{
if (!m_visible)
{
return true;
}
// 枠
textBox.drawFrame();
// 文字表示
for (int i = 0; i < m_line_height; i++)
{
// 行番号表示
font(ToString(line + i + 1), L" ").draw({ offset + textBox.pos + Point(font(L"0").region().w * (ToString(textArray.size()).length - ToString(line + i + 1).length), i * font.height) });
// 幅超えてたら
if (font(textArray[line + i]).region().w > textBox.w - offset.x - font(Format(textArray.size())).region().w - 15)
{
int len = (int)textArray[line + i].length;
while (len > 0)
{
len--;
if (font(textArray[line + i].substr(0, len)).region().w <= textBox.w - offset.x - font(Format(textArray.size())).region().w - 15)
{
break;
}
}
font(textArray[line + i].substr(0, len)).draw(offset + textBox.pos + Point(font(Format(textArray.size())).region().w + 15, i * font.height));
}
else
{
font(textArray[line + i]).draw(offset + textBox.pos + Point(font(Format(textArray.size(), L" ")).region().w + 15, i * font.height));
}
}
// 右上の行数表示
String cursor = Format(line + 1, L"-", line + m_line_height, L"/", textArray.size(), L" (", ToString(((double)(line + m_line_height) / textArray.size()) * 100.0, 0), L"%)");
font(cursor).region().movedBy(textBox.pos + Point(textBox.w - font(cursor).region().w - offset.x, offset.y)).draw();
font(cursor).draw(textBox.pos + Point(textBox.w - font(cursor).region().w - offset.x, offset.y), Palette::Black);
// 入力検出
if (textBox.mouseOver || m_enableOutside)
{
// ↑なら1行、PageUpなら表示行分 行を戻す
// ↓なら1行、PageDownなら表示行分 行をすすめる
// Endなら、最後の行に移動
// Homeなら最初の行に移動
if (Input::KeyUp.pressed || Input::KeyPageUp.clicked)
{
line -= Input::KeyPageUp.clicked ? m_line_height : 1;
}
else if (Input::KeyDown.pressed || Input::KeyPageDown.clicked)
{
line += Input::KeyPageDown.clicked ? m_line_height : 1;
}
else if (Input::KeyEnd.clicked)
{
line = (int)textArray.size() - m_line_height;
}
else if (Input::KeyHome.clicked)
{
line = 0;
}
// マウスホイールで移動
// Shift押しながらで高速移動
line += Input::KeyShift.pressed ? Mouse::Wheel() * 10 : Mouse::Wheel();
if (line < 0) line = 0;
if (line + m_line_height >= textArray.size()) line = (int)textArray.size() - m_line_height;
}
return true;
}
};
void Main()
{
ScrollTextBox textBox(TextReader(L"Main.cpp").readAll(), { 40, 40 }, { 560, 400 });
textBox.setEnableOutside(true);
while (System::Update())
{
textBox.update();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment