Exemplo n.º 1
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
gint
x_event_motion (GschemPageView *page_view, GdkEventMotion *event, GschemToplevel *w_current)
{
  PAGE *page = gschem_page_view_get_page (page_view);
  int w_x, w_y;
  int unsnapped_wx, unsnapped_wy;
  int skip_event=0;
  GdkEvent *test_event;

  g_return_val_if_fail ((w_current != NULL), 0);

  if (page == NULL) {
    return TRUE; /* terminate event */
  }

  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;

#if DEBUG
  /*  printf("MOTION!\n");*/
#endif

#ifdef HAVE_LIBSTROKE
  if (DOING_STROKE == TRUE) {
    x_stroke_record (w_current, event->x, event->y);
    return(0);
  }
#endif /* HAVE_LIBSTROKE */

  /* skip the moving event if there are other moving events in the
     gdk event queue (Werner)
     Only skip the event if is the same event and no buttons or modifier
     keys changed*/
  if ((test_event = gdk_event_get()) != NULL) {
    if (test_event->type == GDK_MOTION_NOTIFY
        && ((GdkEventMotion *) test_event)->state == event->state) {
      skip_event= 1;
    }
    gdk_event_put(test_event); /* put it back in front of the queue */
    gdk_event_free(test_event);
    if (skip_event == 1)
      return 0;
  }

  gschem_page_view_SCREENtoWORLD (page_view, (int) event->x, (int) event->y,
                                  &unsnapped_wx, &unsnapped_wy);
  w_x = snap_grid (w_current, unsnapped_wx);
  w_y = snap_grid (w_current, unsnapped_wy);

  if (w_current->cowindow) {
    coord_display_update(w_current, (int) event->x, (int) event->y);
  }

  gschem_page_view_pan_motion (page_view, w_current->mousepan_gain, (int) event->x, (int) event->y);

  /* Huge switch statement to evaluate state transitions. Jump to
   * end_motion label to escape the state evaluation rather
   * than returning from the function directly. */
  scm_dynwind_begin ((scm_t_dynwind_flags) 0);
  g_dynwind_window (w_current);

  if (w_current->inside_action) {
    if (page->place_list != NULL) {
      switch(w_current->event_state) {
        case (COPYMODE)   :
        case (MCOPYMODE)  :
        case (COMPMODE)   :
        case (PASTEMODE)  :
        case (TEXTMODE)   : o_place_motion (w_current, w_x, w_y); break;
        case (MOVEMODE)   : o_move_motion (w_current, w_x, w_y); break;
        default: break;
      }
    } else {
      switch(w_current->event_state) {
        case (ARCMODE)    : o_arc_motion (w_current, w_x, w_y, ARC_RADIUS); break;
        case (BOXMODE)    : o_box_motion  (w_current, w_x, w_y); break;
        case (BUSMODE)    : o_bus_motion (w_current, w_x, w_y); break;
        case (CIRCLEMODE) : o_circle_motion (w_current, w_x, w_y); break;
        case (LINEMODE)   : o_line_motion (w_current, w_x, w_y); break;
        case (NETMODE)    : o_net_motion (w_current, w_x, w_y); break;
        case (PATHMODE)   : o_path_motion (w_current, w_x, w_y); break;
        case (PICTUREMODE): o_picture_motion (w_current, w_x, w_y); break;
        case (PINMODE)    : o_pin_motion (w_current, w_x, w_y); break;
        case (GRIPS)      : o_grips_motion(w_current, w_x, w_y); break;
        case (SBOX)       : o_select_box_motion (w_current, unsnapped_wx, unsnapped_wy); break;
        case (ZOOMBOX)    : a_zoom_box_motion (w_current, unsnapped_wx, unsnapped_wy); break;
        case (SELECT)     : o_select_motion (w_current, w_x, w_y); break;
        default: break;
      }
    }
  } else {
    switch(w_current->event_state) {
      case(NETMODE)    :   o_net_start_magnetic(w_current, w_x, w_y); break;
      default: break;
    }
  }

  scm_dynwind_end ();

  return(0);
}
Exemplo n.º 2
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
int o_net_add_busrippers(GschemToplevel *w_current, OBJECT *net_obj,
                         GList *prev_conn_objects)

{
  OBJECT *new_obj;
  GList *cl_current = NULL;
  OBJECT *bus_object = NULL;
  CONN *found_conn = NULL;
  int done;
  int otherone;
  BUS_RIPPER rippers[2];
  int ripper_count = 0;
  int i;
  double length;
  int sign;
  double distance1, distance2;
  int first, second;
  int made_changes = FALSE;
  const int ripper_size = w_current->bus_ripper_size;
  int complex_angle = 0;
  const CLibSymbol *rippersym = NULL;

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_val_if_fail (page_view != NULL, FALSE);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_val_if_fail (page != NULL, FALSE);

  length = o_line_length(net_obj);

  if (!prev_conn_objects) {
    return(FALSE);
  }

  if (length <= ripper_size) {
    return(FALSE);
  }

  /* check for a bus connection and draw rippers if so */
  cl_current = prev_conn_objects;
  while (cl_current != NULL) {

    bus_object = (OBJECT *) cl_current->data;
    if (bus_object && bus_object->type == OBJ_BUS) {
      /* yes, using the net routine is okay */
      int bus_orientation = o_net_orientation(bus_object);
      int net_orientation = o_net_orientation(net_obj);

      /* find the CONN structure which is associated with this object */
      GList *cl_current2 = net_obj->conn_list;
      done = FALSE;
      while (cl_current2 != NULL && !done) {
	CONN *tmp_conn = (CONN *) cl_current2->data;

	if (tmp_conn && tmp_conn->other_object &&
	    tmp_conn->other_object == bus_object) {

	  found_conn = tmp_conn;
	  done = TRUE;
	}

	cl_current2 = g_list_next(cl_current2);
      }

      if (!found_conn) {
        return(FALSE);
      }

      otherone = !found_conn->whichone;

      /* now deal with the found connection */
      if (bus_orientation == HORIZONTAL && net_orientation == VERTICAL) {
	/* printf("found horiz bus %s %d!\n", bus_object->name,
           found_conn->whichone);*/

        sign = bus_object->bus_ripper_direction;
        if (!sign) {
          if (bus_object->line->x[0] < bus_object->line->x[1]) {
            first = 0;
            second = 1;
          } else {
            first = 1;
            second = 0;
          }

          distance1 = abs(bus_object->line->x[first] -
                          net_obj->line->x[found_conn->whichone]);
          distance2 = abs(bus_object->line->x[second] -
                          net_obj->line->x[found_conn->whichone]);

          if (distance1 <= distance2) {
            sign = 1;
          } else {
            sign = -1;
          }
          bus_object->bus_ripper_direction = sign;
        }
        /* printf("hor sign: %d\n", sign); */

        if (net_obj->line->y[otherone] < bus_object->line->y[0]) {
          /* new net is below bus */
          /*printf("below\n");*/

          if (ripper_count >= 2) {
            /* try to exit gracefully */
            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
            made_changes = FALSE;
            break;
          }

          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
            /* non-symmetric */
            if (sign == 1) {
              complex_angle = 0;
            } else {
              complex_angle = 90;
            }
          } else {
            /* symmetric */
            complex_angle = 0;
          }

          net_obj->line->y[found_conn->whichone] -= ripper_size;
          net_obj->w_bounds_valid_for = NULL;
          rippers[ripper_count].x[0] =
            net_obj->line->x[found_conn->whichone];
          rippers[ripper_count].y[0] =
            net_obj->line->y[found_conn->whichone];
          rippers[ripper_count].x[1] =
            net_obj->line->x[found_conn->whichone] + sign*ripper_size;
          rippers[ripper_count].y[1] =
            net_obj->line->y[found_conn->whichone] + ripper_size;
          ripper_count++;
          /* printf("done\n"); */
          made_changes++;

        } else {
          /* new net is above bus */
          /* printf("above\n"); */

          if (ripper_count >= 2) {
            /* try to exit gracefully */
            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
            made_changes = FALSE;
            break;
          }

          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
            /* non-symmetric */
            if (sign == 1) {
              complex_angle = 270;
            } else {
              complex_angle = 180;
            }
          } else {
            /* symmetric */
            complex_angle = 180;
          }

          net_obj->line->y[found_conn->whichone] += ripper_size;
          net_obj->w_bounds_valid_for = NULL;
          rippers[ripper_count].x[0] =
            net_obj->line->x[found_conn->whichone];
          rippers[ripper_count].y[0] =
            net_obj->line->y[found_conn->whichone];
          rippers[ripper_count].x[1] =
            net_obj->line->x[found_conn->whichone] + sign*ripper_size;
          rippers[ripper_count].y[1] =
            net_obj->line->y[found_conn->whichone] - ripper_size;
            ripper_count++;

            /* printf("done\n"); */
          made_changes++;
        }


      } else if (bus_orientation == VERTICAL &&
		 net_orientation == HORIZONTAL) {

	/* printf("found vert bus %s %d!\n", bus_object->name,
           found_conn->whichone); */

        sign = bus_object->bus_ripper_direction;
        if (!sign) {
          if (bus_object->line->y[0] < bus_object->line->y[1]) {
            first = 0;
            second = 1;
          } else {
            first = 1;
            second = 0;
          }

          distance1 = abs(bus_object->line->y[first] -
                          net_obj->line->y[found_conn->whichone]);
          distance2 = abs(bus_object->line->y[second] -
                          net_obj->line->y[found_conn->whichone]);

          if (distance1 <= distance2) {
            sign = 1;
          } else {
            sign = -1;
          }
          bus_object->bus_ripper_direction = sign;
        }
        /* printf("ver sign: %d\n", sign); */


        if (net_obj->line->x[otherone] < bus_object->line->x[0]) {
          /* new net is to the left of the bus */
          /* printf("left\n"); */

          if (ripper_count >= 2) {
            /* try to exit gracefully */
            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
            made_changes = FALSE;
            break;
          }

          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
            /* non-symmetric */
            if (sign == 1) {
              complex_angle = 0;
            } else {
              complex_angle = 270;
            }
          } else {
            /* symmetric */
            complex_angle = 270;
          }

          net_obj->line->x[found_conn->whichone] -= ripper_size;
          net_obj->w_bounds_valid_for = NULL;
          rippers[ripper_count].x[0] =
            net_obj->line->x[found_conn->whichone];
          rippers[ripper_count].y[0] =
            net_obj->line->y[found_conn->whichone];
          rippers[ripper_count].x[1] =
            net_obj->line->x[found_conn->whichone] + ripper_size;
          rippers[ripper_count].y[1] =
            net_obj->line->y[found_conn->whichone] + sign*ripper_size;
          ripper_count++;

          made_changes++;
        } else {
          /* new net is to the right of the bus */
          /* printf("right\n"); */

          if (ripper_count >= 2) {
            /* try to exit gracefully */
            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
            made_changes = FALSE;
            break;
          }

          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
            /* non-symmetric */
            if (sign == 1) {
              complex_angle = 90;
            } else {
              complex_angle = 180;
            }
          } else {
            /* symmetric */
            complex_angle = 90;
          }

          net_obj->line->x[found_conn->whichone] += ripper_size;
          net_obj->w_bounds_valid_for = NULL;
          rippers[ripper_count].x[0] =
            net_obj->line->x[found_conn->whichone];
          rippers[ripper_count].y[0] =
            net_obj->line->y[found_conn->whichone];
          rippers[ripper_count].x[1] =
            net_obj->line->x[found_conn->whichone] - ripper_size;
          rippers[ripper_count].y[1] =
            net_obj->line->y[found_conn->whichone] + sign*ripper_size;
          ripper_count++;

          made_changes++;
        }
      }
    }


    cl_current = g_list_next(cl_current);
  }

  if (made_changes) {
    s_conn_remove_object_connections (page->toplevel, net_obj);

    if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
      GList *symlist =
	s_clib_search (page->toplevel->bus_ripper_symname, CLIB_EXACT);
      if (symlist != NULL) {
        rippersym = (CLibSymbol *) symlist->data;
      }
      g_list_free (symlist);
    }

    for (i = 0; i < ripper_count; i++) {
      if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
        new_obj = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
                  rippers[i].x[0], rippers[i].y[0],
                  rippers[i].x[1], rippers[i].y[1]);
        s_page_append (page->toplevel, page, new_obj);
      } else {

        if (rippersym != NULL) {
          new_obj = o_complex_new (page->toplevel, OBJ_COMPLEX, DEFAULT_COLOR,
                                   rippers[i].x[0], rippers[i].y[0],
                                   complex_angle, 0,
                                   rippersym,
                                   page->toplevel->bus_ripper_symname, 1);
          s_page_append_list (page->toplevel, page,
                              o_complex_promote_attribs (page->toplevel, new_obj));
          s_page_append (page->toplevel, page, new_obj);
        } else {
          s_log_message(_("Bus ripper symbol [%s] was not found in any component library\n"),
                        page->toplevel->bus_ripper_symname);
        }
      }
    }

    s_conn_update_object (page, net_obj);
    return(TRUE);
  }

  return(FALSE);
}
Exemplo n.º 3
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
gint
x_event_button_released (GschemPageView *page_view, GdkEventButton *event, GschemToplevel *w_current)
{
  PAGE *page = gschem_page_view_get_page (page_view);
  int unsnapped_wx, unsnapped_wy;
  int w_x, w_y;

  g_return_val_if_fail ((page_view != NULL), 0);
  g_return_val_if_fail ((w_current != NULL), 0);

  if (page == NULL) {
    return TRUE; /* terminate event */
  }

#if DEBUG
  printf("released! %d \n", w_current->event_state);
#endif

  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;

  gschem_page_view_SCREENtoWORLD (page_view, (int) event->x, (int) event->y,
                                  &unsnapped_wx, &unsnapped_wy);
  w_x = snap_grid (w_current, unsnapped_wx);
  w_y = snap_grid (w_current, unsnapped_wy);

  /* Huge switch statement to evaluate state transitions. Jump to
   * end_button_released label to escape the state evaluation rather
   * than returning from the function directly. */
  scm_dynwind_begin ((scm_t_dynwind_flags) 0);
  g_dynwind_window (w_current);

  if (event->button == 1) {

    if (w_current->inside_action) {
      if (page->place_list != NULL) {
        switch(w_current->event_state) {
          case (COPYMODE)  :
          case (MCOPYMODE) : o_copy_end(w_current); break;
          case (MOVEMODE)  : o_move_end(w_current); break;
          default: break;
        }
      } else {
        switch(w_current->event_state) {
          case (GRIPS)     : o_grips_end(w_current); break;
          case (PATHMODE)  : o_path_end (w_current, w_x, w_y); break;
          case (SBOX)      : o_select_box_end(w_current, unsnapped_wx, unsnapped_wy); break;
          case (SELECT)    : o_select_end(w_current, unsnapped_wx, unsnapped_wy); break;
          case (ZOOMBOX)   : a_zoom_box_end(w_current, unsnapped_wx, unsnapped_wy); break;
          default: break;
        }
      }
    }
  } else if (event->button == 2) {

    if (w_current->inside_action) {
      if (w_current->event_state == COMPMODE||
          w_current->event_state == TEXTMODE||
          w_current->event_state == MOVEMODE||
          w_current->event_state == COPYMODE  ||
          w_current->event_state == MCOPYMODE ||
          w_current->event_state == PASTEMODE ) {

        if (w_current->event_state == MOVEMODE) {
          o_move_invalidate_rubber (w_current, FALSE);
        } else {
          o_place_invalidate_rubber (w_current, FALSE);
        }
        w_current->rubber_visible = 0;

        o_place_rotate(w_current);

        if (w_current->event_state == COMPMODE) {
          o_complex_place_changed_run_hook (w_current);
        }

        if (w_current->event_state == MOVEMODE) {
          o_move_invalidate_rubber (w_current, TRUE);
        } else {
          o_place_invalidate_rubber (w_current, TRUE);
        }
        w_current->rubber_visible = 1;
        goto end_button_released;
      }
    }

    switch(w_current->middle_button) {
      case(ACTION):
        if (w_current->inside_action && (page->place_list != NULL)) {
          switch(w_current->event_state) {
            case (COPYMODE): o_copy_end(w_current); break;
            case (MOVEMODE): o_move_end(w_current); break;
          }
        }
      break;

#ifdef HAVE_LIBSTROKE
      case(STROKE):
      DOING_STROKE = FALSE;
      x_stroke_translate_and_execute (w_current);
      break;
#endif /* HAVE_LIBSTROKE */

      case(MID_MOUSEPAN_ENABLED):
        if (gschem_page_view_pan_end (page_view) && w_current->undo_panzoom) {
          o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY);
        }
      break;
    }

  } else if (event->button == 3) {
      /* just for ending a mouse pan */
      if (gschem_page_view_pan_end (page_view) && w_current->undo_panzoom) {
        o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY);
      }
  }
 end_button_released:
  scm_dynwind_end ();

  return(0);
}
Exemplo n.º 4
0
/*! \brief finish a net drawing action
 * \par Function Description
 * This function finishes the drawing of a net. If we have a visible
 * magnetic marker, we use that instead of the current cursor
 * position.
 *
 * The rubber nets are removed, the nets and cues are drawn and the
 * net is added to the TOPLEVEL structure.
 *
 * The function returns TRUE if it has drawn a net, FALSE otherwise.
 */
void o_net_end(GschemToplevel *w_current, int w_x, int w_y)
{
  int primary_zero_length, secondary_zero_length;
  int found_primary_connection = FALSE;
  int save_wx, save_wy;

  GList *prev_conn_objects;
  OBJECT *new_net = NULL;

  /* Save a list of added objects to run the %add-objects-hook later */
  GList *added_objects = NULL;

  g_assert( w_current->inside_action != 0 );

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  o_net_invalidate_rubber (w_current);

  if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1)
    o_net_finishmagnetic(w_current);

  w_current->rubber_visible = 0;

  /* See if either of the nets are zero length.  We'll only add */
  /* the non-zero ones */
  primary_zero_length = (w_current->first_wx == w_current->second_wx) &&
    (w_current->first_wy == w_current->second_wy);

  secondary_zero_length = (w_current->second_wx == w_current->third_wx) &&
      (w_current->second_wy == w_current->third_wy);

  /* If both nets are zero length... */
  /* this ends the net drawing behavior */
  if ( primary_zero_length && secondary_zero_length ) {
    o_net_reset(w_current);
    return;
  }

  save_wx = w_current->third_wx;
  save_wy = w_current->third_wy;

  if (w_current->third_wx != snap_grid (w_current, w_current->third_wx)
      || w_current->third_wy != snap_grid (w_current, w_current->third_wy))
      s_log_message(_("Warning: Ending net at off grid coordinate\n"));

  if (!primary_zero_length ) {
  /* create primary net */
      new_net = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
                          w_current->first_wx, w_current->first_wy,
                          w_current->second_wx, w_current->second_wy);
      s_page_append (page->toplevel, page, new_net);

      added_objects = g_list_prepend (added_objects, new_net);

      /* conn stuff */
      /* LEAK CHECK 1 */
      prev_conn_objects = s_conn_return_others (NULL, new_net);
      o_net_add_busrippers (w_current, new_net, prev_conn_objects);
      g_list_free (prev_conn_objects);

#if DEBUG
      printf("primary:\n");
      s_conn_print(new_net->conn_list);
#endif

      /* Go off and search for valid connection on this newly created net */
      found_primary_connection = s_conn_net_search(new_net, 1,
                                                   new_net->conn_list);
      if (found_primary_connection)
      {
      	/* if a net connection is found, reset start point of next net */
	save_wx = w_current->second_wx;
	save_wy = w_current->second_wy;
      }
  }


  /* If the second net is not zero length, add it as well */
  /* Also, a valid net connection from the primary net was not found */
  if (!secondary_zero_length && !found_primary_connection) {

      /* Add secondary net */
      new_net = o_net_new(page->toplevel, OBJ_NET, NET_COLOR,
                          w_current->second_wx, w_current->second_wy,
                          w_current->third_wx, w_current->third_wy);
      s_page_append (page->toplevel, page, new_net);

      added_objects = g_list_prepend (added_objects, new_net);

      /* conn stuff */
      /* LEAK CHECK 2 */
      prev_conn_objects = s_conn_return_others (NULL, new_net);
      o_net_add_busrippers (w_current, new_net, prev_conn_objects);
      g_list_free (prev_conn_objects);
#if DEBUG
      s_conn_print(new_net->conn_list);
#endif
  }

  /* Call add-objects-hook */
  if (added_objects != NULL) {
    g_run_hook_object_list (w_current, "%add-objects-hook", added_objects);
    g_list_free (added_objects);
  }

  w_current->first_wx = save_wx;
  w_current->first_wy = save_wy;

  gschem_toplevel_page_content_changed (w_current, page);
  o_undo_savestate_old(w_current, UNDO_ALL);

  /* Continue net drawing */
  o_net_start(w_current, w_current->first_wx, w_current->first_wy);
}
Exemplo n.º 5
0
/*! \brief guess the best direction for the next net drawing action
 *  \par Function Description
 *  This function checks all connectable objects at a starting point.
 *  It determines the best drawing direction for each quadrant of the
 *  possible net endpoint.
 *
 *  The directions are stored in the GschemToplevel->net_direction variable
 *  as a bitfield.
 */
void o_net_guess_direction(GschemToplevel *w_current,
			   int wx, int wy)
{
  int up=0, down=0, left=0, right=0;
  int x1, y1, x2, y2;
  int xmin, ymin, xmax, ymax;
  int orientation;
  GList *object_list, *iter1, *iter2;
  OBJECT *o_current;

  int *current_rules;
  /* badness values       {OVERWRITE, ORTHO, CONTINUE} */
  const int pin_rules[] = {100, 50, 0};
  const int bus_rules[] = {90, 0, 40};
  const int net_rules[] = {80, 30, 0};

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  object_list = g_list_append (NULL, page->connectible_list);

  for (iter1 = object_list; iter1 != NULL; iter1 = g_list_next(iter1)) {
    for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
      o_current = (OBJECT*) iter2->data;

      if ((orientation = o_net_orientation(o_current)) == NEITHER)
	continue;

      switch (o_current->type) {
      case OBJ_NET:
	current_rules = (int*) net_rules;
	break;
      case OBJ_PIN:
	current_rules = (int*) pin_rules;
	break;
      case OBJ_BUS:
	current_rules = (int*) bus_rules;
	break;
      default:
	g_assert_not_reached ();
      }

      x1 = o_current->line->x[0];
      x2 = o_current->line->x[1];
      y1 = o_current->line->y[0];
      y2 = o_current->line->y[1];

      xmin = min(x1, x2);
      ymin = min(y1, y2);
      xmax = max(x1, x2);
      ymax = max(y1, y2);

      if (orientation == HORIZONTAL && wy == y1) {
	if (wx == xmin) {
	  up = max(up, current_rules[1]);
	  down = max(down, current_rules[1]);
	  right = max(right, current_rules[0]);
	  left = max(left, current_rules[2]);
	}
	else if (wx == xmax) {
	  up = max(up, current_rules[1]);
	  down = max(down, current_rules[1]);
	  right = max(right, current_rules[2]);
	  left = max(left, current_rules[0]);
	}
	else if (xmin < wx && wx < xmax) {
	  up = max(up, current_rules[1]);
	  down = max(down, current_rules[1]);
	  right = max(right, current_rules[0]);
	  left = max(left, current_rules[0]);
	}
	else {
	  continue;
	}
      }
      if (orientation == VERTICAL && wx == x1) {
	if (wy == ymin) {
	  up = max(up, current_rules[0]);
	  down = max(down, current_rules[2]);
	  right = max(right, current_rules[1]);
	  left = max(left, current_rules[1]);
	}
	else if (wy == ymax) {
	  up = max(up, current_rules[2]);
	  down = max(down, current_rules[0]);
	  right = max(right, current_rules[1]);
	  left = max(left, current_rules[1]);
	}
	else if (ymin < wy && wy < ymax) {
	  up = max(up, current_rules[0]);
	  down = max(down, current_rules[0]);
	  right = max(right, current_rules[1]);
	  left = max(left, current_rules[1]);
	}
	else {
	  continue;
	}
      }
    }
  }

  w_current->net_direction = 0;
  w_current->net_direction |= up >= right ? 0 : QUADRANT1;
  w_current->net_direction |= up >= left ? 0 : QUADRANT2;
  w_current->net_direction |= down >= left ? 0 : QUADRANT3;
  w_current->net_direction |= down >= right ? 0 : QUADRANT4;

#if 0
  printf("o_net_guess_direction: up=%d down=%d left=%d right=%d direction=%d\n",
	 up, down, left, right, w_current->net_direction);
#endif
  g_list_free (object_list);
}
Exemplo n.º 6
0
/*! \brief Updates the preview widget.
 *  \par Function Description
 *  This function updates the preview: if the preview is active and a
 *  filename has been given, it opens the file and displays
 *  it. Otherwise it displays a blank page.
 *
 *  \param [in] preview The preview widget.
 */
static void
preview_update (Preview *preview)
{
  int left, top, right, bottom;
  int width, height;
  GError * err = NULL;

  GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview);

  g_return_if_fail (preview_view != NULL);
  PAGE *preview_page = gschem_page_view_get_page (preview_view);

  if (preview_page == NULL) {
    return;
  }

  TOPLEVEL *preview_toplevel = preview_page->toplevel;

  /* delete old preview */
  s_page_delete_objects (preview_toplevel, preview_page);

  if (preview->active) {
    g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
    if (preview->filename != NULL) {
      /* open up file in current page */
      f_open_flags (preview_toplevel, preview_page,
                    preview->filename,
                    F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
      /* test value returned by f_open... - Fix me */
      /* we should display something if there an error occured - Fix me */
    }
    if (preview->buffer != NULL) {
      /* Load the data buffer */
      GList * objects = o_read_buffer (preview_toplevel,
                                       NULL, preview->buffer, -1,
                                       _("Preview Buffer"), &err);

      if (err == NULL) {
        s_page_append_list (preview_toplevel, preview_page,
                            objects);
      }
      else {
        s_page_append (preview_toplevel, preview_page,
                       o_text_new(preview_toplevel, OBJ_TEXT, 2, 100, 100, LOWER_MIDDLE, 0,
                                  err->message, 10, VISIBLE, SHOW_NAME_VALUE));
        g_error_free(err);
      }
    }
  }

  if (world_get_object_glist_bounds (preview_toplevel,
                                     s_page_objects (preview_page),
                                     &left, &top,
                                     &right, &bottom)) {
    /* Clamp the canvas size to the extents of the page being previewed */
    width = right - left;
    height = bottom - top;

    GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (preview_view);
    geometry->world_left   = left   - ((double)width  * OVER_ZOOM_FACTOR);
    geometry->world_right  = right  + ((double)width  * OVER_ZOOM_FACTOR);
    geometry->world_top    = top    - ((double)height * OVER_ZOOM_FACTOR);
    geometry->world_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
  }

  /* display current page (possibly empty) */
  gschem_page_view_zoom_extents (preview_view, NULL);
}
Exemplo n.º 7
0
/*! \brief find the closest possible location to connect to
 *  \par Function Description
 *  This function calculates the distance to all connectable objects
 *  and searches the closest connection point.
 *  It searches for pins, nets and busses.
 *
 *  The connection point is stored in GschemToplevel->magnetic_wx and
 *  GschemToplevel->magnetic_wy. If no connection is found. Both variables
 *  are set to -1.
 */
void o_net_find_magnetic(GschemToplevel *w_current,
			 int w_x, int w_y)
{
  int x1, x2, y1, y2, min_x, min_y;
  double mindist, minbest, dist1, dist2;
  double weight, min_weight;
  int magnetic_reach = 0;
  OBJECT *o_current;
  OBJECT *o_magnetic = NULL;
  GList *object_list, *iter1, *iter2;

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  minbest = min_x = min_y = 0;
  min_weight = 0;

  /* max distance of all the different reaches */
  magnetic_reach = max(MAGNETIC_PIN_REACH, MAGNETIC_NET_REACH);
  magnetic_reach = max(magnetic_reach, MAGNETIC_BUS_REACH);

  object_list = g_list_append (NULL, page->connectible_list);

  for (iter1 = object_list; iter1 != NULL; iter1 = g_list_next(iter1)) {
    for (iter2 = (GList*) iter1->data; iter2 != NULL; iter2 = g_list_next(iter2)) {
      int left, top, right, bottom;
      o_current = (OBJECT*) iter2->data;

      if (!world_get_single_object_bounds(page->toplevel, o_current,
                                          &left, &top, &right, &bottom) ||
          !visible (w_current, left, top, right, bottom))
	continue; /* skip invisible objects */

      if (o_current->type == OBJ_PIN) {
	min_x = o_current->line->x[o_current->whichend];
	min_y = o_current->line->y[o_current->whichend];

	mindist = hypot(w_x - min_x, w_y - min_y);
	weight = mindist / MAGNETIC_PIN_WEIGHT;
      }

      else if (o_current->type == OBJ_NET
	       || o_current->type == OBJ_BUS) {
	/* we have 3 possible points to connect:
	   2 endpoints and 1 midpoint point */
	x1 = o_current->line->x[0];
	y1 = o_current->line->y[0];
	x2 = o_current->line->x[1];
	y2 = o_current->line->y[1];
	/* endpoint tests */
	dist1 = hypot(w_x - x1, w_y - y1);
	dist2 = hypot(w_x - x2, w_y - y2);
	if (dist1 < dist2) {
	  min_x = x1;
	  min_y = y1;
	  mindist = dist1;
	}
	else {
	  min_x = x2;
	  min_y = y2;
	  mindist = dist2;
	}

	/* midpoint tests */
	if ((x1 == x2)  /* vertical net */
	    && ((y1 >= w_y && w_y >= y2)
		|| (y2 >= w_y && w_y >= y1))) {
	  if (abs(w_x - x1) < mindist) {
	    mindist = abs(w_x - x1);
	    min_x = x1;
	    min_y = w_y;
	  }
	}
	if ((y1 == y2)  /* horitontal net */
	    && ((x1 >= w_x && w_x >= x2)
		|| (x2 >= w_x && w_x >= x1))) {
	  if (abs(w_y - y1) < mindist) {
	    mindist = abs(w_y - y1);
	    min_x = w_x;
	    min_y = y1;
	  }
	}

	if (o_current->type == OBJ_BUS)
	  weight = mindist / MAGNETIC_BUS_WEIGHT;
	else /* OBJ_NET */
	  weight = mindist / MAGNETIC_NET_WEIGHT;
      }
      else { /* neither pin nor net or bus */
	continue;
      }

      if (o_magnetic == NULL
	  || weight < min_weight) {
	minbest = mindist;
	min_weight = weight;
	o_magnetic = o_current;
	w_current->magnetic_wx = min_x;
	w_current->magnetic_wy = min_y;
      }
    }
  }

  /* check whether we found an object and if it's close enough */
  if (o_magnetic != NULL) {
    switch (o_magnetic->type) {
    case (OBJ_PIN): magnetic_reach = MAGNETIC_PIN_REACH; break;
    case (OBJ_NET): magnetic_reach = MAGNETIC_NET_REACH; break;
    case (OBJ_BUS): magnetic_reach = MAGNETIC_BUS_REACH; break;
    }
    if (minbest > gschem_page_view_WORLDabs (page_view, magnetic_reach)) {
      w_current->magnetic_wx = -1;
      w_current->magnetic_wy = -1;
    }
  }
  else {
    w_current->magnetic_wx = -1;
    w_current->magnetic_wy = -1;
  }

  g_list_free (object_list);
}
Exemplo n.º 8
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_motion (GschemToplevel *w_current, int w_x, int w_y)
{
  GList *selection, *s_current;
  OBJECT *object;
  gint object_x, object_y;
  gboolean resnap = FALSE;
  SNAP_STATE snap_mode;

  g_assert (w_current->inside_action != 0);

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);
  g_return_if_fail (page->place_list != NULL);

  snap_mode = gschem_options_get_snap_mode (w_current->options);

  selection = geda_list_get_glist (page->selection_list);

  /* realign the object if we are in resnap mode */
  if ((selection != NULL) && (snap_mode == SNAP_RESNAP)) {
    if (g_list_length(selection) > 1) {
      /* find an object that is not attached to any other object */
      for (s_current = selection;
           s_current != NULL;
           s_current = g_list_next(s_current)) {
        if (((OBJECT *) s_current->data)->attached_to == NULL) {
          object = (OBJECT *) s_current->data;
          resnap = TRUE;
          break;
        }
      }

      /* Only resnap single elements. This is also the case if
         the selection contains one object and all other object
         elements are attributes of the object element.*/
      for (s_current = selection;
           s_current != NULL && resnap == TRUE;
           s_current = g_list_next(s_current)) {
        if (!(object == (OBJECT *) s_current->data)
            && !o_attrib_is_attached(page->toplevel,
                                     (OBJECT *) s_current->data, object)) {
          resnap = FALSE;
        }
      }
    } else { /* single object */
      resnap = TRUE;
      object = (OBJECT *) selection->data;
    }

    /* manipulate w_x and w_y in a way that will lead to a position
       of the object that is aligned with the grid */
    if (resnap) {
      if (o_get_position(page->toplevel, &object_x, &object_y, object)) {
        w_x += snap_grid (w_current, object_x) - object_x;
        w_y += snap_grid (w_current, object_y) - object_y;
      }
    }
  }

  o_move_invalidate_rubber (w_current, FALSE);
  w_current->second_wx = w_x;
  w_current->second_wy = w_y;
  o_move_invalidate_rubber (w_current, TRUE);
}
Exemplo n.º 9
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_check_endpoint(GschemToplevel *w_current, OBJECT * object)
{
  GList *cl_current;
  CONN *c_current;
  OBJECT *other;
  int whichone;

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  if (!object)
  return;

  if (object->type != OBJ_NET && object->type != OBJ_PIN &&
      object->type != OBJ_BUS) {
    fprintf(stderr, _("Got a non line object in o_move_check_endpoint\n"));
    return;
  }

  for (cl_current = object->conn_list;
       cl_current != NULL;
       cl_current = g_list_next(cl_current)) {

    c_current = (CONN *) cl_current->data;
    other = c_current->other_object;

    if (other == NULL)
      continue;

    /* really make sure that the object is not selected */
    if (other->selected)
      continue;

    /* Catch pins, whos parent object is selected. */
    if (other->parent != NULL && other->parent->selected)
      continue;

    if (c_current->type != CONN_ENDPOINT &&
        (c_current->type != CONN_MIDPOINT ||
         c_current->other_whichone == -1))
      continue;

    if (/* (net)pin to (net)pin contact */
        (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_NET &&
          other->type == OBJ_PIN &&  other->pin_type == PIN_TYPE_NET)) {

     /* net to (net)pin contact */
     /* (object->type == OBJ_NET &&
          other->type == OBJ_PIN && other->pin_type == PIN_TYPE_NET) */

      OBJECT *new_net;
      /* other object is a pin, insert a net */
      new_net = o_net_new (page->toplevel, OBJ_NET, NET_COLOR,
                           c_current->x, c_current->y,
                           c_current->x, c_current->y);
      s_page_append (page->toplevel, page, new_net);
      /* This new net object is only picked up for stretching later,
       * somewhat of a kludge. If the move operation is cancelled, these
       * new 0 length nets are removed by the "undo" operation invoked.
       */
    }

    /* Only attempt to stretch nets and buses */
    if (other->type != OBJ_NET && other->type != OBJ_BUS)
      continue;

    whichone = o_move_return_whichone (other, c_current->x, c_current->y);

#if DEBUG
    printf ("FOUND: %s type: %d, whichone: %d, x,y: %d %d\n",
            other->name, c_current->type,
            whichone, c_current->x, c_current->y);

    printf("other x,y: %d %d\n", c_current->x, c_current->y);
    printf("type: %d return: %d real: [ %d %d ]\n",
           c_current->type, whichone, c_current->whichone,
           c_current->other_whichone);
#endif

    if (whichone >= 0 && whichone <= 1) {
      w_current->stretch_list = s_stretch_add (w_current->stretch_list,
                                               other, whichone);
    }
  }

}
Exemplo n.º 10
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_end(GschemToplevel *w_current)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  GList *s_current = NULL;
  OBJECT *object;
  int diff_x, diff_y;
  GList *s_iter;
  GList *rubbernet_objects = NULL;
  gboolean net_rubber_band_mode;

  g_return_if_fail (w_current != NULL);
  g_return_if_fail (page != NULL);

  g_assert (w_current->inside_action != 0);

  object = o_select_return_first_object(w_current);

  if (!object) {
    /* actually this is an error condition hack */
    i_action_stop (w_current);
    i_set_state(w_current, SELECT);
    return;
  }

  diff_x = w_current->second_wx - w_current->first_wx;
  diff_y = w_current->second_wy - w_current->first_wy;

  o_move_invalidate_rubber (w_current, FALSE);
  w_current->rubber_visible = 0;

  net_rubber_band_mode = gschem_options_get_net_rubber_band_mode (w_current->options);

  if (net_rubber_band_mode) {
    o_move_end_rubberband (w_current, diff_x, diff_y, &rubbernet_objects);
  }

  /* Unset the dont_redraw flag on rubberbanded objects.
   * We set this above, in o_move_start(). */
  for (s_iter = w_current->stretch_list;
       s_iter != NULL; s_iter = g_list_next (s_iter)) {
    STRETCH *stretch = s_iter->data;
    stretch->object->dont_redraw = FALSE;
  }

  s_current = geda_list_get_glist( page->selection_list );

  while (s_current != NULL) {

    object = (OBJECT *) s_current->data;

    if (object == NULL) {
      fprintf(stderr, _("ERROR: NULL object in o_move_end!\n"));
      exit(-1);
    }


    switch (object->type) {
      case (OBJ_COMPLEX):
      case (OBJ_PLACEHOLDER):

        /* TODO: Fix so we can just pass the complex to o_move_end_lowlevel,
         * IE.. by falling through the bottom of this case statement. */

        /* this next section of code is from */
        /* o_complex_world_translate_world */
        object->complex->x = object->complex->x + diff_x;
        object->complex->y = object->complex->y + diff_y;

        o_move_end_lowlevel_glist (w_current, object->complex->prim_objs,
                                   diff_x, diff_y);
        object->w_bounds_valid_for = NULL;
        break;

      default:
        o_move_end_lowlevel (w_current, object, diff_x, diff_y);
        break;
    }

    s_current = g_list_next(s_current);
  }

  /* Draw the objects that were moved */
  o_invalidate_glist (w_current, geda_list_get_glist (page->selection_list));

  /* Draw the connected nets/buses that were also changed */
  o_invalidate_glist (w_current, rubbernet_objects);

  /* Call move-objects-hook for moved objects and changed connected
   * nets/buses */
  GList *moved_list = g_list_concat (page->place_list, rubbernet_objects);
  page->place_list = NULL;
  rubbernet_objects = NULL;
  g_run_hook_object_list (w_current, "%move-objects-hook", moved_list);
  g_list_free (moved_list);

  gschem_toplevel_page_content_changed (w_current, page);
  o_undo_savestate_old(w_current, UNDO_ALL);

  s_stretch_destroy_all (w_current->stretch_list);
  w_current->stretch_list = NULL;

  i_set_state(w_current, SELECT);
  i_action_stop (w_current);
}
Exemplo n.º 11
0
/*! \brief Handle motion during a move operation, resnapping if necessary
 * \par Function Description
 * Handle movement during a move operation, by updating the global
 * candidate transformation parameters.  The \a w_x and \b w_y
 * parameters are the incremental translation to be handled.
 *
 * This function mostly exists to implement the "resnapping" logic,
 * which destructively puts objects back onto the grid during a move
 * operation, as long as specific criteria are met.
 *
 * \param w_current  Global gschem state structure.
 * \param w_x        X-axis translation
 * \param w_y        Y-axis translation
 */
void o_move_motion (GschemToplevel *w_current, int w_x, int w_y)
{
  GList *selection, *s_current;
  OBJECT *object = NULL;
  gint object_x, object_y;
  SNAP_STATE snap_mode;

  g_assert (w_current->inside_action != 0);

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);
  g_return_if_fail (page->place_list != NULL);

  snap_mode = gschem_options_get_snap_mode (w_current->options);

  selection = geda_list_get_glist (page->selection_list);

  /* There are three posssibilities:
   *
   * 1. There is exactly one object selected, in which case it is
   *    snapped.
   *
   * 2. There are multiple objects selected, but there is some object
   *    O[i] such that all other selected objects O[j!=i] are attached
   *    as attributes of O[i].  In that case, the O[i] is snapped.
   *
   * 3. Other cases, in which case no snapping occurs.
   */

  if (NULL == selection || SNAP_RESNAP != snap_mode) {
    object = NULL;

  } else if (1 == g_list_length (selection)) {
    object = (OBJECT *) selection->data;

  } else {

    /* The object that things are supposed to be attached to */
    OBJECT *attached = NULL;

    /* Scan the selection, searching for an object that's not attached
     * to any other object.  As we go, also check whether everything
     * in the list that *is* attached as an attribute is attached to
     * the same object. */
    for (s_current = selection;
         NULL != s_current;
         s_current = g_list_next (s_current)) {

      OBJECT *candidate = (OBJECT *) s_current->data;

      if (NULL == candidate->attached_to) {

        /* If the object is *not* attached as an attribute, then check
         * whether we previously found an independent object.  If we
         * did, we can't do snapping, so give up. */
        if (NULL == object) {
          object = candidate;
        } else if (candidate != object) {
          break; /* Give up */
        }

      } else {

        /* If the object is attached as an attribute, then check if
         * it's attached as an attribute of the same object as
         * everything else is.  If not, we can't do snapping, so give
         * up. */
        if (NULL == attached) {
          attached = candidate->attached_to;
        } else if (attached != candidate->attached_to) {
          break; /* Give up */
        }
      }
    }

    if (NULL == object ||
        (NULL != attached && object != attached)) {
      object = NULL;
    } else {
      g_assert (NULL != object);
    }
  }

  /* manipulate w_x and w_y in a way that will lead to a position
     of the object that is aligned with the grid */
  if (NULL != object) {
    if (geda_object_get_position (object, &object_x, &object_y)) {
      w_x += snap_grid (w_current, object_x) - object_x;
      w_y += snap_grid (w_current, object_y) - object_y;
    }
  }

  o_move_invalidate_rubber (w_current, FALSE);
  w_current->second_wx = w_x;
  w_current->second_wy = w_y;
  o_move_invalidate_rubber (w_current, TRUE);
}
Exemplo n.º 12
0
/*! \brief End the input of a path.
 *  \par Function Description
 *  This function ends the process of interactively adding a path to the
 *  current sheet.
 *
 *  It first erases the last temporary path displayed, calculates the
 *  corresponding world coordinates of the two ends of the path and finally
 *  adds a new initialized path object to the list of object of the current
 *  sheet.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] w_x        (unused)
 *  \param [in] w_y        (unused)
 */
gboolean
o_path_end(GschemToplevel *w_current, int w_x, int w_y)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  TOPLEVEL *toplevel = gschem_page_view_get_toplevel (page_view);
  PAGE *page = gschem_page_view_get_page (page_view);
  gboolean close_path, end_path, start_path;
  PATH *p;
  PATH_SECTION *section, *prev_section;
  int x1, y1, x2, y2;

  g_assert (w_current);
  g_assert (w_current->toplevel);
  g_assert (w_current->temp_path != NULL);
  g_assert (w_current->temp_path->sections != NULL);
  g_assert (toplevel != NULL);
  g_assert (page != NULL);

  o_path_invalidate_rubber (w_current);

  x1 = w_current->first_wx;
  y1 = w_current->first_wy;
  x2 = w_current->second_wx;
  y2 = w_current->second_wy;
  p = w_current->temp_path;

  /* Check whether the section that's being added is the initial
   * MOVETO.  This is detected if the path is currently empty. */
  start_path = (p->num_sections == 0);

  prev_section = start_path ? NULL : &p->sections[p->num_sections - 1];

  /* Check whether the section that's being added closes the path.
   * This is detected if the location of the node is the same as the
   * location of the starting node, and there is at least one section
   * in the path in addition to the initial MOVETO section. */
  section = &p->sections[0];
  close_path = (!start_path
                && x1 == section->x3
                && y1 == section->y3);

  /* Check whether the section that's being added ends the path. This
   * is detected if the location of the node is the same as the
   * location of the previous node. */
  end_path = (!start_path
              && x1 == prev_section->x3
              && y1 == prev_section->y3);

  /* Add predicted next sections */
  path_next_sections (w_current);

  if (end_path || close_path) {
    /* Add object to page and clean up path drawing state */
    OBJECT *obj = o_path_new_take_path (toplevel, OBJ_PATH,
                                        GRAPHIC_COLOR, p);
    w_current->temp_path = NULL;
    w_current->first_wx = -1;
    w_current->first_wy = -1;
    w_current->second_wx = -1;
    w_current->second_wy = -1;
    w_current->third_wx = -1;
    w_current->third_wy = -1;

    s_page_append (toplevel, page, obj);
    g_run_hook_object (w_current, "%add-objects-hook", obj);
    gschem_toplevel_page_content_changed (w_current, page);
    o_undo_savestate (w_current, page, UNDO_ALL);

    w_current->rubber_visible = FALSE;

    return FALSE;
  } else {
    /* Leave state as it is and continue path drawing... */

    /* Save the control point coordinates for the next section */
    w_current->third_wx = x2;
    w_current->third_wy = y2;

    return TRUE;
  }
}
Exemplo n.º 13
0
/*! \brief End placement action
 *
 *  \par Function Description
 *  This function finishes the current placement action by adding
 *  objects to the current page at the given new world coordinates
 *  and redrawing them on the canvas. It also saves the current
 *  state in the undo list and updates the menus.
 *
 *  If \a continue_placing is TRUE, a copy of the placement list
 *  is saved to start a new place action.
 *
 *  \param [in]  w_current  GschemToplevel which we're drawing for.
 *  \param [in]  w_x        The current world X coordinate.
 *  \param [in]  w_y        The current world Y coordinate.
 *  \param [in]  hook_name  The hook to run after adding the objects.
 */
void o_place_end (GschemToplevel *w_current,
                  int w_x, int w_y,
                  int continue_placing,
                  const char* hook_name)
{
  int w_diff_x, w_diff_y;
  OBJECT *o_current;
  GList *temp_dest_list = NULL;
  GList *connected_objects = NULL;
  GList *iter;

  g_return_if_fail (w_current != NULL);
  g_assert (w_current->inside_action != 0);

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);

  /* erase old image */
  /* o_place_invalidate_rubber (w_current, FALSE); */
  w_current->rubber_visible = 0;

  /* Calc final object positions */
  w_current->second_wx = w_x;
  w_current->second_wy = w_y;

  w_diff_x = w_current->second_wx - w_current->first_wx;
  w_diff_y = w_current->second_wy - w_current->first_wy;

  if (continue_placing) {
    /* Make a copy of the place list if we want to keep it afterwards */
    temp_dest_list = o_glist_copy_all (page->toplevel,
                                       page->place_list,
                                       temp_dest_list);
  } else {
    /* Otherwise just take it */
    temp_dest_list = page->place_list;
    page->place_list = NULL;
  }

  geda_object_list_translate (temp_dest_list, w_diff_x, w_diff_y);

  /* Attach each item back onto the page's object list. Update object
   * connectivity and add the new objects to the selection list.*/
  for (iter = temp_dest_list; iter != NULL; iter = g_list_next (iter)) {
    o_current = iter->data;

    s_page_append (page->toplevel, page, o_current);

    /* Update object connectivity */
    s_conn_update_object (page, o_current);
    connected_objects = s_conn_return_others (connected_objects, o_current);
  }

  if (hook_name != NULL) {
    g_run_hook_object_list (w_current, hook_name, temp_dest_list);
  }

  o_invalidate_glist (w_current, connected_objects);
  g_list_free (connected_objects);
  connected_objects = NULL;

  gschem_toplevel_page_content_changed (w_current, page);
  o_invalidate_glist (w_current, temp_dest_list); /* only redraw new objects */
  g_list_free (temp_dest_list);

  o_undo_savestate_old (w_current, UNDO_ALL);
  i_update_menus (w_current);

  if (!continue_placing) {
    i_set_state(w_current, SELECT);
    i_action_stop (w_current);
  }
}
Exemplo n.º 14
0
/*! \brief Draw a bounding box or outline for OBJECT placement
 *  \par Function Description
 *  This function draws either the OBJECTS in the place list
 *  or a rectangle around their bounding box, depending upon the
 *  currently selected w_current->actionfeedback_mode. This takes the
 *  value BOUNDINGBOX or OUTLINE.
 *
 * The function applies manhatten mode constraints to the coordinates
 * before drawing if the CONTROL key is recording as being pressed in
 * the w_current structure.
 *
 *  \param w_current   GschemToplevel which we're drawing for.
 *  \param renderer    Renderer to use for drawing.
 */
void
o_place_draw_rubber (GschemToplevel *w_current, EdaRenderer *renderer)
{
  int diff_x, diff_y;
  cairo_t *cr = eda_renderer_get_cairo_context (renderer);

  g_return_if_fail (w_current != NULL);

  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (page_view != NULL);

  PAGE *page = gschem_page_view_get_page (page_view);
  g_return_if_fail (page != NULL);
  g_return_if_fail (page->place_list != NULL);

  /* Don't worry about the previous drawing method and movement
   * constraints, use with the current settings */
  w_current->last_drawb_mode = w_current->actionfeedback_mode;
  w_current->drawbounding_action_mode = (w_current->CONTROLKEY &&
                                         ! ((w_current->event_state == PASTEMODE) ||
                                            (w_current->event_state == COMPMODE) ||
                                            (w_current->event_state == TEXTMODE)))
                                        ? CONSTRAINED : FREE;

  /* Calculate delta of X-Y positions from buffer's origin */
  diff_x = w_current->second_wx - w_current->first_wx;
  diff_y = w_current->second_wy - w_current->first_wy;

  /* Adjust the coordinates according to the movement constraints */
  if (w_current->drawbounding_action_mode == CONSTRAINED ) {
    if (abs(diff_x) >= abs(diff_y)) {
      w_current->second_wy = w_current->first_wy;
      diff_y = 0;
    } else {
      w_current->second_wx = w_current->first_wx;
      diff_x = 0;
    }
  }

  /* Translate the cairo context to the required offset before drawing. */
  cairo_save (cr);
  cairo_translate (cr, diff_x, diff_y);

  /* Draw with the appropriate mode */
  if (w_current->last_drawb_mode == BOUNDINGBOX) {
    GArray *map = eda_renderer_get_color_map (renderer);
    int flags = eda_renderer_get_cairo_flags (renderer);
    int left, top, bottom, right;

    /* Find the bounds of the drawing to be done */
    world_get_object_glist_bounds (page->toplevel,
                                   page->place_list,
                                   &left, &top, &right, &bottom);

    /* Draw box outline */
    eda_cairo_box (cr, flags, 0, left, top, right, bottom);
    eda_cairo_set_source_color (cr, BOUNDINGBOX_COLOR, map);
    eda_cairo_stroke (cr, flags, TYPE_SOLID, END_NONE, 0, -1, -1);
  } else {
    GList *iter;
    for (iter = page->place_list; iter != NULL;
         iter = g_list_next (iter)) {
      eda_renderer_draw (renderer, (OBJECT *) iter->data);
    }
  }
  cairo_restore (cr);
}