/* Gnome-Streamer * Copyright (C) <1999> Erik Walthinsen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "gsteditor.h" #include "gsteditorproject.h" #include "gsteditorproperty.h" /* class functions */ static void gst_editor_element_class_init (GstEditorElementClass *klass); static void gst_editor_element_init (GstEditorElement *element); static void gst_editor_element_set_arg (GtkObject *object,GtkArg *arg,guint id); static void gst_editor_element_get_arg (GtkObject *object,GtkArg *arg,guint id); static void gst_editor_element_realize (GstEditorElement *element); static gint gst_editor_element_event (GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element); /* events fired by items within self */ static gint gst_editor_element_resizebox_event (GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element); static gint gst_editor_element_group_event (GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element); static gint gst_editor_element_state_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data); /* utility functions */ static void gst_editor_element_resize (GstEditorElement *element); static void gst_editor_element_set_state (GstEditorElement *element, gint id,gboolean set); static void gst_editor_element_add_pad_wrapper (GstEditorElement *element, GstPad *pad); static void gst_editor_element_add_pad (GstEditorElement *element, GstPad *pad); GstEditorPadTemplate* gst_editor_element_add_padtemplate (GstEditorElement *element, GstPadTemplate *pad); static void gst_editor_element_sync_state (GstEditorElement *element); static void gst_editor_element_sync_state_wrapper (GstEditorElement *element); static void gst_editor_element_move (GstEditorElement *element, gdouble dx,gdouble dy); static void gst_editor_element_position_changed (GstEditorElement *element, GstEditorElement *parent); static gchar *_gst_editor_element_states[] = { "S","R","P","F" }; static GstElementState _gst_element_states[] = { GST_STATE_NULL, GST_STATE_READY, GST_STATE_PLAYING, GST_STATE_PAUSED, }; enum { ARG_0, ARG_X, ARG_Y, ARG_WIDTH, ARG_HEIGHT, ARG_X1, ARG_Y1, ARG_X2, ARG_Y2, ARG_ELEMENT, ARG_ACTIVE, }; enum { NAME_CHANGED, POSITION_CHANGED, SIZE_CHANGED, LAST_SIGNAL }; static GtkObjectClass *parent_class; static guint gst_editor_element_signals[LAST_SIGNAL] = { 0 }; GtkType gst_editor_element_get_type(void) { static GtkType element_type = 0; if (!element_type) { static const GtkTypeInfo element_info = { "GstEditorElement", sizeof(GstEditorElement), sizeof(GstEditorElementClass), (GtkClassInitFunc)gst_editor_element_class_init, (GtkObjectInitFunc)gst_editor_element_init, NULL, NULL, (GtkClassInitFunc)NULL, }; element_type = gtk_type_unique(gtk_object_get_type(),&element_info); } return element_type; } static void gst_editor_element_class_init (GstEditorElementClass *klass) { GtkObjectClass *object_class; object_class = (GtkObjectClass*)klass; parent_class = gtk_type_class(gtk_object_get_type()); gst_editor_element_signals[NAME_CHANGED] = gtk_signal_new ("name_changed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GstEditorElementClass, name_changed), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GST_TYPE_EDITOR_ELEMENT); gst_editor_element_signals[POSITION_CHANGED] = gtk_signal_new ("position_changed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GstEditorElementClass, position_changed), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GST_TYPE_EDITOR_ELEMENT); gst_editor_element_signals[SIZE_CHANGED] = gtk_signal_new ("size_changed", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GstEditorElementClass, size_changed), gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GST_TYPE_EDITOR_ELEMENT); gtk_object_class_add_signals(object_class,gst_editor_element_signals,LAST_SIGNAL); gtk_object_add_arg_type("GstEditorElement::x",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY, ARG_X); gtk_object_add_arg_type("GstEditorElement::y",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY, ARG_Y); gtk_object_add_arg_type("GstEditorElement::width",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY, ARG_WIDTH); gtk_object_add_arg_type("GstEditorElement::height",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE|GTK_ARG_CONSTRUCT_ONLY, ARG_HEIGHT); gtk_object_add_arg_type("GstEditorElement::x1",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1); gtk_object_add_arg_type("GstEditorElement::y1",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1); gtk_object_add_arg_type("GstEditorElement::x2",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2); gtk_object_add_arg_type("GstEditorElement::y2",GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2); gtk_object_add_arg_type("GstEditorElement::element",GTK_TYPE_POINTER, GTK_ARG_READABLE, ARG_ELEMENT); gtk_object_add_arg_type("GstEditorElement::active",GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ACTIVE); klass->realize = gst_editor_element_realize; klass->event = gst_editor_element_event; object_class->set_arg = gst_editor_element_set_arg; object_class->get_arg = gst_editor_element_get_arg; } static void gst_editor_element_init (GstEditorElement *element) { element->active = FALSE; } GstEditorElement* gst_editor_element_new (GstElement *element, const gchar *first_arg_name, ...) { GstEditorElement *editorelement; va_list args; g_return_val_if_fail(element != NULL, NULL); g_return_val_if_fail(GST_IS_ELEMENT(element), NULL); editorelement = GST_EDITOR_ELEMENT(gtk_type_new(GST_TYPE_EDITOR_ELEMENT)); editorelement->element = element; GST_EDITOR_SET_OBJECT(element, editorelement); va_start(args,first_arg_name); gst_editor_element_construct(editorelement,first_arg_name,args); va_end(args); return editorelement; } void gst_editor_element_set_name (GstEditorElement *element, const gchar *name) { g_return_if_fail(GST_IS_EDITOR_ELEMENT(element)); g_return_if_fail(name != NULL); gst_element_set_name(element->element, (gchar *)name); gnome_canvas_item_set(element->title, "text", name, NULL); gtk_signal_emit(GTK_OBJECT(element),gst_editor_element_signals[NAME_CHANGED], element); } const gchar* gst_editor_element_get_name (GstEditorElement *element) { g_return_val_if_fail(GST_IS_EDITOR_ELEMENT(element), NULL); return gst_element_get_name(element->element); } void gst_editor_element_construct (GstEditorElement *element, const gchar *first_arg_name, va_list args) { GtkObject *obj = GTK_OBJECT(element); GSList *arg_list = NULL, *info_list = NULL; gchar *error; // g_print("in gst_editor_element_construct()\n"); error = gtk_object_args_collect(GTK_OBJECT_TYPE(obj),&arg_list, &info_list,first_arg_name,args); if (error) { g_warning("gst_editor_element_construct(): %s",error); g_free(error); } else { GSList *arg,*info; // g_print("setting all the arguments on the element\n"); for (arg=arg_list,info=info_list;arg;arg=arg->next,info=info->next) gtk_object_arg_set(obj,arg->data,info->data); gtk_args_collect_cleanup(arg_list,info_list); } } static void gst_editor_element_set_arg (GtkObject *object, GtkArg *arg, guint id) { GstEditorElement *element; /* get the major types of this object */ element = GST_EDITOR_ELEMENT(object); switch (id) { case ARG_X: element->x = GTK_VALUE_DOUBLE(*arg); break; case ARG_Y: element->y = GTK_VALUE_DOUBLE(*arg); break; case ARG_WIDTH: element->width = GTK_VALUE_DOUBLE(*arg); element->resize = TRUE; break; case ARG_HEIGHT: element->height = GTK_VALUE_DOUBLE(*arg); element->resize = TRUE; break; case ARG_X1: element->x = GTK_VALUE_DOUBLE(*arg); element->resize = TRUE; break; case ARG_Y1: element->y = GTK_VALUE_DOUBLE(*arg); element->resize = TRUE; break; case ARG_X2: // make sure it's big enough, grow if not element->width = MAX(GTK_VALUE_DOUBLE(*arg),element->minwidth); element->resize = TRUE; break; case ARG_Y2: // make sure it's big enough, grow if not element->height = MAX(GTK_VALUE_DOUBLE(*arg),element->minheight); element->resize = TRUE; break; case ARG_ACTIVE: element->active = GTK_VALUE_BOOL(*arg); gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->border), "width_units", (element->active ? 2.0 : 1.0), NULL); break; default: g_warning("gsteditorelement: unknown arg!"); break; } } static void gst_editor_element_get_arg(GtkObject *object, GtkArg *arg, guint id) { GstEditorElement *element; /* get the major types of this object */ element = GST_EDITOR_ELEMENT(object); switch (id) { case ARG_X: GTK_VALUE_INT(*arg) = element->x + (element->width / 2.0); break; case ARG_Y: GTK_VALUE_INT(*arg) = element->y + (element->height / 2.0); break; case ARG_WIDTH: GTK_VALUE_INT(*arg) = element->width; break; case ARG_HEIGHT: GTK_VALUE_INT(*arg) = element->height; break; case ARG_X1: GTK_VALUE_INT(*arg) = element->x; break; case ARG_Y1: GTK_VALUE_INT(*arg) = element->y; break; case ARG_X2: GTK_VALUE_INT(*arg) = element->x + element->width; break; case ARG_Y2: GTK_VALUE_INT(*arg) = element->y + element->height; break; case ARG_ELEMENT: GTK_VALUE_POINTER(*arg) = element->element; break; case ARG_ACTIVE: GTK_VALUE_BOOL(*arg) = element->active; break; default: arg->type = GTK_TYPE_INVALID; break; } } static GtkMenu* gst_editor_element_get_popup_menu (GstEditorElement *element) { GtkMenu *menu; menu = GTK_MENU (gtk_menu_new ()); gtk_menu_append (menu, gtk_menu_item_new_with_label ("cut")); gtk_menu_append (menu, gtk_menu_item_new_with_label ("copy")); gtk_menu_append (menu, gtk_menu_item_new_with_label ("paste")); gtk_widget_show_all (GTK_WIDGET (menu)); return menu; } static void gst_editor_element_realize (GstEditorElement *element) { GnomeCanvasGroup *parentgroup; gint i; gdouble x1,y1,x2,y2; GList *pads; // g_print("realizing editor element %p\n",element); /* we have to have a parent by this point */ g_return_if_fail(element->parent != NULL); // set the state signal of the actual element gtk_signal_connect_object (GTK_OBJECT(element->element),"state_change", GTK_SIGNAL_FUNC(gst_editor_element_sync_state_wrapper), GTK_OBJECT (element)); gtk_signal_connect_object (GTK_OBJECT(element->element),"new_pad", GTK_SIGNAL_FUNC(gst_editor_element_add_pad_wrapper), GTK_OBJECT (element)); gtk_signal_connect_object (GTK_OBJECT(element->parent),"position_changed", GTK_SIGNAL_FUNC(gst_editor_element_position_changed), GTK_OBJECT (element)); // create the bounds if we haven't had them set // g_print("centering element at %.2fx%.2f (%.2fx%.2f)\n", // element->x,element->y,element->width,element->height); /* create the group holding all the stuff for this element */ parentgroup = GST_EDITOR_ELEMENT(element->parent)->group; element->group = GNOME_CANVAS_GROUP(gnome_canvas_item_new(parentgroup, gnome_canvas_group_get_type(), "x",element->x - (element->width / 2.0), "y",element->y - (element->height / 2.0),NULL)); // g_print("origin of group is %.2fx%.2f\n", // element->x - (element->width / 2.0), // element->y - (element->height / 2.0)); g_return_if_fail(element->group != NULL); GST_EDITOR_SET_OBJECT(element->group,element); gtk_signal_connect(GTK_OBJECT(element->group),"event", GTK_SIGNAL_FUNC(gst_editor_element_group_event),element); // calculate the inter-group coords (x1,y1,x2,y2 are convenience vars) x1 = 0.0;y1 = 0.0; x2 = element->width;y2 = element->height; /* create bordering box */ element->border = gnome_canvas_item_new(element->group, gnome_canvas_rect_get_type(), "width_units",1.0,"fill_color","white","outline_color","black", "x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL); g_return_if_fail(element->border != NULL); GST_EDITOR_SET_OBJECT(element->border,element); /* create resizing box */ element->resizebox = gnome_canvas_item_new(element->group, gnome_canvas_rect_get_type(), "width_units",1.0,"fill_color","white","outline_color","black", "x1",x2-4.0,"y1",y2-4.0,"x2",x2,"y2",y2,NULL); g_return_if_fail(element->resizebox != NULL); GST_EDITOR_SET_OBJECT(element->resizebox,element); gtk_signal_connect(GTK_OBJECT(element->resizebox),"event", GTK_SIGNAL_FUNC(gst_editor_element_resizebox_event),element); /* create the title */ element->title = gnome_canvas_item_new(element->group, gnome_canvas_text_get_type(), "text",gst_element_get_name(GST_ELEMENT(element->element)), "x",x1+1.0,"y",y1+1.0,"anchor",GTK_ANCHOR_NORTH_WEST, "font_gdk",gtk_widget_get_default_style()->font, NULL); g_return_if_fail(element->title != NULL); GST_EDITOR_SET_OBJECT(element->title,element); /* create the state boxen */ for (i=0;i<4;i++) { element->statebox[i] = gnome_canvas_item_new(element->group, gnome_canvas_rect_get_type(), "width_units",1.0,"fill_color","white","outline_color","black", "x1",0.0,"y1",0.0,"x2",0.0,"y2",0.0, NULL); g_return_if_fail(element->statebox[i] != NULL); GST_EDITOR_SET_OBJECT(element->statebox[i],element); gtk_signal_connect(GTK_OBJECT(element->statebox[i]),"event", GTK_SIGNAL_FUNC(gst_editor_element_state_event), GINT_TO_POINTER(i)); element->statetext[i] = gnome_canvas_item_new(element->group, gnome_canvas_text_get_type(), "text",_gst_editor_element_states[i], "x",0.0,"y",0.0,"anchor",GTK_ANCHOR_NORTH_WEST, "font","-*-*-*-*-*-*-6-*-*-*-*-*-*-*", NULL); g_return_if_fail(element->statetext[i] != NULL); GST_EDITOR_SET_OBJECT(element->statetext[i],element); gtk_signal_connect(GTK_OBJECT(element->statetext[i]),"event", GTK_SIGNAL_FUNC(gst_editor_element_state_event), GINT_TO_POINTER(i)); } // get all the padtemplates pads = gst_element_get_padtemplate_list(element->element); while (pads) { GstPadTemplate *temp = (GstPadTemplate *) pads->data; gst_editor_element_add_padtemplate (element,temp); pads = g_list_next(pads); } // get all the pads pads = gst_element_get_pad_list(element->element); while (pads) { GstPad *pad = GST_PAD(pads->data); gst_editor_element_add_pad(element,pad); pads = g_list_next(pads); } element->realized = TRUE; // force a resize element->resize = TRUE; gst_editor_element_resize(element); // recenter things on the supposed center // g_print("recentering element at %.2fx%.2f (%.2fx%.2f)\n", // element->x,element->y,element->width,element->height); element->x -= (element->width / 2.0); element->y -= (element->height / 2.0); gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group), "x",element->x,"y",element->y,NULL); // g_print("origin of group is %.2fx%.2f\n",element->x,element->y); gst_editor_element_repack(element); } static void gst_editor_element_resize (GstEditorElement *element) { gdouble itemwidth,itemheight; gdouble groupwidth,groupheight; GList *pads; GstEditorPad *editorpad; GstEditorPadTemplate *editorpadtemplate; gint i; if (element->resize != TRUE) return; element->resize = FALSE; // g_print("resizing element\n"); element->minwidth = element->insidewidth; element->minheight = element->insideheight; // get the text size and add it into minsize g_return_if_fail(element->title != NULL); itemwidth = gst_util_get_double_arg(GTK_OBJECT(element->title), "text_width") + 2.0; itemheight = gst_util_get_double_arg(GTK_OBJECT(element->title), "text_height") + 2.0; element->titlewidth = itemwidth; element->titleheight = itemheight; element->minwidth = MAX(element->minwidth,itemwidth); element->minheight += itemheight; // now do the bottom bar // find the biggest of the state chars element->statewidth = 0.0;element->stateheight = 0.0; for (i=0;i<4;i++) { g_return_if_fail(element->statetext[i] != NULL); itemwidth = 16.0; itemheight = 16.0; element->statewidth = MAX(element->statewidth,itemwidth); element->stateheight = MAX(element->stateheight,itemheight); } // calculate the size of the primary group groupwidth = element->statewidth * 5; // 4 states plus playstate groupheight = element->stateheight; // add in the resize box groupwidth += 7.0; // 2.0 for buffer, 5.0 for actual size groupheight = MAX(groupheight,5.0); // update the minsize element->minwidth = MAX(element->minwidth,groupwidth); element->minheight += groupheight; // now go and try to calculate necessary space for the pads element->sinkwidth = 10.0;element->sinkheight = 0.0;element->sinks = 0; pads = element->sinkpads; while (pads) { editorpad = GST_EDITOR_PAD(pads->data); element->sinkwidth = MAX(element->sinkwidth,editorpad->width); element->sinkheight = MAX(element->sinkheight,editorpad->height); element->sinks++; pads = g_list_next(pads); } element->srcwidth = 10.0;element->srcheight = 0.0;element->srcs = 0; pads = element->srcpads; while (pads) { editorpad = GST_EDITOR_PAD(pads->data); element->srcwidth = MAX(element->srcwidth,editorpad->width); element->srcheight = MAX(element->srcheight,editorpad->height); element->srcs++; pads = g_list_next(pads); } pads = element->sinkpadtemps; while (pads) { editorpadtemplate = GST_EDITOR_PADTEMPLATE(pads->data); element->sinkwidth = MAX(element->sinkwidth,editorpadtemplate->width); element->sinkheight = MAX(element->sinkheight,editorpadtemplate->height); element->sinks++; pads = g_list_next(pads); } pads = element->srcpadtemps; while (pads) { editorpadtemplate = GST_EDITOR_PADTEMPLATE(pads->data); element->srcwidth = MAX(element->srcwidth,editorpadtemplate->width); element->srcheight = MAX(element->srcheight,editorpadtemplate->height); element->srcs++; pads = g_list_next(pads); } // add in the needed space element->minheight += MAX((element->sinkheight*element->sinks), (element->srcheight*element->srcs)) + 4.0; element->minwidth = MAX(element->minwidth, ((element->sinkwidth) + (element->srcwidth) + 4.0)); // g_print("have %d sinks (%.2fx%.2f) and %d srcs (%.2fx%.2f)\n", // element->sinks,element->sinkwidth,element->sinkheight, // element->srcs,element->srcwidth,element->srcheight); // grow the element to hold all the stuff // g_print("minsize is %.2fx%.2f, //",element->minwidth,element->minheight); // g_print("size was %.2fx%.2f, ",element->width,element->height); element->width = MAX(element->width,element->minwidth); element->height = MAX(element->height,element->minheight); // g_print("is now %.2fx%.2f\n",element->width,element->height); gtk_signal_emit(GTK_OBJECT(element),gst_editor_element_signals[SIZE_CHANGED], element); } void gst_editor_element_repack (GstEditorElement *element) { GList *pads; GstEditorPad *editorpad; GstEditorPadTemplate *editorpadtemplate; gint sinks; gint srcs; gdouble x1,y1,x2,y2; gint i; if (!element->realized) return; gst_editor_element_resize(element); // still use x1,y1,x2,y2 so we can change around later x1 = 0.0;y1 = 0.0; x2 = element->width;y2 = element->height; // g_print("repacking element at %.2fx%.2f + %.2fx%.2f\n", // element->x,element->y,x2,y2); // move the element group to match gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->group), "x",element->x,"y",element->y,NULL); // start by resizing the bordering box g_return_if_fail(element->border != NULL); gtk_object_set(GTK_OBJECT(element->border), "x1",x1,"y1",y1,"x2",x2,"y2",y2,NULL); // then move the text to the new top left g_return_if_fail(element->title != NULL); gtk_object_set(GTK_OBJECT(element->title), "x",x1+1.0,"y",y1+1.0, "anchor",GTK_ANCHOR_NORTH_WEST, NULL); // and move the resize box g_return_if_fail(element->resizebox != NULL); gtk_object_set(GTK_OBJECT(element->resizebox), "x1",x2-5.0,"y1",y2-5.0,"x2",x2,"y2",y2,NULL); // now place the state boxes for (i=0;i<4;i++) { g_return_if_fail(element->statebox[i] != NULL); gtk_object_set(GTK_OBJECT(element->statebox[i]), "x1",x1+(element->statewidth*i), "y1",y2-element->stateheight, "x2",x1+(element->statewidth*(i+1)),"y2",y2,NULL); g_return_if_fail(element->statetext[i] != NULL); gtk_object_set(GTK_OBJECT(element->statetext[i]), "x",x1+(element->statewidth*i)+2.0, "y",y2-element->stateheight+1.0, "anchor",GTK_ANCHOR_NORTH_WEST,NULL); } gst_editor_element_sync_state(element); // now we try to place all the pads sinks = element->sinks; pads = element->sinkpads; while (pads) { editorpad = GST_EDITOR_PAD(pads->data); gtk_object_set(GTK_OBJECT(editorpad), "x",x1, "y",y2 - 2.0 - element->stateheight - (element->sinkheight * sinks), NULL); gst_editor_pad_repack(editorpad); sinks--; pads = g_list_next(pads); } pads = element->sinkpadtemps; while (pads) { editorpadtemplate = GST_EDITOR_PADTEMPLATE(pads->data); gtk_object_set(GTK_OBJECT(editorpadtemplate), "x",x1, "y",y2 - 2.0 - element->stateheight - (element->sinkheight * sinks), NULL); gst_editor_padtemplate_repack(editorpadtemplate); sinks--; pads = g_list_next(pads); } srcs = element->srcs; pads = element->srcpads; while (pads) { editorpad = GST_EDITOR_PAD(pads->data); gtk_object_set(GTK_OBJECT(editorpad), "x",x2 - editorpad->width, "y",y2 - 2.0 - element->stateheight - (element->srcheight * srcs), NULL); gst_editor_pad_repack(editorpad); srcs--; pads = g_list_next(pads); } pads = element->srcpadtemps; while (pads) { editorpadtemplate = GST_EDITOR_PADTEMPLATE(pads->data); gtk_object_set(GTK_OBJECT(editorpadtemplate), "x",x2 - editorpadtemplate->width, "y",y2 - 2.0 - element->stateheight - (element->srcheight * srcs), NULL); gst_editor_padtemplate_repack(editorpadtemplate); srcs--; pads = g_list_next(pads); } gtk_signal_emit(GTK_OBJECT(element),gst_editor_element_signals[SIZE_CHANGED], element); // g_print("done resizing element\n"); } static void gst_editor_element_add_pad_wrapper (GstEditorElement *element, GstPad *pad) { gdk_threads_enter (); gst_editor_element_add_pad (element, pad); element->resize = TRUE; gst_editor_element_repack (element); gdk_threads_leave (); } static void gst_editor_element_add_pad_func (GstEditorElement *element, GstPad *pad) { GstEditorPad *editorpad; editorpad = gst_editor_pad_new (element, pad, NULL); // FIXME does this need to check for ghost/real? if (GST_PAD_DIRECTION(pad) == GST_PAD_SINK) { element->sinkpads = g_list_prepend(element->sinkpads,editorpad); element->sinks++; // g_print("added 'new' pad to sink list\n"); } else if (GST_PAD_DIRECTION(pad) == GST_PAD_SRC) { element->srcpads = g_list_prepend(element->srcpads,editorpad); element->srcs++; // g_print("added 'new' pad to src list\n"); } else g_print("HUH?!? Don't know which direction this pad is...\n"); gst_editor_element_repack(element); } static void gst_editor_element_add_pad (GstEditorElement *element, GstPad *pad) { GstPadTemplate *temp; temp = pad->padtemplate; if (!temp) { gst_editor_element_add_pad_func (element,pad); } else { // find the template GList *temppads; temppads = element->sinkpadtemps; while (temppads) { GstEditorPadTemplate *editorpadtemp = (GstEditorPadTemplate *) temppads->data; if (editorpadtemp->padtemplate == temp) { gst_editor_padtemplate_add_pad (editorpadtemp, pad); break; } temppads = g_list_next (temppads); } temppads = element->srcpadtemps; while (temppads) { GstEditorPadTemplate *editorpadtemp = (GstEditorPadTemplate *) temppads->data; if (editorpadtemp->padtemplate == temp) { gst_editor_padtemplate_add_pad (editorpadtemp, pad); break; } temppads = g_list_next (temppads); } } } GstEditorPadTemplate* gst_editor_element_add_padtemplate (GstEditorElement *element, GstPadTemplate *pad) { GstEditorPadTemplate *editorpad; g_print ("gsteditorelement: new padtemplate\n"); editorpad = gst_editor_padtemplate_new (element, pad, NULL); if (pad->direction == GST_PAD_SINK) { element->sinkpadtemps = g_list_prepend(element->sinkpadtemps,editorpad); element->sinks++; // g_print("added 'new' pad to sink list\n"); } else if (pad->direction == GST_PAD_SRC) { // g_print("added 'new' pad to src list\n"); element->srcpadtemps = g_list_prepend(element->srcpadtemps,editorpad); element->srcs++; } else g_print("HUH?!? Don't know which direction this pad is...\n"); gst_editor_element_repack(element); return editorpad; } static gint gst_editor_element_group_event (GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element) { switch(event->type) { case GDK_BUTTON_PRESS: gst_editor_property_show(gst_editor_property_get(), element); break; default: break; } if (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event) return (GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass)->event)( item,event,element); return FALSE; } static gint gst_editor_element_event(GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element) { gdouble dx,dy; GdkCursor *fleur; // g_print("element in event, type %d\n",event->type); switch(event->type) { case GDK_ENTER_NOTIFY: return TRUE; case GDK_LEAVE_NOTIFY: return TRUE; case GDK_BUTTON_PRESS: { if (event->button.button == 3) { GtkMenu *menu; menu = gst_editor_element_get_popup_menu (element); gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time); return TRUE; } else { // dragxy coords are world coords of button press element->dragx = event->button.x; element->dragy = event->button.y; // set some flags element->dragging = TRUE; element->moved = FALSE; fleur = gdk_cursor_new (GDK_FLEUR); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | // GDK_ENTER_NOTIFY_MASK | // GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK, fleur,event->button.time); return TRUE; } } case GDK_MOTION_NOTIFY: if (element->dragging) { dx = event->button.x - element->dragx; dy = event->button.y - element->dragy; gst_editor_element_move(element,dx,dy); element->dragx = event->button.x; element->dragy = event->button.y; element->moved = TRUE; } return TRUE; case GDK_BUTTON_RELEASE: if (element->dragging) { element->dragging = FALSE; gnome_canvas_item_ungrab(item,event->button.time); } if (!element->moved) { GstEditorElementClass *elementclass; elementclass = GST_EDITOR_ELEMENT_CLASS(GTK_OBJECT(element)->klass); if (elementclass->button_event) (elementclass->button_event)(item,event,element); } //g_print("in element group_event, setting inchild"); //element->canvas->inchild = TRUE; return TRUE; default: break; } return FALSE; } static gint gst_editor_element_resizebox_event (GnomeCanvasItem *item, GdkEvent *event, GstEditorElement *element) { GdkCursor *bottomright; gdouble item_x,item_y; // g_print("in resizebox_event...\n"); // calculate coords relative to the group, not the box item_x = event->button.x; item_y = event->button.y; gnome_canvas_item_w2i(item->parent,&item_x,&item_y); switch(event->type) { case GDK_ENTER_NOTIFY: gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->resizebox), "fill_color", "red" , NULL); return TRUE; break; case GDK_LEAVE_NOTIFY: gnome_canvas_item_set(GNOME_CANVAS_ITEM(element->resizebox), "fill_color", "white" , NULL); element->hesitating = FALSE; return TRUE; break; case GDK_BUTTON_PRESS: element->dragx = event->button.x; element->dragy = event->button.y; element->resizing = TRUE; element->hesitating = TRUE; bottomright = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_RELEASE_MASK, bottomright,event->button.time); return TRUE; break; case GDK_MOTION_NOTIFY: if (element->resizing) { // doing a set because the code is in the arg set code // g_print("resizing to x2,y2 of %.2f,%.2f\n",item_x,item_y); gtk_object_set(GTK_OBJECT(element),"x2",item_x,"y2",item_y,NULL); element->resize = TRUE; gst_editor_element_repack(element); return TRUE; } break; case GDK_BUTTON_RELEASE: if (element->resizing) { element->resizing = FALSE; gnome_canvas_item_ungrab(item,event->button.time); //g_print("in element resizebox_event, setting inchild"); //element->canvas->inchild = TRUE; return TRUE; } break; default: break; } return FALSE; } static gint gst_editor_element_state_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) { GstEditorElement *element; gint id = GPOINTER_TO_INT(data); GdkCursor *uparrow; element = GST_EDITOR_GET_OBJECT(item); switch (event->type) { case GDK_ENTER_NOTIFY: uparrow = gdk_cursor_new(GDK_SB_UP_ARROW); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK, uparrow,event->button.time); /* NOTE: when grabbing canvas item, always get pointer_motion, this will allow you to actually get all the other synth events */ break; case GDK_LEAVE_NOTIFY: gnome_canvas_item_ungrab(item,event->button.time); break; case GDK_BUTTON_PRESS: { GdkEventButton *buttonevent = (GdkEventButton *)event; if (buttonevent->button == 1) return TRUE; return FALSE; } case GDK_BUTTON_RELEASE: { GdkEventButton *buttonevent = (GdkEventButton *)event; if (buttonevent->button != 1) return FALSE; if (id < 4) { gdk_threads_leave (); gst_editor_element_set_state(element,id,TRUE); gdk_threads_enter (); } else g_warning("Uh, shouldn't have gotten here, unknown state\n"); //g_print("in element statebox_event, setting inchild"); //element->canvas->inchild = TRUE; return TRUE; } default: break; } return FALSE; } static void gst_editor_element_set_state(GstEditorElement *element, gint id,gboolean set) { gboolean stateset = TRUE; /* if we have no element, set anyway */ //g_print("element set state %d\n", id); if (element->element) stateset = gst_element_set_state(element->element,_gst_element_states[id]); } static void gst_editor_element_sync_state_wrapper (GstEditorElement *element) { gdk_threads_enter (); gst_editor_element_sync_state (element); gdk_threads_leave (); } static void gst_editor_element_sync_state (GstEditorElement *element) { gint id; GstElementState state = GST_STATE(element->element); for (id=0;id<4;id++) { if (_gst_element_states[id] == state) { gtk_object_set(GTK_OBJECT(element->statebox[id]), "fill_color","black",NULL); gtk_object_set(GTK_OBJECT(element->statetext[id]), "fill_color","white",NULL); } else { gtk_object_set(GTK_OBJECT(element->statebox[id]), "fill_color","white",NULL); gtk_object_set(GTK_OBJECT(element->statetext[id]), "fill_color","black",NULL); } } } static void gst_editor_element_position_changed (GstEditorElement *element, GstEditorElement *parent) { if (element != parent) gtk_signal_emit(GTK_OBJECT(element),gst_editor_element_signals[POSITION_CHANGED], element); } static void gst_editor_element_move(GstEditorElement *element, gdouble dx,gdouble dy) { // this is a 'little' trick to keep from repacking the whole thing... element->x += dx;element->y += dy; gnome_canvas_item_move(GNOME_CANVAS_ITEM(element->group),dx,dy); gtk_signal_emit(GTK_OBJECT(element),gst_editor_element_signals[POSITION_CHANGED], element); }