From 1760562202dcd0251def1af2b445a7fbd4b2c19a Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Mon, 13 Feb 2023 09:58:12 -0500 Subject: [PATCH] Add a sample UI for linux apps - lighting app (#24979) * Initial version of a imgui UI in light app for linux. Also fixed linux app shutdown to handle signals by loop terminating instead of app killing. * remove some fixme comments * Fix unit tests ... with-ui variant was added * Restyle * Update text and remove some commented out code * Restyle --------- Co-authored-by: Andrei Litvin --- .gitmodules | 4 + examples/common/QRCode/BUILD.gn | 5 +- examples/lighting-app/linux/BUILD.gn | 13 + examples/lighting-app/linux/main.cpp | 13 + examples/lighting-app/linux/ui.cpp | 370 ++++++++++++++++++ examples/lighting-app/linux/ui.h | 28 ++ examples/platform/linux/AppMain.cpp | 7 + scripts/build/build/targets.py | 1 + scripts/build/builders/host.py | 4 + .../build/testdata/all_targets_linux_x64.txt | 2 +- third_party/imgui/BUILD.gn | 63 +++ third_party/imgui/imgui.gni | 23 ++ third_party/imgui/repo | 1 + 13 files changed, 532 insertions(+), 2 deletions(-) create mode 100644 examples/lighting-app/linux/ui.cpp create mode 100644 examples/lighting-app/linux/ui.h create mode 100644 third_party/imgui/BUILD.gn create mode 100644 third_party/imgui/imgui.gni create mode 160000 third_party/imgui/repo diff --git a/.gitmodules b/.gitmodules index b10429140c7edc..d9f332d45c1e8a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -289,3 +289,7 @@ path = third_party/libwebsockets/repo url = https://github.com/warmcat/libwebsockets platforms = linux,darwin,tizen +[submodule "third_party/imgui/repo"] + path = third_party/imgui/repo + url = https://github.com/ocornut/imgui + platforms = linux diff --git a/examples/common/QRCode/BUILD.gn b/examples/common/QRCode/BUILD.gn index d7918f55d5433e..b876f484357d0c 100644 --- a/examples/common/QRCode/BUILD.gn +++ b/examples/common/QRCode/BUILD.gn @@ -21,7 +21,10 @@ config("qrcode-common_config") { static_library("QRCode") { output_name = "libqrcode-common" - sources = [ "repo/c/qrcodegen.c" ] + sources = [ + "repo/c/qrcodegen.c", + "repo/c/qrcodegen.h", + ] public_configs = [ ":qrcode-common_config" ] diff --git a/examples/lighting-app/linux/BUILD.gn b/examples/lighting-app/linux/BUILD.gn index 721f408437d7c7..3b20243631b6de 100644 --- a/examples/lighting-app/linux/BUILD.gn +++ b/examples/lighting-app/linux/BUILD.gn @@ -16,6 +16,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/build/chip/tools.gni") import("${chip_root}/src/app/common_flags.gni") +import("${chip_root}/third_party/imgui/imgui.gni") assert(chip_build_tools) @@ -46,6 +47,18 @@ executable("chip-lighting-app") { "${chip_root}/src/lib", ] + if (chip_examples_enable_imgui_ui) { + deps += [ + "${chip_root}/examples/common/QRCode", + "${chip_root}/third_party/imgui", + ] + + sources += [ + "ui.cpp", + "ui.h", + ] + } + include_dirs = [ "include" ] if (chip_enable_pw_rpc) { diff --git a/examples/lighting-app/linux/main.cpp b/examples/lighting-app/linux/main.cpp index 7813c59979c929..a74aa5df4c3059 100644 --- a/examples/lighting-app/linux/main.cpp +++ b/examples/lighting-app/linux/main.cpp @@ -26,6 +26,10 @@ #include #include +#if defined(CHIP_IMGUI_ENABLED) && CHIP_IMGUI_ENABLED +#include "ui.h" +#endif + using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; @@ -81,7 +85,16 @@ int main(int argc, char * argv[]) } LightingMgr().Init(); + +#if defined(CHIP_IMGUI_ENABLED) && CHIP_IMGUI_ENABLED + example::Ui::Start(); +#endif + ChipLinuxAppMainLoop(); +#if defined(CHIP_IMGUI_ENABLED) && CHIP_IMGUI_ENABLED + example::Ui::Stop(); +#endif + return 0; } diff --git a/examples/lighting-app/linux/ui.cpp b/examples/lighting-app/linux/ui.cpp new file mode 100644 index 00000000000000..32ff5f401bbe59 --- /dev/null +++ b/examples/lighting-app/linux/ui.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ui.h" + +#include // examples/platform/linux/Options.h +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace example { +namespace Ui { + +namespace { + +std::atomic gUiRunning{ false }; + +class DeviceState +{ +public: + DeviceState() { sem_init(&mChipLoopWaitSemaphore, 0 /* shared */, 0); } + ~DeviceState() { sem_destroy(&mChipLoopWaitSemaphore); } + + // Initialize. MUST be called within the CHIP main loop as it + // loads startup data. + void Init(); + + // Use ImgUI to show the current state + void ShowUi(); + + // Fetches the current state from Ember + void UpdateState(); + +private: + static constexpr int kQRCodeVersion = qrcodegen_VERSION_MAX; + static constexpr int kMaxQRBufferSize = qrcodegen_BUFFER_LEN_FOR_VERSION(kQRCodeVersion); + + sem_t mChipLoopWaitSemaphore; + + bool mHasQRCode = false; + uint8_t mQRData[kMaxQRBufferSize] = { 0 }; + + // light data: + bool mOnOff = false; + + // Updates the data (run in the chip event loop) + void ChipLoopUpdate(); + + void InitQRCode(); + + // Run in CHIPMainLoop to access ember in a single threaded + // fashion + static void ChipLoopUpdateCallback(intptr_t self); +}; + +DeviceState gDeviceState; + +void DeviceState::Init() +{ + InitQRCode(); +} + +void DeviceState::InitQRCode() +{ + + chip::PayloadContents payload = LinuxDeviceOptions::GetInstance().payload; + if (!payload.isValidQRCodePayload()) + { + return; + } + + char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; + chip::MutableCharSpan qrCode(payloadBuffer); + + CHIP_ERROR err = GetQRCode(qrCode, payload); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Failed to load QR code: %" CHIP_ERROR_FORMAT, err.Format()); + return; + } + + if (qrCode.size() > kMaxQRBufferSize) + { + ChipLogError(AppServer, "Insufficient qr code buffer size to encode"); + return; + } + + uint8_t tempAndData[kMaxQRBufferSize]; + memcpy(tempAndData, qrCode.data(), qrCode.size()); + + mHasQRCode = qrcodegen_encodeBinary(tempAndData, qrCode.size(), mQRData, qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, + qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); + + if (!mHasQRCode) + { + ChipLogError(AppServer, "Failed to encode QR code"); + return; + } +} + +inline ImVec2 operator+(const ImVec2 & a, const ImVec2 & b) +{ + return ImVec2(a.x + b.x, a.y + b.y); +} + +void DeviceState::ShowUi() +{ + ImGui::Begin("Light app"); + ImGui::Text("Here is the current ember device state:"); + ImGui::Checkbox("Light is ON", &mOnOff); + ImGui::End(); + + if (mHasQRCode) + { + ImGui::Begin("QR Code."); + + ImDrawList * drawList = ImGui::GetWindowDrawList(); + + constexpr int kBorderSize = 35; + constexpr int kMinWindowSize = 200; + const int kQRCodeSize = qrcodegen_getSize(mQRData); + + ImVec2 pos = ImGui::GetWindowPos(); + ImVec2 size = ImGui::GetWindowSize(); + + if (size.y < kMinWindowSize) + { + size = ImVec2(kMinWindowSize, kMinWindowSize); + ImGui::SetWindowSize(size); + } + + // Fill the entire window white, then figure out borders + drawList->AddRectFilled(pos, pos + size, IM_COL32_WHITE); + + // add a border + if (size.x >= 2 * kBorderSize && size.y >= 2 * kBorderSize) + { + size.x -= 2 * kBorderSize; + size.y -= 2 * kBorderSize; + pos.x += kBorderSize; + pos.y += kBorderSize; + } + + // create a square rectangle: keep only the smaller side and adjust the + // other + if (size.x > size.y) + { + pos.x += (size.x - size.y) / 2; + size.x = size.y; + } + else if (size.y > size.x) + { + pos.y += (size.y - size.x) / 2; + size.y = size.x; + } + + const ImVec2 squareSize = ImVec2(size.x / static_cast(kQRCodeSize), size.y / static_cast(kQRCodeSize)); + + for (int y = 0; y < kQRCodeSize; ++y) + { + for (int x = 0; x < kQRCodeSize; ++x) + { + if (qrcodegen_getModule(mQRData, x, y)) + { + ImVec2 placement = + ImVec2(pos.x + static_cast(x) * squareSize.x, pos.y + static_cast(y) * squareSize.y); + drawList->AddRectFilled(placement, placement + squareSize, IM_COL32_BLACK); + } + } + } + + ImGui::End(); + } +} + +void DeviceState::ChipLoopUpdate() +{ + // This will contain a dimmable light + static constexpr chip::EndpointId kLightEndpointId = 1; + + // TODO: + // - consider error checking + // - add more attributes to the display (color? brightness?) + { + uint8_t value; + emberAfReadServerAttribute(kLightEndpointId, chip::app::Clusters::OnOff::Id, + chip::app::Clusters::OnOff::Attributes::OnOff::Id, &value, sizeof(value)); + mOnOff = (value != 0); + } +} + +void DeviceState::ChipLoopUpdateCallback(intptr_t self) +{ + DeviceState * _this = reinterpret_cast(self); + _this->ChipLoopUpdate(); + sem_post(&_this->mChipLoopWaitSemaphore); // notify complete +} + +void DeviceState::UpdateState() +{ + chip::DeviceLayer::PlatformMgr().ScheduleWork(&ChipLoopUpdateCallback, reinterpret_cast(this)); + // ensure update is done when existing + if (sem_trywait(&mChipLoopWaitSemaphore) != 0) + { + if (!gUiRunning.load()) + { + // UI should stop, no need to wait, probably chip main loop is stopped + return; + } + std::this_thread::yield(); + } +} + +void UiInit(SDL_GLContext * gl_context, SDL_Window ** window) +{ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) + { + ChipLogError(AppServer, "SDL Init Error: %s\n", SDL_GetError()); + return; + } + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + *window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, + window_flags); + *gl_context = SDL_GL_CreateContext(*window); + SDL_GL_MakeCurrent(*window, *gl_context); + SDL_GL_SetSwapInterval(1); // Enable vsync + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO & io = ImGui::GetIO(); + (void) io; + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + // ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplSDL2_InitForOpenGL(*window, *gl_context); + ImGui_ImplOpenGL3_Init("#version 130"); +} + +void UiShutdown(SDL_GLContext * gl_context, SDL_Window ** window) +{ + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + + SDL_GL_DeleteContext(*gl_context); + SDL_DestroyWindow(*window); + SDL_Quit(); +} + +void UiLoop() +{ + SDL_GLContext gl_context; + SDL_Window * window = nullptr; + + UiInit(&gl_context, &window); + + ImGuiIO & io = ImGui::GetIO(); + + while (gUiRunning.load()) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL2_ProcessEvent(&event); + if (event.type == SDL_QUIT) + { + chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); + } + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && + event.window.windowID == SDL_GetWindowID(window)) + { + chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); + } + } + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + + gDeviceState.UpdateState(); + gDeviceState.ShowUi(); + + // rendering + ImGui::Render(); + glViewport(0, 0, (int) io.DisplaySize.x, (int) io.DisplaySize.y); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + SDL_GL_SwapWindow(window); + } + + UiShutdown(&gl_context, &window); + + ChipLogProgress(AppServer, "UI thread Stopped..."); +} + +static std::thread gUiThread; + +} // namespace + +void Start() +{ + // Init inside the "main" thread, so that it can access globals + // proparly (for QR code and such) + gDeviceState.Init(); + + gUiRunning = true; + std::thread uiThread(&UiLoop); + gUiThread.swap(uiThread); +} + +void Stop() +{ + gUiRunning = false; + gUiThread.join(); +} + +} // namespace Ui +} // namespace example diff --git a/examples/lighting-app/linux/ui.h b/examples/lighting-app/linux/ui.h new file mode 100644 index 00000000000000..85bf2aadf6ba30 --- /dev/null +++ b/examples/lighting-app/linux/ui.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace example { +namespace Ui { + +void Start(); + +void Stop(); + +} // namespace Ui +} // namespace example diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 876e0da8bc3751..05b8066f23bece 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -124,6 +124,11 @@ void Cleanup() // TODO(16968): Lifecycle management of storage-using components like GroupDataProvider, etc } +void StopSignalHandler(int signal) +{ + DeviceLayer::PlatformMgr().StopEventLoopTask(); +} + } // namespace #if CHIP_DEVICE_CONFIG_ENABLE_WPA @@ -389,6 +394,8 @@ void ChipLinuxAppMainLoop() ApplicationInit(); + signal(SIGTERM, StopSignalHandler); + signal(SIGINT, StopSignalHandler); DeviceLayer::PlatformMgr().RunEventLoop(); #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 2a6b1701de403e..db7053e9fdb301 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -148,6 +148,7 @@ def BuildHostTarget(): target.AppendModifier('clang', use_clang=True) target.AppendModifier('test', extra_tests=True) target.AppendModifier('rpc', enable_rpcs=True) + target.AppendModifier('with-ui', imgui_ui=True) return target diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index b05a034e41b6d0..b3bfbaa7a326ba 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -229,6 +229,7 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, use_coverage=False, use_dmalloc=False, minmdns_address_policy=None, minmdns_high_verbosity=False, + imgui_ui=False, crypto_library: HostCryptoLibrary = None): super(HostBuilder, self).__init__( root=os.path.join(root, 'examples', app.ExamplePath()), @@ -282,6 +283,9 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, if use_libfuzzer: self.extra_gn_options.append('is_libfuzzer=true') + if imgui_ui: + self.extra_gn_options.append('chip_examples_enable_imgui_ui=true') + self.use_coverage = use_coverage if use_coverage: self.extra_gn_options.append('use_coverage=true') diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index 7b7ae2126f1e85..77c780e3431b98 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -8,7 +8,7 @@ efr32-{brd4161a,brd4187c,brd4163a,brd4164a,brd4166a,brd4170a,brd4186a,brd4187a,b esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only] genio-lighting-app linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-coverage][-dmalloc][-clang] -linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,python-bindings,tv-app,tv-casting-app,bridge,dynamic-bridge,tests,chip-cert,address-resolve-tool}[-nodeps][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-coverage][-dmalloc][-clang][-test][-rpc] +linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,minmdns,light,lock,shell,ota-provider,ota-requestor,python-bindings,tv-app,tv-casting-app,bridge,dynamic-bridge,tests,chip-cert,address-resolve-tool}[-nodeps][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui] linux-x64-efr32-test-runner[-clang] imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release] infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage] diff --git a/third_party/imgui/BUILD.gn b/third_party/imgui/BUILD.gn new file mode 100644 index 00000000000000..362e9641fc0091 --- /dev/null +++ b/third_party/imgui/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +config("imgui_config") { + include_dirs = [ + "repo", + "repo/backends", + ] + defines = [ "CHIP_IMGUI_ENABLED=1" ] + + # FUTURE: these should be parsed from `sdl2-config --cflags` + include_dirs += [ "/usr/include/SDL2" ] + defines += [ "_REENTRANT" ] +} + +source_set("imgui") { + sources = [ + "repo/imconfig.h", + "repo/imgui.cpp", + "repo/imgui.h", + "repo/imgui_draw.cpp", + "repo/imgui_internal.h", + "repo/imgui_tables.cpp", + "repo/imgui_widgets.cpp", + "repo/imstb_rectpack.h", + "repo/imstb_textedit.h", + "repo/imstb_truetype.h", + ] + + # SDL2 + OPENGL3 backend enabled directly here since + # the includes are circular (backend includes imgui) + sources += [ + "repo/backends/imgui_impl_opengl3.cpp", + "repo/backends/imgui_impl_opengl3.h", + "repo/backends/imgui_impl_sdl2.cpp", + "repo/backends/imgui_impl_sdl2.h", + ] + + # FUTURE: SDL2 libs should be from `sdl2-config --libs` + # Also different platforms may require different seettings (e.g. on mac this + # seems to need `-framework OpenGl -framework CoreFoundation` + libs = [ + "SDL2", + "GL", + "dl", + ] + + public_configs = [ ":imgui_config" ] +} diff --git a/third_party/imgui/imgui.gni b/third_party/imgui/imgui.gni new file mode 100644 index 00000000000000..6db92047d9747e --- /dev/null +++ b/third_party/imgui/imgui.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +import("${chip_root}/src/platform/device.gni") + +declare_args() { + # Enable UI functionality for example apps + chip_examples_enable_imgui_ui = false +} diff --git a/third_party/imgui/repo b/third_party/imgui/repo new file mode 160000 index 00000000000000..85395b76b08111 --- /dev/null +++ b/third_party/imgui/repo @@ -0,0 +1 @@ +Subproject commit 85395b76b08111961aa6e0ff026fd5152d48aa15