You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SimpleSkyCam/gui.cc

415 lines
12 KiB

/***************************************************************************************
*
* main.cc is part of SimpleSkyCam.
*
*****************************************************************************************/
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
#else
#include <unistd.h> /* close() */
#endif
#include <stdio.h>
#include <list>
#include <math.h>
#include "gui.h"
#include "config.h"
#include "video.h"
#include "output.h"
#include "detect.h"
#include "configuration.h"
extern GtkBuilder *_builder_; // work around for threads
extern Output output;
extern Detect detect;
//
// defines what should happen on clicking a point on the input videodata
int video_enterdata = VID_ENTERDATA_NONE; // see VID_ENTERDATA_xxxxx
position_2d video_enterdata_pos;
detect_movement detectedpos_data = {0};
GtkWidget *detect_da = NULL;
GdkPixbuf *detect_pixbuf = NULL;
GtkWidget *image_da = NULL;
GdkPixbuf *image_pixbuf = NULL;
extern GtkWidget *debug_da;
extern GdkPixbuf *debug_pixbuf;
std::string filename = "";
extern Configuration config;
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// call back functions
//
gboolean cb_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) {
config.SaveDefault();
gtk_main_quit();
return FALSE;
};
//
// setup default values
//
void cb_window_show (GtkWidget *widget, gpointer data) {
GtkWidget *btnstart = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-rec"));
GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop"));
GtkWidget *w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
GtkWidget *h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
GtkWidget *rbdefdetect = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright"));
GtkWidget *rbdeffolow = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2"));
// changing the value, will cause the 'change' event to be triggered
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdefdetect), true);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdeffolow), true);
gtk_widget_set_sensitive(btnstart, true);
gtk_widget_set_sensitive(btnstop, false);
gtk_entry_set_text(GTK_ENTRY(w),"300");
gtk_entry_set_text(GTK_ENTRY(h),"300");
detect.SetObjectSize(300, 300);
cb_video_btnrefreshlist (NULL, NULL);
//
// load config and setup elements
config.LoadDefault();
//
// show debug output window.
if (config.show_debugwin) {
printf ("%s:%d show debug window\n", __FILE__, __LINE__);
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-debug"));
if (wnd) gtk_widget_show (wnd);
}
GtkWidget *cfg_rgbenc = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-bilinearrgb"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_rgbenc), (config.debayer_mode != 0));
//
// update the input video controls every 2 seconds.
g_timeout_add(2000, videoctrl_update, NULL);
};
void cb_menu_set_rgbenc (GtkCheckMenuItem *checkmenuitem, gpointer user_data) {
if (gtk_check_menu_item_get_active(checkmenuitem) == TRUE) config.debayer_mode = 1;
else config.debayer_mode = 0;
}
//
// callback from filter thread. Data will point to the output VideoFrame.
// Access to this data must be Locked before use.
//
/* gboolean cb_thread_filter (gpointer data) {
VideoFrame *vf = (VideoFrame *) data;
int pix_h, pix_w;
if (image_da == NULL)
image_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "image-da"));
if (vf == NULL) {
return false;
}
output.LockImageMutex();
if (image_pixbuf) {
pix_h = gdk_pixbuf_get_height(image_pixbuf);
pix_w = gdk_pixbuf_get_width(image_pixbuf);
}
else pix_h = 0;
if (image_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) {
if (image_pixbuf != NULL) g_object_unref (image_pixbuf);
printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h);
image_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h);
pix_w = vf->w;
pix_h = vf->h;
}
vf->ToPixbuf(image_pixbuf);
gdk_window_invalidate_rect(gtk_widget_get_window(image_da), NULL, true);
output.UnLockImageMutex();
return false;
};
*/
//
// callback from detect thread. Data will point to the temp VideoFrame.
// this is propabely the object detection
// Access to this data must be Locked before use and pointers must be looked to
gboolean cb_thread_detect (gpointer data) {
GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx"));
GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy"));
DetectOutput *dout = (DetectOutput *) data;
int pix_h, pix_w, x, y;
if (detect_da == NULL)
detect_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "temp-da"));
if (dout == NULL) return false;
if (dout->image == NULL) return false;
detect.LockImageMutex();
gtk_entry_set_text(GTK_ENTRY(e_x), std::to_string(dout->posx).c_str());
gtk_entry_set_text(GTK_ENTRY(e_y), std::to_string(dout->posy).c_str());
x = dout->posx; // save value for later use (unlocked image data)
y = dout->posy;
if (detect_pixbuf) {
pix_h = gdk_pixbuf_get_height(detect_pixbuf);
pix_w = gdk_pixbuf_get_width(detect_pixbuf);
}
else pix_h = 0;
if (detect_pixbuf == NULL || pix_h != dout->image->h || pix_w != dout->image->w) {
if (detect_pixbuf != NULL) g_object_unref (detect_pixbuf);
printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, dout->image->w, dout->image->h);
detect_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, dout->image->w, dout->image->h);
pix_w = dout->image->w;
pix_h = dout->image->h;
}
dout->image->ToPixbuf(&detect_pixbuf);
gdk_window_invalidate_rect(gtk_widget_get_window(detect_da), NULL, true);
output.NewFrame(dout->rawimage);
detect.UnLockImageMutex();
//
// detect movements, by creating a ring buffer and we comptare the current
// position with the one DETECT_MOVEMENT_SAMPLES frames ago.
//
struct timeval tv = detectedpos_data.samples[0].ts;
float ftime = get_cycletime(&tv);
float fdist = sqrtf ( (x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) *
(x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) +
(y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y) *
(y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y));
if (fdist > 20.0) {
for (int i = 0; i < DETECT_MOVEMENT_SAMPLES; i++) {
detectedpos_data.samples[i].x = x;
detectedpos_data.samples[i].y = y;
detectedpos_data.samples[i].ts = tv;
}
}
detectedpos_data.dx = (float)(x-detectedpos_data.samples[0].x) / ftime;
detectedpos_data.dy = (float)(y-detectedpos_data.samples[0].y) / ftime;
for (int i = 1; i < DETECT_MOVEMENT_SAMPLES; i++)
detectedpos_data.samples[i-1] = detectedpos_data.samples[i];
detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].ts = tv;
detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x = x;
detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y = y;
return false;
};
void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) {
int clientw, clienth, pixbufw, pixbufh;
float clientar, pixbufar;
GdkPixbuf *pixbuf = NULL;
GdkPixbuf *src = NULL;
if (area == image_da) src = image_pixbuf;
else if (area == detect_da) src = detect_pixbuf;
else if (area == debug_da && debug_pixbuf != NULL) src = debug_pixbuf;
else return;
clienth = gtk_widget_get_allocated_height(area);
clientw = gtk_widget_get_allocated_width(area);
clientar = (float)clientw/(float)clienth;
pixbufh = gdk_pixbuf_get_height(src);
pixbufw = gdk_pixbuf_get_width(src);
pixbufar = (float)pixbufw/(float)pixbufh;
if (pixbufar < clientar) {
clientw = (pixbufar * (float) clienth);
}
else {
clienth = ((float) clientw / pixbufar);
}
pixbuf = gdk_pixbuf_scale_simple (src, clientw, clienth, GDK_INTERP_NEAREST);
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
cairo_paint(cr);
cairo_fill (cr);
g_object_unref (pixbuf);
};
void cb_detect_btnsetsize (GtkWidget *widget, gpointer data) {
GtkWidget *txtw = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
GtkWidget *txth = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
detect.SetObjectSize( atoi(gtk_entry_get_text(GTK_ENTRY(txtw))),
atoi(gtk_entry_get_text(GTK_ENTRY(txth))));
};
void cb_detect_bright (GtkRange *range, gpointer data) {
double value;
value = gtk_range_get_value(range);
detect.SetMinBrightness(value);
};
void cb_detect_followtype (GtkWidget *widget, gpointer data) {
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) {
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet0")))
detect.SetFollowType(AUTOFOLLOW_OFF);
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet1")))
detect.SetFollowType(AUTOFOLLOW_BRIGHT);
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2")))
detect.SetFollowType(AUTOFOLLOW_CROSSC);
}
};
void cb_detect_detecttype (GtkWidget *widget, gpointer data) {
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) {
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff")))
detect.SetDetectType(AUTODETECT_OFF);
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright")))
detect.SetDetectType(AUTODETECT_BRIGHT);
}
};
void cb_detect_btnsetpos (GtkWidget *widget, gpointer data) {
GtkWidget *rboff = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff"));
// changing the value, will cause the 'change' event to be triggered
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rboff), true);
video_enterdata = VID_ENTERDATA_POS;
};
void cb_detect_show_window (GtkWidget *widget, gpointer data) {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-detect"));
gtk_widget_show(wnd);
};
/*
* setup destination path
*/
void cb_input_btnsetdestpath (GtkWidget *widget, gpointer data) {
GtkBuilder *builder = (GtkBuilder *) data;
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "windows-input"));
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
gint res;
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
dialog = gtk_file_chooser_dialog_new ("Open Folder",
window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Open",
GTK_RESPONSE_ACCEPT,
NULL);
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT) {
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
filename = gtk_file_chooser_get_filename (chooser);
config.SetDestPath(filename);
GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
gtk_entry_set_text(GTK_ENTRY(entry), filename);
g_free (filename);
}
gtk_widget_destroy (dialog);
};
void cb_input_show_window (GtkWidget *widget, gpointer data) {
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input"));
gtk_widget_show(wnd);
};
void draw_text (cairo_t *cr, int x, int y, float border, std::string text) {
cairo_pattern_t *t = NULL;
double r, g, b, a;
t = cairo_get_source(cr);
cairo_pattern_get_rgba(t, &r, &g, &b, &a);
for (int i = 0; i < 5; i++) {
int dx, dy;
switch (i) {
case 0:
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
dx = -1;
dy = 0;
break;
case 1:
dx = +1;
dy = 0;
break;
case 2:
dx = 0;
dy = -1;
break;
case 3:
dx = 0;
dy = +1;
break;
case 4:
cairo_set_source_rgba(cr, r, g, b, a);
dx = 0;
dy = 0;
break;
}
cairo_move_to (cr, x+dx, y+dy);
cairo_show_text(cr, text.c_str());
cairo_stroke(cr);
}
};
#define DRAW_PRINTF_LEN 512
void draw_printf(cairo_t *cr, int x, int y, float border, char *fmt,...) {
va_list args;
char buffer[DRAW_PRINTF_LEN];
va_start (args, fmt);
vsnprintf (buffer, (DRAW_PRINTF_LEN-1), fmt, args);
va_end (args);
buffer[DRAW_PRINTF_LEN-1] = 0;
draw_text (cr, x, y, border, buffer);
};