Skip to content
Merged
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
17 changes: 8 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,6 @@ FetchContent_Declare(
)
FetchContent_Populate(kissfft)

# Fetch stb for PNG loading in icon registry (single-header, no build needed)
FetchContent_Declare(
stb
GIT_REPOSITORY https://github.com/nothings/stb.git
GIT_TAG master
)
FetchContent_Populate(stb)

# Fetch nlohmann/json for serialization (header-only)
FetchContent_Declare(
nlohmann_json
Expand Down Expand Up @@ -213,7 +205,6 @@ add_subdirectory("adc")
add_subdirectory("coax")
add_subdirectory("pfb_channelizer")
add_subdirectory("iq_plot")
add_subdirectory("icon_registry")
add_subdirectory("ideal_filter")
add_subdirectory("attenuator")
add_subdirectory("combiner")
Expand All @@ -224,6 +215,14 @@ add_subdirectory("tutorial")
# Install targets
# =============================================================================
install(TARGETS tiny-rf-simulator RUNTIME DESTINATION bin)
# Install component data (JSON library definitions + S-parameter files) and
# built-in extension payloads next to the executable. The app resolves both
# scan roots exe-relative (refreshExtensions in app.cpp, scanRoots in
# extension_manager.cpp), matching the layout/ + SessionState exe-relative
# convention.
install(DIRECTORY component_data DESTINATION bin)
install(DIRECTORY extensions DESTINATION bin)


# Install documentation
install(FILES README.md LICENSE DESTINATION share/doc/rf-simulator)
Expand Down
51 changes: 50 additions & 1 deletion app/src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
#include <portable-file-dialogs.h>
#include <unordered_map>
#include <utility>
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <climits>
#include <mach-o/dyld.h>
#else
#include <climits>
#include <unistd.h>
#endif
// Keep only filesystem-safe characters for path segments: [A-Za-z0-9-_ ].
// Strips everything else (incl. /, \\, and . which eliminates .. risks).
// Trims leading/trailing spaces. Returns fallback if result is empty.
Expand All @@ -34,6 +43,37 @@ static std::string sanitizePathSegment(const std::string &s, const std::string &
return out.empty() ? fallback : out;
}

// Directory of the running executable, for exe-relative data/layout lookup.
// Falls back to the current working directory if exe-path detection fails.
// Same convention as layout/ (LayoutManager) and tutorial/ (TutorialState).
static std::string appExeDir() {
std::string exe_path;
#ifdef _WIN32
char buf[MAX_PATH] = {};
DWORD n = GetModuleFileNameA(nullptr, buf, sizeof(buf));
if (n > 0 && n < sizeof(buf))
exe_path = buf;
#elif defined(__APPLE__)
char buf[PATH_MAX] = {};
uint32_t size = sizeof(buf);
if (_NSGetExecutablePath(buf, &size) == 0)
exe_path = buf;
#else
char buf[PATH_MAX] = {};
ssize_t n = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
exe_path = buf;
}
#endif
if (exe_path.empty())
return std::filesystem::current_path().string();
std::filesystem::path parent = std::filesystem::path(exe_path).parent_path();
if (parent.empty())
return std::filesystem::current_path().string();
return parent.string();
}

RfSimulatorApp::RfSimulatorApp() : m_components(m_graph_engine, m_view_manager) {
m_graph_widget = std::make_unique<NodeGraphWidget>(m_graph_engine);
m_serializer = std::make_unique<ProjectSerializer>(
Expand Down Expand Up @@ -234,7 +274,16 @@ void RfSimulatorApp::refreshExtensions() {
if (fs::exists("rf-sim-libraries")) {
m_library.scan("rf-sim-libraries");
}
if (fs::exists("component_data/library")) {
// Built-in examples: prefer the exe-relative install location
// (<exe_dir>/component_data/library) so installed binaries find their
// shipped data; fall back to the source-tree-relative path (CWD == repo
// root) when running from a build tree. Same exe-relative convention as
// layout/ and SessionState.
const std::filesystem::path exe_builtin_library =
std::filesystem::path(appExeDir()) / "component_data" / "library";
if (std::filesystem::exists(exe_builtin_library)) {
m_library.scan(exe_builtin_library.string());
} else if (std::filesystem::exists("component_data/library")) {
m_library.scan("component_data/library");
}

Expand Down
48 changes: 48 additions & 0 deletions app/src/extension_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,57 @@

#include <algorithm>
#include <charconv>
#include <climits>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <string_view>

#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
#else
#include <unistd.h>
#endif

#include <nlohmann/json.hpp>

namespace fs = std::filesystem;

namespace {

// Directory of the running executable, for exe-relative installed payloads.
// Falls back to the current working directory if exe-path detection fails.
// Same convention as layout/ (LayoutManager) and tutorial/ (TutorialState).
std::string detectExeDir() {
std::string exe_path;
#ifdef _WIN32
char buf[MAX_PATH] = {};
DWORD n = GetModuleFileNameA(nullptr, buf, sizeof(buf));
if (n > 0 && n < sizeof(buf))
exe_path = buf;
#elif defined(__APPLE__)
char buf[PATH_MAX] = {};
uint32_t size = sizeof(buf);
if (_NSGetExecutablePath(buf, &size) == 0)
exe_path = buf;
#else
char buf[PATH_MAX] = {};
ssize_t n = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (n > 0) {
buf[n] = '\0';
exe_path = buf;
}
#endif
if (exe_path.empty())
return fs::current_path().string();
fs::path parent = fs::path(exe_path).parent_path();
if (parent.empty())
return fs::current_path().string();
return parent.string();
}

std::optional<int> parseVersionPart(std::string_view part) {
if (part.empty())
return std::nullopt;
Expand Down Expand Up @@ -101,6 +141,14 @@ std::optional<std::string> readManifestId(const fs::path &manifest_path) {
std::vector<fs::path> ExtensionManager::scanRoots(const fs::path &project_root) const {
std::vector<fs::path> roots;
roots.push_back(fs::path(PROJECT_SOURCE_DIR) / "extensions");
// Installed built-in payloads live next to the executable
// (<exe_dir>/extensions), matching the install rules and the layout/ +
// SessionState exe-relative convention. Nonexistent in dev/build-tree
// layouts (loadRoot skips missing roots), so discovery is unchanged
// there. Placed right after the source-tree root and before the
// global/project-local roots, so later-root shadowing precedence is
// preserved (built-in > global > project-local).
roots.push_back(fs::path(detectExeDir()) / "extensions");
#ifdef _WIN32
if (const char *home = std::getenv("USERPROFILE"))
roots.push_back(fs::path(home) / ".rf-sim" / "extensions");
Expand Down
5 changes: 4 additions & 1 deletion attenuator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
cmake_minimum_required(VERSION 3.20)
project(attenuator LANGUAGES CXX)

add_library(attenuator_engine
src/attenuator_engine.cpp
)

target_include_directories(attenuator_engine PUBLIC include)
target_include_directories(attenuator_engine PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(attenuator_engine
PUBLIC common
PUBLIC simulator::touchstone_parser
Expand Down
3 changes: 3 additions & 0 deletions common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(common LANGUAGES CXX)

add_library(common INTERFACE)

target_include_directories(common
Expand Down
25 changes: 0 additions & 25 deletions icon_registry/CMakeLists.txt

This file was deleted.

17 changes: 0 additions & 17 deletions icon_registry/include/icon_registry.h

This file was deleted.

33 changes: 0 additions & 33 deletions icon_registry/src/icon_registry.cpp

This file was deleted.

37 changes: 0 additions & 37 deletions icon_registry/src/texture_loader.cpp

This file was deleted.

5 changes: 0 additions & 5 deletions icon_registry/src/texture_loader.h

This file was deleted.

3 changes: 2 additions & 1 deletion logging/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
project(logging)
cmake_minimum_required(VERSION 3.20)
project(logging LANGUAGES CXX)

# Backend
add_library(logging_core STATIC
Expand Down
4 changes: 3 additions & 1 deletion node_graph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ add_library(simulator::node_graph_engine ALIAS node_graph_engine)
# ---- UI Widget ----
add_library(node_graph_widget STATIC
src/node_graph_widget.cpp
src/node_graph_widget_groups.cpp
src/node_graph_widget_tooltips.cpp
src/schematic_symbols.cpp
)

target_include_directories(node_graph_widget
Expand All @@ -28,7 +31,6 @@ target_link_libraries(node_graph_widget
simulator::node_graph_engine
imnodes
simulator::core
simulator::icon_registry
)

add_library(simulator::node_graph_widget ALIAS node_graph_widget)
5 changes: 1 addition & 4 deletions node_graph/include/node_graph_widget.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "group.h"
#include "icon_registry.h"
#include "imgui.h"
#include "node_graph_engine.h"
#include <functional>
#include <string>
Expand All @@ -20,8 +20,6 @@ class NodeGraphWidget {

void draw(const char *title, bool *p_open = nullptr);

IconRegistry &iconRegistry() { return m_icons; }

// Callbacks for app to create/destroy components
std::function<void()> onNodeMoved;
std::function<void(int node_id)> onRemoveNode;
Expand Down Expand Up @@ -63,7 +61,6 @@ class NodeGraphWidget {
private:
NodeGraphEngine &m_engine;
ImNodesEditorContext *m_context;
IconRegistry m_icons;

// Interaction state tracking
int m_clicked_pin = -1;
Expand Down
Loading