Hi all,

I've just gotten started working with geda.  Up until now I'd been doing
all of my
work using eaglecad but I'm starting to outgrow its functionality and
I'd really like to
use truly free tools.

After playing with gschem for a while, I decided to try my hand at an
alternate
implementation for adding nets.  Basically now when you draw a net in
orthogonal
mode two nets are drawn.  Say you started the net at (0,0) and now your
mouse is at (15,10).  One net will be drawn horizontally from (0,0) to
(15,0) and the other
from (15,0) to (15,10).

See screenshots of these two scenarios:
Drawing net: http://oscar.dcarr.org/geda/gschem_net_1.png
Net created: http://oscar.dcarr.org/geda/gschem_net_2.png

This part seems to be working pretty well.  However I used to sometimes
get segfaults.
Now they've magically disappeared. 

The problem occurred in the function o_net_end ( in o_net.c --- .nw,
whatever)
At the second call to "o_cue_undraw_list(w_current, other_objects)" line
546.
What do these calls do? 

Also please look at lines 477, 522 and 559.  Am I leaking anything here?

I'll attach the actual file (hope thats not uncool).
Its also online at: http://oscar.dcarr.org/geda/o_net.c
Also note that I added two doubles (second_x, second_y) to libgeda's
"struct st_toplevel" in struct.h that hold the last endpoint of the
second net.

I'd appreciate any comments on this work --- positive or negative.  I
think that once I finish
that this mode may be useful but others may or may not feel that way.

Thanks for your time,
David Carr

#line 29 "../noweb/o_net.nw"
/* gEDA - GPL Electronic Design Automation
 * gschem - gEDA Schematic Capture
 * Copyright (C) 1998-2000 Ales V. Hvezda
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
 */


#line 11 "../noweb/o_net.nw"
/* DO NOT read or edit this file ! Use ../noweb/o_net.nw instead */

#line 52 "../noweb/o_net.nw"
#include <config.h>

#include <stdio.h>
#include <math.h>

#include <libgeda/libgeda.h>

#include "../include/globals.h"
#include "../include/prototype.h"

#ifdef HAVE_LIBDMALLOC
#include <dmalloc.h>
#endif

#line 75 "../noweb/o_net.nw"
void o_net_draw(TOPLEVEL * w_current, OBJECT * o_current)
{
  int size;
  int x1, y1, x2, y2;           /* screen coords */

#if NET_DEBUG                   /* debug */
  char *tempstring;
  GdkFont *font;
#endif

  if (o_current == NULL) {
    return;
  }

  if (o_current->line == NULL) {
    return;
  }

  o_net_recalc(w_current, o_current);

  /* reuse line's routine */
  if (!o_line_visible(w_current, o_current->line, &x1, &y1, &x2, &y2)) {
    return;
  }
#if DEBUG
  printf("drawing net\n\n");
#endif

  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);

    if (size < 0)
      size = 0;

    gdk_gc_set_line_attributes(w_current->gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_BUTT, GDK_CAP_NOT_LAST);

    gdk_gc_set_line_attributes(w_current->bus_gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_BUTT, GDK_CAP_NOT_LAST);
  }

  if (w_current->override_color != -1) {

    gdk_gc_set_foreground(w_current->gc,
                          x_get_color(w_current->override_color));

    gdk_draw_line(w_current->window, w_current->gc, x1, y1, x2, y2);
    gdk_draw_line(w_current->backingstore, w_current->gc, x1, y1, x2, y2);
  } else {

    gdk_gc_set_foreground(w_current->gc, x_get_color(o_current->color));
    gdk_draw_line(w_current->window, w_current->gc, x1, y1, x2, y2);
    gdk_draw_line(w_current->backingstore, w_current->gc, x1, y1, x2, y2);


#if NET_DEBUG
    /* temp debug only */
    font = gdk_fontset_load("10x20");
    tempstring = g_strdup_printf("%s", o_current->name);
    gdk_draw_text(w_current->window,
                  font,
                  w_current->gc,
                  x1 + 20, y1 + 20, tempstring, strlen(tempstring));
    gdk_draw_text(w_current->backingstore,
                  font,
                  w_current->gc,
                  x1 + 20, y1 + 20, tempstring, strlen(tempstring));
    gdk_font_unref(font);
    free(tempstring);
#endif
  }

#if DEBUG
  printf("drew net\n\n");
#endif

  /* yes zero is right for the width -> use hardware lines */
  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);

    gdk_gc_set_line_attributes(w_current->bus_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  if (o_current->draw_grips && w_current->draw_grips == TRUE) {

    /* pb20011109 - modified to use the new o_line_[draw|erase]_grips() */
    /*              reuse the line functions */
    if (!o_current->selected) {
      /* object is no more selected, erase the grips */
      o_current->draw_grips = FALSE;
      o_line_erase_grips(w_current, o_current);
    } else {
      /* object is selected, draw the grips */
      o_line_draw_grips(w_current, o_current);
    }

  }
}


#line 205 "../noweb/o_net.nw"
void o_net_erase(TOPLEVEL * w_current, OBJECT * o_current)
{
  w_current->override_color = w_current->background_color;
  o_net_draw(w_current, o_current);
  w_current->override_color = -1;
}


#line 223 "../noweb/o_net.nw"
void
o_net_draw_xor(TOPLEVEL * w_current, int dx, int dy, OBJECT * o_current)
{
  int size;
  int color;

  if (o_current->line == NULL) {
    return;
  }

  if (o_current->saved_color != -1) {
    color = o_current->saved_color;
  } else {
    color = o_current->color;
  }

  gdk_gc_set_foreground(w_current->outline_xor_gc, x_get_darkcolor(color));

  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);
    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size + 1,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
                o_current->line->screen_x[0] + dx,
                o_current->line->screen_y[0] + dy,
                o_current->line->screen_x[1] + dx,
                o_current->line->screen_y[1] + dy);

  /* backing store ? not approriate here */

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
}


#line 276 "../noweb/o_net.nw"
void
o_net_draw_xor_single(TOPLEVEL * w_current, int dx, int dy, int whichone,
                      OBJECT * o_current)
{
  int color;
  int dx1 = -1, dx2 = -1, dy1 = -1, dy2 = -1;

  if (o_current->line == NULL) {
    return;
  }

  if (o_current->saved_color != -1) {
    color = o_current->saved_color;
  } else {
    color = o_current->color;
  }

  gdk_gc_set_foreground(w_current->outline_xor_gc, x_get_darkcolor(color));

#if 0                           /* if I had this enabled, than xoring would 
leave a lot of mouse drops */
  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);
    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size + 1,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
#endif

  if (whichone == 0) {
    dx1 = dx;
    dy1 = dy;
    dx2 = 0;
    dy2 = 0;
  } else if (whichone == 1) {
    dx2 = dx;
    dy2 = dy;
    dx1 = 0;
    dy1 = 0;
  } else {
    fprintf(stderr,
            _("Got an invalid which one in o_net_draw_xor_single\n"));
  }

  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
                o_current->line->screen_x[0] + dx1,
                o_current->line->screen_y[0] + dy1,
                o_current->line->screen_x[1] + dx2,
                o_current->line->screen_y[1] + dy2);

  /* backing store ? not approriate here */

#if 0                           /* if I had this enabled, than xoring would 
leave a lot of mouse drops */
  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
#endif
}


#line 348 "../noweb/o_net.nw"
void o_net_start(TOPLEVEL * w_current, int x, int y)
{
  int size;

  /* initalize all parameters used when drawing the new net */
  w_current->last_x = w_current->start_x = w_current->second_x = 
fix_x(w_current, x);
  w_current->last_y = w_current->start_y = w_current->second_y = 
fix_y(w_current, y);


#if 0                           /* not ready for prime time use, this is the 
snap any point #if 0 */
  int distance1;
  int distance2;
  OBJECT *real;
  OBJECT *o_current;
  int temp_x, temp_y;
  o_current = o_CONN_search_closest_range(w_current,
                                          w_current->page_current->
                                          object_head, w_current->start_x,
                                          w_current->start_y, &temp_x,
                                          &temp_y, 200, NULL, NULL);

  if (o_current) {
    w_current->last_x = w_current->start_x = temp_x;
    w_current->last_y = w_current->start_y = temp_y;
  } else {
    w_current->last_x = w_current->start_x = fix_x(w_current, x);
    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  }
#endif

#if 0                           /* not ready for prime time use */
  /* new net extenstion stuff */
  o_current = w_current->page_current->selection_head->next;
  if (o_current != NULL && w_current->event_state == STARTDRAWNET) {
    if (o_current->type == OBJ_NET) {
      if (o_current->line) {

        real = o_list_sear(     /* ch */
                            w_current->page_current->object_head,
                            o_current);

        if (!real) {
          fprintf(stderr, _("selected a nonexistant object!\n"));
          exit(-1);
        }
        distance1 = dist(real->line->screen_x[0],
                         real->line->screen_y[0],
                         w_current->start_x, w_current->start_y);

        distance2 = dist(real->line->screen_x[1],
                         real->line->screen_y[1],
                         w_current->start_x, w_current->start_y);

        printf("%d %d\n", distance1, distance2);

        if (distance1 < distance2) {
          w_current->last_x = w_current->start_x = real->line->screen_x[0];
          w_current->last_y = w_current->start_y = real->line->screen_y[0];
        } else {
          w_current->last_x = w_current->start_x = real->line->screen_x[1];
          w_current->last_y = w_current->start_y = real->line->screen_y[1];
        }
      }
    } else if (o_current->type == OBJ_COMPLEX ||
               o_current->type == OBJ_PLACEHOLDER) {
      real = o_list_sear(       /* ch */
                          w_current->page_current->object_head, o_current);

      if (!real) {
        fprintf(stderr, _("selected a nonexistant object!\n"));
        exit(-1);
      }

      o_CONN_search_closest(w_current, o_current->complex,
                            w_current->start_x, w_current->start_y,
                            &temp_x, &temp_y, NULL);
      w_current->last_x = w_current->start_x = temp_x;
      w_current->last_y = w_current->start_y = temp_y;
    }

  }
#endif

  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);
    gdk_gc_set_line_attributes(w_current->xor_gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  gdk_gc_set_foreground(w_current->xor_gc,
                        x_get_darkcolor(w_current->select_color));
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->start_x, w_current->start_y,
                w_current->last_x, w_current->last_y);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
}


#line 468 "../noweb/o_net.nw"
int o_net_end(TOPLEVEL * w_current, int x, int y)
{
  int x1, y1;
  int x2, y2;
  int x3, y3;
  int color;
  int size;
  /*int temp_x, temp_y; */
  /* OBJECT *o_current; */
  GList *other_objects = NULL;
  OBJECT *new_net = NULL;

  if (w_current->inside_action == 0) {
    o_redraw(w_current, w_current->page_current->object_head);
    return (FALSE);
  }

  if (w_current->override_net_color == -1) {
    color = w_current->net_color;
  } else {
    color = w_current->override_net_color;
  }

  size = SCREENabs(w_current, NET_WIDTH);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->xor_gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  gdk_gc_set_foreground(w_current->xor_gc,
                        x_get_darkcolor(w_current->select_color));
  /* Erase primary rubber net line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->start_x, w_current->start_y,
                w_current->last_x, w_current->last_y);

  /* Erase secondary rubber net line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                 w_current->last_x, w_current->last_y,
                 w_current->second_x, w_current->second_y);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
    gdk_gc_set_line_attributes(w_current->gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  /* don't allow zero length nets */
  /* this ends the net drawing behavior we want this? hack */
  if ((w_current->start_x == w_current->last_x) &&
      (w_current->start_y == w_current->last_y)) {
    w_current->start_x = (-1);
    w_current->start_y = (-1);
    w_current->last_x = (-1);
    w_current->last_y = (-1);
    w_current->second_x = (-1);
    w_current->second_y = (-1);
    w_current->inside_action = 0;
    i_set_state(w_current, STARTDRAWNET);
    o_net_eraserubber(w_current);
    
    return (FALSE);
  }
#if 0                           /* not ready for prime time use */
  /* second attempt at all snapping */
  o_current = o_CONN_search_closest_range(w_current,
                                          w_current->page_current->
                                          object_head, w_current->last_x,
                                          w_current->last_y, &temp_x,
                                          &temp_y, 200, NULL, NULL);

  if (o_current) {
    w_current->last_x = temp_x;
    w_current->last_y = temp_y;
  } else {
    w_current->last_x = fix_x(w_current, x);
    w_current->last_y = fix_y(w_current, y);
  }
#endif


  /* Primary net runs from (x1,y1)-(x2,y2) */
  /* Secondary net from (x2,y2)-(x3,y3) */
  SCREENtoWORLD(w_current, w_current->start_x, w_current->start_y, &x1,
                &y1);
  SCREENtoWORLD(w_current, w_current->last_x, w_current->last_y, &x2, &y2);
  SCREENtoWORLD(w_current, w_current->second_x, w_current->second_y, &x3, &y3);

  /* Snap points to closest grid location */
  x1 = snap_grid(w_current, x1);
  y1 = snap_grid(w_current, y1);
  x2 = snap_grid(w_current, x2);
  y2 = snap_grid(w_current, y2);
  x3 = snap_grid(w_current, x3);
  y3 = snap_grid(w_current, y3);

  w_current->save_x = w_current->second_x;
  w_current->save_y = w_current->second_y;

  /* create primary net */
  w_current->page_current->object_tail =
      new_net = o_net_add(w_current,
                          w_current->page_current->object_tail,
                          OBJ_NET, color, x1, y1, x2, y2);
  
  /* conn stuff */
  other_objects = s_conn_return_others(other_objects,
                                       w_current->page_current->
                                       object_tail);

  if (o_net_add_busrippers(w_current, new_net, other_objects)) {
    g_list_free(other_objects);
    other_objects = NULL;
    other_objects = s_conn_return_others(other_objects, new_net);
  }
#if DEBUG
  s_conn_print(new_net->conn_list);
#endif

  gdk_gc_set_foreground(w_current->gc, x_get_color(color));
  gdk_draw_line(w_current->window, w_current->gc,
                new_net->line->screen_x[0], new_net->line->screen_y[0],
                new_net->line->screen_x[1], new_net->line->screen_y[1]);
  gdk_draw_line(w_current->backingstore, w_current->gc,
                new_net->line->screen_x[0], new_net->line->screen_y[0],
                new_net->line->screen_x[1], new_net->line->screen_y[1]);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  o_cue_undraw_list(w_current, other_objects);
  o_cue_draw_list(w_current, other_objects);
  o_cue_draw_single(w_current, new_net);

  /* you don't want to consolidate nets which are drawn non-ortho */
  if (w_current->net_consolidate == TRUE && !w_current->CONTROLKEY) {
    o_net_consolidate_segments(w_current, new_net);
  }

  /* If the second net is not zero length, add it as well */
  if (x3 != x2 || y3 != y2) {
      
      w_current->page_current->object_tail =
          new_net = o_net_add(w_current,
                              w_current->page_current->object_tail,
                              OBJ_NET, color, x2, y2, x3, y3);
  
      /* conn stuff */
      other_objects = s_conn_return_others(other_objects,
                                           w_current->page_current->
                                           object_tail);

      if (o_net_add_busrippers(w_current, new_net, other_objects)) {
          g_list_free(other_objects);
          other_objects = NULL;
          other_objects = s_conn_return_others(other_objects, new_net);
      }
#if DEBUG
      s_conn_print(new_net->conn_list);
#endif

      gdk_gc_set_foreground(w_current->gc, x_get_color(color));
      gdk_draw_line(w_current->window, w_current->gc,
                    new_net->line->screen_x[0], new_net->line->screen_y[0],
                    new_net->line->screen_x[1], new_net->line->screen_y[1]);
      gdk_draw_line(w_current->backingstore, w_current->gc,
                    new_net->line->screen_x[0], new_net->line->screen_y[0],
                    new_net->line->screen_x[1], new_net->line->screen_y[1]);

      if (w_current->net_style == THICK) {
          gdk_gc_set_line_attributes(w_current->gc, 0,
                                     GDK_LINE_SOLID,
                                     GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
      }

      o_cue_undraw_list(w_current, other_objects);
      o_cue_draw_list(w_current, other_objects);
      o_cue_draw_single(w_current, new_net);

      /* you don't want to consolidate nets which are drawn non-ortho */
      if (w_current->net_consolidate == TRUE && !w_current->CONTROLKEY) {
          o_net_consolidate_segments(w_current, new_net);
      }
  }
  
  g_list_free(other_objects);

  w_current->page_current->CHANGED = 1;
  w_current->start_x = w_current->save_x;
  w_current->start_y = w_current->save_y;
  o_undo_savestate(w_current, UNDO_ALL);

#if 0                           /* a false attempt at ending the 
rubberbanding.. */
  if (conn_count) {
    w_current->inside_action = 0;
    i_set_state(w_current, STARTDRAWNET);
    o_net_eraserubber(w_current);
  }
#endif

  return (TRUE);
}


#line 631 "../noweb/o_net.nw"
void o_net_rubbernet(TOPLEVEL * w_current, int x, int y)
{
  int diff_x, diff_y;
  int size;
  int ortho;

  if (w_current->inside_action == 0) {
    o_redraw(w_current, w_current->page_current->object_head);
    return;
  }

  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);
    gdk_gc_set_line_attributes(w_current->xor_gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
  gdk_gc_set_foreground(w_current->xor_gc,
                        x_get_darkcolor(w_current->select_color));

  /* Orthognal mode enabled when Control Key is NOT pressed */
  ortho = !w_current->CONTROLKEY;

  /* Erase primary line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->start_x, w_current->start_y,
                w_current->last_x, w_current->last_y);
  /* Erase secondary line*/
  if ( w_current->second_x != -1 && w_current->second_y != -1 ) {
      gdk_draw_line(w_current->window, w_current->xor_gc,
                    w_current->last_x, w_current->last_y,
                    w_current->second_x, w_current->second_y);
  }
 
  /* In orthogonal mode secondary line is the same as the first */
  if (!ortho)
  {
      w_current->second_x = w_current->last_x;
      w_current->second_y = w_current->last_y;
  }

  w_current->last_x = fix_x(w_current, x);
  w_current->last_y = fix_y(w_current, y);

  /* If you press the control key then you can draw non-ortho nets */
  if (ortho) {
    diff_x = abs(w_current->last_x - w_current->start_x);
    diff_y = abs(w_current->last_y - w_current->start_y);

    /* calculate the co-ordinates necessary to draw the lines*/
    if (diff_x >= diff_y) {
      w_current->last_y = w_current->start_y;

      w_current->second_x = w_current->last_x;
      w_current->second_y = mouse_y;
    } else {
      w_current->last_x = w_current->start_x;

      w_current->second_x = mouse_x;
      w_current->second_y = w_current->last_y;
    }
  }

  gdk_gc_set_foreground(w_current->xor_gc,
                        x_get_darkcolor(w_current->select_color));
  
  /* draw primary line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->start_x, w_current->start_y,
                w_current->last_x, w_current->last_y);

  /* Draw secondary line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->last_x, w_current->last_y,
                w_current->second_x, w_current->second_y);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
}


#line 701 "../noweb/o_net.nw"
/* used in button cancel code in x_events.c */
void o_net_eraserubber(TOPLEVEL * w_current)
{
  int size;

  if (w_current->net_style == THICK) {
    size = SCREENabs(w_current, NET_WIDTH);

    if (size < 0)
      size = 0;

    gdk_gc_set_line_attributes(w_current->gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  gdk_gc_set_foreground(w_current->gc,
                        x_get_color(w_current->background_color));

  /* Erase primary primary rubber net line */
  gdk_draw_line(w_current->window, w_current->gc, w_current->start_x,
                w_current->start_y, w_current->last_x, w_current->last_y);

  /* Erase secondary rubber net line */
  gdk_draw_line(w_current->window, w_current->xor_gc,
                w_current->last_x, w_current->last_y,
                w_current->second_x, w_current->second_y);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
}


#line 741 "../noweb/o_net.nw"
/* used in button cancel code in x_events.c */
void o_net_xorrubber(TOPLEVEL * w_current)
{
  int size;

  if (w_current->net_style == THICK) {

    size = SCREENabs(w_current, NET_WIDTH);

    if (size < 0)
      size = 0;

    gdk_gc_set_line_attributes(w_current->gc, size,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }

  gdk_gc_set_foreground(w_current->gc,
                        x_get_darkcolor(w_current->select_color));
  gdk_draw_line(w_current->window, w_current->gc,
                w_current->start_x, w_current->start_y,
                w_current->last_x, w_current->last_y);

  if (w_current->net_style == THICK) {
    gdk_gc_set_line_attributes(w_current->gc, 0,
                               GDK_LINE_SOLID,
                               GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  }
}


#line 784 "../noweb/o_net.nw"
int
o_net_add_busrippers(TOPLEVEL * w_current, OBJECT * net_obj,
                     GList * other_objects)
{
  int color;
  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;
  char *clib = NULL;

  length = o_line_length(net_obj);

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

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

  if (w_current->override_net_color == -1) {
    color = w_current->net_color;
  } else {
    color = w_current->override_net_color;
  }


  /* check for a bus connection and draw rippers if so */
  cl_current = other_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 = cl_current2->next;
      }

      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;
          o_net_recalc(w_current, net_obj);
          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;
          o_net_recalc(w_current, net_obj);
          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;
          o_net_recalc(w_current, net_obj);
          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;
          o_net_recalc(w_current, net_obj);
          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 = cl_current->next;
  }

  if (made_changes) {
    s_conn_remove(w_current, net_obj);

    if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
      const GSList *clibs =
          s_clib_search_basename(w_current->bus_ripper_symname);
      if (clibs != NULL) {
        clib = (gchar *) clibs->data;
      }
    }

    for (i = 0; i < ripper_count; i++) {
      if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
        w_current->page_current->object_tail =
            o_net_add(w_current, w_current->page_current->object_tail,
                      OBJ_NET, color,
                      rippers[i].x[0], rippers[i].y[0],
                      rippers[i].x[1], rippers[i].y[1]);
      } else {

        if (clib) {
          w_current->page_current->object_tail =
              (OBJECT *) o_complex_add(w_current,
                                       w_current->page_current->
                                       object_tail, OBJ_COMPLEX, WHITE,
                                       rippers[i].x[0], rippers[i].y[0],
                                       complex_angle, 0, clib,
                                       w_current->bus_ripper_symname, 1,
                                       TRUE);

          o_complex_draw(w_current, w_current->page_current->object_tail);
        } else {
          s_log_message(_("Could not find %s in any component-library\n"),
                        w_current->bus_ripper_symname);
        }
      }
    }

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

  return (FALSE);
}

Reply via email to