Skip to content

Commit

Permalink
Add EdgeToolbars
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Jan 9, 2024
1 parent 36dfc53 commit 4ac930c
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 26 deletions.
65 changes: 58 additions & 7 deletions src/hello_imgui/doc_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ struct FpsIdling

See [runner_callbacks.h](https://github.com/pthom/hello_imgui/blob/master/src/hello_imgui/runner_callbacks.h).


**VoidFunctionPointer** can hold any void(void) function.
```cpp
using VoidFunction = std::function<void(void)>
```

**AnyEventCallback** can hold any bool(void *) function.
It is designed to handle callbacks for a specific backend.
```cpp
using AnyEventCallback = std::function<bool(void * backendEvent)>
```

**AppendCallback** can compose two callbacks. Use this when you want to set a callback and keep the (maybe) preexisting one.

```cpp
//
// RunnerCallbacks is a struct that contains the callbacks
Expand Down Expand Up @@ -251,6 +265,10 @@ struct RunnerCallbacks
// Also, remember to call ImGui::SameLine() between items.
VoidFunction ShowStatus = EmptyVoidFunction();

// EdgesToolbars: A map that contains the definition of toolbars
// that can be placed on the edges of the App window
std::map<EdgeToolbarType, EdgeToolbar> edgesToolbars;


// --------------- Startup sequence callbacks -------------------

Expand Down Expand Up @@ -343,19 +361,52 @@ struct RunnerCallbacks
};
```

## Edge Toolbars Callbacks
More details on `RunnerParams.edgesToolbars` (a dictionary of `EdgeToolbar`, per edge type)

**VoidFunctionPointer** can hold any void(void) function.
```cpp
using VoidFunction = std::function<void(void)>
struct RunnerCallbacks
{
...
// EdgesToolbars: A map that contains the definition of toolbars
// that can be placed on the edges of the App window
std::map<EdgeToolbarType, EdgeToolbar> edgesToolbars;
...
};
```

**AnyEventCallback** can hold any bool(void *) function.
It is designed to handle callbacks for a specific backend.
Where:
```cpp
using AnyEventCallback = std::function<bool(void * backendEvent)>
```

**AppendCallback** can compose two callbacks. Use this when you want to set a callback and keep the (maybe) preexisting one.
// EdgeToolbarType: location of an Edge Toolbar
enum class EdgeToolbarType
{
Top,
Bottom,
Left,
Right
};

// EdgeToolbar :a toolbar that can be placed on the edges of the App window
// It will be placed in a non-dockable window
struct EdgeToolbar
{
VoidFunction ShowToolbar = EmptyVoidFunction();

// height or width the top toolbar, in em units
// (i.e. multiples of the default font size, to be Dpi aware)
float sizeEm = 2.5f;

// Padding inside the window, in em units
ImVec2 WindowPaddingEm = ImVec2(0.3f, 0.3f);

// Window background color, only used if WindowBg.w > 0
ImVec4 WindowBg = ImVec4(0.f, 0.f, 0.f, 0.f);
};

std::vector<EdgeToolbarType> AllEdgeToolbarTypes();
std::string EdgeToolbarTypeName(EdgeToolbarType e);
```
## MobileCallbacks
Expand Down
21 changes: 20 additions & 1 deletion src/hello_imgui/doc_params.src.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,30 @@ See [runner_params.h](https://github.com/pthom/hello_imgui/blob/master/src/hello
See [runner_callbacks.h](https://github.com/pthom/hello_imgui/blob/master/src/hello_imgui/runner_callbacks.h).
@import "runner_callbacks.h" {md_id=VoidFunction_AnyEventCallback}
```cpp
@import "runner_callbacks.h" {md_id=RunnerCallbacks}
```

@import "runner_callbacks.h" {md_id=VoidFunction_AnyEventCallback}
## Edge Toolbars Callbacks
More details on `RunnerParams.edgesToolbars` (a dictionary of `EdgeToolbar`, per edge type)

```cpp
struct RunnerCallbacks
{
...
// EdgesToolbars: A map that contains the definition of toolbars
// that can be placed on the edges of the App window
std::map<EdgeToolbarType, EdgeToolbar> edgesToolbars;
...
};
```

Where:
```cpp
@import "runner_callbacks.h" {md_id=EdgeToolbar}
```
## MobileCallbacks
Expand Down
5 changes: 3 additions & 2 deletions src/hello_imgui/internal/backend_impls/abstract_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,11 +444,12 @@ void AbstractRunner::SetLayoutResetIfNeeded()

void AbstractRunner::RenderGui()
{
DockingDetails::ProvideWindowOrDock(params);

DockingDetails::ShowToolbars(params);
if (params.imGuiWindowParams.showMenuBar)
Menu_StatusBar::ShowMenu(params);

DockingDetails::ProvideWindowOrDock(params);

if (params.appWindowParams.borderless) // Need to add params.appWindowParams.borderlessResizable
{
#if !defined(HELLOIMGUI_MOBILEDEVICE) && !defined(__EMSCRIPTEN__)
Expand Down
212 changes: 198 additions & 14 deletions src/hello_imgui/internal/docking_details.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "imgui_internal.h"
#include <map>
#include <cassert>
#include <optional>


namespace HelloImGui
Expand Down Expand Up @@ -238,12 +239,10 @@ void ShowDockableWindows(std::vector<DockableWindow>& dockableWindows)
}
}


void DoCreateFullScreenImGuiWindow(const RunnerParams& runnerParams, bool useDocking)
ImRect FullScreenRect_MinusInsets(const RunnerParams& runnerParams)
{
const ImGuiWindowParams& imGuiWindowParams = runnerParams.imGuiWindowParams;

ImGuiViewport* viewport = ImGui::GetMainViewport();
const ImGuiWindowParams& imGuiWindowParams = runnerParams.imGuiWindowParams;

ImVec2 fullScreenSize, fullScreenPos;
{
Expand All @@ -267,28 +266,213 @@ void DoCreateFullScreenImGuiWindow(const RunnerParams& runnerParams, bool useDoc
fullScreenPos += HelloImGui::EmToVec2(imGuiWindowParams.fullScreenWindow_MarginTopLeft);
fullScreenSize -= HelloImGui::EmToVec2(
imGuiWindowParams.fullScreenWindow_MarginTopLeft + imGuiWindowParams.fullScreenWindow_MarginBottomRight
);
);
}

ImGui::SetNextWindowPos(fullScreenPos);
ImGui::SetNextWindowSize(fullScreenSize);
ImGui::SetNextWindowViewport(viewport->ID);
if (useDocking)
ImGui::SetNextWindowBgAlpha(0.0f);
ImRect r(fullScreenPos, fullScreenPos + fullScreenSize);
return r;
}


// This function returns many different positions:
// - position of the main dock space (if edgeToolbarTypeOpt==nullopt)
// - position of an edge toolbar (if edgeToolbarTypeOpt!=nullopt)
ImRect FixedWindowRect(
const RunnerParams& runnerParams,
std::optional<EdgeToolbarType> edgeToolbarTypeOpt)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
const ImGuiWindowParams& imGuiWindowParams = runnerParams.imGuiWindowParams;

ImRect fullScreenRectMinusInsets = FullScreenRect_MinusInsets(runnerParams);
ImVec2 fullScreenPos = fullScreenRectMinusInsets.Min;
ImVec2 fullScreenSize = fullScreenRectMinusInsets.GetSize();

// EdgeToolbar positions
if (edgeToolbarTypeOpt.has_value())
{
auto edgeToolbarType = *edgeToolbarTypeOpt;
auto& edgesToolbarsMap = runnerParams.callbacks.edgesToolbars;
if (edgesToolbarsMap.find(edgeToolbarType) != edgesToolbarsMap.end())
{
auto& edgeToolbar = edgesToolbarsMap.at(edgeToolbarType);
if (edgeToolbar.ShowToolbar)
{
if ( edgeToolbarType == EdgeToolbarType::Top)
{
if (imGuiWindowParams.showMenuBar)
{
float menuHeight = ImGui::GetFrameHeight() * 1.f;
fullScreenPos.y += menuHeight;
}
fullScreenSize.y = HelloImGui::EmSize(edgeToolbar.sizeEm);
}
if ( edgeToolbarType == EdgeToolbarType::Bottom)
{
float height = HelloImGui::EmSize(edgeToolbar.sizeEm);
fullScreenPos.y = fullScreenPos.y + fullScreenSize.y - height - 1.f; // -1 to avoid a thin line
fullScreenSize.y = height;
}
if ( (edgeToolbarType == EdgeToolbarType::Left) || (edgeToolbarType == EdgeToolbarType::Right))
{
float width = HelloImGui::EmSize(edgeToolbar.sizeEm);
if (imGuiWindowParams.showMenuBar)
{
float menuHeight = ImGui::GetFrameHeight() * 1.f;
fullScreenPos.y += menuHeight;
fullScreenSize.y -= menuHeight;
}
if (runnerParams.callbacks.edgesToolbars.find(EdgeToolbarType::Top) != runnerParams.callbacks.edgesToolbars.end())
{
auto height = HelloImGui::EmSize(
runnerParams.callbacks.edgesToolbars.at(EdgeToolbarType::Top).sizeEm);
fullScreenPos.y += height;
fullScreenSize.y -= height - 1.f; // -1 to avoid a thin line between the left and bottom toolbar
}
if (runnerParams.callbacks.edgesToolbars.find(EdgeToolbarType::Bottom) != runnerParams.callbacks.edgesToolbars.end())
{
auto height = HelloImGui::EmSize(
runnerParams.callbacks.edgesToolbars.at(EdgeToolbarType::Bottom).sizeEm);
fullScreenSize.y -= height - 1.f; // -1 to avoid a thin line between the left and bottom toolbar
}
}
if ( edgeToolbarType == EdgeToolbarType::Left)
{
auto width = HelloImGui::EmSize(
runnerParams.callbacks.edgesToolbars.at(EdgeToolbarType::Right).sizeEm);
fullScreenSize.x = width;
}
if ( edgeToolbarType == EdgeToolbarType::Right)
{
auto width = HelloImGui::EmSize(
runnerParams.callbacks.edgesToolbars.at(EdgeToolbarType::Right).sizeEm);
fullScreenPos.x = fullScreenPos.x + fullScreenSize.x - width;
fullScreenSize.x = width + 1.f; // + 1 to avoid a thin line
}
}
}
}

// Update full screen window: take toolbars into account
if (! edgeToolbarTypeOpt.has_value())
{
if (imGuiWindowParams.showMenuBar)
{
float menuHeight = ImGui::GetFrameHeight() * 1.f;
fullScreenPos.y += menuHeight;
fullScreenSize.y -= menuHeight;
}

auto& edgesToolbarsMap = runnerParams.callbacks.edgesToolbars;

for(auto edgeToolbarType: HelloImGui::AllEdgeToolbarTypes())
{
if (edgesToolbarsMap.find(edgeToolbarType) != edgesToolbarsMap.end())
{
auto& edgeToolbar = edgesToolbarsMap.at(edgeToolbarType);
if (edgeToolbar.ShowToolbar)
{
if (edgeToolbarType == EdgeToolbarType::Top)
{
float height = HelloImGui::EmSize(edgeToolbar.sizeEm);
fullScreenPos.y += height;
fullScreenSize.y -= height;
}
if (edgeToolbarType == EdgeToolbarType::Bottom)
{
float height = HelloImGui::EmSize(edgeToolbar.sizeEm);
fullScreenSize.y -= height;
}
if (edgeToolbarType == EdgeToolbarType::Left)
{
float width = HelloImGui::EmSize(edgeToolbar.sizeEm);
fullScreenPos.x += width;
fullScreenSize.x -= width;
}
if (edgeToolbarType == EdgeToolbarType::Right)
{
float width = HelloImGui::EmSize(edgeToolbar.sizeEm);
fullScreenSize.x -= width;
}
}
}
}
}

ImRect r(fullScreenPos, fullScreenPos + fullScreenSize);
return r;
}

static ImGuiWindowFlags WindowFlagsNothing()
{
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove;
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
if (imGuiWindowParams.showMenuBar)
window_flags |= ImGuiWindowFlags_MenuBar;
return window_flags;
}

void DoShowToolbar(
ImRect positionRect,
VoidFunction toolbarFunction,
const std::string& windowId,
ImVec2 windowPaddingEm,
ImVec4 windowBg
)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();

ImGui::SetNextWindowPos(positionRect.Min);
ImGui::SetNextWindowSize(positionRect.GetSize());
ImGui::SetNextWindowViewport(viewport->ID);


ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, HelloImGui::EmToVec2(windowPaddingEm));
if (windowBg.w != 0.f)
ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBg);
static bool p_open = true;
ImGui::Begin(windowId.c_str(), &p_open, WindowFlagsNothing());
ImGui::PopStyleVar(3);
if (windowBg.w != 0.f)
ImGui::PopStyleColor();
toolbarFunction();
ImGui::End();
}


void ShowToolbars(const RunnerParams& runnerParams)
{
for (auto edgeToolbarType: HelloImGui::AllEdgeToolbarTypes())
{
if (runnerParams.callbacks.edgesToolbars.find(edgeToolbarType) != runnerParams.callbacks.edgesToolbars.end())
{
auto& edgeToolbar = runnerParams.callbacks.edgesToolbars.at(edgeToolbarType);
auto fullScreenRect = FixedWindowRect(runnerParams, edgeToolbarType);
std::string windowName = std::string("##") + HelloImGui::EdgeToolbarTypeName(edgeToolbarType) + "_2123243";
DoShowToolbar(fullScreenRect, edgeToolbar.ShowToolbar, windowName, edgeToolbar.WindowPaddingEm, edgeToolbar.WindowBg);
}
}
}

void DoCreateFullScreenImGuiWindow(const RunnerParams& runnerParams, bool useDocking)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImRect fullScreenRect = FixedWindowRect(runnerParams, std::nullopt);

ImGui::SetNextWindowPos(fullScreenRect.Min);
ImGui::SetNextWindowSize(fullScreenRect.GetSize());
ImGui::SetNextWindowViewport(viewport->ID);
if (useDocking)
ImGui::SetNextWindowBgAlpha(0.0f);

ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
static bool p_open = true;
std::string windowTitle = useDocking ? "MainDockSpace" : "Main window (title bar invisible)";
ImGui::Begin(windowTitle.c_str(), &p_open, window_flags);
ImGui::Begin(windowTitle.c_str(), &p_open, WindowFlagsNothing());
ImGui::PopStyleVar(3);
}

Expand Down
1 change: 1 addition & 0 deletions src/hello_imgui/internal/docking_details.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace HelloImGui
// Internal functions below
namespace DockingDetails
{
void ShowToolbars(const RunnerParams& runnerParams);
void ConfigureImGuiDocking(const ImGuiWindowParams& imGuiWindowParams);
void ProvideWindowOrDock(RunnerParams& runnerParams);
void CloseWindowOrDock(ImGuiWindowParams& imGuiWindowParams);
Expand Down
Loading

0 comments on commit 4ac930c

Please sign in to comment.