Skip to content

Commit e806318

Browse files
Merge plotjuggler/main into internal_main (sync 2026-06-10)
Brings: - 9003e55 feat(dialog): WidgetData setListItemColors / listItemColors (#119) - 0c3aa51 chore: bump version to 0.7.0 - 5ee9eee feat(pj_plugins): expose DataSourceHandle::libraryOwner() (#116) - a90a969 feat(pj_base)!: carry frame_id through canonical Image schema (#117)
2 parents bcbdf3b + 9003e55 commit e806318

12 files changed

Lines changed: 50 additions & 7 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ endif()
111111
if(PJ_INSTALL_SDK)
112112
include(CMakePackageConfigHelpers)
113113

114-
set(PJ_PACKAGE_VERSION "0.6.0")
114+
set(PJ_PACKAGE_VERSION "0.7.0")
115115
set(PJ_PACKAGE_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/plotjuggler_sdk)
116116

117117
install(EXPORT plotjuggler_sdkTargets

conanfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
plugin_sdk — umbrella for plugin authors (base + dialog SDK + parser SDK)
77
plugin_host — umbrella for host loaders (data_source/parser/toolbox/dialog)
88
9-
A consuming Conan recipe declares e.g. `plotjuggler_sdk/0.6.0` and then:
9+
A consuming Conan recipe declares e.g. `plotjuggler_sdk/0.7.0` and then:
1010
1111
find_package(plotjuggler_sdk REQUIRED COMPONENTS plugin_sdk)
1212
target_link_libraries(my_plugin PRIVATE plotjuggler_sdk::plugin_sdk)
@@ -30,7 +30,7 @@
3030

3131
class PlotjugglerSdkConan(ConanFile):
3232
name = "plotjuggler_sdk"
33-
version = "0.6.0"
33+
version = "0.7.0"
3434
# Apache-2.0 covers the whole SDK (pj_base + pj_plugins). See LICENSE.
3535
license = "Apache-2.0"
3636
url = "https://github.com/PlotJuggler/plotjuggler_sdk"

docs/builtin_type.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ messages.
150150
| `anchor` | `BufferAnchor` | Keeps `data` alive when it references shared storage. |
151151
| `compressed_depth_min` | `std::optional<float>` | ROS compressed-depth quantization metadata, when present. |
152152
| `compressed_depth_max` | `std::optional<float>` | ROS compressed-depth quantization metadata, when present. |
153+
| `frame_id` | `std::string` | Source coordinate frame (ROS `sensor_msgs/Image` and `foxglove.CompressedImage` both carry it). Lets a consumer match the image to the `CameraInfo` of the same `frame_id` (calibration / native resolution), e.g. to rectify lens distortion so 2D annotations align with the image. Empty when the producer has no frame information. |
153154

154155
Common raw encodings are `rgb8`, `rgba8`, `bgr8`, `bgra8`, `mono8`, and
155156
`mono16`. Common compressed encodings are `jpeg`, `png`, and `qoi`.

pj_base/include/pj_base/builtin/image.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ struct Image {
150150
std::optional<float> compressed_depth_max;
151151

152152
Timestamp timestamp_ns = 0;
153+
154+
/// Source coordinate frame (ROS sensor_msgs/Image and foxglove.CompressedImage
155+
/// both carry it). Lets a consumer match the image to the CameraInfo of the same
156+
/// frame_id (calibration / native resolution), e.g. to rectify lens distortion so
157+
/// 2D annotations align with the image. Empty when the producer has no frame
158+
/// information.
159+
std::string frame_id;
153160
};
154161

155162
} // namespace sdk

pj_base/proto/pj/Image.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,9 @@ message Image {
5757
// ROS compressedDepth quantization maximum; set together with `compressed_depth_min` when `encoding ==
5858
// "compressedDepth"`.
5959
optional float compressed_depth_max = 9;
60+
61+
// Source coordinate frame (ROS sensor_msgs/Image, foxglove.CompressedImage). Lets a consumer match the image to the
62+
// CameraInfo of the same frame_id (calibration / native resolution), e.g. to rectify lens distortion so 2D
63+
// annotations align with the image. Empty when the producer has no frame information.
64+
string frame_id = 10;
6065
}

pj_base/src/builtin/image_codec.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ std::vector<uint8_t> serializeImage(const Image& image) {
5353
if (image.compressed_depth_max.has_value()) {
5454
writer.floatField(9, *image.compressed_depth_max);
5555
}
56+
writer.string(10, image.frame_id);
5657

5758
return out;
5859
}
@@ -139,6 +140,8 @@ Expected<sdk::Image> deserializeImage(const uint8_t* data, size_t size) {
139140
image.compressed_depth_max = v;
140141
return true;
141142
}
143+
case 10:
144+
return tag.type == WireType::kLengthDelimited && r.readString(image.frame_id);
142145
default:
143146
return false;
144147
}

pj_base/tests/image_codec_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ TEST(ImageCodecTest, RoundTripRawRGB8) {
3333
in.encoding = "rgb8";
3434
in.row_step = 6; // 2 px * 3 bytes
3535
in.is_bigendian = false;
36+
in.frame_id = "camera_front";
3637
const std::vector<uint8_t> pixels = {255, 0, 0, 0, 255, 0, 0, 0, 255, 128, 128, 128};
3738
in.data = Span<const uint8_t>(pixels.data(), pixels.size());
3839

@@ -45,6 +46,7 @@ TEST(ImageCodecTest, RoundTripRawRGB8) {
4546
EXPECT_EQ(out->encoding, in.encoding);
4647
EXPECT_EQ(out->row_step, in.row_step);
4748
EXPECT_FALSE(out->is_bigendian);
49+
EXPECT_EQ(out->frame_id, "camera_front");
4850
EXPECT_FALSE(out->compressed_depth_min.has_value());
4951
EXPECT_FALSE(out->compressed_depth_max.has_value());
5052
ASSERT_EQ(out->data.size(), pixels.size());
@@ -70,6 +72,7 @@ TEST(ImageCodecTest, RoundTripCompressedDepthWithRange) {
7072
ASSERT_TRUE(out->compressed_depth_max.has_value());
7173
EXPECT_FLOAT_EQ(*out->compressed_depth_min, 0.5f);
7274
EXPECT_FLOAT_EQ(*out->compressed_depth_max, 10.0f);
75+
EXPECT_TRUE(out->frame_id.empty()); // unset frame_id round-trips as empty
7376
}
7477

7578
} // namespace

pj_plugins/CLAUDE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ submodule-internal modules; `pj_base` carries none).
3535
only `MessageParserPluginBase` + `object_ingest_policy.hpp` live here under
3636
`pj_plugins/sdk/`. (The `docs/ARCHITECTURE.md` §2 diagram is stale on this.)
3737
- **Handles keep the DSO mapped.** Every handle holds a `shared_ptr<void>`
38-
library token, so destroying/hot-reloading the loader cannot `dlclose` a live
39-
plugin. Dialog handles add a non-owning `borrowed()` form for source/toolbox
40-
embedded dialogs — those must not outlive the owning handle.
38+
library token (exposed via `libraryOwner()`), so destroying/hot-reloading the
39+
loader cannot `dlclose` a live plugin — and a lazy ObjectStore payload anchor,
40+
whose `release` fn is plugin code, can capture that token to stay safe past the
41+
handle's own lifetime. Dialog handles add a non-owning `borrowed()` form for
42+
source/toolbox embedded dialogs — those must not outlive the owning handle.
4143

4244
## Read deeper
4345
| For | Read |

pj_plugins/dialog_protocol/include/pj_plugins/host/widget_data_view.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class WidgetDataView {
7575
[[nodiscard]] std::optional<std::vector<std::string>> selectedItems(std::string_view name) const {
7676
return getStringArray(name, "selected_items");
7777
}
78+
[[nodiscard]] std::optional<std::vector<std::string>> listItemColors(std::string_view name) const {
79+
return getStringArray(name, "list_item_colors");
80+
}
7881

7982
// --- QTableWidget ---
8083
[[nodiscard]] std::optional<std::vector<std::string>> tableHeaders(std::string_view name) const {

pj_plugins/dialog_protocol/include/pj_plugins/sdk/widget_data.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ class WidgetData {
9393
return *this;
9494
}
9595

96+
// Set foreground colors for QListWidget items, parallel to the items vector
97+
// set by setListItems. Each entry is a CSS color string (e.g. "#ff0000") or
98+
// empty to use the default palette color. Size must match the items vector.
99+
WidgetData& setListItemColors(std::string_view name, const std::vector<std::string>& colors) {
100+
entry(name)["list_item_colors"] = colors;
101+
return *this;
102+
}
103+
96104
// --- QTableWidget ---
97105
WidgetData& setTableHeaders(std::string_view name, const std::vector<std::string>& headers) {
98106
entry(name)["headers"] = headers;

0 commit comments

Comments
 (0)