Logo Search packages:      
Sourcecode: vertex version File versions

scratchpaddnd.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>

#include "../include/string.h"
#include "../include/strexp.h"

#include "guiutils.h"
#include "cdialog.h"

#include "v3dmp.h"

#include "editor.h"
#include "editordnd.h"

#include "scratchpad.h"
#include "scratchpaddnd.h"
#include "vma.h"
#include "vmapixmaps.h"


void ScratchPadDNDSetIcon(
      vma_scratch_pad_struct *sp, int x, int y
);
void ScratchPadDNDDataRequestCB(
      GtkWidget *widget, GdkDragContext *dc,
      GtkSelectionData *selection_data, guint info, guint t,
      gpointer data
);
void ScratchPadDNDDataRecievedCB(
        GtkWidget *widget,
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
);
static void ScratchPadDNDSetFromEditor(
      vma_scratch_pad_struct *sp,
      gint tar_row, gint src_row,
      mp_vertex_struct *src_v, mp_vertex_struct *src_n,
      mp_vertex_struct *src_tc,
        gbool need_delete
);
static void ScratchPadDNDReorder(
        vma_scratch_pad_struct *sp,
        gint tar_row, gint src_row,
        gbool need_delete
);
void ScratchPadDNDDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
);



/*
 *    ScratchPad drag and drop set icon.
 */
void ScratchPadDNDSetIcon(
      vma_scratch_pad_struct *sp, int x, int y
)
{
        GdkPixmap *pixmap = NULL;
        GdkBitmap *mask = NULL;
        int icon_num = VMA_PIXMAP_MP_POINT_20x20;


        if(sp == NULL)
            return;

        VMAPixmapsListGetValues(
            &vma_pixmaps_list, icon_num,
            &pixmap, &mask, NULL
        );
        if(pixmap != NULL)
        {
            gint w = 15, h = 15;

            gdk_window_get_size((GdkWindow *)pixmap, &w, &h);

          GUIDNDSetDragIcon(
                pixmap, mask,
                (w / 2), (h / 2)
            );
        }
}

/*
 *    ScratchPad drag and drop data request callback.
 */
void ScratchPadDNDDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
)
{
        gboolean data_sent = FALSE;
      GtkCList *clist;
      gint value_num, column;
        vma_scratch_pad_struct *sp = (vma_scratch_pad_struct *)data;
        if((widget == NULL) || (sp == NULL) || (dc == NULL))
            return;

        if(!sp->initialized)
            return;

        /* Sync data on scratchpad. */
        ScratchPadSyncData(sp);

      /* Get selected row (note that recieving function would probably
       * ignore this as it means nothing to it).
       */
      value_num = sp->selected_row;
      column = sp->selected_column;

      clist = (GtkCList *)sp->clist;

      /* Valid row selected? */
      if((clist != NULL) && (value_num > -1))
      {
          if(value_num < clist->rows)
          {
            vma_scratch_pad_row_struct *rd = (vma_scratch_pad_row_struct *)
                gtk_clist_get_row_data(clist, value_num);
            if(rd != NULL)
            {
                int buf_len;
                char *buf;
                int editor_num = -1;
                mp_vertex_struct *v = NULL, *n = NULL, *tc = NULL;
                vma_core_struct *core_ptr = (vma_core_struct *)sp->core_ptr;
                    char num_str[256];


                /* Check which vertex we should set by which column
                 * was selected on the scratchpad's clist.
                 */
                switch(column)
                {
                  case 0:
                  v = &rd->v;
                  break;

                      case 1:
                        n = &rd->n;
                        break;

                      case 2:
                        tc = &rd->tc;
                        break;
                }

                    /* Send out data consisting of a command containing
                 * the following arguments:
                 *
                 * <core_ptr> <editor_num> <value_num>
                 * <vertex_ptr> <normal_ptr> <texcoord_ptr>
                 */
                    /* Calculate length of buf and allocate buf. */
                    buf_len = 24 + 24 + 24 + (24 * 3);
                    buf = (char *)malloc(buf_len * sizeof(char));
                    if(buf != NULL)
                    {
                        /* Format buf. */
                        (*buf) = '\0';
                        sprintf(num_str, "%.8x %i %i",
                            (guint)core_ptr, editor_num, value_num
                        );
                        strcat(buf, num_str);
                        strcat(buf, " ");

                        sprintf(num_str, "%.8x", (guint)v);
                        strcat(buf, num_str); 
                        strcat(buf, " ");

                        sprintf(num_str, "%.8x", (guint)n);
                        strcat(buf, num_str);
                        strcat(buf, " ");

                        sprintf(num_str, "%.8x", (guint)tc);
                        strcat(buf, num_str);

                        /* Send out data. */
                        gtk_selection_data_set(
                            selection_data,
                            GDK_SELECTION_TYPE_STRING,
                            8,              /* 8 bits per character. */
                            buf, strlen(buf)
                        );
                        data_sent = TRUE;

                        /* Free buffer. */
                        free(buf);
                        buf = NULL;
                        buf_len = 0;
                }
            }
          }
      }

        /* Failed to send out data? */
        if(!data_sent)
        {
            const char *strptr = "Error";

            gtk_selection_data_set(
                selection_data,
                GDK_SELECTION_TYPE_STRING,
                8,      /* 8 bits per character. */
                strptr, strlen(strptr)
            );
            data_sent = TRUE;
        }

        return;
}

/*
 *    ScratchPad drag and drop data recieved callback.
 */
void  ScratchPadDNDDataRecievedCB(
        GtkWidget *widget,
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
)
{
        gboolean same, status, need_delete = FALSE;
        const gchar *cstrptr;
        GtkWidget *source_widget;
        GtkCList *clist;
        vma_scratch_pad_struct *sp = (vma_scratch_pad_struct *)data;   
        if((widget == NULL) || (sp == NULL) || (dc == NULL))
            return;   

        if(!sp->initialized)
            return; 

        /* Important, check if we got data. */
        if(selection_data == NULL)
            return;
        if(selection_data->length < 0)
            return;


        /* Source and target widgets same (not editors)? */
        source_widget = gtk_drag_get_source_widget(dc);
        same = ((source_widget == widget) ? TRUE : FALSE);

        /* Sync data on scratchpad. */
        ScratchPadSyncData(sp);

        /* Check if data needs to be deleted, if this drag action was
         * move.
         */
        if(dc->action != GDK_ACTION_COPY)
            need_delete = TRUE;

        /* Get target clist from the input widget. */
        clist = ((GTK_IS_CLIST(widget)) ? GTK_CLIST(widget) : NULL);
        if(clist != NULL)
        {
            gint row, column;
            GList *next;
            gbool       is_editor_values_set_cmd = FALSE;

            if(gtk_clist_get_selection_info(
                    clist, x, y, &row, &column
            ))
            {
                row -= 1;       /* Need to offset. */
            }
            else
            {
                row = clist->rows;
                column = 0;
            }
            if(row < 0)
                row = 0;
            /* Row is now (or atleast should be) positioned where
             * we want to insert.   
             */

            /* DND type check, note that the models clist can recieve
             * drags from other models clists or other primitives
             * clists.
             */ 
            status = FALSE;
            next = dc->targets;
            while(next != NULL)
            {
                cstrptr = (const gchar *)gdk_atom_name((GdkAtom)next->data);
                if(cstrptr != NULL)
                {
                    /* Value set command string? */
                    if(!strcmp(cstrptr, EDITOR_DND_TYPE_VALUES_SET_CMD))
                    {
                        is_editor_values_set_cmd = TRUE; 
                        status = TRUE;
                        break;
                    }
/* Add additional type checks here. */
                }
                next = next->next;
            }
            /* DND type matched what we will accept? */
            if(status)
            {
                /* Selection data of type string? */
                if(selection_data->type != GDK_SELECTION_TYPE_STRING)
                    status = FALSE;
            }
            /* ******************************************************** */
            /* We now have the recieved data type, status indicates if
             * parsing was successful.
             */
            /* Editor value set command? */
            if(status && is_editor_values_set_cmd)
            {
                /* Parse value set command string. */
                vma_core_struct *src_core_ptr = NULL;
                gint    tar_value_num = row, src_value_num = -1,
                  src_editor_num = -1;
                ma_editor_struct *src_editor = NULL;
                mp_vertex_struct *src_v, *src_n, *src_tc;


                EditorDNDParseValuesSetCmd(
                    (const char *)selection_data->data,
                    &src_core_ptr,
                    &src_editor, &src_editor_num,
                    &src_value_num, &src_v, &src_n, &src_tc
                );

            /* Check if the DND occured over the same clist. */
            if(same)
            {
                /* Source and target widgets were the same, so
                 * this implies a reorder.
                 */

                /* Use the same scratchpad's selected_row as the
                 * src_value_num.
                 */
                src_value_num = sp->selected_row;
                ScratchPadDNDReorder(
                  sp, tar_value_num, src_value_num,
                        need_delete
                    );
            }
            else
            {
                /* Source and target widgets were not the same, so
                 * assume it's a set vertex possible from an editor.
                 */
                ScratchPadDNDSetFromEditor(
                  sp, tar_value_num, src_value_num,
                  src_v, src_n, src_tc,
                  need_delete
                );
            }

            }
/* Add handling support for other types here. */

        }

      return;
}


/*
 *    ScratchPad drag and drop set vertex from editor procedure.
 *
 *    Inserts or replaces the item at tar_row, the src_row is
 *    ignored. If need_delete is TRUE then the item will be replaced
 *    (updated) or if need_delete is FALSE then a new item will be
 *    inserted at tar_row.
 */
static void ScratchPadDNDSetFromEditor(
        vma_scratch_pad_struct *sp,
        gint tar_row, gint src_row,
        mp_vertex_struct *src_v, mp_vertex_struct *src_n,
        mp_vertex_struct *src_tc,
        gbool need_delete
)
{
      gint new_row = -1;
      GtkCList *clist;


      if(sp == NULL)
          return;

      clist = (GtkCList *)sp->clist;
      if(clist == NULL)
          return;

      /* If need_delete is TRUE, then that implies we should replace the
       * value on the dropped on row.
       */
      if(need_delete)
      {
          vma_scratch_pad_row_struct *rd;

          /* Sanitize target row, if the target row is -1 then that
           * may imply we're at the last item (see how this function
           * was called).
           */
          if(tar_row < 0) 
                tar_row = clist->rows - 1;
          if(tar_row < 0)
            tar_row = 0;

          /* Get row data. */
          rd = (vma_scratch_pad_row_struct *)gtk_clist_get_row_data(
            clist, tar_row
          );
          if(rd != NULL)
          {
            gchar **strv;
            gint strc;

            /* Set the new row to be the same as the target row. */
            new_row = tar_row;

            if(src_v != NULL)
                memcpy(&rd->v, src_v, sizeof(mp_vertex_struct));
            if(src_n != NULL)
                memcpy(&rd->n, src_n, sizeof(mp_vertex_struct));
            if(src_tc != NULL)
                memcpy(&rd->tc, src_tc, sizeof(mp_vertex_struct));

            /* Allocate row text strings from updated values. */
            strv = ScratchPadAllocRowText(
                sp, &rd->v, &rd->n, &rd->tc, &strc
            );

            /* Update clist row text. */
            if(strc > 0)
                gtk_clist_set_text(clist, tar_row, 0, strv[0]);
            if(strc > 1)
                gtk_clist_set_text(clist, tar_row, 1, strv[1]);
            if(strc > 2)
                gtk_clist_set_text(clist, tar_row, 2, strv[2]);

            /* Deallocate row text, we don't need them anymore. */
            StringFreeArray(strv, strc);
            strv = NULL;
            strc = 0;
          }
          else
          {
            /* Did not get valid row, this may indicate we dropped
             * beyond the last. In any case let's just insert a new row.
             */
            sp->selected_row = tar_row;
            new_row = ScratchPadRowInsert(
                sp, src_v, src_n, src_tc, NULL
            );
          }
      }
      else
      {
          /* Do not delete, this implies a copy. In which case we will
           * just insert a new row.
           */
          sp->selected_row = tar_row;
          new_row = ScratchPadRowInsert(
            sp, src_v, src_n, src_tc, NULL
          );
      }

      /* At this point, if a new row was successfully added then new_row
       * will be > -1.
       */

      /* Was a new row added? */
      if(new_row > -1)
      {
          /* Reset selected row for upcomming selection so that it will
           * detect a row change.
           */
          sp->selected_row = -1;

          /* Select new row and recognize row change. */
          gtk_clist_select_row(clist, new_row, 0);
      }

      return;
}

/*
 *    ScratchPad drag and drop reorder procedure.
 *
 *    Inserts a new item at tar_row and deletes the item at src_row
 *    if need_delete is TRUE.
 *
 *    The new tar_row will be selected on the scratchpad on success.
 */
static void ScratchPadDNDReorder(  
        vma_scratch_pad_struct *sp,
        gint tar_row, gint src_row,
      gbool need_delete
)
{
        GtkCList *clist;
        mp_vertex_struct *src_v = NULL, *src_n = NULL, *src_tc = NULL;
      const gchar *src_comment = NULL;


        if(sp == NULL)
            return;

        clist = (GtkCList *)sp->clist;
        if(clist == NULL)
            return;

      /* Sanitize target row. */
      if(tar_row < 0)
          tar_row = 0;

      /* Source row valid? */
      if(src_row > -1)
      {
          vma_scratch_pad_row_struct *rd;

          /* Get data from source row. */
          rd = (vma_scratch_pad_row_struct *)gtk_clist_get_row_data(
            clist, src_row
          );
          if(rd != NULL)
          {
            src_v = &rd->v;
                src_n = &rd->n;
                src_tc = &rd->tc;
            src_comment = (const gchar *)rd->comment;
          }

          /* Shift source row if it is the same or below the target row
           * in index value, this is to offset for the insert.
           */
          if(src_row >= tar_row)
            src_row += 1;
      }

      /* Insert new row and update tar_row. */
      sp->selected_row = tar_row;
        tar_row = ScratchPadRowInsert(
          sp, src_v, src_n, src_tc, src_comment
      );
      if(tar_row < 0)
          return;

      /* Do we need to delete the source row and is the source row
       * valid?
       */
      if(need_delete && (src_row > -1))
      {
          /* Reduce target row index if source row is above it because
           * we are about to delete the source row.
           */
          if(tar_row > src_row)
          {
            tar_row -= 1;
          }
          gtk_clist_remove(clist, src_row);
          src_row = -1;
      }

      /* Select the target row if it is valid. */
      if((tar_row >= 0) && (tar_row < clist->rows))
          gtk_clist_select_row(clist, tar_row, 0);

        return;
}

/*
 *    ScratchPad drag and drop data delete callback.
 */
void ScratchPadDNDDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
      /* This function is no longer used. */
      return;
}

Generated by  Doxygen 1.6.0   Back to index