Example #1
0
/*! \brief Records a new point for the stroke.
 *  \par Function Description
 *  This function adds the point (<B>x</B>,<B>y</B>) as a new point in
 *  the stroke.
 *
 * The footprint is updated and the new point is drawn on the drawing area.
 *
 *  \param [in] w_current The GschemToplevel object.
 *  \param [in] x        The X coord of the new point.
 *  \param [in] Y        The X coord of the new point.
 */
void
x_stroke_record (GschemToplevel *w_current, gint x, gint y)
{
  cairo_matrix_t user_to_device_matrix;
  double x0, y0;
  GschemPageView *view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (view != NULL);
  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view);
  g_return_if_fail (geometry != NULL);

  g_assert (stroke_points != NULL);

  stroke_record (x, y);

  if (stroke_points->len < STROKE_MAX_POINTS) {
    StrokePoint point = { x, y };

    g_array_append_val (stroke_points, point);

    cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET(view)));
    GedaColor *color = x_color_lookup (w_current, STROKE_COLOR);
    cairo_set_source_rgba (cr,
                           geda_color_get_red_double (color),
                           geda_color_get_green_double (color),
                           geda_color_get_blue_double (color),
                           geda_color_get_alpha_double (color));

    cairo_set_matrix (cr, gschem_page_geometry_get_world_to_screen_matrix (geometry));
    x0 = x;
    y0 = y;
    cairo_device_to_user (cr, &x0, &y0);
    cairo_get_matrix (cr, &user_to_device_matrix);
    cairo_save (cr);
    cairo_identity_matrix (cr);

    cairo_matrix_transform_point (&user_to_device_matrix, &x0, &y0);

    cairo_rectangle (cr, x0, y0, 1, 1);
    cairo_fill (cr);
    cairo_restore (cr);
    cairo_destroy (cr);
  }

}
Example #2
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_end_rubberband (GschemToplevel *w_current,
                            int w_dx, int w_dy,
                            GList** objects)
{
  GList *s_iter, *s_iter_next;

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

  for (s_iter = w_current->stretch_list;
       s_iter != NULL; s_iter = s_iter_next) {
    STRETCH *s_current = s_iter->data;
    OBJECT *object = s_current->object;
    int whichone = s_current->whichone;

    /* Store this now, since we may delete the current item */
    s_iter_next = g_list_next (s_iter);

    if (object->type == OBJ_NET ||
        object->type == OBJ_BUS) {

      /* remove the object's connections */
      s_conn_remove_object_connections (page->toplevel, object);

      object->line->x[whichone] += w_dx;
      object->line->y[whichone] += w_dy;

      if (o_move_zero_length (object)) {
        w_current->stretch_list =
          s_stretch_remove (w_current->stretch_list, object);
        o_delete (w_current, object);
        continue;
      }

      object->w_bounds_valid_for = NULL;
      s_conn_update_object (page, object);
      *objects = g_list_append (*objects, object);
    }
  }
}
Example #3
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_invalidate_rubber (GschemToplevel *w_current, int drawing)
{
  GList *s_iter;
  int dx1, dx2, dy1, dy2;
  gboolean net_rubber_band_mode;

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

  net_rubber_band_mode = gschem_options_get_net_rubber_band_mode (w_current->options);

  o_place_invalidate_rubber (w_current, drawing);
  if (net_rubber_band_mode) {

    for (s_iter = w_current->stretch_list;
         s_iter != NULL; s_iter = g_list_next (s_iter)) {
      STRETCH *s_current = s_iter->data;
      OBJECT *object = s_current->object;

      switch (object->type) {
        case (OBJ_NET):
        case (OBJ_BUS):
          if (s_current->whichone == 0) {
            dx1 = w_current->second_wx - w_current->first_wx;
            dy1 = w_current->second_wy - w_current->first_wy;
            dx2 = dy2 = 0;
          } else {
            dx1 = dy1 = 0;
            dx2 = w_current->second_wx - w_current->first_wx;
            dy2 = w_current->second_wy - w_current->first_wy;
          }

          gschem_page_view_invalidate_world_rect (page_view,
                                                  object->line->x[0] + dx1,
                                                  object->line->y[0] + dy1,
                                                  object->line->x[1] + dx2,
                                                  object->line->y[1] + dy2);
      }
    }
  }
}
Example #4
0
/*! \brief End the input of a circle.
 *  \par Function Description
 *  This function ends the input of the radius of the circle.
 *  The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius
 *  segment, i.e. on the circle. The distance between this point and the
 *  center is the radius of the circle.
 *  <B>w_x</B> and <B>w_y</B> are in world coords.
 *
 *  The center has previously been input and saved as
 *  (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
 *
 *  The temporary circle drawn during the input of the radius is erased.
 *  A new object is allocated, initialized and linked in the object list.
 *  This new object is finally drawn.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] w_x        (unused)
 *  \param [in] w_y        (unused)
 */
void o_circle_end(GschemToplevel *w_current, int w_x, int w_y)
{
  OBJECT *new_obj;

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

  g_assert( w_current->inside_action != 0 );

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

  TOPLEVEL *toplevel = page->toplevel;
  g_return_if_fail (toplevel != NULL);

  /* erase the temporary circle */
  /* o_circle_invalidate_rubber (w_current); */
  w_current->rubber_visible = 0;

  /* circle with null radius are not allowed */
  if (w_current->distance == 0) {
    /* cancel the object creation */
    return;
  }

  /* create the object */
  new_obj = geda_circle_object_new (toplevel,
                                    GRAPHIC_COLOR,
                                    w_current->first_wx,
                                    w_current->first_wy,
                                    w_current->distance);

  s_page_append (toplevel, page, new_obj);

  /* Call add-objects-hook */
  g_run_hook_object (w_current, "%add-objects-hook", new_obj);

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

  i_action_stop (w_current);
}
Example #5
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_net_invalidate_rubber (GschemToplevel *w_current)
{
  int size = 0, magnetic_halfsize;
  int magnetic_x, magnetic_y;
  gboolean magnetic_net_mode;

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

  gschem_page_view_WORLDtoSCREEN (page_view,
                                  w_current->magnetic_wx, w_current->magnetic_wy,
                                  &magnetic_x, &magnetic_y);

  size = gschem_page_view_SCREENabs (page_view, NET_WIDTH);

  magnetic_net_mode = gschem_options_get_magnetic_net_mode (w_current->options);

  if (magnetic_net_mode) {
    if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
      magnetic_halfsize = max (4 * size, MAGNETIC_HALFSIZE);

      o_invalidate_rect (w_current, magnetic_x - magnetic_halfsize,
                                    magnetic_y - magnetic_halfsize,
                                    magnetic_x + magnetic_halfsize,
                                    magnetic_y + magnetic_halfsize);
    }
  }

  gschem_page_view_invalidate_world_rect (page_view,
                                          w_current->first_wx,
                                          w_current->first_wy,
                                          w_current->second_wx,
                                          w_current->second_wy);

  gschem_page_view_invalidate_world_rect (page_view,
                                          w_current->second_wx,
                                          w_current->second_wy,
                                          w_current->third_wx,
                                          w_current->third_wy);
}
Example #6
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_edit_show_hidden (GschemToplevel *w_current, const GList *o_list)
{
  /* this function just shows the hidden text, but doesn't toggle it */
  /* this function does not change the CHANGED bit, no real changes are */
  /* made to the schematic */

  /* toggle show_hidden_text variable, which when it is true */
  /* means that hidden text IS drawn */
  w_current->toplevel->show_hidden_text = !w_current->toplevel->show_hidden_text;
  i_show_state(w_current, NULL); /* update screen status */

  o_edit_show_hidden_lowlevel(w_current, o_list);
  gschem_page_view_invalidate_all (gschem_toplevel_get_current_page_view (w_current));

  if (w_current->toplevel->show_hidden_text) {
    s_log_message(_("Hidden text is now visible\n"));
  } else {
    s_log_message(_("Hidden text is now invisible\n"));
  }
}
Example #7
0
/*! \brief Mirror the objects being placed
 *
 *  \par Function Description
 *  This function erases the objects in the place list, mirrors
 *  them, runs %mirror-objects-hook, and redraws the objects after
 *  mirroring.
 *
 *  \param [in] w_current   The GschemToplevel object.
 */
void o_place_mirror (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);

  o_place_invalidate_rubber (w_current, FALSE);

  geda_object_list_mirror (page->place_list,
                           w_current->first_wx,
                           w_current->first_wy,
                           page->toplevel);

  /* Run mirror-objects-hook */
  g_run_hook_object_list (w_current, "%mirror-objects-hook", page->place_list);

  o_place_invalidate_rubber (w_current, TRUE);
}
Example #8
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_move_prep_rubberband(GschemToplevel *w_current)
{
  GList *s_current;
  OBJECT *object;
  OBJECT *o_current;
  GList *iter;

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

  for (s_current = geda_list_get_glist (page->selection_list);
       s_current != NULL; s_current = g_list_next (s_current)) {
    object = s_current->data;

    if (object == NULL)
      continue;

    switch (object->type) {
      case (OBJ_NET):
      case (OBJ_PIN):
      case (OBJ_BUS):
        o_move_check_endpoint (w_current, object);
        break;

      case (OBJ_COMPLEX):
      case (OBJ_PLACEHOLDER):
        for (iter = object->complex->prim_objs;
             iter != NULL; iter = g_list_next (iter)) {
          o_current = iter->data;

          if (o_current->type == OBJ_PIN) {
            o_move_check_endpoint (w_current, o_current);
          }
        }
        break;
    }
  }
}
Example #9
0
/*! \brief Rotate the objects being placed
 *
 *  \par Function Description
 *  This function erases the objects in the place list, rotates
 *  them, runs %rotate-objects-hook, and redraws the objects after
 *  rotating.
 *
 *  \param [in] w_current   The GschemToplevel object.
 */
void o_place_rotate (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);

  o_place_invalidate_rubber (w_current, FALSE);

  o_glist_rotate_world (page->toplevel,
                        w_current->first_wx,
                        w_current->first_wy,
                        90,
                        page->place_list);

  /* Run rotate-objects-hook */
  g_run_hook_object_list (w_current, "%rotate-objects-hook", page->place_list);

  o_place_invalidate_rubber (w_current, TRUE);
}
Example #10
0
/*! \brief Changes the current page.
 *  \par Function Description
 *  This function displays the specified page <B>page</B> in the
 *  window attached to <B>toplevel</B>.
 *
 *  It changes the <B>toplevel</B>'s current page to <B>page</B>,
 *  draws it and updates the user interface.
 *
 *  <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
 *
 *  \param [in] w_current The toplevel environment.
 *  \param [in] page      The page to become current page.
 */
void
x_window_set_current_page (GschemToplevel *w_current, PAGE *page)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);

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

  o_redraw_cleanstates (w_current);

  gschem_page_view_set_page (page_view, page);

  i_update_menus (w_current);
  i_set_filename (w_current, page->page_filename);

  x_pagesel_update (w_current);
  x_multiattrib_update (w_current);

  gschem_page_view_update_scroll_adjustments (page_view);
  gschem_page_view_invalidate_all (page_view);
}
Example #11
0
/*! \brief draw rubbernet lines to the gc
 *  \par Function Description
 *  This function draws the rubbernets to the graphic context
 */
void
o_net_draw_rubber(GschemToplevel *w_current, EdaRenderer *renderer)
{
  int size = NET_WIDTH, w_magnetic_halfsize;
  cairo_t *cr = eda_renderer_get_cairo_context (renderer);
  GArray *color_map = eda_renderer_get_color_map (renderer);
  int flags = eda_renderer_get_cairo_flags (renderer);
  gboolean magnetic_net_mode;

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

  eda_cairo_set_source_color (cr, SELECT_COLOR, color_map);

  magnetic_net_mode = gschem_options_get_magnetic_net_mode (w_current->options);

  if (magnetic_net_mode) {
    if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) {
      w_magnetic_halfsize = max (4 * size,
                                 gschem_page_view_WORLDabs (page_view, MAGNETIC_HALFSIZE));
      eda_cairo_arc (cr, flags, size,
                     w_current->magnetic_wx, w_current->magnetic_wy,
                     w_magnetic_halfsize, 0, 360);
    }
  }

  /* Primary line */
  eda_cairo_line (cr, flags, END_NONE, size,
                  w_current->first_wx,  w_current->first_wy,
                  w_current->second_wx, w_current->second_wy);

  /* Secondary line */
  eda_cairo_line (cr, flags, END_NONE, size,
                     w_current->second_wx, w_current->second_wy,
                     w_current->third_wx,  w_current->third_wy);

  eda_cairo_stroke (cr, flags, TYPE_SOLID, END_NONE, size, -1, -1);
}
Example #12
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_text_prepare_place(GschemToplevel *w_current, char *text, int color, int align, int rotate, int size)
{
  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);
  if (page == NULL) {
    return;
  }

  TOPLEVEL *toplevel = page->toplevel;
  g_return_if_fail (toplevel != NULL);


  /* Insert the new object into the buffer at world coordinates (0,0).
   * It will be translated to the mouse coordinates during placement. */

  w_current->first_wx = 0;
  w_current->first_wy = 0;

  w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;

  /* remove the old place list if it exists */
  s_delete_object_glist(toplevel, page->place_list);
  page->place_list = NULL;

  /* here you need to add OBJ_TEXT when it's done */
  page->place_list =
    g_list_append(page->place_list,
                  o_text_new (toplevel, color,
                              0, 0, align, rotate, /* zero is angle */
                              text,
                              size,
                              /* has to be visible so you can place it */
                              /* visibility is set when you create the object */
                              VISIBLE, SHOW_NAME_VALUE));

  i_action_start (w_current);
  i_set_state (w_current, TEXTMODE);
}
Example #13
0
/*! \brief Records a new point for the stroke.
 *  \par Function Description
 *  This function adds the point (<B>x</B>,<B>y</B>) as a new point in
 *  the stroke.
 *
 * The footprint is updated and the new point is drawn on the drawing area.
 *
 *  \param [in] w_current The GschemToplevel object.
 *  \param [in] x        The X coord of the new point.
 *  \param [in] Y        The X coord of the new point.
 */
void
x_stroke_record (GschemToplevel *w_current, gint x, gint y)
{
  GschemPageView *view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (view != NULL);

  GdkGC *view_gc = gschem_page_view_get_gc (view);

  g_assert (stroke_points != NULL);

  stroke_record (x, y);

  if (stroke_points->len < STROKE_MAX_POINTS) {
    StrokePoint point = { x, y };

    g_array_append_val (stroke_points, point);

    gdk_gc_set_foreground (view_gc, x_get_color (STROKE_COLOR));
    gdk_draw_point (gtk_widget_get_window (GTK_WIDGET(view)), view_gc, x, y);
  }

}
Example #14
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
gboolean
o_find_selected_object (GschemToplevel *w_current, int w_x, int w_y)
{
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  g_return_val_if_fail (page_view != NULL, FALSE);

  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  g_return_val_if_fail (toplevel != NULL, FALSE);

  int w_slack = gschem_page_view_WORLDabs (page_view, w_current->select_slack_pixels);
  GList *s_current;

  for (s_current = geda_list_get_glist (toplevel->page_current->selection_list);
       s_current != NULL; s_current = g_list_next (s_current)) {
    OBJECT *o_current = s_current->data;

    if (is_object_hit (w_current, o_current, w_x, w_y, w_slack))
      return TRUE;
  }

  return FALSE;
}
Example #15
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
static void
a_zoom_box(GschemToplevel *w_current)
{
  double zx, zy, relativ_zoom_factor;
  double world_pan_center_x, world_pan_center_y;

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

  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (page_view);
  g_return_if_fail (geometry != NULL);

  /*test if there is really a box*/
  if (w_current->first_wx == w_current->second_wx ||
      w_current->first_wy == w_current->second_wy) {
    s_log_message(_("Zoom too small!  Cannot zoom further.\n"));
    return;
  }

  /*calc new zoomfactors and choose the smaller one*/
  zx = (double) abs(geometry->viewport_left - geometry->viewport_right) / abs(w_current->first_wx - w_current->second_wx);
  zy = (double) abs(geometry->viewport_top - geometry->viewport_bottom) / abs(w_current->first_wy - w_current->second_wy);

  relativ_zoom_factor = (zx < zy ? zx : zy);

  /* calculate the center of the zoom box */
  world_pan_center_x = (w_current->first_wx + w_current->second_wx) / 2.0;
  world_pan_center_y = (w_current->first_wy + w_current->second_wy) / 2.0;

  /* and create the new window*/
  gschem_page_view_pan_general (page_view,
                                world_pan_center_x,
                                world_pan_center_y,
                                relativ_zoom_factor);
}
Example #16
0
/*! \brief get the pointer position of a given GschemToplevel
 *  \par Function Description
 *  This function gets the pointer position of the drawing area of the
 *  current workspace <b>GschemToplevel</b>. The flag <b>snapped</b> specifies
 *  whether the pointer position should be snapped to the current grid.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] snapped    An option flag to specify the wished coords
 *  \param [out] wx        snapped/unsnapped world x coordinate
 *  \param [out] wy        snapped/unsnapped world y coordinate
 *
 *  \return Returns TRUE if the pointer position is inside the drawing area.
 *
 */
gboolean
x_event_get_pointer_position (GschemToplevel *w_current, gboolean snapped, gint *wx, gint *wy)
{
  int width;
  int height;
  int sx;
  int sy;
  int x;
  int y;

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

  g_return_val_if_fail (GTK_WIDGET (page_view)->window != NULL, FALSE);

  /* \todo The following line is depricated in GDK 2.24 */
  gdk_drawable_get_size (GTK_WIDGET (page_view)->window, &width, &height);

  gtk_widget_get_pointer(GTK_WIDGET (page_view), &sx, &sy);

  /* check if we are inside the drawing area */
  if ((sx < 0) || (sx >= width) || (sy < 0) || (sy >= height)) {
    return FALSE;
  }

  gschem_page_view_SCREENtoWORLD (page_view, sx, sy, &x, &y);

  if (snapped) {
    x = snap_grid (w_current, x);
    y = snap_grid (w_current, y);
  }

  *wx = x;
  *wy = y;

  return TRUE;
}
Example #17
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *  \note
 *  The object passed in should be the REAL object, NOT any copy in any
 *  selection list
 */
void o_text_change(GschemToplevel *w_current, OBJECT *object, char *string,
		   int visibility, int show)
{
  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);
  TOPLEVEL *toplevel = page->toplevel;

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

  if (object == NULL) {
    return;
  }

  if (object->type != OBJ_TEXT) {
    return;
  }

  o_text_set_string (toplevel, object, string);

  o_set_visibility (toplevel, object, visibility);
  object->show_name_value = show;
  o_text_recreate(toplevel, object);

  /* handle slot= attribute, it's a special case */
  if (object->attached_to != NULL &&
      g_ascii_strncasecmp (string, "slot=", 5) == 0) {
    o_slot_end (w_current, object->attached_to, string);
  }

  gschem_toplevel_page_content_changed (w_current, page);
}
Example #18
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 */
void o_copy_start(GschemToplevel *w_current, int w_x, int w_y)
{
  GList *s_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);

  /* Copy the objects into the buffer at their current position,
   * with future motion relative to the mouse origin, (w_x, w_y). */

  w_current->first_wx = w_x;
  w_current->first_wy = w_y;

  if (!o_select_selected (w_current))
    return;

  s_current = geda_list_get_glist (page->selection_list);

  if (page->place_list != NULL) {
    s_delete_object_glist (page->toplevel, page->place_list);
    page->place_list = NULL;
  }

  page->place_list = o_glist_copy_all (page->toplevel,
                                       s_current,
                                       page->place_list);

  g_run_hook_object_list (w_current,
                          "%copy-objects-hook",
                          page->place_list);

  o_place_start (w_current, w_x, w_y);
}
Example #19
0
/*! \brief Check if a bounding box is visible on the screen.
 *  \par Function Description
 *  This function checks if a given bounding box is visible on the screen.
 *
 *  WARNING: top and bottom are mis-named in world-coords,
 *  top is the smallest "y" value, and bottom is the largest.
 *  Be careful! This doesn't correspond to what you'd expect.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] wleft      Left coordinate of the bounding box.
 *  \param [in] wtop       Top coordinate of the bounding box.
 *  \param [in] wright     Right coordinate of the bounding box.
 *  \param [in] wbottom    Bottom coordinate of the bounding box.
 *  \return TRUE if bounding box is visible, FALSE otherwise
 */
int visible (GschemToplevel *w_current,
             int wleft, int wtop, int wright, int wbottom)
{
  int visible=FALSE;
  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (gschem_toplevel_get_current_page_view (w_current));

  visible = clip_nochange (geometry, wleft, wtop, wright, wtop);

#if DEBUG
  printf("vis1 %d\n", visible);
#endif

  if (!visible) {
    visible = clip_nochange (geometry, wleft, wbottom, wright, wbottom);
  } else {
    return(visible);
  }

#if DEBUG
  printf("vis2 %d\n", visible);
#endif

  if (!visible) {
    visible = clip_nochange (geometry, wleft, wtop, wleft, wbottom);
  } else {
    return(visible);
  }

#if DEBUG
  printf("vis3 %d\n", visible);
#endif

  if (!visible) {
    visible = clip_nochange (geometry, wright, wtop, wright, wbottom);
  } else {
    return(visible);
  }

#if DEBUG
  printf("vis4 %d\n", visible);
#endif

#if DEBUG
  printf("%d %d %d\n", wleft, geometry->viewport_top, wright);
  printf("%d %d %d\n", wtop, geometry->viewport_top, wbottom);
  printf("%d %d %d\n", wleft, geometry->viewport_right, wright);
  printf("%d %d %d\n", wtop, geometry->viewport_bottom, wbottom);
#endif

  /*
   * now check to see if bounding box encompasses the entire viewport.
   * We only need to test if one point on the screen clipping boundary
   * is indide the bounding box of the object.
   */
  if (geometry->viewport_left >= wleft  &&
      geometry->viewport_left <= wright &&
      geometry->viewport_top >= wtop    &&
      geometry->viewport_top <= wbottom ) {
    visible = 1;
  }

#if DEBUG
  printf("vis5 %d\n", visible);
#endif

  return(visible);
}
Example #20
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);
    }
  }

}
Example #21
0
/*! \brief End the input of a box.
 *  \par Function Description
 *  This function ends the input of the second corner of a box.
 *  The (<B>w_x</B>,<B>w_y</B>) point is set to be this second corner. The box is
 *  then defined by (<B>w_current->first_wx</B>,<B>w_current->first_wy</B> and
 *  (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>.
 *  <B>w_x</B> and <B>w_y</B> are in screen unit.
 *
 *  The temporary box is erased ; a new box object is allocated, initialized
 *  and linked to the object list ; The object is finally drawn on the
 *  current sheet.
 *
 *  \param [in] w_current  The GschemToplevel object.
 *  \param [in] w_x        Current x coordinate of pointer in world units.
 *  \param [in] w_y        Current y coordinate of pointer in world units.
 */
void o_box_end(GschemToplevel *w_current, int w_x, int w_y)
{
  OBJECT *new_obj;

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

  g_assert( w_current->inside_action != 0 );

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

  TOPLEVEL *toplevel = page->toplevel;
  g_return_if_fail (toplevel != NULL);

  int box_width, box_height;
  int box_left, box_top;

  /* get the last coords of the pointer */
  w_current->second_wx = w_x;
  w_current->second_wy = w_y;

  /* erase the temporary box */
  /* o_box_invalidate_rubber (w_current); */
  w_current->rubber_visible = 0;

  box_width  = GET_BOX_WIDTH (w_current);
  box_height = GET_BOX_HEIGHT(w_current);
  box_left   = GET_BOX_LEFT  (w_current);
  box_top    = GET_BOX_TOP   (w_current);

  /* boxes with null width or height are not allowed */
  if ((box_width == 0) || (box_height == 0)) {
	  /* cancel the object creation */
	  w_current->first_wx = (-1);
	  w_current->first_wy = (-1);
	  w_current->second_wx  = (-1);
	  w_current->second_wy  = (-1);

  } else {

    /* create the object */
    new_obj = geda_box_object_new (toplevel, OBJ_BOX, GRAPHIC_COLOR,
                                   box_left, box_top,
                                   box_left + box_width, box_top - box_height);
    s_page_append (toplevel, page, new_obj);

#if DEBUG
  printf("coords: %d %d %d %d\n", box_left, box_top, box_width, box_height);
#endif

    w_current->first_wx = (-1);
    w_current->first_wy = (-1);
    w_current->second_wx  = (-1);
    w_current->second_wy  = (-1);

    /* Call add-objects-hook */
    g_run_hook_object (w_current, "%add-objects-hook", new_obj);

    gschem_toplevel_page_content_changed (w_current, page);
    o_undo_savestate(w_current, page, UNDO_ALL);
  }

  i_action_stop (w_current);
}
Example #22
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 = (OBJECT*) 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);
  }
}
Example #23
0
/*! \brief Opens a new page from a file.
 *  \par Function Description
 *  This function opens the file whose name is <B>filename</B> in a
 *  new PAGE of <B>toplevel</B>.
 *
 *  If there is no page for <B>filename</B> in <B>toplevel</B>'s list
 *  of pages, it creates a new PAGE, loads the file in it and returns
 *  a pointer on the new page. Otherwise it returns a pointer on the
 *  existing page.
 *
 *  If the filename passed is NULL, this function creates an empty,
 *  untitled page.  The name of the untitled page is build from
 *  configuration data ('untitled-name') and a counter for uniqueness.
 *
 *  The opened page becomes the current page of <B>toplevel</B>.
 *
 *  \param [in] w_current The toplevel environment.
 *  \param [in] filename The name of the file to open or NULL for a blank page.
 *  \returns A pointer on the new page.
 *
 *  \bug This code should check to make sure any untitled filename
 *  does not conflict with a file on disk.
 */
PAGE*
x_window_open_page (GschemToplevel *w_current, const gchar *filename)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current);
  PAGE *page;
  gchar *fn;

  g_return_val_if_fail (toplevel != NULL, NULL);

  /* Generate untitled filename if none was specified */
  if (filename == NULL) {
    gchar *cwd, *tmp, *untitled_name;
    EdaConfig *cfg;
    cwd = g_get_current_dir ();
    cfg = eda_config_get_context_for_path (cwd);
    untitled_name = eda_config_get_string (cfg, "gschem", "default-filename", NULL);
    tmp = g_strdup_printf ("%s_%d.sch",
                           untitled_name,
                           ++w_current->num_untitled);
    fn = g_build_filename (cwd, tmp, NULL);
    g_free (untitled_name);
    g_free(cwd);
    g_free(tmp);
  } else {
    fn = g_strdup (filename);
  }

  /* Return existing page if it is already loaded */
  page = s_page_search (toplevel, fn);
  if ( page != NULL ) {
    g_free(fn);
    return page;
  }

  page = s_page_new (toplevel, fn);
  s_page_goto (toplevel, page);
  gschem_toplevel_page_changed (w_current);

  /* Load from file if necessary, otherwise just print a message */
  if (filename != NULL) {
    GError *err = NULL;
    if (!quiet_mode)
      s_log_message (_("Loading schematic [%s]\n"), fn);

    if (!f_open (toplevel, page, (gchar *) fn, &err)) {
      GtkWidget *dialog;

      g_warning ("%s\n", err->message);
      dialog = gtk_message_dialog_new_with_markup
        (GTK_WINDOW (w_current->main_window),
         GTK_DIALOG_DESTROY_WITH_PARENT,
         GTK_MESSAGE_ERROR,
         GTK_BUTTONS_CLOSE,
         _("<b>An error occurred while loading the requested file.</b>\n\nLoading from '%s' failed: %s. The gschem log may contain more information."),
         fn, err->message);
      gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file"));
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      g_error_free (err);
    } else {
      gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL));
    }
  } else {
    if (!quiet_mode)
      s_log_message (_("New file [%s]\n"),
                     toplevel->page_current->page_filename);

    g_run_hook_page (w_current, "%new-page-hook", toplevel->page_current);
  }

  gschem_page_view_set_page (page_view,
                             toplevel->page_current);

  o_undo_savestate (w_current, toplevel->page_current, UNDO_ALL);

  /* This line is generally un-needed, however if some code
   * wants to open a page, yet not bring it to the front, it is
   * needed needed to add it into the page manager. Otherwise,
   * it will get done in x_window_set_current_page(...)
   */
  x_pagesel_update (w_current); /* ??? */

  g_free (fn);

  return page;
}
Example #24
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);
}
Example #25
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *  <B>type</B> can be one of the following values:
 *  <DL>
 *    <DT>*</DT><DD>UNDO_ACTION
 *    <DT>*</DT><DD>REDO_ACTION
 *  </DL>
 */
void
o_undo_callback (GschemToplevel *w_current, PAGE *page, int type)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  UNDO *u_current;
  UNDO *u_next;
  UNDO *save_bottom;
  UNDO *save_tos;
  UNDO *save_current;
  int save_logging;
  int find_prev_data=FALSE;

  char *save_filename;

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

  if (w_current->undo_control == FALSE) {
    s_log_message(_("Undo/Redo disabled in rc file\n"));
    return;
  }

  if (page->undo_current == NULL) {
    return;
  }

  if (type == UNDO_ACTION) {
    u_current = page->undo_current->prev;
  } else {
    u_current = page->undo_current->next;
  }

  u_next = page->undo_current;

  if (u_current == NULL) {
    return;
  }

  if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) {
#if DEBUG
    printf("Type: %d\n", u_current->type);
    printf("Current is an undo all, next is viewport only!\n");
#endif
    find_prev_data = TRUE;

    if (w_current->undo_type == UNDO_DISK) {
      u_current->filename = o_undo_find_prev_filename(u_current);
    } else {
      u_current->object_list = o_undo_find_prev_object_head (u_current);
    }
  }

  /* save filename */
  save_filename = g_strdup (page->page_filename);

  /* save structure so it's not nuked */
  save_bottom = page->undo_bottom;
  save_tos = page->undo_tos;
  save_current = page->undo_current;
  page->undo_bottom = NULL;
  page->undo_tos = NULL;
  page->undo_current = NULL;

  o_select_unselect_all (w_current);

  if (w_current->undo_type == UNDO_DISK && u_current->filename) {
    /* delete objects of page */
    s_page_delete_objects (toplevel, page);

    /* Free the objects in the place list. */
    geda_object_list_delete (toplevel, page->place_list);
    page->place_list = NULL;

    gschem_toplevel_page_content_changed (w_current, page);
  } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) {
    /* delete objects of page */
    s_page_delete_objects (toplevel, page);

    /* Free the objects in the place list. */
    geda_object_list_delete (toplevel, page->place_list);
    page->place_list = NULL;

    gschem_toplevel_page_content_changed (w_current, page);
  }


  /* temporarily disable logging */
  save_logging = do_logging;
  do_logging = FALSE;

  if (w_current->undo_type == UNDO_DISK && u_current->filename) {

    f_open(toplevel, page, u_current->filename, NULL);

  } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) {

    s_page_append_list (toplevel, page,
                        o_glist_copy_all (toplevel, u_current->object_list,
                                          NULL));
  }

  page->page_control = u_current->page_control;
  page->up = u_current->up;
  gschem_toplevel_page_content_changed (w_current, page);

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

  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view);

  if (u_current->scale != 0) {
    gschem_page_geometry_set_viewport (geometry,
                                       u_current->x,
                                       u_current->y,
                                       u_current->scale);
    gschem_page_view_invalidate_all (view);
  } else {
    gschem_page_view_zoom_extents (view, u_current->object_list);
  }

  /* restore logging */
  do_logging = save_logging;

  /* set filename right */
  g_free(page->page_filename);
  page->page_filename = save_filename;

  /* final redraw */
  x_pagesel_update (w_current);
  x_multiattrib_update (w_current);
  i_update_menus(w_current);

  /* restore saved undo structures */
  page->undo_bottom = save_bottom;
  page->undo_tos = save_tos;
  page->undo_current = save_current;

  if (type == UNDO_ACTION) {
    if (page->undo_current) {
      page->undo_current = page->undo_current->prev;
      if (page->undo_current == NULL) {
        page->undo_current = page->undo_bottom;
      }
    }
  } else { /* type is REDO_ACTION */
    if (page->undo_current) {
      page->undo_current = page->undo_current->next;
      if (page->undo_current == NULL) {
        page->undo_current = page->undo_tos;
      }
    }
  }

  /* don't have to free data here since filename, object_list are */
  /* just pointers to the real data (lower in the stack) */
  if (find_prev_data) {
    u_current->filename = NULL;
    u_current->object_list = NULL;
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif
}
Example #26
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *
 *  <B>flag</B> can be one of the following values:
 *  <DL>
 *    <DT>*</DT><DD>UNDO_ALL
 *    <DT>*</DT><DD>UNDO_VIEWPORT_ONLY
 *  </DL>
 */
void
o_undo_savestate (GschemToplevel *w_current, PAGE *page, int flag)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  char *filename = NULL;
  GList *object_list = NULL;
  int levels;
  UNDO *u_current;
  UNDO *u_current_next;

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

  g_return_if_fail (page != NULL);

  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view);

  /* save autosave backups if necessary */
  o_autosave_backups(w_current);

  if (w_current->undo_control == FALSE) {
    return;
  }

  if (flag == UNDO_ALL) {

    /* Increment the number of operations since last backup if
       auto-save is enabled */
    if (toplevel->auto_save_interval != 0) {
      page->ops_since_last_backup++;
    }

    /* HACK */
    /* Before we save the undo state, consolidate nets as necessary */

    /* This is where the net consolidation call would have been
     * triggered before it was removed from o_save_buffer().
     */
    if (toplevel->net_consolidate == TRUE)
      geda_net_object_consolidate (toplevel, page);
  }

  if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) {

    filename = g_strdup_printf("%s%cgschem.save%d_%d.sch",
                               tmp_path, G_DIR_SEPARATOR,
                               prog_pid, undo_file_index++);

    /* Changed from f_save to o_save when adding backup copy creation. */
    /* f_save manages the creaton of backup copies.
       This way, f_save is called only when saving a file, and not when
       saving an undo backup copy */
    o_save (toplevel, s_page_objects (page), filename, NULL);

  } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) {
    object_list = o_glist_copy_all (toplevel,
                                    s_page_objects (page),
                                    object_list);
  }

  /* Clear Anything above current */
  if (page->undo_current) {
    s_undo_remove_rest(toplevel, page->undo_current->next);
    page->undo_current->next = NULL;
  } else { /* undo current is NULL */
    s_undo_remove_rest(toplevel, page->undo_bottom);
    page->undo_bottom = NULL;
  }

  page->undo_tos = page->undo_current;

  if (geometry != NULL) {
    page->undo_tos = s_undo_add(page->undo_tos,
                                flag, filename, object_list,
                                (geometry->viewport_left + geometry->viewport_right) / 2,
                                (geometry->viewport_top + geometry->viewport_bottom) / 2,
                                /* scale */
                                max (((double) abs (geometry->viewport_right - geometry->viewport_left) / geometry->screen_width),
                                  ((double) abs (geometry->viewport_top - geometry->viewport_bottom) / geometry->screen_height)),
                                page->page_control,
                                page->up);
  } else {
    page->undo_tos = s_undo_add(page->undo_tos,
                                flag, filename, object_list,
                                0, /* center x */
                                0, /* center y */
                                0, /* scale */
                                page->page_control,
                                page->up);
  }

  page->undo_current =
      page->undo_tos;

  if (page->undo_bottom == NULL) {
    page->undo_bottom =
        page->undo_tos;
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("BOTTOM: %s\n", page->undo_bottom->filename);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif

  g_free(filename);

  /* Now go through and see if we need to free/remove some undo levels */
  /* so we stay within the limits */

  /* only check history every 10 undo savestates */
  if (undo_file_index % 10) {
    return;
  }

  levels = s_undo_levels(page->undo_bottom);

#if DEBUG
  printf("levels: %d\n", levels);
#endif

  if (levels >= w_current->undo_levels + UNDO_PADDING) {
    levels = levels - w_current->undo_levels;

#if DEBUG
    printf("Trimming: %d levels\n", levels);
#endif

    u_current = page->undo_bottom;

    while (levels > 0) {
      /* Because we use a pad you are always guaranteed to never */
      /* exhaust the list */
      g_assert (u_current != NULL);

      u_current_next = u_current->next;

      if (u_current->filename) {
#if DEBUG
        printf("Freeing: %s\n", u_current->filename);
#endif
        unlink(u_current->filename);
        g_free(u_current->filename);
      }

      if (u_current->object_list) {
        geda_object_list_delete (toplevel, u_current->object_list);
        u_current->object_list = NULL;
      }

      u_current->next = NULL;
      u_current->prev = NULL;
      g_free(u_current);

      u_current = u_current_next;
      levels--;
    }

    g_assert (u_current != NULL);
    u_current->prev = NULL;
    page->undo_bottom = u_current;

#if DEBUG
    printf("New current is: %s\n", u_current->filename);
#endif
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("BOTTOM: %s\n", page->undo_bottom->filename);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif

}
Example #27
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);
}
Example #28
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);
}
Example #29
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);
}
Example #30
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);
}