Skip to content

Commit efa63c8

Browse files
committed
feat(userInterface): add functions input panel
1 parent 552b025 commit efa63c8

2 files changed

Lines changed: 351 additions & 3 deletions

File tree

‎include/mathplotter/userInterface.hpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,23 @@
99
#include <SFML/Graphics/Text.hpp>
1010
#include <imgui.h>
1111

12+
#include <string>
13+
#include <vector>
14+
1215
namespace mathplotter {
1316

1417
class UserInterface {
1518
private:
19+
struct FunctionRow {
20+
std::string expression;
21+
ImVec4 color{1.f, 0.f, 0.f, 1.f};
22+
};
23+
1624
sf::Text m_title;
1725
int m_selectedThemeIndex{0};
26+
std::vector<FunctionRow> m_functionRows;
1827

28+
void DrawFunctionPanel();
1929
void ConfigureTitle(const Theme& theme);
2030
void SelectTheme(Theme& theme);
2131
ImVec4 ToImGuiColor(const sf::Color& color);

‎src/userInterface.cpp‎

Lines changed: 341 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
#include <SFML/Graphics/Rect.hpp>
66
#include <SFML/Graphics/RenderWindow.hpp>
77
#include <imgui.h>
8+
#include <misc/cpp/imgui_stdlib.h>
9+
10+
#include <string>
811

912
namespace mathplotter {
1013

1114
UserInterface::UserInterface(const sf::Font& font, const Theme& theme)
1215
: m_title(font, "Math Plotter++"),
13-
m_selectedThemeIndex(0) {
16+
m_selectedThemeIndex(0),
17+
m_functionRows(1) {
1418
ConfigureTitle(theme);
1519
}
1620

@@ -122,9 +126,343 @@ namespace mathplotter {
122126
ImGui::End();
123127
}
124128

125-
void UserInterface::Draw(sf::RenderWindow& window, Theme& theme) {
129+
void UserInterface::DrawFunctionPanel() {
130+
constexpr ImGuiWindowFlags windowFlags{
131+
ImGuiWindowFlags_NoMove |
132+
ImGuiWindowFlags_NoResize |
133+
ImGuiWindowFlags_NoCollapse |
134+
ImGuiWindowFlags_NoTitleBar |
135+
ImGuiWindowFlags_AlwaysAutoResize
136+
};
137+
138+
ImGui::SetNextWindowPos(
139+
{10.f, 10.f},
140+
ImGuiCond_Always
141+
);
142+
143+
const ImGuiViewport* viewport{ImGui::GetMainViewport()};
144+
145+
const float maxHeight{
146+
viewport->WorkSize.y - 20.f
147+
};
148+
149+
ImGui::SetNextWindowSizeConstraints(
150+
{230.f, 0.f},
151+
{230.f, maxHeight}
152+
);
153+
154+
ImGui::PushStyleVar(
155+
ImGuiStyleVar_WindowPadding,
156+
{0.f, 0.f}
157+
);
158+
159+
ImGui::Begin("Functions", nullptr, windowFlags);
160+
161+
ImGui::PopStyleVar();
162+
163+
constexpr std::size_t maxFunctions{15};
164+
165+
constexpr float headerHeight{40.f};
166+
constexpr float numberColumnWidth{30.f};
167+
168+
constexpr ImGuiTableFlags headerFlags{
169+
ImGuiTableFlags_BordersOuterV |
170+
ImGuiTableFlags_BordersInnerV |
171+
ImGuiTableFlags_NoSavedSettings
172+
};
173+
174+
ImGui::PushStyleVar(
175+
ImGuiStyleVar_CellPadding,
176+
{0.f, 0.f}
177+
);
178+
179+
ImGui::PushStyleVar(
180+
ImGuiStyleVar_ItemSpacing,
181+
{
182+
ImGui::GetStyle().ItemSpacing.x,
183+
0.f
184+
}
185+
);
186+
187+
if (ImGui::BeginTable("FunctionHeader", 2, headerFlags)) {
188+
ImGui::TableSetupColumn(
189+
"Add",
190+
ImGuiTableColumnFlags_WidthFixed,
191+
numberColumnWidth
192+
);
193+
194+
ImGui::TableSetupColumn(
195+
"Title",
196+
ImGuiTableColumnFlags_WidthStretch
197+
);
198+
199+
ImGui::TableNextRow(
200+
ImGuiTableRowFlags_None,
201+
headerHeight
202+
);
203+
204+
ImGui::TableSetColumnIndex(0);
205+
206+
ImGui::PushStyleVar(
207+
ImGuiStyleVar_FrameBorderSize,
208+
0.f
209+
);
210+
211+
if (
212+
ImGui::Button(
213+
"+",
214+
{
215+
ImGui::GetContentRegionAvail().x,
216+
headerHeight
217+
}
218+
) &&
219+
m_functionRows.size() < maxFunctions
220+
) {
221+
m_functionRows.emplace_back();
222+
}
223+
224+
ImGui::PopStyleVar();
225+
226+
ImGui::TableSetColumnIndex(1);
227+
228+
const ImVec2 titleSize{
229+
ImGui::CalcTextSize("Function")
230+
};
231+
232+
ImGui::SetCursorPosX(
233+
ImGui::GetCursorPosX() +
234+
(ImGui::GetContentRegionAvail().x - titleSize.x) / 2.f
235+
);
236+
237+
ImGui::SetCursorPosY(
238+
ImGui::GetCursorPosY() +
239+
(headerHeight - titleSize.y) / 2.f
240+
);
241+
242+
ImGui::TextUnformatted("Function");
243+
244+
ImGui::EndTable();
245+
}
246+
247+
ImGui::PopStyleVar(2);
248+
249+
bool addNewRow{false};
250+
251+
constexpr ImGuiTableFlags tableFlags{
252+
ImGuiTableFlags_BordersOuter |
253+
ImGuiTableFlags_BordersInnerH |
254+
ImGuiTableFlags_NoSavedSettings
255+
};
256+
257+
ImGui::PushStyleVar(
258+
ImGuiStyleVar_CellPadding,
259+
{0.f, 0.f}
260+
);
261+
262+
if (ImGui::BeginTable("FunctionTable", 3, tableFlags)) {
263+
ImGui::TableSetupColumn(
264+
"Number",
265+
ImGuiTableColumnFlags_WidthFixed,
266+
numberColumnWidth
267+
);
268+
269+
ImGui::TableSetupColumn(
270+
"Color",
271+
ImGuiTableColumnFlags_WidthFixed,
272+
30.f
273+
);
274+
275+
ImGui::TableSetupColumn(
276+
"Expression",
277+
ImGuiTableColumnFlags_WidthStretch
278+
);
279+
280+
constexpr ImVec4 transparent{0.f, 0.f, 0.f, 0.f};
281+
282+
ImGui::PushStyleColor(ImGuiCol_FrameBg, transparent);
283+
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, transparent);
284+
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, transparent);
285+
286+
ImGui::PushStyleVar(
287+
ImGuiStyleVar_FrameBorderSize,
288+
0.f
289+
);
290+
291+
constexpr float rowHeight{30.f};
292+
const ImVec2 tableStart{
293+
ImGui::GetCursorScreenPos()
294+
};
295+
296+
for (std::size_t i{0}; i < m_functionRows.size(); ++i) {
297+
ImGui::PushID(static_cast<int>(i));
298+
299+
ImGui::TableNextRow(
300+
ImGuiTableRowFlags_None,
301+
rowHeight
302+
);
303+
304+
ImGui::TableSetColumnIndex(0);
305+
const std::string number{
306+
std::to_string(i + 1)
307+
};
308+
309+
const ImVec2 numberSize{
310+
ImGui::CalcTextSize(number.c_str())
311+
};
312+
313+
ImGui::SetCursorPosX(
314+
ImGui::GetCursorPosX() +
315+
(ImGui::GetContentRegionAvail().x - numberSize.x) / 2.f
316+
);
317+
318+
ImGui::SetCursorPosY(
319+
ImGui::GetCursorPosY() +
320+
(rowHeight - numberSize.y) / 2.f
321+
);
322+
323+
ImGui::TextUnformatted(number.c_str());
324+
325+
ImGui::TableSetColumnIndex(1);
326+
327+
if (!m_functionRows[i].expression.empty()) {
328+
329+
constexpr float colorSize{16.f};
330+
331+
const float horizontalOffset{
332+
(ImGui::GetContentRegionAvail().x - colorSize) / 2.f
333+
};
334+
335+
ImGui::SetCursorPosX(
336+
ImGui::GetCursorPosX() + horizontalOffset
337+
);
338+
339+
ImGui::SetCursorPosY(
340+
ImGui::GetCursorPosY() +
341+
(rowHeight - colorSize) / 2.f
342+
);
343+
344+
ImGui::PushStyleVar(
345+
ImGuiStyleVar_FrameBorderSize,
346+
1.f
347+
);
348+
349+
ImGui::PushStyleColor(
350+
ImGuiCol_Border,
351+
ImVec4(0.f, 0.f, 0.f, 1.f)
352+
);
353+
354+
if (
355+
ImGui::ColorButton(
356+
"##FunctionColor",
357+
m_functionRows[i].color,
358+
ImGuiColorEditFlags_NoTooltip,
359+
{colorSize, colorSize}
360+
)
361+
) {
362+
ImGui::OpenPopup("FunctionColorPicker");
363+
}
364+
365+
const ImVec2 colorButtonMax{ImGui::GetItemRectMax()};
366+
const ImVec2 colorButtonMin{ImGui::GetItemRectMin()};
367+
368+
ImGui::SetNextWindowPos(
369+
{
370+
colorButtonMax.x + 5.f,
371+
colorButtonMin.y
372+
},
373+
ImGuiCond_Appearing
374+
);
375+
376+
if (
377+
ImGui::BeginPopup(
378+
"FunctionColorPicker",
379+
ImGuiWindowFlags_NoMove
380+
)
381+
) {
382+
constexpr ImGuiColorEditFlags colorPickerFlags{
383+
ImGuiColorEditFlags_NoAlpha |
384+
ImGuiColorEditFlags_NoInputs |
385+
ImGuiColorEditFlags_NoSidePreview |
386+
ImGuiColorEditFlags_NoSmallPreview
387+
};
388+
389+
ImGui::SetNextItemWidth(160.f);
390+
391+
ImGui::ColorPicker4(
392+
"##ColorPicker",
393+
&m_functionRows[i].color.x,
394+
colorPickerFlags
395+
);
396+
397+
ImGui::EndPopup();
398+
}
399+
400+
ImGui::PopStyleColor();
401+
ImGui::PopStyleVar();
402+
}
403+
404+
ImGui::TableSetColumnIndex(2);
405+
406+
ImGui::SetCursorPosY(
407+
ImGui::GetCursorPosY() +
408+
(rowHeight - ImGui::GetFrameHeight()) / 2.f
409+
);
410+
411+
ImGui::SetNextItemWidth(-1.f);
412+
413+
const bool submitted{
414+
ImGui::InputText(
415+
"##FunctionExpression",
416+
&m_functionRows[i].expression,
417+
ImGuiInputTextFlags_EnterReturnsTrue
418+
)
419+
};
420+
421+
if (
422+
submitted &&
423+
!m_functionRows[i].expression.empty() &&
424+
i == m_functionRows.size() - 1
425+
) {
426+
addNewRow = true;
427+
}
428+
429+
ImGui::PopID();
430+
}
431+
ImGui::PopStyleVar();
432+
ImGui::PopStyleColor(3);
433+
434+
ImGui::EndTable();
435+
const float separatorX{
436+
tableStart.x + numberColumnWidth + 1.f
437+
};
438+
439+
const float tableBottom{
440+
tableStart.y +
441+
rowHeight * static_cast<float>(m_functionRows.size())
442+
};
443+
444+
ImGui::GetWindowDrawList()->AddLine(
445+
{separatorX, tableStart.y},
446+
{separatorX, tableBottom},
447+
ImGui::GetColorU32(ImGuiCol_TableBorderStrong)
448+
);
449+
}
450+
ImGui::PopStyleVar();
451+
452+
if (
453+
addNewRow &&
454+
m_functionRows.size() < maxFunctions
455+
) {
456+
m_functionRows.emplace_back();
457+
}
458+
459+
ImGui::End();
460+
}
461+
462+
void UserInterface::Draw([[maybe_unused]]sf::RenderWindow& window, Theme& theme) {
463+
DrawFunctionPanel();
126464
SelectTheme(theme);
127-
window.draw(m_title);
465+
//window.draw(m_title);
128466
}
129467

130468
} // namespace mathplotter

0 commit comments

Comments
 (0)