Exemplo n.º 1
0
/*! \brief Invalidate bounding box or outline for OBJECT placement
 *
 *  \par Function Description
 *  This function invalidates the bounding box where objects would be
 *  drawn by o_place_draw_rubber()
 *
 * 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.
 *
 * The "drawing" parameter is used to indicate if this drawing should
 * immediately use the selected feedback mode and positioning constraints.
 *
 * With drawing=TRUE, the selected conditions are used immediately,
 * otherwise the conditions from the last drawing operation are used,
 * saving the new state for next time.
 *
 * This function should be called with drawing=TRUE when starting a
 * rubberbanding operation and when otherwise refreshing the rubberbanded
 * outline (e.g. after a screen redraw). For any undraw operation, should
 * be called with drawing=FALSE, ensuring that the undraw XOR matches the
 * mode and constraints of the corresponding "draw" operation.
 *
 * If any mode / constraint changes are made between a undraw, redraw XOR
 * pair, the latter (draw) operation must be called with drawing=TRUE. If
 * no mode / constraint changes were made between the pair, it is not
 * harmful to call the draw operation with "drawing=FALSE".
 *
 *  \param [in] w_current   GschemToplevel which we're drawing for.
 *  \param [in] drawing     Set to FALSE for undraw operations to ensure
 *                            matching conditions to a previous draw operation.
 */
void o_place_invalidate_rubber (GschemToplevel *w_current, int drawing)
{
  int diff_x, diff_y;
  int left, top, bottom, right;

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

  /* If drawing is true, then don't worry about the previous drawing
   * method and movement constraints, use with the current settings */
  if (drawing) {
    /* Ensure we set this to flag there is "something" supposed to be
     * drawn when the invalidate call below causes an expose event. */
    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 */

  /* Need to update the w_current->{first,second}_w{x,y} coords even
   * though we're only invalidating because the move rubberband code
   * (which may execute right after this function) expects these
   * coordinates to be correct.
   */
  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;
    }
  }

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

  gschem_page_view_invalidate_world_rect (page_view,
                                          left + diff_x,
                                          top + diff_y,
                                          right + diff_x,
                                          bottom + diff_y);
}
Exemplo n.º 2
0
/*! \brief Updates the preview widget.
 *  \par Function Description
 *  This function update the preview: if the preview is active and a
 *  filename has been given, it opens the file and display
 *  it. Otherwise it display a blank page.
 *
 *  \param [in] preview The preview widget.
 */
static void
preview_update (Preview *preview)
{
  GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
  TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
  int left, top, right, bottom;
  int width, height;

  if (preview_toplevel->page_current == NULL) {
    return;
  }
  
  /* delete old preview, create new page */
  /* it would be better to just resets current page - Fix me */
  s_page_delete (preview_toplevel, preview_toplevel->page_current);
  s_page_goto (preview_toplevel, s_page_new (preview_toplevel, "preview"));
  
  if (preview->active) {
    g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
    if (preview->filename != NULL) {
      /* open up file in current page */
      f_open_flags (preview_toplevel, preview_toplevel->page_current,
                    preview->filename,
                    F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
      /* test value returned by f_open... - Fix me */
      /* we should display something if there an error occured - Fix me */
    }
    if (preview->buffer != NULL) {

      /* Load the data buffer */
      s_page_append_list (preview_toplevel, preview_toplevel->page_current,
                          o_read_buffer (preview_toplevel,
                                         NULL, preview->buffer, -1,
                                         _("Preview Buffer")));
    }
  }

  if (world_get_object_glist_bounds (preview_toplevel,
                                     s_page_objects (preview_toplevel->page_current),
                                     &left, &top,
                                     &right, &bottom)) {
    /* Clamp the canvas size to the extents of the page being previewed */
    width = right - left;
    height = bottom - top;
    preview_toplevel->init_left   = left  - ((double)width * OVER_ZOOM_FACTOR);
    preview_toplevel->init_right  = right + ((double)width * OVER_ZOOM_FACTOR);
    preview_toplevel->init_top    = top    - ((double)height * OVER_ZOOM_FACTOR);
    preview_toplevel->init_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
  }

  /* display current page (possibly empty) */
  a_zoom_extents (preview_w_current,
                  s_page_objects (preview_toplevel->page_current),
                  A_PAN_DONT_REDRAW);
  o_invalidate_all (preview_w_current);
  
}
Exemplo n.º 3
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.
 *
 * The "drawing" parameter is used to indicate if this drawing should
 * immediately use the selected feedback mode and positioning constraints.
 *
 * With drawing=TRUE, the selected conditions are used immediately,
 * otherwise the conditions from the last drawing operation are used,
 * saving the new state for next time.
 *
 * This function should be called with drawing=TRUE when starting a
 * rubberbanding operation and when otherwise refreshing the rubberbanded
 * outline (e.g. after a screen redraw). For any undraw operation, should
 * be called with drawing=FALSE, ensuring that the undraw XOR matches the
 * mode and constraints of the corresponding "draw" operation.
 *
 * If any mode / constraint changes are made between a undraw, redraw XOR
 * pair, the latter (draw) operation must be called with drawing=TRUE. If
 * no mode / constraint changes were made between the pair, it is not
 * harmful to call the draw operation with "drawing=FALSE".
 *
 *  \param [in] w_current   GSCHEM_TOPLEVEL which we're drawing for.
 *  \param [in] drawing     Set to FALSE for undraw operations to ensure
 *                            matching conditions to a previous draw operation.
 */
void o_place_draw_rubber (GSCHEM_TOPLEVEL *w_current, int drawing)
{
  TOPLEVEL *toplevel = w_current->toplevel;
  int diff_x, diff_y;
  int left, top, bottom, right;

  g_return_if_fail (toplevel->page_current->place_list != NULL);

  /* If drawing is true, then don't worry about the previous drawing
   * method and movement constraints, use with the current settings */
  if (drawing) {
    w_current->last_drawb_mode = w_current->actionfeedback_mode;
    w_current->drawbounding_action_mode = (w_current->CONTROLKEY)
                                            ? 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;
    }
  }

  /* Draw with the appropriate mode */
  if (w_current->last_drawb_mode == BOUNDINGBOX) {

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

    gschem_cairo_box (w_current, 0, left  + diff_x, top    + diff_y,
                                    right + diff_x, bottom + diff_y);

    gschem_cairo_set_source_color (w_current,
                                   x_color_lookup_dark (BOUNDINGBOX_COLOR));
    gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
  } else {
    o_glist_draw_place (w_current, diff_x, diff_y,
                        toplevel->page_current->place_list);
  }

  /* Save movement constraints and drawing method for any
   * corresponding undraw operation. */
  w_current->last_drawb_mode = w_current->actionfeedback_mode;
  w_current->drawbounding_action_mode = (w_current->CONTROLKEY)
                                          ? CONSTRAINED : FREE;
}
Exemplo n.º 4
0
/*! \brief Queries the bounds of a complex object.
 *  \par Function Description
 *  This function returns the bounding box of the complex object
 *  <B>object</B>.
 *
 *  \param [in]  toplevel The toplevel environment.
 *  \param [in]  complex   The complex object.
 *  \param [out] left      The leftmost edge of the bounding box (in
 *                         world units).
 *  \param [out] top       The upper edge of the bounding box (in
 *                         world units).
 *  \param [out] right     The rightmost edge of the bounding box (in
 *                         world units).
 *  \param [out] bottom    The bottom edge of the bounding box (in
 *                         screen units).
 */
void world_get_complex_bounds(TOPLEVEL *toplevel, OBJECT *complex,
			      int *left, int *top, int *right, int *bottom)
{
  g_return_if_fail (complex != NULL &&
                    (complex->type == OBJ_COMPLEX ||
                     complex->type == OBJ_PLACEHOLDER) &&
                    complex->complex != NULL);

  world_get_object_glist_bounds (toplevel, complex->complex->prim_objs,
                                 left, top, right, bottom);
}
Exemplo n.º 5
0
/*! \brief Invalidate bounding box or outline for OBJECT placement
 *
 *  \par Function Description
 *  This function invalidates the bounding box where objects would be
 *  drawn by o_place_draw_rubber()
 *
 * 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.
 *
 * The "drawing" parameter is used to indicate if this drawing should
 * immediately use the selected feedback mode and positioning constraints.
 *
 * With drawing=TRUE, the selected conditions are used immediately,
 * otherwise the conditions from the last drawing operation are used,
 * saving the new state for next time.
 *
 * This function should be called with drawing=TRUE when starting a
 * rubberbanding operation and when otherwise refreshing the rubberbanded
 * outline (e.g. after a screen redraw). For any undraw operation, should
 * be called with drawing=FALSE, ensuring that the undraw XOR matches the
 * mode and constraints of the corresponding "draw" operation.
 *
 * If any mode / constraint changes are made between a undraw, redraw XOR
 * pair, the latter (draw) operation must be called with drawing=TRUE. If
 * no mode / constraint changes were made between the pair, it is not
 * harmful to call the draw operation with "drawing=FALSE".
 *
 *  \param [in] w_current   GSCHEM_TOPLEVEL which we're drawing for.
 *  \param [in] drawing     Set to FALSE for undraw operations to ensure
 *                            matching conditions to a previous draw operation.
 */
void o_place_invalidate_rubber (GSCHEM_TOPLEVEL *w_current, int drawing)
{
  TOPLEVEL *toplevel = w_current->toplevel;
  int diff_x, diff_y;
  int left, top, bottom, right;
  int s_left, s_top, s_bottom, s_right;

  g_return_if_fail (toplevel->page_current->place_list != NULL);

  /* If drawing is true, then don't worry about the previous drawing
   * method and movement constraints, use with the current settings */
  if (drawing) {
    /* Ensure we set this to flag there is "something" supposed to be
     * drawn when the invaliate call below causes an expose event. */
    w_current->last_drawb_mode = w_current->actionfeedback_mode;
    w_current->drawbounding_action_mode = (w_current->CONTROLKEY)
                                            ? 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 */

  /* Need to update the w_current->{first,second}_w{x,y} coords even
   * though we're only invalidating because the move rubberband code
   * (which may execute right after this function) expects these
   * coordinates to be correct.
   */
  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;
    }
  }

  /* Find the bounds of the drawing to be done */
  world_get_object_glist_bounds (toplevel, toplevel->page_current->place_list,
                                 &left, &top, &right, &bottom);
  WORLDtoSCREEN (w_current, left + diff_x, top + diff_y, &s_left, &s_top);
  WORLDtoSCREEN (w_current, right + diff_x, bottom + diff_y, &s_right, &s_bottom);

  o_invalidate_rect (w_current, s_left, s_top, s_right, s_bottom);
}
Exemplo n.º 6
0
/*! \brief Export a figure-style PDF file of the current page.
 * \par Function Description
 * Exports the current page as a PDF file to \a filename.  The export
 * is carried out using a page size matching the size of the visible
 * extents of the schematic page.
 *
 * \param w_current A #GschemToplevel structure.
 * \param filename  The filename for generated PDF.
 *
 * \returns TRUE if the operation was successful.
 */
gboolean
x_print_export_pdf (GschemToplevel *w_current,
                    const gchar *filename)
{
  cairo_surface_t *surface;
  cairo_status_t cr_status;
  cairo_t *cr;
  int status, wx_min, wy_min, wx_max, wy_max;
  double width, height;

  /* First, calculate a transformation matrix for the cairo
   * context. We want to center the extents of the page in the
   * available page area. */
  status = world_get_object_glist_bounds (w_current->toplevel,
                                          s_page_objects (w_current->toplevel->page_current),
                                          &wx_min, &wy_min, &wx_max, &wy_max);
  if (status) {
    width  = (wx_max - wx_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI;
    height = (wy_max - wy_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI;
  } else {
    /* Fallback size if there are no drawable objects */
    width = height = DEFAULT_PDF_SIZE;
  }

  surface = cairo_pdf_surface_create (filename, width, height);
  cr = cairo_create (surface);

  x_print_draw_page (w_current->toplevel, w_current->toplevel->page_current,
                     cr, NULL, width, height,
                     w_current->toplevel->image_color, FALSE);

  cairo_destroy (cr);
  cairo_surface_finish (surface);

  cr_status = cairo_surface_status (surface);
  if (cr_status != CAIRO_STATUS_SUCCESS) {
    g_warning (_("Failed to write PDF to '%1$s': %2$s\n"),
               filename,
               cairo_status_to_string (cr_status));
    return FALSE;
  }

  cairo_surface_destroy (surface);
  return TRUE;
}
Exemplo n.º 7
0
/*! \brief Calculate the bounds of a complex object
 *
 *  On failure, this function sets the bounds to empty.
 *
 *  \param [in] toplevel The toplevel object.
 *  \param [in] object The complex object.
 *  \param [out] bounds The bounds of the complex object
 */
void
geda_complex_object_calculate_bounds (TOPLEVEL *toplevel,
                                      const OBJECT *object,
                                      GedaBounds *bounds)
{
  geda_bounds_init (bounds);

  g_return_if_fail (object != NULL);
  g_return_if_fail (((object->type == OBJ_COMPLEX) || (object->type == OBJ_PLACEHOLDER)));
  g_return_if_fail (object->complex != NULL);

  world_get_object_glist_bounds (toplevel,
                                 object->complex->prim_objs,
                                 &(bounds->min_x),
                                 &(bounds->min_y),
                                 &(bounds->max_x),
                                 &(bounds->max_y));
}
Exemplo n.º 8
0
/*! \brief Create a default page setup for a schematic page.
 * \par Function Description
 * Creates and returns a new #GtkPageSetup for \a page, taking into
 * account the requested \a paper_size_name.  If \a paper_size_name is
 * NULL, the system default paper size is used. The \a orientation may
 * be LANDSCAPE, PORTRAIT or AUTOLAYOUT.  If \a AUTOLAYOUT is chosen,
 * the page orientation that best fits the page contents is chosen.
 *
 * \param toplevel A #TOPLEVEL structure.
 * \param page     The #PAGE to generate a page setup for.
 * \param paper_size_name   The name of the paper size to use.
 * \param orientation       The paper orientation to use.
 *
 * \returns A newly-created page setup.
 */
static GtkPageSetup *
x_print_default_page_setup (TOPLEVEL *toplevel, PAGE *page)
{
  GtkPageSetup *setup = gtk_page_setup_new ();
  GtkPaperSize *papersize;
  int status, wx_min, wy_min, wx_max, wy_max;
  EdaConfig *cfg;
  gchar *paper, *orientation;

  /* Get configuration values */
  cfg =         eda_config_get_context_for_path (s_page_get_filename (page));
  paper =       eda_config_get_string (cfg, CFG_GROUP_PRINTING,
                                       CFG_KEY_PRINTING_PAPER, NULL);
  orientation = eda_config_get_string (cfg, CFG_GROUP_PRINTING,
                                       CFG_KEY_PRINTING_ORIENTATION, NULL);

  /* If the paper size is valid, set it up with default margins. */
  papersize = gtk_paper_size_new (paper);
  if (papersize != NULL) {
    gtk_page_setup_set_paper_size_and_default_margins (setup, papersize);
  }

  if (g_strcmp0 (orientation, "landscape") == 0) {
    gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
  } else if (g_strcmp0 (orientation, "portrait") == 0) {
    gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT);
  } else if (orientation == NULL
             || g_strcmp0 (orientation, "auto") == 0) {
    /* Automatically choose the orientation that fits best */
    status = world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                            &wx_min, &wy_min, &wx_max, &wy_max);
    if (!status || (wx_max - wx_min) > (wy_max - wy_min)) {
      /* Default to landscape */
      gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
    } else {
      gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT);
    }
  }

  g_free (paper);
  g_free (orientation);
  return setup;
}
Exemplo n.º 9
0
/*! \brief Draw a page.
 * \par Function Description
 * Draws the \a page on the Cairo context \a cr, which should have
 * dimensions \a cr_width and \a cr_height.  If the Pango context \a
 * pc is provided, it is used for rendering of text.  The parameter \a
 * is_color controls whether to enable color printing, and \a
 * is_raster should be set if drawing to a raster surface such as an
 * image.
 *
 * \param toplevel A #TOPLEVEL structure.
 * \param page     The #PAGE to be rendered.
 * \param cr       The Cairo context to render to.
 * \param pc       A Pango context for text rendering, or NULL.
 * \param cr_width The width of the drawing area.
 * \param cr_height The height of the drawing area.
 * \param is_color TRUE if drawing should be in color; FALSE otherwise.
 * \param is_raster TRUE if drawing to a raster image surface; FALSE otherwise.
 */
static void
x_print_draw_page (TOPLEVEL *toplevel, PAGE *page,
                   cairo_t *cr, PangoContext *pc,
                   double cr_width, double cr_height,
                   gboolean is_color, gboolean is_raster)
{
  EdaRenderer *renderer;
  cairo_matrix_t mtx;
  GArray *color_map;
  int status, wx_min, wy_min, wx_max, wy_max;
  double w_width, w_height, scale;
  GList *iter;

  /* First, calculate a transformation matrix for the cairo
   * context. We want to center the extents of the page in the
   * available page area. */
  status = world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                          &wx_min, &wy_min, &wx_max, &wy_max);
  /* If there are no printable objects, draw nothing. */
  if (!status) return;

  w_width = wx_max - wx_min;
  w_height = wy_max - wy_min;
  scale = fmin (cr_width / w_width, cr_height / w_height);
  cairo_matrix_init (&mtx,
                     scale, 0,
                     0, -scale,
                     - (wx_min + 0.5*w_width) * scale + 0.5*cr_width,
                     (wy_min + 0.5*w_height) * scale + 0.5*cr_height);

  /* Second, build the color map.  If no color printing is desired,
   * transform the print color map into a black-and-white color map by
   * making the background color transparent and replacing all other
   * enabled colors with solid black. */
  color_map = g_array_sized_new (FALSE, FALSE, sizeof(GedaColor), MAX_COLORS);
  color_map = g_array_append_vals (color_map, print_colors, MAX_COLORS);
  if (!is_color) {
    int i;
    for (i = 0; i < MAX_COLORS; i++) {
      GedaColor *c = &g_array_index (color_map, GedaColor, i);
      if (!c->enabled) continue;

      /* Disable background color & fully-transparent colors */
      if (c->a == 0 || i == BACKGROUND_COLOR) {
        c->enabled = FALSE;
        continue;
      }

      /* Set any remaining colors solid black */
      c->r = 0;
      c->g = 0;
      c->b = 0;
      c->a = ~0;
    }
  }

  /* Thirdly, create and initialise a renderer */
  renderer = EDA_RENDERER (g_object_new (EDA_TYPE_RENDERER,
                                         "cairo-context", cr,
                                         "pango-context", pc,
                                         "color-map", color_map,
                                         "render-flags", is_raster ? EDA_RENDERER_FLAG_HINTING : 0,
                                         NULL));

  /* Finally, actually do drawing */
  cairo_save (cr);
  cairo_transform (cr, &mtx);

  /* Draw background */
  eda_cairo_set_source_color (cr, BACKGROUND_COLOR, color_map);
  cairo_paint (cr);

  /* Draw all objects and cues */
  for (iter = (GList *) s_page_objects (page);
       iter != NULL;
       iter = g_list_next (iter)) {
    eda_renderer_draw (renderer, (OBJECT *) iter->data);
  }
  for (iter = (GList *) s_page_objects (page);
       iter != NULL;
       iter = g_list_next (iter)) {
    eda_renderer_draw_cues (renderer, (OBJECT *) iter->data);
  }

  cairo_restore (cr);

  g_object_unref (renderer);
  g_array_free (color_map, TRUE);
}
Exemplo n.º 10
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);
}
Exemplo n.º 11
0
/* Calculates a page layout.  If page is NULL, uses the first page
 * (this is convenient for single-page rendering).  The required size
 * of the page is returned in extents, and the cairo transformation
 * matrix needed to fit the drawing into the page is returned in mtx.
 * Takes into account all of the margin/orientation/paper settings,
 * and the size of the drawing itself. */
static void
export_layout_page (PAGE *page, cairo_rectangle_t *extents, cairo_matrix_t *mtx)
{
  cairo_rectangle_t drawable;
  int wx_min, wy_min, wx_max, wy_max, w_width, w_height;
  gboolean landscape = FALSE;
  gdouble m[4]; /* Calculated margins */
  gdouble s; /* Calculated scale */
  gdouble slack[2]; /* Calculated alignment slack */

  if (page == NULL) {
    const GList *pages = geda_list_get_glist (toplevel->pages);
    g_assert (pages != NULL && pages->data != NULL);
    page = (PAGE *) pages->data;
  }

  /* Set the margins. If none were provided by the user, get them
   * from the paper size (if a paper size is being used) or just use a
   * sensible default. */
  if (settings.margins[0] >= 0) {
    memcpy (m, settings.margins, 4*sizeof(gdouble));
  } else if (settings.paper != NULL) {
    m[0] = gtk_paper_size_get_default_top_margin (settings.paper, GTK_UNIT_POINTS);
    m[1] = gtk_paper_size_get_default_left_margin (settings.paper, GTK_UNIT_POINTS);
    m[2] = gtk_paper_size_get_default_bottom_margin (settings.paper, GTK_UNIT_POINTS);
    m[3] = gtk_paper_size_get_default_right_margin (settings.paper, GTK_UNIT_POINTS);
  } else {
    m[0] = DEFAULT_MARGIN;
    m[1] = DEFAULT_MARGIN;
    m[2] = DEFAULT_MARGIN;
    m[3] = DEFAULT_MARGIN;
  }

  /* Now calculate extents of objects within page */
  world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                 &wx_min, &wy_min, &wx_max, &wy_max);
  w_width = wx_max - wx_min;
  w_height = wy_max - wy_min;

  /* If a size was specified, use it.  Otherwise, use paper size, if
   * provided.  Fall back to just using the size of the drawing. */
  extents->x = extents->y = 0;
  if (settings.size[0] >= 0) {
    /* get extents from size */

    extents->width = settings.size[0];
    extents->height = settings.size[1];

  } else if (settings.paper != NULL) {
    /* get extents from paper */

    gdouble p_width, p_height;

    /* Select orientation */
    switch (settings.layout) {
    case ORIENTATION_LANDSCAPE:
      landscape = TRUE;
      break;
    case ORIENTATION_PORTRAIT:
      landscape = FALSE;
      break;
    case ORIENTATION_AUTO:
    default:
      landscape = (w_width > w_height);
      break;
    }

    p_width = gtk_paper_size_get_width (settings.paper, GTK_UNIT_POINTS);
    p_height = gtk_paper_size_get_height (settings.paper, GTK_UNIT_POINTS);

    if (landscape) {
      extents->width = p_height;
      extents->height = p_width;
    } else {
      extents->width = p_width;
      extents->height = p_height;
    }
  } else {
    /* get extents from drawing */

    extents->width = w_width * settings.scale; /* in points */
    extents->height = w_height * settings.scale; /* in points */

    /* If the extents were obtained from the drawing, grow the extents
     * rather than shrinking the drawable area.  This ensures that the
     * overall aspect ratio of the image remains correct. */
    extents->width += m[1] + m[3];
    extents->height += m[0] + m[2];
  }

  drawable.x = m[1];
  drawable.y = m[0];

  drawable.width = extents->width - m[1] - m[3];
  drawable.height = extents->height - m[0] - m[2];

  /* Calculate optimum scale */
  s = fmin (drawable.width / w_width, drawable.height / w_height);

  /* Calculate alignment slack */
  slack[0] = fmin (1, fmax (0, settings.align[0])) * (drawable.width - w_width * s);
  slack[1] = fmin (1, fmax (0, settings.align[1])) * (drawable.height - w_height * s);

  /* Finally, create and set a cairo transformation matrix that
   * centres the drawing into the drawable area. */
  cairo_matrix_init (mtx, s, 0, 0, -s,
                     - wx_min * s + drawable.x + slack[0],
                     (wy_min + w_height) * s + drawable.y + slack[1]);
}
Exemplo n.º 12
0
/*! \brief Attach attribute to object.
 *
 * Attach the name=value pair to the OBJECT "object". This function
 * was stolen from gschem/src/o_attrib.c:o_attrib_add_attrib and
 * hacked for gattrib.
 * \param toplevel TOPLEVEL to operate on
 * \param text_string
 * \param visibility
 * \param show_name_value
 * \param object
 * \returns pointer to the object
 * \todo Does it need to return OBJECT?
 */
OBJECT *
s_object_attrib_add_attrib_in_object (TOPLEVEL *toplevel,
                                      char *text_string,
                                      int visibility,
                                      int show_name_value,
                                      OBJECT * object)
{
  int world_x = -1, world_y = -1;
  int color;
  int left, right, top, bottom;
  OBJECT *o_current;
  OBJECT *new_obj;

  o_current = object;

  /* creating a toplevel or unattached attribute */
  if (o_current) {
    /* get coordinates of where to place the text object */
    switch (o_current->type) {
    case (OBJ_COMPLEX):
      world_x = o_current->complex->x;
      world_y = o_current->complex->y;
      color = ATTRIBUTE_COLOR;
      break;

    case (OBJ_NET):
      world_x = o_current->complex->x;
      world_y = o_current->complex->y;
      color = ATTRIBUTE_COLOR;
      break;

    default:
      fprintf(stderr, _("In s_object_attrib_add_attrib_in_object, trying to add attrib to non-complex or non-net!\n"));
      exit(-1);
    }
  } else {    /* This must be a floating attrib, but what is that !?!?!?!?!  */
    world_get_object_glist_bounds (toplevel,
                                   s_page_objects (toplevel->page_current),
                                   &left, &top, &right, &bottom);

    /* this really is the lower left hand corner */
    world_x = left;
    world_y = top;

    /* printf("%d %d\n", world_x, world_y); */
    color = DETACHED_ATTRIBUTE_COLOR;
  }

  /* first create text item */
#if DEBUG
  printf("===  In s_object_attrib_add_attrib_in_object, about to attach new text attrib with properties:\n");
  printf("     color = %d\n", color);
  printf("     text_string = %s \n", text_string);
  printf("     text_size = %d \n", toplevel->text_size);
  printf("     visibility = %d \n", visibility);
  printf("     show_name_value = %d \n", show_name_value);
#endif

  new_obj = o_text_new (toplevel, color, world_x, world_y,
                        LOWER_LEFT, 0, /* zero is angle */
                        text_string, DEFAULT_TEXT_SIZE,
                        visibility, show_name_value);
  s_page_append (toplevel, toplevel->page_current, new_obj);

  /* now toplevel->page_current->object_tail contains new text item */

  /* now attach the attribute to the object (if o_current is not NULL) */
  /* remember that o_current contains the object to get the attribute */
  if (o_current) {
    o_attrib_attach (toplevel, new_obj, o_current, FALSE);
  }

  o_selection_add (toplevel,
                   toplevel->page_current->selection_list, new_obj);


  toplevel->page_current->CHANGED = 1;

  return new_obj;
}
Exemplo n.º 13
0
/*! \brief Updates the preview widget.
 *  \par Function Description
 *  This function updates the preview: if the preview is active and a
 *  filename has been given, it opens the file and displays
 *  it. Otherwise it displays a blank page.
 *
 *  \param [in] preview The preview widget.
 */
static void
preview_update (Preview *preview)
{
  int left, top, right, bottom;
  int width, height;
  GError * err = NULL;

  GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview);

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

  if (preview_page == NULL) {
    return;
  }

  TOPLEVEL *preview_toplevel = preview_page->toplevel;

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

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

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

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

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

  /* display current page (possibly empty) */
  gschem_page_view_zoom_extents (preview_view, NULL);
}
Exemplo n.º 14
0
/* text item */
OBJECT *o_attrib_add_attrib(GschemToplevel *w_current,
			    const char *text_string, int visibility, 
			    int show_name_value, OBJECT *object)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  OBJECT *new_obj;
  int world_x = - 1, world_y = -1;
  int align = LOWER_LEFT;
  int angle = 0;
  int color;
  int left, right, top, bottom;
  OBJECT *o_current;

  color = DETACHED_ATTRIBUTE_COLOR;

  o_current = object;

  /* creating a toplevel or unattached attribute */
  if (o_current) {
    /* get coordinates of where to place the text object */
    switch(o_current->type) {
      case(OBJ_COMPLEX):
      case(OBJ_PLACEHOLDER):
        world_x = o_current->complex->x;
        world_y = o_current->complex->y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_ARC):
        world_x = o_current->arc->x;
        world_y = o_current->arc->y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_CIRCLE):
        world_x = o_current->circle->center_x;
        world_y = o_current->circle->center_y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_BOX):
        world_x = o_current->box->upper_x;
        world_y = o_current->box->upper_y;
        align = LOWER_LEFT;
        angle = 0;
        color = ATTRIBUTE_COLOR;
        break;

      case(OBJ_LINE):
      case(OBJ_NET):
      case(OBJ_PIN):
      case(OBJ_BUS):
        {
          int dx = o_current->line->x[1] - o_current->line->x[0];
          int dy = o_current->line->y[1] - o_current->line->y[0];

          if (dy == 0) {
              if (dx > 0) {
                  world_x = o_current->line->x[0] + SPACING_FROM_END;
                  world_y = o_current->line->y[0] + SPACING_PERPENDICULAR;

                  align = LOWER_LEFT;
                  angle = 0;
              }
              else {
                  world_x = o_current->line->x[0] - SPACING_FROM_END;
                  world_y = o_current->line->y[0] + SPACING_PERPENDICULAR;

                  align = LOWER_RIGHT;
                  angle = 0;
              }
          }
          else if (dx == 0) {
              if (dy > 0) {
                  world_x = o_current->line->x[0] - SPACING_PERPENDICULAR;
                  world_y = o_current->line->y[0] + SPACING_FROM_END;

                  align = LOWER_LEFT;
                  angle = 90;
              }
              else {
                  world_x = o_current->line->x[0] - SPACING_PERPENDICULAR;
                  world_y = o_current->line->y[0] - SPACING_FROM_END;

                  align = LOWER_RIGHT;
                  angle = 90;
              }
          }
          else {
              world_x = o_current->line->x[0];
              world_y = o_current->line->y[0];

              align = LOWER_LEFT;
              angle = 0;
          }

          color = ATTRIBUTE_COLOR;
        }
        break;

      case(OBJ_TEXT):
        world_x = o_current->text->x;
        world_y = o_current->text->y;
        color = DETACHED_ATTRIBUTE_COLOR;
        align = LOWER_LEFT;
        angle = 0;
        o_current = NULL;
        break;
    }
  } else {
    world_get_object_glist_bounds (toplevel,
                                   s_page_objects (toplevel->page_current),
                                   &left, &top, &right, &bottom);
	
    /* this really is the lower left hand corner */	
    world_x = left; 
    world_y = top;  

    /* printf("%d %d\n", world_x, world_y); */
    align = LOWER_LEFT;
    angle = 0;
    color = DETACHED_ATTRIBUTE_COLOR;
  }

  /* first create text item */
  new_obj = o_text_new(toplevel, color, world_x, world_y,
                       align, angle, text_string,
                       w_current->text_size, /* current text size */
                       visibility, show_name_value);
  s_page_append (toplevel, toplevel->page_current, new_obj);

  /* now attach the attribute to the object (if o_current is not NULL) */
  /* remember that o_current contains the object to get the attribute */
  if (o_current) {
    o_attrib_attach (toplevel, new_obj, o_current, FALSE);
  }

  o_selection_add (toplevel, toplevel->page_current->selection_list, new_obj);

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

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

  gschem_toplevel_page_content_changed (w_current, toplevel->page_current);

  return new_obj;
}
Exemplo n.º 15
0
/*! \brief guess the whichend of pins of object list
 *  \par Function Description
 *  This function determines the whichend of the pins in the \a object_list.
 *  In older libgeda file format versions there was no information about the 
 *  active end of pins.
 *  This function calculates the bounding box of all pins in the object list.
 *  The side of the pins that are closer to the boundary of the box are
 *  set as active ends of the pins.
 *  
 *  \param toplevel    The TOPLEVEL object
 *  \param object_list list of OBJECTs
 *  \param num_pins    pin count in the object list
 *
 */
void o_pin_update_whichend(TOPLEVEL *toplevel,
                           GList *object_list, int num_pins)
{
  OBJECT *o_current;
  GList *iter;
  int top = 0, left = 0;
  int right = 0, bottom = 0;
  int d1, d2, d3, d4;
  int min0, min1;
  int min0_whichend, min1_whichend;
  int rleft, rtop, rright, rbottom;
  int found;

  if (object_list && num_pins) {
    if (num_pins == 1 || toplevel->force_boundingbox) {
      world_get_object_glist_bounds (toplevel, object_list,
                                     &left, &top, &right, &bottom);
    } else {
      found = 0;

      /* only look at the pins to calculate bounds of the symbol */
      iter = object_list;
      while (iter != NULL) {
        o_current = (OBJECT *)iter->data;
        if (o_current->type == OBJ_PIN) {
          rleft = o_current->w_left;
          rtop = o_current->w_top;
          rright = o_current->w_right;
          rbottom = o_current->w_bottom;

          if ( found ) {
            left = min( left, rleft );
            top = min( top, rtop );
            right = max( right, rright );
            bottom = max( bottom, rbottom );
          } else {
            left = rleft;
            top = rtop;
            right = rright;
            bottom = rbottom;
            found = 1;
          }
        }
        iter = g_list_next (iter);
      }

    }
  } else {
    return;
  }

  iter = object_list;
  while (iter != NULL) {
    o_current = (OBJECT *)iter->data;
    /* Determine which end of the pin is on or nearest the boundary */
    if (o_current->type == OBJ_PIN && o_current->whichend == -1) {
      if (o_current->line->y[0] == o_current->line->y[1]) {
        /* horizontal */
        
        if (o_current->line->x[0] == left) {
          o_current->whichend = 0;
        } else if (o_current->line->x[1] == left) {
          o_current->whichend = 1;        
        } else if (o_current->line->x[0] == right) {
          o_current->whichend = 0;        
        } else if (o_current->line->x[1] == right) {
          o_current->whichend = 1;
        } else {
            
          d1 = abs(o_current->line->x[0] - left);
          d2 = abs(o_current->line->x[1] - left);
          d3 = abs(o_current->line->x[0] - right);
          d4 = abs(o_current->line->x[1] - right);

          if (d1 <= d2) {
            min0 = d1;
            min0_whichend = 0;
          } else {
            min0 = d2;
            min0_whichend = 1;
          }

          if (d3 <= d4) {
            min1 = d3;
            min1_whichend = 0;
          } else {
            min1 = d4;
            min1_whichend = 1;
          }

          if (min0 <= min1) {
            o_current->whichend = min0_whichend;
          } else {
            o_current->whichend = min1_whichend;
          }
        }
           
      } else if (o_current->line->x[0] == o_current->line->x[1]) {
        /* vertical */
        
        if (o_current->line->y[0] == top) {
          o_current->whichend = 0;
        } else if (o_current->line->y[1] == top) {
          o_current->whichend = 1;        
        } else if (o_current->line->x[0] == bottom) {
          o_current->whichend = 0;        
        } else if (o_current->line->x[1] == bottom) {
          o_current->whichend = 1;
        } else {
            
          d1 = abs(o_current->line->y[0] - top);
          d2 = abs(o_current->line->y[1] - top);
          d3 = abs(o_current->line->y[0] - bottom);
          d4 = abs(o_current->line->y[1] - bottom);

          if (d1 <= d2) {
            min0 = d1;
            min0_whichend = 0;
          } else {
            min0 = d2;
            min0_whichend = 1;
          }

          if (d3 <= d4) {
            min1 = d3;
            min1_whichend = 0;
          } else {
            min1 = d4;
            min1_whichend = 1;
          }

          if (min0 <= min1) {
            o_current->whichend = min0_whichend;
          } else {
            o_current->whichend = min1_whichend;
          }
        }
      }
    }
    iter = g_list_next (iter);
  }
}