Skip to content

Commit

Permalink
update hello_imgui (add input_text_resizable)
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed May 14, 2024
1 parent 7eb627c commit b9c0389
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 24,987 deletions.
34 changes: 24 additions & 10 deletions bindings/imgui_bundle/demos_cpp/demos_immapp/demo_docking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ It demonstrates how to:

#include "hello_imgui/hello_imgui.h"
#include "hello_imgui/icons_font_awesome_6.h"
#include "nlohmann/json.hpp"
#include "imgui.h"
#include "imgui_stdlib.h"
#include "imgui_internal.h"
Expand Down Expand Up @@ -41,7 +42,12 @@ It demonstrates how to:
//////////////////////////////////////////////////////////////////////////
struct MyAppSettings
{
std::string name = "Test";
HelloImGui::InputTextData motto = HelloImGui::InputTextData(
"Hello, Dear ImGui\n"
"Unleash your creativity!\n",
true, // multiline
ImVec2(14.f, 3.f) // initial size (in em)
);
int value = 10;
};

Expand Down Expand Up @@ -114,17 +120,25 @@ void LoadFonts(AppState& appState) // This is called by runnerParams.callbacks.L
// Warning, the save/load function below are quite simplistic!
std::string MyAppSettingsToString(const MyAppSettings& myAppSettings)
{
std::stringstream ss;
ss << myAppSettings.name << "\n";
ss << myAppSettings.value;
return ss.str();
using namespace nlohmann;
json j;
j["motto"] = HelloImGui::InputTextDataToString(myAppSettings.motto);
j["value"] = myAppSettings.value;
return j.dump();
}
MyAppSettings StringToMyAppSettings(const std::string& s)
{
std::stringstream ss(s);
MyAppSettings myAppSettings;
ss >> myAppSettings.name;
ss >> myAppSettings.value;
using namespace nlohmann;
try {
json j = json::parse(s);
myAppSettings.motto = HelloImGui::InputTextDataFromString(j["motto"].get<std::string>());
myAppSettings.value = j["value"];
}
catch (json::exception& e)
{
HelloImGui::Log(HelloImGui::LogLevel::Error, "Error while parsing user settings: %s", e.what());
}
return myAppSettings;
}

Expand Down Expand Up @@ -220,9 +234,9 @@ void DemoUserSettings(AppState& appState)
ImGui::PushFont(appState.TitleFont); ImGui::Text("User settings"); ImGui::PopFont();
ImGui::BeginGroup();
ImGui::SetNextItemWidth(HelloImGui::EmSize(7.f));
ImGui::InputText("Name", &appState.myAppSettings.name);
ImGui::SetNextItemWidth(HelloImGui::EmSize(7.f));
ImGui::SliderInt("Value", &appState.myAppSettings.value, 0, 100);
HelloImGui::InputTextResizable("Motto", &appState.myAppSettings.motto);
ImGui::Text("(this text widget is resizable)");
ImGui::EndGroup();
if (ImGui::IsItemHovered())
ImGui::SetTooltip("The values below are stored in the application settings ini file and restored at startup");
Expand Down
39 changes: 25 additions & 14 deletions bindings/imgui_bundle/demos_python/demos_immapp/demo_docking.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
# - use a specific application state (instead of using static variables)
# - save some additional user settings within imgui ini file
# - use borderless windows, that are movable and resizable


import json
from enum import Enum
import time

from imgui_bundle import hello_imgui, icons_fontawesome_6, imgui, immapp, imgui_ctx, ImVec4
from imgui_bundle import hello_imgui, icons_fontawesome_6, imgui, immapp, imgui_ctx, ImVec4, ImVec2
from imgui_bundle.demos_python import demo_utils
from typing import List

Expand All @@ -23,9 +22,16 @@
# Our Application State
##########################################################################
class MyAppSettings:
name: str = "Test"
motto: hello_imgui.InputTextData
value: int = 10

def __init__(self):
self.motto = hello_imgui.InputTextData(
"Hello, Dear ImGui\n"
"Unleash your creativity!\n",
True, # multiline
ImVec2(14.0, 3.0) # initial size (in em)
)

class RocketState(Enum):
Init = 0
Expand Down Expand Up @@ -99,16 +105,20 @@ def load_fonts(app_state: AppState): # This is called by runnerParams.callbacks

# Warning, the save/load function below are quite simplistic!
def my_app_settings_to_string(settings: MyAppSettings) -> str:
r = settings.name + "\n" + str(settings.value)
return r
as_dict = {}
as_dict["motto"] = hello_imgui.input_text_data_to_dict(settings.motto)
as_dict["value"] = settings.value
return json.dumps(as_dict)


def string_to_my_app_settings(s: str) -> MyAppSettings:
r = MyAppSettings()
lines = s.splitlines(False)
if len(lines) >= 2:
r.name = lines[0]
r.value = int(lines[1])
try:
as_dict = json.loads(s)
r.motto = hello_imgui.input_text_data_from_dict(as_dict["motto"])
r.value = as_dict["value"]
except Exception as e:
hello_imgui.log(hello_imgui.LogLevel.error, f"Error while loading user settings: {e}")
return r


Expand Down Expand Up @@ -209,14 +219,15 @@ def demo_user_settings(app_state: AppState):
imgui.pop_font()

imgui.begin_group()
imgui.set_next_item_width(hello_imgui.em_size(7.0))
_, app_state.my_app_settings.name = imgui.input_text(
"Name", app_state.my_app_settings.name
)

imgui.set_next_item_width(hello_imgui.em_size(7.0))
_, app_state.my_app_settings.value = imgui.slider_int(
"Value", app_state.my_app_settings.value, 0, 100
)

_ = hello_imgui.input_text_resizable("Motto", app_state.my_app_settings.motto)
imgui.text("(this text widget is resizable)")

imgui.end_group()
if imgui.is_item_hovered():
imgui.set_tooltip("The values below are stored in the application settings ini file and restored at startup")
Expand Down
87 changes: 76 additions & 11 deletions bindings/imgui_bundle/hello_imgui.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ ImGuiWindowFlags = imgui_bundle.imgui.WindowFlags
# ImWcharPair is used to defined unicode glyph ranges
ImWcharPair = Tuple[int, int]

DictTypeInputTextData = dict[str, Any]


def EmptyVoidFunction() -> VoidFunction:
pass

Expand Down Expand Up @@ -2011,7 +2014,7 @@ class DockingSplit:
# `nodeFlags`: *ImGuiDockNodeFlags_ (enum)*.
# Flags to apply to the new dock space
# (enable/disable resizing, splitting, tab bar, etc.)
node_flags: ImGuiDockNodeFlags = DockNodeFlags_.none
node_flags: ImGuiDockNodeFlags = ImGuiDockNodeFlags_None

# DockingSplit(const DockSpaceName& initialDock_ = "", const DockSpaceName& newDock_ = "", /* original C++ signature */
# ImGuiDir_ direction_ = ImGuiDir_Down, float ratio_ = 0.25f,
Expand All @@ -2021,9 +2024,9 @@ class DockingSplit:
self,
initial_dock_: DockSpaceName = "",
new_dock_: DockSpaceName = "",
direction_: ImGuiDir_ = Dir_.down,
direction_: ImGuiDir_ = ImGuiDir_Down,
ratio_: float = 0.25,
node_flags_: ImGuiDockNodeFlags = DockNodeFlags_.none,
node_flags_: ImGuiDockNodeFlags = ImGuiDockNodeFlags_None,
) -> None:
"""Constructor"""
pass
Expand Down Expand Up @@ -2113,7 +2116,7 @@ class DockableWindow:
# ImGuiCond windowPositionCondition = ImGuiCond_FirstUseEver; /* original C++ signature */
# `windowPosCondition`: _ImGuiCond, default=ImGuiCond_FirstUseEver_.
# When to apply the window position.
window_position_condition: ImGuiCond = Cond_.first_use_ever
window_position_condition: ImGuiCond = ImGuiCond_FirstUseEver

# DockableWindow( /* original C++ signature */
# const std::string & label_ = "",
Expand Down Expand Up @@ -2186,7 +2189,7 @@ class DockingParams:
# Most flags are inherited by children dock spaces.
# You can also set flags for specific dock spaces via `DockingSplit.nodeFlags`
main_dock_space_node_flags: ImGuiDockNodeFlags = (
DockNodeFlags_.passthru_central_node
ImGuiDockNodeFlags_PassthruCentralNode
)

# --------------- Layout handling -----------------------------
Expand Down Expand Up @@ -2235,7 +2238,7 @@ class DockingParams:
docking_splits: List[DockingSplit] = List[DockingSplit](),
dockable_windows: List[DockableWindow] = List[DockableWindow](),
layout_name: str = "Default",
main_dock_space_node_flags: ImGuiDockNodeFlags = DockNodeFlags_.passthru_central_node,
main_dock_space_node_flags: ImGuiDockNodeFlags = ImGuiDockNodeFlags_PassthruCentralNode,
layout_condition: DockingLayoutCondition = DockingLayoutCondition.first_use_ever,
layout_reset: bool = False,
) -> None:
Expand Down Expand Up @@ -2900,11 +2903,6 @@ class SimpleRunnerParams:

# @@md

# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# hello_imgui/hello_imgui_widgets.h included by hello_imgui.h //
# //////////////////////////////////////////////////////////////////////////////////////////////////////////////
# Some additional widgets and utilities for ImGui

# void BeginGroupColumn(); /* original C++ signature */
def begin_group_column() -> None:
"""calls ImGui::BeginGroup()"""
Expand All @@ -2915,6 +2913,8 @@ def end_group_column() -> None:
"""calls ImGui::EndGroup() + ImGui::SameLine()"""
pass

# @@md#WidgetWithResizeHandle

# ImVec2 WidgetWithResizeHandle( /* original C++ signature */
# const char* id,
# VoidFunction widgetGuiFunction,
Expand Down Expand Up @@ -2946,6 +2946,71 @@ def widget_with_resize_handle(
"""
pass

# @@md

# --------------------------------------------------------------------------------------------

# @@md#InputTextResizable

class InputTextData:
"""`InputTextResizable`: displays a resizable text input widget
The `InputTextResizable` widget allows you to create a text input field that can be resized by the user.
It supports both single-line and multi-line text input.
Note: the size of the widget is expressed in em units.
**Usage example:**
C++:
```cpp
// Somewhere in the application state
(static) InputTextData textInput("My text", True, ImVec2(10, 3));
// In the GUI function
bool changed = InputTextResizable("Label", &textInput);
```
Python:
```python
# Somewhere in the application state
text_input = hello_imgui.InputTextData("My text", multiline=True, size_em=ImVec2(10, 3))
# In the GUI function
changed, text_input = hello_imgui.InputTextResizable("Label", text_input)
```
"""

# std::string Text; /* original C++ signature */
text: str
# bool Multiline = false; /* original C++ signature */
multiline: bool = False
# ImVec2 SizeEm = ImVec2(0, 0); /* original C++ signature */
size_em: ImVec2 = ImVec2(0, 0)

# InputTextData(const std::string& text = "", bool multiline = false, ImVec2 size_em = ImVec2(0, 0)) : Text(text), Multiline(multiline), SizeEm(size_em) {} /* original C++ signature */
def __init__(
self, text: str = "", multiline: bool = False, size_em: ImVec2 = ImVec2(0, 0)
) -> None:
pass

# bool InputTextResizable(const char* label, InputTextData* textInput); /* original C++ signature */
def input_text_resizable(label: str, text_input: InputTextData) -> bool:
pass

# DictTypeInputTextData InputTextDataToDict(const InputTextData& data); /* original C++ signature */
def input_text_data_to_dict(data: InputTextData) -> DictTypeInputTextData:
pass

# InputTextData InputTextDataFromDict(const DictTypeInputTextData& dict); /* original C++ signature */
def input_text_data_from_dict(dict: DictTypeInputTextData) -> InputTextData:
pass

# to/from string
# std::string InputTextDataToString(const InputTextData& data); /* original C++ signature */
def input_text_data_to_string(data: InputTextData) -> str:
pass

# InputTextData InputTextDataFromString(const std::string& str); /* original C++ signature */
def input_text_data_from_string(str: str) -> InputTextData:
pass

# @@md

# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# hello_imgui.h continued //
# //////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 0 additions & 8 deletions external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ if(IMGUI_BUNDLE_INSTALL_CPP)
ibd_add_installable_dependency(fplus)
endif()

# Add nlohmann_json
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/nlohmann_json>)
if(IMGUI_BUNDLE_INSTALL_CPP)
install(DIRECTORY nlohmann_json/nlohmann DESTINATION include)
ibd_add_installable_dependency(nlohmann_json)
endif()


###############################################################################
# Build ImGui & Hello ImGui
Expand Down
52 changes: 51 additions & 1 deletion external/hello_imgui/bindings/hello_imgui_amalgamation.h
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,7 @@ struct SimpleRunnerParams
// hello_imgui/hello_imgui_widgets.h included by hello_imgui.h //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Some additional widgets and utilities for ImGui

#include <variant>

namespace HelloImGui
{
Expand All @@ -2322,6 +2322,8 @@ namespace HelloImGui

void EndGroupColumn(); // calls ImGui::EndGroup() + ImGui::SameLine()

// @@md#WidgetWithResizeHandle

// WidgetWithResizeHandle: adds a resize handle to a widget
// Example usage with ImPlot:
// void gui()
Expand All @@ -2344,6 +2346,54 @@ namespace HelloImGui
std::optional<VoidFunction> onItemHovered = std::nullopt
);

// @@md


// --------------------------------------------------------------------------------------------

// @@md#InputTextResizable

// `InputTextResizable`: displays a resizable text input widget
//
// The `InputTextResizable` widget allows you to create a text input field that can be resized by the user.
// It supports both single-line and multi-line text input.
// Note: the size of the widget is expressed in em units.
// **Usage example:**
// C++:
// ```cpp
// // Somewhere in the application state
// (static) InputTextData textInput("My text", true, ImVec2(10, 3));
// // In the GUI function
// bool changed = InputTextResizable("Label", &textInput);
// ```
// Python:
// ```python
// # Somewhere in the application state
// text_input = hello_imgui.InputTextData("My text", multiline=True, size_em=ImVec2(10, 3))
// # In the GUI function
// changed, text_input = hello_imgui.InputTextResizable("Label", text_input)
// ```
struct InputTextData
{
std::string Text;
bool Multiline = false;
ImVec2 SizeEm = ImVec2(0, 0);

InputTextData(const std::string& text = "", bool multiline = false, ImVec2 size_em = ImVec2(0, 0)) : Text(text), Multiline(multiline), SizeEm(size_em) {}
};
bool InputTextResizable(const char* label, InputTextData* textInput);

// Serialization for InputTextData
// -------------------------------
// to/from dict
using DictTypeInputTextData = std::map<std::string, std::variant<std::string, bool, float>>;
DictTypeInputTextData InputTextDataToDict(const InputTextData& data);
InputTextData InputTextDataFromDict(const DictTypeInputTextData& dict);
// to/from string
std::string InputTextDataToString(const InputTextData& data);
InputTextData InputTextDataFromString(const std::string& str);

// @@md
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit b9c0389

Please sign in to comment.