Logo Search packages:      
Sourcecode: vertex version File versions

scratchpad.c

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

#include <sys/types.h>
#include <gtk/gtk.h>

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

#include "v3dmodel.h"
#include "v3dmp.h"

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

#include "editor.h"
#include "editorselect.h"
#include "editorlist.h"
#include "editorviewcb.h"
#include "editordnd.h"

#include "scratchpad.h"
#include "scratchpadcb.h"
#include "scratchpaddnd.h"

#include "vmacfg.h"
#include "vmacfglist.h"
#include "vmastyles.h"
#include "vma.h"
#include "vmautils.h"
#include "config.h"


#include "scratchpad.xpm"
#include "images/icon_close_20x20.xpm"


gchar **ScratchPadAllocRowText(
      vma_scratch_pad_struct *sp,
      mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
      gint *strc
);
void ScratchPadUpdateTargetEditors(vma_scratch_pad_struct *sp);
gint ScratchPadGetEditorIndex(
      vma_scratch_pad_struct *sp, const char *s
);
void *ScratchPadGetEditorPtr(vma_scratch_pad_struct *sp);

gint ScratchPadRowInsert(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
        const gchar *comment
);
gint ScratchPadRowAppend(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
        const gchar *comment
);
void ScratchPadRowRemove(vma_scratch_pad_struct *sp);

void ScratchPadCommentsTextFetch(
        vma_scratch_pad_struct *sp, const char *data
);
void ScratchPadCommentsTextApply(
        vma_scratch_pad_struct *sp, vma_scratch_pad_row_struct *rd
);

int ScratchPadSetVertex(
        vma_scratch_pad_struct *sp, mp_vertex_struct *v
);
int ScratchPadSetNormal(
        vma_scratch_pad_struct *sp, mp_vertex_struct *n
);
int ScratchPadSetTexCoord(
        vma_scratch_pad_struct *sp, mp_vertex_struct *tc
);
int ScratchPadSetAll(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc
);

static void ScratchPadBuildMenuBar(
        vma_scratch_pad_struct *sp, GtkWidget *parent
);

vma_scratch_pad_struct *ScratchPadNew(gpointer core_ptr);
void ScratchPadSyncData(vma_scratch_pad_struct *sp);
void ScratchPadUpdateAppearance(vma_scratch_pad_struct *sp);
void ScratchPadUpdateMenus(vma_scratch_pad_struct *sp);
void ScratchPadMap(vma_scratch_pad_struct *sp);
void ScratchPadUnmap(vma_scratch_pad_struct *sp);
void ScratchPadDelete(vma_scratch_pad_struct *sp);


/* Title (program name prefixed). */
#define SP_TITLE  ": ScratchPad"


#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)))


/*
 *    Returns on array of allocated strings suitable for setting
 *    the row text for 3 columns on a scratch pad's clist.
 *
 *    The returned strc should be a value of 3.
 */
gchar **ScratchPadAllocRowText(
      vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
        gint *strc
)
{
      gint t = 3;
      gint vertex_decimals, normal_decimals, texcoord_decimals;
      gchar **strv, *strptr;
      gchar fmt_str[256];


        if(strc != NULL)
            (*strc) = 0;

      if(sp == NULL)
          return(NULL);

      /* Allocate string array. */
      strv = (gchar **)calloc(t, sizeof(gchar *));
      if(strv == NULL)
          return(NULL);

      /* Update return. */
      if(strc != NULL)
          (*strc) = t;

      /* Get number of decimal places. */
      vertex_decimals = CLIP(sp->vertex_decimals, 0, 6);
        normal_decimals = CLIP(sp->normal_decimals, 0, 6);
        texcoord_decimals = CLIP(sp->texcoord_decimals, 0, 6);

      sprintf(
          fmt_str,
          "%%.%if, %%.%if, %%.%if",
          vertex_decimals, normal_decimals,
          texcoord_decimals
      );

      /* First string, vertex. */
      strv[0] = strptr = (gchar *)g_malloc(256 * sizeof(gchar));
      if(strptr != NULL)
      {
          if(v != NULL)
            sprintf(strptr, fmt_str, v->x, v->y, v->z);
          else
            (*strptr) = '\0';
      }

      /* Second string, normal. */
        strv[1] = strptr = (gchar *)g_malloc(256 * sizeof(gchar));
        if(strptr != NULL)
        {
            if(n != NULL)
                sprintf(strptr, fmt_str, n->x, n->y, n->z);
            else
                (*strptr) = '\0';
        }

      /* Third string texcoords. */
        strv[2] = strptr = (gchar *)g_malloc(256 * sizeof(gchar));
        if(strptr != NULL)
        {
            if(tc != NULL)
                sprintf(strptr, fmt_str, tc->x, tc->y, tc->z);
            else
                (*strptr) = '\0';
        }

      return(strv);
}


/*
 *    Updates the target_combo widget on the given
 *    scratch pad sp.
 */
void ScratchPadUpdateTargetEditors(vma_scratch_pad_struct *sp)
{
      int editor_num;
      GtkWidget *w;
      GtkCombo *combo;
      GList *glist;
      vma_core_struct *core_ptr;
      ma_editor_struct *editor_ptr;
      gchar *buf;
      gint buf_len;


      if(sp == NULL)
          return;

      core_ptr = (vma_core_struct *)sp->core_ptr;
      if(core_ptr == NULL)
          return;

      w = sp->target_combo;
      if(w == NULL)
          return;

      combo = GTK_COMBO(w);

      /* Begin creating a new list based on editors on the core
       * structure.
       */
      glist = NULL;
      for(editor_num = 0; editor_num < core_ptr->total_editors; editor_num++)
      {
          editor_ptr = core_ptr->editor[editor_num];
          if(editor_ptr == NULL)
            continue;

          buf = NULL;
          if(editor_ptr->loaded_filename == NULL)
          {
            buf_len = 256;
            buf = (gchar *)g_malloc((buf_len + 1) * sizeof(gchar));
            if(buf == NULL)
                continue;

                sprintf(
                buf,
                "Editor %i: Untitled",
                editor_num
            );
          }
          else
          {
                buf_len = 256 + strlen(editor_ptr->loaded_filename);
                buf = (gchar *)g_malloc((buf_len + 1) * sizeof(gchar));
                if(buf == NULL)
                    continue;

            sprintf(
                buf,
                "Editor %i: %s",
                editor_num,
                editor_ptr->loaded_filename
            );
          }
          if(buf == NULL)
            continue;

          glist = g_list_append(glist, strdup(buf));

          g_free(buf);
          buf = NULL;
      }

      /* Transfer our newly created glist to the combo's list. This will
       * delete the previous list on the combo and transfer our list to
       * it, so we should not referance our glist again.
       */
      GUIComboSetList(combo, glist);
      glist = NULL;

      return;
}

/*
 *    Selects the target editor on the scratch pad to the given
 *    editor, returns the editor index on success or -1 on failure.
 *
 *    Note that the list on the scratch pad's target_combo should be
 *    properly updated first with a call to 
 *    ScratchPadUpdateTargetEditors() before calling this function.
 */
gint ScratchPadSelectEditorPtr(
        vma_scratch_pad_struct *sp, void *editor_ptr
)
{
      gint i, editor_num;
      vma_core_struct *core_ptr;
      GtkWidget *w;
      GtkCombo *combo;
      GList *glist;


      if((sp == NULL) || (editor_ptr == NULL))
          return(-1);

      core_ptr = (vma_core_struct *)sp->core_ptr;
      if(core_ptr == NULL)
          return(-1);

      w = sp->target_combo;
      if(w == NULL)
          return(-1);

      combo = GTK_COMBO(w);

      /* Count to the given editor pointer, do not count NULL
       * pointers so that editor_num will be the glist index
       * on the combo's glist.
       */
      for(i = 0, editor_num = 0; i < core_ptr->total_editors; i++)
      {
          if(core_ptr->editor[i] == NULL)
            continue;

          if(core_ptr->editor[i] == editor_ptr)
            break;

          editor_num++;
      }

      /* Get glist on target_combo. */
      glist = (GList *)GUIComboGetList(combo);
      for(i = 0; glist != NULL; i++)
      {
          if(i == editor_num)
          {
            gchar *strptr = ((glist->data == NULL) ?
                NULL : strdup((const gchar *)glist->data)
            );
            gint position = 0;

            if(strptr != NULL)
            {
                gtk_entry_set_text(GTK_ENTRY(combo->entry), strptr);

                ScratchPadTargetComboTextInsertCB(
                  GTK_EDITABLE(combo->entry),
                  strptr, strlen(strptr), &position,
                  (gpointer)sp
                );

                g_free(strptr);
            }
            glist = NULL;
            break;
          }

          glist = glist->next;
      }

      return(editor_num);
}

/*
 *    Returns the editor's index based on the selected editor
 *    on the given scratch pad sp's target_combo.
 *
 *    If the string s is not NULL then it will be used to match for
 *    a matching string in the target_combo's list. If s is NULL
 *    then the value from the entry_text will be used.
 *
 *    Can return -1 on error.
 */
gint ScratchPadGetEditorIndex(
      vma_scratch_pad_struct *sp, const char *s
)
{
        int editor_num;
        GtkWidget *w;
        GtkCombo *combo;
        GList *glist;
        vma_core_struct *core_ptr;
      const gchar *entry_text;


        if(sp == NULL)
            return(-1);

        core_ptr = (vma_core_struct *)sp->core_ptr;
        if(core_ptr == NULL)
            return(-1);

        w = sp->target_combo;
        if(w == NULL)
            return(-1);

        combo = GTK_COMBO(w);

      /* No given string? */
      if(s == NULL)
      {
          /* Use string from target_combo's entry. */
          entry_text = gtk_entry_get_text(GTK_ENTRY(combo->entry));
      }
      else
      {
          entry_text = s;
      }
      if(entry_text == NULL)
          return(-1);

      glist = (GList *)GUIComboGetList(combo);
      if(glist == NULL)
          return(-1);

      for(editor_num = 0; editor_num < core_ptr->total_editors; editor_num++)
        {
          /* Skip editor pointers that are NULL, this will have the
           * editor_num index take into account NULL editor pointers.
           */
          if(core_ptr->editor[editor_num] == NULL)
            continue;

          if(glist == NULL)
            break;

          if(glist->data != NULL)
          {
            if(!strcasecmp(entry_text, (const gchar *)glist->data))
                return(editor_num);
          }

          glist = glist->next;
      }

      return(-1);
}

/*
 *    Returns the pointer to a ma_editor_struct that is the current
 *    one selected on the scratch pad or NULL for none/error.
 */
void *ScratchPadGetEditorPtr(vma_scratch_pad_struct *sp)
{
      int i;
      vma_core_struct *core_ptr;


      if(sp == NULL)
          return(NULL);

      core_ptr = (vma_core_struct *)sp->core_ptr;
        if(core_ptr == NULL)
            return(NULL);

      i = sp->editor_num;
      if((i >= 0) && (i < core_ptr->total_editors))
          return(core_ptr->editor[i]);
      else
          return(NULL);
}


/*
 *    Inserts a new row on the scratch pad's clist.
 *
 *    Returns the row index of the new row or -1 on error.
 */
gint ScratchPadRowInsert(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
      const gchar *comment
)
{
      GtkWidget *w;
      GtkCList *clist;
      vma_scratch_pad_row_struct *rd;
      gint new_row = -1;


      if(sp == NULL)
          return(new_row);

      w = sp->clist;
      if(w == NULL)
          return(new_row);

      clist = GTK_CLIST(w);

      /* Insert from beginning if nothing selected. */
      if(sp->selected_row < 0)
          sp->selected_row = 0;

      /* If selected row out of bounds, then call append function. */
      if(sp->selected_row >= clist->rows)
          return(ScratchPadRowAppend(sp, v, n, tc, comment));

      /* Allocate new row data. */
      rd = (vma_scratch_pad_row_struct *)calloc(
          1, sizeof(vma_scratch_pad_row_struct)
      );
      if(rd != NULL)
      {
          gchar **strv;
          gint strc;

          strv = ScratchPadAllocRowText(sp, v, n, tc, &strc);

          new_row = gtk_clist_insert(clist, sp->selected_row, strv);

          StringFreeArray(strv, strc);
          strv = NULL;
          strc = 0;

          /* Set up row data values. */
          rd->core_ptr = sp->core_ptr;
          rd->scratch_pad_ptr = (gpointer)sp;
          if(v != NULL)
            memcpy(&rd->v, v, sizeof(mp_vertex_struct));
            if(n != NULL)
                memcpy(&rd->n, n, sizeof(mp_vertex_struct));
            if(tc != NULL)
                memcpy(&rd->tc, tc, sizeof(mp_vertex_struct));
          if(comment != NULL)
          {
            g_free(rd->comment);
            rd->comment = strdup(comment);
          }

          /* Record row data on new clist row. */
          gtk_clist_set_row_data_full(
            clist, new_row, (gpointer)rd, ScratchPadRowDeleteCB
          );
      }

      return(new_row);
}

/*
 *    Appends a new row on the scratch pad's clist.
 *
 *      Returns the row index of the new row or -1 on error.
 */
gint ScratchPadRowAppend(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc,
      const gchar *comment
)
{
        GtkWidget *w;   
        GtkCList *clist;
        vma_scratch_pad_row_struct *rd;
        gint new_row = -1;


        if(sp == NULL)   
            return(new_row);

        w = sp->clist;
        if(w == NULL)
            return(new_row);

        clist = GTK_CLIST(w);

        /* Allocate new row data. */
        rd = (vma_scratch_pad_row_struct *)calloc(
            1, sizeof(vma_scratch_pad_row_struct)
        );
        if(rd != NULL)   
        {
            gchar **strv; 
            gint strc;

            strv = ScratchPadAllocRowText(sp, v, n, tc, &strc);

            new_row = gtk_clist_append(clist, strv);

            StringFreeArray(strv, strc);
            strv = NULL;
            strc = 0;

            /* Set up row data values. */
            rd->core_ptr = sp->core_ptr;
            rd->scratch_pad_ptr = (gpointer)sp;
            if(v != NULL)
                memcpy(&rd->v, v, sizeof(mp_vertex_struct));
            if(n != NULL)
                memcpy(&rd->n, n, sizeof(mp_vertex_struct));
            if(tc != NULL)
                memcpy(&rd->tc, tc, sizeof(mp_vertex_struct));
            if(comment != NULL)
            {
                g_free(rd->comment);
                rd->comment = strdup(comment);
            }

            /* Record row data on new clist row. */
            gtk_clist_set_row_data_full(
                clist, new_row, (gpointer)rd, ScratchPadRowDeleteCB
            );
        }

      return(new_row);
}

/*
 *    Removes the selected row on the scratch pad's clist.
 */
void ScratchPadRowRemove(vma_scratch_pad_struct *sp)
{
        GtkWidget *w;
        GtkCList *clist;


        if(sp == NULL)
            return;

        w = sp->clist;
        if(w == NULL)
            return;

        clist = GTK_CLIST(w);

      if((sp->selected_row >= 0) && (sp->selected_row <= clist->rows))
      {
          gtk_clist_remove(clist, sp->selected_row);
      }

      return;
}


/*
 *    Updates the comments text widget with the given comment string
 *    data.
 *
 *    If data is NULL then the comment string data will be fetched
 *    from the selected row data (if any).
 */
void ScratchPadCommentsTextFetch(
        vma_scratch_pad_struct *sp, const char *data
)
{
      GtkWidget *w;
      GtkText *text;
      GtkEditable *editable;
      GtkStyle *style_ptr;
      GdkFont *font;


      if(sp == NULL)
          return;

      if(!sp->initialized)
          return;

      w = sp->comments_text;
      if(w == NULL)
          return;

      text = GTK_TEXT(w);
      editable = GTK_EDITABLE(w);


        /* Clear comments text widget. */
        gtk_text_freeze(text);
        gtk_text_set_point(text, 0);
        gtk_editable_delete_text(
            editable, 0, -1
        );
      gtk_text_thaw(text);


      /* If no data is given then take data from the selected
       * row if any.
       */
      if(data == NULL)
      {
          GtkCList *clist = (GtkCList *)sp->clist;
          if(clist != NULL)
          {
            gint row = sp->selected_row;

            if((row >= 0) && (row < clist->rows))
            {
                vma_scratch_pad_row_struct *rd = (vma_scratch_pad_row_struct *)
                  gtk_clist_get_row_data(clist, row);
                if(rd != NULL)
                  data = (const gchar *)rd->comment;
            }
          }
      }

      /* Still no data? */
      if(data == NULL)
      {
          /* No data to fetch, give up. */
          return;
      }

      /* Get text style and font. */
        style_ptr = styles_list.text_editable;
        font = ((style_ptr == NULL) ? NULL : style_ptr->font);

      /* Set new comments text. */ 
      gtk_text_freeze(text);
      gtk_text_set_point(text, 0);
      gtk_text_insert(
          text, font, NULL, NULL,
          data, -1
      );
      gtk_text_thaw(text);

      return;
}

/*
 *    Applies the data in the scratch pad's comments_text widget and
 *    sets it to the given vma_scratch_pad_row_struct rd if it is not
 *    NULL.  If the given rd is NULL then the selected row on the
 *    scratch pad will be used instead.
 *
 *    On success sp->comments_text_has_changes will be set to FALSE.
 */
void ScratchPadCommentsTextApply(
      vma_scratch_pad_struct *sp, vma_scratch_pad_row_struct *rd
)
{
        GtkWidget *w;
        GtkText *text;
        GtkEditable *editable;
      gchar *data;


        if(sp == NULL)
            return;

        if(!sp->initialized)
            return;

        w = sp->comments_text;
        if(w == NULL)
            return;

        text = GTK_TEXT(w);
        editable = GTK_EDITABLE(w);


        /* If no row data is given then use the selected row. */
        if(rd == NULL)
        {
            GtkCList *clist = (GtkCList *)sp->clist;
            if(clist != NULL)
            {
                gint row = sp->selected_row;
                if((row >= 0) && (row < clist->rows))
                {
                rd = (vma_scratch_pad_row_struct *)
                        gtk_clist_get_row_data(clist, row);
                }
            }
        }
      /* Still no row data? */
      if(rd == NULL)
          return;


      /* Get data from comments_text. */
      data = gtk_editable_get_chars(
          editable, 0, -1
      );
      if(data != NULL)
      {
          /* Update comment on row data, deallocating the old one and
           * transfering the new one to it.
           */
          g_free(rd->comment);
          rd->comment = data;
          data = NULL;

          sp->comments_text_has_changes = FALSE;
      }

      return;
}

/*
 *    Gets selected target editor on the specified sp and sets its
 *    selected primitive's vertex to the specified vertex v.
 *
 *    Returns the following errors:
 *
 *    -1    General error.
 *    -2    Selected primitive on editor does not have vertices.
 *    -3    Invalid target editor.
 *    -4    No model or primitives selected on editor.
 *    -5    Editor's write protect is enabled.
 */
gint ScratchPadSetVertex(
      vma_scratch_pad_struct *sp, mp_vertex_struct *v
)
{
      ma_editor_struct *editor;
      GtkCList *values_clist;
      int model_num;
      v3d_model_struct *model_ptr;
      int pn;
      void *p;
      int tar_v_num;
      mp_vertex_struct *tar_v;
      

      if((sp == NULL) || (v == NULL))
          return(-1);

      editor = (ma_editor_struct *)ScratchPadGetEditorPtr(sp);
      if(editor == NULL)
          return(-3);

      if(VMAWriteProtectCheck(editor))
          return(-5);

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

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

      tar_v = V3DMPGetVertex(p, tar_v_num);
      if(tar_v == NULL)
          return(-2);

      memcpy(tar_v, v, sizeof(mp_vertex_struct));


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

      /* Refetch editor's values list. */
      EditorListDeleteValuesG(editor);
      EditorListAddValuesRG(editor, p);

      /* Try to reselect the last row on the editor's clist. */
      if(values_clist != NULL)
          gtk_clist_select_row(values_clist, tar_v_num, 0);
 
      /* Update editor's menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);

      return(0);
}

/*
 *      Gets selected target editor on the specified sp and sets its
 *      selected primitive's vertex's normal to the specified normal n.
 *
 *      Returns the following errors:
 *
 *      -1      General error.
 *      -2      Selected primitive on editor does not have vertices.
 *      -3      Invalid target editor.
 *      -4      No model or primitives selected on editor.
 *      -5      Editor's write protect is enabled.
 */
gint ScratchPadSetNormal(
        vma_scratch_pad_struct *sp, mp_vertex_struct *n
)
{
        ma_editor_struct *editor;
        GtkCList *values_clist;
        int model_num;
        v3d_model_struct *model_ptr;   
        int pn;
        void *p;
        int tar_n_num;
        mp_vertex_struct *tar_n;


        if((sp == NULL) || (n == NULL))
            return(-1);

        editor = (ma_editor_struct *)ScratchPadGetEditorPtr(sp);
        if(editor == NULL)
            return(-3);

        if(VMAWriteProtectCheck(editor))
            return(-5);

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

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

        tar_n_num = EditorGetSelected(
            editor->selected_value, editor->total_selected_values,
            0
        );
        if(tar_n_num < 0)
            return(-4);

        tar_n = V3DMPGetNormal(p, tar_n_num);
        if(tar_n == NULL)
            return(-2);

        memcpy(tar_n, n, sizeof(mp_vertex_struct));

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

        /* Refetch editor's values list. */
        EditorListDeleteValuesG(editor);
        EditorListAddValuesRG(editor, p);

        /* Try to reselect the last row on the editor's clist. */
        if(values_clist != NULL)
            gtk_clist_select_row(values_clist, tar_n_num, 0);

        /* Update editor's menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);

        return(0);
} 

/*
 *      Gets selected target editor on the specified sp and sets its
 *      selected primitive's vertex's texcoord to the specified texcoord tc.
 *
 *      Returns the following errors:
 *
 *      -1      General error.
 *      -2      Selected primitive on editor does not have vertices.
 *      -3      Invalid target editor.
 *      -4      No model or primitives selected on editor.
 *      -5      Editor's write protect is enabled.
 */
int ScratchPadSetTexCoord(
        vma_scratch_pad_struct *sp, mp_vertex_struct *tc
)
{
        ma_editor_struct *editor;
        GtkCList *values_clist;
        int model_num;
        v3d_model_struct *model_ptr;   
        int pn;
        void *p;
        int tar_tc_num;
        mp_vertex_struct *tar_tc;


        if((sp == NULL) || (tc == NULL))
            return(-1);

        editor = (ma_editor_struct *)ScratchPadGetEditorPtr(sp);
        if(editor == NULL)
            return(-3);

        if(VMAWriteProtectCheck(editor))
            return(-5);

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

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

        tar_tc_num = EditorGetSelected(
            editor->selected_value, editor->total_selected_values,
            0
        );
        if(tar_tc_num < 0)
            return(-4);

        tar_tc = V3DMPGetTexCoord(p, tar_tc_num);
        if(tar_tc == NULL)
            return(-2);

        memcpy(tar_tc, tc, sizeof(mp_vertex_struct));

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

        /* Refetch editor's values list. */
        EditorListDeleteValuesG(editor);
        EditorListAddValuesRG(editor, p);

        /* Try to reselect the last row on the editor's clist. */
        if(values_clist != NULL)
            gtk_clist_select_row(values_clist, tar_tc_num, 0);

        /* Update editor's menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);

        return(0);
}

/*
 *      Gets selected target editor on the specified sp and sets its
 *      selected primitive's vertex, normal, and texcoord to the specified 
 *    vertex, normal, and texcoord.
 *
 *      Returns the following errors:
 *
 *      -1      General error.
 *      -2      Selected primitive on editor does not have vertices.
 *      -3      Invalid target editor.
 *      -4      No model or primitives selected on editor.
 *      -5      Editor's write protect is enabled.
 */
int ScratchPadSetAll(
        vma_scratch_pad_struct *sp,
        mp_vertex_struct *v, mp_vertex_struct *n, mp_vertex_struct *tc
)
{
        ma_editor_struct *editor;
      GtkCList *values_clist;
        int model_num;
        v3d_model_struct *model_ptr;
        int pn;
        void *p;
        int tar_vtx_num;
        mp_vertex_struct *tar_vtx;


        if(sp == NULL)
            return(-1);   

        editor = (ma_editor_struct *)ScratchPadGetEditorPtr(sp);
        if(editor == NULL)
            return(-3);

        if(VMAWriteProtectCheck(editor))
            return(-5);

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

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

      /* Get selected value item number. */
        tar_vtx_num = EditorGetSelected(
            editor->selected_value, editor->total_selected_values,
            0
        );
        if(tar_vtx_num < 0)
            return(-4);

      /* Set vertex. */
      if(v != NULL)
      {
          tar_vtx = V3DMPGetVertex(p, tar_vtx_num);
          if(tar_vtx == NULL)
            return(-2);

            memcpy(tar_vtx, v, sizeof(mp_vertex_struct));
      }

        /* Set normal. */
        if(n != NULL)
        {
            tar_vtx = V3DMPGetNormal(p, tar_vtx_num);
            if(tar_vtx == NULL)
                return(-2);

            memcpy(tar_vtx, n, sizeof(mp_vertex_struct));
        }

        /* Set texcoord. */
        if(tc != NULL)
        {
            tar_vtx = V3DMPGetTexCoord(p, tar_vtx_num);
            if(tar_vtx == NULL)
                return(-2);

            memcpy(tar_vtx, tc, sizeof(mp_vertex_struct));
        }

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

        /* Refetch editor's values list. */
        EditorListDeleteValuesG(editor);
        EditorListAddValuesRG(editor, p);

        /* Try to reselect the last row on the editor's clist. */
        if(values_clist != NULL)
            gtk_clist_select_row(values_clist, tar_vtx_num, 0);

        /* Update editor's menus and redraw views. */
        EditorUpdateMenus(editor);
        EditorUpdateAllViewMenus(editor);
        EditorRedrawAllViews(editor);

        return(0);
}

/*
 *      Builds the menu bar and menus on to the scratch pad and parents
 *      to the given parent widget (assumed to be a handle bar).
 *
 *      Inputs assumed valid, returns non-zero on error.
 */
static void ScratchPadBuildMenuBar(
      vma_scratch_pad_struct *sp, GtkWidget *parent
)
{
        GtkWidget *menu_bar, *menu, *w, *fw;
        int accel_key;
        void *accel_group;
        unsigned int accel_mods;
        void *client_data = (void *)sp;
        u_int8_t **icon;
        char *label = NULL;
        void (*func_cb)(GtkWidget *, gpointer) = NULL;
        int (*enter_cb)(void *, void *, void *) = (void *)ScratchPadMenuItemEnterCB;


        /* Create menu bar. */
        menu_bar = (GtkWidget *)GUIMenuBarCreate(&accel_group);
        sp->menu_bar = menu_bar;
        gtk_container_add(GTK_CONTAINER(parent), menu_bar);
        gtk_widget_show(menu_bar);

#define DO_ADD_MENU_ITEM_LABEL      \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_LABEL, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  client_data, func_cb \
 ); \
 GUISetMenuItemCrossingCB( \
  w, enter_cb, client_data, NULL, client_data \
 ); \
}
#define DO_ADD_MENU_ITEM_LABEL_NO_ENTERCB \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_LABEL, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  client_data, func_cb \
 ); \
}
#define DO_ADD_MENU_ITEM_SUBMENU          \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_SUBMENU, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  client_data, func_cb \
 ); \
 if(w != NULL) \
  GUIMenuItemSetSubMenu(w, submenu); \
}
#define DO_ADD_MENU_ITEM_CHECK                  \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_CHECK, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  client_data, func_cb \
 ); \
 GUISetMenuItemCrossingCB( \
  w, enter_cb, client_data, NULL, client_data \
 ); \
}
#define DO_ADD_MENU_SEP       \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL, \
  NULL, NULL, 0, 0, NULL, \
  NULL, NULL \
 ); \
}
            
        /* Create file menu. */ 
        menu = GUIMenuCreate();
        if(menu != NULL)
        {
            icon = (u_int8_t **)icon_close_20x20_xpm;
            label = "Close";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadCloseButtonCB;
            DO_ADD_MENU_ITEM_LABEL
          sp->file_close_mi = w;
      }
        GUIMenuAddToMenuBar(
            menu_bar, menu,
            "File",
            GUI_MENU_BAR_ALIGN_LEFT
        );


        /* Create edit menu. */
        menu = GUIMenuCreate();
        if(menu != NULL)
        {
            icon = NULL;
            label = "Set Vertex";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadSetVertexCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_set_vertex_mi = w;

            icon = NULL;
            label = "Set Normal";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadSetNormalCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_set_normal_mi = w;

            icon = NULL;
            label = "Set TexCoord";
            accel_key = 0; 
            accel_mods = 0;
            func_cb = ScratchPadSetTexCoordCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_set_texcoord_mi = w;

            icon = NULL;
            label = "Set All";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadSetAllCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_set_all_mi = w;

          DO_ADD_MENU_SEP

            icon = NULL;
            label = "Insert";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadInsertCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_insert_mi = w;

            icon = NULL;
            label = "Delete";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadDeleteCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_delete_mi = w;

            DO_ADD_MENU_SEP

            icon = NULL;
            label = "Change Value...";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadEditCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->edit_edit_mi = w;
      }
        GUIMenuAddToMenuBar(
            menu_bar, menu,
            "Edit",
            GUI_MENU_BAR_ALIGN_LEFT
        );


#undef DO_ADD_MENU_ITEM_LABEL
#undef DO_ADD_MENU_ITEM_LABEL_NO_ENTERCB
#undef DO_ADD_MENU_ITEM_SUBMENU
#undef DO_ADD_MENU_ITEM_CHECK
#undef DO_ADD_MENU_SEP

        /* Attach accel group to toplevel window. */
        if((sp->toplevel != NULL) &&
           (accel_group != NULL)
        )
        {
            gtk_window_add_accel_group(
                GTK_WINDOW(sp->toplevel),
                (GtkAccelGroup *)accel_group
            );
        }

      return;
}


/*
 *    Creates a new scratch pad window.
 */
vma_scratch_pad_struct *ScratchPadNew(gpointer core_ptr)
{
        GtkWidget *w, *fw, *menu, *parent, *parent2, *parent3, *handle_box;
      GtkWidget *scroll_parent;
      gint toplevel_width, toplevel_height, clist_toplevel_height;
      gint column_width[3];
      gpointer combo_rtn;
      GtkCombo *combo;
      GtkCList *clist;
/*    gint border_major = 5; */
      gint border_minor = 2;
      gchar *heading[3];
        GtkTargetEntry dnd_type[1];

      gint accel_key;
      gpointer accel_group;
      guint accel_mods;
        gpointer client_data;
        u_int8_t **icon;
      const gchar *label = NULL;
        void (*func_cb)(GtkWidget *, gpointer) = NULL;
      gint (*enter_cb)(gpointer, gpointer, gpointer) =
          (gpointer)ScratchPadMenuItemEnterCB;
        vma_scratch_pad_struct *sp = (vma_scratch_pad_struct *)calloc(
            1, sizeof(vma_scratch_pad_struct)
        );


        if(sp == NULL)
            return(NULL);


#define DO_ADD_MENU_ITEM_LABEL      \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_LABEL, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  client_data, func_cb \
 ); \
 GUISetMenuItemCrossingCB( \
  w, enter_cb, client_data, NULL, client_data \
 ); \
}

#define DO_ADD_MENU_SEP       \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL, \
  NULL, NULL, 0, 0, NULL, \
  NULL, NULL \
 ); \
}


        /* Get previous toplevel size. */
        toplevel_width = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_WIDTH
        );
        if(toplevel_width < 1)
            toplevel_width = VMA_SCRATCHPAD_DEF_WIDTH;

        toplevel_height = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_HEIGHT
        );
        if(toplevel_height < 1)
            toplevel_height = VMA_SCRATCHPAD_DEF_HEIGHT;

      clist_toplevel_height = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_CLIST_HEIGHT
        );
        if(toplevel_height < 1)
            toplevel_height = VMA_SCRATCHPAD_DEF_HEIGHT * 0.5;

      column_width[0] = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_CH0
        );
        column_width[1] = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_CH1
        );
        column_width[2] = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_SCRATCHPAD_CH2
        );


        /* Reset values. */
        sp->initialized = TRUE;
        sp->map_state = FALSE;
      sp->core_ptr = core_ptr;

      sp->comments_text_has_changes = FALSE;

      sp->vertex_decimals = VMACFGItemListGetValueI(
          option, VMA_CFG_PARM_DATA_DECIMALS_POSITION
      );
      sp->normal_decimals = sp->vertex_decimals;
      sp->texcoord_decimals = sp->normal_decimals;

      sp->selected_column = -1;
      sp->selected_row = -1;
      sp->editor_num = -1;


      /* Get cursors. */
        sp->text_cur = gdk_cursor_new(GDK_XTERM);


        /* Toplevel. */
        sp->toplevel = w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_widget_add_events(
          w,
            GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_press_event",
            GTK_SIGNAL_FUNC(ScratchPadEventCB),
            (gpointer)sp
        );
        gtk_signal_connect(  
            GTK_OBJECT(w), "key_release_event",
            GTK_SIGNAL_FUNC(ScratchPadEventCB),
            (gpointer)sp
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "configure_event",
            GTK_SIGNAL_FUNC(ScratchPadEventCB),
            (gpointer)sp
        );

        gtk_widget_realize(w);
        GUISetWMIcon(w->window, (u_int8_t **)scratchpad_xpm);
        gtk_widget_set_usize(
            w, toplevel_width, toplevel_height
        );
        gtk_window_set_policy(
            GTK_WINDOW(w),
            TRUE, TRUE, FALSE
        );
        if(!GTK_WIDGET_NO_WINDOW(w))
        {
            GdkGeometry geometry;

            geometry.min_width = 100;
            geometry.min_height = 70;

            geometry.base_width = 0;
            geometry.base_height = 0;

            geometry.width_inc = 1;
            geometry.height_inc = 1;
/*
            geometry.min_aspect = 1.3;
            geometry.max_aspect = 1.3;
 */
            gdk_window_set_geometry_hints(
                w->window,
                &geometry, 
                GDK_HINT_MIN_SIZE |
                GDK_HINT_BASE_SIZE |
                /* GDK_HINT_ASPECT | */
                GDK_HINT_RESIZE_INC
            );
        }
/*
        gdk_window_set_decorations(
          w->window,
            GDK_DECOR_TITLE |
            GDK_DECOR_MENU |
            GDK_DECOR_MINIMIZE
        );
        gdk_window_set_functions(
          w->window,
            GDK_FUNC_MOVE |
            GDK_FUNC_MINIMIZE |   
            GDK_FUNC_CLOSE
        );
 */     
        gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(ScratchPadCloseCB),
            (gpointer)sp
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(ScratchPadDestroyCB),
            (gpointer)sp
        );
        gtk_window_set_title(GTK_WINDOW(w), PROG_NAME SP_TITLE);
        gtk_container_set_border_width(GTK_CONTAINER(w), 0);
        parent = w;

        /* Main vbox. */
        w = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(parent), w);
        gtk_container_set_border_width(GTK_CONTAINER(w), 0);
        gtk_widget_show(w);
        parent = w;


      /* Build menu, first creating a handle box to place it in. */
        handle_box = gtk_handle_box_new();
        gtk_box_pack_start(GTK_BOX(parent), handle_box, FALSE, FALSE, 0);
/*
        GTK_HANDLE_BOX(handle_box)->shrink_on_detach = 0;
 */
        gtk_widget_show(handle_box);
        ScratchPadBuildMenuBar(sp, handle_box);


      /* Hbox to hold combo box. */
      w = gtk_hbox_new(FALSE, border_minor);
      gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
      gtk_container_set_border_width(GTK_CONTAINER(w), border_minor);
      gtk_widget_show(w);
        parent2 = w;

        /* Target editor combo. */
        w = (GtkWidget *)GUIComboCreate(
            NULL,       /* No label. */
            "Default",        /* Initial value. */
            NULL,       /* Initial glist. */
            16,                 /* Max items, 16 should be enough. */
            &combo_rtn,
            (void *)sp,         /* Client data. */
            NULL,               /* Don't need callbacks. */
            NULL
        );
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        sp->target_combo = w = (GtkWidget *)combo_rtn;
        combo = GTK_COMBO(w);
/*    gtk_widget_set_usize(w, 400, -1); */
        gtk_entry_set_editable(GTK_ENTRY(combo->entry), FALSE);
        gtk_combo_set_case_sensitive(combo, TRUE);
        gtk_signal_connect(
            GTK_OBJECT(combo->entry), "insert_text",
            GTK_SIGNAL_FUNC(ScratchPadTargetComboTextInsertCB),
            (gpointer)sp
        );
        gtk_signal_connect(
            GTK_OBJECT(combo->button), "enter",
            GTK_SIGNAL_FUNC(ScratchPadTargetComboButtonEnterCB),
            (gpointer)sp
        );

        /* Paned to hold clist and comments text. */
        w = gtk_vpaned_new();
        gtk_paned_set_handle_size(GTK_PANED(w), VMA_DEF_PANED_HANDLE_SIZE);
        gtk_paned_set_gutter_size(GTK_PANED(w), VMA_DEF_PANED_GUTTER_SIZE);
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
      parent2 = w;   


      /* Hbox to hold clist. */
        sp->clist_toplevel = w = gtk_hbox_new(FALSE, border_minor);
      gtk_paned_add1(GTK_PANED(parent2), w);
        gtk_container_set_border_width(GTK_CONTAINER(w), border_minor);
      gtk_widget_set_usize(w, -1, clist_toplevel_height);
        gtk_widget_show(w);
        parent3 = w;

      /* Scrolled window for clist. */
        w = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(
            GTK_SCROLLED_WINDOW(w),
            GTK_POLICY_AUTOMATIC,
            GTK_POLICY_AUTOMATIC
        );
      gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
      scroll_parent = w;

      /* Clist. */
      heading[0] = g_strdup("Vertex");
      heading[1] = g_strdup("Normal");
      heading[2] = g_strdup("TexCoord");
        sp->clist = w = gtk_clist_new_with_titles(3, heading);
      g_free(heading[0]);
        g_free(heading[1]);
        g_free(heading[2]);
        if(!GTK_WIDGET_NO_WINDOW(w))
        {
            /* Tie to button press callback (for mapping menu). */
            gtk_widget_add_events(
                w,
                GDK_BUTTON_PRESS_MASK
            );
            gtk_signal_connect(
                GTK_OBJECT(w), "button_press_event",
                GTK_SIGNAL_FUNC(ScratchPadMenuMapCB),
                (gpointer)sp
            );
        }
      clist = GTK_CLIST(w);
/*    gtk_widget_set_usize(w, -1, panel_models_list_size); */
        gtk_clist_column_titles_passive(clist);
        gtk_clist_set_selection_mode(clist, GTK_SELECTION_SINGLE);
        gtk_clist_set_row_height(clist, VMA_LIST_ROW_SPACING);
        gtk_container_add(GTK_CONTAINER(scroll_parent), w);
        gtk_clist_set_column_justification(
            clist, 0, GTK_JUSTIFY_LEFT
        );
      gtk_clist_set_column_width(
          clist, 0, column_width[0]
      );
        gtk_clist_set_column_justification(
            clist, 1, GTK_JUSTIFY_LEFT
        );
        gtk_clist_set_column_width(
            clist, 1, column_width[1]
        );
        gtk_clist_set_column_justification(
            clist, 2, GTK_JUSTIFY_LEFT
        );
        gtk_clist_set_shadow_type(GTK_CLIST(w), GTK_SHADOW_IN);
        gtk_signal_connect(
            GTK_OBJECT(w), "select_row",
            GTK_SIGNAL_FUNC(ScratchPadCListSelectCB),
            (gpointer)sp
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "unselect_row",
            GTK_SIGNAL_FUNC(ScratchPadCListUnselectCB),
            (gpointer)sp
        );
        /* Set up DND for the clist, it can send and recieve set vertex
         * command strings.
         */
        dnd_type[0].target = EDITOR_DND_TYPE_VALUES_SET_CMD;
        dnd_type[0].flags = GTK_TARGET_SAME_APP;
        dnd_type[0].info = 12345;               /* Ignored. */
        GUIDNDSetSrc(
            w,
            &dnd_type, 1,                       /* DND target types. */
            GDK_ACTION_COPY | GDK_ACTION_MOVE,  /* Actions. */
            GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,/* Buttons. */
            NULL,
            ScratchPadDNDDataRequestCB,
            ScratchPadDNDDataDeleteCB,
            NULL,
            sp
        );
        dnd_type[0].target = EDITOR_DND_TYPE_VALUES_SET_CMD;
        dnd_type[0].flags = GTK_TARGET_SAME_APP;
        dnd_type[0].info = 12345;               /* Ignored. */
        GUIDNDSetTar(
            w,
            &dnd_type, 1,                       /* DND target types. */
            GDK_ACTION_COPY | GDK_ACTION_MOVE,  /* Actions. */
            GDK_ACTION_MOVE,                    /* Default action if same. */
            GDK_ACTION_COPY,                    /* Default action. */
            ScratchPadDNDDataRecievedCB,
            sp
        );
      gtk_widget_show(w);


      /* Clist menu. */
      accel_group = NULL;
      client_data = (void *)sp;
        sp->clist_menu = menu = GUIMenuCreate();
        if(menu != NULL)
        {
            icon = NULL;
            label = "Set Vertex";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadSetVertexCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_set_vertex_mi = w;

            icon = NULL;
            label = "Set Normal";
            accel_key = 0;   
            accel_mods = 0;
            func_cb = ScratchPadSetNormalCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_set_normal_mi = w;
            
            icon = NULL;
          label = "Set TexCoord";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadSetTexCoordCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_set_texcoord_mi = w;

            icon = NULL;
            label = "Set All";   
            accel_key = 0;
            accel_mods = 0; 
            func_cb = ScratchPadSetAllCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_set_all_mi = w;

            DO_ADD_MENU_SEP

            icon = NULL;
            label = "Insert";
            accel_key = 0;
            accel_mods = 0;  
            func_cb = ScratchPadInsertCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_insert_mi = w;

            icon = NULL;
            label = "Delete";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadDeleteCB;
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_delete_mi = w;
         
            DO_ADD_MENU_SEP

            icon = NULL;
            label = "Change Value...";
            accel_key = 0;
            accel_mods = 0;
            func_cb = ScratchPadEditCB;  
            DO_ADD_MENU_ITEM_LABEL
            sp->clist_edit_mi = w;
        }


        /* ********************************************************** */
        /* Hbox for table which will hold text widget. */
        w = gtk_hbox_new(FALSE, 0);
      gtk_paned_add2(GTK_PANED(parent2), w);
        gtk_widget_show(w);
        parent3 = w;

        /* Table for text and scroll bar widgets. */
        w = gtk_table_new(2, 2, FALSE);
        gtk_table_set_row_spacing(GTK_TABLE(w), 0, 2);
        gtk_table_set_col_spacing(GTK_TABLE(w), 0, 2);
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 2);
        gtk_widget_show(w);
        parent3 = w;

        sp->comments_text = w = gtk_text_new(NULL, NULL);
        /* Need to connect button_press_event signal_after just
         * after text widget is created, this is so that the right
         * click menu can be mapped properly.
         */
/*
        gtk_signal_connect_after(
            GTK_OBJECT(w), "button_press_event",
            GTK_SIGNAL_FUNC(EditorTDialogMenuMapCB),
            (gpointer)d
        );
        gtk_signal_connect_after(
            GTK_OBJECT(w), "key_press_event",
            GTK_SIGNAL_FUNC(EditorTDialogKeyEventCB),
            (gpointer)d
        );
 */
        gtk_text_set_editable(GTK_TEXT(w), TRUE);
        gtk_text_set_word_wrap(GTK_TEXT(w), TRUE);
        gtk_table_attach(
            GTK_TABLE(parent3), w,
            0, 1, 0, 1,
            GTK_EXPAND | GTK_SHRINK | GTK_FILL,
            GTK_EXPAND | GTK_SHRINK | GTK_FILL,
            0, 0
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "changed",
            GTK_SIGNAL_FUNC(ScratchPadTextChangeCB),
            (gpointer)sp
        );
        gtk_widget_realize(w);
        if(sp->text_cur != NULL)
            gdk_window_set_cursor(w->window, sp->text_cur);
        gtk_widget_show(w);

        scroll_parent = gtk_vscrollbar_new(GTK_TEXT(w)->vadj);
        gtk_table_attach(
            GTK_TABLE(parent3), scroll_parent,
            1, 2, 0, 1,
            GTK_FILL,
            GTK_EXPAND | GTK_SHRINK | GTK_FILL,
            0, 0
        );
        gtk_widget_show(scroll_parent);




      /* Update editor listing on targets combo. */
      ScratchPadUpdateTargetEditors(sp);

      /* Update apperance and menus. */
      ScratchPadUpdateAppearance(sp);

      return(sp);
}


/*
 *    Syncs all data on the given scratch pad.
 *
 *    Changed values in the widgets will be applied to the clist's
 *    row datas as needed.
 */
void ScratchPadSyncData(vma_scratch_pad_struct *sp)
{
      GtkCList *clist;

        if(sp == NULL)
            return;

        if(!sp->initialized)
            return;

      clist = (GtkCList *)sp->clist;
      if(clist != NULL)
      {
          gint row = sp->selected_row;
          if((row >= 0) && (row < clist->rows))
          {
            /* Got selected row, now apply data from widgets to the
             * selected row.
             */
            vma_scratch_pad_row_struct *rd = gtk_clist_get_row_data(
                clist, row
            );
            if(rd != NULL)
            {
                /* Got selected row, now apply data from widgets to
                 * the selected row.
                 */

                /* Comments. */
                if(sp->comments_text_has_changes)
                  ScratchPadCommentsTextApply(sp, rd);

            }
          }
      }

        return;
}


/*
 *    Updates appearance values on the given scratch pad.
 *
 *    This should be called whenever the global configuration has
 *    changed.
 */
void ScratchPadUpdateAppearance(vma_scratch_pad_struct *sp)
{
        static gbool reenterant = FALSE;
        GtkWidget *w;


        if(sp == NULL)
            return;

        if(!sp->initialized)
            return;

        if(reenterant)
            return;
        else
            reenterant = TRUE;


      /* Update text widget text style. */
      w = sp->comments_text;
      if(w != NULL)
      {
          const gchar *font_name = VMACFGItemListGetValueS(
            option, VMA_CFG_PARM_FONT_NAME_EDITABLE
          );
          GtkRcStyle *rcstyle = gtk_rc_style_new();
          if(font_name != NULL)
          {
            g_free(rcstyle->font_name);
            rcstyle->font_name = g_strdup(font_name);
          }

          gtk_widget_modify_style(w, rcstyle);

          GUIRCStyleDeallocUnref(rcstyle);
      }


      /* Update resolution. */
      sp->vertex_decimals = VMACFGItemListGetValueI(
          option, VMA_CFG_PARM_DATA_DECIMALS_POSITION
      );
      sp->normal_decimals = sp->vertex_decimals;
      sp->texcoord_decimals = sp->normal_decimals;


      /* Update menus. */
        ScratchPadUpdateMenus(sp);

      reenterant = FALSE;
      return;
}

/*
 *    Updates menus on the given scratch pad.
 */
void ScratchPadUpdateMenus(vma_scratch_pad_struct *sp)
{
        static gbool reenterant = FALSE;
        gbool sensitivity;
        gint selected_row;
        GtkWidget *w;
        int toolbar_btn_layout = 2;


      if(sp == NULL)
          return;

      if(!sp->initialized)
          return;

        if(reenterant)
            return;
        else
            reenterant = TRUE;

        /* Get toolbar button style. */
        toolbar_btn_layout = VMACFGItemListGetValueI(
            option, VMA_CFG_PARM_TOOLBAR_STYLE
        );

      /* Get selected row. */
      selected_row = sp->selected_row;


#define SET_WIDGET_SENSITIVITY            \
{ \
 if(w != NULL) \
  gtk_widget_set_sensitive(w, sensitivity); \
}

#define SET_CHECK_MENU_ITEM_STATE   \
{ \
 if(w != NULL) \
  GTK_CHECK_MENU_ITEM(w)->active = state; \
}

#define SET_BUTTON_LAYOUT           \
{ \
 if(w != NULL) \
 { \
  switch(toolbar_btn_layout) \
  { \
   case 2: \
    GUIButtonChangeLayout(w, 1, 1); \
    gtk_widget_set_usize(w, 60, 50); \
    break; \
   case 1: \
    GUIButtonChangeLayout(w, 1, 0); \
    gtk_widget_set_usize(w, 30, 30); \
    break; \
   default: \
    GUIButtonChangeLayout(w, 0, 1); \
    gtk_widget_set_usize(w, -1, 30); \
    break; \
  } \
 } \
}

      sensitivity = ((selected_row > -1) ? TRUE : FALSE);
      w = sp->edit_set_vertex_mi;
      SET_WIDGET_SENSITIVITY
        w = sp->edit_set_normal_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->edit_set_texcoord_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->edit_set_all_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->edit_delete_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->edit_edit_mi;
        SET_WIDGET_SENSITIVITY

        w = sp->clist_set_vertex_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->clist_set_normal_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->clist_set_texcoord_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->clist_set_all_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->clist_delete_mi;
        SET_WIDGET_SENSITIVITY
        w = sp->clist_edit_mi;
        SET_WIDGET_SENSITIVITY


#undef SET_WIDGET_SENSITIVITY
#undef SET_CHECK_MENU_ITEM_STATE
#undef SET_BUTTON_LAYOUT

      reenterant = FALSE;
      return;
}

/*
 *    Maps the given scratch pad sp.
 */
void ScratchPadMap(vma_scratch_pad_struct *sp)
{
      GtkWidget *w;

      if(sp == NULL)
          return;

      if(!sp->map_state)
      {
          w = sp->toplevel;
          if(w != NULL)
            gtk_widget_show(w);

          sp->map_state = TRUE;
      }
}

/*
 *    Unmaps the given scratch pad sp.
 */
void ScratchPadUnmap(vma_scratch_pad_struct *sp)
{
        GtkWidget *w;

        if(sp == NULL)
            return;

        if(sp->map_state)
        {
            w = sp->toplevel;
            if(w != NULL)
                gtk_widget_hide(w);

            sp->map_state = FALSE;
        }
}

/*
 *    Deletes the given scratch pad sp.
 */
void ScratchPadDelete(vma_scratch_pad_struct *sp)
{
      GdkCursor **cur;
      GtkWidget **w;


      if(sp == NULL)
          return;

      if(sp->initialized)
      {
#define DO_DESTROY_CURSOR     \
{ \
 if((*cur) != NULL) \
 { \
  GdkCursor *tc = *cur; \
  (*cur) = NULL; \
  gdk_cursor_destroy(tc); \
 } \
}

#define DO_DESTROY_WIDGET     \
{ \
 if((*w) != NULL) \
 { \
  GtkWidget *tmp_w = *w; \
  (*w) = NULL; \
  gtk_widget_destroy(tmp_w); \
 } \
}


          /* Begin destroying widgets. */

          w = &sp->clist_menu;
            sp->clist_set_normal_mi = NULL;
            sp->clist_set_texcoord_mi = NULL;
            sp->clist_set_all_mi = NULL;
            sp->clist_insert_mi = NULL;
            sp->clist_delete_mi = NULL;
            sp->clist_edit_mi = NULL;
          DO_DESTROY_WIDGET

          w = &sp->menu_bar;
          DO_DESTROY_WIDGET

            w = &sp->target_combo;
            DO_DESTROY_WIDGET

          w = &sp->clist;
          DO_DESTROY_WIDGET

          w = &sp->comments_text;
          DO_DESTROY_WIDGET

          w = &sp->toplevel;
          DO_DESTROY_WIDGET


          cur = &sp->text_cur;
          DO_DESTROY_CURSOR

#undef DO_DESTROY_CURSOR
#undef DO_DESTROY_WIDGET
      }

      /* Deallocate structure itself. */
      g_free(sp);
}


Generated by  Doxygen 1.6.0   Back to index