Skip to content

Commit

Permalink
[glass] Replace Window/View with immediate mode
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJohnson committed Oct 22, 2024
1 parent 5af935c commit fae7325
Show file tree
Hide file tree
Showing 14 changed files with 394 additions and 289 deletions.
102 changes: 52 additions & 50 deletions glass/src/app/native/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "glass/Context.h"
#include "glass/MainMenuBar.h"
#include "glass/Storage.h"
#include "glass/View.h"
#include "glass/Window.h"
#include "glass/networktables/NetworkTables.h"
#include "glass/networktables/NetworkTablesProvider.h"
#include "glass/networktables/NetworkTablesSettings.h"
Expand All @@ -43,10 +43,10 @@ static std::unique_ptr<glass::NetworkTablesProvider> gNtProvider;
static std::unique_ptr<glass::NetworkTablesModel> gNetworkTablesModel;
static std::unique_ptr<glass::NetworkTablesSettings> gNetworkTablesSettings;
static glass::LogData gNetworkTablesLog;
static std::unique_ptr<glass::Window> gNetworkTablesWindow;
static std::unique_ptr<glass::Window> gNetworkTablesInfoWindow;
static std::unique_ptr<glass::Window> gNetworkTablesSettingsWindow;
static std::unique_ptr<glass::Window> gNetworkTablesLogWindow;
static glass::Window* gNetworkTablesWindow;
static glass::Window* gNetworkTablesInfoWindow;
static glass::Window* gNetworkTablesSettingsWindow;
static glass::Window* gNetworkTablesLogWindow;

static glass::MainMenuBar gMainMenu;
static bool gAbout = false;
Expand Down Expand Up @@ -134,55 +134,34 @@ static void NtInitialize() {
}
});

gNetworkTablesLogWindow = std::make_unique<glass::Window>(
glass::GetStorageRoot().GetChild("NetworkTables Log"),
"NetworkTables Log", glass::Window::kHide);
gNetworkTablesLogWindow->SetView(
std::make_unique<glass::LogView>(&gNetworkTablesLog));
gNetworkTablesLogWindow = glass::imm::CreateWindow("NetworkTables Log", false,
glass::Window::kHide);
gNetworkTablesLogWindow->SetDefaultPos(250, 615);
gNetworkTablesLogWindow->SetDefaultSize(600, 130);
gNetworkTablesLogWindow->DisableRenamePopup();
gui::AddLateExecute([] { gNetworkTablesLogWindow->Display(); });

// NetworkTables table window
gNetworkTablesModel = std::make_unique<glass::NetworkTablesModel>();
gui::AddEarlyExecute([] { gNetworkTablesModel->Update(); });

gNetworkTablesWindow = std::make_unique<glass::Window>(
glass::GetStorageRoot().GetChild("NetworkTables View"), "NetworkTables");
gNetworkTablesWindow->SetView(
std::make_unique<glass::NetworkTablesView>(gNetworkTablesModel.get()));
gNetworkTablesWindow = glass::imm::CreateWindow("NetworkTables View");
gNetworkTablesWindow->SetDefaultPos(250, 277);
gNetworkTablesWindow->SetDefaultSize(750, 185);
gNetworkTablesWindow->DisableRenamePopup();
gui::AddLateExecute([] { gNetworkTablesWindow->Display(); });

// NetworkTables info window
gNetworkTablesInfoWindow = std::make_unique<glass::Window>(
glass::GetStorageRoot().GetChild("NetworkTables Info"),
"NetworkTables Info");
gNetworkTablesInfoWindow->SetView(glass::MakeFunctionView(
[&] { glass::DisplayNetworkTablesInfo(gNetworkTablesModel.get()); }));
gNetworkTablesInfoWindow = glass::imm::CreateWindow(
"NetworkTables Info", false, glass::Window::kHide);
gNetworkTablesInfoWindow->SetDefaultPos(250, 130);
gNetworkTablesInfoWindow->SetDefaultSize(750, 145);
gNetworkTablesInfoWindow->SetDefaultVisibility(glass::Window::kHide);
gNetworkTablesInfoWindow->DisableRenamePopup();
gui::AddLateExecute([] { gNetworkTablesInfoWindow->Display(); });

// NetworkTables settings window
gNetworkTablesSettings = std::make_unique<glass::NetworkTablesSettings>(
"glass", glass::GetStorageRoot().GetChild("NetworkTables Settings"));
gui::AddEarlyExecute([] { gNetworkTablesSettings->Update(); });

gNetworkTablesSettingsWindow = std::make_unique<glass::Window>(
glass::GetStorageRoot().GetChild("NetworkTables Settings"),
"NetworkTables Settings");
gNetworkTablesSettingsWindow->SetView(
glass::MakeFunctionView([] { gNetworkTablesSettings->Display(); }));
gNetworkTablesSettingsWindow =
glass::imm::CreateWindow("NetworkTables Settings");
gNetworkTablesSettingsWindow->SetDefaultPos(30, 30);
gNetworkTablesSettingsWindow->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
gNetworkTablesSettingsWindow->DisableRenamePopup();
gui::AddLateExecute([] { gNetworkTablesSettingsWindow->Display(); });

gui::AddWindowScaler([](float scale) {
// scale default window positions
Expand Down Expand Up @@ -236,8 +215,6 @@ int main(int argc, char** argv) {

glass::AddStandardNetworkTablesViews(*gNtProvider);

gui::AddLateExecute([] { gMainMenu.Display(); });

gMainMenu.AddMainMenu([] {
if (ImGui::BeginMenu("View")) {
if (ImGui::MenuItem("Set Enter Key")) {
Expand All @@ -249,18 +226,10 @@ int main(int argc, char** argv) {
ImGui::EndMenu();
}
if (ImGui::BeginMenu("NetworkTables")) {
if (gNetworkTablesSettingsWindow) {
gNetworkTablesSettingsWindow->DisplayMenuItem("NetworkTables Settings");
}
if (gNetworkTablesWindow) {
gNetworkTablesWindow->DisplayMenuItem("NetworkTables View");
}
if (gNetworkTablesInfoWindow) {
gNetworkTablesInfoWindow->DisplayMenuItem("NetworkTables Info");
}
if (gNetworkTablesLogWindow) {
gNetworkTablesLogWindow->DisplayMenuItem("NetworkTables Log");
}
gNetworkTablesSettingsWindow->DisplayMenuItem("NetworkTables Settings");
gNetworkTablesWindow->DisplayMenuItem("NetworkTables View");
gNetworkTablesInfoWindow->DisplayMenuItem("NetworkTables Info");
gNetworkTablesLogWindow->DisplayMenuItem("NetworkTables Log");
ImGui::MenuItem("NetworkTables Debug Logging", nullptr,
&gNetworkTablesDebugLog);
ImGui::Separator();
Expand Down Expand Up @@ -295,6 +264,42 @@ int main(int argc, char** argv) {
});

gui::AddLateExecute([] {
gMainMenu.Display();

if (glass::imm::BeginWindow(gNetworkTablesLogWindow)) {
auto& settings = glass::GetStorage().GetOrNewData<glass::LogSettings>(
&gNetworkTablesLog);
if (glass::imm::BeginWindowSettingsPopup()) {
settings.DisplayMenu();
ImGui::EndPopup();
}
glass::DisplayLog(&gNetworkTablesLog, settings.IsAutoScroll());
}
glass::imm::EndWindow();

if (glass::imm::BeginWindow(gNetworkTablesWindow)) {
auto& settings =
glass::GetStorage().GetOrNewData<glass::NetworkTablesFlagsSettings>();
if (glass::imm::BeginWindowSettingsPopup()) {
settings.DisplayMenu();
glass::DisplayNetworkTablesAddMenu(gNetworkTablesModel.get(), {},
settings.GetFlags());
ImGui::EndPopup();
}
DisplayNetworkTables(gNetworkTablesModel.get(), settings.GetFlags());
}
glass::imm::EndWindow();

if (glass::imm::BeginWindow(gNetworkTablesInfoWindow)) {
glass::DisplayNetworkTablesInfo(gNetworkTablesModel.get());
}
glass::imm::EndWindow();

if (glass::imm::BeginWindow(gNetworkTablesSettingsWindow)) {
gNetworkTablesSettings->Display();
}
glass::imm::EndWindow();

if (gAbout) {
ImGui::OpenPopup("About");
gAbout = false;
Expand Down Expand Up @@ -359,9 +364,6 @@ int main(int argc, char** argv) {
}
gui::Main();

gNetworkTablesSettingsWindow.reset();
gNetworkTablesLogWindow.reset();
gNetworkTablesWindow.reset();
gNetworkTablesModel.reset();
gNtProvider.reset();
gPlotProvider.reset();
Expand Down
192 changes: 111 additions & 81 deletions glass/src/lib/native/cpp/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,17 @@

using namespace glass;

Window::Window(Storage& storage, std::string_view id,
Window::Window(Storage& storage, Storage& windowStorage, std::string_view id,
Visibility defaultVisibility)
: m_id{id},
m_name{storage.GetString("name")},
: m_storage{storage},
m_id{id},
m_name{windowStorage.GetString("name")},
m_defaultName{id},
m_visible{storage.GetBool("visible", defaultVisibility != kHide)},
m_enabled{storage.GetBool("enabled", defaultVisibility != kDisabled)},
m_defaultVisible{storage.GetValue("visible").boolDefault},
m_defaultEnabled{storage.GetValue("enabled").boolDefault} {}

void Window::SetVisibility(Visibility visibility) {
m_visible = visibility != kHide;
m_enabled = visibility != kDisabled;
}

void Window::SetDefaultVisibility(Visibility visibility) {
m_defaultVisible = visibility != kHide;
m_defaultEnabled = visibility != kDisabled;
}
m_visible{windowStorage.GetBool("visible", defaultVisibility != kHide)},
m_enabled{
windowStorage.GetBool("enabled", defaultVisibility != kDisabled)},
m_defaultVisible{windowStorage.GetValue("visible").boolDefault},
m_defaultEnabled{windowStorage.GetValue("enabled").boolDefault} {}

void Window::Display() {
if (!m_view) {
Expand All @@ -47,68 +39,11 @@ void Window::Display() {
return;
}

if (m_posCond != 0) {
ImGui::SetNextWindowPos(m_pos, m_posCond);
}
if (m_sizeCond != 0) {
ImGui::SetNextWindowSize(m_size, m_sizeCond);
}
if (m_setPadding) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, m_padding);
}

std::string label;
if (m_name.empty()) {
label = fmt::format("{}###{}", m_defaultName, m_id);
} else {
label = fmt::format("{}###{}", m_name, m_id);
}

if (Begin(label.c_str(), &m_visible, m_flags)) {
if (BeginWindow()) {
if (m_renamePopupEnabled || m_view->HasSettings()) {
bool isClicked = (ImGui::IsMouseReleased(ImGuiMouseButton_Right) &&
ImGui::IsItemHovered());
ImGuiWindow* window = ImGui::GetCurrentWindow();

bool settingsButtonClicked = false;
// Not docked, and window has just enough for the circles not to be
// touching
if (!ImGui::IsWindowDocked() &&
ImGui::GetWindowWidth() > (ImGui::GetFontSize() + 2) * 3 +
ImGui::GetStyle().FramePadding.x * 2) {
const ImGuiItemFlags itemFlagsRestore =
ImGui::GetCurrentContext()->CurrentItemFlags;

ImGui::GetCurrentContext()->CurrentItemFlags |=
ImGuiItemFlags_NoNavDefaultFocus;
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;

// Allow to draw outside of normal window
ImGui::PushClipRect(window->OuterRectClipped.Min,
window->OuterRectClipped.Max, false);

const ImRect titleBarRect = ImGui::GetCurrentWindow()->TitleBarRect();
const ImVec2 position = {titleBarRect.Max.x -
(ImGui::GetStyle().FramePadding.x * 3) -
(ImGui::GetFontSize() * 2),
titleBarRect.Min.y};
settingsButtonClicked =
HamburgerButton(ImGui::GetID("#SETTINGS"), position);

ImGui::PopClipRect();

ImGui::GetCurrentContext()->CurrentItemFlags = itemFlagsRestore;
}
if (settingsButtonClicked || isClicked) {
ImGui::OpenPopup(window->ID);
}

if (ImGui::BeginPopupEx(window->ID,
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings)) {
if (BeginWindowSettingsPopup()) {
if (m_renamePopupEnabled) {
ItemEditName(&m_name);
EditName();
}
m_view->Settings();

Expand All @@ -120,10 +55,7 @@ void Window::Display() {
} else {
m_view->Hidden();
}
End();
if (m_setPadding) {
ImGui::PopStyleVar();
}
EndWindow();
}

bool Window::DisplayMenuItem(const char* label) {
Expand All @@ -144,3 +76,101 @@ void Window::ScaleDefault(float scale) {
m_size.y *= scale;
}
}

bool Window::BeginWindow() {
PushStorageStack(m_storage);

if (!m_visible || !m_enabled) {
return false;
}
m_inWindow = true;

if (m_posCond != 0) {
ImGui::SetNextWindowPos(m_pos, m_posCond);
}
if (m_sizeCond != 0) {
ImGui::SetNextWindowSize(m_size, m_sizeCond);
}
if (m_setPadding) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, m_padding);
}

std::string label;
if (m_name.empty()) {
label = fmt::format("{}###{}", m_defaultName, m_id);
} else {
label = fmt::format("{}###{}", m_name, m_id);
}

return ImGui::Begin(label.c_str(), &m_visible, m_flags);
}

void Window::EndWindow() {
PopStorageStack();
if (!m_inWindow) {
return;
}
m_inWindow = false;
ImGui::End();
if (m_setPadding) {
ImGui::PopStyleVar();
}
}

bool Window::BeginWindowSettingsPopup() {
bool isClicked = (ImGui::IsMouseReleased(ImGuiMouseButton_Right) &&
ImGui::IsItemHovered());
ImGuiWindow* window = ImGui::GetCurrentWindow();

bool settingsButtonClicked = false;
// Not docked, and window has just enough for the circles not to be touching
if (!ImGui::IsWindowDocked() &&
ImGui::GetWindowWidth() > (ImGui::GetFontSize() + 2) * 3 +
ImGui::GetStyle().FramePadding.x * 2) {
const ImGuiItemFlags itemFlagsRestore =
ImGui::GetCurrentContext()->CurrentItemFlags;

ImGui::GetCurrentContext()->CurrentItemFlags |=
ImGuiItemFlags_NoNavDefaultFocus;
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;

// Allow to draw outside of normal window
ImGui::PushClipRect(window->OuterRectClipped.Min,
window->OuterRectClipped.Max, false);

const ImRect titleBarRect = ImGui::GetCurrentWindow()->TitleBarRect();
const ImVec2 position = {titleBarRect.Max.x -
(ImGui::GetStyle().FramePadding.x * 3) -
(ImGui::GetFontSize() * 2),
titleBarRect.Min.y};
settingsButtonClicked =
HamburgerButton(ImGui::GetID("#SETTINGS"), position);

ImGui::PopClipRect();

ImGui::GetCurrentContext()->CurrentItemFlags = itemFlagsRestore;
}
if (settingsButtonClicked || isClicked) {
ImGui::OpenPopup(window->ID);
}

return ImGui::BeginPopupEx(window->ID, ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings);
}

Window* imm::CreateWindow(Storage& root, std::string_view id, bool duplicateOk,
Window::Visibility defaultVisibility) {
Storage& storage = root.GetChild(id);
Storage& windowStorage = storage.GetChild("window");
if (auto window = windowStorage.GetData<Window>()) {
if (!duplicateOk) {
fmt::print(stderr, "GUI: ignoring duplicate window '{}'\n", id);
return nullptr;
}
return window;
}
windowStorage.SetData(
std::make_shared<Window>(storage, id, defaultVisibility));
return windowStorage.GetData<Window>();
}
Loading

0 comments on commit fae7325

Please sign in to comment.