blob: acbaf8eb5eebbd3cec1c96ecb4deeb78a9458f54 [file] [log] [blame]
Parker Schuhef47dbf2017-03-04 16:59:30 -08001#include "aos/vision/debug/debug_window.h"
Parker Schuh2cd173d2017-01-28 00:12:01 -08002
3#include <gdk-pixbuf/gdk-pixbuf.h>
4#include <gtk/gtk.h>
5#include <poll.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <functional>
9#include <memory>
10#include <vector>
11
12#include "aos/vision/image/image_types.h"
13
14namespace aos {
15namespace vision {
16
17template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
18gboolean DrawCallback(GtkWidget *, cairo_t *cr, gpointer data) {
19 return ((*((T *)data)).*DrawMethod)(cr);
20}
21
22template <typename T, gboolean (T::*DrawMethod)(cairo_t *cr)>
23void g_draw_signal_connect(GtkWidget *widget, T *obj) {
24 gboolean (*fnptr)(GtkWidget *, cairo_t *, gpointer) =
25 DrawCallback<T, DrawMethod>;
26 g_signal_connect(widget, "draw", G_CALLBACK(fnptr), obj);
27}
28
Parker Schuhef47dbf2017-03-04 16:59:30 -080029struct DebugWindow::Internals {
Parker Schuh2cd173d2017-01-28 00:12:01 -080030 Internals(bool flip) : flip_(flip) {}
31
32 gboolean Draw(cairo_t *cr) {
33 needs_draw = false;
34 cairo_scale(cr, scale_factor, scale_factor);
35 if (pixbuf != nullptr) {
36 cairo_save(cr);
37 if (flip_) {
38 cairo_translate(cr, ptr.fmt().w, ptr.fmt().h);
39 cairo_scale(cr, -1, -1);
40 }
41 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0);
42 cairo_paint(cr);
43 cairo_restore(cr);
44 }
45
46 int w = ptr.fmt().w;
47 int h = ptr.fmt().h;
48 if (overlays) {
49 for (const auto &ov : *overlays) {
50 cairo_save(cr);
51 CairoRender render(cr);
52 // move the drawing to match the window size
53 ov->Draw(&render, w, h);
54 cairo_restore(cr);
55 }
56 }
57
58 return FALSE;
59 }
60
61 GdkPixbuf *pixbuf = nullptr;
62 GtkWidget *drawing_area = nullptr;
63 ImagePtr ptr;
64 bool needs_draw = true;
65 GtkWidget *window;
66 std::vector<OverlayBase *> *overlays = nullptr;
67 double scale_factor;
68
69 // flip the image rows on drawing
70 bool flip_ = false;
71
72 // clear per frame
73 bool clear_per_frame_ = true;
74};
75
Parker Schuhef47dbf2017-03-04 16:59:30 -080076void DebugWindow::SetOverlays(std::vector<OverlayBase *> *overlays) {
Parker Schuh2cd173d2017-01-28 00:12:01 -080077 self->overlays = overlays;
78}
79
Parker Schuhef47dbf2017-03-04 16:59:30 -080080void DebugWindow::Redraw() {
Parker Schuh2cd173d2017-01-28 00:12:01 -080081 if (!self->needs_draw) {
82 gtk_widget_queue_draw(self->drawing_area);
83 self->needs_draw = true;
84 }
85}
86
Parker Schuhef47dbf2017-03-04 16:59:30 -080087void DebugWindow::UpdateImage(ImagePtr ptr) {
Parker Schuh2cd173d2017-01-28 00:12:01 -080088 if (ptr.data() != self->ptr.data()) {
89 int w = ptr.fmt().w;
90 int h = ptr.fmt().h;
91 self->pixbuf = gdk_pixbuf_new_from_data(
92 (const unsigned char *)ptr.data(), GDK_COLORSPACE_RGB, FALSE, 8,
93 ptr.fmt().w, ptr.fmt().h, 3 * ptr.fmt().w, NULL, NULL);
94 self->ptr = ptr;
95
96 gtk_window_set_default_size(GTK_WINDOW(self->window), w * scale_factor,
97 h * scale_factor);
98
99 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
100 h * scale_factor);
101 window_height_ = h;
102 window_width_ = w;
103 }
Parker Schuh309dd722017-02-25 11:31:18 -0800104 if (!shown_yet_) {
105 gtk_widget_show_all(self->window);
106 shown_yet_ = true;
107 }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800108}
109
Parker Schuhef47dbf2017-03-04 16:59:30 -0800110void DebugWindow::MoveTo(int x, int y) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800111 gtk_window_move(GTK_WINDOW(self->window), x, y);
112}
113
Parker Schuhef47dbf2017-03-04 16:59:30 -0800114void DebugWindow::SetScale(double scale_factor_inp) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800115 int w = window_width_;
116 int h = window_height_;
117
118 scale_factor = scale_factor_inp;
119 self->scale_factor = scale_factor;
120
121 gtk_window_resize(GTK_WINDOW(self->window), w * scale_factor,
122 h * scale_factor);
123
124 gtk_widget_set_size_request(self->drawing_area, w * scale_factor,
125 h * scale_factor);
126}
127
128gboolean debug_viewer_key_press_event(GtkWidget * /*widget*/,
129 GdkEventKey *event, gpointer user_data) {
130 auto &key_press_cb =
Parker Schuhef47dbf2017-03-04 16:59:30 -0800131 reinterpret_cast<DebugWindow *>(user_data)->key_press_event;
Parker Schuh2cd173d2017-01-28 00:12:01 -0800132 if (key_press_cb) key_press_cb(event->keyval);
133 return FALSE;
134}
135
Parker Schuhef47dbf2017-03-04 16:59:30 -0800136DebugWindow::DebugWindow(bool flip) : self(new Internals(flip)) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800137 self->scale_factor = scale_factor;
138 GtkWidget *window;
139 auto drawing_area = self->drawing_area = gtk_drawing_area_new();
140 gtk_widget_set_size_request(drawing_area, window_width_ * scale_factor,
141 window_height_ * scale_factor);
142 gtk_widget_add_events(drawing_area, GDK_KEY_PRESS_MASK);
143
Parker Schuhef47dbf2017-03-04 16:59:30 -0800144 g_draw_signal_connect<DebugWindow::Internals, &DebugWindow::Internals::Draw>(
Parker Schuh2cd173d2017-01-28 00:12:01 -0800145 drawing_area, self.get());
146
147 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
148 self->window = window;
149 g_signal_connect(window, "key-press-event",
150 G_CALLBACK(debug_viewer_key_press_event), this);
151 gtk_window_set_title(GTK_WINDOW(window), "Window");
152 gtk_window_set_default_size(GTK_WINDOW(window), window_width_ * scale_factor,
153 window_height_ * scale_factor);
154
155 gtk_container_add(GTK_CONTAINER(window), drawing_area);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800156}
Parker Schuhef47dbf2017-03-04 16:59:30 -0800157DebugWindow::~DebugWindow() {}
Parker Schuh2cd173d2017-01-28 00:12:01 -0800158
159void CairoRender::Text(int x, int y, int /*text_x*/, int /*text_y*/,
160 const std::string &text) {
161 auto *pango_lay = pango_cairo_create_layout(cr_);
162 cairo_move_to(cr_, x, y);
163 pango_layout_set_text(pango_lay, text.data(), text.size());
164 pango_cairo_show_layout(cr_, pango_lay);
165 g_object_unref(pango_lay);
166}
167
168} // namespace vision
169} // namespace aos