/*! \brief Unembed a picture, reloading the image from disk * * \par Function Description * This function re-reads the image file associated with the picture, and * discards the embeded copy of the file. * * \param [in] toplevel The TOPLEVEL object. * \param [in] object The picture OBJECT to unembed */ void o_picture_unembed (TOPLEVEL *toplevel, OBJECT *object) { GError *err = NULL; GdkPixbuf *pixbuf; gchar *filename; pixbuf = gdk_pixbuf_new_from_file (object->picture->filename, &err); if (err != NULL) { s_log_message (_("Failed to load image from file [%s]: %s\n"), object->picture->filename, err->message); g_error_free (err); return; } /* Change to the new pixbuf loaded from the file. */ if (object->picture->original_picture != NULL) g_object_unref(object->picture->original_picture); object->picture->original_picture = pixbuf; g_free (object->picture->file_content); object->picture->file_content = NULL; object->picture->file_length = 0; object->picture->embedded = 0; filename = g_path_get_basename(object->picture->filename); s_log_message (_("Picture [%s] has been unembedded\n"), filename); g_free(filename); }
/*! \brief Add symbol-generating Scheme procedures to the library. * \par Function Description * Adds a source to the library based on Scheme procedures. See page * \ref libscms for more information. Two procedures are required: \a * listfunc must return a Scheme list of symbol names, and \a getfunc * must return a string containing symbol data when passed a symbol * name. * * \param listfunc A Scheme function returning a list of symbols. * \param getfunc A Scheme function returning symbol data. * \param name A descriptive name for the component source. * * \return The new CLibSource. */ const CLibSource *s_clib_add_scm (SCM listfunc, SCM getfunc, const gchar *name) { CLibSource *source; gchar *realname; if (name == NULL) { s_log_message (_("Cannot add library: name not specified.")); return NULL; } realname = uniquify_source_name (name); if (scm_is_false (scm_procedure_p (listfunc)) && scm_is_false (scm_procedure_p (getfunc))) { s_log_message (_("Cannot add Scheme-library [%1$s]: callbacks must be closures."), realname); return NULL; } source = g_new0 (CLibSource, 1); source->type = CLIB_SCM; source->name = realname; source->list_fn = scm_gc_protect_object (listfunc); source->get_fn = scm_gc_protect_object (getfunc); refresh_scm (source); clib_sources = g_list_prepend (clib_sources, source); return source; }
/*! \brief read a net object from a char buffer * \par Function Description * This function reads a net object from the buffer \a buf. * If the netobject was read successfully, a new net object is * allocated and appended to the \a object_list. * * \param [in] toplevel The TOPLEVEL object * \param [in] buf a text buffer (usually a line of a schematic file) * \param [in] release_ver The release number gEDA * \param [in] fileformat_ver a integer value of the file format * \return The object list, or NULL on error. * */ OBJECT *o_net_read (TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; char type; int x1, y1; int x2, y2; int color; if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse net object")); return NULL; } if (x1 == x2 && y1 == y2) { s_log_message (_("Found a zero length net [ %c %d %d %d %d %d ]\n"), type, x1, y1, x2, y2, color); } if (toplevel->override_net_color != -1) { color = toplevel->override_net_color; } if (color < 0 || color > MAX_COLORS) { s_log_message (_("Found an invalid color [ %s ]\n"), buf); s_log_message (_("Setting color to default color\n")); color = DEFAULT_COLOR; } new_obj = o_net_new (toplevel, type, color, x1, y1, x2, y2); return new_obj; }
/*! \brief Add symbol-generating commands to the library * \par Function Description * Adds a set of commands which can generate symbols to the * library. \a list_cmd and \a get_cmd should be strings consisting * of an executable name followed by any arguments required. * Executables are resolved using the current PATH. See page \ref * libcmds for more information on library commands. * * \param list_cmd The executable & arguments used to list available * symbols. * \param get_cmd The executable & arguments used to retrieve symbol * data. * \param name A descriptive name for the component source. * \return The CLibSource associated with the component source. */ const CLibSource *s_clib_add_command (const gchar *list_cmd, const gchar *get_cmd, const gchar *name) { CLibSource *source; gchar *realname; if (name == NULL) { s_log_message (_("Cannot add library: name not specified.")); return NULL; } realname = uniquify_source_name (name); if (list_cmd == NULL || get_cmd == NULL) { s_log_message (_("Cannot add library [%1$s]: both 'list' and " "'get' commands must be specified."), realname); } source = g_new0 (CLibSource, 1); source->type = CLIB_CMD; source->name = realname; source->list_cmd = g_strdup (list_cmd); source->get_cmd = g_strdup (get_cmd); refresh_command (source); /* Sources added later get sacnned earlier */ clib_sources = g_list_prepend (clib_sources, source); return source; }
static void g_rc_parse__process_error (GError **err, const gchar *pname) { char *pbase; /* Take no chances; if err was not set for some reason, bail out. */ if (*err == NULL) { const gchar *msgl = _("ERROR: An unknown error occurred while parsing configuration files."); s_log_message ("%s\n", msgl); fprintf(stderr, "%s\n", msgl); } else { /* Config files are allowed to be missing or skipped; check for * this. */ if (g_error_matches (*err, G_FILE_ERROR, G_FILE_ERROR_NOENT) || g_error_matches (*err, EDA_ERROR, EDA_ERROR_RC_TWICE)) { return; } s_log_message (_("ERROR: %s\n"), (*err)->message); fprintf (stderr, _("ERROR: %s\n"), (*err)->message); } /* g_path_get_basename() allocates memory, but we don't care * because we're about to exit. */ pbase = g_path_get_basename (pname); fprintf (stderr, _("ERROR: The %s log may contain more information.\n"), pbase); exit (1); }
/*! \brief Saves all the pages of a TOPLEVEL object. * \par Function Description * Saves all the pages in the <B>toplevel</B> parameter. * * \param [in] toplevel The TOPLEVEL to save pages from. * \return The number of failed tries to save a page. */ gint s_page_save_all (TOPLEVEL *toplevel) { const GList *iter; PAGE *p_current; gint status = 0; for ( iter = geda_list_get_glist( toplevel->pages ); iter != NULL; iter = g_list_next( iter ) ) { p_current = (PAGE *)iter->data; if (f_save (toplevel, p_current, p_current->page_filename, NULL)) { s_log_message (_("Saved [%s]\n"), p_current->page_filename); /* reset the CHANGED flag of p_current */ p_current->CHANGED = 0; } else { s_log_message (_("Could NOT save [%s]\n"), p_current->page_filename); /* increase the error counter */ status++; } } return status; }
/*! \brief * \par Function Description * This function reads a formatted text buffer describing an arc * in the gEDA file format and initializes the corresponding object. * * Depending on the version of the file format the data extraction is * performed differently : currently pre-20000704 and 20000704 on one * hand and post-20000704 file format version on the other hand are supported. * The version is specified in string pointed by <B>fileformat_ver</B>. * * To get information on the various file formats have a * look to the fileformats.html document. * * The object is initialized with the functions #o_set_line_options() and #o_set_fill_options(). * The second one is only used to put initialize unused values for an arc as an arc can not be filled. * * The arc is allocated initialized with the function #o_arc_new(). * * A negative or null radius is not allowed. * * \param [in] toplevel The TOPLEVEL object. * \param [in] buf * \param [in] release_ver * \param [in] fileformat_ver * \return */ OBJECT *o_arc_read (TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver) { OBJECT *new_obj; char type; int x1, y1; int radius; int start_angle, end_angle; int color; int arc_width, arc_length, arc_space; int arc_type; int arc_end; /*! \note * Depending on the version of the file format used to describe this arc, * the buffer is parsed differently. The unknown parameters of the less * restrictive - the oldest - file format are set to common values */ if(release_ver <= VERSION_20000704) { sscanf(buf, "%c %d %d %d %d %d %d", &type, &x1, &y1, &radius, &start_angle, &end_angle, &color); arc_width = 0; arc_end = END_NONE; arc_type = TYPE_SOLID; arc_space = -1; arc_length= -1; } else { sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type, &x1, &y1, &radius, &start_angle, &end_angle, &color, &arc_width, &arc_end, &arc_type, &arc_length, &arc_space); } /* Error check */ if (radius <= 0) { s_log_message (_("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n"), type, x1, y1, radius, start_angle, end_angle, color); } if (color < 0 || color > MAX_COLORS) { s_log_message(_("Found an invalid color [ %s ]\n"), buf); s_log_message(_("Setting color to default color\n")); color = DEFAULT_COLOR; } /* Allocation and initialization */ new_obj = o_arc_new(toplevel, OBJ_ARC, color, x1, y1, radius, start_angle, end_angle); o_set_line_options(toplevel, new_obj, arc_end, arc_type, arc_width, arc_length, arc_space); o_set_fill_options(toplevel, new_obj, FILLING_HOLLOW, -1, -1, -1, -1, -1); return new_obj; }
/*! \brief Re-poll a scheme procedure for symbols. * \par Function Description * Calls a Scheme procedure to obtain a list of available symbols, * and updates the source with the new list * * Private function used only in s_clib.c. */ static void refresh_scm (CLibSource *source) { SCM symlist; SCM symname; CLibSymbol *symbol; char *tmp; g_return_if_fail (source != NULL); g_return_if_fail (source->type == CLIB_SCM); /* Clear the current symbol list */ g_list_foreach (source->symbols, (GFunc) free_symbol, NULL); g_list_free (source->symbols); source->symbols = NULL; symlist = scm_call_0 (source->list_fn); if (scm_is_false (scm_list_p (symlist))) { s_log_message (_("Failed to scan library [%1$s]: Scheme function returned non-list."), source->name); return; } while (!scm_is_null (symlist)) { symname = SCM_CAR (symlist); if (!scm_is_string (symname)) { s_log_message (_("Non-string symbol name while scanning library [%1$s]"), source->name); } else { symbol = g_new0 (CLibSymbol, 1); symbol->source = source; /* Need to make sure that the correct free() function is called * on strings allocated by Guile. */ tmp = scm_to_utf8_string (symname); symbol->name = g_strdup(tmp); free (tmp); /* Prepend because it's faster and it doesn't matter what order we * add them. */ source->symbols = g_list_prepend (source->symbols, symbol); } symlist = SCM_CDR (symlist); } /* Now sort the list of symbols by name. */ source->symbols = g_list_sort (source->symbols, (GCompareFunc) compare_symbol_name); s_clib_flush_search_cache(); s_clib_flush_symbol_cache(); }
/*! \brief Use gschemdoc to open a browser to a specific wiki page * * \param [in] wikiname the name of the wiki page * * \par Function Description * Invokes gschemdoc with its -w switch to open a browser to the wiki * page specified by wikiname. If wikiname is empty or not a string, * will browse to the main wiki page. */ SCM g_funcs_browse_wiki(SCM wikiname) { char *wikistr; int pid; /* Extract wiki name string from Scheme value structure. * If not a string, use the empty string */ if (scm_is_string (wikiname)) { wikistr = scm_to_utf8_string(wikiname); } else { wikistr = ""; } #ifndef __MINGW32__ pid = fork(); if (pid < 0) { /* Fork failed. Still in parent process, so can use the log * window */ if (scm_is_string (wikiname)) free(wikistr); s_log_message(_("Could not fork\n")); return SCM_BOOL_F; } else if (pid > 0) { /* Parent process, we're finished here */ if (scm_is_string (wikiname)) free(wikistr); return SCM_BOOL_T; } /* begin daughter process stuff */ /* assume gschemdoc is part of path */ char *gschemdoc = "gschemdoc"; char *wikiarg = "-w"; execlp(gschemdoc, gschemdoc, wikiarg, wikistr, NULL); /* if we return, then nothing happened */ fprintf(stderr, _("Could not invoke %s\n"), gschemdoc); _exit(0); /* end daughter process stuff */ #else /* __MINGW32__ */ s_log_message(_("Documentation commands not supported under MinGW.\n")); return SCM_BOOL_F; #endif /* __MINGW32__ */ }
void s_symstruct_print(SYMCHECK *s_current) { GList *list; char *msg; if (verbose_mode > 2) { list = s_current->info_messages; while (list != NULL) { msg = (char *) list->data; /* printf("found info: %s\n", msg); */ if (msg) { s_log_message(_("Info: %1$s"), msg); g_free(msg); } list = g_list_next(list); } } if (verbose_mode > 1) { list = s_current->warning_messages; while (list != NULL) { msg = (char *) list->data; /* printf("found warning: %s\n", msg); */ if (msg) { s_log_message(_("Warning: %1$s"), msg); g_free(msg); } list = g_list_next(list); } } if (verbose_mode > 0) { list = s_current->error_messages; while (list != NULL) { msg = (char *) list->data; /* printf("found error: %s\n", msg); */ if (msg && verbose_mode) { s_log_message(_("ERROR: %1$s"), msg); g_free(msg); } list = g_list_next(list); } } }
/*! \brief read a pin object from a char buffer * \par Function Description * This function reads a pin object from the buffer \a buf. * If the pin object was read successfully, a new pin object is * allocated and appended to the \a object_list. * * \param [in] toplevel The TOPLEVEL object * \param [in] buf a text buffer (usually a line of a schematic file) * \param [in] release_ver The release number gEDA * \param [in] fileformat_ver a integer value of the file format * \return The object list, or NULL on error. */ OBJECT *o_pin_read (TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; char type; int x1, y1; int x2, y2; int color; int pin_type; int whichend; if (release_ver <= VERSION_20020825) { if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object")); return NULL; } pin_type = PIN_TYPE_NET; whichend = -1; } else { if (sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color, &pin_type, &whichend) != 8) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object")); return NULL; } } if (whichend == -1) { s_log_message (_("Found a pin which did not have the whichone field set.\n" "Verify and correct manually.\n")); } else if (whichend < -1 || whichend > 1) { s_log_message (_("Found an invalid whichend on a pin (reseting to zero): %d\n"), whichend); whichend = 0; } if (color < 0 || color > MAX_COLORS) { s_log_message (_("Found an invalid color [ %s ]\n"), buf); s_log_message (_("Setting color to default color\n")); color = DEFAULT_COLOR; } if (toplevel->override_pin_color != -1) { color = toplevel->override_pin_color; } new_obj = o_pin_new (toplevel, type, color, x1, y1, x2, y2, pin_type, whichend); return new_obj; }
/*! \brief read a bus object from a char buffer * \par Function Description * This function reads a bus object from the buffer \a buf. * If the bus object was read successfully, a new bus object is * allocated and appended to the \a object_list. * * \param [in] toplevel The TOPLEVEL object * \param [in] buf a text buffer (usually a line of a schematic file) * \param [in] release_ver The release number gEDA * \param [in] fileformat_ver a integer value of the file format * \return The object list, or NULL on error. */ OBJECT *o_bus_read (TOPLEVEL *toplevel, const char buf[], unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; char type; int x1, y1; int x2, y2; int color; int ripper_dir; if (release_ver <= VERSION_20020825) { if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object")); return NULL; } ripper_dir = 0; } else { if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color, &ripper_dir) != 7) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object")); return NULL; } } if (x1 == x2 && y1 == y2) { s_log_message (_("Found a zero length bus [ %c %d %d %d %d %d ]\n"), type, x1, y1, x2, y2, color); } if (toplevel->override_bus_color != -1) { color = toplevel->override_bus_color; } if (color < 0 || color > MAX_COLORS) { s_log_message (_("Found an invalid color [ %s ]\n"), buf); s_log_message (_("Setting color to default color\n")); color = DEFAULT_COLOR; } if (ripper_dir < -1 || ripper_dir > 1) { s_log_message (_("Found an invalid bus ripper direction [ %s ]\n"), buf); s_log_message (_("Resetting direction to neutral (no direction)\n")); ripper_dir = 0; } new_obj = o_bus_new (toplevel, type, color, x1, y1, x2, y2, ripper_dir); return new_obj; }
/* this cannot be called recursively */ void o_unlock(GschemToplevel *w_current) { OBJECT *object = NULL; GList *s_current = NULL; s_current = geda_list_get_glist( w_current->toplevel->page_current->selection_list ); while(s_current != NULL) { object = (OBJECT *) s_current->data; if (object) { /* only unlock if the object is locked */ if (object->selectable == FALSE) { object->selectable = TRUE; object->color = object->locked_color; object->locked_color = -1; gschem_toplevel_page_content_changed (w_current, w_current->toplevel->page_current); } else { s_log_message(_("Object already unlocked\n")); } } s_current = g_list_next(s_current); } o_undo_savestate_old(w_current, UNDO_ALL); }
/* This locks the entire selected list. It does lock components, but does NOT * change the color (of primatives of the components) though * this cannot be called recursively */ void o_lock(GSCHEM_TOPLEVEL *w_current) { OBJECT *object = NULL; GList *s_current = NULL; /* skip over head */ s_current = geda_list_get_glist( w_current->toplevel->page_current->selection_list ); while(s_current != NULL) { object = (OBJECT *) s_current->data; if (object) { /* check to see if locked_color is already being used */ if (object->locked_color == -1) { object->selectable = FALSE; object->locked_color = object->color; object->color = LOCK_COLOR; w_current->toplevel->page_current->CHANGED=1; } else { s_log_message(_("Object already locked\n")); } } s_current = g_list_next(s_current); } if (!w_current->SHIFTKEY) o_select_unselect_all(w_current); o_undo_savestate(w_current, UNDO_ALL); i_update_menus(w_current); }
/* this cannot be called recursively */ void o_unlock(GSCHEM_TOPLEVEL *w_current) { OBJECT *object = NULL; GList *s_current = NULL; s_current = geda_list_get_glist( w_current->toplevel->page_current->selection_list ); while(s_current != NULL) { object = (OBJECT *) s_current->data; if (object) { /* only unlock if the object is locked */ if (object->selectable == FALSE) { object->selectable = TRUE; object->color = object->locked_color; object->locked_color = -1; w_current->toplevel->page_current->CHANGED = 1; } else { s_log_message(_("Object already unlocked\n")); } } s_current = g_list_next(s_current); } o_undo_savestate(w_current, UNDO_ALL); }
/*! \brief embed an object into a schematic * \par Function Description * This functions embeds an object \a o_current into a * libgeda. Currently complex objects are just marked to * be embedded later. Picture objects are embedded immediatly. * * \param toplevel The TOPLEVEL object * \param o_current The OBJECT to embed */ void o_embed(TOPLEVEL *toplevel, OBJECT *o_current) { PAGE *page = o_get_page_compat (toplevel, o_current); int page_modified = 0; /* check o_current is a complex and is not already embedded */ if (o_current->type == OBJ_COMPLEX && !o_complex_is_embedded (o_current)) { /* set the embedded flag */ o_current->complex_embedded = TRUE; s_log_message (_("Component [%s] has been embedded\n"), o_current->complex_basename); page_modified = 1; } /* If it's a picture and it's not embedded */ if ( (o_current->type == OBJ_PICTURE) && !o_picture_is_embedded (toplevel, o_current) ) { o_picture_embed (toplevel, o_current); page_modified = 1; } if (page_modified && page != NULL) { /* page content has been modified */ page->CHANGED = 1; } }
/*! \brief Get symbol data from a Scheme-based component source. * \par Function Description * Get symbol data from a Scheme-based component source. The return * value should be free()'d when no longer needed. * * Private function used only in s_clib.c. * * \param symbol Symbol to get data for. * \return Allocated buffer containing symbol data. */ static gchar *get_data_scm (const CLibSymbol *symbol) { SCM symdata; char *tmp; gchar *result; g_return_val_if_fail ((symbol != NULL), NULL); g_return_val_if_fail ((symbol->source->type == CLIB_SCM), NULL); symdata = scm_call_1 (symbol->source->get_fn, scm_from_utf8_string (symbol->name)); if (!scm_is_string (symdata)) { s_log_message (_("Failed to load symbol data [%1$s] from source [%2$s]"), symbol->name, symbol->source->name); return NULL; } /* Need to make sure that the correct free() function is called * on strings allocated by Guile. */ tmp = scm_to_utf8_string (symdata); result = g_strdup(tmp); free (tmp); return result; }
/*! \brief Modify the description of a circle OBJECT. * \par Function Description * This function modifies the description of the circle object <B>*object</B> * depending on <B>whichone</B> that give the meaning of the <B>x</B> and <B>y</B> * parameters. * * If <B>whichone</B> is equal to <B>CIRCLE_CENTER</B>, the new center of the * circle is given by (<B>x</B>,<B>y</B>) where <B>x</B> and <B>y</B> are in world units. * * If <B>whichone</B> is equal to <B>CIRCLE_RADIUS</B>, the radius is given by * <B>x</B> - in world units. <B>y</B> is ignored. * * The bounding box of the circle object is updated after the modification of its * parameters. * * \param [in] toplevel The TOPLEVEL object. * \param [in,out] object Circle OBJECT to modify. * \param [in] x New center x coordinate, or radius value. * \param [in] y New center y coordinate. * Unused if radius is being modified. * \param [in] whichone Which circle parameter to modify. * * <B>whichone</B> can have the following values: * <DL> * <DT>*</DT><DD>CIRCLE_CENTER * <DT>*</DT><DD>CIRCLE_RADIUS * </DL> */ void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object, int x, int y, int whichone) { o_emit_pre_change_notify (toplevel, object); switch(whichone) { case CIRCLE_CENTER: /* modify the center of the circle */ object->circle->center_x = x; object->circle->center_y = y; break; case CIRCLE_RADIUS: /* modify the radius of the circle */ if (x == 0) { s_log_message(_("Null radius circles are not allowed\n")); return; } object->circle->radius = x; break; default: break; } /* recalculate the boundings */ o_circle_recalc(toplevel, object); o_emit_change_notify (toplevel, object); }
/*! \brief Select a script and execute it * \par Function Description * This function opens a file selection dialog. The selected script * is executed. */ void setup_script_selector (GSCHEM_TOPLEVEL *w_current) { char *filename; w_current->sowindow = gtk_file_chooser_dialog_new (_("Execute Script..."), GTK_WINDOW(w_current->main_window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_EXECUTE, GTK_RESPONSE_ACCEPT, NULL); /* Set the alternative button order (ok, cancel, help) for other systems */ gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->sowindow), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); if (gtk_dialog_run (GTK_DIALOG (w_current->sowindow)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w_current->sowindow)); if (!(g_file_test(filename, G_FILE_TEST_IS_DIR))) { s_log_message(_("Executing guile script [%s]\n"), filename); g_read_file(filename); } g_free (filename); } gtk_widget_destroy (GTK_WIDGET(w_current->sowindow)); w_current->sowindow = NULL; }
/*! \brief Set an #OBJECT's line options. * \par Function Description * This function allows a line's end, type, width, length and space to be set. * See #OBJECT_END and #OBJECT_TYPE for information on valid * object end and type values. * * \param [in] toplevel The TOPLEVEL object. * \param [in,out] o_current OBJECT to set line options on. * \param [in] end An OBJECT_END. * \param [in] type An OBJECT_TYPE. * \param [in] width Line width. * \param [in] length Line length. * \param [in] space Spacing between dashes/dots. Cannot be negative. * * \todo Make space an unsigned int and check for a max value instead. * If a max value is not required, then it would simplify the code. */ void o_set_line_options(TOPLEVEL *toplevel, OBJECT *o_current, OBJECT_END end, OBJECT_TYPE type, int width, int length, int space) { if(o_current == NULL) { return; } /* do some error checking / correcting */ switch(type) { case(TYPE_DOTTED): if (space < 1) { space = 100; s_log_message (_("Invalid space specified, setting to 100\n")); } break; case(TYPE_DASHED): case(TYPE_CENTER): case(TYPE_PHANTOM): if (length < 1) { length = 100; s_log_message (_("Invalid length specified, setting to 100\n")); } if (space < 1) { space = 100; s_log_message (_("Invalid space specified, setting to 100\n")); } break; default: break; } o_emit_pre_change_notify (toplevel, o_current); o_current->line_width = width; o_current->line_end = end; o_current->line_type = type; o_current->line_length = length; o_current->line_space = space; /* Recalculate the object's bounding box */ o_recalc_single_object( toplevel, o_current ); o_emit_change_notify (toplevel, o_current); }
/* Error handler function used by x_rc_parse_gschem(). */ static void x_rc_parse_gschem_error (GError **err, GSCHEM_TOPLEVEL *w_current) { char *msg2; /* Secondary text */ GtkWidget *dialog; g_assert (w_current != NULL); g_assert (err != NULL); /* Take no chances; if err was not set for some reason, it's a * problem. */ if (*err == NULL) { /* Log message */ s_log_message (_("ERROR: An unknown error occurred while parsing " "configuration files.\n")); /* Dialog message */ msg2 = g_strdup (_("An unknown error occurred while parsing configuration files." "\n\nThe gschem log may contain more information.")); } else { /* Config files are allowed to be missing or skipped; check for * this. */ if (g_error_matches (*err, G_FILE_ERROR, G_FILE_ERROR_NOENT) || g_error_matches (*err, EDA_ERROR, EDA_ERROR_RC_TWICE)) { return; } /* Log message */ s_log_message (_("ERROR: %s\n"), (*err)->message); /* Dialog message */ msg2 = g_strdup_printf (_("%s\n\n" "The gschem log may contain more information."), (*err)->message); } dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Cannot load gschem configuration.")); g_object_set (G_OBJECT (dialog), "secondary-text", msg2, NULL); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (msg2); }
/*! \brief Closes a page. * \par Function Description * This function closes the page <B>page</B> of toplevel * <B>toplevel</B>. * * If necessary, the current page of <B>toplevel</B> is changed to * the next valid page or to a new untitled page. * * \param [in] w_current The toplevel environment. * \param [in] page The page to close. */ void x_window_close_page (GSCHEM_TOPLEVEL *w_current, PAGE *page) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *new_current = NULL; GList *iter; g_return_if_fail (toplevel != NULL); g_return_if_fail (page != NULL); g_assert (page->pid != -1); /* If we're closing whilst inside a move action, re-wind the * page contents back to their state before we started */ if (w_current->inside_action && (w_current->event_state == MOVE || w_current->event_state == ENDMOVE)) { o_move_cancel (w_current); } if (page == toplevel->page_current) { /* as it will delete current page, select new current page */ /* first look up in page hierarchy */ new_current = s_page_search_by_page_id (toplevel->pages, page->up); if (new_current == NULL) { /* no up in hierarchy, choice is prev, next, new page */ iter = g_list_find( geda_list_get_glist( toplevel->pages ), page ); if ( g_list_previous( iter ) ) { new_current = (PAGE *)g_list_previous( iter )->data; } else if ( g_list_next( iter ) ) { new_current = (PAGE *)g_list_next( iter )->data; } else { /* need to add a new untitled page */ new_current = NULL; } } /* new_current will be the new current page at the end of the function */ } s_log_message (page->CHANGED ? _("Discarding page [%s]\n") : _("Closing [%s]\n"), page->page_filename); /* remove page from toplevel list of page and free */ s_page_delete (toplevel, page); /* Switch to a different page if we just removed the current */ if (toplevel->page_current == NULL) { /* Create a new page if there wasn't another to switch to */ if (new_current == NULL) { new_current = x_window_open_page (w_current, NULL); } /* change to new_current and update display */ x_window_set_current_page (w_current, new_current); } }
/*! \brief Create a character string representation of a picture OBJECT. * \par Function Description * This function formats a string in the buffer <B>*buff</B> to describe * the picture object <B>*object</B>. * * \param [in] object Picture OBJECT to create string from. * \return A pointer to the picture OBJECT character string. * * \note * Caller must g_free returned character string. * */ char *o_picture_save(OBJECT *object) { int width, height, x1, y1; gchar *encoded_picture=NULL; gchar *out=NULL; guint encoded_picture_length; /* calculate the width and height of the box */ width = abs(object->picture->lower_x - object->picture->upper_x); height = abs(object->picture->upper_y - object->picture->lower_y); /* calculate the lower left corner of the box */ x1 = object->picture->upper_x; y1 = object->picture->upper_y - height; /* move the origin to 0, 0*/ #if DEBUG printf("picture: %d %d %d %d\n", x1, y1, width, height); #endif /* Encode the picture if it's embedded */ if (object->picture->embedded == 1) { encoded_picture = s_encoding_base64_encode( (char *)object->picture->file_content, object->picture->file_length, &encoded_picture_length, TRUE); if (encoded_picture == NULL) { s_log_message(_("ERROR: o_picture_save: unable to encode the picture.\n")); } } if (object->picture->embedded==1 && encoded_picture != NULL) { out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s\n%s\n%s", object->type, x1, y1, width, height, object->picture->angle, /* Convert the (0,1) chars to ASCII */ (object->picture->mirrored)+0x30, object->picture->embedded+0x30, object->picture->filename, encoded_picture, "."); } else { out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s", object->type, x1, y1, width, height, object->picture->angle, /* Convert the (0,1) chars to ASCII */ (object->picture->mirrored)+0x30, object->picture->embedded+0x30, object->picture->filename); } g_free(encoded_picture); return(out); }
/*! \brief Embed the image file associated with a picture * * \par Function Description * This function reads and embeds image file associated with the picture. * * \param [in] toplevel The TOPLEVEL object. * \param [in] object The picture OBJECT to embed */ void o_picture_embed (TOPLEVEL *toplevel, OBJECT *object) { GError *err = NULL; GdkPixbuf *pixbuf; gchar *filename; /* Free any existing embedded data */ g_free (object->picture->file_content); object->picture->file_content = NULL; g_file_get_contents (object->picture->filename, &object->picture->file_content, &object->picture->file_length, &err); if (err != NULL) { s_log_message (_("Failed to load image from file [%s]: %s\n"), object->picture->filename, err->message); g_error_free (err); return; } object->picture->embedded = 1; pixbuf = o_picture_pixbuf_from_buffer (object->picture->file_content, object->picture->file_length, &err); if (err != NULL) { s_log_message (_("Failed to load image from embedded data [%s]: %s\n"), object->picture->filename, err->message); s_log_message (_("Falling back to file loading. Picture unembedded.\n")); g_error_free (err); object->picture->embedded = 0; return; } /* Change to the new pixbuf loaded before we embedded. */ if (object->picture->original_picture != NULL) g_object_unref(object->picture->original_picture); object->picture->original_picture = pixbuf; filename = g_path_get_basename(object->picture->filename); s_log_message (_("Picture [%s] has been embedded\n"), filename); g_free(filename); }
/*! \brief Execute a library command. * \par Function Description * Execute a library command, returning the standard output, or \b * NULL if the command fails for some reason. The system \b PATH is * used to find the program to execute. * The command can write messages to the standard error output. They * are forwarded to the libgeda logging mechanism. * * Private function used only in s_clib.c. * * \todo This is probably generally useful. * * \param command Command string to execute. * \return The program's output, or \b NULL on failure. */ static gchar *run_source_command (const gchar *command) { gchar *standard_output = NULL; gchar *standard_error = NULL; gint exit_status; GError *e = NULL; gboolean success = FALSE; g_return_val_if_fail((command != NULL), NULL); g_spawn_command_line_sync (command, &standard_output, &standard_error, &exit_status, &e); if (e != NULL) { s_log_message (_("Library command failed [%1$s]: %2$s"), command, e->message); g_error_free (e); } else if (WIFSIGNALED(exit_status)) { s_log_message (_("Library command failed [%1$s]: Uncaught signal %2$i."), command, WTERMSIG(exit_status)); } else if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status)) { s_log_message (_("Library command failed [%1$s]"), command); s_log_message(_("Error output was:\n%1$s"), standard_error); } else { success = TRUE; } /* forward library command messages */ if (success && standard_error != NULL) s_log_message ("%s", standard_error); g_free (standard_error); if (success) return standard_output; g_free (standard_output); return NULL; }
/*! \brief unembed an object from a schematic * \par Function Description * This functions unembeds an object \a o_current from a * libgeda structure. Complex objects are just marked to * be not embedded. Picture objects are unembeded immediatly. * * \param toplevel The TOPLEVEL object * \param o_current The OBJECT to unembed */ void o_unembed(TOPLEVEL *toplevel, OBJECT *o_current) { const CLibSymbol *sym; PAGE *page = o_get_page_compat (toplevel, o_current); int page_modified = 0; /* check o_current is an embedded complex */ if (o_current->type == OBJ_COMPLEX && o_complex_is_embedded (o_current)) { /* search for the symbol in the library */ sym = s_clib_get_symbol_by_name (o_current->complex_basename); if (sym == NULL) { /* symbol not found in the symbol library: signal an error */ s_log_message (_("Could not find component [%s], while trying to " "unembed. Component is still embedded\n"), o_current->complex_basename); } else { /* clear the embedded flag */ o_current->complex_embedded = FALSE; s_log_message (_("Component [%s] has been successfully unembedded\n"), o_current->complex_basename); page_modified = 1; } } /* If it's a picture and it's embedded */ if ( (o_current->type == OBJ_PICTURE) && o_picture_is_embedded (toplevel, o_current)) { o_picture_unembed (toplevel, o_current); page_modified = 1; } if (page_modified && page != NULL) { page->CHANGED = 1; } }
/*! \brief Search for the parent page of a page in hierarchy. * \par Function Description * This function searches the parent page of page \a page in the * hierarchy. It checks all the pages in the list \a page_list. * * It returns a pointer on the page if found, NULL otherwise. * * \note * The page \a current_page must be in the list \a page_list. * * \param [in] page_list The list of pages in which to search. * \param [in] current_page The reference page for the search. * \returns A pointer on the page found or NULL if not found. */ PAGE * s_hierarchy_find_up_page (GedaPageList *page_list, PAGE *current_page) { if (current_page->up < 0) { s_log_message(_("There are no schematics above the current one!\n")); return NULL; } return s_page_search_by_page_id (page_list, current_page->up); }
/*! \brief Saves a page to a file. * \par Function Description * This function saves the page <B>page</B> to a file named * <B>filename</B>. * * It returns the value returned by function <B>f_save()</B> trying * to save page <B>page</B> to file <B>filename</B> (1 on success, 0 * on failure). * * <B>page</B> may not be the current page of <B>toplevel</B>. The * current page of <B>toplevel</B> is not affected by this function. * * \param [in] toplevel The toplevel environment. * \param [in] page The page to save. * \param [in] filename The name of the file in which to save page. * \returns 1 on success, 0 otherwise. */ gint x_window_save_page (GSCHEM_TOPLEVEL *w_current, PAGE *page, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current; const gchar *log_msg, *state_msg; gint ret; g_return_val_if_fail (toplevel != NULL, 0); g_return_val_if_fail (page != NULL, 0); g_return_val_if_fail (filename != NULL, 0); /* save current page for restore after opening */ old_current = toplevel->page_current; /* change to page */ s_page_goto (toplevel, page); /* and try saving current page to filename */ ret = (gint)f_save (toplevel, filename); if (ret != 1) { /* an error occured when saving page to file */ log_msg = _("Could NOT save page [%s]\n"); state_msg = _("Error while trying to save"); } else { /* successful save of page to file, update page... */ /* change page name if necessary and prepare log message */ if (g_ascii_strcasecmp (page->page_filename, filename) != 0) { g_free (page->page_filename); page->page_filename = g_strdup (filename); log_msg = _("Saved as [%s]\n"); } else { log_msg = _("Saved [%s]\n"); } state_msg = _("Saved"); /* reset page CHANGED flag */ page->CHANGED = 0; /* update recent file list */ recent_files_add(filename); } /* log status of operation */ s_log_message (log_msg, filename); /* update display and page manager */ x_window_set_current_page (w_current, old_current); i_set_state_msg (w_current, SELECT, state_msg); i_update_toolbar (w_current); return ret; }
/*! \brief Embed the image file associated with a picture * \par Function Description * Verify that a picture has valid data associated with it, and if so, * mark it to be embedded. * * \param [in] toplevel The TOPLEVEL object. * \param [in] object The picture OBJECT to embed */ void o_picture_embed (TOPLEVEL *toplevel, OBJECT *object) { const gchar *filename = o_picture_get_filename (object); gchar *basename; if (o_picture_is_embedded (object)) return; if (object->picture->file_content == NULL) { s_log_message (_("Picture [%1$s] has no image data."), filename); s_log_message (_("Falling back to file loading. Picture is still unembedded.")); object->picture->embedded = 0; return; } object->picture->embedded = 1; basename = g_path_get_basename (filename); s_log_message (_("Picture [%1$s] has been embedded."), basename); g_free (basename); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_edit_show_hidden (GSCHEM_TOPLEVEL *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); o_invalidate_all (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")); } }