mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-18 10:23:43 +08:00
cabana: smooth startup layout (#38794)
* cabana: smooth startup layout * cabana: remove camera tab startup comment * cabana: initialize dock geometry on the first frame * cabana: remove route loading placeholder
This commit is contained in:
@@ -132,6 +132,8 @@ public:
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
#endif
|
||||
// Restore geometry and render the initial layout before mapping the window.
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
window_ = glfwCreateWindow(1600, 900, "Cabana", nullptr, nullptr);
|
||||
if (window_ == nullptr) {
|
||||
glfwTerminate();
|
||||
@@ -212,6 +214,8 @@ int run(std::unique_ptr<AbstractStream> stream, StreamLoader stream_loader, cons
|
||||
inistate::applyWindowGeometry(glfw.window());
|
||||
|
||||
MainWindow win(glfw.window(), std::move(stream), std::move(stream_loader), dbc_file);
|
||||
renderFrame(glfw.window(), &win);
|
||||
glfwShowWindow(glfw.window());
|
||||
while (!win.exited()) {
|
||||
if (g_signal_exit.exchange(false)) {
|
||||
printf("\nexiting...\n");
|
||||
|
||||
@@ -184,7 +184,7 @@ void MainWindow::drawMenuBar() {
|
||||
if (ImGui::MenuItem("Full Screen", "Ctrl+F11")) toggleFullScreen();
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem(messages_widget_ ? messages_widget_->title().c_str() : "MESSAGES", nullptr, &messages_visible_);
|
||||
ImGui::MenuItem(video_dock_title_.empty() ? "##video_dock" : video_dock_title_.c_str(), nullptr, &video_visible_);
|
||||
ImGui::MenuItem(video_dock_title_.empty() ? "Video" : video_dock_title_.c_str(), nullptr, &video_visible_);
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Reset Window Layout")) {
|
||||
messages_visible_ = video_visible_ = true;
|
||||
@@ -789,8 +789,10 @@ void MainWindow::drawWaitDialog() {
|
||||
|
||||
void MainWindow::drawDockspace() {
|
||||
const ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
// Use the menu bar's current-frame reservation, including on the first frame.
|
||||
const ImRect work_rect = static_cast<const ImGuiViewportP *>(viewport)->GetBuildWorkRect();
|
||||
ImGui::SetNextWindowPos(work_rect.Min);
|
||||
ImGui::SetNextWindowSize(work_rect.GetSize());
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
@@ -813,6 +815,7 @@ void MainWindow::drawDockspace() {
|
||||
// messages left, video (with charts) right, center widget in the middle
|
||||
ImGui::DockBuilderRemoveNode(dock_id);
|
||||
ImGui::DockBuilderAddNode(dock_id, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodePos(dock_id, ImGui::GetCursorScreenPos());
|
||||
ImGui::DockBuilderSetNodeSize(dock_id, dock_size);
|
||||
ImGuiID center = dock_id, left = 0, right = 0;
|
||||
ImGui::DockBuilderSplitNode(center, ImGuiDir_Left, 0.28f, &left, ¢er);
|
||||
@@ -856,11 +859,13 @@ bool beginPanel(const char *name, bool *open, ImGuiWindowFlags flags = 0) {
|
||||
} // namespace
|
||||
|
||||
void MainWindow::drawMessagesPanel() {
|
||||
const std::string name = messages_widget_->title() + MESSAGES_PANEL_ID;
|
||||
const std::string name = (messages_widget_ ? messages_widget_->title() : "MESSAGES") + std::string(MESSAGES_PANEL_ID);
|
||||
setNextPanelClass();
|
||||
if (beginPanel(name.c_str(), &messages_visible_)) {
|
||||
help_overlay_.add(messages_widget_->whatsThis(), ImGui::GetCurrentWindow()->Rect());
|
||||
messages_widget_->draw();
|
||||
if (messages_widget_) {
|
||||
help_overlay_.add(messages_widget_->whatsThis(), ImGui::GetCurrentWindow()->Rect());
|
||||
messages_widget_->draw();
|
||||
}
|
||||
}
|
||||
const bool floating = floatingOut();
|
||||
ImGui::End();
|
||||
@@ -868,13 +873,13 @@ void MainWindow::drawMessagesPanel() {
|
||||
}
|
||||
|
||||
void MainWindow::drawVideoPanel() {
|
||||
const std::string name = video_dock_title_ + VIDEO_PANEL;
|
||||
const std::string name = (video_dock_title_.empty() ? "Video" : video_dock_title_) + VIDEO_PANEL;
|
||||
setNextPanelClass();
|
||||
const bool video_open = beginPanel(name.c_str(), &video_visible_);
|
||||
const bool floating = floatingOut();
|
||||
if (!video_open) {
|
||||
if (video_widget_ && !video_open) {
|
||||
video_widget_->setVisible(false); // the dock is collapsed or tabbed behind another one, like hideEvent
|
||||
} else {
|
||||
} else if (video_widget_) {
|
||||
const ImVec2 avail = ImGui::GetContentRegionAvail();
|
||||
const bool live = can->liveStreaming();
|
||||
// the bordered child pads its content, so the heights the widget asks for grow by the padding
|
||||
@@ -962,9 +967,11 @@ void MainWindow::draw() {
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
if (messages_widget_ && messages_visible_) drawMessagesPanel();
|
||||
// Submit the same dock windows while loading, so ImGui doesn't collapse their
|
||||
// nodes and then redistribute the layout when the stream's widgets arrive.
|
||||
if (messages_visible_) drawMessagesPanel();
|
||||
if (video_widget_ && !video_visible_) video_widget_->setVisible(false);
|
||||
if (video_widget_ && video_visible_) drawVideoPanel();
|
||||
if (video_visible_) drawVideoPanel();
|
||||
if (charts_widget_ && charts_floating_) {
|
||||
bool open = true;
|
||||
ImGui::SetNextWindowSize(ImGui::GetMainViewport()->WorkSize, ImGuiCond_Appearing);
|
||||
|
||||
@@ -95,7 +95,7 @@ float CameraWidget::frameAspectRatio() const {
|
||||
if (frame_texture_.width > 0 && frame_texture_.height > 0) {
|
||||
return (float)frame_texture_.width / frame_texture_.height;
|
||||
}
|
||||
return 1928.0f / 1208.0f; // the road camera, until the first frame arrives
|
||||
return DEFAULT_CAMERA_ASPECT_RATIO; // the road camera, until the first frame arrives
|
||||
}
|
||||
|
||||
void CameraWidget::paint() {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "tools/cabana/core/observable.h"
|
||||
#include "msgq/visionipc/visionipc_client.h"
|
||||
|
||||
constexpr float DEFAULT_CAMERA_ASPECT_RATIO = 1928.0f / 1208.0f;
|
||||
|
||||
// Center-crop the source to fill the destination without stretching.
|
||||
inline ImVec2 videoFillUv(const ImVec2 &size, float aspect_ratio) {
|
||||
const float ratio = size.x / size.y / aspect_ratio;
|
||||
|
||||
@@ -261,6 +261,16 @@ void VideoWidget::createCameraWidget() {
|
||||
if (index != -1) cam_widget_->setStreamType((VisionStreamType)camera_tab_->tabData(index));
|
||||
}));
|
||||
connections_.push_back(static_cast<ReplayStream *>(can)->qLogLoaded.connect([this](std::shared_ptr<LogReader> qlog) { cam_widget_->parseQLog(qlog); }));
|
||||
|
||||
if (auto *replay = getReplay(); replay && !replay->hasFlag(REPLAY_FLAG_NO_VIPC)) {
|
||||
std::set<VisionStreamType> streams;
|
||||
for (const auto &[num, segment] : replay->route().segments()) {
|
||||
if (!segment.narrow_road_cam.empty() || !segment.qcamera.empty()) streams.insert(VISION_STREAM_NARROW_ROAD);
|
||||
if (replay->hasFlag(REPLAY_FLAG_CABIN_CAMERA) && !segment.cabin_cam.empty()) streams.insert(VISION_STREAM_CABIN);
|
||||
if (replay->hasFlag(REPLAY_FLAG_WIDE_ROAD) && !segment.wide_road_cam.empty()) streams.insert(VISION_STREAM_WIDE_ROAD);
|
||||
}
|
||||
vipcAvailableStreamsUpdated(streams);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoWidget::drawCameraWidget() {
|
||||
@@ -344,10 +354,10 @@ float VideoWidget::sizeHintHeight() const {
|
||||
return MIN_VIDEO_HEIGHT + SLIDER_HEIGHT + toolbarHeight();
|
||||
}
|
||||
|
||||
// the video pane opens with the camera at its natural aspect ratio, filling the width of the dock
|
||||
// Keep the pane's default proportions stable as frames arrive or cameras change.
|
||||
float VideoWidget::defaultHeight(float width) const {
|
||||
if (!cam_widget_) return toolbarHeight(); // live streams have no camera or slider
|
||||
const float cam_height = std::max((float)MIN_VIDEO_HEIGHT, width / cam_widget_->frameAspectRatio());
|
||||
const float cam_height = std::max((float)MIN_VIDEO_HEIGHT, width / DEFAULT_CAMERA_ASPECT_RATIO);
|
||||
const float tab_height = camera_tab_->count() >= 2 ? ImGui::GetFrameHeight() : 0.0f;
|
||||
return cam_height + tab_height + SLIDER_HEIGHT + toolbarHeight();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user