performance 复制按钮
This commit is contained in:
@@ -24,6 +24,8 @@ struct Plot_Render_Context {
|
||||
std::shared_ptr<Frame_Lifecycle_Observer> frame_lifecycle_observer;
|
||||
std::mutex performance_update_callback_mutex;
|
||||
std::function<void()> performance_update_callback;
|
||||
std::mutex performance_clipboard_callback_mutex;
|
||||
std::function<void(std::string)> performance_clipboard_callback;
|
||||
std::atomic<std::uint64_t> performance_plot_id{0};
|
||||
mutable std::mutex performance_plot_name_mutex;
|
||||
std::string performance_plot_name;
|
||||
|
||||
@@ -152,6 +152,25 @@ static std::function<void()> performance_update_callback(const std::shared_ptr<P
|
||||
std::lock_guard<std::mutex> lock(ctx->performance_update_callback_mutex);
|
||||
return ctx->performance_update_callback;
|
||||
}
|
||||
static std::function<void(std::string)> performance_clipboard_callback(const std::shared_ptr<Plot_Render_Context>& ctx) {
|
||||
if (!ctx)
|
||||
return {};
|
||||
std::lock_guard<std::mutex> lock(ctx->performance_clipboard_callback_mutex);
|
||||
return ctx->performance_clipboard_callback;
|
||||
}
|
||||
static std::string performance_snapshot_text(const Performance_Display_Snapshot& snapshot) {
|
||||
std::size_t size = 0;
|
||||
for (const auto& line : snapshot.lines)
|
||||
size += line.size() + 1;
|
||||
std::string text;
|
||||
text.reserve(size);
|
||||
for (std::size_t i = 0; i < snapshot.lines.size(); ++i) {
|
||||
if (i)
|
||||
text.push_back('\n');
|
||||
text += snapshot.lines[i];
|
||||
}
|
||||
return text;
|
||||
}
|
||||
static void request_performance_update(const std::shared_ptr<Performance_Worker_State>& worker) {
|
||||
if (!worker)
|
||||
return;
|
||||
@@ -198,6 +217,7 @@ static std::shared_ptr<Performance_Overlay> attach_performance_overlay_impl(Plot
|
||||
if (options)
|
||||
created_shower->set_options(*options);
|
||||
created_shower->set_update_callback(performance_update_callback(ctx));
|
||||
created_shower->set_clipboard_callback(performance_clipboard_callback(ctx));
|
||||
std::atomic_store_explicit(&ctx->frame_lifecycle_observer, std::static_pointer_cast<Frame_Lifecycle_Observer>(created_shower), std::memory_order_release);
|
||||
return created_shower;
|
||||
}
|
||||
@@ -267,6 +287,18 @@ void set_performance_overlay_update_callback(Plot_Core& plot, std::function<void
|
||||
if (shower)
|
||||
shower->set_update_callback(performance_update_callback(ctx));
|
||||
}
|
||||
void set_performance_overlay_clipboard_callback(Plot_Core& plot, std::function<void(std::string)> callback) {
|
||||
auto ctx = Plot_Core_Context_Access::render_context(plot);
|
||||
if (!ctx)
|
||||
return;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ctx->performance_clipboard_callback_mutex);
|
||||
ctx->performance_clipboard_callback = std::move(callback);
|
||||
}
|
||||
auto shower = performance_overlay_owner(ctx);
|
||||
if (shower)
|
||||
shower->set_clipboard_callback(performance_clipboard_callback(ctx));
|
||||
}
|
||||
void notify_performance_overlay_viewport_changed(Plot_Core& plot) {
|
||||
auto shower = performance_overlay_owner(Plot_Core_Context_Access::render_context(plot));
|
||||
if (!shower || !shower->enabled())
|
||||
@@ -400,7 +432,17 @@ bool Performance_Overlay::handle_wheel(PointF position, double angle_delta_y, do
|
||||
}
|
||||
bool Performance_Overlay::handle_pointer_press(PointF position) {
|
||||
auto snapshot = display_snapshot();
|
||||
if (!snapshot || snapshot->max_scroll_offset <= 0.0)
|
||||
if (!snapshot)
|
||||
return false;
|
||||
if (!snapshot->copy_button_rect.empty() && snapshot->copy_button_rect.contains(position)) {
|
||||
d()->copy_to_clipboard(performance_snapshot_text(*snapshot));
|
||||
return true;
|
||||
}
|
||||
if (!snapshot->close_button_rect.empty() && snapshot->close_button_rect.contains(position)) {
|
||||
set_enabled(false);
|
||||
return true;
|
||||
}
|
||||
if (snapshot->max_scroll_offset <= 0.0)
|
||||
return false;
|
||||
if (snapshot->scroll_thumb_rect.contains(position)) {
|
||||
d()->metrics_worker->drag_anchor_y.store(position.y - snapshot->scroll_thumb_rect.y, std::memory_order_release);
|
||||
@@ -437,6 +479,9 @@ void Performance_Overlay::set_update_callback(std::function<void()> callback) {
|
||||
std::lock_guard<std::mutex> lock(d()->metrics_worker->update_callback_mutex);
|
||||
d()->metrics_worker->update_callback = std::move(callback);
|
||||
}
|
||||
void Performance_Overlay::set_clipboard_callback(std::function<void(std::string)> callback) {
|
||||
d()->set_clipboard_callback(std::move(callback));
|
||||
}
|
||||
void write_frame_performance_log(std::shared_ptr<const Frame_Lifecycle_Record> frame) {
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../architecture/Frame_Scheduler.h"
|
||||
#include "../base/Color.h"
|
||||
#include "../base/Geometry.h"
|
||||
@@ -63,6 +64,7 @@ public:
|
||||
bool handle_pointer_move(PointF position);
|
||||
bool handle_pointer_release(PointF position);
|
||||
void set_update_callback(std::function<void()> callback);
|
||||
void set_clipboard_callback(std::function<void(std::string)> callback);
|
||||
|
||||
private:
|
||||
Performance_Overlay_Private* d();
|
||||
|
||||
@@ -453,18 +453,45 @@ struct Performance_Layout_Builder {
|
||||
RectF panel_rect;
|
||||
RectF scroll_bar_rect;
|
||||
RectF scroll_thumb_rect;
|
||||
RectF copy_button_rect;
|
||||
RectF close_button_rect;
|
||||
double content_width{};
|
||||
double copy_button_width{};
|
||||
double close_button_width{};
|
||||
double toolbar_height{};
|
||||
double button_gap{4.0};
|
||||
static std::string value(double number, int precision = 2) {
|
||||
return format_number(number, {.precision = precision});
|
||||
}
|
||||
double panel_height(double line_height, Performance_Overlay_Render_State* state, int plot_height) const {
|
||||
return std::min(content_height(line_height, state), static_cast<double>(std::max(0, plot_height)));
|
||||
}
|
||||
double text_top(Performance_Overlay_Render_State* state) const {
|
||||
return static_cast<double>(state->top_margin) + toolbar_height + 4.0;
|
||||
}
|
||||
double content_height(double line_height, Performance_Overlay_Render_State* state) const {
|
||||
return line_height * static_cast<double>(render_lines.size()) + state->top_margin + state->bottom_margin;
|
||||
return line_height * static_cast<double>(render_lines.size()) + text_top(state) + state->bottom_margin;
|
||||
}
|
||||
double content_viewport_height(Performance_Overlay_Render_State* state, double height) const {
|
||||
return std::max(0.0, height - state->top_margin - state->bottom_margin);
|
||||
return std::max(0.0, height - text_top(state) - state->bottom_margin);
|
||||
}
|
||||
void update_toolbar_button_rects(Performance_Overlay_Render_State* state) {
|
||||
copy_button_rect = {};
|
||||
close_button_rect = {};
|
||||
if (panel_rect.empty() || toolbar_height <= 0.0)
|
||||
return;
|
||||
double right = panel_rect.width - static_cast<double>(state->right_margin + state->scroll_bar_width + state->scroll_bar_margin * 2);
|
||||
double left = static_cast<double>(state->left_margin);
|
||||
double available_width = std::max(0.0, right - left);
|
||||
double close_width = std::min(close_button_width, available_width);
|
||||
if (close_width <= 0.0)
|
||||
return;
|
||||
close_button_rect = RectF{right - close_width, static_cast<double>(state->top_margin), close_width, toolbar_height};
|
||||
available_width = std::max(0.0, close_button_rect.x - button_gap - left);
|
||||
double copy_width = std::min(copy_button_width, available_width);
|
||||
if (copy_width <= 0.0)
|
||||
return;
|
||||
copy_button_rect = RectF{close_button_rect.x - button_gap - copy_width, static_cast<double>(state->top_margin), copy_width, toolbar_height};
|
||||
}
|
||||
void update_scroll_bar_rects(Performance_Overlay_Render_State* state, double max_scroll, double scroll, double visible_height, double total_height) {
|
||||
if (max_scroll <= 0.0 || panel_rect.width <= 0.0 || panel_rect.height <= 0.0 || total_height <= 0.0) {
|
||||
@@ -1038,6 +1065,7 @@ struct Performance_Layout_Builder {
|
||||
double max_width = 0.0;
|
||||
for (const auto& line : render_lines)
|
||||
max_width = std::max(max_width, line.width);
|
||||
max_width = std::max(max_width, copy_button_width + button_gap + close_button_width);
|
||||
double measured_width = max_width
|
||||
+ static_cast<double>(state->left_margin + state->right_margin + state->scroll_bar_width + state->scroll_bar_margin * 2);
|
||||
held_width = std::max(held_width, measured_width);
|
||||
@@ -1201,6 +1229,8 @@ struct Performance_Overlay_Private {
|
||||
std::shared_ptr<Performance_Worker_State> metrics_worker;
|
||||
mutable std::mutex identity_mutex;
|
||||
Performance_Log_Plot_Identity log_identity;
|
||||
mutable std::mutex clipboard_callback_mutex;
|
||||
std::function<void(std::string)> clipboard_callback;
|
||||
|
||||
Performance_Overlay_Private()
|
||||
: metrics_worker(std::make_shared<Performance_Worker_State>()) {}
|
||||
@@ -1233,6 +1263,21 @@ struct Performance_Overlay_Private {
|
||||
return log_identity;
|
||||
}
|
||||
|
||||
void set_clipboard_callback(std::function<void(std::string)> callback) {
|
||||
std::lock_guard<std::mutex> lock(clipboard_callback_mutex);
|
||||
clipboard_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void copy_to_clipboard(std::string text) const {
|
||||
std::function<void(std::string)> callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(clipboard_callback_mutex);
|
||||
callback = clipboard_callback;
|
||||
}
|
||||
if (callback)
|
||||
callback(std::move(text));
|
||||
}
|
||||
|
||||
static const char* feedback_outcome_event(Frame_Outcome outcome) {
|
||||
switch (outcome) {
|
||||
case Frame_Outcome::Presented:
|
||||
@@ -1334,6 +1379,11 @@ struct Performance_Overlay_Private {
|
||||
metrics = measure_canvas.measure_text("0123456789 ABC \xE4\xB8\xAD\xE6\x96\x87");
|
||||
if (metrics.line_height() <= 0.0)
|
||||
metrics = measure_canvas.measure_text("M");
|
||||
Text_Metrics copy_metrics = measure_canvas.measure_text("Copy");
|
||||
Text_Metrics close_metrics = measure_canvas.measure_text("Close");
|
||||
layout.copy_button_width = std::max(48.0, copy_metrics.width + 16.0);
|
||||
layout.close_button_width = std::max(48.0, close_metrics.width + 16.0);
|
||||
layout.toolbar_height = std::max(20.0, metrics.line_height() + 4.0);
|
||||
layout.seed_static_field_widths(measure_canvas);
|
||||
layout.build_render_lines(measure_canvas);
|
||||
}
|
||||
@@ -1346,11 +1396,13 @@ struct Performance_Overlay_Private {
|
||||
if (panel_width <= 0.0 || height <= 0.0)
|
||||
return snapshot;
|
||||
double content_height = layout.content_height(line_height, &state);
|
||||
double text_content_height = line_height * static_cast<double>(layout.render_lines.size());
|
||||
double content_viewport_height = layout.content_viewport_height(&state, height);
|
||||
double max_scroll = std::max(0.0, content_height - content_viewport_height);
|
||||
double max_scroll = std::max(0.0, text_content_height - content_viewport_height);
|
||||
double scroll = performance_clamp_scroll_offset(worker_state.scroll_offset.load(std::memory_order_acquire), max_scroll);
|
||||
worker_state.scroll_offset.store(scroll, std::memory_order_release);
|
||||
layout.panel_rect = RectF{0.0, 0.0, panel_width, height};
|
||||
layout.update_toolbar_button_rects(&state);
|
||||
Image image(static_cast<int>(std::ceil(panel_width)), static_cast<int>(std::ceil(height)));
|
||||
image.fill(Color::transparent());
|
||||
Canvas canvas(image);
|
||||
@@ -1361,13 +1413,13 @@ struct Performance_Overlay_Private {
|
||||
canvas.set_pen(Pen{state.foreground});
|
||||
RectF text_rect{
|
||||
static_cast<double>(state.left_margin),
|
||||
static_cast<double>(state.top_margin),
|
||||
layout.text_top(&state),
|
||||
std::max(0.0, panel_width - state.left_margin - state.right_margin - state.scroll_bar_width - state.scroll_bar_margin * 2),
|
||||
std::max(0.0, height - state.top_margin - state.bottom_margin)
|
||||
std::max(0.0, height - layout.text_top(&state) - state.bottom_margin)
|
||||
};
|
||||
canvas.set_clip_rect(text_rect);
|
||||
int first_line = std::max(0, static_cast<int>(std::floor(scroll / line_height)));
|
||||
double y = static_cast<double>(state.top_margin) - (scroll - static_cast<double>(first_line) * line_height);
|
||||
double y = layout.text_top(&state) - (scroll - static_cast<double>(first_line) * line_height);
|
||||
layout.text_runs.clear();
|
||||
for (int i = first_line; i < static_cast<int>(layout.render_lines.size()) && y < text_rect.bottom(); ++i, y += line_height) {
|
||||
if (y + line_height < text_rect.y)
|
||||
@@ -1375,7 +1427,23 @@ struct Performance_Overlay_Private {
|
||||
layout.draw_render_line(canvas, layout.render_lines[static_cast<std::size_t>(i)], text_rect.x, y, line_height, state);
|
||||
}
|
||||
canvas.reset_clip();
|
||||
layout.update_scroll_bar_rects(&state, max_scroll, scroll, content_viewport_height, content_height);
|
||||
if (!layout.copy_button_rect.empty()) {
|
||||
canvas.set_brush(Brush{state.scroll_track, Brush_Style::Solid});
|
||||
canvas.fill_rect(layout.copy_button_rect);
|
||||
canvas.set_pen(Pen{state.scroll_thumb});
|
||||
canvas.draw_rect(layout.copy_button_rect);
|
||||
canvas.set_pen(Pen{state.foreground});
|
||||
canvas.draw_text(layout.copy_button_rect, Text_Align::Center, "Copy");
|
||||
}
|
||||
if (!layout.close_button_rect.empty()) {
|
||||
canvas.set_brush(Brush{state.scroll_track, Brush_Style::Solid});
|
||||
canvas.fill_rect(layout.close_button_rect);
|
||||
canvas.set_pen(Pen{state.scroll_thumb});
|
||||
canvas.draw_rect(layout.close_button_rect);
|
||||
canvas.set_pen(Pen{state.warning_color});
|
||||
canvas.draw_text(layout.close_button_rect, Text_Align::Center, "Close");
|
||||
}
|
||||
layout.update_scroll_bar_rects(&state, max_scroll, scroll, content_viewport_height, text_content_height);
|
||||
if (!layout.scroll_bar_rect.empty()) {
|
||||
canvas.set_brush(Brush{state.scroll_track, Brush_Style::Solid});
|
||||
canvas.fill_rect(layout.scroll_bar_rect);
|
||||
@@ -1386,6 +1454,8 @@ struct Performance_Overlay_Private {
|
||||
snapshot->destination_rect = layout.panel_rect;
|
||||
snapshot->scroll_track_rect = layout.scroll_bar_rect;
|
||||
snapshot->scroll_thumb_rect = layout.scroll_thumb_rect;
|
||||
snapshot->copy_button_rect = layout.copy_button_rect;
|
||||
snapshot->close_button_rect = layout.close_button_rect;
|
||||
snapshot->content_height = content_height;
|
||||
snapshot->scroll_offset = scroll;
|
||||
snapshot->max_scroll_offset = max_scroll;
|
||||
|
||||
@@ -29,6 +29,8 @@ struct Performance_Display_Snapshot {
|
||||
RectF viewport_rect;
|
||||
RectF scroll_track_rect;
|
||||
RectF scroll_thumb_rect;
|
||||
RectF copy_button_rect;
|
||||
RectF close_button_rect;
|
||||
Size viewport_size;
|
||||
double content_height{};
|
||||
double scroll_offset{};
|
||||
|
||||
@@ -23,6 +23,7 @@ LIB_DECL bool performance_overlay_enabled(const Plot_Core& plot);
|
||||
LIB_DECL void set_performance_overlay_enabled(Plot_Core& plot, bool enabled);
|
||||
LIB_DECL std::shared_ptr<const Performance_Display_Snapshot> performance_overlay_snapshot(const Plot_Core& plot);
|
||||
LIB_DECL void set_performance_overlay_update_callback(Plot_Core& plot, std::function<void()> callback);
|
||||
LIB_DECL void set_performance_overlay_clipboard_callback(Plot_Core& plot, std::function<void(std::string)> callback);
|
||||
LIB_DECL void notify_performance_overlay_viewport_changed(Plot_Core& plot);
|
||||
LIB_DECL bool performance_overlay_handle_wheel(Plot_Core& plot, PointF position, double angle_delta_y, double pixel_delta_y);
|
||||
LIB_DECL bool performance_overlay_handle_pointer_press(Plot_Core& plot, PointF position);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Core/plottable/export.h"
|
||||
#include "Core/plot/Plot_Core_Access.h"
|
||||
#include "Core/architecture/Plot_Render_Context.h"
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
#include <QResizeEvent>
|
||||
@@ -60,6 +62,9 @@ void Abs_Plot_Private::attach_widget(Abs_Plot* plot) {
|
||||
guarded_plot->update();
|
||||
});
|
||||
});
|
||||
set_performance_overlay_clipboard_callback(*core, [](std::string text) {
|
||||
QGuiApplication::clipboard()->setText(QString::fromUtf8(text.data(), static_cast<int>(text.size())));
|
||||
});
|
||||
}
|
||||
|
||||
Abs_Plot::Abs_Plot(Abs_Plot_Private* private_data)
|
||||
@@ -73,6 +78,7 @@ Abs_Plot::Abs_Plot(Abs_Plot_Private* private_data)
|
||||
Abs_Plot::~Abs_Plot() {
|
||||
if (d) {
|
||||
set_performance_overlay_update_callback(*d->core, {});
|
||||
set_performance_overlay_clipboard_callback(*d->core, {});
|
||||
d->core->deactivate_view();
|
||||
delete d;
|
||||
d = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user