Created
December 28, 2017 06:25
-
-
Save oyakodon/2bfef80f0a241970afd0de9ea7918ff6 to your computer and use it in GitHub Desktop.
スクロールできるテキスト表示 / Siv3D, C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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