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
912namespace 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