next up previous contents index
Next: The Rotate Setup-Method Up: Project Rotate Previous: Project Rotate

A New User-Interface

 

As explained in section 5.5.8 most problems of the Rot2d interface created with the method "get-editor" result from binding the rulers to a fixed instance. Since we can only edit one instance at a time it would be sufficient to create one set of rulers for all Rot2d instances and to update the instance they point to -- as the coordinate rulers variables are updated when the current point is changed.

We will place all rulers and buttons in a group to make editing easier. If the current instance is of class Rot2d we bind all rulers to this instance and activate the group, if no Rot2d instance is available we just deactivate the group so that the rulers cannot be used accidentally.

We don't have to change "update-point", but we need a method to update the other rulers and to activate or deactivate the group. Since there is no special instance the method should be sent to "update-editor" is a class method:

/*
 * This time we make all rulers global. This is no problem because
 * only one interface all instances of class Rot2d is created.
 */

static GROUP *editor = NULL;
static RULER *current, *xpos, *ypos, *zpos, *angle, *discr;


CLASS *rot2d_update_editor(INSTANCE *inst)
{
  CLASS *self;
  ROT2D *rot;

  self = (CLASS *)START_METHOD(G_CLASS);
  ASSURE(self, "", END_METHOD(NULL));

  /*
   * No editor -> no update.
   */
  if(!editor)
    END_METHOD(NULL);

  /*
   * We have to make sure that the instance that was passed to this
   * method has class Rot2d (or a subclass) before we can bind the
   * rulers to it. Of course we need a curve.
   */
  if(g_has_superclass(inst, Rot2d) && (rot = (ROT2D *)inst)->curve) {
    /*
     * The method of the current ruler was already set to "update-point"
     * when it was created, now we can set the instance. Additionally
     * we limit the ruler and give it a suitable scaling.
     */
    GRAPE(current, "set-instance")(rot);
    GRAPE(current, "set-variable")(&rot->current);
    GRAPE(current, "set-min-max")
      (0.0, (double)rot->curve->number_of_points - 1.0);
    GRAPE(current, "set-scale")((double)rot->curve->number_of_points - 1.0);
    GRAPE(current, "set-offset")(0.0);

    /*
     * We may have changed the current value by hand,
     * therefore we have to update the coordinate rulers.
     */
    GRAPE(rot, "update-point")();

    /*
     * Also set the variable for angle and discretization.
     */
    GRAPE(angle, "set-variable")(&rot->angle);
    GRAPE(discr, "set-variable")(&rot->discr);

    /*
     * Finally we change the label of the group to
     * the instance's name and activate it.
     */
    GRAPE(editor, "set-label")(rot->name);
    GRAPE(editor, "set")(ACTIVE);
  } else {
    /*
     * We didn't get a Rot2d, therefore we have no instance to edit.
     * The label is set accordingly and the group is deactivated.
     */
    GRAPE(editor, "set-label")("No Object");
    GRAPE(editor, "set")(INACTIVE);
  }

  END_METHOD(self);
}

As you can see there are some more problems fixed now. The current ruler is limited, its layout is adapted to the curve's number of points. The editor group gets the instance's name as label, this will help distinguishing instances if we have more than one (and they have different names).

Now here is the new "get-editor" method. It is a class method, too, since we create only one interface for the Rot2d class. It places the rulers and buttons in a group that is returned. The items are not added to the manager this time, this is left to the calling program which will add the group to the project instead of the manager. For creating the item the new_item function (see section 5.5.3) is used. Button and ruler sizes are relative to the group size, therefore we don't have to calculate them explicitly:

GROUP *rot2d_get_editor()
{
  CLASS *self;
  static int ctmp = 0, dtmp = 0.0;
  static double xtmp = 0.0, ytmp = 0.0, ztmp = 0.0;
  static double atmp = 0.0;

  /*
   * Now "get-editor" is a class method, because it only depends
   * on class Rot2d and not on a specific instance of this class.
   */
  self = (CLASS *)START_METHOD(G_CLASS);
  ASSURE(self, "", END_METHOD(NULL));

  /*
   * The editor is created once. If "get-editor" is called again,
   * only the already created editor is returned.
   */
  if(!editor) {
    /*
     * We use new_item to create rulers and buttons, this allows
     * to specify methods, instances, sizes and so on with one call.
     * Because the method is called on the class we have no instance
     * to bind the rulers to, therefore we need dummy variables at
     * the moment. Later the rulers will be bound to the real instance
     * variables by "update-editor". The current ruler again gets
     * the method "update-point" to update the coordinate rulers if
     * the current point is changed. The ruler sizes are set to
     * MENU_MAX_SIZE because they are put into a group.
     */
    current = (RULER *)new_item(Ruler, I_Name, "point", I_Var, &ctmp, dfInt,
                                I_Method, "update-point", I_RSizeX, 1.0, I_End);
    xpos = (RULER *)new_item(Ruler, I_Name, "x pos", I_Var, &xtmp, dfDouble,
                             I_RSizeX, 1.0, I_End);
    ypos = (RULER *)new_item(Ruler, I_Name, "y pos", I_Var, &ytmp, dfDouble,
                             I_RSizeX, 1.0, I_End);
    zpos = (RULER *)new_item(Ruler, I_Name, "z pos", I_Var, &ztmp, dfDouble,
                             I_RSizeX, 1.0, I_End);
    /*
     * Because the angle should be in [0, 360] we limit the ruler to
     * this interval. 0 will be at the left side, 360 at the right side
     * of the ruler, it will be decremented/incremented when the arrow
     * buttons are pressed.
     */
    angle = (RULER *)new_item(Ruler, I_Name, "angle", I_Var, &atmp, dfDouble,
                              I_RSizeX, 1.0, I_MinMax, 0.0, 360.0,
                              I_Offset, 0.0, I_Scale, 360.0,
                              I_StepSize, 10.0, I_End);
    /*
     * The discretization ruler gets suitable default settings, too.
     */
    discr = (RULER *)new_item(Ruler, I_Name, "discr", I_Var, &dtmp, dfInt,
                              I_RSizeX, 1.0, I_Min, 1.0, I_Scale, 25.0,
                              I_Offset, 1.0, I_StepSize, 1.0, I_End),
    /*
     * Now we put the rulers and buttons into a group. The titel of the
     * group will be the name of the Rot2d instance we are editing.
     * The suffix "-send" was added to "insert-point" and "delete-point"
     * to avoid problems with the same methods on Triang1d.
     */
    editor = (GROUP *)
      new_item(Group, I_Size, 12.0, 8.0 + 1.25, I_Border, bfBorder|bfTitle,
               I_Item, new_item(Button, I_Method, "rotate-send",
                                I_Label, "rotate", I_RSizeX, 0.5, I_End),
               I_Item, new_item(Button, I_Method, "reset",
                                I_RSizeX, 0.5, I_End),
               I_Item, new_item(Button, I_Method, "insert-point-send",
                                I_Label, "insert-point", I_RSizeX, 0.5, I_End),
               I_Item, new_item(Button, I_Method, "delete-point-send",
                                I_Label, "delete-point", I_RSizeX, 0.5, I_End),
               I_Item, discr, I_Item, angle, I_Item, zpos,
               I_Item, ypos, I_Item, xpos, I_Item, current,
               I_End);
  }

  /*
   * We don't add the editor to the manager, this can
   * be done by the method that called "get-editor".
   */
  END_METHOD(editor);
}

Now all rulers have a decent layout. Unfortunately we don't have an instance to bind the rulers to, because "get-editor" is a class method. Rulers cannot be created without a variable therefore we use temporary variables for the moment, the rulers will be bound to a real instance by "update-editor" later.


next up previous contents index
Next: The Rotate Setup-Method Up: Project Rotate Previous: Project Rotate

SFB 256 Universität Bonn and IAM Universität Freiburg

Copyright © by the Sonderforschungsbereich 256 at the Institut für Angewandte Mathematik, Universität Bonn.