Last active
March 22, 2020 05:38
-
-
Save sthairno/e8b3fbcec7887348a16f4cea2b87c0e8 to your computer and use it in GitHub Desktop.
Siv3D_Window
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> | |
#include"HogeGUI.h" | |
namespace HogeGUI | |
{ | |
struct IControl | |
{ | |
ID id; | |
bool used; | |
RectF rect; | |
virtual void update() = 0; | |
virtual void draw() = 0; | |
}; | |
enum WindowType | |
{ | |
Background, Nomal, Forground, | |
count | |
}; | |
struct Window | |
{ | |
ID id; | |
bool used; | |
String title; | |
RectF rect; | |
Vec2 cursor; | |
WindowFlags flags; | |
bool grab; | |
RectF contentRect; | |
RectF clientRect; | |
Vec2 contentMov; | |
bool vScrollbar_show; | |
VerticalScrollbar vScrollbar; | |
bool hScrollbar_show; | |
HorizontalScrollbar hScrollbar; | |
Array<std::shared_ptr<IControl>> controls; | |
WindowType type; | |
}; | |
const size_t DefaultWindow = 0; | |
const WindowFlags defaultWindowFlags = NoTitlebar | NoResize | NoMove | NoBackground; | |
const WindowFlags tooltipFlags = NoMove | AutoResize | NoTitlebar | AlwaysForground | NoFocus; | |
const int TitlebarHeight = 24; | |
const Font* font; | |
const double ScrollbarR = 8; | |
const double ScrollbarPadding = 5; | |
static Color windowColor = Color(230, 230, 230); | |
static Color titlebarColor = Color(210, 210, 210); | |
static Array<Window> windows; | |
static Array<Array<size_t>> windowOrder = Array<Array<size_t>>(WindowType::count); | |
static size_t cullentWindow; | |
static size_t hoveringWindow; | |
static bool debug_drawRect = false; | |
size_t AddWindow(Window window, WindowType type) | |
{ | |
window.type = type; | |
windows << window; | |
auto idx = windows.size() - 1; | |
windowOrder[type] << idx; | |
Console.writeln(U"ウィンドウ作成 id={}"_fmt(window.id)); | |
return idx; | |
} | |
void DelWindow(size_t idx) | |
{ | |
if (idx == DefaultWindow) | |
{ | |
return; | |
} | |
Console.writeln(U"ウィンドウ削除 id={}"_fmt(windows[idx].id)); | |
windows.remove_at(idx); | |
for (auto tOrder = windowOrder.begin(); tOrder != windowOrder.end(); tOrder++) | |
{ | |
for (size_t i = 0; i < tOrder->size();) | |
{ | |
auto& order = tOrder->operator[](i); | |
if (order == idx) | |
{ | |
tOrder->remove_at(i); | |
continue; | |
} | |
if (order > idx) | |
{ | |
order--; | |
} | |
i++; | |
} | |
} | |
} | |
Window& GetCullentWindow() | |
{ | |
return windows[cullentWindow]; | |
} | |
template<class T> | |
std::shared_ptr<T> GetControl(Window& window, ID id) | |
{ | |
for (auto ctrl = window.controls.begin(); ctrl != window.controls.end(); ctrl++) | |
{ | |
//IDが同じでダウンキャストができたら | |
if ((*ctrl)->id == id) | |
{ | |
auto ptr = std::dynamic_pointer_cast<T, IControl>(*ctrl); | |
if (ptr) | |
{ | |
ptr->used = true; | |
return ptr; | |
} | |
} | |
} | |
return std::shared_ptr<T>(); | |
} | |
void AddControl(Window& window, std::shared_ptr<IControl> ctrl, ID id) | |
{ | |
Console.writeln(U"コントロール追加 window.id={} id={}"_fmt(window.id, id)); | |
ctrl->id = id; | |
ctrl->used = true; | |
window.controls << ctrl; | |
} | |
ID GetID(const String& str) | |
{ | |
return std::hash<String>()(str); | |
} | |
ID GetID(const Rect& rect) | |
{ | |
return std::hash<Rect>()(rect); | |
} | |
ID GetID(const s3d::Texture& tex) | |
{ | |
return std::hash<uint32>()(tex.id().value()); | |
} | |
//ウィンドウを更新 | |
void UpdateWindow(Window& window) | |
{ | |
window.clientRect = RectF(window.rect.size); | |
window.cursor = Vec2(10, 10); | |
window.used = false; | |
if (!(window.flags & WindowFlag::NoTitlebar)) | |
{ | |
if (!(window.flags & WindowFlag::NoMove)) | |
{ | |
auto titleRect = RoundRect(window.rect.pos, window.rect.w, TitlebarHeight, 3); | |
if (WindowHovered() && titleRect.leftClicked()) | |
{ | |
window.grab = true; | |
} | |
if (window.grab) | |
{ | |
if (!MouseL.pressed()) | |
{ | |
window.grab = false; | |
} | |
else | |
{ | |
auto mov = Cursor::DeltaF(); | |
window.rect.pos += mov; | |
window.rect.x = Clamp<double>(window.rect.x, -window.rect.w + 20, Scene::Width() - 20); | |
window.rect.y = Clamp<double>(window.rect.y, 0, Scene::Height() - TitlebarHeight); | |
} | |
} | |
} | |
window.clientRect.y += TitlebarHeight; | |
window.clientRect.h -= TitlebarHeight; | |
} | |
//スクロールバー処理 | |
window.hScrollbar.rect = window.clientRect; | |
window.vScrollbar.rect = window.clientRect; | |
window.hScrollbar_show = window.contentRect.w > window.clientRect.w && !(window.flags & WindowFlag::NoScrollbar); | |
window.vScrollbar_show = window.contentRect.h > window.clientRect.h && !(window.flags & WindowFlag::NoScrollbar); | |
if (window.hScrollbar_show) | |
{ | |
window.clientRect.h -= ScrollbarR * 2 + ScrollbarPadding; | |
} | |
if (window.vScrollbar_show) | |
{ | |
window.clientRect.w -= ScrollbarR * 2 + ScrollbarPadding; | |
} | |
{ | |
Transformer2D transform(Mat3x2::Translate(window.rect.pos), true); | |
if (window.hScrollbar_show) | |
{ | |
window.hScrollbar.max = window.contentRect.w; | |
window.hScrollbar.inc = 10; | |
window.hScrollbar.range = window.clientRect.w; | |
window.hScrollbar.update(window.contentMov.x); | |
} | |
else | |
{ | |
window.contentMov.x = 0; | |
} | |
if (window.vScrollbar_show) | |
{ | |
window.vScrollbar.max = window.contentRect.h; | |
window.vScrollbar.range = window.clientRect.h; | |
window.vScrollbar.inc = 10; | |
window.vScrollbar.range = window.clientRect.h; | |
window.vScrollbar.update(window.contentMov.y); | |
} | |
else | |
{ | |
window.contentMov.y = 0; | |
} | |
} | |
window.contentRect = RectF(-window.contentMov, Vec2()); | |
{ | |
Transformer2D transform(Mat3x2::Translate(window.rect.pos + window.clientRect.pos + window.contentRect.pos), true); | |
auto& controls = window.controls; | |
for (auto control = controls.begin(); control != controls.end(); control++) | |
{ | |
(*control)->used = false; | |
(*control)->update(); | |
} | |
} | |
} | |
//ウィンドウを描画 | |
void DrawWindow(Window& window) | |
{ | |
//自動リサイズ | |
if (window.flags & WindowFlag::AutoResize) | |
{ | |
window.rect.size = window.contentRect.size; | |
if (!(window.flags & WindowFlag::NoTitlebar)) | |
{ | |
window.rect.h += TitlebarHeight; | |
} | |
} | |
//背景描画 | |
if (!(window.flags & WindowFlag::NoBackground)) | |
{ | |
RoundRect(window.rect, 3).draw(windowColor).drawFrame(1, titlebarColor); | |
} | |
//タイトルバー描画 | |
if (!(window.flags & WindowFlag::NoTitlebar)) | |
{ | |
auto titleRect = RoundRect(window.rect.pos, window.rect.w, TitlebarHeight, 3); | |
titleRect.draw(titlebarColor); | |
font->operator()(window.title).drawAt(titleRect.center(), Palette::Black); | |
} | |
//コントロール描画 | |
auto& controls = window.controls; | |
if (controls.size()) | |
{ | |
{ | |
ScopedViewport2D viewport(Rect(window.clientRect.movedBy(window.rect.pos))); | |
Transformer2D transform(Mat3x2::Translate(window.contentRect.pos)); | |
{ | |
for (auto control = controls.begin(); control != controls.end(); control++) | |
{ | |
(*control)->draw(); | |
} | |
} | |
} | |
{ | |
Transformer2D transform(Mat3x2::Translate(window.rect.pos)); | |
//スクロールバー描画 | |
if (window.vScrollbar_show) | |
{ | |
window.vScrollbar.draw(); | |
} | |
if (window.hScrollbar_show) | |
{ | |
window.hScrollbar.draw(); | |
} | |
} | |
} | |
if (debug_drawRect) | |
{ | |
{ | |
Transformer2D transform(Mat3x2::Translate(window.rect.pos + window.clientRect.pos + window.contentRect.pos)); | |
for (auto control = controls.begin(); control != controls.end(); control++) | |
{ | |
(*control)->rect.drawFrame(1, Palette::Pink); | |
} | |
} | |
{ | |
Transformer2D transform(Mat3x2::Translate(window.rect.pos)); | |
window.clientRect.drawFrame(1, Palette::Yellow); | |
window.contentRect.movedBy(window.clientRect.pos).drawFrame(1, Palette::Red); | |
} | |
} | |
} | |
void Init() | |
{ | |
windows.clear(); | |
auto window = Window{ .id = GetID(U"DefaultWindow"),.used = true, .rect = Scene::Rect(), .flags = defaultWindowFlags }; | |
AddWindow(window, Background); | |
cullentWindow = DefaultWindow; | |
font = new Font(16); | |
} | |
void FrameBegin() | |
{ | |
windows[DefaultWindow].rect = Scene::Rect(); | |
for (int type = WindowType::count - 1; type >= 0; type--) | |
{ | |
auto& order = windowOrder[type]; | |
for (int idx = order.size() - 1; idx >= 0; idx--) | |
{ | |
cullentWindow = order[idx]; | |
auto& window = GetCullentWindow(); | |
if (!(window.flags & WindowFlag::NoFocus) && window.rect.intersects(Cursor::PosF())) | |
{ | |
hoveringWindow = cullentWindow; | |
if (MouseL.down() || MouseR.down()) | |
{ | |
WindowSetFocus(); | |
} | |
goto _break; | |
} | |
} | |
} | |
_break: | |
for (size_t idx = 0; idx < windows.size(); idx++) | |
{ | |
cullentWindow = idx; | |
UpdateWindow(GetCullentWindow()); | |
} | |
windows[DefaultWindow].used = true; | |
cullentWindow = DefaultWindow; | |
} | |
void FrameEnd() | |
{ | |
//ウィンドウの削除 | |
for (size_t idx = 0; idx < windows.size();) | |
{ | |
if (!windows[idx].used) | |
{ | |
DelWindow(idx); | |
continue; | |
} | |
idx++; | |
} | |
//ウィンドウの描画 | |
for (int type = 0; type < WindowType::count; type++) | |
{ | |
auto& orders = windowOrder[type]; | |
for (auto order = orders.begin(); order != orders.end(); order++) | |
{ | |
auto& window = windows[*order]; | |
auto& controls = window.controls; | |
controls.remove_if([window](std::shared_ptr<IControl> ctrl) | |
{ | |
if (!ctrl->used) | |
{ | |
Console.writeln(U"コントロール削除 window.id={} id={}"_fmt(window.id, ctrl->id)); | |
return true; | |
} | |
return false; | |
}); | |
DrawWindow(window); | |
} | |
} | |
} | |
void Shutdown() | |
{ | |
font->~Font(); | |
} | |
void WindowBegin(size_t idx) | |
{ | |
windows[idx].used = true; | |
cullentWindow = idx; | |
} | |
void WindowBegin(const String& title, WindowFlags flags, Size size, Point pos) | |
{ | |
size_t id = GetID(title); | |
for (size_t i = 1; i < windows.size(); i++) | |
{ | |
auto& window = windows[i]; | |
if (window.id == id) | |
{ | |
WindowBegin(i); | |
return; | |
} | |
} | |
size_t idx = AddWindow(Window{ .id = id, .title = title, .rect = Rect(pos,size),.flags = flags }, (flags & WindowFlag::AlwaysForground) ? Forground : Nomal); | |
WindowBegin(idx); | |
} | |
void WindowBegin(ID id, const String& title, WindowFlags flags, Size size, Point pos) | |
{ | |
for (size_t i = 1; i < windows.size(); i++) | |
{ | |
auto& window = windows[i]; | |
if (window.id == id) | |
{ | |
WindowBegin(i); | |
return; | |
} | |
} | |
size_t idx = AddWindow(Window{ .id = id, .title = title, .rect = Rect(pos,size),.flags = flags }, (flags & WindowFlag::AlwaysForground) ? Forground : Nomal); | |
WindowBegin(idx); | |
} | |
void WindowEnd() | |
{ | |
cullentWindow = DefaultWindow; | |
} | |
void WindowSetSize(SizeF size) | |
{ | |
GetCullentWindow().rect.size = size; | |
} | |
void WindowSetPos(Vec2 pos) | |
{ | |
GetCullentWindow().rect.pos = pos; | |
} | |
bool WindowHovered() | |
{ | |
return cullentWindow == hoveringWindow; | |
} | |
bool WindowItemHovered() | |
{ | |
return GetCullentWindow().clientRect.intersects(Cursor::Pos()) && WindowHovered(); | |
} | |
void WindowSetFocus() | |
{ | |
Console.writeln(U"ウィンドウを最前面に移動 id={}"_fmt(GetCullentWindow().id)); | |
size_t cullent = cullentWindow; | |
auto& window = GetCullentWindow(); | |
windowOrder[window.type].remove_if([cullent](size_t idx) {return idx == cullent; }); | |
windowOrder[window.type].push_back(cullentWindow); | |
} | |
Vec2& WindowGetCursor() | |
{ | |
return GetCullentWindow().cursor; | |
} | |
Vec2 CalcPos(Window& window, Optional<Vec2> pos, SizeF size) | |
{ | |
Vec2 disppos; | |
if (pos) | |
{ | |
disppos = *pos; | |
window.cursor = *pos; | |
} | |
else | |
{ | |
disppos = window.cursor; | |
} | |
window.cursor.y += size.y + 5; | |
Vec2 br = disppos + size + Vec2(10, 10); | |
window.contentRect.w = Max(window.contentRect.w, br.x); | |
window.contentRect.h = Max(window.contentRect.h, br.y); | |
return disppos; | |
} | |
//Button | |
struct ButtonStringCtrl : IControl | |
{ | |
String text; | |
bool clicked = false; | |
void update() override | |
{ | |
clicked = WindowItemHovered() && rect.leftClicked(); | |
} | |
void draw() override | |
{ | |
rect.rounded(4).draw(Palette::White).drawFrame(1, Palette::Gray); | |
font->operator()(text).drawAt(rect.center(), Palette::Black); | |
} | |
}; | |
bool Button(const String& text, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(text); | |
std::shared_ptr<ButtonStringCtrl> ctrl = GetControl<ButtonStringCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<ButtonStringCtrl>(new ButtonStringCtrl()); | |
ctrl->rect.size = font->operator()(text).boundingRect().size + SizeF(14, 14); | |
ctrl->text = text; | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
return ctrl->clicked; | |
} | |
struct ButtonTextureCtrl : IControl | |
{ | |
ColorF color; | |
Texture texture; | |
bool clicked = false; | |
ButtonTextureCtrl(const s3d::Texture& tex) :texture(tex) {} | |
void update() override | |
{ | |
clicked = WindowItemHovered() && rect.leftClicked(); | |
} | |
void draw() override | |
{ | |
rect.rounded(4).draw(Palette::White).drawFrame(1, Palette::Gray); | |
texture.drawAt(rect.center(), color); | |
} | |
}; | |
bool Button(const Texture& texture, const ColorF& color, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(texture); | |
std::shared_ptr<ButtonTextureCtrl> ctrl = GetControl<ButtonTextureCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<ButtonTextureCtrl>(new ButtonTextureCtrl(texture)); | |
ctrl->rect.size = texture.size() + SizeF(14, 14); | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->color = color; | |
return ctrl->clicked; | |
} | |
//Label | |
struct LabelCtrl : IControl | |
{ | |
ColorF col; | |
String text; | |
void update() override | |
{ | |
} | |
void draw() override | |
{ | |
font->operator()(text).draw(rect.pos, col); | |
} | |
}; | |
void Label(const String& text, ColorF color, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(text); | |
std::shared_ptr<LabelCtrl> ctrl = GetControl<LabelCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<LabelCtrl>(new LabelCtrl()); | |
ctrl->rect.size = font->operator()(text).region().size; | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->text = text; | |
ctrl->col = color; | |
} | |
//TextBox | |
struct TextBoxCtrl : IControl | |
{ | |
bool isInit = false; | |
s3d::TextBox textbox; | |
s3d::TextBox::State state; | |
double width; | |
String& text; | |
String label; | |
TextBoxCtrl(String& text) :text(text) {} | |
void update() override | |
{ | |
if (isInit == false) | |
{ | |
textbox = s3d::TextBox(*font, rect.pos, width); | |
isInit = true; | |
} | |
textbox.setText(text); | |
textbox.setPos(rect.pos); | |
state = textbox.update(WindowItemHovered() && MouseL.down()); | |
text = textbox.getText(); | |
} | |
void draw() override | |
{ | |
if (textbox.isActive()) | |
{ | |
textbox.drawOverlay(); | |
} | |
else | |
{ | |
textbox.draw(); | |
if (text.size() == 0) | |
{ | |
font->operator()(label).draw(rect.pos + Vec2(5, 1), Palette::Gray); | |
} | |
} | |
} | |
}; | |
void TextBox(const String& label, String& text, double width, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(label); | |
std::shared_ptr<TextBoxCtrl> ctrl = GetControl<TextBoxCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<TextBoxCtrl>(new TextBoxCtrl(text)); | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.size.x = width; | |
ctrl->rect.size.y = font->height() + 2; | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->width = width; | |
ctrl->label = label; | |
} | |
//Texture | |
struct ImageCtrl : IControl | |
{ | |
ColorF color; | |
Texture texture; | |
ImageCtrl(const Texture& tex) :texture(tex) {} | |
void update() override | |
{ | |
} | |
void draw() override | |
{ | |
texture.draw(rect.pos, color); | |
} | |
}; | |
void Image(const s3d::Texture& texture, const ColorF& color, Optional<Vec2> pos) | |
{ | |
if (texture.isEmpty()) | |
{ | |
return; | |
} | |
Window& window = GetCullentWindow(); | |
ID id = GetID(texture); | |
std::shared_ptr<ImageCtrl> ctrl = GetControl<ImageCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<ImageCtrl>(new ImageCtrl(texture)); | |
ctrl->rect.size = texture.size(); | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->color = color; | |
} | |
//CheckBox | |
const int CheckBoxRectSize = 12; | |
struct CheckBoxCtrl : IControl | |
{ | |
bool& checked; | |
String label; | |
RectF checkRect; | |
CheckBoxCtrl(bool& checked) :checked(checked) {} | |
void update() override | |
{ | |
if (WindowItemHovered() && rect.leftClicked()) | |
{ | |
checked = !checked; | |
} | |
} | |
void draw() override | |
{ | |
checkRect.drawFrame(1, Palette::Black); | |
if (checked) | |
{ | |
font->operator()(U"✔").drawAt(checkRect.center(), Palette::Black); | |
} | |
font->operator()(label).draw(rect.pos + Vec2(CheckBoxRectSize + 3, 0), Palette::Black); | |
} | |
}; | |
void CheckBox(const String& label, bool& checked, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(label); | |
std::shared_ptr<CheckBoxCtrl> ctrl = GetControl<CheckBoxCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<CheckBoxCtrl>(new CheckBoxCtrl(checked)); | |
ctrl->rect.size = font->operator()(label).region().size; | |
ctrl->rect.w += CheckBoxRectSize + 3; | |
ctrl->label = label; | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->checkRect = RectF(Arg::leftCenter = ctrl->rect.leftCenter(), CheckBoxRectSize); | |
} | |
//Callback | |
struct CallbackCtrl : IControl | |
{ | |
std::function<void(RectF)> func; | |
void update() override | |
{ | |
} | |
void draw() override | |
{ | |
func(rect); | |
} | |
}; | |
void Callback(const String& name, const std::function<void(RectF)>& func, SizeF size, Optional<Vec2> pos) | |
{ | |
Window& window = GetCullentWindow(); | |
ID id = GetID(name); | |
std::shared_ptr<CallbackCtrl> ctrl = GetControl<CallbackCtrl>(window, id); | |
if (!ctrl) | |
{ | |
ctrl = std::shared_ptr<CallbackCtrl>(new CallbackCtrl()); | |
AddControl(window, ctrl, id); | |
} | |
ctrl->rect.size = size; | |
ctrl->rect.pos = CalcPos(window, pos, ctrl->rect.size); | |
ctrl->func = func; | |
} | |
//Scrollbar | |
void VerticalScrollbar::update(double& value) | |
{ | |
if (rect.mouseOver() && WindowHovered()) | |
{ | |
value += Mouse::Wheel() * inc; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
if (grab) | |
{ | |
if (!MouseL.pressed()) | |
{ | |
grab = false; | |
} | |
else | |
{ | |
value += Cursor::Delta().y * max / scarea.h; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
} | |
else | |
{ | |
if (grip.leftClicked() && WindowHovered()) | |
{ | |
grab = true; | |
} | |
else if (scarea.leftClicked()) | |
{ | |
value = (Cursor::PosF().y - scarea.y) * max / scarea.h; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
} | |
scarea = RoundRect(rect.tr() + Vec2(-ScrollbarR * 2 - ScrollbarPadding, ScrollbarPadding), ScrollbarR * 2, rect.h - ScrollbarPadding * 2 - ScrollbarR * 2, ScrollbarR); | |
grip = RoundRect(scarea); | |
grip.y += scarea.h * value / max; | |
grip.h *= range / max; | |
} | |
void VerticalScrollbar::draw() | |
{ | |
scarea.draw(ColorF(0.8)); | |
grip.draw(ColorF(0.6)); | |
} | |
void HorizontalScrollbar::update(double& value) | |
{ | |
if (rect.mouseOver()) | |
{ | |
value += Mouse::WheelH() * inc; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
if (grab) | |
{ | |
if (!MouseL.pressed()) | |
{ | |
grab = false; | |
} | |
else | |
{ | |
value += Cursor::Delta().x * max / scarea.w; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
} | |
else | |
{ | |
if (grip.leftClicked() && WindowItemHovered()) | |
{ | |
grab = true; | |
} | |
else if (scarea.leftClicked()) | |
{ | |
value = (Cursor::PosF().x - scarea.x) * max / scarea.w; | |
value = Clamp<double>(value, 0, max - range); | |
} | |
} | |
scarea = RoundRect(rect.bl() + Vec2(ScrollbarPadding, -ScrollbarR * 2 - ScrollbarPadding), rect.w - ScrollbarPadding * 2 - ScrollbarR * 2, ScrollbarR * 2, ScrollbarR); | |
grip = RoundRect(scarea); | |
grip.x += scarea.w * value / max; | |
grip.w *= range / max; | |
} | |
void HorizontalScrollbar::draw() | |
{ | |
scarea.draw(ColorF(0.8)); | |
grip.draw(ColorF(0.6)); | |
} | |
//Debug | |
static bool debug_window = false; | |
void ShowDebugWindow() | |
{ | |
WindowBegin(U"Debug"); | |
Label(U"hoveringWindow:{}"_fmt(hoveringWindow)); | |
Label(U"WindowHovered:{}"_fmt(WindowHovered())); | |
Label(U"WindowItemHovered:{}"_fmt(WindowItemHovered())); | |
Label(U"cullentWindow:{}"_fmt(cullentWindow)); | |
CheckBox(U"debug_drawRect", debug_drawRect); | |
CheckBox(U"Window", debug_window); | |
if (debug_window) | |
{ | |
Label(U" Windows"); | |
for (size_t idx = 0; idx < windows.size(); idx++) | |
{ | |
auto& window = windows[idx]; | |
Label(U" {}: id={} title=\"{}\""_fmt(idx, window.id, window.title)); | |
} | |
Label(U" WindowOrder"); | |
Label(U" Background: {}"_fmt(windowOrder[Background])); | |
Label(U" Nomal: {}"_fmt(windowOrder[Nomal])); | |
Label(U" Forground: {}"_fmt(windowOrder[Forground])); | |
} | |
WindowEnd(); | |
} | |
} |
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
#pragma once | |
# include <Siv3D.hpp> // OpenSiv3D v0.4.2 | |
namespace HogeGUI | |
{ | |
enum WindowFlag | |
{ | |
/// <summary> | |
/// 通常のウィンドウ | |
/// </summary> | |
None = 0, | |
/// <summary> | |
/// タイトルバーを表示しない | |
/// </summary> | |
NoTitlebar = 1 << 0, | |
/// <summary> | |
/// サイズ変更をしない | |
/// </summary> | |
NoResize = 1 << 1, | |
/// <summary> | |
/// 移動をしない | |
/// </summary> | |
NoMove = 1 << 2, | |
/// <summary> | |
/// 背景を表示しない | |
/// </summary> | |
NoBackground = 1 << 3, | |
/// <summary> | |
/// スクロールバーを表示しない | |
/// </summary> | |
NoScrollbar = 1 << 4, | |
/// <summary> | |
/// 自動リサイズ | |
/// </summary> | |
AutoResize = 1 << 5, | |
/// <summary> | |
/// 常に手前に表示 | |
/// </summary> | |
AlwaysForground = 1 << 6, | |
/// <summary> | |
/// フォーカスしない | |
/// </summary> | |
NoFocus = 1 << 7 | |
}; | |
typedef int WindowFlags; | |
typedef size_t ID; | |
void Init(); | |
void FrameBegin(); | |
void FrameEnd(); | |
void Shutdown(); | |
/// <summary> | |
/// ウィンドウ開始 | |
/// </summary> | |
/// <param name="title">タイトル</param> | |
/// <param name="pos">初期位置</param> | |
/// <param name="size">初期サイズ</param> | |
/// <param name="flags">ウィンドウ設定</param> | |
void WindowBegin(const String& title, WindowFlags flags = WindowFlag::None, Size size = Size(300, 300), Point pos = Point(0, 0)); | |
/// <summary> | |
/// ウィンドウ開始 | |
/// </summary> | |
/// <param name="id">ウィンドウID</param> | |
/// <param name="title">タイトル</param> | |
/// <param name="pos">初期位置</param> | |
/// <param name="size">初期サイズ</param> | |
/// <param name="flags">ウィンドウ設定</param> | |
void WindowBegin(ID id, const String& title, WindowFlags flags = WindowFlag::None, Size size = Size(300, 300), Point pos = Point(0, 0)); | |
/// <summary> | |
/// ウィンドウ終了 | |
/// </summary> | |
void WindowEnd(); | |
/// <summary> | |
/// ウィンドウのサイズを変更 | |
/// </summary> | |
void WindowSetSize(SizeF size); | |
/// <summary> | |
/// ウィンドウの位置を変更 | |
/// </summary> | |
void WindowSetPos(Vec2 pos); | |
/// <summary> | |
/// 現在のウィンドウ上にカーソルがあるか | |
/// </summary> | |
bool WindowHovered(); | |
/// <summary> | |
/// 現在のウィンドウを最前面に移動する | |
/// </summary> | |
void WindowSetFocus(); | |
/// <summary> | |
/// ウィンドウのカーソルを取得 | |
/// </summary> | |
Vec2& WindowGetCursor(); | |
/// <summary> | |
/// ボタン | |
/// </summary> | |
/// <param name="text"></param> | |
/// <param name="pos"></param> | |
bool Button(const String& text, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// ボタン | |
/// </summary> | |
/// <param name="texture"></param> | |
/// <param name="color"></param> | |
/// <param name="pos"></param> | |
bool Button(const Texture& texture, const ColorF& color = Palette::White, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// ラベル | |
/// </summary> | |
void Label(const String& text, ColorF color = Palette::Black, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// テキストボックス | |
/// </summary> | |
void TextBox(const String& label, String& text, double width = 200, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// 画像 | |
/// </summary> | |
void Image(const Texture& texture, const ColorF& color = Palette::White, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// チェックボックス | |
/// </summary> | |
void CheckBox(const String& label, bool& checked, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// プログレスバー | |
/// </summary> | |
void ProgressBar(const String& name, double value, double max, double min = 0, double width = 200, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// コールバック関数から描画 | |
/// </summary> | |
void Callback(const String& name, const std::function<void(RectF)>& func, SizeF size, Optional<Vec2> pos = unspecified); | |
/// <summary> | |
/// 垂直スクロールバー | |
/// </summary> | |
class VerticalScrollbar | |
{ | |
private: | |
RoundRect scarea; | |
RoundRect grip; | |
bool grab; | |
public: | |
double max; | |
double range; | |
double inc = 1; | |
Rect rect; | |
void update(double& value); | |
void draw(); | |
}; | |
/// <summary> | |
/// 水平スクロールバー | |
/// </summary> | |
class HorizontalScrollbar | |
{ | |
private: | |
RoundRect scarea; | |
RoundRect grip; | |
bool grab; | |
public: | |
double max; | |
double range; | |
double inc = 1; | |
Rect rect; | |
void update(double& value); | |
void draw(); | |
}; | |
void ShowDebugWindow(); | |
} |
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> | |
#include"HogeGUI.h" | |
void Main() | |
{ | |
Scene::SetBackground(Palette::Aliceblue); | |
bool showTooltip = false; | |
Texture icon(Icon(0xf129, 20)); | |
Texture siv3dKun(U"example/siv3d-kun.png"); | |
HogeGUI::Init(); | |
while (System::Update()) | |
{ | |
HogeGUI::FrameBegin(); | |
HogeGUI::WindowBegin(U"Window", HogeGUI::None, Size(400, 500)); | |
showTooltip = HogeGUI::WindowHovered(); | |
HogeGUI::Label(U"Label"); | |
HogeGUI::Button(U"Button"); | |
HogeGUI::Image(siv3dKun); | |
HogeGUI::WindowEnd(); | |
if (showTooltip) | |
{ | |
HogeGUI::WindowBegin(U"ToolTip", HogeGUI::NoMove | HogeGUI::AutoResize | HogeGUI::NoTitlebar | HogeGUI::AlwaysForground | HogeGUI::NoFocus); | |
HogeGUI::WindowSetPos(Cursor::PosF()); | |
HogeGUI::Image(icon, Palette::Black); | |
HogeGUI::Label(U"HogeHoge ToolTip"); | |
HogeGUI::WindowEnd(); | |
} | |
HogeGUI::ShowDebugWindow(); | |
HogeGUI::FrameEnd(); | |
} | |
HogeGUI::Shutdown(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment