Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/lang/articles/visualization/ggui.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,22 @@ with gui.sub_window("Sub Window", x=10, y=10, width=300, height=100):
color = gui.color_edit_3("name2", color)
```

### Locking a subwindow

You can control whether GGUI subwindows dimensions can be manipulated using these flags.
They all default to `True`:

- `movable`: Allow users to drag the subwindow. If False, position can be updated programmatically.
- `resizable`: Allow users to resize the subwindow. If `False`, size can be updated programmatically.
- `collapsible`: Allow users to collapse the subwindow by clicking its title bar.

```python
# Window that is fully locked
with gui.sub_window("Locked subwindow", 0.1, 0.1, 0.3, 0.2,
resizable=False, movable=False, collapsible=False):
gui.text("Locked!")
```

## Show a window

Call `show()` to show a window.
Expand Down
20 changes: 16 additions & 4 deletions python/taichi/ui/imgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(self, gui) -> None:
self.gui = gui

@contextmanager
def sub_window(self, name, x, y, width, height):
def sub_window(self, name, x, y, width, height, movable=True, resizable=True, collapsible=True):
"""Creating a context manager for subwindow.

Note:
Expand All @@ -26,19 +26,25 @@ def sub_window(self, name, x, y, width, height):
corner of the subwindow, relative to the full window.
width (float): The width of the subwindow relative to the full window.
height (float): The height of the subwindow relative to the full window.
movable (bool): Whether the window can be moved by the user. \
When False, position can only be changed programmatically.
resizable (bool): Whether the window can be resized by the user. \
When False, size can only be changed programmatically.
collapsible (bool): Whether the window can be collapsed by the user. \
When False, the collapse button is disabled.

Example::

>>> with gui.sub_window(name, x, y, width, height) as g:
>>> g.text("Hello, World!")
"""
self.begin(name, x, y, width, height)
self.begin(name, x, y, width, height, movable, resizable, collapsible)
try:
yield self
finally:
self.end()

def begin(self, name, x, y, width, height):
def begin(self, name, x, y, width, height, movable=True, resizable=True, collapsible=True):
"""Creates a subwindow that holds imgui widgets.

All widget function calls (e.g. `text`, `button`) after the `begin`
Expand All @@ -51,8 +57,14 @@ def begin(self, name, x, y, width, height):
corner of the subwindow, relative to the full window.
width (float): The width of the subwindow relative to the full window.
height (float): The height of the subwindow relative to the full window.
movable (bool): Whether the window can be moved by the user. \
When False, position can only be changed programmatically.
resizable (bool): Whether the window can be resized by the user. \
When False, size can only be changed programmatically.
collapsible (bool): Whether the window can be collapsed by the user. \
When False, the collapse button is disabled.
"""
self.gui.begin(name, x, y, width, height)
self.gui.begin(name, x, y, width, height, movable, resizable, collapsible)

def end(self):
"""End the description of the current subwindow."""
Expand Down
11 changes: 9 additions & 2 deletions taichi/python/export_ggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ py::array_t<float> mat4_to_nparray(glm::mat4 mat) {

struct PyGui {
GuiBase *gui; // not owned
void begin(std::string name, float x, float y, float width, float height) {
gui->begin(name, x, y, width, height);
void begin(std::string name,
float x,
float y,
float width,
float height,
bool movable = true,
bool resizable = true,
bool collapsible = true) {
gui->begin(name, x, y, width, height, movable, resizable, collapsible);
}
void end() {
gui->end();
Expand Down
5 changes: 4 additions & 1 deletion taichi/ui/common/gui_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ class GuiBase {
float x,
float y,
float width,
float height) = 0;
float height,
bool movable = true,
bool resizable = true,
bool collapsible = true) = 0;
virtual void end() = 0;
virtual void text(const std::string &text) = 0;
virtual void text(const std::string &text, glm::vec3 color) = 0;
Expand Down
44 changes: 40 additions & 4 deletions taichi/ui/ggui/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,49 @@ void Gui::begin(const std::string &name,
float x,
float y,
float width,
float height) {
float height,
bool movable,
bool resizable,
bool collapsible) {
if (!initialized()) {
return;
}
ImGui::SetNextWindowPos(ImVec2(abs_x(x), abs_y(y)), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(abs_x(width), abs_y(height)), ImGuiCond_Once);
ImGui::Begin(name.c_str());

// Update window dimensions when locked, so programmatic updates use current
// window size
if ((!movable || !resizable) && app_context_->config.show_window) {
#ifdef ANDROID
widthBeforeDPIScale =
(int)ANativeWindow_getWidth(app_context_->taichi_window());
heightBeforeDPIScale =
(int)ANativeWindow_getHeight(app_context_->taichi_window());
#else
glfwGetWindowSize(app_context_->taichi_window(), &widthBeforeDPIScale,
&heightBeforeDPIScale);
#endif
}

// Set position: Always if locked, Once if unlocked
ImGuiCond pos_cond = movable ? ImGuiCond_Once : ImGuiCond_Always;
ImGui::SetNextWindowPos(ImVec2(abs_x(x), abs_y(y)), pos_cond);

// Set size: Always if locked, Once if unlocked
ImGuiCond size_cond = resizable ? ImGuiCond_Once : ImGuiCond_Always;
ImGui::SetNextWindowSize(ImVec2(abs_x(width), abs_y(height)), size_cond);

// Build window flags
ImGuiWindowFlags flags = 0;
if (!movable) {
flags |= ImGuiWindowFlags_NoMove;
}
if (!resizable) {
flags |= ImGuiWindowFlags_NoResize;
}
if (!collapsible) {
flags |= ImGuiWindowFlags_NoCollapse;
}

ImGui::Begin(name.c_str(), nullptr, flags);
is_empty_ = false;
}
void Gui::end() {
Expand Down
5 changes: 4 additions & 1 deletion taichi/ui/ggui/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ class TI_DLL_EXPORT Gui final : public GuiBase {
float x,
float y,
float width,
float height) override;
float height,
bool movable = true,
bool resizable = true,
bool collapsible = true) override;
void end() override;
void text(const std::string &text) override;
void text(const std::string &text, glm::vec3 color) override;
Expand Down
5 changes: 4 additions & 1 deletion taichi/ui/ggui/gui_metal.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ class TI_DLL_EXPORT GuiMetal final : public GuiBase {
float x,
float y,
float width,
float height) override;
float height,
bool movable = true,
bool resizable = true,
bool collapsible = true) override;
void end() override;
void text(const std::string &text) override;
void text(const std::string &text, glm::vec3 color) override;
Expand Down
34 changes: 30 additions & 4 deletions taichi/ui/ggui/gui_metal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,36 @@
float GuiMetal::abs_y(float y) { return y * heightBeforeDPIScale; }

void GuiMetal::begin(const std::string &name, float x, float y, float width,
float height) {
ImGui::SetNextWindowPos(ImVec2(abs_x(x), abs_y(y)), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(abs_x(width), abs_y(height)), ImGuiCond_Once);
ImGui::Begin(name.c_str());
float height, bool movable, bool resizable,
bool collapsible) {
// Update window dimensions when locked, so programmatic updates use current
// window size
if ((!movable || !resizable) && app_context_->config.show_window) {
glfwGetWindowSize(app_context_->taichi_window(), &widthBeforeDPIScale,
&heightBeforeDPIScale);
}

// Set position: Always if locked, Once if unlocked
ImGuiCond pos_cond = movable ? ImGuiCond_Once : ImGuiCond_Always;
ImGui::SetNextWindowPos(ImVec2(abs_x(x), abs_y(y)), pos_cond);

// Set size: Always if locked, Once if unlocked
ImGuiCond size_cond = resizable ? ImGuiCond_Once : ImGuiCond_Always;
ImGui::SetNextWindowSize(ImVec2(abs_x(width), abs_y(height)), size_cond);

// Build window flags
ImGuiWindowFlags flags = 0;
if (!movable) {
flags |= ImGuiWindowFlags_NoMove;
}
if (!resizable) {
flags |= ImGuiWindowFlags_NoResize;
}
if (!collapsible) {
flags |= ImGuiWindowFlags_NoCollapse;
}

ImGui::Begin(name.c_str(), nullptr, flags);
is_empty_ = false;
}
void GuiMetal::end() { ImGui::End(); }
Expand Down
Loading