Logo Search packages:      
Sourcecode: vertex version File versions

editordnd.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 "editorcb.h"
#include "editorviewcb.h"
#include "editorp.h"
#include "editorlist.h"
#include "editorselect.h"
#include "editordnd.h"

#include "vmapixmaps.h"
#include "vmadde.h"
#include "vma.h"
#include "vmautils.h"

#ifdef MEMWATCH
# include "memwatch.h"
#endif


/* Recieved data command string parsing. */
static void EditorDNDParseModelsCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        int **sel_models, int *total_sel_models
);
static void EditorDNDParsePrimitivesCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        v3d_model_struct **sel_model_ptr, int *sel_model_num,
        int **sel_primitives, int *total_sel_primitives
);
static void EditorDNDParseModelCreateCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
      v3d_model_struct **new_model_ptr,
      const char **new_name_ptr
);
static void EditorDNDParsePrimitiveCreateCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
      int *ptype, void **p
);
void EditorDNDParseValuesSetCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        int *value_num,
      mp_vertex_struct **v, mp_vertex_struct **n, mp_vertex_struct **tc
);


/* Inserting to target editor routines. */
static void EditorDNDModelsListAdd(
        ma_editor_struct *editor, v3d_model_struct *model_ptr,
      int *select, int total_selects,
        int insert_pos
);
static void EditorDNDModelsListAddList(
        ma_editor_struct *editor,
        v3d_model_struct **model, int total_models,
      int *select, int total_selects,
        int insert_pos
);
static void EditorDNDPrimitivesListAdd(
        ma_editor_struct *editor, int model_num, void *p,
      int *select, int total_selects,
        int insert_pos
);
static void EditorDNDPrimitivesListAddList(
        ma_editor_struct *editor, int model_num,
        void **primitive, int total_primitives,
      int *select, int total_selects,
        int insert_pos
);
static void EditorDNDValuesListSet(
        ma_editor_struct *editor,
      int value_num,
      mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc
);


/* DND handling for the models list. */
void EditorDNDModelsListSetIcon(
        ma_editor_struct *editor, int x, int y
);
void EditorDNDModelsListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
);
void EditorDNDModelsListDataRecievedCB(
        GtkWidget *widget, 
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
);
static void EditorDNDModelsListDoDeleteModels(
        ma_editor_struct *editor,
        int *selected_model, int total_selected_models
);
void EditorDNDModelsListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
);


/* DND handling for the primitives list. */
void EditorDNDPrimitivesListSetIcon(
      ma_editor_struct *editor, int x, int y
);
void EditorDNDPrimitivesListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
);
void EditorDNDPrimitivesListDataRecievedCB(
        GtkWidget *widget, 
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
);
static void EditorDNDPrimitivesListDoDeletePrimitives(
        ma_editor_struct *editor, v3d_model_struct *model_ptr,
        int *selected_primitive, int total_selected_primitives
);
void EditorDNDPrimitivesListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
);


/* DND handling for the values list. */
void EditorDNDValuesListSetIcon(
      ma_editor_struct *editor, int x, int y
);
void EditorDNDValuesListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
);
void EditorDNDValuesListDataRecievedCB(
        GtkWidget *widget,
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
);
void EditorDNDValuesListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
);


#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))

/*
 *      Checks if editor has changes, if it does not then it will
 *      mark it as having changes.
 */
#define EDITOR_DO_UPDATE_HAS_CHANGES    \
{ \
 if(!editor->has_changes) \
  editor->has_changes = TRUE; \
}


/*
 *      Parses input string s as a DND recieved `models transfer
 *    command string', and sets the return values.
 *
 *      Parses input string s and returns the requested values.
 *
 *      Note that sel_models is dynamically allocated and must be
 *      free()'ed by the calling function.
 *
 *      All inputs assumed valid.
 */
static void EditorDNDParseModelsCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        int **sel_models, int *total_sel_models
)
{
        unsigned int addr_val;
        int i, n, strc;
        char **strv;


        /* Reset returns. */
        if(core_ptr != NULL)
            (*core_ptr) = NULL;
        if(editor_ptr != NULL)
            (*editor_ptr) = NULL;
        if(editor_num != NULL)
            (*editor_num) = -1;
        if(sel_models != NULL)
            (*sel_models) = NULL;
        if(total_sel_models != NULL)
            (*total_sel_models) = 0;

        if(string == NULL)
            return;

        /* If first word in string states "error" then give up. */
        if(strcasepfx(string, "error"))
            return;

        /* Parse models command, format is as follows:
         * <core_ptr> <editor_num> <selected_models...>
         */
        strv = strexp(string, &strc);
        if(strv == NULL)
            return;

        /* Get core_ptr (format in hex with no "0x" prefix). */
        if(strc > 0)
            i = sscanf(strv[0], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (core_ptr != NULL))
            (*core_ptr) = (vma_core_struct *)addr_val;


        /* Get editor number. */
        if((strc > 1) && (editor_num != NULL))
            (*editor_num) = atoi(strv[1]);

        /* Get editor pointer. */
        if((core_ptr != NULL) &&
           (editor_num != NULL) && (editor_ptr != NULL)
        )
        {
            int total_editors = (((*core_ptr) == NULL) ?
                0 : (*core_ptr)->total_editors
            );

            if(((*editor_num) >= 0) &&
               ((*editor_num) < total_editors) &&
               ((*core_ptr) != NULL)
            )
                (*editor_ptr) = (*core_ptr)->editor[*editor_num];
        }

        /* Get list of model numbers. */
        if((sel_models != NULL) && (total_sel_models != NULL))
        {
            const char *cstrptr;

          /* Start at parsed argument number 2. */
            for(i = 2; i < strc; i++)
            {
                cstrptr = (const char *)strv[i];
                if(cstrptr == NULL)
                    continue;

                n = (*total_sel_models);
                (*total_sel_models) = n + 1;
                (*sel_models) = (int *)realloc(
                    *sel_models,
                    (*total_sel_models) * sizeof(int)
                );
                if((*sel_models) == NULL)
                {
                    (*total_sel_models) = 0;
                    break;
                }
                else
                {
                    (*sel_models)[n] = atoi(cstrptr);
                }
            }
        }

        /* Free exploded string. */
        StringFreeArray(strv, strc);

      return;
}

/*
 *    Parses input string s as a DND recieved `primitives transfer
 *    command string', and sets the return values.
 *
 *    Note that sel_primitives is dynamically allocated and must be
 *    free()'ed by the calling function.
 *
 *    All inputs assumed valid.
 */
static void EditorDNDParsePrimitivesCmd(
      const char *string,
      vma_core_struct **core_ptr,
      ma_editor_struct **editor_ptr, int *editor_num,
      v3d_model_struct **sel_model_ptr, int *sel_model_num,
      int **sel_primitives, int *total_sel_primitives
)
{
      unsigned int addr_val;
      int i, n, strc;
      char **strv;


      /* Reset returns. */
      if(core_ptr != NULL)
          (*core_ptr) = NULL;
      if(editor_ptr != NULL)
          (*editor_ptr) = NULL;
      if(editor_num != NULL)
          (*editor_num) = -1;
      if(sel_model_ptr != NULL)
          (*sel_model_ptr) = NULL;
      if(sel_model_num != NULL)
          (*sel_model_num) = -1;
      if(sel_primitives != NULL)
          (*sel_primitives) = NULL;
      if(total_sel_primitives != NULL)
          (*total_sel_primitives) = 0;

      if(string == NULL)
          return;

      /* If first word in string states "error" then give up. */
      if(strcasepfx(string, "error"))
          return;

      /* Parse primitives command, format is as follows:
       * <core_ptr> <editor_num> <selected_model_num>
       * <selected_primitives...>
       */
      strv = strexp(string, &strc);
      if(strv == NULL)
          return;


        /* Get core_ptr (format in hex with no "0x" prefix). */
      if(strc > 0)
          i = sscanf(strv[0], "%x", (unsigned int *)&addr_val);
      else
          i = 0;
      if((i > 0) && (core_ptr != NULL))
          (*core_ptr) = (vma_core_struct *)addr_val;


      /* Get editor number. */
      if((strc > 1) && (editor_num != NULL))
          (*editor_num) = atoi(strv[1]);

      /* Get editor pointer. */
      if((core_ptr != NULL) &&
           (editor_num != NULL) && (editor_ptr != NULL)
      )
      {
          int total_editors = (((*core_ptr) == NULL) ?
            0 : (*core_ptr)->total_editors
          );

          if(((*editor_num) >= 0) &&
               ((*editor_num) < total_editors) &&
               ((*core_ptr) != NULL)
          )
            (*editor_ptr) = (*core_ptr)->editor[*editor_num];
      }

      /* Get selected model number. */
      if((strc > 2) && (sel_model_num != NULL))
          (*sel_model_num) = atoi(strv[2]);

      /* Get selected model pointer. */
      if((core_ptr != NULL) && (editor_ptr != NULL) &&
           (sel_model_num != NULL) && (sel_model_ptr != NULL)
      )
      {
          if((*editor_ptr) != NULL)
          {
            if(((*sel_model_num) >= 0) &&
                   ((*sel_model_num) < (*editor_ptr)->total_models)
            )
                (*sel_model_ptr) = (*editor_ptr)->model[*sel_model_num];
          }
      }

      /* Get list of primitive numbers. */
      if((sel_primitives != NULL) && (total_sel_primitives != NULL))
      {
          const char *cstrptr;

            /* Start at parsed argument number 3. */
          for(i = 3; i < strc; i++)
          {
            cstrptr = (const char *)strv[i];
            if(cstrptr == NULL)
                continue;

            n = (*total_sel_primitives);
            (*total_sel_primitives) = n + 1;
            (*sel_primitives) = (int *)realloc(
                *sel_primitives,
                (*total_sel_primitives) * sizeof(int)
            );
            if((*sel_primitives) == NULL)
            {
                (*total_sel_primitives) = 0;
                break;
            }
            else
            {
                (*sel_primitives)[n] = atoi(cstrptr);
            }
          }
      }

      /* Free exploded string. */
      StringFreeArray(strv, strc);

      return;
}

/*
 *      Parses input string s as a DND recieved `create model command
 *    string', and sets the return values.
 *
 *    Note that *new_model_ptr will point to a statically allocated
 *    model that must not be deallocated or modified.
 *
 *      All inputs assumed valid.
 */
static void EditorDNDParseModelCreateCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        v3d_model_struct **new_model_ptr,
      const char **new_name_ptr
)
{
        unsigned int addr_val;
        int i, strc;
        char **strv;


        /* Reset returns. */
        if(core_ptr != NULL)
            (*core_ptr) = NULL;
        if(editor_ptr != NULL)
            (*editor_ptr) = NULL;
        if(editor_num != NULL)
            (*editor_num) = -1;
        if(new_model_ptr != NULL)
            (*new_model_ptr) = NULL;
      if(new_name_ptr != NULL)
          (*new_name_ptr) = NULL;

        if(string == NULL)
            return;

        /* If first word in string states "error" then give up. */
        if(strcasepfx(string, "error"))
            return;

        /* Parse primitives command, format is as follows:
         * <core_ptr> <editor_num> <new_model_ptr>
         *
         */
        strv = strexp(string, &strc);
        if(strv == NULL)
            return;

        /* Get core_ptr (format in hex with no "0x" prefix). */
        if(strc > 0)
            i = sscanf(strv[0], "%x", (unsigned int *)&addr_val);
        else 
            i = 0;
        if((i > 0) && (core_ptr != NULL))
            (*core_ptr) = (vma_core_struct *)addr_val;


        /* Get editor number. */
        if((strc > 1) && (editor_num != NULL))
            (*editor_num) = atoi(strv[1]);

        /* Get editor pointer. */
        if((core_ptr != NULL) &&
           (editor_num != NULL) && (editor_ptr != NULL)
        )
        {
            int total_editors = (((*core_ptr) == NULL) ?
                0 : (*core_ptr)->total_editors
            );

            if(((*editor_num) >= 0) &&
               ((*editor_num) < total_editors) &&
               ((*core_ptr) != NULL)
            )
                (*editor_ptr) = (*core_ptr)->editor[*editor_num];
        }

        /* Get new_model_ptr (format in hex with no "0x" prefix). */
        if(strc > 2)
            i = sscanf(strv[2], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (new_model_ptr != NULL))
            (*new_model_ptr) = (v3d_model_struct *)addr_val;

        /* Get new_name_ptr (format in hex with no "0x" prefix). */
        if(strc > 3)
            i = sscanf(strv[3], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (new_name_ptr != NULL))
            (*new_name_ptr) = (const char *)addr_val;

        /* Free exploded string. */
        StringFreeArray(strv, strc);

        return;
}

/*
 *      Parses input string s as a DND recieved `create primitive command
 *      string', and sets the return values.
 *
 *    The returned primitive p should not be modified.
 *
 *      All inputs assumed valid.
 */
static void EditorDNDParsePrimitiveCreateCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        int *ptype, void **p
)
{
        unsigned int addr_val;
        int i, strc;
        char **strv;


        /* Reset returns. */
        if(core_ptr != NULL)
            (*core_ptr) = NULL;
        if(editor_ptr != NULL)
            (*editor_ptr) = NULL;
        if(editor_num != NULL)
            (*editor_num) = -1;
        if(ptype != NULL)
            (*ptype) = -1;
      if(p != NULL)
          (*p) = NULL;

        if(string == NULL)
            return;

        /* If first word in string states "error" then give up. */
        if(strcasepfx(string, "error"))
            return;

        /* Parse primitives command, format is as follows:
         * <core_ptr> <editor_num> <ptype>
         *
         */
        strv = strexp(string, &strc);
        if(strv == NULL)
            return;

        /* Get core_ptr (format in hex with no "0x" prefix). */
        if(strc > 0)
            i = sscanf(strv[0], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (core_ptr != NULL))
            (*core_ptr) = (vma_core_struct *)addr_val;


        /* Get editor number. */
        if((strc > 1) && (editor_num != NULL))
            (*editor_num) = atoi(strv[1]);

        /* Get editor pointer from number. */
        if((core_ptr != NULL) &&
           (editor_num != NULL) && (editor_ptr != NULL)
        )
        {
            int total_editors = (((*core_ptr) == NULL) ?
                0 : (*core_ptr)->total_editors
            );

            if(((*editor_num) >= 0) &&
               ((*editor_num) < total_editors) &&
               ((*core_ptr) != NULL)
            )
                (*editor_ptr) = (*core_ptr)->editor[*editor_num];
        }

        /* Get new primitive type. */
        if((strc > 2) && (ptype != NULL))
            (*ptype) = atoi(strv[2]);

        /* Get primitive pointer (format in hex with no "0x" prefix). */
        if(strc > 3)
            i = sscanf(strv[3], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (p != NULL))
            (*p) = (void *)addr_val;


        /* Free exploded string. */
        StringFreeArray(strv, strc);

        return;
}

/*
 *      Parses input string s as a DND recieved `set value command
 *      string', and sets the return values.
 *
 *      The returned mp_vertex_struct pointers should not be modified.
 *
 *      All inputs assumed valid.
 */
void EditorDNDParseValuesSetCmd(
        const char *string,
        vma_core_struct **core_ptr,
        ma_editor_struct **editor_ptr, int *editor_num,
        int *value_num, 
        mp_vertex_struct **v, mp_vertex_struct **n, mp_vertex_struct **tc
)
{
        unsigned int addr_val;
        int i, strc;
        char **strv;


        /* Reset returns. */
        if(core_ptr != NULL)
            (*core_ptr) = NULL;
        if(editor_ptr != NULL)
            (*editor_ptr) = NULL;
        if(editor_num != NULL)
            (*editor_num) = -1;
        if(value_num != NULL)
            (*value_num) = -1;
        if(v != NULL)
            (*v) = NULL;
        if(n != NULL)
            (*n) = NULL;
        if(tc != NULL)
            (*tc) = NULL;


        if(string == NULL)
            return;

        /* If first word in string states "error" then give up. */
        if(strcasepfx(string, "error"))
            return;

        /* Parse primitives command, format is as follows:
         * <core_ptr> <editor_num> <ptype>
         *
         */
        strv = strexp(string, &strc);
        if(strv == NULL)
            return;

        /* Get core_ptr (format in hex with no "0x" prefix). */
        if(strc > 0)
            i = sscanf(strv[0], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (core_ptr != NULL))
            (*core_ptr) = (vma_core_struct *)addr_val;


        /* Get editor number. */
        if((strc > 1) && (editor_num != NULL))
            (*editor_num) = atoi(strv[1]);

        /* Get editor pointer from number. */
        if((core_ptr != NULL) &&
           (editor_num != NULL) && (editor_ptr != NULL)
        )
        {
            int total_editors = (((*core_ptr) == NULL) ?
                0 : (*core_ptr)->total_editors
            );
            
            if(((*editor_num) >= 0) &&
               ((*editor_num) < total_editors) &&
               ((*core_ptr) != NULL)
            )
                (*editor_ptr) = (*core_ptr)->editor[*editor_num];
        }

        /* Get value number (row on values list). */
        if((strc > 2) && (value_num != NULL))
            (*value_num) = atoi(strv[2]);

        /* Get vertex pointer (format in hex with no "0x" prefix). */
        if(strc > 3)
            i = sscanf(strv[3], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (v != NULL))
            (*v) = (mp_vertex_struct *)addr_val;

        /* Get normal pointer (format in hex with no "0x" prefix). */
        if(strc > 4)
            i = sscanf(strv[4], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (n != NULL))
            (*n) = (mp_vertex_struct *)addr_val;

        /* Get texcoord pointer (format in hex with no "0x" prefix). */
        if(strc > 5)
            i = sscanf(strv[5], "%x", (unsigned int *)&addr_val);
        else
            i = 0;
        if((i > 0) && (tc != NULL))
            (*tc) = (mp_vertex_struct *)addr_val;

        /* Free exploded string. */
        StringFreeArray(strv, strc);
            
        return;
}



/*
 *    Adds the specified model to the editor's model list at the
 *    specified position in the models list. The given model should
 *    not be realized, it will be realized in this function.
 *
 *    The pointer to the given model should not be referanced again
 *    after calling this function.
 *
 *    Models clist on the editor will be updated.
 */
static void EditorDNDModelsListAdd(
      ma_editor_struct *editor, v3d_model_struct *model_ptr,
      int *select, int total_selects,
      int insert_pos
)
{
      gint i, n;
      GtkCList *clist;


      if((editor == NULL) || (model_ptr == NULL))
      {
          V3DModelDestroy(model_ptr);
          return;
      }

      clist = (GtkCList *)editor->models_list;

      /* Sanitize insert position. */
      if(insert_pos < 0)
          insert_pos = 0;

      /* Sanitize total number of models. */
      if(editor->total_models < 0)
          editor->total_models = 0;

      /* Allocate a new pointer for the models list. */
      n = editor->total_models;
      editor->total_models = n + 1;
      editor->model = (v3d_model_struct **)realloc(
          editor->model,
          editor->total_models * sizeof(v3d_model_struct *)
      );
      if(editor->model == NULL)
      {
          /* Memory allocation error, destroy given model and
           * return.
           */
          V3DModelDestroy(model_ptr);
          return;
      }
      else
      {
          editor->model[n] = NULL;
      }

      /* Shift selections on target editor for item numbers
       * that are equal or greater than insert_pos.
       */
      if(insert_pos <= EditorSelectedModelIndex(editor))
      {
          editor->selected_model_item += 1;
      }
      for(i = 0; i < total_selects; i++)
      {
          if(insert_pos <= select[i])
            select[i] += 1;
      }

      /* Handle by insert_pos. */
        if(insert_pos < editor->total_models)
        {
          /* Insert at the specified insert position, all items
           * currently at and below insert_pos will be shifted
           * down one unit.
           */

          /* Shift pointers. */
          for(i = editor->total_models - 1;
            i > (insert_pos + 1 - 1);
              i--
          )
            editor->model[i] = editor->model[i - 1];
      }
      else if(insert_pos >= editor->total_models)
      {
          /* Append. */
          insert_pos = editor->total_models - 1;

          /* No need to shift list pointers. */
        }
      else
      {
          /* Could not add model into list. */
          V3DModelDestroy(model_ptr);
          return;
      }

      /* Value of insert_pos should now definatly be valid. */

      /* Set new model into the models list. */
      editor->model[insert_pos] = model_ptr;

      /* Insert new row on models clist. */
      if(clist != NULL)
      {
          gchar *val[1];

          val[0] = strdup("");
          gtk_clist_insert(clist, insert_pos, val);
          free(val[0]);
          EditorListModelsSet(
            (GtkWidget *)clist, insert_pos, model_ptr, TRUE
          );
      }

        /* Realize all primitives on new model. */
        EditorPrimitiveRealizeAll(editor, insert_pos, TRUE);


      return;
}

/*
 *      Adds the list of models to the given editor.
 *
 *      The given list of models will be transfered and should no
 *      longer be referanced (including the pointer array) after calling
 *      this function. If transfer was sucessful, the model and its
 *    primitives will be realized.
 */
static void EditorDNDModelsListAddList(
        ma_editor_struct *editor,
      v3d_model_struct **model, int total_models,
      int *select, int total_selects,
        int insert_pos
)
{
        int i;


        /* Sanitize insert_pos if possible. */
        if(editor != NULL)
        {
          /* Sanitize insert position to number of models on the
           * editor. Note that we include 1 + the last model
           * index on the editor!
           */
          if(insert_pos > editor->total_models)
            insert_pos = editor->total_models;
          if(insert_pos < 0)
            insert_pos = 0;
        }

        /* Insert last to first. */
        for(i = total_models - 1; i >= 0; i--)
        {
            EditorDNDModelsListAdd(
                editor, model[i],
            select, total_selects,
            insert_pos
          );
        }

        /* Models have been inserted, deleted just the models pointer
         * array.
         */
        free(model);
      model = NULL;
      total_models = 0;

      return;
}

/*
 *      Adds the specified primitive to the specified model on the
 *    editor. The given primitive should not be realized, it will be
 *    realized in this function.
 *
 *      The pointer to the given primitive should not be referanced
 *      again after calling this function.
 *
 *      Primitives clist on the editor will be updated.
 */
static void EditorDNDPrimitivesListAdd(
        ma_editor_struct *editor, int model_num, void *p,
      int *select, int total_selects,
      int insert_pos
)
{
      gint i, n;   
        GtkCList *clist;
      v3d_model_struct *model_ptr;
      gboolean model_sel_on_editor = FALSE;


        if((editor == NULL) || (p == NULL))
      {
          V3DMPDestroy(p);
            return;
      }

        clist = (GtkCList *)editor->primitives_list;

      /* Get pointer to specified model number on editor. */
      model_ptr = V3DModelListGetPtr(
          editor->model, editor->total_models, model_num
      );
      if(model_ptr == NULL)
      {
          /* Model apparently does not exist on editor, so we cannot
           * add primitives to it. Destroy the primitive and return.
           */
          V3DMPDestroy(p);
          return;
      }

      /* Check if the given model number is selected on the editor. */
      if(model_num == EditorSelectedModelIndex(editor))
          model_sel_on_editor = TRUE;


        /* Sanitize insert position. */
        if(insert_pos < 0)
            insert_pos = 0;

        /* Sanitize total number of primitives on model. */
        if(model_ptr->total_primitives < 0)
            model_ptr->total_primitives = 0;

        /* Allocate a new pointer for the primitives list on the model. */
        n = model_ptr->total_primitives;
        model_ptr->total_primitives = n + 1;
        model_ptr->primitive = (void **)realloc(
            model_ptr->primitive,
            model_ptr->total_primitives * sizeof(void *)
        );
        if(model_ptr->primitive == NULL)
        {
            /* Memory allocation error, destroy given primitive and
             * return.
             */
            V3DMPDestroy(p);
            return;
        }
        else
        {
            model_ptr->primitive[n] = NULL;
        }

      /* Shift selected primitives list values on the editor
       * for any selected primitive value equal or greater than
       * insert_pos if the model is selected on the editor.
       */
      if(model_sel_on_editor)
      {
          for(i = 0; i < editor->total_selected_primitives; i++)
          {
            if(insert_pos <= editor->selected_primitive[i])
                editor->selected_primitive[i] += 1;
          }
          for(i = 0; i < total_selects; i++)
            {
                if(insert_pos <= select[i])
                    select[i] += 1;
            }
      }

        /* Handle by insert_pos. */
        if(insert_pos < model_ptr->total_primitives)
        {
            /* Insert at the specified insert position, all items
             * currently at and below insert_pos will be shifted
             * down one unit.
             */
        
            /* Shift pointers. */
            for(i = model_ptr->total_primitives - 1;
                i > (insert_pos + 1 - 1);
                i--
            )
                model_ptr->primitive[i] = model_ptr->primitive[i - 1];
        }
        else if(insert_pos >= model_ptr->total_primitives)
        {
            /* Append. */
            insert_pos = model_ptr->total_primitives - 1;

            /* No need to shift list pointers. */
        }
        else
        {
            /* Could not add primitive into model, so destroy the 
           * primitive and return.
           */
            V3DMPDestroy(p);
            return;
        }

        /* Value of insert_pos should now definatly be valid. */

        /* Set new primitive into model's primitives list. */
        model_ptr->primitive[insert_pos] = p;

        /* Insert new row on primitives clist if the model is selected. */
        if((clist != NULL) && (model_sel_on_editor))
        {
            gchar *val[1];

            val[0] = strdup("");
            gtk_clist_insert(clist, insert_pos, val);
          free(val[0]);

          EditorListPrimitivesSet(
            (GtkWidget *)clist, insert_pos, p, TRUE
          );
        }

        /* Realize primitive on model. */
      EditorPrimitiveRealize(editor, p, TRUE);

      return;
}

/*
 *    Adds the list of primitives to the given model on the editor.
 *
 *    The given list of primitives will be transfered and should no
 *    longer be referanced (including the pointer array) after calling
 *    this function. If transfer was sucessful, the primitives will be
 *    realized by this function.
 */
static void EditorDNDPrimitivesListAddList(
        ma_editor_struct *editor, int model_num,
      void **primitive, int total_primitives,
      int *select, int total_selects,
        int insert_pos
)
{
      int i;
      v3d_model_struct *model_ptr;


      /* Sanitize insert_pos if possible. */
      if(editor != NULL)
      {
          model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
          );
          if(model_ptr != NULL)
          {
            /* Sanitize insert position to number of primitives
             * currently on the model.
             *
             * Note we allow insert_pos to be 1 + the highest index
             * on the model's primitives list, since we *can* insert
             * one past the highest index.
             */
            if(insert_pos > model_ptr->total_primitives)
                insert_pos = model_ptr->total_primitives;
            if(insert_pos < 0)
                insert_pos = 0;
          }
      }

      /* Insert last to first. */
      for(i = total_primitives - 1; i >= 0; i--)
      {
          EditorDNDPrimitivesListAdd(
            editor, model_num, primitive[i],
            select, total_selects,
            insert_pos
          );
      }

      /* Primitives have been inserted, deleted just the pointer
       * array.
       */
      free(primitive);
      primitive = NULL;
      total_primitives = 0;

      return;
}

/*
 *    Sets the editor's selected model primitive's vertex values to the
 *    given values.
 *
 *    If no model or single primitive is selected or the vertex 
 *    number specified by value_num has no vertex then no operation
 *    will be performed.
 *
 *    The given values will not be modified.
 */
static void EditorDNDValuesListSet(
        ma_editor_struct *editor, 
        int value_num,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc
)
{
      gbool vertex_has_been_set = FALSE;
      gint last_selected_value;
      gint model_num, pn;
      v3d_model_struct *model_ptr;
      gpointer p;
      GtkCList *clist;


      if(editor == NULL)
          return;

      model_num = EditorSelectedModelIndex(editor);
      model_ptr = V3DModelListGetPtr(
          editor->model, editor->total_models, model_num
      );
      if(model_ptr == NULL)
          return;

      if(editor->total_selected_primitives == 1)
          pn = editor->selected_primitive[0];
      else
          pn = -1;
      p = V3DMPListGetPtr(
          model_ptr->primitive, model_ptr->total_primitives, pn
      );
      if(p == NULL)
          return;

      /* Record previously selected value number on editor. */
      last_selected_value = EditorGetSelected(
          editor->selected_value, editor->total_selected_values,
          0
      );

      /* Get editor's values clist. */
      clist = (GtkCList *)editor->values_list;
      if(clist == NULL)
          return;


      /* If given value number is invalid, then set it to be the
       * last value item index.
       */
      if((value_num < 0) || (value_num >= clist->rows))
          value_num = clist->rows - 1;
      /* Still invalid? */
      if(value_num < 0)
          value_num = 0;


      /* Given vertex valid? */
      if(v != NULL)
      {
          mp_vertex_struct *tar_v = V3DMPGetVertex(p, value_num);
          if(tar_v != NULL)
          {
            memcpy(tar_v, v, sizeof(mp_vertex_struct));
            vertex_has_been_set = TRUE;
          }
      }

        /* Given normal valid? */
        if(n != NULL)
        {
            mp_vertex_struct *tar_n = V3DMPGetNormal(p, value_num);
            if(tar_n != NULL)
          {
                memcpy(tar_n, n, sizeof(mp_vertex_struct));
            vertex_has_been_set = TRUE;
          }
        }

        /* Given texcoord valid? */
        if(tc != NULL)
        {
            mp_vertex_struct *tar_tc = V3DMPGetTexCoord(p, value_num);
            if(tar_tc != NULL)
          {
                memcpy(tar_tc, tc, sizeof(mp_vertex_struct));
                vertex_has_been_set = TRUE;
            }
        }

      if(vertex_has_been_set)
      {
          /* Update editor's values clist and reselect. */
          EditorListDeleteValuesG(editor);
          EditorListAddValuesRG(editor, p);

          /* Select newly set vertex number. */
          gtk_clist_select_row(clist, value_num, 0);

          EDITOR_DO_UPDATE_HAS_CHANGES
      }

      return;
}


/*
 *      Sets the DND icon based on models clist's row matched at
 *    the given coordinates.
 */
void EditorDNDModelsListSetIcon(
      ma_editor_struct *editor, int x, int y
)
{
      gint column, row;
      GtkCList *clist;
      v3d_model_struct *model_ptr;


      if(editor == NULL)
          return;

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

      if(!gtk_clist_get_selection_info(
          clist, x, y, &row, &column
      ))
      {
          row = -1;
          column = -1;
      }

      model_ptr = V3DModelListGetPtr(
          editor->model, editor->total_models,
          row
      );

        if(model_ptr != NULL)
        {
            GdkPixmap *pixmap = NULL;
            GdkBitmap *mask = NULL;
          int icon_num = VMA_PIXMAP_MODEL_OTHER_20x20;


          if(model_ptr->type == V3D_MODEL_TYPE_STANDARD)
          {
            if(model_ptr->flags & V3D_MODEL_FLAG_HIDE)
                icon_num = VMA_PIXMAP_MODEL_HIDDEN_20x20;
            else
                icon_num = VMA_PIXMAP_MODEL_20x20;
          }
          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)
            );
            }
        }   
}

/*
 *      DND `data request' callback for the editor's models list.
 */
void EditorDNDModelsListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
)
{
        gboolean data_sent = FALSE;
        GtkCList *clist;
      gint model_num;
        v3d_model_struct *model;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
            return;

        if(!editor->initialized)
            return;

        /* Sync data on editor. */
        EditorSyncData(editor);

        /* Get selected model. */
      model_num = EditorSelectedModelIndex(editor);
        model = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
        );

        /* Get clist from the input widget. */
        clist = ((GTK_IS_CLIST(widget)) ? GTK_CLIST(widget) : NULL);
        if((clist != NULL) && (model != NULL))
        {
          /* Send out data consisting of a command containing the
           * following arguments:
           * <core_ptr> <editor_num> <selected_models...>
           */
          int i;
          char *buf;
          int buf_len;
          int editor_num = -1;
          vma_core_struct *core_ptr = (vma_core_struct *)editor->core_ptr;
          char num_str[80];

          /* Find editor number in core structure. */
          if(core_ptr != NULL)
          {
            for(i = 0; i < core_ptr->total_editors; i++)
            {
                if(core_ptr->editor[i] == editor)
                {
                  editor_num = i;
                  break;
                }
            }
          }

          /* Allocate buf, enough for just one model number for now
           * since only one model can be selected.
           */
          buf_len = 24 + 24 + (24 * 1);
          buf = (char *)malloc(buf_len * sizeof(char));
          if(buf != NULL)
          {
            /* Format buf. */
            (*buf) = '\0';
            sprintf(num_str, "%.8x %i", (guint)core_ptr, editor_num);
            strcat(buf, num_str);
            strcat(buf, " ");
            sprintf(num_str, "%i", model_num);
            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;
}

/*
 *      DND `data recieved' callback for the editor's models list.
 *
 *    The recieved data will be checked if it is either a models or
 *    primitives transfer command string and if so, it will be parsed
 *    and then appropriate action taken.
 *
 *    Deletion of data from the source will also be handled here.
 *
 *    This function cannot handle data recieved from other
 *    applications since it relys on accessable pointers in memory.
 */
void EditorDNDModelsListDataRecievedCB(
        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;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
                return;

        if(!editor->initialized || editor->processing)
            return;

      if(VMAWriteProtectCheck(editor))
          return;

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

      /* Mark editor as processing. */
      editor->processing = TRUE;

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

        EDITOR_DO_UPDATE_HAS_CHANGES

        /* Sync data on editor. */
        EditorSyncData(editor);

        /* 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)
        {
          int i;
            gint row, column;
            GList *next;
          gbool   is_editor_models_cmd = FALSE,
                  is_editor_primitives_cmd = FALSE,
                  is_editor_model_create_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)
                {
                /* Models transfer command string from another
                 * editor (possibly this one)?
                 */
                    if(!strcmp(cstrptr, EDITOR_DND_TYPE_MODELS_CMD))
                    {
                  is_editor_models_cmd = TRUE;
                        status = TRUE;
                        break;
                    }
                    /* Primitives transfer command string from another
                     * editor (possibly this one)?
                     */
                    else if(!strcmp(cstrptr, EDITOR_DND_TYPE_PRIMITIVES_CMD))
                    {
                        is_editor_primitives_cmd = TRUE;
                        status = TRUE;
                        break;
                    }
                    /* Model create command string. */
                    else if(!strcmp(cstrptr, EDITOR_DND_TYPE_MODEL_CREATE_CMD))
                    {
                        is_editor_model_create_cmd = TRUE;
                        status = TRUE;
                        break;
                    }
                }
                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 models transfer command? */
            if(status && is_editor_models_cmd)
            {
                /* Parse editor models transfer command string.
                 * A source editor wants to transfer a list of models
                 * to our target editor.
                 */
            vma_core_struct *src_core_ptr = NULL;
            int   tar_new_sel,
                  src_editor_num = -1,
                  *src_sel_model = NULL,
                  src_total_sel_models = 0;
            ma_editor_struct *src_editor = NULL;

            EditorDNDParseModelsCmd(
                (const char *)selection_data->data,
                &src_core_ptr,
                &src_editor, &src_editor_num,
                &src_sel_model, &src_total_sel_models
            );

            /* Is source editor valid? */
            if(src_editor != NULL)
            {
                v3d_model_struct **new_model, *model_ptr;
                int n, total_new_models;


                /* Copy new models from source editor into a
                 * tempory list.
                 */
                total_new_models = src_total_sel_models;
                if(total_new_models > 0)
                  new_model = (v3d_model_struct **)calloc(
                      total_new_models, sizeof(v3d_model_struct *)
                  );
                else
                  new_model = NULL;
                if(new_model == NULL)
                {
                  total_new_models = 0;
                }
                else
                {
                  for(i = 0; i < total_new_models; i++)
                  {
                      n = src_sel_model[i];

                      /* Match model on source editor. */
                      model_ptr = V3DModelListGetPtr(
                        src_editor->model, src_editor->total_models,
                        n
                      );
                      /* Duplicate model from source editor. */
                      new_model[i] = V3DModelDup(model_ptr);
                  }
                }

                /* If same editor, then unselect all. */
                if(same)
                  gtk_clist_unselect_all(clist);

                /* Insert new models to target editor, new models
                 * will be transfered and should no longer be
                 * referenced after this call.
                 */
                EditorDNDModelsListAddList(
                  editor,
                  new_model, total_new_models,
                  same ? src_sel_model : NULL,
                  same ? src_total_sel_models : 0,
                  row
                );
                new_model = NULL;
                total_new_models = 0;

                    /* Calculate new row to select on target editor. */
                tar_new_sel = row;

                    /* Delete selected models on source editor as
                 * needed.
                 */
                if(need_delete)
                {
                  /* Delete selected models on source editor. */
                  EditorDNDModelsListDoDeleteModels(
                      src_editor,
                      src_sel_model,
                      src_total_sel_models
                  );
                  if(same)
                  {
                      /* Offset new selected item due to deletion
                       * of items with lower index values.
                       */
                      for(i = 0, n = 0; i < src_total_sel_models; i++)
                      {
                        if(src_sel_model[i] < 0)
                            continue;
                        if(src_sel_model[i] < tar_new_sel)
                            n++;
                      }
                      tar_new_sel -= n;
                  }
                  else
                  {
                      /* Redraw views on source editor since it is
                       * not the target editor.
                       */
                      EditorRedrawAllViews(src_editor);
                  }
                }

                    /* Select first row on target editor's models list,
                     * this will update the menus and redraw.
                     */
                    if((tar_new_sel >= 0) && (tar_new_sel < clist->rows))
                        gtk_clist_select_row(clist, tar_new_sel, 0);
                } /* Is source editor valid? */

            /* Free local selected items list. */
            free(src_sel_model);
            src_sel_model = NULL;
            src_total_sel_models = 0;           
          }
            /* ******************************************************** */
            /* Editor primitives transfer command? */
            else if(status && is_editor_primitives_cmd)
            {
                /* Parse editor primitives transfer command string.
                 * A source editor wants to transfer a list of primitives
                 * to our target editor. Note that they want to transfer
             * the list of primitives to a model on our models list.
             * The dropped on model will be the model to transfer
             * the list of primitives to.
                 */
                vma_core_struct *src_core_ptr = NULL;
                int     src_editor_num = -1,
                        src_sel_model_num = -1,
                        tar_model_num = -1,
                        *src_sel_primitive = NULL,
                        src_total_sel_primitives = 0;
                v3d_model_struct        *src_sel_model_ptr = NULL,
                                        *tar_model_ptr = NULL;
                ma_editor_struct *src_editor = NULL;


                /* Get model on target editor that was dropped on, this
             * will be the model to put the list of primitives into.
             */
                tar_model_num = row;
            if(tar_model_num >= editor->total_models)
                tar_model_num = editor->total_models - 1;
            if(tar_model_num < 0)
                tar_model_num = 0;
                tar_model_ptr = V3DModelListGetPtr(
                    editor->model, editor->total_models, tar_model_num
                );

                /* Parse string. */
                EditorDNDParsePrimitivesCmd(
                    (const char *)selection_data->data,
                    &src_core_ptr,
                    &src_editor, &src_editor_num,
                    &src_sel_model_ptr, &src_sel_model_num,
                    &src_sel_primitive, &src_total_sel_primitives
                );

                /* Is source editor valid and selected model of type
                 * V3D_MODEL_TYPE_STANDARD on both editors?
                 */
                if((src_editor != NULL) &&
                   ((src_sel_model_ptr == NULL) ? 0 :
                        (src_sel_model_ptr->type == V3D_MODEL_TYPE_STANDARD)
                   ) &&
                   ((tar_model_ptr == NULL) ? 0 :
                        (tar_model_ptr->type == V3D_MODEL_TYPE_STANDARD)
               )
            )
            {
                    void *p, **new_primitive;
                    int n, total_new_primitives;


                    /* Copy new primitives from source editor's model
                 * into our tempory primitives list.
                 */
                total_new_primitives = src_total_sel_primitives;
                    if(total_new_primitives > 0)
                        new_primitive = (void **)calloc(
                            total_new_primitives, sizeof(void *)
                        );
                else
                  new_primitive = NULL;
                    if(new_primitive == NULL)
                {
                        total_new_primitives = 0;
                }
                else
                {
                        for(i = 0; i < total_new_primitives; i++)
                        {
                            n = src_sel_primitive[i];

                            /* Match primitive on source model. */
                            p = V3DMPListGetPtr(
                                src_sel_model_ptr->primitive,
                        src_sel_model_ptr->total_primitives,
                                n
                            );
                            /* Duplicate primitive from source model. */
                            new_primitive[i] = V3DMPDup(p);
                       }
                    }

                    /* If same editor and same model, then unselect all. */
                    if((editor == src_editor) &&
                       (tar_model_ptr == src_sel_model_ptr)
                )
                {
                  if(editor->primitives_list != NULL)
                      gtk_clist_unselect_all(
                        GTK_CLIST(editor->primitives_list)
                      );
                }

                    /* Insert new primitives to target model (the dropped
                 * on target model, not the selected target model),
                 * new primitives will be transfered and should no
                 * longer be referenced after this call. Remember
                 * that we insert at 0 since the row value reflects
                 * the droped on row on the target editor's models
                 * list.
                     */
                if((editor == src_editor) &&
                       (tar_model_ptr == src_sel_model_ptr)
                    )
                        EditorDNDPrimitivesListAddList(
                            editor, tar_model_num,
                            new_primitive, total_new_primitives,
                            src_sel_primitive, src_total_sel_primitives,
                            0           /* Insert pos on target models list. */
                        );
                else
                        EditorDNDPrimitivesListAddList(
                            editor, tar_model_num,
                      new_primitive, total_new_primitives,
                            NULL, 0,      /* Do not modify select. */
                      0       /* Insert pos on target models list. */
                        );
                    new_primitive = NULL;
                total_new_primitives = 0;

                    /* Delete selected models on source editor as
                     * needed.
                     */
                    if(need_delete)
                    {
                        /* Delete the selected primitives on the selected
                         * model of the source editor.
                         */
                        EditorDNDPrimitivesListDoDeletePrimitives(
                            src_editor, src_sel_model_ptr,
                      src_sel_primitive, src_total_sel_primitives
                        );

                        /* Redraw displays on source editor if not same
                         * as target editor.
                         */
                        if(editor != src_editor)
                            EditorRedrawAllViews(src_editor);
                    }

                    /* Redraw displays on target editor. */
                    EditorRedrawAllViews(editor);

                }       /* Is source editor valid? */
            else
            {
                /* Something went wrong, we could not drop to a
                 * model on the target editor's models list. Lets
                 * try to notify the user about what went wrong.
                 */
                if(src_editor == NULL)
                  CDialogGetResponse(
"Non-critical internal error!",
"The drag source editor pointer is NULL.",
"The program encountered a non-critical internal error in\n\
which some data was inconsistant, the operation has been\n\
aborted. It is unlikely that any data was lost.",
                            CDIALOG_ICON_ERROR,
                            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
                            CDIALOG_BTNFLAG_OK
                        );
                else if(src_sel_model_ptr == NULL)
                        CDialogGetResponse(
"Non-critical internal error!",
"The drag source model pointer is NULL.",
"The program encountered a non-critical internal error in\n\
which some data was inconsistant, the operation has been\n\
aborted. It is unlikely that any data was lost.",
                            CDIALOG_ICON_ERROR,
                            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
                            CDIALOG_BTNFLAG_OK   
                        ); 
                else if((tar_model_ptr == NULL) ? 1 :
                        (tar_model_ptr->type != V3D_MODEL_TYPE_STANDARD)
                    )
                        CDialogGetResponse(
"That model cannot contain primitives!",
"The model that you dropped on cannot contain primitives,\n\
the selected primitive(s) have been moved back to their\n\
previous location.",
"The model that you dropped the selected primitives on is\n\
not of type V3D_MODEL_TYPE_STANDARD, therefore it cannot\n\
contain primitives. The primitive(s) that you attempted to\n\
move or copy have been left in their previous location.",
                            CDIALOG_ICON_ERROR,
                            CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP,
                            CDIALOG_BTNFLAG_OK
                        );
            }

                /* Free list of selected source primitives, it is no
             * longer needed.
                 */
                free(src_sel_primitive);
            src_sel_primitive = NULL;
            src_total_sel_primitives = 0;
            }
            /* Editor model create command? */
            else if(status && is_editor_model_create_cmd)
            {
                /* Parse editor model create command string.
                 * A source editor wants to create a model on to our
                 * target editor.
                 */
                vma_core_struct *src_core_ptr = NULL;
                int src_editor_num = -1;
                ma_editor_struct *src_editor = NULL;
                v3d_model_struct *src_model_ptr;      /* New model to be created, read only. */
            const char *src_name_ptr;

                EditorDNDParseModelCreateCmd(
                    (const char *)selection_data->data,
                    &src_core_ptr,
                    &src_editor, &src_editor_num,
                    &src_model_ptr,
                &src_name_ptr
                );   

            /* Sync data on target editor. */
            EditorSyncData(editor);

                /* New referance model valid? */
                if(src_model_ptr != NULL)
            {
                int tar_model_num = row;
                v3d_model_struct *new_model_ptr = V3DModelDup(
                  src_model_ptr
                );

                /* Update new model's name. */
                if(new_model_ptr != NULL)
                {
                  if(src_name_ptr != NULL)
                  {
                      free(new_model_ptr->name);
                      new_model_ptr->name = strdup(src_name_ptr);
                  }
                }

                /* If same editor, then unselect all. */
                if(editor == src_editor)
                  gtk_clist_unselect_all(clist);

                    /* Insert new model to target editor, the given
                 * model will be transfered and should not be
                 * referanced again. Remember that we insert at 0
                 * since the row value reflects the droped on row on
                 * the target editor's models list.
                     */
                EditorDNDModelsListAdd(
                  editor, new_model_ptr,
                  NULL, 0,          /* No selection list. */
                  tar_model_num
                );
                new_model_ptr = NULL;

                    /* Select first row on target editor's models list,
                     * this will update the menus and redraw.
                     */
                    if((tar_model_num >= 0) && (tar_model_num < clist->rows))
                        gtk_clist_select_row(clist, tar_model_num, 0);
            }
                else
                {
                    /* Something went wrong, we could not drop to a
                     * model on the target editor's models list. Lets
                     * try to notify the user about what went wrong.
                     */


            }
          }
/* Add support for recieving of other drop types here. */
      }


      /* Mark as no longer processing. */
      editor->processing = FALSE;

}

/*
 *    Procedure to delete the specified models on the given editor,
 *    this function is designed to be called when a dnd requires
 *    the source editor's models deleted.
 */
static void EditorDNDModelsListDoDeleteModels(
      ma_editor_struct *editor,
      int *selected_model, int total_selected_models
)
{
      int *s, st;
      int i, j, model_num;
      v3d_model_struct *model_ptr;
      GtkCList *clist;


      if((editor == NULL) || (selected_model == NULL) ||
           (total_selected_models <= 0)
      )
          return;

        clist = (GtkCList *)editor->models_list;


      /* Make a local copy of the selections list. */
      st = total_selected_models;
      s = (int *)malloc(st * sizeof(int));
      if(s == NULL)
          return;
      else
          memcpy(s, selected_model, st * sizeof(int));

      EDITOR_DO_UPDATE_HAS_CHANGES

      /* Go through each selected model. */
      for(i = 0; i < st; i++)
      {
          model_num = s[i];
            model_ptr = V3DModelListGetPtr(
                editor->model, editor->total_models, model_num
            );
            if(model_ptr != NULL)
          {
                /* Delete selected model, first unrealize all model
                 * primitives on it then destroy it. Note that we don't
             * use EditorModelDelete() since we accomplish the same
             * thing cept faster doing the destroying of models
             * ourselves in this function.
                 */
                EditorPrimitiveUnrealizeAll(editor, model_num);
                V3DModelDestroy(model_ptr);
                model_ptr = NULL;
                editor->model[model_num] = NULL;
          }
      }

      /* Go through each model and shift pointers on NULL's. */
      if(clist != NULL)
          gtk_clist_freeze(clist);
      for(model_num = 0; model_num < editor->total_models; model_num++)
      {
            if(editor->model[model_num] != NULL)
                continue;

          /* Decrease total pointers and shift. */
            editor->total_models--;
            for(j = model_num; j < editor->total_models; j++)
                editor->model[j] = editor->model[j + 1];

            /* Remove corresponding item from clist. */
          if(clist != NULL)
            gtk_clist_remove(clist, model_num);

            /* Go back one row so we can check if again after shift
             * incase next row was NULL.
             */
          model_num--;
      }
      if(clist != NULL)
            gtk_clist_thaw(clist);

      /* Reallocate models list on editor. */
      if(editor->total_models > 0)
      {
          editor->model = (v3d_model_struct **)realloc(
            editor->model,
            editor->total_models * sizeof(v3d_model_struct *)
          );
          if(editor->model == NULL)
          {
            editor->total_models = 0;
          }
      }
      else
      {
          free(editor->model);
          editor->model = NULL;
          editor->total_models = 0;
      }

      /* Now unselect all rows on the models list. */
      if(clist != NULL)
          gtk_clist_unselect_all(clist);
      /* Need to call the select callback manually. */
      EditorModelsListSelectCB(
          (GtkWidget *)clist,
          -1, -1,       /* Unselect row and column. */
          NULL,
          editor
      );

      /* Free local selections list which we allocated. */
      free(s);

      return;
}

/*
 *      DND data delete callback for the editor's models list.
 */
void EditorDNDModelsListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
      /* Function no longer used. */
      return;
}



/*
 *    Sets DND icon matched to the primitives clist's row at the
 *    given coordinates.
 */
void EditorDNDPrimitivesListSetIcon(
        ma_editor_struct *editor, int x, int y
)
{
        gint column, row;
        GtkCList *clist;
        v3d_model_struct *model_ptr;
      void *p = NULL;


        if(editor == NULL)
            return;

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

        if(!gtk_clist_get_selection_info(
            clist, x, y, &row, &column
        ))
        {
            row = -1;    
            column = -1;
        }

      model_ptr = V3DModelListGetPtr(
          editor->model, editor->total_models,
          EditorSelectedModelIndex(editor)
      );
      if(model_ptr != NULL)
          p = V3DMPListGetPtr(
            model_ptr->primitive, model_ptr->total_primitives, row
          );

      if(p != NULL)
      {
          GdkPixmap *pixmap = NULL;
          GdkBitmap *mask = NULL;
          int icon_code = VMAPixmapsListGetMPCode(
            &vma_pixmaps_list, *(int *)p
          );

          VMAPixmapsListGetValues(
            &vma_pixmaps_list, icon_code,
            &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)
                );
          }
      }
}


/*
 *    DND `data request' callback for the editor's primitives list.
 */
void EditorDNDPrimitivesListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
)
{
        gboolean data_sent = FALSE;
        GtkCList *clist;
      v3d_model_struct *model;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
            return;

      if(!editor->initialized)
          return;

        /* Sync data on editor. */
        EditorSyncData(editor);

      /* Get selected model. */
      model = V3DModelListGetPtr(
          editor->model, editor->total_models,
          EditorSelectedModelIndex(editor)
      );

        /* Get clist from the input widget. */
        clist = ((GTK_IS_CLIST(widget)) ? GTK_CLIST(widget) : NULL);
        if((clist != NULL) && (editor->total_selected_primitives > 0) &&
         (model != NULL)
      )
        {
            /* Send out data consisting of a command containing the
             * following arguments:
             * <core_ptr> <editor_num> <selected_model>
           * <selected_primitives...>
             */
            int i;
            char *buf;
            int buf_len;
            int editor_num = -1;
          v3d_model_struct *model_ptr;
          int model_num;
            vma_core_struct *core_ptr = (vma_core_struct *)editor->core_ptr;
            char num_str[256];

            /* Find editor number in core structure. */
            if(core_ptr != NULL)
            {
                for(i = 0; i < core_ptr->total_editors; i++)
                {
                    if(core_ptr->editor[i] == editor)
                    {
                        editor_num = i;
                        break;
                    }
                }
            }

          /* Get selected model on editor. */
          model_num = EditorSelectedModelIndex(editor);
          model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
          );

            /* Allocate buf. */
            buf_len = 24 + 24 + 24 +
            (editor->total_selected_primitives * 24);
            buf = (char *)malloc(buf_len * sizeof(char)); 
            if(buf != NULL)
          {
                /* Format buf. */
                (*buf) = '\0';
                sprintf(num_str, "%.8x %i", (guint)core_ptr, editor_num);
                strcat(buf, num_str);

                strcat(buf, " ");
                sprintf(num_str, "%i", model_num);
                strcat(buf, num_str);

            strcat(buf, " ");
            for(i = 0; i < editor->total_selected_primitives; i++)
            {
                strcat(buf, " ");
                sprintf(num_str, "%i", editor->selected_primitive[i]);
                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;
}

/*
 *      DND `data recieved' callback for the editor's primitives list.
 *
 *      The recieved data will be checked if it is primitives transfer
 *    command string and if so, it will be parsed and then appropriate
 *    action taken.    
 *
 *      Deletion of data from the source will also be handled here.
 *
 *      This function cannot handle data recieved from other
 *      applications since it relys on accessable pointers in memory.
 */
void EditorDNDPrimitivesListDataRecievedCB(
        GtkWidget *widget,
        GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data,
        guint info, guint t,
        gpointer data
)
{
      gboolean need_delete = FALSE;
        gchar *strptr;
        gboolean same;
        GtkWidget *source_widget;
        GtkCList *clist;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
                return;

        if(!editor->initialized || editor->processing)
            return;

      if(VMAWriteProtectCheck(editor))
          return;

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

      /* Mark editor as processing. */
      editor->processing = TRUE;

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

      EDITOR_DO_UPDATE_HAS_CHANGES

      /* Sync data on editor. */
      EditorSyncData(editor);

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

        /* Get clist from the input widget. */
        clist = ((GTK_IS_CLIST(widget)) ? GTK_CLIST(widget) : NULL);
        if(clist != NULL)
        {
          int i;
            gint row, column;
          gbool status;
          gbool   is_primitives_transfer = FALSE,
                  is_primitive_create = FALSE;
            GList *next;
            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. */
            status = FALSE;
            next = dc->targets;
            while(next != NULL)
            {
                strptr = gdk_atom_name((GdkAtom)next->data);
                if(strptr != NULL)
                {
                    if(!strcmp(strptr, EDITOR_DND_TYPE_PRIMITIVES_CMD))
                    {
                        status = TRUE;
                  is_primitives_transfer = TRUE;
                        break;
                    }
                else if(!strcmp(strptr, EDITOR_DND_TYPE_PRIMITIVE_CREATE_CMD))
                {
                        status = TRUE;
                  is_primitive_create = TRUE;
                        break;
                }
                }
                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 primitives transfer command? */
            if(status && is_primitives_transfer)
            {
                /* Parse editor primitives transfer command string.
                 * A source editor wants to transfer a list of primitives
                 * to our target editor's primitives list.
                 */
                vma_core_struct *src_core_ptr = NULL;
                int     tar_new_sel,
                  src_editor_num = -1,
                        src_sel_model_num = -1,
                  tar_model_num = -1,
                  *src_sel_primitive = NULL,
                        src_total_sel_primitives = 0;
            v3d_model_struct  *src_sel_model_ptr = NULL,
                              *tar_model_ptr = NULL;
                ma_editor_struct *src_editor = NULL;


            /* Get selected model on target editor. */
            tar_model_num = EditorSelectedModelIndex(editor);
            tar_model_ptr = V3DModelListGetPtr(
                editor->model, editor->total_models, tar_model_num
            );

                /* Parse string. */
                EditorDNDParsePrimitivesCmd(
                    (const char *)selection_data->data,
                    &src_core_ptr,
                    &src_editor, &src_editor_num,
                &src_sel_model_ptr, &src_sel_model_num,
                    &src_sel_primitive, &src_total_sel_primitives
                );

                /* Is source editor valid and selected model of type
                 * V3D_MODEL_TYPE_STANDARD on both editors?
                 */
                if((src_editor != NULL) &&
                   ((src_sel_model_ptr == NULL) ? 0 :
                  (src_sel_model_ptr->type == V3D_MODEL_TYPE_STANDARD)
               ) &&
               ((tar_model_ptr == NULL) ? 0 :
                        (tar_model_ptr->type == V3D_MODEL_TYPE_STANDARD)
                   )
            )
                {
                void *p, **new_primitive;
                int n, total_new_primitives;


                    /* Copy new primitives from source editor's model. */
                    total_new_primitives = src_total_sel_primitives;
                    if(total_new_primitives > 0)
                        new_primitive = (void **)calloc(
                            total_new_primitives, sizeof(void *)
                        );
                    else
                        new_primitive = NULL;
                    if(new_primitive == NULL)
                    {      
                        total_new_primitives = 0;
                    }
                    else
                    {
                        for(i = 0; i < total_new_primitives; i++)
                        {
                            n = src_sel_primitive[i];

                            /* Match primitive on source model. */
                            p = V3DMPListGetPtr(
                                src_sel_model_ptr->primitive,
                                src_sel_model_ptr->total_primitives,
                                n
                            );
                            /* Duplicate primitive from source model. */
                            new_primitive[i] = V3DMPDup(p);
                       }
                    }   

                /* If editors are the same then unselect all. */
                if(same)
                  gtk_clist_unselect_all(clist);

                /* Insert new primitives to selected model on the
                 * target editor, new primitives will be transfered
                 * and should no longer be referenced after this
                 * call.
                     */
                    EditorDNDPrimitivesListAddList(
                        editor, tar_model_num,
                        new_primitive, total_new_primitives,
                        same ? src_sel_primitive : NULL,
                        same ? src_total_sel_primitives : 0,
                        row
                    );
                    new_primitive = NULL;
                    total_new_primitives = 0;

                    /* Calculate new row to select on target editor. */
                    tar_new_sel = row;

                    /* Delete selected primitives on the selected model on
                 * the source editor as needed.
                     */
                    if(need_delete)
                    {
                        /* Delete the selected primitives on the selected
                   * model of the source editor.
                         */
                        EditorDNDPrimitivesListDoDeletePrimitives(
                            src_editor, src_sel_model_ptr,
                      src_sel_primitive, src_total_sel_primitives
                  );
                  if(same)
                  {
                            /* Offset new selected item due to deletion
                             * of items with lower index values.
                             */
                            for(i = 0, n = 0; i < src_total_sel_primitives; i++)
                            {
                                if(src_sel_primitive[i] < 0)
                                    continue;
                                if(src_sel_primitive[i] < tar_new_sel)    
                                    n++;
                            }
                            tar_new_sel -= n;
                  }
                  else
                  {
                      /* Redraw displays on source editor if not
                       * same as target editor.
                       */
                            EditorRedrawAllViews(src_editor);
                        }
                    }

                    /* Select first row on target editor's models list, 
                     * this will update the menus and redraw.
                     */
                    if((tar_new_sel >= 0) && (tar_new_sel < clist->rows))
                        gtk_clist_select_row(clist, tar_new_sel, 0);
                }       /* Is source editor valid? */

                /* Free list of selected primitives, it is no longer
                 * needed.
                 */
                free(src_sel_primitive);
            src_sel_primitive = NULL;
            src_total_sel_primitives = 0;
          }
            /* Create primitive command? */
            else if(status && is_primitive_create)
            {
                /* Parse primitive create command string.
                 * A source editor or just primitives palette wants
             * us to create a new primitive on our target editor's
             * primitives list.
                 */
                vma_core_struct *src_core_ptr = NULL;
                int     src_editor_num = -1,
                        tar_model_num = -1,
                        src_ptype = -1;
                v3d_model_struct *tar_model_ptr = NULL;
                ma_editor_struct *src_editor = NULL;
            void *src_p;


                /* Get selected model on target editor. */
                tar_model_num = EditorSelectedModelIndex(editor);
                tar_model_ptr = V3DModelListGetPtr(
                    editor->model, editor->total_models, tar_model_num
                );

                /* Parse string. */
            EditorDNDParsePrimitiveCreateCmd(
                (const char *)selection_data->data,
                    &src_core_ptr,
                    &src_editor, &src_editor_num,
                    &src_ptype, &src_p
                );

            /* Create a new primitive on our target editor, this
             * will update menus and redraw the editor as needed.
             *
             * The given copy of the source primitive will be 
             * transfered to the editor and should not be referanced
             * again.
             */
            EditorPrimitiveDoCreateSimple(
                editor,
                src_ptype,          /* Primitive type. */
                row,          /* Insert position. */
                V3DMPDup(src_p)
            );
          }
/* Add support for other drop types here. */
        }

      /* Mark as no longer processing. */
      editor->processing = FALSE;

      return;
}


/*
 *      Procedure to delete the specified primitivess on the given model,
 *      this function is designed to be called when a dnd requires
 *      the source editor model's primitives deleted.
 */           
static void EditorDNDPrimitivesListDoDeletePrimitives(
        ma_editor_struct *editor, v3d_model_struct *model_ptr,
        int *selected_primitive, int total_selected_primitives
)
{
        int *s, st;
        int i, j, pn;
      void *p;
        GtkCList *clist;


        if((editor == NULL) || (model_ptr == NULL) ||
           (selected_primitive == NULL) ||
         (total_selected_primitives <= 0)
        )
            return;

        clist = (GtkCList *)editor->primitives_list;


        /* Make a local copy of the selections list. */
        st = total_selected_primitives;
        s = (int *)malloc(st * sizeof(int));
        if(s == NULL)
            return;
        else
            memcpy(s, selected_primitive, st * sizeof(int));

        EDITOR_DO_UPDATE_HAS_CHANGES

        /* Go through each selected primitive on the model. */
        for(i = 0; i < st; i++)
        {
            pn = s[i];
            p = V3DMPListGetPtr(
            model_ptr->primitive, model_ptr->total_primitives, pn
            );
            if(p != NULL)
            {
                /* Unrealize the primitive and destroy it. */
                EditorPrimitiveUnrealize(editor, p);
                V3DMPDestroy(p);
                model_ptr->primitive[pn] = NULL;
            }
        }

        /* Go through each model and shift pointers on NULL's. */
        if(clist != NULL)
            gtk_clist_freeze(clist);
        for(pn = 0; pn < model_ptr->total_primitives; pn++)
        {
            if(model_ptr->primitive[pn] != NULL)
                continue;

            /* Decrease total pointers and shift. */
            model_ptr->total_primitives--;
            for(j = pn; j < model_ptr->total_primitives; j++)
                model_ptr->primitive[j] = model_ptr->primitive[j + 1];

            /* Remove corresponding item from clist. */
            if(clist != NULL)
                gtk_clist_remove(clist, pn);

            /* Go back one row so we can check if again after shift
             * incase next row was NULL.
             */
            pn--;
        }
        if(clist != NULL)
            gtk_clist_thaw(clist);

        /* Reallocate primitives list on model. */
        if(model_ptr->total_primitives > 0)
        {
            model_ptr->primitive = (void **)realloc(
                model_ptr->primitive,
                model_ptr->total_primitives * sizeof(void *)
            );
            if(model_ptr->primitive == NULL)
            {
                model_ptr->total_primitives = 0;
            }
        }
        else
        {
            free(model_ptr->primitive);
            model_ptr->primitive = NULL;
            model_ptr->total_primitives = 0;
        }

        /* Now unselect all rows on the primitives list. */
        EditorUnselectAll(
            &editor->selected_primitive,
            &editor->total_selected_primitives
        );
      if(clist != NULL)
          gtk_clist_unselect_all(clist);

        /* Free local selections list which we allocated. */
        free(s);

        return;
}

/*
 *    DND data delete callback for the editor's primitives list.
 */
void EditorDNDPrimitivesListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
      /* Function no longer used. */
      return;
}



/*
 *    Sets DND icon for the values list.
 */
void EditorDNDValuesListSetIcon(
      ma_editor_struct *editor, int x, int y
)
{
      GdkPixmap *pixmap = NULL;
      GdkBitmap *mask = NULL;
      int icon_num = VMA_PIXMAP_MP_POINT_20x20;


      if(editor == 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)
            );
      }
}

/*
 *    DND `data request' callback for the editor's values list.
 */
void EditorDNDValuesListDataRequestCB(
        GtkWidget *widget, GdkDragContext *dc,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
)
{
        gboolean data_sent = FALSE;
        v3d_model_struct *model_ptr;
      gint model_num, pn, value_num;
      gpointer p;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
            return;

        if(!editor->initialized)
            return;

        /* Sync data on editor. */
        EditorSyncData(editor);

      /* Get selected value item. */
      value_num = EditorGetSelected(
          editor->selected_value, editor->total_selected_values,
          0
      );

        /* Get selected model. */
      model_num = EditorSelectedModelIndex(editor);
        model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
        );
      if((model_ptr != NULL) && (value_num > -1))
      {
          /* Model is valid, now try to get selected primitive. */
          if(editor->total_selected_primitives == 1)
            pn = editor->selected_primitive[0];
          else
            pn = -1;
          p = V3DMPListGetPtr(
            model_ptr->primitive, model_ptr->total_primitives, pn
          );
          if(p != NULL)
          {
            /* Got valid primitive. */
            int buf_len;
            char *buf;
            int editor_num = -1;
            vma_core_struct *core_ptr = (vma_core_struct *)editor->core_ptr;
            char num_str[256];
            mp_vertex_struct *v, *n, *tc;


            /* Send out data consisting of a command containing the
             * following arguments:
             *
             * <core_ptr> <editor_num> <value_num>
             * <vertex_ptr> <normal_ptr> <texcoord_ptr>
             */
            v = V3DMPGetVertex(p, value_num);
            n = V3DMPGetNormal(p, value_num);
            tc = V3DMPGetTexCoord(p, value_num);

            /* 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;
}

/*
 *      DND `data recieved' callback for the editor's values list.
 *
 *      The recieved data will be checked if it is either a set values
 *    and if so, it will be parsed and then appropriate action taken.
 *
 *      Deletion of data from the source will also be handled here.
 *
 *      This function cannot handle data recieved from other
 *      applications since it relys on accessable pointers in memory.
 */
void EditorDNDValuesListDataRecievedCB(
        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;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if((widget == NULL) || (editor == NULL) || (dc == NULL))
                return;

        if(!editor->initialized || editor->processing)
            return;

        if(VMAWriteProtectCheck(editor))
            return;

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

        /* Mark editor as processing. */
        editor->processing = TRUE;

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

        EDITOR_DO_UPDATE_HAS_CHANGES

        /* Sync data on editor. */
        EditorSyncData(editor);

        /* 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;
                int     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
                );

            /* Update vertex on target editor's selected primitive
             * if any.
             */
            EditorDNDValuesListSet(
                editor, tar_value_num,
                src_v, src_n, src_tc
            );

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

        }

        /* Mark as no longer processing. */
        editor->processing = FALSE;

      return;
}


/*
 *      DND data delete callback for the editor's values list.
 */
void EditorDNDValuesListDataDeleteCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
        /* Function no longer used. */
      return;
}

Generated by  Doxygen 1.6.0   Back to index