From 9a6645036a1fd4f2c414fe0f3c98fe0c020379ce Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sat, 20 May 2023 15:15:16 +0900 Subject: [PATCH 01/13] =?UTF-8?q?TODO=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fa82cab..e1eb349 100644 --- a/README.md +++ b/README.md @@ -125,12 +125,14 @@ whole,graph の中身は下記入力項目を参照。 - UI周りのコードの整理 - カラーテピッカーのスペース改善 - 矢印ボタンを右クリックでplt生成と画像生成を自動で続けて行う +- 整数同士の演算の切り捨て対策 - 入力欄に大量の文字を入れるとはみ出る対策 - データファイルのドラッグ&ドロップ - カラーテーマの完全削除 - アプリの大きさを変えられるようにする - with linesとかの開くやつの閉じる機能 - フォント指定 +- ラベルのギリシャ文字 - 複数pltファイル読み込み - グルーピング機能 - ドキュメント作成...要る? From cad8f4d733105d3d090d53950bb944ef6ea7a9dc Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Wed, 31 May 2023 02:12:24 +0900 Subject: [PATCH 02/13] =?UTF-8?q?key(=E5=87=A1=E4=BE=8B)=E3=81=AE=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E3=81=A8=E5=9B=B2=E3=81=84=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/plt_create.h | 7 ++ pltGUI/plt_setting.h | 156 ++++++++++++++++++++++++++++++++++++++++ pltGUI/ui_plt_setting.h | 15 ++++ 3 files changed, 178 insertions(+) diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index b771658..e5ee4aa 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -30,6 +30,13 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { if (ws.logscale_x.b) writer << U"set logscale x"; if (ws.logscale_y.b) writer << U"set logscale y"; if (ws.sample.b) writer << U"set sample " << ws.sample.v.text; + if (ws.key.b) { + writer << U"set key " << ws.key.v.pos.getItem() << (ws.key.v.box ? U" box" : U""); + } + else { + writer << U"unset key"; + } + // 全体設定の最後 diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index d6337c5..6009dfc 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -6,6 +6,7 @@ template class WithBool { public: + WithBool(bool _b=false) :b(_b) {}; bool b = false; T v; }; @@ -17,6 +18,160 @@ class WithBool { bool b = false; }; +class Pulldown +{ +public: + + Pulldown() = default; + + Pulldown(const Array& items,const size_t& index = 0, const Point& pos = { 0,0 }) + : m_items{ items } + , m_rect{ pos, 0, (FontAsset(U"main").height() + m_padding.y * 2) } + { + for (const auto& item : m_items) + { + m_rect.w = Max(m_rect.w, static_cast(FontAsset(U"main")(item).region().w)); + } + m_rect.w += (m_padding.x * 2 + m_downButtonSize); + m_index = Clamp(index, size_t(0), items.size()); + } + + bool isEmpty() const + { + return m_items.empty(); + } + + void update() + { + if (isEmpty()) + { + return; + } + + if (m_rect.leftClicked()) + { + m_isOpen = (not m_isOpen); + } + + Point pos = m_rect.pos.movedBy(0, m_rect.h); + + if (m_isOpen) + { + for (auto i : step(m_items.size())) + { + if (const Rect rect{ pos, m_rect.w, m_rect.h }; + rect.leftClicked()) + { + m_index = i; + m_isOpen = false; + break; + } + + pos.y += m_rect.h; + } + } + } + + void draw() const + { + m_rect.draw(); + + if (isEmpty()) + { + return; + } + + m_rect.drawFrame(1, 0, m_isOpen ? UIColor::Accent : UIColor::frame()); + + Point pos = m_rect.pos; + + FontAsset(U"main")(m_items[m_index]).draw(pos + m_padding, UIColor::text()); + + Triangle{ (m_rect.x + m_rect.w - m_downButtonSize / 2.0 - m_padding.x), (m_rect.y + m_rect.h / 2.0), + (m_downButtonSize * 0.5), 180_deg }.draw(UIColor::text()); + + pos.y += m_rect.h; + + if (m_isOpen) + { + const Rect backRect{ pos, m_rect.w, (m_rect.h * m_items.size()) }; + + backRect.drawShadow({ 1, 1 }, 4, 1).draw(); + + for (const auto& item : m_items) + { + if (const Rect rect{ pos, m_rect.size }; + rect.mouseOver()) + { + rect.draw(UIColor::Accent.lerp(UIColor::Base,0.5)); + } + + FontAsset(U"main")(item).draw((pos + m_padding), Palette::Black); + + pos.y += m_rect.h; + } + + backRect.drawFrame(1, 0, Palette::Gray); + } + } + + void setPos(const Point& pos) + { + m_rect.setPos(pos); + } + + const Rect& getRect() const + { + return m_rect; + } + + size_t getIndex() const + { + return m_index; + } + + String getItem() const + { + if (isEmpty()) + { + return{}; + } + + return m_items[m_index]; + } + + void setIndex(const size_t& index) { + if (InRange(index, size_t(0), m_items.size())) { + m_index = index; + } + } + + bool isOpen() { + return m_isOpen; + } + +private: + + Array m_items; + + size_t m_index = 0; + + Size m_padding{ 6, 2 }; + + Rect m_rect; + + int32 m_downButtonSize = 16; + + bool m_isOpen = false; +}; + + +class PltKey { +public: + Array poslist{ U"top left",U"top right",U"bottom left", U"bottom right", U"top outside", U"bottom outside" }; + Pulldown pos{ poslist, 1 }; + bool box; +}; /// @brief タイトルなどグラフ全体の設定 class WholeSetting { @@ -31,6 +186,7 @@ class WholeSetting { WithBool logscale_x; WithBool logscale_y; WithBool sample; + WithBool key{ true }; WithBool loadfile; }; diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index f954a6d..1f24b3c 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -50,6 +50,17 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"sample", dpos.x(180)); MyGUI::TextBox(s.sample, dpos.y(55)); + MyGUI::CheckBoxArea(s.key.b, dpos.x(20), s.key.v.pos.isOpen() ? Vec2(600, 250) : Vec2(600, 50)); + MyGUI::Text(U"key", dpos.x(180)); + s.key.v.pos.setPos((dpos.x(250) - Vec2(0, 15)).asPoint()); + s.key.v.pos.update(); + s.key.v.pos.draw(); + MyGUI::CheckBox(s.key.v.box, dpos.x(20)); + MyGUI::Text(U"box", dpos.y(55)); + if (s.key.v.pos.isOpen()) { + dpos.y(200); + } + MyGUI::CheckBoxArea(s.loadfile.b, dpos.x(20), Vec2(600, 50)); MyGUI::Text(U"load", dpos.x(180)); MyGUI::Text(FileSystem::FileName(s.loadfile.v), dpos.x(380)); @@ -57,6 +68,10 @@ class WholeSettingUI : public ScrollableUI { Optional file = Dialog::OpenFile(Array{ FileFilter{U"gnuplot",{U"plt"}},FileFilter::AllFiles() }); if (file) s.loadfile.v = *file; } + + + + dpos.y(200); } }; From bc6d8db2fec0a88c732d1ed7c84a6101939389e5 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Wed, 31 May 2023 02:13:39 +0900 Subject: [PATCH 03/13] =?UTF-8?q?=E5=AF=BE=E6=95=B0=E8=BB=B8=E3=81=AE10^n?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/plt_create.h | 2 ++ pltGUI/plt_setting.h | 2 ++ pltGUI/ui_plt_setting.h | 11 ++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index e5ee4aa..644ef86 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -29,6 +29,8 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { if (ws.yrange_min.b) writer << U"set yrange [" << ws.yrange_min.v.text << U":" << ws.yrange_max.v.text << U"]"; if (ws.logscale_x.b) writer << U"set logscale x"; if (ws.logscale_y.b) writer << U"set logscale y"; + if (ws.logscale_x_exp_not.b) writer << U"set format x \"10^{%L}\""; + if (ws.logscale_y_exp_not.b) writer << U"set format y \"10^{%L}\""; if (ws.sample.b) writer << U"set sample " << ws.sample.v.text; if (ws.key.b) { writer << U"set key " << ws.key.v.pos.getItem() << (ws.key.v.box ? U" box" : U""); diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 6009dfc..903595d 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -185,6 +185,8 @@ class WholeSetting { WithBool yrange_max; WithBool logscale_x; WithBool logscale_y; + WithBool logscale_x_exp_not;//exponential notation + WithBool logscale_y_exp_not;//exponential notation WithBool sample; WithBool key{ true }; WithBool loadfile; diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index 1f24b3c..4af1c8d 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -43,8 +43,17 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"logscale", dpos.x(200)); MyGUI::CheckBoxArea(s.logscale_x.b, dpos.x(20), Size(30, 50)); MyGUI::Text(U"x", dpos.x(70)); + MyGUI::CheckBoxArea(s.logscale_x_exp_not.b, dpos.x(20), Size(150, 50)); + FontAsset(U"main")(U"n").drawAt(20.0, Vec2(dpos) + Vec2(30, -10), UIColor::text()); + MyGUI::Text(U"10 notation", dpos); + dpos.y(55); + dpos.x(220); MyGUI::CheckBoxArea(s.logscale_y.b, dpos.x(20), Size(30, 50)); - MyGUI::Text(U"y", dpos.y(55)); + MyGUI::Text(U"y", dpos.x(70)); + MyGUI::CheckBoxArea(s.logscale_y_exp_not.b, dpos.x(20), Size(150, 50)); + FontAsset(U"main")(U"n").drawAt(20.0, Vec2(dpos) + Vec2(30, -10), UIColor::text()); + MyGUI::Text(U"10 notation", dpos); + dpos.y(55); MyGUI::CheckBoxArea(s.sample.b, dpos.x(20), Vec2(400, 50)); MyGUI::Text(U"sample", dpos.x(180)); From 58f8fddc2a102d7333e157f74e6d1f452eb7c077 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Wed, 31 May 2023 20:26:07 +0900 Subject: [PATCH 04/13] =?UTF-8?q?tics(=E7=9B=AE=E7=9B=9B=E3=82=8A)?= =?UTF-8?q?=E3=81=AE=E5=85=A5=E5=8A=9B=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/plt_create.h | 11 ++++------- pltGUI/plt_setting.h | 2 ++ pltGUI/ui_plt_setting.h | 9 +++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index 644ef86..0953f5d 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -32,13 +32,10 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { if (ws.logscale_x_exp_not.b) writer << U"set format x \"10^{%L}\""; if (ws.logscale_y_exp_not.b) writer << U"set format y \"10^{%L}\""; if (ws.sample.b) writer << U"set sample " << ws.sample.v.text; - if (ws.key.b) { - writer << U"set key " << ws.key.v.pos.getItem() << (ws.key.v.box ? U" box" : U""); - } - else { - writer << U"unset key"; - } - + if (ws.key.b) writer << U"set key " << ws.key.v.pos.getItem() << (ws.key.v.box ? U" box" : U""); + else writer << U"unset key"; + if (ws.xtics.b) writer << U"set xtics " << ws.xtics.v.text; + if (ws.ytics.b) writer << U"set ytics " << ws.ytics.v.text; // 全体設定の最後 diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 903595d..346ae4e 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -189,6 +189,8 @@ class WholeSetting { WithBool logscale_y_exp_not;//exponential notation WithBool sample; WithBool key{ true }; + WithBool xtics; + WithBool ytics; WithBool loadfile; }; diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index 4af1c8d..070d06c 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -70,6 +70,15 @@ class WholeSettingUI : public ScrollableUI { dpos.y(200); } + dpos.x(20); + MyGUI::Text(U"tics", dpos.x(200)); + MyGUI::CheckBoxArea(s.xtics.b, dpos.x(20), Size(160, 50)); + MyGUI::Text(U"x", dpos.x(20)); + MyGUI::TextBox(s.xtics, dpos.x(170), Size(120, 36)); + MyGUI::CheckBoxArea(s.ytics.b, dpos.x(20), Size(160, 50)); + MyGUI::Text(U"y", dpos.x(20)); + MyGUI::TextBox(s.ytics, dpos.y(55), Size(120, 36)); + MyGUI::CheckBoxArea(s.loadfile.b, dpos.x(20), Vec2(600, 50)); MyGUI::Text(U"load", dpos.x(180)); MyGUI::Text(FileSystem::FileName(s.loadfile.v), dpos.x(380)); From b12a328c9994ae63fa9c476cde7a5e903c51cc60 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Wed, 31 May 2023 20:59:19 +0900 Subject: [PATCH 05/13] =?UTF-8?q?grid/=E3=82=B0=E3=83=AA=E3=83=83=E3=83=89?= =?UTF-8?q?=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/plt_create.h | 1 + pltGUI/plt_setting.h | 1 + pltGUI/ui_plt_setting.h | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index 0953f5d..0051a8e 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -36,6 +36,7 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { else writer << U"unset key"; if (ws.xtics.b) writer << U"set xtics " << ws.xtics.v.text; if (ws.ytics.b) writer << U"set ytics " << ws.ytics.v.text; + if (ws.grid.b) writer << U"set grid"; // 全体設定の最後 diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 346ae4e..568416d 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -191,6 +191,7 @@ class WholeSetting { WithBool key{ true }; WithBool xtics; WithBool ytics; + WithBool grid; WithBool loadfile; }; diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index 070d06c..54de713 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -79,6 +79,10 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"y", dpos.x(20)); MyGUI::TextBox(s.ytics, dpos.y(55), Size(120, 36)); + MyGUI::CheckBoxArea(s.grid.b, dpos.x(20)); + MyGUI::Text(U"grid", dpos.y(55)); + + MyGUI::CheckBoxArea(s.loadfile.b, dpos.x(20), Vec2(600, 50)); MyGUI::Text(U"load", dpos.x(180)); MyGUI::Text(FileSystem::FileName(s.loadfile.v), dpos.x(380)); From 44b821c80001b50cae874fd8029c8b8244c3e942 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Wed, 31 May 2023 21:25:56 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=E7=9F=A2=E5=8D=B0=E3=83=9C=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E5=8F=B3=E3=82=AF=E3=83=AA=E3=83=83=E3=82=AF=E3=81=A7?= =?UTF-8?q?=E5=90=8C=E6=99=82=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/my_gui.h | 6 +----- pltGUI/ui_controller.h | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pltGUI/my_gui.h b/pltGUI/my_gui.h index 15e7415..6e44be9 100644 --- a/pltGUI/my_gui.h +++ b/pltGUI/my_gui.h @@ -507,11 +507,7 @@ namespace MyGUI { if (mouseOver) { arrow.drawFrame(2, UIColor::frame(uis)); Cursor::RequestStyle(CursorStyle::Hand); - if (rect.leftClicked()) { - watch.restart(); - return true; - } } - return false; + return mouseOver; } } diff --git a/pltGUI/ui_controller.h b/pltGUI/ui_controller.h index 68de730..d24fdd8 100644 --- a/pltGUI/ui_controller.h +++ b/pltGUI/ui_controller.h @@ -119,11 +119,31 @@ class UIController { } if (MyGUI::ArrowIconButton(Vec2(230, 35), watch1)) { - CreatePltFile(whole, graphs); - readPltFile(); + if (MouseL.down()) { + watch1.restart(); + CreatePltFile(whole, graphs); + readPltFile(); + } + if (MouseR.down()) { + watch1.restart(); + CreatePltFile(whole, graphs); + readPltFile(); + watch2.restart(); + executePltFile(); + } } if (MyGUI::ArrowIconButton(Vec2(480, 35), watch2)) { - executePltFile(); + if (MouseL.down()) { + watch2.restart(); + executePltFile(); + } + if (MouseR.down()) { + watch1.restart(); + CreatePltFile(whole, graphs); + readPltFile(); + watch2.restart(); + executePltFile(); + } } } From 2499398b85a1100a0f16f0216e4a198526463bed Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sat, 3 Jun 2023 01:05:33 +0900 Subject: [PATCH 07/13] =?UTF-8?q?.plt=E3=81=AE=E5=AE=9F=E8=A1=8C=E3=82=92?= =?UTF-8?q?=E6=97=A2=E5=AE=9A=E3=81=AE=E3=82=A2=E3=83=97=E3=83=AA=E3=81=A7?= =?UTF-8?q?=E3=81=AF=E3=81=AA=E3=81=8Fgnuplot=E3=82=92=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E3=81=97=E3=81=A6=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E3=80=82=E3=81=BE=E3=81=9F=E3=80=81=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=81=AF.bat=E3=81=A7=E8=A1=8C=E3=81=86=E3=81=93?= =?UTF-8?q?=E3=81=A8=E3=81=A7=E3=80=81=E3=82=A6=E3=82=A3=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=A6=E3=82=92=E9=9D=9E=E3=82=A2=E3=82=AF=E3=83=86=E3=82=A3?= =?UTF-8?q?=E3=83=96=E3=81=AB=E3=81=AA=E3=82=89=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/App/executeplot.bat | 1 + pltGUI/plt_create.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 pltGUI/App/executeplot.bat diff --git a/pltGUI/App/executeplot.bat b/pltGUI/App/executeplot.bat new file mode 100644 index 0000000..76e72f8 --- /dev/null +++ b/pltGUI/App/executeplot.bat @@ -0,0 +1 @@ +gnuplot result.plt \ No newline at end of file diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index 0051a8e..9a6940c 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -4,6 +4,8 @@ #include #include +#pragma comment( lib, "shell32.lib" ) + /// @brief pltファイルを作成する。場所は開発中は./pltGUI/App/ /// @param whole, graphs はUIの方 void CreatePltFile(WholeSettingUI& whole, Array& graphs) { @@ -102,5 +104,6 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { /// @brief pltファイルを実行する。 /// @brief 実行にかかる時間も特に停止しないので注意 void executePltFile() { - System::LaunchFile(U"result.plt"); + //cf: https://www.lisz-works.com/entry/2016/11/16/224520 + ShellExecute(NULL, L"open", L"cmd.exe", L"/c executeplot.bat", L"", SW_HIDE); } From dd18be41f3b8f9de4df94f201158591e871f0fef Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sat, 3 Jun 2023 19:25:34 +0900 Subject: [PATCH 08/13] =?UTF-8?q?terminal=E3=82=92pngcairo/gif/svg/pdfcair?= =?UTF-8?q?o=E3=81=8B=E3=82=89=E6=8C=87=E5=AE=9A=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +-- pltGUI/App/executeplot.bat | 2 +- pltGUI/Main.cpp | 2 +- pltGUI/plt_create.h | 9 ++++--- pltGUI/plt_setting.h | 52 ++++++++++++++++++++++++++++++++++---- pltGUI/ui_controller.h | 34 +++++++++++++++++-------- pltGUI/ui_plt_setting.h | 16 ++++++++++++ 7 files changed, 95 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 27a46b0..8f6e966 100644 --- a/.gitignore +++ b/.gitignore @@ -426,5 +426,5 @@ gmon.out **/example/* # Ignore output files -pltGUI/App/result.plt -pltGUI/App/result.png +pltGUI/App/output.* +pltGUI/App/plot.plt diff --git a/pltGUI/App/executeplot.bat b/pltGUI/App/executeplot.bat index 76e72f8..a77a213 100644 --- a/pltGUI/App/executeplot.bat +++ b/pltGUI/App/executeplot.bat @@ -1 +1 @@ -gnuplot result.plt \ No newline at end of file +gnuplot plot.plt \ No newline at end of file diff --git a/pltGUI/Main.cpp b/pltGUI/Main.cpp index 947dd2e..1d65518 100644 --- a/pltGUI/Main.cpp +++ b/pltGUI/Main.cpp @@ -1,4 +1,4 @@ -# include // OpenSiv3D v0.6.6 +# include // OpenSiv3D v0.6.9 #include "ui_common.h" #include "ui_controller.h" diff --git a/pltGUI/plt_create.h b/pltGUI/plt_create.h index 9a6940c..7341ec9 100644 --- a/pltGUI/plt_create.h +++ b/pltGUI/plt_create.h @@ -9,11 +9,11 @@ /// @brief pltファイルを作成する。場所は開発中は./pltGUI/App/ /// @param whole, graphs はUIの方 void CreatePltFile(WholeSettingUI& whole, Array& graphs) { - TextWriter writer(U"result.plt", TextEncoding::UTF8_NO_BOM);//BOM付きだとgnuplotで読めない模様 + TextWriter writer(U"plot.plt", TextEncoding::UTF8_NO_BOM);//BOM付きだとgnuplotで読めない模様 // オープンに失敗 if (not writer) { - throw Error{ U"Failed to open `result.plt`" }; + throw Error{ U"Failed to open `plot.plt`"}; } @@ -22,8 +22,9 @@ void CreatePltFile(WholeSettingUI& whole, Array& graphs) { // 全体設定の書き込み WholeSetting& ws = whole.s; - writer << U"set terminal pngcairo"; - writer << U"set output \"result.png\""; + if (ws.sizex.b) writer << U"set terminal " << ws.terminal.getInfo().command << U" size " << ws.sizex.v.text << U"," << ws.sizey.v.text; + else writer << U"set terminal " << ws.terminal.getInfo().command; + writer << U"set output \"output.{}\""_fmt(Terminal::ext); if (ws.title.b) writer << U"set title \"" << ws.title.v.text << U"\""; if (ws.xlabel.b) writer << U"set xlabel \"" << ws.xlabel.v.text << U"\""; if (ws.ylabel.b) writer << U"set ylabel \"" << ws.ylabel.v.text << U"\""; diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 568416d..fe6b13f 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -41,16 +41,21 @@ class Pulldown return m_items.empty(); } - void update() + Pulldown* update() { if (isEmpty()) { - return; + return this; + } + + if (m_nextClose) { + m_isOpen = (not m_isOpen); + m_nextClose = false; } if (m_rect.leftClicked()) { - m_isOpen = (not m_isOpen); + m_nextClose = true; } Point pos = m_rect.pos.movedBy(0, m_rect.h); @@ -63,13 +68,14 @@ class Pulldown rect.leftClicked()) { m_index = i; - m_isOpen = false; + m_nextClose = true; break; } pos.y += m_rect.h; } } + return this; } void draw() const @@ -115,9 +121,10 @@ class Pulldown } } - void setPos(const Point& pos) + Pulldown* setPos(const Point& pos) { m_rect.setPos(pos); + return this; } const Rect& getRect() const @@ -163,6 +170,8 @@ class Pulldown int32 m_downButtonSize = 16; bool m_isOpen = false; + + bool m_nextClose = false; }; @@ -173,9 +182,42 @@ class PltKey { bool box; }; +class Terminal { +public: + struct Info{ + String display; + String ext; + String command; + bool canLoad; + String defSize; + }; + Array infolist; + Terminal(const Array& infos) { + infolist = infos; + ext = infolist[0].ext; + Array dispset; + for (Info& i : infolist) + dispset << i.display; + pd = Pulldown{ dispset }; + }; + inline static String ext; + Info getInfo() { + return infolist[pd.getIndex()]; + }; + Pulldown pd; +}; + /// @brief タイトルなどグラフ全体の設定 class WholeSetting { public: + Terminal terminal{ Array{ + {U"pngcairo",U"png",U"pngcairo enhanced",true, U"640 , 480"}, + {U"gif",U"gif",U"gif enhanced", true, U"640 , 480"}, + {U"svg *",U"svg",U"svg enhanced", false, U"640 , 480"}, + {U"pdfcairo *",U"pdf",U"pdfcairo enhanced",false, U"5in , 3in"}, + }}; + WithBool sizex; + WithBool sizey; WithBool title; WithBool xlabel; WithBool ylabel; diff --git a/pltGUI/ui_controller.h b/pltGUI/ui_controller.h index d24fdd8..f12d921 100644 --- a/pltGUI/ui_controller.h +++ b/pltGUI/ui_controller.h @@ -22,7 +22,7 @@ class UIController { void readPltFile() { - TextReader reader(U"result.plt"); + TextReader reader(U"plot.plt"); if (reader){ reader.readAll(pltFileTES.text); @@ -30,7 +30,7 @@ class UIController { } } void readPltImage() { - pltImageTexture = Texture(U"result.png"); + pltImageTexture = Texture(U"output.{}"_fmt(Terminal::ext)); } void drawPltViewPage() { @@ -38,13 +38,13 @@ class UIController { if (MyGUI::SaveIconButton(Vec2(700, 85))) { Optional path = Dialog::SaveFile(Array{ FileFilter{U"gnuplot",{U"plt"}},FileFilter::AllFiles() }); - if (path) FileSystem::Copy(U"result.plt", *path, CopyOption::OverwriteExisting); + if (path) FileSystem::Copy(U"plot.plt", *path, CopyOption::OverwriteExisting); } if (SimpleGUI::TextArea(pltFileTES, Vec2(50, 130), Size(700, 450), 1e10)) { - TextWriter writer(U"result.plt", TextEncoding::UTF8_NO_BOM); + TextWriter writer(U"plot.plt", TextEncoding::UTF8_NO_BOM); if (not writer) { - throw Error{ U"Failed to open `result.plt`" }; + throw Error{ U"Failed to open `plot.plt`" }; } writer.write(pltFileTES.text); } @@ -53,20 +53,32 @@ class UIController { void drawImageViewPage() { tabSpaceRect.draw(tabSpaceColor); + FilePath file = U"output.{}"_fmt(Terminal::ext); if (MyGUI::ReloadIconButton(Vec2(550, 85))) { readPltImage(); } if (MyGUI::SaveIconButton(Vec2(700, 85))) { - Optional path = Dialog::SaveFile(Array{ FileFilter::PNG(),FileFilter::JPEG(), FileFilter::AllFiles() }); - if (path) FileSystem::Copy(U"result.png", *path, CopyOption::OverwriteExisting); + Optional path = Dialog::SaveFile(Array{ FileFilter{whole.s.terminal.pd.getItem(),{Terminal::ext}}, FileFilter::AllFiles()}); + if (path) FileSystem::Copy(file, *path, CopyOption::OverwriteExisting); } - - if (not pltImageTexture.isEmpty()) { - pltImageTexture.drawAt(Scene::Center() + Vec2(0, 50)); + if (not FileSystem::Exists(file)) { + FontAsset(U"main")(file + U" is not exists.").drawAt(Scene::CenterF(), UIColor::text()); + } + else if (whole.s.terminal.getInfo().canLoad) { + if (not pltImageTexture.isEmpty()) { + pltImageTexture.drawAt(Scene::Center() + Vec2(0, 50)); + } + else { + FontAsset(U"main")(U"Failed to read "+file).drawAt(Scene::CenterF(), UIColor::text()); + } } else { - FontAsset(U"main")(U"Failed to read result.png").draw(50, 100, UIColor::text()); + FontAsset(U"main")(U"This {} file is unable to preview in this app."_fmt(Terminal::ext)).drawAt(Scene::CenterF(),UIColor::text()); + if (SimpleGUI::ButtonAt(U"Open with default app", Scene::CenterF() + Vec2(0, 50))) { + System::LaunchFile( file); + } + } } diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index 54de713..b5caa54 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -13,6 +13,22 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"Whole Setting Page", dpos.y(50)); + dpos.x(20); + MyGUI::Text(U"terminal", dpos.x(180)); + s.terminal.pd.setPos(dpos.x(170).asPoint() - Point(0, 15))->update()->draw(); + MyGUI::Text(U"default size : "+s.terminal.getInfo().defSize, dpos.y(55)); + Terminal::ext = s.terminal.getInfo().ext; + if (s.terminal.pd.isOpen()) { + MyGUI::Text(U"* : unable to preview\n in this app", Vec2(dpos) + Vec2(370,30)); + dpos.y(130); + } + MyGUI::CheckBoxArea(s.sizex.b, dpos.x(20)); + s.sizey.b = s.sizex.b; + MyGUI::Text(U"size", dpos.x(180)); + MyGUI::TextBox(s.sizex, dpos.x(190), Size(180, 36)); + MyGUI::Text(U" ,", dpos.x(30)); + MyGUI::TextBox(s.sizey, dpos.y(55), Size(180, 36)); + MyGUI::CheckBoxArea(s.title.b, dpos.x(20)); MyGUI::Text(U"title", dpos.x(180)); MyGUI::TextBox(s.title, dpos.y(55), Size(400, 36)); From ef71ef3b7c6b18066eedf4efed9cbc9a11169bc6 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sun, 4 Jun 2023 13:02:05 +0900 Subject: [PATCH 09/13] =?UTF-8?q?=E7=AF=84=E5=9B=B2=E9=81=B8=E6=8A=9E?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E4=BB=98=E3=81=8DTextArea=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90=E3=80=82UI=E3=81=AB=E5=8F=8D=E6=98=A0=E3=81=AF?= =?UTF-8?q?=E3=81=BE=E3=81=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/my_gui.h | 936 +++++++++++++++++++++++++++++++++++++++++ pltGUI/plt_setting.h | 20 +- pltGUI/ui_common.h | 17 + pltGUI/ui_controller.h | 12 +- 4 files changed, 961 insertions(+), 24 deletions(-) diff --git a/pltGUI/my_gui.h b/pltGUI/my_gui.h index 6e44be9..b94b609 100644 --- a/pltGUI/my_gui.h +++ b/pltGUI/my_gui.h @@ -7,6 +7,123 @@ namespace MyGUI { + constexpr double MinTextBoxWidth = 40.0; + constexpr double MinTextAreaHeight = 36.0; + constexpr double TextAreaScrollBarWidth = 3.0; + constexpr double TextAreaScrollBarMinHeight = 16.0; + constexpr ColorF TextAreaEditingTextBackgroundColor{ 0.8 }; + constexpr ColorF TextAreaSelectingTextBackgroundColor{ 0.8, 0.9, 1.0 }; + constexpr ColorF TextAreaScrollBarColor{ 0.67 }; + /// @brief テキストエリアの編集情報 | Text area editing information + struct TextAreaEditState + { + /// @brief テキスト | Text + String text; + + size_t cursorPos = 0; + + size_t rangeSelectFrom = 0; + bool rangeSelecting = 0; + + double scrollY = 0.0; + + bool refreshScroll = false; + + bool active = false; + + bool textChanged = false; + + size_t lineNum; + + Stopwatch leftPressStopwatch, rightPressStopwatch, cursorStopwatch; + + Stopwatch upPressStopwatch, downPressStopwatch; + + Array glyphs; + + Array> glyphPositions; + + struct ClipInfo + { + Vec2 pos; + + double width; + + uint32 index = 0; + + bool isEndOfLine = false; + + bool isLastLine = false; + + bool selected = false; + }; + + Array clipInfos; + + const size_t TextAreaTabSize = 12; + + SIV3D_NODISCARD_CXX20 + TextAreaEditState() = default; + + SIV3D_NODISCARD_CXX20 + TextAreaEditState(const String& defaultText) + : text{ defaultText } + , cursorPos{ defaultText.size() } + { + rebuildGlyphs(); + } + + SIV3D_NODISCARD_CXX20 + TextAreaEditState(String&& defaultText) noexcept + : text{ std::move(defaultText) } + , cursorPos{ text.size() } + { + rebuildGlyphs(); + } + + void clear() noexcept + { + text.clear(); + cursorPos = 0; + scrollY = 0.0; + glyphs.clear(); + resetStopwatches(); + } + + void resetStopwatches() noexcept + { + leftPressStopwatch.reset(); + rightPressStopwatch.reset(); + cursorStopwatch.reset(); + upPressStopwatch.reset(); + downPressStopwatch.reset(); + } + + void rebuildGlyphs() + { + const Font& font = SimpleGUI::GetFont(); + const double spaceWidth = font.spaceWidth(); + + glyphs = font.getGlyphs(text); + + for (auto& glyph : glyphs) + { + if (glyph.codePoint == U'\t') + { + glyph.xAdvance = (spaceWidth * TextAreaTabSize); + } + else if (IsControl(glyph.codePoint)) + { + glyph.xAdvance = 0; + } + } + } + + String getSelectingString() + { + return text.substr(Min(cursorPos, rangeSelectFrom), AbsDiff(cursorPos, rangeSelectFrom)); + } + }; bool TabButton(const StringView label, const Vec2& bottomCenter, const bool& selected, const SizeF& size = Size(120, 40)) { const Font& font = FontAsset(U"bold"); @@ -367,6 +484,825 @@ namespace MyGUI { return text.textChanged; } + static void TextAreaDraw(const TextAreaEditState& text, const Font& font, const int32 fontHeight, const RectF& region, + const RectF& textRenderRegion, const double textRenderRegionBottomY, + const double textCursorLineX, const double textCursorLineY0, const double textCursorLineY1, + const String& editingText, const Vec2& editingTextPos, const double maxScroll, const bool enabled) + { + // テキストエリアの描画 + if (enabled) + { + if (text.active) + { + region + .draw() + .drawFrame(0.0, 1.5, ColorF{ 0.35, 0.7, 1.0, 0.75 }) + .drawFrame(2.5, 0.0, ColorF{ 0.35, 0.7, 1.0 }); + + // 範囲選択領域の背景色描画 + for (const auto& clipInfo : text.clipInfos) + { + if (clipInfo.selected) + { + const auto& glyph = text.glyphs[clipInfo.index]; + RectF bgRect{ clipInfo.pos.x - 1 ,clipInfo.pos.y - glyph.getOffset().y , clipInfo.width + 2, fontHeight }; + bgRect.getOverlap(textRenderRegion).draw(TextAreaSelectingTextBackgroundColor); + } + } + } + else + { + region + .draw() + .drawFrame(2.0, 0.0, ColorF{ 0.5 }); + } + } + else + { + region + .draw(ColorF{ 0.9 }) + .drawFrame(2.0, 0.0, ColorF{ 0.67 }); + } + + // テキスト入力カーソルの描画 + if (text.active && enabled) + { + const bool showCursor = (text.cursorStopwatch.ms() % 1200 < 600) + || (text.leftPressStopwatch.isRunning() && (text.leftPressStopwatch < SecondsF{ 0.5 })) + || (text.rightPressStopwatch.isRunning() && (text.rightPressStopwatch < SecondsF{ 0.5 })) + || (text.upPressStopwatch.isRunning() && (text.upPressStopwatch < SecondsF{ 0.5 })) + || (text.downPressStopwatch.isRunning() && (text.downPressStopwatch < SecondsF{ 0.5 })); + + if (showCursor) + { + if ((textCursorLineY0 < textRenderRegionBottomY) + && (textRenderRegion.y < textCursorLineY1)) + { + const double x = (Math::Ceil(textCursorLineX) - 0.5); + Line{ x, textCursorLineY0, x, textCursorLineY1 }.stretched(-2).draw(1, Palette::Black); + } + } + } + + { + const ColorF textColor = UIColor::text(enabled ? UIState::active : UIState::disabled); + const auto& pixelShader = Font::GetPixelShader(font.method()); + + // テキストの描画 + { + const ScopedCustomShader2D shader{ pixelShader }; + + for (const auto& clipInfo : text.clipInfos) + { + const auto& glyph = text.glyphs[clipInfo.index]; + + if ((glyph.codePoint == U'\t') || (glyph.codePoint == U'\n')) + { + continue; + } + + glyph.texture.drawClipped(clipInfo.pos, textRenderRegion, textColor); + } + } + + if (editingText) + { + // 変換テキストとその領域の取得 + const Array editingGlyphs = font.getGlyphs(editingText); + Array editingGlyphPositions(editingGlyphs.size()); + { + Vec2 penPos = editingTextPos; + + for (size_t i = 0; i < editingGlyphs.size(); ++i) + { + const auto& glyph = editingGlyphs[i]; + editingGlyphPositions[i] = (penPos + glyph.getOffset()); + penPos.x += glyph.xAdvance; + } + } + + // 変換テキスト背景の描画 + if (editingGlyphs) + { + const auto& firstGlyph = editingGlyphs.front(); + const auto& lastGlyph = editingGlyphs.back(); + const Vec2 pos = (editingGlyphPositions.front() - firstGlyph.getOffset()); + const double w = ((editingGlyphPositions.back().x - lastGlyph.getOffset().x + lastGlyph.xAdvance) - pos.x); + RectF{ pos, w, fontHeight }.draw(TextAreaEditingTextBackgroundColor); + +# if SIV3D_PLATFORM(WINDOWS) + + // 変換テキストの選択範囲の描画 + { + const std::pair editingTarget = Platform::Windows::TextInput::GetCursorIndex(); + + if (editingTarget.second && ((editingTarget.first + editingTarget.second) <= editingGlyphPositions.size())) + { + const int32 firstIndex = editingTarget.first; + const int32 lastIndex = (editingTarget.first + editingTarget.second - 1); + const double x0 = editingGlyphPositions[firstIndex].x; + const double x1 = editingGlyphPositions[lastIndex].x + editingGlyphs[lastIndex].xAdvance; + RectF{ x0, (pos.y + fontHeight - 2), (x1 - x0), 2 }.draw(UIColor::text()); + } + } + +# endif + } + + // 変換テキストの描画 + { + const ScopedCustomShader2D shader{ pixelShader }; + + for (size_t i = 0; i < editingGlyphs.size(); ++i) + { + const auto& glyph = editingGlyphs[i]; + glyph.texture.draw(editingGlyphPositions[i], textColor); + } + } + } + } + + // スクロールバーの描画 + if (maxScroll) + { + const RectF scrollRegion = RectF{ textRenderRegion.tr().movedBy(2, 0), TextAreaScrollBarWidth, textRenderRegion.h }.stretched(0, -2); + const double scrollBarHeight = Max(((scrollRegion.h / (scrollRegion.h - maxScroll)) * scrollRegion.h), TextAreaScrollBarMinHeight); + const double scrollBaroffset = ((scrollRegion.h - scrollBarHeight) * (text.scrollY / maxScroll)); + RectF{ scrollRegion.pos.x, (scrollRegion.pos.y + scrollBaroffset), scrollRegion.w, scrollBarHeight }.rounded(TextAreaScrollBarWidth * 0.5).draw(TextAreaScrollBarColor); + } + } + + bool TextAreaAt(WithBool& textwb, const Vec2& center, const SizeF& size) + { + TextAreaEditState& text = textwb.v; + const bool enabled = textwb.b; + + text.cursorPos = Min(text.cursorPos, text.text.size()); + + const Font& font = SimpleGUI::GetFont(); + const int32 fontHeight = font.height(); + + const String previousText = text.text; + const String editingText = ((text.active && enabled) ? TextInput::GetEditingText() : U""); + + // テキストを更新する + { + if (text.active && enabled) + { + // 入力で選択範囲を上書き + if (String input = TextInput::GetRawInput(); + text.rangeSelecting && input && +# if SIV3D_PLATFORM(MACOS) + not (KeyCommand.pressed() || KeyControl.pressed()) +# else + not KeyControl.pressed() +# endif + ) + { + text.text.erase(Min(text.cursorPos, text.rangeSelectFrom), AbsDiff(text.cursorPos, text.rangeSelectFrom)); + text.cursorPos = Min(text.cursorPos, text.rangeSelectFrom); + text.rangeSelecting = false; + if (input.includes(U'\b')) + { + text.text.insert(text.text.begin() + text.cursorPos, U' '); + ++text.cursorPos; + } + else if (input.includes(char32(0x7F))) + { + text.text.insert(text.text.begin() + text.cursorPos, U' '); + } + } + + // ショートカットキーによるペースト + if ((not editingText) && +# if SIV3D_PLATFORM(MACOS) + ((KeyCommand + KeyV).down() || (KeyControl + KeyV).down()) +# else + (KeyControl + KeyV).down() +# endif + ) + { + if (text.rangeSelecting) + { + text.text.erase(Min(text.cursorPos, text.rangeSelectFrom), AbsDiff(text.cursorPos, text.rangeSelectFrom)); + text.cursorPos = Min(text.cursorPos, text.rangeSelectFrom); + text.rangeSelecting = false; + } + if (String paste; Clipboard::GetText(paste)) + { + text.text.insert(text.cursorPos, paste); + text.cursorPos += paste.size(); + } + } + + // ショートカットキーによるコピー + if ((not editingText) && text.rangeSelecting && +# if SIV3D_PLATFORM(MACOS) + ((KeyCommand + KeyC).down() || (KeyControl + KeyC).down()) +# else + (KeyControl + KeyC).down() +# endif + ) + { + Clipboard::SetText(text.getSelectingString()); + } + + // ショートカットキーによる切り取り + if ((not editingText) && text.rangeSelecting && +# if SIV3D_PLATFORM(MACOS) + ((KeyCommand + KeyX).down() || (KeyControl + KeyX).down()) +# else + (KeyControl + KeyX).down() +# endif + ) + { + Clipboard::SetText(text.getSelectingString()); + text.text.erase(Min(text.cursorPos, text.rangeSelectFrom), AbsDiff(text.cursorPos, text.rangeSelectFrom)); + text.cursorPos = Min(text.cursorPos, text.rangeSelectFrom); + text.rangeSelecting = false; + } + + // ショートカットキーによる全選択 + if ((not editingText) && +# if SIV3D_PLATFORM(MACOS) + ((KeyCommand + KeyA).down() || (KeyControl + KeyA).down()) +# else + (KeyControl + KeyA).down() +# endif + ) + { + text.rangeSelectFrom = 0; + text.cursorPos = text.text.size(); + text.rangeSelecting = true; + } + + // text.text を更新する + text.cursorPos = TextInput::UpdateText(text.text, text.cursorPos, TextInputMode::AllowEnterTabBackSpaceDelete); + + } + + /* + // 最大字数を超えていたら削る + if (maxChars < text.text.size()) + { + text.text.resize(maxChars); + text.cursorPos = Min(text.cursorPos, maxChars); + } + */ + + // 文字列に変更があったかを調べる + text.textChanged = (text.text != previousText); + + // 文字列に変更があれば + if (text.textChanged) + { + // カーソル点滅をリセットする + text.cursorStopwatch.restart(); + + // グリフを再構築する + text.rebuildGlyphs(); + } + } + + // テキストエリア + const RectF region{ Arg::center = center, Max(size.x, MinTextBoxWidth), Max(size.y, MinTextAreaHeight) }; + + // 入力カーソルのアクティブ / 非アクティブを切り替える + if (MouseL.down() && (TextInput::GetEditingText().isEmpty())) + { + if (Cursor::OnClientRect() && region.mouseOver()) + { + text.active = true; + text.resetStopwatches(); + } + else + { + text.active = false; + } + } + + const RectF textRenderRegion = region.stretched(-2, -(6 + TextAreaScrollBarWidth), -2, -8); + const double textRenderRegionRightX = textRenderRegion.rightX(); + const double textRenderRegionBottomY = textRenderRegion.bottomY(); + + double textCursorLineX = 0.0, textCursorLineY0 = 0.0, textCursorLineY1 = 0.0; + if (text.active && (text.cursorPos == 0)) + { + textCursorLineX = textRenderRegion.x; + textCursorLineY0 = (textRenderRegion.y + text.scrollY); + textCursorLineY1 = (textCursorLineY0 + fontHeight); + } + + Vec2 editingTextPos = textRenderRegion.pos; + double newScrollY = Min(text.scrollY + (region.mouseOver() ? (Mouse::Wheel() * -fontHeight * 0.5) : 0.0), 0.0); + double scrollOffset = 0.0; + uint16 maxRow = 0; + { + text.glyphPositions.clear(); + text.clipInfos.clear(); + text.lineNum = 0; + + Vec2 penPos = textRenderRegion.pos; + uint16 row = 0; + uint16 column = 1; + + // 入力した文字列の各文字と、位置と描画領域を記録する。 + for (auto&& [index, glyph] : Indexed(text.glyphs)) + { + // 改行文字であるか + bool isLF = false; + + // 改行が発生したか + bool isLineBreak = false; + + // 改行の場合、描画位置を下にずらす + if (glyph.codePoint == U'\n') + { + text.lineNum++; + isLF = true; + penPos.x = textRenderRegion.x; + penPos.y += fontHeight; + column = 0; + maxRow = ++row; + } + + const double xAdvance = glyph.xAdvance; + + Vec2 glyphPos = penPos.movedBy(0, text.scrollY); + { + // テキストがテキスト描画領域右端からはみ出る場合、テキストを枠内に収めるようにテキストを折り返す + if (textRenderRegionRightX < (glyphPos.x + xAdvance)) + { + penPos.x = textRenderRegion.x; + penPos.y += fontHeight; + isLineBreak = true; + column = 1; + maxRow = ++row; + } + + // テキストの描画位置のオフセットを決定する + if ((index + 1) == text.cursorPos) + { + const double d1 = ((penPos.y + fontHeight + newScrollY) - textRenderRegionBottomY); + const double d2 = (textRenderRegion.y - (penPos.y + newScrollY)); + + if (0.0 < d1) + { + scrollOffset = -d1; + } + else if (0.0 < d2) + { + scrollOffset = d2; + } + } + + glyphPos = (penPos + glyph.getOffset() + Vec2{ 0, text.scrollY }); + } + + /* + // グリフのクリップ領域(描画矩形)を決める + RectF clipRect{ 0 }; + { + // x 方向のクリップを決める + if (InRange(glyphPos.x, (textRenderRegion.x - xAdvance), textRenderRegion.x)) + { + clipRect.x = textRenderRegion.x; + clipRect.w = ((glyphPos.x + xAdvance - textRenderRegion.x) - glyph.getOffset().x); + } + else if (InRange(glyphPos.x, textRenderRegion.x, (textRenderRegionRightX - xAdvance))) + { + clipRect.x = glyphPos.x; + clipRect.w = (xAdvance - glyph.getOffset().x); + } + else if (InRange(glyphPos.x, (textRenderRegionRightX - xAdvance), textRenderRegionRightX)) + { + clipRect.x = glyphPos.x; + clipRect.w = ((textRenderRegionRightX - glyphPos.x) - glyph.getOffset().x); + } + // y 方向のクリップを決める + if (InRange(glyphPos.y, (textRenderRegion.y - fontHeight), textRenderRegion.y)) + { + clipRect.y = textRenderRegion.y; + clipRect.h = (glyphPos.y + fontHeight - textRenderRegion.y); + } + else if (InRange(glyphPos.y, textRenderRegion.y, (textRenderRegion.y + size.y - fontHeight))) + { + clipRect.y = glyphPos.y; + clipRect.h = fontHeight; + } + else if (InRange(glyphPos.y, (textRenderRegionBottomY - fontHeight), textRenderRegionBottomY)) + { + clipRect.y = glyphPos.y; + clipRect.h = (textRenderRegionBottomY - glyphPos.y); + } + } + */ + + // テキストエリアの範囲内にある文字のみ描画対象に加える。 + if (InRange(glyphPos.x, (textRenderRegion.x - xAdvance), textRenderRegionRightX) + && InRange(glyphPos.y, (textRenderRegion.y - fontHeight - glyph.yAdvance), (textRenderRegionBottomY + fontHeight * 2 - glyph.yAdvance))) + { + bool selected = text.rangeSelecting && InRange(index, Min(text.cursorPos, text.rangeSelectFrom), Max(text.cursorPos, text.rangeSelectFrom) - 1); + if (Max(text.cursorPos, text.rangeSelectFrom) == 0) + { + selected = false; + } + + if (isLF) + { + if (text.clipInfos) + { + text.clipInfos.back().isEndOfLine = true; + } + + text.clipInfos.push_back({ glyphPos, xAdvance, static_cast(index), false, false, selected }); + } + else + { + const bool isEndOfText = (index == (text.glyphs.size() - 1)); + + if (isLineBreak && text.clipInfos) + { + text.clipInfos.back().isEndOfLine = true; + } + + text.clipInfos.push_back({ glyphPos, xAdvance, static_cast(index), isEndOfText, false, selected }); + } + } + + { + text.glyphPositions.emplace_back(row, column); + ++column; + } + + // テキストカーソルの位置の計算を計算する + if (text.active && (text.cursorPos == (index + 1))) + { + double yBegin = 0.0, yEnd = 0.0; + + if ((penPos.y + text.scrollY) < textRenderRegion.y) + { + yBegin = textRenderRegion.y; + } + else + { + yBegin = (penPos.y + text.scrollY); + } + + if (textRenderRegionBottomY < (penPos.y + fontHeight + text.scrollY)) + { + yEnd = textRenderRegionBottomY; + } + else + { + yEnd = (penPos.y + fontHeight + text.scrollY); + } + + if ((textRenderRegionRightX < (glyphPos.x + xAdvance)) + || ((glyphPos.x + xAdvance) < textRenderRegion.x)) + { + yBegin = 0.0; + yEnd = 0.0; + } + + //textCursorLineX = (glyphPos.x + (isLF ? 0 : clipRect.w)); + textCursorLineX = (glyphPos.x + (isLF ? 0 : xAdvance) + 1); + textCursorLineY0 = yBegin; + textCursorLineY1 = yEnd; + + //editingTextPos = Vec2{ (glyphPos.x + (isLF ? 0 : clipRect.w)), (penPos.y + text.scrollY) }; + editingTextPos = Vec2{ (glyphPos.x + (isLF ? 0 : xAdvance) + 1), (penPos.y + text.scrollY) }; + } + + if (isLF) + { + continue; + } + + penPos.x += xAdvance; + } + + // テキストカーソルの位置の計算を計算する + if (text.active && (text.cursorPos == 0)) + { + double yBegin = 0.0, yEnd = 0.0; + + if ((textRenderRegion.y + text.scrollY) < textRenderRegion.y) + { + yBegin = textRenderRegion.y; + } + else + { + yBegin = (textRenderRegion.y + text.scrollY); + } + + if (textRenderRegionBottomY < (textRenderRegion.y + fontHeight + text.scrollY)) + { + yEnd = textRenderRegionBottomY; + } + else + { + yEnd = (textRenderRegion.y + fontHeight + text.scrollY); + } + + textCursorLineX = textRenderRegion.x; + textCursorLineY0 = yBegin; + textCursorLineY1 = yEnd; + + editingTextPos = Vec2{ textRenderRegion.x, (textRenderRegion.y + text.scrollY) }; + } + } + + // テキストカーソルを更新する + if (text.glyphPositions) + { + if (text.refreshScroll) + { + if (text.cursorPos == 0) + { + newScrollY = 0.0; + } + else + { + newScrollY = (text.scrollY + scrollOffset); + } + + text.refreshScroll = false; + } + + text.refreshScroll |= (text.textChanged || editingText); + + if (text.active && enabled && (not editingText)) + { + // キーでテキストカーソルを移動させる + // 一定時間押下すると、テキストカーソルが高速に移動 + + // テキストカーソルを先頭へ移動させる + if ((KeyControl + KeyHome).down()) // [ctrl] + [home]: 全体の先頭へ + { + text.cursorPos = 0; + text.cursorStopwatch.restart(); + text.refreshScroll = true; + } + else if ( +# if SIV3D_PLATFORM(MACOS) + ((KeyControl + KeyA).down() || KeyHome.down()) +# else + KeyHome.down() +# endif + ) // [home]: 行頭へ + { + for (int32 i = (static_cast(text.cursorPos) - 1); 0 <= i; --i) + { + if (text.glyphs[i].codePoint == '\n') + { + text.cursorPos = (i + 1); + text.cursorStopwatch.restart(); + text.refreshScroll = true; + break; + } + else if (i == 0) + { + text.cursorPos = 0; + text.cursorStopwatch.restart(); + text.refreshScroll = true; + break; + } + } + } + + // テキストカーソルを末尾へ移動させる + if ((KeyControl + KeyEnd).down()) // [ctrl] + [end]: 全体の末尾へ + { + text.cursorPos = text.text.size(); + text.cursorStopwatch.restart(); + text.refreshScroll = true; + } + else if ( +# if SIV3D_PLATFORM(MACOS) + ((KeyControl + KeyE).down() || KeyEnd.down()) +# else + KeyEnd.down() +# endif + ) // [end]: 行末へ + { + for (size_t i = text.cursorPos; i <= text.text.size(); ++i) + { + if (i == text.text.size()) + { + text.cursorPos = text.text.size(); + text.cursorStopwatch.restart(); + text.refreshScroll = true; + break; + } + else if (text.glyphs[i].codePoint == '\n') + { + text.cursorPos = i; + text.cursorStopwatch.restart(); + text.refreshScroll = true; + break; + } + } + } + + // [←] キー + if ((0 < text.cursorPos) + && (KeyLeft.down() || ((SecondsF{ 0.33 } < KeyLeft.pressedDuration()) && (SecondsF{ 0.06 } < text.leftPressStopwatch)))) + { + --text.cursorPos; + text.leftPressStopwatch.restart(); + text.refreshScroll = true; + } + + // [→] キー + if ((text.cursorPos < text.text.size()) + && (KeyRight.down() || ((SecondsF{ 0.33 } < KeyRight.pressedDuration()) && (SecondsF{ 0.06 } < text.rightPressStopwatch)))) + { + ++text.cursorPos; + 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); + + if (0 < currentRow) + { + for (int32 i = (static_cast(text.cursorPos) - 1); 0 <= i; --i) + { + if (i == 0) + { + text.cursorPos = 0; + break; + } + + const auto& glyphPosition = text.glyphPositions[i - 1]; + const int32 row = glyphPosition.first; + const int32 column = glyphPosition.second; + + if (row < currentRow) + { + if ((row + 1) < currentRow) + { + text.cursorPos = (i + 1); + break; + } + + if (column <= currentColumn) + { + text.cursorPos = i; + break; + } + } + } + } + + text.upPressStopwatch.restart(); + text.refreshScroll = true; + } + + // [↓] キーでテキストカーソルを下に移動させる + if (KeyDown.down() || ((SecondsF{ 0.33 } < KeyDown.pressedDuration()) && (SecondsF{ 0.06 } < text.downPressStopwatch))) + { + const int32 maxCursorIndex = static_cast(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); + + if (currentRow < (text.glyphPositions.back().first)) + { + for (int32 i = (static_cast(text.cursorPos) + 1); i <= maxCursorIndex; ++i) + { + const auto& glyphPosition = text.glyphPositions[i - 1]; + const int32 row = glyphPosition.first; + const int32 column = glyphPosition.second; + + if (currentRow < row) + { + if ((currentRow + 1) < row) + { + text.cursorPos = (i - 1); + break; + } + + if (currentColumn <= column) + { + text.cursorPos = i; + break; + } + } + + if (i == maxCursorIndex) + { + text.cursorPos = maxCursorIndex; + break; + } + } + } + + text.downPressStopwatch.restart(); + text.refreshScroll = true; + } + } + } + + // テキストエリアクリックでテキストカーソルを移動させる + if (const Vec2 cursorPos = Cursor::PosF(); + enabled && textRenderRegion.intersects(cursorPos) && MouseL.pressed()) + { + if (text.clipInfos) + { + text.cursorPos = text.clipInfos.front().index; + } + + // 最後の行の文字をマーク + if (1 <= text.clipInfos.size()) + { + auto it = text.clipInfos.rbegin(); + + it->isLastLine = true; + it->isEndOfLine = true; + + ++it; + + for (; it != text.clipInfos.rend(); ++it) + { + if (it->isEndOfLine) + { + break; + } + + it->isLastLine = true; + } + } + + // カーソルの移動先を求める + for (const auto& clipInfo : text.clipInfos) + { + const auto& glyph = text.glyphs[clipInfo.index]; + + const Vec2 penPos = (clipInfo.pos - glyph.getOffset()); + + RectF rect{ penPos, glyph.xAdvance, fontHeight }; + + if (clipInfo.isEndOfLine) + { + rect.w = (textRenderRegionRightX - rect.x); + } + + if (clipInfo.isLastLine) + { + rect.h = (textRenderRegionBottomY - rect.y); + } + + if (rect.intersects(cursorPos)) + { + text.cursorPos = (clipInfo.index + ((glyph.xAdvance / 2) <= (cursorPos.x - penPos.x))); + text.cursorStopwatch.restart(); + break; + } + } + } + + if (MouseL.down() && not KeyShift.pressed() || + (not KeyShift.pressed() && (KeyLeft | KeyRight | KeyUp | KeyDown).down())) + { + text.rangeSelecting = false; + //text.rangeSelectFrom = text.cursorPos; + } + else if (text.active && ((KeyShift.pressed() && (KeyLeft | KeyRight | KeyUp | KeyDown).down() || MouseL.down()) || (MouseL.pressed() && not MouseL.down()))) + { + text.rangeSelecting = true; + } + else if (MouseL.up() && text.rangeSelectFrom == text.cursorPos) + { + text.rangeSelecting = false; + } + if (not text.rangeSelecting) + { + text.rangeSelectFrom = text.cursorPos; + } + + const double maxScroll = Min(-((maxRow + 1.5) * fontHeight - region.h), 0.0); + text.scrollY = Clamp(newScrollY, maxScroll, 0.0); + + //描画 + TextAreaDraw(text, font, fontHeight, region, textRenderRegion, textRenderRegionBottomY, + textCursorLineX, textCursorLineY0, textCursorLineY1, + editingText, editingTextPos, maxScroll, enabled); + + return text.textChanged; + } + + bool TextArea(WithBool& textwb, const Vec2& pos, const SizeF& size) + { + const double width = Max(size.x, MinTextBoxWidth); + const double height = Max(size.y, MinTextAreaHeight); + return TextAreaAt(textwb, pos.movedBy((width * 0.5), (height * 0.5)) - Vec2(0,18), SizeF{width, height}); + } + void RadioButtonCircle(UIState uis, const Vec2& center) { const double size = 24; const Circle outerCiecle{ center,size / 2 }; diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index fe6b13f..032ebae 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -1,23 +1,7 @@ #pragma once +#include "my_gui.h" -/// @brief T型の値と、bool値を保持 -/// @brief pltのオプションの値とは別にそれを使用するかどうかに使う -template -class WithBool { -public: - WithBool(bool _b=false) :b(_b) {}; - bool b = false; - T v; -}; - -/// @brief void型の時の完全特殊化 -template <> -class WithBool { -public: - bool b = false; -}; - class Pulldown { public: @@ -218,7 +202,7 @@ class WholeSetting { }}; WithBool sizex; WithBool sizey; - WithBool title; + WithBool title; WithBool xlabel; WithBool ylabel; WithBool xrange_min; diff --git a/pltGUI/ui_common.h b/pltGUI/ui_common.h index e91cfbd..cf2cf43 100644 --- a/pltGUI/ui_common.h +++ b/pltGUI/ui_common.h @@ -1,5 +1,22 @@ #pragma once +/// @brief T型の値と、bool値を保持 +/// @brief pltのオプションの値とは別にそれを使用するかどうかに使う +template +class WithBool { +public: + WithBool(bool _b = false) :b(_b) {}; + bool b = false; + T v; +}; + +/// @brief void型の時の完全特殊化 +template <> +class WithBool { +public: + bool b = false; +}; + class UIState { public: enum E { diff --git a/pltGUI/ui_controller.h b/pltGUI/ui_controller.h index f12d921..8aa5ff0 100644 --- a/pltGUI/ui_controller.h +++ b/pltGUI/ui_controller.h @@ -17,7 +17,7 @@ class UIController { WholeSettingUI whole; Array graphs{ 1 }; - TextAreaEditState pltFileTES; + WithBool pltFileTES{true}; Texture pltImageTexture; @@ -25,8 +25,8 @@ class UIController { TextReader reader(U"plot.plt"); if (reader){ - reader.readAll(pltFileTES.text); - pltFileTES.rebuildGlyphs(); + reader.readAll(pltFileTES.v.text); + pltFileTES.v.rebuildGlyphs(); } } void readPltImage() { @@ -40,13 +40,13 @@ class UIController { Optional path = Dialog::SaveFile(Array{ FileFilter{U"gnuplot",{U"plt"}},FileFilter::AllFiles() }); if (path) FileSystem::Copy(U"plot.plt", *path, CopyOption::OverwriteExisting); } - - if (SimpleGUI::TextArea(pltFileTES, Vec2(50, 130), Size(700, 450), 1e10)) { + + if (MyGUI::TextAreaAt(pltFileTES, Scene::CenterF()+Vec2(0,50), Size(700, 450))) { TextWriter writer(U"plot.plt", TextEncoding::UTF8_NO_BOM); if (not writer) { throw Error{ U"Failed to open `plot.plt`" }; } - writer.write(pltFileTES.text); + writer.write(pltFileTES.v.text); } } From 8d50dca9f7897ab7fe30c1c9a160c43ff2baf61a Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sun, 4 Jun 2023 15:54:13 +0900 Subject: [PATCH 10/13] =?UTF-8?q?=E7=AF=84=E5=9B=B2=E9=81=B8=E6=8A=9E?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E4=BB=98=E3=81=8DTextArea=E3=81=AB=E7=BD=AE?= =?UTF-8?q?=E3=81=8D=E6=8F=9B=E3=81=88=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/app_option.h | 2 +- pltGUI/my_gui.h | 40 ++++++++++++++++---- pltGUI/plt_setting.h | 58 +++++++++++++++++----------- pltGUI/ui_common.h | 9 +++++ pltGUI/ui_plt_setting.h | 84 ++++++++++++++++++++++------------------- 5 files changed, 125 insertions(+), 68 deletions(-) diff --git a/pltGUI/app_option.h b/pltGUI/app_option.h index e892c7f..247865f 100644 --- a/pltGUI/app_option.h +++ b/pltGUI/app_option.h @@ -23,7 +23,7 @@ class AppOption { } dpos += Vec2(0,100); - MyGUI::RadioButtonAreas(colorTypeIndex, Array{ dpos+Vec2(160, 0),dpos+Vec2(270,0) }, Array{ Vec2(60, 50) }); + MyGUI::RadioButtonAreas(colorTypeIndex, Array{ dpos+Vec2(160, 0),dpos+Vec2(270,0) }, Array{ Size(60, 50) }); MyGUI::Text(U"plt color as ", dpos+Vec2(20, 0)); MyGUI::Text(U"RGB", dpos+Vec2(180, 0)); MyGUI::Text(U"HSV", dpos+Vec2(290, 0)); diff --git a/pltGUI/my_gui.h b/pltGUI/my_gui.h index b94b609..4254d65 100644 --- a/pltGUI/my_gui.h +++ b/pltGUI/my_gui.h @@ -17,6 +17,28 @@ namespace MyGUI { /// @brief テキストエリアの編集情報 | Text area editing information struct TextAreaEditState { + + TextAreaEditState operator = (const TextAreaEditState& other) { + text = other.text; + cursorPos = other.cursorPos; + rangeSelectFrom = other.rangeSelectFrom; + rangeSelecting = other.rangeSelecting; + scrollY = other.scrollY; + refreshScroll = other.refreshScroll; + active = other.active; + textChanged = other.textChanged; + lineNum = other.lineNum; + leftPressStopwatch = other.leftPressStopwatch; + rightPressStopwatch = other.rightPressStopwatch; + cursorStopwatch = other.cursorStopwatch; + upPressStopwatch = other.upPressStopwatch; + downPressStopwatch = other.downPressStopwatch; + glyphs = other.glyphs; + glyphPositions = other.glyphPositions; + clipInfos = other.clipInfos; + return *this; + } + /// @brief テキスト | Text String text; @@ -33,7 +55,7 @@ namespace MyGUI { bool textChanged = false; - size_t lineNum; + int32 lineNum = 0; Stopwatch leftPressStopwatch, rightPressStopwatch, cursorStopwatch; @@ -62,10 +84,8 @@ namespace MyGUI { const size_t TextAreaTabSize = 12; - SIV3D_NODISCARD_CXX20 TextAreaEditState() = default; - SIV3D_NODISCARD_CXX20 TextAreaEditState(const String& defaultText) : text{ defaultText } , cursorPos{ defaultText.size() } @@ -73,7 +93,6 @@ namespace MyGUI { rebuildGlyphs(); } - SIV3D_NODISCARD_CXX20 TextAreaEditState(String&& defaultText) noexcept : text{ std::move(defaultText) } , cursorPos{ text.size() } @@ -123,6 +142,10 @@ namespace MyGUI { { return text.substr(Min(cursorPos, rangeSelectFrom), AbsDiff(cursorPos, rangeSelectFrom)); } + + Size size(const size_t& width=600) { + return Size(width, 36 + 30 * lineNum); + } }; bool TabButton(const StringView label, const Vec2& bottomCenter, const bool& selected, const SizeF& size = Size(120, 40)) { @@ -818,7 +841,6 @@ namespace MyGUI { // 改行の場合、描画位置を下にずらす if (glyph.codePoint == U'\n') { - text.lineNum++; isLF = true; penPos.x = textRenderRegion.x; penPos.y += fontHeight; @@ -859,6 +881,10 @@ namespace MyGUI { glyphPos = (penPos + glyph.getOffset() + Vec2{ 0, text.scrollY }); } + if (isLF or isLineBreak) { + text.lineNum++; + } + /* // グリフのクリップ領域(描画矩形)を決める RectF clipRect{ 0 }; @@ -1285,7 +1311,7 @@ namespace MyGUI { text.rangeSelectFrom = text.cursorPos; } - const double maxScroll = Min(-((maxRow + 1.5) * fontHeight - region.h), 0.0); + const double maxScroll = Min(-((maxRow) * fontHeight - region.h), 0.0); text.scrollY = Clamp(newScrollY, maxScroll, 0.0); //描画 @@ -1313,7 +1339,7 @@ namespace MyGUI { if (uis.isActive()) innerCiecle.draw(UIColor::Accent); } - bool RadioButtonAreas(int& index, const Array& leftCenters, const Array& areaSizes) { + bool RadioButtonAreas(int& index, const Array& leftCenters, const Array& areaSizes) { const size_t dataSize = leftCenters.size(); const bool canMouseOver = scrollSpaceRect.mouseOver() && Window::GetState().focused; const int previousValue = index; diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 032ebae..321d8bb 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -200,23 +200,23 @@ class WholeSetting { {U"svg *",U"svg",U"svg enhanced", false, U"640 , 480"}, {U"pdfcairo *",U"pdf",U"pdfcairo enhanced",false, U"5in , 3in"}, }}; - WithBool sizex; - WithBool sizey; + WithBool sizex; + WithBool sizey; WithBool title; - WithBool xlabel; - WithBool ylabel; - WithBool xrange_min; - WithBool xrange_max; - WithBool yrange_min; - WithBool yrange_max; + WithBool xlabel; + WithBool ylabel; + WithBool xrange_min; + WithBool xrange_max; + WithBool yrange_min; + WithBool yrange_max; WithBool logscale_x; WithBool logscale_y; WithBool logscale_x_exp_not;//exponential notation WithBool logscale_y_exp_not;//exponential notation - WithBool sample; + WithBool sample; WithBool key{ true }; - WithBool xtics; - WithBool ytics; + WithBool xtics; + WithBool ytics; WithBool grid; WithBool loadfile; }; @@ -225,19 +225,35 @@ class WholeSetting { /// @brief 色などグラフごとの設定 class GraphSetting { - enum class LineTypeE; public: + GraphSetting operator = (const GraphSetting& other) { + graph_index = other.graph_index; + graph_func = other.graph_func; + graph_data = other.graph_data; + using_x = other.using_x; + using_y = other.using_y; + title = other.title; + linecolor = other.linecolor; + withlines = other.withlines; + linewidth = other.linewidth; + linetype = other.linetype; + withpoints = other.withpoints; + pointsize = other.pointsize; + pointtype = other.pointtype; + return *this; + } + int graph_index = 0; - WithBool graph_func; - WithBool graph_data; - WithBool using_x; - WithBool using_y; - WithBool title; + WithBool graph_func; + WithBool graph_data; + WithBool using_x; + WithBool using_y; + WithBool title; WithBool linecolor; WithBool withlines; - WithBool linewidth; - WithBool linetype; + WithBool linewidth; + WithBool linetype; WithBool withpoints; - WithBool pointsize; - WithBool pointtype; + WithBool pointsize; + WithBool pointtype; }; diff --git a/pltGUI/ui_common.h b/pltGUI/ui_common.h index cf2cf43..5b724ac 100644 --- a/pltGUI/ui_common.h +++ b/pltGUI/ui_common.h @@ -5,6 +5,11 @@ template class WithBool { public: + WithBool operator = (const WithBool& other) { + b = other.b; + v = other.v; + return *this; + } WithBool(bool _b = false) :b(_b) {}; bool b = false; T v; @@ -14,6 +19,10 @@ class WithBool { template <> class WithBool { public: + WithBool operator = (const WithBool& other) { + b = other.b; + return *this; + } bool b = false; }; diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index b5caa54..d3fe196 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -7,6 +7,7 @@ /// @brief 全体設定の入力UI class WholeSettingUI : public ScrollableUI { public: + const Size padding{0,14}; WholeSetting s; void draw() { Scroll(); @@ -22,38 +23,38 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"* : unable to preview\n in this app", Vec2(dpos) + Vec2(370,30)); dpos.y(130); } - MyGUI::CheckBoxArea(s.sizex.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.sizex.b, dpos.x(20), Size(600,Max(s.sizex.v.size().y,s.sizey.v.size().y))+padding); s.sizey.b = s.sizex.b; MyGUI::Text(U"size", dpos.x(180)); - MyGUI::TextBox(s.sizex, dpos.x(190), Size(180, 36)); + MyGUI::TextArea(s.sizex, dpos.x(190), s.sizex.v.size(180)); MyGUI::Text(U" ,", dpos.x(30)); - MyGUI::TextBox(s.sizey, dpos.y(55), Size(180, 36)); + MyGUI::TextArea(s.sizey, dpos.y(55+30*Max(s.sizex.v.lineNum, s.sizey.v.lineNum)), s.sizey.v.size(180)); - MyGUI::CheckBoxArea(s.title.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.title.b, dpos.x(20), s.title.v.size(600)+padding); MyGUI::Text(U"title", dpos.x(180)); - MyGUI::TextBox(s.title, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.title, dpos.y(55 + s.title.v.lineNum * 30), s.title.v.size(400)); - MyGUI::CheckBoxArea(s.xlabel.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.xlabel.b, dpos.x(20),s.xlabel.v.size(600)+padding); MyGUI::Text(U"xlabel", dpos.x(180)); - MyGUI::TextBox(s.xlabel, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.xlabel, dpos.y(55 + s.xlabel.v.lineNum * 30), s.xlabel.v.size(400)); - MyGUI::CheckBoxArea(s.ylabel.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.ylabel.b, dpos.x(20),s.ylabel.v.size(600)+padding); MyGUI::Text(U"ylabel", dpos.x(180)); - MyGUI::TextBox(s.ylabel, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.ylabel, dpos.y(55+s.ylabel.v.lineNum*30), s.ylabel.v.size(400)); - MyGUI::CheckBoxArea(s.xrange_min.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.xrange_min.b, dpos.x(20),Size(600,Max(s.xrange_min.v.size().y, s.xrange_max.v.size().y))+padding); s.xrange_max.b = s.xrange_min.b; MyGUI::Text(U"xrange", dpos.x(180)); - MyGUI::TextBox(s.xrange_min, dpos.x(190), Size(180, 36)); + MyGUI::TextArea(s.xrange_min, dpos.x(190), s.xrange_min.v.size(180)); MyGUI::Text(U"~", dpos.x(30)); - MyGUI::TextBox(s.xrange_max, dpos.y(55), Size(180, 36)); + MyGUI::TextArea(s.xrange_max, dpos.y(55+ 30 * Max(s.xrange_min.v.lineNum, s.xrange_max.v.lineNum)), s.xrange_max.v.size(180)); - MyGUI::CheckBoxArea(s.yrange_min.b, dpos.x(20)); + MyGUI::CheckBoxArea(s.yrange_min.b, dpos.x(20), Size(600, Max(s.yrange_min.v.size().y, s.yrange_max.v.size().y)) + padding); s.yrange_max.b = s.yrange_min.b; MyGUI::Text(U"yrange", dpos.x(180)); - MyGUI::TextBox(s.yrange_min, dpos.x(190), Size(180, 36)); + MyGUI::TextArea(s.yrange_min, dpos.x(190), s.yrange_min.v.size(180)); MyGUI::Text(U"~", dpos.x(30)); - MyGUI::TextBox(s.yrange_max, dpos.y(55), Size(180, 36)); + MyGUI::TextArea(s.yrange_max, dpos.y(55+ 30 * Max(s.yrange_min.v.lineNum, s.yrange_max.v.lineNum)), s.yrange_max.v.size(180)); dpos.x(20); MyGUI::Text(U"logscale", dpos.x(200)); @@ -71,9 +72,9 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"10 notation", dpos); dpos.y(55); - MyGUI::CheckBoxArea(s.sample.b, dpos.x(20), Vec2(400, 50)); + MyGUI::CheckBoxArea(s.sample.b, dpos.x(20), s.sample.v.size(600)+padding); MyGUI::Text(U"sample", dpos.x(180)); - MyGUI::TextBox(s.sample, dpos.y(55)); + MyGUI::TextArea(s.sample, dpos.y(55+ s.sample.v.lineNum*30),s.sample.v.size(400)); MyGUI::CheckBoxArea(s.key.b, dpos.x(20), s.key.v.pos.isOpen() ? Vec2(600, 250) : Vec2(600, 50)); MyGUI::Text(U"key", dpos.x(180)); @@ -88,12 +89,12 @@ class WholeSettingUI : public ScrollableUI { dpos.x(20); MyGUI::Text(U"tics", dpos.x(200)); - MyGUI::CheckBoxArea(s.xtics.b, dpos.x(20), Size(160, 50)); + MyGUI::CheckBoxArea(s.xtics.b, dpos.x(20), s.xtics.v.size(160)+padding); MyGUI::Text(U"x", dpos.x(20)); - MyGUI::TextBox(s.xtics, dpos.x(170), Size(120, 36)); - MyGUI::CheckBoxArea(s.ytics.b, dpos.x(20), Size(160, 50)); + MyGUI::TextArea(s.xtics, dpos.x(170), s.xtics.v.size(120)); + MyGUI::CheckBoxArea(s.ytics.b, dpos.x(20), s.ytics.v.size(160) + padding); MyGUI::Text(U"y", dpos.x(20)); - MyGUI::TextBox(s.ytics, dpos.y(55), Size(120, 36)); + MyGUI::TextArea(s.ytics, dpos.y(55+30*Max(s.xtics.v.lineNum,s.ytics.v.lineNum)), s.ytics.v.size(120)); MyGUI::CheckBoxArea(s.grid.b, dpos.x(20)); MyGUI::Text(U"grid", dpos.y(55)); @@ -117,6 +118,8 @@ class WholeSettingUI : public ScrollableUI { /// @brief 個別のグラフ設定の入力UI class GraphSettingUI : public ScrollableUI { public: + const Size padding{ 0,14 }; + GraphSettingUI operator = (const GraphSettingUI& other) { s = other.s; return *this; @@ -129,12 +132,12 @@ class GraphSettingUI : public ScrollableUI { MyGUI::Text(U"Graph Setting Page", dpos.y(50)); - MyGUI::RadioButtonAreas(s.graph_index, Array{ dpos.pos + Vec2(0,0), dpos.pos + Vec2(0,55) }, Array{ Vec2(600,50) }); + MyGUI::RadioButtonAreas(s.graph_index, Array{ dpos.pos + Vec2(0,0), dpos.pos + Vec2(0,55+ s.graph_func.v.lineNum*30) }, Array{ s.graph_func.v.size(600)+padding,Size(600,s.graph_index==1?110+30 * Max(s.using_x.v.lineNum, s.using_y.v.lineNum) :50)}); s.graph_func.b = s.graph_index == 0; s.graph_data.b = s.graph_index == 1; MyGUI::Text(U"function", dpos.x(200) + Vec2(20, 0)); - MyGUI::TextBox(s.graph_func, dpos.y(55), Size(400, 36)); - Line{ dpos.pos - Vec2(0,41),dpos.pos - Vec2(0,14) }.draw(2, UIColor::frame()); + MyGUI::TextArea(s.graph_func, dpos.y(55+s.graph_func.v.lineNum*30), s.graph_func.v.size(400)); + Line{ dpos.pos - Vec2(0,41 + s.graph_func.v.lineNum * 30),dpos.pos - Vec2(0,14) }.draw(2, UIColor::frame()); MyGUI::Text(U"datafile", dpos.x(200) + Vec2(20, 0)); MyGUI::Text(FileSystem::FileName(s.graph_data.v.text), dpos.x(380)); if (MyGUI::FolderIconButton(dpos.y(55))) { @@ -143,19 +146,19 @@ class GraphSettingUI : public ScrollableUI { } if (s.graph_index == 1) { dpos.x(50); - MyGUI::CheckBoxArea(s.using_x.b, dpos.x(20), Size(550, 50)); + MyGUI::CheckBoxArea(s.using_x.b, dpos.x(20), Size(550, 36+30 * Max(s.using_x.v.lineNum, s.using_y.v.lineNum))+padding); s.using_y.b = s.using_x.b; MyGUI::Text(U"using", dpos.x(130)); - MyGUI::TextBox(s.using_x, dpos.x(190), Size(180, 36)); + MyGUI::TextArea(s.using_x, dpos.x(190), s.using_x.v.size(180)); MyGUI::Text(U":", dpos.x(30)); - MyGUI::TextBox(s.using_y, dpos.y(55), Size(180, 36)); + MyGUI::TextArea(s.using_y, dpos.y(60+30*Max(s.using_x.v.lineNum, s.using_y.v.lineNum)), s.using_y.v.size(180)); } - MyGUI::CheckBoxArea(s.title.b, dpos.x(20), Vec2(600, 50)); + MyGUI::CheckBoxArea(s.title.b, dpos.x(20), s.title.v.size(600)+padding); MyGUI::Text(U"title", dpos.x(180)); - MyGUI::TextBox(s.title, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.title, dpos.y(55+30*s.title.v.lineNum), s.title.v.size(400)); - MyGUI::CheckBoxArea(s.withlines.b, dpos.x(20), s.withlines.b ? (s.linecolor.b ? Vec2(600, 295) : Vec2(600, 220)) : Vec2(600, 50)); + MyGUI::CheckBoxArea(s.withlines.b, dpos.x(20), Size(600, s.withlines.b ? (s.linecolor.b ? 295 : 220) + (s.linewidth.v.lineNum + s.linetype.v.lineNum) * 30 : 50)); MyGUI::Text(U"with lines", dpos.y(55)); if (s.withlines.b) { dpos.x(50); @@ -165,19 +168,19 @@ class GraphSettingUI : public ScrollableUI { dpos.y(s.linecolor.b ? 130 : 55); dpos.x(50); - MyGUI::CheckBoxArea(s.linewidth.b, dpos.x(20), Vec2(545, 50)); + MyGUI::CheckBoxArea(s.linewidth.b, dpos.x(20), s.linewidth.v.size(545)+padding); MyGUI::Text(U"linewidth", dpos.x(130)); - MyGUI::TextBox(s.linewidth, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.linewidth, dpos.y(55+ s.linewidth.v.lineNum*30), s.linewidth.v.size(400)); dpos.x(50); - MyGUI::CheckBoxArea(s.linetype.b, dpos.x(20), Vec2(545, 50)); + MyGUI::CheckBoxArea(s.linetype.b, dpos.x(20), s.linetype.v.size(545)+padding); MyGUI::Text(U"linetype", dpos.x(130)); - MyGUI::TextBox(s.linetype, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.linetype, dpos.y(55+ s.linetype.v.lineNum*30), s.linetype.v.size(400)); dpos.y(5); } - MyGUI::CheckBoxArea(s.withpoints.b, dpos.x(20), s.withpoints.b ? (s.linecolor.b ? Vec2(600, 295) : Vec2(600, 220)) : Vec2(600, 50)); + MyGUI::CheckBoxArea(s.withpoints.b, dpos.x(20), Size(600,s.withpoints.b ? (s.linecolor.b ? 295: 220)+(s.pointsize.v.lineNum+s.pointtype.v.lineNum)*30 : 50)); MyGUI::Text(U"with points", dpos.y(55)); if (s.withpoints.b) { dpos.x(50); @@ -187,16 +190,19 @@ class GraphSettingUI : public ScrollableUI { dpos.y(s.linecolor.b ? 130 : 55); dpos.x(50); - MyGUI::CheckBoxArea(s.pointsize.b, dpos.x(20), Vec2(545, 50)); + MyGUI::CheckBoxArea(s.pointsize.b, dpos.x(20), s.pointsize.v.size(545)+padding); MyGUI::Text(U"pointsize", dpos.x(130)); - MyGUI::TextBox(s.pointsize, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.pointsize, dpos.y(55+ s.pointsize.v.lineNum*30), s.pointsize.v.size(400)); dpos.x(50); - MyGUI::CheckBoxArea(s.pointtype.b, dpos.x(20), Vec2(545, 50)); + MyGUI::CheckBoxArea(s.pointtype.b, dpos.x(20), s.pointtype.v.size(545)+padding); MyGUI::Text(U"pointtype", dpos.x(130)); - MyGUI::TextBox(s.pointtype, dpos.y(55), Size(400, 36)); + MyGUI::TextArea(s.pointtype, dpos.y(55+ s.pointsize.v.lineNum*30), s.pointtype.v.size(400)); dpos.y(5); } + + + dpos.y(200); } }; From 9cc809e4786e94c7cf65fa36de9361551b858006 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sun, 4 Jun 2023 17:06:03 +0900 Subject: [PATCH 11/13] =?UTF-8?q?UI=E3=83=87=E3=82=B6=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=81=AE=E6=94=B9=E8=89=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/Main.cpp | 2 +- pltGUI/my_gui.h | 2 +- pltGUI/plt_setting.h | 6 +++--- pltGUI/ui_plt_setting.h | 13 +++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pltGUI/Main.cpp b/pltGUI/Main.cpp index 1d65518..c1ce51b 100644 --- a/pltGUI/Main.cpp +++ b/pltGUI/Main.cpp @@ -4,7 +4,7 @@ void Main() { - Window::SetTitle(U"pltGUI"); + Window::SetTitle(U"pltGUI v1.2.0"); addLicense(); LicenseManager::DisableDefaultTrigger(); diff --git a/pltGUI/my_gui.h b/pltGUI/my_gui.h index 4254d65..56ef0db 100644 --- a/pltGUI/my_gui.h +++ b/pltGUI/my_gui.h @@ -519,7 +519,7 @@ namespace MyGUI { { region .draw() - .drawFrame(0.0, 1.5, ColorF{ 0.35, 0.7, 1.0, 0.75 }) + //.drawFrame(0.0, 1.5, ColorF{ 0.35, 0.7, 1.0, 0.75 }) .drawFrame(2.5, 0.0, ColorF{ 0.35, 0.7, 1.0 }); // 範囲選択領域の背景色描画 diff --git a/pltGUI/plt_setting.h b/pltGUI/plt_setting.h index 321d8bb..633824c 100644 --- a/pltGUI/plt_setting.h +++ b/pltGUI/plt_setting.h @@ -71,7 +71,7 @@ class Pulldown return; } - m_rect.drawFrame(1, 0, m_isOpen ? UIColor::Accent : UIColor::frame()); + m_rect.drawFrame(m_isOpen ? 2.5:2, 0, m_isOpen ? UIColor::Accent : Color{ 128 }); Point pos = m_rect.pos; @@ -86,7 +86,7 @@ class Pulldown { const Rect backRect{ pos, m_rect.w, (m_rect.h * m_items.size()) }; - backRect.drawShadow({ 1, 1 }, 4, 1).draw(); + backRect/*.drawShadow({1, 1}, 4, 1)*/.draw(); for (const auto& item : m_items) { @@ -101,7 +101,7 @@ class Pulldown pos.y += m_rect.h; } - backRect.drawFrame(1, 0, Palette::Gray); + backRect.drawFrame(2, 0, ColorF{ 0.5 }); } } diff --git a/pltGUI/ui_plt_setting.h b/pltGUI/ui_plt_setting.h index d3fe196..d741881 100644 --- a/pltGUI/ui_plt_setting.h +++ b/pltGUI/ui_plt_setting.h @@ -76,16 +76,17 @@ class WholeSettingUI : public ScrollableUI { MyGUI::Text(U"sample", dpos.x(180)); MyGUI::TextArea(s.sample, dpos.y(55+ s.sample.v.lineNum*30),s.sample.v.size(400)); - MyGUI::CheckBoxArea(s.key.b, dpos.x(20), s.key.v.pos.isOpen() ? Vec2(600, 250) : Vec2(600, 50)); + MyGUI::CheckBoxArea(s.key.b, dpos.x(20), Size(600, (s.key.b ? 60 : 0) + (s.key.v.pos.isOpen() ? 250 : 50))); MyGUI::Text(U"key", dpos.x(180)); - s.key.v.pos.setPos((dpos.x(250) - Vec2(0, 15)).asPoint()); - s.key.v.pos.update(); - s.key.v.pos.draw(); - MyGUI::CheckBox(s.key.v.box, dpos.x(20)); - MyGUI::Text(U"box", dpos.y(55)); + s.key.v.pos.setPos((dpos.y(55) - Vec2(0, 15)).asPoint())->update()->draw(); if (s.key.v.pos.isOpen()) { dpos.y(200); } + if (s.key.b) { + dpos.x(220); + MyGUI::CheckBoxArea(s.key.v.box, dpos.x(20), Size(50, 50)); + MyGUI::Text(U"box", dpos.y(55)); + } dpos.x(20); MyGUI::Text(U"tics", dpos.x(200)); From 7316f9f27358b7f29056b4b8dce9d765222a01f6 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sun, 4 Jun 2023 17:30:27 +0900 Subject: [PATCH 12/13] =?UTF-8?q?=E3=83=AA=E3=83=B3=E3=82=AF=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pltGUI/app_option.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pltGUI/app_option.h b/pltGUI/app_option.h index 247865f..4be0cfe 100644 --- a/pltGUI/app_option.h +++ b/pltGUI/app_option.h @@ -16,11 +16,24 @@ class AppOption { Vec2 dpos{100,150}; - RectF{ Arg::leftCenter= dpos, Size(600,60) }.draw(UIColor::ratio(0.1)).drawFrame(3,UIColor::ratio(0.9)); - MyGUI::Text(U"Lisence", dpos+Vec2(20, 0)); - if (MyGUI::Button(U"View in Browser", dpos + Vec2(150, 0),Size(170,40))) { + MyGUI::Text(U"Documents", dpos+Vec2(20,0)); + if (MyGUI::Button(U"Lisence", dpos + Vec2(150, 0),Size(170,40))) { System::LaunchBrowser(U"./Licenses.html"); } + if (MyGUI::Button(U"Local README.md", dpos + Vec2(330, 0),Size(180,40))) { + System::LaunchFile(U"./README.md"); + } + dpos += Vec2(0,50); + MyGUI::Text(U"Links", dpos+Vec2(20,0)); + if (MyGUI::Button(U"Online README", dpos + Vec2(100, 0), Size(170, 40))) { + System::LaunchBrowser(U"https://github.com/OUCC/pltGUI/releases"); + } + if (MyGUI::Button(U"pltGUI releases", dpos + Vec2(280, 0), Size(170, 40))) { + System::LaunchBrowser(U"https://github.com/OUCC/pltGUI/releases"); + } + if (MyGUI::Button(U"OUCC Twitter", dpos + Vec2(460, 0), Size(170, 40))) { + System::LaunchBrowser(U"https://twitter.com/OUCC"); + } dpos += Vec2(0,100); MyGUI::RadioButtonAreas(colorTypeIndex, Array{ dpos+Vec2(160, 0),dpos+Vec2(270,0) }, Array{ Size(60, 50) }); From b2f6b85e28d58f3ab80c3d84c5147bf0126c9023 Mon Sep 17 00:00:00 2001 From: MrMocchy Date: Sun, 4 Jun 2023 17:43:16 +0900 Subject: [PATCH 13/13] =?UTF-8?q?README=E3=81=AE=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 93 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index e1eb349..813efe6 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,32 @@ -# pltGUI +# pltGUI v1.2.0 gnuplotのpltファイルをGUIから作成できるツール +## 開発環境 +**OpenSiv3D v0.6.9** +**gnuplot 5.4 patchlevel 6** +Windows 11 +Microsoft Visual Studio Community 2022 (v17.4.3) -## 環境 -gnuplot 5.4 patchlevel 6 -OpenSiv3D 0.6.6 +## 使い始め方 +- http://www.gnuplot.info よりgnuplotをインストール、コマンドラインからgnuplotを実行できることを確認 +- https://github.com/OUCC/pltGUI/releases より最新バージョンのzipファイルをダウンロード、展開、`pltGUI.exe`を実行 ## 使い方 -0. https://github.com/OUCC/pltGUI/releases よりzipファイルをダウンロード、展開、`pltGUI.exe`を実行。 1. plt Settingのwhole,graphに入力していく。 (複数のグラフを重ねて描写したいなら+マークで増やす) 2. plt Settingからplt Fileへの矢印を押してpltファイルを生成。 -3. plt Fileのタブをクリックして中身を確認、必要に応じて保存。 -4. plt FileからImageへの矢印を押して画像を生成。 +3. (plt Fileのタブをクリックして中身を確認、必要に応じて保存) +4. plt FileからImageへの矢印を押して画像を生成。 +(矢印を右クリックで2.と4.を連続して実行) 5. Imageから画像を確認、1.に戻って修正。 6. 気に入ったら保存。 +### フィードバック +Twitterの[@OUCC](https://twitter.com/OUCC)へのDM、またはGitHubの[Issues](https://github.com/OUCC/pltGUI/issues)でお知らせください。 + ## 画面構成 -### スクショ +### スクショ (v1.1.0) - plt Setting - whole ![see readme_images/whole.png](readme_images/whole.png) @@ -43,7 +51,7 @@ OpenSiv3D 0.6.6 - 歯車のアイコンボタン のUIがある。 -**矢印のアイコンボタンはそれぞれ、plt Settingの入力からplt Fileの生成、plt Fileを実行して画像の生成をするボタン**。これを押さないと生成されない。押すと生成中のアニメーションが再生されるが、実行時間とは無関係。 +矢印のアイコンボタンはそれぞれ、plt Settingの入力からplt Fileの生成、plt Fileを実行して画像の生成をするボタン。これを押さないと生成されない。押すと生成中のアニメーションが再生されるが、実行時間とは無関係。**右クリックで両方の生成を連続して行う。** その他の項目(歯車含む)は切り替え式のタブで、中身は以下の通り。 - plt Setting @@ -56,8 +64,7 @@ OpenSiv3D 0.6.6 作成したpltファイルから生成したグラフの画像 右上のSave asで保存できる。 - app options(歯車アイコン) -テーマなどアプリの設定 -キーワードの省略(例:`linecolor`→`lc`)や、アプリのテーマカラーなどを指定できる +GitHubやTwitterへのリンクや、色がrgbかhsvか、キーワードの省略(例:`linecolor`→`lc`、ほんの一部のみ)の選択 plt Settingのタブはその中にもタブを持つ。 - whole @@ -73,16 +80,20 @@ whole,graph の中身は下記入力項目を参照。 **注意**:データファイルを指定して描画する場合、生成されるplt Fileでは絶対パスで書かれるため、ユーザー名の流出などに注意。 ### 入力項目 -チェックなしは今後追加したいもの。 -`vX.X.X`は追加されたバージョン、無表記は`v1.0.0`。 +`vX.X.X`は追加された/最終更新されたバージョン、無表記は`v1.0.0`。 - plt setting - whole + - terminal `v1.2.0` + - size `v1.2.0` - title - xrange, yrange - - logscale x, y + - logscale x, y, x$10^n$, y$10^n$ `v1.2.0` - sample - xlabel, ylabel + - key `v1.2.0` + - tics x,y `v1.2.0` + - grid `v1.2.0` - load `v1.1.0` - graph - 削除ボタン @@ -108,6 +119,7 @@ whole,graph の中身は下記入力項目を参照。 - save as - app options - ライセンスの表示 + - Readme, Releaces, OUCC Twitterへのリンク - pltファイルでの色の指定がrgbかhsvか - キーワードの省略(部分的) - アプリのテーマカラーの指定(Base,Main,Accent)(サポート終了) @@ -118,14 +130,10 @@ whole,graph の中身は下記入力項目を参照。 ## 今後の予定 要望があれば積極的に取り入れます。 -上のやつからやるつもり。 -- 凡例の有無と位置の調整 -- グリッド -- logscaleの指数表記 +上のやつからやるつもり。 +次の更新は夏休みに、v2として大幅な変更となると思われます。 - UI周りのコードの整理 -- カラーテピッカーのスペース改善 -- 矢印ボタンを右クリックでplt生成と画像生成を自動で続けて行う -- 整数同士の演算の切り捨て対策 +- カラーピッカーのスペース改善 - 入力欄に大量の文字を入れるとはみ出る対策 - データファイルのドラッグ&ドロップ - カラーテーマの完全削除 @@ -133,22 +141,45 @@ whole,graph の中身は下記入力項目を参照。 - with linesとかの開くやつの閉じる機能 - フォント指定 - ラベルのギリシャ文字 +- キーワード省略の完全化 - 複数pltファイル読み込み - グルーピング機能 +- 整数同士の演算の切り捨て対策 +- 言語設定(英/日) - ドキュメント作成...要る? - splot -## 更新履歴 +## 更新履歴 +- [new]:新機能 +- [add]:項目の追加 +- [system]:内部システムの変更 +- [remove]:削除 + +#### v1.2.0 2023-06-04 +- [add] key/凡例の有無と位置と囲い +- [add] 対数軸の$10^n$表記 +- [add] tics/目盛り +- [add] grid/グリッド +- [new] 矢印ボタンを右クリックでplt生成と画像生成を自動で続けて行うように +- [system] .pltの実行を既定のアプリではなく、gnuplotを指定してするbatファイルを起動するように変更。 +これにより、グラフ生成時にウィンドウが非アクティブにならないようになった。 +- [add] terminalをpngcairo/gif/svg/pdfcairoから指定できるように +- [new] テキストボックスで範囲選択可能に +また、テキストボックスではみ出すのを折り返すように +(改行も可能だがグラフ生成時にエラーとなる場合がある) +- [remove] テキストボックスの中身削除のXアイコンを削除 +- [add] オプションにReleacesやOUCCTwitterなどへのリンクのボタンを追加 + #### v1.1.0 2023-04-30 -Siv3Dバージョンアップ (v0.6.6 → v0.6.9) -pltファイルを編集可能に -pltファイルの実行を公式機能で行えるように -ライセンス更新 -plt Filesのreloadを削除 -Save asの拡張子選択でAll Filesを選択可能に -カラーテーマ変更機能のサポート終了(今回以降追加の機能にカラーテーマは適用されない) +- [system] Siv3Dバージョンアップ (v0.6.6 → v0.6.9) +- [system] ライセンス更新 +- [system] pltファイルの実行を公式機能で行えるように +- [new] pltファイルを編集可能に +- [remove] plt Filesのreloadを削除 +- [add] Save asの拡張子選択でAll Filesを選択可能に +- [remove] カラーテーマ変更機能のサポート終了(今回以降追加の機能にカラーテーマは適用されない) #### v1.0.0 2023-04-13 -初リリース -内容は省略 \ No newline at end of file +- 初リリース +- 内容は省略 \ No newline at end of file