summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2018-07-13 06:17:58 +0000
committerRuben Undheim <ruben.undheim@gmail.com>2018-07-13 06:17:58 +0000
commit9e0bd16a997e55d6b9c2e80734ea8e61794c7602 (patch)
treed73377e0368b0c730d5a14019b1eee53897505bf /src
parente1fffcb07ce0d8b0db9e0b4b5e1e0c1128197af5 (diff)
New upstream version 0.84.22
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am102
-rw-r--r--src/clipboard.c27
-rw-r--r--src/clipboard.h21
-rw-r--r--src/coords.c154
-rw-r--r--src/coords.h102
-rw-r--r--src/cursors.c35
-rw-r--r--src/cursors.h21
-rw-r--r--src/debug.h45
-rw-r--r--src/dialogs.c244
-rw-r--r--src/dialogs.h32
-rw-r--r--src/engines/Makefile.am28
-rw-r--r--src/engines/engine-internal.h42
-rw-r--r--src/engines/engine.c195
-rw-r--r--src/engines/engine.h40
-rw-r--r--src/engines/gnucap.c555
-rw-r--r--src/engines/gnucap.h26
-rw-r--r--src/engines/netlist-helper.c624
-rw-r--r--src/engines/netlist-helper.h57
-rw-r--r--src/engines/ngspice-analysis.c1485
-rw-r--r--src/engines/ngspice-analysis.h93
-rw-r--r--src/engines/ngspice-watcher.c715
-rw-r--r--src/engines/ngspice-watcher.h62
-rw-r--r--src/engines/ngspice.c551
-rw-r--r--src/engines/ngspice.h47
-rw-r--r--src/errors.c14
-rw-r--r--src/errors.h17
-rw-r--r--src/file-manager.c20
-rw-r--r--src/file-manager.h14
-rw-r--r--src/file.c129
-rw-r--r--src/file.h8
-rw-r--r--src/gplot/Makefile.am19
-rw-r--r--src/gplot/gplot-internal.h31
-rw-r--r--src/gplot/gplot.c688
-rw-r--r--src/gplot/gplot.h41
-rw-r--r--src/gplot/gplotfunction.c70
-rw-r--r--src/gplot/gplotfunction.h21
-rw-r--r--src/gplot/gplotlines.c224
-rw-r--r--src/gplot/gplotlines.h22
-rw-r--r--src/load-common.h44
-rw-r--r--src/load-library.c290
-rw-r--r--src/load-library.h40
-rw-r--r--src/load-schematic.c599
-rw-r--r--src/load-schematic.h7
-rw-r--r--src/log-interface.h44
-rw-r--r--src/log-view.c52
-rw-r--r--src/log-view.h42
-rw-r--r--src/log.c107
-rw-r--r--src/log.h41
-rw-r--r--src/main.c61
-rw-r--r--src/model/Makefile.am40
-rw-r--r--src/model/item-data.c403
-rw-r--r--src/model/item-data.h128
-rw-r--r--src/model/node-store-private.h353
-rw-r--r--src/model/node-store.c1021
-rw-r--r--src/model/node-store.h76
-rw-r--r--src/model/node.c199
-rw-r--r--src/model/node.h36
-rw-r--r--src/model/part-label.h11
-rw-r--r--src/model/part-private.h30
-rw-r--r--src/model/part-property.c258
-rw-r--r--src/model/part-property.h10
-rw-r--r--src/model/part.c843
-rw-r--r--src/model/part.h57
-rw-r--r--src/model/schematic-print-context.h25
-rw-r--r--src/model/schematic.c806
-rw-r--r--src/model/schematic.h127
-rw-r--r--src/model/textbox.c186
-rw-r--r--src/model/textbox.h37
-rw-r--r--src/model/wire-private.h11
-rw-r--r--src/model/wire.c296
-rw-r--r--src/model/wire.h62
-rw-r--r--src/netlist-editor.c206
-rw-r--r--src/netlist-editor.h35
-rw-r--r--src/options.c59
-rw-r--r--src/options.h36
-rw-r--r--src/oregano-config.c73
-rw-r--r--src/oregano-config.h6
-rw-r--r--src/oregano-utils.c54
-rw-r--r--src/oregano-utils.h23
-rw-r--r--src/oregano.c175
-rw-r--r--src/oregano.h43
-rw-r--r--src/part-browser.c401
-rw-r--r--src/part-browser.h8
-rw-r--r--src/pixmaps/Makefile.am13
-rw-r--r--src/plot.c509
-rw-r--r--src/plot.h6
-rw-r--r--src/save-schematic.c347
-rw-r--r--src/save-schematic.h8
-rw-r--r--src/schematic-view-menu.h339
-rw-r--r--src/schematic-view.c1620
-rw-r--r--src/schematic-view.h71
-rw-r--r--src/settings.c240
-rw-r--r--src/settings.h6
-rw-r--r--src/sheet/Makefile.am38
-rw-r--r--src/sheet/create-wire.c840
-rw-r--r--src/sheet/create-wire.h31
-rw-r--r--src/sheet/grid.c156
-rw-r--r--src/sheet/grid.h40
-rw-r--r--src/sheet/node-item.c70
-rw-r--r--src/sheet/node-item.h28
-rw-r--r--src/sheet/part-item.c1144
-rw-r--r--src/sheet/part-item.h31
-rw-r--r--src/sheet/plot-add-function.c97
-rw-r--r--src/sheet/plot-add-function.h9
-rw-r--r--src/sheet/rubberband.c255
-rw-r--r--src/sheet/rubberband.h66
-rw-r--r--src/sheet/sheet-item-factory.c27
-rw-r--r--src/sheet/sheet-item-factory.h9
-rw-r--r--src/sheet/sheet-item.c873
-rw-r--r--src/sheet/sheet-item.h93
-rw-r--r--src/sheet/sheet-private.h62
-rw-r--r--src/sheet/sheet.c1651
-rw-r--r--src/sheet/sheet.h155
-rw-r--r--src/sheet/textbox-item.c421
-rw-r--r--src/sheet/textbox-item.h39
-rw-r--r--src/sheet/wire-item.c831
-rw-r--r--src/sheet/wire-item.h35
-rw-r--r--src/sim-settings-gui.c1217
-rw-r--r--src/sim-settings-gui.h113
-rw-r--r--src/sim-settings.c1550
-rw-r--r--src/sim-settings.h220
-rw-r--r--src/simulation.c233
-rw-r--r--src/simulation.h132
-rw-r--r--src/splash.c63
-rw-r--r--src/splash.h15
-rw-r--r--src/stock.c14
-rw-r--r--src/stock.h6
-rw-r--r--src/stock/Makefile.am18
-rw-r--r--src/tools/cancel-info.c79
-rw-r--r--src/tools/cancel-info.h (renamed from src/model/sheet-pos.h)36
-rw-r--r--src/tools/thread-pipe.c600
-rw-r--r--src/tools/thread-pipe.h57
-rw-r--r--src/wscript49
-rw-r--r--src/xml-compat.h7
-rw-r--r--src/xml-helper.c67
-rw-r--r--src/xml-helper.h17
136 files changed, 16083 insertions, 12652 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index f4090a4..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,102 +0,0 @@
-SUBDIRS = \
- gplot \
- engines \
- model \
- sheet \
- stock \
- pixmaps
-
-AM_CFLAGS = -Wall -DG_DISABLE_DEPRECATED -DGSEAL_ENABLE \
- -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED \
- -DGTK_DISABLE_DEPRECATED \
- -DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
- -DGTK_DISABLE_SINGLE_INCLUDES
-
-oreganodir = $(datadir)/oregano
-
-INCLUDES = \
- -DVERSION="\"$(VERSION)\"" \
- -DPACKAGE=\""oregano\"" \
- -DGETTEXT_PACKAGE=\""oregano\"" \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -I$(includedir) $(GNOME_INCLUDEDIR) \
- -DOREGANO_UIDIR=\""$(oreganodir)/xml"\" \
- -DOREGANO_LIBRARYDIR=\""$(oreganodir)/libraries"\" \
- -DOREGANO_MODELDIR=\""$(oreganodir)/models"\" \
- -DOREGANO_LANGDIR=\""$(oreganodir)/language-specs"\" \
- -DDATADIR=\""$(datadir)"\" \
- -I./sheet \
- -I./gplot \
- -I./model \
- -I./engines \
- -I. \
- $(OREGANO_CFLAGS)
-
-bin_PROGRAMS = oregano
-
-OREGANO_LIBS += gplot/libgplot.a \
- engines/libengines.a \
- model/libmodel.a \
- sheet/libsheet.a
-
-oregano_PIXMAPS = \
- plot.xpm \
- tool_wire.xpm \
- tool_part.xpm \
- tool_arrow.xpm \
- tool_text.xpm \
- mini_icon.xpm \
- logo.png
-
-oregano_SOURCES = \
- clipboard.h \
- clipboard.c \
- cursors.c \
- cursors.h \
- dialogs.c \
- dialogs.h \
- errors.c \
- errors.h \
- file.c \
- file.h \
- file-manager.c \
- file-manager.h \
- load-common.h \
- load-library.c \
- load-library.h \
- load-schematic.c \
- load-schematic.h \
- main.c \
- netlist-editor.c \
- netlist-editor.h \
- oregano-config.c \
- oregano-config.h \
- oregano-utils.c \
- oregano-utils.h \
- part-browser.c \
- part-browser.h \
- plot.c \
- plot.h \
- save-schematic.c \
- save-schematic.h \
- schematic-view.c \
- schematic-view.h \
- schematic-view-menu.h \
- settings.c \
- settings.h \
- sim-settings.c \
- sim-settings.h \
- simulation.c \
- simulation.h \
- splash.h \
- splash.c \
- stock.c \
- stock.h \
- xml-compat.h \
- xml-helper.c \
- xml-helper.h \
- oregano.c \
- oregano.h
-
-oregano_LDADD = \
- $(OREGANO_LIBS)
diff --git a/src/clipboard.c b/src/clipboard.c
index 98c69fe..66c04b7 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -36,13 +36,13 @@
#include "sheet-item.h"
#include "clipboard.h"
-struct _ClipboardData {
+struct _ClipboardData
+{
ItemData *item_data;
SheetItemClass *item_class;
};
-void
-clipboard_empty (void)
+void clipboard_empty (void)
{
GSList *list;
ClipboardData *cb_data;
@@ -61,8 +61,7 @@ clipboard_empty (void)
oregano.clipboard = NULL;
}
-gboolean
-clipboard_is_empty (void)
+gboolean clipboard_is_empty (void)
{
if (oregano.clipboard == NULL)
return TRUE;
@@ -70,8 +69,7 @@ clipboard_is_empty (void)
return g_slist_length (oregano.clipboard) > 0 ? FALSE : TRUE;
}
-void
-clipboard_foreach (ClipBoardFunction callback, gpointer user_data)
+void clipboard_foreach (ClipBoardFunction callback, gpointer user_data)
{
GSList *list;
ClipboardData *data;
@@ -85,8 +83,7 @@ clipboard_foreach (ClipBoardFunction callback, gpointer user_data)
}
}
-void
-clipboard_add_object (GObject *item)
+void clipboard_add_object (GObject *item)
{
ItemDataClass *id_class;
ItemData *item_data, *clone;
@@ -111,16 +108,14 @@ clipboard_add_object (GObject *item)
oregano.clipboard = g_slist_prepend (oregano.clipboard, cb_data);
}
-GObject *
-clipboard_data_get_item_data (ClipboardData *data)
+GObject *clipboard_data_get_item_data (ClipboardData *data)
{
g_return_val_if_fail (data != NULL, NULL);
return G_OBJECT (data->item_data);
}
-GObjectClass *
-clipboard_data_get_item_class (ClipboardData *data)
+GObjectClass *clipboard_data_get_item_class (ClipboardData *data)
{
g_return_val_if_fail (data != NULL, NULL);
diff --git a/src/clipboard.h b/src/clipboard.h
index 8f98871..05c1d47 100644
--- a/src/clipboard.h
+++ b/src/clipboard.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __CLIPBOARD_H
@@ -35,14 +35,13 @@
typedef struct _ClipboardData ClipboardData;
-typedef void (*ClipBoardFunction) (ClipboardData *data, gpointer user_data);
+typedef void (*ClipBoardFunction)(ClipboardData *data, gpointer user_data);
-void clipboard_empty (void);
-gboolean clipboard_is_empty (void);
-void clipboard_foreach (ClipBoardFunction callback,
- gpointer user_data);
-void clipboard_add_object (GObject *item);
-GObjectClass *clipboard_data_get_item_class (ClipboardData *data);
-GObject *clipboard_data_get_item_data (ClipboardData *data);
+void clipboard_empty (void);
+gboolean clipboard_is_empty (void);
+void clipboard_foreach (ClipBoardFunction callback, gpointer user_data);
+void clipboard_add_object (GObject *item);
+GObjectClass *clipboard_data_get_item_class (ClipboardData *data);
+GObject *clipboard_data_get_item_data (ClipboardData *data);
#endif
diff --git a/src/coords.c b/src/coords.c
new file mode 100644
index 0000000..57eb66a
--- /dev/null
+++ b/src/coords.c
@@ -0,0 +1,154 @@
+/*
+ * coords.c
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2012-2013 Bernhard Schuster
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "coords.h"
+
+inline Coords *coords_new (gdouble x, gdouble y)
+{
+ Coords *c = g_malloc (sizeof(Coords));
+ g_assert (c != NULL);
+ c->x = x;
+ c->y = y;
+ return c;
+}
+
+inline Coords *coords_new_copy (const Coords *src) { return coords_new (src->x, src->y); }
+
+inline void coords_destroy (Coords *c)
+{
+ g_free (c);
+}
+
+inline Coords *coords_add (Coords *a, const Coords *b)
+{
+ if (!a || !b)
+ return NULL;
+ a->x += b->x;
+ a->y += b->y;
+ return a;
+}
+
+inline Coords coords_sum (const Coords *a, const Coords *b)
+{
+ g_assert (a);
+ g_assert (b);
+
+ Coords c;
+ c.x = a->x + b->x;
+ c.y = a->y + b->y;
+ return c;
+}
+
+inline Coords coords_sub (const Coords *a, const Coords *b)
+{
+ g_assert (a);
+ g_assert (b);
+
+ Coords c;
+ c.x = a->x - b->x;
+ c.y = a->y - b->y;
+ return c;
+}
+
+inline Coords *coords_sum_new (const Coords *a, const Coords *b)
+{
+ if (G_UNLIKELY (!a || !b))
+ return NULL;
+ Coords *c = coords_new (a->x, a->y);
+ c->x += b->x;
+ c->y += b->y;
+ return c;
+}
+
+inline Coords *coords_set (Coords *a, const Coords *val)
+{
+ if (G_UNLIKELY (!a || !val))
+ return NULL;
+ a->x = val->x;
+ a->y = val->y;
+ return a;
+}
+
+inline Coords coords_average (const Coords *a, const Coords *b)
+{
+ Coords r = (Coords)(*a);
+ r.x += b->x;
+ r.x /= 2.0;
+ r.y += b->y;
+ r.y /= 2.0;
+ return r;
+}
+
+inline gdouble coords_dot (const Coords *a, const Coords *b)
+{
+ return (a->x * b->x) + (a->y * b->y);
+}
+
+inline gdouble coords_cross (const Coords *a, const Coords *b)
+{
+ return (a->x * b->y) - (a->y * b->x);
+}
+
+inline gdouble coords_euclid (const Coords *a) { return sqrt (coords_dot (a, a)); }
+
+inline gdouble coords_euclid2 (const Coords *a) { return coords_dot (a, a); }
+
+inline gdouble coords_distance (const Coords *a, const Coords *b)
+{
+ return sqrt (coords_dot (a, b));
+}
+
+#define CIRCLE_R_SHIFT(x, r) ((x >> r) | (x << (sizeof(x) * 8 - r)))
+#define CIRCLE_L_SHIFT(x, l) ((x << l) | (x >> (sizeof(x) * 8 - l)))
+inline guint coords_hash (gconstpointer v)
+{
+ const Coords *c = v;
+ const guint x = (guint)(c->x);
+ const guint y = (guint)(c->y);
+ return CIRCLE_L_SHIFT (x, 7) ^ CIRCLE_R_SHIFT (y, 3);
+}
+
+inline gboolean coords_equal (const Coords *a, const Coords *b)
+{
+ return G_UNLIKELY (fabs (a->x - b->x) < COORDS_DELTA && fabs (a->y - b->y) < COORDS_DELTA);
+}
+
+inline gint coords_compare (const Coords *a, const Coords *b)
+{
+ if (coords_equal (a, b))
+ return 0;
+ if ((a->x > b->x) || (fabs (a->x - b->x) < (COORDS_DELTA * COORDS_DELTA) && (a->y > b->y)))
+ return -1;
+ return +1;
+}
diff --git a/src/coords.h b/src/coords.h
new file mode 100644
index 0000000..30e30fa
--- /dev/null
+++ b/src/coords.h
@@ -0,0 +1,102 @@
+/*
+ * coords.c
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2012-2013 Bernhard Schuster
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __COORDS_H
+#define __COORDS_H
+
+#define COORDS_DELTA (1e-5)
+
+#include <glib.h>
+#include <math.h>
+
+typedef struct _Coords
+{
+ gdouble x;
+ gdouble y;
+} Coords;
+
+Coords *coords_new (gdouble x, gdouble y);
+
+Coords *coords_new_copy (const Coords *c);
+
+void coords_destroy (Coords *c);
+
+/*
+ * Adds b to a and returns a pointer to a which holds now the result
+ */
+Coords *coords_add (Coords *a, const Coords *b);
+
+/*
+ * Adds b to a and returns a ptr to a Coord struct which has to be freed by
+ * either coords_destroy
+ */
+Coords *coords_sum_new (const Coords *a, const Coords *b);
+
+Coords *coords_set (Coords *a, const Coords *val);
+
+/*
+ *
+ */
+Coords coords_sum (const Coords *a, const Coords *b);
+
+Coords coords_sub (const Coords *a, const Coords *b);
+
+/*
+ * calculates the average of two points
+ */
+Coords coords_average (const Coords *a, const Coords *b);
+
+gdouble coords_cross (const Coords *a, const Coords *b);
+
+gdouble coords_dot (const Coords *a, const Coords *b);
+
+gdouble coords_euclid (const Coords *a);
+
+gdouble coords_euclid2 (const Coords *a);
+
+gdouble coords_distance (const Coords *a, const Coords *b);
+
+gboolean coords_equal (const Coords *a, const Coords *b);
+
+/*
+ * used for GHashTable key hashing
+ */
+guint coords_hash (gconstpointer v);
+
+/*
+ * used for comparsion in GHashTable
+ */
+gint coords_compare (const Coords *a, const Coords *b);
+
+#endif /* __COORDS_H */
diff --git a/src/cursors.c b/src/cursors.c
index 80f9d04..78ac010 100644
--- a/src/cursors.c
+++ b/src/cursors.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,46 +26,39 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "cursors.h"
+#include "debug.h"
OreganoCursor oregano_cursors[] = {
- { NULL, GDK_LEFT_PTR },
- { NULL, GDK_TCROSS },
- { NULL, GDK_PENCIL },
- { NULL, GDK_XTERM },
- { NULL, -1 }
-};
+ {NULL, GDK_LEFT_PTR}, {NULL, GDK_TCROSS}, {NULL, GDK_PENCIL}, {NULL, GDK_XTERM}, {NULL, -1}};
-void
-cursors_init (void)
+void cursors_init (void)
{
int i;
GdkDisplay *display;
- display = gdk_display_get_default();
+ display = gdk_display_get_default ();
for (i = 0; oregano_cursors[i].type != -1; i++) {
- oregano_cursors[i].cursor =
- gdk_cursor_new_for_display (display,
- oregano_cursors[i].type);
+ oregano_cursors[i].cursor = gdk_cursor_new_for_display (display, oregano_cursors[i].type);
}
}
-void
-cursors_shutdown (void)
+void cursors_shutdown (void)
{
int i;
- for (i = 0; oregano_cursors[i].type != -1; i++)
- g_object_unref (oregano_cursors[i].cursor);
+ for (i = 0; oregano_cursors[i].type != -1; i++) {
+ if (oregano_cursors[i].cursor)
+ g_object_unref (oregano_cursors[i].cursor);
+ }
}
-void
-cursor_set_widget (GtkWidget *w, int name)
+void cursor_set_widget (GtkWidget *w, int name)
{
if (gtk_widget_get_window (w))
gdk_window_set_cursor (gtk_widget_get_window (w), oregano_cursors[name].cursor);
diff --git a/src/cursors.h b/src/cursors.h
index cd13c4b..0b840e1 100644
--- a/src/cursors.h
+++ b/src/cursors.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,28 +26,29 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __CURSORS_H
#define __CURSORS_H
#include <gtk/gtk.h>
-#define OREGANO_CURSOR_LEFT_PTR 0
-#define OREGANO_CURSOR_CROSS 1
-#define OREGANO_CURSOR_PENCIL 2
-#define OREGANO_CURSOR_CARET 3
+#define OREGANO_CURSOR_LEFT_PTR 0
+#define OREGANO_CURSOR_CROSS 1
+#define OREGANO_CURSOR_PENCIL 2
+#define OREGANO_CURSOR_CARET 3
-typedef struct {
+typedef struct
+{
GdkCursor *cursor;
GdkCursorType type;
} OreganoCursor;
extern OreganoCursor oregano_cursors[];
-void cursors_init (void);
-void cursors_shutdown (void);
+void cursors_init (void);
+void cursors_shutdown (void);
void cursor_set_widget (GtkWidget *w, int name);
#endif
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..e9e4003
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,45 @@
+/*
+ * debug.h
+ *
+ *
+ * Authors:
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 2012-2013 Bernhard Schuster
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib/gprintf.h>
+
+#ifdef DEBUG_THIS
+#undef DEBUG_THIS
+#endif
+#define DEBUG_THIS 0
+
+#ifndef DEBUG_ALL
+#define DEBUG_ALL 0
+#endif
+
+#define NG_DEBUG(msg, ...) \
+ { \
+ if (DEBUG_THIS || DEBUG_ALL) { \
+ g_printf ("%s:%d @ %s +++ " msg "\n", __FILE__, __LINE__, __FUNCTION__, \
+ ##__VA_ARGS__); \
+ } \
+ }
diff --git a/src/dialogs.c b/src/dialogs.c
index 1c6b90d..a18c2df 100644
--- a/src/dialogs.c
+++ b/src/dialogs.c
@@ -4,12 +4,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,10 +27,12 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
+#include <sys/syscall.h>
+
#include <glib/gi18n.h>
#include <gtk/gtk.h>
@@ -35,152 +41,216 @@
#include "pixmaps/logo.xpm"
-static GtkWidget *about = NULL;
+/*
+ * Schedule a call to the oregano_error() function so that it is
+ * called whenever there are no higher priority events pending.
+ *
+ * The caller should schedule this function call using the GLib
+ * function g_idle_add_full().
+ */
+gboolean oregano_schedule_error (gchar *msg) { oregano_error_with_title (msg, NULL); return G_SOURCE_REMOVE; }
-void
-oregano_error (gchar *msg)
+/*
+ * Schedule a call to the oregano_error_with_title() function
+ * so that it is called whenever there are no higher priority
+ * events pending.
+ *
+ * The caller should schedule this function call using the GLib
+ * function g_idle_add_full().
+ */
+gboolean oregano_schedule_error_with_title (OreganoTitleMsg *tm)
{
- oregano_error_with_title (msg, NULL);
+ oregano_error_with_title (tm->title, tm->msg);
+ g_free (tm->title);
+ g_free (tm->msg);
+ g_free (tm);
+
+ return G_SOURCE_REMOVE;
}
-void
-oregano_error_with_title (gchar *title, gchar *desc)
+void oregano_error (gchar *msg) { oregano_error_with_title (msg, NULL); }
+
+void oregano_error_with_title (gchar *title, gchar *msg)
{
GtkWidget *dialog;
- GString* span_msg;
+ GString *span_msg;
+ pid_t tid = 0;
+
+#ifdef SYS_gettid
+ tid = syscall(SYS_gettid);
+#endif
+ // make sure that this is running in the main thread
+ if (tid && (getpid() != tid)) {
+ OreganoTitleMsg *tm = g_malloc (sizeof (OreganoTitleMsg));
+ g_assert (tm != NULL);
+ tm->title = g_strdup (title);
+ tm->msg = g_strdup (msg);
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) oregano_schedule_error_with_title, tm, NULL);
+ return;
+ }
span_msg = g_string_new ("<span weight=\"bold\" size=\"large\">");
span_msg = g_string_append (span_msg, title);
- span_msg = g_string_append (span_msg,"</span>");
+ span_msg = g_string_append (span_msg, "</span>");
- if (desc && desc[0] != '\0') {
- span_msg = g_string_append (span_msg,"\n\n");
- span_msg = g_string_append (span_msg, desc);
+ if (msg && msg[0] != '\0') {
+ span_msg = g_string_append (span_msg, "\n\n");
+ span_msg = g_string_append (span_msg, msg);
}
- dialog = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- span_msg->str);
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, NULL);
+
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), span_msg->str);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
gtk_dialog_run (GTK_DIALOG (dialog));
g_string_free (span_msg, TRUE);
+
gtk_widget_destroy (dialog);
}
-void
-oregano_warning (gchar *msg)
+/*
+ * Schedule a call to the oregano_warning() function so that it is
+ * called whenever there are no higher priority events pending.
+ *
+ * The caller should schedule this function call using the GLib
+ * function g_idle_add_full().
+ */
+gboolean oregano_schedule_warning (gchar *msg) { oregano_warning_with_title (msg, NULL); return G_SOURCE_REMOVE; }
+
+/*
+ * Schedule a call to the oregano_warning_with_title() function
+ * so that it is called whenever there are no higher priority
+ * events pending.
+ *
+ * The caller should schedule this function call using the GLib
+ * function g_idle_add_full().
+ */
+gboolean oregano_schedule_warning_with_title (OreganoTitleMsg *tm)
{
- oregano_warning_with_title (msg, NULL);
+ oregano_warning_with_title (tm->title, tm->msg);
+ g_free (tm->title);
+ g_free (tm->msg);
+ g_free (tm);
+
+ return G_SOURCE_REMOVE;
}
-void
-oregano_warning_with_title (gchar *title, gchar *desc)
+void oregano_warning (gchar *msg) { oregano_warning_with_title (msg, NULL); }
+
+void oregano_warning_with_title (gchar *title, gchar *msg)
{
GtkWidget *dialog;
- GString* span_msg;
+ GString *span_msg;
+ pid_t tid = 0;
+
+#ifdef SYS_gettid
+ tid = syscall(SYS_gettid);
+#endif
+ // make sure that this is running in the main thread
+ if (tid && (getpid() != tid)) {
+ OreganoTitleMsg *tm = g_malloc (sizeof (OreganoTitleMsg));
+ g_assert (tm != NULL);
+ tm->title = g_strdup (title);
+ tm->msg = g_strdup (msg);
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) oregano_schedule_warning_with_title, tm, NULL);
+ return;
+ }
span_msg = g_string_new ("<span weight=\"bold\" size=\"large\">");
span_msg = g_string_append (span_msg, title);
- span_msg = g_string_append (span_msg,"</span>");
+ span_msg = g_string_append (span_msg, "</span>");
- if (desc && desc[0] != '\0') {
- span_msg = g_string_append (span_msg,"\n\n");
- span_msg = g_string_append (span_msg, desc);
+ if (msg && msg[0] != '\0') {
+ span_msg = g_string_append (span_msg, "\n\n");
+ span_msg = g_string_append (span_msg, msg);
}
- dialog = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- span_msg->str);
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE, NULL);
+
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), span_msg->str);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
gtk_dialog_run (GTK_DIALOG (dialog));
g_string_free (span_msg, TRUE);
+
gtk_widget_destroy (dialog);
}
-gint
-oregano_question (gchar *msg)
+/*
+ * Schedule a call to the oregano_question() function so that it is
+ * called whenever there are no higher priority events pending.
+ *
+ * The caller should schedule this function call using the GLib
+ * function g_idle_add_full().
+ */
+gboolean oregano_schedule_question (OreganoQuestionAnswer *qa) {
+ qa->ans = oregano_question (qa->msg);
+ g_free (qa->msg);
+
+ return G_SOURCE_REMOVE;
+}
+
+gint oregano_question (gchar *msg)
{
GtkWidget *dialog;
gint ans;
- dialog = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_OK,
- GTK_BUTTONS_CANCEL,
- msg);
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO, NULL);
+
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
ans = gtk_dialog_run (GTK_DIALOG (dialog));
- switch (ans) {
- case GTK_RESPONSE_ACCEPT:
- return TRUE;
- default:
- return FALSE;
- }
-
gtk_widget_destroy (dialog);
+
+ return (ans == GTK_RESPONSE_YES);
}
-void
-dialog_about (void)
+void dialog_about (void)
{
+ static GtkWidget *about = NULL;
GdkPixbuf *logo;
- const gchar *authors[] = {
- "Richard Hult",
- "Margarita Manterola",
- "Andres de Barbara",
- "Gustavo M. Pereyra",
- "Maximiliano Curia",
- "Ricardo Markiewicz",
- "Marc Lorber",
- NULL
- };
-
- const char *docs[] = {
- "Ricardo Markiewicz <rmarkie@fi.uba.ar> (es)",
- "Jordi Mallach <tradgnome@softcatala.net> (ca)",
- "Marc Lorber <lorber.marc@wanadoo.fr> (en)",
- NULL
- };
-
- const gchar *copy = _("(c) 2009-2012 Marc Lorber 2003-2006 LUGFi\n(c) 1999-2001 Richard Hult");
-
- // Allow only one about box at a time.
- if (about) {
- gdk_window_raise (gtk_widget_get_window (about));
- return;
- }
+ const gchar *authors[] = {"Richard Hult", "Margarita Manterola", "Andres de Barbara",
+ "Gustavo M. Pereyra", "Maximiliano Curia", "Ricardo Markiewicz",
+ "Marc Lorber", "Bernhard Schuster", "Guido Trentalancia",
+ NULL};
+
+ const char *docs[] = {"Ricardo Markiewicz <rmarkie@fi.uba.ar> (es)",
+ "Jordi Mallach <tradgnome@softcatala.net> (ca)",
+ "Marc Lorber <lorber.marc@wanadoo.fr> (en)",
+ "Bernhard Schuster <bernhard@ahoi.io> (de)",
+ NULL};
+
+ const gchar *copy = _ ("(c) 2017 Guido Trentalancia\n"
+ "(c) 2012-2017 Bernhard Schuster\n"
+ "(c) 2009-2012 Marc Lorber\n"
+ "(c) 2003-2006 LUGFi\n"
+ "(c) 1999-2001 Richard Hult");
- logo = gdk_pixbuf_new_from_xpm_data ((const char **) logo_xpm);
+ logo = gdk_pixbuf_new_from_xpm_data ((const char **)logo_xpm);
about = gtk_about_dialog_new ();
gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (about), "Oregano");
gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (about), VERSION);
gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (about), copy);
- gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about),
- _("Schematic capture and circuit simulation.\n"));
- gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (about),
- "GNU General Public License");
- gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (about),
- "https://github.com/marc-lorber/oregano");
+ gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about),
+ _ ("Schematic capture and circuit simulation.\n"));
+ gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (about), "GNU General Public License");
+ gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (about), "https://ahoi.io/project/oregano");
gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (about), authors);
gtk_about_dialog_set_documenters (GTK_ABOUT_DIALOG (about), docs);
gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (about), logo);
gtk_dialog_run (GTK_DIALOG (about));
gtk_widget_destroy (about);
+ about = NULL;
}
diff --git a/src/dialogs.h b/src/dialogs.h
index 01d8e44..5556e56 100644
--- a/src/dialogs.h
+++ b/src/dialogs.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __DIALOGS_H
@@ -35,10 +37,30 @@
#include "schematic.h"
+typedef struct _OreganoTitleMsg OreganoTitleMsg;
+typedef struct _OreganoQuestionAnswer OreganoQuestionAnswer;
+
+struct _OreganoTitleMsg
+{
+ gchar *title;
+ gchar *msg;
+};
+
+struct _OreganoQuestionAnswer
+{
+ gchar *msg;
+ gint ans;
+};
+
+gboolean oregano_schedule_error (gchar *msg);
+gboolean oregano_schedule_error_with_title (OreganoTitleMsg *tm);
void oregano_error (gchar *msg);
-void oregano_error_with_title (gchar *title, gchar *desc);
+void oregano_error_with_title (gchar *title, gchar *msg);
+gboolean oregano_schedule_warning (gchar *msg);
+gboolean oregano_schedule_warning_with_title (OreganoTitleMsg *tm);
void oregano_warning (gchar *msg);
-void oregano_warning_with_title (gchar *title, gchar *desc);
+void oregano_warning_with_title (gchar *title, gchar *msg);
+gboolean oregano_schedule_question (OreganoQuestionAnswer *qa);
gint oregano_question (gchar *msg);
void dialog_about (void);
diff --git a/src/engines/Makefile.am b/src/engines/Makefile.am
deleted file mode 100644
index 09af9f1..0000000
--- a/src/engines/Makefile.am
+++ /dev/null
@@ -1,28 +0,0 @@
-oreganodir = $(datadir)/oregano
-
-AM_CFLAGS = -g -Wall -DG_DISABLE_DEPRECATED -DGSEAL_ENABLE \
- -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED \
- -DGTK_DISABLE_DEPRECATED \
- -DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
- -DGTK_DISABLE_SINGLE_INCLUDES
-
-INCLUDES = \
- $(OREGANO_CFLAGS) -I$(top_srcdir)/src \
- -I$(top_srcdir)/src/model -I$(top_srcdir)/src/sheet \
- -DOREGANO_XMLDIR=\""$(oreganodir)/xml"\" \
- -DOREGANO_LIBRARYDIR=\""$(oreganodir)/libraries"\" \
- -DOREGANO_MODELDIR=\""$(oreganodir)/models"\"
-
-noinst_LIBRARIES = libengines.a
-libengines_a_SOURCES = \
- engine.c \
- engine-internal.h \
- engine.h \
- gnucap.c \
- gnucap.h \
- netlist-helper.c \
- netlist-helper.h \
- ngspice-analysis.c \
- ngspice.c \
- ngspice-analysis.h \
- ngspice.h
diff --git a/src/engines/engine-internal.h b/src/engines/engine-internal.h
index 4f5bafe..661fcfd 100644
--- a/src/engines/engine-internal.h
+++ b/src/engines/engine-internal.h
@@ -5,7 +5,7 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __ENGINE_INTERNAL_H
#define __ENGINE_INTERNAL_H 1
@@ -34,28 +34,34 @@
#include "schematic.h"
#include "simulation.h"
-#define OREGANO_TYPE_ENGINE (oregano_engine_get_type ())
-#define OREGANO_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
-#define OREGANO_IS_ENGINE_CLASS(klass) (G_TYPE_CLASS_TYPE((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
-#define OREGANO_ENGINE_GET_CLASS(klass) (G_TYPE_INSTANCE_GET_INTERFACE((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
+#define OREGANO_TYPE_ENGINE (oregano_engine_get_type ())
+#define OREGANO_ENGINE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
+#define OREGANO_IS_ENGINE_CLASS(klass) \
+ (G_TYPE_CLASS_TYPE ((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
+#define OREGANO_ENGINE_GET_CLASS(klass) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((klass), OREGANO_TYPE_ENGINE, OreganoEngineClass))
typedef struct _OreganoEngineClass OreganoEngineClass;
-struct _OreganoEngineClass {
+struct _OreganoEngineClass
+{
GTypeInterface parent;
- void (*start) (OreganoEngine *engine);
- void (*stop) (OreganoEngine *engine);
- void (*progress) (OreganoEngine *engine, double *p);
- void (*get_netlist) (OreganoEngine *engine, const gchar *sm, GError **error);
- GList* (*get_results) (OreganoEngine *engine);
- gchar* (*get_operation) (OreganoEngine *engine);
- gboolean (*has_warnings) (OreganoEngine *engine);
- gboolean (*is_available) (OreganoEngine *engine);
+ void (*start)(OreganoEngine *engine);
+ void (*stop)(OreganoEngine *engine);
+ void (*progress_solver)(OreganoEngine *engine, double *p);
+ void (*progress_reader)(OreganoEngine *engine, double *p);
+ gboolean (*get_netlist)(OreganoEngine *engine, const gchar *sm, GError **error);
+ GList *(*get_results)(OreganoEngine *engine);
+ gchar *(*get_operation_solver)(OreganoEngine *engine);
+ gchar *(*get_operation_reader)(OreganoEngine *engine);
+ gboolean (*has_warnings)(OreganoEngine *engine);
+ gboolean (*is_available)(OreganoEngine *engine);
// Signals
- void (*done) ();
- void (*abort) ();
+ void (*done)();
+ void (*abort)();
};
#endif
diff --git a/src/engines/engine.c b/src/engines/engine.c
index 738a0b9..5984bd4 100644
--- a/src/engines/engine.c
+++ b/src/engines/engine.c
@@ -4,12 +4,14 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,8 +25,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib/gi18n.h>
@@ -35,155 +37,158 @@
#include "ngspice.h"
static gchar *analysis_names[] = {
- N_("Operating Point"),
- N_("Transient Analysis"),
- N_("DC transfer characteristic"),
- N_("AC Analysis"),
- N_("Transfer Function"),
- N_("Distortion Analysis"),
- N_("Noise Analysis"),
- N_("Pole-Zero Analysis"),
- N_("Sensitivity Analysis"),
- N_("Fourier Analysis"),
- N_("Unknown Analysis"),
- NULL
-};
-
-// Signals
-enum {
- DONE,
- ABORTED,
- LAST_SIGNAL
-};
-
-static guint engine_signals[LAST_SIGNAL] = { 0 };
+ [ANALYSIS_TYPE_NONE] = N_ ("None"),
+ [ANALYSIS_TYPE_OP_POINT] = N_ ("Operating Point"),
+ [ANALYSIS_TYPE_TRANSIENT] = N_ ("Transient Analysis"),
+ [ANALYSIS_TYPE_DC_TRANSFER] = N_ ("DC transfer characteristic"),
+ [ANALYSIS_TYPE_AC] = N_ ("AC Analysis"),
+ [ANALYSIS_TYPE_TRANSFER] = N_ ("Transfer Function"),
+ [ANALYSIS_TYPE_DISTORTION] = N_ ("Distortion Analysis"),
+ [ANALYSIS_TYPE_NOISE] = N_ ("Noise Spectral Density Curves"),
+ [ANALYSIS_TYPE_POLE_ZERO] = N_ ("Pole-Zero Analysis"),
+ [ANALYSIS_TYPE_SENSITIVITY] = N_ ("Sensitivity Analysis"),
+ [ANALYSIS_TYPE_FOURIER] = N_ ("Fourier analysis"),
+ [ANALYSIS_TYPE_UNKNOWN] = N_ ("Unknown Analysis"),
+ NULL};
+
+// Engines Types
+static gchar *engine_names[] = {
+ [OREGANO_ENGINE_GNUCAP] = N_ ("gnucap"),
+ [OREGANO_ENGINE_SPICE3] = N_ ("spice3"),
+ [OREGANO_ENGINE_NGSPICE] = N_ ("ngspice"),
+ NULL};
+
+// Signals
+enum { DONE, ABORTED, LAST_SIGNAL };
+
+static guint engine_signals[LAST_SIGNAL] = {0};
static void oregano_engine_base_init (gpointer g_class);
-GType
-oregano_engine_get_type (void)
+GType oregano_engine_get_type (void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
- sizeof (OreganoEngineClass),
- oregano_engine_base_init, // base_init
- NULL, // base_finalize
- NULL, // class_init
- NULL, // class_finalize
- NULL, // class_data
- 0,
- 0, // n_preallocs
- NULL // instance_init
+ sizeof(OreganoEngineClass),
+ oregano_engine_base_init, // base_init
+ NULL, // base_finalize
+ NULL, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+ 0,
+ 0, // n_preallocs
+ NULL // instance_init
};
- type = g_type_register_static (G_TYPE_INTERFACE, "OreganoEngine", &info,
- 0);
+ type = g_type_register_static (G_TYPE_INTERFACE, "OreganoEngine", &info, 0);
}
return type;
}
-static void
-oregano_engine_base_init (gpointer g_class)
+static void oregano_engine_base_init (gpointer g_class)
{
static gboolean initialized = FALSE;
if (!initialized) {
// create interface signals here.
- engine_signals[DONE] = g_signal_new ("done",
- G_TYPE_FROM_CLASS (g_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (OreganoEngineClass, done),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- engine_signals[ABORTED] = g_signal_new ("aborted",
- G_TYPE_FROM_CLASS (g_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (OreganoEngineClass, abort),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
+ engine_signals[DONE] =
+ g_signal_new ("done", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (OreganoEngineClass, done), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ engine_signals[ABORTED] =
+ g_signal_new ("aborted", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (OreganoEngineClass, abort), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
initialized = TRUE;
}
}
-void
-oregano_engine_start (OreganoEngine *self)
+void oregano_engine_start (OreganoEngine *self) { OREGANO_ENGINE_GET_CLASS (self)->start (self); }
+
+void oregano_engine_stop (OreganoEngine *self) { OREGANO_ENGINE_GET_CLASS (self)->stop (self); }
+
+gboolean oregano_engine_has_warnings (OreganoEngine *self)
{
- OREGANO_ENGINE_GET_CLASS (self)->start (self);
+ return OREGANO_ENGINE_GET_CLASS (self)->has_warnings (self);
}
-void
-oregano_engine_stop (OreganoEngine *self)
+gboolean oregano_engine_is_available (OreganoEngine *self)
{
- OREGANO_ENGINE_GET_CLASS (self)->stop (self);
+ return OREGANO_ENGINE_GET_CLASS (self)->is_available (self);
}
-gboolean
-oregano_engine_has_warnings (OreganoEngine *self)
+void oregano_engine_get_progress_solver (OreganoEngine *self, double *p)
{
- return OREGANO_ENGINE_GET_CLASS (self)->has_warnings (self);
+ g_return_if_fail(OREGANO_ENGINE_GET_CLASS (self)->progress_solver != NULL);
+ OREGANO_ENGINE_GET_CLASS (self)->progress_solver (self, p);
}
-gboolean
-oregano_engine_is_available (OreganoEngine *self)
+void oregano_engine_get_progress_reader (OreganoEngine *self, double *p)
{
- return OREGANO_ENGINE_GET_CLASS (self)->is_available (self);
+ g_return_if_fail(OREGANO_ENGINE_GET_CLASS(self)->progress_reader != NULL);
+ OREGANO_ENGINE_GET_CLASS (self)->progress_reader (self, p);
}
-void
-oregano_engine_get_progress (OreganoEngine *self, double *p)
+gboolean oregano_engine_generate_netlist (OreganoEngine *self, const gchar *file, GError **error)
{
- OREGANO_ENGINE_GET_CLASS (self)->progress (self, p);
+ return OREGANO_ENGINE_GET_CLASS (self)->get_netlist (self, file, error);
}
-void
-oregano_engine_generate_netlist (OreganoEngine *self, const gchar *file, GError **error)
+GList *oregano_engine_get_results (OreganoEngine *self)
{
- OREGANO_ENGINE_GET_CLASS (self)->get_netlist (self, file, error);
+ return OREGANO_ENGINE_GET_CLASS (self)->get_results (self);
}
-GList*
-oregano_engine_get_results (OreganoEngine *self)
+gchar *oregano_engine_get_current_operation_solver (OreganoEngine *self)
{
- return OREGANO_ENGINE_GET_CLASS (self)->get_results (self);
+ g_return_val_if_fail(OREGANO_ENGINE_GET_CLASS (self)->get_operation_solver != NULL, NULL);
+ return OREGANO_ENGINE_GET_CLASS (self)->get_operation_solver (self);
}
-gchar*
-oregano_engine_get_current_operation (OreganoEngine *self)
+gchar *oregano_engine_get_current_operation_reader (OreganoEngine *self)
{
- return OREGANO_ENGINE_GET_CLASS (self)->get_operation (self);
+ g_return_val_if_fail(OREGANO_ENGINE_GET_CLASS (self)->get_operation_reader != NULL, NULL);
+ return OREGANO_ENGINE_GET_CLASS (self)->get_operation_reader (self);
}
-OreganoEngine*
-oregano_engine_factory_create_engine (gint type, Schematic *sm)
+
+OreganoEngine *oregano_engine_factory_create_engine (gint type, Schematic *sm)
{
OreganoEngine *engine;
switch (type) {
- case OREGANO_ENGINE_GNUCAP:
- engine = oregano_gnucap_new (sm);
+ case OREGANO_ENGINE_GNUCAP:
+ engine = oregano_gnucap_new (sm);
break;
- case OREGANO_ENGINE_NGSPICE:
- engine = oregano_ngspice_new (sm);
+ case OREGANO_ENGINE_SPICE3:
+ engine = oregano_spice_new (sm, TRUE);
break;
- default:
- engine = NULL;
+ case OREGANO_ENGINE_NGSPICE:
+ engine = oregano_spice_new (sm, FALSE);
+ break;
+ default:
+ engine = NULL;
}
return engine;
}
-gchar *
-oregano_engine_get_analysis_name (SimulationData *sdat)
+gchar *oregano_engine_get_analysis_name_by_type(AnalysisType type) {
+ return g_strdup(_(analysis_names[type]));
+}
+
+gchar *oregano_engine_get_engine_name_by_index (const guint index) {
+ return g_strdup (_(engine_names[index]));
+}
+
+/**
+ * @sdat: nullable
+ */
+gchar *oregano_engine_get_analysis_name (SimulationData *sdat)
{
if (sdat == NULL) {
- return g_strdup (_(analysis_names[ANALYSIS_UNKNOWN]));
+ return g_strdup (_ (analysis_names[ANALYSIS_TYPE_UNKNOWN]));
}
- return g_strdup (_(analysis_names[sdat->type]));
+ return g_strdup (_ (analysis_names[sdat->type]));
}
diff --git a/src/engines/engine.h b/src/engines/engine.h
index a7175cc..de6ef2e 100644
--- a/src/engines/engine.h
+++ b/src/engines/engine.h
@@ -5,7 +5,7 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __ENGINE_H
@@ -35,31 +35,29 @@
#include "schematic.h"
#include "simulation.h"
-
-#define OREGANO_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OREGANO_TYPE_ENGINE, OreganoEngine))
-#define OREGANO_IS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), OREGANO_TYPE_ENGINE))
+#define OREGANO_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_ENGINE, OreganoEngine))
+#define OREGANO_IS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_ENGINE))
typedef struct _OreganoEngine OreganoEngine;
-// Engines IDs
-enum {
- OREGANO_ENGINE_GNUCAP=0,
- OREGANO_ENGINE_NGSPICE,
- OREGANO_ENGINE_COUNT
-};
+// Engines IDs
+enum { OREGANO_ENGINE_GNUCAP = 0, OREGANO_ENGINE_SPICE3, OREGANO_ENGINE_NGSPICE, OREGANO_ENGINE_COUNT };
OreganoEngine *oregano_engine_factory_create_engine (gint type, Schematic *sm);
-GType oregano_engine_get_type (void);
-void oregano_engine_start (OreganoEngine *engine);
-void oregano_engine_stop (OreganoEngine *engine);
+GType oregano_engine_get_type (void);
+void oregano_engine_start (OreganoEngine *engine);
+void oregano_engine_stop (OreganoEngine *engine);
gboolean oregano_engine_has_warnings (OreganoEngine *engine);
-void oregano_engine_get_progress (OreganoEngine *engine, double *p);
-void oregano_engine_generate_netlist (OreganoEngine *engine,
- const gchar *file, GError **error);
-GList *oregano_engine_get_results (OreganoEngine *engine);
-gchar *oregano_engine_get_current_operation (OreganoEngine *);
+void oregano_engine_get_progress_solver (OreganoEngine *engine, double *p);
+void oregano_engine_get_progress_reader (OreganoEngine *engine, double *p);
+gboolean oregano_engine_generate_netlist (OreganoEngine *engine, const gchar *file, GError **error);
+GList *oregano_engine_get_results (OreganoEngine *engine);
+gchar *oregano_engine_get_current_operation_solver (OreganoEngine *);
+gchar *oregano_engine_get_current_operation_reader (OreganoEngine *);
gboolean oregano_engine_is_available (OreganoEngine *);
-gchar *oregano_engine_get_analysis_name (SimulationData *id);
+gchar *oregano_engine_get_analysis_name_by_type(AnalysisType type);
+gchar *oregano_engine_get_engine_name_by_index (const guint index);
+gchar *oregano_engine_get_analysis_name (SimulationData *id);
#endif
diff --git a/src/engines/gnucap.c b/src/engines/gnucap.c
index e6297d0..f712153 100644
--- a/src/engines/gnucap.c
+++ b/src/engines/gnucap.c
@@ -5,7 +5,7 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -42,14 +42,8 @@
// TODO Move analysis data and result to another file
#include "simulation.h"
-typedef enum {
- STATE_IDLE,
- IN_VARIABLES,
- IN_VALUES,
- STATE_ABORT
-} ParseDataState;
-
-struct analysis_tag {
+struct analysis_tag
+{
gchar *name;
guint len;
};
@@ -61,12 +55,13 @@ static struct analysis_tag analysis_tags[] = {
{"#Freq", 5}, /* AC */
};
-#define IS_THIS_ITEM(str,item) (!strncmp(str,item.name,item.len))
+#define IS_THIS_ITEM(str, item) (!strncmp (str, item.name, item.len))
#define GNUCAP_TITLE '#'
-#define TAGS_COUNT (sizeof (analysis_tags) / sizeof (struct analysis_tag))
+#define TAGS_COUNT (sizeof(analysis_tags) / sizeof(struct analysis_tag))
// Parser STATUS
-struct _OreganoGnuCapPriv {
+struct _OreganoGnuCapPriv
+{
GPid child_pid;
gint child_stdout;
GIOChannel *child_iochannel;
@@ -84,41 +79,39 @@ struct _OreganoGnuCapPriv {
guint buf_count;
};
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
static void gnucap_class_init (OreganoGnuCapClass *klass);
static void gnucap_finalize (GObject *object);
static void gnucap_dispose (GObject *object);
static void gnucap_instance_init (GTypeInstance *instance, gpointer g_class);
static void gnucap_interface_init (gpointer g_iface, gpointer iface_data);
-static gboolean gnucap_child_stdout_cb (GIOChannel *source, GIOCondition condition, OreganoGnuCap *gnucap);
+static gboolean gnucap_child_stdout_cb (GIOChannel *source, GIOCondition condition,
+ OreganoGnuCap *gnucap);
static void gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap);
static gdouble strtofloat (char *s);
static GObjectClass *parent_class = NULL;
-GType
-oregano_gnucap_get_type (void)
+GType oregano_gnucap_get_type (void)
{
static GType type = 0;
if (type == 0) {
- static const GTypeInfo info = {
- sizeof (OreganoGnuCapClass),
- NULL, // base_init
- NULL, // base_finalize
- (GClassInitFunc) gnucap_class_init, // class_init
- NULL, // class_finalize
- NULL, // class_data
- sizeof (OreganoGnuCap),
- 0, // n_preallocs
- (GInstanceInitFunc) gnucap_instance_init, // instance_init
- NULL
- };
+ static const GTypeInfo info = {sizeof(OreganoGnuCapClass),
+ NULL, // base_init
+ NULL, // base_finalize
+ (GClassInitFunc)gnucap_class_init, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+ sizeof(OreganoGnuCap),
+ 0, // n_preallocs
+ (GInstanceInitFunc)gnucap_instance_init, // instance_init
+ NULL};
static const GInterfaceInfo gnucap_info = {
- (GInterfaceInitFunc) gnucap_interface_init, // interface_init
- NULL, // interface_finalize
- NULL // interface_data
+ (GInterfaceInitFunc)gnucap_interface_init, // interface_init
+ NULL, // interface_finalize
+ NULL // interface_data
};
type = g_type_register_static (G_TYPE_OBJECT, "OreganoGnuCap", &info, 0);
@@ -127,8 +120,7 @@ oregano_gnucap_get_type (void)
return type;
}
-static void
-gnucap_class_init (OreganoGnuCapClass *klass)
+static void gnucap_class_init (OreganoGnuCapClass *klass)
{
GObjectClass *object_class;
@@ -140,72 +132,60 @@ gnucap_class_init (OreganoGnuCapClass *klass)
object_class->finalize = gnucap_finalize;
}
-static void
-gnucap_finalize (GObject *object)
+static void gnucap_finalize (GObject *object)
{
SimulationData *data;
OreganoGnuCap *gnucap;
- GList *list;
+ GList *iter;
int i;
gnucap = OREGANO_GNUCAP (object);
- list = gnucap->priv->analysis;
- while (list) {
- data = SIM_DATA (list->data);
- for (i=0; i<data->n_variables; i++) {
+ iter = gnucap->priv->analysis;
+ for (; iter; iter = iter->next) {
+ data = SIM_DATA (iter->data);
+ for (i = 0; i < data->n_variables; i++) {
g_free (data->var_names[i]);
g_free (data->var_units[i]);
}
g_free (data->var_names);
g_free (data->var_units);
- for (i=0; i<data->n_variables; i++)
+ for (i = 0; i < data->n_variables; i++)
g_array_free (data->data[i], TRUE);
g_free (data->min_data);
g_free (data->max_data);
- g_free (list->data);
- list = list->next;
+ g_free (iter->data);
}
g_list_free (gnucap->priv->analysis);
gnucap->priv->analysis = NULL;
- g_list_free_full (list, g_object_unref);
parent_class->finalize (object);
}
-static void
-gnucap_dispose (GObject *object)
-{
- parent_class->dispose (object);
-}
+static void gnucap_dispose (GObject *object) { parent_class->dispose (object); }
-static gboolean
-gnucap_has_warnings (OreganoEngine *self)
-{
- return FALSE;
-}
+static gboolean gnucap_has_warnings (OreganoEngine *self) { return FALSE; }
-static gboolean
-gnucap_is_available (OreganoEngine *self)
+static gboolean gnucap_is_available (OreganoEngine *self)
{
gchar *exe;
exe = g_find_program_in_path ("gnucap");
- if (!exe) return FALSE; // gnucap not found
+ if (!exe)
+ return FALSE; // gnucap not found
g_free (exe);
return TRUE;
}
-static void
-gnucap_generate_netlist (OreganoEngine *engine, const gchar *filename,
- GError **error)
+static gboolean gnucap_generate_netlist (OreganoEngine *engine, const gchar *filename,
+ GError **error)
{
OreganoGnuCap *gnucap;
Netlist output;
SimOption *so;
- GList *list;
+ GList *iter;
FILE *file;
GError *local_error = NULL;
@@ -214,53 +194,50 @@ gnucap_generate_netlist (OreganoEngine *engine, const gchar *filename,
netlist_helper_create (gnucap->priv->schematic, &output, &local_error);
if (local_error != NULL) {
g_propagate_error (error, local_error);
- return;
+ return FALSE;
}
file = fopen (filename, "w");
if (!file) {
- oregano_error (g_strdup_printf ("Creation of %s not possible\n", filename));
- return;
+ oregano_error (g_strdup_printf ("Creation of file %s not possible\n", filename));
+ return FALSE;
}
- list = sim_settings_get_options (output.settings);
-
// Prints title
fputs (output.title ? output.title : "Title: <unset>", file);
fputs ("\n"
- "*----------------------------------------------"
- "\n"
- "*\tGNUCAP - NETLIST"
- "\n", file);
+ "*----------------------------------------------"
+ "\n"
+ "*\tGNUCAP - NETLIST"
+ "\n",
+ file);
// Prints Options
- fputs (".options OUT=120 ",file);
+ fputs (".options OUT=120 ", file);
- while (list) {
- so = list->data;
+ iter = sim_settings_get_options (output.settings);
+ for (; iter; iter = iter->next) {
+ so = iter->data;
// Prevent send NULL text
if (so->value) {
- if (strlen(so->value) > 0) {
- g_fprintf (file,"%s=%s ",so->name,so->value);
+ if (strlen (so->value) > 0) {
+ g_fprintf (file, "%s=%s ", so->name, so->value);
}
}
- list = list->next;
}
- fputc ('\n',file);
+ fputc ('\n', file);
// Include of subckt models
- fputs ("*------------- Models -------------------------\n",file);
- list = output.models;
- while (list) {
+ fputs ("*------------- Models -------------------------\n", file);
+ for (iter = output.models; iter; iter = iter->next) {
gchar *model;
- model = (gchar *)list->data;
- g_fprintf (file,".include %s/%s.model\n", OREGANO_MODELDIR, model);
- list = list->next;
+ model = (gchar *)iter->data;
+ g_fprintf (file, ".include %s/%s.model\n", OREGANO_MODELDIR, model);
}
- // Prints template parts
- fputs ("*------------- Circuit Description-------------\n",file);
+ // Prints template parts
+ fputs ("*------------- Circuit Description-------------\n", file);
fputs (output.template->str, file);
- fputs ("\n*----------------------------------------------\n",file);
+ fputs ("\n*----------------------------------------------\n", file);
// Prints Transient Analysis
if (sim_settings_get_trans (output.settings)) {
@@ -268,71 +245,70 @@ gnucap_generate_netlist (OreganoEngine *engine, const gchar *filename,
g_fprintf (file, ".print tran %s\n", tmp_str);
g_free (tmp_str);
- g_fprintf (file, ".tran %g %g ",
- sim_settings_get_trans_start (output.settings),
- sim_settings_get_trans_stop (output.settings));
+ g_fprintf (file, ".tran %g %g ", sim_settings_get_trans_start (output.settings),
+ sim_settings_get_trans_stop (output.settings));
if (!sim_settings_get_trans_step_enable (output.settings))
- g_fprintf (file,"%g",
- (sim_settings_get_trans_stop (output.settings)-
- sim_settings_get_trans_start (output.settings))/100);
+ g_fprintf (file, "%g", (sim_settings_get_trans_stop (output.settings) -
+ sim_settings_get_trans_start (output.settings)) /
+ 100);
else
- g_fprintf (file,"%g", sim_settings_get_trans_step (output.settings));
+ g_fprintf (file, "%g", sim_settings_get_trans_step (output.settings));
if (sim_settings_get_trans_init_cond (output.settings)) {
- fputs(" UIC\n", file);
- }
- else {
- fputs("\n", file);
+ fputs (" UIC\n", file);
+ } else {
+ fputs ("\n", file);
}
}
- // Print DC Analysis
+ // Print DC Analysis
if (sim_settings_get_dc (output.settings)) {
- g_fprintf (file, ".print dc %s\n", netlist_helper_create_analysis_string (output.store, FALSE));
- fputs (".dc ",file);
+ g_fprintf (file, ".print dc %s\n",
+ netlist_helper_create_analysis_string (output.store, FALSE));
+ fputs (".dc ", file);
// GNUCAP don't support nesting so the first or the second
// Maybe an error message must be show if both are on
- g_fprintf (file, "%s %g %g %g",
- sim_settings_get_dc_vsrc(output.settings),
- sim_settings_get_dc_start (output.settings),
- sim_settings_get_dc_stop (output.settings),
- sim_settings_get_dc_step (output.settings));
- fputc ('\n',file);
+ g_fprintf (file, "%s %g %g %g", sim_settings_get_dc_vsrc (output.settings),
+ sim_settings_get_dc_start (output.settings),
+ sim_settings_get_dc_stop (output.settings),
+ sim_settings_get_dc_step (output.settings));
+ fputc ('\n', file);
}
// Prints AC Analysis
if (sim_settings_get_ac (output.settings)) {
double ac_start, ac_stop, ac_step;
// GNUCAP dont support OCT or DEC: Maybe an error message
- // must be shown if the netlist is set in that way.
- ac_start = sim_settings_get_ac_start (output.settings) ;
+ // must be shown if the netlist is set in that way.
+ ac_start = sim_settings_get_ac_start (output.settings);
ac_stop = sim_settings_get_ac_stop (output.settings);
ac_step = (ac_stop - ac_start) / sim_settings_get_ac_npoints (output.settings);
- g_fprintf(file, ".print ac %s\n", netlist_helper_create_analysis_string (output.store, TRUE));
+ g_fprintf (file, ".print ac %s\n",
+ netlist_helper_create_analysis_string (output.store, TRUE));
// AC format : ac start stop step_size
g_fprintf (file, ".ac %g %g %g\n", ac_start, ac_stop, ac_step);
}
-
+
// Prints analysis using a Fourier transform
/* if (sim_settings_get_fourier (output.settings)) {
- gchar *tmp_str = netlist_helper_create_analysis_string (output.store, FALSE);
- g_fprintf (file, ".four %d %s\n",
- sim_settings_get_fourier_frequency (output.settings), tmp_str);
- g_free (tmp_str);
+ gchar *tmp_str = netlist_helper_create_analysis_string (output.store,
+ FALSE);
+ g_fprintf (file, ".four %d %s\n",
+ sim_settings_get_fourier_frequency (output.settings),
+ tmp_str);
+ g_free (tmp_str);
}*/
- g_list_free_full (list, g_object_unref);
-
// Debug op analysis.
fputs (".print op v(nodes)\n", file);
fputs (".op\n", file);
fputs (".end\n", file);
fclose (file);
+ return TRUE;
}
-static void
-gnucap_progress (OreganoEngine *self, double *d)
+static void gnucap_progress (OreganoEngine *self, double *d)
{
OreganoGnuCap *gnucap = OREGANO_GNUCAP (self);
@@ -340,8 +316,7 @@ gnucap_progress (OreganoEngine *self, double *d)
(*d) = gnucap->priv->progress;
}
-static void
-gnucap_stop (OreganoEngine *self)
+static void gnucap_stop (OreganoEngine *self)
{
OreganoGnuCap *gnucap = OREGANO_GNUCAP (self);
g_io_channel_shutdown (gnucap->priv->child_iochannel, TRUE, NULL);
@@ -350,8 +325,7 @@ gnucap_stop (OreganoEngine *self)
g_spawn_close_pid (gnucap->priv->child_stdout);
}
-static void
-gnucap_watch_cb (GPid pid, gint status, OreganoGnuCap *gnucap)
+static void gnucap_watch_cb (GPid pid, gint status, OreganoGnuCap *gnucap)
{
// check for status, see man waitpid(2)
if (WIFEXITED (status)) {
@@ -371,18 +345,17 @@ gnucap_watch_cb (GPid pid, gint status, OreganoGnuCap *gnucap)
gnucap->priv->current = NULL;
if (gnucap->priv->num_analysis == 0) {
- schematic_log_append_error (gnucap->priv->schematic,
- _("### Too few or none analysis found ###\n"));
+ schematic_log_append_error (gnucap->priv->schematic,
+ _ ("### Too few or none analysis found ###\n"));
gnucap->priv->aborted = TRUE;
g_signal_emit_by_name (G_OBJECT (gnucap), "aborted");
- }
- else
+ } else
g_signal_emit_by_name (G_OBJECT (gnucap), "done");
}
}
-static gboolean
-gnucap_child_stdout_cb (GIOChannel *source, GIOCondition condition, OreganoGnuCap *gnucap)
+static gboolean gnucap_child_stdout_cb (GIOChannel *source, GIOCondition condition,
+ OreganoGnuCap *gnucap)
{
gchar *line;
gsize len, terminator;
@@ -400,8 +373,7 @@ gnucap_child_stdout_cb (GIOChannel *source, GIOCondition condition, OreganoGnuCa
return TRUE;
}
-static void
-gnucap_start (OreganoEngine *self)
+static void gnucap_start (OreganoEngine *self)
{
OreganoGnuCap *gnucap;
GError *error = NULL;
@@ -418,67 +390,57 @@ gnucap_start (OreganoEngine *self)
}
error = NULL;
- if (g_spawn_async_with_pipes (
- NULL, // Working directory
- argv,
- NULL,
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL,
- NULL,
- &gnucap->priv->child_pid,
- NULL, // STDIN
- &gnucap->priv->child_stdout, // STDOUT
- NULL, // STDERR
- &error
- )) {
+ if (g_spawn_async_with_pipes (NULL, // Working directory
+ argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL,
+ NULL, &gnucap->priv->child_pid,
+ NULL, // STDIN
+ &gnucap->priv->child_stdout, // STDOUT
+ NULL, // STDERR
+ &error)) {
// Add a watch for process status
g_child_watch_add (gnucap->priv->child_pid, (GChildWatchFunc)gnucap_watch_cb, gnucap);
// Add a GIOChannel to read from process stdout
gnucap->priv->child_iochannel = g_io_channel_unix_new (gnucap->priv->child_stdout);
// Watch the I/O Channel to read child strout
- gnucap->priv->child_iochannel_watch = g_io_add_watch (gnucap->priv->child_iochannel,
- G_IO_IN|G_IO_PRI|G_IO_HUP|G_IO_NVAL, (GIOFunc)gnucap_child_stdout_cb, gnucap);
- }
- else {
+ gnucap->priv->child_iochannel_watch = g_io_add_watch (
+ gnucap->priv->child_iochannel, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc)gnucap_child_stdout_cb, gnucap);
+ } else {
gnucap->priv->aborted = TRUE;
- schematic_log_append_error (gnucap->priv->schematic, _("Unable to execute GnuCap."));
+ schematic_log_append_error (gnucap->priv->schematic, _ ("Unable to execute GnuCap."));
g_signal_emit_by_name (G_OBJECT (gnucap), "aborted");
}
}
-static GList*
-gnucap_get_results (OreganoEngine *self)
+static GList *gnucap_get_results (OreganoEngine *self)
{
return OREGANO_GNUCAP (self)->priv->analysis;
}
-static gchar *
-gnucap_get_operation (OreganoEngine *self)
+static gchar *gnucap_get_operation (OreganoEngine *self)
{
OreganoGnuCapPriv *priv = OREGANO_GNUCAP (self)->priv;
if (priv->current == NULL)
- return _("None");
+ return g_strdup(_("None"));
return oregano_engine_get_analysis_name (priv->current);
}
-static void
-gnucap_interface_init (gpointer g_iface, gpointer iface_data)
+static void gnucap_interface_init (gpointer g_iface, gpointer iface_data)
{
OreganoEngineClass *klass = (OreganoEngineClass *)g_iface;
klass->start = gnucap_start;
klass->stop = gnucap_stop;
- klass->progress = gnucap_progress;
+ klass->progress_solver = gnucap_progress;
klass->get_netlist = gnucap_generate_netlist;
klass->has_warnings = gnucap_has_warnings;
klass->get_results = gnucap_get_results;
- klass->get_operation = gnucap_get_operation;
+ klass->get_operation_solver = gnucap_get_operation;
klass->is_available = gnucap_is_available;
}
-static void
-gnucap_instance_init (GTypeInstance *instance, gpointer g_class)
+static void gnucap_instance_init (GTypeInstance *instance, gpointer g_class)
{
OreganoGnuCap *self = OREGANO_GNUCAP (instance);
@@ -493,8 +455,7 @@ gnucap_instance_init (GTypeInstance *instance, gpointer g_class)
self->priv->aborted = FALSE;
}
-OreganoEngine*
-oregano_gnucap_new (Schematic *sc)
+OreganoEngine *oregano_gnucap_new (Schematic *sc)
{
OreganoGnuCap *gnucap;
@@ -504,12 +465,12 @@ oregano_gnucap_new (Schematic *sc)
return OREGANO_ENGINE (gnucap);
}
-typedef struct {
+typedef struct
+{
gchar *name;
} GCap_Variable;
-static GCap_Variable *
-_get_variables (gchar *str, gint *count)
+static GCap_Variable *_get_variables (gchar *str, gint *count)
{
GCap_Variable *out;
gchar *tmp[100];
@@ -519,7 +480,8 @@ _get_variables (gchar *str, gint *count)
i = 0;
ini = str;
// Put blank in advance
- while (isspace (*ini)) ini++;
+ while (isspace (*ini))
+ ini++;
fin = ini;
while (*fin != '\0') {
if (isspace (*fin)) {
@@ -528,10 +490,11 @@ _get_variables (gchar *str, gint *count)
*fin = ' ';
i++;
ini = fin;
- while (isspace (*ini)) ini++;
+ while (isspace (*ini))
+ ini++;
fin = ini;
- }
- else fin++;
+ } else
+ fin++;
}
if (i == 0) {
@@ -541,23 +504,22 @@ _get_variables (gchar *str, gint *count)
out = g_new0 (GCap_Variable, i);
(*count) = i;
- for ( i=0; i< (*count); i++ ) {
+ for (i = 0; i < (*count); i++) {
out[i].name = tmp[i];
}
return out;
}
-static void
-_free_variables (GCap_Variable *v, gint count)
+static void _free_variables (GCap_Variable *v, gint count)
{
int i;
- for (i=0; i<count; i++)
+ for (i = 0; i < count; i++)
g_free (v[i].name);
g_free (v);
}
-gdouble
-strtofloat (gchar *s) {
+gdouble strtofloat (gchar *s)
+{
gdouble val;
gchar *error;
@@ -565,25 +527,26 @@ strtofloat (gchar *s) {
// If the value looks like : 100.u, adjust it
// We need this because GNU Cap's or ngSpice float notation
switch (error[0]) {
- case 'u':
- val /= 1000000;
+ case 'u':
+ val /= 1000000;
break;
- case 'n':
- val /= 1000000;
- val /= 1000;
+ case 'n':
+ val /= 1000000;
+ val /= 1000;
break;
- case 'p':
- val /= 1000000;
- val /= 1000000;
+ case 'p':
+ val /= 1000000;
+ val /= 1000000;
break;
- case 'f':
- val /= 100;
+ case 'f':
+ val /= 100;
break;
- case 'K':
- val *= 1000;
+ case 'K':
+ val *= 1000;
break;
- default:
- if (strcmp (error, "Meg") == 0) val *= 1000000;
+ default:
+ if (strcmp (error, "Meg") == 0)
+ val *= 1000000;
}
return val;
@@ -591,8 +554,7 @@ strtofloat (gchar *s) {
// Main method. Here we'll transform GnuCap output
// into SimulationResults!
-static void
-gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap)
+static void gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap)
{
static SimulationData *sdata;
static Analysis *data;
@@ -603,28 +565,27 @@ gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap)
gdouble val;
gchar *s;
- for (j=0; j < len; j++) {
+ for (j = 0; j < len; j++) {
if (raw[j] != '\n') {
buf[priv->buf_count++] = raw[j];
continue;
}
buf[priv->buf_count] = '\0';
- //Got a complete line
+ // Got a complete line
s = buf;
- NG_DEBUG (g_strdup_printf ("%s", s));
+ NG_DEBUG ("%s", s);
if (s[0] == GNUCAP_TITLE) {
SimSettings *sim_settings;
gdouble np1;
- sim_settings = (SimSettings *)schematic_get_sim_settings (priv->schematic);
+ sim_settings = schematic_get_sim_settings (priv->schematic);
data = g_new0 (Analysis, 1);
priv->current = sdata = SIM_DATA (data);
priv->analysis = g_list_append (priv->analysis, sdata);
priv->num_analysis++;
- sdata->state = STATE_IDLE;
- sdata->type = ANALYSIS_UNKNOWN;
+ sdata->type = ANALYSIS_TYPE_UNKNOWN;
sdata->functions = NULL;
// Calculates the quantity of variables
@@ -632,92 +593,90 @@ gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap)
for (i = 0; i < TAGS_COUNT; i++)
if (IS_THIS_ITEM (variables[0].name, analysis_tags[i]))
- sdata->type = i;
+ sdata->type = i + 1;
- sdata->state = IN_VALUES;
sdata->n_variables = n;
- sdata->got_points = 0;
- sdata->got_var = 0;
- sdata->var_names = (char**) g_new0 (gpointer, n);
- sdata->var_units = (char**) g_new0 (gpointer, n);
- sdata->data = (GArray**) g_new0 (gpointer, n);
+ sdata->got_points = 0;
+ sdata->got_var = 0;
+ sdata->var_names = (char **)g_new0 (gpointer, n);
+ sdata->var_units = (char **)g_new0 (gpointer, n);
+ sdata->data = (GArray **)g_new0 (gpointer, n);
for (i = 0; i < n; i++)
- sdata->data[i] = g_array_new (TRUE, TRUE, sizeof (double));
+ sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
sdata->min_data = g_new (double, n);
sdata->max_data = g_new (double, n);
for (i = 0; i < n; i++) {
- sdata->min_data[i] = G_MAXDOUBLE;
+ sdata->min_data[i] = G_MAXDOUBLE;
sdata->max_data[i] = -G_MAXDOUBLE;
}
for (i = 0; i < n; i++) {
sdata->var_names[i] = g_strdup (variables[i].name);
switch (sdata->type) {
- case TRANSIENT:
- if (i==0)
- sdata->var_units[i] = g_strdup (_("time"));
- else {
- if (strstr (sdata->var_names[i], "db") != NULL) {
- sdata->var_units[i] = g_strdup ("db");
- }
- else
- sdata->var_units[i] = g_strdup (_("voltage"));
- }
+ case ANALYSIS_TYPE_TRANSIENT:
+ if (i == 0)
+ sdata->var_units[i] = g_strdup (_ ("time"));
+ else {
+ if (strstr (sdata->var_names[i], "db") != NULL) {
+ sdata->var_units[i] = g_strdup ("db");
+ } else
+ sdata->var_units[i] = g_strdup (_ ("voltage"));
+ }
break;
- case AC:
- if (i == 0)
- sdata->var_units[i] = g_strdup (_("frequency"));
- else {
- if (strstr (sdata->var_names[i], "db") != NULL) {
- sdata->var_units[i] = g_strdup ("db");
- }
- else
- sdata->var_units[i] = g_strdup (_("voltage"));
- }
+ case ANALYSIS_TYPE_AC:
+ if (i == 0)
+ sdata->var_units[i] = g_strdup (_ ("frequency"));
+ else {
+ if (strstr (sdata->var_names[i], "db") != NULL) {
+ sdata->var_units[i] = g_strdup ("db");
+ } else
+ sdata->var_units[i] = g_strdup (_ ("voltage"));
+ }
break;
- default:
- sdata->var_units[i] = g_strdup ("");
+ default:
+ sdata->var_units[i] = g_strdup ("");
}
}
sdata->n_variables = n;
switch (sdata->type) {
- case TRANSIENT:
- data->transient.sim_length =
- sim_settings_get_trans_stop (sim_settings) -
- sim_settings_get_trans_start (sim_settings);
- data->transient.step_size =
- sim_settings_get_trans_step (sim_settings);
- break;
- case AC:
- data->ac.start = sim_settings_get_ac_start (sim_settings);
- data->ac.stop = sim_settings_get_ac_stop (sim_settings);
- data->ac.sim_length = sim_settings_get_ac_npoints (sim_settings);
- break;
- case OP_POINT:
- case DC_TRANSFER:
- np1 = 1.;
- data->dc.start = sim_settings_get_dc_start (sim_settings);
- data->dc.stop = sim_settings_get_dc_stop (sim_settings);
- data->dc.step = sim_settings_get_dc_step (sim_settings);
- np1 = (data->dc.stop - data->dc.start) / data->dc.step;
-
- data->dc.sim_length = np1;
- break;
- case TRANSFER:
- case DISTORTION:
- case NOISE:
- case POLE_ZERO:
- case SENSITIVITY:
- case FOURIER:
- break;
- case ANALYSIS_UNKNOWN:
- g_error (_("Unknown analysis"));
- break;
+ case ANALYSIS_TYPE_TRANSIENT:
+ data->transient.sim_length = sim_settings_get_trans_stop (sim_settings) -
+ sim_settings_get_trans_start (sim_settings);
+ data->transient.step_size = sim_settings_get_trans_step (sim_settings);
+ break;
+ case ANALYSIS_TYPE_AC:
+ data->ac.start = sim_settings_get_ac_start (sim_settings);
+ data->ac.stop = sim_settings_get_ac_stop (sim_settings);
+ data->ac.sim_length = sim_settings_get_ac_npoints (sim_settings);
+ break;
+ case ANALYSIS_TYPE_OP_POINT:
+ break;
+ case ANALYSIS_TYPE_DC_TRANSFER:
+ np1 = 1.;
+ data->dc.start = sim_settings_get_dc_start (sim_settings);
+ data->dc.stop = sim_settings_get_dc_stop (sim_settings);
+ data->dc.step = sim_settings_get_dc_step (sim_settings);
+ np1 = (data->dc.stop - data->dc.start) / data->dc.step;
+
+ data->dc.sim_length = np1;
+ break;
+ case ANALYSIS_TYPE_TRANSFER:
+ case ANALYSIS_TYPE_DISTORTION:
+ case ANALYSIS_TYPE_NOISE:
+ case ANALYSIS_TYPE_POLE_ZERO:
+ case ANALYSIS_TYPE_SENSITIVITY:
+ case ANALYSIS_TYPE_FOURIER:
+ break;
+ case ANALYSIS_TYPE_NONE:
+ g_error (_ ("No analysis"));
+ break;
+ case ANALYSIS_TYPE_UNKNOWN:
+ g_error (_ ("Unknown analysis"));
+ break;
}
- }
- else {
+ } else {
if ((priv->analysis == NULL) || (isalpha (s[0]))) {
if (priv->buf_count > 1) {
schematic_log_append (priv->schematic, s);
@@ -727,49 +686,39 @@ gnucap_parse (gchar *raw, gint len, OreganoGnuCap *gnucap)
continue;
}
- switch (sdata->state) {
- case IN_VALUES:
- val = strtofloat (s);
- switch (sdata->type) {
- case TRANSIENT:
- priv->progress = val / data->transient.sim_length;
- break;
- case AC:
- priv->progress = (val - data->ac.start) / data->ac.sim_length;
- break;
- case DC_TRANSFER:
- priv->progress = val / data->ac.sim_length;
- default:
- break;
- }
- if (priv->progress > 1.0)
- priv->progress = 1.0;
-
- variables = _get_variables (s, &n);
- for (i = 0; i < n; i++) {
- val = strtofloat (variables[i].name);
- sdata->data[i] = g_array_append_val (sdata->data[i], val);
-
- // Update the minimal and maximal values so far.
- if (val < sdata->min_data[i])
- sdata->min_data[i] = val;
- if (val > sdata->max_data[i])
- sdata->max_data[i] = val;
- }
+ val = strtofloat (s);
+ switch (sdata->type) {
+ case ANALYSIS_TYPE_TRANSIENT:
+ priv->progress = val / data->transient.sim_length;
+ break;
+ case ANALYSIS_TYPE_AC:
+ priv->progress = (val - data->ac.start) / data->ac.sim_length;
+ break;
+ case ANALYSIS_TYPE_DC_TRANSFER:
+ priv->progress = val / data->ac.sim_length;
+ break;
+ default:
+ break;
+ }
+ if (priv->progress > 1.0)
+ priv->progress = 1.0;
- _free_variables (variables, n);
- sdata->got_points++;
- sdata->got_var = n;
- break;
- default:
- if (priv->buf_count > 1) {
- if (strstr (s, _("abort")))
- sdata->state = STATE_ABORT;
- schematic_log_append_error (priv->schematic, s);
- }
+ variables = _get_variables (s, &n);
+ for (i = 0; i < n; i++) {
+ val = strtofloat (variables[i].name);
+ sdata->data[i] = g_array_append_val (sdata->data[i], val);
+
+ // Update the minimum and maximum values so far.
+ if (val < sdata->min_data[i])
+ sdata->min_data[i] = val;
+ if (val > sdata->max_data[i])
+ sdata->max_data[i] = val;
}
+
+ _free_variables (variables, n);
+ sdata->got_points++;
+ sdata->got_var = n;
}
priv->buf_count = 0;
}
}
-
diff --git a/src/engines/gnucap.h b/src/engines/gnucap.h
index e5f9709..bdd0483 100644
--- a/src/engines/gnucap.h
+++ b/src/engines/gnucap.h
@@ -5,7 +5,7 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __GNUCAP_ENGINE
@@ -34,28 +34,32 @@
#include "engine.h"
-#define OREGANO_TYPE_GNUCAP (oregano_gnucap_get_type ())
-#define OREGANO_GNUCAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_GNUCAP, OreganoGnuCap))
-#define OREGANO_GNUCAP_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), OREGANO_TYPE_GNUCAP, OreganoGnuCapClass))
-#define OREGANO_IS_GNUCAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_GNUCAP))
+#define OREGANO_TYPE_GNUCAP (oregano_gnucap_get_type ())
+#define OREGANO_GNUCAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_GNUCAP, OreganoGnuCap))
+#define OREGANO_GNUCAP_CLASS(vtable) \
+ (G_TYPE_CHECK_CLASS_CAST ((vtable), OREGANO_TYPE_GNUCAP, OreganoGnuCapClass))
+#define OREGANO_IS_GNUCAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_GNUCAP))
#define OREGANO_IS_GNUCAP_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), OREGANO_TYPE_GNUCAP))
-#define OREGANO_GNUCAP_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), OREGANO_TYPE_GNUCAP, OreganoGnuCapClass))
+#define OREGANO_GNUCAP_GET_CLASS(inst) \
+ (G_TYPE_INSTANCE_GET_CLASS ((inst), OREGANO_TYPE_GNUCAP, OreganoGnuCapClass))
typedef struct _OreganoGnuCap OreganoGnuCap;
typedef struct _OreganoGnuCapPriv OreganoGnuCapPriv;
typedef struct _OreganoGnuCapClass OreganoGnuCapClass;
-struct _OreganoGnuCap {
+struct _OreganoGnuCap
+{
GObject parent;
OreganoGnuCapPriv *priv;
};
-struct _OreganoGnuCapClass {
+struct _OreganoGnuCapClass
+{
GObjectClass parent;
};
-GType oregano_gnucap_get_type (void);
+GType oregano_gnucap_get_type (void);
OreganoEngine *oregano_gnucap_new (Schematic *sm);
#endif
diff --git a/src/engines/netlist-helper.c b/src/engines/netlist-helper.c
index 478d333..851a605 100644
--- a/src/engines/netlist-helper.c
+++ b/src/engines/netlist-helper.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <Lorber.Marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
@@ -47,25 +51,23 @@
#include "errors.h"
#include "dialogs.h"
-#define NG_DEBUG(s) if (0) g_print ("NG: %s\n", s)
-
-static void netlist_helper_node_foreach_reset (gpointer key, gpointer value,
- gpointer user_data);
-static void netlist_helper_wire_traverse (Wire *wire, NetlistData *data);
-static void netlist_helper_node_traverse (Node *node, NetlistData *data);
-static void netlist_helper_node_foreach_traverse (gpointer key,
- gpointer value, NetlistData *data);
-static gboolean netlist_helper_foreach_model_free (gpointer key, gpointer model,
- gpointer user_data);
-static gboolean netlist_helper_foreach_model_save (gpointer key, gpointer model,
- gpointer user_data);
-static char * netlist_helper_linebreak (char *str);
-static void netlist_helper_nl_node_traverse (Node *node, GSList **lst);
-
-static void
-netlist_helper_nl_wire_traverse (Wire *wire, GSList **lst)
+#include "debug.h"
+
+static void netlist_helper_node_foreach_reset (gpointer key, gpointer value, gpointer user_data);
+static void netlist_helper_wire_traverse (Wire *wire, NetlistData *data);
+static void netlist_helper_node_traverse (Node *node, NetlistData *data);
+static void netlist_helper_node_foreach_traverse (gpointer key, gpointer value, NetlistData *data);
+static gboolean netlist_helper_foreach_model_free (gpointer key, gpointer model,
+ gpointer user_data);
+static gboolean netlist_helper_foreach_model_save (gpointer key, gpointer model,
+ gpointer user_data);
+static char *netlist_helper_linebreak (char *str);
+static void netlist_helper_nl_node_traverse (Node *node, GSList **lst);
+
+static void netlist_helper_nl_wire_traverse (Wire *wire, GSList **lst)
{
- GSList *nodes;
+ GSList *iter;
+ GSList *iter2;
g_return_if_fail (wire != NULL);
g_return_if_fail (IS_WIRE (wire));
@@ -75,26 +77,27 @@ netlist_helper_nl_wire_traverse (Wire *wire, GSList **lst)
wire_set_visited (wire, TRUE);
- for (nodes = wire_get_nodes (wire); nodes; nodes = nodes->next) {
- GSList *pins;
- Part *part;
- Node *node = nodes->data;
+ for (iter = wire_get_nodes (wire); iter; iter = iter->next) {
+ Node *node = iter->data;
+
+ for (iter2 = node->pins; iter2; iter2 = iter2->next) {
+ Pin *pin = iter2->data;
+ Part *part = PART (pin->part);
- for (pins=node->pins; pins; pins=pins->next) {
char *template, *tmp;
char **template_split;
- part = PART (((Pin *)pins->data)->part);
-
tmp = part_get_property (part, "template");
- if (!tmp) continue;
+ if (!tmp)
+ continue;
template = part_property_expand_macros (part, tmp);
template_split = g_strsplit (template, " ", 0);
- (*lst) = g_slist_prepend (*lst, g_strdup (template_split[0]));
+ if (template_split[0] != NULL)
+ (*lst) = g_slist_prepend (*lst, g_strdup (template_split[0]));
g_strfreev (template_split);
g_free (tmp);
@@ -103,13 +106,11 @@ netlist_helper_nl_wire_traverse (Wire *wire, GSList **lst)
netlist_helper_nl_node_traverse (node, lst);
}
- g_slist_free_full (nodes, g_object_unref);
}
-static void
-netlist_helper_nl_node_traverse (Node *node, GSList **lst)
+static void netlist_helper_nl_node_traverse (Node *node, GSList **lst)
{
- GSList *wires;
+ GSList *iter;
g_return_if_fail (node != NULL);
g_return_if_fail (IS_NODE (node));
@@ -119,44 +120,46 @@ netlist_helper_nl_node_traverse (Node *node, GSList **lst)
node_set_visited (node, TRUE);
- for (wires = node->wires; wires; wires = wires->next) {
- Wire *wire = wires->data;
+ for (iter = node->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
netlist_helper_nl_wire_traverse (wire, lst);
}
- g_slist_free_full (wires, g_object_unref);
}
-static GSList *
-netlist_helper_get_clamp_parts (NodeStore *store, Node *node)
+/**
+ * traverses the netlist and picks up all clamp type parts
+ *
+ * TODO this is part of the "logic" that determines which "nodes" (or V levels)
+ * TODO will be plotted (or: not discarded)
+ *
+ * @returns a list of parts whose type is clamp
+ */
+static GSList *netlist_helper_get_clamp_parts (NodeStore *store, Node *node)
{
- GList *wires;
- GSList *list;
+ GList *iter;
+ GSList *iter2;
Wire *wire;
GSList *ret = NULL;
- if (!node) return NULL;
+ if (!node)
+ return NULL;
+
+ node_store_node_foreach (store, (GHFunc *)netlist_helper_node_foreach_reset, NULL);
- node_store_node_foreach (store, (GHFunc *) netlist_helper_node_foreach_reset,
- NULL);
- for (wires = store->wires; wires; wires = wires->next) {
- wire = wires->data;
+ for (iter = store->wires; iter; iter = iter->next) {
+ wire = iter->data;
wire_set_visited (wire, FALSE);
}
- list = node->wires;
- while (list) {
- netlist_helper_nl_wire_traverse (list->data, &ret);
- list = list->next;
+ for (iter2 = node->wires; iter2; iter2 = iter2->next) {
+ wire = iter2->data;
+ netlist_helper_nl_wire_traverse (wire, &ret);
}
- g_list_free_full (wires, g_object_unref);
- g_slist_free_full (list, g_object_unref);
-
return ret;
}
-void
-netlist_helper_init_data (NetlistData *data)
+void netlist_helper_init_data (NetlistData *data)
{
data->pins = g_hash_table_new (g_direct_hash, g_direct_equal);
data->models = g_hash_table_new (g_str_hash, g_str_equal);
@@ -167,18 +170,16 @@ netlist_helper_init_data (NetlistData *data)
data->node_and_number_list = NULL;
}
-void
-netlist_helper_node_foreach_reset (gpointer key, gpointer value, gpointer user_data)
+void netlist_helper_node_foreach_reset (gpointer key, gpointer value, gpointer user_data)
{
Node *node = value;
node_set_visited (node, FALSE);
}
-void
-netlist_helper_wire_traverse (Wire *wire, NetlistData *data)
+void netlist_helper_wire_traverse (Wire *wire, NetlistData *data)
{
- GSList *nodes;
+ GSList *iter;
g_return_if_fail (wire != NULL);
g_return_if_fail (IS_WIRE (wire));
@@ -188,23 +189,22 @@ netlist_helper_wire_traverse (Wire *wire, NetlistData *data)
wire_set_visited (wire, TRUE);
- for (nodes = wire_get_nodes (wire); nodes; nodes = nodes->next) {
- Node *node = nodes->data;
+ for (iter = wire_get_nodes (wire); iter; iter = iter->next) {
+ Node *node = iter->data;
netlist_helper_node_traverse (node, data);
}
- g_slist_free_full (nodes, g_object_unref);
}
-void
-netlist_helper_node_traverse (Node *node, NetlistData *data)
+void netlist_helper_node_traverse (Node *node, NetlistData *data)
{
- GSList *wires, *pins;
+ GSList *iter;
gchar *prop;
NodeAndNumber *nan;
g_return_if_fail (node != NULL);
g_return_if_fail (IS_NODE (node));
+ g_return_if_fail (data != NULL);
if (node_is_visited (node))
return;
@@ -215,12 +215,11 @@ netlist_helper_node_traverse (Node *node, NetlistData *data)
nan = g_new0 (NodeAndNumber, 1);
nan->node_nr = data->node_nr;
nan->node = node;
- data->node_and_number_list = g_list_prepend (data->node_and_number_list,
- nan);
+ data->node_and_number_list = g_list_prepend (data->node_and_number_list, nan);
// Traverse the pins at this node.
- for (pins = node->pins; pins; pins = pins->next) {
- Pin *pin = pins->data;
+ for (iter = node->pins; iter; iter = iter->next) {
+ Pin *pin = iter->data;
// First see if the pin belongs to an "internal", special part.
prop = part_get_property (pin->part, "internal");
@@ -246,79 +245,13 @@ netlist_helper_node_traverse (Node *node, NetlistData *data)
marker->node_nr = data->node_nr;
marker->name = value;
data->mark_list = g_slist_prepend (data->mark_list, marker);
- }
- else if (!g_ascii_strcasecmp (prop, "ground")) {
- data->gnd_list = g_slist_prepend (data->gnd_list, GINT_TO_POINTER (data->node_nr));
- }
- else if (!g_ascii_strcasecmp (prop, "point")) {
- data->clamp_list = g_slist_prepend (data->clamp_list, GINT_TO_POINTER (data->node_nr));
- }
- else if (!g_ascii_strncasecmp (prop, "jumper", 5)) {
- // Either jumper2 or jumper4.
- Node *opposite_node;
- Pin opposite_pin;
- gint pin_nr, opposite_pin_nr;
- SheetPos pos;
- Pin *jumper_pins;
- gint num_pins;
-
- opposite_pin_nr = -1;
- num_pins = part_get_num_pins (pin->part);
- jumper_pins = part_get_pins (pin->part);
- for (pin_nr = 0; pin_nr < num_pins; pin_nr++) {
- if (&jumper_pins[pin_nr] == pin) {
- opposite_pin_nr = pin_nr;
- break;
- }
- }
-
- switch (opposite_pin_nr) {
- case 0:
- opposite_pin_nr = 1;
- break;
- case 1:
- opposite_pin_nr = 0;
- break;
- case 2:
- opposite_pin_nr = 3;
- break;
- case 3:
- opposite_pin_nr = 2;
- break;
- default:
- g_assert (TRUE);
- break;
- }
-
- opposite_pin = jumper_pins[opposite_pin_nr];
-
- item_data_get_pos (ITEM_DATA (pin->part), &pos);
- pos.x += opposite_pin.offset.x;
- pos.y += opposite_pin.offset.y;
-
- opposite_node = node_store_get_node (data->store, pos);
-
-#if 0
- if (node_is_visited (opposite_node)) {
- GList *list;
- /* Set the node name on the current node to the same as the
- already visited node. */
- for (list = data->node_and_number_list; list; list = list->next) {
- NodeAndNumber *opposite_nan = list->data;
-
- if (opposite_nan->node == opposite_node)
- nan->node_nr = opposite_nan->node_nr;
- }
- g_list_free_full (list, g_object_unref);
- }
-#endif
- netlist_helper_node_traverse (opposite_node, data);
- }
+ } else if (g_ascii_strcasecmp (prop, "ground") == 0) {
+ data->gnd_list = g_slist_prepend (data->gnd_list, GINT_TO_POINTER (data->node_nr));
- if (g_ascii_strcasecmp (prop, "point")) {
- g_free (prop);
- continue;
+ } else if (g_ascii_strcasecmp (prop, "clamp") == 0) {
+ data->clamp_list =
+ g_slist_prepend (data->clamp_list, GINT_TO_POINTER (data->node_nr));
}
g_free (prop);
}
@@ -335,19 +268,18 @@ netlist_helper_node_traverse (Node *node, NetlistData *data)
}
// Traverse the wires at this node.
- for (wires = node->wires; wires; wires = wires->next) {
- Wire *wire = wires->data;
+ for (iter = node->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
netlist_helper_wire_traverse (wire, data);
}
- g_slist_free_full (wires, g_object_unref);
- g_slist_free_full (pins, g_object_unref);
}
-void
-netlist_helper_node_foreach_traverse (gpointer key, gpointer value, NetlistData *data)
+void netlist_helper_node_foreach_traverse (gpointer key, gpointer value, NetlistData *data)
{
Node *node = value;
+ g_return_if_fail (data != NULL);
+
// Only visit nodes that are not already visited.
if (node_is_visited (node))
return;
@@ -357,8 +289,7 @@ netlist_helper_node_foreach_traverse (gpointer key, gpointer value, NetlistData
data->node_nr++;
}
-gint
-compare_marker (gconstpointer a, gconstpointer b)
+gint compare_marker (gconstpointer a, gconstpointer b)
{
const Marker *ma;
gint node_nr;
@@ -372,28 +303,23 @@ compare_marker (gconstpointer a, gconstpointer b)
return 1;
}
-gboolean
-netlist_helper_foreach_model_save (gpointer key, gpointer model,
- gpointer user_data)
+gboolean netlist_helper_foreach_model_save (gpointer key, gpointer model, gpointer user_data)
{
- GList **l = (GList **)user_data;
+ GList **l = user_data;
(*l) = g_list_prepend (*l, g_strdup ((gchar *)key));
return TRUE;
}
-gboolean
-netlist_helper_foreach_model_free (gpointer key, gpointer model,
- gpointer user_data)
+gboolean netlist_helper_foreach_model_free (gpointer key, gpointer model, gpointer user_data)
{
g_free (key);
return FALSE;
}
-char *
-netlist_helper_linebreak (char *str)
+char *netlist_helper_linebreak (char *str)
{
char **split, *tmp;
GString *out;
@@ -410,8 +336,7 @@ netlist_helper_linebreak (char *str)
out = g_string_append_c (out, '\n');
out = g_string_append (out, split[i] + 1);
}
- }
- else {
+ } else {
out = g_string_append (out, split[i]);
}
@@ -424,28 +349,44 @@ netlist_helper_linebreak (char *str)
return tmp;
}
-void
-netlist_helper_create (Schematic *sm, Netlist *out, GError **error)
+void update_schematic(Schematic *sm) {
+ char *version = schematic_get_version(sm);
+ if (version == NULL) {
+ NodeStore *store = schematic_get_store(sm);
+
+ for (GList *iter = store->parts; iter; iter = iter->next) {
+ int node_ctr = 1;
+ Part *part = iter->data;
+ update_connection_designators(part, part_get_property_ref(part, "template"), &node_ctr);
+ }
+ }
+ schematic_set_version(sm, VERSION);
+
+ return;
+}
+
+// FIXME this one piece of ugly+bad code
+void netlist_helper_create (Schematic *sm, Netlist *out, GError **error)
{
NetlistData data;
- GList *parts, *wires, *list;
+ GList *iter;
Part *part;
- gint pin_nr, num_pins, num_nodes, num_gnd_nodes, i, j, num_clamps;
+ gint pin_nr, num_nodes, num_gnd_nodes, i, j, num_clamps;
Pin *pins;
gchar *template, **template_split;
NodeStore *store;
gchar **node2real;
- schematic_log_clear (sm);
-
out->models = NULL;
out->title = schematic_get_filename (sm);
out->settings = schematic_get_sim_settings (sm);
store = schematic_get_store (sm);
out->store = store;
+
node_store_node_foreach (store, (GHFunc *)netlist_helper_node_foreach_reset, NULL);
- for (wires = store->wires; wires; wires = wires->next) {
- Wire *wire = wires->data;
+
+ for (iter = store->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
wire_set_visited (wire, FALSE);
}
@@ -458,82 +399,74 @@ netlist_helper_create (Schematic *sm, Netlist *out, GError **error)
// Check if there is a Ground node
if (num_gnd_nodes == 0) {
- schematic_log_append (sm, _("No ground node. Aborting.\n"));
- schematic_log_show (sm);
- g_set_error (error,
- OREGANO_ERROR,
- OREGANO_SIMULATE_ERROR_NO_GND,
- _("Possibly due to a faulty circuit schematic. Please check that\n"
- "you have a ground node and try again."));
+ g_set_error (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND,
+ _ ("At least one GND is required. Add at least one and try again."));
}
else if (num_clamps == 0) {
- schematic_log_append (sm, _("No test clamps found. Aborting.\n"));
- schematic_log_show (sm);
- g_set_error (error,
- OREGANO_ERROR,
- OREGANO_SIMULATE_ERROR_NO_CLAMP,
- _("Possibly due to a faulty circuit schematic. Please check that\n"
- "you have one o more test clamps and try again."));
+ // FIXME put a V/I clamp on each and every subtree
+ // FIXME and let the user toggle visibility in the plot window
+ // FIXME see also TODO/FIXME above
+ g_set_error (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP,
+ _ ("No test clamps found. Add at least one and try again."));
}
else {
num_nodes = data.node_nr - 1;
-
- // Build an array for going from node nr to "real node nr",
- // where gnd nodes are nr 0 and the rest of the nodes are
- // 1, 2, 3, ...
- node2real = g_new0 (gchar*, num_nodes + 1);
-
+
+ // Build an array for going from node nr to "real node nr",
+ // where gnd nodes are nr 0 and the rest of the nodes are
+ // 1, 2, 3, ...
+ node2real = g_new0 (gchar *, num_nodes + 1 + 1);
+ node2real[num_nodes + 1] = NULL; // so we can use g_strfreev
+
for (i = 1, j = 1; i <= num_nodes; i++) {
GSList *mlist;
if (g_slist_find (data.gnd_list, GINT_TO_POINTER (i))) {
node2real[i] = g_strdup ("0");
- }
- else if ((mlist = g_slist_find_custom (data.mark_list,
- GINT_TO_POINTER (i), compare_marker))) {
+ } else if ((mlist = g_slist_find_custom (data.mark_list, GINT_TO_POINTER (i),
+ compare_marker))) {
Marker *marker = mlist->data;
node2real[i] = g_strdup (marker->name);
- }
- else {
+ } else {
node2real[i] = g_strdup_printf ("%d", j++);
}
}
- // Fill in the netlist node names for all the used nodes.
- for (list = data.node_and_number_list; list; list = list->next) {
- NodeAndNumber *nan = list->data;
- if (nan->node->netlist_node_name != NULL)
+ // Fill in the netlist node names for all the used nodes.
+ for (iter = data.node_and_number_list; iter; iter = iter->next) {
+ NodeAndNumber *nan = iter->data;
+ if (nan->node_nr > 0) {
g_free (nan->node->netlist_node_name);
- if (nan->node_nr != 0)
nan->node->netlist_node_name = g_strdup (node2real[nan->node_nr]);
+ }
}
// Initialize out->template
out->template = g_string_new ("");
- for (parts = store->parts; parts; parts = parts->next) {
+ for (iter = store->parts; iter; iter = iter->next) {
+ part = iter->data;
+
gchar *tmp, *internal;
GString *str;
-
- part = parts->data;
+
internal = part_get_property (part, "internal");
if (internal != NULL) {
gint node_nr;
Pin *pins;
- if (g_ascii_strcasecmp (internal, "point") != 0) {
+ if (g_ascii_strcasecmp (internal, "clamp") != 0) {
g_free (internal);
continue;
}
-
+
// Got a clamp!, set node number
pins = part_get_pins (part);
node_nr = GPOINTER_TO_INT (g_hash_table_lookup (data.pins, &pins[0]));
if (!node_nr) {
- g_warning ("Couln't find part, pin_nr %d.", 0);
- }
- else {
+ g_warning ("Couldn't find part, pin_nr %d.", 0);
+ } else {
// need to substrac 1, netlist starts in 0, and node_nr in 1
pins[0].node_nr = atoi (node2real[node_nr]);
}
@@ -547,144 +480,133 @@ netlist_helper_create (Schematic *sm, Netlist *out, GError **error)
}
template = part_property_expand_macros (part, tmp);
- NG_DEBUG (g_strdup_printf ("Template: '%s'\n" "macro : '%s'\n", tmp, template));
- if (tmp != NULL) g_free (tmp);
+ NG_DEBUG ("Template: '%s'\n"
+ "macro : '%s'\n",
+ tmp, template);
+ g_free (tmp);
tmp = netlist_helper_linebreak (template);
- if (template != NULL) g_free (template);
+ g_free (template);
template = tmp;
- num_pins = part_get_num_pins (part);
pins = part_get_pins (part);
- template_split = g_strsplit (template, " ", 0);
- if (template != NULL) g_free (template);
- template = NULL;
+
+
+
+ GRegex *regex;
+ GMatchInfo *match_info;
+ GError *error = NULL;
+
+ regex = g_regex_new("%\\d*", 0, 0, NULL);
+ g_regex_match_full(regex, template, -1, 0, 0, &match_info, &error);
+ template_split = g_regex_split(regex, template, 0);
str = g_string_new ("");
- i = 0;
- while (template_split[i] != NULL && template_split[i][0] != '%') {
- g_string_append (str, template_split[i++]);
- g_string_append_c (str , ' ');
- NG_DEBUG (g_strdup_printf ("str: %s\n", str->str));
- }
+ NG_DEBUG ("Reading pins.\n)");
+
+ int i;
+ for (i = 0; g_match_info_matches(match_info); i++) {
+ g_string_append (str, template_split[i]);
- NG_DEBUG (g_strdup_printf ("Reading %d pins.\n)", num_pins));
+ gchar *word = g_match_info_fetch(match_info, 0);
- for (pin_nr = 0; pin_nr < num_pins; pin_nr++) {
+
+ pin_nr = g_ascii_strtoll(word + 1, NULL, 10) - 1;
gint node_nr = 0;
node_nr = GPOINTER_TO_INT (g_hash_table_lookup (data.pins, &pins[pin_nr]));
if (!node_nr) {
- gchar * tmp = g_strdup_printf (_("Couldn't find part, pin_nr %d."), pin_nr);
- oregano_error_with_title (_("Problem of library:"), tmp);
- return;
- }
- else {
+ g_set_error (&error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_SUCH_PART,
+ _ ("Could not find part in library, pin #%d."), pin_nr);
+ return; // FIXME wtf?? this leaks like hell and did for ages!
+ } else {
gchar *tmp;
tmp = node2real[node_nr];
// need to substrac 1, netlist starts in 0, and node_nr in 1
pins[pin_nr].node_nr = atoi (node2real[node_nr]);
g_string_append (str, tmp);
- g_string_append_c (str, ' ');
- NG_DEBUG (g_strdup_printf ("str: %s\n", str->str));
- i++;
+ NG_DEBUG ("str: %s\n", str->str);
}
- while (template_split[i] != NULL) {
- if (template_split[i][0] == '%')
- break;
-
- g_string_append (str, template_split[i]);
- g_string_append_c (str, ' ');
- NG_DEBUG (g_strdup_printf ("str: %s\n", str->str));
- i++;
- }
+ g_free(word);
+ g_match_info_next(match_info, NULL);
}
-
- NG_DEBUG (g_strdup_printf ("Done with pins, i = %d\n", i));
-
- while (template_split[i] != NULL) {
- if (template_split[i][0] == '%')
- break;
+ g_match_info_free(match_info);
+ g_free (template);
+ template = NULL;
+ g_regex_unref(regex);
+ if (template_split[i] != NULL) {
g_string_append (str, template_split[i]);
- g_string_append_c (str, ' ');
- NG_DEBUG (g_strdup_printf ("str: %s\n", str->str));
- i++;
}
-
g_strfreev (template_split);
- NG_DEBUG (g_strdup_printf ("str: %s\n", str->str));
+ if (error != NULL) {
+ g_printerr("Error while matching: %s\n", error->message);
+ g_error_free(error);
+ }
+
+ NG_DEBUG ("Done with pins, i = %d\n", i);
+
+ NG_DEBUG ("str: %s\n", str->str);
out->template = g_string_append (out->template, str->str);
out->template = g_string_append_c (out->template, '\n');
g_string_free (str, TRUE);
}
- for (i = 0; i < num_nodes + 1; i++) {
- g_free (node2real[i]);
- }
- g_free (node2real);
+ g_strfreev (node2real);
- g_hash_table_foreach (data.models, (GHFunc)netlist_helper_foreach_model_save,
- &out->models);
+ g_hash_table_foreach (data.models, (GHFunc)netlist_helper_foreach_model_save, &out->models);
return;
}
g_hash_table_foreach (data.models, (GHFunc)netlist_helper_foreach_model_free, NULL);
g_hash_table_destroy (data.models);
g_hash_table_destroy (data.pins);
- for (list = data.node_and_number_list; list; list = list->next) {
- NodeAndNumber *nan = list->data;
- if (nan != NULL) g_free (nan);
- }
- g_list_free (data.node_and_number_list);
-
- g_list_free_full (wires, g_object_unref);
- g_list_free_full (list, g_object_unref);
+ g_list_free_full (data.node_and_number_list, (GDestroyNotify)g_free);
}
-char *
-netlist_helper_create_analysis_string (NodeStore *store, gboolean do_ac)
+char *netlist_helper_create_analysis_string (NodeStore *store, gboolean do_ac)
{
- GList *p;
+ GList *iter;
+ Part *part;
gchar *prop;
GString *out;
gchar *ret;
out = g_string_new ("");
- for (p = node_store_get_parts (store); p; p = p->next) {
- prop = part_get_property (p->data, "internal");
+ for (iter = node_store_get_parts (store); iter; iter = iter->next) {
+ part = iter->data;
+ prop = part_get_property (part, "internal");
if (prop) {
- if (!g_ascii_strcasecmp (prop, "point")) {
- Pin *pins = part_get_pins (p->data);
- g_free (prop);
+ if (!g_ascii_strcasecmp (prop, "clamp")) {
+ Pin *pins = part_get_pins (part);
+
+ prop = part_get_property (part, "type");
- prop = part_get_property (p->data, "type");
-
if (!g_ascii_strcasecmp (prop, "v")) {
if (!do_ac) {
g_string_append_printf (out, " %s(%d)", prop, pins[0].node_nr);
- }
- else {
+ } else {
gchar *ac_type, *ac_db;
- ac_type = part_get_property (p->data, "ac_type");
- ac_db = part_get_property (p->data, "ac_db");
-
+ ac_type = part_get_property (part, "ac_type");
+ ac_db = part_get_property (part, "ac_db");
+
if (!g_ascii_strcasecmp (ac_db, "true"))
- g_string_append_printf (out, " %s%sdb(%d)", prop, ac_type, pins[0].node_nr);
+ g_string_append_printf (out, " %s%sdb(%d)", prop, ac_type,
+ pins[0].node_nr);
else
- g_string_append_printf (out, " %s%s(%d)", prop, ac_type, pins[0].node_nr);
+ g_string_append_printf (out, " %s%s(%d)", prop, ac_type,
+ pins[0].node_nr);
}
- }
- else {
+ } else {
Node *node;
- SheetPos lookup_key;
- SheetPos part_pos;
-
- item_data_get_pos (ITEM_DATA (p->data), &part_pos);
+ Coords lookup_key;
+ Coords part_pos;
+
+ item_data_get_pos (ITEM_DATA (part), &part_pos);
lookup_key.x = part_pos.x + pins[0].offset.x;
lookup_key.y = part_pos.y + pins[0].offset.y;
@@ -692,77 +614,143 @@ netlist_helper_create_analysis_string (NodeStore *store, gboolean do_ac)
node = node_store_get_or_create_node (store, lookup_key);
if (node) {
- GSList *lst, *it;
- it = lst = netlist_helper_get_clamp_parts (store, node);
- while (it) {
- g_string_append_printf (out, " i(%s)", (char *)it->data);
- it = it->next;
+ GSList *lst, *iter;
+ iter = lst = netlist_helper_get_clamp_parts (store, node);
+
+ for (; iter; iter = iter->next) {
+ g_string_append_printf (out, " i(%s)", (char *)iter->data);
}
- g_slist_free (lst);
+ g_slist_free_full (lst, g_free); // need to free this, we are owning it!
}
}
}
+ g_free (prop);
}
}
ret = out->str;
g_string_free (out, FALSE);
- g_list_free_full (p, g_object_unref);
return ret;
}
-GSList *
-netlist_helper_get_voltmeters_list (Schematic *sm, GError **error)
+GSList *netlist_helper_get_voltmeters_list (Schematic *sm, GError **error, gboolean with_type)
{
Netlist netlist_data;
- GError *local_error = 0;
+ GError *e = NULL;
GSList *clamp_list = NULL;
NodeStore *node_store;
- GList *p;
+ GList *iter;
gchar *prop;
+ Part *part;
+ Pin *pins;
+ gint i;
+ gchar *ac_type, *ac_db, *tmp;
- netlist_helper_create (sm, &netlist_data, &local_error);
- error = &local_error;
+ netlist_helper_create (sm, &netlist_data, &e);
+ if (e) {
+ g_propagate_error (error, e);
+ return NULL;
+ }
node_store = netlist_data.store;
- for (p = node_store_get_parts (node_store); p; p = p->next) {
- prop = part_get_property (p->data, "internal");
+ for (iter = node_store_get_parts (node_store); iter; iter = iter->next) {
+ part = iter->data;
+ prop = part_get_property (part, "internal");
if (prop) {
- if (!g_ascii_strcasecmp (prop, "point")) {
- Pin *pins = part_get_pins (p->data);
+ if (!g_ascii_strcasecmp (prop, "clamp")) {
g_free (prop);
- prop = part_get_property (p->data, "type");
-
+ prop = part_get_property (part, "type");
+
if (!g_ascii_strcasecmp (prop, "v")) {
- gchar * tmp;
- tmp = g_strdup_printf ("%d", pins[0].node_nr);
+ pins = part_get_pins (part);
+ if (with_type) {
+ ac_type = part_get_property(part, "ac_type");
+ ac_db = part_get_property(part, "ac_db");
+ i = 0;
+ while (ac_type[i]) {
+ ac_type[i] = g_ascii_toupper(ac_type[i]);
+ i++;
+ }
+ if (!g_strcmp0(ac_db, "true"))
+ tmp = g_strdup_printf ("VDB(%d)", pins[0].node_nr);
+ else
+ tmp = g_strdup_printf ("V%s(%d)", ac_type, pins[0].node_nr);
+ g_free(ac_type);
+ g_free(ac_db);
+ } else {
+ tmp = g_strdup_printf ("%d", pins[0].node_nr);
+ }
clamp_list = g_slist_prepend (clamp_list, tmp);
- if (0) printf ("clamp_list = %s\n", tmp);
- }
+ if (0)
+ printf ("clamp_list = %s\n", tmp);
+ }
}
+ g_free(prop);
}
}
if (0) {
- clamp_list = g_slist_prepend (clamp_list, "3");
- clamp_list = g_slist_prepend (clamp_list, "2");
- clamp_list = g_slist_prepend (clamp_list, "1");
+ clamp_list = g_slist_prepend (clamp_list, "3");
+ clamp_list = g_slist_prepend (clamp_list, "2");
+ clamp_list = g_slist_prepend (clamp_list, "1");
}
if (0) {
GSList *slist = NULL;
gchar *text = NULL;
-
+
slist = g_slist_copy (clamp_list);
text = g_strdup_printf ("V(%d)", atoi (slist->data));
slist = slist->next;
- while (slist)
- {
+ while (slist) {
text = g_strdup_printf ("%s V(%d)", text, atoi (slist->data));
slist = slist->next;
}
- if (0) printf ("clamp_list = %s\n", text);
+ if (0)
+ printf ("clamp_list = %s\n", text);
}
- g_list_free_full (p, g_object_unref);
-
+
return clamp_list;
}
+
+GSList *netlist_helper_get_voltage_sources_list (Schematic *sm, GError **error, gboolean ac_only)
+{
+ Netlist netlist_data;
+ GError *e = NULL;
+ GSList *sources_list = NULL;
+ NodeStore *node_store;
+ GList *iter;
+ gchar *prop;
+ Part *part;
+
+ netlist_helper_create (sm, &netlist_data, &e);
+ if (e) {
+ g_propagate_error (error, e);
+ return NULL;
+ }
+
+ node_store = netlist_data.store;
+
+ for (iter = node_store_get_parts (node_store); iter; iter = iter->next) {
+ part = iter->data;
+ prop = part_get_property (part, "Refdes");
+ if (prop) {
+ if (prop[0] == 'V' && (prop[1] >= '0' && prop[1] <= '9')) {
+ gchar *tmp;
+ tmp = g_strdup (&prop[1]);
+ if (ac_only) {
+ g_free(prop);
+ prop = part_get_property (part, "Frequency");
+ if (prop)
+ sources_list = g_slist_append (sources_list, tmp);
+ } else {
+ sources_list = g_slist_append (sources_list, tmp);
+ }
+ if (0)
+ printf ("sources_list = %s\n", tmp);
+ }
+ g_free(prop);
+ }
+ }
+
+ return sources_list;
+}
diff --git a/src/engines/netlist-helper.h b/src/engines/netlist-helper.h
index f0dbc33..5847dfa 100644
--- a/src/engines/netlist-helper.h
+++ b/src/engines/netlist-helper.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2010 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NETLIST_HELPER_H
#define __NETLIST_HELPER_H
@@ -37,40 +39,45 @@
#include "schematic.h"
#include "sim-settings.h"
-typedef struct {
- gint node_nr; ///< Node number
+typedef struct
+{
+ gint node_nr; ///< Node number
GHashTable *pins;
GHashTable *models;
- GSList *gnd_list; ///< Ground parts on the schematic
- GSList *clamp_list; ///< Test clamps on the schematic
- GSList *mark_list;
- GList *node_and_number_list;
- NodeStore *store;
+ GSList *gnd_list; ///< Ground parts on the schematic
+ GSList *clamp_list; ///< Test clamps on the schematic
+ GSList *mark_list;
+ GList *node_and_number_list;
+ NodeStore *store;
} NetlistData;
-typedef struct {
- gchar *cmd;
- gchar *title;
- GString *template;
+typedef struct
+{
+ gchar *cmd;
+ gchar *title;
+ GString *template;
SimSettings *settings;
- NodeStore *store;
- GList *models;
+ NodeStore *store;
+ GList *models;
} Netlist;
-typedef struct {
- gint node_nr;
+typedef struct
+{
+ gint node_nr;
gchar *name;
} Marker;
-typedef struct {
- gint node_nr;
+typedef struct
+{
+ gint node_nr;
Node *node;
} NodeAndNumber;
-void netlist_helper_init_data (NetlistData *data);
-void netlist_helper_create (Schematic *sm, Netlist *out, GError **error);
-char * netlist_helper_create_analysis_string (NodeStore *store,
- gboolean do_ac);
-GSList * netlist_helper_get_voltmeters_list (Schematic *sm, GError **error);
+void update_schematic(Schematic *sm);
+void netlist_helper_init_data (NetlistData *data);
+void netlist_helper_create (Schematic *sm, Netlist *out, GError **error);
+char *netlist_helper_create_analysis_string (NodeStore *store, gboolean do_ac);
+GSList *netlist_helper_get_voltmeters_list (Schematic *sm, GError **error, gboolean with_type);
+GSList *netlist_helper_get_voltage_sources_list (Schematic *sm, GError **error, gboolean ac_only);
#endif
diff --git a/src/engines/ngspice-analysis.c b/src/engines/ngspice-analysis.c
index 79c18c9..9936a80 100644
--- a/src/engines/ngspice-analysis.c
+++ b/src/engines/ngspice-analysis.c
@@ -3,10 +3,14 @@
*
* Authors:
* Marc Lorber <Lorber.Marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -20,8 +24,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -36,65 +40,63 @@
#include "dialogs.h"
#include "engine-internal.h"
#include "ngspice-analysis.h"
+#include "../tools/thread-pipe.h"
+#include "../tools/cancel-info.h"
-typedef enum {
- STATE_IDLE,
- IN_VARIABLES,
- IN_VALUES,
- STATE_ABORT
-} ParseDataState;
-
-static gchar *analysis_names[] = {
- "Operating Point" ,
- "Transient Analysis" ,
- "DC transfer characteristic" ,
- "AC Analysis" ,
- "Transfer Function" ,
- "Distortion Analysis" ,
- "Noise Analysis" ,
- "Pole-Zero Analysis" ,
- "Sensitivity Analysis" ,
- "Fourier analysis" ,
- "Unknown Analysis" ,
- NULL
-};
-
-#define SP_TITLE "oregano\n"
-#define CPU_TIME "CPU time since last call:"
-
-#define TAGS_COUNT (sizeof (analysis_tags) / sizeof (struct analysis_tag))
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-#define IS_THIS_ITEM(str,item) (!strncmp (str,item,strlen(item)))
+#define SP_TITLE "oregano\n"
+#define CPU_TIME "CPU time since last call:"
-typedef struct {
- gchar *name;
-} NGSPICE_Variable;
+#define TAGS_COUNT (sizeof(analysis_tags) / sizeof(struct analysis_tag))
+#include "debug.h"
+#define IS_THIS_ITEM(str, item) (!strncmp (str, item, strlen (item)))
+#ifdef DEBUG_THIS
+#undef DEBUG_THIS
+#endif
+#define DEBUG_THIS 1
-static NGSPICE_Variable *
-get_variables (gchar *str, gint *count)
+/**
+ * \brief extract the resulting variables from ngspice output
+ *
+ * In ngspice a number can terminate only with a space,
+ * while in spice3 a number can also terminate with a
+ * comma.
+ *
+ * In the Fourier analysis the name of the output ends
+ * with a colon.
+ *
+ * Tested function.
+ *
+ * @returns a GArray filled up doubles
+ */
+gchar **get_variables (const gchar *str, gint *count)
{
- NGSPICE_Variable *out;
+ g_return_val_if_fail (str, NULL);
+
+ gchar **out;
static gchar *tmp[100];
- gchar *ini, *fin;
+ const gchar *start, *end;
gint i = 0;
- i = 0;
- ini = str;
-
- /* Put blank in advance */
- while (isspace(*ini)) ini++;
- fin = ini;
- while (*fin != '\0') {
- if (isspace(*fin)) {
- *fin = '\0';
- tmp[i] = g_strdup (ini);
- *fin = ' ';
+ start = str;
+ while (isspace (*start))
+ start++;
+ end = start;
+ while (*end != '\0') {
+ if (isspace (*end) || *end == ',' || *end == ':') {
+ // number ended, designate as such and replace the string
+ tmp[i] = g_strndup (start, (gsize)(end - start));
i++;
- ini = fin;
- while (isspace(*ini)) ini++;
- fin = ini;
- }
- else fin++;
+ start = end;
+ while (isspace (*start) || *start == ',' || *start == ':')
+ start++;
+ end = start;
+ } else {
+ end++;
+ }
+ }
+ if (end > start) {
+ tmp[i] = g_strndup (start, (gsize)(end - start));
+ i++;
}
if (i == 0) {
@@ -102,95 +104,96 @@ get_variables (gchar *str, gint *count)
return NULL;
}
- out = g_new0 (NGSPICE_Variable, i);
+ // append an extra NUL slot to allow using g_strfreev
+ out = g_new0 (gchar *, i + 1);
(*count) = i;
- for ( i=0; i<(*count); i++ ) {
- out[i].name = tmp[i];
- }
+ memcpy (out, tmp, sizeof(gchar *) * i);
+ out[i] = NULL;
return out;
}
-void
-parse_dc_analysis (OreganoNgSpice *ngspice, gchar * tmp)
+/**
+ * @resources: caller frees
+ */
+static ThreadPipe *parse_dc_analysis (NgspiceAnalysisResources *resources)
{
+ ThreadPipe *pipe = resources->pipe;
+ gchar **buf = &resources->buf;
+ const SimSettings* const sim_settings = resources->sim_settings;
+ GList **analysis = resources->analysis;
+ guint *num_analysis = resources->num_analysis;
+
static SimulationData *sdata;
static Analysis *data;
- OreganoNgSpicePriv *priv = ngspice->priv;
- SimSettings *sim_settings;
- static gchar buf[256];
- gboolean found = FALSE;
- NGSPICE_Variable *variables;
- gint i, n=0, index=0;
+ gsize size;
+ gboolean found = FALSE;
+ gchar **variables;
+ gint i, n = 0, index = 0;
gdouble val[10];
gdouble np1;
- sim_settings = (SimSettings *)schematic_get_sim_settings (priv->schematic);
+ NG_DEBUG ("DC: result str\n>>>\n%s\n<<<", *buf);
+
data = g_new0 (Analysis, 1);
- priv->current = sdata = SIM_DATA (data);
- priv->analysis = g_list_append (priv->analysis, sdata);
- priv->num_analysis = 1;
- sdata->state = IN_VALUES;
- sdata->type = DC_TRANSFER;
+ sdata = SIM_DATA (data);
+ sdata->type = ANALYSIS_TYPE_DC_TRANSFER;
sdata->functions = NULL;
-
np1 = 1.;
- ANALYSIS (sdata)->dc.start =
- sim_settings_get_dc_start (sim_settings);
- ANALYSIS (sdata)->dc.stop =
- sim_settings_get_dc_stop (sim_settings);
- ANALYSIS (sdata)->dc.step =
- sim_settings_get_dc_step (sim_settings);
-
- np1 = (ANALYSIS (sdata)->dc.stop -
- ANALYSIS (sdata)->dc.start) / ANALYSIS (sdata)->dc.step;
+ ANALYSIS (sdata)->dc.start = sim_settings_get_dc_start (sim_settings);
+ ANALYSIS (sdata)->dc.stop = sim_settings_get_dc_stop (sim_settings);
+ ANALYSIS (sdata)->dc.step = sim_settings_get_dc_step (sim_settings);
+
+ np1 = (ANALYSIS (sdata)->dc.stop - ANALYSIS (sdata)->dc.start) / ANALYSIS (sdata)->dc.step;
ANALYSIS (sdata)->dc.sim_length = np1;
-
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
-
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
// Calculates the number of variables
- variables = get_variables (buf, &n);
+ variables = get_variables (*buf, &n);
+ if (!variables)
+ return pipe;
- n=n-1;
- sdata->var_names = (char**) g_new0 (gpointer, n);
- sdata->var_units = (char**) g_new0 (gpointer, n);
+ n = n - 1;
+ sdata->var_names = (char **)g_new0 (gpointer, n);
+ sdata->var_units = (char **)g_new0 (gpointer, n);
sdata->var_names[0] = g_strdup ("Voltage sweep");
- sdata->var_units[0] = g_strdup (_("voltage"));
- sdata->var_names[1] = g_strdup (variables[2].name);
- sdata->var_units[1] = g_strdup (_("voltage"));
-
- sdata->state = IN_VALUES;
+ sdata->var_units[0] = g_strdup (_ ("voltage"));
+ sdata->var_names[1] = g_strdup (variables[2]);
+ sdata->var_units[1] = g_strdup (_ ("voltage"));
+
sdata->n_variables = 2;
- sdata->got_points = 0;
- sdata->got_var = 0;
- sdata->data = (GArray**) g_new0 (gpointer, 2);
-
- fgets (buf, 255, priv->inputfp);
+ sdata->got_points = 0;
+ sdata->got_var = 0;
+ sdata->data = (GArray **)g_new0 (gpointer, 2);
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
for (i = 0; i < 2; i++)
- sdata->data[i] = g_array_new (TRUE, TRUE, sizeof (double));
-
+ sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
+
sdata->min_data = g_new (double, n);
sdata->max_data = g_new (double, n);
// Read the data
- for (i=0; i<2; i++) {
+ for (i = 0; i < 2; i++) {
sdata->min_data[i] = G_MAXDOUBLE;
sdata->max_data[i] = -G_MAXDOUBLE;
}
found = FALSE;
- while ((fgets (buf, 255, priv->inputfp) != NULL) && !found) {
- if (strlen (buf)<= 2) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
+ while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0) && !found) {
+ if (strlen (*buf) <= 2) {
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
}
- tmp=&buf[0];
- variables = get_variables (tmp, &i);
- index = atoi (variables[0].name);
- for (i=0; i<n; i++) {
- val[i]=g_ascii_strtod (variables[i+1].name, NULL);
+ variables = get_variables (*buf, &i);
+ if (!variables)
+ return pipe;
+ index = atoi (variables[0]);
+ for (i = 0; i < n; i++) {
+ val[i] = g_ascii_strtod (variables[i + 1], NULL);
sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
if (val[i] < sdata->min_data[i])
sdata->min_data[i] = val[i];
@@ -199,436 +202,1000 @@ parse_dc_analysis (OreganoNgSpice *ngspice, gchar * tmp)
}
sdata->got_points++;
sdata->got_var = 2;
- if (index >= ANALYSIS (sdata)->dc.sim_length) found = TRUE;
+ if (index >= ANALYSIS (sdata)->dc.sim_length)
+ found = TRUE;
}
- return;
-
+
+ *analysis = g_list_append (*analysis, sdata);
+ (*num_analysis)++;
+
+ return pipe;
}
-void
-parse_transient_analysis (OreganoNgSpice *ngspice, gchar * tmp)
+/**
+ * @resources: caller frees
+ */
+static ThreadPipe *parse_ac_analysis (NgspiceAnalysisResources *resources)
{
+ ThreadPipe *pipe = resources->pipe;
+ gboolean is_vanilla = resources->is_vanilla;
+ gchar *scale, **variables, **buf = &resources->buf;
+ const SimSettings* const sim_settings = resources->sim_settings;
+ GList **analysis = resources->analysis;
+ guint *num_analysis = resources->num_analysis;
static SimulationData *sdata;
static Analysis *data;
- OreganoNgSpicePriv *priv = ngspice->priv;
- SimSettings *sim_settings;
- static gchar buf[256];
- gboolean found = FALSE;
- NGSPICE_Variable *variables;
- gint i, n = 0, m = 0, p = 0;
- gdouble val[10];
- GSList *nodes_list = NULL;
- GError *error = NULL;
- gint nodes_nb=0;
- GArray **val_tmp1;
- GArray **val_tmp2;
- GArray **val_tmp3;
-
- sim_settings = (SimSettings *)schematic_get_sim_settings (priv->schematic);
+ gsize size;
+ gboolean found = FALSE;
+ gint i, n = 0, index = 0;
+ gdouble fstart, fstop, val[10];
+
+ NG_DEBUG ("AC: result str\n>>>\n%s\n<<<", *buf);
+
data = g_new0 (Analysis, 1);
- priv->current = sdata = SIM_DATA (data);
- priv->analysis = g_list_append (priv->analysis, sdata);
- priv->num_analysis = 1;
- sdata->state = IN_VALUES;
- sdata->type = ANALYSIS_UNKNOWN;
+ sdata = SIM_DATA (data);
+ sdata->type = ANALYSIS_TYPE_AC;
sdata->functions = NULL;
- // Identify the number of analysis from the number of clamp
- // ASCII format of ngspice only returns 3 columns at a time
- nodes_list = netlist_helper_get_voltmeters_list (priv->schematic, &error);
- for ( ; nodes_list; nodes_list = nodes_list->next ) {
- nodes_nb++;
- }
+ ANALYSIS (sdata)->ac.sim_length = 1.;
+
+ ANALYSIS (sdata)->ac.start = fstart = sim_settings_get_ac_start (sim_settings);
+ ANALYSIS (sdata)->ac.stop = fstop = sim_settings_get_ac_stop (sim_settings);
+
+ scale = sim_settings_get_ac_type (sim_settings);
+ if (!g_ascii_strcasecmp (scale, "LIN")) {
+ ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings);
+ } else if (!g_ascii_strcasecmp (scale, "DEC")) {
+ ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings) * log10 (fstop / fstart);
+ } else if (!g_ascii_strcasecmp (scale, "OCT")) {
+ ANALYSIS (sdata)->ac.sim_length = (double) sim_settings_get_ac_npoints (sim_settings) * log10 (fstop / fstart) / log10 (2);
+ }
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ // Calculates the number of variables
+ variables = get_variables (*buf, &n);
+ if (!variables)
+ return pipe;
- if (nodes_nb > 9) {
- oregano_warning (_("Only the 9 first nodes will be considered"));
- nodes_nb = 9;
- }
-
- tmp = g_strchug (tmp);
- for (i = 0; analysis_names[i]; i++) {
- if (g_str_has_prefix (g_strdup (tmp), analysis_names[i])) {
- sdata->type = i;
- }
- }
-
- ANALYSIS (sdata)->transient.sim_length =
- sim_settings_get_trans_stop (sim_settings) -
- sim_settings_get_trans_start (sim_settings);
- ANALYSIS (sdata)->transient.step_size =
- sim_settings_get_trans_step (sim_settings);
-
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
-
- sdata->var_names = (char**) g_new0 (gpointer, nodes_nb + 1);
- sdata->var_units = (char**) g_new0 (gpointer, nodes_nb + 1);
- variables = get_variables (buf, &n);
n = n - 1;
- sdata->var_names[0] = g_strdup (_("Time"));
- sdata->var_units[0] = g_strdup (_("time"));
- for (i = 1; i < n; i++) {
- sdata->var_names[i] = g_strdup (variables[i+1].name);
- sdata->var_units[i] = g_strdup (_("voltage"));
- }
- sdata->state = IN_VALUES;
- sdata->n_variables = nodes_nb+1;
- sdata->got_points = 0;
- sdata->got_var = 0;
- sdata->data = (GArray**) g_new0 (gpointer, nodes_nb+1);
-
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
-
- for (i = 0; i < nodes_nb+1; i++)
- sdata->data[i] = g_array_new (TRUE, TRUE, sizeof (double));
-
- val_tmp1 = (GArray**) g_new0 (gpointer, 4);
- val_tmp2 = (GArray**) g_new0 (gpointer, 4);
- val_tmp3 = (GArray**) g_new0 (gpointer, 4);
- for (i = 0; i < 4; i++) {
- val_tmp1[i] = g_array_new (TRUE, TRUE, sizeof (double));
- val_tmp2[i] = g_array_new (TRUE, TRUE, sizeof (double));
- val_tmp3[i] = g_array_new (TRUE, TRUE, sizeof (double));
- }
-
- sdata->min_data = g_new (double, nodes_nb+1);
- sdata->max_data = g_new (double, nodes_nb+1);
+ sdata->var_names = (char **)g_new0 (gpointer, n);
+ sdata->var_units = (char **)g_new0 (gpointer, n);
+ sdata->var_names[0] = g_strdup ("Frequency");
+ sdata->var_units[0] = g_strdup (_ ("frequency"));
+ sdata->var_names[1] = g_strdup (variables[2]);
+ sdata->var_units[1] = g_strdup (_ ("voltage"));
+
+ sdata->n_variables = 2;
+ sdata->got_points = 0;
+ sdata->got_var = 0;
+ sdata->data = (GArray **)g_new0 (gpointer, 2);
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ for (i = 0; i < 2; i++)
+ sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
+
+ sdata->min_data = g_new (double, n);
+ sdata->max_data = g_new (double, n);
// Read the data
- for (i=0; i < nodes_nb +1; i++) {
+ for (i = 0; i < 2; i++) {
sdata->min_data[i] = G_MAXDOUBLE;
sdata->max_data[i] = -G_MAXDOUBLE;
}
found = FALSE;
- while ((fgets (buf, 255, priv->inputfp) != NULL) && !found) {
- gint k=0;
- if (strlen (buf)<= 2) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
+ while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0) && !found) {
+ if (strlen (*buf) <= 2) {
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
}
- tmp=&buf[0];
- variables = get_variables (tmp, &k);
- for (i=0; i<n; i++) {
- val[i]=g_ascii_strtod (variables[i+1].name, NULL);
- val_tmp1[i] = g_array_append_val (val_tmp1[i], val[i]);
+
+ variables = get_variables (*buf, &i);
+ if (!variables)
+ return pipe;
+
+ index = atoi (variables[0]);
+ for (i = 0; i < n; i++) {
+ if (i == 0)
+ val[i] = g_ascii_strtod (variables[i + 1], NULL);
+ if (is_vanilla && i > 0)
+ val[i] = g_ascii_strtod (variables[i + 2], NULL);
+ else
+ val[i] = g_ascii_strtod (variables[i + 1], NULL);
+ sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
if (val[i] < sdata->min_data[i])
sdata->min_data[i] = val[i];
if (val[i] > sdata->max_data[i])
sdata->max_data[i] = val[i];
}
- if (val[0] >= ANALYSIS (sdata)->transient.sim_length) found = TRUE;
+ sdata->got_points++;
+ sdata->got_var = 2;
+ if (index >= ANALYSIS (sdata)->ac.sim_length - 1)
+ found = TRUE;
}
- if (n < nodes_nb + 1) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- variables = get_variables (buf, &m);
- m=m-1;
-
- for (i=1; i<m; i++) {
- sdata->var_names[i+n-1] = g_strdup (variables[i+1].name);
- sdata->var_units[i+n-1] = g_strdup (_("voltage"));
+ *analysis = g_list_append (*analysis, sdata);
+ (*num_analysis)++;
+
+ return pipe;
+}
+
+/**
+ * Structure that helps parsing the output of ngspice.
+ *
+ * @name: The name (handled like an ID) of the column.
+ * @unit: The physical unit. it can have one of the following values:
+ * "none", "time", "voltage", "current", "unknown"
+ * @data: The data.
+ * @min: The min value of the data.
+ * @max: The max value of the data.
+ */
+typedef struct {
+ GString *name;
+ GString *unit;
+ GArray *data;
+ gdouble min;
+ gdouble max;
+} NgspiceColumn;
+
+/**
+ * Structure that helps parsing the output of ngspice.
+ *
+ * @ngspice_columns: The columns.
+ * @current_variables: New columns are appended to the end
+ * of the columns array. Because the index- and time-column
+ * are displayed repeatedly with every 3 new columns, there
+ * is needed an information how to interpret the incoming
+ * data to append it to the right columns. The current_variables
+ * array maps the position of the input data in the file
+ * to the position of the related column position in the table.
+ */
+typedef struct {
+ GPtrArray *ngspice_columns;
+ GArray *current_variables;
+} NgspiceTable;
+
+/**
+ * Allocates memory.
+ *
+ * @name: The name (ID) of the new column
+ * @predicted_size: The predicted end size of the new column.
+ */
+static NgspiceColumn *ngspice_column_new(const gchar *name, guint predicted_size) {
+ NgspiceColumn *ret_val = malloc(sizeof(NgspiceColumn));
+
+ ret_val->name = g_string_new(name);
+
+ if (g_str_has_prefix(name, "Index"))
+ ret_val->unit = g_string_new("none");
+ else if (g_str_has_prefix(name, "time"))
+ ret_val->unit = g_string_new("time");
+ else if (g_str_has_prefix(name, "V") || g_str_has_prefix(name, "v"))
+ ret_val->unit = g_string_new("voltage");
+ else if (g_str_has_suffix(name, "#branch"))
+ ret_val->unit = g_string_new("current");
+ else
+ ret_val->unit = g_string_new("unknown");
+
+ ret_val->data = g_array_sized_new(TRUE, TRUE, sizeof(gdouble), predicted_size);
+ ret_val->min = G_MAXDOUBLE;
+ ret_val->max = -G_MAXDOUBLE;
+
+ return ret_val;
+}
+
+/**
+ * Frees memory.
+ */
+static void ngspice_column_destroy(gpointer ptr) {
+ NgspiceColumn *column = (NgspiceColumn *)ptr;
+ if (column == NULL)
+ return;
+ if (column->name != NULL)
+ g_string_free(column->name, TRUE);
+ if (column->unit != NULL)
+ g_string_free(column->unit, TRUE);
+ g_free(column);
+}
+
+/**
+ * Allocates memory.
+ */
+static NgspiceTable *ngspice_table_new() {
+ NgspiceTable *ret_val = malloc(sizeof(NgspiceTable));
+ ret_val->ngspice_columns = g_ptr_array_new_with_free_func(ngspice_column_destroy);
+ ret_val->current_variables = g_array_new(TRUE, TRUE, sizeof(guint));
+ return ret_val;
+}
+
+/**
+ * Frees the memory.
+ */
+static void ngspice_table_destroy(NgspiceTable *ngspice_table) {
+
+ if (ngspice_table->ngspice_columns != NULL) {
+ guint len = ngspice_table->ngspice_columns->len;
+
+ for (int i = 0; i < len; i++) {
+ NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[i];
+ if (column != NULL)
+ g_array_free(column->data, TRUE);
}
- fgets (buf, 255, priv->inputfp);
- found = FALSE;
- while ((fgets (buf, 255, priv->inputfp) != NULL) && !found) {
- gint k=0;
- if (strlen (buf)<= 2) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- }
- tmp=&buf[0];
- variables = get_variables (tmp, &k);
- for (i = 0; i < m; i++) {
- val[i]=g_ascii_strtod (variables[i+1].name, NULL);
- val_tmp2[i] = g_array_append_val (val_tmp2[i], val[i]);
- if (val[i] < sdata->min_data[i+n])
- sdata->min_data[i+n-1] = val[i];
- if (val[i] > sdata->max_data[i+n])
- sdata->max_data[i+n-1] = val[i];
+
+ g_ptr_array_free(ngspice_table->ngspice_columns, TRUE);
+ }
+
+ if (ngspice_table->current_variables != NULL)
+ g_array_free(ngspice_table->current_variables, TRUE);
+
+ g_free(ngspice_table);
+}
+
+/**
+ * Converts "x...x#branch" to "I(x...x)".
+ *
+ * Let "x...x" be the name of a part in the ngspice netlist,
+ * then the current variable (current, that flows through
+ * that part) of that part is named
+ * "x...x#branch" in ngspice. To shorten the name and make
+ * it prettier, the name will be displayed as "I(x...x)"
+ * in Oregano (analogous to V(node_nr)).
+ */
+static void convert_variable_name(gchar **variable) {
+ gchar **splitted = g_regex_split_simple("\\#branch", *variable, 0, 0);
+ g_free(*variable);
+ *variable = g_strdup_printf("I(%s)", *splitted);
+ g_strfreev(splitted);
+}
+
+/**
+ * Creates and appends new columns to the table, if there are new variables.
+ * The referenced columns are now the newly added columns.
+ *
+ * @predicted_size: The predicted end size of the new columns. It is assumed
+ * that the new columns will have the same size.
+ */
+static void ngspice_table_new_columns(NgspiceTable *ngspice_table, gchar **variables, guint predicted_size) {
+ if (ngspice_table->ngspice_columns->len > 0) {
+ NgspiceColumn *column = (NgspiceColumn *)ngspice_table->ngspice_columns->pdata[0];
+ predicted_size = column->data->len;
+ }
+
+ g_array_free(ngspice_table->current_variables, TRUE);
+ ngspice_table->current_variables = g_array_new(TRUE, TRUE, sizeof(guint));
+
+ for (gchar **variable = variables; *variable != NULL && **variable != '\n' && **variable != 0; variable++) {
+ if (g_str_has_suffix(*variable, "#branch"))
+ convert_variable_name(variable);
+ int i;
+ for (i = 0; i < ngspice_table->ngspice_columns->len; i++) {
+ if (!strcmp(*variable, ((NgspiceColumn *)ngspice_table->ngspice_columns->pdata[i])->name->str))
+ break;
+ }
+ if (i == ngspice_table->ngspice_columns->len) {
+ NgspiceColumn *new_column = ngspice_column_new(*variable, predicted_size);
+ g_ptr_array_add(ngspice_table->ngspice_columns, new_column);
+ }
+ g_array_append_val(ngspice_table->current_variables, i);
+ }
+}
+
+/**
+ * Appends a split line to the end of the current referenced columns.
+ */
+static void ngspice_table_add_data(NgspiceTable *ngspice_table, gchar **data) {
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(*data != NULL);
+ if (**data == 0)
+ return;
+ g_return_if_fail(ngspice_table != NULL);
+
+ guint64 index = g_ascii_strtoull(*data, NULL, 10);
+ for (int i = 0; data[i] != NULL && data[i][0] != 0 && data[i][0] != '\n' && i < ngspice_table->current_variables->len; i++) {
+ guint column_index = g_array_index(ngspice_table->current_variables, guint, i);
+ NgspiceColumn *column = (NgspiceColumn*)(ngspice_table->ngspice_columns->pdata[column_index]);
+ if (column->data->len > index) {
+ continue;//assert equal
+ }
+ gdouble new_content = g_ascii_strtod(data[i], NULL);
+ g_array_append_val(column->data, new_content);
+ if (new_content < column->min)
+ column->min = new_content;
+ if (new_content > column->max)
+ column->max = new_content;
+ }
+}
+
+/**
+ * Counts the number of different guints. If a certain
+ * guint occurs more than once, it is counted as one.
+ */
+static guint get_real_len(GArray *array_guint) {
+ guint ret_val = 0;
+ for (guint i = 0; i < array_guint->len; i++) {
+ ret_val++;
+ for (guint j = 0; j < i; j++) {
+ if (g_array_index(array_guint, guint, i) == g_array_index(array_guint, guint, j)) {
+ ret_val--;
+ break;
}
- if (val[0] >= ANALYSIS (sdata)->transient.sim_length) found = TRUE;
}
- if (n + m -1 < nodes_nb + 1) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- variables = get_variables (buf, &p);
- p=p-1;
-
- for (i=1; i<p; i++) {
- sdata->var_names[i+n+m-2] = g_strdup (variables[i+1].name);
- sdata->var_units[i+n+m-2] = g_strdup (_("voltage"));
+ }
+
+ return ret_val;
+}
+
+/**
+ * Returns the index that is currently parsed.
+ *
+ * The first referenced column is the string-index column,
+ * the second referenced column is the time. The index and
+ * the time column can already be filled up by earlier
+ * iterations, so the length of the third referenced column
+ * represents the index that is currently parsed.
+ */
+static guint get_current_index(NgspiceTable *ngspice_table) {
+ guint column_nr = g_array_index(ngspice_table->current_variables, guint, 2);
+ NgspiceColumn *column = g_ptr_array_index(ngspice_table->ngspice_columns, column_nr);
+ return column->data->len;
+}
+
+typedef struct {
+ NgspiceTable *table;
+ ThreadPipe *pipe;
+ gboolean is_cancel;
+} ParseTransientAnalysisReturnResources;
+
+/**
+ * @resources: caller frees
+ */
+static ParseTransientAnalysisReturnResources parse_transient_analysis_resources (NgspiceAnalysisResources *resources)
+{
+ gchar **buf = &resources->buf;
+ const SimSettings *sim_settings = resources->sim_settings;
+ guint *num_analysis = resources->num_analysis;
+ ProgressResources *progress_reader = resources->progress_reader;
+ guint64 no_of_data_rows = resources->no_of_data_rows_transient;
+ guint no_of_variables = resources->no_of_variables;
+
+
+ enum STATE {
+ NGSPICE_ANALYSIS_STATE_READ_DATA,
+ NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END,
+ NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END,
+ NGSPICE_ANALYSIS_STATE_DATA_END,
+ NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW,
+ NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD
+ };
+
+ g_mutex_lock(&progress_reader->progress_mutex);
+ progress_reader->progress = 0;
+ progress_reader->time = g_get_monotonic_time();
+ g_mutex_unlock(&progress_reader->progress_mutex);
+
+ gsize size;
+
+ NgspiceTable *ngspice_table = ngspice_table_new();
+
+ ParseTransientAnalysisReturnResources ret_val;
+ ret_val.table = ngspice_table;
+ ret_val.pipe = resources->pipe;
+ ret_val.is_cancel = TRUE;
+
+ enum STATE state = NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END;
+
+ guint i = 0;
+
+ do {
+ if (i % 50 == 0 && cancel_info_is_cancel(resources->cancel_info))
+ return ret_val;
+
+ switch (state) {
+ case NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW:
+ {
+ gchar **splitted_line = g_regex_split_simple(" +", *buf, 0, 0);
+
+ ngspice_table_new_columns(ngspice_table, splitted_line, no_of_data_rows);
+
+ g_strfreev(splitted_line);
+
+ state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD;
+ break;
}
- fgets (buf, 255, priv->inputfp);
- found = FALSE;
- while ((fgets (buf, 255, priv->inputfp) != NULL) && !found) {
- gint k=0;
- if (strlen (buf)<= 2) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- }
- tmp=&buf[0];
- variables = get_variables (tmp, &k);
- for (i = 0; i < p; i++) {
- val[i]=g_ascii_strtod (variables[i+1].name, NULL);
- val_tmp3[i] = g_array_append_val (val_tmp3[i], val[i]);
- if (val[i] < sdata->min_data[i+n+m-3])
- sdata->min_data[i+n+m-3] = val[i];
- if (val[i] > sdata->max_data[i+n+m-3])
- sdata->max_data[i+n+m-3] = val[i];
+ case NGSPICE_ANALYSIS_STATE_READ_DATA:
+ {
+ gchar **splitted_line = g_regex_split_simple("\\t+|-{2,}", *buf, 0, 0);
+
+ ngspice_table_add_data(ngspice_table, splitted_line);
+
+ g_strfreev(splitted_line);
+
+ if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
+ return ret_val;
+
+ switch (*buf[0]) {
+ case '\f':{
+ // estimate progress begin
+ guint len_of_current_variables = get_real_len(ngspice_table->current_variables) - 2;
+ guint len_of_current_columns = ngspice_table->ngspice_columns->len - 2;
+ guint count_of_variables_already_finished = len_of_current_columns - len_of_current_variables;
+ g_mutex_lock(&progress_reader->progress_mutex);
+ progress_reader->progress = (double)count_of_variables_already_finished / (double)no_of_variables +
+ (double)len_of_current_variables / (double)no_of_variables *
+ (double)get_current_index(ngspice_table) / (double)no_of_data_rows;
+ progress_reader->time = g_get_monotonic_time();
+ g_mutex_unlock(&progress_reader->progress_mutex);
+ // estimate progress end
+
+ state = NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END;
+ break;}
+ case '\n':
+ state = NGSPICE_ANALYSIS_STATE_DATA_END;
+ break;
}
- if (val[0] >= ANALYSIS (sdata)->transient.sim_length) found = TRUE;
+ break;
}
- }
- }
- found = FALSE;
- while (!found) {
- gdouble val0 = 0.;
- for (i=0; i<nodes_nb+1; i++) {
- // 0 = time
- // From node 1 to node 3
- if (i < n) {
- gdouble val=0;
- val = g_array_index (val_tmp1[i], gdouble, sdata->got_points);
- if (i == 0) val0 = val;
- sdata->data[i] = g_array_append_val (sdata->data[i], val);
+ case NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD:
+ {
+ if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
+ return ret_val;
+
+ if (*buf[0] != '-')
+ state = NGSPICE_ANALYSIS_STATE_READ_DATA;
+ break;
}
- // From node 4 to node 6
- else if (i < n+m-1) {
- gdouble val=0;
- val = g_array_index (val_tmp2[i-n+1], gdouble, sdata->got_points);
- sdata->data[i] = g_array_append_val (sdata->data[i], val);
+ case NGSPICE_ANALYSIS_STATE_DATA_SMALL_BLOCK_END:
+ {
+ if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
+ return ret_val;
+
+ switch (*buf[0]) {
+ case 'I':
+ state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_OLD;
+ break;
+ case ' ':
+ state = NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END;
+ break;
+ }
+ break;
}
- // From node 7 to node 9
- else {
- gdouble val=0;
- val = g_array_index (val_tmp3[i-n-m+2], gdouble, sdata->got_points);
- sdata->data[i] = g_array_append_val (sdata->data[i], val);
+ case NGSPICE_ANALYSIS_STATE_DATA_LARGE_BLOCK_END:
+ {
+ if ((ret_val.pipe = thread_pipe_pop(ret_val.pipe, (gpointer *)buf, &size)) == NULL)
+ return ret_val;
+
+ if (*buf[0] == 'I')
+ state = NGSPICE_ANALYSIS_STATE_READ_VARIABLES_NEW;
+ break;
}
+ case NGSPICE_ANALYSIS_STATE_DATA_END:
+ break;
}
- sdata->got_points++;
- sdata->got_var = nodes_nb+1;
- if (val0 >= ANALYSIS (sdata)->transient.sim_length) found = TRUE;
+ } while (state != NGSPICE_ANALYSIS_STATE_DATA_END);
+
+ ret_val.is_cancel = FALSE;
+
+ SimulationData *sdata = SIM_DATA (g_new0 (Analysis, 1));
+ sdata->type = ANALYSIS_TYPE_TRANSIENT;
+ sdata->functions = NULL;
+
+ gint nodes_nb = ngspice_table->ngspice_columns->len - 2;
+
+ ANALYSIS (sdata)->transient.sim_length =
+ sim_settings_get_trans_stop (sim_settings) - sim_settings_get_trans_start (sim_settings);
+ ANALYSIS (sdata)->transient.step_size = sim_settings_get_trans_step (sim_settings);
+
+ sdata->var_names = g_new0 (gchar *, nodes_nb + 1);
+ sdata->var_units = g_new0 (gchar *, nodes_nb + 1);
+ sdata->data = g_new0 (GArray *, nodes_nb + 1);
+ sdata->min_data = g_new (gdouble, nodes_nb + 1);
+ sdata->max_data = g_new (gdouble, nodes_nb + 1);
+
+ for (int i = 0; i < nodes_nb + 1; i++) {
+ NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[i+1];
+ sdata->var_names[i] = g_strdup(column->name->str);
+ sdata->var_units[i] = g_strdup(column->unit->str);
+ sdata->data[i] = column->data;
+ sdata->min_data[i] = column->min;
+ sdata->max_data[i] = column->max;
+
+ ngspice_table->ngspice_columns->pdata[i+1] = NULL;
+ }
+ sdata->n_variables = nodes_nb + 1;
+ NgspiceColumn *column = ngspice_table->ngspice_columns->pdata[0];
+ sdata->got_points = column->data->len;
+ sdata->got_var = nodes_nb + 1;
+
+ (*num_analysis)++;
+ *resources->analysis = g_list_append (*resources->analysis, sdata);
+
+ return ret_val;
+}
+
+static ThreadPipe *parse_transient_analysis (NgspiceAnalysisResources *resources) {
+ ParseTransientAnalysisReturnResources ret_res = parse_transient_analysis_resources(resources);
+
+ ngspice_table_destroy(ret_res.table);
+
+ if (ret_res.is_cancel && ret_res.pipe) {
+ thread_pipe_set_read_eof(ret_res.pipe);
+ ret_res.pipe = NULL;
}
+
+ return ret_res.pipe;
}
-void
-parse_fourier_analysis (OreganoNgSpice *ngspice, gchar * tmp)
+/**
+ * @resources: caller frees
+ */
+static ThreadPipe *parse_fourier_analysis (NgspiceAnalysisResources *resources)
{
+ ThreadPipe *pipe = resources->pipe;
+ gchar **buf = &resources->buf;
+ const SimSettings *sim_settings = resources->sim_settings;
+ GList **analysis = resources->analysis;
+ guint *num_analysis = resources->num_analysis;
+
static SimulationData *sdata;
static Analysis *data;
- OreganoNgSpicePriv *priv = ngspice->priv;
- SimSettings *sim_settings;
- static gchar buf[256];
- NGSPICE_Variable *variables;
- gint i, n=0, freq, j, k;
- gdouble val[10], mag[10][10];
+ gsize size;
+ gchar **variables;
+ gint i, n = 0, j, k;
+ gdouble val[3];
gchar **node_ids;
gchar *vout;
-
- sim_settings = (SimSettings *)schematic_get_sim_settings (priv->schematic);
-
+ NG_DEBUG ("FOURIER: result str\n>>>\n%s\n<<<", *buf);
- // New analysis
data = g_new0 (Analysis, 1);
sdata = SIM_DATA (data);
- priv->current = sdata;
- priv->analysis = g_list_append (priv->analysis, sdata);
- sdata->state = IN_VALUES;
+ sdata->type = ANALYSIS_TYPE_FOURIER;
sdata->functions = NULL;
- priv->num_analysis++;
- sdata->type = FOURIER;
- tmp = g_strchug (tmp);
- ANALYSIS (sdata)->fourier.freq =
- sim_settings_get_fourier_frequency (sim_settings);
+ g_strchug (*buf);
+ ANALYSIS (sdata)->fourier.freq = sim_settings_get_fourier_frequency (sim_settings);
+
vout = sim_settings_get_fourier_vout (sim_settings);
- node_ids = g_strsplit (g_strdup (vout), " ", 0);
- for (i=0; node_ids[i]!= NULL; i++) {}
- ANALYSIS (sdata)->fourier.nb_var = i+1;
+ node_ids = g_strsplit (vout, " ", 0);
+ for (i = 0; node_ids[i] != NULL; i++) {
+ }
+ g_strfreev (node_ids);
g_free (vout);
-
+ ANALYSIS (sdata)->fourier.nb_var = i + 1;
n = ANALYSIS (sdata)->fourier.nb_var;
sdata->n_variables = n;
- sdata->var_names = (char**) g_new0 (gpointer, n);
- sdata->var_units = (char**) g_new0 (gpointer, n);
- variables = get_variables (tmp, &k);
- sdata->var_names[0] = _("Frequency");
- sdata->var_names[1] = g_strdup (variables[3].name);
- for (i = 0; i < n; i++) {
- if (i == 0)
- sdata->var_units[i] = g_strdup (_("frequency"));
- else
- sdata->var_units[i] = g_strdup (_("voltage"));
- }
- sdata->state = IN_VALUES;
- sdata->got_points = 0;
- sdata->got_var = 0;
- sdata->data = (GArray**) g_new0 (gpointer, n);
-
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
+ sdata->var_names = (char **)g_new0 (gpointer, n);
+ sdata->var_units = (char **)g_new0 (gpointer, n);
+ sdata->var_names[0] = g_strdup ("Frequency");
+ sdata->var_units[0] = g_strdup (_ ("frequency"));
+
+ sdata->got_points = 0;
+ sdata->got_var = 0;
+
+ sdata->data = (GArray **)g_new0 (gpointer, n);
for (i = 0; i < n; i++)
- sdata->data[i] = g_array_new (TRUE, TRUE, sizeof (double));
-
+ sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
+
sdata->min_data = g_new (double, n);
sdata->max_data = g_new (double, n);
- // Read the data
- for (i=0; i<n; i++) {
- sdata->min_data[i] = G_MAXDOUBLE;;
+ for (i = 0; i < n; i++) {
+ sdata->min_data[i] = G_MAXDOUBLE;
sdata->max_data[i] = -G_MAXDOUBLE;
}
-
- for (j=0; j<10; j++) {
- fgets (buf, 255, priv->inputfp);
- sscanf (buf, "\t%d\t%d\t%lf\t%lf", &i, &freq, &val[0], &val[1]);
- mag[j][0] = (gdouble) freq;
- mag[j][1] = val[0];
- }
-
- for (j=2; j<n; j++) {
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- tmp = &buf[0];
- variables = get_variables (tmp, &k);
- sdata->var_names[j] = g_strdup (variables[3].name);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
-
- for (k=0; k<10; k++) {
- fgets (buf, 255, priv->inputfp);
- sscanf (buf, "\t%d\t%d\t%lf\t%lf", &i, &freq, &val[0], &val[1]);
- mag[k][j]=val[0];
+
+ // For each output voltage (plus the frequency for the x-axis),
+ // scan its data set
+ for (k = 1; k < n; k++) {
+ variables = get_variables (*buf, &i);
+ if (!variables)
+ return pipe;
+
+ // Skip data set header (4 lines)
+ for (i = 0; i < 4; i++)
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ sdata->var_names[k] = g_strdup_printf ("mag(%s)", variables[3]);
+ sdata->var_units[k] = g_strdup (_ ("voltage"));
+
+ // Scan data set for 10 harmonics
+ for (j = 0; j < 10; j++) {
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ if (!pipe)
+ return pipe;
+
+ sscanf (*buf, "\t%d\t%lf\t%lf\t%lf", &i, &val[0], &val[1], &val[2]);
+ if (k == 1) {
+ sdata->data[0] = g_array_append_val (sdata->data[0], val[0]);
+ if (val[0] < sdata->min_data[0])
+ sdata->min_data[0] = val[0];
+ if (val[0] > sdata->max_data[0])
+ sdata->max_data[0] = val[0];
+ sdata->data[1] = g_array_append_val (sdata->data[1], val[1]);
+ if (val[1] < sdata->min_data[1])
+ sdata->min_data[1] = val[1];
+ if (val[1] > sdata->max_data[1])
+ sdata->max_data[1] = val[1];
+ sdata->got_points = sdata->got_points + 2;
+ } else {
+ sdata->data[k] = g_array_append_val (sdata->data[k], val[1]);
+ if (val[1] < sdata->min_data[k])
+ sdata->min_data[k] = val[1];
+ if (val[1] > sdata->max_data[k])
+ sdata->max_data[k] = val[1];
+ sdata->got_points++;
+ }
}
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ if (!pipe)
+ return pipe;
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ if (!pipe)
+ return pipe;
+
+ }
+
+ sdata->got_var = n;
+
+ *analysis = g_list_append (*analysis, sdata);
+ (*num_analysis)++;
+
+ return pipe;
+}
+
+/**
+ * @resources: caller frees
+ */
+static ThreadPipe *parse_noise_analysis (NgspiceAnalysisResources *resources)
+{
+ ThreadPipe *pipe = resources->pipe;
+ gboolean is_vanilla = resources->is_vanilla;
+ gchar *scale, **variables, **buf = &resources->buf;
+ const SimSettings* const sim_settings = resources->sim_settings;
+ GList **analysis = resources->analysis;
+ guint *num_analysis = resources->num_analysis;
+ static SimulationData *sdata;
+ static Analysis *data;
+ gsize size;
+ gboolean found = FALSE;
+ gint i, n = 0, index = 0;
+ gdouble fstart, fstop, val[10];
+
+ NG_DEBUG ("NOISE: result str\n>>>\n%s\n<<<", *buf);
+
+ data = g_new0 (Analysis, 1);
+ sdata = SIM_DATA (data);
+ sdata->type = ANALYSIS_TYPE_NOISE;
+ sdata->functions = NULL;
+
+ ANALYSIS (sdata)->noise.sim_length = 1.;
+
+ ANALYSIS (sdata)->noise.start = fstart = sim_settings_get_noise_start (sim_settings);
+ ANALYSIS (sdata)->noise.stop = fstop = sim_settings_get_noise_stop (sim_settings);
+
+ scale = sim_settings_get_noise_type (sim_settings);
+ if (!g_ascii_strcasecmp (scale, "LIN")) {
+ ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings);
+ } else if (!g_ascii_strcasecmp (scale, "DEC")) {
+ ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings) * log10 (fstop / fstart);
+ } else if (!g_ascii_strcasecmp (scale, "OCT")) {
+ ANALYSIS (sdata)->noise.sim_length = (double) sim_settings_get_noise_npoints (sim_settings) * log10 (fstop / fstart) / log10 (2);
}
-
- for (i=0; i<n; i++) {
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ // Calculates the number of variables
+ variables = get_variables (*buf, &n);
+ if (!variables)
+ return pipe;
+
+ n = n - 1;
+ sdata->var_names = (char **)g_new0 (gpointer, 3);
+ sdata->var_units = (char **)g_new0 (gpointer, 3);
+ sdata->var_names[0] = g_strdup ("Frequency");
+ sdata->var_units[0] = g_strdup (_ ("frequency"));
+ sdata->var_names[1] = g_strdup ("Input Noise Spectrum");
+ sdata->var_units[1] = g_strdup (_ ("psd"));
+ sdata->var_names[2] = g_strdup ("Output Noise Spectrum");
+ sdata->var_units[2] = g_strdup (_ ("psd"));
+
+ sdata->n_variables = 3;
+ sdata->got_points = 0;
+ sdata->got_var = 0;
+ sdata->data = (GArray **)g_new0 (gpointer, 3);
+
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ for (i = 0; i < 3; i++)
+ sdata->data[i] = g_array_new (TRUE, TRUE, sizeof(double));
+
+ sdata->min_data = g_new (double, 3);
+ sdata->max_data = g_new (double, 3);
+
+ // Read the data
+ for (i = 0; i < 3; i++) {
sdata->min_data[i] = G_MAXDOUBLE;
sdata->max_data[i] = -G_MAXDOUBLE;
}
-
- for (j=0; j<10; j++) {
- for (i=0; i<n; i++) {
- sdata->data[i] = g_array_append_val (sdata->data[i], mag[j][i]);
- if (mag[j][i] < sdata->min_data[i])
- sdata->min_data[i] = mag[j][i];
- if (mag[j][i] > sdata->max_data[i])
- sdata->max_data[i] = mag[j][i];
- sdata->got_points++;
- sdata->got_var = n;
+ found = FALSE;
+ while (!found && ((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0)) {
+ if (strlen (*buf) <= 2) {
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ }
+
+ variables = get_variables (*buf, &i);
+ if (!variables)
+ return pipe;
+
+ index = atoi (variables[0]);
+ for (i = 0; i < 3; i++) {
+ val[i] = g_ascii_strtod (variables[i + 1], NULL);
+ sdata->data[i] = g_array_append_val (sdata->data[i], val[i]);
+ if (val[i] < sdata->min_data[i])
+ sdata->min_data[i] = val[i];
+ if (val[i] > sdata->max_data[i])
+ sdata->max_data[i] = val[i];
+ }
+ sdata->got_points++;
+
+ if (index >= ANALYSIS (sdata)->noise.sim_length - 1)
+ found = TRUE;
+ }
+
+ // Spice 3f5 is affected by a sort of bug and prints extra data
+ if (is_vanilla) {
+ while (((pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size)) != 0)) {
+ if (strlen (*buf) < 2)
+ break;
}
- NG_DEBUG (g_strdup_printf ("ngspice-analysis: mag[%d][0]=%lf\tmag[%d][1]=%lf\n", j, mag[j][0], j, mag[j][1]));
}
- return;
+
+ sdata->got_var = 3;
+
+ *analysis = g_list_append (*analysis, sdata);
+ (*num_analysis)++;
+
+ return pipe;
}
-void
-ngspice_parse (OreganoNgSpice *ngspice)
+/**
+ * Stores all the data coming through the given pipe to the given file.
+ * This is needed because in case of failure, ngspice prints additional
+ * error information to stdout.
+ *
+ * Maybe the user wants to analyze the ngspice output by external software.
+ */
+void ngspice_save (const gchar *path_to_file, ThreadPipe *pipe, CancelInfo *cancel_info)
{
- OreganoNgSpicePriv *priv = ngspice->priv;
- SimSettings *sim_settings;
- static gchar buf[256];
- gchar * tmp = NULL;
- gboolean found = FALSE;
- gint i, analysis_type = 11;
- gboolean transient_enabled = FALSE;
- gboolean fourier_enabled = FALSE;
- gboolean dc_enabled = FALSE;
- //gboolean ac_enabled = FALSE;
-
- sim_settings = (SimSettings *)schematic_get_sim_settings (priv->schematic);
-
- transient_enabled = sim_settings_get_trans (sim_settings);
- fourier_enabled = sim_settings_get_fourier (sim_settings);
- //ac_enabled = sim_settings_get_ac (sim_settings);
- dc_enabled = sim_settings_get_dc (sim_settings);
-
- priv->inputfp = fopen ("/tmp/netlist.lst", "r");
-
- fgets (buf, 255, priv->inputfp);
- fgets (buf, 255, priv->inputfp);
- while ((fgets (buf, 255, priv->inputfp) != NULL) && !found) {
- if (g_str_has_suffix (g_strdup (buf), SP_TITLE)) {
- found = TRUE;
- }
+ FILE *file = fopen(path_to_file, "w");
+ gpointer buf = NULL;
+ gsize size;
+
+ for (int i = 0; (pipe = thread_pipe_pop(pipe, &buf, &size)) != NULL; i++) {
+ if (size != 0)
+ fwrite(buf, 1, size, file);
+ /**
+ * cancel_info uses mutex operations, so it shouldn't be
+ * called to often.
+ */
+ if (i % 50 == 0 && cancel_info_is_cancel(cancel_info))
+ break;
}
- tmp = &buf[0];
- tmp = g_strchug (tmp);
- NG_DEBUG (g_strdup_printf ("0 buf = %s\n", buf));
+ fclose(file);
+ if (pipe != NULL)
+ thread_pipe_set_read_eof(pipe);
+}
- for (i = 0; analysis_names[i]; i++) {
- if (g_str_has_prefix (g_strdup (tmp), analysis_names[i])) {
- analysis_type = i;
+static gboolean get_analysis_type(gchar *buf_in, AnalysisType *type_out) {
+
+ int i = 0;
+ gchar *analysis_name = oregano_engine_get_analysis_name_by_type(i);
+ while (analysis_name) {
+ if (g_str_has_prefix (buf_in, analysis_name)) {
+ *type_out = i;
+ g_free(analysis_name);
+ return TRUE;
}
+ g_free(analysis_name);
+
+ i++;
+ analysis_name = oregano_engine_get_analysis_name_by_type(i);
}
- if (!analysis_names[analysis_type]) {
- oregano_warning (_("No analysis found"));
- return;
+ return FALSE;
+}
+
+static guint64 parse_no_of_data_rows(gchar *line) {
+ gchar **splitted = g_regex_split_simple("No\\. of Data Rows \\: \\D*(\\d+)\\n", line, 0, 0);
+ guint64 no_of_data_rows = g_ascii_strtoull(splitted[1], NULL, 10);
+ g_strfreev(splitted);
+
+ return no_of_data_rows;
+}
+
+static guint parse_no_of_variables(ThreadPipe *pipe, gchar **buf) {
+ gsize size;
+
+ for (int i = 0; i < 5; i++)
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+
+ guint no_of_variables = 0;
+ while (**buf != '\n') {
+ no_of_variables++;
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
}
- if (transient_enabled) {
- if (g_str_has_prefix (analysis_names[analysis_type],
- "Transient Analysis")) {
- parse_transient_analysis (ngspice, buf);
+ return no_of_variables;
+}
+
+/**
+ * @resources: caller frees
+ */
+void ngspice_analysis (NgspiceAnalysisResources *resources)
+{
+ ThreadPipe *pipe = resources->pipe;
+ const SimSettings *sim_settings = resources->sim_settings;
+ AnalysisTypeShared *current = resources->current;
+ gboolean is_vanilla = resources->is_vanilla;
+ gchar **buf = &resources->buf;
+ gsize size;
+ gboolean end_of_output;
+ gboolean transient_enabled = sim_settings_get_trans (sim_settings);
+ gboolean fourier_enabled = sim_settings_get_fourier (sim_settings);
+ gboolean dc_enabled = sim_settings_get_dc (sim_settings);
+ gboolean ac_enabled = sim_settings_get_ac (sim_settings);
+ gboolean noise_enabled = sim_settings_get_noise (sim_settings);
+
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ if (!is_vanilla) {
+ // Get the number of AC Analysis data rows
+ while (ac_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+ }
+ if (ac_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
+ resources->no_of_data_rows_ac = parse_no_of_data_rows(*buf);
+
+ if (ac_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ // Get the number of DC Analysis data rows
+ while (dc_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
- else {
- oregano_warning (_("Transient analysis expected not found"));
+ if (dc_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
+ resources->no_of_data_rows_dc = parse_no_of_data_rows(*buf);
+
+ if (dc_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ // Get the number of Operating Point Analysis data rows
+ while (!g_str_has_prefix (*buf, "No. of Data Rows : ")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
- }
-
- fgets (buf, 255, priv->inputfp);
- NG_DEBUG (g_strdup_printf ("1 buf = %s\n", buf));
- tmp = &buf[0];
- tmp = g_strchug (tmp);
-
- analysis_type = ANALYSIS_UNKNOWN;
- for (i = 0; analysis_names[i]; i++) {
- if (g_str_has_prefix (g_strdup (tmp), analysis_names[i])) {
- analysis_type = i;
+ if (g_str_has_prefix(*buf, "No. of Data Rows : "))
+ resources->no_of_data_rows_op = parse_no_of_data_rows(*buf);
+
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ // Get the number of Transient Analysis variables
+ while (transient_enabled && !g_str_has_prefix (*buf, "Initial Transient Solution")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
- }
- if (fourier_enabled) {
- if (g_str_has_prefix(analysis_names[analysis_type], "Fourier analysis")) {
- parse_fourier_analysis (ngspice, buf);
+ if (transient_enabled && g_str_has_prefix(*buf, "Initial Transient Solution"))
+ resources->no_of_variables = parse_no_of_variables(pipe, buf);
+
+ if (transient_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ // Get the number of Transient Analysis data rows
+ while (transient_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
- else {
- oregano_warning (_("Fourier analysis expected not found"));
+ if (transient_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
+ resources->no_of_data_rows_transient = parse_no_of_data_rows(*buf);
+
+ if (transient_enabled && thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+
+ // Get the number of Noise Analysis data rows
+ while (noise_enabled && !g_str_has_prefix (*buf, "No. of Data Rows : ")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
- }
- fgets (buf, 255, priv->inputfp);
- NG_DEBUG (g_strdup_printf ("2 buf = %s\n", buf));
- tmp = &buf[0];
- tmp = g_strchug (tmp);
-
- analysis_type = ANALYSIS_UNKNOWN;
- for (i = 0; analysis_names[i]; i++) {
- if (g_str_has_prefix (g_strdup (tmp), analysis_names[i])) {
- analysis_type = i;
+ if (noise_enabled && g_str_has_prefix(*buf, "No. of Data Rows : "))
+ resources->no_of_data_rows_noise = parse_no_of_data_rows(*buf);
+ } else {
+ while (!g_str_has_prefix (*buf, "Operating point information:")) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
}
}
- if (dc_enabled) {
- if (g_str_has_prefix(analysis_names[analysis_type], "DC transfer characteristic")) {
- parse_dc_analysis (ngspice, buf);
+
+ while (!g_str_has_suffix (*buf, SP_TITLE)) {
+ if (thread_pipe_pop(pipe, (gpointer *)buf, &size) == NULL)
+ return;
+ }
+
+ end_of_output = FALSE;
+ for (int i = 0; transient_enabled || fourier_enabled || dc_enabled || ac_enabled || noise_enabled; i++) {
+
+ AnalysisType analysis_type = ANALYSIS_TYPE_NONE;
+
+ do {
+ pipe = thread_pipe_pop(pipe, (gpointer *)buf, &size);
+ g_strstrip (*buf);
+ if (!g_ascii_strncasecmp (*buf, "CPU time", 8))
+ end_of_output = TRUE;
+ NG_DEBUG ("%d buf = %s", i, *buf);
+ } while (pipe != NULL && !end_of_output && (*buf[0] == '*' || *buf[0] == '\0'));
+
+ // The simulation has finished: no more analysis to parse
+ if (end_of_output)
+ break;
+
+ if (!get_analysis_type(*buf, &analysis_type) && i == 0) {
+ oregano_warning ("No analysis found");
+ break;
}
- else {
- oregano_warning (_("DC Sweep expected but not found"));
+
+ gboolean unexpected_analysis_found = FALSE;
+
+ g_mutex_lock(&current->mutex);
+ current->type = analysis_type;
+ g_mutex_unlock(&current->mutex);
+
+ switch (analysis_type) {
+ case ANALYSIS_TYPE_TRANSIENT:
+ pipe = parse_transient_analysis (resources);
+ transient_enabled = FALSE;
+ break;
+ case ANALYSIS_TYPE_FOURIER:
+ pipe = parse_fourier_analysis (resources);
+ fourier_enabled = FALSE;
+ break;
+ case ANALYSIS_TYPE_DC_TRANSFER:
+ pipe = parse_dc_analysis (resources);
+ dc_enabled = FALSE;
+ break;
+ case ANALYSIS_TYPE_AC:
+ pipe = parse_ac_analysis (resources);
+ ac_enabled = FALSE;
+ break;
+ case ANALYSIS_TYPE_NOISE:
+ pipe = parse_noise_analysis (resources);
+ noise_enabled = FALSE;
+ break;
+ default:
+ oregano_warning ("Unexpected analysis found");
+ unexpected_analysis_found = TRUE;
+ break;
}
+
+ g_mutex_lock(&current->mutex);
+ current->type = ANALYSIS_TYPE_NONE;
+ g_mutex_unlock(&current->mutex);
+
+ if (unexpected_analysis_found || pipe == NULL)
+ break;
}
-
- fclose (priv->inputfp);
+
+ if (pipe != NULL)
+ thread_pipe_set_read_eof(pipe);
+
+ resources->pipe = NULL;
}
diff --git a/src/engines/ngspice-analysis.h b/src/engines/ngspice-analysis.h
index 658be41..171b894 100644
--- a/src/engines/ngspice-analysis.h
+++ b/src/engines/ngspice-analysis.h
@@ -4,12 +4,14 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,8 +25,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NGSPICE_ANALYSIS_H
@@ -35,37 +37,80 @@
#include <sys/wait.h>
#include <ctype.h>
#include <glib/gi18n.h>
+#include "../tools/thread-pipe.h"
+#include "../tools/cancel-info.h"
#include "ngspice.h"
#include "netlist-helper.h"
#include "dialogs.h"
#include "engine-internal.h"
#include "ngspice.h"
+/*
+ * The file buffer size (recommended value
+ * is 512 bytes).
+ */
+#define BSIZE_SP 512
+
+/**
+ * Progress is a shared variable between GUI thread
+ * that displays the progress bar and working thread
+ * which executes the heavy work.
+ */
+typedef struct {
+ gdouble progress;
+ // time (from g_get_monotonic_time) of the last writing access
+ gint64 time;
+ GMutex progress_mutex;
+} ProgressResources;
+
+/**
+ * AnalysisType is a shared variable between progress
+ * bar displaying GUI thread and the working thread.
+ */
+typedef struct {
+ AnalysisType type;
+ GMutex mutex;
+} AnalysisTypeShared;
+
+typedef struct {
+ ThreadPipe *pipe;
+ gchar *buf;
+ gboolean is_vanilla;
+ const SimSettings* sim_settings;
+ AnalysisTypeShared *current;
+ GList **analysis;
+ guint *num_analysis;
+ ProgressResources *progress_reader;
+ guint64 no_of_data_rows_ac;
+ guint64 no_of_data_rows_dc;
+ guint64 no_of_data_rows_op;
+ guint64 no_of_data_rows_transient;
+ guint64 no_of_data_rows_noise;
+ guint no_of_variables;
+ CancelInfo *cancel_info;
+} NgspiceAnalysisResources;
+
// Parser STATUS
-struct _OreganoNgSpicePriv {
- GPid child_pid;
- gint child_stdout;
- gint child_error;
- GIOChannel *child_iochannel;
- GIOChannel *child_ioerror;
- gint child_iochannel_watch;
- gint child_ioerror_watch;
- Schematic *schematic;
+struct _OreganoNgSpicePriv
+{
+ gboolean is_vanilla;
+
+ GPid child_pid;
+
+ Schematic *schematic;
+
+ gboolean aborted;
+ CancelInfo *cancel_info;
- gboolean aborted;
+ GList *analysis;
+ guint num_analysis;
+ AnalysisTypeShared current;
- GList *analysis;
- gint num_analysis;
- SimulationData *current;
- double progress;
- gboolean char_last_newline;
- guint status;
- guint buf_count;
- // Added to store ngspice output into a file
- // input for oregano...
- FILE *inputfp;
+ ProgressResources progress_ngspice;
+ ProgressResources progress_reader;
};
-void ngspice_parse (OreganoNgSpice *ngspice);
+void ngspice_analysis (NgspiceAnalysisResources *resources);
+void ngspice_save (const gchar *path_to_file, ThreadPipe *pipe, CancelInfo *cancel_info);
#endif
diff --git a/src/engines/ngspice-watcher.c b/src/engines/ngspice-watcher.c
new file mode 100644
index 0000000..417ab74
--- /dev/null
+++ b/src/engines/ngspice-watcher.c
@@ -0,0 +1,715 @@
+/*
+ * ngspice-watcher.c
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <math.h>
+
+#include "../tools/thread-pipe.h"
+#include "ngspice.h"
+#include "ngspice-analysis.h"
+#include "../log-interface.h"
+#include "ngspice-watcher.h"
+
+enum ERROR_STATE {
+ ERROR_STATE_NO_ERROR,
+ ERROR_STATE_NO_SUCH_FILE_OR_DIRECTORY,
+ ERROR_STATE_ERROR_IN_NETLIST
+};
+
+//data wrapper
+typedef struct {
+ GMutex mutex;
+ GCond cond;
+ gboolean boolean;
+} IsNgspiceStderrDestroyed;
+
+//data wrapper
+typedef struct {
+ gchar *path_to_file;
+ ThreadPipe *pipe;
+ CancelInfo *cancel_info;
+} NgSpiceSaverResources;
+
+//data wrapper
+typedef struct {
+ ThreadPipe *thread_pipe_worker;
+ ThreadPipe *thread_pipe_saver;
+} NgSpiceWatchForkResources;
+
+//data wrapper
+typedef struct {
+ NgSpiceWatchForkResources ngspice_watch_fork_resources;
+ guint cancel_info_count;
+ CancelInfo *cancel_info;
+} NgSpiceWatchSTDOUTResources;
+
+//data wrapper
+typedef struct {
+ ProgressResources *progress_ngspice;
+ LogInterface log;
+ const SimSettings *sim_settings;
+ enum ERROR_STATE *error_state;
+ IsNgspiceStderrDestroyed *is_ngspice_stderr_destroyed;
+} NgSpiceWatchSTDERRResources;
+
+//data wrapper
+typedef struct {
+ GThread *worker;
+ GThread *saver;
+ LogInterface log;
+ const void* emit_instance;
+ GPid *child_pid;
+ gboolean *aborted;
+ guint *num_analysis;
+ GMainLoop *main_loop;
+ gchar *netlist_file;
+ gchar *ngspice_result_file;
+ enum ERROR_STATE *error_state;
+ IsNgspiceStderrDestroyed *is_ngspice_stderr_destroyed;
+ CancelInfo *cancel_info;
+} NgSpiceWatcherWatchNgSpiceResources;
+
+/**
+ * Wraps the heavy work of a function into a thread.
+ */
+static gpointer ngspice_worker (NgspiceAnalysisResources *resources) {
+
+ ngspice_analysis(resources);
+
+ cancel_info_unsubscribe(resources->cancel_info);
+ g_free(resources);
+
+ return NULL;
+}
+
+/**
+ * Wraps the heavy work of a function into a thread.
+ */
+static gpointer ngspice_saver (NgSpiceSaverResources *resources)
+{
+ ngspice_save(resources->path_to_file, resources->pipe, resources->cancel_info);
+
+ cancel_info_unsubscribe(resources->cancel_info);
+ g_free(resources->path_to_file);
+ g_free(resources);
+
+ return NULL;
+}
+
+/**
+ * returns the number of strings in a NULL terminated array of strings
+ */
+static int get_count(gchar** array) {
+ int i = 0;
+ while (array[i] != NULL)
+ i++;
+ return i;
+}
+
+/**
+ * adds the line number followed by a colon and a space at the beginning of each line
+ */
+static void add_line_numbers(gchar **string) {
+ gchar **splitted = g_regex_split_simple("\\n", *string, 0, 0);
+ GString *new_string = g_string_new("");
+ //why -1? Because g_regex_split_simple adds one empty string too much at the end
+ //of the array.
+ int count = get_count(splitted) - 1;
+ int max_length = floor(log10((double) count)) + 1;
+ //splitted[i+1] != NULL (why not only i but i+1?) because g_regex_split_simple
+ //adds one empty string too much at the end of the array
+ for (int i = 0; splitted[i+1] != NULL; i++)
+ g_string_append_printf(new_string, "%0*d: %s\n", max_length, i+1, splitted[i]);
+ //remove the last newline, which was added additionally
+ new_string = g_string_truncate(new_string, new_string->len - 1);
+ g_free(*string);
+ *string = new_string->str;
+ g_string_free(new_string, FALSE);
+}
+
+//data wrapper
+typedef struct {
+ const void* emit_instance;
+ gchar *signal_name;
+} NgspiceEmitData;
+
+/**
+ * Use this function to return the program main control flow to the
+ * main thread (which is the gui thread).
+ */
+static gboolean g_signal_emit_by_name_main_thread(NgspiceEmitData *data) {
+ const void* emit_instance = data->emit_instance;
+ gchar *signal_name = data->signal_name;
+ g_free(data);
+ g_signal_emit_by_name (G_OBJECT (emit_instance), signal_name);
+ g_free(signal_name);
+ return G_SOURCE_REMOVE;
+}
+
+/**
+ * main function of the ngspice watcher
+ */
+static gpointer ngspice_watcher_main(GMainLoop *main_loop) {
+ g_main_loop_run(main_loop);
+
+ // unrefs its GMainContext by 1
+ g_main_loop_unref(main_loop);
+
+ return NULL;
+}
+
+/**
+ * forks data to file and heap
+ */
+static void ngspice_watcher_fork_data(NgSpiceWatchForkResources *resources, gpointer data, gsize size) {
+ thread_pipe_push(resources->thread_pipe_worker, data, size);
+ /**
+ * size_in = size - 1, because the trailing 0 of the string should not
+ * be written to file.
+ */
+ thread_pipe_push(resources->thread_pipe_saver, data, size - 1);
+}
+
+/**
+ * forks eof to file-pipe and heap-pipe
+ */
+static void ngspice_watcher_fork_eof(NgSpiceWatchForkResources *resources) {
+ thread_pipe_set_write_eof(resources->thread_pipe_worker);
+ thread_pipe_set_write_eof(resources->thread_pipe_saver);
+}
+
+/**
+ * Does not handle input resources.
+ */
+static gboolean ngspice_watcher_watch_stdout_resources(GIOChannel *channel, GIOCondition condition, NgSpiceWatchSTDOUTResources *resources) {
+ gchar *str_return = NULL;
+ gsize length;
+ gsize terminator_pos;
+ GError *error = NULL;
+
+ resources->cancel_info_count++;
+ if (resources->cancel_info_count % 50 == 0 && cancel_info_is_cancel(resources->cancel_info)) {
+ return G_SOURCE_REMOVE;
+ }
+
+ GIOStatus status = g_io_channel_read_line(channel, &str_return, &length, &terminator_pos, &error);
+ if (error) {
+ gchar *message = g_strdup_printf ("spice pipe stdout: %s - %i", error->message, error->code);
+ g_printf("%s", message);
+ g_free(message);
+ g_clear_error (&error);
+ } else if (status == G_IO_STATUS_NORMAL && length > 0) {
+ ngspice_watcher_fork_data(&resources->ngspice_watch_fork_resources, str_return, length + 1);
+ } else if (status == G_IO_STATUS_EOF) {
+ return G_SOURCE_REMOVE;
+ }
+ if (str_return)
+ g_free(str_return);
+ return G_SOURCE_CONTINUE;
+}
+
+/**
+ * ngspice reading source function
+ *
+ * reads the pipe (stdout) of ngspice
+ */
+static gboolean ngspice_watcher_watch_stdout(GIOChannel *channel, GIOCondition condition, NgSpiceWatchSTDOUTResources *resources) {
+
+ gboolean g_source_continue = ngspice_watcher_watch_stdout_resources(channel, condition, resources);
+
+ if (g_source_continue == G_SOURCE_CONTINUE)
+ return G_SOURCE_CONTINUE;
+
+ ngspice_watcher_fork_eof(&resources->ngspice_watch_fork_resources);
+ g_source_destroy(g_main_current_source());
+ cancel_info_unsubscribe(resources->cancel_info);
+ g_free(resources);
+ return G_SOURCE_REMOVE;
+}
+
+static void ngspice_watch_ngspice_resources_finalize(NgSpiceWatcherWatchNgSpiceResources *resources) {
+ g_source_destroy(g_main_current_source());
+ g_main_loop_quit(resources->main_loop);
+ g_spawn_close_pid (*resources->child_pid);
+ *resources->child_pid = 0;
+
+ g_free(resources->ngspice_result_file);
+ g_free(resources->netlist_file);
+ g_free(resources->error_state);
+ g_mutex_clear(&resources->is_ngspice_stderr_destroyed->mutex);
+ g_cond_clear(&resources->is_ngspice_stderr_destroyed->cond);
+ g_free(resources);
+}
+
+static void print_additional_info(LogInterface log, const gchar *ngspice_result_file, const gchar *netlist_file) {
+ log.log_append_error(log.log, "\n### spice output: ###\n\n");
+ gchar *ngspice_error_contents = NULL;
+ gsize ngspice_error_length;
+ GError *ngspice_error_read_error = NULL;
+
+ g_file_get_contents(ngspice_result_file, &ngspice_error_contents, &ngspice_error_length, &ngspice_error_read_error);
+ add_line_numbers(&ngspice_error_contents);
+ log.log_append_error(log.log, ngspice_error_contents);
+ g_free(ngspice_error_contents);
+ if (ngspice_error_read_error != NULL)
+ g_error_free(ngspice_error_read_error);
+
+ gchar *netlist_contents = NULL;
+ gsize netlist_lentgh;
+ GError *netlist_read_error = NULL;
+ g_file_get_contents(netlist_file, &netlist_contents, &netlist_lentgh, &netlist_read_error);
+ add_line_numbers(&netlist_contents);
+ log.log_append_error(log.log, "\n\n### netlist: ###\n\n");
+ log.log_append_error(log.log, netlist_contents);
+ g_free(netlist_contents);
+ if (netlist_read_error != NULL)
+ g_error_free(netlist_read_error);
+}
+
+enum NGSPICE_WATCHER_RETURN_VALUE {
+ NGSPICE_WATCHER_RETURN_VALUE_DONE,
+ NGSPICE_WATCHER_RETURN_VALUE_ABORTED,
+ NGSPICE_WATCHER_RETURN_VALUE_CANCELED
+};
+
+/**
+ * Does not care about input resource handling.
+ */
+static enum NGSPICE_WATCHER_RETURN_VALUE
+ngspice_watcher_watch_ngspice_resources (GPid pid, gint status, NgSpiceWatcherWatchNgSpiceResources *resources) {
+ GThread *worker = resources->worker;
+ GThread *saver = resources->saver;
+ LogInterface log = resources->log;
+ guint *num_analysis = resources->num_analysis;
+ enum ERROR_STATE *error_state = resources->error_state;
+ IsNgspiceStderrDestroyed *is_ngspice_stderr_destroyed = resources->is_ngspice_stderr_destroyed;
+
+ // wait for stderr to finish reading
+ g_mutex_lock(&is_ngspice_stderr_destroyed->mutex);
+ while (!is_ngspice_stderr_destroyed->boolean)
+ g_cond_wait(&is_ngspice_stderr_destroyed->cond, &is_ngspice_stderr_destroyed->mutex);
+ g_mutex_unlock(&is_ngspice_stderr_destroyed->mutex);
+
+ GError *exit_error = NULL;
+ gboolean exited_normal = g_spawn_check_exit_status(status, &exit_error);
+ if (exit_error != NULL)
+ g_error_free(exit_error);
+
+ g_thread_join(worker);
+
+ if (cancel_info_is_cancel(resources->cancel_info))
+ return NGSPICE_WATCHER_RETURN_VALUE_CANCELED;
+
+
+ if (!exited_normal) {
+ // check for exit via return in main, exit() or _exit() of the child, see man
+ // waitpid(2)
+ // WIFEXITED(wstatus)
+ // returns true if the child terminated normally, that is, by call‐
+ // ing exit(3) or _exit(2), or by returning from main().
+ if (!(WIFEXITED (status)))
+ log.log_append_error(log.log, "### spice exited with exception ###\n");
+ else
+ log.log_append_error(log.log, "### spice exited abnormally ###\n");
+
+ g_thread_join(saver);
+
+ switch (*error_state) {
+ case ERROR_STATE_NO_ERROR:
+ log.log_append_error(log.log, "### unknown error detected ###\n");
+ log.log_append_error(log.log, "The following information might help you to analyze the error.\n");
+
+ print_additional_info(log, resources->ngspice_result_file, resources->netlist_file);
+ break;
+ case ERROR_STATE_NO_SUCH_FILE_OR_DIRECTORY:
+ log.log_append_error(log.log, "spice could not simulate because netlist generation failed.\n");
+ break;
+ case ERROR_STATE_ERROR_IN_NETLIST:
+ log.log_append_error(log.log, "### netlist error detected ###\n");
+ log.log_append_error(log.log, "You made a mistake in the simulation settings or part properties.\n");
+ log.log_append_error(log.log, "The following information will help you to analyze the error.\n");
+
+ print_additional_info(log, resources->ngspice_result_file, resources->netlist_file);
+ break;
+ }
+
+ return NGSPICE_WATCHER_RETURN_VALUE_ABORTED;
+ }
+ // saver not needed any more. It could have been needed by error handling.
+ g_thread_unref(saver);
+
+ if (*num_analysis == 0) {
+ log.log_append_error(log.log, _("### Too few or none analysis found ###\n"));
+ return NGSPICE_WATCHER_RETURN_VALUE_ABORTED;
+ }
+
+ return NGSPICE_WATCHER_RETURN_VALUE_DONE;
+
+}
+
+/**
+ * function is called after ngspice process has died and the ngspice reading
+ * source function is finished with reading to
+ * - clean up,
+ * - check if all went good or fail,
+ * - wait for data conversion thread,
+ * - return the main program flow to the gui thread.
+ */
+static void ngspice_watcher_watch_ngspice (GPid pid, gint status, NgSpiceWatcherWatchNgSpiceResources *resources) {
+ enum NGSPICE_WATCHER_RETURN_VALUE ret_val = ngspice_watcher_watch_ngspice_resources (pid, status, resources);
+
+ NgspiceEmitData *emitData = g_malloc(sizeof(NgspiceEmitData));
+ emitData->emit_instance = resources->emit_instance;
+
+ switch(ret_val) {
+ case NGSPICE_WATCHER_RETURN_VALUE_ABORTED:
+ case NGSPICE_WATCHER_RETURN_VALUE_CANCELED:
+ emitData->signal_name = g_strdup("aborted");
+ *resources->aborted = TRUE;
+ break;
+ case NGSPICE_WATCHER_RETURN_VALUE_DONE:
+ emitData->signal_name = g_strdup("done");
+ break;
+ }
+
+ cancel_info_unsubscribe(resources->cancel_info);
+ ngspice_watch_ngspice_resources_finalize(resources);
+
+ /*
+ * return to main thread
+ *
+ * Don't return too early, because if you do, the ngspice
+ * object could be finalized but some resources depend on it.
+ */
+ g_main_context_invoke(NULL, (GSourceFunc)g_signal_emit_by_name_main_thread, emitData);
+}
+
+/**
+ * Extracts a progress number (time of transient analysis)
+ * out of a string (if existing) and saves it to the thread-shared
+ * progress variable.
+ */
+static void read_progress_ngspice(ProgressResources *progress_ngspice, gdouble progress_end, const gchar *line) {
+ if (!g_regex_match_simple("Reference value.*\\r", line, 0, 0))
+ return;
+ gchar **splitted = g_regex_split_simple(".* (.+)\\r", line, 0, 0);
+ gchar **ptr;
+ for (ptr = splitted; *ptr != NULL; ptr++)
+ if (**ptr != 0)
+ break;
+ if (*ptr != NULL) {
+ gdouble progress_absolute = g_ascii_strtod(*ptr, NULL);
+
+ g_mutex_lock(&progress_ngspice->progress_mutex);
+ progress_ngspice->progress = progress_absolute / progress_end;
+ if (g_str_has_suffix(line, "\r\n"))
+ progress_ngspice->progress = 1;
+ progress_ngspice->time = g_get_monotonic_time();
+ g_mutex_unlock(&progress_ngspice->progress_mutex);
+ }
+ g_strfreev(splitted);
+}
+
+/**
+ * Reads stderr of ngspice.
+ *
+ * stderr of ngspice might contain progress information.
+ */
+static gboolean ngspice_child_stderr_cb (GIOChannel *channel, GIOCondition condition,
+ NgSpiceWatchSTDERRResources *resources)
+{
+ LogInterface log = resources->log;
+ const SimSettings* const sim_settings = resources->sim_settings;
+ ProgressResources *progress_ngspice = resources->progress_ngspice;
+ enum ERROR_STATE *error_state = resources->error_state;
+ IsNgspiceStderrDestroyed *is_ngspice_stderr_destroyed = resources->is_ngspice_stderr_destroyed;
+
+ gchar *line = NULL;
+ gsize len, terminator;
+ GError *e = NULL;
+
+ GIOStatus status = g_io_channel_read_line (channel, &line, &len, &terminator, &e);
+ if (e) {
+ gchar *message = g_strdup_printf("spice pipe stderr: %s - %i", e->message, e->code);
+ log.log_append_error(log.log, message);
+ g_free(message);
+ g_clear_error (&e);
+ } else if (status == G_IO_STATUS_NORMAL && len > 0) {
+ log.log_append_error(log.log, line);
+
+ if (g_str_has_suffix(line, ": No such file or directory\n"))
+ *error_state = ERROR_STATE_NO_SUCH_FILE_OR_DIRECTORY;
+ if (g_str_equal(line, "spice stopped due to error, no simulation run!\n"))
+ *error_state = ERROR_STATE_ERROR_IN_NETLIST;
+
+ gdouble progress_end = sim_settings_get_trans_stop(sim_settings);
+ read_progress_ngspice(progress_ngspice, progress_end, line);
+ } else if (status == G_IO_STATUS_EOF) {
+ g_source_destroy(g_main_current_source());
+ g_free(resources);
+
+ // emit signal, that stderr reading has finished
+ g_mutex_lock(&is_ngspice_stderr_destroyed->mutex);
+ is_ngspice_stderr_destroyed->boolean = TRUE;
+ g_cond_signal(&is_ngspice_stderr_destroyed->cond);
+ g_mutex_unlock(&is_ngspice_stderr_destroyed->mutex);
+
+ return G_SOURCE_REMOVE;
+ }
+ if (line)
+ g_free (line);
+
+ return G_SOURCE_CONTINUE;
+}
+
+/**
+ * @resources: caller frees
+ *
+ * Prepares data structures to launch some threads and finally launches them.
+ *
+ * The launched threads are:
+ * - process ngspice
+ * - thread watcher
+ * - thread saver
+ * - thread worker
+ *
+ * As you should know ngspice is the program that actually simulates the simulation.
+ *
+ * The watcher thread handles stdout- and death-events of the ngspice process.
+ * stdout data is forked to the threads "saver" and "worker".
+ * As response to the death-event of ngspice, the watcher
+ * - cleans the field of war,
+ * - checks if all went good and creates error messages if not all went good,
+ * - waits for the worker to finish work,
+ * - finally returns the main program flow to the gui thread.
+ *
+ * The stderr-events are handled by the main (gui) thread, because it is not heavy work.
+ * Furthermore additionally shared variables can be avoided.
+ *
+ * The saver saves the data to SSD/HDD (temporary folder). It is needed to create
+ * good error messages in case of failure. Besides of that the user can analyze
+ * the data with external/other programs.
+ *
+ * The worker parses the stream of data, interprets and converts it to structured data
+ * so it can be plotted by gui.
+ */
+void ngspice_watcher_build_and_launch(const NgspiceWatcherBuildAndLaunchResources *resources) {
+ LogInterface log = resources->log;
+ const SimSettings* const sim_settings = resources->sim_settings;
+ gboolean is_vanilla = resources->is_vanilla;
+ GPid *child_pid = resources->child_pid;
+ gboolean *aborted = resources->aborted;
+ const void* emit_instance = resources->emit_instance;
+ guint *num_analysis = resources->num_analysis;
+ ProgressResources *progress_ngspice = resources->progress_ngspice;
+ ProgressResources *progress_reader = resources->progress_reader;
+ GList **analysis = resources->analysis;
+ AnalysisTypeShared *current = resources->current;
+ GError *e = NULL;
+
+ char *argv[] = {NULL, "-b", resources->netlist_file, NULL};
+
+ if (is_vanilla)
+ argv[0] = SPICE_EXE;
+ else
+ argv[0] = NGSPICE_EXE;
+
+ gint ngspice_stdout_fd;
+ gint ngspice_stderr_fd;
+ // Launch ngspice
+ if (!g_spawn_async_with_pipes (NULL, // Working directory
+ argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL,
+ NULL, child_pid,
+ NULL, // STDIN
+ &ngspice_stdout_fd, // STDOUT
+ &ngspice_stderr_fd, // STDERR
+ &e)) {
+
+ *aborted = TRUE;
+ log.log_append_error(log.log, _("Unable to execute NgSpice."));
+ g_signal_emit_by_name (G_OBJECT (emit_instance), "aborted");
+ g_clear_error (&e);
+ return;
+
+ }
+
+ // synchronizes stderr listener with is_ngspice_finished listener (needed for error handling)
+ IsNgspiceStderrDestroyed *is_ngspice_stderr_destroyed = g_new0(IsNgspiceStderrDestroyed, 1);
+ g_mutex_init(&is_ngspice_stderr_destroyed->mutex);
+ g_cond_init(&is_ngspice_stderr_destroyed->cond);
+ is_ngspice_stderr_destroyed->boolean = FALSE;
+
+ // variable needed for error handling
+ enum ERROR_STATE *error_state = g_new0(enum ERROR_STATE, 1);
+
+ GMainContext *forker_context = g_main_context_new();
+ GMainLoop *forker_main_loop = g_main_loop_new(forker_context, FALSE);
+ g_main_context_unref(forker_context);
+
+ // Create pipes to fork the stdout data of ngspice
+ ThreadPipe *thread_pipe_worker = thread_pipe_new(20, 2048);
+ ThreadPipe *thread_pipe_saver = thread_pipe_new(20, 2048);
+
+ /**
+ * Launch analyzer
+ */
+ NgspiceAnalysisResources *ngspice_worker_resources = g_new0(NgspiceAnalysisResources, 1);
+ ngspice_worker_resources->analysis = analysis;
+ ngspice_worker_resources->buf = NULL;
+ ngspice_worker_resources->is_vanilla = is_vanilla;
+ ngspice_worker_resources->current = current;
+ ngspice_worker_resources->no_of_data_rows_ac = 0;
+ ngspice_worker_resources->no_of_data_rows_dc = 0;
+ ngspice_worker_resources->no_of_data_rows_op = 0;
+ ngspice_worker_resources->no_of_data_rows_transient = 0;
+ ngspice_worker_resources->no_of_data_rows_noise = 0;
+ ngspice_worker_resources->no_of_variables = 0;
+ ngspice_worker_resources->num_analysis = num_analysis;
+ ngspice_worker_resources->pipe = thread_pipe_worker;
+ ngspice_worker_resources->progress_reader = progress_reader;
+ ngspice_worker_resources->sim_settings = sim_settings;
+ ngspice_worker_resources->cancel_info = resources->cancel_info;
+ cancel_info_subscribe(ngspice_worker_resources->cancel_info);
+
+ GThread *worker = g_thread_new("spice worker", (GThreadFunc)ngspice_worker, ngspice_worker_resources);
+
+ /**
+ * Launch output saver
+ */
+ NgSpiceSaverResources *ngspice_saver_resources = g_new0(NgSpiceSaverResources, 1);
+ ngspice_saver_resources->path_to_file = g_strdup(resources->ngspice_result_file);
+ ngspice_saver_resources->pipe = thread_pipe_saver;
+ ngspice_saver_resources->cancel_info = resources->cancel_info;
+ cancel_info_subscribe(ngspice_saver_resources->cancel_info);
+
+ GThread *saver = g_thread_new("spice saver", (GThreadFunc)ngspice_saver, ngspice_saver_resources);
+
+ /**
+ * Add an ngspice-is-finished watcher
+ */
+ NgSpiceWatcherWatchNgSpiceResources *ngspice_watcher_watch_ngspice_resources = g_new0(NgSpiceWatcherWatchNgSpiceResources, 1);
+ ngspice_watcher_watch_ngspice_resources->emit_instance = emit_instance;
+ ngspice_watcher_watch_ngspice_resources->aborted = aborted;
+ ngspice_watcher_watch_ngspice_resources->child_pid = child_pid;
+ ngspice_watcher_watch_ngspice_resources->log = log;
+ ngspice_watcher_watch_ngspice_resources->num_analysis = num_analysis;
+ ngspice_watcher_watch_ngspice_resources->worker = worker;
+ ngspice_watcher_watch_ngspice_resources->saver = saver;
+ ngspice_watcher_watch_ngspice_resources->main_loop = forker_main_loop;
+ ngspice_watcher_watch_ngspice_resources->ngspice_result_file = g_strdup(resources->ngspice_result_file);
+ ngspice_watcher_watch_ngspice_resources->netlist_file = g_strdup(resources->netlist_file);
+ ngspice_watcher_watch_ngspice_resources->error_state = error_state;
+ ngspice_watcher_watch_ngspice_resources->is_ngspice_stderr_destroyed = is_ngspice_stderr_destroyed;
+ ngspice_watcher_watch_ngspice_resources->cancel_info = resources->cancel_info;
+ cancel_info_subscribe(ngspice_watcher_watch_ngspice_resources->cancel_info);
+
+ GSource *child_watch_source = g_child_watch_source_new (*child_pid);
+ g_source_set_priority (child_watch_source, G_PRIORITY_LOW);
+ g_source_set_callback (child_watch_source, (GSourceFunc)ngspice_watcher_watch_ngspice, ngspice_watcher_watch_ngspice_resources, NULL);
+ g_source_attach (child_watch_source, forker_context);
+ g_source_unref (child_watch_source);
+
+ /**
+ * Add a GIOChannel to read from process stdout
+ */
+ NgSpiceWatchSTDOUTResources *ngspice_watch_stdout_resources = g_new0(NgSpiceWatchSTDOUTResources, 1);
+ ngspice_watch_stdout_resources->ngspice_watch_fork_resources.thread_pipe_worker = thread_pipe_worker;
+ ngspice_watch_stdout_resources->ngspice_watch_fork_resources.thread_pipe_saver = thread_pipe_saver;
+ ngspice_watch_stdout_resources->cancel_info = resources->cancel_info;
+ cancel_info_subscribe(ngspice_watch_stdout_resources->cancel_info);
+
+ GIOChannel *ngspice_stdout_channel = g_io_channel_unix_new(ngspice_stdout_fd);
+ g_io_channel_set_close_on_unref(ngspice_stdout_channel, TRUE);
+ GSource *ngspice_stdout_source = g_io_create_watch (ngspice_stdout_channel, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL);
+ g_io_channel_unref(ngspice_stdout_channel);
+ g_source_set_priority (ngspice_stdout_source, G_PRIORITY_HIGH);
+ g_source_set_callback (ngspice_stdout_source, (GSourceFunc)ngspice_watcher_watch_stdout, ngspice_watch_stdout_resources, NULL);
+ g_source_attach (ngspice_stdout_source, forker_context);
+ g_source_unref (ngspice_stdout_source);
+
+ /**
+ * Add a GIOChannel to read from process stderr (attach to gui thread because it prints to log).
+ * I hope that ngspice does not print too much errors so that it is a minor work
+ * that does not hold the gui back from paint and user events
+ */
+ NgSpiceWatchSTDERRResources *ngspice_watch_stderr_resources = g_new0(NgSpiceWatchSTDERRResources, 1);
+ ngspice_watch_stderr_resources->log = log;
+ ngspice_watch_stderr_resources->sim_settings = sim_settings;
+ ngspice_watch_stderr_resources->progress_ngspice = progress_ngspice;
+ ngspice_watch_stderr_resources->error_state = error_state;
+ ngspice_watch_stderr_resources->is_ngspice_stderr_destroyed = is_ngspice_stderr_destroyed;
+
+ GIOChannel *ngspice_stderr_channel = g_io_channel_unix_new (ngspice_stderr_fd);
+ g_io_channel_set_close_on_unref(ngspice_stderr_channel, TRUE);
+ // sometimes there is no data and then the GUI will hang up if NONBLOCK not set
+ g_io_channel_set_flags(ngspice_stderr_channel, g_io_channel_get_flags(ngspice_stderr_channel) | G_IO_FLAG_NONBLOCK, NULL);
+ GSource *channel_stderr_watch_source = g_io_create_watch(ngspice_stderr_channel, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL);
+ g_io_channel_unref(ngspice_stderr_channel);
+ g_source_set_priority (channel_stderr_watch_source, G_PRIORITY_LOW);
+ g_source_set_callback (channel_stderr_watch_source, (GSourceFunc)ngspice_child_stderr_cb, ngspice_watch_stderr_resources, NULL);
+ g_source_attach (channel_stderr_watch_source, NULL);
+ g_source_unref (channel_stderr_watch_source);
+
+ // Launch watcher
+ g_thread_unref(g_thread_new("spice forker", (GThreadFunc)ngspice_watcher_main, forker_main_loop));
+}
+
+NgspiceWatcherBuildAndLaunchResources *ngspice_watcher_build_and_launch_resources_new(OreganoNgSpice *ngspice) {
+
+ NgspiceWatcherBuildAndLaunchResources *resources = g_new0(NgspiceWatcherBuildAndLaunchResources, 1);
+
+ resources->is_vanilla = ngspice->priv->is_vanilla;
+ resources->aborted = &ngspice->priv->aborted;
+ resources->analysis = &ngspice->priv->analysis;
+ resources->child_pid = &ngspice->priv->child_pid;
+ resources->current = &ngspice->priv->current;
+ resources->emit_instance = ngspice;
+
+ resources->log.log = ngspice->priv->schematic;
+ resources->log.log_append = (LogFunction)schematic_log_append;
+ resources->log.log_append_error = (LogFunction)schematic_log_append_error;
+
+ resources->num_analysis = &ngspice->priv->num_analysis;
+ resources->progress_ngspice = &ngspice->priv->progress_ngspice;
+ resources->progress_reader = &ngspice->priv->progress_reader;
+ resources->sim_settings = schematic_get_sim_settings(ngspice->priv->schematic);
+
+ resources->netlist_file = g_strdup("/tmp/netlist.tmp");
+ resources->ngspice_result_file = g_strdup("/tmp/netlist.lst");
+
+ resources->cancel_info = ngspice->priv->cancel_info;
+ cancel_info_subscribe(resources->cancel_info);
+
+ return resources;
+}
+
+void ngspice_watcher_build_and_launch_resources_finalize(NgspiceWatcherBuildAndLaunchResources *resources) {
+ cancel_info_unsubscribe(resources->cancel_info);
+ g_free(resources->netlist_file);
+ g_free(resources->ngspice_result_file);
+ g_free(resources);
+}
diff --git a/src/engines/ngspice-watcher.h b/src/engines/ngspice-watcher.h
new file mode 100644
index 0000000..f54ff4a
--- /dev/null
+++ b/src/engines/ngspice-watcher.h
@@ -0,0 +1,62 @@
+/*
+ * ngspice-watcher.h
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ENGINES_NGSPICE_WATCHER_H_
+#define ENGINES_NGSPICE_WATCHER_H_
+
+#include "../log-interface.h"
+#include "../sim-settings.h"
+#include "ngspice-analysis.h"
+
+typedef struct _NgspiceWatcherBuildAndLaunchResources NgspiceWatcherBuildAndLaunchResources;
+
+/**
+ * This struct has to be public for testing purposes.
+ */
+struct _NgspiceWatcherBuildAndLaunchResources {
+ LogInterface log;//in
+ const SimSettings* sim_settings;//in
+ gboolean is_vanilla;//in
+ GPid* child_pid;//out
+ gboolean* aborted;//out
+ //OreganoNgSpice object
+ const void* emit_instance;//in
+ guint* num_analysis;//out
+ ProgressResources* progress_ngspice;//out
+ ProgressResources* progress_reader;//out
+ GList** analysis;//out
+ AnalysisTypeShared* current;//out
+ gchar* ngspice_result_file;//in
+ gchar* netlist_file;//in
+ CancelInfo *cancel_info;//in
+};
+
+NgspiceWatcherBuildAndLaunchResources *ngspice_watcher_build_and_launch_resources_new(OreganoNgSpice *ngspice);
+void ngspice_watcher_build_and_launch_resources_finalize(NgspiceWatcherBuildAndLaunchResources *resources);
+
+void ngspice_watcher_build_and_launch(const NgspiceWatcherBuildAndLaunchResources *resources);
+
+#endif /* ENGINES_NGSPICE_WATCHER_H_ */
diff --git a/src/engines/ngspice.c b/src/engines/ngspice.c
index cd013ba..ee482e6 100644
--- a/src/engines/ngspice.c
+++ b/src/engines/ngspice.c
@@ -4,12 +4,16 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,8 +27,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -39,43 +43,37 @@
#include "dialogs.h"
#include "engine-internal.h"
#include "ngspice-analysis.h"
+#include "errors.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "ngspice-watcher.h"
static void ngspice_class_init (OreganoNgSpiceClass *klass);
static void ngspice_finalize (GObject *object);
static void ngspice_dispose (GObject *object);
static void ngspice_instance_init (GTypeInstance *instance, gpointer g_class);
static void ngspice_interface_init (gpointer g_iface, gpointer iface_data);
-static gboolean ngspice_child_stdout_cb (GIOChannel *source,
- GIOCondition condition, OreganoNgSpice *ngspice);
-static gboolean ngspice_child_stderr_cb (GIOChannel *source,
- GIOCondition condition, OreganoNgSpice *ngspice);
static GObjectClass *parent_class = NULL;
-GType
-oregano_ngspice_get_type (void)
+GType oregano_ngspice_get_type (void)
{
static GType type = 0;
if (type == 0) {
- static const GTypeInfo info = {
- sizeof (OreganoNgSpiceClass),
- NULL, // base_init
- NULL, // base_finalize
- (GClassInitFunc) ngspice_class_init, // class_init
- NULL, // class_finalize
- NULL, // class_data
- sizeof (OreganoNgSpice),
- 0, // n_preallocs
- (GInstanceInitFunc) ngspice_instance_init, // instance_init
- NULL
- };
+ static const GTypeInfo info = {sizeof(OreganoNgSpiceClass),
+ NULL, // base_init
+ NULL, // base_finalize
+ (GClassInitFunc)ngspice_class_init, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+ sizeof(OreganoNgSpice),
+ 0, // n_preallocs
+ (GInstanceInitFunc)ngspice_instance_init, // instance_init
+ NULL};
static const GInterfaceInfo ngspice_info = {
- (GInterfaceInitFunc) ngspice_interface_init,// interface_init
- NULL, // interface_finalize
- NULL // interface_data
+ (GInterfaceInitFunc)ngspice_interface_init, // interface_init
+ NULL, // interface_finalize
+ NULL // interface_data
};
type = g_type_register_static (G_TYPE_OBJECT, "OreganoNgSpice", &info, 0);
@@ -84,8 +82,7 @@ oregano_ngspice_get_type (void)
return type;
}
-static void
-ngspice_class_init (OreganoNgSpiceClass *klass)
+static void ngspice_class_init (OreganoNgSpiceClass *klass)
{
GObjectClass *object_class;
@@ -97,395 +94,385 @@ ngspice_class_init (OreganoNgSpiceClass *klass)
object_class->finalize = ngspice_finalize;
}
-static void
-ngspice_finalize (GObject *object)
+static void ngspice_finalize (GObject *object)
{
- SimulationData *data;
OreganoNgSpice *ngspice;
- GList *list;
+ GList *iter;
int i;
ngspice = OREGANO_NGSPICE (object);
- list = ngspice->priv->analysis;
- while (list) {
- data = SIM_DATA (list->data);
+ iter = ngspice->priv->analysis;
+ for (; iter; iter = iter->next) {
+ SimulationData *data = SIM_DATA (iter->data);
+ for (i = 0; i < data->n_variables; i++) {
+ g_free(data->var_names[i]);
+ g_free(data->var_units[i]);
+ g_array_free (data->data[i], TRUE);
+ }
g_free (data->var_names);
g_free (data->var_units);
- for (i=0; i<data->n_variables; i++)
- g_array_free (data->data[i], TRUE);
-
+ g_free (data->data);
g_free (data->min_data);
g_free (data->max_data);
-
- g_free (list->data);
- list = list->next;
+
+ g_free (data);
}
g_list_free (ngspice->priv->analysis);
- ngspice->priv->analysis = NULL;
- g_list_free_full (list, g_object_unref);
+ g_mutex_clear(&ngspice->priv->progress_ngspice.progress_mutex);
+ g_mutex_clear(&ngspice->priv->progress_reader.progress_mutex);
+ g_mutex_clear(&ngspice->priv->current.mutex);
+ cancel_info_unsubscribe(ngspice->priv->cancel_info);
+ g_free(ngspice->priv);
parent_class->finalize (object);
}
-static void
-ngspice_dispose (GObject *object)
-{
- parent_class->dispose (object);
-}
+static void ngspice_dispose (GObject *object) { parent_class->dispose (object); }
-static gboolean
-ngspice_has_warnings (OreganoEngine *self)
-{
- return FALSE;
-}
+static gboolean ngspice_has_warnings (OreganoEngine *self) { return FALSE; }
-static gboolean
-ngspice_is_available (OreganoEngine *self)
+static gboolean ngspice_is_available (OreganoEngine *self)
{
+ gboolean is_vanilla;
gchar *exe;
- exe = g_find_program_in_path ("ngspice");
+ OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
+
+ is_vanilla = ngspice->priv->is_vanilla;
- if (!exe) return FALSE; // ngspice not found
+ if (is_vanilla)
+ exe = g_find_program_in_path (SPICE_EXE);
+ else
+ exe = g_find_program_in_path (NGSPICE_EXE);
+
+ if (!exe)
+ return FALSE; // ngspice not found
g_free (exe);
return TRUE;
}
-static void
-ngspice_generate_netlist (OreganoEngine *engine, const gchar *filename,
- GError **error)
+/**
+ * \brief create a netlist buffer from the engine inernals
+ *
+ * @engine
+ * @error [allow-none]
+ */
+static GString *ngspice_generate_netlist_buffer (OreganoEngine *engine, GError **error)
{
OreganoNgSpice *ngspice;
Netlist output;
- SimOption *so;
- GList *list;
- FILE *file;
- GError *local_error = NULL;
+ GList *iter;
+ GError *e = NULL;
+ GString *buffer = NULL;
ngspice = OREGANO_NGSPICE (engine);
- netlist_helper_create (ngspice->priv->schematic, &output, &local_error);
- if (local_error != NULL) {
- g_propagate_error (error, local_error);
- return;
+ netlist_helper_create (ngspice->priv->schematic, &output, &e);
+ if (e) {
+ g_propagate_error (error, e);
+ return NULL;
}
- file = fopen (filename, "w");
- if (!file) {
- oregano_error (g_strdup_printf ("Creation of %s not possible\n", filename));
- return;
+ buffer = g_string_sized_new (500);
+ if (!buffer) {
+ g_set_error_literal (&e, OREGANO_ERROR, OREGANO_OOM,
+ "Failed to allocate intermediate buffer.");
+ g_propagate_error (error, e);
+ return NULL;
}
-
- list = sim_settings_get_options (output.settings);
-
- // Prints title
- fputs ("* ",file);
- fputs (output.title ? output.title : "Title: <unset>", file);
- fputs ("\n"
- "*----------------------------------------------"
- "\n"
- "*\tngspice - NETLIST"
- "\n", file);
+ // Prints title
+ g_string_append (buffer, "* ");
+ g_string_append (buffer, output.title ? output.title : "Title: <unset>");
+ g_string_append (buffer, "\n"
+ "*----------------------------------------------"
+ "\n"
+ "*\tngspice - NETLIST"
+ "\n");
// Prints Options
- fputs (".options OUT=120 ",file);
+ g_string_append (buffer, ".options OUT=120 ");
- while (list) {
- so = list->data;
+ iter = sim_settings_get_options (output.settings);
+ for (; iter; iter = iter->next) {
+ const SimOption *so = iter->data;
// Prevent send NULL text
if (so->value) {
- if (strlen(so->value) > 0) {
- g_fprintf (file,"%s=%s ",so->name,so->value);
+ if (strlen (so->value) > 0) {
+ g_string_append_printf (buffer, "%s=%s ", so->name, so->value);
}
}
- list = list->next;
}
- fputc ('\n',file);
+ g_string_append_c (buffer, '\n');
// Include of subckt models
- fputs ("*------------- Models -------------------------\n",file);
- list = output.models;
- while (list) {
- gchar *model;
- model = (gchar *)list->data;
- g_fprintf (file,".include %s/%s.model\n", OREGANO_MODELDIR, model);
- list = list->next;
+ g_string_append (buffer, "*------------- Models -------------------------\n");
+ for (iter = output.models; iter; iter = iter->next) {
+ const gchar *model = iter->data;
+ gchar *model_with_ext = g_strdup_printf ("%s.model", model);
+ gchar *model_path = g_build_filename (OREGANO_MODELDIR, model_with_ext, NULL);
+ g_string_append_printf (buffer, ".include %s\n", model_path);
+ g_free (model_path);
+ g_free (model_with_ext);
}
- // Prints template parts
- fputs ("*------------- Circuit Description-------------\n",file);
- fputs (output.template->str, file);
- fputs ("\n*----------------------------------------------\n",file);
+ // Prints template parts
+ g_string_append (buffer, "*------------- Circuit Description-------------\n");
+ g_string_append (buffer, output.template->str);
+ g_string_append (buffer, "\n*----------------------------------------------\n");
// Prints Transient Analysis
if (sim_settings_get_trans (output.settings)) {
gdouble st = 0;
gdouble start = sim_settings_get_trans_start (output.settings);
- gdouble stop = sim_settings_get_trans_stop (output.settings);
+ gdouble stop = sim_settings_get_trans_stop (output.settings);
if (sim_settings_get_trans_step_enable (output.settings))
st = sim_settings_get_trans_step (output.settings);
else
- st = (stop-start) / 50;
+ st = (stop - start) / 50;
+
+ if ((stop - start) <= 0) {
+ // FIXME ask for swapping or cancel simulation
+ oregano_error (_ ("Transient: Start time is after Stop time - fix this."
+ "stop figure\n"));
+ g_string_free (buffer, TRUE);
+ return NULL;
+ }
- if ((stop-start) <= 0) {
- oregano_error (_("Your transient analysis settings present a "
- "weakness... the start figure is greater than "
- "stop figure\n"));
- return;
+ g_string_append_printf (buffer, ".tran %e %e %e", st, stop, start);
+ if (sim_settings_get_trans_init_cond (output.settings)) {
+ g_string_append_printf (buffer, " uic");
}
+ g_string_append_printf (buffer, "\n");
- g_fprintf (file, ".tran %lf %lf %lf\n", st, stop, start);
- {
+ if (sim_settings_get_trans_analyze_all(output.settings)) {
+ g_string_append_printf (buffer, ".print tran all\n");
+ } else {
gchar *tmp_str = netlist_helper_create_analysis_string (output.store, FALSE);
- g_fprintf (file, ".print tran %s\n", tmp_str);
+ g_string_append_printf (buffer, ".print tran %s\n", tmp_str);
g_free (tmp_str);
-
}
- fputs ("\n", file);
+ g_string_append_c (buffer, '\n');
}
- // Print DC Analysis
+ // Prints DC Analysis
if (sim_settings_get_dc (output.settings)) {
- fputs (".dc ",file);
+ g_string_append (buffer, ".dc ");
if (sim_settings_get_dc_vsrc (output.settings)) {
- g_fprintf (file, "V_V%s %g %g %g\n",
- sim_settings_get_dc_vsrc (output.settings),
- sim_settings_get_dc_start (output.settings),
- sim_settings_get_dc_stop (output.settings),
- sim_settings_get_dc_step (output.settings));
- g_fprintf (file, ".print dc V(%s)\n", sim_settings_get_dc_vsrc (output.settings));
+ g_string_append_printf (buffer, "V_%s %g %g %g\n",
+ sim_settings_get_dc_vsrc (output.settings),
+ sim_settings_get_dc_start (output.settings),
+ sim_settings_get_dc_stop (output.settings),
+ sim_settings_get_dc_step (output.settings));
+ g_string_append_printf (buffer, ".print dc V(%s)\n",
+ sim_settings_get_dc_vout (output.settings));
}
}
// Prints AC Analysis
if (sim_settings_get_ac (output.settings)) {
- g_fprintf (file, ".ac %s %d %g %g\n",
- sim_settings_get_ac_type (output.settings),
- sim_settings_get_ac_npoints (output.settings),
- sim_settings_get_ac_start (output.settings),
- sim_settings_get_ac_stop (output.settings));
+ if (sim_settings_get_ac_vout (output.settings)) {
+ g_string_append_printf (buffer, ".ac %s %d %g %g\n",
+ sim_settings_get_ac_type (output.settings),
+ sim_settings_get_ac_npoints (output.settings),
+ sim_settings_get_ac_start (output.settings),
+ sim_settings_get_ac_stop (output.settings));
+ g_string_append_printf (buffer, ".print ac %s\n",
+ sim_settings_get_ac_vout (output.settings));
+ }
}
-
+
// Prints analysis using a Fourier transform
- if (sim_settings_get_fourier (output.settings)) {
- g_fprintf (file, ".four %d %s\n",
- sim_settings_get_fourier_frequency (output.settings),
- sim_settings_get_fourier_nodes (output.settings));
+ if (sim_settings_get_fourier (output.settings)) {
+ if (sim_settings_get_fourier_frequency (output.settings) &&
+ sim_settings_get_fourier_nodes (output.settings)) {
+ g_string_append_printf (buffer, ".four %.3f %s\n",
+ sim_settings_get_fourier_frequency (output.settings),
+ sim_settings_get_fourier_nodes (output.settings));
+ }
}
- g_list_free_full (list, g_object_unref);
-
- // Debug op analysis.
- fputs (".op\n", file);
- fputs ("\n.END\n", file);
- fclose (file);
+ // Prints Noise Analysis
+ if (sim_settings_get_noise (output.settings)) {
+ if (sim_settings_get_noise_vout (output.settings)) {
+ g_string_append_printf (buffer, ".noise V(%s) V_%s %s %d %g %g\n",
+ sim_settings_get_noise_vout (output.settings),
+ sim_settings_get_noise_vsrc (output.settings),
+ sim_settings_get_noise_type (output.settings),
+ sim_settings_get_noise_npoints (output.settings),
+ sim_settings_get_noise_start (output.settings),
+ sim_settings_get_noise_stop (output.settings));
+ g_string_append (buffer, ".print noise inoise_spectrum onoise_spectrum\n");
+ }
+ }
+
+ g_string_append (buffer, ".op\n\n.END\n");
+
+ return buffer;
}
-static void
-ngspice_progress (OreganoEngine *self, double *d)
+/**
+ * \brief generate a netlist and write to file
+ *
+ * @engine engine to extract schematic and settings from
+ * @filename target netlist file, user selected
+ * @error [allow-none]
+ */
+static gboolean ngspice_generate_netlist (OreganoEngine *engine, const gchar *filename,
+ GError **error)
{
- OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
+ GError *e = NULL;
+ GString *buffer;
+ gboolean success = FALSE;
+
+ buffer = ngspice_generate_netlist_buffer (engine, &e);
+ if (!buffer) {
+ oregano_error (g_strdup_printf ("Failed generate netlist buffer\n"));
+ g_propagate_error (error, e);
+ return FALSE;
+ }
+
+ success = g_file_set_contents (filename, buffer->str, buffer->len, &e);
+ g_string_free (buffer, TRUE);
- ngspice->priv->progress += 0.1;
- (*d) = ngspice->priv->progress;
+ if (!success) {
+ g_propagate_error (error, e);
+ oregano_error (g_strdup_printf ("Failed to open file \"%s\" in 'w' mode.\n", filename));
+ return FALSE;
+ }
+ return TRUE;
}
-static void
-ngspice_stop (OreganoEngine *self)
+static void ngspice_progress (OreganoEngine *self, double *d)
{
OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
- g_io_channel_shutdown (ngspice->priv->child_iochannel, TRUE, NULL);
- g_source_remove (ngspice->priv->child_iochannel_watch);
- g_spawn_close_pid (ngspice->priv->child_pid);
- g_spawn_close_pid (ngspice->priv->child_stdout);
-}
-static void
-ngspice_watch_cb (GPid pid, gint status, OreganoNgSpice *ngspice)
-{
- // check for status, see man waitpid(2)
- if (WIFEXITED (status)) {
- gchar *line;
- gsize len;
- g_io_channel_read_to_end (ngspice->priv->child_iochannel, &line, &len, NULL);
- if (len > 0) {
- fprintf (ngspice->priv->inputfp, "%s", line);
- }
- g_free (line);
-
- // Free stuff
- g_io_channel_shutdown (ngspice->priv->child_iochannel, TRUE, NULL);
- g_source_remove (ngspice->priv->child_iochannel_watch);
- g_spawn_close_pid (ngspice->priv->child_pid);
- g_spawn_close_pid (ngspice->priv->child_stdout);
- g_io_channel_shutdown (ngspice->priv->child_ioerror, TRUE, NULL);
- g_source_remove (ngspice->priv->child_ioerror_watch);
- g_spawn_close_pid (ngspice->priv->child_error);
-
- ngspice->priv->current = NULL;
- fclose (ngspice->priv->inputfp);
- ngspice_parse (ngspice);
-
- if (ngspice->priv->num_analysis == 0) {
- schematic_log_append_error (ngspice->priv->schematic,
- _("### Too few or none analysis found ###\n"));
- ngspice->priv->aborted = TRUE;
- g_signal_emit_by_name (G_OBJECT (ngspice), "aborted");
- }
- else {
- g_signal_emit_by_name (G_OBJECT (ngspice), "done");
- }
- }
+ g_mutex_lock(&ngspice->priv->progress_ngspice.progress_mutex);
+ *d = ngspice->priv->progress_ngspice.progress;
+ g_mutex_unlock(&ngspice->priv->progress_ngspice.progress_mutex);
}
-static gboolean
-ngspice_child_stdout_cb (GIOChannel *source, GIOCondition condition, OreganoNgSpice *ngspice)
+static void reader_progress (OreganoEngine *self, double *d)
{
- gchar *line;
- gsize len, terminator;
- GIOStatus status;
- GError *error = NULL;
-
- status = g_io_channel_read_line (source, &line, &len, &terminator, &error);
- if ((status & G_IO_STATUS_NORMAL) && (len > 0)) {
- fprintf (ngspice->priv->inputfp, "%s", line);
- }
- g_free (line);
-
- // Let UI update
- return g_main_context_iteration (NULL, FALSE);
+ OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
+
+ g_mutex_lock(&ngspice->priv->progress_reader.progress_mutex);
+ *d = ngspice->priv->progress_reader.progress;
+ g_mutex_unlock(&ngspice->priv->progress_reader.progress_mutex);
}
-static gboolean
-ngspice_child_stderr_cb (GIOChannel *source, GIOCondition condition, OreganoNgSpice *ngspice)
+static void ngspice_stop (OreganoEngine *self)
{
- gchar *line;
- gsize len, terminator;
- GIOStatus status;
- GError *error = NULL;
-
- status = g_io_channel_read_line (source, &line, &len, &terminator, &error);
- if ((status & G_IO_STATUS_NORMAL) && (len > 0)) {
- schematic_log_append_error (ngspice->priv->schematic, line);
+ OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
+ cancel_info_set_cancel(ngspice->priv->cancel_info);
+ GPid child_pid = ngspice->priv->child_pid;
+ if (child_pid != 0) {
+ // CTRL+C (Terminal quit signal.)
+ kill(child_pid, SIGINT);
+ ngspice->priv->child_pid = 0;
}
- g_free (line);
-
- // Let UI update
- g_main_context_iteration (NULL, FALSE);
- return TRUE;
}
-static void
-ngspice_start (OreganoEngine *self)
+static void ngspice_start (OreganoEngine *self)
{
- OreganoNgSpice *ngspice;
- GError *error = NULL;
- char *argv[] = {"ngspice", "-b", "/tmp/netlist.tmp", NULL};
-
- ngspice = OREGANO_NGSPICE (self);
- oregano_engine_generate_netlist (self, "/tmp/netlist.tmp", &error);
- if (error != NULL) {
- ngspice->priv->aborted = TRUE;
- schematic_log_append_error (ngspice->priv->schematic, error->message);
+ OreganoNgSpice *ngspice = OREGANO_NGSPICE (self);
+ OreganoNgSpicePriv *priv = ngspice->priv;
+
+ GError *e = NULL;
+ if (!oregano_engine_generate_netlist (self, "/tmp/netlist.tmp", &e)) {
+ priv->aborted = TRUE;
+ if (e)
+ schematic_log_append_error (priv->schematic, e->message);
+ else
+ schematic_log_append_error(priv->schematic, "Error at netlist generation.");
g_signal_emit_by_name (G_OBJECT (ngspice), "aborted");
- g_error_free (error);
+ g_clear_error (&e);
return;
}
-
- // Open the file storing the output of ngspice
- ngspice->priv->inputfp = fopen ("/tmp/netlist.lst", "w");
-
- error = NULL;
- if (g_spawn_async_with_pipes (
- NULL, // Working directory
- argv,
- NULL,
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL,
- NULL,
- &ngspice->priv->child_pid,
- NULL, // STDIN
- &ngspice->priv->child_stdout, // STDOUT
- &ngspice->priv->child_error, // STDERR
- &error)) {
- // Add a watch for process status
- g_child_watch_add (ngspice->priv->child_pid, (GChildWatchFunc)ngspice_watch_cb, ngspice);
- // Add a GIOChannel to read from process stdout
- ngspice->priv->child_iochannel = g_io_channel_unix_new (ngspice->priv->child_stdout);
- // Watch the I/O Channel to read child strout
- ngspice->priv->child_iochannel_watch = g_io_add_watch (ngspice->priv->child_iochannel,
- G_IO_IN|G_IO_PRI|G_IO_HUP|G_IO_NVAL, (GIOFunc)ngspice_child_stdout_cb, ngspice);
- // Add a GIOChannel to read from process stderr
- ngspice->priv->child_ioerror = g_io_channel_unix_new (ngspice->priv->child_error);
- // Watch the I/O error channel to read the child sterr
- ngspice->priv->child_ioerror_watch = g_io_add_watch (ngspice->priv->child_ioerror,
- G_IO_IN|G_IO_PRI|G_IO_HUP|G_IO_NVAL, (GIOFunc)ngspice_child_stderr_cb, ngspice);
-
- }
- else {
- ngspice->priv->aborted = TRUE;
- schematic_log_append_error (ngspice->priv->schematic, _("Unable to execute NgSpice."));
- g_signal_emit_by_name (G_OBJECT (ngspice), "aborted");
- }
+
+ NgspiceWatcherBuildAndLaunchResources *resources = ngspice_watcher_build_and_launch_resources_new(ngspice);
+ ngspice_watcher_build_and_launch(resources);
+ ngspice_watcher_build_and_launch_resources_finalize(resources);
}
-static GList*
-ngspice_get_results (OreganoEngine *self)
+static GList *ngspice_get_results (OreganoEngine *self)
{
if (OREGANO_NGSPICE (self)->priv->analysis == NULL)
printf ("pas d'analyse\n");
return OREGANO_NGSPICE (self)->priv->analysis;
}
-static gchar *
-ngspice_get_operation (OreganoEngine *self)
+static gchar *ngspice_get_operation_ngspice (OreganoEngine *self)
+{
+ OreganoNgSpicePriv *priv = OREGANO_NGSPICE (self)->priv;
+
+ g_mutex_lock(&priv->progress_ngspice.progress_mutex);
+ gint64 old_time = priv->progress_ngspice.time;
+ g_mutex_unlock(&priv->progress_ngspice.progress_mutex);
+
+ gint64 new_time = g_get_monotonic_time();
+ if (new_time - old_time >= 1000000)
+ return g_strdup("ngspice not responding");
+ return g_strdup(_("ngspice solving"));
+}
+
+static gchar *ngspice_get_operation_reader (OreganoEngine *self)
{
OreganoNgSpicePriv *priv = OREGANO_NGSPICE (self)->priv;
- if (priv->current == NULL)
- return _("None");
+ g_mutex_lock(&priv->current.mutex);
+ AnalysisType type = priv->current.type;
+ g_mutex_unlock(&priv->current.mutex);
- return oregano_engine_get_analysis_name (priv->current);
+ return oregano_engine_get_analysis_name_by_type(type);
}
-static void
-ngspice_interface_init (gpointer g_iface, gpointer iface_data)
+static void ngspice_interface_init (gpointer g_iface, gpointer iface_data)
{
OreganoEngineClass *klass = (OreganoEngineClass *)g_iface;
klass->start = ngspice_start;
klass->stop = ngspice_stop;
- klass->progress = ngspice_progress;
+ klass->progress_solver = ngspice_progress;
+ klass->progress_reader = reader_progress;
klass->get_netlist = ngspice_generate_netlist;
klass->has_warnings = ngspice_has_warnings;
klass->get_results = ngspice_get_results;
- klass->get_operation = ngspice_get_operation;
+ klass->get_operation_solver = ngspice_get_operation_ngspice;
+ klass->get_operation_reader = ngspice_get_operation_reader;
klass->is_available = ngspice_is_available;
}
-static void
-ngspice_instance_init (GTypeInstance *instance, gpointer g_class)
+static void ngspice_instance_init (GTypeInstance *instance, gpointer g_class)
{
OreganoNgSpice *self = OREGANO_NGSPICE (instance);
self->priv = g_new0 (OreganoNgSpicePriv, 1);
- self->priv->progress = 0.0;
- self->priv->char_last_newline = TRUE;
- self->priv->status = 0;
- self->priv->buf_count = 0;
+ self->priv->progress_ngspice.progress = 0.0;
+ self->priv->progress_ngspice.time = g_get_monotonic_time();
+ g_mutex_init(&self->priv->progress_ngspice.progress_mutex);
+ self->priv->progress_reader.progress = 0.0;
+ self->priv->progress_reader.time = g_get_monotonic_time();
+ g_mutex_init(&self->priv->progress_reader.progress_mutex);
+ self->priv->current.type = ANALYSIS_TYPE_NONE;
+ g_mutex_init(&self->priv->current.mutex);
self->priv->num_analysis = 0;
self->priv->analysis = NULL;
- self->priv->current = NULL;
self->priv->aborted = FALSE;
+
+ self->priv->cancel_info = cancel_info_new();
}
-OreganoEngine*
-oregano_ngspice_new (Schematic *sc)
+/*
+ * Set "is_vanilla" to TRUE if using the original spice3 from
+ * UC Berkeley.
+ */
+OreganoEngine *oregano_spice_new (Schematic *sc, gboolean is_vanilla)
{
OreganoNgSpice *ngspice;
ngspice = OREGANO_NGSPICE (g_object_new (OREGANO_TYPE_NGSPICE, NULL));
ngspice->priv->schematic = sc;
+ ngspice->priv->is_vanilla = is_vanilla;
return OREGANO_ENGINE (ngspice);
}
diff --git a/src/engines/ngspice.h b/src/engines/ngspice.h
index bb46dc6..26e00f8 100644
--- a/src/engines/ngspice.h
+++ b/src/engines/ngspice.h
@@ -4,12 +4,14 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,39 +25,60 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NGSPICE_H
#define __NGSPICE_H
+/*
+ * The name of the vanilla spice3 executable.
+ */
+#define SPICE_EXE "spice3"
+
+/*
+ * The name of the ngspice executable.
+ */
+#define NGSPICE_EXE "ngspice"
+
+/*
+ * The filename used for the temporary noise
+ * analysis file.
+ */
+#define NOISE_ANALYSIS_FILENAME "oregano-noise.txt"
+
#include <gtk/gtk.h>
#include "engine.h"
-#define OREGANO_TYPE_NGSPICE (oregano_ngspice_get_type ())
-#define OREGANO_NGSPICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_NGSPICE, OreganoNgSpice))
-#define OREGANO_NGSPICE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), OREGANO_TYPE_NGSPICE, OreganoNgSpiceClass))
-#define OREGANO_IS_NGSPICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_NGSPICE))
+#define OREGANO_TYPE_NGSPICE (oregano_ngspice_get_type ())
+#define OREGANO_NGSPICE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_NGSPICE, OreganoNgSpice))
+#define OREGANO_NGSPICE_CLASS(vtable) \
+ (G_TYPE_CHECK_CLASS_CAST ((vtable), OREGANO_TYPE_NGSPICE, OreganoNgSpiceClass))
+#define OREGANO_IS_NGSPICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_NGSPICE))
#define OREGANO_IS_NGSPICE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), OREGANO_TYPE_NGSPICE))
-#define OREGANO_NGSPICE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), OREGANO_TYPE_NGSPICE, OreganoNgSpiceClass))
+#define OREGANO_NGSPICE_GET_CLASS(inst) \
+ (G_TYPE_INSTANCE_GET_CLASS ((inst), OREGANO_TYPE_NGSPICE, OreganoNgSpiceClass))
typedef struct _OreganoNgSpice OreganoNgSpice;
typedef struct _OreganoNgSpicePriv OreganoNgSpicePriv;
typedef struct _OreganoNgSpiceClass OreganoNgSpiceClass;
-struct _OreganoNgSpice {
+struct _OreganoNgSpice
+{
GObject parent;
OreganoNgSpicePriv *priv;
};
-struct _OreganoNgSpiceClass {
+struct _OreganoNgSpiceClass
+{
GObjectClass parent;
};
-GType oregano_ngspice_get_type (void);
-OreganoEngine *oregano_ngspice_new (Schematic *sm);
+GType oregano_ngspice_get_type (void);
+OreganoEngine *oregano_spice_new (Schematic *sm, gboolean is_vanilla);
#endif
diff --git a/src/errors.c b/src/errors.c
index b03dcc2..af3cd44 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -5,9 +5,9 @@
* Author:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
- *
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
* Copyright (C) 2003-2008 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
*
@@ -23,14 +23,13 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "errors.h"
-GQuark
-oregano_error_quark (void)
+GQuark oregano_error_quark (void)
{
static GQuark err = 0;
if (!err) {
@@ -38,4 +37,3 @@ oregano_error_quark (void)
}
return err;
}
-
diff --git a/src/errors.h b/src/errors.h
index 937bb6f..89d7c59 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -2,14 +2,16 @@
* errors.h
*
*
- * Author:
+ * Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Web page: https://ahoi.io/project/oregano
*
- * Web page: https://github.com/marc-lorber/oregano
- *
* Copyright (C) 2003-2008 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,8 +25,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __ERRORS_H
@@ -32,16 +34,19 @@
#include <glib.h>
-#define OREGANO_ERROR (oregano_error_quark())
+#define OREGANO_ERROR (oregano_error_quark ())
GQuark oregano_error_quark (void);
typedef enum {
OREGANO_SIMULATE_ERROR_NO_GND,
OREGANO_SIMULATE_ERROR_NO_CLAMP,
+ OREGANO_SIMULATE_ERROR_NO_SUCH_PART,
OREGANO_SIMULATE_ERROR_IO_ERROR,
OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
OREGANO_SCHEMATIC_FILE_NOT_FOUND,
+ OREGANO_UI_ERROR_NO_BUILDER,
+ OREGANO_OOM
} OREGANO_ERRORS;
#endif
diff --git a/src/file-manager.c b/src/file-manager.c
index 8be0460..0548d76 100644
--- a/src/file-manager.c
+++ b/src/file-manager.c
@@ -7,7 +7,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
@@ -24,26 +24,22 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "file-manager.h"
FileType file_types[] = {
- FILE_TYPE ("oregano", "Oregano Schematic File", schematic_parse_xml_file,
- schematic_write_xml)
-};
+ FILE_TYPE ("oregano", "Oregano Schematic File", schematic_parse_xml_file, schematic_write_xml)};
-#define FILE_TYPES_COUNT (sizeof(file_types)/sizeof(FileType))
+#define FILE_TYPES_COUNT (sizeof(file_types) / sizeof(FileType))
-
-FileType *
-file_manager_get_handler (const gchar *fname)
+FileType *file_manager_get_handler (const gchar *fname)
{
int i;
gchar *ext, *ptr;
- FileType *ft = NULL;
+ FileType *ft = NULL;
g_return_val_if_fail (fname != NULL, NULL);
@@ -57,7 +53,7 @@ file_manager_get_handler (const gchar *fname)
ptr++;
}
- for (i=0; i<FILE_TYPES_COUNT; i++)
+ for (i = 0; i < FILE_TYPES_COUNT; i++)
if (!strcmp (file_types[i].extension, ext)) {
ft = &file_types[i];
break;
diff --git a/src/file-manager.h b/src/file-manager.h
index 73888d4..66a9869 100644
--- a/src/file-manager.h
+++ b/src/file-manager.h
@@ -7,7 +7,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
@@ -24,8 +24,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _FILE_MANAGER_H_
@@ -38,9 +38,13 @@
#include "load-schematic.h"
#include "save-schematic.h"
-#define FILE_TYPE(a,b,c,d) {a, b, c, d}
+#define FILE_TYPE(a, b, c, d) \
+ { \
+ a, b, c, d \
+ }
-typedef struct _file_manager_ext_ {
+typedef struct _file_manager_ext_
+{
gchar *extension;
gchar *description;
int (*load_func)(Schematic *schematic, const gchar *filename, GError **error);
diff --git a/src/file.c b/src/file.c
index a6bb04c..b0802ad 100644
--- a/src/file.c
+++ b/src/file.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
@@ -39,9 +39,7 @@
#include "dialogs.h"
#include "save-schematic.h"
-
-char *
-dialog_open_file (SchematicView *sv)
+char *dialog_open_file (SchematicView *sv)
{
GtkWidget *dialog;
GtkFileFilter *allfilter, *orefilter;
@@ -49,39 +47,38 @@ dialog_open_file (SchematicView *sv)
allfilter = gtk_file_filter_new ();
orefilter = gtk_file_filter_new ();
-
- gtk_file_filter_set_name (orefilter, _("Oregano Files"));
+
+ gtk_file_filter_set_name (orefilter, _ ("Oregano Files"));
gtk_file_filter_add_pattern (orefilter, "*.oregano");
- gtk_file_filter_set_name (allfilter, _("All Files"));
+ gtk_file_filter_set_name (allfilter, _ ("All Files"));
gtk_file_filter_add_pattern (allfilter, "*");
-
- dialog = gtk_file_chooser_dialog_new (_("Open File"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
-
+
+ dialog = gtk_file_chooser_dialog_new (_ ("Open File"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Open"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), orefilter);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), allfilter);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
- name = gtk_file_chooser_get_filename (
- GTK_FILE_CHOOSER (dialog));
- if (name[strlen (name)-1] == '/')
+ name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (name[strlen (name) - 1] == '/') {
+ g_free (name);
name = NULL;
- else
- name = g_strdup (name);
- }
- else
+ }
+ } else
name = NULL;
gtk_widget_destroy (dialog);
return name;
}
-void
-dialog_save_as (SchematicView *sv)
+void dialog_save_as (SchematicView *sv)
{
GtkWidget *dialog;
GtkFileFilter *orefilter, *allfilter;
@@ -91,33 +88,33 @@ dialog_save_as (SchematicView *sv)
orefilter = gtk_file_filter_new ();
allfilter = gtk_file_filter_new ();
- gtk_file_filter_set_name (orefilter, _("Oregano Files"));
+ gtk_file_filter_set_name (orefilter, _ ("Oregano Files"));
gtk_file_filter_add_pattern (orefilter, "*.oregano");
- gtk_file_filter_set_name (allfilter, _("All Files"));
+ gtk_file_filter_set_name (allfilter, _ ("All Files"));
gtk_file_filter_add_pattern (allfilter, "*");
-
- dialog = gtk_file_chooser_dialog_new (_("Save File"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
+
+ dialog = gtk_file_chooser_dialog_new (_ ("Save File"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Save"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), orefilter);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), allfilter);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
- name = gtk_file_chooser_get_filename (
- GTK_FILE_CHOOSER (dialog));
- if (name [strlen (name) - 1] != '/') {
+ name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (name[strlen (name) - 1] != '/') {
gchar *tmp;
const gchar *base = g_path_get_basename (name);
if (strchr (base, '.') == NULL) {
tmp = g_strconcat (name, ".oregano", NULL);
- }
- else {
+ } else {
tmp = g_strdup (name);
}
@@ -126,9 +123,7 @@ dialog_save_as (SchematicView *sv)
schematic_set_filename (sm, tmp);
if (!schematic_save_file (sm, &error)) {
- char *msg = g_strdup_printf (
- "Could not save Schematic file %s\n",
- tmp);
+ char *msg = g_strdup_printf ("Could not save Schematic file %s\n", tmp);
oregano_error (msg);
g_free (msg);
g_free (name);
@@ -140,52 +135,50 @@ dialog_save_as (SchematicView *sv)
gtk_widget_destroy (dialog);
}
-char *
-dialog_netlist_file (SchematicView *sv)
+char *dialog_netlist_file (SchematicView *sv)
{
GtkWidget *dialog;
char *name = NULL;
- dialog = gtk_file_chooser_dialog_new (_("Netlist File"),
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
+ dialog = gtk_file_chooser_dialog_new (_ ("Netlist File"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Save"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
- gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
- TRUE);
-
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (name[strlen (name) - 1] == '/') {
name = NULL;
- }
- else {
+ } else {
name = g_strdup (name);
}
- }
- else
+ } else
name = NULL;
gtk_widget_destroy (dialog);
return name;
}
-char *
-dialog_file_open (const gchar *title)
+char *dialog_file_open (const gchar *title)
{
GtkWidget *dialog;
char *name = NULL;
dialog = gtk_file_chooser_dialog_new (title,
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
- NULL);
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Save"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
@@ -193,11 +186,9 @@ dialog_file_open (const gchar *title)
if (name[strlen (name) - 1] == '/') {
g_free (name);
name = NULL;
- }
- else
+ } else
name = g_strdup (name);
- }
- else
+ } else
name = NULL;
gtk_widget_destroy (dialog);
diff --git a/src/file.h b/src/file.h
index 89173e0..497d37b 100644
--- a/src/file.h
+++ b/src/file.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __FILE_H
@@ -38,7 +38,7 @@
#include "schematic-view.h"
char *dialog_open_file (SchematicView *sv);
-void dialog_save_as (SchematicView *sv);
+void dialog_save_as (SchematicView *sv);
char *dialog_netlist_file (SchematicView *sv);
char *dialog_file_open (const gchar *file);
diff --git a/src/gplot/Makefile.am b/src/gplot/Makefile.am
deleted file mode 100644
index a7dd460..0000000
--- a/src/gplot/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
-oreganodir = $(datadir)/oregano
-
-AM_CFLAGS = -Wall -DG_DISABLE_DEPRECATED -DGSEAL_ENABLE \
- -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED \
- -DGTK_DISABLE_DEPRECATED -DGTK_DISABLE_SINGLE_INCLUDES \
- -DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES
-
-INCLUDES = \
- $(OREGANO_CFLAGS)
-
-noinst_LIBRARIES = libgplot.a
-libgplot_a_SOURCES = \
- gplot.c \
- gplotfunction.c \
- gplotfunction.h \
- gplot-internal.h \
- gplot.h \
- gplotlines.c \
- gplotlines.h
diff --git a/src/gplot/gplot-internal.h b/src/gplot/gplot-internal.h
index 90a1aee..2e3aecf 100644
--- a/src/gplot/gplot-internal.h
+++ b/src/gplot/gplot-internal.h
@@ -3,8 +3,8 @@
*
* Authors:
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -22,8 +22,8 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _GPLOT_INTERNAL_H_
@@ -41,30 +41,33 @@
typedef struct _GPlotClass GPlotClass;
typedef struct _GPlotPriv GPlotPriv;
-
-struct _GPlot {
+struct _GPlot
+{
GtkLayout parent;
GPlotPriv *priv;
};
-struct _GPlotClass {
+struct _GPlotClass
+{
GtkLayoutClass parent_class;
};
-
// Internal definitions associated to gplotfunction.h
-#define TYPE_GPLOT_FUNCTION (g_plot_function_get_type ())
-#define GPLOT_FUNCTION_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, TYPE_GPLOT_FUNCTION, GPlotFunctionClass)
-#define GPLOT_FUNCTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TYPE_GPLOT_FUNCTION, GPlotFunctionClass))
+#define TYPE_GPLOT_FUNCTION (g_plot_function_get_type ())
+#define GPLOT_FUNCTION_CLASS(klass) \
+ G_TYPE_CHECK_CLASS_CAST (klass, TYPE_GPLOT_FUNCTION, GPlotFunctionClass)
+#define GPLOT_FUNCTION_GET_CLASS(inst) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TYPE_GPLOT_FUNCTION, GPlotFunctionClass))
typedef struct _GPlotFunctionClass GPlotFunctionClass;
-struct _GPlotFunctionClass {
+struct _GPlotFunctionClass
+{
GTypeInterface parent;
- void (*draw) (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
- void (*get_bbox) (GPlotFunction *, GPlotFunctionBBox *);
+ void (*draw)(GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
+ void (*get_bbox)(GPlotFunction *, GPlotFunctionBBox *);
};
#endif
diff --git a/src/gplot/gplot.c b/src/gplot/gplot.c
index 9f50432..185f6cc 100644
--- a/src/gplot/gplot.c
+++ b/src/gplot/gplot.c
@@ -4,12 +4,14 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,8 +25,8 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
@@ -34,10 +36,10 @@
#define BORDER_SIZE 50
-static void g_plot_class_init (GPlotClass* class);
-static void g_plot_init (GPlot* plot);
-static gboolean g_plot_draw (GtkWidget* widget, cairo_t *cr);
-static cairo_t* g_plot_create_cairo (GPlot *);
+static void g_plot_class_init (GPlotClass *class);
+static void g_plot_init (GPlot *plot);
+static gboolean g_plot_draw (GtkWidget *widget, cairo_t *cr);
+static cairo_t *g_plot_create_cairo (GPlot *);
static gboolean g_plot_motion_cb (GtkWidget *, GdkEventMotion *, GPlot *);
static gboolean g_plot_button_press_cb (GtkWidget *, GdkEventButton *, GPlot *);
static gboolean g_plot_button_release_cb (GtkWidget *, GdkEventButton *, GPlot *);
@@ -47,17 +49,12 @@ static void g_plot_dispose (GObject *object);
static void get_order_of_magnitude (gdouble val, gdouble *man, gdouble *pw);
-enum {
- ACTION_NONE,
- ACTION_STARTING_PAN,
- ACTION_PAN,
- ACTION_STARTING_REGION,
- ACTION_REGION
-};
+enum { ACTION_NONE, ACTION_STARTING_PAN, ACTION_PAN, ACTION_STARTING_REGION, ACTION_REGION };
+
+static GtkLayoutClass *parent_class = NULL;
-static GtkLayoutClass* parent_class = NULL;
-
-struct _GPlotPriv {
+struct _GPlotPriv
+{
GList *functions;
gchar *xlabel;
@@ -75,8 +72,8 @@ struct _GPlotPriv {
gdouble zoom;
gdouble offset_x;
gdouble offset_y;
- gdouble last_x;
- gdouble last_y;
+ gdouble press_x;
+ gdouble press_y;
// Window->Viewport * Transformation Matrix
cairo_matrix_t matrix;
@@ -86,36 +83,31 @@ struct _GPlotPriv {
GPlotFunctionBBox viewport_bbox;
GPlotFunctionBBox rubberband;
+
+#if GTK_CHECK_VERSION(3,22,0)
+ GdkDrawingContext *gdk_ctx;
+
+ cairo_region_t *region;
+#endif
};
-GType
-g_plot_get_type ()
+GType g_plot_get_type ()
{
static GType g_plot_type = 0;
-
+
if (!g_plot_type) {
static const GTypeInfo g_plot_info = {
- sizeof (GPlotClass),
- NULL,
- NULL,
- (GClassInitFunc) g_plot_class_init,
- NULL,
- NULL,
- sizeof (GPlot),
- 0,
- (GInstanceInitFunc) g_plot_init,
- NULL
- };
+ sizeof(GPlotClass), NULL, NULL, (GClassInitFunc)g_plot_class_init, NULL,
+ NULL, sizeof(GPlot), 0, (GInstanceInitFunc)g_plot_init, NULL};
g_plot_type = g_type_register_static (GTK_TYPE_LAYOUT, "GPlot", &g_plot_info, 0);
}
return g_plot_type;
}
-static void
-g_plot_class_init (GPlotClass* class)
+static void g_plot_class_init (GPlotClass *class)
{
- GObjectClass* object_class;
- GtkWidgetClass* widget_class;
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (class);
widget_class = GTK_WIDGET_CLASS (class);
@@ -127,32 +119,35 @@ g_plot_class_init (GPlotClass* class)
object_class->finalize = g_plot_finalize;
}
-static cairo_t*
-g_plot_create_cairo (GPlot *p)
+static cairo_t *g_plot_create_cairo (GPlot *p)
{
+ GdkWindow *window;
cairo_t *cr;
- cr = gdk_cairo_create (gtk_layout_get_bin_window (GTK_LAYOUT (p)));
+ window = gtk_layout_get_bin_window (GTK_LAYOUT (p));
+
+#if GTK_CHECK_VERSION(3,22,0)
+ p->priv->region = gdk_window_get_clip_region (window);
+ p->priv->gdk_ctx = gdk_window_begin_draw_frame (window, p->priv->region);
+ cr = gdk_drawing_context_get_cairo_context (p->priv->gdk_ctx);
+#else
+ cr = gdk_cairo_create (window);
+#endif
return cr;
}
-static void
-g_plot_finalize (GObject *object)
+static void g_plot_finalize (GObject *object)
{
GPlot *p = GPLOT (object);
- if (p->priv->xlabel)
- g_free (p->priv->xlabel);
-
- if (p->priv->ylabel)
- g_free (p->priv->ylabel);
+ g_free (p->priv->xlabel);
+ g_free (p->priv->ylabel);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-g_plot_dispose (GObject *object)
+static void g_plot_dispose (GObject *object)
{
GList *lst;
GPlot *plot;
@@ -172,40 +167,39 @@ g_plot_dispose (GObject *object)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
-static int
-get_best_exponent (int div)
+static int get_best_exponent (int div)
{
// http://en.wikipedia.org/wiki/Micro
switch (div) {
- case -24:
- case -21:
- case -18:
- case -15:
- case -12:
- case -9:
- case -6:
- case -3:
- case 0:
- case 3:
- case 6:
- case 9:
- case 12:
- case 15:
- case 18:
- case 21:
- case 24:
- return div;
+ case -24:
+ case -21:
+ case -18:
+ case -15:
+ case -12:
+ case -9:
+ case -6:
+ case -3:
+ case 0:
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ case 18:
+ case 21:
+ case 24:
+ return div;
}
- if (div == -1) return -3;
+ if (div == -1)
+ return -3;
if ((div - 1) % 3 == 0)
return div - 1;
return div + 1;
}
-void
-draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max,
- gboolean vertical, gint *div)
+void draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max, gboolean vertical,
+ gint *div)
{
gchar *label;
cairo_text_extents_t extents;
@@ -218,7 +212,7 @@ draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max,
get_order_of_magnitude (min, &man1, &pw1);
get_order_of_magnitude (max, &man2, &pw2);
- (*div) = get_best_exponent ((pw2+pw1) / 2.0 + 0.5);
+ (*div) = get_best_exponent ((pw2 + pw1) / 2.0 + 0.5);
if ((*div) == 0)
divisor = 1;
else
@@ -229,9 +223,9 @@ draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max,
else
s = (bbox->xmax - bbox->xmin) / 10.0;
- for (i = (vertical?bbox->ymin:bbox->xmin), j = max;
- i <= (vertical?bbox->ymax:bbox->xmax) + 0.5; i += s, j -= step) {
- label = g_strdup_printf ("%.2f", j / divisor);
+ for (i = (vertical ? bbox->ymin : bbox->xmin), j = max;
+ i <= (vertical ? bbox->ymax : bbox->xmax) + 0.5; i += s, j -= step) {
+ label = g_strdup_printf ("%.*f", MAX(0, (int)(2 - floor(log10(fabs((max - min)/divisor))))), j / divisor);
cairo_text_extents (cr, label, &extents);
if (vertical) {
@@ -239,10 +233,9 @@ draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max,
y1 = i;
x2 = bbox->xmin + 4;
y2 = i;
- x3 = bbox->xmin - extents.width * 1.5;
+ x3 = bbox->xmin - extents.width - 6;
y3 = i + extents.height / 2.0;
- }
- else {
+ } else {
x1 = i;
y1 = bbox->ymax - 4;
x2 = i;
@@ -254,48 +247,69 @@ draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max,
cairo_move_to (cr, x1, y1);
cairo_line_to (cr, x2, y2);
cairo_move_to (cr, x3, y3);
+ if (!vertical && extents.width > s - 5) {
+ cairo_save(cr);
+ cairo_rotate(cr, M_PI/10);
+ }
cairo_show_text (cr, label);
+ if (!vertical && extents.width > s - 5) {
+ cairo_restore(cr);
+ }
g_free (label);
}
cairo_stroke (cr);
}
-static gchar*
-get_unit_text (int div)
+static gchar *get_unit_text (int div)
{
// http://en.wikipedia.org/wiki/Micro
switch (div) {
- case -24: return g_strdup ("y");
- case -21: return g_strdup ("z");
- case -18: return g_strdup ("a");
- case -15: return g_strdup ("f");
- case -12: return g_strdup ("p");
- case -9: return g_strdup ("n");
- case -6: return g_strdup ("\302\265");
- case -3: return g_strdup ("m");
- case 0: return g_strdup ("");
- case 3: return g_strdup ("k");
- case 6: return g_strdup ("M");
- case 9: return g_strdup ("G");
- case 12: return g_strdup ("T");
- case 15: return g_strdup ("P");
- case 18: return g_strdup ("E");
- case 21: return g_strdup ("Z");
- case 24: return g_strdup ("Y");
+ case -24:
+ return g_strdup ("y");
+ case -21:
+ return g_strdup ("z");
+ case -18:
+ return g_strdup ("a");
+ case -15:
+ return g_strdup ("f");
+ case -12:
+ return g_strdup ("p");
+ case -9:
+ return g_strdup ("n");
+ case -6:
+ return g_strdup ("\302\265");
+ case -3:
+ return g_strdup ("m");
+ case 0:
+ return g_strdup ("");
+ case 3:
+ return g_strdup ("k");
+ case 6:
+ return g_strdup ("M");
+ case 9:
+ return g_strdup ("G");
+ case 12:
+ return g_strdup ("T");
+ case 15:
+ return g_strdup ("P");
+ case 18:
+ return g_strdup ("E");
+ case 21:
+ return g_strdup ("Z");
+ case 24:
+ return g_strdup ("Y");
}
return g_strdup_printf ("10e%02d", div);
}
-static gboolean
-g_plot_draw (GtkWidget* widget, cairo_t *cr)
+static gboolean g_plot_draw (GtkWidget *widget, cairo_t *cr)
{
- static double dashes[] =
- {3, // ink
- 3, // skip
- 3, // ink
- 3}; // skip
- static int ndash = sizeof (dashes) / sizeof (dashes[0]);
+ static double dashes[] = {3, // ink
+ 3, // skip
+ 3, // ink
+ 3}; // skip
+ static int ndash = sizeof(dashes) / sizeof(dashes[0]);
static double offset = -0.2;
GPlot *plot;
@@ -325,19 +339,19 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
// Paint background
cairo_save (cr);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, 0, 0, width, height);
- cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_fill (cr);
cairo_restore (cr);
// Plot Border
cairo_save (cr);
- cairo_set_line_width (cr, 0.5);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
- cairo_stroke (cr);
+ cairo_set_line_width (cr, 0.5);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
+ cairo_stroke (cr);
cairo_restore (cr);
-
+
priv->viewport_bbox.xmax = width - priv->right_border;
priv->viewport_bbox.xmin = priv->left_border;
priv->viewport_bbox.ymax = height - priv->bottom_border;
@@ -345,75 +359,92 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
// Calculating Window to Viewport matrix
aX = (priv->viewport_bbox.xmax - priv->viewport_bbox.xmin) /
- (priv->window_bbox.xmax - priv->window_bbox.xmin);
+ (priv->window_bbox.xmax - priv->window_bbox.xmin);
bX = -aX * priv->window_bbox.xmin + priv->viewport_bbox.xmin;
aY = (priv->viewport_bbox.ymax - priv->viewport_bbox.ymin) /
- (priv->window_bbox.ymin - priv->window_bbox.ymax);
+ (priv->window_bbox.ymin - priv->window_bbox.ymax);
bY = -aY * priv->window_bbox.ymax + priv->viewport_bbox.ymin;
cairo_matrix_init (&priv->matrix, aX, 0, 0, aY, bX, bY);
+ //plot functions
cairo_save (cr);
- cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
- cairo_clip (cr);
+ cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
+ cairo_clip (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_set_matrix (cr, &priv->matrix);
- lst = plot->priv->functions;
- while (lst) {
- f = (GPlotFunction *)lst->data;
- g_plot_function_draw (f, cr, &priv->window_bbox);
- lst = lst->next;
- }
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_transform(cr, &priv->matrix);
+ lst = plot->priv->functions;
+ while (lst) {
+ f = (GPlotFunction *)lst->data;
+ g_plot_function_draw (f, cr, &priv->window_bbox);
+ lst = lst->next;
+ }
cairo_restore (cr);
+ //plot red axis
cairo_save (cr);
+ {
cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
cairo_clip (cr);
+ //plot x axis
cairo_save (cr);
- cairo_set_matrix (cr, &priv->matrix);
+ {
+ cairo_transform(cr, &priv->matrix);
cairo_move_to (cr, priv->window_bbox.xmin, 0.0);
cairo_line_to (cr, priv->window_bbox.xmax, 0.0);
+ }
cairo_restore (cr);
cairo_save (cr);
+ {
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
+ }
cairo_restore (cr);
+ //plot y axis
cairo_save (cr);
- cairo_set_matrix (cr, &priv->matrix);
+ {
+ cairo_transform(cr, &priv->matrix);
cairo_move_to (cr, 0.0, priv->window_bbox.ymin);
cairo_line_to (cr, 0.0, priv->window_bbox.ymax);
+ }
cairo_restore (cr);
cairo_save (cr);
+ {
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
+ }
cairo_restore (cr);
+ }
cairo_restore (cr);
+ //plot axis ticks
cairo_save (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_set_line_width (cr, 1);
-
- draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.ymin, priv->window_bbox.ymax, TRUE, &div);
- if (priv->ylabel_unit) {
- g_free (priv->ylabel_unit);
- priv->ylabel_unit = NULL;
- }
- if (div != 1)
- priv->ylabel_unit = get_unit_text (div);
- draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.xmax, priv->window_bbox.xmin, FALSE, &div);
- if (priv->xlabel_unit) {
- g_free (priv->xlabel_unit);
- priv->xlabel_unit = NULL;
- }
- if (div != 1)
- priv->xlabel_unit = get_unit_text (div);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_line_width (cr, 1);
+
+ draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.ymin, priv->window_bbox.ymax, TRUE,
+ &div);
+ if (priv->ylabel_unit) {
+ g_free (priv->ylabel_unit);
+ priv->ylabel_unit = NULL;
+ }
+ if (div != 1)
+ priv->ylabel_unit = get_unit_text (div);
+ draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.xmax, priv->window_bbox.xmin, FALSE,
+ &div);
+ if (priv->xlabel_unit) {
+ g_free (priv->xlabel_unit);
+ priv->xlabel_unit = NULL;
+ }
+ if (div != 1)
+ priv->xlabel_unit = get_unit_text (div);
cairo_restore (cr);
- // Axis Labels
+ // Axis x Label
if (priv->xlabel) {
char *txt;
if (priv->xlabel_unit == NULL)
@@ -422,16 +453,17 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
txt = g_strdup_printf ("%s %s", priv->xlabel_unit, priv->xlabel);
cairo_save (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_set_font_size (cr, 14);
- cairo_text_extents (cr, txt, &extents);
- cairo_move_to (cr, width/2.0 - extents.width/2.0, height-extents.height/2.0);
- cairo_show_text (cr, txt);
- cairo_stroke (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, txt, &extents);
+ cairo_move_to (cr, width / 2.0 - extents.width / 2.0, height - extents.height / 2.0);
+ cairo_show_text (cr, txt);
+ cairo_stroke (cr);
cairo_restore (cr);
g_free (txt);
}
+ //axis y label
if (priv->ylabel) {
char *txt;
if (priv->ylabel_unit == NULL)
@@ -440,16 +472,17 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
txt = g_strdup_printf ("%s %s", priv->ylabel_unit, priv->ylabel);
cairo_save (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_set_font_size (cr, 14);
- cairo_text_extents (cr, txt, &extents);
- cairo_move_to (cr, extents.height, height/2.0 + extents.width/2.0);
- cairo_rotate (cr, 4.7124);
- cairo_show_text (cr, txt);
- cairo_stroke (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, txt, &extents);
+ cairo_move_to (cr, extents.height, height / 2.0 + extents.width / 2.0);
+ cairo_rotate (cr, 4.7124);
+ cairo_show_text (cr, txt);
+ cairo_stroke (cr);
cairo_restore (cr);
}
+ //plot rubberband (zoom-in-rectangle)
if (priv->action == ACTION_REGION) {
gdouble x, y, w, h;
x = priv->rubberband.xmin;
@@ -457,13 +490,12 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
w = priv->rubberband.xmax;
h = priv->rubberband.ymax;
cairo_save (cr);
- cairo_identity_matrix (cr);
- cairo_set_dash (cr, dashes, ndash, offset);
+ cairo_set_dash (cr, dashes, ndash, offset);
- cairo_set_line_width (cr, 2);
- cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
- cairo_rectangle (cr, x, y, w-x, h-y);
- cairo_stroke (cr);
+ cairo_set_line_width (cr, 2);
+ cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
+ cairo_rectangle (cr, x, y, w - x, h - y);
+ cairo_stroke (cr);
cairo_restore (cr);
}
g_list_free_full (lst, g_object_unref);
@@ -471,13 +503,12 @@ g_plot_draw (GtkWidget* widget, cairo_t *cr)
return FALSE;
}
-static void
-g_plot_init (GPlot* plot)
+static void g_plot_init (GPlot *plot)
{
plot->priv = g_new0 (GPlotPriv, 1);
plot->priv->zoom_mode = GPLOT_ZOOM_REGION;
- plot->priv->functions = NULL;
+ plot->priv->functions = NULL;
plot->priv->action = ACTION_NONE;
plot->priv->zoom = 1.0;
plot->priv->offset_x = 0.0;
@@ -492,31 +523,28 @@ g_plot_init (GPlot* plot)
plot->priv->ylabel_unit = NULL;
}
-GtkWidget*
-g_plot_new ()
+GtkWidget *g_plot_new ()
{
GPlot *plot;
plot = GPLOT (g_object_new (TYPE_GPLOT, NULL));
- gtk_widget_add_events (GTK_WIDGET (plot),
- GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|
- GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_MOTION_MASK|
- GDK_BUTTON1_MOTION_MASK|GDK_BUTTON2_MOTION_MASK|
- GDK_BUTTON3_MOTION_MASK);
-
- g_signal_connect (G_OBJECT (plot), "motion-notify-event",
- G_CALLBACK (g_plot_motion_cb), plot);
- g_signal_connect (G_OBJECT (plot), "button-press-event",
- G_CALLBACK (g_plot_button_press_cb), plot);
- g_signal_connect (G_OBJECT (plot), "button-release-event",
+ gtk_widget_add_events (GTK_WIDGET (plot), GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK);
+
+ g_signal_connect (G_OBJECT (plot), "motion-notify-event", G_CALLBACK (g_plot_motion_cb), plot);
+ g_signal_connect (G_OBJECT (plot), "button-press-event", G_CALLBACK (g_plot_button_press_cb),
+ plot);
+ g_signal_connect (G_OBJECT (plot), "button-release-event",
G_CALLBACK (g_plot_button_release_cb), plot);
return GTK_WIDGET (plot);
}
-int
-g_plot_add_function (GPlot *plot, GPlotFunction *func)
+int g_plot_add_function (GPlot *plot, GPlotFunction *func)
{
g_return_val_if_fail (IS_GPLOT (plot), -1);
@@ -525,182 +553,177 @@ g_plot_add_function (GPlot *plot, GPlotFunction *func)
return 0;
}
-static gboolean
-g_plot_motion_cb (GtkWidget *w, GdkEventMotion *e, GPlot *p)
+static gboolean g_plot_motion_cb (GtkWidget *w, GdkEventMotion *e, GPlot *p)
{
- switch (p->priv->zoom_mode) {
- case GPLOT_ZOOM_INOUT:
- if ((p->priv->action == ACTION_STARTING_PAN) || (p->priv->action == ACTION_PAN)) {
- gdouble dx, dy;
- cairo_matrix_t t = p->priv->matrix;
- GdkCursor *cursor = gdk_cursor_new (GDK_FLEUR);
- gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
- gdk_flush ();
-
- dx = p->priv->last_x - e->x;
- dy = p->priv->last_y - e->y;
-
- cairo_matrix_invert (&t);
- cairo_matrix_transform_distance (&t, &dx, &dy);
-
- p->priv->window_bbox.xmin -= dx;
- p->priv->window_bbox.xmax -= dx;
- p->priv->window_bbox.ymin -= dy;
- p->priv->window_bbox.ymax -= dy;
+#if GTK_CHECK_VERSION (3,16,0)
+ GdkDisplay *display;
+ display = gtk_widget_get_display (w);
+#endif
- p->priv->last_x = e->x;
- p->priv->last_y = e->y;
- p->priv->action = ACTION_PAN;
- gtk_widget_queue_draw (w);
- }
+ switch (p->priv->zoom_mode) {
+ case GPLOT_ZOOM_INOUT:
+ if ((p->priv->action == ACTION_STARTING_PAN) || (p->priv->action == ACTION_PAN)) {
+ gdouble dx, dy;
+ cairo_matrix_t t = p->priv->matrix;
+#if GTK_CHECK_VERSION (3,16,0)
+ GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
+#else
+ GdkCursor *cursor = gdk_cursor_new (GDK_FLEUR);
+#endif
+ gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
+ gdk_flush ();
+
+ dx = p->priv->press_x - e->x;
+ dy = p->priv->press_y - e->y;
+
+ cairo_matrix_invert (&t);
+ cairo_matrix_transform_distance (&t, &dx, &dy);
+
+ p->priv->window_bbox.xmin -= dx;
+ p->priv->window_bbox.xmax -= dx;
+ p->priv->window_bbox.ymin -= dy;
+ p->priv->window_bbox.ymax -= dy;
+
+ p->priv->press_x = e->x;
+ p->priv->press_y = e->y;
+ p->priv->action = ACTION_PAN;
+ gtk_widget_queue_draw (w);
+ }
break;
- case GPLOT_ZOOM_REGION:
- if ((p->priv->action == ACTION_STARTING_REGION) || (p->priv->action == ACTION_REGION)) {
- gdouble dx, dy;
- GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);
- gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
- gdk_flush ();
-
- /* dx < 0 == moving to the left */
- dx = e->x - p->priv->last_x;
- dy = e->y - p->priv->last_y;
-
- if (dx < 0) {
- p->priv->rubberband.xmin = e->x;
- }
- else {
- p->priv->rubberband.xmax = e->x;
- }
- if (dy < 0) {
- p->priv->rubberband.ymin = e->y;
- }
- else {
- p->priv->rubberband.ymax = e->y;
- }
-
- p->priv->action = ACTION_REGION;
- gtk_widget_queue_draw (w);
- }
+ case GPLOT_ZOOM_REGION:
+ if ((p->priv->action == ACTION_STARTING_REGION) || (p->priv->action == ACTION_REGION)) {
+#if GTK_CHECK_VERSION (3,16,0)
+ GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_CROSS);
+#else
+ GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);
+#endif
+ gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
+ gdk_flush ();
+
+ p->priv->rubberband.xmin = MIN(e->x, p->priv->press_x);
+ p->priv->rubberband.xmax = MAX(e->x, p->priv->press_x);
+
+ p->priv->rubberband.ymin = MIN(e->y, p->priv->press_y);
+ p->priv->rubberband.ymax = MAX(e->y, p->priv->press_y);
+
+ p->priv->action = ACTION_REGION;
+ gtk_widget_queue_draw (w);
+ }
}
return FALSE;
}
-static gboolean
-g_plot_button_press_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
+static gboolean g_plot_button_press_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
{
g_return_val_if_fail (IS_GPLOT (p), TRUE);
if (e->type == GDK_2BUTTON_PRESS) {
/* TODO : Check function below cursor and open a property dialog :) */
- }
- else {
+ } else {
switch (p->priv->zoom_mode) {
- case GPLOT_ZOOM_INOUT:
- if (e->button == 1) {
- p->priv->action = ACTION_STARTING_PAN;
- p->priv->last_x = e->x;
- p->priv->last_y = e->y;
- }
+ case GPLOT_ZOOM_INOUT:
+ if (e->button == 1) {
+ p->priv->action = ACTION_STARTING_PAN;
+ p->priv->press_x = e->x;
+ p->priv->press_y = e->y;
+ }
break;
- case GPLOT_ZOOM_REGION:
- if ((e->button == 1)) {
- p->priv->action = ACTION_STARTING_REGION;
- p->priv->rubberband.xmin = e->x;
- p->priv->rubberband.ymin = e->y;
- p->priv->rubberband.xmax = e->x;
- p->priv->rubberband.ymax = e->y;
- p->priv->last_x = e->x;
- p->priv->last_y = e->y;
- }
+ case GPLOT_ZOOM_REGION:
+ if (e->button == 1) {
+ p->priv->action = ACTION_STARTING_REGION;
+ p->priv->rubberband.xmin = e->x;
+ p->priv->rubberband.ymin = e->y;
+ p->priv->rubberband.xmax = e->x;
+ p->priv->rubberband.ymax = e->y;
+ p->priv->press_x = e->x;
+ p->priv->press_y = e->y;
+ }
}
}
return TRUE;
}
-static gboolean
-g_plot_button_release_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
+static gboolean g_plot_button_release_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
{
gdouble zoom = 0.0;
g_return_val_if_fail (IS_GPLOT (p), TRUE);
switch (p->priv->zoom_mode) {
- case GPLOT_ZOOM_INOUT:
- if (p->priv->action != ACTION_PAN) {
- switch (e->button) {
- case 1:
- p->priv->zoom += 0.1;
- zoom = 1.1;
- break;
- case 3:
- p->priv->zoom -= 0.1;
- zoom = 0.9;
- }
- p->priv->window_bbox.xmin /= zoom;
- p->priv->window_bbox.xmax /= zoom;
- p->priv->window_bbox.ymin /= zoom;
- p->priv->window_bbox.ymax /= zoom;
- gtk_widget_queue_draw (w);
- }
- else {
- gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
- gdk_flush ();
+ case GPLOT_ZOOM_INOUT:
+ if (p->priv->action != ACTION_PAN) {
+ switch (e->button) {
+ case 1:
+ p->priv->zoom += 0.1;
+ zoom = 1.1;
+ break;
+ case 3:
+ p->priv->zoom -= 0.1;
+ zoom = 0.9;
}
+ p->priv->window_bbox.xmin /= zoom;
+ p->priv->window_bbox.xmax /= zoom;
+ p->priv->window_bbox.ymin /= zoom;
+ p->priv->window_bbox.ymax /= zoom;
+ gtk_widget_queue_draw (w);
+ } else {
+ gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
+ gdk_flush ();
+ }
break;
- case GPLOT_ZOOM_REGION:
- if ((e->button == 1) && (p->priv->action == ACTION_REGION)) {
- gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
- gdk_flush ();
- {
- gdouble x1, y1, x2, y2;
- cairo_matrix_t t = p->priv->matrix;
- cairo_matrix_invert (&t);
-
- x1 = p->priv->rubberband.xmin;
- y1 = p->priv->rubberband.ymin;
- x2 = p->priv->rubberband.xmax;
- y2 = p->priv->rubberband.ymax;
-
- cairo_matrix_transform_point (&t, &x1, &y1);
- cairo_matrix_transform_point (&t, &x2, &y2);
-
- p->priv->window_bbox.xmin = x1;
- p->priv->window_bbox.xmax = x2;
- p->priv->window_bbox.ymin = y2;
- p->priv->window_bbox.ymax = y1;
- }
- }
- else if (e->button == 3) {
- gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
- gdk_flush ();
+ case GPLOT_ZOOM_REGION:
+ if ((e->button == 1) && (p->priv->action == ACTION_REGION)) {
+ gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
+ gdk_flush ();
+
+ if (e->x < p->priv->press_x || e->y < p->priv->press_y) {
+ g_plot_reset_zoom(p);
+ } else {
+ gdouble x1, y1, x2, y2;
+ cairo_matrix_t t = p->priv->matrix;
+ cairo_matrix_invert (&t);
+
+ x1 = p->priv->rubberband.xmin;
+ y1 = p->priv->rubberband.ymin;
+ x2 = p->priv->rubberband.xmax;
+ y2 = p->priv->rubberband.ymax;
+
+ cairo_matrix_transform_point (&t, &x1, &y1);
+ cairo_matrix_transform_point (&t, &x2, &y2);
+
+ p->priv->window_bbox.xmin = x1;
+ p->priv->window_bbox.xmax = x2;
+ p->priv->window_bbox.ymin = y2;
+ p->priv->window_bbox.ymax = y1;
}
- gtk_widget_queue_draw (w);
+ } else if (e->button == 3) {
+ gdk_window_set_cursor (gtk_widget_get_window (w), NULL);
+ gdk_flush ();
+ }
+ gtk_widget_queue_draw (w);
}
p->priv->action = ACTION_NONE;
return TRUE;
}
-void
-g_plot_set_zoom_mode (GPlot *p, guint mode)
+void g_plot_set_zoom_mode (GPlot *p, guint mode)
{
g_return_if_fail (IS_GPLOT (p));
p->priv->zoom_mode = mode;
}
-guint
-g_plot_get_zoom_mode (GPlot *p)
+guint g_plot_get_zoom_mode (GPlot *p)
{
g_return_val_if_fail (IS_GPLOT (p), 0);
return p->priv->zoom_mode;
}
-static void
-g_plot_update_bbox (GPlot *p)
+static void g_plot_update_bbox (GPlot *p)
{
GPlotFunction *f;
GPlotFunctionBBox bbox;
@@ -738,8 +761,7 @@ g_plot_update_bbox (GPlot *p)
priv->window_valid = TRUE;
}
-void
-g_plot_reset_zoom (GPlot *p)
+void g_plot_reset_zoom (GPlot *p)
{
g_return_if_fail (IS_GPLOT (p));
@@ -748,8 +770,7 @@ g_plot_reset_zoom (GPlot *p)
gtk_widget_queue_draw (GTK_WIDGET (p));
}
-void
-g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
+void g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
{
cairo_text_extents_t extents;
@@ -760,12 +781,16 @@ g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_set_font_size (cr, 14);
cairo_text_extents (cr, x, &extents);
+#if GTK_CHECK_VERSION(3,22,0)
+ gdk_window_end_draw_frame (gtk_layout_get_bin_window (GTK_LAYOUT (p)) , p->priv->gdk_ctx);
+ cairo_region_destroy (p->priv->region);
+#else
cairo_destroy (cr);
+#endif
p->priv->xlabel = g_strdup (x);
p->priv->bottom_border = BORDER_SIZE + extents.height;
- }
- else {
+ } else {
p->priv->bottom_border = BORDER_SIZE;
if (p->priv->xlabel) {
g_free (p->priv->xlabel);
@@ -778,14 +803,18 @@ g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_set_font_size (cr, 14);
cairo_text_extents (cr, y, &extents);
+#if GTK_CHECK_VERSION(3,22,0)
+ gdk_window_end_draw_frame (gtk_layout_get_bin_window (GTK_LAYOUT (p)) , p->priv->gdk_ctx);
+ cairo_region_destroy (p->priv->region);
+#else
cairo_destroy (cr);
+#endif
p->priv->xlabel = g_strdup (x);
p->priv->left_border = BORDER_SIZE + extents.height;
p->priv->ylabel = g_strdup (y);
- }
- else {
+ } else {
p->priv->left_border = BORDER_SIZE;
if (p->priv->ylabel) {
g_free (p->priv->ylabel);
@@ -794,8 +823,7 @@ g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
}
}
-void
-g_plot_clear (GPlot *plot)
+void g_plot_clear (GPlot *plot)
{
GList *lst;
@@ -814,8 +842,7 @@ g_plot_clear (GPlot *plot)
g_list_free (lst);
}
-void
-g_plot_window_to_device (GPlot *plot, double *x, double *y)
+void g_plot_window_to_device (GPlot *plot, double *x, double *y)
{
cairo_t *cr;
@@ -825,18 +852,23 @@ g_plot_window_to_device (GPlot *plot, double *x, double *y)
cr = g_plot_create_cairo (plot);
cairo_set_matrix (cr, &plot->priv->matrix);
cairo_device_to_user (cr, x, y);
+
+#if GTK_CHECK_VERSION(3,22,0)
+ gdk_window_end_draw_frame (gtk_layout_get_bin_window (GTK_LAYOUT (plot)) , plot->priv->gdk_ctx);
+ cairo_region_destroy (plot->priv->region);
+#else
cairo_destroy (cr);
+#endif
}
-static void
-get_order_of_magnitude (gdouble val, gdouble *man, gdouble *pw)
+static void get_order_of_magnitude (gdouble val, gdouble *man, gdouble *pw)
{
gdouble b;
gdouble sx;
b = (val != 0.0 ? log10 (fabs (val)) / 3.0 : 0.0);
- b = 3.0 * rint (b);
+ b = 3.0 * rint (b);
sx = (b != 0.0 ? pow (10.0, b) : 1.0);
*man = val / sx;
- *pw = b;
+ *pw = b;
}
diff --git a/src/gplot/gplot.h b/src/gplot/gplot.h
index a03c31c..8b269ff 100644
--- a/src/gplot/gplot.h
+++ b/src/gplot/gplot.h
@@ -4,8 +4,8 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _GPLOT_H_
@@ -34,26 +34,25 @@
#include <gtk/gtk.h>
#include <glib.h>
-#define GPLOT(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT, GPlot)
-#define IS_GPLOT(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT)
-#define TYPE_GPLOT (g_plot_get_type())
+#define GPLOT(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT, GPlot)
+#define IS_GPLOT(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT)
+#define TYPE_GPLOT (g_plot_get_type ())
typedef struct _GPlot GPlot;
-typedef struct _GPlotFunction {} GPlotFunction;
+typedef struct _GPlotFunction
+{
+} GPlotFunction;
-enum {
- GPLOT_ZOOM_INOUT,
- GPLOT_ZOOM_REGION
-};
+enum { GPLOT_ZOOM_INOUT, GPLOT_ZOOM_REGION };
-GType g_plot_get_type ();
-GtkWidget* g_plot_new ();
-void g_plot_clear (GPlot *);
-int g_plot_add_function (GPlot *, GPlotFunction *);
-void g_plot_set_zoom_mode (GPlot *, guint);
-guint g_plot_get_zoom_mode (GPlot *);
-void g_plot_reset_zoom (GPlot *);
-void g_plot_set_axis_labels (GPlot *, gchar *, gchar *);
-void g_plot_window_to_device (GPlot *, double *x, double *y);
+GType g_plot_get_type ();
+GtkWidget *g_plot_new ();
+void g_plot_clear (GPlot *);
+int g_plot_add_function (GPlot *, GPlotFunction *);
+void g_plot_set_zoom_mode (GPlot *, guint);
+guint g_plot_get_zoom_mode (GPlot *);
+void g_plot_reset_zoom (GPlot *);
+void g_plot_set_axis_labels (GPlot *, gchar *, gchar *);
+void g_plot_window_to_device (GPlot *, double *x, double *y);
#endif
diff --git a/src/gplot/gplotfunction.c b/src/gplot/gplotfunction.c
index d88de06..1702116 100644
--- a/src/gplot/gplotfunction.c
+++ b/src/gplot/gplotfunction.c
@@ -4,8 +4,8 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -23,63 +23,55 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "gplot-internal.h"
#include "gplotfunction.h"
-
-static void
-g_plot_function_base_init (gpointer g_class)
+static void g_plot_function_base_init (gpointer g_class)
{
static gboolean initialized = FALSE;
if (!initialized) {
// create interface signals here.
initialized = TRUE;
- g_object_interface_install_property (g_class,
- g_param_spec_boolean ("visible",
- "gplot_function_visible",
- "Get/Set if function is visible",
- TRUE,
- G_PARAM_READWRITE));
+ g_object_interface_install_property (
+ g_class,
+ g_param_spec_boolean ("visible", "gplot_function_visible",
+ "Get/Set if function is visible", TRUE, G_PARAM_READWRITE));
}
}
-GType
-g_plot_function_get_type (void)
+GType g_plot_function_get_type (void)
{
static GType type = 0;
- if (type == 0) {
- static const GTypeInfo info = {
- sizeof (GPlotFunctionClass),
- g_plot_function_base_init, // base_init
- NULL, // base_finalize
- NULL, // class_init
- NULL, // class_finalize
- NULL, // class_data
- 0,
- 0, // n_preallocs
- NULL // instance_init
- };
- type = g_type_register_static (G_TYPE_INTERFACE, "GPlotFunction", &info, 0);
- }
- return type;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof(GPlotFunctionClass),
+ g_plot_function_base_init, // base_init
+ NULL, // base_finalize
+ NULL, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+ 0,
+ 0, // n_preallocs
+ NULL // instance_init
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE, "GPlotFunction", &info, 0);
+ }
+ return type;
}
-void
-g_plot_function_draw (GPlotFunction *self, cairo_t * cr, GPlotFunctionBBox *bbox)
+void g_plot_function_draw (GPlotFunction *self, cairo_t *cr, GPlotFunctionBBox *bbox)
{
- if (GPLOT_FUNCTION_GET_CLASS (self)->draw)
- GPLOT_FUNCTION_GET_CLASS (self)->draw (self, cr, bbox);
+ if (GPLOT_FUNCTION_GET_CLASS (self)->draw)
+ GPLOT_FUNCTION_GET_CLASS (self)->draw (self, cr, bbox);
}
-void
-g_plot_function_get_bbox (GPlotFunction *self, GPlotFunctionBBox *bbox)
+void g_plot_function_get_bbox (GPlotFunction *self, GPlotFunctionBBox *bbox)
{
- if (GPLOT_FUNCTION_GET_CLASS (self)->get_bbox)
- GPLOT_FUNCTION_GET_CLASS (self)->get_bbox (self, bbox);
+ if (GPLOT_FUNCTION_GET_CLASS (self)->get_bbox)
+ GPLOT_FUNCTION_GET_CLASS (self)->get_bbox (self, bbox);
}
-
diff --git a/src/gplot/gplotfunction.h b/src/gplot/gplotfunction.h
index bbd0e2f..6575317 100644
--- a/src/gplot/gplotfunction.h
+++ b/src/gplot/gplotfunction.h
@@ -5,8 +5,8 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
- *
+ * Web page: https://ahoi.io/project/oregano
+ *
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2010 Marc Lorber
@@ -23,8 +23,8 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _GPLOT_FUNCTION_H_
@@ -32,19 +32,20 @@
#include <gtk/gtk.h>
-#define GPLOT_FUNCTION(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT_FUNCTION, GPlotFunction)
-#define IS_GPLOT_FUNCTION(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT_FUNCTION)
+#define GPLOT_FUNCTION(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT_FUNCTION, GPlotFunction)
+#define IS_GPLOT_FUNCTION(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT_FUNCTION)
-typedef struct _GPlotFunctionBBox {
+typedef struct _GPlotFunctionBBox
+{
gdouble xmin;
gdouble ymin;
gdouble xmax;
gdouble ymax;
} GPlotFunctionBBox;
-void g_plot_function_draw (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
-void g_plot_function_get_bbox (GPlotFunction *, GPlotFunctionBBox *);
-void g_plot_function_set_visible (GPlotFunction *, gboolean);
+void g_plot_function_draw (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
+void g_plot_function_get_bbox (GPlotFunction *, GPlotFunctionBBox *);
+void g_plot_function_set_visible (GPlotFunction *, gboolean);
gboolean g_plot_function_get_visible (GPlotFunction *);
#endif
diff --git a/src/gplot/gplotlines.c b/src/gplot/gplotlines.c
index 9f1bf3e..5b7ab66 100644
--- a/src/gplot/gplotlines.c
+++ b/src/gplot/gplotlines.c
@@ -5,7 +5,7 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -23,8 +23,8 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
@@ -36,41 +36,36 @@ typedef struct _GPlotLines GPlotLines;
typedef struct _GPlotLinesPriv GPlotLinesPriv;
typedef struct _GPlotLinesClass GPlotLinesClass;
-struct _GPlotLines {
+struct _GPlotLines
+{
GObject parent;
GPlotLinesPriv *priv;
};
-struct _GPlotLinesClass {
+struct _GPlotLinesClass
+{
GObjectClass parent;
};
-GType g_plot_function_get_type ();
+GType g_plot_function_get_type ();
-static void g_plot_lines_class_init (GPlotLinesClass* class);
-static void g_plot_lines_init (GPlotLines* plot);
+static void g_plot_lines_class_init (GPlotLinesClass *class);
+static void g_plot_lines_init (GPlotLines *plot);
static void g_plot_lines_draw (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
static void g_plot_lines_get_bbox (GPlotFunction *, GPlotFunctionBBox *);
static void g_plot_lines_function_init (GPlotFunctionClass *iface);
-static void g_plot_lines_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-static void g_plot_lines_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *spec);
-
-static GObjectClass* parent_class = NULL;
-
-enum {
- ARG_0,
- ARG_WIDTH,
- ARG_COLOR,
- ARG_COLOR_GDKCOLOR,
- ARG_VISIBLE,
- ARG_GRAPH_TYPE,
- ARG_SHIFT
-};
+static void g_plot_lines_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void g_plot_lines_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec);
-struct _GPlotLinesPriv {
+static GObjectClass *parent_class = NULL;
+
+enum { ARG_0, ARG_WIDTH, ARG_COLOR, ARG_COLOR_GDKRGBA, ARG_VISIBLE, ARG_GRAPH_TYPE, ARG_SHIFT };
+
+struct _GPlotLinesPriv
+{
gboolean bbox_valid;
GPlotFunctionBBox bbox;
gdouble *x;
@@ -83,7 +78,7 @@ struct _GPlotLinesPriv {
// Line Color
gchar *color_string;
- GdkColor color;
+ GdkRGBA color;
// Graphic type
GraphicType graphic_type;
@@ -92,44 +87,37 @@ struct _GPlotLinesPriv {
gdouble shift;
};
-#define TYPE_GPLOT_LINES (g_plot_lines_get_type ())
-#define TYPE_GPLOT_GRAPHIC_TYPE (g_plot_lines_graphic_get_type ())
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#define TYPE_GPLOT_LINES (g_plot_lines_get_type ())
+#define TYPE_GPLOT_GRAPHIC_TYPE (g_plot_lines_graphic_get_type ())
+#include "debug.h"
G_DEFINE_TYPE_WITH_CODE (GPlotLines, g_plot_lines, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (TYPE_GPLOT_FUNCTION,
- g_plot_lines_function_init));
+ G_IMPLEMENT_INTERFACE (TYPE_GPLOT_FUNCTION, g_plot_lines_function_init));
-GType
-g_plot_lines_graphic_get_type (void)
+GType g_plot_lines_graphic_get_type (void)
{
static GType etype = 0;
- if (etype == 0) {
- static const GEnumValue values[] = {
- { FUNCTIONAL_CURVE, "FUNCTIONAL_CURVE", "funct-curve" },
- { FREQUENCY_PULSE, "FREQUENCY_PULSE", "freq-pulse" },
- { 0, NULL, NULL }
- };
- etype = g_enum_register_static ("GraphicType", values);
- }
- return etype;
+ if (etype == 0) {
+ static const GEnumValue values[] = {{FUNCTIONAL_CURVE, "FUNCTIONAL_CURVE", "funct-curve"},
+ {FREQUENCY_PULSE, "FREQUENCY_PULSE", "freq-pulse"},
+ {0, NULL, NULL}};
+ etype = g_enum_register_static ("GraphicType", values);
+ }
+ return etype;
}
-static void
-g_plot_lines_function_init (GPlotFunctionClass *iface)
+static void g_plot_lines_function_init (GPlotFunctionClass *iface)
{
iface->draw = g_plot_lines_draw;
iface->get_bbox = g_plot_lines_get_bbox;
}
-static void
-g_plot_lines_dispose (GObject *object)
+static void g_plot_lines_dispose (GObject *object)
{
- G_OBJECT_CLASS (parent_class)->dispose(object);
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
-static void
-g_plot_lines_finalize (GObject *object)
+static void g_plot_lines_finalize (GObject *object)
{
GPlotLines *lines;
@@ -145,14 +133,13 @@ g_plot_lines_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-g_plot_lines_class_init (GPlotLinesClass* class)
+static void g_plot_lines_class_init (GPlotLinesClass *class)
{
- GObjectClass* object_class;
+ GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
parent_class = g_type_class_peek_parent (class);
-
+
object_class->set_property = g_plot_lines_set_property;
object_class->get_property = g_plot_lines_get_property;
object_class->dispose = g_plot_lines_dispose;
@@ -161,31 +148,34 @@ g_plot_lines_class_init (GPlotLinesClass* class)
g_object_class_override_property (object_class, ARG_VISIBLE, "visible");
g_object_class_install_property (object_class, ARG_WIDTH,
- g_param_spec_double ("width", "GPlotLines::width",
- "the line width", 0.1, 5.0, 1.0, G_PARAM_READWRITE));
+ g_param_spec_double ("width", "GPlotLines::width",
+ "the line width", 0.1, 5.0, 1.0,
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class, ARG_COLOR,
- g_param_spec_string ("color", "GPlotLines::color",
- "the string color line", "white", G_PARAM_READWRITE));
+ g_param_spec_string ("color", "GPlotLines::color",
+ "the string color line", "white",
+ G_PARAM_READWRITE));
- g_object_class_install_property (object_class, ARG_COLOR_GDKCOLOR,
- g_param_spec_pointer ("color-rgb", "GPlotLines::color-rgb",
- "the GdkColor of the line", G_PARAM_READWRITE));
+ g_object_class_install_property (object_class, ARG_COLOR_GDKRGBA,
+ g_param_spec_pointer ("color-rgb", "GPlotLines::color-rgb",
+ "the GdkRGBA of the line",
+ G_PARAM_READWRITE));
- g_object_class_install_property (object_class, ARG_GRAPH_TYPE,
- g_param_spec_enum ("graph-type", "GPlotLines::graph-type",
- "the type of graphic", TYPE_GPLOT_GRAPHIC_TYPE,
- FUNCTIONAL_CURVE, G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, ARG_GRAPH_TYPE,
+ g_param_spec_enum ("graph-type", "GPlotLines::graph-type", "the type of graphic",
+ TYPE_GPLOT_GRAPHIC_TYPE, FUNCTIONAL_CURVE, G_PARAM_READWRITE));
g_object_class_install_property (object_class, ARG_SHIFT,
- g_param_spec_double ("shift", "GPlotLines::shift",
- "the shift for multiple pulses", 0.0, 500.0, 50.0, G_PARAM_READWRITE));
+ g_param_spec_double ("shift", "GPlotLines::shift",
+ "the shift for multiple pulses", 0.0,
+ 15e+10, 50.0, G_PARAM_READWRITE));
}
-static void
-g_plot_lines_init (GPlotLines* plot)
+static void g_plot_lines_init (GPlotLines *plot)
{
- GPlotLinesPriv* priv = g_new0 (GPlotLinesPriv, 1);
+ GPlotLinesPriv *priv = g_new0 (GPlotLinesPriv, 1);
priv->bbox_valid = FALSE;
@@ -194,41 +184,39 @@ g_plot_lines_init (GPlotLines* plot)
priv->width = 1.0;
priv->visible = TRUE;
priv->color_string = g_strdup ("white");
- memset (&priv->color, 0xFF, sizeof (GdkColor));
+ memset (&priv->color, 0xFF, sizeof(GdkRGBA));
}
-static void
-g_plot_lines_set_property (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *spec)
+static void g_plot_lines_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
{
GPlotLines *plot = GPLOT_LINES (object);
switch (prop_id) {
- case ARG_VISIBLE:
- plot->priv->visible = g_value_get_boolean (value);
- break;
- case ARG_WIDTH:
- plot->priv->width = g_value_get_double (value);
- break;
- case ARG_COLOR:
- g_free (plot->priv->color_string);
- plot->priv->color_string = g_strdup (g_value_get_string (value));
- gdk_color_parse (plot->priv->color_string, &plot->priv->color);
- break;
- case ARG_GRAPH_TYPE:
- plot->priv->graphic_type = g_value_get_enum (value);
- break;
- case ARG_SHIFT:
- plot->priv->shift = g_value_get_double (value);
- break;
- default:
- break;
+ case ARG_VISIBLE:
+ plot->priv->visible = g_value_get_boolean (value);
+ break;
+ case ARG_WIDTH:
+ plot->priv->width = g_value_get_double (value);
+ break;
+ case ARG_COLOR:
+ g_free (plot->priv->color_string);
+ plot->priv->color_string = g_strdup (g_value_get_string (value));
+ gdk_rgba_parse (&plot->priv->color, plot->priv->color_string);
+ break;
+ case ARG_GRAPH_TYPE:
+ plot->priv->graphic_type = g_value_get_enum (value);
+ break;
+ case ARG_SHIFT:
+ plot->priv->shift = g_value_get_double (value);
+ break;
+ default:
+ break;
}
}
-static void
-g_plot_lines_get_property (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec)
+static void g_plot_lines_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec)
{
GPlotLines *plot = GPLOT_LINES (object);
@@ -253,8 +241,7 @@ g_plot_lines_get_property (GObject *object, guint prop_id, GValue *value,
}
}
-GPlotFunction*
-g_plot_lines_new (gdouble *x, gdouble *y, guint points)
+GPlotFunction *g_plot_lines_new (gdouble *x, gdouble *y, guint points)
{
GPlotLines *plot;
@@ -266,8 +253,7 @@ g_plot_lines_new (gdouble *x, gdouble *y, guint points)
return GPLOT_FUNCTION (plot);
}
-static void
-g_plot_lines_get_bbox (GPlotFunction *f, GPlotFunctionBBox *bbox)
+static void g_plot_lines_get_bbox (GPlotFunction *f, GPlotFunctionBBox *bbox)
{
GPlotLines *plot;
@@ -300,11 +286,9 @@ g_plot_lines_get_bbox (GPlotFunction *f, GPlotFunctionBBox *bbox)
(*bbox) = plot->priv->bbox;
}
-
// This procedure is in charge to link points with ligne.
// Modified to only draw spectral ray for Fourier analysis.
-static void
-g_plot_lines_draw (GPlotFunction *f, cairo_t *cr, GPlotFunctionBBox *bbox)
+static void g_plot_lines_draw (GPlotFunction *f, cairo_t *cr, GPlotFunctionBBox *bbox)
{
gboolean first_point = TRUE;
guint point;
@@ -317,53 +301,49 @@ g_plot_lines_draw (GPlotFunction *f, cairo_t *cr, GPlotFunctionBBox *bbox)
plot = GPLOT_LINES (f);
- if (!plot->priv->visible) return;
+ if (!plot->priv->visible)
+ return;
points = plot->priv->points;
x = plot->priv->x;
y = plot->priv->y;
- if (plot->priv->graphic_type == FUNCTIONAL_CURVE) {
+ if (plot->priv->graphic_type == FUNCTIONAL_CURVE) {
for (point = 1; point < points; point++) {
- if ((x[point] >= bbox->xmin) && (x[point] <= bbox->xmax) &&
- (y[point] >= bbox->ymin) && (y[point] <= bbox->ymax)) {
+ if ((x[point] >= bbox->xmin) && (x[point] <= bbox->xmax) && (y[point] >= bbox->ymin) &&
+ (y[point] <= bbox->ymax)) {
if (first_point) {
- cairo_move_to (cr, x[point-1], y[point-1]);
+ cairo_move_to (cr, x[point - 1], y[point - 1]);
first_point = FALSE;
}
cairo_line_to (cr, x[point], y[point]);
- }
- else {
+ } else {
if (!first_point) {
cairo_line_to (cr, x[point], y[point]);
first_point = TRUE;
}
}
}
- }
- else {
+ } else {
for (point = 1; point < points; point++) {
- x1 = x[point-1]+plot->priv->shift;
+ x1 = x[point - 1] + plot->priv->shift;
y1 = 0;
- NG_DEBUG (g_strdup_printf ("gplotlines: x= %lf\ty= %lf\n", x1, y1));
+ NG_DEBUG ("gplotlines: x= %lf\ty= %lf\n", x1, y1);
cairo_line_to (cr, x1, y1);
- cairo_move_to (cr, x[point]+ plot->priv->shift, y[point]);
+ cairo_move_to (cr, x[point] + plot->priv->shift, y[point]);
}
-
}
if (point < points) {
cairo_line_to (cr, x[point], y[point]);
}
cairo_save (cr);
- cairo_set_source_rgb (cr,
- plot->priv->color.red / 65535.0,
- plot->priv->color.green / 65535.0,
- plot->priv->color.blue / 65535.0);
- cairo_identity_matrix (cr);
- cairo_set_line_width (cr, plot->priv->width);
- cairo_stroke (cr);
+ cairo_set_source_rgb (cr, plot->priv->color.red, plot->priv->color.green,
+ plot->priv->color.blue);
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, plot->priv->width);
+ cairo_stroke (cr);
cairo_restore (cr);
}
diff --git a/src/gplot/gplotlines.h b/src/gplot/gplotlines.h
index 56450af..3dc252f 100644
--- a/src/gplot/gplotlines.h
+++ b/src/gplot/gplotlines.h
@@ -4,8 +4,8 @@
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -23,24 +23,20 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _GPLOT_LINES_H_
#define _GPLOT_LINES_H_
-#include "gplotfunction.h"
-
+#include "gplotfunction.h"
-typedef enum {
- FUNCTIONAL_CURVE=0,
- FREQUENCY_PULSE
-} GraphicType;
+typedef enum { FUNCTIONAL_CURVE = 0, FREQUENCY_PULSE } GraphicType;
-#define GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT_LINES, GPlotLines)
-#define IS_GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT_LINES)
+#define GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_GPLOT_LINES, GPlotLines)
+#define IS_GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_GPLOT_LINES)
-GPlotFunction* g_plot_lines_new (gdouble *x, gdouble *y, guint points);
+GPlotFunction *g_plot_lines_new (gdouble *x, gdouble *y, guint points);
#endif
diff --git a/src/load-common.h b/src/load-common.h
index 675a7ab..4313282 100644
--- a/src/load-common.h
+++ b/src/load-common.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __LOAD_COMMON_H
@@ -35,42 +35,44 @@
#include <glib.h>
-#include "sheet-pos.h"
+#include "coords.h"
// Note: this must be synced with Pin in part.h for now.
-typedef struct {
- SheetPos pos;
+typedef struct
+{
+ Coords pos;
} Connection;
-typedef struct {
+typedef struct
+{
gchar *name;
gchar *value;
} Property;
-typedef struct {
+typedef struct
+{
gchar *name;
gchar *author;
gchar *version;
- GSList *parts_list;
-
- GHashTable *part_hash;
- GHashTable *symbol_hash;
+ GHashTable *part_hash;
+ GHashTable *symbol_hash;
} Library;
-typedef struct {
- gchar *name;
+typedef struct
+{
+ gchar *name;
- gchar *description;
+ gchar *description;
- Library* library;
+ Library *library;
- gchar *symbol_name;
- int symbol_rotation;
+ gchar *symbol_name;
+ int symbol_rotation;
- gchar *refdes;
- gchar *template;
- gchar *model;
+ gchar *refdes;
+ gchar *template;
+ gchar *model;
GSList *labels;
GSList *properties;
} LibraryPart;
diff --git a/src/load-library.c b/src/load-library.c
index 6ef337c..827e27d 100644
--- a/src/load-library.c
+++ b/src/load-library.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <goocanvas.h>
@@ -46,6 +46,7 @@ typedef enum {
PARSE_LIBRARY,
PARSE_NAME,
PARSE_AUTHOR,
+ PARSE_VERSION,
PARSE_SYMBOLS,
PARSE_SYMBOL,
PARSE_SYMBOL_NAME,
@@ -74,7 +75,8 @@ typedef enum {
PARSE_ERROR
} State;
-typedef struct {
+typedef struct
+{
Library *library;
State state;
@@ -82,12 +84,12 @@ typedef struct {
gint unknown_depth;
GString *content;
- // Temporary placeholder for part
+ // Temporary placeholder for part
LibraryPart *part;
PartLabel *label;
Property *property;
- // Temporary placeholder for symbol
+ // Temporary placeholder for symbol
LibrarySymbol *symbol;
Connection *connection;
SymbolObject *object;
@@ -96,8 +98,7 @@ typedef struct {
static xmlEntityPtr get_entity (void *user_data, const xmlChar *name);
static void start_document (ParseState *state);
static void end_document (ParseState *state);
-static void start_element (ParseState *state, const xmlChar *name,
- const xmlChar **attrs);
+static void start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs);
static void end_element (ParseState *state, const xmlChar *name);
static void my_characters (ParseState *state, const xmlChar *chars, int len);
@@ -106,58 +107,56 @@ static void my_error (void *user_data, const char *msg, ...);
static void my_fatal_error (void *user_data, const char *msg, ...);
static xmlSAXHandler oreganoSAXParser = {
- 0, // internalSubset
- 0, // isStandalone
- 0, // hasInternalSubset
- 0, // hasExternalSubset
- 0, // resolveEntity
- (getEntitySAXFunc) get_entity, // getEntity
- 0, // entityDecl
- 0, // notationDecl
- 0, // attributeDecl
- 0, // elementDecl
- 0, // unparsedEntityDecl
- 0, // setDocumentLocator
- (startDocumentSAXFunc) start_document, // startDocument
- (endDocumentSAXFunc) end_document, // endDocument
- (startElementSAXFunc)start_element, // startElement
- (endElementSAXFunc)end_element, // endElement
- 0, // reference
- (charactersSAXFunc) my_characters, // characters
- 0, // ignorableWhitespace
- 0, // processingInstruction
- 0, // (commentSAXFunc)0, comment
- (warningSAXFunc)my_warning, // warning
- (errorSAXFunc)my_error, // error
- (fatalErrorSAXFunc)my_fatal_error, // fatalError
+ 0, // internalSubset
+ 0, // isStandalone
+ 0, // hasInternalSubset
+ 0, // hasExternalSubset
+ 0, // resolveEntity
+ (getEntitySAXFunc)get_entity, // getEntity
+ 0, // entityDecl
+ 0, // notationDecl
+ 0, // attributeDecl
+ 0, // elementDecl
+ 0, // unparsedEntityDecl
+ 0, // setDocumentLocator
+ (startDocumentSAXFunc)start_document, // startDocument
+ (endDocumentSAXFunc)end_document, // endDocument
+ (startElementSAXFunc)start_element, // startElement
+ (endElementSAXFunc)end_element, // endElement
+ 0, // reference
+ (charactersSAXFunc)my_characters, // characters
+ 0, // ignorableWhitespace
+ 0, // processingInstruction
+ 0, // (commentSAXFunc)0, comment
+ (warningSAXFunc)my_warning, // warning
+ (errorSAXFunc)my_error, // error
+ (fatalErrorSAXFunc)my_fatal_error, // fatalError
};
-LibrarySymbol *
-library_get_symbol (const gchar *symbol_name)
+LibrarySymbol *library_get_symbol (const gchar *symbol_name)
{
LibrarySymbol *symbol;
Library *library;
- GList *libraries;
+ GList *iter;
g_return_val_if_fail (symbol_name != NULL, NULL);
symbol = NULL;
- for (libraries = oregano.libraries; libraries; libraries = libraries->next) {
- library = libraries->data;
- symbol = g_hash_table_lookup (library->symbol_hash, symbol_name);
- if (symbol)
- break;
+ for (iter = oregano.libraries; iter; iter = iter->next) {
+ library = iter->data;
+ symbol = g_hash_table_lookup (library->symbol_hash, symbol_name);
+ if (symbol)
+ break;
}
if (symbol == NULL) {
- g_message (_("Could not find the requested symbol: %s\n"), symbol_name);
+ g_message (_ ("Could not find the requested symbol: %s\n"), symbol_name);
}
return symbol;
}
-LibraryPart *
-library_get_part (Library *library, const gchar *part_name)
+LibraryPart *library_get_part (Library *library, const gchar *part_name)
{
LibraryPart *part;
@@ -166,33 +165,30 @@ library_get_part (Library *library, const gchar *part_name)
part = g_hash_table_lookup (library->part_hash, part_name);
if (part == NULL) {
- g_message (_("Could not find the requested part: %s\n"), part_name);
+ g_message (_ ("Could not find the requested part: %s\n"), part_name);
}
return part;
}
-Library *
-library_parse_xml_file (const gchar *filename)
+Library *library_parse_xml_file (const gchar *filename)
{
Library *library;
ParseState state;
- if (oreganoXmlSAXParseFile (&oreganoSAXParser, &state, filename) < 0) {
+ if (!oreganoXmlSAXParseFile (&oreganoSAXParser, &state, filename)) {
g_warning ("Library '%s' not well formed!", filename);
}
if (state.state == PARSE_ERROR) {
library = NULL;
- }
- else {
+ } else {
library = state.library;
}
return library;
}
-static void
-start_document (ParseState *state)
+static void start_document (ParseState *state)
{
state->state = PARSE_START;
state->unknown_depth = 0;
@@ -214,15 +210,13 @@ start_document (ParseState *state)
state->library->symbol_hash = g_hash_table_new (g_str_hash, g_str_equal);
}
-static void
-end_document (ParseState *state)
+static void end_document (ParseState *state)
{
if (state->unknown_depth != 0)
g_warning ("unknown_depth != 0 (%d)", state->unknown_depth);
}
-static void
-start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs)
+static void start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs)
{
const char *name = (const char *)xml_name;
@@ -231,8 +225,7 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (strcmp (name, "ogo:library")) {
g_warning ("Expecting 'ogo:library'. Got '%s'", name);
state->state = PARSE_ERROR;
- }
- else
+ } else
state->state = PARSE_LIBRARY;
break;
@@ -240,18 +233,17 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:author")) {
state->state = PARSE_AUTHOR;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:name")) {
+ } else if (!strcmp (name, "ogo:name")) {
state->state = PARSE_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:symbols")) {
+ } else if (!strcmp (name, "ogo:version")) {
+ state->state = PARSE_VERSION;
+ g_string_truncate (state->content, 0);
+ } else if (!strcmp (name, "ogo:symbols")) {
state->state = PARSE_SYMBOLS;
- }
- else if (!strcmp (name, "ogo:parts")) {
+ } else if (!strcmp (name, "ogo:parts")) {
state->state = PARSE_PARTS;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -262,8 +254,7 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:symbol")) {
state->state = PARSE_SYMBOL;
state->symbol = g_new0 (LibrarySymbol, 1);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -274,14 +265,11 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:name")) {
state->state = PARSE_SYMBOL_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:objects")) {
+ } else if (!strcmp (name, "ogo:objects")) {
state->state = PARSE_SYMBOL_OBJECTS;
- }
- else if (!strcmp (name, "ogo:connections")) {
+ } else if (!strcmp (name, "ogo:connections")) {
state->state = PARSE_SYMBOL_CONNECTIONS;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -293,20 +281,17 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
state->object->type = SYMBOL_OBJECT_LINE;
state->state = PARSE_SYMBOL_LINE;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:arc")) {
+ } else if (!strcmp (name, "ogo:arc")) {
state->object = g_new0 (SymbolObject, 1);
state->object->type = SYMBOL_OBJECT_ARC;
state->state = PARSE_SYMBOL_ARC;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:text")) {
+ } else if (!strcmp (name, "ogo:text")) {
state->object = g_new0 (SymbolObject, 1);
state->object->type = SYMBOL_OBJECT_TEXT;
state->state = PARSE_SYMBOL_TEXT;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -318,22 +303,19 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
state->state = PARSE_SYMBOL_CONNECTION;
state->connection = g_new0 (Connection, 1);
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
-
case PARSE_PARTS:
if (!strcmp (name, "ogo:part")) {
state->state = PARSE_PART;
state->part = g_new0 (LibraryPart, 1);
state->part->library = state->library;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -343,22 +325,17 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:name")) {
state->state = PARSE_PART_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:description")) {
+ } else if (!strcmp (name, "ogo:description")) {
state->state = PARSE_PART_DESCRIPTION;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:symbol")) {
+ } else if (!strcmp (name, "ogo:symbol")) {
state->state = PARSE_PART_USESYMBOL;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:labels")) {
+ } else if (!strcmp (name, "ogo:labels")) {
state->state = PARSE_PART_LABELS;
- }
- else if (!strcmp (name, "ogo:properties")) {
+ } else if (!strcmp (name, "ogo:properties")) {
state->state = PARSE_PART_PROPERTIES;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -368,8 +345,7 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:label")) {
state->state = PARSE_PART_LABEL;
state->label = g_new0 (PartLabel, 1);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -379,16 +355,13 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:name")) {
state->state = PARSE_PART_LABEL_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:text")) {
+ } else if (!strcmp (name, "ogo:text")) {
state->state = PARSE_PART_LABEL_TEXT;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:position")) {
+ } else if (!strcmp (name, "ogo:position")) {
state->state = PARSE_PART_LABEL_POS;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -399,8 +372,7 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:property")) {
state->state = PARSE_PART_PROPERTY;
state->property = g_new0 (Property, 1);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -410,12 +382,10 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
if (!strcmp (name, "ogo:name")) {
state->state = PARSE_PART_PROPERTY_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!strcmp (name, "ogo:value")) {
+ } else if (!strcmp (name, "ogo:value")) {
state->state = PARSE_PART_PROPERTY_VALUE;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -437,7 +407,8 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
case PARSE_PART_PROPERTY_VALUE:
case PARSE_NAME:
case PARSE_AUTHOR:
- // there should be no tags inside these types of tags
+ case PARSE_VERSION:
+ // there should be no tags inside these types of tags
g_message ("*** '%s' tag found", name);
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
@@ -450,15 +421,14 @@ start_element (ParseState *state, const xmlChar *xml_name, const xmlChar **attrs
state->unknown_depth++;
break;
case PARSE_FINISH:
- // should not start new elements in this state
+ // should not start new elements in this state
g_assert_not_reached ();
break;
}
- //g_message("Start element %s (state %s)", name, states[state->state]);
+ // g_message("Start element %s (state %s)", name, states[state->state]);
}
-static void
-end_element (ParseState *state, const xmlChar *name)
+static void end_element (ParseState *state, const xmlChar *name)
{
switch (state->state) {
case PARSE_UNKNOWN:
@@ -474,12 +444,15 @@ end_element (ParseState *state, const xmlChar *name)
state->library->name = g_strdup (state->content->str);
state->state = PARSE_LIBRARY;
break;
+ case PARSE_VERSION:
+ state->library->version = g_strdup (state->content->str);
+ state->state = PARSE_LIBRARY;
+ break;
case PARSE_SYMBOLS:
state->state = PARSE_LIBRARY;
break;
case PARSE_SYMBOL:
- g_hash_table_insert (state->library->symbol_hash, state->symbol->name,
- state->symbol);
+ g_hash_table_insert (state->library->symbol_hash, state->symbol->name, state->symbol);
state->state = PARSE_SYMBOLS;
break;
case PARSE_SYMBOL_NAME:
@@ -489,16 +462,14 @@ end_element (ParseState *state, const xmlChar *name)
case PARSE_SYMBOL_OBJECTS:
state->state = PARSE_SYMBOL;
break;
- case PARSE_SYMBOL_LINE:
- {
+ case PARSE_SYMBOL_LINE: {
int i, j;
gchar *ptr;
gchar **points;
- i= sscanf (state->content->str,"%d %n",
- &state->object->u.uline.spline,&j);
- if ( i )
- ptr = state->content->str+j;
+ i = sscanf (state->content->str, "%d %n", &state->object->u.uline.spline, &j);
+ if (i)
+ ptr = state->content->str + j;
else {
state->object->u.uline.spline = FALSE;
ptr = state->content->str;
@@ -507,45 +478,43 @@ end_element (ParseState *state, const xmlChar *name)
points = g_strsplit (ptr, "(", 0);
i = 0;
- // Count the points.
+ // Count the points.
while (points[i] != NULL) {
i++;
}
- // Do not count the first string, which simply is a (.
+ // Do not count the first string, which simply is a (.
i--;
- // Construct goo canvas points.
+ // Construct goo canvas points.
state->object->u.uline.line = goo_canvas_points_new (i);
for (j = 0; j < i; j++) {
double x, y;
- sscanf (points[j+1], "%lf %lf)", &x, &y);
+ sscanf (points[j + 1], "%lf %lf)", &x, &y);
state->object->u.uline.line->coords[2 * j] = x;
state->object->u.uline.line->coords[2 * j + 1] = y;
}
g_strfreev (points);
- state->symbol->symbol_objects = g_slist_prepend (state->symbol->symbol_objects, state->object);
+ state->symbol->symbol_objects =
+ g_slist_prepend (state->symbol->symbol_objects, state->object);
state->state = PARSE_SYMBOL_OBJECTS;
- }
- break;
+ } break;
case PARSE_SYMBOL_ARC:
- sscanf (state->content->str, "(%lf %lf)(%lf %lf)",
- &state->object->u.arc.x1, &state->object->u.arc.y1,
- &state->object->u.arc.x2, &state->object->u.arc.y2);
- state->symbol->symbol_objects = g_slist_prepend (state->symbol->symbol_objects, state->object);
+ sscanf (state->content->str, "(%lf %lf)(%lf %lf)", &state->object->u.arc.x1,
+ &state->object->u.arc.y1, &state->object->u.arc.x2, &state->object->u.arc.y2);
+ state->symbol->symbol_objects =
+ g_slist_prepend (state->symbol->symbol_objects, state->object);
state->state = PARSE_SYMBOL_OBJECTS;
break;
case PARSE_SYMBOL_TEXT:
- sscanf ( state->content->str,"(%d %d)%s",
- &state->object->u.text.x,
- &state->object->u.text.y,
- state->object->u.text.str
- );
- state->symbol->symbol_objects = g_slist_prepend (state->symbol->symbol_objects, state->object);
+ sscanf (state->content->str, "(%d %d)%s", &state->object->u.text.x,
+ &state->object->u.text.y, state->object->u.text.str);
+ state->symbol->symbol_objects =
+ g_slist_prepend (state->symbol->symbol_objects, state->object);
state->state = PARSE_SYMBOL_OBJECTS;
break;
@@ -555,8 +524,9 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_SYMBOL_CONNECTION:
sscanf (state->content->str, "(%lf %lf)", &state->connection->pos.x,
- &state->connection->pos.y);
- state->symbol->connections = g_slist_prepend (state->symbol->connections, state->connection);
+ &state->connection->pos.y);
+ state->symbol->connections =
+ g_slist_prepend (state->symbol->connections, state->connection);
state->state = PARSE_SYMBOL_CONNECTIONS;
break;
@@ -564,8 +534,7 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_LIBRARY;
break;
case PARSE_PART:
- g_hash_table_insert (state->library->part_hash, state->part->name,
- state->part);
+ g_hash_table_insert (state->library->part_hash, state->part->name, state->part);
state->state = PARSE_PARTS;
break;
case PARSE_PART_NAME:
@@ -585,8 +554,7 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_PART_LABEL:
state->state = PARSE_PART_LABELS;
- state->part->labels = g_slist_prepend (state->part->labels,
- state->label);
+ state->part->labels = g_slist_prepend (state->part->labels, state->label);
break;
case PARSE_PART_LABEL_NAME:
state->label->name = g_strdup (state->content->str);
@@ -597,8 +565,7 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_PART_LABEL;
break;
case PARSE_PART_LABEL_POS:
- sscanf (state->content->str, "(%lf %lf)", &state->label->pos.x,
- &state->label->pos.y);
+ sscanf (state->content->str, "(%lf %lf)", &state->label->pos.x, &state->label->pos.y);
state->state = PARSE_PART_LABEL;
break;
case PARSE_PART_PROPERTIES:
@@ -606,8 +573,7 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_PART_PROPERTY:
state->state = PARSE_PART_PROPERTIES;
- state->part->properties = g_slist_prepend (state->part->properties,
- state->property);
+ state->part->properties = g_slist_prepend (state->part->properties, state->property);
break;
case PARSE_PART_PROPERTY_NAME:
state->property->name = g_strdup (state->content->str);
@@ -619,43 +585,38 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_LIBRARY:
- // The end of the file.
+ // The end of the file.
state->state = PARSE_FINISH;
break;
case PARSE_ERROR:
break;
case PARSE_START:
case PARSE_FINISH:
- // There should not be a closing tag in this state.
+ // There should not be a closing tag in this state.
g_assert_not_reached ();
break;
}
- //g_message("End element %s (state %s)", name, states[state->state]);
+ // g_message("End element %s (state %s)", name, states[state->state]);
}
-static void
-my_characters (ParseState *state, const xmlChar *chars, int len)
+static void my_characters (ParseState *state, const xmlChar *chars, int len)
{
int i;
- if (state->state == PARSE_FINISH ||
- state->state == PARSE_START ||
- state->state == PARSE_PARTS ||
- state->state == PARSE_PART)
+ if (state->state == PARSE_FINISH || state->state == PARSE_START ||
+ state->state == PARSE_PARTS || state->state == PARSE_PART)
return;
for (i = 0; i < len; i++)
g_string_append_c (state->content, chars[i]);
}
-static xmlEntityPtr
-get_entity (void *user_data, const xmlChar *name)
+static xmlEntityPtr get_entity (void *user_data, const xmlChar *name)
{
return xmlGetPredefinedEntity (name);
}
-static void
-my_warning (void *user_data, const char *msg, ...)
+static void my_warning (void *user_data, const char *msg, ...)
{
va_list args;
@@ -664,8 +625,7 @@ my_warning (void *user_data, const char *msg, ...)
va_end (args);
}
-static void
-my_error (void *user_data, const char *msg, ...)
+static void my_error (void *user_data, const char *msg, ...)
{
va_list args;
@@ -674,8 +634,7 @@ my_error (void *user_data, const char *msg, ...)
va_end (args);
}
-static void
-my_fatal_error (void *user_data, const char *msg, ...)
+static void my_fatal_error (void *user_data, const char *msg, ...)
{
va_list args;
@@ -683,4 +642,3 @@ my_fatal_error (void *user_data, const char *msg, ...)
g_logv ("XML", G_LOG_LEVEL_ERROR, msg, args);
va_end (args);
}
-
diff --git a/src/load-library.h b/src/load-library.h
index f913988..03b836d 100644
--- a/src/load-library.h
+++ b/src/load-library.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __LOAD_LIBRARY_H
@@ -41,41 +41,43 @@ typedef struct _LibrarySymbol LibrarySymbol;
#include "load-common.h"
-struct _LibrarySymbol {
- char *name;
+struct _LibrarySymbol
+{
+ char *name;
GSList *connections;
GSList *symbol_objects;
};
-typedef enum {
- SYMBOL_OBJECT_LINE,
- SYMBOL_OBJECT_ARC,
- SYMBOL_OBJECT_TEXT
-} SymbolObjectType;
+typedef enum { SYMBOL_OBJECT_LINE, SYMBOL_OBJECT_ARC, SYMBOL_OBJECT_TEXT } SymbolObjectType;
-struct _SymbolObject {
+struct _SymbolObject
+{
SymbolObjectType type;
- union {
- struct {
+ union
+ {
+ struct
+ {
gboolean spline;
GooCanvasPoints *line;
} uline;
- struct {
+ struct
+ {
double x1;
double y1;
double x2;
double y2;
} arc;
- struct {
- gint x,y;
+ struct
+ {
+ gint x, y;
gchar str[256];
} text;
} u;
};
-Library *library_parse_xml_file (const gchar *filename);
-LibrarySymbol *library_get_symbol (const gchar *symbol_name);
-LibraryPart *library_get_part (Library *library, const gchar *part_name);
+Library *library_parse_xml_file (const gchar *filename);
+LibrarySymbol *library_get_symbol (const gchar *symbol_name);
+LibraryPart *library_get_part (Library *library, const gchar *part_name);
#endif
diff --git a/src/load-schematic.c b/src/load-schematic.c
index 710e31f..8c19bd1 100644
--- a/src/load-schematic.c
+++ b/src/load-schematic.c
@@ -2,17 +2,21 @@
* load-schematic.c
*
*
- * Author:
+ * Authors:
* Richard Hult <rhult@hem.passagen.se>
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
@@ -38,20 +42,22 @@
#include "xml-helper.h"
#include "load-common.h"
#include "load-schematic.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "part-label.h"
+#include "schematic.h"
#include "sim-settings.h"
#include "textbox.h"
#include "errors.h"
+#include "engines/netlist-helper.h"
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
typedef enum {
PARSE_START,
PARSE_SCHEMATIC,
PARSE_TITLE,
PARSE_AUTHOR,
+ PARSE_VERSION,
PARSE_COMMENTS,
PARSE_SIMULATION_SETTINGS,
@@ -62,9 +68,12 @@ typedef enum {
PARSE_TRANSIENT_STEP,
PARSE_TRANSIENT_STEP_ENABLE,
PARSE_TRANSIENT_INIT_COND,
+ PARSE_TRANSIENT_ANALYZE_ALL,
PARSE_AC_SETTINGS,
PARSE_AC_ENABLED,
+ PARSE_AC_VOUT,
+ PARSE_AC_TYPE,
PARSE_AC_NPOINTS,
PARSE_AC_START,
PARSE_AC_STOP,
@@ -72,6 +81,7 @@ typedef enum {
PARSE_DC_SETTINGS,
PARSE_DC_ENABLED,
PARSE_DC_VSRC,
+ PARSE_DC_VOUT,
PARSE_DC_START,
PARSE_DC_STOP,
PARSE_DC_STEP,
@@ -81,12 +91,20 @@ typedef enum {
PARSE_FOURIER_FREQ,
PARSE_FOURIER_VOUT,
+ PARSE_NOISE_SETTINGS,
+ PARSE_NOISE_ENABLED,
+ PARSE_NOISE_VSRC,
+ PARSE_NOISE_VOUT,
+ PARSE_NOISE_TYPE,
+ PARSE_NOISE_NPOINTS,
+ PARSE_NOISE_START,
+ PARSE_NOISE_STOP,
+
PARSE_OPTION_LIST,
PARSE_OPTION,
PARSE_OPTION_NAME,
PARSE_OPTION_VALUE,
-
PARSE_ZOOM,
PARSE_PARTS,
@@ -112,7 +130,7 @@ typedef enum {
PARSE_WIRES,
PARSE_WIRE,
PARSE_WIRE_POINTS,
-// PARSE_WIRE_LABEL,
+ // PARSE_WIRE_LABEL,
PARSE_TEXTBOXES,
PARSE_TEXTBOX,
PARSE_TEXTBOX_TEXT,
@@ -122,7 +140,8 @@ typedef enum {
PARSE_ERROR
} State;
-typedef struct {
+typedef struct
+{
State state;
State prev_state;
int unknown_depth;
@@ -130,21 +149,22 @@ typedef struct {
Schematic *schematic;
SimSettings *sim_settings;
- char *title;
char *author;
+ char *title;
+ char *oregano_version;
char *comments;
char *textbox_text;
// Temporary place holder for a wire
- SheetPos wire_start;
- SheetPos wire_end;
+ Coords wire_start;
+ Coords wire_end;
// Temporary place holder for a part
LibraryPart *part;
PartLabel *label;
Property *property;
- SheetPos pos;
+ Coords pos;
int rotation;
IDFlip flip;
@@ -155,8 +175,7 @@ typedef struct {
static xmlEntityPtr get_entity (void *user_data, const xmlChar *name);
static void start_document (ParseState *state);
static void end_document (ParseState *state);
-static void start_element (ParseState *state, const xmlChar *name,
- const xmlChar **attrs);
+static void start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs);
static void end_element (ParseState *state, const xmlChar *name);
static void my_characters (ParseState *state, const xmlChar *chars, int len);
@@ -168,47 +187,45 @@ static void create_wire (ParseState *state);
static void create_part (ParseState *state);
static xmlSAXHandler oreganoSAXParser = {
- 0, // internalSubset
- 0, // isStandalone
- 0, // hasInternalSubset
- 0, // hasExternalSubset
- 0, // resolveEntity
- (getEntitySAXFunc) get_entity, // getEntity
- 0, // entityDecl
- 0, // notationDecl
- 0, // attributeDecl
- 0, // elementDecl
- 0, // unparsedEntityDecl
- 0, // setDocumentLocator
- (startDocumentSAXFunc) start_document, // startDocument
- (endDocumentSAXFunc) end_document, // endDocument
- (startElementSAXFunc) start_element, // startElement
- (endElementSAXFunc) end_element, // endElement
- 0, // reference
- (charactersSAXFunc) my_characters, // characters
- 0, // ignorableWhitespace
- 0, // processingInstruction
- 0, //(commentSAXFunc)0, comment
- (warningSAXFunc) my_warning, // warning
- (errorSAXFunc) my_error, // error
- (fatalErrorSAXFunc) my_fatal_error, // fatalError
+ 0, // internalSubset
+ 0, // isStandalone
+ 0, // hasInternalSubset
+ 0, // hasExternalSubset
+ 0, // resolveEntity
+ (getEntitySAXFunc)get_entity, // getEntity
+ 0, // entityDecl
+ 0, // notationDecl
+ 0, // attributeDecl
+ 0, // elementDecl
+ 0, // unparsedEntityDecl
+ 0, // setDocumentLocator
+ (startDocumentSAXFunc)start_document, // startDocument
+ (endDocumentSAXFunc)end_document, // endDocument
+ (startElementSAXFunc)start_element, // startElement
+ (endElementSAXFunc)end_element, // endElement
+ 0, // reference
+ (charactersSAXFunc)my_characters, // characters
+ 0, // ignorableWhitespace
+ 0, // processingInstruction
+ 0, //(commentSAXFunc)0, comment
+ (warningSAXFunc)my_warning, // warning
+ (errorSAXFunc)my_error, // error
+ (fatalErrorSAXFunc)my_fatal_error, // fatalError
};
-static void
-create_textbox (ParseState *state)
+static void create_textbox (ParseState *state)
{
Textbox *textbox;
textbox = textbox_new (NULL);
- item_data_set_pos (ITEM_DATA (textbox), &state->pos);
textbox_set_text (textbox, state->textbox_text);
+ item_data_set_pos (ITEM_DATA (textbox), &state->pos);
schematic_add_item (state->schematic, ITEM_DATA (textbox));
}
-static void
-create_wire (ParseState *state)
+static void create_wire (ParseState *state)
{
- SheetPos start_pos, length;
+ Coords start_pos, length;
Wire *wire;
start_pos.x = state->wire_start.x;
@@ -217,74 +234,79 @@ create_wire (ParseState *state)
length.y = state->wire_end.y - start_pos.y;
wire = wire_new ();
- item_data_set_pos (ITEM_DATA (wire), &state->wire_start);
wire_set_length (wire, &length);
+ item_data_set_pos (ITEM_DATA (wire), &state->wire_start);
schematic_add_item (state->schematic, ITEM_DATA (wire));
}
-static void
-create_part (ParseState *state)
+static void create_part (ParseState *state)
{
Part *part;
LibraryPart *library_part = state->part;
part = part_new_from_library_part (library_part);
- if (!part)
+ if (!part) {
+ g_warning ("Failed to create Part from LibraryPart");
return;
+ }
item_data_set_pos (ITEM_DATA (part), &state->pos);
item_data_rotate (ITEM_DATA (part), state->rotation, NULL);
if (state->flip & ID_FLIP_HORIZ)
- item_data_flip (ITEM_DATA (part), TRUE, NULL);
+ item_data_flip (ITEM_DATA (part), ID_FLIP_HORIZ, NULL);
if (state->flip & ID_FLIP_VERT)
- item_data_flip (ITEM_DATA (part), FALSE, NULL);
+ item_data_flip (ITEM_DATA (part), ID_FLIP_VERT, NULL);
schematic_add_item (state->schematic, ITEM_DATA (part));
}
-int
-schematic_parse_xml_file (Schematic *sm, const char *filename, GError **error)
+int schematic_parse_xml_file (Schematic *sm, const char *filename, GError **error)
{
ParseState state;
- int retval = 0;
+ int retval = 0;
state.schematic = sm;
state.sim_settings = schematic_get_sim_settings (sm);
- state.title = NULL;
state.author = NULL;
+ state.title = NULL;
+ state.oregano_version = NULL;
state.comments = NULL;
- if (oreganoXmlSAXParseFile (&oreganoSAXParser, &state, filename) < 0) {
+ if (!oreganoXmlSAXParseFile (&oreganoSAXParser, &state, filename)) {
g_warning ("Document not well formed!");
if (error != NULL) {
- g_set_error (error,
- OREGANO_ERROR,
- OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
- _("Bad file format."));
+ g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
+ _ ("Bad file format."));
}
retval = -1;
}
if (state.state == PARSE_ERROR) {
if (error != NULL) {
- g_set_error (error,
- OREGANO_ERROR,
- OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
- _("Unknown parser error."));
+ g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
+ _ ("Unknown parser error."));
}
retval = -2;
}
+ schematic_set_filename(sm, filename);
schematic_set_author (sm, state.author);
schematic_set_title (sm, state.title);
+ schematic_set_version(sm, state.oregano_version);
schematic_set_comments (sm, state.comments);
+ g_free(state.author);
+ g_free(state.title);
+ g_free(state.oregano_version);
+ g_free(state.comments);
+
+ update_schematic(sm);
+
return retval;
}
-static void
-start_document (ParseState *state)
+static void start_document (ParseState *state)
{
state->state = PARSE_START;
state->unknown_depth = 0;
@@ -294,24 +316,21 @@ start_document (ParseState *state)
state->part = NULL;
}
-static void
-end_document (ParseState *state)
+static void end_document (ParseState *state)
{
if (state->unknown_depth != 0)
g_warning ("unknown_depth != 0 (%d)", state->unknown_depth);
}
-static void
-start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
+static void start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
{
switch (state->state) {
case PARSE_START:
if (xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:schematic")) {
g_warning ("Expecting 'ogo:schematic'. Got '%s'", name);
state->state = PARSE_ERROR;
- }
- else
+ } else
state->state = PARSE_SCHEMATIC;
break;
@@ -319,32 +338,27 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:author")) {
state->state = PARSE_AUTHOR;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:title")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:title")) {
state->state = PARSE_TITLE;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:comments")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:version")) {
+ state->state = PARSE_VERSION;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:comments")) {
state->state = PARSE_COMMENTS;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:zoom")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:zoom")) {
state->state = PARSE_ZOOM;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:simulation-settings")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:simulation-settings")) {
state->state = PARSE_SIMULATION_SETTINGS;
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:parts")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:parts")) {
state->state = PARSE_PARTS;
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:wires")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:wires")) {
state->state = PARSE_WIRES;
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:textboxes")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:textboxes")) {
state->state = PARSE_TEXTBOXES;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -352,22 +366,19 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_SIMULATION_SETTINGS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:transient")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:transient")) {
state->state = PARSE_TRANSIENT_SETTINGS;
- }
- else if ( !xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:ac")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:ac")) {
state->state = PARSE_AC_SETTINGS;
- }
- else if ( !xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:dc-sweep")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:dc-sweep")) {
state->state = PARSE_DC_SETTINGS;
- }
- else if ( !xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:fourier")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:fourier")) {
state->state = PARSE_FOURIER_SETTINGS;
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:options")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:noise")) {
+ state->state = PARSE_NOISE_SETTINGS;
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:options")) {
state->state = PARSE_OPTION_LIST;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -375,31 +386,28 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_TRANSIENT_SETTINGS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:enabled")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
state->state = PARSE_TRANSIENT_ENABLED;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:start")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
state->state = PARSE_TRANSIENT_START;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:stop")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
state->state = PARSE_TRANSIENT_STOP;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:step")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step")) {
state->state = PARSE_TRANSIENT_STEP;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:step-enabled")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step-enabled")) {
state->state = PARSE_TRANSIENT_STEP_ENABLE;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:init-conditions")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:init-conditions")) {
state->state = PARSE_TRANSIENT_INIT_COND;
g_string_truncate (state->content, 0);
- }
- else {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:analyze-all")) {
+ state->state = PARSE_TRANSIENT_ANALYZE_ALL;
+ g_string_truncate (state->content, 0);
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -407,23 +415,25 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_AC_SETTINGS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:enabled")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
state->state = PARSE_AC_ENABLED;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:npoints")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
+ state->state = PARSE_AC_VOUT;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:type")) {
+ state->state = PARSE_AC_TYPE;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:npoints")) {
state->state = PARSE_AC_NPOINTS;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:start")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
state->state = PARSE_AC_START;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:stop")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
state->state = PARSE_AC_STOP;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -431,27 +441,25 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_DC_SETTINGS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:enabled")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
state->state = PARSE_DC_ENABLED;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:vsrc1")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vsrc1")) {
state->state = PARSE_DC_VSRC;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:start1")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
+ state->state = PARSE_DC_VOUT;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start1")) {
state->state = PARSE_DC_START;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:stop1")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop1")) {
state->state = PARSE_DC_STOP;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:step1")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step1")) {
state->state = PARSE_DC_STEP;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -459,47 +467,70 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_FOURIER_SETTINGS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:enabled")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
state->state = PARSE_FOURIER_ENABLED;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:freq")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:freq")) {
state->state = PARSE_FOURIER_FREQ;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:vout")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout")) {
state->state = PARSE_FOURIER_VOUT;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
+ state->prev_state = state->state;
+ state->state = PARSE_UNKNOWN;
+ state->unknown_depth++;
+ }
+ break;
+
+ case PARSE_NOISE_SETTINGS:
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
+ state->state = PARSE_NOISE_ENABLED;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vsrc1")) {
+ state->state = PARSE_NOISE_VSRC;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
+ state->state = PARSE_NOISE_VOUT;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:type")) {
+ state->state = PARSE_NOISE_TYPE;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:npoints")) {
+ state->state = PARSE_NOISE_NPOINTS;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
+ state->state = PARSE_NOISE_START;
+ g_string_truncate (state->content, 0);
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
+ state->state = PARSE_NOISE_STOP;
+ g_string_truncate (state->content, 0);
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
- break;
+ break;
case PARSE_OPTION_LIST:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:option")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:option")) {
state->state = PARSE_OPTION;
- state->option= g_new0 (SimOption,1);
+ state->option = g_new0 (SimOption, 1);
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_OPTION:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:name")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
state->state = PARSE_OPTION_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:value")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:value")) {
state->state = PARSE_OPTION_VALUE;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -507,94 +538,78 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_PARTS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:part")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:part")) {
state->state = PARSE_PART;
state->part = g_new0 (LibraryPart, 1);
state->rotation = 0;
state->flip = ID_FLIP_NONE;
state->label = NULL;
state->property = NULL;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_PART:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:name")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
state->state = PARSE_PART_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:library")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:library")) {
state->state = PARSE_PART_LIBNAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:refdes")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:refdes")) {
state->state = PARSE_PART_REFDES;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:position")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
state->state = PARSE_PART_POSITION;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:rotation")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:rotation")) {
state->state = PARSE_PART_ROTATION;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:flip")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:flip")) {
state->state = PARSE_PART_FLIP;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:template")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:template")) {
state->state = PARSE_PART_TEMPLATE;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:model")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:model")) {
state->state = PARSE_PART_MODEL;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:symbol")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:symbol")) {
state->state = PARSE_PART_SYMNAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:labels")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:labels")) {
state->state = PARSE_PART_LABELS;
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:properties")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:properties")) {
state->state = PARSE_PART_PROPERTIES;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_PART_LABELS:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:label")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:label")) {
state->state = PARSE_PART_LABEL;
state->label = g_new0 (PartLabel, 1);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_PART_LABEL:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:name")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
state->state = PARSE_PART_LABEL_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:text")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:text")) {
state->state = PARSE_PART_LABEL_TEXT;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:position")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
state->state = PARSE_PART_LABEL_POS;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -602,49 +617,43 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_PART_PROPERTIES:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:property")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:property")) {
state->state = PARSE_PART_PROPERTY;
state->property = g_new0 (Property, 1);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_PART_PROPERTY:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:name")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
state->state = PARSE_PART_PROPERTY_NAME;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:value")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:value")) {
state->state = PARSE_PART_PROPERTY_VALUE;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
-
case PARSE_WIRES:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:wire")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:wire")) {
state->state = PARSE_WIRE;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_WIRE:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:points")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:points")) {
state->state = PARSE_WIRE_POINTS;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -652,25 +661,22 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
break;
case PARSE_TEXTBOXES:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:textbox")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:textbox")) {
state->state = PARSE_TEXTBOX;
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
}
break;
case PARSE_TEXTBOX:
- if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:position")) {
+ if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
state->state = PARSE_TEXTBOX_POSITION;
g_string_truncate (state->content, 0);
- }
- else if (!xmlStrcmp (BAD_CAST name, BAD_CAST"ogo:text")) {
+ } else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:text")) {
state->state = PARSE_TEXTBOX_TEXT;
g_string_truncate (state->content, 0);
- }
- else {
+ } else {
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
state->unknown_depth++;
@@ -684,12 +690,15 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
case PARSE_TRANSIENT_STEP_ENABLE:
case PARSE_AC_ENABLED:
+ case PARSE_AC_VOUT:
+ case PARSE_AC_TYPE:
case PARSE_AC_NPOINTS:
case PARSE_AC_START:
case PARSE_AC_STOP:
case PARSE_DC_ENABLED:
case PARSE_DC_VSRC:
+ case PARSE_DC_VOUT:
case PARSE_DC_START:
case PARSE_DC_STOP:
case PARSE_DC_STEP:
@@ -698,6 +707,14 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
case PARSE_FOURIER_FREQ:
case PARSE_FOURIER_VOUT:
+ case PARSE_NOISE_ENABLED:
+ case PARSE_NOISE_VSRC:
+ case PARSE_NOISE_VOUT:
+ case PARSE_NOISE_TYPE:
+ case PARSE_NOISE_NPOINTS:
+ case PARSE_NOISE_START:
+ case PARSE_NOISE_STOP:
+
case PARSE_WIRE_POINTS:
case PARSE_OPTION_NAME:
case PARSE_OPTION_VALUE:
@@ -720,8 +737,11 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
case PARSE_ZOOM:
case PARSE_TITLE:
case PARSE_AUTHOR:
+ case PARSE_VERSION:
case PARSE_COMMENTS:
- // there should be no tags inside these types of tags
+ case PARSE_TRANSIENT_INIT_COND:
+ case PARSE_TRANSIENT_ANALYZE_ALL:
+ // there should be no tags inside these types of tags
g_message ("*** '%s' tag found", name);
state->prev_state = state->state;
state->state = PARSE_UNKNOWN;
@@ -734,19 +754,17 @@ start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
state->unknown_depth++;
break;
case PARSE_FINISH:
- // should not start new elements in this state
+ // should not start new elements in this state
g_assert_not_reached ();
break;
- case PARSE_TRANSIENT_INIT_COND:
- break;
}
- //g_message("Start element %s (state %s)", name, states[state->state]);
+ // g_message("Start element %s (state %s)", name, states[state->state]);
}
-static void
-end_element (ParseState *state, const xmlChar *name)
+static void end_element (ParseState *state, const xmlChar *name)
{
GList *libs;
+ Schematic *schematic = state->schematic;
switch (state->state) {
case PARSE_UNKNOWN:
@@ -762,12 +780,15 @@ end_element (ParseState *state, const xmlChar *name)
state->title = g_strdup (state->content->str);
state->state = PARSE_SCHEMATIC;
break;
+ case PARSE_VERSION:
+ state->oregano_version = g_strdup (state->content->str);
+ state->state = PARSE_SCHEMATIC;
+ break;
case PARSE_COMMENTS:
state->comments = g_strdup (state->content->str);
state->state = PARSE_SCHEMATIC;
break;
- case PARSE_ZOOM:
- {
+ case PARSE_ZOOM: {
double zoom;
zoom = g_strtod (state->content->str, NULL);
@@ -780,18 +801,17 @@ end_element (ParseState *state, const xmlChar *name)
case PARSE_SIMULATION_SETTINGS:
state->state = PARSE_SCHEMATIC;
break;
-
+
case PARSE_TRANSIENT_SETTINGS:
state->state = PARSE_SIMULATION_SETTINGS;
break;
case PARSE_TRANSIENT_ENABLED:
sim_settings_set_trans (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_TRANSIENT_SETTINGS;
break;
case PARSE_TRANSIENT_START:
- sim_settings_set_trans_start (state->sim_settings,
- state->content->str);
+ sim_settings_set_trans_start (state->sim_settings, state->content->str);
state->state = PARSE_TRANSIENT_SETTINGS;
break;
case PARSE_TRANSIENT_STOP:
@@ -804,12 +824,17 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_TRANSIENT_STEP_ENABLE:
sim_settings_set_trans_step_enable (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_TRANSIENT_SETTINGS;
break;
case PARSE_TRANSIENT_INIT_COND:
sim_settings_set_trans_init_cond (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
+ state->state = PARSE_TRANSIENT_SETTINGS;
+ break;
+ case PARSE_TRANSIENT_ANALYZE_ALL:
+ sim_settings_set_trans_analyze_all(state->sim_settings,
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_TRANSIENT_SETTINGS;
break;
@@ -818,11 +843,21 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_AC_ENABLED:
sim_settings_set_ac (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_AC_SETTINGS;
+ break;
+ case PARSE_AC_VOUT:
+ sim_settings_set_ac_vout (state->sim_settings, state->content->str);
+ state->state = PARSE_AC_SETTINGS;
+ break;
+ case PARSE_AC_TYPE:
+ sim_settings_set_ac_type (state->sim_settings, state->content->str);
+ state->state = PARSE_AC_SETTINGS;
+ break;
case PARSE_AC_NPOINTS:
sim_settings_set_ac_npoints (state->sim_settings, state->content->str);
state->state = PARSE_AC_SETTINGS;
+ break;
case PARSE_AC_START:
sim_settings_set_ac_start (state->sim_settings, state->content->str);
state->state = PARSE_AC_SETTINGS;
@@ -837,11 +872,17 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_DC_ENABLED:
sim_settings_set_dc (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_DC_SETTINGS;
+ break;
case PARSE_DC_VSRC:
sim_settings_set_dc_vsrc (state->sim_settings, state->content->str);
state->state = PARSE_DC_SETTINGS;
+ break;
+ case PARSE_DC_VOUT:
+ sim_settings_set_dc_vout (state->sim_settings, state->content->str);
+ state->state = PARSE_DC_SETTINGS;
+ break;
case PARSE_DC_START:
sim_settings_set_dc_start (state->sim_settings, state->content->str);
state->state = PARSE_DC_SETTINGS;
@@ -854,13 +895,13 @@ end_element (ParseState *state, const xmlChar *name)
sim_settings_set_dc_step (state->sim_settings, state->content->str);
state->state = PARSE_DC_SETTINGS;
break;
-
+
case PARSE_FOURIER_SETTINGS:
state->state = PARSE_SIMULATION_SETTINGS;
break;
case PARSE_FOURIER_ENABLED:
sim_settings_set_fourier (state->sim_settings,
- !g_ascii_strcasecmp (state->content->str, "true"));
+ !g_ascii_strcasecmp (state->content->str, "true"));
state->state = PARSE_FOURIER_SETTINGS;
break;
case PARSE_FOURIER_FREQ:
@@ -872,22 +913,55 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_FOURIER_SETTINGS;
break;
+ case PARSE_NOISE_SETTINGS:
+ state->state = PARSE_SIMULATION_SETTINGS;
+ break;
+ case PARSE_NOISE_ENABLED:
+ sim_settings_set_noise (state->sim_settings,
+ !g_ascii_strcasecmp (state->content->str, "true"));
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_VSRC:
+ sim_settings_set_noise_vsrc (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_VOUT:
+ sim_settings_set_noise_vout (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_TYPE:
+ sim_settings_set_noise_type (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_NPOINTS:
+ sim_settings_set_noise_npoints (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_START:
+ sim_settings_set_noise_start (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+ case PARSE_NOISE_STOP:
+ sim_settings_set_noise_stop (state->sim_settings, state->content->str);
+ state->state = PARSE_NOISE_SETTINGS;
+ break;
+
case PARSE_OPTION_LIST:
state->state = PARSE_SIMULATION_SETTINGS;
break;
case PARSE_OPTION:
state->state = PARSE_OPTION_LIST;
- sim_settings_add_option (state->sim_settings,state->option);
- state->option = g_new0 (SimOption,1);
+ sim_settings_add_option (state->sim_settings, state->option);
+ state->option = g_new0 (SimOption, 1);
break;
case PARSE_OPTION_NAME:
state->option->name = g_strdup (state->content->str);
- state->state=PARSE_OPTION;
+ state->state = PARSE_OPTION;
break;
case PARSE_OPTION_VALUE:
state->option->value = g_strdup (state->content->str);
- state->state=PARSE_OPTION;
+ state->state = PARSE_OPTION;
break;
case PARSE_PARTS:
@@ -906,7 +980,7 @@ end_element (ParseState *state, const xmlChar *name)
state->part->library = NULL;
libs = oregano.libraries;
while (libs) {
- Library *lib = (Library *) libs->data;
+ Library *lib = (Library *)libs->data;
if (g_ascii_strcasecmp (state->content->str, lib->name) == 0) {
state->part->library = lib;
break;
@@ -916,6 +990,16 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_PART_POSITION:
sscanf (state->content->str, "(%lf %lf)", &state->pos.x, &state->pos.y);
+ // Try to fix invalid positions
+ if (state->pos.x < 0)
+ state->pos.x = -state->pos.x;
+ if (state->pos.y < 0)
+ state->pos.y = -state->pos.y;
+ // Determine the maximum parts' coordinates to be used during sheet creation
+ if (state->pos.x > schematic_get_width(schematic))
+ schematic_set_width(schematic, (guint) state->pos.x);
+ if (state->pos.y > schematic_get_height(schematic))
+ schematic_set_height(schematic, (guint) state->pos.y);
state->state = PARSE_PART;
break;
case PARSE_PART_ROTATION:
@@ -923,9 +1007,9 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_PART;
break;
case PARSE_PART_FLIP:
- if (g_ascii_strcasecmp ( state->content->str, "horizontal") == 0)
+ if (g_ascii_strcasecmp (state->content->str, "horizontal") == 0)
state->flip = state->flip | ID_FLIP_HORIZ;
- else if (g_ascii_strcasecmp ( state->content->str, "vertical") == 0)
+ else if (g_ascii_strcasecmp (state->content->str, "vertical") == 0)
state->flip = state->flip | ID_FLIP_VERT;
state->state = PARSE_PART;
break;
@@ -950,8 +1034,7 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_PART_LABEL:
state->state = PARSE_PART_LABELS;
- state->part->labels = g_slist_prepend (state->part->labels,
- state->label);
+ state->part->labels = g_slist_prepend (state->part->labels, state->label);
break;
case PARSE_PART_LABEL_NAME:
state->label->name = g_strdup (state->content->str);
@@ -962,8 +1045,7 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_PART_LABEL;
break;
case PARSE_PART_LABEL_POS:
- sscanf (state->content->str, "(%lf %lf)", &state->label->pos.x,
- &state->label->pos.y);
+ sscanf (state->content->str, "(%lf %lf)", &state->label->pos.x, &state->label->pos.y);
state->state = PARSE_PART_LABEL;
break;
case PARSE_PART_PROPERTIES:
@@ -971,8 +1053,7 @@ end_element (ParseState *state, const xmlChar *name)
break;
case PARSE_PART_PROPERTY:
state->state = PARSE_PART_PROPERTIES;
- state->part->properties = g_slist_prepend (state->part->properties,
- state->property);
+ state->part->properties = g_slist_prepend (state->part->properties, state->property);
break;
case PARSE_PART_PROPERTY_NAME:
state->property->name = g_strdup (state->content->str);
@@ -987,13 +1068,12 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_SCHEMATIC;
break;
case PARSE_WIRE:
- create_wire (state);
state->state = PARSE_WIRES;
break;
case PARSE_WIRE_POINTS:
- sscanf (state->content->str, "(%lf %lf)(%lf %lf)",
- &state->wire_start.x, &state->wire_start.y,
- &state->wire_end.x, &state->wire_end.y);
+ sscanf (state->content->str, "(%lf %lf)(%lf %lf)", &state->wire_start.x,
+ &state->wire_start.y, &state->wire_end.x, &state->wire_end.y);
+ create_wire (state);
state->state = PARSE_WIRE;
break;
@@ -1005,8 +1085,7 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_TEXTBOXES;
break;
case PARSE_TEXTBOX_POSITION:
- sscanf (state->content->str, "(%lf %lf)",
- &state->pos.x, &state->pos.y);
+ sscanf (state->content->str, "(%lf %lf)", &state->pos.x, &state->pos.y);
state->state = PARSE_TEXTBOX;
break;
case PARSE_TEXTBOX_TEXT:
@@ -1014,42 +1093,37 @@ end_element (ParseState *state, const xmlChar *name)
state->state = PARSE_TEXTBOX;
break;
case PARSE_SCHEMATIC:
- // The end of the file.
+ // The end of the file.
state->state = PARSE_FINISH;
break;
case PARSE_ERROR:
break;
case PARSE_START:
case PARSE_FINISH:
- // There should not be a closing tag in this state.
+ // There should not be a closing tag in this state.
g_assert_not_reached ();
break;
}
}
-static void
-my_characters (ParseState *state, const xmlChar *chars, int len)
+static void my_characters (ParseState *state, const xmlChar *chars, int len)
{
int i;
- if (state->state == PARSE_FINISH ||
- state->state == PARSE_START ||
- state->state == PARSE_PARTS ||
- state->state == PARSE_PART)
+ if (state->state == PARSE_FINISH || state->state == PARSE_START ||
+ state->state == PARSE_PARTS || state->state == PARSE_PART)
return;
for (i = 0; i < len; i++)
g_string_append_c (state->content, chars[i]);
}
-static xmlEntityPtr
-get_entity (void *user_data, const xmlChar *name)
+static xmlEntityPtr get_entity (void *user_data, const xmlChar *name)
{
return xmlGetPredefinedEntity (name);
}
-static void
-my_warning (void *user_data, const char *msg, ...)
+static void my_warning (void *user_data, const char *msg, ...)
{
va_list args;
@@ -1058,8 +1132,8 @@ my_warning (void *user_data, const char *msg, ...)
va_end (args);
}
-static void
-my_error (void *user_data, const char *msg, ...)
+// FIXME this should not be critical but forward to the oregano log buffer
+static void my_error (void *user_data, const char *msg, ...)
{
va_list args;
@@ -1068,8 +1142,7 @@ my_error (void *user_data, const char *msg, ...)
va_end (args);
}
-static void
-my_fatal_error (void *user_data, const char *msg, ...)
+static void my_fatal_error (void *user_data, const char *msg, ...)
{
va_list args;
diff --git a/src/load-schematic.h b/src/load-schematic.h
index 6243de9..ce3926d 100644
--- a/src/load-schematic.h
+++ b/src/load-schematic.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __LOAD_SCHEMATIC_H
@@ -39,5 +39,4 @@
gint schematic_parse_xml_file (Schematic *sm, const gchar *filename, GError **);
-
#endif
diff --git a/src/log-interface.h b/src/log-interface.h
new file mode 100644
index 0000000..d51eab3
--- /dev/null
+++ b/src/log-interface.h
@@ -0,0 +1,44 @@
+/*
+ * log-interface.h
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Use this interface to get rid of GUI dependencies. For example
+ * if you want to write a unit test in which the test function
+ * needs a log to not throw an exception.
+ */
+
+#ifndef LOG_INTERFACE_H_
+#define LOG_INTERFACE_H_
+
+typedef void (*LogFunction)(gpointer log, const char *message);
+
+typedef struct {
+ LogFunction log_append;
+ LogFunction log_append_error;
+ gpointer log;
+} LogInterface;
+
+#endif /* LOG_INTERFACE_H_ */
diff --git a/src/log-view.c b/src/log-view.c
new file mode 100644
index 0000000..fa5d5bd
--- /dev/null
+++ b/src/log-view.c
@@ -0,0 +1,52 @@
+#include "log-view.h"
+
+#define LOG_VIEW_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), TYPE_LOG_VIEW, LogViewPrivate))
+
+struct _LogViewPrivate
+{
+ char x;
+};
+
+G_DEFINE_TYPE (LogView, log_view, GTK_TYPE_TREE_VIEW);
+
+static void log_view_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (log_view_parent_class)->finalize (object);
+}
+
+static void log_view_class_init (LogViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = log_view_finalize;
+
+ g_type_class_add_private (object_class, sizeof(LogViewPrivate));
+}
+
+static void log_view_init (LogView *self) { self->priv = LOG_VIEW_GET_PRIVATE (self); }
+
+LogView *log_view_new ()
+{
+ LogView *self = g_object_new (TYPE_LOG_VIEW, NULL);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self), TRUE);
+
+ GtkTreeViewColumn *col1, *col2;
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+
+ g_object_ref (renderer);
+
+ col1 = gtk_tree_view_column_new_with_attributes ("Source", renderer, "text", 0, NULL);
+
+ col2 = gtk_tree_view_column_new_with_attributes ("Message", renderer, "text", 1, NULL);
+
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (self), col1, 0);
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (self), col2, 1);
+
+ return self;
+}
+
+void log_view_set_store (LogView *lv, Log *ls)
+{
+ gtk_tree_view_set_model (GTK_TREE_VIEW (lv), GTK_TREE_MODEL (ls));
+}
diff --git a/src/log-view.h b/src/log-view.h
new file mode 100644
index 0000000..8124711
--- /dev/null
+++ b/src/log-view.h
@@ -0,0 +1,42 @@
+#ifndef __LOG_VIEW_H__
+#define __LOG_VIEW_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "log.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_LOG_VIEW (log_view_get_type ())
+#define LOG_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_LOG_VIEW, LogView))
+#define LOG_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_LOG_VIEW, LogView const))
+#define LOG_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_LOG_VIEW, LogViewClass))
+#define LOG_IS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_LOG_VIEW))
+#define LOG_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_LOG_VIEW))
+#define LOG_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_LOG_VIEW, LogViewClass))
+
+typedef struct _LogView LogView;
+typedef struct _LogViewClass LogViewClass;
+typedef struct _LogViewPrivate LogViewPrivate;
+
+struct _LogView
+{
+ GtkTreeView parent;
+
+ LogViewPrivate *priv;
+};
+
+struct _LogViewClass
+{
+ GtkTreeViewClass parent_class;
+};
+
+GType log_view_get_type (void) G_GNUC_CONST;
+LogView *log_view_new (void);
+
+void log_view_set_store (LogView *lv, Log *ls);
+
+G_END_DECLS
+
+#endif /* __LOG_VIEW_H__ */
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..a48486f
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,107 @@
+#include <string.h>
+#include "log.h"
+
+#define LOG_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), LOG_TYPE, LogPrivate))
+
+struct _LogPrivate
+{
+ char x;
+};
+
+G_DEFINE_TYPE (Log, log, GTK_TYPE_LIST_STORE);
+
+static void log_finalize (GObject *object) { G_OBJECT_CLASS (log_parent_class)->finalize (object); }
+
+static void log_class_init (LogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = log_finalize;
+
+ g_type_class_add_private (object_class, sizeof(LogPrivate));
+}
+
+static void log_init (Log *self)
+{
+ static GType v[] = {G_TYPE_STRING, G_TYPE_STRING};
+ self->priv = LOG_GET_PRIVATE (self);
+ gtk_list_store_set_column_types (GTK_LIST_STORE (self), 2, v);
+}
+
+Log *log_new () { return g_object_new (LOG_TYPE, NULL); }
+
+/**
+ * trim only newlines
+ */
+gchar *log_append_trim_message(const gchar *string) {
+ if (string == NULL)
+ return NULL;
+ gchar **array = g_regex_split_simple("[\\r\\n]*(.*?)[\\n$]+", string, 0, 0);
+ gchar *ret_val = g_strdup(array[0]);
+ g_strfreev(array);
+ if (*ret_val == 0) {
+ g_free(ret_val);
+ ret_val = NULL;
+ }
+ return ret_val;
+}
+
+/**
+ * Show on top of the items in the logview.
+ *
+ * If the previous message had an '\r' at the end, the previous message will be
+ * replaced by the new message instead of prepending the new message.
+ *
+ * Leading and trailing '\n's will be truncated.
+ */
+void log_append (Log *log, const gchar *prefix, const gchar *message)
+{
+ //trim message (only newlines), because newlines do not make sense in the log view
+ gchar *message_trimed = log_append_trim_message(message);
+ if (message_trimed == NULL)
+ return;
+
+ GtkTreeIter iter;
+ //if the previous message had an '\r' at the end, the previous message will be
+ //replaced by the new message instead of prepending the new message
+ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(log), &iter)) {
+ GValue previous_value;
+ previous_value.g_type = 0;
+ gtk_tree_model_get_value(GTK_TREE_MODEL(log), &iter, 1, &previous_value);
+ const gchar *previous_message = g_value_get_string(&previous_value);
+
+ if (previous_message != NULL && previous_message[strlen(previous_message) - 1] != '\r')
+ gtk_list_store_prepend (GTK_LIST_STORE (log), &iter);
+ g_value_unset(&previous_value);
+ } else {
+ gtk_list_store_prepend (GTK_LIST_STORE (log), &iter);
+ }
+ gtk_list_store_set (GTK_LIST_STORE (log), &iter, 0, g_strdup (prefix), 1, g_strdup (message_trimed),
+ -1);
+ g_free(message_trimed);
+}
+
+void log_append_error (Log *log, const gchar *prefix, const gchar *message, GError *error)
+{
+ if (error == NULL) {
+ return log_append (log, prefix, message);
+ }
+ gchar *concat = NULL;
+
+ if (message) {
+ concat = g_strdup_printf ("%s\n%s - %i", message, error->message, error->code);
+ } else {
+ concat = g_strdup_printf ("\n%s - %i", error->message, error->code);
+ }
+
+ GtkTreeIter item;
+ gtk_list_store_insert (GTK_LIST_STORE (log), &item, 0);
+ gtk_list_store_set (GTK_LIST_STORE (log), &item, 0, g_strdup (prefix), 1, concat, -1);
+}
+
+void log_clear (Log *log) { gtk_list_store_clear (GTK_LIST_STORE (log)); }
+
+void log_export (Log *log, const gchar *path)
+{
+ // FIXME TODO
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..12b009f
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,41 @@
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define LOG_TYPE (log_get_type ())
+#define LOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOG_TYPE, Log))
+#define LOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOG_TYPE, Log const))
+#define LOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOG_TYPE, LogClass))
+#define LOG_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOG_TYPE))
+#define LOG_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LOG_TYPE))
+#define LOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOG_TYPE, LogClass))
+
+typedef struct _Log Log;
+typedef struct _LogClass LogClass;
+typedef struct _LogPrivate LogPrivate;
+
+struct _Log
+{
+ GtkListStore parent;
+
+ LogPrivate *priv;
+};
+
+struct _LogClass
+{
+ GtkListStoreClass parent_class;
+};
+
+GType log_get_type (void) G_GNUC_CONST;
+Log *log_new (void);
+
+void log_append (Log *log, const gchar *prefix, const gchar *message);
+
+void log_append_error (Log *log, const gchar *prefix, const gchar *message, GError *error);
+
+G_END_DECLS
+
+#endif /* __LOG_H__ */
diff --git a/src/main.c b/src/main.c
index a2e3852..8b19664 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,13 +1,14 @@
/*
* main.c
*
- * Author:
+ *
+ * Authors:
* Richard Hult <rhult@hem.passagen.se>
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -25,22 +26,31 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-#include <config.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include "oregano.h"
+#include "options.h"
+#include "schematic.h"
-int
-main (int argc, char *argv[])
+int main (int argc, char *argv[])
{
+ // keep in mind the app is a subclass of GtkApplication
+ // which is a subclass of GApplication
+ // so casts from g_application_get_default to
+ // GtkApplication as well as GApplication or Oregano
+ // are explicitly allowed
Oregano *app;
+ GError *error = NULL;
int status;
-
+ gpointer class = NULL;
#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
@@ -48,10 +58,35 @@ main (int argc, char *argv[])
textdomain (GETTEXT_PACKAGE);
#endif
- gtk_init (&argc, &argv);
- app = oregano_new ();
- status = g_application_run (G_APPLICATION (app), argc, argv);
- g_object_unref (app);
+ oregano_options_parse (&argc, &argv, &error);
+ if (error) {
+ g_warning ("Failed to parse commandline arguments: %i - %s", error->code, error->message);
+ g_clear_error (&error);
+ return 1;
+ }
+ if (oregano_options_version()) {
+ g_printf("Oregano "VERSION"\n"
+ " Website: https://ahoi.io/projects/oregano\n"
+ " License: GPLv2/GPLv3\n"
+ " Main Developer: Bernhard Schuster\n");
+ return 0;
+ }
+
+ // required?
+ gtk_init (&argc, &argv);
+
+ // required, as we possibly need signal
+ // information within oregano.c _before_ the
+ // first Schematic instance exists
+ class = g_type_class_ref (TYPE_SCHEMATIC);
+ app = oregano_new ();
+
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+
+ oregano_deallocate_memory ();
+
+ g_object_unref (app);
+ g_type_class_unref (class);
- return status;
+ return status;
}
diff --git a/src/model/Makefile.am b/src/model/Makefile.am
deleted file mode 100644
index 6abbb8b..0000000
--- a/src/model/Makefile.am
+++ /dev/null
@@ -1,40 +0,0 @@
-oreganodir = $(datadir)/oregano
-
-AM_CFLAGS = -Wall -DG_DISABLE_DEPRECATED -DGSEAL_ENABLE \
- -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED \
- -DGTK_DISABLE_DEPRECATED \
- -DG_DISABLE_SINGLE_INCLUDES -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
- -DGTK_DISABLE_SINGLE_INCLUDES
-
-INCLUDES = \
- -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
- -I$(includedir) $(GNOME_INCLUDEDIR) \
- -DOREGANO_UIDIR=\""$(oreganodir)/xml"\" \
- -DOREGANO_LIBRARYDIR=\""$(oreganodir)/libraries"\" \
- -DOREGANO_MODELDIR=\""$(oreganodir)/models"\" \
- -DDATADIR=\""$(datadir)"\" \
- -DGETTEXT_PACKAGE=\""oregano\"" \
- $(OREGANO_CFLAGS) -I$(top_srcdir)/src -I$(top_srcdir)/src/sheet \
- -I$(top_srcdir)/src/engines
-
-noinst_LIBRARIES = libmodel.a
-libmodel_a_SOURCES = \
- item-data.c \
- item-data.h \
- node.c \
- node.h \
- node-store.c \
- node-store.h \
- part.c \
- part.h \
- part-property.c \
- part-property.h \
- schematic.c \
- schematic.h \
- sheet-pos.h \
- textbox.c \
- textbox.h \
- wire.c \
- wire.h \
- wire-private.h \
- part-private.h
diff --git a/src/model/item-data.c b/src/model/item-data.c
index 382a012..c9391d4 100644
--- a/src/model/item-data.c
+++ b/src/model/item-data.c
@@ -8,12 +8,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -27,80 +29,87 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-#include "goocanvas.h"
+#include <glib.h>
+#include <goocanvas.h>
#include "item-data.h"
#include "node-store.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
static void item_data_class_init (ItemDataClass *klass);
static void item_data_init (ItemData *item_data);
-static void item_data_set_gproperty (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-static void item_data_get_gproperty (GObject *object, guint prop_id,
- GValue *value, GParamSpec *spec);
+static void item_data_set_gproperty (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void item_data_get_gproperty (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec);
static void item_data_copy (ItemData *dest, ItemData *src);
-static gboolean emit_moved_signal_when_handler_connected (gpointer data);
-enum {
- ARG_0,
- ARG_STORE,
- ARG_POS
-};
+enum { ARG_0, ARG_STORE, ARG_POS };
enum {
MOVED,
ROTATED,
FLIPPED,
+ CHANGED, // used to notify the view to reset and recalc the transformation
HIGHLIGHT,
LAST_SIGNAL
};
-struct _ItemDataPriv {
+struct _ItemDataPriv
+{
NodeStore *store;
- SheetPos pos;
- // Bounding box.
+
+ // modificator matrices
+ cairo_matrix_t translate;
+ cairo_matrix_t rotate;
+ cairo_matrix_t flip;
+
+ // Bounding box
GooCanvasBounds bounds;
};
-// Structure defined to cover exchange between g_timeout_add and the
-// function in charge to emit the moved signal only once the handler
-// has been connected.
-typedef struct {
- ItemData *item_data;
- SheetPos delta;
-} SignalStruct;
+G_DEFINE_TYPE (ItemData, item_data, G_TYPE_OBJECT);
-G_DEFINE_TYPE (ItemData, item_data, G_TYPE_OBJECT)
+static guint item_data_signals[LAST_SIGNAL] = {0};
-static guint item_data_signals [LAST_SIGNAL] = { 0 };
+static void item_data_init (ItemData *item_data)
+{
+ ItemDataPriv *priv;
+
+ priv = g_slice_new0 (ItemDataPriv);
+
+ priv->bounds.x1 = priv->bounds.x2 = priv->bounds.y1 = priv->bounds.y2 = 0;
-static void
-item_data_dispose (GObject *object)
+ cairo_matrix_init_identity (&(priv->translate));
+ cairo_matrix_init_identity (&(priv->rotate));
+ cairo_matrix_init_identity (&(priv->flip));
+
+ item_data->priv = priv;
+}
+
+static void item_data_dispose (GObject *object)
{
+ ItemDataPriv *priv = ITEM_DATA (object)->priv;
// Remove the item from the sheet node store if there.
- if (ITEM_DATA (object)->priv->store) {
+ if (priv->store) {
item_data_unregister (ITEM_DATA (object));
}
-
+ g_slice_free (ItemDataPriv, priv);
G_OBJECT_CLASS (item_data_parent_class)->dispose (object);
}
-
-static void
-item_data_finalize (GObject *object)
+static void item_data_finalize (GObject *object)
{
g_return_if_fail (object != NULL);
G_OBJECT_CLASS (item_data_parent_class)->finalize (object);
}
-static void
-item_data_class_init (ItemDataClass *klass)
+static void item_data_class_init (ItemDataClass *klass)
{
GObjectClass *object_class;
@@ -108,63 +117,41 @@ item_data_class_init (ItemDataClass *klass)
object_class = G_OBJECT_CLASS (klass);
- // This assignment must be performed before the call
+ // This assignment must be performed before the call
// to g_object_class_install_property
object_class->set_property = item_data_set_gproperty;
object_class->get_property = item_data_get_gproperty;
- g_object_class_install_property (object_class, ARG_STORE,
- g_param_spec_pointer ("store", "ItemData::store",
- "the store data", G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, ARG_STORE,
+ g_param_spec_pointer ("store", "ItemData::store", "the store data", G_PARAM_READWRITE));
- g_object_class_install_property (object_class, ARG_POS,
- g_param_spec_pointer ("pos", "ItemData::pos",
- "the pos data", G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, ARG_POS,
+ g_param_spec_pointer ("pos", "ItemData::pos", "the pos data", G_PARAM_READWRITE));
object_class->dispose = item_data_dispose;
object_class->finalize = item_data_finalize;
- item_data_signals [MOVED] = g_signal_new ("moved",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (ItemDataClass, moved),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- item_data_signals [ROTATED] = g_signal_new ("rotated",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE,
- 1,
- G_TYPE_INT);
-
- item_data_signals [FLIPPED] = g_signal_new ("flipped",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE,
- 1,
- G_TYPE_INT);
-
- item_data_signals [HIGHLIGHT] = g_signal_new ("highlight",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
+ item_data_signals[MOVED] =
+ g_signal_new ("moved", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ItemDataClass, moved), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ item_data_signals[ROTATED] =
+ g_signal_new ("rotated", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+
+ item_data_signals[FLIPPED] =
+ g_signal_new ("flipped", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+
+ item_data_signals[CHANGED] =
+ g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ item_data_signals[HIGHLIGHT] =
+ g_signal_new ("highlight", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
// Methods.
klass->clone = NULL;
@@ -173,38 +160,27 @@ item_data_class_init (ItemDataClass *klass)
klass->flip = NULL;
klass->reg = NULL;
klass->unreg = NULL;
+ klass->changed = NULL;
// Signals.
klass->moved = NULL;
}
-static void
-item_data_init (ItemData *item_data)
-{
- ItemDataPriv *priv;
-
- priv = g_new0 (ItemDataPriv, 1);
-
- priv->pos.x = 0;
- priv->pos.y = 0;
- priv->bounds.x1 = priv->bounds.x2 = priv->bounds.y1 = priv->bounds.y2 = 0;
+////////////////////////////////////////////////////////////////////////////////
+// END BOILER PLATE
+////////////////////////////////////////////////////////////////////////////////
- item_data->priv = priv;
-}
-
-ItemData *
-item_data_new (void)
+ItemData *item_data_new (void)
{
ItemData *item_data;
- item_data = ITEM_DATA (g_object_new (item_data_get_type(), NULL));
+ item_data = ITEM_DATA (g_object_new (item_data_get_type (), NULL));
return item_data;
}
-static void
-item_data_set_gproperty (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *spec)
+static void item_data_set_gproperty (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
{
ItemData *item_data = ITEM_DATA (object);
@@ -213,13 +189,12 @@ item_data_set_gproperty (GObject *object, guint prop_id, const GValue *value,
item_data->priv->store = g_value_get_pointer (value);
break;
default:
- break;
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (item_data, prop_id, spec);
}
}
-static void
-item_data_get_gproperty (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec)
+static void item_data_get_gproperty (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec)
{
ItemData *item_data = ITEM_DATA (object);
@@ -232,72 +207,48 @@ item_data_get_gproperty (GObject *object, guint prop_id, GValue *value,
}
}
-void
-item_data_get_pos (ItemData *item_data, SheetPos *pos)
+/**
+ * returns the top left corner of the item
+ */
+void item_data_get_pos (ItemData *item_data, Coords *pos)
{
g_return_if_fail (item_data != NULL);
g_return_if_fail (IS_ITEM_DATA (item_data));
g_return_if_fail (pos != NULL);
-
- *pos = item_data->priv->pos;
+ ItemDataPriv *priv;
+ priv = item_data->priv;
+ pos->x = priv->translate.x0;
+ pos->y = priv->translate.y0;
}
-void
-item_data_set_pos (ItemData *item_data, SheetPos *pos)
+void item_data_set_pos (ItemData *item_data, Coords *pos)
{
ItemDataPriv *priv;
- SheetPos delta;
- SignalStruct *signal_struct;
+ gboolean handler_connected;
- g_return_if_fail (pos != NULL);
- g_return_if_fail (item_data != NULL);
+ g_return_if_fail (pos);
+ g_return_if_fail (item_data);
g_return_if_fail (IS_ITEM_DATA (item_data));
- if (pos == NULL)
- return;
-
priv = item_data->priv;
- priv->pos.x = pos->x;
- priv->pos.y = pos->y;
-
- delta.x = pos->x;
- delta.y = pos->y;
-
- signal_struct = g_new0 (SignalStruct, 1);
- signal_struct->item_data = item_data;
- signal_struct->delta = delta;
- g_timeout_add (10,
- (gpointer) emit_moved_signal_when_handler_connected,
- (gpointer) signal_struct);
-}
-static gboolean
-emit_moved_signal_when_handler_connected (gpointer data)
-{
- gboolean handler_connected;
- SignalStruct *signal_struct = (SignalStruct *) data;
- SheetPos delta;
- ItemData *item_data;
+ cairo_matrix_init_translate (&(priv->translate), pos->x, pos->y);
- item_data = signal_struct->item_data;
- delta.x = signal_struct->delta.x;
- delta.y = signal_struct->delta.y;
-
- handler_connected = g_signal_handler_is_connected (G_OBJECT (item_data),
- item_data->moved_handler_id);
+ handler_connected =
+ g_signal_handler_is_connected (G_OBJECT (item_data), item_data->moved_handler_id);
if (handler_connected) {
- g_signal_emit_by_name (G_OBJECT (item_data),
- "moved", &delta);
+ g_signal_emit_by_name (G_OBJECT (item_data), "moved", pos);
+ }
+ handler_connected =
+ g_signal_handler_is_connected (G_OBJECT (item_data), item_data->changed_handler_id);
+ if (handler_connected) {
+ g_signal_emit_by_name (G_OBJECT (item_data), "changed");
}
-
- return !handler_connected;
}
-void
-item_data_move (ItemData *item_data, SheetPos *delta)
+void item_data_move (ItemData *item_data, const Coords *delta)
{
ItemDataPriv *priv;
- SignalStruct *signal_struct;
g_return_if_fail (item_data != NULL);
g_return_if_fail (IS_ITEM_DATA (item_data));
@@ -305,22 +256,17 @@ item_data_move (ItemData *item_data, SheetPos *delta)
if (delta == NULL)
return;
+ if (fabs (delta->x) < 1e-2 && fabs (delta->y) < 1e-2)
+ return;
+
priv = item_data->priv;
- priv->pos.x += delta->x;
- priv->pos.y += delta->y;
- delta->x = priv->pos.x;
- delta->y = priv->pos.y;
-
- signal_struct = g_new0 (SignalStruct, 1);
- signal_struct->item_data = item_data;
- signal_struct->delta = (* delta);
- g_timeout_add (10,
- (gpointer) emit_moved_signal_when_handler_connected,
- (gpointer) signal_struct);
+ cairo_matrix_translate (&(priv->translate), delta->x, delta->y);
+
+ g_signal_emit_by_name (G_OBJECT (item_data), "changed");
}
-gpointer // NodeStore *
-item_data_get_store (ItemData *item_data)
+// NodeStore *
+gpointer item_data_get_store (ItemData *item_data)
{
g_return_val_if_fail (item_data != NULL, NULL);
g_return_val_if_fail (IS_ITEM_DATA (item_data), NULL);
@@ -328,8 +274,7 @@ item_data_get_store (ItemData *item_data)
return item_data->priv->store;
}
-ItemData *
-item_data_clone (ItemData *src)
+ItemData *item_data_clone (ItemData *src)
{
ItemDataClass *id_class;
@@ -343,20 +288,20 @@ item_data_clone (ItemData *src)
return id_class->clone (src);
}
-static void
-item_data_copy (ItemData *dest, ItemData *src)
+static void item_data_copy (ItemData *dest, ItemData *src)
{
g_return_if_fail (dest != NULL);
g_return_if_fail (IS_ITEM_DATA (dest));
g_return_if_fail (src != NULL);
g_return_if_fail (IS_ITEM_DATA (src));
- dest->priv->pos = src->priv->pos;
+ dest->priv->translate = src->priv->translate;
+ dest->priv->rotate = src->priv->rotate;
+ dest->priv->flip = src->priv->flip;
dest->priv->store = NULL;
}
-void
-item_data_get_relative_bbox (ItemData *data, SheetPos *p1, SheetPos *p2)
+void item_data_get_relative_bbox (ItemData *data, Coords *p1, Coords *p2)
{
g_return_if_fail (data != NULL);
g_return_if_fail (IS_ITEM_DATA (data));
@@ -372,27 +317,28 @@ item_data_get_relative_bbox (ItemData *data, SheetPos *p1, SheetPos *p2)
}
}
-void
-item_data_get_absolute_bbox (ItemData *data, SheetPos *p1, SheetPos *p2)
+void item_data_get_absolute_bbox (ItemData *data, Coords *p1, Coords *p2)
{
g_return_if_fail (data != NULL);
g_return_if_fail (IS_ITEM_DATA (data));
+ ItemDataPriv *priv;
+
item_data_get_relative_bbox (data, p1, p2);
+ priv = data->priv;
if (p1) {
- p1->x += data->priv->pos.x;
- p1->y += data->priv->pos.y;
+ p1->x += priv->translate.x0;
+ p1->y += priv->translate.y0;
}
if (p2) {
- p2->x += data->priv->pos.x;
- p2->y += data->priv->pos.y;
+ p2->x += priv->translate.x0;
+ p2->y += priv->translate.y0;
}
}
-void
-item_data_set_relative_bbox (ItemData *data, SheetPos *p1, SheetPos *p2)
+void item_data_set_relative_bbox (ItemData *data, Coords *p1, Coords *p2)
{
g_return_if_fail (data != NULL);
g_return_if_fail (IS_ITEM_DATA (data));
@@ -408,20 +354,20 @@ item_data_set_relative_bbox (ItemData *data, SheetPos *p1, SheetPos *p2)
}
}
-void
-item_data_list_get_absolute_bbox (GList *item_data_list, SheetPos *p1,
- SheetPos *p2)
+void item_data_list_get_absolute_bbox (GList *item_data_list, Coords *p1, Coords *p2)
{
- GList *list;
- SheetPos b1, b2;
+ GList *iter;
+ Coords b1, b2;
if (item_data_list == NULL)
return;
item_data_get_absolute_bbox (item_data_list->data, p1, p2);
- for (list = item_data_list; list; list = list->next) {
- item_data_get_absolute_bbox (list->data, &b1, &b2);
+ for (iter = item_data_list; iter; iter = iter->next) {
+ if (G_UNLIKELY (iter->data == NULL))
+ continue;
+ item_data_get_absolute_bbox (iter->data, &b1, &b2);
if (p1) {
p1->x = MIN (p1->x, b1.x);
@@ -433,11 +379,9 @@ item_data_list_get_absolute_bbox (GList *item_data_list, SheetPos *p1,
p2->y = MAX (p2->y, b2.y);
}
}
- g_list_free_full (list, g_object_unref);
}
-void
-item_data_rotate (ItemData *data, int angle, SheetPos *center)
+void item_data_rotate (ItemData *data, int angle, Coords *center)
{
ItemDataClass *id_class;
@@ -450,8 +394,7 @@ item_data_rotate (ItemData *data, int angle, SheetPos *center)
}
}
-void
-item_data_flip (ItemData *data, gboolean horizontal, SheetPos *center)
+void item_data_flip (ItemData *data, IDFlip direction, Coords *center)
{
ItemDataClass *id_class;
@@ -460,12 +403,11 @@ item_data_flip (ItemData *data, gboolean horizontal, SheetPos *center)
id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (data));
if (id_class->flip) {
- id_class->flip (data, horizontal, center);
+ id_class->flip (data, direction, center);
}
}
-void
-item_data_unregister (ItemData *data)
+void item_data_unregister (ItemData *data)
{
ItemDataClass *id_class;
@@ -478,23 +420,21 @@ item_data_unregister (ItemData *data)
}
}
-int
-item_data_register (ItemData *data)
+gboolean item_data_register (ItemData *data)
{
ItemDataClass *id_class;
- g_return_val_if_fail (data != NULL, -1);
- g_return_val_if_fail (IS_ITEM_DATA (data), -1);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (IS_ITEM_DATA (data), FALSE);
id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (data));
if (id_class->reg) {
return id_class->reg (data);
}
- return -1;
+ return FALSE;
}
-char *
-item_data_get_refdes_prefix (ItemData *data)
+char *item_data_get_refdes_prefix (ItemData *data)
{
ItemDataClass *id_class;
@@ -509,8 +449,7 @@ item_data_get_refdes_prefix (ItemData *data)
return NULL;
}
-void
-item_data_set_property (ItemData *data, char *property, char *value)
+void item_data_set_property (ItemData *data, char *property, char *value)
{
ItemDataClass *id_class;
@@ -524,8 +463,7 @@ item_data_set_property (ItemData *data, char *property, char *value)
}
}
-gboolean
-item_data_has_properties (ItemData *data)
+gboolean item_data_has_properties (ItemData *data)
{
ItemDataClass *id_class;
@@ -539,8 +477,7 @@ item_data_has_properties (ItemData *data)
return FALSE;
}
-void
-item_data_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
+void item_data_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
{
ItemDataClass *id_class;
@@ -553,3 +490,49 @@ item_data_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
id_class->print (data, cr, ctx);
}
}
+
+/**
+ * \brief changed, forcefully emits a changed signal to recalculate the morph
+ *matrix
+ *
+ * @param data determines which item to refresh
+ *
+ * \note this function does _not_ request a redraw
+ */
+void item_data_changed (ItemData *data)
+{
+ ItemDataClass *id_class;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_ITEM_DATA (data));
+
+ id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (data));
+ if (id_class->changed == NULL)
+ return;
+
+ return id_class->changed (data);
+}
+
+/**
+ * @param data
+ * @returns [transfer-none] pointer to cairo matrix which only includes the
+ * translation
+ */
+cairo_matrix_t *item_data_get_translate (ItemData *data)
+{
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (IS_ITEM_DATA (data), NULL);
+ return &(data->priv->translate);
+}
+
+/**
+ * @param data
+ * @returns [transfer-none] pointer to cairo matrix which only includes the
+ * rotation
+ */
+cairo_matrix_t *item_data_get_rotate (ItemData *data)
+{
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (IS_ITEM_DATA (data), NULL);
+ return &(data->priv->rotate);
+}
diff --git a/src/model/item-data.h b/src/model/item-data.h
index fb1b4b6..4ebf177 100644
--- a/src/model/item-data.h
+++ b/src/model/item-data.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __ITEM_DATA_H
#define __ITEM_DATA_H
@@ -36,31 +38,36 @@
#include <cairo/cairo.h>
-#include "sheet-pos.h"
+#include "coords.h"
+#include "grid.h"
#include "schematic-print-context.h"
-#define TYPE_ITEM_DATA (item_data_get_type ())
-#define ITEM_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ITEM_DATA, ItemData))
-#define ITEM_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ITEM_DATA, ItemDataClass))
-#define IS_ITEM_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ITEM_DATA))
-#define IS_ITEM_DATA_CLASS(klass) (G_TYPE_CHECK_INSTANCE_GET_CLASS ((klass), TYPE_ITEM_DATA, ItemDataClass))
+#define TYPE_ITEM_DATA (item_data_get_type ())
+#define ITEM_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ITEM_DATA, ItemData))
+#define ITEM_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ITEM_DATA, ItemDataClass))
+#define IS_ITEM_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ITEM_DATA))
+#define IS_ITEM_DATA_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_GET_CLASS ((klass), TYPE_ITEM_DATA, ItemDataClass))
typedef struct _ItemData ItemData;
typedef struct _ItemDataClass ItemDataClass;
typedef struct _ItemDataPriv ItemDataPriv;
typedef enum {
- ID_FLIP_NONE = 0,
- ID_FLIP_HORIZ = 1 << 0,
- ID_FLIP_VERT = 1 << 1
+ ID_FLIP_NONE = 0,
+ ID_FLIP_HORIZ = 1 << 0,
+ ID_FLIP_VERT = 1 << 1,
+ ID_FLIP_MASK = 3
} IDFlip;
-struct _ItemData {
- GObject parent;
- gulong moved_handler_id;
- gulong rotated_handler_id;
- gulong flipped_handler_id;
- ItemDataPriv * priv;
+struct _ItemData
+{
+ GObject parent;
+ gulong moved_handler_id;
+ gulong rotated_handler_id;
+ gulong flipped_handler_id;
+ gulong changed_handler_id;
+ ItemDataPriv *priv;
};
struct _ItemDataClass
@@ -68,95 +75,92 @@ struct _ItemDataClass
GObjectClass parent_class;
// Signals.
- void (*moved) (ItemData *data, SheetPos *delta);
+ void (*moved)(ItemData *data, Coords *delta);
// Methods.
- ItemData * (*clone) (ItemData *src);
- void (*copy) (ItemData *dest, ItemData *src);
- void (*rotate) (ItemData *data, int angle,
- SheetPos *center);
- void (*flip) (ItemData *data, gboolean horizontal,
- SheetPos *center);
- void (*unreg) (ItemData *data);
- int (*reg) (ItemData *data);
-
- char* (*get_refdes_prefix) (ItemData *data);
- void (*set_property) (ItemData *data, char *property,
- char *value);
- gboolean (*has_properties) (ItemData *data);
-
- void (*print) (ItemData *data, cairo_t *cr,
- SchematicPrintContext *ctx);
+ ItemData *(*clone)(ItemData *src);
+ void (*copy)(ItemData *dest, ItemData *src);
+ void (*rotate)(ItemData *data, int angle, Coords *center);
+ void (*flip)(ItemData *data, IDFlip direction, Coords *center);
+ void (*unreg)(ItemData *data);
+ int (*reg)(ItemData *data);
+ void (*changed)(ItemData *data);
+
+ char *(*get_refdes_prefix)(ItemData *data);
+ void (*set_property)(ItemData *data, char *property, char *value);
+ gboolean (*has_properties)(ItemData *data);
+
+ void (*print)(ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
};
-GType item_data_get_type (void);
+GType item_data_get_type (void);
// Create a new ItemData object
ItemData *item_data_new (void);
// Clone an ItemData
// param src A valid ItemData
-ItemData * item_data_clone (ItemData *src);
+ItemData *item_data_clone (ItemData *src);
// Get Item position
-void item_data_get_pos (ItemData *item_data, SheetPos *pos);
+void item_data_get_pos (ItemData *item_data, Coords *pos);
// Set Item position
-void item_data_set_pos (ItemData *item_data, SheetPos *pos);
+void item_data_set_pos (ItemData *item_data, Coords *pos);
// Move an ItemData
// \param delta offset to move the item
-void item_data_move (ItemData *item_data, SheetPos *delta);
+void item_data_move (ItemData *item_data, const Coords *delta);
-// Get the bounding box of an item data
-//Retrieve the bounding box of the item relative to position
+// Get the bounding box of an item data
+// Retrieve the bounding box of the item relative to position
// \param p1 Where to store the upper-left point
// \param p2 Where to store the lower-right point
-void item_data_get_relative_bbox (ItemData *data, SheetPos *p1,
- SheetPos *p2);
+void item_data_get_relative_bbox (ItemData *data, Coords *p1, Coords *p2);
// Set the relative bounding box
-void item_data_set_relative_bbox (ItemData *data, SheetPos *p1,
- SheetPos *p2);
+void item_data_set_relative_bbox (ItemData *data, Coords *p1, Coords *p2);
// Get absolute bounding box
// This function is like item_data_get_relative_bbox but it add
// the item position to the bbox vertex
-void item_data_get_absolute_bbox (ItemData *data, SheetPos *p1,
- SheetPos *p2);
+void item_data_get_absolute_bbox (ItemData *data, Coords *p1, Coords *p2);
// Get the absolute bounding box of a list of items
// This return a bbox that enclose all item in a list
-void item_data_list_get_absolute_bbox (GList *item_data_list,
- SheetPos *p1, SheetPos *p2);
+void item_data_list_get_absolute_bbox (GList *item_data_list, Coords *p1, Coords *p2);
// Rotate an item
-void item_data_rotate (ItemData *data, int angle, SheetPos *center);
+void item_data_rotate (ItemData *data, int angle, Coords *center);
// Flip an item
-void item_data_flip (ItemData *data, gboolean horizontal,
- SheetPos *center);
+void item_data_flip (ItemData *data, IDFlip direction, Coords *center);
// Get the Store associated for this item
// Store is a class that hold all items in a schematic
-gpointer item_data_get_store (ItemData *item_data);
+gpointer item_data_get_store (ItemData *item_data);
// Unregister item in its Store
-void item_data_unregister (ItemData *data);
+void item_data_unregister (ItemData *data);
// Register item in its Store
-int item_data_register (ItemData *data);
+int item_data_register (ItemData *data);
// Get the prefix of a part reference
-char * item_data_get_refdes_prefix (ItemData *data);
+char *item_data_get_refdes_prefix (ItemData *data);
-gboolean item_data_has_properties (ItemData *date);
+gboolean item_data_has_properties (ItemData *date);
// Set property
-void item_data_set_property (ItemData *data, char *property,
- char *value);
+void item_data_set_property (ItemData *data, char *property, char *value);
// Print Item data
// This method implement the Cairo stuff for schematic print of an item.
-void item_data_print (ItemData *data, cairo_t *cr,
- SchematicPrintContext *ctx);
+void item_data_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
+
+// Refresh the canvas representation of the item based on the itemdata's
+// properties (or its subclasses)
+void item_data_changed (ItemData *data);
+//
+cairo_matrix_t *item_data_get_translate (ItemData *data);
+cairo_matrix_t *item_data_get_rotate (ItemData *data);
#endif
diff --git a/src/model/node-store-private.h b/src/model/node-store-private.h
new file mode 100644
index 0000000..a41a067
--- /dev/null
+++ b/src/model/node-store-private.h
@@ -0,0 +1,353 @@
+#ifndef NODE_STORE_PRIV_H__
+#define NODE_STORE_PRIV_H__
+
+#include <glib.h>
+
+#include "coords.h"
+#include "node.h"
+#include "wire.h"
+
+#include "debug.h"
+static gboolean is_point_on_wire (Wire *w, Coords *where);
+
+static void add_node (gpointer key, Node *node, GList **list)
+{
+ *list = g_list_prepend (*list, node);
+}
+
+static void add_node_position (gpointer key, Node *node, GList **list)
+{
+ if (node_needs_dot (node))
+ *list = g_list_prepend (*list, key);
+}
+
+/**
+ * check if 2 wires intersect
+ * @param a wire
+ * @param b wire
+ * @param where [out] [NULL allowed] the position of intersection, if
+ * @returns TRUE when @a and @b intersect, else FALSE
+ */
+gboolean do_wires_intersect (Wire *a, Wire *b, Coords *where)
+{
+ g_assert (a);
+ g_assert (b);
+ Coords delta1, start1;
+ Coords delta2, start2;
+ wire_get_pos_and_length (a, &start1, &delta1);
+ wire_get_pos_and_length (b, &start2, &delta2);
+
+ // parallel check
+ const gdouble d = coords_cross (&delta1, &delta2);
+ if (fabs (d) < NODE_EPSILON) {
+ NG_DEBUG ("do_wires_intersect(%p,%p): NO! d=%lf\n", a, b, d);
+ return FALSE;
+ }
+
+ // implemented according to
+ // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
+ const Coords qminusp = coords_sub (&start2, &start1);
+
+ // p = start1, q = start2, r = delta1, s = delta2
+ const gdouble t = coords_cross (&qminusp, &delta1) / d;
+ const gdouble u = coords_cross (&qminusp, &delta2) / d;
+
+ if (t >= -NODE_EPSILON && t - NODE_EPSILON <= 1.f && u >= -NODE_EPSILON &&
+ u - NODE_EPSILON <= 1.f) {
+ NG_DEBUG ("do_wires_intersect(%p,%p): YES! t,u = %lf,%lf\n", a, b, t, u);
+ if (where) {
+ where->x = start1.x + u * delta1.x;
+ where->y = start1.y + u * delta1.y;
+ }
+ return TRUE;
+ }
+ NG_DEBUG ("do_wires_intersect(%p,%p): NO! t,u = %lf,%lf\n", a, b, t, u);
+ return FALSE;
+}
+
+/**
+ * @param store which NodeStore to use
+ * @param pos where to look for wires
+ * @returns list of wire at position p (including endpoints)
+ */
+static GSList *get_wires_at_pos (NodeStore *store, Coords pos)
+{
+ GList *iter;
+ GSList *wire_list;
+
+ g_return_val_if_fail (store, FALSE);
+ g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
+
+ wire_list = NULL;
+
+ for (iter = store->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
+
+ if (is_point_on_wire (wire, &pos))
+ wire_list = g_slist_prepend (wire_list, wire);
+ }
+
+ return wire_list;
+}
+
+/**
+ * projects the point @p onto wire @w
+ * @param w the wire
+ * @param p the point
+ * @param projected [out][NULL-allowed] the point p is projected onto - this is
+ * always filled no matter of return value
+ * @param d [out][NULL-allowed] the distance between @p and @projected - this is
+ * always filled no matter of return value
+ * @returns TRUE if the point was within the line segement bounds, else FALSE
+ */
+static gboolean project_point_on_wire (Wire *w, Coords *p, Coords *projected, gdouble *d)
+{
+ Coords cstart, clen;
+ wire_get_pos_and_length (w, &cstart, &clen);
+
+ const Coords delta = coords_sub (p, &cstart);
+ const gdouble l2 = coords_euclid2 (&clen);
+ const gdouble lambda = coords_dot (&delta, &clen) / l2;
+ Coords pro = {cstart.x + lambda * clen.x, cstart.y + lambda * clen.y};
+ if (projected) {
+ *projected = pro;
+ }
+ if (d) {
+ pro.x -= p->x;
+ pro.y -= p->y;
+ *d = coords_euclid2 (&pro);
+ }
+
+ return (lambda >= 0. - NODE_EPSILON && lambda <= 1. + NODE_EPSILON);
+}
+
+/**
+ * test if point is within a wire (including endpoints)
+ * @param w the wire
+ * @param p the point to test
+ */
+static gboolean is_point_on_wire (Wire *w, Coords *p)
+{
+ g_assert (w);
+ g_assert (IS_WIRE (w));
+ g_assert (p);
+ gdouble d = -7777.7777;
+ const gboolean ret = project_point_on_wire (w, p, NULL, &d);
+ return (ret && fabs (d) < NODE_EPSILON);
+}
+
+/**
+ * check if the two given wires have any incomon endpoints
+ * @param w the wire
+ * @param p the point to test
+ */
+static gboolean is_point_at_end_of_wire (Wire *w, Coords *p)
+{
+ g_assert (w);
+ g_assert (IS_WIRE (w));
+ g_assert (p);
+
+ Coords start1, end1;
+ wire_get_start_and_end_pos (w, &start1, &end1);
+
+ return coords_equal (&start1, p) || coords_equal (&end1, p);
+}
+
+/**
+ * check if 2 wires are colinear/parallel
+ */
+static gboolean check_colinear (Wire *a, Wire *b)
+{
+ Coords la, sa;
+ Coords lb, sb;
+ wire_get_pos_and_length (a, &sa, &la);
+ wire_get_pos_and_length (b, &sb, &lb);
+
+// below implementations are idential
+#if 0
+ Coords nb;
+ n1.x = +lb.y;
+ n1.y = -lb.x;
+ return fabs(coords_dot (&la,&nb)) < NODE_EPSILON;
+#else
+ return fabs (coords_cross (&la, &lb)) < NODE_EPSILON;
+#endif
+}
+
+/**
+ * check if the two given wires overlap
+ * @param so start overlap
+ * @param eo end overlap
+ */
+static gboolean do_wires_overlap (Wire *a, Wire *b, Coords *so, Coords *eo)
+{
+ g_assert (a);
+ g_assert (IS_WIRE (a));
+ g_assert (b);
+ g_assert (IS_WIRE (b));
+ g_assert (so);
+ g_assert (eo);
+
+ Coords sa, la, ea;
+ Coords sb, lb, eb;
+
+ wire_get_pos_and_length (a, &sa, &la);
+ wire_get_pos_and_length (b, &sb, &lb);
+ ea = coords_sum (&sa, &la);
+ eb = coords_sum (&sb, &lb);
+
+ // parallel check
+ if (!check_colinear (a, b))
+ return FALSE;
+
+ const gboolean sb_on_a = is_point_on_wire (a, &sb);
+ const gboolean eb_on_a = is_point_on_wire (a, &eb);
+ const gboolean sa_on_b = is_point_on_wire (b, &sa);
+ const gboolean ea_on_b = is_point_on_wire (b, &ea);
+
+ // a-----b++++++b---a
+ if (sb_on_a && eb_on_a) {
+ *so = sb;
+ *eo = eb;
+ return TRUE;
+ }
+ if (sa_on_b && ea_on_b) {
+ *so = sa;
+ *eo = ea;
+ return TRUE;
+ }
+
+ // a----b~~~~a++++++b
+ // this also covers "touching" of colinear wires
+ if (sb_on_a && sa_on_b) {
+ *so = sb;
+ *eo = sa;
+ return TRUE;
+ }
+ if (eb_on_a && sa_on_b) {
+ *so = eb;
+ *eo = ea;
+ return TRUE;
+ }
+ if (sb_on_a && ea_on_b) {
+ *so = sb;
+ *eo = ea;
+ return TRUE;
+ }
+ if (eb_on_a && ea_on_b) {
+ *so = eb;
+ *eo = sa;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * check if wires a and b form a t crossing
+ * @param a
+ * @param b
+ * @param t [out][NULL-allowed] which endpoint is the T point (where both wires
+ * "intersect")
+ * @returns which of the inputs
+ * @attention wire @a and @b are taken as granted to be intersecting
+ * @attention L-like crossings are a special form of T-crossings
+ */
+gboolean is_t_crossing (Wire *a, Wire *b, Coords *t)
+{
+ g_assert (a);
+ g_assert (IS_WIRE (a));
+ g_assert (b);
+ g_assert (IS_WIRE (b));
+
+ Coords sa, ea, sb, eb;
+
+ wire_get_start_and_end_pos (a, &sa, &ea);
+ wire_get_start_and_end_pos (b, &sb, &eb);
+
+ if (is_point_on_wire (a, &sb) /* && !is_point_on_wire (a, &sb)*/) {
+ if (t) // a
+ *t = sb; // sbbb
+ return TRUE; // a
+ }
+ if (is_point_on_wire (a, &eb) /* && !is_point_at_end_of_wire (a, &eb)*/) {
+ if (t) // a
+ *t = eb; // bbe
+ return TRUE; // a
+ }
+ if (is_point_on_wire (b, &sa) /* && !is_point_at_end_of_wire (b, &sa)*/) {
+ if (t)
+ *t = sa;
+ return TRUE;
+ }
+ if (is_point_on_wire (b, &ea) /* && !is_point_at_end_of_wire (b, &ea)*/) {
+ if (t)
+ *t = ea;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * merge wire @b into wire @a, where @so and @eo are the overlapping wire part
+ *
+ * @param a wire
+ * @param b wire to merge into @a
+ * @param so [out] coords of the overlapping wire part - start
+ * @param eo [out] coords of the overlapping wire part - end
+ * @returns the pointer to a, or NUL if something went wrong
+ * @attention onlycall this for two parallel and overlapping wires, ever!
+ */
+static Wire *vulcanize_wire (NodeStore *store, Wire *a, Wire *b)
+{
+ g_assert (store);
+ g_assert (IS_NODE_STORE (store));
+ g_assert (a);
+ g_assert (IS_WIRE (a));
+ g_assert (b);
+ g_assert (IS_WIRE (b));
+
+ Coords starta, enda;
+ Coords startb, endb;
+ GSList *list;
+
+ wire_get_start_pos (a, &starta);
+ wire_get_end_pos (a, &enda);
+ wire_get_start_pos (b, &startb);
+ wire_get_end_pos (b, &endb);
+
+ Coords start, end, len;
+ start.x = MIN (MIN (starta.x, startb.x), MIN (enda.x, endb.x));
+ start.y = MIN (MIN (starta.y, startb.y), MIN (enda.y, endb.y));
+ end.x = MAX (MAX (starta.x, startb.x), MAX (enda.x, endb.x));
+ end.y = MAX (MAX (starta.y, startb.y), MAX (enda.y, endb.y));
+ len.x = end.x - start.x;
+ len.y = end.y - start.y;
+
+ g_assert ((fabs (len.x) < NODE_EPSILON) ^ (fabs (len.y) < NODE_EPSILON));
+
+// FIXME register and unregister to new position
+#define CREATE_NEW_WIRE 0
+// always null, or schematic_add_item in create_wire
+// will return pure bogus (and potentially crash!)
+#if CREATE_NEW_WIRE
+ Wire *w = wire_new (item_data_get_grid (ITEM_DATA (a)));
+ g_return_val_if_fail (w, NULL);
+ g_return_val_if_fail (IS_WIRE (w), NULL);
+#else
+ Wire *w = a;
+#endif
+ item_data_set_pos (ITEM_DATA (w), &start);
+ wire_set_length (w, &len);
+
+ for (list = wire_get_nodes (b); list;) {
+ Node *n = list->data;
+ list = list->next; // needs to be done here, as wire_add_node mods the list
+ if (!IS_NODE (n))
+ g_warning ("Found bogus node entry in wire %p, ignored.", b);
+ wire_add_node (w, n);
+ node_add_wire (n, w);
+ }
+ return w;
+}
+
+#endif /* NODE_STORE_PRIVATE_H__ */
diff --git a/src/model/node-store.c b/src/model/node-store.c
index 2342c5c..6b09df5 100644
--- a/src/model/node-store.c
+++ b/src/model/node-store.c
@@ -1,19 +1,27 @@
/*
* node-store.c
*
- * This is where the circuit elements (pins/wires) are stored.
+ *
+ * Store nodes, wires to hashtables.
+ * Generate new wires, merge new wire create requests where possible with
+ *already existing ones
+ *
*
* Authors:
* Richard Hult <rhult@hem.passagen.se>
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2012-2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -27,8 +35,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -36,57 +44,47 @@
#include <gtk/gtk.h>
#include <math.h>
+#define NODE_EPSILON 1e-10
+#define HASH_EPSILON 1e-3
#include "node-store.h"
+#include "node-store-private.h"
#include "node.h"
#include "part.h"
#include "wire.h"
#include "wire-private.h"
-// NODE_EPSILON is used to check for intersection.
-#define NODE_EPSILON 1e-10
-// HASH_EPSILON is used in the hash equality check function.
-#define HASH_EPSILON 1e-3
-// Share an endpoint?
-#define SEP(p1x,p1y,p2x,p2y) (IS_EQ(p1x, p2x) && IS_EQ(p1y, p2y))
-// Equals?
-#define IS_EQ(a,b) (fabs ((a) - (b)) < NODE_EPSILON)
-
-#define ON_THE_WIRE(p1,start,end) (fabs((end.y-start.y)*(p1.x-start.x)-(end.x-start.x)*(p1.y-start.y))<NODE_EPSILON )
-
-#define NG_DEBUG(s) if (0) g_print ("NG: %s\n", s)
-
-static void node_store_class_init (NodeStoreClass *klass);
-static void node_store_init (NodeStore *store);
-static guint node_hash (gconstpointer key);
-static int node_equal (gconstpointer a, gconstpointer b);
-static GSList *wires_intersect (NodeStore *store, double x1, double y1,
- double x2, double y2);
-static GSList *wire_intersect_parts (NodeStore *store, Wire *wire);
-static int is_wire_at_pos (double x1, double y1, double x2, double y2,
- SheetPos pos);
-static GSList *wires_at_pos (NodeStore *store, SheetPos pos);
-static int do_wires_intersect (double Ax, double Ay, double Bx, double By,
- double Cx, double Cy, double Dx, double Dy, SheetPos *pos);
-static void node_store_finalize (GObject *self);
-static void node_store_dispose (GObject *self);
-
-typedef struct {
- Wire *wire;
- SheetPos pos;
-} IntersectionPoint;
-
-enum {
- NODE_DOT_ADDED,
- NODE_DOT_REMOVED,
- LAST_SIGNAL
-};
-
-G_DEFINE_TYPE (NodeStore, node_store, G_TYPE_OBJECT)
-
-static guint node_store_signals [LAST_SIGNAL] = { 0 };
-
-static void
-node_store_finalize (GObject *object)
+#include "debug.h"
+
+/* NODE_EPSILON is used to check for intersection. */
+/* HASH_EPSILON is used in the hash equality check function. */
+
+/* Share an endpoint? */
+#define SEP(p1x, p1y, p2x, p2y) (IS_EQ (p1x, p2x) && IS_EQ (p1y, p2y))
+
+/* Equals? */
+#define IS_EQ(a, b) (fabs ((a) - (b)) < NODE_EPSILON)
+
+#define ON_THE_WIRE(p1, start, end) \
+ (fabs ((end.y - start.y) * (p1.x - start.x) - (end.x - start.x) * (p1.y - start.y)) < \
+ NODE_EPSILON)
+
+static void node_store_class_init (NodeStoreClass *klass);
+static void node_store_init (NodeStore *store);
+static void node_store_finalize (GObject *self);
+static void node_store_dispose (GObject *self);
+
+enum { NODE_DOT_ADDED, NODE_DOT_REMOVED, LAST_SIGNAL };
+
+G_DEFINE_TYPE (NodeStore, node_store, G_TYPE_OBJECT);
+
+static guint node_store_signals[LAST_SIGNAL] = {0};
+
+static void node_store_dispose (GObject *self)
+{
+ G_OBJECT_CLASS (node_store_parent_class)->dispose (self);
+}
+
+static void node_store_finalize (GObject *object)
{
NodeStore *self = NODE_STORE (object);
@@ -107,18 +105,15 @@ node_store_finalize (GObject *object)
g_list_free (self->items);
self->items = NULL;
}
+ if (self->textbox) {
+ g_list_free (self->textbox);
+ self->textbox = NULL;
+ }
G_OBJECT_CLASS (node_store_parent_class)->finalize (object);
}
-static void
-node_store_dispose (GObject *self)
-{
- G_OBJECT_CLASS (node_store_parent_class)->dispose (self);
-}
-
-static void
-node_store_class_init (NodeStoreClass *klass)
+static void node_store_class_init (NodeStoreClass *klass)
{
GObjectClass *gobject_class;
@@ -128,31 +123,18 @@ node_store_class_init (NodeStoreClass *klass)
gobject_class->finalize = node_store_finalize;
gobject_class->dispose = node_store_dispose;
- node_store_signals [NODE_DOT_ADDED] =
- g_signal_new ("node_dot_added",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (NodeStoreClass, node_dot_added),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1, G_TYPE_POINTER);
-
- node_store_signals [NODE_DOT_REMOVED] =
- g_signal_new ("node_dot_removed",
- TYPE_NODE_STORE,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (NodeStoreClass, node_dot_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1, G_TYPE_POINTER);
+ node_store_signals[NODE_DOT_ADDED] =
+ g_signal_new ("node_dot_added", G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NodeStoreClass, node_dot_added), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ node_store_signals[NODE_DOT_REMOVED] =
+ g_signal_new ("node_dot_removed", TYPE_NODE_STORE, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NodeStoreClass, node_dot_removed), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
}
-static void
-node_store_init (NodeStore *self)
+static void node_store_init (NodeStore *self)
{
self->nodes = g_hash_table_new (node_hash, node_equal);
self->wires = NULL;
@@ -161,14 +143,13 @@ node_store_init (NodeStore *self)
self->textbox = NULL;
}
-NodeStore *
-node_store_new (void)
-{
- return NODE_STORE(g_object_new (TYPE_NODE_STORE, NULL));
-}
+////////////////////////////////////////////////////////////////////////////////
+// END BOILERPLATE
+////////////////////////////////////////////////////////////////////////////////
-static void
-node_dot_added_callback (Node *node, SheetPos *pos, NodeStore *store)
+NodeStore *node_store_new (void) { return NODE_STORE (g_object_new (TYPE_NODE_STORE, NULL)); }
+
+static void node_dot_added_callback (Node *node, Coords *pos, NodeStore *store)
{
g_return_if_fail (store != NULL);
g_return_if_fail (IS_NODE_STORE (store));
@@ -176,21 +157,23 @@ node_dot_added_callback (Node *node, SheetPos *pos, NodeStore *store)
g_signal_emit_by_name (G_OBJECT (store), "node_dot_added", pos);
}
-static void
-node_dot_removed_callback (Node *node, SheetPos *pos, NodeStore *store)
+static void node_dot_removed_callback (Node *node, Coords *pos, NodeStore *store)
{
- g_return_if_fail (store != NULL);
+ g_return_if_fail (store);
g_return_if_fail (IS_NODE_STORE (store));
g_signal_emit_by_name (G_OBJECT (store), "node_dot_removed", pos);
}
-Node *
-node_store_get_or_create_node (NodeStore *self, SheetPos pos)
+/**
+ * lookup if a node at @pos exists, if so return it, otherwise
+ * create one, add it to the nodestore and return it
+ */
+Node *node_store_get_or_create_node (NodeStore *self, Coords pos)
{
Node *node;
- g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (self, NULL);
g_return_val_if_fail (IS_NODE_STORE (self), NULL);
node = g_hash_table_lookup (self->nodes, &pos);
@@ -200,65 +183,58 @@ node_store_get_or_create_node (NodeStore *self, SheetPos pos)
node = node_new (pos);
g_signal_connect_object (G_OBJECT (node), "node_dot_added",
- G_CALLBACK (node_dot_added_callback), G_OBJECT (self), 0);
+ G_CALLBACK (node_dot_added_callback), G_OBJECT (self), 0);
g_signal_connect_object (G_OBJECT (node), "node_dot_removed",
- G_CALLBACK (node_dot_removed_callback), G_OBJECT (self), 0);
+ G_CALLBACK (node_dot_removed_callback), G_OBJECT (self), 0);
g_hash_table_insert (self->nodes, &node->key, node);
}
- // If there was a previously stored node here, just
- // return that node.
return node;
}
-int
-node_store_add_part (NodeStore *self, Part *part)
+/**
+ * register a part to the nodestore
+ */
+gboolean node_store_add_part (NodeStore *self, Part *part)
{
- GSList *wire_list, *list;
- Node *node;
- SheetPos lookup_key;
- SheetPos part_pos;
- gdouble x, y;
- int i, num_pins;
-
- g_return_val_if_fail (self != NULL, FALSE);
+ NG_DEBUG ("-0-");
+ g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
- g_return_val_if_fail (part != NULL, FALSE);
+ g_return_val_if_fail (part, FALSE);
g_return_val_if_fail (IS_PART (part), FALSE);
+ GSList *iter, *copy;
+ Node *node;
+ Coords pin_pos;
+ Coords part_pos;
+ int i, num_pins;
+ Pin *pins;
+
num_pins = part_get_num_pins (part);
+ pins = part_get_pins (part);
item_data_get_pos (ITEM_DATA (part), &part_pos);
for (i = 0; i < num_pins; i++) {
- Pin *pins;
-
- pins = part_get_pins (part);
- x = part_pos.x + pins[i].offset.x;
- y = part_pos.y + pins[i].offset.y;
-
- //Use the position of the pin as hash key.
- lookup_key.x = x;
- lookup_key.y = y;
+ // Use the position of the pin as hash key.
+ pin_pos.x = part_pos.x + pins[i].offset.x;
+ pin_pos.y = part_pos.y + pins[i].offset.y;
// Retrieve a node for this position.
- node = node_store_get_or_create_node (self, lookup_key);
+ node = node_store_get_or_create_node (self, pin_pos);
// Add all the wires that intersect this pin to the node store.
- wire_list = wires_at_pos (self, lookup_key);
-
- for (list = wire_list; list; list = list->next) {
- Wire *wire = list->data;
-
- NG_DEBUG ("Add pin to wire.\n");
+ copy = get_wires_at_pos (self, pin_pos);
+ for (iter = copy; iter; iter = iter->next) {
+ Wire *wire = copy->data;
node_add_wire (node, wire);
wire_add_node (wire, node);
}
- g_slist_free (wire_list);
+ g_slist_free (copy);
node_add_pin (node, &pins[i]);
}
@@ -270,51 +246,48 @@ node_store_add_part (NodeStore *self, Part *part)
return TRUE;
}
-int
-node_store_remove_part (NodeStore *self, Part *part)
+/**
+ * remove/unregister a part from the nodestore
+ * this does _not_ free the part!
+ */
+gboolean node_store_remove_part (NodeStore *self, Part *part)
{
Node *node;
- SheetPos lookup_key;
- SheetPos pos;
- gdouble x, y;
+ Coords pin_pos;
+ Coords part_pos;
int i, num_pins;
Pin *pins;
- g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (IS_NODE_STORE (self), FALSE);
- g_return_val_if_fail (part != NULL, FALSE);
+ g_return_val_if_fail (part, FALSE);
g_return_val_if_fail (IS_PART (part), FALSE);
self->parts = g_list_remove (self->parts, part);
self->items = g_list_remove (self->items, part);
num_pins = part_get_num_pins (part);
- item_data_get_pos (ITEM_DATA (part), &pos);
+ item_data_get_pos (ITEM_DATA (part), &part_pos);
pins = part_get_pins (part);
for (i = 0; i < num_pins; i++) {
- x = pos.x + pins[i].offset.x;
- y = pos.y + pins[i].offset.y;
-
- // Use the position of the pin as lookup key.
- lookup_key.x = x;
- lookup_key.y = y;
+ pin_pos.x = part_pos.x + pins[i].offset.x;
+ pin_pos.y = part_pos.y + pins[i].offset.y;
- node = g_hash_table_lookup (self->nodes, &lookup_key);
+ node = g_hash_table_lookup (self->nodes, &pin_pos);
if (node) {
if (!node_remove_pin (node, &pins[i])) {
- g_warning ("Couldn't remove pin.");
+ g_warning ("Could not remove pin[%i] from node %p.", i, node);
return FALSE;
}
// If the node is empty after removing the pin,
// remove the node as well.
if (node_is_empty (node)) {
- g_hash_table_remove (self->nodes, &lookup_key);
+ g_hash_table_remove (self->nodes, &pin_pos);
g_object_unref (G_OBJECT (node));
}
- }
- else {
+ } else {
return FALSE;
}
}
@@ -322,8 +295,7 @@ node_store_remove_part (NodeStore *self, Part *part)
return TRUE;
}
-int
-node_store_add_textbox (NodeStore *self, Textbox *text)
+gboolean node_store_add_textbox (NodeStore *self, Textbox *text)
{
g_object_set (G_OBJECT (text), "store", self, NULL);
self->textbox = g_list_prepend (self->textbox, text);
@@ -331,178 +303,202 @@ node_store_add_textbox (NodeStore *self, Textbox *text)
return TRUE;
}
-int
-node_store_remove_textbox (NodeStore *self, Textbox *text)
+gboolean node_store_remove_textbox (NodeStore *self, Textbox *text)
{
self->textbox = g_list_remove (self->textbox, text);
return TRUE;
}
-int
-node_store_add_wire (NodeStore *store, Wire *wire)
+/**
+ * Remove all wires in the nodestore that overlap with a given
+ * wire (preserve the longest of the two overlapping wires).
+ * This is basically an optimization of the nodestore.
+ */
+void node_store_remove_overlapping_wires (NodeStore *store, Wire *wire)
{
- gdouble x1, y1, x2, y2;
- GSList *ip_list, *list;
- IntersectionPoint *ipoint;
+ gdouble a, b;
+ Coords start_pos, end_pos, start_pos_other, end_pos_other;
+ Coords length, length_other;
+ Coords so, eo;
+ GList *list, *to_be_removed = NULL;
+ Node *sn, *en;
+ Wire *other;
+ gboolean overlap;
+
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (IS_NODE_STORE (store));
+ g_return_if_fail (wire != NULL);
+ g_return_if_fail (IS_WIRE (wire));
+
+ // Check for overlapping with other wires.
+ for (list = store->wires; list && list->data != wire; list = list->next) {
+ g_assert (list->data != NULL);
+ g_assert (IS_WIRE (list->data));
+ other = list->data;
+ overlap = do_wires_overlap (wire, other, &so, &eo);
+ NG_DEBUG ("overlap [ %p] and [ %p ] -- %s", wire, other,
+ overlap == TRUE ? "YES" : "NO");
+ if (overlap) {
+ sn = node_store_get_node (store, eo);
+ en = node_store_get_node (store, so);
+ if (!sn && !en)
+ wire = vulcanize_wire (store, wire, other);
+ wire_get_pos_and_length (wire, &start_pos, &length);
+ wire_get_pos_and_length (other, &start_pos_other, &length_other);
+ wire_get_start_and_end_pos (wire, &start_pos, &end_pos);
+ wire_get_start_and_end_pos (other, &start_pos_other, &end_pos_other);
+ if (length.x < 0) {
+ a = start_pos.x;
+ b = end_pos.x;
+ start_pos.x = b;
+ end_pos.x = a;
+ length.x = -length.x;
+ }
+ if (length.y < 0) {
+ a = start_pos.y;
+ b = end_pos.y;
+ start_pos.y = b;
+ end_pos.y = a;
+ length.y = -length.y;
+ }
+ if (length_other.x < 0) {
+ a = start_pos_other.x;
+ b = end_pos_other.x;
+ start_pos_other.x = b;
+ end_pos_other.x = a;
+ length_other.x = -length_other.x;
+ }
+ if (length_other.y < 0) {
+ a = start_pos_other.y;
+ b = end_pos_other.y;
+ start_pos_other.y = b;
+ end_pos_other.y = a;
+ length_other.y = -length_other.y;
+ }
+ if (length.x > 0 && length_other.x > 0 && length.y == 0 && length_other.y == 0) {
+ if (start_pos.x >= start_pos_other.x && end_pos.x <= end_pos_other.x)
+ to_be_removed = g_list_append (to_be_removed, wire);
+ if (start_pos_other.x >= start_pos.x && end_pos_other.x <= end_pos.x)
+ to_be_removed = g_list_append (to_be_removed, other);
+ } else if (length.y > 0 && length_other.y > 0 && length.x == 0 && length_other.x == 0) {
+ if (start_pos.y >= start_pos_other.y && end_pos.y <= end_pos_other.y)
+ to_be_removed = g_list_append (to_be_removed, wire);
+ if (start_pos_other.y >= start_pos.y && end_pos_other.y <= end_pos.y)
+ to_be_removed = g_list_append (to_be_removed, other);
+ }
+ }
+ }
+
+ // Remove all the wires that overlap with a given wire
+ for (list = to_be_removed; list; list = list->next) {
+ if (node_store_remove_wire (store, list->data))
+ wire_delete (list->data);
+ }
+ g_list_free (to_be_removed);
+}
+
+/**
+ * add/register the wire to the nodestore
+ *
+ * @param store
+ * @param wire
+ * @returns TRUE if the wire was added or merged, else FALSE
+ */
+gboolean node_store_add_wire (NodeStore *store, Wire *wire)
+{
+ GList *list;
Node *node;
- SheetPos pos, length;
+ Coords where;
+ int i = 0;
- g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (store, FALSE);
g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
- g_return_val_if_fail (wire != NULL, FALSE);
+ g_return_val_if_fail (wire, FALSE);
g_return_val_if_fail (IS_WIRE (wire), FALSE);
- wire_get_pos_and_length (wire, &pos, &length);
-
- x1 = pos.x;
- y1 = pos.y;
- x2 = x1 + length.x;
- y2 = y1 + length.y;
-
// Check for intersection with other wires.
- ip_list = wires_intersect (store, x1, y1, x2, y2);
-
- for (list = ip_list; list; list = list->next) {
- ipoint = list->data;
-
- if (IS_EQ (x1, x2) && ((ipoint->pos.y == y1) || (ipoint->pos.y == y2))) {
- SheetPos w_pos, w_length;
- gboolean can_join;
- GSList *nodes;
-
- wire_get_pos_and_length (ipoint->wire, &w_pos, &w_length);
- gdouble _x1, _x2, _y1, _y2;
-
- _x1 = w_pos.x;
- _y1 = w_pos.y;
- _x2 = _x1 + w_length.x;
- _y2 = _y1 + w_length.y;
-
- can_join = TRUE;
- nodes = wire_get_nodes (wire);
- for (; nodes; nodes = nodes->next) {
- SheetPos p1;
- Node *node = (Node *)nodes->data;
-
- p1.x = _x1;
- p1.y = _y1;
- if ((fabs (node->key.x - p1.x) < 1e-3) &&
- (fabs (node->key.y - p1.y) < 1e-3)){
- can_join = FALSE;
- break;
- }
- p1.x = _x2;
- p1.y = _y2;
- if ((fabs (node->key.x - p1.x) < 1e-3) &&
- (fabs (node->key.y - p1.y) < 1e-3)){
- can_join = FALSE;
- break;
- }
- }
-
- if (IS_EQ(_x1, _x2) && can_join) {
- if (w_pos.x < pos.x) pos.x = w_pos.x;
- if (w_pos.y < pos.y) pos.y = w_pos.y;
- length.x += w_length.x;
- length.y += w_length.y;
-
- // Update the new size and pos of the wire
- item_data_unregister (ITEM_DATA (ipoint->wire));
- wire_set_length (ipoint->wire, &length);
- item_data_set_pos (ITEM_DATA (ipoint->wire), &pos);
- wire_update_bbox (ipoint->wire);
- item_data_register (ITEM_DATA (ipoint->wire));
-
- // Done!, return -1 so wire is deleted
- return -1;
- }
- }
- else if (IS_EQ (y1, y2) &&
- ((ipoint->pos.x == x1) ||
- (ipoint->pos.x == x2))) {
- SheetPos w_pos, w_length;
- gboolean can_join;
- GSList *nodes;
-
- wire_get_pos_and_length (ipoint->wire, &w_pos, &w_length);
- gdouble _x1, _x2, _y1, _y2;
-
- _x1 = w_pos.x;
- _y1 = w_pos.y;
- _x2 = _x1 + w_length.x;
- _y2 = _y1 + w_length.y;
-
- can_join = TRUE;
- nodes = wire_get_nodes (wire);
- for (; nodes; nodes = nodes->next) {
- SheetPos p;
- Node *node = (Node *)nodes->data;
-
- p.x = _x1;
- p.y = _y1;
- if ((fabs (node->key.x - p.x) < 1e-3) &&
- (fabs (node->key.y - p.y) < 1e-3)){
- can_join = FALSE;
- break;
- }
- p.x = _x2;
- p.y = _y2;
- if ((fabs (node->key.x - p.x) < 1e-3) &&
- (fabs (node->key.y - p.y) < 1e-3)){
- can_join = FALSE;
- break;
+ for (list = store->wires; list; list = list->next) {
+ g_assert (list->data != NULL);
+ g_assert (IS_WIRE (list->data));
+
+ Wire *other = list->data;
+ if (do_wires_intersect (wire, other, &where)) {
+ if (is_t_crossing (wire, other, &where) || is_t_crossing (other, wire, &where)) {
+
+ node = node_store_get_or_create_node (store, where);
+
+ node_add_wire (node, wire);
+ node_add_wire (node, other);
+
+ wire_add_node (wire, node);
+ wire_add_node (other, node);
+
+ NG_DEBUG ("Add wire %p to wire %p @ %lf,%lf.\n", wire, other, where.x, where.y);
+ } else {
+ // magic node removal if a x crossing is overlapped with another wire
+ node = node_store_get_node (store, where);
+ NG_DEBUG ("Nuke that node [ %p ] at coords inbetween", node);
+ if (node) {
+ Coords c[4];
+ wire_get_start_and_end_pos (other, c + 0, c + 1);
+ wire_get_start_and_end_pos (wire, c + 2, c + 3);
+ if (!coords_equal (&where, c + 0) && !coords_equal (&where, c + 1) &&
+ !coords_equal (&where, c + 2) && !coords_equal (&where, c + 3)) {
+
+ wire_remove_node (wire, node);
+ wire_remove_node (other, node);
+ node_remove_wire (node, wire);
+ node_remove_wire (node, other);
+ }
}
}
-
- if (IS_EQ(_y1, _y2) && can_join) {
- if (w_pos.x < pos.x) pos.x = w_pos.x;
- if (w_pos.y < pos.y) pos.y = w_pos.y;
- length.x += w_length.x;
- length.y += w_length.y;
-
- // Update the new size and pos of the wire
- item_data_unregister (ITEM_DATA (ipoint->wire));
- wire_set_length (ipoint->wire, &length);
- item_data_set_pos (ITEM_DATA (ipoint->wire), &pos);
- wire_update_bbox (ipoint->wire);
- item_data_register (ITEM_DATA (ipoint->wire));
-
- // Done!, return -1 so wire si deleted
- return -1;
- }
}
+ }
- node = node_store_get_or_create_node (store, ipoint->pos);
-
- // Add the wire, and also the wire that is intersected.
- node_add_wire (node, wire);
- node_add_wire (node, ipoint->wire);
+ node_store_remove_overlapping_wires (store, wire);
- wire_add_node (wire, node);
- wire_add_node (ipoint->wire, node);
+ // Check for intersection with parts (pins).
+ for (list = store->parts; list; list = list->next) {
+ g_assert (list->data != NULL);
+ g_assert (IS_PART (list->data));
- NG_DEBUG ("Add wire to wire.\n");
+ Coords part_pos;
+ gint num_pins = -1;
+ Part *part = list->data;
- g_free (ipoint);
- }
- g_slist_free (ip_list);
+ num_pins = part_get_num_pins (part);
+ item_data_get_pos (ITEM_DATA (part), &part_pos);
- // Check for intersection with parts (pins).
- ip_list = wire_intersect_parts (store, wire);
+ // Go through all the parts and see which of their
+ // pins that intersect the wire.
+ for (i = 0; i < num_pins; i++) {
+ Pin *pins;
+ Coords lookup_pos;
- for (list = ip_list; list; list = list->next) {
- node = list->data;
+ pins = part_get_pins (part);
+ lookup_pos.x = part_pos.x + pins[i].offset.x;
+ lookup_pos.y = part_pos.y + pins[i].offset.y;
- // Add the wire to the node (pin) that it intersected.
- node_add_wire (node, wire);
- wire_add_node (wire, node);
+ // If there is a wire at this pin's position,
+ // add it to the return list.
+ if (is_point_on_wire (wire, &lookup_pos)) {
+ Node *node;
+ node = node_store_get_node (store, lookup_pos);
- NG_DEBUG ("Add wire to pin.\n");
+ if (node != NULL) {
+ // Add the wire to the node (pin) that it intersected.
+ node_add_wire (node, wire);
+ wire_add_node (wire, node);
+ NG_DEBUG ("Add wire %p to pin (node) %p.\n", wire, node);
+ } else {
+ g_warning ("Bug: Found no node at pin at (%g %g).\n", lookup_pos.x,
+ lookup_pos.y);
+ }
+ }
+ }
}
- g_slist_free (ip_list);
-
g_object_set (G_OBJECT (wire), "store", store, NULL);
store->wires = g_list_prepend (store->wires, wire);
store->items = g_list_prepend (store->items, wire);
@@ -510,214 +506,81 @@ node_store_add_wire (NodeStore *store, Wire *wire)
return TRUE;
}
-int
-node_store_remove_wire (NodeStore *store, Wire *wire)
+/**
+ * removes/unregisters a wire from the nodestore
+ * this does _not_ free the wire itself!
+ */
+gboolean node_store_remove_wire (NodeStore *store, Wire *wire)
{
- GSList *list;
- SheetPos lookup_key, pos, length;
+ GSList *copy, *iter;
+ Coords lookup_key;
- g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (store, FALSE);
g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
- g_return_val_if_fail (wire != NULL, FALSE);
+ g_return_val_if_fail (wire, FALSE);
g_return_val_if_fail (IS_WIRE (wire), FALSE);
if (item_data_get_store (ITEM_DATA (wire)) == NULL) {
- g_warning ("Trying to remove non-stored wire.");
+ g_warning ("Trying to remove not-stored wire %p.", wire);
return FALSE;
}
- wire_get_pos_and_length (wire, &pos, &length);
-
store->wires = g_list_remove (store->wires, wire);
store->items = g_list_remove (store->items, wire);
// If the nodes that this wire passes through will be
// empty when the wire is removed, remove the node as well.
- // We must work on a copy of the nodes list, since it
- // changes as we remove nodes.
- list = g_slist_copy (wire_get_nodes (wire));
-
- for (; list; list = list->next) {
- Node *node = list->data;
+ // FIXME if done properly, a list copy is _not_ necessary
+ copy = g_slist_copy (wire_get_nodes (wire));
+ for (iter = copy; iter; iter = iter->next) {
+ Node *node = iter->data;
lookup_key = node->key;
node_remove_wire (node, wire);
-
wire_remove_node (wire, node);
if (node_is_empty (node))
g_hash_table_remove (store->nodes, &lookup_key);
}
- g_slist_free (list);
+ g_slist_free (copy);
return TRUE;
}
-static GSList *
-wire_intersect_parts (NodeStore *store, Wire *wire)
-{
- GList *list;
- GSList *ip_list;
- Node *node;
- SheetPos lookup_pos;
- SheetPos part_pos, wire_pos, wire_length;
- Part *part;
- double x, y, wire_x1, wire_y1, wire_x2, wire_y2;
- int i, num_pins;
-
- g_return_val_if_fail (store != NULL, FALSE);
- g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
- g_return_val_if_fail (wire != NULL, FALSE);
- g_return_val_if_fail (IS_WIRE (wire), FALSE);
-
- ip_list = NULL;
-
- wire_get_pos_and_length (wire, &wire_pos, &wire_length);
-
- wire_x1 = wire_pos.x;
- wire_x2 = wire_pos.x + wire_length.x;
- wire_y1 = wire_pos.y;
- wire_y2 = wire_pos.y + wire_length.y;
-
- // Go through all the parts and see which of their
- // pins that intersect the wire.
- for (list = store->parts; list; list = list->next) {
- part = list->data;
-
- num_pins = part_get_num_pins (part);
- item_data_get_pos (ITEM_DATA (part), &part_pos);
-
- for (i = 0; i < num_pins; i++) {
- Pin *pins;
-
- pins = part_get_pins (part);
- x = part_pos.x + pins[i].offset.x;
- y = part_pos.y + pins[i].offset.y;
-
- lookup_pos.x = x;
- lookup_pos.y = y;
-
- // If there is a wire at this pin's position,
- // add it to the return list.
- if (is_wire_at_pos (wire_x1, wire_y1, wire_x2, wire_y2, lookup_pos)) {
- node = node_store_get_node (store, lookup_pos);
-
- if (node != NULL)
- ip_list = g_slist_prepend (ip_list, node);
- }
- }
- }
- g_list_free_full (list, g_object_unref);
-
- return ip_list;
-}
-
-static GSList *
-wires_at_pos (NodeStore *store, SheetPos pos)
-{
- GList *list;
- GSList *wire_list;
- Wire *wire;
- SheetPos wire_pos, wire_length;
- double x1, y1, x2, y2;
-
- g_return_val_if_fail (store != NULL, FALSE);
- g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
-
- wire_list = NULL;
-
- for (list = store->wires; list; list = list->next) {
- wire = list->data;
-
- wire_get_pos_and_length (wire, &wire_pos, &wire_length);
- x1 = wire_pos.x;
- y1 = wire_pos.y;
- x2 = x1 + wire_length.x;
- y2 = y1 + wire_length.y;
-
- if (is_wire_at_pos (x1, y1, x2, y2, pos))
- wire_list = g_slist_prepend (wire_list, wire);
- }
- g_list_free_full (list, g_object_unref);
-
- return wire_list;
-}
-
-int
-node_store_is_wire_at_pos (NodeStore *store, SheetPos pos)
+/**
+ * check if there is at least one wire at the specified position
+ *
+ * @param store which NodeStore to check
+ * @param pos the position
+ * @returns TRUE or FALSE
+ */
+gboolean node_store_is_wire_at_pos (NodeStore *store, Coords pos)
{
- GList *list;
- Wire *wire;
- SheetPos wire_pos, wire_length;
- double x1, y1, x2, y2;
+ GList *iter;
- g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (store, FALSE);
g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
- for (list = store->wires; list; list = list->next) {
- wire = list->data;
+ for (iter = store->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
- wire_get_pos_and_length (wire, &wire_pos, &wire_length);
- x1 = wire_pos.x;
- y1 = wire_pos.y;
- x2 = x1 + wire_length.x;
- y2 = y1 + wire_length.y;
-
- if (is_wire_at_pos (x1, y1, x2, y2, pos))
+ if (is_point_on_wire (wire, &pos))
return TRUE;
}
- g_list_free_full (list, g_object_unref);
-
return FALSE;
}
-static GSList *
-wires_intersect (NodeStore *store, double x1, double y1, double x2, double y2)
-{
- GList *list;
- GSList *ip_list;
- Wire *wire;
- SheetPos pos, wire_pos, wire_length;
- double wire_x1, wire_y1, wire_x2, wire_y2;
-
- g_return_val_if_fail (store != NULL, FALSE);
- g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
-
- // Search through all the wires. Is there a better way?
- ip_list = NULL;
- for (list = store->wires; list; list = list->next) {
- wire = list->data;
-
- wire_get_pos_and_length (wire, &wire_pos, &wire_length);
- wire_x1 = wire_pos.x;
- wire_y1 = wire_pos.y;
- wire_x2 = wire_x1 + wire_length.x;
- wire_y2 = wire_y1 + wire_length.y;
-
- if (do_wires_intersect (x1, y1, x2, y2, wire_x1, wire_y1,
- wire_x2, wire_y2, &pos)) {
- IntersectionPoint *ip;
-
- ip = g_new0 (IntersectionPoint, 1);
-
- ip->wire = wire;
- ip->pos = pos;
- ip_list = g_slist_prepend (ip_list, ip);
- }
- }
- g_list_free_full (list, g_object_unref);
-
- return ip_list;
-}
-
-// node_store_get_node
-
-// Find the node that has an element at a certain position.
-Node *
-node_store_get_node (NodeStore *store, SheetPos pos)
+/**
+ * lookup node at specified position
+ *
+ * @param store which store to check
+ * @param pos where to check in that store
+ * @returns the node pointer if there is a node, else NULL
+ */
+Node *node_store_get_node (NodeStore *store, Coords pos)
{
Node *node;
@@ -727,53 +590,17 @@ node_store_get_node (NodeStore *store, SheetPos pos)
node = g_hash_table_lookup (store->nodes, &pos);
if (!node) {
- NG_DEBUG (g_strdup_printf ("No node at (%g, %g)\n", pos.x, pos.y));}
- else {
- NG_DEBUG (g_strdup_printf ("Found node at (%g, %g)\n", pos.x, pos.y));}
- return node;
-}
-
-static guint
-node_hash (gconstpointer key)
-{
- SheetPos *sp = (SheetPos *) key;
- int x, y;
-
- // Hash on any other node?
-
- x = (int)rint (sp->x) % 256;
- y = (int)rint (sp->y) % 256;
-
- return (y << 8) | x;
-}
-
-static int
-node_equal (gconstpointer a, gconstpointer b)
-{
- SheetPos *spa, *spb;
-
- spa = (SheetPos *) a;
- spb = (SheetPos *) b;
-
- if (fabs (spa->y - spb->y) > HASH_EPSILON) {
- if (fabs (spa->y - spb->y) < 2.0)
- NG_DEBUG ("A neighbour of B in Y\n");
-
- return 0;
+ NG_DEBUG ("No node at (%g, %g)", pos.x, pos.y);
+ } else {
+ NG_DEBUG ("Found node at (%g, %g)", pos.x, pos.y);
}
-
- if (fabs (spa->x - spb->x) > HASH_EPSILON) {
- if (fabs (spa->x - spb->x) < 5.0)
- NG_DEBUG ("A neighbour of B in X\n\n");
-
- return 0;
- }
-
- return 1;
+ return node;
}
-void
-node_store_node_foreach (NodeStore *store, GHFunc *func, gpointer user_data)
+/**
+ * Call GHFunc for each node in the nodestore
+ */
+void node_store_node_foreach (NodeStore *store, GHFunc *func, gpointer user_data)
{
g_return_if_fail (store != NULL);
g_return_if_fail (IS_NODE_STORE (store));
@@ -781,106 +608,10 @@ node_store_node_foreach (NodeStore *store, GHFunc *func, gpointer user_data)
g_hash_table_foreach (store->nodes, (gpointer)func, user_data);
}
-static int
-is_wire_at_pos (double x1, double y1, double x2, double y2, SheetPos pos)
-{
- double k, x0, y0;
-
- x0 = pos.x;
- y0 = pos.y;
-
- if (!IS_EQ (x1, x2) && !IS_EQ (y1, y2)) {
- k = ((y2 - y1)) / ((x2 - x1));
- if (IS_EQ (y0, (y1 + k * (x0 - x1)))) {
- return TRUE;
- }
- }
- else if (IS_EQ (x2, x1) && IS_EQ (x1, x0)) {
- if (y0 >= y1 && y0 <= y2) {
- return TRUE;
- }
- }
- else if (IS_EQ (y2, y1) && IS_EQ (y1, y0)) {
- if (x0 >= x1 && x0 <= x2) {
- return TRUE;
- }
- }
-
- NG_DEBUG (g_strdup_printf ("no match: (%g %g) -> (%g %g), (%g %g)\n", x1, y1, x2, y2, pos.x, pos.y));
-
- return FALSE;
-}
-
-// Decides if two wires intersect. Note that wires that share an
-// endpoint are considered intersecting each other. Intersection point
-// is returned in pos.
-static int
-do_wires_intersect (double Ax, double Ay, double Bx, double By, double Cx,
- double Cy, double Dx, double Dy, SheetPos *pos)
-{
- double r, s, d;
-
- // Wires don't intersect if they share an endpoint. NOTE: they do here...
- if (SEP (Ax, Ay, Cx, Cy)) { // same starting point
- pos->x = Ax;
- pos->y = Ay;
- return TRUE;
- }
- else if (SEP (Ax, Ay, Dx, Dy)) { // 1st start == 2nd end
- pos->x = Ax;
- pos->y = Ay;
- return TRUE;
- }
- else if (SEP (Bx, By, Cx, Cy)) { // 1st end == 2nd start
- pos->x = Bx;
- pos->y = By;
- return TRUE;
- }
- else if (SEP (Bx, By, Dx, Dy)) { // 1st end == 2nd end
- pos->x = Bx;
- pos->y = By;
- return TRUE;
- }
-
- // Calculate the denominator.
- d = ((Bx - Ax) * (Dy - Cy) - (By - Ay) * (Dx - Cx));
-
- // We have two parallell wires if d = 0.
- if (fabs (d) < NODE_EPSILON) {
- return FALSE;
- }
-
- r = ((Ay - Cy) * (Dx - Cx) - (Ax - Cx) * (Dy - Cy));
- r = r / d;
- s = ((Ay - Cy) * (Bx - Ax) - (Ax - Cx) * (By - Ay)) / d;
-
- // Check for intersection, which we have for values of
- // r and s in [0, 1].
- if (r >= 0 &&
- (r - 1.0) < NODE_EPSILON &&
- s >= 0 &&
- (s - 1.0) < NODE_EPSILON) {
-
- // Calculate the intersection point.
- pos->x = Ax + r * (Bx - Ax);
- pos->y = Ay + r * (By - Ay);
-
- // to be accepted only if it coincides with the start or end
- // of any of the wires
- if ( SEP (pos->x,pos->y,Ax,Ay) ||
- SEP (pos->x,pos->y,Bx,By) ||
- SEP (pos->x,pos->y,Cx,Cy) ||
- SEP (pos->x,pos->y,Dx,Dy) )
- return TRUE;
- else
- return FALSE;
- }
-
- return FALSE;
-}
-
-GList *
-node_store_get_parts (NodeStore *store)
+/**
+ * [transfer-none]
+ */
+GList *node_store_get_parts (NodeStore *store)
{
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (IS_NODE_STORE (store), NULL);
@@ -888,8 +619,10 @@ node_store_get_parts (NodeStore *store)
return store->parts;
}
-GList *
-node_store_get_wires (NodeStore *store)
+/**
+ * [transfer-none]
+ */
+GList *node_store_get_wires (NodeStore *store)
{
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (IS_NODE_STORE (store), NULL);
@@ -897,8 +630,10 @@ node_store_get_wires (NodeStore *store)
return store->wires;
}
-GList *
-node_store_get_items (NodeStore *store)
+/**
+ * [transfer-none]
+ */
+GList *node_store_get_items (NodeStore *store)
{
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (IS_NODE_STORE (store), NULL);
@@ -906,21 +641,10 @@ node_store_get_items (NodeStore *store)
return store->items;
}
-static void
-add_node (gpointer key, Node *node, GList **list)
-{
- *list = g_list_prepend (*list, node);
-}
-
-static void
-add_node_position (gpointer key, Node *node, GList **list)
-{
- if (node_needs_dot (node))
- *list = g_list_prepend (*list, key);
-}
-
-GList *
-node_store_get_node_positions (NodeStore *store)
+/**
+ * the caller has to free the list himself, but not the actual data items!
+ */
+GList *node_store_get_node_positions (NodeStore *store)
{
GList *result;
@@ -928,13 +652,15 @@ node_store_get_node_positions (NodeStore *store)
g_return_val_if_fail (IS_NODE_STORE (store), NULL);
result = NULL;
- g_hash_table_foreach (store->nodes, (GHFunc) add_node_position, &result);
+ g_hash_table_foreach (store->nodes, (GHFunc)add_node_position, &result);
return result;
}
-GList *
-node_store_get_nodes (NodeStore *store)
+/**
+ * the caller has to free the list himself, but not the actual data items!
+ */
+GList *node_store_get_nodes (NodeStore *store)
{
GList *result;
@@ -942,16 +668,15 @@ node_store_get_nodes (NodeStore *store)
g_return_val_if_fail (IS_NODE_STORE (store), NULL);
result = NULL;
- g_hash_table_foreach (store->nodes, (GHFunc) add_node, &result);
+ g_hash_table_foreach (store->nodes, (GHFunc)add_node, &result);
return result;
}
-void
-node_store_get_bounds (NodeStore *store, NodeRect *rect)
+void node_store_get_bounds (NodeStore *store, NodeRect *rect)
{
GList *list;
- SheetPos p1, p2;
+ Coords p1, p2;
g_return_if_fail (store != NULL);
g_return_if_fail (IS_NODE_STORE (store));
@@ -970,14 +695,12 @@ node_store_get_bounds (NodeStore *store, NodeRect *rect)
rect->x1 = MAX (rect->x1, p2.x);
rect->y1 = MAX (rect->y1, p2.y);
}
- g_list_free_full (list, g_object_unref);
}
-gint
-node_store_count_items (NodeStore *store, NodeRect *rect)
+gint node_store_count_items (NodeStore *store, NodeRect *rect)
{
GList *list;
- SheetPos p1, p2;
+ Coords p1, p2;
ItemData *data;
gint n;
@@ -990,23 +713,20 @@ node_store_count_items (NodeStore *store, NodeRect *rect)
for (list = store->items, n = 0; list; list = list->next) {
data = ITEM_DATA (list->data);
item_data_get_absolute_bbox (data, &p1, &p2);
- if (p1.x <= rect->x1 && p1.y <= rect->y1 &&
- p2.x >= rect->x0 && p2.y >= rect->y0) {
+ if (p1.x <= rect->x1 && p1.y <= rect->y1 && p2.x >= rect->x0 && p2.y >= rect->y0) {
n++;
}
}
- g_list_free_full (list, g_object_unref);
return n;
}
-static void
-draw_dot (SheetPos *key, Node *value, cairo_t *cr)
+static void draw_dot (Coords *pos, Node *value, cairo_t *cr)
{
if (node_needs_dot (value)) {
cairo_save (cr);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_translate (cr, key->x, key->y);
+ cairo_translate (cr, pos->x, pos->y);
cairo_scale (cr, 1.0, 1.0);
cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI);
cairo_fill (cr);
@@ -1014,8 +734,7 @@ draw_dot (SheetPos *key, Node *value, cairo_t *cr)
}
}
-void
-node_store_print_items (NodeStore *store, cairo_t *cr, SchematicPrintContext *ctx)
+void node_store_print_items (NodeStore *store, cairo_t *cr, SchematicPrintContext *ctx)
{
GList *list;
ItemData *data;
@@ -1028,16 +747,14 @@ node_store_print_items (NodeStore *store, cairo_t *cr, SchematicPrintContext *ct
data = ITEM_DATA (list->data);
item_data_print (data, cr, ctx);
}
- g_list_free_full (list, g_object_unref);
g_hash_table_foreach (store->nodes, (GHFunc)draw_dot, cr);
}
-int
-node_store_is_pin_at_pos (NodeStore *store, SheetPos pos)
+gboolean node_store_is_pin_at_pos (NodeStore *store, Coords pos)
{
int num_pins;
- SheetPos part_pos;
+ Coords part_pos;
GList *p;
Part *part;
Pin *pins;
@@ -1056,11 +773,9 @@ node_store_is_pin_at_pos (NodeStore *store, SheetPos pos)
x = part_pos.x + pins[i].offset.x;
y = part_pos.y + pins[i].offset.y;
- if ((x == pos.x) && (y == pos.y)) {
- return 1;
- }
+ if (fabs (x - pos.x) < NODE_EPSILON && fabs (y - pos.y) < NODE_EPSILON)
+ return TRUE;
}
}
- g_list_free_full (p, g_object_unref);
- return 0;
+ return FALSE;
}
diff --git a/src/model/node-store.h b/src/model/node-store.h
index 3e42630..9d6aba5 100644
--- a/src/model/node-store.h
+++ b/src/model/node-store.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NODE_STORE_H
#define __NODE_STORE_H
@@ -35,14 +37,14 @@
#include <glib.h>
#include <glib-object.h>
-#include "sheet-pos.h"
-
-#define TYPE_NODE_STORE node_store_get_type ()
-#define NODE_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE_STORE, NodeStore))
-#define NODE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE_STORE, NodeStoreClass))
-#define IS_NODE_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE_STORE))
-#define NODE_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NODE_STORE, NodeStoreClass))
+#include "coords.h"
+#define TYPE_NODE_STORE node_store_get_type ()
+#define NODE_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE_STORE, NodeStore))
+#define NODE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE_STORE, NodeStoreClass))
+#define IS_NODE_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE_STORE))
+#define NODE_STORE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NODE_STORE, NodeStoreClass))
typedef struct _NodeStore NodeStore;
typedef struct _NodeStoreClass NodeStoreClass;
@@ -54,7 +56,8 @@ typedef struct _NodeRect NodeRect;
#include "part.h"
#include "textbox.h"
-struct _NodeStore {
+struct _NodeStore
+{
GObject parent;
GHashTable *nodes;
@@ -70,8 +73,8 @@ struct _NodeStoreClass
// signals
- void (*node_dot_added) (NodeStore*);
- void (*node_dot_removed) (NodeStore*);
+ void (*node_dot_added)(NodeStore *);
+ void (*node_dot_removed)(NodeStore *);
};
struct _NodeRect
@@ -79,29 +82,28 @@ struct _NodeRect
double x0, y0, x1, y1;
};
-GType node_store_get_type (void);
-NodeStore *node_store_new (void);
-Node *node_store_get_node (NodeStore *store, SheetPos pos);
-int node_store_add_part (NodeStore *store, Part *part);
-int node_store_remove_part (NodeStore *store, Part *part);
-int node_store_add_wire (NodeStore *store, Wire *wire);
-int node_store_remove_wire (NodeStore *store, Wire *wire);
-int node_store_add_textbox (NodeStore *self, Textbox *text);
-int node_store_remove_textbox (NodeStore *self, Textbox *text);
-void node_store_node_foreach (NodeStore *store, GHFunc *func,
- gpointer user_data);
-int node_store_is_wire_at_pos (NodeStore *store, SheetPos pos);
-int node_store_is_pin_at_pos (NodeStore *store, SheetPos pos);
-GList *node_store_get_parts (NodeStore *store);
-GList *node_store_get_wires (NodeStore *store);
-GList *node_store_get_items (NodeStore *store);
-GList *node_store_get_node_positions (NodeStore *store);
-GList *node_store_get_nodes (NodeStore *store);
-void node_store_dump_wires (NodeStore *store);
-void node_store_get_bounds (NodeStore *store, NodeRect *rect);
-gint node_store_count_items (NodeStore *store, NodeRect *rect);
-void node_store_print_items (NodeStore *store, cairo_t *opc,
- SchematicPrintContext *ctx);
-Node *node_store_get_or_create_node (NodeStore *store, SheetPos pos);
+GType node_store_get_type (void);
+NodeStore *node_store_new (void);
+Node *node_store_get_node (NodeStore *store, Coords pos);
+gboolean node_store_add_part (NodeStore *store, Part *part);
+gboolean node_store_remove_part (NodeStore *store, Part *part);
+void node_store_remove_overlapping_wires (NodeStore *store, Wire *wire);
+gboolean node_store_add_wire (NodeStore *store, Wire *wire);
+gboolean node_store_remove_wire (NodeStore *store, Wire *wire);
+gboolean node_store_add_textbox (NodeStore *self, Textbox *text);
+gboolean node_store_remove_textbox (NodeStore *self, Textbox *text);
+void node_store_node_foreach (NodeStore *store, GHFunc *func, gpointer user_data);
+gboolean node_store_is_wire_at_pos (NodeStore *store, Coords pos);
+gboolean node_store_is_pin_at_pos (NodeStore *store, Coords pos);
+GList *node_store_get_parts (NodeStore *store);
+GList *node_store_get_wires (NodeStore *store);
+GList *node_store_get_items (NodeStore *store);
+GList *node_store_get_node_positions (NodeStore *store);
+GList *node_store_get_nodes (NodeStore *store);
+void node_store_dump_wires (NodeStore *store);
+void node_store_get_bounds (NodeStore *store, NodeRect *rect);
+gint node_store_count_items (NodeStore *store, NodeRect *rect);
+void node_store_print_items (NodeStore *store, cairo_t *opc, SchematicPrintContext *ctx);
+Node *node_store_get_or_create_node (NodeStore *store, Coords pos);
#endif
diff --git a/src/model/node.c b/src/model/node.c
index a8f5af8..dc04c89 100644
--- a/src/model/node.c
+++ b/src/model/node.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
@@ -35,47 +35,35 @@
#include "node.h"
#include "part.h"
-#define NG_DEBUG(s) if (0) g_print ("NG: %s\n", s)
+#include "debug.h"
static void node_class_init (NodeClass *klass);
static void node_init (Node *node);
-enum {
- NODE_DOT_ADDED,
- NODE_DOT_REMOVED,
- VOLTAGE_CHANGED,
- LAST_SIGNAL
-};
+enum { NODE_DOT_ADDED, NODE_DOT_REMOVED, VOLTAGE_CHANGED, LAST_SIGNAL };
G_DEFINE_TYPE (Node, node, G_TYPE_OBJECT)
-static guint node_signals [LAST_SIGNAL] = { 0 };
+static guint node_signals[LAST_SIGNAL] = {0};
-static void
-node_dispose (GObject *object)
+static void node_dispose (GObject *object) { G_OBJECT_CLASS (node_parent_class)->dispose (object); }
+
+static void node_finalize (GObject *object)
{
+ g_return_if_fail (object != NULL);
+
// Remove the pins and wires encountered by the node.
if (NODE (object)->pins) {
g_slist_free (NODE (object)->pins);
}
-
+
if (NODE (object)->wires) {
g_slist_free (NODE (object)->wires);
}
-
- G_OBJECT_CLASS (node_parent_class)->dispose (object);
-}
-
-
-static void
-node_finalize (GObject *object)
-{
- g_return_if_fail (object != NULL);
G_OBJECT_CLASS (node_parent_class)->finalize (object);
}
-static void
-node_class_init (NodeClass *klass)
+static void node_class_init (NodeClass *klass)
{
GObjectClass *object_class;
@@ -83,38 +71,21 @@ node_class_init (NodeClass *klass)
object_class->dispose = node_dispose;
object_class->finalize = node_finalize;
node_parent_class = g_type_class_peek_parent (klass);
-
-
- node_signals [NODE_DOT_ADDED] = g_signal_new ("node_dot_added",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- node_signals [NODE_DOT_REMOVED] = g_signal_new ("node_dot_removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- node_signals [VOLTAGE_CHANGED] = g_signal_new ("voltage_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+
+ node_signals[NODE_DOT_ADDED] =
+ g_signal_new ("node_dot_added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ node_signals[NODE_DOT_REMOVED] =
+ g_signal_new ("node_dot_removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ node_signals[VOLTAGE_CHANGED] =
+ g_signal_new ("voltage_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
-static void
-node_init (Node *node)
+static void node_init (Node *node)
{
node->pin_count = 0;
node->wire_count = 0;
@@ -123,32 +94,36 @@ node_init (Node *node)
node->visited = FALSE;
}
-Node *
-node_new (SheetPos pos)
+Node *node_new (Coords pos)
{
Node *node;
- node = NODE (g_object_new (node_get_type(), NULL));
+ node = NODE (g_object_new (node_get_type (), NULL));
node->key = pos;
return node;
}
-#define SEP(p1,p2) ((fabs(p1.x - p2.x) < 1e-3) && (fabs(p1.y - p2.y) < 1e-3))
-#define ON_THE_WIRE(p1,start,end) (fabs((end.y-start.y)*(p1.x-start.x)-(end.x-start.x)*(p1.y-start.y))<1.e-5)
-gboolean
-node_needs_dot (Node *node)
+#define SEP(p1, p2) ((fabs (p1.x - p2.x) < 1e-3) && (fabs (p1.y - p2.y) < 1e-3))
+#define ON_THE_WIRE(p1, start, end) \
+ (fabs ((end.y - start.y) * (p1.x - start.x) - (end.x - start.x) * (p1.y - start.y)) < 1.e-5)
+gboolean node_needs_dot (Node *node)
{
Wire *wire1, *wire2;
- SheetPos start_pos1, length1, end_pos1;
- SheetPos start_pos2, length2, end_pos2;
+ Coords start_pos1, length1, end_pos1;
+ Coords start_pos2, length2, end_pos2;
- if ((node->pin_count > 2) || (node->wire_count > 2))
+ NG_DEBUG ("node: %p --- pins: %i --- wires: %i", node, node->pin_count, node->wire_count);
+
+ // always display a black dot if a part hits a wire
+ if (node->pin_count > 0 && node->wire_count > 0) {
+ NG_DEBUG (" TRUE (pins>0 && wires>0)");
return TRUE;
- else if ((node->pin_count + node->wire_count) > 2)
+ } else if (node->pin_count > 1 || node->wire_count > 2) {
+ NG_DEBUG (" TRUE (pins>1 || wires>2)");
return TRUE;
- else if (node->wire_count == 2) {
+ } else if (node->wire_count == 2) {
// Check that we don't have two wire endpoints.
wire1 = node->wires->data;
wire2 = node->wires->next->data;
@@ -161,42 +136,17 @@ node_needs_dot (Node *node)
end_pos2.x = start_pos2.x + length2.x;
end_pos2.y = start_pos2.y + length2.y;
- if (!(SEP (start_pos1, start_pos2) ||
- SEP (start_pos1, end_pos2) ||
- SEP (end_pos1, end_pos2) ||
- SEP (end_pos1, start_pos2))) {
-
- // The dot is only needed when the end/start-point of
- // one of the wires in on the other wire.
- if (ON_THE_WIRE (start_pos1, start_pos2, end_pos2) ||
- ON_THE_WIRE ( end_pos1, start_pos2, end_pos2) ||
- ON_THE_WIRE (start_pos2, start_pos1, end_pos1) ||
- ON_THE_WIRE ( end_pos2, start_pos1, end_pos1)
- ) {
- return TRUE;
- }
- else
- return FALSE;
+ if (!(SEP (start_pos1, start_pos2) || SEP (start_pos1, end_pos2) ||
+ SEP (end_pos1, end_pos2) || SEP (end_pos1, start_pos2))) {
+ return TRUE;
}
-
return FALSE;
- }
- else if (node->pin_count == 1 && node->wire_count == 1) {
- // Check if we have one wire with a pin in the 'middle'.
- wire1 = node->wires->data;
- wire_get_pos_and_length (wire1, &start_pos1, &length1);
- end_pos1.x = start_pos1.x + length1.x;
- end_pos1.y = start_pos1.y + length1.y;
-
- if (!SEP (node->key, start_pos1) && !SEP (node->key, end_pos1))
- return TRUE;
}
-
+ NG_DEBUG (" FALSE (else)");
return FALSE;
}
-gint
-node_add_pin (Node *node, Pin *pin)
+gboolean node_add_pin (Node *node, Pin *pin)
{
gboolean dot;
@@ -213,15 +163,13 @@ node_add_pin (Node *node, Pin *pin)
node->pins = g_slist_prepend (node->pins, pin);
node->pin_count++;
-
if (!dot && node_needs_dot (node))
g_signal_emit_by_name (G_OBJECT (node), "node_dot_added", &node->key);
return TRUE;
}
-gint
-node_remove_pin (Node *node, Pin *pin)
+gboolean node_remove_pin (Node *node, Pin *pin)
{
gboolean dot;
@@ -243,8 +191,7 @@ node_remove_pin (Node *node, Pin *pin)
return TRUE;
}
-gint
-node_add_wire (Node *node, Wire *wire)
+gboolean node_add_wire (Node *node, Wire *wire)
{
gboolean dot;
@@ -269,8 +216,7 @@ node_add_wire (Node *node, Wire *wire)
return TRUE;
}
-gint
-node_remove_wire (Node *node, Wire *wire)
+gboolean node_remove_wire (Node *node, Wire *wire)
{
gboolean dot;
@@ -298,8 +244,7 @@ node_remove_wire (Node *node, Wire *wire)
return TRUE;
}
-gint
-node_is_empty (Node *node)
+gboolean node_is_empty (Node *node)
{
g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (IS_NODE (node), FALSE);
@@ -310,8 +255,7 @@ node_is_empty (Node *node)
return FALSE;
}
-gint
-node_is_visited (Node *node)
+gboolean node_is_visited (Node *node)
{
g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (IS_NODE (node), FALSE);
@@ -319,11 +263,46 @@ node_is_visited (Node *node)
return node->visited;
}
-void
-node_set_visited (Node *node, gboolean is_visited)
+void node_set_visited (Node *node, gboolean is_visited)
{
g_return_if_fail (node != NULL);
g_return_if_fail (IS_NODE (node));
node->visited = is_visited;
}
+
+#define HASH_EPSILON 1e-3
+
+/**
+ * Hash function to be used with a GHashTable (and others)
+ */
+guint node_hash (gconstpointer key)
+{
+ Coords *sp = (Coords *)key;
+ register int x, y;
+ const int shift = sizeof(int) * 8 / 2;
+
+ // Hash on any other node?
+
+ x = (int)rint (sp->x) % 1 << shift;
+ y = (int)rint (sp->y) % 1 << shift;
+
+ return (y << shift) | x;
+}
+
+/**
+ * Comparsion function to be used with a GHashTable (and others)
+ */
+gboolean node_equal (gconstpointer a, gconstpointer b)
+{
+ const Coords *ca = a;
+ const Coords *cb = b;
+
+ if (fabs (ca->y - cb->y) > HASH_EPSILON)
+ return 0;
+
+ if (fabs (ca->x - cb->x) > HASH_EPSILON)
+ return 0;
+
+ return 1;
+}
diff --git a/src/model/node.h b/src/model/node.h
index a5983ce..c170f31 100644
--- a/src/model/node.h
+++ b/src/model/node.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,21 +26,21 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NODE_H
#define __NODE_H
#include <gtk/gtk.h>
-#include "sheet-pos.h"
+#include "coords.h"
#include "part.h"
-#define TYPE_NODE (node_get_type ())
-#define NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE, Node))
-#define NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE, NodeClass))
-#define IS_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE))
+#define TYPE_NODE (node_get_type ())
+#define NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE, Node))
+#define NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE, NodeClass))
+#define IS_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE))
#define IS_NODE_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), TYPE_NODE, NodeClass))
typedef struct _Node Node;
@@ -48,7 +48,8 @@ typedef struct _NodeClass NodeClass;
#include "wire.h"
-struct _Node {
+struct _Node
+{
GObject parent;
// Used for traversing all nodes in the netlist generation.
@@ -63,7 +64,7 @@ struct _Node {
GSList *pins;
GSList *wires;
- SheetPos key;
+ Coords key;
};
struct _NodeClass
@@ -72,18 +73,21 @@ struct _NodeClass
};
GType node_get_type (void);
-Node *node_new (SheetPos pos);
+Node *node_new (Coords pos);
gint node_is_empty (Node *node);
-gint node_add_pin (Node *node, Pin *pin);
-gint node_remove_pin (Node *node, Pin *pin);
+gboolean node_add_pin (Node *node, Pin *pin);
+gboolean node_remove_pin (Node *node, Pin *pin);
-gint node_add_wire (Node *node, Wire *wire);
-gint node_remove_wire (Node *node, Wire *wire);
+gboolean node_add_wire (Node *node, Wire *wire);
+gboolean node_remove_wire (Node *node, Wire *wire);
-gint node_is_visited (Node *node);
+gboolean node_is_visited (Node *node);
void node_set_visited (Node *node, gboolean is_visited);
gboolean node_needs_dot (Node *node);
+guint node_hash (gconstpointer key);
+gboolean node_equal (gconstpointer a, gconstpointer b);
+
#endif
diff --git a/src/model/part-label.h b/src/model/part-label.h
index cd9daff..5a60b72 100644
--- a/src/model/part-label.h
+++ b/src/model/part-label.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,17 +26,18 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_LABEL_H
#define __PART_LABEL_H
-typedef struct {
+typedef struct
+{
gchar *name;
gchar *text;
- SheetPos pos;
+ Coords pos;
} PartLabel;
#endif
diff --git a/src/model/part-private.h b/src/model/part-private.h
index 6f705a0..771db33 100644
--- a/src/model/part-private.h
+++ b/src/model/part-private.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,26 +28,30 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_PRIVATE_H
#define __PART_PRIVATE_H
-struct _PartPriv {
- guint16 num_pins : 16;
- guint16 rotation : 16;
- IDFlip flip : 8;
+#include <glib.h>
- gchar *name;
- GSList *properties;
- GSList *labels;
+struct _PartPriv
+{
+ guint16 num_pins : 16;
+ // guint16 rotation : 16;
+ IDFlip flip : 8;
- gchar *symbol_name;
+ gchar *name;
+ GSList *properties;
+ GSList *labels;
+
+ gchar *symbol_name;
Library *library;
- Pin *pins; // Array of pins.
+ Pin *pins; // Array of pins, without any transformations applied.
+ Pin *pins_orig;
};
#endif
diff --git a/src/model/part-property.c b/src/model/part-property.c
index f4b1733..1553075 100644
--- a/src/model/part-property.c
+++ b/src/model/part-property.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib.h>
@@ -43,10 +43,9 @@
// @param cls2 returns second clause
// @param sz returns number of characters parsed
// @return the name of a macro variable
-static char *get_macro_name (const char *str, char **cls1,
- char **cls2, size_t *sz)
+static char *get_macro_name (char macro, const char *str, char **cls1, char **cls2, size_t *sz)
{
- char separators[] = { ",.;/|()" };
+ char separators[] = {",.;/|()"};
GString *out;
const char *q, *qend;
char *csep = NULL;
@@ -74,11 +73,11 @@ static char *get_macro_name (const char *str, char **cls1,
if (rc)
goto error;
- // Look for conditional clauses
- if (csep) {
- // get the first one
+ // Look for conditional clauses
+ if (csep && macro != '@' && macro != '&') {
+ // get the first one
GString *aux;
- q++; // skip the separator and store the clause in tmp
+ q++; // skip the separator and store the clause in tmp
aux = g_string_new ("");
for (; (*q) && (*q != *csep); q++)
g_string_append_c (aux, *q);
@@ -89,10 +88,10 @@ static char *get_macro_name (const char *str, char **cls1,
}
*cls1 = aux->str;
- q++; // skip the end-of-clause separator
+ q++; // skip the end-of-clause separator
g_string_free (aux, FALSE);
- // Check for the second one
+ // Check for the second one
if ((*q) && (csep = strchr (separators, *q))) {
q++; // skip the separator and store in tmp
aux = g_string_new ("");
@@ -106,12 +105,12 @@ static char *get_macro_name (const char *str, char **cls1,
}
*cls2 = aux->str;
- q++; // skip the end-of-clause separator
+ q++; // skip the end-of-clause separator
g_string_free (aux, FALSE);
}
}
- *sz = out->len;
+ *sz = out->len + (*cls1 != NULL ? strlen(*cls1) + 2 : 0) + (*cls2 != NULL ? strlen(*cls2) + 2 : 0);
ret = NULL;
if (out->len > 0) {
out = g_string_append_c (out, '\0');
@@ -121,13 +120,32 @@ static char *get_macro_name (const char *str, char **cls1,
return ret;
- error:
+error:
g_string_free (out, TRUE);
return NULL;
}
-char *
-part_property_expand_macros (Part *part, char *string)
+// Rules:
+// @<id> value of <id>. If no value, error
+// &<id> value of <id> if <id> is defined
+// ?<id>s...s text between s...s separators if <id> defined
+// ?<id>s...ss...s text between 1st s...s separators if <id> defined
+// else 2nd s...s clause
+// ~<id>s...s text between s...s separators if <id> undefined
+// ~<id>s...ss...s text between 1st s...s separators if <id> undefined
+// else 2nd s...s clause
+// #<id>s...s text between s...s separators if <id> defined, but
+// delete rest of template if <id> undefined
+
+// Separators can be any of {',', '.', ';', '/', '|', '(', ')'}.
+// For an opening-closing pair of
+// separators the same character has to be used.
+
+// Examples:
+// R^@refdes %1 %2 @value
+// V^@refdes %+ %- SIN(@offset @ampl @freq 0 0)
+// ?DC|DC @DC|
+char *part_property_expand_macros (Part *part, char *string)
{
static char mcode[] = {"@?~#&"};
char *value;
@@ -142,25 +160,7 @@ part_property_expand_macros (Part *part, char *string)
g_return_val_if_fail (string != NULL, NULL);
cls1 = cls2 = q0 = NULL;
- // Rules:
- // @<id> value of <id>. If no value, error
- // &<id> value of <id> if <id> is defined
- // ?<id>s...s text between s...s separators if <id> defined
- // ?<id>s...ss...s text between 1st s...s separators if <id> defined
- // else 2nd s...s clause
- // ~<id>s...s text between s...s separators if <id> undefined
- // ~<id>s...ss...s text between 1st s...s separators if <id> undefined
- // else 2nd s...s clause
- // #<id>s...s text between s...s separators if <id> defined, but
- // delete rest of tempalte if <id> undefined
-
- // Separators can be any of (, . ; / |) For an opening-closing pair of
- // separators the same character ahs to be used.
-
- // Examples: R^@refdes %1 %2 @value
- // V^@refdes %+ %- SIN(@offset @ampl @freq 0 0)
- // ?DC|DC @DC|
-
+
tmp0 = temp = g_strdup (string);
out = g_string_new ("");
@@ -168,87 +168,76 @@ part_property_expand_macros (Part *part, char *string)
for (temp = string; *temp;) {
// Look for any of the macro char codes.
if (strchr (mcode, *temp)) {
- qn = get_macro_name (temp + 1, &cls1, &cls2, &sln);
+ qn = get_macro_name (*temp, temp + 1, &cls1, &cls2, &sln);
if (qn == NULL)
return NULL;
value = part_get_property (part, qn);
if ((*temp == '@' || *temp == '&') && value) {
out = g_string_append (out, value);
- }
- else if (*temp =='&' && !value) {
- g_warning ( "expand macro error: macro %s undefined", qn);
+ } else if (*temp == '&' && !value) {
+ g_warning ("expand macro error: macro %s undefined", qn);
g_free (qn);
return NULL;
- }
- else if (*temp == '?' || *temp == '~') {
+ } else if (*temp == '?' || *temp == '~') {
if (cls1 == NULL) {
g_warning ("error in template: %s", temp);
g_free (qn);
return NULL;
}
- q0 = (value
- ? (*temp == '?' ? cls1 : cls2)
- : (*temp == '?' ? cls2 : cls1)
- );
+ q0 = (value ? (*temp == '?' ? cls1 : cls2) : (*temp == '?' ? cls2 : cls1));
if (q0) {
t0 = part_property_expand_macros (part, q0);
if (!t0) {
- g_warning ( "error in template: %s", temp);
+ g_warning ("error in template: %s", temp);
g_free (qn);
- }
- else {
+ } else {
out = g_string_append (out, t0);
g_free (t0);
}
}
- }
- else if (*temp=='#') {
+ } else if (*temp == '#') {
if (value) {
t0 = part_property_expand_macros (part, value);
if (!t0) {
- g_warning ( "error in template: %s", temp);
+ g_warning ("error in template: %s", temp);
g_free (qn);
- }
- else {
+ } else {
out = g_string_append (out, t0);
g_free (t0);
}
- }
- else
+ } else
*(temp + sln) = 0;
}
temp += 1;
temp += sln;
- if (qn) g_free (qn);
- if (cls1) g_free (cls1);
- if (cls2) g_free (cls2);
- }
- else {
- if ( *temp== '\\' ) {
+ g_free (qn);
+ g_free (cls1);
+ g_free (cls2);
+ } else {
+ if (*temp == '\\') {
temp++;
switch (*temp) {
case 'n':
out = g_string_append_c (out, '\n');
- break;
+ break;
case 't':
out = g_string_append_c (out, '\t');
- break;
+ break;
case 'r':
out = g_string_append_c (out, '\r');
- break;
+ break;
case 'f':
out = g_string_append_c (out, '\f');
}
temp++;
- }
- else {
+ } else {
out = g_string_append_c (out, *temp);
temp++;
}
}
}
- if (tmp0) g_free (tmp0);
+ g_free (tmp0);
out = g_string_append_c (out, '\0');
ret = g_strdup (out->str);
@@ -256,3 +245,136 @@ part_property_expand_macros (Part *part, char *string)
return ret;
}
+
+/**
+ * see #168
+ */
+void update_connection_designators(Part *part, char **prop, int *node_ctr)
+{
+ if (prop == NULL || *prop == NULL)
+ return;
+ if (node_ctr == NULL)
+ return;
+ if (part == NULL || !IS_PART(part))
+ return;
+
+ char *temp = *prop;
+ GString *out = g_string_new ("");
+
+ int breakout = FALSE;
+ while (!breakout) {
+ char **prop_split = g_regex_split_simple("[@?~#&%].*", temp, 0, 0);
+ if (prop_split[0] == NULL) {
+ g_strfreev(prop_split);
+ break;
+ }
+ temp += strlen(prop_split[0]);
+ g_string_append_printf(out, "%s", prop_split[0]);
+ g_strfreev(prop_split);
+ char macro = *temp;
+ temp++;
+ switch (macro) {
+ case '%':
+ {
+ char **prop_split = g_regex_split_simple(" .*", temp, 0, 0);
+ temp += strlen(prop_split[0]);
+ g_string_append_printf(out, "%%%d", (*node_ctr)++);
+ g_strfreev(prop_split);
+ break;
+ }
+ case '@':
+ {
+ char **prop_split = g_regex_split_simple("[,.;/|() ].*", temp, 0, 0);
+ temp += strlen(prop_split[0]);
+ char *prop_ref_name = prop_split[0];
+ char **prop_ref_value = part_get_property_ref(part, prop_ref_name);
+ g_string_append_printf(out, "@%s", prop_ref_name);
+ update_connection_designators(part, prop_ref_value, node_ctr);
+ g_strfreev(prop_split);
+ break;
+ }
+ case '&':
+ {
+ char **prop_split = g_regex_split_simple("[,.;/|() ].*", temp, 0, 0);
+ temp += strlen(prop_split[0]);
+ char *prop_ref_name = prop_split[0];
+ char **prop_ref_value = part_get_property_ref(part, prop_ref_name);
+ g_string_append_printf(out, "&%s", prop_ref_name);
+ if (prop_ref_value != NULL && *prop_ref_value != NULL)
+ update_connection_designators(part, prop_ref_value, node_ctr);
+ g_strfreev(prop_split);
+ break;
+ }
+ case '?':
+ case '~':
+ {
+ char **prop_split = g_regex_split_simple("([,.;/|()])(.*?)(\\g{-3})(?(?=[,.;/|()])([,.;/|()])(.*?)(\\g{-3})).*", temp, 0, 0);
+ char *prop_ref_name = g_strdup(prop_split[0]);
+ char separator1 = *prop_split[1];
+ char *cls1 = g_strdup(prop_split[2]);
+ //separator1 == *prop_split_name[3]
+ char separator2 = prop_split[4] != NULL ? *prop_split[4] : 0;
+ char *cls2 = NULL;
+ if (separator2 != 0) {
+ cls2 = g_strdup(prop_split[5]);
+ }
+ char **prop_ref_value = part_get_property_ref(part, prop_ref_name);
+ for (int i = 0; prop_split[i] != NULL; i++)
+ temp += strlen(prop_split[i]);
+ g_strfreev(prop_split);
+
+ if (
+ (macro == '?' && prop_ref_value != NULL && *prop_ref_value != NULL)
+ ||
+ (macro == '~' && (prop_ref_value == NULL || *prop_ref_value == NULL))
+ )
+ update_connection_designators(part, &cls1, node_ctr);
+ else if (cls2 != NULL)
+ update_connection_designators(part, &cls2, node_ctr);
+
+ g_string_append_printf(out, "%c%s%c%s%c", macro, prop_ref_name, separator1, cls1, separator1);
+ if (cls2 != NULL) {
+ g_string_append_printf(out, "%c%s%c", separator2, cls2, separator2);
+ g_free(cls2);
+ }
+
+ g_free(cls1);
+ g_free(prop_ref_name);
+ break;
+ }
+ case '#':
+ {
+ char **prop_split = g_regex_split_simple("([,.;/|()])(.*?)(\\g{-3}).*", temp, 0, 0);
+ char *prop_ref_name = g_strdup(prop_split[0]);
+ char separator = *prop_split[1];
+ char *cls = g_strdup(prop_split[2]);
+ //separator == *prop_split_name[3]
+ char **prop_ref_value = part_get_property_ref(part, prop_ref_name);
+ for (int i = 0; prop_split[i] != NULL; i++)
+ temp += strlen(prop_split[i]);
+ g_strfreev(prop_split);
+
+ if (prop_ref_value != NULL && *prop_ref_value != NULL) {
+ update_connection_designators(part, &cls, node_ctr);
+ g_string_append_printf(out, "#%s%c%s%c", prop_ref_name, separator, cls, separator);
+ } else {
+ g_string_append_printf(out, "#%s%c%s%c%s", prop_ref_name, separator, cls, separator, temp);
+ breakout = TRUE;
+ }
+
+ g_free(cls);
+ g_free(prop_ref_name);
+ break;
+ }
+ default:
+ {
+ breakout = TRUE;
+ break;
+ }
+ }
+ }
+ g_free(*prop);
+ *prop = out->str;
+ g_string_free (out, FALSE);
+ return;
+}
diff --git a/src/model/part-property.h b/src/model/part-property.h
index 3bd3b5c..698774f 100644
--- a/src/model/part-property.h
+++ b/src/model/part-property.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_PROPERTY_H
@@ -35,11 +35,13 @@
#include "part.h"
-typedef struct {
+typedef struct
+{
gchar *name;
gchar *value;
} PartProperty;
+void update_connection_designators (Part *part, char **prop, int *node_ctr);
gchar *part_property_expand_macros (Part *part, gchar *string);
#endif
diff --git a/src/model/part.c b/src/model/part.c
index aad128d..0ef7336 100644
--- a/src/model/part.c
+++ b/src/model/part.c
@@ -8,12 +8,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://beerbach.me/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
*
* This program is free software; you can redistribute it and/or
@@ -28,14 +32,15 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <glib/gi18n.h>
+#include <stdlib.h>
#include "part.h"
#include "part-property.h"
@@ -47,17 +52,16 @@
#include "schematic-print-context.h"
#include "dialogs.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
static void part_class_init (PartClass *klass);
static void part_init (Part *part);
-static void part_set_gproperty (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
+static void part_set_gproperty (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
-static void part_get_gproperty (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec);
+static void part_get_gproperty (GObject *object, guint prop_id, GValue *value, GParamSpec *spec);
static int part_set_properties (Part *part, GSList *properties);
static gboolean part_has_properties (ItemData *part);
@@ -68,9 +72,9 @@ static void part_copy (ItemData *dest, ItemData *src);
static ItemData *part_clone (ItemData *src);
-static void part_rotate (ItemData *data, int angle, SheetPos *center);
+static void part_rotate (ItemData *data, int angle, Coords *center);
-static void part_flip (ItemData *data, gboolean horizontal, SheetPos *center);
+static void part_flip (ItemData *data, IDFlip direction, Coords *center);
static void part_update_bbox (Part *part);
@@ -78,12 +82,12 @@ static void part_unregister (ItemData *data);
static int part_register (ItemData *data);
+static void part_changed (ItemData *data);
+
static void part_set_property (ItemData *data, char *property, char *value);
static char *part_get_refdes_prefix (ItemData *data);
static void part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
-static gboolean emit_rotated_signal_when_handler_connected (gpointer data);
-static gboolean emit_flipped_signal_when_handler_connected (gpointer data);
enum {
ARG_0,
@@ -91,41 +95,20 @@ enum {
ARG_LABELS,
};
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-// Structure defined to cover exchange between g_timeout_add and the
-// function in charge to emit the rotated signal only once the handler
-// has been connected.
-typedef struct {
- Part *part;
-} SignalRotatedStruct;
+G_DEFINE_TYPE (Part, part, TYPE_ITEM_DATA);
-// Structure defined to cover exchange between g_timeout_add and the
-// function in charge to emit the flipped signal only once the handler
-// has been connected.
-typedef struct {
- Part * part;
- gboolean horizontal;
- SheetPos *center;
-} SignalFlippedStruct;
+static ItemDataClass *parent_class = NULL;
-G_DEFINE_TYPE (Part, part, TYPE_ITEM_DATA)
+static void part_init (Part *part) { part->priv = g_slice_new0 (PartPriv); }
-static guint part_signals [LAST_SIGNAL] = { 0 };
-static ItemDataClass *parent_class = NULL;
+static void part_dispose (GObject *object) { G_OBJECT_CLASS (parent_class)->dispose (object); }
-static void
-part_finalize (GObject *object)
+static void part_finalize (GObject *object)
{
- Part *part;
PartPriv *priv;
GSList *list;
- part = PART (object);
- priv = part->priv;
+ priv = PART (object)->priv;
if (priv) {
g_free (priv->name);
@@ -149,21 +132,15 @@ part_finalize (GObject *object)
g_slist_free (priv->labels);
g_free (priv->pins);
+ g_free (priv->pins_orig);
g_free (priv->symbol_name);
- g_free (priv);
- part->priv = NULL;
+
+ g_slice_free (PartPriv, priv);
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-part_dispose (GObject *object)
-{
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-part_class_init (PartClass *klass)
+static void part_class_init (PartClass *klass)
{
GObjectClass *object_class;
ItemDataClass *item_data_class;
@@ -178,12 +155,12 @@ part_class_init (PartClass *klass)
object_class->dispose = part_dispose;
object_class->finalize = part_finalize;
- g_object_class_install_property (object_class, ARG_PROPERTIES,
- g_param_spec_pointer ("properties", "properties",
- "the properties", G_PARAM_READWRITE));
- g_object_class_install_property (object_class, ARG_LABELS,
- g_param_spec_pointer ("labels", "labels", "the labels",
- G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, ARG_PROPERTIES,
+ g_param_spec_pointer ("properties", "properties", "the properties", G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class, ARG_LABELS,
+ g_param_spec_pointer ("labels", "labels", "the labels", G_PARAM_READWRITE));
item_data_class->clone = part_clone;
item_data_class->copy = part_copy;
@@ -191,35 +168,19 @@ part_class_init (PartClass *klass)
item_data_class->flip = part_flip;
item_data_class->unreg = part_unregister;
item_data_class->reg = part_register;
+ item_data_class->changed = part_changed;
item_data_class->get_refdes_prefix = part_get_refdes_prefix;
item_data_class->set_property = part_set_property;
item_data_class->has_properties = part_has_properties;
item_data_class->print = part_print;
-
- part_signals[CHANGED] =
- g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (PartClass, changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
}
-static void
-part_init (Part *part)
-{
- PartPriv *priv;
+////////////////////////////////////////////////////////////////////////////////
+// END BOILER PLATE
+////////////////////////////////////////////////////////////////////////////////
- priv = g_new0 (PartPriv, 1);
-
- part->priv = priv;
-}
-
-Part *
-part_new (void)
+Part *part_new ()
{
Part *part;
@@ -228,8 +189,7 @@ part_new (void)
return part;
}
-Part *
-part_new_from_library_part (LibraryPart *library_part)
+Part *part_new_from_library_part (LibraryPart *library_part)
{
Part *part;
GSList *pins;
@@ -245,11 +205,10 @@ part_new_from_library_part (LibraryPart *library_part)
priv = part->priv;
symbol = library_get_symbol (library_part->symbol_name);
- if (symbol == NULL) {
- oregano_warning (g_strdup_printf (_("Couldn't find the requested symbol"
- "%s for part %s in library.\n"),
- library_part->symbol_name,
- library_part->name));
+ if (symbol == NULL) {
+ oregano_warning (g_strdup_printf (_ ("Couldn't find the requested symbol"
+ "%s for part %s in library.\n"),
+ library_part->symbol_name, library_part->name));
return NULL;
}
@@ -258,10 +217,8 @@ part_new_from_library_part (LibraryPart *library_part)
if (pins)
part_set_pins (part, pins);
- g_object_set (G_OBJECT (part),
- "Part::properties", library_part->properties,
- "Part::labels", library_part->labels,
- NULL);
+ g_object_set (G_OBJECT (part), "Part::properties", library_part->properties, "Part::labels",
+ library_part->labels, NULL);
priv->name = g_strdup (library_part->name);
priv->symbol_name = g_strdup (library_part->symbol_name);
@@ -272,9 +229,8 @@ part_new_from_library_part (LibraryPart *library_part)
return part;
}
-static void
-part_set_gproperty (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *spec)
+static void part_set_gproperty (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
{
GSList *list;
Part *part = PART (object);
@@ -291,9 +247,7 @@ part_set_gproperty (GObject *object, guint prop_id, const GValue *value,
}
}
-static void
-part_get_gproperty (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec)
+static void part_get_gproperty (GObject *object, guint prop_id, GValue *value, GParamSpec *spec)
{
Part *part = PART (object);
PartPriv *priv = part->priv;
@@ -307,8 +261,7 @@ part_get_gproperty (GObject *object, guint prop_id, GValue *value,
}
}
-int
-part_get_num_pins (Part *part)
+gint part_get_num_pins (Part *part)
{
PartPriv *priv;
@@ -319,20 +272,48 @@ part_get_num_pins (Part *part)
return priv->num_pins;
}
-int
-part_get_rotation (Part *part)
+/**
+ * @returns the rotation in degrees
+ * @attention steps of 90 degrees only!
+ */
+gint part_get_rotation (Part *part)
{
- PartPriv *priv;
+ ItemData *item;
+ gdouble register a, b, c, d;
+ cairo_matrix_t *t;
g_return_val_if_fail (part != NULL, 0);
g_return_val_if_fail (IS_PART (part), 0);
- priv = part->priv;
- return priv->rotation;
+ item = ITEM_DATA (part);
+
+ t = item_data_get_rotate (item);
+ a = t->xx;
+ b = t->xy;
+ c = t->yx;
+ d = t->yy;
+
+ //check whether matrix is rotation matrix
+ //Let Q be the matrix. Q is a rotation matrix if and only if Q^T Q = I and det Q = 1.
+ //Then it is existing a real value alpha so that
+ // ( a b ) ( cos(alpha) -sin(alpha) )
+ //Q = ( ) = ( )
+ // ( c d ) ( sin(alpha) cos(alpha) )
+ if (G_UNLIKELY (fabs (1 - (a * a + c * c)) > 1e-10 || fabs (1 - (b * b + d * d)) > 1e-10 || fabs (a*b + c*d) > 1e-10 || fabs (1 - (a*d - b*c)) > 1e-10)) {
+ g_warning ("Unabled to calculate rotation from matrix. Assuming 0°.");
+ return 0;
+ }
+
+ //Now we want to extract alpha.
+ //this case differentiation is only for numerical stability at the edges of the domains of definition of acos and atan
+ if (-0.5 <= a && a <= 0.5) {
+ return 180. / M_PI * (acos(a) + (c < 0 ? M_PI : 0));
+ } else {
+ return 180. / M_PI * (atan(c/a) + (a < 0 ? M_PI : 0));
+ }
}
-IDFlip
-part_get_flip (Part *part)
+IDFlip part_get_flip (Part *part)
{
PartPriv *priv;
@@ -343,8 +324,7 @@ part_get_flip (Part *part)
return priv->flip;
}
-Pin *
-part_get_pins (Part *part)
+Pin *part_get_pins (Part *part)
{
PartPriv *priv;
@@ -355,16 +335,14 @@ part_get_pins (Part *part)
return priv->pins;
}
-static gboolean
-part_has_properties (ItemData *item)
+static gboolean part_has_properties (ItemData *item)
{
Part *part = PART (item);
return part->priv->properties != NULL;
}
-static int
-part_set_properties (Part *part, GSList *properties)
+static gboolean part_set_properties (Part *part, GSList *properties)
{
PartPriv *priv;
GSList *list;
@@ -392,8 +370,7 @@ part_set_properties (Part *part, GSList *properties)
return TRUE;
}
-GSList *
-part_get_properties (Part *part)
+GSList *part_get_properties (Part *part)
{
PartPriv *priv;
@@ -405,8 +382,10 @@ part_get_properties (Part *part)
return priv->properties;
}
-char *
-part_get_property (Part *part, char *name)
+/**
+ * @return no free() pls
+ */
+char **part_get_property_ref (Part *part, char *name)
{
PartPriv *priv;
GSList *props;
@@ -421,14 +400,25 @@ part_get_property (Part *part, char *name)
for (props = priv->properties; props; props = props->next) {
prop = props->data;
if (g_ascii_strcasecmp (prop->name, name) == 0) {
- return g_strdup (prop->value);
+ return &(prop->value);
}
}
+ return ((char **)0);
+}
+
+/**
+ * @returns [transfer-full]
+ */
+char *part_get_property (Part *part, char *name)
+{
+ char **prop = part_get_property_ref(part, name);
+ if (prop != NULL && *prop != NULL) {
+ return g_strdup(*prop);
+ }
return NULL;
}
-static int
-part_set_labels (Part *part, GSList *labels)
+static gboolean part_set_labels (Part *part, GSList *labels)
{
PartPriv *priv;
GSList *list;
@@ -466,8 +456,10 @@ part_set_labels (Part *part, GSList *labels)
return TRUE;
}
-int
-part_set_pins (Part *part, GSList *pins)
+/**
+ * overwrite the pins with those given in the list
+ */
+gboolean part_set_pins (Part *part, GSList *pins)
{
PartPriv *priv;
GSList *list;
@@ -481,29 +473,32 @@ part_set_pins (Part *part, GSList *pins)
num_pins = g_slist_length (pins);
- if (priv->pins)
- g_free (priv->pins);
+ g_free (priv->pins);
+ g_free (priv->pins_orig);
priv->pins = g_new0 (Pin, num_pins);
+ priv->pins_orig = g_new0 (Pin, num_pins);
+
priv->num_pins = num_pins;
for (list = pins, i = 0; list; list = list->next, i++) {
// Note that this is slightly hackish. The list contains
- // Connections which only have the SheetPos field.
+ // Connections which only have the Coords field.
Pin *pin = list->data;
- priv->pins[i].pin_nr = i;
- priv->pins[i].node_nr= 0;
- priv->pins[i].offset.x = pin->offset.x;
- priv->pins[i].offset.y = pin->offset.y;
- priv->pins[i].part = part;
+ priv->pins_orig[i].pin_nr = i;
+ priv->pins_orig[i].node_nr = 0;
+ priv->pins_orig[i].offset.x = pin->offset.x;
+ priv->pins_orig[i].offset.y = pin->offset.y;
+ priv->pins_orig[i].part = part;
+
+ memcpy (priv->pins, priv->pins_orig, sizeof(Pin) * num_pins);
}
return TRUE;
}
-GSList *
-part_get_labels (Part *part)
+GSList *part_get_labels (Part *part)
{
PartPriv *priv;
@@ -515,156 +510,183 @@ part_get_labels (Part *part)
return priv->labels;
}
-static void
-part_rotate (ItemData *data, int angle, SheetPos *center)
+/**
+ * \brief rotate an item by an @angle increment (may be negative)
+ *
+ * @angle the increment the item will be rotated (usually 90° steps)
+ * @center_pos if rotated as part of a group, this is the center to rotate
+ *around
+ */
+static void part_rotate (ItemData *data, int angle, Coords *center_pos)
{
- cairo_matrix_t affine;
- double dx, dy, x, y;
- Part *part;
- PartPriv *priv;
- int i, tot_rotation;
- SheetPos b1, b2, part_center_before, part_center_after, delta;
- SignalRotatedStruct *signal_struct;
-
- g_return_if_fail (data != NULL);
+ g_return_if_fail (data);
g_return_if_fail (IS_PART (data));
- if (angle == 0)
- return;
+ cairo_matrix_t morph, morph_rot, local_rot;
+ gint i;
+ gdouble x, y;
+ Part *part;
+ PartPriv *priv;
+ gboolean handler_connected;
part = PART (data);
priv = part->priv;
- tot_rotation = (priv->rotation + angle) % 360;
-
- priv->rotation = tot_rotation;
- angle = tot_rotation;
+ // FIXME store vanilla coords, apply the morph
+ // FIXME to these and store the result in the
+ // FIXME instance then everything will be fine
+ // XXX also prevents rounding yiggle up downs
- cairo_matrix_init_rotate (&affine, (double) (angle* M_PI / 180));
+ angle /= 90;
+ angle *= 90;
- // Rotate the pins.
- for (i = 0; i < priv->num_pins; i++) {
- x = priv->pins[i].offset.x;
- y = priv->pins[i].offset.y;
- cairo_matrix_transform_point (&affine, &x, &y);
+ // normalize it
+ angle = angle % 360;
- if (fabs (x) < 1e-2)
- x = 0.0;
- if (fabs (y) < 1e-2)
- y = 0.0;
+ if (angle == 0)
+ return;
- priv->pins[i].offset.x = x;
- priv->pins[i].offset.y = y;
- }
+ cairo_matrix_init_rotate (&local_rot, (double)angle * M_PI / 180.);
- // Rotate the bounding box.
- item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
- part_center_before.x = (b1.x + b2.x) / 2;
- part_center_before.y = (b1.y + b2.y) / 2;
+ cairo_matrix_multiply (item_data_get_rotate (data), item_data_get_rotate (data), &local_rot);
- x = b1.x;
- y = b1.y;
- cairo_matrix_transform_point (&affine, &x, &y);
- b1.x = x;
- b1.y = y;
+ morph_rot = *(item_data_get_rotate (data));
- x = b2.x;
- y = b2.y;
- cairo_matrix_transform_point (&affine, &x, &y);
- b2.x = x;
- b2.y = y;
+ cairo_matrix_multiply (&morph, &morph_rot, item_data_get_translate (data));
- item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2);
+ Coords delta_to_center, delta_to_center_transformed;
+ Coords delta_to_apply;
+ Coords item_pos;
- if (center) {
- SheetPos part_pos;
- gfloat tmp_x, tmp_y;
+ item_data_get_pos (ITEM_DATA (part), &item_pos);
- part_center_after.x = (b1.x + b2.x) / 2;
- part_center_after.y = (b1.y + b2.y) / 2;
+ Coords rotation_center;
- dx = part_center_before.x - part_center_after.x;
- dy = part_center_before.y - part_center_after.y;
+ if (center_pos == NULL) {
+ rotation_center = item_pos;
+ } else {
+ rotation_center = *center_pos;
+ }
- item_data_get_pos (ITEM_DATA (part), &part_pos);
+ delta_to_center_transformed = delta_to_center = coords_sub (&rotation_center, &item_pos);
+ cairo_matrix_transform_point (&local_rot, &(delta_to_center_transformed.x),
+ &(delta_to_center_transformed.y));
- tmp_x = x = part_center_before.x - center->x + part_pos.x;
- tmp_y = y = part_center_before.y - center->y + part_pos.y;
- cairo_matrix_transform_point (&affine, &x, &y);
+ delta_to_apply = coords_sub (&delta_to_center, &delta_to_center_transformed);
- delta.x = dx + x - tmp_x;
- delta.y = dy + y - tmp_y;
+#define DEBUG_THIS 0
+ // use the cairo matrix funcs to transform the pin
+ // positions relative to the item center
+ // this is only indirectly related to displayin
+ // HINT: we need to modify the actual pins to make the
+ // pin tests work being used to detect connections
- item_data_move (ITEM_DATA (part), &delta);
+ // Rotate the pins.
+ for (i = 0; i < priv->num_pins; i++) {
+ if (priv->pins_orig && priv->pins) {
+ x = priv->pins_orig[i].offset.x;
+ y = priv->pins_orig[i].offset.y;
+ cairo_matrix_transform_point (&morph_rot, &x, &y);
+
+ if (fabs (x) < 1e-2)
+ x = 0.0;
+ if (fabs (y) < 1e-2)
+ y = 0.0;
+
+ priv->pins[i].offset.x = x;
+ priv->pins[i].offset.y = y;
+ }
}
-
- // Let the views (canvas items) know about the rotation.
- signal_struct = g_new0 (SignalRotatedStruct, 1);
- signal_struct->part = part;
- g_timeout_add (10,
- (gpointer) emit_rotated_signal_when_handler_connected,
- (gpointer) signal_struct);
-}
-static gboolean
-emit_rotated_signal_when_handler_connected (gpointer data)
-{
- gboolean handler_connected;
- SignalRotatedStruct *signal_struct = (SignalRotatedStruct *) data;
- int angle = 0;
- Part *part;
-
-
- part = signal_struct->part;
- angle = part->priv->rotation;
+ item_data_move (data, &delta_to_apply);
- handler_connected = g_signal_handler_is_connected (G_OBJECT (part),
- ITEM_DATA (part)->rotated_handler_id);
+ handler_connected = g_signal_handler_is_connected (G_OBJECT (data), data->changed_handler_id);
if (handler_connected) {
- g_signal_emit_by_name (G_OBJECT (part),
- "rotated", angle);
+ g_signal_emit_by_name (G_OBJECT (data), "changed");
+ } else {
+ NG_DEBUG ("handler not yet registerd.");
}
-
- return !handler_connected;
+ NG_DEBUG ("\n\n");
}
-static void
-part_flip (ItemData *data, gboolean horizontal, SheetPos *center)
+/**
+ * flip a part in a given direction
+ * @direction gives the direction the item will be flipped, end users pov!
+ * @center the center to flip over - currently ignored FIXME
+ */
+static void part_flip (ItemData *data, IDFlip direction, Coords *center)
{
+#if 0
Part *part;
PartPriv *priv;
int i;
cairo_matrix_t affine;
double x, y;
- SignalFlippedStruct *signal_struct;
-
- g_return_if_fail (data != NULL);
+ double scale_v, scale_h;
+ gboolean handler_connected;
+ Coords delta;
+ Coords pos, trans;
+ Coords b1, b2;
+ Coords pos_new, pos_old;
+ //FIXME properly recenter after flipping
+ //Coords part_center_before, part_center_after, delta;
+
+ g_return_if_fail (data);
g_return_if_fail (IS_PART (data));
part = PART (data);
priv = part->priv;
- if (horizontal && !(priv->flip & ID_FLIP_HORIZ))
- priv->flip = priv->flip | ID_FLIP_HORIZ;
- else if (horizontal && (priv->flip & ID_FLIP_HORIZ))
- priv->flip = priv->flip & ~ID_FLIP_HORIZ;
- else if (!horizontal && !(priv->flip & ID_FLIP_VERT))
- priv->flip = priv->flip | ID_FLIP_VERT;
- else if (!horizontal && (priv->flip & ID_FLIP_VERT))
- priv->flip = priv->flip & ~ID_FLIP_VERT;
-
- if (horizontal)
- cairo_matrix_init_scale (&affine, 1.0, -1.0);
- else
- cairo_matrix_init_scale (&affine, -1.0, 1.0);
-
- //Flip the pins.
+ item_data_get_pos (data, &trans);
+
+ // mask, just for the sake of cleanness
+ direction &= ID_FLIP_MASK;
+
+ // TODO evaluate if we really want to be able to do double flips (180* rots via flipping)
+ g_assert (direction != ID_FLIP_MASK);
+
+
+ // create a transformation _relativ_ to the current _state_
+ // reverse axis and fix the created offset by adding 2*pos.x or .y
+
+ // convert the flip direction to binary, used in the matrix setup
+ // keep in mind that we do relativ manipulations within the model
+ // which in turn makes this valid for all rotations!
+ scale_h = ((direction & ID_FLIP_HORIZ) != 0) ? -1. : 1.;
+ scale_v = ((direction & ID_FLIP_VERT) != 0) ? -1. : 1.;
+
+ // magic, if we are in either 270 or 90 state, we need to rotate the flip state by 90° to draw it properly
+ // TODO maybe better put this into the rotation function
+ if ((priv->rotation / 90) % 2 == 1) {
+ priv->flip ^= ID_FLIP_MASK;
+ }
+ // toggle the direction
+ priv->flip ^= direction;
+ if ((priv->flip & ID_FLIP_MASK)== ID_FLIP_MASK) {
+ priv->flip = ID_FLIP_NONE;
+ priv->rotation += 180;
+ priv->rotation %= 360;
+ }
+
+ cairo_matrix_init_scale (&affine, scale_h, scale_v);
+
+ item_data_get_pos (data, &pos_old);
+ pos_new = pos_old;
+ cairo_matrix_transform_point (&affine, &pos_new.x, &pos_new.y);
+
+ g_printf ("\ncenter %p [old] x=%lf,y=%lf -->", data, pos_old.x, pos_old.y);
+ g_printf (" x=%lf, y=%lf\n", pos_new.x, pos_new.y);
+ delta.x = - pos_new.x + pos_old.x;
+ delta.y = - pos_new.y + pos_old.y;
+
+ // flip the pins
for (i = 0; i < priv->num_pins; i++) {
+
x = priv->pins[i].offset.x;
y = priv->pins[i].offset.y;
cairo_matrix_transform_point (&affine, &x, &y);
-
+
if (fabs (x) < 1e-2)
x = 0.0;
if (fabs (y) < 1e-2)
@@ -674,85 +696,34 @@ part_flip (ItemData *data, gboolean horizontal, SheetPos *center)
priv->pins[i].offset.y = y;
}
- // Tell the views.
- signal_struct = g_new0 (SignalFlippedStruct, 1);
- signal_struct->part = part;
- signal_struct->horizontal = horizontal;
- signal_struct->center = center;
- g_timeout_add (10,
- (gpointer) emit_flipped_signal_when_handler_connected,
- (gpointer) signal_struct);
-}
-
-static
-gboolean emit_flipped_signal_when_handler_connected (gpointer data)
-{
- gboolean handler_connected;
- SignalFlippedStruct *signal_struct = (SignalFlippedStruct *) data;
- gboolean horizontal;
- SheetPos *center;
- Part *part;
-
- SheetPos part_center_before = {0.0, 0.0}, part_center_after = {0.0, 0.0};
- SheetPos b1, b2;
- cairo_matrix_t affine;
- double x, y;
-
-
- part = signal_struct->part;
- horizontal = signal_struct->horizontal;
- center = signal_struct->center;
-
- handler_connected = g_signal_handler_is_connected (G_OBJECT (part),
+ // tell the view
+ handler_connected = g_signal_handler_is_connected (G_OBJECT (part),
ITEM_DATA(part)->flipped_handler_id);
if (handler_connected) {
- g_signal_emit_by_name (G_OBJECT (part),
- "flipped", horizontal);
-
- if (center) {
- item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
- part_center_before.x = (b1.x + b2.x) / 2;
- part_center_before.y = (b1.y + b2.y) / 2;
- }
-
- // Flip the bounding box.
- x = b1.x;
- y = b1.y;
- cairo_matrix_transform_point (&affine, &x, &y);
- b1.x = x;
- b1.y = y;
-
- x = b2.x;
- y = b2.y;
- cairo_matrix_transform_point (&affine, &x, &y);
- b2.x = x;
- b2.y = y;
-
- item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2);
+ g_signal_emit_by_name (G_OBJECT (part), "flipped", priv->flip);
- if (center) {
- SheetPos part_pos, delta;
- double dx, dy;
+ // TODO - proper boundingbox center calculation
- part_center_after.x = b1.x + (b2.x - b1.x) / 2;
- part_center_after.y = b1.y + (b2.y - b1.y) / 2;
+ item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
- dx = part_center_before.x - part_center_after.x;
- dy = part_center_before.y - part_center_after.y;
+ // flip the bounding box.
+ cairo_matrix_transform_point (&affine, &b1.x, &b1.y);
+ cairo_matrix_transform_point (&affine, &b2.x, &b2.y);
- item_data_get_pos (ITEM_DATA (part), &part_pos);
+ item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2);
+ item_data_set_pos (ITEM_DATA (part), &pos);
- delta.x = dx + part_pos.x;
- delta.y = dy + part_pos.y;
- item_data_move (ITEM_DATA (part), &delta);
- }
+ // FIXME - proper recenter to boundingbox center
}
-
- return !handler_connected;
+ if (g_signal_handler_is_connected (G_OBJECT (part),
+ ITEM_DATA (part)->changed_handler_id)) {
+ g_signal_emit_by_name (G_OBJECT (part),
+ "changed");
+ }
+#endif
}
-static ItemData *
-part_clone (ItemData *src)
+static ItemData *part_clone (ItemData *src)
{
Part *src_part, *new_part;
ItemDataClass *id_class;
@@ -760,20 +731,20 @@ part_clone (ItemData *src)
g_return_val_if_fail (src != NULL, NULL);
g_return_val_if_fail (IS_PART (src), NULL);
- id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS(src));
+ id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (src));
if (id_class->copy == NULL)
return NULL;
src_part = PART (src);
- new_part = PART (g_object_new (TYPE_PART, NULL));
+ new_part = g_object_new (TYPE_PART, NULL);
new_part->priv->pins = g_new0 (Pin, src_part->priv->num_pins);
+ new_part->priv->pins_orig = g_new0 (Pin, src_part->priv->num_pins);
id_class->copy (ITEM_DATA (new_part), src);
return ITEM_DATA (new_part);
}
-static void
-part_copy (ItemData *dest, ItemData *src)
+static void part_copy (ItemData *dest, ItemData *src)
{
Part *dest_part, *src_part;
GSList *list;
@@ -790,21 +761,26 @@ part_copy (ItemData *dest, ItemData *src)
dest_part = PART (dest);
src_part = PART (src);
- dest_part->priv->rotation = src_part->priv->rotation;
+ // dest_part->priv->rotation = src_part->priv->rotation;
dest_part->priv->flip = src_part->priv->flip;
dest_part->priv->num_pins = src_part->priv->num_pins;
dest_part->priv->library = src_part->priv->library;
dest_part->priv->name = g_strdup (src_part->priv->name);
dest_part->priv->symbol_name = g_strdup (src_part->priv->symbol_name);
- memcpy (dest_part->priv->pins, src_part->priv->pins,
- src_part->priv->num_pins * sizeof (Pin));
- for (i = 0; i < dest_part->priv->num_pins; i++)
- dest_part->priv->pins[i].part = dest_part;
+ if (src_part->priv->pins) {
+ memcpy (dest_part->priv->pins, src_part->priv->pins, src_part->priv->num_pins * sizeof(Pin));
+ for (i = 0; i < dest_part->priv->num_pins; i++)
+ dest_part->priv->pins[i].part = dest_part;
+ }
+ if (src_part->priv->pins_orig) {
+ memcpy (dest_part->priv->pins_orig, src_part->priv->pins_orig, src_part->priv->num_pins * sizeof(Pin));
+ for (i = 0; i < dest_part->priv->num_pins; i++)
+ dest_part->priv->pins_orig[i].part = dest_part;
+ }
// Copy properties and labels.
- dest_part->priv->properties =
- g_slist_copy (src_part->priv->properties);
+ dest_part->priv->properties = g_slist_copy (src_part->priv->properties);
for (list = dest_part->priv->properties; list; list = list->next) {
PartProperty *prop, *new_prop;
@@ -828,16 +804,15 @@ part_copy (ItemData *dest, ItemData *src)
}
}
-static void
-part_update_bbox (Part *part)
+static void part_update_bbox (Part *part)
{
- GSList *objects;
+ GSList *iter;
LibrarySymbol *symbol;
SymbolObject *object;
GooCanvasPoints *points;
int i;
- SheetPos b1, b2;
+ Coords b1, b2;
symbol = library_get_symbol (part->priv->symbol_name);
if (symbol == NULL) {
@@ -847,9 +822,8 @@ part_update_bbox (Part *part)
b1.x = b1.y = b2.x = b2.y = 0.0;
- for (objects = symbol->symbol_objects; objects;
- objects = objects->next) {
- object = objects->data;
+ for (iter = symbol->symbol_objects; iter; iter = iter->next) {
+ object = iter->data;
switch (object->type) {
case SYMBOL_OBJECT_LINE:
points = object->u.uline.line;
@@ -878,18 +852,16 @@ part_update_bbox (Part *part)
break;
- case SYMBOL_OBJECT_TEXT:
- {
- /*GdkFont *font = gdk_font_load ("Sans 10");
- b1.x = b1.y = 0;
- b2.x = 2*object->u.text.x +
- gdk_string_width (font, object->u.text.str );
- b2.y = 2*object->u.text.y +
- gdk_string_height (font,object->u.text.str );
- */
- }
- break;
-
+ case SYMBOL_OBJECT_TEXT: {
+ // FIXME use cairo pango layout
+ /*GdkFont *font = gdk_font_load ("Sans 10");
+ b1.x = b1.y = 0;
+ b2.x = 2*object->u.text.x +
+ gdk_string_width (font, object->u.text.str );
+ b2.y = 2*object->u.text.y +
+ gdk_string_height (font,object->u.text.str );
+ */
+ } break;
default:
g_warning ("Unknown symbol object.\n");
@@ -900,8 +872,7 @@ part_update_bbox (Part *part)
item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2);
}
-static void
-part_unregister (ItemData *data)
+static void part_unregister (ItemData *data)
{
NodeStore *store;
@@ -911,21 +882,52 @@ part_unregister (ItemData *data)
node_store_remove_part (store, PART (data));
}
-static int
-part_register (ItemData *data)
+/**
+ * register a part to its nodestore
+ * @param data the part
+ * @attention the @data has to have a valid nodestore set
+ */
+static int part_register (ItemData *data)
{
NodeStore *store;
- g_return_val_if_fail (IS_PART (data), -1);
+ g_return_val_if_fail (IS_PART (data), FALSE);
store = item_data_get_store (data);
node_store_add_part (store, PART (data));
- return 0;
+ return TRUE;
+}
+
+/**
+ * simply signal a change in the part
+ */
+static void part_changed (ItemData *data)
+{
+ g_return_if_fail (IS_PART (data));
+
+#if 0
+ Part *part;
+ Coords loc = {0., 0.};
+ int angle = 0;
+ IDFlip flip = ID_FLIP_NONE;
+
+ part = (Part *)data;
+
+
+ flip = part_get_flip (part);
+ angle = part_get_rotation (part);
+ item_data_get_pos (data, &loc);
+
+ //FIXME isn't it more sane to just emit the changed?
+ g_signal_emit_by_name (data, "moved", &loc);
+ g_signal_emit_by_name (data, "flipped", flip);
+ g_signal_emit_by_name (data, "rotated", angle);
+#endif
+ g_signal_emit_by_name (data, "changed");
}
-static char *
-part_get_refdes_prefix (ItemData *data)
+static char *part_get_refdes_prefix (ItemData *data)
{
Part *part;
char *refdes;
@@ -941,17 +943,16 @@ part_get_refdes_prefix (ItemData *data)
// Get the 'prefix' i.e R for resistors.
length = strlen (refdes);
- for (i = 0; i < length; i++) {
- if (isdigit (refdes[length-i -1])) {
- refdes[length -i -1] = '\0';
- }
- else break;
+ for (i = 0; i < length; i++) {
+ if (isdigit (refdes[length - i - 1])) {
+ refdes[length - i - 1] = '\0';
+ } else
+ break;
}
return g_strdup (refdes);
}
-static void
-part_set_property (ItemData *data, char *property, char *value)
+static void part_set_property (ItemData *data, char *property, char *value)
{
Part *part;
PartPriv *priv;
@@ -979,8 +980,11 @@ part_set_property (ItemData *data, char *property, char *value)
}
}
-static void
-part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
+/**
+ * print the part onto a physical sheet of paper or pdf, which is represented by
+ * @cr
+ */
+static void part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
{
GSList *objects, *labels;
SymbolObject *object;
@@ -989,7 +993,7 @@ part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
int i, rotation;
Part *part;
PartPriv *priv;
- SheetPos pos;
+ Coords pos;
IDFlip flip;
GooCanvasPoints *line;
@@ -1010,80 +1014,63 @@ part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
cairo_save (cr);
- gdk_cairo_set_source_color (cr, &ctx->colors.components);
+ gdk_cairo_set_source_rgba (cr, &ctx->colors.components);
+
rotation = part_get_rotation (part);
- if (rotation != 0) {
- cairo_translate (cr, x0, y0);
-
- flip = part_get_flip (part);
- if (flip) {
- if ((flip & ID_FLIP_HORIZ) && !(flip & ID_FLIP_VERT))
- cairo_scale (cr, -1, 1);
- if (!(flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT))
- cairo_scale (cr, 1, -1);
- if ((flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT))
- rotation+=180;
- }
-
- cairo_rotate (cr, rotation*M_PI/180);
- cairo_translate (cr, -x0, -y0);
- }
- else {
- flip = part_get_flip (part);
- if (flip) {
- cairo_translate (cr, x0, y0);
- if ((flip & ID_FLIP_HORIZ) && !(flip & ID_FLIP_VERT))
- cairo_scale (cr, -1, 1);
- if (!(flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT))
- cairo_scale (cr, 1, -1);
- if ((flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT))
- cairo_scale (cr,-1,-1);
- cairo_translate (cr, -x0, -y0);
- }
+ flip = part_get_flip (part);
+
+ if ((flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT))
+ rotation += 180;
+ else if (flip == ID_FLIP_HORIZ)
+ cairo_scale (cr, -1, 1);
+ else if (flip == ID_FLIP_VERT)
+ cairo_scale (cr, 1, -1);
+
+ // Rotate around the item position
+ if (rotation %= 360) {
+ cairo_translate(cr, x0, y0);
+ cairo_rotate (cr, rotation * M_PI / 180);
+ cairo_translate(cr, -x0, -y0);
}
for (objects = symbol->symbol_objects; objects; objects = objects->next) {
object = (SymbolObject *)(objects->data);
switch (object->type) {
- case SYMBOL_OBJECT_LINE:
- line = object->u.uline.line;
- for (i = 0; i < line->num_points; i++) {
- double x, y;
-
- x = line->coords[i * 2];
- y = line->coords[i * 2 + 1];
-
- if (i == 0)
- cairo_move_to (cr, x0 + x, y0 + y);
- else
- cairo_line_to (cr, x0 + x, y0 + y);
- }
- break;
- case SYMBOL_OBJECT_ARC: {
- gdouble x1 = object->u.arc.x1;
- gdouble y1 = object->u.arc.y1;
- gdouble x2 = object->u.arc.x2;
- gdouble y2 = object->u.arc.y2;
- gdouble width, height, x, y;
-
- x = (x2 - x1) / 2 + x1;
- y = (y2 - y1) / 2 + y1;
- width = x2 - x1;
- height = y2 - y1;
-
- cairo_save (cr);
- cairo_translate (cr, x0 + x, y0 + y);
- cairo_scale (cr, width / 2.0, height / 2.0);
- cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI);
- cairo_restore (cr);
+ case SYMBOL_OBJECT_LINE:
+ line = object->u.uline.line;
+ for (i = 0; i < line->num_points; i++) {
+ double x, y;
+
+ x = line->coords[i * 2];
+ y = line->coords[i * 2 + 1];
+
+ if (i == 0)
+ cairo_move_to (cr, x0 + x, y0 + y);
+ else
+ cairo_line_to (cr, x0 + x, y0 + y);
}
break;
- default:
- g_warning (
- "Print part: Part %s contains unknown object.",
- priv->name
- );
+ case SYMBOL_OBJECT_ARC: {
+ gdouble x1 = object->u.arc.x1;
+ gdouble y1 = object->u.arc.y1;
+ gdouble x2 = object->u.arc.x2;
+ gdouble y2 = object->u.arc.y2;
+ gdouble width, height, x, y;
+
+ x = (x2 + x1) / 2;
+ y = (y2 + y1) / 2;
+ width = x2 - x1;
+ height = y2 - y1;
+
+ cairo_save (cr);
+ cairo_translate (cr, x0 + x, y0 + y);
+ cairo_scale (cr, width / 2.0, height / 2.0);
+ cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI);
+ cairo_restore (cr);
+ } break;
+ default:
+ g_warning ("Print part: Part %s contains unknown object.", priv->name);
continue;
}
@@ -1091,7 +1078,7 @@ part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
}
// We don't want to rotate labels text, only the (x,y) coordinate
- gdk_cairo_set_source_color (cr, &ctx->colors.labels);
+ gdk_cairo_set_source_rgba (cr, &ctx->colors.labels);
for (labels = part_get_labels (part); labels; labels = labels->next) {
gdouble x, y;
PartLabel *label = (PartLabel *)labels->data;
@@ -1104,22 +1091,22 @@ part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
text = part_property_expand_macros (part, label->text);
/* Align the label.
switch (rotation) {
- case 90:
- y += text_height*opc->scale;
- break;
- case 180:
- break;
- case 270:
- x -= text_width*opc->scale;
- break;
- case 0:
- default:
- break;
+ case 90:
+ y += text_height*opc->scale;
+ break;
+ case 180:
+ break;
+ case 270:
+ x -= text_width*opc->scale;
+ break;
+ case 0:
+ default:
+ break;
} */
cairo_save (cr);
- cairo_move_to (cr, x, y);
- cairo_show_text (cr, text);
+ cairo_move_to (cr, x, y);
+ cairo_show_text (cr, text);
cairo_restore (cr);
g_free (text);
}
diff --git a/src/model/part.h b/src/model/part.h
index 3d267b0..7a9f7c7 100644
--- a/src/model/part.h
+++ b/src/model/part.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
*
* This program is free software; you can redistribute it and/or
@@ -27,8 +29,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_H
@@ -36,14 +38,14 @@
#include <gtk/gtk.h>
-#include "sheet-pos.h"
+#include "coords.h"
#include "clipboard.h"
#include "load-common.h"
-#define TYPE_PART (part_get_type())
-#define PART(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PART, Part))
-#define PART_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PART, PartClass))
-#define IS_PART(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PART))
+#define TYPE_PART (part_get_type ())
+#define PART(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PART, Part))
+#define PART_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PART, PartClass))
+#define IS_PART(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PART))
#define IS_PART_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), TYPE_PART, PartClass))
typedef struct _Part Part;
@@ -53,8 +55,9 @@ typedef struct _PartPriv PartPriv;
#include "item-data.h"
-struct _Pin {
- SheetPos offset;
+struct _Pin
+{
+ Coords offset;
guint pin_nr;
gint node_nr; // Node number into the netlist
Part *part;
@@ -62,30 +65,32 @@ struct _Pin {
#define PIN(x) ((Pin *)(x))
-struct _Part {
- ItemData parent;
- PartPriv * priv;
+struct _Part
+{
+ ItemData parent;
+ PartPriv *priv;
};
struct _PartClass
{
ItemDataClass parent_class;
- void (*changed) ();
+ void (*changed)();
};
-GType part_get_type (void);
-Part * part_new (void);
-Part * part_new_from_library_part (LibraryPart *library_part);
-int part_get_num_pins (Part *part);
-Pin * part_get_pins (Part *part);
-int part_set_pins (Part *part, GSList *connections);
-int part_get_rotation (Part *part);
-IDFlip part_get_flip (Part *part);
-void part_labels_rotate (Part *part, int rotation);
-char * part_get_property (Part *part, char *name);
-GSList * part_get_properties (Part *part);
-GSList * part_get_labels (Part *part);
+GType part_get_type (void);
+Part *part_new ();
+Part *part_new_from_library_part (LibraryPart *library_part);
+gint part_get_num_pins (Part *part);
+Pin *part_get_pins (Part *part);
+gboolean part_set_pins (Part *part, GSList *connections);
+gboolean part_get_rotation (Part *part);
+IDFlip part_get_flip (Part *part);
+void part_labels_rotate (Part *part, int rotation);
+char **part_get_property_ref (Part *part, char *name);
+char *part_get_property (Part *part, char *name);
+GSList *part_get_properties (Part *part);
+GSList *part_get_labels (Part *part);
ClipboardData *part_clipboard_dup (Part *part);
diff --git a/src/model/schematic-print-context.h b/src/model/schematic-print-context.h
index 60ee322..84b67a4 100644
--- a/src/model/schematic-print-context.h
+++ b/src/model/schematic-print-context.h
@@ -1,15 +1,18 @@
/*
* schematic-print-context.h
*
+ *
* Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,23 +26,25 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _SCHEMATIC_PRINT_CONTEXT_
#define _SCHEMATIC_PRINT_CONTEXT_
#include <gdk/gdk.h>
-typedef struct _SchematicColors {
- GdkColor components;
- GdkColor labels;
- GdkColor wires;
- GdkColor text;
- GdkColor background;
+typedef struct _SchematicColors
+{
+ GdkRGBA components;
+ GdkRGBA labels;
+ GdkRGBA wires;
+ GdkRGBA text;
+ GdkRGBA background;
} SchematicColors;
-typedef struct _SchematicPrintContext {
+typedef struct _SchematicPrintContext
+{
SchematicColors colors;
} SchematicPrintContext;
diff --git a/src/model/schematic.c b/src/model/schematic.c
index 7329441..2cf6294 100644
--- a/src/model/schematic.c
+++ b/src/model/schematic.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
@@ -40,13 +44,15 @@
#include "node-store.h"
#include "file-manager.h"
#include "settings.h"
-#include "sim-settings.h"
+#include "../sim-settings-gui.h"
#include "simulation.h"
#include "errors.h"
#include "schematic-print-context.h"
+#include "log.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-typedef struct _SchematicsPrintOptions {
+#include "debug.h"
+typedef struct _SchematicsPrintOptions
+{
GtkColorButton *components;
GtkColorButton *labels;
GtkColorButton *wires;
@@ -54,49 +60,41 @@ typedef struct _SchematicsPrintOptions {
GtkColorButton *background;
} SchematicPrintOptions;
-struct _SchematicPriv {
- char *title;
- char *filename;
- char *author;
- char *comments;
- char *netlist_filename;
+struct _SchematicPriv
+{
+ char *oregano_version;
+ char *title;
+ char *filename;
+ char *author;
+ char *comments;
+ char *netlist_filename;
- SchematicColors colors;
- SchematicPrintOptions *printoptions;
+ SchematicColors colors;
+ SchematicPrintOptions *printoptions;
// Data for various dialogs.
- gpointer settings;
- gpointer sim_settings;
- gpointer simulation;
+ gpointer settings;
+ SimSettingsGui *sim_settings;
+ gpointer simulation;
- GList *current_items;
+ GList *current_items;
- NodeStore *store;
- GHashTable *symbols;
- GHashTable *refdes_values;
+ NodeStore *store;
+ GHashTable *symbols;
+ GHashTable *refdes_values;
- double zoom;
+ guint width;
+ guint height;
- gboolean dirty;
+ double zoom;
- GtkTextBuffer *log;
- GtkTextTag *tag_error;
-};
+ gboolean dirty;
+
+ Log *logstore;
-typedef enum {
- REFDATA_SINGLE,
- REFDATA_RANGE,
- REFDATA_MIN,
- REFDATA_MAX
-} RefDataType;
-
-typedef struct {
- RefDataType type;
- union {
- int nr;
- struct { int min; int max; } range;
- } u;
-} RefData;
+ GtkTextBuffer *log;
+ GtkTextTag *tag_error;
+};
enum {
TITLE_CHANGED,
@@ -108,88 +106,66 @@ enum {
LAST_SIGNAL
};
-G_DEFINE_TYPE (Schematic, schematic, G_TYPE_OBJECT)
+G_DEFINE_TYPE (Schematic, schematic, G_TYPE_OBJECT);
static void schematic_init (Schematic *schematic);
-static void schematic_class_init (SchematicClass *klass);
+static void schematic_class_init (SchematicClass *klass);
static void schematic_finalize (GObject *object);
static void schematic_dispose (GObject *object);
static void item_data_destroy_callback (gpointer s, GObject *data);
-static void item_moved_callback (ItemData *data, SheetPos *pos, Schematic *sm);
+static void item_moved_callback (ItemData *data, Coords *pos, Schematic *sm);
-static int schematic_get_lowest_available_refdes (Schematic *schematic,
- char *prefix);
-static void schematic_set_lowest_available_refdes (Schematic *schematic,
- char *prefix, int num);
+static int schematic_get_lowest_available_refdes (Schematic *schematic, char *prefix);
+static void schematic_set_lowest_available_refdes (Schematic *schematic, char *prefix, int num);
static GObjectClass *parent_class = NULL;
-static guint schematic_signals[LAST_SIGNAL] = { 0 };
+static guint schematic_signals[LAST_SIGNAL] = {0};
static GList *schematic_list = NULL;
static int schematic_count_ = 0;
-static void
-schematic_class_init (SchematicClass *klass)
+static void schematic_class_init (SchematicClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
- schematic_signals[TITLE_CHANGED] = g_signal_new ("title_changed",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, title_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1,
- G_TYPE_STRING );
-
- schematic_signals[LAST_SCHEMATIC_DESTROYED] = g_signal_new ("last_schematic_destroyed",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, last_schematic_destroyed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- schematic_signals[ITEM_DATA_ADDED] = g_signal_new ("item_data_added",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, item_data_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- schematic_signals[NODE_DOT_ADDED] = g_signal_new ("node_dot_added",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, node_dot_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1,
- G_TYPE_POINTER);
-
- schematic_signals[NODE_DOT_REMOVED] = g_signal_new ("node_dot_removed",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, node_dot_removed),
- NULL, NULL, g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- schematic_signals[LOG_UPDATED] = g_signal_new ("log_updated",
- TYPE_SCHEMATIC,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicClass, log_updated),
- NULL, NULL, g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,0);
+ schematic_signals[TITLE_CHANGED] =
+ g_signal_new ("title_changed", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, title_changed), NULL, NULL,
+ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ schematic_signals[LAST_SCHEMATIC_DESTROYED] =
+ g_signal_new ("last_schematic_destroyed", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, last_schematic_destroyed), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ schematic_signals[ITEM_DATA_ADDED] =
+ g_signal_new ("item_data_added", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, item_data_added), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ schematic_signals[NODE_DOT_ADDED] =
+ g_signal_new ("node_dot_added", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, node_dot_added), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ schematic_signals[NODE_DOT_REMOVED] =
+ g_signal_new ("node_dot_removed", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, node_dot_removed), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ schematic_signals[LOG_UPDATED] =
+ g_signal_new ("log_updated", TYPE_SCHEMATIC, G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicClass, log_updated), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
object_class->finalize = schematic_finalize;
object_class->dispose = schematic_dispose;
}
-static void
-node_dot_added_callback (NodeStore *store, SheetPos *pos, Schematic *schematic)
+static void node_dot_added_callback (NodeStore *store, Coords *pos, Schematic *schematic)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -197,8 +173,7 @@ node_dot_added_callback (NodeStore *store, SheetPos *pos, Schematic *schematic)
g_signal_emit_by_name (schematic, "node_dot_added", pos);
}
-static void
-node_dot_removed_callback (NodeStore *store, SheetPos *pos, Schematic *schematic)
+static void node_dot_removed_callback (NodeStore *store, Coords *pos, Schematic *schematic)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -206,8 +181,7 @@ node_dot_removed_callback (NodeStore *store, SheetPos *pos, Schematic *schematic
g_signal_emit_by_name (schematic, "node_dot_removed", pos);
}
-static void
-schematic_init (Schematic *schematic)
+static void schematic_init (Schematic *schematic)
{
SchematicPriv *priv;
@@ -215,49 +189,52 @@ schematic_init (Schematic *schematic)
priv->printoptions = NULL;
// Colors
- priv->colors.components.red = 65535;
+ priv->colors.components.red = 1.0;
priv->colors.components.green = 0;
priv->colors.components.blue = 0;
+ priv->colors.components.alpha = 1.0;
priv->colors.labels.red = 0;
- priv->colors.labels.green = 35723;
- priv->colors.labels.blue = 35723;
+ priv->colors.labels.green = 0.5451;
+ priv->colors.labels.blue = 0.5451;
+ priv->colors.labels.alpha = 1.0;
priv->colors.wires.red = 0;
priv->colors.wires.green = 0;
- priv->colors.wires.blue = 65535;
- priv->colors.text.red = 0;
- priv->colors.text.green = 0;
- priv->colors.text.blue = 0;
+ priv->colors.wires.blue = 1.0;
+ priv->colors.wires.alpha = 1.0;
+ priv->colors.text.red = 1.0;
+ priv->colors.text.green = 1.0;
+ priv->colors.text.blue = 1.0;
+ priv->colors.text.alpha = 1.0;
priv->symbols = g_hash_table_new (g_str_hash, g_str_equal);
priv->refdes_values = g_hash_table_new (g_str_hash, g_str_equal);
priv->store = node_store_new ();
+ priv->width = 0;
+ priv->height = 0;
priv->dirty = FALSE;
- priv->log = gtk_text_buffer_new (NULL);
- priv->tag_error = gtk_text_buffer_create_tag (priv->log, "error",
- "foreground", "red",
- "weight", PANGO_WEIGHT_BOLD,
- NULL);
+ priv->logstore = log_new ();
+ priv->log = gtk_text_buffer_new (NULL); // LEGACY
+ priv->tag_error = gtk_text_buffer_create_tag (priv->log, "error", "foreground", "red", "weight",
+ PANGO_WEIGHT_BOLD, NULL);
- g_signal_connect_object (priv->store, "node_dot_added",
- G_CALLBACK (node_dot_added_callback), G_OBJECT (schematic),
- G_CONNECT_AFTER);
+ g_signal_connect_object (priv->store, "node_dot_added", G_CALLBACK (node_dot_added_callback),
+ G_OBJECT (schematic), G_CONNECT_AFTER);
g_signal_connect_object (priv->store, "node_dot_removed",
- G_CALLBACK (node_dot_removed_callback), G_OBJECT (schematic),
- G_CONNECT_AFTER);
+ G_CALLBACK (node_dot_removed_callback), G_OBJECT (schematic),
+ G_CONNECT_AFTER);
- priv->sim_settings = sim_settings_new (schematic);
+ priv->sim_settings = sim_settings_gui_new (schematic);
priv->settings = settings_new (schematic);
- priv->simulation = simulation_new (schematic);
+ priv->simulation = simulation_new (schematic, priv->logstore);
priv->filename = NULL;
priv->netlist_filename = NULL;
- priv->author = g_strdup ("");
+ priv->author = g_strdup (g_get_user_name ());
priv->comments = g_strdup ("");
}
-Schematic *
-schematic_new (void)
+Schematic *schematic_new (void)
{
Schematic *schematic;
@@ -269,8 +246,7 @@ schematic_new (void)
return schematic;
}
-static void
-schematic_dispose (GObject *object)
+static void schematic_dispose (GObject *object)
{
Schematic *schematic;
GList *list;
@@ -278,11 +254,11 @@ schematic_dispose (GObject *object)
schematic = SCHEMATIC (object);
// Disconnect weak item signal
- for (list=schematic->priv->current_items; list; list=list->next)
- g_object_weak_unref (G_OBJECT (list->data),
- item_data_destroy_callback, G_OBJECT (schematic));
+ for (list = schematic->priv->current_items; list; list = list->next)
+ g_object_weak_unref (G_OBJECT (list->data), item_data_destroy_callback,
+ G_OBJECT (schematic));
- g_object_unref (G_OBJECT (schematic->priv->log));
+ g_clear_object (&schematic->priv->log);
schematic_count_--;
schematic_list = g_list_remove (schematic_list, schematic);
@@ -296,31 +272,29 @@ schematic_dispose (GObject *object)
G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (schematic));
}
-static void
-schematic_finalize (GObject *object)
+static void schematic_finalize (GObject *object)
{
- Schematic *sm;
-
- sm = SCHEMATIC (object);
- if (sm->priv) {
- g_free (sm->priv->simulation);
- g_hash_table_destroy (sm->priv->symbols);
- g_hash_table_destroy (sm->priv->refdes_values);
- if (sm->priv->netlist_filename)
- g_free (sm->priv->netlist_filename);
-
- g_free (sm->priv);
- sm->priv = NULL;
+ Schematic *sm = SCHEMATIC (object);
+ SchematicPriv *priv = sm->priv;
+ if (priv) {
+ g_free (priv->simulation);
+ g_hash_table_destroy (priv->symbols);
+ g_hash_table_destroy (priv->refdes_values);
+ g_clear_object (&priv->store);
+ g_clear_object (&priv->logstore);
+ g_free (priv->netlist_filename);
+ g_free (priv->comments);
+ g_free (priv->author);
+ g_free (priv->filename);
+ g_free (priv->settings);
+ sim_settings_gui_finalize(priv->sim_settings);
+ g_free (priv);
}
G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (sm));
}
-// Get/set functions.
-// ***************** /
-
-char *
-schematic_get_title (Schematic *schematic)
+char *schematic_get_title (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -328,8 +302,7 @@ schematic_get_title (Schematic *schematic)
return schematic->priv->title;
}
-char *
-schematic_get_author (Schematic *schematic)
+char *schematic_get_author (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -337,8 +310,15 @@ schematic_get_author (Schematic *schematic)
return schematic->priv->author;
}
-char *
-schematic_get_comments (Schematic *schematic)
+char *schematic_get_version (Schematic *schematic)
+{
+ g_return_val_if_fail (schematic != NULL, NULL);
+ g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
+
+ return schematic->priv->oregano_version;
+}
+
+char *schematic_get_comments (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -346,47 +326,54 @@ schematic_get_comments (Schematic *schematic)
return schematic->priv->comments;
}
-void
-schematic_set_title (Schematic *schematic, const gchar *title)
+void schematic_set_title (Schematic *schematic, const gchar *title)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- if (!title) return;
+ if (!title)
+ return;
- if (schematic->priv->title)
- g_free (schematic->priv->title);
+ g_free (schematic->priv->title);
schematic->priv->title = g_strdup (title);
g_signal_emit_by_name (schematic, "title_changed", schematic->priv->title);
}
-void
-schematic_set_author (Schematic *schematic, const gchar *author)
+void schematic_set_author (Schematic *schematic, const gchar *author)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- if (!author) return;
+ if (!author)
+ return;
- if (schematic->priv->author)
- g_free (schematic->priv->author);
+ g_free (schematic->priv->author);
schematic->priv->author = g_strdup (author);
}
-void
-schematic_set_comments (Schematic *schematic, const gchar *comments)
+void schematic_set_version (Schematic *schematic, const gchar *oregano_version)
+{
+ g_return_if_fail (schematic != NULL);
+ g_return_if_fail (IS_SCHEMATIC (schematic));
+
+ if (!oregano_version)
+ return;
+
+ g_free (schematic->priv->oregano_version);
+ schematic->priv->oregano_version = g_strdup (oregano_version);
+}
+
+void schematic_set_comments (Schematic *schematic, const gchar *comments)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- if (schematic->priv->comments)
- g_free (schematic->priv->comments);
+ g_free (schematic->priv->comments);
schematic->priv->comments = g_strdup (comments);
}
-char *
-schematic_get_filename (Schematic *schematic)
+char *schematic_get_filename (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -394,8 +381,7 @@ schematic_get_filename (Schematic *schematic)
return schematic->priv->filename;
}
-void
-schematic_set_filename (Schematic *schematic, const gchar *filename)
+void schematic_set_filename (Schematic *schematic, const gchar *filename)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -404,8 +390,7 @@ schematic_set_filename (Schematic *schematic, const gchar *filename)
schematic->priv->filename = g_strdup (filename);
}
-char *
-schematic_get_netlist_filename (Schematic *schematic)
+char *schematic_get_netlist_filename (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -413,20 +398,49 @@ schematic_get_netlist_filename (Schematic *schematic)
return schematic->priv->netlist_filename;
}
-void
-schematic_set_netlist_filename (Schematic *schematic, char *filename)
+void schematic_set_netlist_filename (Schematic *schematic, char *filename)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- if (schematic->priv->netlist_filename)
- g_free (schematic->priv->netlist_filename);
+ g_free (schematic->priv->netlist_filename);
schematic->priv->netlist_filename = g_strdup (filename);
}
-double
-schematic_get_zoom (Schematic *schematic)
+guint schematic_get_width (const Schematic *schematic)
+{
+ g_return_val_if_fail (schematic != NULL, 0.);
+ g_return_val_if_fail (IS_SCHEMATIC (schematic), 0.);
+
+ return schematic->priv->width;
+}
+
+void schematic_set_width (Schematic *schematic, const guint width)
+{
+ g_return_if_fail (schematic != NULL);
+ g_return_if_fail (IS_SCHEMATIC (schematic));
+
+ schematic->priv->width = width;
+}
+
+guint schematic_get_height (const Schematic *schematic)
+{
+ g_return_val_if_fail (schematic != NULL, 0.);
+ g_return_val_if_fail (IS_SCHEMATIC (schematic), 0.);
+
+ return schematic->priv->height;
+}
+
+void schematic_set_height (Schematic *schematic, const guint height)
+{
+ g_return_if_fail (schematic != NULL);
+ g_return_if_fail (IS_SCHEMATIC (schematic));
+
+ schematic->priv->height = height;
+}
+
+double schematic_get_zoom (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, 1.0);
g_return_val_if_fail (IS_SCHEMATIC (schematic), 1.0);
@@ -434,8 +448,7 @@ schematic_get_zoom (Schematic *schematic)
return schematic->priv->zoom;
}
-void
-schematic_set_zoom (Schematic *schematic, double zoom)
+void schematic_set_zoom (Schematic *schematic, double zoom)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -443,8 +456,7 @@ schematic_set_zoom (Schematic *schematic, double zoom)
schematic->priv->zoom = zoom;
}
-NodeStore *
-schematic_get_store (Schematic *schematic)
+NodeStore *schematic_get_store (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -452,8 +464,7 @@ schematic_get_store (Schematic *schematic)
return schematic->priv->store;
}
-gpointer
-schematic_get_settings (Schematic *schematic)
+gpointer schematic_get_settings (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -461,8 +472,15 @@ schematic_get_settings (Schematic *schematic)
return schematic->priv->settings;
}
-gpointer
-schematic_get_sim_settings (Schematic *schematic)
+SimSettings *schematic_get_sim_settings (Schematic *schematic)
+{
+ g_return_val_if_fail (schematic != NULL, NULL);
+ g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
+
+ return schematic->priv->sim_settings->sim_settings;
+}
+
+SimSettingsGui *schematic_get_sim_settings_gui (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -470,8 +488,7 @@ schematic_get_sim_settings (Schematic *schematic)
return schematic->priv->sim_settings;
}
-gpointer
-schematic_get_simulation (Schematic *schematic)
+gpointer schematic_get_simulation (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -479,19 +496,26 @@ schematic_get_simulation (Schematic *schematic)
return schematic->priv->simulation;
}
-void
-schematic_log_append (Schematic *schematic, const char *message)
+Log *schematic_get_log_store (Schematic *schematic)
+{
+ g_return_val_if_fail (schematic != NULL, NULL);
+ g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
+
+ return schematic->priv->logstore;
+}
+
+void schematic_log_append (Schematic *schematic, const char *message)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- gtk_text_buffer_insert_at_cursor (
- schematic->priv->log,
- message, strlen (message));
+ log_append (schematic->priv->logstore, "Schematic Info", message);
+
+ // LEGACY
+ gtk_text_buffer_insert_at_cursor (schematic->priv->log, message, strlen (message));
}
-void
-schematic_log_append_error (Schematic *schematic, const char *message)
+void schematic_log_append_error (Schematic *schematic, const char *message)
{
GtkTextIter iter;
SchematicPriv *priv;
@@ -501,13 +525,14 @@ schematic_log_append_error (Schematic *schematic, const char *message)
priv = schematic->priv;
+ log_append (schematic->priv->logstore, "simulation engine Error", message);
+
+ // LEGACY
gtk_text_buffer_get_end_iter (priv->log, &iter);
- gtk_text_buffer_insert_with_tags (priv->log, &iter, message,
- -1, priv->tag_error, NULL);
+ gtk_text_buffer_insert_with_tags (priv->log, &iter, message, -1, priv->tag_error, NULL);
}
-void
-schematic_log_show (Schematic *schematic)
+void schematic_log_show (Schematic *schematic)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -515,18 +540,15 @@ schematic_log_show (Schematic *schematic)
g_signal_emit_by_name (schematic, "log_updated", schematic->priv->log);
}
-void
-schematic_log_clear (Schematic *schematic)
+void schematic_log_clear (Schematic *schematic)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
- gtk_text_buffer_set_text (
- schematic->priv->log, "", -1);
+ gtk_text_buffer_set_text (schematic->priv->log, "", -1);
}
-GtkTextBuffer*
-schematic_get_log_text (Schematic *schematic)
+GtkTextBuffer *schematic_get_log_text (Schematic *schematic)
{
g_return_val_if_fail (schematic != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
@@ -534,75 +556,56 @@ schematic_get_log_text (Schematic *schematic)
return schematic->priv->log;
}
-int
-schematic_count (void)
-{
- return schematic_count_;
-}
+int schematic_count (void) { return schematic_count_; }
-Schematic *
-schematic_read (char *name, GError **out_error)
+Schematic *schematic_read (const char *name, GError **error)
{
Schematic *new_sm;
- int ret;
- char *fname;
- GError *error = NULL;
+ const char *fname;
+ GError *e = NULL;
FileType *ft;
g_return_val_if_fail (name != NULL, NULL);
- fname = g_filename_from_uri (name, NULL, &error);
+ fname = g_filename_from_uri (name, NULL, &e);
if (!fname) {
fname = name;
- if (error) {
- g_error_free (error);
- error = NULL;
- }
+ g_clear_error (&e);
}
if (!g_file_test (fname, G_FILE_TEST_EXISTS)) {
- g_set_error (out_error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
- _("File %s does not exists."), fname);
+ g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
+ _ ("File %s does not exist."), fname);
return NULL;
}
// Get File Handler
ft = file_manager_get_handler (fname);
if (ft == NULL) {
- g_set_error (out_error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
- _("Unknown file format for %s."), fname);
+ g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
+ _ ("Unknown file format for %s."), fname);
return NULL;
}
new_sm = schematic_new ();
- /* TODO : Add GError-like error reporting! */
- ret = ft->load_func (new_sm, fname, &error);
-
- if (error != NULL) {
- g_propagate_error (out_error, error);
- g_object_unref (G_OBJECT (new_sm));
+ ft->load_func (new_sm, fname, &e);
+ if (e) {
+ g_propagate_error (error, e);
+ g_clear_object (&new_sm);
return NULL;
}
- if (ret) {
- g_object_unref (G_OBJECT (new_sm));
- new_sm = NULL;
- g_set_error (out_error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
- _("Load fails!."));
- }
- else
- schematic_set_dirty (new_sm, FALSE);
+ schematic_set_dirty (new_sm, FALSE);
return new_sm;
}
-gint
-schematic_save_file (Schematic *sm, GError **error)
+gint schematic_save_file (Schematic *sm, GError **error)
{
FileType *ft;
- GError *internal_error = NULL;
+ GError *e = NULL;
g_return_val_if_fail (sm != NULL, FALSE);
@@ -610,44 +613,52 @@ schematic_save_file (Schematic *sm, GError **error)
if (ft == NULL) {
g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_FILE_NOT_FOUND,
- _("Unknown file format for %s."), schematic_get_filename (sm));
+ _ ("Unknown file format for %s."), schematic_get_filename (sm));
return FALSE;
}
- if (ft->save_func (sm, &internal_error)) {
+ if (ft->save_func (sm, &e)) {
schematic_set_title (sm, g_path_get_basename (sm->priv->filename));
schematic_set_dirty (sm, FALSE);
return TRUE;
}
- g_propagate_error (error, internal_error);
+ g_propagate_error (error, e);
- g_error_free (internal_error);
return FALSE; // Save fails!
}
-void
-schematic_add_item (Schematic *sm, ItemData *data)
+/**
+ * \brief add an ItemData object to a Schematic
+ *
+ * @param sm the schematic the item will be added to
+ * @param data fully initilalized ItemData object
+ */
+void schematic_add_item (Schematic *sm, ItemData *data)
{
NodeStore *store;
char *prefix = NULL, *refdes = NULL;
int num;
- g_return_if_fail (sm != NULL);
+ g_return_if_fail (sm);
g_return_if_fail (IS_SCHEMATIC (sm));
- g_return_if_fail (data != NULL);
+ g_return_if_fail (data);
g_return_if_fail (IS_ITEM_DATA (data));
store = sm->priv->store;
- g_object_set (G_OBJECT (data),
- "store", store,
- NULL);
-
- if (item_data_register (data) == -1)
- // Item does not be added
+ g_assert (store);
+ g_assert (IS_NODE_STORE (store));
+
+ g_object_set (G_OBJECT (data), "store", store, NULL);
+
+ // item data will call the child register function
+ // for parts e.g. this ends up in <node_store_add_part>
+ // which requires a valid position to add the node dots
+ if (item_data_register (data) == -1) {
return;
+ }
- // Some items need a reference designator. Find a good one.
+ // Some items need a reference designator, so get a good one
prefix = item_data_get_refdes_prefix (data);
if (prefix != NULL) {
num = schematic_get_lowest_available_refdes (sm, prefix);
@@ -660,21 +671,18 @@ schematic_add_item (Schematic *sm, ItemData *data)
g_free (refdes);
sm->priv->current_items = g_list_prepend (sm->priv->current_items, data);
- g_object_weak_ref (G_OBJECT (data), item_data_destroy_callback,
- G_OBJECT (sm));
-
- g_signal_connect_object (data, "moved", G_CALLBACK (item_moved_callback),
- sm, 0);
+ g_object_weak_ref (G_OBJECT (data), item_data_destroy_callback, G_OBJECT (sm));
sm->priv->dirty = TRUE;
- g_signal_emit_by_name (sm,
- "item_data_added", data);
+ // if the item gets moved mark the schematic as dirty
+ g_signal_connect_object (data, "moved", G_CALLBACK (item_moved_callback), sm, 0);
+
+ // causes a canvas item (view) to be generated
+ g_signal_emit_by_name (sm, "item_data_added", data);
}
-void
-schematic_parts_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data)
+void schematic_parts_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data)
{
GList *list;
@@ -687,12 +695,9 @@ schematic_parts_foreach (Schematic *schematic,
for (list = node_store_get_parts (schematic->priv->store); list; list = list->next) {
func (list->data, user_data);
}
- g_list_free_full (list, g_object_unref);
}
-void
-schematic_wires_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data)
+void schematic_wires_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data)
{
GList *list;
@@ -705,12 +710,9 @@ schematic_wires_foreach (Schematic *schematic,
for (list = node_store_get_wires (schematic->priv->store); list; list = list->next) {
func (list->data, user_data);
}
- g_list_free_full (list, g_object_unref);
}
-void
-schematic_items_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data)
+void schematic_items_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data)
{
GList *list;
@@ -723,11 +725,9 @@ schematic_items_foreach (Schematic *schematic,
for (list = schematic->priv->current_items; list; list = list->next) {
func (list->data, user_data);
}
- g_list_free_full (list, g_object_unref);
}
-GList *
-schematic_get_items (Schematic *sm)
+GList *schematic_get_items (Schematic *sm)
{
g_return_val_if_fail (sm != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC (sm), NULL);
@@ -735,8 +735,7 @@ schematic_get_items (Schematic *sm)
return sm->priv->current_items;
}
-static void
-item_data_destroy_callback (gpointer s, GObject *data)
+static void item_data_destroy_callback (gpointer s, GObject *data)
{
Schematic *sm = SCHEMATIC (s);
schematic_set_dirty (sm, TRUE);
@@ -745,8 +744,7 @@ item_data_destroy_callback (gpointer s, GObject *data)
}
}
-static int
-schematic_get_lowest_available_refdes (Schematic *schematic, char *prefix)
+static int schematic_get_lowest_available_refdes (Schematic *schematic, char *prefix)
{
gpointer key, value;
@@ -754,18 +752,14 @@ schematic_get_lowest_available_refdes (Schematic *schematic, char *prefix)
g_return_val_if_fail (IS_SCHEMATIC (schematic), -1);
g_return_val_if_fail (prefix != NULL, -1);
- if ( g_hash_table_lookup_extended (schematic->priv->refdes_values,
- prefix, &key, &value) ) {
+ if (g_hash_table_lookup_extended (schematic->priv->refdes_values, prefix, &key, &value)) {
return GPOINTER_TO_INT (value);
- }
- else {
+ } else {
return 1;
}
}
-static void
-schematic_set_lowest_available_refdes (Schematic *schematic,
- char *prefix, int num)
+static void schematic_set_lowest_available_refdes (Schematic *schematic, char *prefix, int num)
{
gpointer key, value;
@@ -775,16 +769,13 @@ schematic_set_lowest_available_refdes (Schematic *schematic,
// If there already is a key, use it, otherwise copy the prefix and
// use as key.
- if (!g_hash_table_lookup_extended (schematic->priv->refdes_values,
- prefix, &key, &value))
+ if (!g_hash_table_lookup_extended (schematic->priv->refdes_values, prefix, &key, &value))
key = g_strdup (prefix);
- g_hash_table_insert (schematic->priv->refdes_values,
- key, GINT_TO_POINTER (num));
+ g_hash_table_insert (schematic->priv->refdes_values, key, GINT_TO_POINTER (num));
}
-gboolean
-schematic_is_dirty (Schematic *sm)
+gboolean schematic_is_dirty (Schematic *sm)
{
g_return_val_if_fail (sm != NULL, FALSE);
g_return_val_if_fail (IS_SCHEMATIC (sm), FALSE);
@@ -792,8 +783,7 @@ schematic_is_dirty (Schematic *sm)
return sm->priv->dirty;
}
-void
-schematic_set_dirty (Schematic *sm, gboolean b)
+void schematic_set_dirty (Schematic *sm, gboolean b)
{
g_return_if_fail (sm != NULL);
g_return_if_fail (IS_SCHEMATIC (sm));
@@ -801,8 +791,7 @@ schematic_set_dirty (Schematic *sm, gboolean b)
sm->priv->dirty = b;
}
-static void
-item_moved_callback (ItemData *data, SheetPos *pos, Schematic *sm)
+static void item_moved_callback (ItemData *data, Coords *pos, Schematic *sm)
{
g_return_if_fail (data != NULL);
g_return_if_fail (IS_ITEM_DATA (data));
@@ -810,35 +799,33 @@ item_moved_callback (ItemData *data, SheetPos *pos, Schematic *sm)
schematic_set_dirty (sm, TRUE);
}
-static void
-schematic_render (Schematic *sm, cairo_t *cr)
+static void schematic_render (Schematic *sm, cairo_t *cr)
{
NodeStore *store;
SchematicPrintContext schematic_print_context;
schematic_print_context.colors = sm->priv->colors;
store = schematic_get_store (sm);
-
+
node_store_print_items (store, cr, &schematic_print_context);
}
-GdkColor
-convert_to_grayscale (GdkColor *source)
+GdkRGBA convert_to_grayscale (GdkRGBA *source)
{
- GdkColor color;
- int factor;
+ GdkRGBA color;
+ gdouble factor;
+
+ factor = source->red * 0.299 + source->green * 0.587 + source->blue * 0.114;
- factor = (source->red + source->green + source->blue)/3;
color.red = factor;
color.green = factor;
color.blue = factor;
- color.pixel = source->pixel;
+ color.alpha = source->alpha;
return color;
}
-void
-schematic_export (Schematic *sm, const gchar *filename,
- gint img_w, gint img_h, int bg, int color, int format)
+void schematic_export (Schematic *sm, const gchar *filename, gint img_w, gint img_h, int bg,
+ int color, int format)
{
NodeRect bbox;
NodeStore *store;
@@ -862,36 +849,36 @@ schematic_export (Schematic *sm, const gchar *filename,
switch (format) {
#ifdef CAIRO_HAS_SVG_SURFACE
- case 0:
- surface = cairo_svg_surface_create (filename, img_w, img_h);
+ case 0:
+ surface = cairo_svg_surface_create (filename, img_w, img_h);
break;
#endif
#ifdef CAIRO_HAS_PDF_SURFACE
- case 1:
- surface = cairo_pdf_surface_create (filename, img_w, img_h);
+ case 1:
+ surface = cairo_pdf_surface_create (filename, img_w, img_h);
break;
#endif
#ifdef CAIRO_HAS_PS_SURFACE
- case 2:
- surface = cairo_ps_surface_create (filename, img_w, img_h);
+ case 2:
+ surface = cairo_ps_surface_create (filename, img_w, img_h);
break;
#endif
- default:
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, img_w, img_h);
+ default:
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, img_w, img_h);
}
cr = cairo_create (surface);
// Background
switch (bg) {
- case 1: // White
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_rectangle (cr, 0, 0, img_w, img_h);
- cairo_fill (cr);
- break;
- case 2: // Black
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, 0, 0, img_w, img_h);
- cairo_fill (cr);
+ case 1: // White
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_rectangle (cr, 0, 0, img_w, img_h);
+ cairo_fill (cr);
+ break;
+ case 2: // Black
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_rectangle (cr, 0, 0, img_w, img_h);
+ cairo_fill (cr);
}
graph_w = img_w * 0.8;
@@ -905,8 +892,8 @@ schematic_export (Schematic *sm, const gchar *filename,
// Preparing...
cairo_save (cr);
- cairo_translate (cr, (img_w - graph_w)/2.0, (img_h - graph_h) / 2.0);
- cairo_scale (cr, scale, scale);
+ cairo_translate (cr, (img_w - graph_w) / 2.0, (img_h - graph_h) / 2.0);
+ cairo_scale (cr, scale, scale);
cairo_translate (cr, -bbox.x0, -bbox.y0);
cairo_set_line_width (cr, 0.5);
@@ -928,26 +915,24 @@ schematic_export (Schematic *sm, const gchar *filename,
}
}
-static void
-draw_rotule (Schematic *sm, cairo_t *cr)
+static void draw_rotule (Schematic *sm, cairo_t *cr)
{
cairo_save (cr);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_set_line_width (cr, 0.5);
- cairo_rectangle (cr, 0, 0, 180, 20);
- cairo_rectangle (cr, 0, 20, 180, 10);
- cairo_stroke (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_set_line_width (cr, 0.5);
+ cairo_rectangle (cr, 0, 0, 180, 20);
+ cairo_rectangle (cr, 0, 20, 180, 10);
+ cairo_stroke (cr);
cairo_restore (cr);
}
-static void
-draw_page (GtkPrintOperation *operation,
- GtkPrintContext *context, int page_nr, Schematic *sm)
+static void draw_page (GtkPrintOperation *operation, GtkPrintContext *context, int page_nr,
+ Schematic *sm)
{
NodeStore *store;
NodeRect bbox;
gdouble page_w, page_h;
-
+
page_w = gtk_print_context_get_width (context);
page_h = gtk_print_context_get_height (context);
@@ -955,15 +940,15 @@ draw_page (GtkPrintOperation *operation,
// Draw a red rectangle, as wide as the paper (inside the margins)
cairo_save (cr);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_set_line_width (cr, 0.5);
- cairo_rectangle (cr, 20, 10, page_w-30, page_h-20);
- cairo_stroke (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_set_line_width (cr, 0.5);
+ cairo_rectangle (cr, 20, 10, page_w - 30, page_h - 20);
+ cairo_stroke (cr);
cairo_restore (cr);
cairo_save (cr);
- cairo_translate (cr, page_w-190, page_h-40);
- draw_rotule (sm, cr);
+ cairo_translate (cr, page_w - 190, page_h - 40);
+ draw_rotule (sm, cr);
cairo_restore (cr);
store = schematic_get_store (sm);
@@ -971,117 +956,108 @@ draw_page (GtkPrintOperation *operation,
node_store_get_bounds (store, &bbox);
cairo_save (cr);
- cairo_set_line_width (cr, 0.5);
- cairo_set_source_rgb (cr, 0, 0, 0);
- cairo_translate (cr, page_w * 0.1, page_h * 0.1);
- // 0.4 is the convert factor between Model unit and
- // milimeters, unit used in printing
- cairo_scale (cr, 0.4, 0.4);
- cairo_translate (cr, -bbox.x0, -bbox.y0);
- schematic_render (sm, cr);
+ cairo_set_line_width (cr, 0.5);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_translate (cr, page_w * 0.1, page_h * 0.1);
+ // 0.4 is the convert factor between Model unit and
+ // milimeters, unit used in printing
+ cairo_scale (cr, 0.4, 0.4);
+ cairo_translate (cr, -bbox.x0, -bbox.y0);
+ schematic_render (sm, cr);
cairo_restore (cr);
}
-static GObject*
-print_options (GtkPrintOperation *operation, Schematic *sm)
+static GObject *print_options (GtkPrintOperation *operation, Schematic *sm)
{
GtkBuilder *gui;
GError *perror = NULL;
-
- if ((gui = gtk_builder_new ()) == NULL) {
- return G_OBJECT (gtk_label_new (_("Error loading print-options.ui")));
- }
- if (!g_file_test (OREGANO_UIDIR "/print-options.ui", G_FILE_TEST_EXISTS)) {
- return G_OBJECT (gtk_label_new (_("Error loading print-options.ui")));
+ if ((gui = gtk_builder_new ()) == NULL) {
+ return G_OBJECT (gtk_label_new (_ ("Error loading print-options.ui")));
}
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/print-options.ui",
- &perror) <= 0) {
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/print-options.ui", &perror) <= 0) {
g_error_free (perror);
- return G_OBJECT (gtk_label_new (_("Error loading print-options.ui")));
+ return G_OBJECT (gtk_label_new (_ ("Error loading print-options.ui")));
}
- if (sm->priv->printoptions)
- g_free (sm->priv->printoptions);
+ g_free (sm->priv->printoptions);
sm->priv->printoptions = g_new0 (SchematicPrintOptions, 1);
- sm->priv->printoptions->components = GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_components"));
- sm->priv->printoptions->labels = GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_labels"));
- sm->priv->printoptions->wires = GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_wires"));
- sm->priv->printoptions->text = GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_text"));
- sm->priv->printoptions->background = GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_background"));
+ sm->priv->printoptions->components =
+ GTK_COLOR_BUTTON (gtk_builder_get_object (gui, "color_components"));
+ sm->priv->printoptions->labels =
+ GTK_COLOR_BUTTON (gtk_builder_get_object (gui, "color_labels"));
+ sm->priv->printoptions->wires = GTK_COLOR_BUTTON (gtk_builder_get_object (gui, "color_wires"));
+ sm->priv->printoptions->text = GTK_COLOR_BUTTON (gtk_builder_get_object (gui, "color_text"));
+ sm->priv->printoptions->background =
+ GTK_COLOR_BUTTON (gtk_builder_get_object (gui, "color_background"));
// Set default colors
- gtk_color_button_set_color (GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_components")),
- &sm->priv->colors.components);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_labels")),
- &sm->priv->colors.labels);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_wires")),
- &sm->priv->colors.wires);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_text")),
- &sm->priv->colors.text);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (
- gtk_builder_get_object (gui, "color_background")),
- &sm->priv->colors.background);
+ gtk_color_chooser_set_rgba (
+ GTK_COLOR_CHOOSER (gtk_builder_get_object (gui, "color_components")),
+ &sm->priv->colors.components);
+ gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (gtk_builder_get_object (gui, "color_labels")),
+ &sm->priv->colors.labels);
+ gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (gtk_builder_get_object (gui, "color_wires")),
+ &sm->priv->colors.wires);
+ gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (gtk_builder_get_object (gui, "color_text")),
+ &sm->priv->colors.text);
+ gtk_color_chooser_set_rgba (
+ GTK_COLOR_CHOOSER (gtk_builder_get_object (gui, "color_background")),
+ &sm->priv->colors.background);
return gtk_builder_get_object (gui, "widget");
}
-static void
-read_print_options (GtkPrintOperation *operation, GtkWidget *widget, Schematic *sm)
+static void read_print_options (GtkPrintOperation *operation, GtkWidget *widget, Schematic *sm)
{
SchematicPrintOptions *colors = sm->priv->printoptions;
- gtk_color_button_get_color (colors->components, &sm->priv->colors.components);
- gtk_color_button_get_color (colors->labels, &sm->priv->colors.labels);
- gtk_color_button_get_color (colors->wires, &sm->priv->colors.wires);
- gtk_color_button_get_color (colors->text, &sm->priv->colors.text);
- gtk_color_button_get_color (colors->background, &sm->priv->colors.background);
+ gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colors->components),
+ &sm->priv->colors.components);
+ gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colors->labels), &sm->priv->colors.labels);
+ gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colors->wires), &sm->priv->colors.wires);
+ gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colors->text), &sm->priv->colors.text);
+ gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colors->background),
+ &sm->priv->colors.background);
g_free (sm->priv->printoptions);
sm->priv->printoptions = NULL;
}
-void
-schematic_print (Schematic *sm, GtkPageSetup *page, GtkPrintSettings *settings, gboolean preview)
+void schematic_print (Schematic *sm, GtkPageSetup *page, GtkPrintSettings *settings,
+ gboolean preview)
{
GtkPrintOperation *op;
GtkPrintOperationResult res;
op = gtk_print_operation_new ();
- gtk_print_operation_set_print_settings (op, settings);
+ if (settings != NULL)
+ gtk_print_operation_set_print_settings (op, settings);
gtk_print_operation_set_default_page_setup (op, page);
gtk_print_operation_set_n_pages (op, 1);
gtk_print_operation_set_unit (op, GTK_UNIT_MM);
gtk_print_operation_set_use_full_page (op, TRUE);
- g_signal_connect (op, "create-custom-widget",
- G_CALLBACK (print_options), sm);
- g_signal_connect (op, "custom-widget-apply",
- G_CALLBACK (read_print_options), sm);
- g_signal_connect (op, "draw_page",
- G_CALLBACK (draw_page), sm);
+ g_signal_connect (op, "create-custom-widget", G_CALLBACK (print_options), sm);
+ g_signal_connect (op, "custom-widget-apply", G_CALLBACK (read_print_options), sm);
+ g_signal_connect (op, "draw_page", G_CALLBACK (draw_page), sm);
- gtk_print_operation_set_custom_tab_label (op, _("Schematic"));
+ gtk_print_operation_set_custom_tab_label (op, _ ("Schematic"));
if (preview)
- res = gtk_print_operation_run (op, GTK_PRINT_OPERATION_ACTION_PREVIEW,
- NULL, NULL);
+ res = gtk_print_operation_run (op, GTK_PRINT_OPERATION_ACTION_PREVIEW, NULL, NULL);
else
- res = gtk_print_operation_run (op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
- NULL, NULL);
+ res = gtk_print_operation_run (op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL, NULL);
if (res == GTK_PRINT_OPERATION_RESULT_CANCEL) {
+ } else if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+ if (settings != NULL)
+ g_object_unref (settings);
+ settings = g_object_ref (gtk_print_operation_get_print_settings (op));
}
+
+ g_object_unref (op);
}
diff --git a/src/model/schematic.h b/src/model/schematic.h
index a4f4dab..3637271 100644
--- a/src/model/schematic.h
+++ b/src/model/schematic.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,13 +28,16 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SCHEMATIC_H__
#define __SCHEMATIC_H__
+// typedefing before including makes circular dependencies possible.
+typedef struct _Schematic Schematic;
+
#include <gtk/gtk.h>
#include <cairo/cairo.h>
#include <cairo/cairo-features.h>
@@ -49,74 +54,86 @@
#include "part.h"
#include "wire.h"
#include "node-store.h"
+#include "log.h"
+
+#include "../sim-settings.h"
+#include "sim-settings-gui.h"
-#define TYPE_SCHEMATIC (schematic_get_type ())
-#define SCHEMATIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCHEMATIC, Schematic))
-#define SCHEMATIC_CLASS (klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCHEMATIC, SchematicClass))
-#define IS_SCHEMATIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCHEMATIC))
-#define IS_SCHEMATIC_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCHEMATIC, SchematicClass))
+#define TYPE_SCHEMATIC (schematic_get_type ())
+#define SCHEMATIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCHEMATIC, Schematic))
+#define SCHEMATIC_CLASS (klass)(G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCHEMATIC, SchematicClass))
+#define IS_SCHEMATIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCHEMATIC))
+#define IS_SCHEMATIC_CLASS(klass) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCHEMATIC, SchematicClass))
-typedef struct _Schematic Schematic;
typedef struct _SchematicClass SchematicClass;
-typedef struct _SchematicPriv SchematicPriv;
+typedef struct _SchematicPriv SchematicPriv;
-typedef void (*ForeachItemDataFunc) (ItemData *item_data, gpointer user_data);
+typedef void (*ForeachItemDataFunc)(ItemData *item_data, gpointer user_data);
-struct _Schematic {
+struct _Schematic
+{
GObject parent;
SchematicPriv *priv;
};
-struct _SchematicClass {
+struct _SchematicClass
+{
GObjectClass parent_class;
// signals
- void (*title_changed) (Schematic* ,gchar*);
- void (*item_data_added) (Schematic*, gpointer*);
- void (*log_updated) (gpointer);
- void (*node_dot_added) (Schematic*);
- void (*node_dot_removed) (Schematic*, gpointer*);
- void (*last_schematic_destroyed) (Schematic*);
+ void (*title_changed)(Schematic *, gchar *);
+ void (*item_data_added)(Schematic *, gpointer *);
+ void (*log_updated)(gpointer);
+ void (*node_dot_added)(Schematic *);
+ void (*node_dot_removed)(Schematic *, gpointer *);
+ void (*last_schematic_destroyed)(Schematic *);
};
-GType schematic_get_type (void);
+GType schematic_get_type (void);
Schematic *schematic_new (void);
-char *schematic_get_title (Schematic *schematic);
-void schematic_set_title (Schematic *schematic, const gchar *title);
-char *schematic_get_author (Schematic *schematic);
-void schematic_set_author (Schematic *schematic, const gchar *author);
-char *schematic_get_comments (Schematic *schematic);
-void schematic_set_comments (Schematic *schematic, const gchar *comments);
-char *schematic_get_filename (Schematic *schematic);
-void schematic_set_filename (Schematic *schematic, const gchar *filename);
-char *schematic_get_netlist_filename (Schematic *schematic);
-void schematic_set_netlist_filename (Schematic *schematic, char *filename);
-int schematic_count (void);
-double schematic_get_zoom (Schematic *schematic);
-void schematic_set_zoom (Schematic *schematic, double zoom);
-void schematic_add_item (Schematic *sm, ItemData *data);
-void schematic_parts_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data);
-void schematic_wires_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data);
-void schematic_items_foreach (Schematic *schematic,
- ForeachItemDataFunc func, gpointer user_data);
-GList *schematic_get_items (Schematic *sm);
+char *schematic_get_title (Schematic *schematic);
+void schematic_set_title (Schematic *schematic, const gchar *title);
+char *schematic_get_author (Schematic *schematic);
+void schematic_set_author (Schematic *schematic, const gchar *author);
+char *schematic_get_version (Schematic *schematic);
+void schematic_set_version (Schematic *schematic, const gchar *author);
+char *schematic_get_comments (Schematic *schematic);
+void schematic_set_comments (Schematic *schematic, const gchar *comments);
+char *schematic_get_filename (Schematic *schematic);
+void schematic_set_filename (Schematic *schematic, const gchar *filename);
+char *schematic_get_netlist_filename (Schematic *schematic);
+void schematic_set_netlist_filename (Schematic *schematic, char *filename);
+int schematic_count (void);
+guint schematic_get_width (const Schematic *schematic);
+guint schematic_get_height (const Schematic *schematic);
+double schematic_get_zoom (Schematic *schematic);
+void schematic_set_width (Schematic *schematic, const guint width);
+void schematic_set_height (Schematic *schematic, const guint height);
+void schematic_set_zoom (Schematic *schematic, double zoom);
+void schematic_add_item (Schematic *sm, ItemData *data);
+void schematic_parts_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data);
+void schematic_wires_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data);
+void schematic_items_foreach (Schematic *schematic, ForeachItemDataFunc func, gpointer user_data);
+GList *schematic_get_items (Schematic *sm);
NodeStore *schematic_get_store (Schematic *schematic);
-gpointer schematic_get_settings (Schematic *schematic);
-gpointer schematic_get_sim_settings (Schematic *schematic);
-gpointer schematic_get_simulation (Schematic *schematic);
-void schematic_log_clear (Schematic *schematic);
-void schematic_log_append (Schematic *schematic, const char *message);
-void schematic_log_append_error (Schematic *schematic, const char *message);
-void schematic_log_show (Schematic *schematic);
+gpointer schematic_get_settings (Schematic *schematic);
+SimSettings *schematic_get_sim_settings (Schematic *schematic);
+SimSettingsGui *schematic_get_sim_settings_gui (Schematic *schematic);
+gpointer schematic_get_simulation (Schematic *schematic);
+Log *schematic_get_log_store (Schematic *schematic);
+void schematic_log_clear (Schematic *schematic);
+void schematic_log_append (Schematic *schematic, const char *message);
+void schematic_log_append_error (Schematic *schematic, const char *message);
+void schematic_log_show (Schematic *schematic);
GtkTextBuffer *schematic_get_log_text (Schematic *schematic);
-int schematic_count (void);
-gboolean schematic_is_dirty (Schematic *sm);
-void schematic_set_dirty (Schematic *sm, gboolean b);
-gint schematic_save_file (Schematic *sm, GError **error);
-Schematic *schematic_read (char *fname, GError **error);
-void schematic_print (Schematic *sm, GtkPageSetup *p, GtkPrintSettings *s, gboolean preview);
-void schematic_export (Schematic *sm, const gchar *filename, gint img_w, gint img_h, int bg, int color, int format);
+int schematic_count (void);
+gboolean schematic_is_dirty (Schematic *sm);
+void schematic_set_dirty (Schematic *sm, gboolean b);
+gint schematic_save_file (Schematic *sm, GError **error);
+Schematic *schematic_read (const char *fname, GError **error);
+void schematic_print (Schematic *sm, GtkPageSetup *p, GtkPrintSettings *s, gboolean preview);
+void schematic_export (Schematic *sm, const gchar *filename, gint img_w, gint img_h, int bg,
+ int color, int format);
#endif /* __SCHEMATIC_H__ */
diff --git a/src/model/textbox.c b/src/model/textbox.c
index 8e7a46c..ba41b67 100644
--- a/src/model/textbox.c
+++ b/src/model/textbox.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
@@ -46,34 +46,27 @@ static void textbox_class_init (TextboxClass *klass);
static void textbox_init (Textbox *textbox);
static void textbox_copy (ItemData *dest, ItemData *src);
static ItemData *textbox_clone (ItemData *src);
-static void textbox_rotate (ItemData *data, int angle, SheetPos *center);
+static void textbox_rotate (ItemData *data, int angle, Coords *center);
static void textbox_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
static int textbox_register (ItemData *data);
static void textbox_unregister (ItemData *data);
static gboolean textbox_has_properties (ItemData *data);
-static void textbox_flip (ItemData *data, gboolean horizontal,
- SheetPos *center);
+static void textbox_flip (ItemData *data, IDFlip direction, Coords *center);
+enum { TEXT_CHANGED, FONT_CHANGED, LAST_SIGNAL };
-enum {
- TEXT_CHANGED,
- FONT_CHANGED,
- LAST_SIGNAL
-};
-
-struct _TextboxPriv {
+struct _TextboxPriv
+{
char *text;
char *font;
};
G_DEFINE_TYPE (Textbox, textbox, TYPE_ITEM_DATA)
-static guint textbox_signals[LAST_SIGNAL] = { 0 };
-
+static guint textbox_signals[LAST_SIGNAL] = {0};
-static void
-textbox_finalize (GObject *object)
+static void textbox_finalize (GObject *object)
{
Textbox *textbox = TEXTBOX (object);
TextboxPriv *priv = textbox->priv;
@@ -83,14 +76,12 @@ textbox_finalize (GObject *object)
G_OBJECT_CLASS (textbox_parent_class)->finalize (object);
}
-static void
-textbox_dispose (GObject *object)
+static void textbox_dispose (GObject *object)
{
G_OBJECT_CLASS (textbox_parent_class)->dispose (object);
}
-static void
-textbox_class_init (TextboxClass *klass)
+static void textbox_class_init (TextboxClass *klass)
{
GObjectClass *object_class;
ItemDataClass *item_data_class;
@@ -100,26 +91,14 @@ textbox_class_init (TextboxClass *klass)
object_class = G_OBJECT_CLASS (klass);
textbox_signals[TEXT_CHANGED] =
- g_signal_new ("text_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
+ g_signal_new ("text_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
textbox_signals[FONT_CHANGED] =
- g_signal_new ("font_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- object_class->finalize= textbox_finalize;
+ g_signal_new ("font_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ object_class->finalize = textbox_finalize;
object_class->dispose = textbox_dispose;
item_data_class->clone = textbox_clone;
@@ -132,15 +111,13 @@ textbox_class_init (TextboxClass *klass)
item_data_class->print = textbox_print;
}
-static void
-textbox_init (Textbox *textbox)
+static void textbox_init (Textbox *textbox)
{
TextboxPriv *priv = g_new0 (TextboxPriv, 1);
textbox->priv = priv;
}
-Textbox *
-textbox_new (char *font)
+Textbox *textbox_new (char *font)
{
Textbox *textbox;
@@ -154,8 +131,7 @@ textbox_new (char *font)
return textbox;
}
-static ItemData *
-textbox_clone (ItemData *src)
+static ItemData *textbox_clone (ItemData *src)
{
Textbox *new_textbox;
ItemDataClass *id_class;
@@ -163,7 +139,7 @@ textbox_clone (ItemData *src)
g_return_val_if_fail (src != NULL, NULL);
g_return_val_if_fail (IS_TEXTBOX (src), NULL);
- id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS(src));
+ id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (src));
if (id_class->copy == NULL)
return NULL;
@@ -173,8 +149,7 @@ textbox_clone (ItemData *src)
return ITEM_DATA (new_textbox);
}
-static void
-textbox_copy (ItemData *dest, ItemData *src)
+static void textbox_copy (ItemData *dest, ItemData *src)
{
Textbox *dest_textbox, *src_textbox;
@@ -193,14 +168,13 @@ textbox_copy (ItemData *dest, ItemData *src)
dest_textbox->priv->font = src_textbox->priv->font;
}
-static void
-textbox_rotate (ItemData *data, int angle, SheetPos *center)
+static void textbox_rotate (ItemData *data, int angle, Coords *center)
{
cairo_matrix_t affine;
double x, y;
Textbox *textbox;
- SheetPos b1, b2;
- SheetPos textbox_center, delta;
+ Coords b1, b2;
+ Coords textbox_center, delta;
g_return_if_fail (data != NULL);
g_return_if_fail (IS_TEXTBOX (data));
@@ -216,13 +190,13 @@ textbox_rotate (ItemData *data, int angle, SheetPos *center)
textbox_center.y = b1.y + (b2.y - b1.y) / 2;
}
- cairo_matrix_init_rotate (&affine, (double) angle * M_PI / 180);
+ cairo_matrix_init_rotate (&affine, (double)angle * M_PI / 180);
// Let the views (canvas items) know about the rotation.
g_signal_emit_by_name (G_OBJECT (textbox), "rotated", angle);
if (center) {
- SheetPos textbox_pos;
+ Coords textbox_pos;
item_data_get_pos (ITEM_DATA (textbox), &textbox_pos);
@@ -237,14 +211,13 @@ textbox_rotate (ItemData *data, int angle, SheetPos *center)
}
}
-static void
-textbox_flip (ItemData *data, gboolean horizontal, SheetPos *center)
+static void textbox_flip (ItemData *data, IDFlip direction, Coords *center)
{
cairo_matrix_t affine;
double x, y;
Textbox *textbox;
- SheetPos b1, b2;
- SheetPos textbox_center = {0.0, 0.0}, delta;
+ Coords b1, b2;
+ Coords textbox_center = {0.0, 0.0}, delta;
g_return_if_fail (data != NULL);
g_return_if_fail (IS_TEXTBOX (data));
@@ -257,16 +230,16 @@ textbox_flip (ItemData *data, gboolean horizontal, SheetPos *center)
textbox_center.y = b1.y + (b2.y - b1.y) / 2;
}
- if (horizontal)
+ if (direction == ID_FLIP_HORIZ)
cairo_matrix_init_scale (&affine, -1, 1);
else
cairo_matrix_init_scale (&affine, 1, -1);
// Let the views (canvas items) know about the rotation.
- g_signal_emit_by_name (G_OBJECT (textbox), "flipped", horizontal);
+ g_signal_emit_by_name (G_OBJECT (textbox), "flipped", direction);
if (center) {
- SheetPos textbox_pos;
+ Coords textbox_pos;
item_data_get_pos (ITEM_DATA (textbox), &textbox_pos);
@@ -281,26 +254,20 @@ textbox_flip (ItemData *data, gboolean horizontal, SheetPos *center)
}
}
-void
-textbox_update_bbox (Textbox *textbox)
+void textbox_update_bbox (Textbox *textbox)
{
- SheetPos b1, b2;
+ Coords b1, b2;
b1.x = 0.0;
- b1.y = 0.0-5; // - font->ascent;
- b2.x = 0.0+5; // + rbearing;
- b2.y = 0.0+5; // + font->descent;
+ b1.y = 0.0 - 5; // - font->ascent;
+ b2.x = 0.0 + 5; // + rbearing;
+ b2.y = 0.0 + 5; // + font->descent;
item_data_set_relative_bbox (ITEM_DATA (textbox), &b1, &b2);
}
-static gboolean
-textbox_has_properties (ItemData *data)
-{
- return TRUE;
-}
+static gboolean textbox_has_properties (ItemData *data) { return TRUE; }
-void
-textbox_set_text (Textbox *textbox, const char *text)
+void textbox_set_text (Textbox *textbox, const char *text)
{
g_return_if_fail (textbox != NULL);
g_return_if_fail (IS_TEXTBOX (textbox));
@@ -312,8 +279,7 @@ textbox_set_text (Textbox *textbox, const char *text)
g_signal_emit_by_name (G_OBJECT (textbox), "text_changed", text);
}
-char *
-textbox_get_text (Textbox *textbox)
+char *textbox_get_text (Textbox *textbox)
{
g_return_val_if_fail (textbox != NULL, NULL);
g_return_val_if_fail (IS_TEXTBOX (textbox), NULL);
@@ -321,8 +287,7 @@ textbox_get_text (Textbox *textbox)
return textbox->priv->text;
}
-void
-textbox_set_font (Textbox *textbox, char *font)
+void textbox_set_font (Textbox *textbox, char *font)
{
g_return_if_fail (textbox != NULL);
g_return_if_fail (IS_TEXTBOX (textbox));
@@ -335,12 +300,10 @@ textbox_set_font (Textbox *textbox, char *font)
textbox_update_bbox (textbox);
- g_signal_emit_by_name(G_OBJECT (textbox),
- "font_changed", textbox->priv->font);
+ g_signal_emit_by_name (G_OBJECT (textbox), "font_changed", textbox->priv->font);
}
-char *
-textbox_get_font (Textbox *textbox)
+char *textbox_get_font (Textbox *textbox)
{
g_return_val_if_fail (textbox != NULL, NULL);
g_return_val_if_fail (IS_TEXTBOX (textbox), NULL);
@@ -348,38 +311,36 @@ textbox_get_font (Textbox *textbox)
return textbox->priv->font;
}
-static void
-textbox_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
+static void textbox_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
{
-/* GnomeCanvasPoints *line;
- double x0, y0;
- ArtPoint dst, src;
- double affine[6];
- int i;
- Textbox *textbox;
- TextboxPriv *priv;
- SheetPos pos;
-
- g_return_if_fail (data != NULL);
- g_return_if_fail (IS_TEXTBOX (data));
-
- textbox = TEXTBOX (data);
- priv = textbox->priv;
-
- item_data_get_pos (ITEM_DATA (textbox), &pos);
- src.x = pos.x;
- src.y = pos.y;
-
- art_affine_identity (affine);
-
- gnome_print_setfont (opc->ctx,
- gnome_font_face_get_font_default (opc->label_font, 6));
- print_draw_text (opc->ctx, priv->text, &src);
- */
+ /* GnomeCanvasPoints *line;
+ double x0, y0;
+ ArtPoint dst, src;
+ double affine[6];
+ int i;
+ Textbox *textbox;
+ TextboxPriv *priv;
+ Coords pos;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_TEXTBOX (data));
+
+ textbox = TEXTBOX (data);
+ priv = textbox->priv;
+
+ item_data_get_pos (ITEM_DATA (textbox), &pos);
+ src.x = pos.x;
+ src.y = pos.y;
+
+ art_affine_identity (affine);
+
+ gnome_print_setfont (opc->ctx,
+ gnome_font_face_get_font_default (opc->label_font, 6));
+ print_draw_text (opc->ctx, priv->text, &src);
+ */
}
-static void
-textbox_unregister (ItemData *data)
+static void textbox_unregister (ItemData *data)
{
NodeStore *store;
@@ -389,8 +350,7 @@ textbox_unregister (ItemData *data)
node_store_remove_textbox (store, TEXTBOX (data));
}
-static int
-textbox_register (ItemData *data)
+static int textbox_register (ItemData *data)
{
NodeStore *store;
diff --git a/src/model/textbox.h b/src/model/textbox.h
index 8e505d9..c7e8260 100644
--- a/src/model/textbox.h
+++ b/src/model/textbox.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __TEXTBOX_H
@@ -38,35 +38,36 @@
#include "clipboard.h"
#include "item-data.h"
-#define TYPE_TEXTBOX (textbox_get_type ())
-#define TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TEXTBOX, Textbox))
-#define TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TEXTBOX, TextboxClass))
-#define IS_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TEXTBOX))
+#define TYPE_TEXTBOX (textbox_get_type ())
+#define TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TEXTBOX, Textbox))
+#define TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TEXTBOX, TextboxClass))
+#define IS_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TEXTBOX))
#define IS_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_GET_CLASS ((klass), TYPE_TEXTBOX))
typedef struct _Textbox Textbox;
typedef struct _TextboxClass TextboxClass;
typedef struct _TextboxPriv TextboxPriv;
-struct _Textbox {
- ItemData parent;
+struct _Textbox
+{
+ ItemData parent;
TextboxPriv *priv;
- gulong text_changed_handler_id;
- gulong font_changed_handler_id;
+ gulong text_changed_handler_id;
+ gulong font_changed_handler_id;
};
struct _TextboxClass
{
ItemDataClass parent_class;
- Textbox *(*dup) (Textbox *textbox);
+ Textbox *(*dup)(Textbox *textbox);
};
-GType textbox_get_type (void);
+GType textbox_get_type (void);
Textbox *textbox_new (char *font);
-void textbox_set_text (Textbox *textbox, const char *text);
-char *textbox_get_text (Textbox *textbox);
-void textbox_set_font (Textbox *textbox, char *font);
-char *textbox_get_font (Textbox *textbox);
-void textbox_update_bbox (Textbox *textbox);
+void textbox_set_text (Textbox *textbox, const char *text);
+char *textbox_get_text (Textbox *textbox);
+void textbox_set_font (Textbox *textbox, char *font);
+char *textbox_get_font (Textbox *textbox);
+void textbox_update_bbox (Textbox *textbox);
#endif
diff --git a/src/model/wire-private.h b/src/model/wire-private.h
index 57f2172..10c241c 100644
--- a/src/model/wire-private.h
+++ b/src/model/wire-private.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,20 +26,21 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __WIRE_PRIVATE_H
#define __WIRE_PRIVATE_H
-struct _WirePriv {
+struct _WirePriv
+{
// Used to traverse the wires during netlist generation.
gboolean visited : 1;
GSList *nodes;
- SheetPos length;
+ Coords length;
WireDir direction;
};
diff --git a/src/model/wire.c b/src/model/wire.c
index 1ef99d1..8ab064b 100644
--- a/src/model/wire.c
+++ b/src/model/wire.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <goocanvas.h>
@@ -39,36 +43,30 @@
#include "wire-private.h"
#include "clipboard.h"
#include "schematic-print-context.h"
+#include "oregano-utils.h"
-static void wire_class_init (WireClass *klass);
-static void wire_init (Wire *wire);
-static void wire_copy (ItemData *dest, ItemData *src);
+static void wire_class_init (WireClass *klass);
+static void wire_init (Wire *wire);
+static void wire_copy (ItemData *dest, ItemData *src);
static ItemData *wire_clone (ItemData *src);
-static void wire_rotate (ItemData *data, int angle, SheetPos *center);
-static void wire_flip (ItemData *data, gboolean horizontal,
- SheetPos *center);
-static void wire_unregister (ItemData *data);
-static int wire_register (ItemData *data);
-static gboolean wire_has_properties (ItemData *data);
-static void wire_print (ItemData *data, cairo_t *cr,
- SchematicPrintContext *ctx);
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-enum {
- ARG_0,
- ARG_CHANGED,
- ARG_DELETE,
- ARG_LAST_SIGNAL
-};
+static void wire_rotate (ItemData *data, int angle, Coords *center);
+static void wire_flip (ItemData *data, IDFlip direction, Coords *center);
+static void wire_unregister (ItemData *data);
+static int wire_register (ItemData *data);
+static gboolean wire_has_properties (ItemData *data);
+static void wire_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx);
+static void wire_changed (ItemData *data);
+
+#include "debug.h"
+
+enum { ARG_0, ARG_DELETE, ARG_LAST_SIGNAL };
G_DEFINE_TYPE (Wire, wire, TYPE_ITEM_DATA)
-static guint wire_signals [ARG_LAST_SIGNAL] = { 0 };
+static guint wire_signals[ARG_LAST_SIGNAL] = {0};
static ItemDataClass *parent_class = NULL;
-static void
-wire_finalize (GObject *object)
+static void wire_finalize (GObject *object)
{
Wire *wire = WIRE (object);
WirePriv *priv = wire->priv;
@@ -82,15 +80,9 @@ wire_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-wire_dispose (GObject *object)
-{
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
+static void wire_dispose (GObject *object) { G_OBJECT_CLASS (parent_class)->dispose (object); }
-static void
-wire_class_init (WireClass *klass)
+static void wire_class_init (WireClass *klass)
{
GObjectClass *object_class;
ItemDataClass *item_data_class;
@@ -102,25 +94,10 @@ wire_class_init (WireClass *klass)
object_class->dispose = wire_dispose;
object_class->finalize = wire_finalize;
- wire_signals [ARG_CHANGED] = g_signal_new ("changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (WireClass, changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- wire_signals [ARG_DELETE] = g_signal_new ("delete",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (WireClass, delete),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
+ wire_signals[ARG_DELETE] =
+ g_signal_new ("delete", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (WireClass, delete), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
item_data_class->clone = wire_clone;
item_data_class->copy = wire_copy;
@@ -130,10 +107,10 @@ wire_class_init (WireClass *klass)
item_data_class->reg = wire_register;
item_data_class->has_properties = wire_has_properties;
item_data_class->print = wire_print;
+ item_data_class->changed = wire_changed;
}
-static void
-wire_init (Wire *wire)
+static void wire_init (Wire *wire)
{
WirePriv *priv = g_new0 (WirePriv, 1);
@@ -148,14 +125,17 @@ wire_init (Wire *wire)
wire->priv = priv;
}
-Wire *
-wire_new (void)
+void wire_dbg_print (Wire *w)
{
- return WIRE (g_object_new (TYPE_WIRE, NULL));
+ Coords pos;
+ item_data_get_pos (ITEM_DATA (w), &pos);
+ NG_DEBUG ("Wire %p is defined by (%lf,%lf) + lambda * (%lf,%lf)\n", w, pos.x, pos.y,
+ w->priv->length.x, w->priv->length.y);
}
-gint
-wire_add_node (Wire *wire, Node *node)
+Wire *wire_new () { return WIRE (g_object_new (TYPE_WIRE, NULL)); }
+
+gint wire_add_node (Wire *wire, Node *node)
{
WirePriv *priv;
@@ -174,8 +154,7 @@ wire_add_node (Wire *wire, Node *node)
return TRUE;
}
-gint
-wire_remove_node (Wire *wire, Node *node)
+gint wire_remove_node (Wire *wire, Node *node)
{
WirePriv *priv;
@@ -195,8 +174,7 @@ wire_remove_node (Wire *wire, Node *node)
return TRUE;
}
-GSList *
-wire_get_nodes (Wire *wire)
+GSList *wire_get_nodes (Wire *wire)
{
WirePriv *priv;
@@ -208,8 +186,7 @@ wire_get_nodes (Wire *wire)
return priv->nodes;
}
-void
-wire_get_start_pos (Wire *wire, SheetPos *pos)
+void wire_get_start_pos (Wire *wire, Coords *pos)
{
g_return_if_fail (wire != NULL);
g_return_if_fail (IS_WIRE (wire));
@@ -218,8 +195,7 @@ wire_get_start_pos (Wire *wire, SheetPos *pos)
item_data_get_pos (ITEM_DATA (wire), pos);
}
-void
-wire_get_end_pos (Wire *wire, SheetPos *pos)
+void wire_get_end_pos (Wire *wire, Coords *pos)
{
WirePriv *priv;
@@ -235,8 +211,22 @@ wire_get_end_pos (Wire *wire, SheetPos *pos)
pos->y += priv->length.y;
}
-void
-wire_get_pos_and_length (Wire *wire, SheetPos *pos, SheetPos *length)
+void wire_get_start_and_end_pos (Wire *wire, Coords *start, Coords *end)
+{
+ WirePriv *priv;
+
+ g_return_if_fail (wire != NULL);
+ g_return_if_fail (IS_WIRE (wire));
+ g_return_if_fail (start != NULL);
+ g_return_if_fail (end != NULL);
+
+ priv = wire->priv;
+
+ item_data_get_pos (ITEM_DATA (wire), start);
+ *end = coords_sum (start, &(priv->length));
+}
+
+void wire_get_pos_and_length (Wire *wire, Coords *pos, Coords *length)
{
WirePriv *priv;
@@ -250,8 +240,16 @@ wire_get_pos_and_length (Wire *wire, SheetPos *pos, SheetPos *length)
*length = priv->length;
}
-void
-wire_set_length (Wire *wire, SheetPos *length)
+void wire_set_pos (Wire *wire, Coords *pos)
+{
+ g_return_if_fail (wire != NULL);
+ g_return_if_fail (IS_WIRE (wire));
+ g_return_if_fail (pos != NULL);
+
+ item_data_set_pos (ITEM_DATA (wire), pos);
+}
+
+void wire_set_length (Wire *wire, Coords *length)
{
WirePriv *priv;
@@ -264,20 +262,16 @@ wire_set_length (Wire *wire, SheetPos *length)
if (length->x == 0) {
wire->priv->direction = WIRE_DIR_VERT;
- }
- else if (length->y == 0) {
+ } else if (length->y == 0) {
wire->priv->direction = WIRE_DIR_HORIZ;
- }
- else {
+ } else {
wire->priv->direction = WIRE_DIR_DIAG;
}
- g_signal_emit_by_name (G_OBJECT (wire),
- "changed");
+ g_signal_emit_by_name (G_OBJECT (wire), "changed");
}
-gint
-wire_is_visited (Wire *wire)
+gboolean wire_is_visited (Wire *wire)
{
WirePriv *priv;
@@ -289,8 +283,7 @@ wire_is_visited (Wire *wire)
return priv->visited;
}
-void
-wire_set_visited (Wire *wire, gboolean is_visited)
+void wire_set_visited (Wire *wire, gboolean is_visited)
{
WirePriv *priv;
@@ -302,8 +295,7 @@ wire_set_visited (Wire *wire, gboolean is_visited)
priv->visited = is_visited;
}
-static ItemData *
-wire_clone (ItemData *src)
+static ItemData *wire_clone (ItemData *src)
{
Wire *new_wire;
ItemDataClass *id_class;
@@ -311,7 +303,7 @@ wire_clone (ItemData *src)
g_return_val_if_fail (src != NULL, NULL);
g_return_val_if_fail (IS_WIRE (src), NULL);
- id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS(src));
+ id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (src));
if (id_class->copy == NULL)
return NULL;
@@ -321,8 +313,7 @@ wire_clone (ItemData *src)
return ITEM_DATA (new_wire);
}
-static void
-wire_copy (ItemData *dest, ItemData *src)
+static void wire_copy (ItemData *dest, ItemData *src)
{
Wire *dest_wire, *src_wire;
@@ -341,109 +332,57 @@ wire_copy (ItemData *dest, ItemData *src)
dest_wire->priv->length = src_wire->priv->length;
}
-static void
-wire_rotate (ItemData *data, int angle, SheetPos *center_pos)
+static void wire_rotate (ItemData *data, int angle, Coords *center_pos)
{
cairo_matrix_t affine;
- double dx, dy, x, y;
+ Coords start_pos;
Wire *wire;
WirePriv *priv;
- SheetPos b1, b2;
- SheetPos wire_center_before, wire_center_after, delta;
g_return_if_fail (data != NULL);
g_return_if_fail (IS_WIRE (data));
+ g_return_if_fail (center_pos != NULL);
if (angle == 0)
return;
wire = WIRE (data);
- if (center_pos) {
- item_data_get_absolute_bbox (ITEM_DATA (wire), &b1, &b2);
- wire_center_before.x = (b1.x + b2.x) / 2;
- wire_center_before.y = (b1.y + b2.y) / 2;
- }
+ wire_get_start_pos (wire, &start_pos);
priv = wire->priv;
if (priv->direction == WIRE_DIR_VERT) {
priv->direction = WIRE_DIR_HORIZ;
- }
- else if (priv->direction == WIRE_DIR_HORIZ) {
+ } else if (priv->direction == WIRE_DIR_HORIZ) {
priv->direction = WIRE_DIR_VERT;
}
- cairo_matrix_init_rotate (&affine, (double) angle * M_PI / 180.0);
-
- // Rotate the wire's end point.
- x = priv->length.x;
- y = priv->length.y;
-
- cairo_matrix_transform_point (&affine, &x, &y);
-
- if (fabs (x) < 1e-2)
- x = 0.0;
- if (fabs (y) < 1e-2)
- y = 0.0;
-
- // 'Normalize'.
- if (y < 0 || (y == 0 && x < 0)) {
- priv->length.x = -x;
- priv->length.y = -y;
- delta.x = -x;
- delta.y = -y;
-
- item_data_move (ITEM_DATA (wire), &delta);
- }
- else {
- priv->length.x = x;
- priv->length.y = y;
- }
-
- // Let the views (canvas items) know about the rotation.
- g_signal_emit_by_name (G_OBJECT (wire), "rotated", angle);
-
- // Update bounding box.
- wire_update_bbox (wire);
-
- if (center_pos) {
- SheetPos wire_pos;
-
- item_data_get_absolute_bbox (ITEM_DATA (wire), &b1, &b2);
+ cairo_matrix_init_identity(&affine);
+ cairo_matrix_translate(&affine, center_pos->x, center_pos->y);
+ cairo_matrix_rotate(&affine, (double)angle * M_PI / 180.0);
+ cairo_matrix_translate(&affine, -center_pos->x, -center_pos->y);
- wire_center_after.x = (b1.x + b2.x) / 2;
- wire_center_after.y = (b1.y + b2.y) / 2;
+ cairo_matrix_transform_distance (&affine, &priv->length.x, &priv->length.y);
- dx = wire_center_before.x - wire_center_after.x;
- dy = wire_center_before.y - wire_center_after.y;
+ cairo_matrix_transform_point (&affine, &start_pos.x, &start_pos.y);
- item_data_get_pos (ITEM_DATA (wire), &wire_pos);
+ wire_set_pos (wire, &start_pos);
- x = wire_center_before.x - center_pos->x;
- y = wire_center_before.y - center_pos->y;
- dx = dx - x;
- dy = dy - y;
- cairo_matrix_transform_point (&affine, &x, &y);
-
- delta.x = dx + x + b1.x;
- delta.y = dy + y + b1.y;
+ // Update bounding box.
+ wire_update_bbox (wire);
- item_data_move (ITEM_DATA (wire), &delta);
- }
+ // Let the views (canvas items) know about the rotation.
+ g_signal_emit_by_name (G_OBJECT (wire), "rotated", angle); // legacy
+ g_signal_emit_by_name (G_OBJECT (wire), "changed");
}
-static void
-wire_flip (ItemData *data, gboolean horizontal, SheetPos *center)
-{
- // Do nothing!
- return;
-}
+// FIXME if we have a center pos, this actually needs to do some transform magic
+static void wire_flip (ItemData *data, IDFlip direction, Coords *center) { return; }
-void
-wire_update_bbox (Wire *wire)
+void wire_update_bbox (Wire *wire)
{
- SheetPos b1, b2, pos, length;
+ Coords b1, b2, pos, length;
wire_get_pos_and_length (wire, &pos, &length);
@@ -453,14 +392,9 @@ wire_update_bbox (Wire *wire)
item_data_set_relative_bbox (ITEM_DATA (wire), &b1, &b2);
}
-static gboolean
-wire_has_properties (ItemData *data)
-{
- return FALSE;
-}
+static gboolean wire_has_properties (ItemData *data) { return FALSE; }
-static void
-wire_unregister (ItemData *data)
+static void wire_unregister (ItemData *data)
{
NodeStore *store;
@@ -470,21 +404,29 @@ wire_unregister (ItemData *data)
node_store_remove_wire (store, WIRE (data));
}
-static int
-wire_register (ItemData *data)
+static gboolean wire_register (ItemData *data)
{
NodeStore *store;
- g_return_val_if_fail (IS_WIRE (data), -1);
+ g_return_val_if_fail (IS_WIRE (data), FALSE);
store = item_data_get_store (data);
return node_store_add_wire (store, WIRE (data));
}
-static void
-wire_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
+static void wire_changed (ItemData *data)
+{
+ Coords loc;
+ g_return_if_fail (IS_WIRE (data));
+
+ item_data_get_pos (data, &loc);
+ g_signal_emit_by_name ((GObject *)data, "moved", &loc);
+ g_signal_emit_by_name ((GObject *)data, "changed");
+}
+
+static void wire_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
{
- SheetPos start_pos, end_pos;
+ Coords start_pos, end_pos;
Wire *wire;
g_return_if_fail (data != NULL);
@@ -496,10 +438,10 @@ wire_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx)
wire_get_end_pos (wire, &end_pos);
cairo_save (cr);
- gdk_cairo_set_source_color (cr, &ctx->colors.wires);
- cairo_move_to (cr, start_pos.x, start_pos.y);
- cairo_line_to (cr, end_pos.x, end_pos.y);
- cairo_stroke (cr);
+ gdk_cairo_set_source_rgba (cr, &ctx->colors.wires);
+ cairo_move_to (cr, start_pos.x, start_pos.y);
+ cairo_line_to (cr, end_pos.x, end_pos.y);
+ cairo_stroke (cr);
cairo_restore (cr);
}
diff --git a/src/model/wire.h b/src/model/wire.h
index f211cd8..352cd41 100644
--- a/src/model/wire.h
+++ b/src/model/wire.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __WIRE_H
@@ -35,13 +37,13 @@
#include <gtk/gtk.h>
-#include "sheet-pos.h"
+#include "coords.h"
#include "clipboard.h"
-#define TYPE_WIRE (wire_get_type ())
-#define WIRE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_WIRE, Wire))
-#define WIRE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_WIRE, WireClass))
-#define IS_WIRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_WIRE))
+#define TYPE_WIRE (wire_get_type ())
+#define WIRE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_WIRE, Wire))
+#define WIRE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_WIRE, WireClass))
+#define IS_WIRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_WIRE))
#define IS_WIRE_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), TYPE_WIRE))
typedef struct _Wire Wire;
@@ -50,6 +52,7 @@ typedef struct _WirePriv WirePriv;
#include "node-store.h"
#include "node.h"
+#include "grid.h"
typedef enum {
WIRE_DIR_NONE = 0,
@@ -58,7 +61,8 @@ typedef enum {
WIRE_DIR_DIAG = 3
} WireDir;
-struct _Wire {
+struct _Wire
+{
ItemData parent;
WirePriv *priv;
};
@@ -67,26 +71,28 @@ struct _WireClass
{
ItemDataClass parent_class;
- Wire *(*dup) (Wire *wire);
- void (*changed) ();
- void (*delete) ();
+ Wire *(*dup)(Wire *wire);
+ void (*changed)();
+ void (*delete)();
};
-GType wire_get_type (void);
-Wire * wire_new (void);
-NodeStore * wire_get_store (Wire *wire);
-gint wire_set_store (Wire *wire, NodeStore *store);
-gint wire_add_node (Wire *wire, Node *node);
-gint wire_remove_node (Wire *wire, Node *node);
-GSList * wire_get_nodes (Wire *wire);
-void wire_get_start_pos (Wire *wire, SheetPos *pos);
-void wire_get_end_pos (Wire *wire, SheetPos *pos);
-void wire_get_pos_and_length (Wire *wire, SheetPos *pos,
- SheetPos *length);
-void wire_set_length (Wire *wire, SheetPos *length);
-gint wire_is_visited (Wire *wire);
-void wire_set_visited (Wire *wire, gboolean is_visited);
-void wire_delete (Wire *wire);
-void wire_update_bbox (Wire *wire);
+GType wire_get_type (void);
+Wire *wire_new ();
+NodeStore *wire_get_store (Wire *wire);
+gint wire_set_store (Wire *wire, NodeStore *store);
+gint wire_add_node (Wire *wire, Node *node);
+gint wire_remove_node (Wire *wire, Node *node);
+GSList *wire_get_nodes (Wire *wire);
+void wire_get_start_pos (Wire *wire, Coords *pos);
+void wire_get_end_pos (Wire *wire, Coords *pos);
+void wire_get_start_and_end_pos (Wire *wire, Coords *start, Coords *end);
+void wire_get_pos_and_length (Wire *wire, Coords *pos, Coords *length);
+void wire_set_pos (Wire *wire, Coords *pos);
+void wire_set_length (Wire *wire, Coords *length);
+gint wire_is_visited (Wire *wire);
+void wire_set_visited (Wire *wire, gboolean is_visited);
+void wire_delete (Wire *wire);
+void wire_update_bbox (Wire *wire);
+void wire_dbg_print (Wire *w);
#endif
diff --git a/src/netlist-editor.c b/src/netlist-editor.c
index b9d9d08..25352f5 100644
--- a/src/netlist-editor.c
+++ b/src/netlist-editor.c
@@ -2,14 +2,16 @@
* netlist-editor.c
*
*
- * Author:
+ * Authors:
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2004-2008 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,20 +25,25 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <glib/gi18n.h>
-#include <gtksourceview/gtksourcelanguagemanager.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gtksourceview/gtksource.h>
#include "netlist-editor.h"
#include "netlist-helper.h"
#include "simulation.h"
#include "file.h"
#include "dialogs.h"
+#include "oregano.h"
+
+#include "debug.h"
static void netlist_editor_finalize (GObject *object);
static void netlist_editor_dispose (GObject *object);
@@ -46,18 +53,18 @@ void netlist_editor_init (NetlistEditor *nle);
static GObjectClass *parent_class = NULL;
-struct _NetlistEditorPriv {
+struct _NetlistEditorPriv
+{
SchematicView *sv;
- gchar * font;
- GdkColor bgcolor, selectcolor, textcolor;
+ gchar *font;
GtkTextView *view;
GtkSourceBuffer *buffer;
GtkWindow *toplevel;
GtkButton *save, *close;
-};
+};
-static void
-netlist_editor_class_init (NetlistEditorClass *klass) {
+static void netlist_editor_class_init (NetlistEditorClass *klass)
+{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
@@ -67,8 +74,7 @@ netlist_editor_class_init (NetlistEditorClass *klass) {
object_class->dispose = netlist_editor_dispose;
}
-static void
-netlist_editor_finalize (GObject *object)
+static void netlist_editor_finalize (GObject *object)
{
NetlistEditor *nle = NETLIST_EDITOR (object);
@@ -84,8 +90,7 @@ netlist_editor_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-netlist_editor_dispose (GObject *object)
+static void netlist_editor_dispose (GObject *object)
{
NetlistEditor *nle = NETLIST_EDITOR (object);
@@ -94,33 +99,23 @@ netlist_editor_dispose (GObject *object)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
-GType
-netlist_editor_get_type (void)
+GType netlist_editor_get_type (void)
{
static GType netlist_editor_type = 0;
if (!netlist_editor_type) {
static const GTypeInfo netlist_editor_info = {
- sizeof (NetlistEditorClass),
- NULL,
- NULL,
- (GClassInitFunc) netlist_editor_class_init,
- NULL,
- NULL,
- sizeof (NetlistEditor),
- 0,
- (GInstanceInitFunc) netlist_editor_init,
- NULL
- };
- netlist_editor_type = g_type_register_static (G_TYPE_OBJECT,
- "NetlistEditor",
- &netlist_editor_info, 0);
+ sizeof(NetlistEditorClass), NULL, NULL,
+ (GClassInitFunc)netlist_editor_class_init, NULL, NULL,
+ sizeof(NetlistEditor), 0, (GInstanceInitFunc)netlist_editor_init,
+ NULL};
+ netlist_editor_type =
+ g_type_register_static (G_TYPE_OBJECT, "NetlistEditor", &netlist_editor_info, 0);
}
return netlist_editor_type;
}
-void
-netlist_editor_save (GtkWidget * widget, NetlistEditor * nle)
+void netlist_editor_save (GtkWidget *widget, NetlistEditor *nle)
{
char *name;
@@ -141,8 +136,8 @@ netlist_editor_save (GtkWidget * widget, NetlistEditor * nle)
fp = fopen (name, "wt");
if (!fp) {
gchar *msg;
- msg = g_strdup_printf (_("The file %s could not be saved"), name);
- oregano_error_with_title (_("Could not save temporary netlist file"), msg);
+ msg = g_strdup_printf (_ ("The file %s could not be saved"), name);
+ oregano_error_with_title (_ ("Could not save temporary netlist file"), msg);
g_free (msg);
return;
}
@@ -156,11 +151,10 @@ netlist_editor_save (GtkWidget * widget, NetlistEditor * nle)
// This method append OREGANO_LANGDIR directory where the netlist.lang file
// is located to the search path of GtkSourceLanguageManager.
-void
-setup_language_manager_path (GtkSourceLanguageManager *lm)
+void setup_language_manager_path (GtkSourceLanguageManager *lm)
{
gchar **lang_files;
- const gchar * const * temp;
+ const gchar *const *temp;
GPtrArray *dirs;
int i, lang_files_count;
char **new_langs;
@@ -168,108 +162,97 @@ setup_language_manager_path (GtkSourceLanguageManager *lm)
dirs = g_ptr_array_new ();
// Stolen from gtranslator
- for (temp = gtk_source_language_manager_get_search_path(lm);
- temp != NULL && *temp != NULL; ++temp)
- g_ptr_array_add (dirs, g_strdup(*temp));
+ for (temp = gtk_source_language_manager_get_search_path (lm); temp != NULL && *temp != NULL;
+ ++temp)
+ g_ptr_array_add (dirs, g_strdup (*temp));
g_ptr_array_add (dirs, NULL);
- lang_files = (gchar **) g_ptr_array_free (dirs, FALSE);
+ lang_files = (gchar **)g_ptr_array_free (dirs, FALSE);
lang_files_count = g_strv_length (lang_files);
- new_langs = g_new (char*, lang_files_count + 2);
+ new_langs = g_new (char *, lang_files_count + 2);
for (i = 0; lang_files[i]; i++)
- new_langs[i] = lang_files[i];
+ new_langs[i] = g_strdup (lang_files[i]);
new_langs[lang_files_count] = g_strdup (OREGANO_LANGDIR);
- new_langs[lang_files_count+1] = NULL;
+ new_langs[lang_files_count + 1] = NULL;
g_strfreev (lang_files);
gtk_source_language_manager_set_search_path (lm, new_langs);
}
-NetlistEditor *
-netlist_editor_new (GtkSourceBuffer * textbuffer) {
- NetlistEditor * nle;
+NetlistEditor *netlist_editor_new (GtkSourceBuffer *textbuffer)
+{
+ NetlistEditor *nle;
GtkBuilder *gui;
GError *perror = NULL;
- GtkWidget * toplevel;
- GtkScrolledWindow * scroll;
- GtkSourceView * source_view;
- GtkSourceLanguageManager * lm;
- GtkButton * save, * close;
- GtkSourceLanguage *lang=NULL;
-
- if (!textbuffer)
+ GtkWidget *toplevel;
+ GtkScrolledWindow *scroll;
+ GtkSourceView *source_view;
+ GtkSourceLanguageManager *lm;
+ GtkButton *save, *close;
+ GtkSourceLanguage *lang = NULL;
+
+ if (!textbuffer)
return NULL;
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create the netlist dialog"));
- return NULL;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- nle = NETLIST_EDITOR (g_object_new (netlist_editor_get_type (), NULL));
-
- if (!g_file_test (OREGANO_UIDIR "/view-netlist.ui", G_FILE_TEST_EXISTS)) {
- gchar *msg;
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/view-netlist.ui");
- oregano_error_with_title (_("Could not create the netlist dialog"), msg);
- g_free (msg);
+ oregano_error (_ ("Could not create the netlist dialog"));
return NULL;
}
+ gtk_builder_set_translation_domain (gui, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/view-netlist.ui",
- &perror) <= 0) {
- gchar *msg;
+ nle = NETLIST_EDITOR (g_object_new (netlist_editor_get_type (), NULL));
+
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/view-netlist.ui", &perror) <= 0) {
+ gchar *msg;
msg = perror->message;
- oregano_error_with_title (_("Could not create the netlist dialog"), msg);
+ oregano_error_with_title (_ ("Could not create the netlist dialog"), msg);
g_error_free (perror);
return NULL;
}
-
+
toplevel = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
gtk_window_set_default_size (GTK_WINDOW (toplevel), 800, 600);
gtk_window_set_title (GTK_WINDOW (toplevel), "Net List Editor\n");
-
+
scroll = GTK_SCROLLED_WINDOW (gtk_builder_get_object (gui, "netlist-scrolled-window"));
-
+
source_view = GTK_SOURCE_VIEW (gtk_source_view_new ());
lm = GTK_SOURCE_LANGUAGE_MANAGER (gtk_source_language_manager_new ());
setup_language_manager_path (lm);
- g_object_set_data_full (G_OBJECT (source_view), "language-manager",
- lm, (GDestroyNotify) g_object_unref);
+ g_object_set_data_full (G_OBJECT (source_view), "language-manager", lm,
+ (GDestroyNotify)g_object_unref);
lang = gtk_source_language_manager_get_language (lm, "netlist");
if (lang) {
+ const gchar *name = gtk_source_language_get_name (lang);
+ g_message ("Loading syntax highlighting %s from %s", name, OREGANO_LANGDIR "/netlist.lang");
gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (textbuffer), lang);
gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (textbuffer), TRUE);
gtk_source_buffer_set_highlight_matching_brackets (GTK_SOURCE_BUFFER (textbuffer), TRUE);
- }
- else {
+ } else {
g_warning ("Can't load netlist.lang in %s", OREGANO_LANGDIR "/netlist.lang");
}
gtk_text_view_set_editable (GTK_TEXT_VIEW (source_view), TRUE);
- gtk_text_view_set_buffer (GTK_TEXT_VIEW (source_view), GTK_TEXT_BUFFER (textbuffer));
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (source_view), GTK_TEXT_BUFFER (textbuffer));
gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (source_view));
-
+
close = GTK_BUTTON (gtk_builder_get_object (gui, "btn_close"));
- g_signal_connect_swapped (G_OBJECT (close), "clicked",
- G_CALLBACK (g_object_unref), G_OBJECT (nle));
+ g_signal_connect_swapped (G_OBJECT (close), "clicked", G_CALLBACK (g_object_unref),
+ G_OBJECT (nle));
save = GTK_BUTTON (gtk_builder_get_object (gui, "btn_save"));
- g_signal_connect (G_OBJECT (save), "clicked",
- G_CALLBACK (netlist_editor_save), nle);
-
+ g_signal_connect (G_OBJECT (save), "clicked", G_CALLBACK (netlist_editor_save), nle);
+
// Set tab, fonts, wrap mode, colors, etc. according
- // to preferences
+ // to preferences
nle->priv->view = GTK_TEXT_VIEW (source_view);
nle->priv->toplevel = GTK_WINDOW (toplevel);
nle->priv->save = save;
@@ -277,12 +260,11 @@ netlist_editor_new (GtkSourceBuffer * textbuffer) {
nle->priv->buffer = textbuffer;
gtk_widget_show_all (GTK_WIDGET (toplevel));
-
- return nle;
+
+ return nle;
}
-NetlistEditor *
-netlist_editor_new_from_file (gchar * filename)
+NetlistEditor *netlist_editor_new_from_file (gchar *filename)
{
GtkSourceBuffer *buffer;
gchar *content;
@@ -295,8 +277,8 @@ netlist_editor_new_from_file (gchar * filename)
if (!(g_file_test (filename, G_FILE_TEST_EXISTS))) {
gchar *msg;
// gettext support
- msg = g_strdup_printf (_("The file %s could not be found."), filename);
- oregano_error_with_title (_("Could not find the required file"), msg);
+ msg = g_strdup_printf (_ ("The file %s could not be found."), filename);
+ oregano_error_with_title (_ ("Could not find the required file"), msg);
g_free (msg);
return NULL;
}
@@ -310,39 +292,39 @@ netlist_editor_new_from_file (gchar * filename)
return editor;
}
-void
-netlist_editor_init (NetlistEditor * nle) {
+void netlist_editor_init (NetlistEditor *nle)
+{
nle->priv = g_new0 (NetlistEditorPriv, 1);
-
+
nle->priv->toplevel = NULL;
nle->priv->sv = NULL;
}
-NetlistEditor *
-netlist_editor_new_from_schematic_view (SchematicView *sv)
+NetlistEditor *netlist_editor_new_from_schematic_view (SchematicView *sv)
{
NetlistEditor *editor;
gchar *name = "/tmp/oregano.netlist";
- GError *error = 0;
+ GError *e = NULL;
Schematic *sm;
OreganoEngine *engine;
sm = schematic_view_get_schematic (sv);
- engine = oregano_engine_factory_create_engine (OREGANO_ENGINE_GNUCAP, sm);
- oregano_engine_generate_netlist (engine, name, &error);
+ engine = oregano_engine_factory_create_engine (oregano.engine, sm);
+ oregano_engine_generate_netlist (engine, name, &e);
g_object_unref (engine);
- if (error != NULL) {
- if (g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
- oregano_error_with_title (_("Could not create a netlist"), error->message);
- g_clear_error (&error);
- }
- else {
- oregano_error (_("An unexpected error has occurred"));
+ if (e) {
+ if (g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
+ log_append_error (schematic_get_log_store (sm), "Netlist",
+ _ ("Could not create a netlist"), e);
+ } else {
+ log_append_error (schematic_get_log_store (sm), "Netlist",
+ _ ("Unexpected error occured"), e);
}
+ g_clear_error (&e);
return NULL;
}
diff --git a/src/netlist-editor.h b/src/netlist-editor.h
index 8901bf2..08e46cb 100644
--- a/src/netlist-editor.h
+++ b/src/netlist-editor.h
@@ -6,7 +6,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2004-2008 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
@@ -23,8 +23,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NETLIST_EDIT_H
@@ -32,38 +32,41 @@
#include <glib.h>
#include <gtk/gtk.h>
-#include <gtksourceview/gtksourceview.h>
+#include <gtksourceview/gtksource.h>
#include "schematic-view.h"
#include "errors.h"
#include "engine.h"
-#define TYPE_NETLIST_EDITOR (netlist_editor_get_type ())
-#define NETLIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NETLIST_EDITOR, NetlistEditor))
-#define NETLIST_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NETLIST_EDITOR, NetlistEditorClass))
-#define IS_NETLIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NETLIST_EDITOR))
-#define IS_NETLIST_EDITOR_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NETLIST_EDITOR, NetlistEditorClass))
+#define TYPE_NETLIST_EDITOR (netlist_editor_get_type ())
+#define NETLIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NETLIST_EDITOR, NetlistEditor))
+#define NETLIST_EDITOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NETLIST_EDITOR, NetlistEditorClass))
+#define IS_NETLIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NETLIST_EDITOR))
+#define IS_NETLIST_EDITOR_CLASS(klass) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NETLIST_EDITOR, NetlistEditorClass))
-
-typedef struct _NetlistEditor NetlistEditor;
+typedef struct _NetlistEditor NetlistEditor;
typedef struct _NetlistEditorClass NetlistEditorClass;
-typedef struct _NetlistEditorPriv NetlistEditorPriv;
+typedef struct _NetlistEditorPriv NetlistEditorPriv;
-struct _NetlistEditor {
+struct _NetlistEditor
+{
GObject parent;
NetlistEditorPriv *priv;
};
-struct _NetlistEditorClass {
+struct _NetlistEditorClass
+{
GObjectClass parent_class;
// Signals go here
};
GType netlist_editor_get_type (void);
-NetlistEditor *netlist_editor_new_from_file (gchar * filename);
+NetlistEditor *netlist_editor_new_from_file (gchar *filename);
NetlistEditor *netlist_editor_new_from_schematic_view (SchematicView *sv);
-NetlistEditor *netlist_editor_new (GtkSourceBuffer * textbuffer);
+NetlistEditor *netlist_editor_new (GtkSourceBuffer *textbuffer);
#endif
diff --git a/src/options.c b/src/options.c
new file mode 100644
index 0000000..9d7cd45
--- /dev/null
+++ b/src/options.c
@@ -0,0 +1,59 @@
+#include "options.h"
+#include <gtk/gtk.h> //for gtk_get_option_group
+
+OreganoOptions opts = {
+ .debug = {.wires = FALSE, .boxes = FALSE, .dots = FALSE, .directions = FALSE, .all = FALSE}};
+
+GOptionEntry entries[] = {
+ {"version", 0, 0, G_OPTION_ARG_NONE, &(opts.version),
+ "Print the version and quit.", NULL},
+ {"debug-wires", 0, 0, G_OPTION_ARG_NONE, &(opts.debug.wires),
+ "Give them randomly alternating colors.", NULL},
+ {"debug-boundingboxes", 0, 0, G_OPTION_ARG_NONE, &(opts.debug.boxes),
+ "Draw them in semi transparent purple.", NULL},
+ {"debug-dots", 0, 0, G_OPTION_ARG_NONE, &(opts.debug.dots),
+ "Draw an extra color circle around dots which are always shown.", NULL},
+ {"debug-directions", 0, 0, G_OPTION_ARG_NONE, &(opts.debug.directions),
+ "Draw fancy direction arrows top left edge of the sheet.", NULL},
+ {"debug-all", 0, 0, G_OPTION_ARG_NONE, &(opts.debug.all), "Enable all debug-* options.", NULL},
+ {NULL}};
+
+/**
+ * parse the commandline options for gtk args and oregano recognized ones
+ * results will be written to a global Options struct (opts)
+ * @param argc pointer to argc from main
+ * @param argv pointer to argv from main
+ * @param e a GError ptr ptr which will be filled in case of an error
+ */
+gboolean oregano_options_parse (int *argc, char **argv[], GError **e)
+{
+ GError *error = NULL;
+ gboolean r = FALSE;
+ GOptionContext *context;
+ context = g_option_context_new ("- electrical engineering tool");
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ r = g_option_context_parse (context, argc, argv, &error);
+ if (error) {
+ if (e)
+ *e = g_error_copy (error);
+ g_error_free (error);
+ error = NULL;
+ }
+ g_option_context_free (context);
+ return r;
+}
+
+
+inline gboolean oregano_options_version () { return opts.version; }
+
+inline gboolean oregano_options_debug_wires () { return opts.debug.wires || opts.debug.all; }
+
+inline gboolean oregano_options_debug_boxes () { return opts.debug.boxes || opts.debug.all; }
+
+inline gboolean oregano_options_debug_dots () { return opts.debug.dots || opts.debug.all; }
+
+inline gboolean oregano_options_debug_directions ()
+{
+ return opts.debug.directions || opts.debug.all;
+}
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 0000000..7157fab
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,36 @@
+#ifndef OPTION_H__
+#define OPTION_H__
+
+#ifndef GETTEXT_PACKAGE
+#define GETTEXT_PACKAGE "oregano"
+#endif
+
+#include <glib.h>
+
+typedef struct
+{
+ gboolean version;
+ struct
+ {
+ gboolean wires;
+ gboolean boxes;
+ gboolean dots;
+ gboolean directions;
+ gboolean all;
+ } debug;
+
+} OreganoOptions;
+
+gboolean oregano_options_parse (int *argc, char **argv[], GError **e);
+
+gboolean oregano_options_version ();
+
+gboolean oregano_options_debug_wires ();
+
+gboolean oregano_options_debug_boxes ();
+
+gboolean oregano_options_debug_dots ();
+
+gboolean oregano_options_debug_directions ();
+
+#endif /* OPTION_H__ */
diff --git a/src/oregano-config.c b/src/oregano-config.c
index 7e8a184..f73dac8 100644
--- a/src/oregano-config.c
+++ b/src/oregano-config.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
@@ -42,44 +42,33 @@
#include "dialogs.h"
#include "engine.h"
-#define OREGLIB_EXT "oreglib"
+#define OREGLIB_EXT "oreglib"
-static gboolean is_oregano_library_name (gchar* name);
+static gboolean is_oregano_library_name (gchar *name);
static void load_library_error (gchar *name);
-void
-oregano_config_load (void)
+void oregano_config_load (void)
{
- oregano.settings = g_settings_new ("apps.oregano");
- oregano.engine = g_settings_get_int (oregano.settings,
- "engine");
- oregano.compress_files = g_settings_get_boolean (oregano.settings,
- "compress-files");
- oregano.show_log = g_settings_get_boolean (oregano.settings,
- "show-log");
- oregano.show_splash = g_settings_get_boolean (oregano.settings,
- "show-splash");
+ oregano.settings = g_settings_new ("io.ahoi.oregano");
+ oregano.engine = g_settings_get_int (oregano.settings, "engine");
+ oregano.compress_files = g_settings_get_boolean (oregano.settings, "compress-files");
+ oregano.show_log = g_settings_get_boolean (oregano.settings, "show-log");
+ oregano.show_splash = g_settings_get_boolean (oregano.settings, "show-splash");
// Let's deal with first use -I don't like this-
if ((oregano.engine < 0) || (oregano.engine >= OREGANO_ENGINE_COUNT))
oregano.engine = 0;
}
-void
-oregano_config_save (void)
+void oregano_config_save (void)
{
- g_settings_set_int (oregano.settings, "engine",
- oregano.engine);
- g_settings_set_boolean (oregano.settings, "compress-files",
- oregano.compress_files);
- g_settings_set_boolean (oregano.settings, "show-log",
- oregano.show_log);
- g_settings_set_boolean (oregano.settings, "show-splash",
- oregano.show_splash);
+ g_settings_set_int (oregano.settings, "engine", oregano.engine);
+ g_settings_set_boolean (oregano.settings, "compress-files", oregano.compress_files);
+ g_settings_set_boolean (oregano.settings, "show-log", oregano.show_log);
+ g_settings_set_boolean (oregano.settings, "show-splash", oregano.show_splash);
}
-void
-oregano_lookup_libraries (Splash *sp)
+void oregano_lookup_libraries (Splash *sp)
{
gchar *fname;
DIR *libdir;
@@ -89,7 +78,8 @@ oregano_lookup_libraries (Splash *sp)
oregano.libraries = NULL;
libdir = opendir (OREGANO_LIBRARYDIR);
- if (libdir == NULL) return;
+ if (libdir == NULL)
+ return;
if (oregano.libraries != NULL) {
closedir (libdir);
@@ -104,15 +94,15 @@ oregano_lookup_libraries (Splash *sp)
}
g_free (fname);
- while ((libentry=readdir (libdir)) != NULL) {
+ while ((libentry = readdir (libdir)) != NULL) {
if (is_oregano_library_name (libentry->d_name) &&
- strcmp (libentry->d_name,"default.oreglib")) {
+ strcmp (libentry->d_name, "default.oreglib")) {
fname = g_build_filename (OREGANO_LIBRARYDIR, libentry->d_name, NULL);
// do the following only if splash is enabled
if (sp) {
char txt[50];
- sprintf (txt, _("Loading %s ..."), libentry->d_name);
+ sprintf (txt, _ ("Loading %s ..."), libentry->d_name);
oregano_splash_step (sp, txt);
}
@@ -120,7 +110,7 @@ oregano_lookup_libraries (Splash *sp)
library = library_parse_xml_file (fname);
if (library)
- oregano.libraries = g_list_append ( oregano.libraries, library);
+ oregano.libraries = g_list_append (oregano.libraries, library);
else
load_library_error (fname);
@@ -130,15 +120,14 @@ oregano_lookup_libraries (Splash *sp)
closedir (libdir);
}
-static gboolean
-is_oregano_library_name (gchar *name)
+static gboolean is_oregano_library_name (gchar *name)
{
gchar *dot;
dot = strchr (name, '.');
if (dot == NULL || dot[1] == '\0')
return FALSE;
- dot++; // Points to the extension.
+ dot++; // Points to the extension.
if (strcmp (dot, OREGLIB_EXT) == 0)
return TRUE;
@@ -146,15 +135,13 @@ is_oregano_library_name (gchar *name)
return FALSE;
}
-static void
-load_library_error (gchar *name)
+static void load_library_error (gchar *name)
{
gchar *title, *desc;
- title = g_strdup_printf (_("Could not read the parts library: %s "),
- name);
- desc = g_strdup_printf (_("The file is probably corrupt. Please "
- "reinstall the parts library or Oregano "
- "and try again."));
+ title = g_strdup_printf (_ ("Could not read the parts library: %s "), name);
+ desc = g_strdup_printf (_ ("The file is probably corrupt. Please "
+ "reinstall the parts library or Oregano "
+ "and try again."));
oregano_error_with_title (title, desc);
g_free (title);
g_free (desc);
diff --git a/src/oregano-config.h b/src/oregano-config.h
index 54a7f8e..5f36303 100644
--- a/src/oregano-config.h
+++ b/src/oregano-config.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __OREGANO_CONFIG_H
diff --git a/src/oregano-utils.c b/src/oregano-utils.c
index 779a6e0..099fcdc 100644
--- a/src/oregano-utils.c
+++ b/src/oregano-utils.c
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
*
* This program is free software; you can redistribute it and/or
@@ -27,59 +29,77 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <gtk/gtk.h>
+#include "debug.h"
#include "oregano-utils.h"
-gdouble
-oregano_strtod (const gchar *str, const gchar unit)
+gdouble oregano_strtod (const gchar *str, const gchar *unit)
{
+ gboolean unit_does_not_match = FALSE;
gdouble ret;
gchar *endptr, *c;
+ size_t unit_length = 0;
+
+ if (unit)
+ unit_length = strlen (unit);
if (!str)
return 0.0;
-
+
ret = g_ascii_strtod (str, &endptr);
+
for (c = endptr; *c; c++) {
switch (*c) {
case 'T':
ret *= 1e12;
- return ret;
+ break;
case 'G':
ret *= 1e9;
- return ret;
+ break;
case 'M':
ret *= 1e6;
- return ret;
+ break;
case 'k':
ret *= 1e3;
- return ret;
+ break;
case 'm':
ret *= 1e-3;
- return ret;
+ break;
case 'u':
ret *= 1e-6;
- return ret;
+ break;
case 'n':
ret *= 1e-9;
- return ret;
+ break;
case 'p':
ret *= 1e-12;
- return ret;
+ break;
case 'f':
ret *= 1e-15;
- return ret;
+ break;
+ case ' ':
+ break;
default:
- if (*c == unit)
- return ret;
+ if (c) {
+ if (!g_ascii_strncasecmp (c, unit, unit_length)) {
+ return ret;
+ } else {
+ unit_does_not_match = TRUE;
+ break;
+ }
+ }
break;
}
}
+
+ if (unit_does_not_match)
+ g_printf ("Unexpected unit of measurement\n");
+
return ret;
}
diff --git a/src/oregano-utils.h b/src/oregano-utils.h
index 43d5ed5..4f2c1a0 100644
--- a/src/oregano-utils.h
+++ b/src/oregano-utils.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,13 +28,26 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __OREGANO_UTILS_H
#define __OREGANO_UTILS_H
-gdouble oregano_strtod (const gchar *str, const gchar unit);
+gdouble oregano_strtod (const gchar *str, const gchar *unit);
+
+#define DEGSANITY(x) \
+ do { \
+ while (rotation < 0) \
+ x += 360; \
+ x %= 360; \
+ } while (0)
+#define DEG2RAD(x) ((double)x * M_PI / 180.)
+#define RAD2DEG(x) ((double)x * 180. / M_PI)
+#define COORDS_AVERAGE(tl, br) \
+ { \
+ (tl.x + br.x) / 2., (tl.y + br.y) / 2. \
+ }
#endif
diff --git a/src/oregano.c b/src/oregano.c
index 25c9c3b..fa45777 100644
--- a/src/oregano.c
+++ b/src/oregano.c
@@ -1,13 +1,16 @@
/*
* oregano.c
*
- * Author:
- * Richard Hult <rhult@hem.passagen.se>
- * Ricardo Markiewicz <rmarkie@fi.uba.ar>
- * Andres de Barbara <adebarbara@fi.uba.ar>
- * Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Oregano, a tool for schematic capture and simulation of electronic
* circuits.
@@ -15,6 +18,8 @@
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -28,8 +33,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#define ENABLE_NLS 1
@@ -43,8 +48,8 @@
#include <signal.h>
#include <gio/gdesktopappinfo.h>
-
#include "dialogs.h"
+#include "engine.h"
#include "schematic.h"
#include "schematic-view.h"
#include "cursors.h"
@@ -66,103 +71,107 @@ int oregano_debugging;
static void oregano_application (GApplication *app, GFile *file);
static void oregano_activate (GApplication *application);
-static void oregano_open (GApplication *application, GFile **files,
- gint n_files, const gchar *hint);
+static void oregano_open (GApplication *application, GFile **files, gint n_files,
+ const gchar *hint);
-static void
-oregano_finalize (GObject *object)
+static void oregano_finalize (GObject *object)
{
- G_OBJECT_CLASS (oregano_parent_class)->finalize (object);
+ cursors_shutdown ();
+ G_OBJECT_CLASS (oregano_parent_class)->finalize (object);
}
-static void
-oregano_class_init (OreganoClass *klass)
-{
+static void oregano_class_init (OreganoClass *klass)
+{
G_APPLICATION_CLASS (klass)->activate = oregano_activate;
- G_APPLICATION_CLASS (klass)->open = oregano_open;
+ G_APPLICATION_CLASS (klass)->open = oregano_open;
G_OBJECT_CLASS (klass)->finalize = oregano_finalize;
}
-static void
-oregano_init (Oregano *object)
+static void oregano_init (Oregano *object)
{
+ guint i;
+ gchar *engine_name;
+
cursors_init ();
stock_init ();
oregano_config_load ();
+
+ // check if the engine loaded from the configuration exists...
+ // otherwise pick up the next one !
+ engine_name = oregano_engine_get_engine_name_by_index (oregano.engine);
+ if (g_find_program_in_path (engine_name) == NULL) {
+ oregano.engine = OREGANO_ENGINE_COUNT;
+ for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
+ g_free (engine_name);
+ engine_name = oregano_engine_get_engine_name_by_index (i);
+ if (g_find_program_in_path (engine_name) != NULL) {
+ oregano.engine = i;
+ }
+ }
+ }
+ g_free (engine_name);
+
+ // simulation cannot run, disable log
+ if (oregano.engine < 0 || oregano.engine >= OREGANO_ENGINE_COUNT)
+ oregano.show_log = FALSE;
}
-Oregano *
-oregano_new (void)
+Oregano *oregano_new (void)
{
- g_type_init ();
-
- return g_object_new (oregano_get_type (),
- "application-id", "org.gnome.oregano",
- "flags", G_APPLICATION_HANDLES_OPEN,
- NULL);
+ return g_object_new (oregano_get_type (), "application-id", "org.gnome.oregano", "flags",
+ G_APPLICATION_HANDLES_OPEN, NULL);
}
// GApplication implementation
-static void
-oregano_activate (GApplication *application)
+static void oregano_activate (GApplication *application)
{
- oregano_application (application, NULL);
+ oregano_application (application, NULL);
}
-static void
-oregano_open (GApplication *application, GFile **files, gint n_files,
- const gchar *hint)
+static void oregano_open (GApplication *application, GFile **files, gint n_files, const gchar *hint)
{
- gint i;
+ gint i;
- for (i = 0; i < n_files; i++)
- oregano_application (application, files[i]);
+ for (i = 0; i < n_files; i++)
+ oregano_application (application, files[i]);
}
-static gboolean
-quit_hook (GSignalInvocationHint *ihint,
- guint n_param_values,
- const GValue *param_values,
- gpointer data)
+static gboolean quit_hook (GSignalInvocationHint *ihint, guint n_param_values,
+ const GValue *param_values, gpointer data)
{
return FALSE;
}
-static void
-oregano_application (GApplication *app, GFile *file)
+static void oregano_application (GApplication *app, GFile *file)
{
- Schematic *schematic = NULL ;
+ Schematic *schematic = NULL;
SchematicView *schematic_view = NULL;
gchar *msg;
Splash *splash = NULL;
+ GError *error = NULL;
- if (!g_file_test (OREGANO_UIDIR "/splash.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("You seem to be running Oregano without "
- "having it installed properly on your system.\n\n"
- "Please install Oregano and try again."));
-
- oregano_error (msg);
- g_free (msg);
- return;
- }
-
- // Keep non localized input for ngspice
+ // Keep non localized input for ngspice
setlocale (LC_NUMERIC, "C");
+
if (oregano.show_splash) {
- splash = oregano_splash_new ();
+ splash = oregano_splash_new (&error);
+ if (error) {
+ msg = g_strdup_printf (_ ("Failed to spawn splash-screen \'%s\''. Code %i - %s"),
+ OREGANO_UIDIR "splash.ui", error->code, error->message);
+ oregano_error (msg);
+ g_free (msg);
+ g_clear_error (&error);
+ // non fatal issue
+ }
}
- //splash == NULL if showing splash is disabled
+ // splash == NULL if showing splash is disabled
oregano_lookup_libraries (splash);
if (oregano.libraries == NULL) {
- oregano_error (
- _("Could not find a parts library.\n\n"
- "This is probably due to a faulty installation "
- "of Oregano. Please check your installation."));
+ oregano_error (_ ("Could not find a parts library.\n\n"
+ "Supposed to be in " OREGANO_LIBRARYDIR));
return;
}
@@ -177,31 +186,39 @@ oregano_application (GApplication *app, GFile *file)
schematic = schematic_read (fname, &error);
if (schematic) {
schematic_view = schematic_view_new (schematic);
- gtk_window_set_application (GTK_WINDOW (schematic_view_get_toplevel (schematic_view)),
- GTK_APPLICATION (app));
gtk_widget_show_all (schematic_view_get_toplevel (schematic_view));
schematic_set_filename (schematic, fname);
schematic_set_title (schematic, g_path_get_basename (fname));
}
- }
- else {
+ } else {
schematic = schematic_new ();
schematic_view = schematic_view_new (schematic);
- gtk_window_set_application (GTK_WINDOW (schematic_view_get_toplevel (schematic_view)),
- GTK_APPLICATION (app));
gtk_widget_show_all (schematic_view_get_toplevel (schematic_view));
}
- g_signal_add_emission_hook (
- g_signal_lookup ("last_schematic_destroyed", TYPE_SCHEMATIC),
- 0,
- quit_hook,
- NULL,
- NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("last_schematic_destroyed", TYPE_SCHEMATIC), 0,
+ quit_hook, NULL, NULL);
- if (oregano.show_splash)
- oregano_splash_done (splash, _("Welcome to Oregano"));
+ if (oregano.show_splash && splash)
+ oregano_splash_done (splash, _ ("Welcome to Oregano"));
+}
- cursors_shutdown ();
+void oregano_deallocate_memory (void)
+{
+ GList *iter;
+ Library *l;
+
+ g_object_unref (oregano.settings);
+
+ // Free the memory used by the parts libraries
+ for (iter = oregano.libraries; iter; iter = iter->next) {
+ l = (Library *) iter->data;
+ g_free (l->name);
+ g_free (l->author);
+ g_free (l->version);
+ }
+ g_list_free_full (oregano.libraries, g_free);
+
+ clipboard_empty ();
}
diff --git a/src/oregano.h b/src/oregano.h
index a60b0d6..e143df3 100644
--- a/src/oregano.h
+++ b/src/oregano.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __MAIN_H
#define __MAIN_H
@@ -38,34 +38,32 @@
G_BEGIN_DECLS
-#define OREGANO_TYPE_APPLICATION (oregano_get_type ())
-#define OREGANO_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_APPLICATION, Oregano))
-#define OREGANO_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OREGANO_TYPE_APPLICATION, OreganoClass))
-#define OREGANO_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_APPLICATION))
-#define OREGANO_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OREGANO_TYPE_APPLICATION))
-#define OREGANO_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OREGANO_TYPE_APPLICATION, OreganoClass))
-
-typedef struct {
+#define OREGANO_TYPE_APPLICATION (oregano_get_type ())
+#define OREGANO_APPLICATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OREGANO_TYPE_APPLICATION, Oregano))
+#define OREGANO_APPLICATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), OREGANO_TYPE_APPLICATION, OreganoClass))
+#define OREGANO_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OREGANO_TYPE_APPLICATION))
+#define OREGANO_IS_APPLICATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), OREGANO_TYPE_APPLICATION))
+#define OREGANO_APPLICATION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), OREGANO_TYPE_APPLICATION, OreganoClass))
+
+typedef struct
+{
GtkApplication parent_instance;
} Oregano;
-typedef struct {
+typedef struct
+{
GtkApplicationClass parent_class;
} OreganoClass;
-typedef struct {
+typedef struct
+{
GList *libraries;
GSList *clipboard;
- // list for library paths
- GList *lib_path;
-
- // list for model paths
- GList *model_path;
-
- // hash table with model names as keys and paths as data
- GHashTable *models;
-
GSettings *settings;
gint engine;
gboolean compress_files;
@@ -76,7 +74,6 @@ typedef struct {
extern OreganoApp oregano;
extern int oregano_debugging;
-
Oregano *oregano_new (void);
G_END_DECLS
diff --git a/src/part-browser.c b/src/part-browser.c
index b2b4ed2..a77dd26 100644
--- a/src/part-browser.c
+++ b/src/part-browser.c
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
@@ -42,30 +44,32 @@
#include "part-browser.h"
#include "part-item.h"
#include "dialogs.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "sheet.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
typedef struct _Browser Browser;
-struct _Browser {
- SchematicView *schematic_view;
- GtkWidget *viewport;
- GtkWidget *list;
- GtkWidget *canvas;
- GooCanvasText *description;
- GooCanvasGroup *preview;
- Library *library;
- gboolean hidden;
+struct _Browser
+{
+ SchematicView *schematic_view;
+ GtkWidget *viewport;
+ GtkWidget *list;
+ GtkWidget *canvas;
+ GooCanvasText *description;
+ GooCanvasGroup *preview;
+ Library *library;
+ gboolean hidden;
// Models for the TreeView
- GtkTreeModel *real_model;
- GtkTreeModel *sort_model;
- GtkTreeModel *filter_model;
- GtkEntry *filter_entry;
- gint filter_len;
+ GtkTreeModel *real_model;
+ GtkTreeModel *sort_model;
+ GtkTreeModel *filter_model;
+ GtkEntry *filter_entry;
+ gint filter_len;
};
-typedef struct {
+typedef struct
+{
Browser *br;
SchematicView *schematic_view;
char *library_name;
@@ -78,16 +82,15 @@ typedef struct {
static void update_preview (Browser *br);
static void add_part (gpointer key, LibraryPart *part, Browser *br);
-static int part_selected (GtkTreeView *list, GtkTreePath *arg1,
- GtkTreeViewColumn *col, Browser *br);
+static int part_selected (GtkTreeView *list, GtkTreePath *arg1, GtkTreeViewColumn *col,
+ Browser *br);
static void part_browser_setup_libs (Browser *br, GtkBuilder *gui);
static void library_switch_cb (GtkWidget *item, Browser *br);
static void preview_realized (GtkWidget *widget, Browser *br);
-static void wrap_string (char* str, int width);
+static void wrap_string (char *str, int width);
static void place_cmd (GtkWidget *widget, Browser *br);
-static gboolean
-part_list_filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+static gboolean part_list_filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
char *part_name;
const char *s;
@@ -97,8 +100,10 @@ part_list_filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
s = gtk_entry_get_text (GTK_ENTRY (br->filter_entry));
// Without filter, the part is shown
- if (s == NULL) return TRUE;
- if (br->filter_len == 0) return TRUE;
+ if (s == NULL)
+ return TRUE;
+ if (br->filter_len == 0)
+ return TRUE;
gtk_tree_model_get (model, iter, 0, &part_name, -1);
@@ -118,8 +123,7 @@ part_list_filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
return FALSE;
}
-static int
-part_search_change (GtkWidget *widget, Browser *br)
+static int part_search_change (GtkWidget *widget, Browser *br)
{
const char *s = gtk_entry_get_text (GTK_ENTRY (widget));
@@ -132,8 +136,7 @@ part_search_change (GtkWidget *widget, Browser *br)
return TRUE;
}
-static void
-part_search_activate (GtkWidget *widget, Browser *br)
+static void part_search_activate (GtkWidget *widget, Browser *br)
{
GtkTreeSelection *selection;
GtkTreePath *path;
@@ -149,12 +152,11 @@ part_search_activate (GtkWidget *widget, Browser *br)
}
}
-static void
-place_cmd (GtkWidget *widget, Browser *br)
+static void place_cmd (GtkWidget *widget, Browser *br)
{
LibraryPart *library_part;
char *part_name;
- SheetPos pos;
+ Coords pos;
Sheet *sheet;
Part *part;
GtkTreeModel *model;
@@ -177,24 +179,20 @@ place_cmd (GtkWidget *widget, Browser *br)
library_part = library_get_part (br->library, part_name);
part = part_new_from_library_part (library_part);
if (!part) {
- oregano_error (_("Unable to load required part"));
+ oregano_error (_ ("Unable to load required part"));
return;
}
pos.x = pos.y = 0;
item_data_set_pos (ITEM_DATA (part), &pos);
+ sheet_connect_part_item_to_floating_group (sheet, (gpointer)br->schematic_view);
sheet_select_all (sheet, FALSE);
sheet_clear_ghosts (sheet);
sheet_add_ghost_item (sheet, ITEM_DATA (part));
-
- sheet_connect_part_item_to_floating_group (sheet,
- (gpointer) br->schematic_view);
}
-static int
-part_selected (GtkTreeView *list, GtkTreePath *arg1, GtkTreeViewColumn *col,
- Browser *br)
+static int part_selected (GtkTreeView *list, GtkTreePath *arg1, GtkTreeViewColumn *col, Browser *br)
{
// if double-click over an item, place it on work area
place_cmd (NULL, br);
@@ -202,15 +200,14 @@ part_selected (GtkTreeView *list, GtkTreePath *arg1, GtkTreeViewColumn *col,
return FALSE;
}
-static void
-update_preview (Browser *br)
+static void update_preview (Browser *br)
{
LibraryPart *library_part;
gdouble new_x, new_y, x1, y1, x2, y2;
gdouble text_width;
gdouble width, height;
GooCanvasBounds bounds;
- gdouble scale;
+ gdouble scale;
cairo_matrix_t transf, affine;
gchar *part_name;
char *description;
@@ -222,6 +219,9 @@ update_preview (Browser *br)
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (br->list));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (br->list));
+ if (!GTK_IS_TREE_SELECTION (selection))
+ return;
+
if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
return;
}
@@ -229,35 +229,28 @@ update_preview (Browser *br)
gtk_tree_model_get (model, &iter, 0, &part_name, -1);
library_part = library_get_part (br->library, part_name);
-
+
// If there is already a preview part-item, destroy its group and create a
// new one.
if (br->preview != NULL) {
goo_canvas_item_remove (GOO_CANVAS_ITEM (br->preview));
}
-
- br->preview = GOO_CANVAS_GROUP (goo_canvas_group_new (
- goo_canvas_get_root_item (GOO_CANVAS (br->canvas)),
- NULL));
+
+ br->preview = GOO_CANVAS_GROUP (
+ goo_canvas_group_new (goo_canvas_get_root_item (GOO_CANVAS (br->canvas)), NULL));
goo_canvas_set_bounds (GOO_CANVAS (br->canvas), 0.0, 0.0, 250.0, 110.0);
- g_object_get (br->preview,
- "width", &width,
- "height", &height,
- NULL);
-
+ g_object_get (br->preview, "width", &width, "height", &height, NULL);
+
if (!library_part)
return;
part_item_create_canvas_items_for_preview (br->preview, library_part);
// Unconstraint the canvas width & height to adjust for the part description
- g_object_set (br->preview,
- "width", -1.0,
- "height", -1.0,
- NULL);
-
+ g_object_set (br->preview, "width", -1.0, "height", -1.0, NULL);
+
// Get the coordonates */
goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (br->preview), &bounds);
x1 = bounds.x1;
@@ -265,66 +258,52 @@ update_preview (Browser *br)
y1 = bounds.y1;
y2 = bounds.y2;
- // Translate in such a way that the canvas centre remains in (0, 0)
+ // Translate in such a way that the canvas centre remains in (0, 0)
cairo_matrix_init_translate (&transf, -(x2 + x1) / 2.0f + PREVIEW_WIDTH / 2,
-(y2 + y1) / 2.0f + PREVIEW_HEIGHT / 2);
- // Compute the scale of the widget
+ // Compute the scale of the widget
if ((x2 - x1 != 0) || (y2 - y1 != 0)) {
if ((x2 - x1) < (y2 - y1))
scale = 0.60f * PREVIEW_HEIGHT / (y2 - y1);
else
scale = 0.60f * PREVIEW_WIDTH / (x2 - x1);
- }
- else
+ } else
scale = 5;
cairo_matrix_init_scale (&affine, scale, scale);
cairo_matrix_multiply (&transf, &transf, &affine);
- // Apply the transformation
+ // Apply the transformation
goo_canvas_item_set_transform (GOO_CANVAS_ITEM (br->preview), &transf);
-
- // Compute the motion to centre the Preview widget
+
+ // Compute the motion to centre the Preview widget
new_x = 100 + (PREVIEW_WIDTH - x1 - x2) / 2;
new_y = (PREVIEW_HEIGHT - y1 - y2) / 2 - 10;
- // Apply the transformation
- if (scale > 5.0) scale = 3.0;
- goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->preview),
- new_x,
- new_y,
- scale,
- 0.0);
-
+ // Apply the transformation
+ if (scale > 5.0)
+ scale = 3.0;
+ goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->preview), new_x, new_y, scale, 0.0);
+
description = g_strdup (library_part->description);
wrap_string (description, 20);
- g_object_set (br->description,
- "text", description,
- NULL);
+ g_object_set (br->description, "text", description, NULL);
g_free (description);
- g_object_get (G_OBJECT (br->description),
- "width", &text_width,
- NULL);
-
- goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->description),
- 50.0,
- -20.0,
- 1.0,
- 0.0);
+ g_object_get (G_OBJECT (br->description), "width", &text_width, NULL);
+
+ goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->description), 50.0, -20.0, 1.0, 0.0);
g_free (part_name);
}
-static gboolean
-select_row (GtkTreeView *list, Browser *br)
+static gboolean select_row (GtkTreeView *list, Browser *br)
{
update_preview (br);
return FALSE;
}
-static void
-add_part (gpointer key, LibraryPart *part, Browser *br)
+static void add_part (gpointer key, LibraryPart *part, Browser *br)
{
GtkTreeIter iter;
GtkListStore *model;
@@ -340,50 +319,45 @@ add_part (gpointer key, LibraryPart *part, Browser *br)
}
// Read the available parts from the library and put them in the browser clist.
-static void
-update_list (Browser *br)
+static void update_list (Browser *br)
{
GtkListStore *model;
model = GTK_LIST_STORE (br->real_model);
gtk_list_store_clear (model);
- g_hash_table_foreach (br->library->part_hash, (GHFunc) add_part, br);
+ g_hash_table_foreach (br->library->part_hash, (GHFunc)add_part, br);
}
-
// Show a part browser. If one already exists, just bring it up, otherwise
// create it. We can afford to keep it in memory all the time, and we don't
// have to delete it and build it every time it is needed. If already shown,
// hide it.
-void
-part_browser_toggle_show (SchematicView *schematic_view)
+void part_browser_toggle_visibility (SchematicView *schematic_view)
{
Browser *browser = schematic_view_get_browser (schematic_view);
-
+
if (browser == NULL) {
- // part_browser_create (schematic_view);
- }
- else {
+ // part_browser_create (schematic_view);
+ g_warning ("This should never happen. No Part Browser.");
+ } else {
browser->hidden = !(browser->hidden);
if (browser->hidden) {
gtk_widget_hide (browser->viewport);
- }
- else {
+ } else {
gtk_widget_show_all (browser->viewport);
}
}
}
-void
-part_browser_dnd (GtkSelectionData *selection_data, int x, int y)
+void part_browser_dnd (GtkSelectionData *selection_data, int x, int y)
{
LibraryPart *library_part;
- SheetPos pos;
+ Coords pos;
DndData *data;
Sheet *sheet;
Part *part;
- data = (DndData *) (gtk_selection_data_get_data (selection_data));
+ data = (DndData *)(gtk_selection_data_get_data (selection_data));
g_return_if_fail (data != NULL);
@@ -397,22 +371,20 @@ part_browser_dnd (GtkSelectionData *selection_data, int x, int y)
library_part = library_get_part (data->br->library, data->part_name);
part = part_new_from_library_part (library_part);
if (!part) {
- oregano_error (_("Unable to load required part"));
+ oregano_error (_ ("Unable to load required part"));
return;
}
item_data_set_pos (ITEM_DATA (part), &pos);
+ sheet_connect_part_item_to_floating_group (sheet, (gpointer)data->schematic_view);
sheet_select_all (sheet, FALSE);
sheet_clear_ghosts (schematic_view_get_sheet (data->schematic_view));
sheet_add_ghost_item (sheet, ITEM_DATA (part));
-
- sheet_connect_part_item_to_floating_group (sheet, (gpointer) data->schematic_view);
}
-static void
-drag_data_get (GtkWidget *widget, GdkDragContext *context,
- GtkSelectionData *selection_data, guint info, guint time, Browser *br)
+static void drag_data_get (GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info, guint time, Browser *br)
{
DndData *data;
GtkTreeSelection *selection;
@@ -429,12 +401,12 @@ drag_data_get (GtkWidget *widget, GdkDragContext *context,
data->library_name = br->library->name;
- // Get the current selected row
+ // Get the current selected row
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (br->list));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (br->list));
if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
- // No selection, Action canceled
+ // No selection, Action canceled
return;
}
@@ -442,11 +414,8 @@ drag_data_get (GtkWidget *widget, GdkDragContext *context,
data->part_name = part_name;
- gtk_selection_data_set (selection_data,
- gtk_selection_data_get_target (selection_data),
- 8,
- (gpointer) data,
- sizeof (DndData));
+ gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8,
+ (gpointer)data, sizeof(DndData));
// gtk_selection_data_set copies the information so we can free it now.
g_free (data);
@@ -455,28 +424,24 @@ drag_data_get (GtkWidget *widget, GdkDragContext *context,
// part_browser_create
//
// Creates a new part browser. This is only called once per schematic window.
-GtkWidget *
-part_browser_create (SchematicView *schematic_view)
+GtkWidget *part_browser_create (SchematicView *schematic_view)
{
Browser *br;
- GtkBuilder *gui;
- GError *perror = NULL;
- char *msg;
+ GtkBuilder *builder;
+ GError *e = NULL;
GtkWidget *w, *view;
GtkCellRenderer *cell_text;
GtkTreeViewColumn *cell_column;
- static GtkTargetEntry dnd_types[] =
- { { "x-application/oregano-part", 0, DRAG_PART_INFO } };
+ static GtkTargetEntry dnd_types[] = {{"x-application/oregano-part", 0, DRAG_PART_INFO}};
- static int dnd_num_types = sizeof (dnd_types) / sizeof (dnd_types[0]);
+ static int dnd_num_types = sizeof(dnd_types) / sizeof(dnd_types[0]);
GtkTreePath *path;
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create part browser"));
+ if ((builder = gtk_builder_new ()) == NULL) {
+ oregano_error (_ ("Could not create part browser"));
return NULL;
- }
- else
- gtk_builder_set_translation_domain (gui, NULL);
+ } else
+ gtk_builder_set_translation_domain (builder, NULL);
br = g_new0 (Browser, 1);
br->preview = NULL;
@@ -485,102 +450,76 @@ part_browser_create (SchematicView *schematic_view)
schematic_view_set_browser (schematic_view, br);
- if (!g_file_test (OREGANO_UIDIR "/part-browser.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall "
- "Oregano to fix this."),
- OREGANO_UIDIR "/part-browser.ui");
-
- oregano_error_with_title (_("Could not create part browser"), msg);
- g_free (msg);
+ if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/part-browser.ui", &e) <= 0) {
+ oregano_error_with_title (_ ("Could not create part browser"), e->message);
+ g_error_free (e);
return NULL;
}
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/part-browser.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create part browser"), msg);
- g_error_free (perror);
- return NULL;
- }
+ view = GTK_WIDGET (gtk_builder_get_object (builder, "viewport1"));
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
- view = GTK_WIDGET (gtk_builder_get_object (gui, "viewport1"));
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (view), 115);
- gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (view),
- 115);
-
w = goo_canvas_new ();
gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (w));
-
+
br->canvas = w;
- g_signal_connect (w, "realize", (GCallback) preview_realized, br);
+ g_signal_connect (w, "realize", (GCallback)preview_realized, br);
- //gtk_widget_set_size_request (w, PREVIEW_WIDTH,
+ // gtk_widget_set_size_request (w, PREVIEW_WIDTH,
// PREVIEW_HEIGHT + PREVIEW_TEXT_HEIGHT);
goo_canvas_set_bounds (GOO_CANVAS (w), 0, 0, PREVIEW_WIDTH,
- (PREVIEW_HEIGHT + PREVIEW_TEXT_HEIGHT));
+ (PREVIEW_HEIGHT + PREVIEW_TEXT_HEIGHT));
br->description = GOO_CANVAS_TEXT (goo_canvas_text_new (
- goo_canvas_get_root_item (GOO_CANVAS (br->canvas)),
- "", 0.0, PREVIEW_HEIGHT - 9.0, 100.0, GOO_CANVAS_ANCHOR_NORTH_WEST,
- "font", "sans 9",
- NULL));
+ goo_canvas_get_root_item (GOO_CANVAS (br->canvas)), "", 0.0, PREVIEW_HEIGHT - 9.0, 100.0,
+ GOO_CANVAS_ANCHOR_NORTH_WEST, "font", "sans 9", NULL));
- // Set up dnd.
- g_signal_connect (G_OBJECT (br->canvas), "drag_data_get",
- G_CALLBACK (drag_data_get), br);
+ // Set up dnd.
+ g_signal_connect (G_OBJECT (br->canvas), "drag_data_get", G_CALLBACK (drag_data_get), br);
- gtk_drag_source_set (br->canvas, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
- dnd_types, dnd_num_types, GDK_ACTION_MOVE);
+ gtk_drag_source_set (br->canvas, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, dnd_types, dnd_num_types,
+ GDK_ACTION_MOVE);
- br->filter_entry = GTK_ENTRY (gtk_builder_get_object (gui, "part_search"));
+ br->filter_entry = GTK_ENTRY (gtk_builder_get_object (builder, "part_search"));
- g_signal_connect (G_OBJECT (br->filter_entry), "changed",
- G_CALLBACK (part_search_change), br);
- g_signal_connect (G_OBJECT (br->filter_entry), "activate",
- G_CALLBACK (part_search_activate), br);
+ g_signal_connect (G_OBJECT (br->filter_entry), "changed", G_CALLBACK (part_search_change), br);
+ g_signal_connect (G_OBJECT (br->filter_entry), "activate", G_CALLBACK (part_search_activate),
+ br);
- // Buttons.
- w = GTK_WIDGET (gtk_builder_get_object (gui, "place_button"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (place_cmd), br);
+ // Buttons.
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "place_button"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (place_cmd), br);
- // Update the libraries option menu
+ // Update the libraries option menu
br->library = g_list_nth_data (oregano.libraries, 0);
- part_browser_setup_libs (br, gui);
+ part_browser_setup_libs (br, builder);
- // Parts list.
- w = GTK_WIDGET (gtk_builder_get_object (gui, "parts_list"));
+ // Parts list.
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "parts_list"));
br->list = w;
- // Create the List Model for TreeView, this is a Real model
+ // Create the List Model for TreeView, this is a Real model
br->real_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
cell_text = gtk_cell_renderer_text_new ();
- cell_column = gtk_tree_view_column_new_with_attributes (
- "", cell_text,
- "text", 0,
- NULL);
+ cell_column = gtk_tree_view_column_new_with_attributes ("", cell_text, "text", 0, NULL);
- // Create the sort model for the items, this sort the real model
- br->sort_model = gtk_tree_model_sort_new_with_model (
- GTK_TREE_MODEL (br->real_model));
+ // Create the sort model for the items, this sort the real model
+ br->sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (br->real_model));
- gtk_tree_sortable_set_sort_column_id (
- GTK_TREE_SORTABLE (br->sort_model),
- 0, GTK_SORT_ASCENDING);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (br->sort_model), 0,
+ GTK_SORT_ASCENDING);
// Create the filter sorted model. This filter items based on user
- // request for fast item search
+ // request for fast item search
br->filter_model = gtk_tree_model_filter_new (br->sort_model, NULL);
- gtk_tree_model_filter_set_visible_func (
- GTK_TREE_MODEL_FILTER (br->filter_model),
- part_list_filter_func, br, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (br->filter_model),
+ part_list_filter_func, br, NULL);
- // If we have TreeFilter use it, if not, just use sorting model only
+ // If we have TreeFilter use it, if not, just use sorting model only
if (br->filter_model)
gtk_tree_view_set_model (GTK_TREE_VIEW (w), br->filter_model);
else
@@ -590,19 +529,15 @@ part_browser_create (SchematicView *schematic_view)
update_list (br);
// Set up TreeView dnd.
- g_signal_connect (G_OBJECT (w), "drag_data_get",
- G_CALLBACK (drag_data_get), br);
+ g_signal_connect (G_OBJECT (w), "drag_data_get", G_CALLBACK (drag_data_get), br);
- gtk_drag_source_set (w, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
- dnd_types, dnd_num_types, GDK_ACTION_MOVE);
+ gtk_drag_source_set (w, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, dnd_types, dnd_num_types,
+ GDK_ACTION_MOVE);
- g_signal_connect (G_OBJECT (w), "cursor_changed",
- G_CALLBACK (select_row), br);
- g_signal_connect (G_OBJECT (w), "row_activated",
- G_CALLBACK (part_selected), br);
+ g_signal_connect (G_OBJECT (w), "cursor_changed", G_CALLBACK (select_row), br);
+ g_signal_connect (G_OBJECT (w), "row_activated", G_CALLBACK (part_selected), br);
- br->viewport = GTK_WIDGET (gtk_builder_get_object (gui,
- "part_browser_vbox"));
+ br->viewport = GTK_WIDGET (gtk_builder_get_object (builder, "part_browser_vbox"));
path = gtk_tree_path_new_first ();
gtk_tree_view_set_cursor (GTK_TREE_VIEW (w), path, NULL, FALSE);
@@ -612,65 +547,59 @@ part_browser_create (SchematicView *schematic_view)
return br->viewport;
}
-static void
-part_browser_setup_libs (Browser *br, GtkBuilder *gui) {
+static void part_browser_setup_libs (Browser *br, GtkBuilder *builder)
+{
GtkWidget *combo_box, *w;
GList *libs;
gboolean first = FALSE;
- w = GTK_WIDGET (gtk_builder_get_object (gui, "library_optionmenu"));
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "library_optionmenu"));
gtk_widget_destroy (w);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "table1"));
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "grid1"));
combo_box = gtk_combo_box_text_new ();
- gtk_table_attach (GTK_TABLE (w), combo_box, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL,
- GTK_SHRINK,
- 0, 0);
+ gtk_grid_attach (GTK_GRID (w), combo_box, 1, 0, 1, 1);
libs = oregano.libraries;
while (libs) {
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box),
- ((Library *)libs->data)->name);
+ ((Library *)libs->data)->name);
libs = libs->next;
if (!first) {
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box),0);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
first = TRUE;
}
}
- g_signal_connect (G_OBJECT (combo_box), "changed",
- G_CALLBACK (library_switch_cb), br);
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (library_switch_cb), br);
}
-static void
-library_switch_cb (GtkWidget *combo_box, Browser *br)
+static void library_switch_cb (GtkWidget *combo_box, Browser *br)
{
GtkTreePath *path;
GList *libs = oregano.libraries;
- br->library = (Library *) g_list_nth_data (libs,
- gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)));
+ br->library =
+ (Library *)g_list_nth_data (libs, gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)));
update_list (br);
-
+
path = gtk_tree_path_new_first ();
gtk_tree_view_set_cursor (GTK_TREE_VIEW (br->list), path, NULL, FALSE);
gtk_tree_path_free (path);
}
-static void
-wrap_string (char* str, int width)
+static void wrap_string (char *str, int width)
{
- const int minl = width/2;
+ const int minl = width / 2;
char *lnbeg, *sppos, *ptr;
int te = 0;
g_return_if_fail (str != NULL);
- lnbeg= sppos = ptr = str;
+ lnbeg = sppos = ptr = str;
while (*ptr) {
if (*ptr == '\t')
@@ -685,7 +614,7 @@ wrap_string (char* str, int width)
te = 0;
}
- if (*ptr=='\n') {
+ if (*ptr == '\n') {
lnbeg = ptr;
te = 0;
}
@@ -693,18 +622,4 @@ wrap_string (char* str, int width)
}
}
-static void
-preview_realized (GtkWidget *widget, Browser *br)
-{
- update_preview (br);
-}
-
-void
-part_browser_reparent (gpointer *br, GtkWidget *new_parent)
-{
- Browser *b;
- g_return_if_fail (br != NULL);
-
- b = (Browser *)br;
- gtk_widget_reparent (GTK_WIDGET (b->viewport), new_parent);
-}
+static void preview_realized (GtkWidget *widget, Browser *br) { update_preview (br); }
diff --git a/src/part-browser.h b/src/part-browser.h
index 6f7c232..6fa3ec7 100644
--- a/src/part-browser.h
+++ b/src/part-browser.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_BROWSER_H
@@ -37,7 +37,7 @@
#include "schematic.h"
-void part_browser_toggle_show (SchematicView *schematic_view);
+void part_browser_toggle_visibility (SchematicView *schematic_view);
GtkWidget *part_browser_create (SchematicView *schematic_view);
void part_browser_dnd (GtkSelectionData *selection_data, gint x, gint y);
void part_browser_place_selected_part (Schematic *sm);
diff --git a/src/pixmaps/Makefile.am b/src/pixmaps/Makefile.am
deleted file mode 100644
index 1e94d03..0000000
--- a/src/pixmaps/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-EXTRA_DIST = \
- README \
- log.xpm \
- menu_zoom.xcf \
- menu_zoom.xpm \
- mini_icon.xpm \
- mini_icon_plot.xcf \
- mini_icon_plot.xpm \
- plot.xpm \
- tool_arrow.xpm \
- tool_text.xpm \
- tool_wire.xpm \
- logo.xpm
diff --git a/src/plot.c b/src/plot.c
index 87d7833..3e1b8a7 100644
--- a/src/plot.c
+++ b/src/plot.c
@@ -4,15 +4,19 @@
*
* Authors:
* Richard Hult <rhult@hem.passagen.se>
- * Ricardo Markiewicz <rmarkie@fi.uba.ar>
- * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
- * Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2006 Ricardo Markiewicz
- * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
@@ -51,64 +55,55 @@
#define PLOT_HEIGHT 300
#define DEBUG_PLOT 0
-#define GET_Y_POINT(y_val,y_min,factor) \
- (PLOT_HEIGHT-((y_val)-(y_min))*(factor))
-#define GET_Y_VALUE(y_point,y_min,factor) \
- ((y_min)+(PLOT_HEIGHT-(y_point))/(factor))
-#define GET_X_POINT(x_val,x_min,factor) (((x_val)-(x_min))*(factor))
-#define GET_X_VALUE(x_point,x_min,factor) ((x_min)+(x_point)/(factor))
+#define GET_Y_POINT(y_val, y_min, factor) (PLOT_HEIGHT - ((y_val) - (y_min)) * (factor))
+#define GET_Y_VALUE(y_point, y_min, factor) ((y_min) + (PLOT_HEIGHT - (y_point)) / (factor))
+#define GET_X_POINT(x_val, x_min, factor) (((x_val) - (x_min)) * (factor))
+#define GET_X_VALUE(x_point, x_min, factor) ((x_min) + (x_point) / (factor))
#define PLOT_AXIS_COLOR "black"
#define PLOT_CURVE_COLOR "medium sea green"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
static guint next_color = 0;
static guint next_pulse = 0;
static guint n_curve_colors = 7;
-static char *plot_curve_colors[] = {
- "white",
- "green",
- "red",
- "yellow",
- "cyan",
- "pink",
- "orange1",
- 0
-};
-
-typedef struct {
- GtkWidget *window;
- GtkWidget *canvas;
- GtkWidget *coord; // shows the coordinates of the mouse
- GtkWidget *combo_box;
-
- GtkWidget *plot;
-
- gboolean show_cursor;
-
- OreganoEngine *sim;
- SimulationData *current;
-
- gboolean logx;
- gboolean logy;
-
- gchar *title;
- gchar *xtitle;
- gchar *ytitle;
-
- gint width; // width of the plot, excluding
- gint height; // axes, titles and padding etc
-
- gdouble plot_min;
- gdouble plot_max;
- gdouble x_min;
- gdouble x_max;
-
- gdouble padding_x; // padding around the plot. Note that
- gdouble padding_y; // titles, axes etc live here
-
- gint selected; // the currently selected plot in the clist
- gint prev_selected;
+static char *plot_curve_colors[] = {"white", "green", "red", "yellow",
+ "cyan", "pink", "orange1", 0};
+
+typedef struct
+{
+ GtkWidget *window;
+ GtkWidget *canvas;
+ GtkWidget *coord; // shows the coordinates of the mouse
+ GtkWidget *combo_box;
+
+ GtkWidget *plot;
+
+ gboolean show_cursor;
+
+ OreganoEngine *sim;
+ SimulationData *current;
+
+ gboolean logx;
+ gboolean logy;
+
+ gchar *title;
+ gchar *xtitle;
+ gchar *ytitle;
+
+ gint width; // width of the plot, excluding
+ gint height; // axes, titles and padding etc
+
+ gdouble plot_min;
+ gdouble plot_max;
+ gdouble x_min;
+ gdouble x_max;
+
+ gdouble padding_x; // padding around the plot. Note that
+ gdouble padding_y; // titles, axes etc live here
+
+ gint selected; // the currently selected plot in the clist
+ gint prev_selected;
} Plot;
static GtkWidget *plot_window_create (Plot *plot);
@@ -118,49 +113,43 @@ static void plot_canvas_movement (GtkWidget *, GdkEventMotion *, Plot *);
static void add_function (GtkMenuItem *menuitem, Plot *plot);
static void close_window (GtkMenuItem *menuitem, Plot *plot);
-static gchar *
-get_variable_units (gchar *str)
+static gchar *get_variable_units (gchar *str)
{
-gchar *tmp;
+ gchar *tmp;
if (str == NULL)
return g_strdup ("##");
- if (!strcmp (str, _("voltage"))) {
+ if (!strcmp (str, _ ("voltage"))) {
tmp = g_strdup ("V");
- }
- else if (!strcmp (str, "db") ) {
+ } else if (!strcmp (str, "db")) {
tmp = g_strdup ("db");
- }
- else if (!strcmp (str, _("time")) ) {
+ } else if (!strcmp (str, _ ("time"))) {
tmp = g_strdup ("s");
- }
- else if (!strcmp (str, _("frequency")) ) {
+ } else if (!strcmp (str, _ ("frequency"))) {
tmp = g_strdup ("Hz");
- }
- else if (!strcmp (str, _("current")) ) {
+ } else if (!strcmp (str, _ ("current"))) {
tmp = g_strdup ("A");
- }
- else {
+ } else if (!strcmp (str, _ ("psd"))) {
+ tmp = g_strdup ("V^2 / Hz");
+ } else {
tmp = g_strdup ("##");
}
return tmp;
}
-static gint
-delete_event_cb (GtkWidget *widget, GdkEvent *event, Plot *plot)
+static gint delete_event_cb (GtkWidget *widget, GdkEvent *event, Plot *plot)
{
plot->window = NULL;
g_object_unref (plot->sim);
- if (plot->ytitle) g_free (plot->ytitle);
+ g_free (plot->ytitle);
g_free (plot);
plot = NULL;
return FALSE;
}
-// Call this to close the plot window
-static void
-destroy_window (GtkWidget *widget, Plot *plot)
+// Call this to close the plot window
+static void destroy_window (GtkWidget *widget, Plot *plot)
{
gtk_widget_destroy (plot->canvas);
gtk_widget_destroy (plot->coord);
@@ -168,43 +157,39 @@ destroy_window (GtkWidget *widget, Plot *plot)
gtk_widget_destroy (plot->window);
g_object_unref (plot->sim);
plot->window = NULL;
- if (plot->title) g_free (plot->title);
+ g_free (plot->title);
g_free (plot);
plot = NULL;
}
-static void
-on_plot_selected (GtkCellRendererToggle *cell_renderer, gchar *path, Plot *plot)
+static void on_plot_selected (GtkCellRendererToggle *cell_renderer, gchar *path, Plot *plot)
{
GPlotFunction *f;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreeView *treeview;
- gboolean activo;
+ gboolean visible = FALSE;
- treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (plot->window),
- "clist"));
+ treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (plot->window), "clist"));
model = gtk_tree_view_get_model (treeview);
- if (!gtk_tree_model_get_iter_from_string (model , &iter, path))
+ if (!gtk_tree_model_get_iter_from_string (model, &iter, path))
return;
- gtk_tree_model_get (model, &iter, 0, &activo, 4, &f, -1);
- activo = !activo;
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, activo, -1);
+ gtk_tree_model_get (model, &iter, 0, &visible, 4, &f, -1);
+ visible = !visible;
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, visible, -1);
- g_object_set (G_OBJECT (f), "visible", activo, NULL);
+ g_object_set (G_OBJECT (f), "visible", visible, NULL);
gtk_widget_queue_draw (plot->plot);
}
-static GPlotFunction*
-create_plot_function_from_simulation_data (guint i, SimulationData *current)
+static GPlotFunction *create_plot_function_from_simulation_data (guint i, SimulationData *current)
{
GPlotFunction *f;
double *X;
double *Y;
- double data;
guint len, j;
gdouble width = 1;
GraphicType graphic_type = FUNCTIONAL_CURVE;
@@ -213,40 +198,33 @@ create_plot_function_from_simulation_data (guint i, SimulationData *current)
len = current->data[i]->len;
X = g_new0 (double, len);
Y = g_new0 (double, len);
-
+
for (j = 0; j < len; j++) {
Y[j] = g_array_index (current->data[i], double, j);
- data = g_array_index (current->data[0], double, j);
- X[j] = data;
+ X[j] = g_array_index (current->data[0], double, j);
}
- if (current->type == FOURIER) {
+ if (current->type == ANALYSIS_TYPE_FOURIER) {
graphic_type = FREQUENCY_PULSE;
next_pulse++;
width = 5.0;
shift_step = X[1] / 20;
- NG_DEBUG (g_strdup_printf ("shift_step = %lf\n", shift_step));
- }
- else {
+ NG_DEBUG ("shift_step = %lf\n", shift_step);
+ } else {
next_pulse = 0;
width = 1.0;
}
f = g_plot_lines_new (X, Y, len);
- g_object_set (G_OBJECT (f), "color",
- plot_curve_colors[(next_color++)%n_curve_colors], NULL);
- g_object_set (G_OBJECT (f), "graph-type",
- graphic_type, NULL);
- g_object_set (G_OBJECT (f), "shift",
- shift_step*next_pulse, NULL);
- g_object_set (G_OBJECT (f), "width",
- width, NULL);
- NG_DEBUG (g_strdup_printf ("plot: create_plot_function_from_simulation_data: shift = %lf\n", 0.1*next_pulse));
+ g_object_set (G_OBJECT (f), "color", plot_curve_colors[(next_color++) % n_curve_colors], NULL);
+ g_object_set (G_OBJECT (f), "graph-type", graphic_type, NULL);
+ g_object_set (G_OBJECT (f), "shift", shift_step * next_pulse, NULL);
+ g_object_set (G_OBJECT (f), "width", width, NULL);
+ NG_DEBUG ("plot: create_plot_function_from_simulation_data: shift = %lf\n", 0.1 * next_pulse);
return f;
}
-static void
-analysis_selected (GtkWidget *combo_box, Plot *plot)
+static void analysis_selected (GtkWidget *combo_box, Plot *plot)
{
int i;
const gchar *ca;
@@ -259,7 +237,7 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
list = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (plot->window), "clist"));
if (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) == -1) {
// Simulation failed?
- g_warning (_("The simulation produced no data!!\n"));
+ g_warning (_ ("The simulation produced no data!!\n"));
return;
}
ca = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo_box));
@@ -268,15 +246,18 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
analysis = oregano_engine_get_results (plot->sim);
for (; analysis; analysis = analysis->next) {
sdat = SIM_DATA (analysis->data);
- if (!strcmp (ca, oregano_engine_get_analysis_name (sdat))) {
+ gchar *analysis_name = oregano_engine_get_analysis_name (sdat);
+ if (!strcmp (ca, analysis_name)) {
plot->current = sdat;
+ g_free(analysis_name);
break;
}
+ g_free(analysis_name);
}
if (plot->current == NULL) {
// Simulation failed?
- g_warning (_("The simulation produced no data!!\n"));
+ g_warning (_ ("The simulation produced no data!!\n"));
return;
}
@@ -286,8 +267,10 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
plot->ytitle = get_variable_units (plot->current->var_units[1]);
g_free (plot->title);
- plot->title = g_strdup_printf (_("Plot - %s"),
- oregano_engine_get_analysis_name (plot->current));
+ gchar *analysis_name = oregano_engine_get_analysis_name (plot->current);
+ plot->title =
+ g_strdup_printf (_ ("Plot - %s"), analysis_name);
+ g_free(analysis_name);
// Set the variable names in the list
model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
@@ -295,12 +278,12 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
// Create root nodes
gtk_tree_store_append (GTK_TREE_STORE (model), &parent_nodes, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (model), &parent_nodes, 0, FALSE, 1,
- _("Nodes"), 2, FALSE, 3, "white", -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent_nodes, 0, FALSE, 1, _ ("Nodes"), 2, FALSE,
+ 3, "white", -1);
gtk_tree_store_append (GTK_TREE_STORE (model), &parent_functions, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (model), &parent_functions, 0, NULL, 1,
- _("Functions"), 2, FALSE, 3, "white", -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent_functions, 0, NULL, 1, _ ("Functions"), 2,
+ FALSE, 3, "white", -1);
g_plot_set_axis_labels (GPLOT (plot->plot), plot->xtitle, plot->ytitle);
g_plot_clear (GPLOT (plot->plot));
@@ -308,27 +291,10 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
for (i = 1; i < plot->current->n_variables; i++) {
GtkTreeIter iter;
GPlotFunction *f;
- if (plot->current->type != DC_TRANSFER) {
- if (strchr(plot->current->var_names[i], '#') == NULL) {
- gchar *color;
-
- f = create_plot_function_from_simulation_data (i,
- plot->current);
- g_object_set (G_OBJECT (f), "visible", FALSE, NULL);
- g_object_get (G_OBJECT (f), "color", &color, NULL);
-
- g_plot_add_function (GPLOT (plot->plot), f);
- gtk_tree_store_append (GTK_TREE_STORE (model), &iter,
- &parent_nodes);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, FALSE,
- 1, plot->current->var_names[i],
- 2, TRUE,
- 3, color,
- 4, f,
- -1);
- }
- }
- else {
+ if (plot->current->type != ANALYSIS_TYPE_DC_TRANSFER) {
+ //FIXME extra axis scaling for current/voltage
+ //FIXME or extra plot window for current/voltage
+ //FIXME or extra analysis for current/voltage
gchar *color;
f = create_plot_function_from_simulation_data (i, plot->current);
@@ -336,40 +302,43 @@ analysis_selected (GtkWidget *combo_box, Plot *plot)
g_object_get (G_OBJECT (f), "color", &color, NULL);
g_plot_add_function (GPLOT (plot->plot), f);
- gtk_tree_store_append (GTK_TREE_STORE (model), &iter,
- &parent_nodes);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
- 0, FALSE,
- 1, plot->current->var_names[i],
- 2, TRUE,
- 3, color,
- 4, f,
- -1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_nodes);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, FALSE, 1,
+ plot->current->var_names[i], 2, TRUE, 3, color, 4, f, -1);
+ } else {
+ gchar *color;
+
+ f = create_plot_function_from_simulation_data (i, plot->current);
+ g_object_set (G_OBJECT (f), "visible", FALSE, NULL);
+ g_object_get (G_OBJECT (f), "color", &color, NULL);
+
+ g_plot_add_function (GPLOT (plot->plot), f);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_nodes);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, FALSE, 1,
+ plot->current->var_names[i], 2, TRUE, 3, color, 4, f, -1);
}
}
gtk_widget_queue_draw (plot->plot);
}
-static void
-plot_canvas_movement (GtkWidget *w, GdkEventMotion *event, Plot *plot)
+static void plot_canvas_movement (GtkWidget *w, GdkEventMotion *event, Plot *plot)
{
- gchar *coord;
- gdouble x,y;
+ gchar *coordstr;
+ gdouble x, y;
x = event->x;
y = event->y;
g_plot_window_to_device (GPLOT (plot->plot), &x, &y);
- coord = g_strdup_printf ("(%g, %g)", x, y);
+ coordstr = g_strdup_printf ("(%g, %g)", x, y);
- gtk_entry_set_text (GTK_ENTRY (plot->coord), coord);
+ gtk_entry_set_text (GTK_ENTRY (plot->coord), coordstr);
- g_free (coord);
+ g_free (coordstr);
}
-static GtkWidget *
-plot_window_create (Plot *plot)
+static GtkWidget *plot_window_create (Plot *plot)
{
GtkTreeView *list;
GtkTreeStore *tree_model;
@@ -381,44 +350,31 @@ plot_window_create (Plot *plot)
GtkBuilder *gui;
GError *perror = NULL;
gchar *msg;
- GtkAccelGroup *accel_group;
+ GtkAccelGroup *accel_group;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (window), _("Oregano - Plot"));
- gtk_container_set_border_width (GTK_CONTAINER (window), 0);
- g_signal_connect (G_OBJECT (window), "delete-event",
- G_CALLBACK (delete_event_cb), plot);
+ gtk_window_set_title (GTK_WINDOW (window), _ ("Oregano - Plot"));
+ gtk_container_set_border_width (GTK_CONTAINER (window), 0);
+ g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (delete_event_cb), plot);
accel_group = gtk_accel_group_new ();
- gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create plot window."));
- return NULL;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/plot-window.ui",G_FILE_TEST_EXISTS))
- {
- msg = g_strdup_printf (_("The file %s could not be found."
- "You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/plot-window.ui");
- oregano_error_with_title (_("Could not create plot window."), msg);
- g_free (msg);
+ oregano_error (_ ("Could not create plot window."));
return NULL;
}
+ gtk_builder_set_translation_domain (gui, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/plot-window.ui",
- &perror) <= 0) {
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/plot-window.ui", &perror) <= 0) {
msg = perror->message;
- oregano_error_with_title (_("Could not create plot window."), msg);
+ oregano_error_with_title (_ ("Could not create plot window."), msg);
g_error_free (perror);
return NULL;
}
- outer_table = GTK_WIDGET (gtk_builder_get_object (gui, "plot_table"));
- plot_scrolled = plot->canvas = GTK_WIDGET (gtk_builder_get_object (gui,
- "plot_scrolled"));
- plot->coord = GTK_WIDGET (gtk_builder_get_object (gui, "pos_label"));
+ outer_table = GTK_WIDGET (gtk_builder_get_object (gui, "plot_grid"));
+ plot_scrolled = plot->canvas = GTK_WIDGET (gtk_builder_get_object (gui, "plot_scrolled"));
+ plot->coord = GTK_WIDGET (gtk_builder_get_object (gui, "pos_label"));
plot->plot = g_plot_new ();
@@ -426,62 +382,59 @@ plot_window_create (Plot *plot)
gtk_widget_set_size_request (plot_scrolled, 600, 400);
g_signal_connect (G_OBJECT (plot->plot), "motion_notify_event",
- G_CALLBACK (plot_canvas_movement), plot);
+ G_CALLBACK (plot_canvas_movement), plot);
- // Creation of the menubar
+ // Creation of the menubar
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- menubar = gtk_menu_bar_new ();
+ menubar = gtk_menu_bar_new ();
gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, TRUE, 0);
- gtk_widget_show (menubar);
+ gtk_widget_show (menubar);
// Creation of the menu
menu = gtk_menu_new ();
- menuitem = gtk_menu_item_new_with_label (_("Add Function"));
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
- g_signal_connect (menuitem, "activate", G_CALLBACK (add_function),
- plot);
+ //add Add Function menuitem
+ menuitem = gtk_menu_item_new_with_label (_ ("Add Function"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ g_signal_connect (menuitem, "activate", G_CALLBACK (add_function), plot);
gtk_widget_show (menuitem);
+ //add separator
menuitem = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
- menuitem = gtk_menu_item_new_with_label (_("Close"));
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
- g_signal_connect (menuitem, "activate", G_CALLBACK (close_window),
- plot);
+ menuitem = gtk_menu_item_new_with_label (_ ("Close"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ g_signal_connect (menuitem, "activate", G_CALLBACK (close_window), plot);
gtk_widget_show (menuitem);
// Installation of the menu in the menubar
- menuitem = gtk_menu_item_new_with_label (_("File"));
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
- gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
- gtk_widget_show (menuitem);
-
+ menuitem = gtk_menu_item_new_with_label (_ ("File"));
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
+ gtk_widget_show (menuitem);
+
g_object_ref (outer_table);
gtk_widget_unparent (outer_table);
gtk_container_add (GTK_CONTAINER (vbox), outer_table);
gtk_widget_show (vbox);
-
+
g_object_ref (vbox);
gtk_widget_unparent (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
-
+
button = GTK_WIDGET (gtk_builder_get_object (gui, "close_button"));
- g_signal_connect (G_OBJECT (button), "clicked",
- G_CALLBACK (destroy_window), plot);
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (destroy_window), plot);
list = GTK_TREE_VIEW (gtk_builder_get_object (gui, "variable_list"));
- tree_model = gtk_tree_store_new (5, G_TYPE_BOOLEAN, G_TYPE_STRING,
- G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
+ tree_model = gtk_tree_store_new (5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_BOOLEAN,
+ G_TYPE_STRING, G_TYPE_POINTER);
// One Column with 2 CellRenderer. First the Toggle and next a Text
column = gtk_tree_view_column_new ();
cell = gtk_cell_renderer_toggle_new ();
- g_signal_connect (G_OBJECT (cell), "toggled",
- G_CALLBACK (on_plot_selected), plot);
+ g_signal_connect (G_OBJECT (cell), "toggled", G_CALLBACK (on_plot_selected), plot);
gtk_tree_view_column_pack_start (column, cell, FALSE);
- gtk_tree_view_column_set_attributes (column, cell, "active", 0, "visible",
- 2, NULL);
+ gtk_tree_view_column_set_attributes (column, cell, "active", 0, "visible", 2, NULL);
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, cell, FALSE);
@@ -502,14 +455,10 @@ plot_window_create (Plot *plot)
w = GTK_WIDGET (gtk_builder_get_object (gui, "analysis_combobox"));
gtk_widget_destroy (w);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "table1"));
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "grid1"));
combo_box = gtk_combo_box_text_new_with_entry ();
-
- gtk_table_attach (GTK_TABLE (w),combo_box,0,1,0,1,
- GTK_SHRINK,
- //GTK_EXPAND | GTK_FILL,
- GTK_SHRINK,
- 0, 0);
+
+ gtk_grid_attach (GTK_GRID (w), combo_box, 0, 0, 1, 1);
plot->combo_box = combo_box;
plot->window = window;
@@ -518,17 +467,32 @@ plot_window_create (Plot *plot)
return window;
}
-int
-plot_show (OreganoEngine *engine)
+int plot_show (OreganoEngine *engine)
{
GList *analysis = NULL;
- GList *combo_items = NULL;
+ GList *analysis_backup = NULL;
Plot *plot;
+ gchar *str = NULL;
gchar *s_current = NULL;
SimulationData *first = NULL;
+ SimulationData *sdat = NULL;
+ gboolean abort = TRUE;
g_return_val_if_fail (engine != NULL, FALSE);
+ // Get the analysis we have
+ analysis = analysis_backup = oregano_engine_get_results (engine);
+
+ for (; analysis; analysis = analysis->next) {
+ sdat = SIM_DATA (analysis->data);
+ str = oregano_engine_get_analysis_name (sdat);
+ if (sdat->type != ANALYSIS_TYPE_OP_POINT)
+ abort = FALSE;
+ }
+
+ if (abort)
+ return FALSE;
+
plot = g_new0 (Plot, 1);
g_object_ref (engine);
@@ -545,28 +509,25 @@ plot_show (OreganoEngine *engine)
next_color = 0;
- // Get the analysis we have
- analysis = oregano_engine_get_results (engine);
-
- for (; analysis ; analysis = analysis->next) {
- SimulationData *sdat = SIM_DATA (analysis->data);
- gchar *str = oregano_engine_get_analysis_name (sdat);
- if (sdat->type == OP_POINT) {
+ for (; analysis_backup; analysis_backup = analysis_backup->next) {
+ sdat = SIM_DATA (analysis_backup->data);
+ str = oregano_engine_get_analysis_name (sdat);
+ if (sdat->type == ANALYSIS_TYPE_OP_POINT) {
continue;
}
+
if (s_current == NULL) {
s_current = str;
first = sdat;
}
- combo_items = g_list_append (combo_items, str);
+
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (plot->combo_box), str);
- gtk_combo_box_set_active (GTK_COMBO_BOX (plot->combo_box),0);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (plot->combo_box), 0);
}
-
- g_signal_connect (G_OBJECT (plot->combo_box), "changed",
- G_CALLBACK (analysis_selected), plot);
- plot->title = g_strdup_printf (_("Plot - %s"), s_current);
+ g_signal_connect (G_OBJECT (plot->combo_box), "changed", G_CALLBACK (analysis_selected), plot);
+
+ plot->title = g_strdup_printf (_ ("Plot - %s"), s_current);
plot->xtitle = get_variable_units (first ? first->var_units[0] : "##");
plot->ytitle = get_variable_units (first ? first->var_units[1] : "!!");
@@ -577,9 +538,8 @@ plot_show (OreganoEngine *engine)
return TRUE;
}
-static GPlotFunction*
-create_plot_function_from_data (SimulationFunction *func,
- SimulationData *current)
+static GPlotFunction *create_plot_function_from_data (SimulationFunction *func,
+ SimulationData *current)
{
GPlotFunction *f;
double *X;
@@ -595,55 +555,47 @@ create_plot_function_from_data (SimulationFunction *func,
for (j = 0; j < len; j++) {
Y[j] = g_array_index (current->data[func->first], double, j);
-
+
data = g_array_index (current->data[func->second], double, j);
switch (func->type) {
- case FUNCTION_MINUS:
- Y[j] -= data;
+ case FUNCTION_SUBTRACT:
+ Y[j] -= data;
break;
- case FUNCTION_TRANSFER:
- if (data < 0.000001f) {
- if (Y[j] < 0)
- Y[j] = -G_MAXDOUBLE;
- else
- Y[j] = G_MAXDOUBLE;
- }
- else {
- Y[j] /= data;
- }
+ case FUNCTION_DIVIDE:
+ if (data < 0.000001f) {
+ if (Y[j] < 0)
+ Y[j] = -G_MAXDOUBLE;
+ else
+ Y[j] = G_MAXDOUBLE;
+ } else {
+ Y[j] /= data;
+ }
}
-
+
X[j] = g_array_index (current->data[0], double, j);
}
- if (current->type == FOURIER) {
+ if (current->type == ANALYSIS_TYPE_FOURIER) {
graphic_type = FREQUENCY_PULSE;
next_pulse++;
width = 5.0;
- }
- else {
+ } else {
next_pulse = 0;
width = 1.0;
}
f = g_plot_lines_new (X, Y, len);
- g_object_set (G_OBJECT (f),
- "color", plot_curve_colors[(next_color++)%n_curve_colors],
- "graph-type", graphic_type,
- "shift", 50.0*next_pulse,
- "width", width,
- NULL);
+ g_object_set (G_OBJECT (f), "color", plot_curve_colors[(next_color++) % n_curve_colors],
+ "graph-type", graphic_type, "shift", 50.0 * next_pulse, "width", width, NULL);
return f;
}
-static void
-close_window (GtkMenuItem *menuitem, Plot *plot)
+static void close_window (GtkMenuItem *menuitem, Plot *plot)
{
destroy_window (GTK_WIDGET (menuitem), plot);
}
-static void
-add_function (GtkMenuItem *menuitem, Plot *plot)
+static void add_function (GtkMenuItem *menuitem, Plot *plot)
{
GtkTreeView *tree;
GtkTreeModel *model;
@@ -654,27 +606,27 @@ add_function (GtkMenuItem *menuitem, Plot *plot)
plot_add_function_show (plot->sim, plot->current);
- tree = GTK_TREE_VIEW (g_object_get_data(G_OBJECT (plot->window), "clist"));
+ tree = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (plot->window), "clist"));
model = gtk_tree_view_get_model (tree);
path = gtk_tree_path_new_from_string ("1");
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
-
+
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
- gtk_tree_store_append(GTK_TREE_STORE (model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, FALSE, 1,
- _("Functions"), 2, FALSE, 3, "white", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, FALSE, 1, _ ("Functions"), 2, FALSE, 3,
+ "white", -1);
lst = plot->current->functions;
- while (lst) {
+ while (lst) {
GPlotFunction *f;
GtkTreeIter child;
int i;
gchar *str = NULL, *name1 = NULL, *name2 = NULL;
SimulationFunction *func = (SimulationFunction *)lst->data;
-
+
for (i = 1; i < plot->current->n_variables; i++) {
if (func->first == i) {
name1 = g_strdup (plot->current->var_names[i]);
@@ -684,12 +636,11 @@ add_function (GtkMenuItem *menuitem, Plot *plot)
}
}
switch (func->type) {
- case FUNCTION_MINUS:
- str = g_strdup_printf ("%s - %s", name1, name2);
+ case FUNCTION_SUBTRACT:
+ str = g_strdup_printf ("%s - %s", name1, name2);
break;
- case FUNCTION_TRANSFER:
- str = g_strdup_printf ("%s(%s, %s)", _("TRANSFER"), name1,
- name2);
+ case FUNCTION_DIVIDE:
+ str = g_strdup_printf ("%s(%s, %s)", _ ("TRANSFER"), name1, name2);
}
f = create_plot_function_from_data (func, plot->current);
@@ -698,8 +649,8 @@ add_function (GtkMenuItem *menuitem, Plot *plot)
g_plot_add_function (GPLOT (plot->plot), f);
gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
- gtk_tree_store_set (GTK_TREE_STORE (model), &child, 0, TRUE, 1, str, 2,
- TRUE, 3, color, 4, f, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &child, 0, TRUE, 1, str, 2, TRUE, 3, color, 4,
+ f, -1);
lst = lst->next;
}
diff --git a/src/plot.h b/src/plot.h
index 5244dc4..de99f62 100644
--- a/src/plot.h
+++ b/src/plot.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PLOT_H
diff --git a/src/save-schematic.c b/src/save-schematic.c
index 393c7b4..3253eff 100644
--- a/src/save-schematic.c
+++ b/src/save-schematic.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,14 +30,14 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "xml-compat.h"
#include "oregano.h"
#include "schematic.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "load-library.h"
#include "part.h"
#include "textbox.h"
@@ -45,25 +49,24 @@
#include "save-schematic.h"
#include "xml-helper.h"
+#include "debug.h"
-#define NG_DEBUG(s) if (1) g_print ("%s\n", s)
-
-typedef struct {
- xmlDocPtr doc; // Xml document.
- xmlNsPtr ns; // Main namespace.
-
- xmlNodePtr node_symbols; // For saving of symbols.
- xmlNodePtr node_parts; // For saving of parts.
- xmlNodePtr node_props; // For saving of properties.
- xmlNodePtr node_labels; // For saving of labels.
- xmlNodePtr node_wires; // For saving of wires.
+typedef struct
+{
+ xmlDocPtr doc; // Xml document.
+ xmlNsPtr ns; // Main namespace.
+
+ xmlNodePtr node_symbols; // For saving of symbols.
+ xmlNodePtr node_parts; // For saving of parts.
+ xmlNodePtr node_props; // For saving of properties.
+ xmlNodePtr node_labels; // For saving of labels.
+ xmlNodePtr node_wires; // For saving of wires.
xmlNodePtr node_textboxes;
} parseXmlContext;
-static void
-write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
+static void write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
{
- xmlNodePtr sim_settings_node, child,analysis,options;
+ xmlNodePtr sim_settings_node, child, analysis, options;
gchar *str;
SimSettings *s;
SimOption *so;
@@ -71,17 +74,15 @@ write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
s = schematic_get_sim_settings (sm);
- sim_settings_node = xmlNewChild (cur, ctxt->ns,
- BAD_CAST"simulation-settings", NULL);
+ sim_settings_node = xmlNewChild (cur, ctxt->ns, BAD_CAST "simulation-settings", NULL);
if (!sim_settings_node) {
g_warning ("Failed during save of simulation settings.\n");
return;
}
- // Transient analysis
- analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "transient",
- NULL);
- if (!analysis) {
+ // Transient analysis
+ analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "transient", NULL);
+ if (!analysis) {
g_warning ("Failed during save of transient analysis settings.\n");
return;
}
@@ -110,20 +111,32 @@ write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
str = "false";
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "step-enabled", BAD_CAST str);
- if (sim_settings_get_trans_init_cond(s))
+ if (sim_settings_get_trans_init_cond (s))
str = "true";
else
str = "false";
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "init-conditions", BAD_CAST str);
- // AC analysis
- analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "ac", NULL);
+ if (sim_settings_get_trans_analyze_all(s))
+ str = "true";
+ else
+ str = "false";
+ child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "analyze-all", BAD_CAST str);
+
+ // AC analysis
+ analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "ac", NULL);
if (!analysis) {
g_warning ("Failed during save of AC analysis settings.\n");
return;
}
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "enabled",
- BAD_CAST (sim_settings_get_ac (s) ? "true" : "false") );
+ BAD_CAST (sim_settings_get_ac (s) ? "true" : "false"));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "vout1", BAD_CAST sim_settings_get_ac_vout (s));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "type", BAD_CAST sim_settings_get_ac_type (s));
str = g_strdup_printf ("%d", sim_settings_get_ac_npoints (s));
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "npoints", BAD_CAST str);
@@ -137,18 +150,20 @@ write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "stop", BAD_CAST str);
g_free (str);
- // DC analysis
- analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "dc-sweep",
- NULL);
+ // DC analysis
+ analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "dc-sweep", NULL);
if (!analysis) {
g_warning ("Failed during save of DC sweep analysis settings.\n");
return;
}
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "enabled",
- BAD_CAST (sim_settings_get_dc (s) ? "true" : "false") );
+ BAD_CAST (sim_settings_get_dc (s) ? "true" : "false"));
- child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "vsrc1",
- BAD_CAST sim_settings_get_dc_vsrc(s));
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "vsrc1", BAD_CAST sim_settings_get_dc_vsrc (s));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "vout1", BAD_CAST sim_settings_get_dc_vout (s));
str = g_strdup_printf ("%g", sim_settings_get_dc_start (s));
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "start1", BAD_CAST str);
@@ -161,68 +176,94 @@ write_xml_sim_settings (xmlNodePtr cur, parseXmlContext *ctxt, Schematic *sm)
str = g_strdup_printf ("%g", sim_settings_get_dc_step (s));
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "step1", BAD_CAST str);
g_free (str);
-
- // Fourier analysis
- analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "fourier", NULL);
+
+ // Fourier analysis
+ analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "fourier", NULL);
if (!analysis) {
g_warning ("Failed during save of Fourier analysis settings.\n");
return;
}
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "enabled",
- BAD_CAST (sim_settings_get_fourier (s) ? "true" : "false") );
+ BAD_CAST (sim_settings_get_fourier (s) ? "true" : "false"));
- str = g_strdup_printf ("%d", sim_settings_get_fourier_frequency (s));
+ str = g_strdup_printf ("%.3f", sim_settings_get_fourier_frequency (s));
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "freq", BAD_CAST str);
g_free (str);
-
+
str = g_strdup_printf ("%s", sim_settings_get_fourier_vout (s));
child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "vout", BAD_CAST str);
g_free (str);
- // Save the options
+ // Noise analysis
+ analysis = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "noise", NULL);
+ if (!analysis) {
+ g_warning ("Failed during save of Noise analysis settings.\n");
+ return;
+ }
+ child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "enabled",
+ BAD_CAST (sim_settings_get_noise (s) ? "true" : "false"));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "vsrc1", BAD_CAST sim_settings_get_noise_vsrc (s));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "vout1", BAD_CAST sim_settings_get_noise_vout (s));
+
+ child =
+ xmlNewChild (analysis, ctxt->ns, BAD_CAST "type", BAD_CAST sim_settings_get_noise_type (s));
+
+ str = g_strdup_printf ("%d", sim_settings_get_noise_npoints (s));
+ child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "npoints", BAD_CAST str);
+ g_free (str);
+
+ str = g_strdup_printf ("%g", sim_settings_get_noise_start (s));
+ child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "start", BAD_CAST str);
+ g_free (str);
+
+ str = g_strdup_printf ("%g", sim_settings_get_noise_stop (s));
+ child = xmlNewChild (analysis, ctxt->ns, BAD_CAST "stop", BAD_CAST str);
+ g_free (str);
+
+ // Save the options
list = sim_settings_get_options (s);
- if ( list ) {
- options = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "options",
- NULL);
+ if (list) {
+ options = xmlNewChild (sim_settings_node, ctxt->ns, BAD_CAST "options", NULL);
if (!options) {
g_warning ("Failed during save of sim engine options.\n");
return;
}
- while ( list ) {
- so = list->data;
- child=xmlNewChild (options, ctxt->ns, BAD_CAST "option", NULL);
- xmlNewChild (child , ctxt->ns, BAD_CAST "name", BAD_CAST so->name);
- xmlNewChild (child , ctxt->ns, BAD_CAST "value", BAD_CAST so->value);
+ while (list) {
+ so = list->data;
+ child = xmlNewChild (options, ctxt->ns, BAD_CAST "option", NULL);
+ xmlNewChild (child, ctxt->ns, BAD_CAST "name", BAD_CAST so->name);
+ xmlNewChild (child, ctxt->ns, BAD_CAST "value", BAD_CAST so->value);
list = list->next;
}
}
}
-static void
-write_xml_property (Property *prop, parseXmlContext *ctxt)
+static void write_xml_property (Property *prop, parseXmlContext *ctxt)
{
xmlNodePtr node_property;
- // Create a node for the property.
- node_property = xmlNewChild (ctxt->node_props, ctxt->ns, BAD_CAST "property",
- NULL);
+ // Create a node for the property.
+ node_property = xmlNewChild (ctxt->node_props, ctxt->ns, BAD_CAST "property", NULL);
if (!node_property) {
g_warning ("Failed during save of property %s.\n", prop->name);
return;
}
- // Store the name.
+ // Store the name.
xmlNewChild (node_property, ctxt->ns, BAD_CAST "name",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST prop->name));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST prop->name));
- // Store the value.
+ // Store the value.
xmlNewChild (node_property, ctxt->ns, BAD_CAST "value",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST prop->value));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST prop->value));
}
-static void
-write_xml_label (PartLabel *label, parseXmlContext *ctxt)
+static void write_xml_label (PartLabel *label, parseXmlContext *ctxt)
{
xmlNodePtr node_label;
gchar *str;
@@ -234,101 +275,103 @@ write_xml_label (PartLabel *label, parseXmlContext *ctxt)
return;
}
- // Store the name.
+ // Store the name.
xmlNewChild (node_label, ctxt->ns, BAD_CAST "name",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST label->name));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST label->name));
// Store the value.
xmlNewChild (node_label, ctxt->ns, BAD_CAST "text",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST label->text));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST label->text));
- str = g_strdup_printf ("(%g %g)", label->pos.x, label->pos.y);
+ str = g_strdup_printf ("(%g %g)", label->pos.x, label->pos.y);
xmlNewChild (node_label, ctxt->ns, BAD_CAST "position", BAD_CAST str);
g_free (str);
}
-static void
-write_xml_part (Part *part, parseXmlContext *ctxt)
+static void write_xml_part (Part *part, parseXmlContext *ctxt)
{
PartPriv *priv;
xmlNodePtr node_part;
gchar *str;
- SheetPos pos;
+ Coords pos;
+
+ g_return_if_fail (part != NULL);
+ g_return_if_fail (IS_PART (part));
priv = part->priv;
- // Create a node for the part.
+ // Create a node for the part.
node_part = xmlNewChild (ctxt->node_parts, ctxt->ns, BAD_CAST "part", NULL);
if (!node_part) {
g_warning ("Failed during save of part %s.\n", priv->name);
return;
}
- str = g_strdup_printf ("%d", priv->rotation);
+ str = g_strdup_printf ("%d", part_get_rotation (part));
xmlNewChild (node_part, ctxt->ns, BAD_CAST "rotation",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
g_free (str);
if (priv->flip & ID_FLIP_HORIZ)
xmlNewChild (node_part, ctxt->ns, BAD_CAST "flip",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "horizontal"));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "horizontal"));
if (priv->flip & ID_FLIP_VERT)
xmlNewChild (node_part, ctxt->ns, BAD_CAST "flip",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "vertical"));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "vertical"));
- // Store the name.
+ // Store the name.
xmlNewChild (node_part, ctxt->ns, BAD_CAST "name",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->name));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->name));
- // Store the name of the library the part resides in.
+ // Store the name of the library the part resides in.
xmlNewChild (node_part, ctxt->ns, BAD_CAST "library",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->library->name));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->library->name));
- // Which symbol to use.
+ // Which symbol to use.
xmlNewChild (node_part, ctxt->ns, BAD_CAST "symbol",
- xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->symbol_name));
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->symbol_name));
- // Position.
+ // Position.
item_data_get_pos (ITEM_DATA (part), &pos);
str = g_strdup_printf ("(%g %g)", pos.x, pos.y);
xmlNewChild (node_part, ctxt->ns, BAD_CAST "position", BAD_CAST str);
g_free (str);
- // Create a node for the properties.
- ctxt->node_props = xmlNewChild (node_part, ctxt->ns, BAD_CAST "properties",
- NULL);
+ // Create a node for the properties.
+ ctxt->node_props = xmlNewChild (node_part, ctxt->ns, BAD_CAST "properties", NULL);
if (!ctxt->node_props) {
g_warning ("Failed during save of part %s.\n", priv->name);
return;
- }
- else{
- g_slist_foreach (priv->properties, (GFunc) write_xml_property,
- ctxt);
+ } else {
+ g_slist_foreach (priv->properties, (GFunc)write_xml_property, ctxt);
}
- // Create a node for the labels.
+ // Create a node for the labels.
ctxt->node_labels = xmlNewChild (node_part, ctxt->ns, BAD_CAST "labels", NULL);
if (!ctxt->node_labels) {
g_warning ("Failed during save of part %s.\n", priv->name);
return;
+ } else {
+ g_slist_foreach (priv->labels, (GFunc)write_xml_label, ctxt);
}
- else{
- g_slist_foreach (priv->labels, (GFunc) write_xml_label, ctxt);
- }
}
-static void
-write_xml_wire (Wire *wire, parseXmlContext *ctxt)
+static gint cmp_nodes (gconstpointer a, gconstpointer b)
+{
+ return coords_compare (&(((const Node *)a)->key), &(((const Node *)b)->key));
+}
+
+static void write_xml_wire (Wire *wire, parseXmlContext *ctxt)
{
xmlNodePtr node_wire;
gchar *str;
- SheetPos start_pos, end_pos;
+ Coords start_pos, end_pos;
g_return_if_fail (wire != NULL);
g_return_if_fail (IS_WIRE (wire));
- // Create a node for the wire.
+ // Create a node for the wire.
node_wire = xmlNewChild (ctxt->node_wires, ctxt->ns, BAD_CAST "wire", NULL);
if (!node_wire) {
g_warning ("Failed during save of wire.\n");
@@ -338,26 +381,56 @@ write_xml_wire (Wire *wire, parseXmlContext *ctxt)
wire_get_start_pos (wire, &start_pos);
wire_get_end_pos (wire, &end_pos);
- str = g_strdup_printf ("(%g %g)(%g %g)",
- start_pos.x, start_pos.y, end_pos.x, end_pos.y);
+ Node *node;
+ Coords last, current, tmp;
+ GSList *iter, *copy;
+
+ copy = g_slist_sort (g_slist_copy (wire_get_nodes (wire)), cmp_nodes);
+ current = last = start_pos;
+
+ for (iter = copy; iter; iter = iter->next) {
+ node = iter->data;
+ if (node == NULL) {
+ g_warning ("Node of wire did not exist [%p].", node);
+ continue;
+ }
+
+ tmp = node->key;
+ if (coords_equal (&tmp, &start_pos))
+ continue;
+ if (coords_equal (&tmp, &end_pos))
+ continue;
+
+ last = current;
+ current = tmp;
+
+ str = g_strdup_printf ("(%g %g)(%g %g)", last.x, last.y, current.x, current.y);
+
+ xmlNewChild (node_wire, ctxt->ns, BAD_CAST "points", BAD_CAST str);
+ g_free (str);
+ }
+ last = current;
+ current = end_pos;
+ str = g_strdup_printf ("(%g %g)(%g %g)", last.x, last.y, current.x, current.y);
+
xmlNewChild (node_wire, ctxt->ns, BAD_CAST "points", BAD_CAST str);
g_free (str);
+
+ g_slist_free (copy);
}
-static void
-write_xml_textbox (Textbox *textbox, parseXmlContext *ctxt)
+static void write_xml_textbox (Textbox *textbox, parseXmlContext *ctxt)
{
xmlNodePtr node_textbox;
gchar *str;
- SheetPos pos;
+ Coords pos;
g_return_if_fail (textbox != NULL);
if (!IS_TEXTBOX (textbox))
return;
// Create a node for the textbox.
- node_textbox = xmlNewChild (ctxt->node_textboxes, ctxt->ns,
- BAD_CAST "textbox", NULL);
+ node_textbox = xmlNewChild (ctxt->node_textboxes, ctxt->ns, BAD_CAST "textbox", NULL);
if (!node_textbox) {
g_warning ("Failed during save of text box.\n");
return;
@@ -373,9 +446,8 @@ write_xml_textbox (Textbox *textbox, parseXmlContext *ctxt)
xmlNewChild (node_textbox, ctxt->ns, BAD_CAST "text", BAD_CAST str);
}
-// Create an XML subtree of doc equivalent to the given Schematic.
-static xmlNodePtr
-write_xml_schematic (parseXmlContext *ctxt, Schematic *sm, GError **error)
+// Create an XML subtree of doc equivalent to the given Schematic.
+static xmlNodePtr write_xml_schematic (parseXmlContext *ctxt, Schematic *sm, GError **error)
{
xmlNodePtr cur;
xmlNodePtr grid;
@@ -384,51 +456,56 @@ write_xml_schematic (parseXmlContext *ctxt, Schematic *sm, GError **error)
cur = xmlNewDocNode (ctxt->doc, ctxt->ns, BAD_CAST "schematic", NULL);
if (cur == NULL) {
- printf ("%s:%d NULL that shall be not NULL!\n", __FILE__,
- __LINE__);
+ printf ("%s:%d NULL that shall be not NULL!\n", __FILE__, __LINE__);
return NULL;
}
if (ctxt->ns == NULL) {
- ogo = xmlNewNs (cur,
- BAD_CAST "http://www.dtek.chalmers.se/~d4hult/oregano/v1",
- BAD_CAST "ogo");
- xmlSetNs (cur,ogo);
+ ogo = xmlNewNs (cur, BAD_CAST "https://beerbach.me/project/oregano/ns/v1", BAD_CAST "ogo");
+ xmlSetNs (cur, ogo);
ctxt->ns = ogo;
}
- // General information about the Schematic.
+ // General information about the Schematic.
str = g_strdup_printf ("%s", schematic_get_author (sm));
- xmlNewChild (cur, ctxt->ns, BAD_CAST "author", xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
+ xmlNewChild (cur, ctxt->ns, BAD_CAST "author",
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
g_free (str);
str = g_strdup_printf ("%s", schematic_get_title (sm));
- xmlNewChild (cur, ctxt->ns, BAD_CAST "title", xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
+ xmlNewChild (cur, ctxt->ns, BAD_CAST "title",
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
+ g_free (str);
+
+ str = g_strdup_printf ("%s", schematic_get_version (sm));
+ xmlNewChild (cur, ctxt->ns, BAD_CAST "version",
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
g_free (str);
str = g_strdup_printf ("%s", schematic_get_comments (sm));
- xmlNewChild (cur, ctxt->ns, BAD_CAST "comments", xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
+ xmlNewChild (cur, ctxt->ns, BAD_CAST "comments",
+ xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
g_free (str);
- // Grid.
+ // Grid.
grid = xmlNewChild (cur, ctxt->ns, BAD_CAST "grid", NULL);
xmlNewChild (grid, ctxt->ns, BAD_CAST "visible", BAD_CAST "true");
xmlNewChild (grid, ctxt->ns, BAD_CAST "snap", BAD_CAST "true");
-
- // Simulation settings.
+
+ // Simulation settings.
write_xml_sim_settings (cur, ctxt, sm);
- // Parts.
+ // Parts.
ctxt->node_parts = xmlNewChild (cur, ctxt->ns, BAD_CAST "parts", NULL);
- schematic_parts_foreach (sm, (gpointer) write_xml_part, ctxt);
+ schematic_parts_foreach (sm, (gpointer)write_xml_part, ctxt);
- // Wires.
+ // Wires.
ctxt->node_wires = xmlNewChild (cur, ctxt->ns, BAD_CAST "wires", NULL);
- schematic_wires_foreach (sm, (gpointer) write_xml_wire, ctxt);
+ schematic_wires_foreach (sm, (gpointer)write_xml_wire, ctxt);
- // Text boxes.
+ // Text boxes.
ctxt->node_textboxes = xmlNewChild (cur, ctxt->ns, BAD_CAST "textboxes", NULL);
- schematic_items_foreach (sm, (gpointer) write_xml_textbox, ctxt);
+ schematic_items_foreach (sm, (gpointer)write_xml_textbox, ctxt);
return cur;
}
@@ -436,17 +513,16 @@ write_xml_schematic (parseXmlContext *ctxt, Schematic *sm, GError **error)
// schematic_write_xml
//
// Save a Sheet to an XML file.
-gint
-schematic_write_xml (Schematic *sm, GError **error)
+gboolean schematic_write_xml (Schematic *sm, GError **error)
{
int ret = -1;
xmlDocPtr xml;
parseXmlContext ctxt;
- GError *internal_error = NULL;
+ GError *err = NULL;
g_return_val_if_fail (sm != NULL, FALSE);
- // Create the tree.
+ // Create the tree.
xml = xmlNewDoc (BAD_CAST "1.0");
if (xml == NULL) {
return FALSE;
@@ -455,34 +531,33 @@ schematic_write_xml (Schematic *sm, GError **error)
ctxt.ns = NULL;
ctxt.doc = xml;
- xmlDocSetRootElement (xml, write_xml_schematic (&ctxt, sm, &internal_error));
+ xmlDocSetRootElement (xml, write_xml_schematic (&ctxt, sm, &err));
- if (internal_error) {
- g_propagate_error (error, internal_error);
+ if (err) {
+ g_propagate_error (error, err);
return FALSE;
}
- // Dump the tree.
+ // Dump the tree.
xmlSetDocCompressMode (xml, oregano.compress_files ? 9 : 0);
{
- char *s =schematic_get_filename (sm);
+ char *s = schematic_get_filename (sm);
if (s != NULL) {
ret = xmlSaveFormatFile (s, xml, 1);
- }
- else {
+ } else {
g_warning ("Schematic has no filename!!\n");
}
}
if (xml != NULL) {
xmlFreeDoc (xml);
- }
- else {
+ } else {
g_warning ("XML object is NULL\n");
}
if (ret < 0)
return FALSE;
+
return TRUE;
}
diff --git a/src/save-schematic.h b/src/save-schematic.h
index b65e66d..8748aa3 100644
--- a/src/save-schematic.h
+++ b/src/save-schematic.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _SAVE_SCHEMATIC_H
@@ -37,6 +37,6 @@
#include "schematic.h"
-gint schematic_write_xml (Schematic *sm, GError **error);
+gboolean schematic_write_xml (Schematic *sm, GError **error);
#endif
diff --git a/src/schematic-view-menu.h b/src/schematic-view-menu.h
index e13d1f7..7855dda 100644
--- a/src/schematic-view-menu.h
+++ b/src/schematic-view-menu.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,165 +28,212 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _SCHEMATIC_VIEW_MENU_
#define _SCHEMATIC_VIEW_MENU_
+
+#include "sim-settings-gui.h"
+
+// TODO: Create only two entries instead of four for stretching the schematic horizontally
+// or vertically (needs proper icons not provided by Gtk).
static GtkActionEntry entries[] = {
- // Name, ICON, Text, CTRL, DESC, CALLBACK
- {"MenuFile", NULL, N_("_File")},
- {"MenuEdit", NULL, N_("_Edit")},
- {"MenuTools", NULL, N_("_Tools")},
- {"MenuView", NULL, N_("_View")},
- {"MenuHelp", NULL, N_("_Help")},
- {"MenuZoom", NULL, N_("_Zoom")},
- {"New", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("Create a new schematic"), G_CALLBACK (new_cmd)},
- {"Open", GTK_STOCK_OPEN, N_("_Open"), "<control>O", N_("Open a schematic"), G_CALLBACK (open_cmd)},
- {"DisplayRecentFiles", NULL, N_("_Recent Files"), NULL, NULL, NULL},
- {"Save", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save a schematic"), G_CALLBACK (save_cmd)},
- {"SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), "<control><shift>S", N_("Save a schematic with other name"), G_CALLBACK (save_as_cmd)},
- {"PrintProperties", NULL, N_("Print Properties"), NULL, N_("Set print properties"), G_CALLBACK (page_properties_cmd)},
- {"Print", GTK_STOCK_PRINT, N_("_Print"), NULL, N_("Print schematic"), G_CALLBACK (print_cmd)},
- {"PrintPreview", GTK_STOCK_PRINT_PREVIEW, N_("Print Preview"), NULL, N_("Preview the schematic before printing"), G_CALLBACK (print_preview_cmd)},
- {"SchematicProperties", NULL, N_("Schematic Pr_operties..."), NULL, N_("Modify the schematic's properties"), G_CALLBACK (properties_cmd)},
- {"Export", NULL, N_("_Export..."), NULL, N_("Export schematic"), G_CALLBACK (export_cmd)},
- {"Close", GTK_STOCK_CLOSE, N_("_Close"), "<control>W", N_("Close the current schematic"), G_CALLBACK (close_cmd)},
- {"Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", N_("Close all schematics"), G_CALLBACK (quit_cmd)},
- {"Cut", GTK_STOCK_CUT, N_("C_ut"), "<control>X", NULL, G_CALLBACK (cut_cmd)},
- {"Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C", NULL, G_CALLBACK (copy_cmd)},
- {"Paste", GTK_STOCK_PASTE, N_("_Paste"), "<control>V", NULL, G_CALLBACK (paste_cmd)},
- {"Delete", GTK_STOCK_DELETE, N_("_Delete"), "<control>D", N_("Delete the selection"), G_CALLBACK (delete_cmd)},
- {"Rotate", STOCK_PIXMAP_ROTATE, N_("_Rotate"), "<control>R", N_("Rotate the selection clockwise"), G_CALLBACK (rotate_cmd)},
- {"FlipH", NULL, N_("Flip _horizontally"), "<control>F", N_("Flip the selection horizontally"), G_CALLBACK (flip_horizontal_cmd)},
- {"FlipV", NULL, N_("Flip _vertically"), "<control><shift>F", N_("Flip the selection vertically"), G_CALLBACK (flip_vertical_cmd)},
- {"SelectAll", NULL, N_("Select _all"), "<control>A", N_("Select all objects on the sheet"), G_CALLBACK (select_all_cmd)},
- {"SelectNone", NULL, N_("Select _none"), "<control><shift>A", N_("Deselect the selected objects"), G_CALLBACK (deselect_all_cmd)},
- {"ObjectProperties", GTK_STOCK_PROPERTIES, N_("_Object Properties..."), NULL, N_("Modify the object's properties"), G_CALLBACK (object_properties_cmd)},
- {"SimulationSettings", GTK_STOCK_PROPERTIES, N_("Simulation S_ettings..."), NULL, N_("Edit the simulation settings"), G_CALLBACK (sim_settings_show)},
- {"Settings", NULL, N_("_Preferences"), NULL, N_("Edit Oregano settings"), G_CALLBACK (settings_show)},
- {"Simulate", GTK_STOCK_EXECUTE, N_("_Simulate"), "F5", N_("Run a simulation"), G_CALLBACK (simulate_cmd)},
- {"Netlist", NULL, N_("_Generate netlist"), NULL, N_("Generate a netlist"), G_CALLBACK (netlist_cmd)},
- {"SmartSearch", NULL, N_("Smart Search"), NULL, N_("Search a part within all the librarys"), G_CALLBACK (smartsearch_cmd)},
- {"Log", NULL, N_("_Log"), NULL, N_("View the latest simulation log"), G_CALLBACK (log_cmd)},
- {"NetlistView", NULL, N_("N_etlist"), NULL, N_("View the circuit netlist"), G_CALLBACK (netlist_view_cmd)},
- {"About", GTK_STOCK_HELP, N_("_About"), NULL, N_("About Oregano"), G_CALLBACK (about_cmd)},
- {"UserManual", NULL, N_("User's Manual"), NULL, N_("Oregano User's Manual"), G_CALLBACK (show_help)},
- {"ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), NULL, N_("Zoom in"), G_CALLBACK (zoom_in_cmd)},
- {"ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), NULL, N_("Zoom out"), G_CALLBACK (zoom_out_cmd)},
+ // Name, ICON, Text, CTRL, DESC, CALLBACK
+ {"MenuFile", NULL, N_ ("_File")},
+ {"MenuEdit", NULL, N_ ("_Edit")},
+ {"MenuTools", NULL, N_ ("_Tools")},
+ {"MenuView", NULL, N_ ("_View")},
+ {"MenuHelp", NULL, N_ ("_Help")},
+ {"MenuZoom", NULL, N_ ("_Zoom")},
+ {"New", GTK_STOCK_NEW, N_ ("_New"), "<control>N", N_ ("Create a new schematic"),
+ G_CALLBACK (new_cmd)},
+ {"Open", GTK_STOCK_OPEN, N_ ("_Open"), "<control>O", N_ ("Open a schematic"),
+ G_CALLBACK (open_cmd)},
+ {"DisplayRecentFiles", NULL, N_ ("_Recent Files"), NULL, NULL, NULL},
+ {"Save", GTK_STOCK_SAVE, N_ ("_Save"), "<control>S", N_ ("Save a schematic"),
+ G_CALLBACK (save_cmd)},
+ {"SaveAs", GTK_STOCK_SAVE_AS, N_ ("Save _As..."), "<control><shift>S",
+ N_ ("Save a schematic with other name"), G_CALLBACK (save_as_cmd)},
+ {"PrintProperties", NULL, N_ ("Print Properties"), NULL, N_ ("Set print properties"),
+ G_CALLBACK (page_properties_cmd)},
+ {"Print", GTK_STOCK_PRINT, N_ ("_Print"), NULL, N_ ("Print schematic"), G_CALLBACK (print_cmd)},
+ {"PrintPreview", GTK_STOCK_PRINT_PREVIEW, N_ ("Print Preview"), NULL,
+ N_ ("Preview the schematic before printing"), G_CALLBACK (print_preview_cmd)},
+ {"SchematicProperties", NULL, N_ ("Schematic Pr_operties..."), NULL,
+ N_ ("Modify the schematic's properties"), G_CALLBACK (properties_cmd)},
+ {"Export", NULL, N_ ("_Export..."), NULL, N_ ("Export schematic"), G_CALLBACK (export_cmd)},
+ {"Close", GTK_STOCK_CLOSE, N_ ("_Close"), "<control>W", N_ ("Close the current schematic"),
+ G_CALLBACK (close_cmd)},
+ {"Quit", GTK_STOCK_QUIT, N_ ("_Quit"), "<control>Q", N_ ("Close all schematics"),
+ G_CALLBACK (quit_cmd)},
+ {"Cut", GTK_STOCK_CUT, N_ ("C_ut"), "<control>X", NULL, G_CALLBACK (cut_cmd)},
+ {"Copy", GTK_STOCK_COPY, N_ ("_Copy"), "<control>C", NULL, G_CALLBACK (copy_cmd)},
+ {"Paste", GTK_STOCK_PASTE, N_ ("_Paste"), "<control>V", NULL, G_CALLBACK (paste_cmd)},
+ {"Delete", GTK_STOCK_DELETE, N_ ("_Delete"), "<control>D", N_ ("Delete the selection"),
+ G_CALLBACK (delete_cmd)},
+ {"Rotate", STOCK_PIXMAP_ROTATE, N_ ("_Rotate"), "<control>R",
+ N_ ("Rotate the selection clockwise"), G_CALLBACK (rotate_cmd)},
+ {"FlipH", NULL, N_ ("Flip _horizontally"), "<control>F", N_ ("Flip the selection horizontally"),
+ G_CALLBACK (flip_horizontal_cmd)},
+ {"FlipV", NULL, N_ ("Flip _vertically"), "<control><shift>F",
+ N_ ("Flip the selection vertically"), G_CALLBACK (flip_vertical_cmd)},
+ {"SelectAll", NULL, N_ ("Select _all"), "<control>A", N_ ("Select all objects on the sheet"),
+ G_CALLBACK (select_all_cmd)},
+ {"SelectNone", NULL, N_ ("Select _none"), "<control><shift>A",
+ N_ ("Deselect the selected objects"), G_CALLBACK (deselect_all_cmd)},
+ {"ObjectProperties", GTK_STOCK_PROPERTIES, N_ ("_Object Properties..."), NULL,
+ N_ ("Modify the object's properties"), G_CALLBACK (object_properties_cmd)},
+ {"SimulationSettings", GTK_STOCK_PROPERTIES, N_ ("Simulation S_ettings..."), NULL,
+ N_ ("Edit the simulation settings"), G_CALLBACK (sim_settings_show)},
+ {"Settings", NULL, N_ ("_Preferences"), NULL, N_ ("Edit Oregano settings"),
+ G_CALLBACK (settings_show)},
+ {"Simulate", GTK_STOCK_EXECUTE, N_ ("_Simulate"), "F5", N_ ("Run a simulation"),
+ G_CALLBACK (schematic_view_simulate_cmd)},
+ {"Netlist", NULL, N_ ("_Generate netlist"), NULL, N_ ("Generate a netlist"),
+ G_CALLBACK (netlist_cmd)},
+ {"SmartSearch", NULL, N_ ("Smart Search"), NULL, N_ ("Search a part within all the librarys"),
+ G_CALLBACK (smartsearch_cmd)},
+ {"Log", NULL, N_ ("_Log"), NULL, N_ ("View the latest simulation log"), G_CALLBACK (log_cmd)},
+ {"NetlistView", NULL, N_ ("N_etlist"), NULL, N_ ("View the circuit netlist"),
+ G_CALLBACK (netlist_view_cmd)},
+ {"About", GTK_STOCK_HELP, N_ ("_About"), NULL, N_ ("About Oregano"), G_CALLBACK (about_cmd)},
+ {"UserManual", NULL, N_ ("User's Manual"), NULL, N_ ("Oregano User's Manual"),
+ G_CALLBACK (show_help)},
+ {"ZoomIn", GTK_STOCK_ZOOM_IN, N_ ("Zoom _In"), NULL, N_ ("Zoom in"), G_CALLBACK (zoom_in_cmd)},
+ {"ZoomOut", GTK_STOCK_ZOOM_OUT, N_ ("Zoom _Out"), NULL, N_ ("Zoom out"),
+ G_CALLBACK (zoom_out_cmd)},
+ {"StretchLeft", GTK_STOCK_GO_BACK, N_ ("Stretch to the left"), NULL, N_ ("Stretch to the left"),
+ G_CALLBACK (stretch_horizontal_cmd)},
+ {"StretchRight", GTK_STOCK_GO_FORWARD, N_ ("Stretch to the right"), NULL, N_ ("Stretch to the right"),
+ G_CALLBACK (stretch_horizontal_cmd)},
+ {"StretchTop", GTK_STOCK_GO_UP, N_ ("Stretch the top"), NULL, N_ ("Stretch the top"),
+ G_CALLBACK (stretch_vertical_cmd)},
+ {"StretchBottom", GTK_STOCK_GO_DOWN, N_ ("Stretch the bottom"), NULL, N_ ("Stretch the bottom"),
+ G_CALLBACK (stretch_vertical_cmd)},
};
static GtkToggleActionEntry toggle_entries[] = {
- {"Labels", NULL, N_("_Node labels"), NULL, N_("Show or hide node labels"), G_CALLBACK (show_label_cmd), FALSE},
- {"Parts", STOCK_PIXMAP_PART_BROWSER, N_("_Parts"), NULL, N_("Show or hide the part browser"), G_CALLBACK (part_browser_cmd), TRUE},
- {"Grid", STOCK_PIXMAP_GRID, N_("_Grid"), NULL, N_("Show or hide the grid"), G_CALLBACK (grid_toggle_snap_cmd), TRUE},
+ {"Labels", NULL, N_ ("_Node labels"), NULL, N_ ("Toggle node label visibility"),
+ G_CALLBACK (show_label_cmd), FALSE},
+ {"Parts", STOCK_PIXMAP_PART_BROWSER, N_ ("_Parts"), NULL, N_ ("Toggle part browser visibility"),
+ G_CALLBACK (part_browser_cmd), TRUE},
+ {"Grid", STOCK_PIXMAP_GRID, N_ ("_Grid"), NULL, N_ ("Toggle grid visibility"),
+ G_CALLBACK (grid_toggle_snap_cmd), TRUE},
+ {"LogView", GTK_STOCK_DIALOG_WARNING, N_ ("LogView"), NULL, N_ ("Toggle log view visibility"),
+ G_CALLBACK (log_toggle_visibility_cmd), TRUE},
};
static GtkRadioActionEntry zoom_entries[] = {
- {"Zoom50", NULL, "50%", NULL, N_("Set the zoom factor to 50%"), 0},
- {"Zoom75", NULL, "75%", NULL, N_("Set the zoom factor to 75%"), 1},
- {"Zoom100", NULL, "100%", "1", N_("Set the zoom factor to 100%"), 2},
- {"Zoom125", NULL, "125%", NULL, N_("Set the zoom factor to 125%"), 3},
- {"Zoom150", NULL, "150%", NULL, N_("Set the zoom factor to 150%"), 4},
+ {"Zoom50", NULL, "50%", NULL, N_ ("Set the zoom to 50%"), 0},
+ {"Zoom75", NULL, "75%", NULL, N_ ("Set the zoom to 75%"), 1},
+ {"Zoom100", NULL, "100%", "1", N_ ("Set the zoom to 100%"), 2},
+ {"Zoom125", NULL, "125%", NULL, N_ ("Set the zoom to 125%"), 3},
+ {"Zoom150", NULL, "150%", NULL, N_ ("Set the zoom to 150%"), 4},
};
static GtkRadioActionEntry tools_entries[] = {
- {"Arrow", STOCK_PIXMAP_ARROW, N_("Arrow"), NULL, N_("Select, move and modify objects"), 0},
- {"Text", GTK_STOCK_BOLD, N_("Text"), NULL, N_("Put text on the schematic"), 1},
- {"Wire", STOCK_PIXMAP_WIRE, N_("Wire"), "1", N_("Draw wires %"), 2},
- {"VClamp", STOCK_PIXMAP_V_CLAMP, N_("Clamp"), NULL, N_("Add voltage clamp"), 3},
+ {"Arrow", STOCK_PIXMAP_ARROW, N_ ("Arrow"), NULL, N_ ("Select, move and modify objects"), 0},
+ {"Text", GTK_STOCK_BOLD, N_ ("Text"), NULL, N_ ("Put text on the schematic"), 1},
+ {"Wire", STOCK_PIXMAP_WIRE, N_ ("Wire"), "1", N_ ("Draw wires"), 2},
+ {"VClamp", STOCK_PIXMAP_V_CLAMP, N_ ("Clamp"), NULL, N_ ("Add voltage clamp"), 3},
};
-static const char *ui_description =
-"<ui>"
-" <menubar name='MainMenu'>"
-" <menu action='MenuFile'>"
-" <menuitem action='New'/>"
-" <menuitem action='Open'/>"
-" <menuitem action='DisplayRecentFiles'/>"
-" <menuitem action='Save'/>"
-" <menuitem action='SaveAs'/>"
-" <separator/>"
-" <menuitem action='PrintProperties'/>"
-" <menuitem action='Print'/>"
-" <menuitem action='PrintPreview'/>"
-" <separator/>"
-" <menuitem action='SchematicProperties'/>"
-" <menuitem action='Export'/>"
-" <separator/>"
-" <menuitem action='Close'/>"
-" <menuitem action='Quit'/>"
-" </menu>"
-" <menu action='MenuEdit'>"
-" <menuitem action='Cut'/>"
-" <menuitem action='Copy'/>"
-" <menuitem action='Paste'/>"
-" <separator/>"
-" <menuitem action='Delete'/>"
-" <menuitem action='Rotate'/>"
-" <menuitem action='FlipH'/>"
-" <menuitem action='FlipV'/>"
-" <separator/>"
-" <menuitem action='SelectAll'/>"
-" <menuitem action='SelectNone'/>"
-" <separator/>"
-" <menuitem action='ObjectProperties'/>"
-" <menuitem action='SimulationSettings'/>"
-" <separator/>"
-" <menuitem action='Settings'/>"
-" </menu>"
-" <menu action='MenuTools'>"
-" <menuitem action='Simulate'/>"
-" <separator/>"
-" <menuitem action='Netlist'/>"
-" <separator/>"
-" <menuitem action='SmartSearch'/>"
-" </menu>"
-" <menu action='MenuView'>"
-" <menu action='MenuZoom'>"
-" <menuitem action='Zoom50'/>"
-" <menuitem action='Zoom75'/>"
-" <menuitem action='Zoom100'/>"
-" <menuitem action='Zoom125'/>"
-" <menuitem action='Zoom150'/>"
-" </menu>"
-" <separator/>"
-" <menuitem action='Log'/>"
-" <menuitem action='Labels'/>"
-" <menuitem action='NetlistView'/>"
-" </menu>"
-" <menu action='MenuHelp'>"
-" <menuitem action='UserManual'/>"
-" <menuitem action='About'/>"
-" </menu>"
-" </menubar>"
-" <toolbar name='StandardToolbar'>"
-" <toolitem action='New'/>"
-" <toolitem action='Open'/>"
-" <toolitem action='Save'/>"
-" <separator/>"
-" <toolitem action='Cut'/>"
-" <toolitem action='Copy'/>"
-" <toolitem action='Paste'/>"
-" <separator/>"
-" <toolitem action='Arrow'/>"
-" <toolitem action='Text'/>"
-" <toolitem action='Wire'/>"
-" <toolitem action='VClamp'/>"
-" <separator/>"
-" <toolitem action='Simulate'/>"
-" <toolitem action='SimulationSettings'/>"
-" <separator/>"
-" <toolitem action='ZoomIn'/>"
-" <toolitem action='ZoomOut'/>"
-" <separator/>"
-" <toolitem action='Grid'/>"
-" <toolitem action='Parts'/>"
-" </toolbar>"
-" <popup name='MainPopup'>"
-" <menuitem action='Paste'/>"
-" </popup>"
-"</ui>";
+static const char *ui_description = "<ui>"
+ " <menubar name='MainMenu'>"
+ " <menu action='MenuFile'>"
+ " <menuitem action='New'/>"
+ " <menuitem action='Open'/>"
+ " <menuitem action='DisplayRecentFiles'/>"
+ " <menuitem action='Save'/>"
+ " <menuitem action='SaveAs'/>"
+ " <separator/>"
+ " <menuitem action='PrintProperties'/>"
+ " <menuitem action='Print'/>"
+ " <menuitem action='PrintPreview'/>"
+ " <separator/>"
+ " <menuitem action='SchematicProperties'/>"
+ " <menuitem action='Export'/>"
+ " <separator/>"
+ " <menuitem action='Close'/>"
+ " <menuitem action='Quit'/>"
+ " </menu>"
+ " <menu action='MenuEdit'>"
+ " <menuitem action='Cut'/>"
+ " <menuitem action='Copy'/>"
+ " <menuitem action='Paste'/>"
+ " <separator/>"
+ " <menuitem action='Delete'/>"
+ " <menuitem action='Rotate'/>"
+ " <menuitem action='FlipH'/>"
+ " <menuitem action='FlipV'/>"
+ " <separator/>"
+ " <menuitem action='SelectAll'/>"
+ " <menuitem action='SelectNone'/>"
+ " <separator/>"
+ " <menuitem action='ObjectProperties'/>"
+ " <menuitem action='SimulationSettings'/>"
+ " <separator/>"
+ " <menuitem action='Settings'/>"
+ " </menu>"
+ " <menu action='MenuTools'>"
+ " <menuitem action='Simulate'/>"
+ " <separator/>"
+ " <menuitem action='Netlist'/>"
+ " <separator/>"
+ " <menuitem action='SmartSearch'/>"
+ " </menu>"
+ " <menu action='MenuView'>"
+ " <menu action='MenuZoom'>"
+ " <menuitem action='Zoom50'/>"
+ " <menuitem action='Zoom75'/>"
+ " <menuitem action='Zoom100'/>"
+ " <menuitem action='Zoom125'/>"
+ " <menuitem action='Zoom150'/>"
+ " </menu>"
+ " <separator/>"
+ " <menuitem action='Log'/>"
+ " <menuitem action='Labels'/>"
+ " <menuitem action='NetlistView'/>"
+ " </menu>"
+ " <menu action='MenuHelp'>"
+ " <menuitem action='UserManual'/>"
+ " <menuitem action='About'/>"
+ " </menu>"
+ " </menubar>"
+ " <toolbar name='StandardToolbar'>"
+ " <toolitem action='New'/>"
+ " <toolitem action='Open'/>"
+ " <toolitem action='Save'/>"
+ " <separator/>"
+ " <toolitem action='Cut'/>"
+ " <toolitem action='Copy'/>"
+ " <toolitem action='Paste'/>"
+ " <separator/>"
+ " <toolitem action='Arrow'/>"
+ " <toolitem action='Text'/>"
+ " <toolitem action='Wire'/>"
+ " <toolitem action='VClamp'/>"
+ " <separator/>"
+ " <toolitem action='Simulate'/>"
+ " <toolitem action='SimulationSettings'/>"
+ " <separator/>"
+ " <toolitem action='ZoomIn'/>"
+ " <toolitem action='ZoomOut'/>"
+ " <separator/>"
+ " <toolitem action='StretchLeft'/>"
+ " <toolitem action='StretchRight'/>"
+ " <toolitem action='StretchTop'/>"
+ " <toolitem action='StretchBottom'/>"
+ " <separator/>"
+ " <toolitem action='Grid'/>"
+ " <toolitem action='Parts'/>"
+ " <toolitem action='LogView'/>"
+ " </toolbar>"
+ " <popup name='MainPopup'>"
+ " <menuitem action='Paste'/>"
+ " </popup>"
+ "</ui>";
#endif
diff --git a/src/schematic-view.c b/src/schematic-view.c
index d2274fc..f1cf234 100644
--- a/src/schematic-view.c
+++ b/src/schematic-view.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
@@ -39,6 +43,7 @@
#include <sys/time.h>
#include <cairo/cairo-features.h>
+#include "schematic.h"
#include "schematic-view.h"
#include "part-browser.h"
#include "stock.h"
@@ -55,17 +60,14 @@
#include "sheet.h"
#include "sheet-item-factory.h"
#include "textbox-item.h"
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "log-view.h"
+#include "log.h"
+#include "debug.h"
#define ZOOM_MIN 0.35
#define ZOOM_MAX 3
-enum {
- CHANGED,
- RESET_TOOL,
- LAST_SIGNAL
-};
+enum { CHANGED, RESET_TOOL, LAST_SIGNAL };
typedef enum {
SCHEMATIC_TOOL_ARROW,
@@ -74,86 +76,86 @@ typedef enum {
SCHEMATIC_TOOL_TEXT
} SchematicTool;
-typedef struct {
- GtkWidget *log_window;
- GtkTextView *log_text;
- GtkBuilder *log_gui;
+typedef struct
+{
+ GtkWidget *log_window;
+ GtkTextView *log_text;
+ GtkBuilder *log_gui;
} LogInfo;
struct _SchematicView
{
- GObject parent;
- GtkWidget *toplevel;
+ GObject parent;
+ GtkWidget *toplevel;
SchematicViewPriv *priv;
};
struct _SchematicViewClass
{
- GObjectClass parent_class;
+ GObjectClass parent_class;
// Signals go here
- void (*changed) (SchematicView *schematic_view);
- void (*reset_tool) (SchematicView *schematic_view);
+ void (*changed)(SchematicView *schematic_view);
+ void (*reset_tool)(SchematicView *schematic_view);
};
-struct _SchematicViewPriv {
- Schematic *schematic;
+struct _SchematicViewPriv
+{
+ Schematic *schematic;
- Sheet *sheet;
+ Sheet *sheet;
- GtkPageSetup *page_setup;
- GtkPrintSettings *print_settings;
+ GtkPageSetup *page_setup;
+ GtkPrintSettings *print_settings;
- gboolean empty;
+ gboolean empty;
- GtkActionGroup *action_group;
- GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
- GtkWidget *floating_part_browser;
- gpointer browser;
+ gpointer browser;
- guint grid : 1;
- SchematicTool tool;
- int cursor;
+ GtkWidget *logview;
+ GtkPaned *paned;
+ guint grid : 1;
+ SchematicTool tool;
+ int cursor;
- LogInfo *log_info;
+ LogInfo *log_info;
};
G_DEFINE_TYPE (SchematicView, schematic_view, G_TYPE_OBJECT)
// Class functions and members.
-static void schematic_view_init(SchematicView *sv);
-static void schematic_view_class_init(SchematicViewClass *klass);
-static void schematic_view_dispose(GObject *object);
-static void schematic_view_finalize(GObject *object);
+static void schematic_view_init (SchematicView *sv);
+static void schematic_view_class_init (SchematicViewClass *klass);
+static void schematic_view_dispose (GObject *object);
+static void schematic_view_finalize (GObject *object);
static void schematic_view_load (SchematicView *sv, Schematic *sm);
+static void schematic_view_do_load (SchematicView *sv, Schematic *sm, const gboolean reload);
+static void schematic_view_reload (SchematicView *sv, Schematic *sm);
// Signal callbacks.
-static void title_changed_callback (Schematic *schematic, char *new_title,
- SchematicView *sv);
+static void title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv);
static void set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv);
-static int delete_event (GtkWidget *widget, GdkEvent *event,
- SchematicView *sv);
-static void data_received (GtkWidget *widget, GdkDragContext *context,
- gint x, gint y, GtkSelectionData *selection_data, guint info,
- guint32 time, SchematicView *sv);
-static void item_data_added_callback (Schematic *schematic, ItemData *data,
- SchematicView *sv);
-static void item_selection_changed_callback (SheetItem *item, gboolean selected,
- SchematicView *sv);
-static void reset_tool_cb (Sheet *sheet, SchematicView *sv);
+static int delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv);
+static void data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint info, guint32 time,
+ SchematicView *sv);
+static void item_data_added_callback (Schematic *schematic, ItemData *data, SchematicView *sv);
+static void item_selection_changed_callback (SheetItem *item, gboolean selected, SchematicView *sv);
+static void reset_tool_cb (Sheet *sheet, SchematicView *sv);
// Misc.
-static int can_close (SchematicView *sv);
-static void setup_dnd (SchematicView *sv);
-static void set_tool (SchematicView *sv, SchematicTool tool);
+static int can_close (SchematicView *sv);
+static void setup_dnd (SchematicView *sv);
+static void set_tool (SchematicView *sv, SchematicTool tool);
-static GList *schematic_view_list = NULL;
+static GList *schematic_view_list = NULL;
static GObjectClass *parent_class = NULL;
-static guint schematic_view_signals[LAST_SIGNAL] = { 0 };
+static guint schematic_view_signals[LAST_SIGNAL] = {0};
-static void
-new_cmd (GtkWidget *widget, Schematic *sv)
+static void new_cmd (GtkWidget *widget, Schematic *sv)
{
Schematic *new_sm;
SchematicView *new_sv;
@@ -164,13 +166,11 @@ new_cmd (GtkWidget *widget, Schematic *sv)
gtk_widget_show_all (new_sv->toplevel);
}
-static void
-properties_cmd (GtkWidget *widget, SchematicView *sv)
+static void properties_cmd (GtkWidget *widget, SchematicView *sv)
{
Schematic *s;
- GtkBuilder *gui;
- GError *perror = NULL;
- gchar *msg;
+ GtkBuilder *builder;
+ GError *e = NULL;
GtkWidget *window;
GtkEntry *title, *author;
GtkTextView *comments;
@@ -180,46 +180,38 @@ properties_cmd (GtkWidget *widget, SchematicView *sv)
s = schematic_view_get_schematic (sv);
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create properties dialog"));
- return;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/properties.ui", G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall"
- "Oregano to fix this."),
- OREGANO_UIDIR "/properties.ui");
-
- oregano_error_with_title (_("Could not create properties dialog"), msg);
+ if ((builder = gtk_builder_new ()) == NULL) {
+ log_append (schematic_get_log_store (s), _ ("SchematicView"),
+ _ ("Could not create properties dialog"));
return;
}
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/properties.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create properties dialog"), msg);
- g_error_free (perror);
+ gtk_builder_set_translation_domain (builder, NULL);
+
+ if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/properties.ui", &e) <= 0) {
+ log_append_error (schematic_get_log_store (s), _ ("SchematicView"),
+ _ ("Could not create properties dialog due to issues with " OREGANO_UIDIR
+ "/properties.ui file."),
+ e);
+ g_clear_error (&e);
return;
}
- window = GTK_WIDGET (gtk_builder_get_object (gui, "properties"));
- title = GTK_ENTRY (gtk_builder_get_object (gui, "title"));
- author = GTK_ENTRY (gtk_builder_get_object (gui, "author"));
- comments = GTK_TEXT_VIEW (gtk_builder_get_object (gui, "comments"));
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "properties"));
+ title = GTK_ENTRY (gtk_builder_get_object (builder, "title"));
+ author = GTK_ENTRY (gtk_builder_get_object (builder, "author"));
+ comments = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "comments"));
buffer = gtk_text_view_get_buffer (comments);
s_title = schematic_get_title (s);
s_author = schematic_get_author (s);
s_comments = schematic_get_comments (s);
-
+
if (s_title)
gtk_entry_set_text (title, s_title);
if (s_author)
gtk_entry_set_text (author, s_author);
if (s_comments)
- gtk_text_buffer_set_text (buffer, s_comments, strlen(s_comments));
+ gtk_text_buffer_set_text (buffer, s_comments, strlen (s_comments));
button = gtk_dialog_run (GTK_DIALOG (window));
@@ -229,8 +221,8 @@ properties_cmd (GtkWidget *widget, SchematicView *sv)
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
- s_title = (gchar *) gtk_entry_get_text (title);
- s_author = (gchar *) gtk_entry_get_text (author);
+ s_title = (gchar *)gtk_entry_get_text (title);
+ s_author = (gchar *)gtk_entry_get_text (author);
s_comments = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
schematic_set_title (s, s_title);
@@ -243,18 +235,18 @@ properties_cmd (GtkWidget *widget, SchematicView *sv)
gtk_widget_destroy (window);
}
-static void
-find_file (GtkButton *button, GtkEntry *text)
+static void find_file (GtkButton *button, GtkEntry *text)
{
GtkWidget *dialog;
- dialog = gtk_file_chooser_dialog_new (
- _("Export to..."),
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
- NULL);
+ dialog = gtk_file_chooser_dialog_new (_ ("Export to..."),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ _("_Open"),
+ GTK_RESPONSE_ACCEPT,
+ NULL);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
char *filename;
@@ -267,15 +259,13 @@ find_file (GtkButton *button, GtkEntry *text)
gtk_widget_destroy (dialog);
}
-static void
-export_cmd (GtkWidget *widget, SchematicView *sv)
+static void export_cmd (GtkWidget *widget, SchematicView *sv)
{
Schematic *s;
- GtkBuilder *gui;
- GError *perror = NULL;
- gchar *msg;
+ GtkBuilder *builder;
+ GError *e = NULL;
GtkWidget *window;
- GtkWidget* warning;
+ GtkWidget *warning;
GtkWidget *w;
GtkEntry *file = NULL;
GtkComboBoxText *combo;
@@ -284,33 +274,25 @@ export_cmd (GtkWidget *widget, SchematicView *sv)
s = schematic_view_get_schematic (sv);
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create export dialog."));
- return;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/export.ui", G_FILE_TEST_EXISTS)) {
- gchar *msg;
- msg = g_strdup_printf (_("The file %s could not be found. You might "
- "need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/export.xml");
-
- oregano_error_with_title (_("Could not create export dialog."), msg);
- g_free (msg);
+ if ((builder = gtk_builder_new ()) == NULL) {
+ log_append (schematic_get_log_store (s), _ ("SchematicView"),
+ _ ("Could not create properties dialog"));
return;
}
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/export.ui", &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create export dialog."), msg);
- g_error_free (perror);
+ gtk_builder_set_translation_domain (builder, NULL);
+
+ if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/export.ui", &e) <= 0) {
+ log_append_error (schematic_get_log_store (s), _ ("SchematicView"),
+ _ ("Could not create properties dialog due to issues with " OREGANO_UIDIR
+ "/exportp.ui file."),
+ e);
+ g_clear_error (&e);
return;
}
- window = GTK_WIDGET (gtk_builder_get_object (gui, "export"));
-
- combo = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (gui, "format"));
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "export"));
+
+ combo = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, "format"));
fc = 0;
#ifdef CAIRO_HAS_SVG_SURFACE
gtk_combo_box_text_append_text (combo, "Scalar Vector Graphics (SVG)");
@@ -329,113 +311,130 @@ export_cmd (GtkWidget *widget, SchematicView *sv)
formats[fc++] = 3;
#endif
- file = GTK_ENTRY (gtk_builder_get_object (gui, "file"));
+ file = GTK_ENTRY (gtk_builder_get_object (builder, "file"));
- w = GTK_WIDGET (gtk_builder_get_object (gui, "find"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (find_file), file);
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "find"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (find_file), file);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
button = gtk_dialog_run (GTK_DIALOG (window));
-
+
if (button == GTK_RESPONSE_OK) {
-
- if (g_path_skip_root (gtk_entry_get_text(file)) == NULL) {
+
+ if (g_path_skip_root (gtk_entry_get_text (file)) == NULL) {
warning = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- _("<span weight=\"bold\" size=\"large\">No filename has "
- "been chosen</span>\n\n"
- "Please, click on the tag, beside, to select an output."));
-
- if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_OK) {
+ NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+ _ ("<span weight=\"bold\" size=\"large\">No filename has "
+ "been chosen</span>\n\n"
+ "Please, click on the tag, beside, to select an output."));
+
+ if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_OK) {
gtk_widget_destroy (GTK_WIDGET (warning));
export_cmd (widget, sv);
gtk_widget_destroy (GTK_WIDGET (window));
return;
}
- }
- else {
-
+ } else {
+
int bg = 0;
GtkSpinButton *spinw, *spinh;
int color_scheme = 0;
GtkWidget *w;
int i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
- w = GTK_WIDGET (gtk_builder_get_object (gui, "bgwhite"));
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) bg = 1;
- w = GTK_WIDGET (gtk_builder_get_object (gui, "bgblack"));
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) bg = 2;
- w = GTK_WIDGET (gtk_builder_get_object (gui, "color"));
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "bgwhite"));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
+ bg = 1;
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "bgblack"));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
+ bg = 2;
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "color"));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
color_scheme = 1;
- spinw = GTK_SPIN_BUTTON (gtk_builder_get_object (gui, "export_width"));
- spinh = GTK_SPIN_BUTTON (gtk_builder_get_object (gui, "export_height"));
- schematic_export (s,
- gtk_entry_get_text (file),
- gtk_spin_button_get_value_as_int (spinw),
- gtk_spin_button_get_value_as_int (spinh),
- bg,
- color_scheme,
- formats[i]);
+ spinw = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "export_width"));
+ spinh = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "export_height"));
+ schematic_export (
+ s, gtk_entry_get_text (file), gtk_spin_button_get_value_as_int (spinw),
+ gtk_spin_button_get_value_as_int (spinh), bg, color_scheme, formats[i]);
}
}
gtk_widget_destroy (window);
}
-static void
-page_properties_cmd (GtkWidget *widget, SchematicView *sv)
+static void page_properties_cmd (GtkWidget *widget, SchematicView *sv)
{
-sv->priv->page_setup = gtk_print_run_page_setup_dialog (NULL,
- sv->priv->page_setup,
- sv->priv->print_settings);
+ if (sv->priv->page_setup) {
+ g_object_unref (sv->priv->page_setup);
+ }
+
+ sv->priv->page_setup =
+ gtk_print_run_page_setup_dialog (NULL, sv->priv->page_setup, sv->priv->print_settings);
}
-static void
-open_cmd (GtkWidget *widget, SchematicView *sv)
+static void open_cmd (GtkWidget *widget, SchematicView *sv)
{
Schematic *new_sm;
- SchematicView *new_sv;
+ SchematicView *new_sv, *t;
char *fname, *uri = NULL;
- GList *list;
- GError *error = NULL;
+ GList *iter;
+ GError *e = NULL;
fname = dialog_open_file (sv);
- if (fname == NULL)
- return;
+ if (!fname)
+ return;
// Repaint the other schematic windows before loading the new file.
new_sv = NULL;
- for (list = schematic_view_list; list; list = list->next) {
- if (SCHEMATIC_VIEW (list->data)->priv->empty)
- new_sv = SCHEMATIC_VIEW (list->data);
- gtk_widget_queue_draw (GTK_WIDGET (SCHEMATIC_VIEW (list->data)->toplevel));
+ for (iter = schematic_view_list; iter; iter = iter->next) {
+ t = SCHEMATIC_VIEW (iter->data);
+ if (t->priv->empty)
+ new_sv = t;
+ gtk_widget_queue_draw (GTK_WIDGET (t->toplevel));
}
while (gtk_events_pending ())
gtk_main_iteration ();
- new_sm = schematic_read(fname, &error);
- if (error != NULL) {
- oregano_error_with_title (_("Could not load file"), error->message);
- g_error_free (error);
+ new_sm = schematic_read (fname, &e);
+ if (e) {
+ gchar *const msg = g_strdup_printf (_ ("Could not load file \"file://%s\""), fname);
+ Schematic *old = schematic_view_get_schematic (sv);
+ log_append_error (schematic_get_log_store (old), _ ("SchematicView"), msg, e);
+ g_clear_error (&e);
+ g_free (msg);
}
if (new_sm) {
GtkRecentManager *manager;
- gchar *uri;
-
+ GtkRecentInfo *rc;
+
manager = gtk_recent_manager_get_default ();
uri = g_strdup_printf ("file://%s", fname);
- if (!gtk_recent_manager_has_item (manager, uri) &&
- (!(uri==NULL))) gtk_recent_manager_add_item (manager, uri);
+
+ if (uri) {
+ rc = gtk_recent_manager_lookup_item (manager, uri, &e);
+ if (e) {
+ g_clear_error (&e);
+ } else {
+ gtk_recent_manager_remove_item (manager, uri, &e);
+ if (e) {
+ gchar *const msg =
+ g_strdup_printf (_ ("Could not load recent file \"%s\""), uri);
+ Schematic *old = schematic_view_get_schematic (sv);
+ log_append_error (schematic_get_log_store (old), _ ("SchematicView"), msg, e);
+ g_clear_error (&e);
+ g_free (msg);
+ }
+ }
+ gtk_recent_manager_add_item (manager, uri);
+ if (rc)
+ gtk_recent_info_unref (rc);
+ }
+
if (!new_sv)
new_sv = schematic_view_new (new_sm);
else
@@ -443,44 +442,54 @@ open_cmd (GtkWidget *widget, SchematicView *sv)
gtk_widget_show_all (new_sv->toplevel);
schematic_set_filename (new_sm, fname);
- schematic_set_title (new_sm, g_path_get_basename(fname));
- }
+ schematic_set_title (new_sm, g_path_get_basename (fname));
- g_list_free_full (list, g_object_unref);
+ g_free (uri);
+ }
g_free (fname);
- g_free (uri);
}
-
-static void
-oregano_recent_open (GtkRecentChooser *chooser, SchematicView *sv)
+static void oregano_recent_open (GtkRecentChooser *chooser, SchematicView *sv)
{
gchar *uri;
- const gchar *mime;
- GtkRecentInfo *item;
+ const gchar *mime;
+ GtkRecentInfo *item;
GtkRecentManager *manager;
Schematic *new_sm;
SchematicView *new_sv = NULL;
- GError *error = NULL;
+ GError *e = NULL;
uri = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (chooser));
- if (!uri) return;
+ if (!uri)
+ return;
manager = gtk_recent_manager_get_default ();
item = gtk_recent_manager_lookup_item (manager, uri, NULL);
- if (!item) return;
-
- mime = gtk_recent_info_get_mime_type (item);
- if (!mime) {
- g_warning (_("Unrecognized mime type"));
+ if (!item)
return;
+ // remove and re-add in order to update the ordering
+ gtk_recent_manager_remove_item (manager, uri, &e);
+ if (e) {
+ gchar *const msg =
+ g_strdup_printf (_ ("Could not load recent file \"%s\"\n%s"), uri, e->message);
+ oregano_error_with_title (_ ("Could not load recent file"), msg);
+ g_clear_error (&e);
+ g_free (msg);
}
+ gtk_recent_manager_add_item (manager, uri);
- if (!strcmp (mime, "application/x-oregano")) {
- new_sm = schematic_read (uri, &error);
- if (error != NULL) {
- oregano_error_with_title (_("Could not load file"), error->message);
- g_error_free (error);
+ mime = gtk_recent_info_get_mime_type (item);
+ if (!mime || strcmp (mime, "application/x-oregano") != 0) {
+ gchar *const msg = g_strdup_printf (_ ("Can not handle file with mimetype \"%s\""), mime);
+ oregano_error_with_title (_ ("Could not load recent file"), msg);
+ g_clear_error (&e);
+ g_free (msg);
+
+ } else {
+ new_sm = schematic_read (uri, &e);
+ if (e) {
+ oregano_error_with_title (_ ("Could not load recent file"), e->message);
+ g_clear_error (&e);
}
if (new_sm) {
if (!new_sv)
@@ -490,19 +499,15 @@ oregano_recent_open (GtkRecentChooser *chooser, SchematicView *sv)
gtk_widget_show_all (new_sv->toplevel);
schematic_set_filename (new_sm, uri);
- schematic_set_title (new_sm, g_path_get_basename(uri));
+ schematic_set_title (new_sm, g_path_get_basename (uri));
}
}
- else
- g_warning (_("Unknown type of file can't open"));
- g_free(uri);
+ g_free (uri);
gtk_recent_info_unref (item);
}
-
-static GtkWidget *
-create_recent_chooser_menu (GtkRecentManager *manager)
+static GtkWidget *create_recent_chooser_menu (GtkRecentManager *manager)
{
GtkWidget *menu;
GtkRecentFilter *filter;
@@ -512,25 +517,22 @@ create_recent_chooser_menu (GtkRecentManager *manager)
gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (menu), 10);
gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (menu), TRUE);
- gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu),
- GTK_RECENT_SORT_MRU);
-
+ gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu), GTK_RECENT_SORT_MRU);
+
filter = gtk_recent_filter_new ();
gtk_recent_filter_add_mime_type (filter, "application/x-oregano");
- gtk_recent_filter_add_application (filter, g_get_application_name());
+ gtk_recent_filter_add_application (filter, g_get_application_name ());
gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (menu), filter);
gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (menu), TRUE);
- g_signal_connect (menu, "item-activated",
- G_CALLBACK (oregano_recent_open), NULL);
+ g_signal_connect (menu, "item-activated", G_CALLBACK (oregano_recent_open), NULL);
gtk_widget_show_all (menu);
return menu;
}
-static void
-display_recent_files (GtkWidget *menu, SchematicView *sv)
+static void display_recent_files (GtkWidget *menu, SchematicView *sv)
{
SchematicViewPriv *priv = sv->priv;
GtkWidget *menuitem;
@@ -538,108 +540,103 @@ display_recent_files (GtkWidget *menu, SchematicView *sv)
GtkRecentManager *manager = NULL;
manager = gtk_recent_manager_get_default ();
- menuitem = gtk_ui_manager_get_widget (priv->ui_manager,
- "/MainMenu/MenuFile/DisplayRecentFiles");
+ menuitem =
+ gtk_ui_manager_get_widget (priv->ui_manager, "/MainMenu/MenuFile/DisplayRecentFiles");
recentmenu = create_recent_chooser_menu (manager);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), recentmenu);
gtk_widget_show (menuitem);
}
-static void
-save_cmd (GtkWidget *widget, SchematicView *sv)
+static void save_cmd (GtkWidget *widget, SchematicView *sv)
{
Schematic *sm;
char *filename;
- GError *error = NULL;
+ GError *e = NULL;
sm = sv->priv->schematic;
filename = schematic_get_filename (sm);
- if (filename == NULL || !strcmp (filename, _("Untitled.oregano"))) {
+ if (filename == NULL || !strcmp (filename, _ ("Untitled.oregano"))) {
dialog_save_as (sv);
return;
- }
- else {
- if (!schematic_save_file (sm, &error)) {
- oregano_error_with_title (_("Could not save schematic file"),
- error->message);
- g_error_free (error);
+ } else {
+ if (!schematic_save_file (sm, &e)) {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Failed to save schematic file."), e);
+ g_clear_error (&e);
}
}
}
-static void
-save_as_cmd (GtkWidget *widget, SchematicView *sv)
-{
- dialog_save_as (sv);
-}
+static void save_as_cmd (GtkWidget *widget, SchematicView *sv) { dialog_save_as (sv); }
-static void
-close_cmd (GtkWidget *widget, SchematicView *sv)
+static void close_cmd (GtkWidget *widget, SchematicView *sv)
{
if (can_close (sv)) {
+ NG_DEBUG (" --- not dirty (anymore), do close schematic_view: %p -- vs -- "
+ "toplevel: %p",
+ sv, schematic_view_get_toplevel (sv));
+
+ gtk_widget_destroy (GTK_WIDGET (schematic_view_get_toplevel (sv)));
+ sv->toplevel = NULL;
+
g_object_unref (G_OBJECT (sv));
}
}
-static void
-select_all_cmd (GtkWidget *widget, SchematicView *sv)
+static void select_all_cmd (GtkWidget *widget, SchematicView *sv)
{
sheet_select_all (sv->priv->sheet, TRUE);
}
-static void
-deselect_all_cmd (GtkWidget *widget, SchematicView *sv)
+static void deselect_all_cmd (GtkWidget *widget, SchematicView *sv)
{
sheet_select_all (sv->priv->sheet, FALSE);
}
-static void
-delete_cmd (GtkWidget *widget, SchematicView *sv)
+static void delete_cmd (GtkWidget *widget, SchematicView *sv)
{
sheet_delete_selection (sv->priv->sheet);
}
-static void
-rotate_cmd (GtkWidget *widget, SchematicView *sv)
+static void rotate_cmd (GtkWidget *widget, SchematicView *sv)
{
if (sv->priv->sheet->state == SHEET_STATE_NONE)
- sheet_rotate_selection (sv->priv->sheet);
+ sheet_rotate_selection (sv->priv->sheet, 90);
else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
- sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
+ sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
sheet_rotate_ghosts (sv->priv->sheet);
}
-static void
-flip_horizontal_cmd (GtkWidget *widget, SchematicView *sv)
+static void flip_horizontal_cmd (GtkWidget *widget, SchematicView *sv)
{
if (sv->priv->sheet->state == SHEET_STATE_NONE)
sheet_flip_selection (sv->priv->sheet, TRUE);
else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
- sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
+ sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
sheet_flip_ghosts (sv->priv->sheet, TRUE);
}
-static void
-flip_vertical_cmd (GtkWidget *widget, SchematicView *sv)
+static void flip_vertical_cmd (GtkWidget *widget, SchematicView *sv)
{
if (sv->priv->sheet->state == SHEET_STATE_NONE)
sheet_flip_selection (sv->priv->sheet, FALSE);
else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
- sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
+ sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
sheet_flip_ghosts (sv->priv->sheet, FALSE);
}
-static void
-object_properties_cmd (GtkWidget *widget, SchematicView *sv)
+static void object_properties_cmd (GtkWidget *widget, SchematicView *sv)
{
sheet_provide_object_properties (sv->priv->sheet);
}
-static void
-copy_cmd (GtkWidget *widget, SchematicView *sv)
+/**
+ * copy the currently selected items
+ */
+static void copy_cmd (GtkWidget *widget, SchematicView *sv)
{
SheetItem *item;
- GList *list;
+ GList *iter;
if (sv->priv->sheet->state != SHEET_STATE_NONE)
return;
@@ -647,23 +644,24 @@ copy_cmd (GtkWidget *widget, SchematicView *sv)
sheet_clear_ghosts (sv->priv->sheet);
clipboard_empty ();
- list = sheet_get_selection (sv->priv->sheet);
- for (; list; list = list->next) {
- item = list->data;
+ iter = sheet_get_selection (sv->priv->sheet);
+ for (; iter; iter = iter->next) {
+ item = iter->data;
clipboard_add_object (G_OBJECT (item));
}
- g_list_free_full (list, g_object_unref);
if (clipboard_is_empty ())
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/Paste"), FALSE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), FALSE);
else
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/Paste"), TRUE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), TRUE);
}
-static void
-cut_cmd (GtkWidget *widget, SchematicView *sv)
+/**
+ * snip the currently selected items
+ */
+static void cut_cmd (GtkWidget *widget, SchematicView *sv)
{
if (sv->priv->sheet->state != SHEET_STATE_NONE)
return;
@@ -672,21 +670,16 @@ cut_cmd (GtkWidget *widget, SchematicView *sv)
sheet_delete_selection (sv->priv->sheet);
if (clipboard_is_empty ())
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/Paste"), FALSE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), FALSE);
else
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/Paste"), TRUE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), TRUE);
}
-static void
-paste_objects (gpointer data, Sheet *sheet)
-{
- sheet_item_paste (sheet, data);
-}
+static void paste_objects (gpointer data, Sheet *sheet) { sheet_item_paste (sheet, data); }
-static void
-paste_cmd (GtkWidget *widget, SchematicView *sv)
+static void paste_cmd (GtkWidget *widget, SchematicView *sv)
{
if (sv->priv->sheet->state != SHEET_STATE_NONE)
return;
@@ -694,92 +687,76 @@ paste_cmd (GtkWidget *widget, SchematicView *sv)
sheet_clear_ghosts (sv->priv->sheet);
sheet_select_all (sv->priv->sheet, FALSE);
- clipboard_foreach ((ClipBoardFunction) paste_objects, sv->priv->sheet);
+ clipboard_foreach ((ClipBoardFunction)paste_objects, sv->priv->sheet);
if (sheet_get_floating_objects (sv->priv->sheet))
- sheet_connect_part_item_to_floating_group (sv->priv->sheet, (gpointer) sv);
+ sheet_connect_part_item_to_floating_group (sv->priv->sheet, (gpointer)sv);
}
-static void
-about_cmd (GtkWidget *widget, Schematic *sm)
-{
- dialog_about ();
-}
+static void about_cmd (GtkWidget *widget, Schematic *sm) { dialog_about (); }
-static void
-log_cmd (GtkWidget *widget, SchematicView *sv)
-{
- schematic_view_log_show (sv, TRUE);
-}
+static void log_cmd (GtkWidget *widget, SchematicView *sv) { schematic_view_log_show (sv, TRUE); }
-static void
-show_label_cmd (GtkToggleAction *toggle, SchematicView *sv)
+static void show_label_cmd (GtkToggleAction *toggle, SchematicView *sv)
{
gboolean show;
- Schematic *sm;
+ Schematic *sm;
Netlist netlist;
- GError *error = 0;
+ GError *e = NULL;
show = gtk_toggle_action_get_active (toggle);
- // Use of netlist_helper_create
+ // Use of netlist_helper_create
sm = sv->priv->schematic;
- netlist_helper_create (sm, &netlist, &error);
- if (error != NULL) {
- if (g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
- oregano_error_with_title (_("Could not create a netlist"),
- error->message);
- g_clear_error (&error);
- }
- else
- oregano_error (_("An unexpected error has occurred"));
- g_clear_error (&error);
+ netlist_helper_create (sm, &netlist, &e);
+ if (e != NULL) {
+ if (g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Could not create a netlist."), e);
+ } else {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Unexpect failure occured."), e);
+ }
+ g_clear_error (&e);
return;
}
-
+
sheet_show_node_labels (sv->priv->sheet, show);
- sheet_update_parts (sv->priv->sheet);
+ sheet_update_parts (sv->priv->sheet);
}
-static void
-print_cmd (GtkWidget *widget, SchematicView *sv)
+static void print_cmd (GtkWidget *widget, SchematicView *sv)
{
- schematic_print (schematic_view_get_schematic (sv),
- sv->priv->page_setup,
- sv->priv->print_settings, FALSE);
+ schematic_print (schematic_view_get_schematic (sv), sv->priv->page_setup,
+ sv->priv->print_settings, FALSE);
}
-static void
-print_preview_cmd (GtkWidget *widget, SchematicView *sv)
+static void print_preview_cmd (GtkWidget *widget, SchematicView *sv)
{
- schematic_print (schematic_view_get_schematic (sv),
- sv->priv->page_setup,
- sv->priv->print_settings, TRUE);
+ schematic_print (schematic_view_get_schematic (sv), sv->priv->page_setup,
+ sv->priv->print_settings, TRUE);
}
-static void
-quit_cmd (GtkWidget *widget, SchematicView *sv)
+static void quit_cmd (GtkWidget *widget, SchematicView *sv)
{
- GList *list, *copy;
+ GList *iter, *copy;
// Duplicate the list as the list is modified during destruction.
copy = g_list_copy (schematic_view_list);
- for (list = copy; list; list = list->next) {
- if (can_close (list->data))
- g_object_unref (list->data);
+ for (iter = copy; iter; iter = iter->next) {
+ close_cmd (NULL, iter->data);
}
g_list_free (copy);
- g_list_free_full (list, g_object_unref);
+ g_application_quit (g_application_get_default ());
}
-static void
-v_clamp_cmd (SchematicView *sv)
+static void v_clamp_cmd (SchematicView *sv)
{
LibraryPart *library_part;
- SheetPos pos;
+ Coords pos;
Sheet *sheet;
Part *part;
GList *lib;
@@ -788,14 +765,15 @@ v_clamp_cmd (SchematicView *sv)
set_tool (sv, SCHEMATIC_TOOL_PART);
sheet = sv->priv->sheet;
- // Find default lib
+ // Find default lib
for (lib = oregano.libraries; lib; lib = lib->next) {
l = (Library *)(lib->data);
- if (!g_ascii_strcasecmp(l->name, "Default")) break;
+ if (!g_ascii_strcasecmp (l->name, "Default"))
+ break;
}
library_part = library_get_part (l, "Test Clamp");
-
+
part = part_new_from_library_part (library_part);
if (!part) {
g_warning ("Clamp not found!");
@@ -808,35 +786,32 @@ v_clamp_cmd (SchematicView *sv)
sheet_select_all (sv->priv->sheet, FALSE);
sheet_clear_ghosts (sv->priv->sheet);
sheet_add_ghost_item (sv->priv->sheet, ITEM_DATA (part));
- sheet_connect_part_item_to_floating_group (sheet, (gpointer) sv);
+ sheet_connect_part_item_to_floating_group (sheet, (gpointer)sv);
}
-static void
-tool_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
+static void tool_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
{
switch (gtk_radio_action_get_current_value (current)) {
- case 0:
- set_tool (sv, SCHEMATIC_TOOL_ARROW);
- break;
- case 1:
- set_tool (sv, SCHEMATIC_TOOL_TEXT);
- break;
- case 2:
- set_tool (sv, SCHEMATIC_TOOL_WIRE);
- break;
- case 3:
- v_clamp_cmd (sv);
+ case 0:
+ set_tool (sv, SCHEMATIC_TOOL_ARROW);
+ break;
+ case 1:
+ set_tool (sv, SCHEMATIC_TOOL_TEXT);
+ break;
+ case 2:
+ set_tool (sv, SCHEMATIC_TOOL_WIRE);
+ break;
+ case 3:
+ v_clamp_cmd (sv);
}
}
-static void
-part_browser_cmd (GtkToggleAction *action, SchematicView *sv)
+static void part_browser_cmd (GtkToggleAction *action, SchematicView *sv)
{
- part_browser_toggle_show (sv);
+ part_browser_toggle_visibility (sv);
}
-static void
-grid_toggle_snap_cmd (GtkToggleAction *action, SchematicView *sv)
+static void grid_toggle_snap_cmd (GtkToggleAction *action, SchematicView *sv)
{
sv->priv->grid = !sv->priv->grid;
@@ -844,19 +819,32 @@ grid_toggle_snap_cmd (GtkToggleAction *action, SchematicView *sv)
grid_show (sv->priv->sheet->grid, sv->priv->grid);
}
-static void
-smartsearch_cmd (GtkWidget *widget, SchematicView *sv)
+static void log_toggle_visibility_cmd (GtkToggleAction *action, SchematicView *sv)
+{
+ g_return_if_fail (sv);
+ g_return_if_fail (sv->priv->logview);
+
+ GtkAllocation allocation;
+ gboolean b = gtk_toggle_action_get_active (action);
+ static int pos = 0;
+ if (pos == 0)
+ pos = gtk_paned_get_position (GTK_PANED (sv->priv->paned));
+
+ gtk_widget_get_allocation (GTK_WIDGET (sv->priv->paned), &allocation);
+ gtk_paned_set_position (GTK_PANED (sv->priv->paned), b ? pos : allocation.height);
+}
+
+static void smartsearch_cmd (GtkWidget *widget, SchematicView *sv)
{
// Perform a research of a part within all librarys
g_print ("TODO: search_smart ()\n");
}
-static void
-netlist_cmd (GtkWidget *widget, SchematicView *sv)
+static void netlist_cmd (GtkWidget *widget, SchematicView *sv)
{
Schematic *sm;
gchar *netlist_name;
- GError *error = 0;
+ GError *e = NULL;
OreganoEngine *engine;
g_return_if_fail (sv != NULL);
@@ -869,34 +857,33 @@ netlist_cmd (GtkWidget *widget, SchematicView *sv)
schematic_set_netlist_filename (sm, netlist_name);
engine = oregano_engine_factory_create_engine (oregano.engine, sm);
- oregano_engine_generate_netlist (engine, netlist_name, &error);
+ oregano_engine_generate_netlist (engine, netlist_name, &e);
sheet_update_parts (sv->priv->sheet);
g_free (netlist_name);
g_object_unref (engine);
-
- if (error != NULL) {
- if (g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
- g_error_matches (error, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
- oregano_error_with_title (_("Could not create a netlist"),
- error->message);
- g_clear_error (&error);
- }
- else
- oregano_error (_("An unexpected error has occurred"));
- return;
+
+ if (e) {
+ if (g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
+ g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Could not create a netlist."), e);
+ } else {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Unexpect failure occured."), e);
+ }
+ g_clear_error (&e);
+ return;
}
}
-static void
-netlist_view_cmd (GtkWidget *widget, SchematicView *sv)
+static void netlist_view_cmd (GtkWidget *widget, SchematicView *sv)
{
netlist_editor_new_from_schematic_view (sv);
}
-static void
-zoom_check (SchematicView *sv)
+static void zoom_check (SchematicView *sv)
{
double zoom;
@@ -905,94 +892,153 @@ zoom_check (SchematicView *sv)
sheet_get_zoom (sv->priv->sheet, &zoom);
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/StandardToolbar/ZoomIn"), zoom < ZOOM_MAX);
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/StandardToolbar/ZoomOut"), zoom > ZOOM_MIN);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/StandardToolbar/ZoomIn"),
+ zoom < ZOOM_MAX);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/StandardToolbar/ZoomOut"),
+ zoom > ZOOM_MIN);
}
-static void
-zoom_in_cmd (GtkWidget *widget, SchematicView *sv)
+static void zoom_in_cmd (GtkWidget *widget, SchematicView *sv)
{
g_return_if_fail (sv != NULL);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
- sheet_change_zoom (sv->priv->sheet, 1.1);
+ sheet_zoom_step (sv->priv->sheet, 1.1);
zoom_check (sv);
}
-static void
-zoom_out_cmd (GtkWidget *widget, SchematicView *sv)
+static void zoom_out_cmd (GtkWidget *widget, SchematicView *sv)
{
g_return_if_fail (sv != NULL);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
- sheet_change_zoom (sv->priv->sheet, 0.9);
+ sheet_zoom_step (sv->priv->sheet, 0.9);
zoom_check (sv);
}
-static void
-zoom_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
+static void zoom_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
{
switch (gtk_radio_action_get_current_value (current)) {
- case 0:
- g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.50, NULL);
- break;
- case 1:
- g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.75, NULL);
- break;
- case 2:
- g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.0, NULL);
- break;
- case 3:
- g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.25, NULL);
- break;
- case 4:
- g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.5, NULL);
+ case 0:
+ g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.50, NULL);
+ break;
+ case 1:
+ g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.75, NULL);
+ break;
+ case 2:
+ g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.0, NULL);
+ break;
+ case 3:
+ g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.25, NULL);
+ break;
+ case 4:
+ g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.5, NULL);
break;
}
zoom_check (sv);
}
-static void
-simulate_cmd (GtkWidget *widget, SchematicView *sv)
+/*
+ * Stretch the sheet horizontally.
+ */
+static void stretch_horizontal_cmd (GtkWidget *widget, SchematicView *sv)
+{
+ Schematic *sm;
+ guint width;
+
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+
+ sm = sv->priv->schematic;
+
+ g_return_if_fail (sm != NULL);
+ g_return_if_fail (IS_SCHEMATIC (sm));
+
+ width = schematic_get_width (sm);
+ schematic_set_width (sm, width * (1.0 + SCHEMATIC_STRETCH_FACTOR));
+
+ if (sheet_replace (sv)) {
+ schematic_view_reload (sv, sm);
+
+ gtk_widget_show_all (schematic_view_get_toplevel (sv));
+ }
+}
+
+/*
+ * Stretch the sheet vertically.
+ */
+static void stretch_vertical_cmd (GtkWidget *widget, SchematicView *sv)
+{
+ Schematic *sm;
+ guint height;
+
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+
+ sm = sv->priv->schematic;
+
+ g_return_if_fail (sm != NULL);
+ g_return_if_fail (IS_SCHEMATIC (sm));
+
+ height = schematic_get_height (sm);
+ schematic_set_height (sm, height * (1.0 + SCHEMATIC_STRETCH_FACTOR));
+
+ if (sheet_replace (sv)) {
+ schematic_view_reload (sv, sm);
+
+ gtk_widget_show_all (schematic_view_get_toplevel (sv));
+ }
+}
+
+void schematic_view_simulate_cmd (GtkWidget *widget, SchematicView *sv)
{
- simulation_show (NULL, sv);
+ Schematic *sm;
+ SimSettings *sim_settings;
+
+ sm = schematic_view_get_schematic (sv);
+ sim_settings = schematic_get_sim_settings (sm);
+
+ // Before running the simulation for the first time, make
+ // sure that the simulation settings are configured (this
+ // includes the removal of missing output vectors from
+ // previous application runs).
+ if (!sim_settings->configured) {
+ // The response_callback() function will take care
+ // of launching the simulation again when the
+ // simulation settings have been accepted.
+ sim_settings->simulation_requested = TRUE;
+ sim_settings_show (NULL, sv);
+ return;
+ }
+
+ simulation_show_progress_bar (NULL, sv);
sheet_update_parts (sv->priv->sheet);
return;
}
-static void
-schematic_view_class_init (SchematicViewClass *klass)
+static void schematic_view_class_init (SchematicViewClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
- schematic_view_signals[CHANGED] = g_signal_new ("changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicViewClass, changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- schematic_view_signals[RESET_TOOL] = g_signal_new ("reset_tool",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SchematicViewClass, reset_tool),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ schematic_view_signals[CHANGED] =
+ g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicViewClass, changed), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ schematic_view_signals[RESET_TOOL] =
+ g_signal_new ("reset_tool", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SchematicViewClass, reset_tool), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
object_class->finalize = schematic_view_finalize;
object_class->dispose = schematic_view_dispose;
}
-static void
-schematic_view_init (SchematicView *sv)
+static void schematic_view_init (SchematicView *sv)
{
sv->priv = g_new0 (SchematicViewPriv, 1);
sv->priv->log_info = g_new0 (LogInfo, 1);
@@ -1001,152 +1047,213 @@ schematic_view_init (SchematicView *sv)
sv->priv->page_setup = NULL;
sv->priv->print_settings = gtk_print_settings_new ();
sv->priv->grid = TRUE;
+ sv->priv->logview = NULL;
}
-static void
-schematic_view_finalize (GObject *object)
+static void schematic_view_finalize (GObject *object)
{
SchematicView *sv = SCHEMATIC_VIEW (object);
if (sv->priv) {
+ if (sv->priv->page_setup) {
+ g_object_unref (sv->priv->page_setup);
+ }
+
+ g_object_unref (sv->priv->print_settings);
+ g_object_unref (sv->priv->action_group);
+ g_object_unref (sv->priv->ui_manager);
+ g_object_unref (sv->priv->paned);
+
+ g_free (sv->priv->log_info);
g_free (sv->priv);
sv->priv = NULL;
}
if (sv->toplevel) {
- gtk_widget_destroy (GTK_WIDGET (sv->toplevel));
+ g_object_unref (G_OBJECT (sv->toplevel));
sv->toplevel = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-schematic_view_dispose (GObject *object)
+static void schematic_view_dispose (GObject *object)
{
SchematicView *sv = SCHEMATIC_VIEW (object);
schematic_view_list = g_list_remove (schematic_view_list, sv);
- // Disconnect sheet's events
- g_signal_handlers_disconnect_by_func (G_OBJECT (sv->priv->sheet),
- G_CALLBACK (sheet_event_callback), sv->priv->sheet);
-
- // Disconnect focus signal
- g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel),
- G_CALLBACK (set_focus), sv);
+ if (sv->toplevel) {
+ // Disconnect focus signal
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel), G_CALLBACK (set_focus), sv);
- // Disconnect destroy event from toplevel
- g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel),
- G_CALLBACK (delete_event), sv);
+ // Disconnect destroy event from toplevel
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel), G_CALLBACK (delete_event), sv);
+ }
if (sv->priv) {
+ if (IS_SHEET (sv->priv->sheet)) {
+ // Disconnect sheet's events
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sv->priv->sheet),
+ G_CALLBACK (sheet_event_callback), sv->priv->sheet);
+ }
+
g_object_unref (G_OBJECT (sv->priv->schematic));
}
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
-static void
-show_help (GtkWidget *widget, SchematicView *sv)
+static void show_help (GtkWidget *widget, SchematicView *sv)
{
- GError *error = NULL;
+ GError *e = NULL;
- GtkWidget *temp;
- temp = sv->toplevel;
+#if GTK_CHECK_VERSION (3,22,0)
+ if (!gtk_show_uri_on_window (GTK_WINDOW (sv->toplevel), "help:oregano", gtk_get_current_event_time (),
+#else
+ if (!gtk_show_uri (gtk_widget_get_screen (sv->toplevel), "help:oregano", gtk_get_current_event_time (),
+#endif
+ &e)) {
+ NG_DEBUG ("Error %s\n", e->message);
+ g_clear_error (&e);
+ }
+}
- if (!gtk_show_uri (gtk_widget_get_screen (temp), "ghelp:oregano",
- gtk_get_current_event_time (), &error)) {
- NG_DEBUG (g_strdup_printf ("Error %s\n", error->message));
- g_error_free (error);
+/**
+ * Get a suitable value for the window size.
+ *
+ * Make the window occupy 3/4 of the screen with a padding of 50px in each
+ * direction
+ */
+static void get_window_size (GtkWindow *window, GdkRectangle *rect)
+{
+ GdkRectangle monitor_rect;
+#if GTK_CHECK_VERSION (3,22,0)
+ GdkMonitor *monitor;
+ GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (window));
+#else
+ gint monitor;
+ GdkScreen *screen = gdk_screen_get_default ();
+#endif
+
+#if GTK_CHECK_VERSION (3,22,0)
+ if (display) {
+ monitor = gdk_display_get_primary_monitor (display);
+ gdk_monitor_get_geometry (monitor, &monitor_rect);
+#else
+ if (screen) {
+ monitor = gdk_screen_get_primary_monitor (screen);
+ gdk_screen_get_monitor_geometry (screen, monitor, &monitor_rect);
+#endif
+
+ rect->width = 3 * (monitor_rect.width - 50) / 4;
+ rect->height = 3 * (monitor_rect.height - 50) / 4;
+ } else {
+ g_warning ("No default screen found. Falling back to 1024x768 window size.");
+ rect->width = 1024;
+ rect->height = 768;
}
}
+static void set_window_size (SchematicView *sv)
+{
+ GdkRectangle rect;
+
+ get_window_size (GTK_WINDOW (sv->toplevel), &rect);
+
+ gtk_window_set_default_size (GTK_WINDOW (sv->toplevel), rect.width, rect.height);
+}
+
#include "schematic-view-menu.h"
-SchematicView *
-schematic_view_new (Schematic *schematic)
+SchematicView *schematic_view_new (Schematic *schematic)
{
SchematicView *sv;
SchematicViewPriv *priv;
+ Schematic *sm;
GtkWidget *w, *hbox, *vbox;
GtkWidget *toolbar, *part_browser;
+ GtkWidget *logview;
+ GtkWidget *logview_scrolled;
GtkActionGroup *action_group;
GtkUIManager *ui_manager;
GtkAccelGroup *accel_group;
GtkWidget *menubar;
- GtkTable *table;
- GError *error = NULL;
- GtkBuilder *gui;
- gchar *msg;
+ GtkGrid *grid;
+ GtkPaned *paned;
+ GError *e = NULL;
+ GtkBuilder *builder;
+ GdkRectangle window_size;
- g_return_val_if_fail (schematic != NULL, NULL);
+ g_return_val_if_fail (schematic, NULL);
g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
- sv = SCHEMATIC_VIEW (g_object_new (schematic_view_get_type(), NULL));
+ sv = SCHEMATIC_VIEW (g_object_new (schematic_view_get_type (), NULL));
schematic_view_list = g_list_prepend (schematic_view_list, sv);
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create main window."));
- return NULL;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/oregano-main.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall "
- "Oregano to fix this"), OREGANO_UIDIR "/oregano-main.ui");
- oregano_error_with_title (_("Could not create main window."), msg);
- g_free (msg);
+ sm = schematic_view_get_schematic (sv);
+
+ if ((builder = gtk_builder_new ()) == NULL) {
+ log_append (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Failed to spawn builder object."));
return NULL;
}
+ gtk_builder_set_translation_domain (builder, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/oregano-main.ui",
- &error) <= 0) {
- msg = error->message;
- oregano_error_with_title (_("Could not create main window."), msg);
- g_error_free (error);
+ if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/oregano-main.ui", &e) <= 0) {
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Could not create main window from file."), e);
+ g_clear_error (&e);
return NULL;
}
- sv->toplevel = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
- table = GTK_TABLE (gtk_builder_get_object (gui, "table1"));
+ sv->toplevel = GTK_WIDGET (gtk_builder_get_object (builder, "toplevel"));
+ grid = GTK_GRID (gtk_builder_get_object (builder, "grid"));
+ paned = GTK_PANED (gtk_builder_get_object (builder, "paned"));
+ sv->priv->paned = paned;
+
+ get_window_size (GTK_WINDOW (sv->toplevel), &window_size);
+ if (schematic_get_width (schematic) < window_size.width)
+ schematic_set_width (schematic, window_size.width);
+ if (schematic_get_height (schematic) < window_size.height)
+ schematic_set_height (schematic, window_size.height);
- sv->priv->sheet = SHEET (sheet_new (10000, 10000));
+ sv->priv->sheet = SHEET (sheet_new ((double) schematic_get_width (schematic) + SHEET_BORDER, (double) schematic_get_height (schematic) + SHEET_BORDER));
- g_signal_connect (G_OBJECT (sv->priv->sheet),
- "event", G_CALLBACK (sheet_event_callback),
- sv->priv->sheet);
+ g_signal_connect (G_OBJECT (sv->priv->sheet), "event", G_CALLBACK (sheet_event_callback),
+ sv->priv->sheet);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
w = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN);
+ gtk_widget_set_hexpand (w, TRUE);
+ gtk_widget_set_vexpand (w, TRUE);
+
gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (sv->priv->sheet));
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 5);
-
+
part_browser = part_browser_create (sv);
gtk_widget_set_hexpand (part_browser, FALSE);
- gtk_box_pack_start (GTK_BOX (hbox), part_browser, FALSE, FALSE, 5);
-
+ gtk_grid_attach_next_to (grid, part_browser, GTK_WIDGET (paned), GTK_POS_RIGHT, 1, 1);
+
priv = sv->priv;
priv->log_info->log_window = NULL;
priv->action_group = action_group = gtk_action_group_new ("MenuActions");
- gtk_action_group_set_translation_domain (priv->action_group,
- GETTEXT_PACKAGE);
- gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries),
- sv);
- gtk_action_group_add_radio_actions (action_group, zoom_entries,
- G_N_ELEMENTS (zoom_entries), 2, G_CALLBACK (zoom_cmd), sv);
- gtk_action_group_add_radio_actions (action_group, tools_entries,
- G_N_ELEMENTS (tools_entries), 0, G_CALLBACK (tool_cmd), sv);
- gtk_action_group_add_toggle_actions (action_group, toggle_entries,
- G_N_ELEMENTS (toggle_entries), sv);
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), sv);
+ gtk_action_group_add_radio_actions (action_group, zoom_entries, G_N_ELEMENTS (zoom_entries), 2,
+ G_CALLBACK (zoom_cmd), sv);
+ gtk_action_group_add_radio_actions (action_group, tools_entries, G_N_ELEMENTS (tools_entries),
+ 0, G_CALLBACK (tool_cmd), sv);
+ g_assert_cmpint (G_N_ELEMENTS (toggle_entries), >=, 4);
+ gtk_action_group_add_toggle_actions (action_group, toggle_entries,
+ G_N_ELEMENTS (toggle_entries), sv);
priv->ui_manager = ui_manager = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
@@ -1154,16 +1261,14 @@ schematic_view_new (Schematic *schematic)
accel_group = gtk_ui_manager_get_accel_group (ui_manager);
gtk_window_add_accel_group (GTK_WINDOW (sv->toplevel), accel_group);
- error = NULL;
- if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1,
- &error)) {
- g_message ("building menus failed: %s", error->message);
- g_error_free (error);
+ if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &e)) {
+ g_message ("building menus failed: %s", e->message);
+ g_clear_error (&e);
return NULL;
}
menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
-
+
// Upgrade the menu bar with the recent files used by oregano
display_recent_files (menubar, sv);
gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
@@ -1174,62 +1279,75 @@ schematic_view_new (Schematic *schematic)
// Fill the window
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
- gtk_table_attach_defaults (table, vbox, 0, 1, 0, 1);
- gtk_window_set_focus (GTK_WINDOW (sv->toplevel),
- GTK_WIDGET (sv->priv->sheet));
+ gtk_paned_pack1 (paned, vbox, FALSE, TRUE);
gtk_widget_grab_focus (GTK_WIDGET (sv->priv->sheet));
- g_signal_connect_after (G_OBJECT (sv->toplevel), "set_focus",
- G_CALLBACK (set_focus), sv);
- g_signal_connect (G_OBJECT (sv->toplevel), "delete_event",
- G_CALLBACK (delete_event), sv);
+ g_signal_connect_after (G_OBJECT (sv->toplevel), "set_focus", G_CALLBACK (set_focus), sv);
+ g_signal_connect (G_OBJECT (sv->toplevel), "delete_event", G_CALLBACK (delete_event), sv);
+
+ sv->priv->logview = logview = GTK_WIDGET (log_view_new ());
+ log_view_set_store (LOG_VIEW (logview), schematic_get_log_store (schematic));
+
+ logview_scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (logview_scrolled), logview);
+ gtk_paned_pack2 (paned, logview_scrolled, FALSE, TRUE);
setup_dnd (sv);
- // Set default sensitive for items
- gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
- "/MainMenu/MenuEdit/ObjectProperties"), FALSE);
- gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
- "/MainMenu/MenuEdit/Paste"), FALSE);
+ // Set default sensitive for items
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (ui_manager, "/MainMenu/MenuEdit/ObjectProperties"), FALSE);
+ gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager, "/MainMenu/MenuEdit/Paste"),
+ FALSE);
- // Set the window size to something reasonable.
- gtk_window_set_default_size (GTK_WINDOW (sv->toplevel),
- 3 * gdk_screen_width () / 5, 3 * gdk_screen_height () / 5);
+ g_signal_connect_object (G_OBJECT (sv), "reset_tool", G_CALLBACK (reset_tool_cb), G_OBJECT (sv),
+ 0);
- g_signal_connect_object (G_OBJECT (sv), "reset_tool",
- G_CALLBACK (reset_tool_cb), G_OBJECT (sv), 0);
+ set_window_size (sv);
schematic_view_load (sv, schematic);
if (!schematic_get_title (sv->priv->schematic)) {
- gtk_window_set_title (GTK_WINDOW (sv->toplevel), _("Untitled.oregano"));
- }
- else {
- gtk_window_set_title (GTK_WINDOW (sv->toplevel),
- schematic_get_title (sv->priv->schematic));
+ gtk_window_set_title (GTK_WINDOW (sv->toplevel), _ ("Untitled.oregano"));
+ } else {
+ gtk_window_set_title (GTK_WINDOW (sv->toplevel), schematic_get_title (sv->priv->schematic));
}
- schematic_set_filename (sv->priv->schematic, _("Untitled.oregano"));
- schematic_set_netlist_filename (sv->priv->schematic, _("Untitled.netlist"));
+ schematic_set_filename (sv->priv->schematic, _ ("Untitled.oregano"));
+ schematic_set_netlist_filename (sv->priv->schematic, _ ("Untitled.netlist"));
+
+ gtk_window_set_application (GTK_WINDOW (schematic_view_get_toplevel (sv)),
+ GTK_APPLICATION (g_application_get_default ()));
return sv;
}
-static void
-schematic_view_load (SchematicView *sv, Schematic *sm)
+static void schematic_view_load (SchematicView *sv, Schematic *sm)
{
- GList *list;
- g_return_if_fail (sv->priv->empty != FALSE);
+ schematic_view_do_load (sv, sm, FALSE);
+}
+
+static void schematic_view_do_load (SchematicView *sv, Schematic *sm, const gboolean reload)
+{
+ GList *list;
+ g_return_if_fail (sv != NULL);
g_return_if_fail (sm != NULL);
+ g_return_if_fail (IS_SCHEMATIC (sm));
+
+ if (!reload)
+ g_return_if_fail (sv->priv->empty != FALSE);
- if (sv->priv->schematic) g_object_unref (G_OBJECT (sv->priv->schematic));
+ if (!reload && sv->priv->schematic)
+ g_object_unref (G_OBJECT (sv->priv->schematic));
sv->priv->schematic = sm;
- g_signal_connect_object (G_OBJECT (sm), "title_changed",
- G_CALLBACK (title_changed_callback), G_OBJECT (sv), 0);
- g_signal_connect_object (G_OBJECT (sm), "item_data_added",
- G_CALLBACK (item_data_added_callback), G_OBJECT (sv), 0);
+ if (!reload) {
+ g_signal_connect_object (G_OBJECT (sm), "title_changed", G_CALLBACK (title_changed_callback),
+ G_OBJECT (sv), 0);
+ g_signal_connect_object (G_OBJECT (sm), "item_data_added",
+ G_CALLBACK (item_data_added_callback), G_OBJECT (sv), 0);
+ }
list = schematic_get_items (sm);
@@ -1239,35 +1357,43 @@ schematic_view_load (SchematicView *sv, Schematic *sm)
sheet_connect_node_dots_to_signals (sv->priv->sheet);
+ // connect logview with logstore
+ if (!reload)
+ log_view_set_store (LOG_VIEW (sv->priv->logview), schematic_get_log_store (sm));
+
+ schematic_set_dirty (sm, FALSE);
+
g_list_free_full (list, g_object_unref);
}
-static void
-item_selection_changed_callback (SheetItem *item, gboolean selected,
- SchematicView *sv)
+static void schematic_view_reload (SchematicView *sv, Schematic *sm)
+{
+ schematic_view_do_load (sv, sm, TRUE);
+}
+
+static void item_selection_changed_callback (SheetItem *item, gboolean selected, SchematicView *sv)
{
guint length;
if (selected) {
sheet_prepend_selected_object (sv->priv->sheet, item);
- }
- else {
+ } else {
sheet_remove_selected_object (sv->priv->sheet, item);
}
length = sheet_get_selected_objects_length (sv->priv->sheet);
if (length && item_data_has_properties (sheet_item_get_data (item)))
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/ObjectProperties"), TRUE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/ObjectProperties"),
+ TRUE);
else
- gtk_action_set_sensitive (gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/MainMenu/MenuEdit/ObjectProperties"), FALSE);
+ gtk_action_set_sensitive (
+ gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/ObjectProperties"),
+ FALSE);
}
// An ItemData got added; create an Item and set up the neccessary handlers.
-static void
-item_data_added_callback (Schematic *schematic, ItemData *data,
- SchematicView *sv)
+static void item_data_added_callback (Schematic *schematic, ItemData *data, SchematicView *sv)
{
Sheet *sheet;
SheetItem *item;
@@ -1279,21 +1405,23 @@ item_data_added_callback (Schematic *schematic, ItemData *data,
if (item != NULL) {
sheet_item_place (item, sv->priv->sheet);
- g_object_set (G_OBJECT (item), "action_group", sv->priv->action_group,
- NULL);
+ g_object_set (G_OBJECT (item), "action_group", sv->priv->action_group, NULL);
g_signal_connect (G_OBJECT (item), "selection_changed",
- G_CALLBACK (item_selection_changed_callback), sv);
+ G_CALLBACK (item_selection_changed_callback), sv);
sheet_add_item (sheet, item);
sv->priv->empty = FALSE;
if (sv->priv->tool == SCHEMATIC_TOOL_PART)
schematic_view_reset_tool (sv);
+
+ // refresh _after_ we added it to the Sheet
+ // this is required to properly display rotation, flip and others
+ item_data_changed (data);
}
}
-static void
-title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv)
+static void title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv)
{
g_return_if_fail (schematic != NULL);
g_return_if_fail (IS_SCHEMATIC (schematic));
@@ -1303,8 +1431,7 @@ title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv
gtk_window_set_title (GTK_WINDOW (sv->toplevel), new_title);
}
-static void
-set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv)
+static void set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv)
{
g_return_if_fail (sv->priv != NULL);
g_return_if_fail (sv->priv->sheet != NULL);
@@ -1313,47 +1440,38 @@ set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv)
gtk_widget_grab_focus (GTK_WIDGET (sv->priv->sheet));
}
-static int
-delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
+static int delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
{
if (can_close (sv)) {
g_object_unref (G_OBJECT (sv));
return FALSE;
- }
- else
+ } else
return TRUE;
}
-static int
-can_close (SchematicView *sv)
+static int can_close (SchematicView *sv)
{
GtkWidget *dialog;
gchar *text, *filename;
- GError *error = NULL;
+ GError *e = NULL;
gint result;
if (!schematic_is_dirty (schematic_view_get_schematic (sv)))
- return TRUE;
-
+ return TRUE;
+
filename = schematic_get_filename (sv->priv->schematic);
- text = g_strdup_printf (_("<span weight=\"bold\" size=\"large\">Save "
- "changes to schematic %s before closing?</span>\n\nIf you don't save, "
- "all changes since you last saved will be permanently lost."),
- filename ? g_path_get_basename (filename) : NULL );
-
- dialog = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_NONE,
- _(text), NULL);
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- _("Close _without Saving"),
- GTK_RESPONSE_NO,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_YES,
- NULL);
+ text =
+ g_strdup_printf (_ ("<span weight=\"bold\" size=\"large\">Save "
+ "changes to schematic %s before closing?</span>\n\nIf you don't save, "
+ "all changes since you last saved will be permanently lost."),
+ filename ? g_path_get_basename (filename) : NULL);
+
+ dialog = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE, _ (text), NULL);
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog), _ ("Close _without Saving"), GTK_RESPONSE_NO,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES,
+ NULL);
g_free (text);
@@ -1362,21 +1480,23 @@ can_close (SchematicView *sv)
gtk_widget_destroy (dialog);
switch (result) {
- case GTK_RESPONSE_YES:
- schematic_save_file (sv->priv->schematic, &error);
- break;
- case GTK_RESPONSE_NO:
- schematic_set_dirty (sv->priv->schematic, FALSE);
- break;
- case GTK_RESPONSE_CANCEL:
- default:
- return FALSE;
+ case GTK_RESPONSE_YES:
+ schematic_save_file (sv->priv->schematic, &e);
+ if (e) {
+ g_clear_error (&e);
+ }
+ break;
+ case GTK_RESPONSE_NO:
+ schematic_set_dirty (sv->priv->schematic, FALSE);
+ break;
+ case GTK_RESPONSE_CANCEL:
+ default:
+ return FALSE;
}
return TRUE;
}
-Sheet *
-schematic_view_get_sheet (SchematicView *sv)
+Sheet *schematic_view_get_sheet (SchematicView *sv)
{
g_return_val_if_fail (sv != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
@@ -1384,8 +1504,15 @@ schematic_view_get_sheet (SchematicView *sv)
return sv->priv->sheet;
}
-Schematic *
-schematic_view_get_schematic (SchematicView *sv)
+void schematic_view_set_sheet (SchematicView *sv, Sheet *sheet)
+{
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+
+ sv->priv->sheet = sheet;
+}
+
+Schematic *schematic_view_get_schematic (SchematicView *sv)
{
g_return_val_if_fail (sv != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
@@ -1393,8 +1520,7 @@ schematic_view_get_schematic (SchematicView *sv)
return sv->priv->schematic;
}
-void
-schematic_view_reset_tool (SchematicView *sv)
+void schematic_view_reset_tool (SchematicView *sv)
{
g_return_if_fail (sv != NULL);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
@@ -1402,79 +1528,75 @@ schematic_view_reset_tool (SchematicView *sv)
g_signal_emit_by_name (G_OBJECT (sv), "reset_tool");
}
-static void
-setup_dnd (SchematicView *sv)
+static void setup_dnd (SchematicView *sv)
{
- static GtkTargetEntry dnd_types[] = {
- { "text/uri-list", 0, DRAG_URI_INFO },
- { "x-application/oregano-part", 0, DRAG_PART_INFO }
- };
- static gint dnd_num_types = sizeof (dnd_types) / sizeof (dnd_types[0]);
+ static GtkTargetEntry dnd_types[] = {{"text/uri-list", 0, DRAG_URI_INFO},
+ {"x-application/oregano-part", 0, DRAG_PART_INFO}};
+ static gint dnd_num_types = sizeof(dnd_types) / sizeof(dnd_types[0]);
gtk_drag_dest_set (GTK_WIDGET (sv->priv->sheet),
- GTK_DEST_DEFAULT_MOTION |
- GTK_DEST_DEFAULT_HIGHLIGHT |
- GTK_DEST_DEFAULT_DROP,
- dnd_types, dnd_num_types, GDK_ACTION_MOVE);
+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
+ dnd_types, dnd_num_types, GDK_ACTION_MOVE);
- g_signal_connect (G_OBJECT (sv->priv->sheet), "drag_data_received",
- G_CALLBACK (data_received),
- "koko");
+ g_signal_connect (G_OBJECT (sv->priv->sheet), "drag_data_received", G_CALLBACK (data_received),
+ "koko");
}
-static void
-data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
- GtkSelectionData *selection_data, guint info, guint32 time,
- SchematicView *sv)
+static void data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint info, guint32 time,
+ SchematicView *sv)
{
gchar **files;
- GError *error = NULL;
+ GError *e = NULL;
// Extract the filenames from the URI-list we received.
switch (info) {
- case DRAG_PART_INFO:
- part_browser_dnd (selection_data, x, y);
+ case DRAG_PART_INFO:
+ part_browser_dnd (selection_data, x, y);
break;
- case DRAG_URI_INFO:
- files = g_strsplit ((gchar *) gtk_selection_data_get_data (selection_data), "\n", -1);
- if (files) {
- int i=0;
- while (files[i]) {
- Schematic *new_sm = NULL;
- int l = strlen (files[i]);
- // Algo remains bad after the split: we agregate back into one \0
- files[i][l-1] = '\0';
-
- if (l <= 0) {
- // Empty file name, ignore!
- i++;
- continue;
- }
+ case DRAG_URI_INFO:
+ files = g_strsplit ((gchar *)gtk_selection_data_get_data (selection_data), "\n", -1);
+ if (files) {
+ int i = 0;
+ while (files[i]) {
+ Schematic *new_sm = NULL;
+ int l = strlen (files[i]);
+ // Algo remains bad after the split: we agregate back into one \0
+ files[i][l - 1] = '\0';
+
+ if (l <= 0) {
+ // Empty file name, ignore!
+ i++;
+ continue;
+ }
- gchar *fname = files[i];
-
- new_sm = schematic_read (fname, &error);
- if (new_sm) {
- SchematicView *new_view;
- new_view = schematic_view_new (new_sm);
- if (new_view) {
- gtk_widget_show_all (new_view->toplevel);
- schematic_set_filename (new_sm, fname);
- }
- // schematic_set_title (new_sm, fname);
- while (gtk_events_pending ()) // Show something.
- gtk_main_iteration ();
- }
- i++;
+ gchar *fname = files[i];
+
+ new_sm = schematic_read (fname, &e);
+ if (e) {
+ // g_warning ()
+ g_clear_error (&e);
+ }
+ if (new_sm) {
+ SchematicView *new_view;
+ new_view = schematic_view_new (new_sm);
+ if (new_view) {
+ gtk_widget_show_all (new_view->toplevel);
+ schematic_set_filename (new_sm, fname);
}
+ // schematic_set_title (new_sm, fname);
+ while (gtk_events_pending ()) // Show something.
+ gtk_main_iteration ();
}
+ i++;
+ }
+ g_strfreev (files);
+ }
}
gtk_drag_finish (context, TRUE, TRUE, time);
}
-
-static void
-set_tool (SchematicView *sv, SchematicTool tool)
+static void set_tool (SchematicView *sv, SchematicTool tool)
{
// Switch from this tool...
switch (sv->priv->tool) {
@@ -1484,19 +1606,19 @@ set_tool (SchematicView *sv, SchematicTool tool)
sheet_item_cancel_floating (sv->priv->sheet);
break;
case SCHEMATIC_TOOL_WIRE:
- /*if (sv->priv->create_wire_context) {
- create_wire_exit (sv->priv->create_wire_context);
- sv->priv->create_wire_context = NULL;
- }*/
- sheet_stop_create_wire (sv->priv->sheet);
- break;
+ /*if (sv->priv->create_wire_context) {
+ create_wire_exit (sv->priv->create_wire_context);
+ sv->priv->create_wire_context = NULL;
+ }*/
+ sheet_stop_create_wire (sv->priv->sheet);
+ break;
case SCHEMATIC_TOOL_TEXT:
- textbox_item_cancel_listen (sv->priv->sheet);
- break;
+ textbox_item_cancel_listen (sv->priv->sheet);
+ break;
case SCHEMATIC_TOOL_PART:
- sheet_item_cancel_floating (sv->priv->sheet);
+ sheet_item_cancel_floating (sv->priv->sheet);
default:
- break;
+ break;
}
// ...to this tool.
@@ -1506,8 +1628,7 @@ set_tool (SchematicView *sv, SchematicTool tool)
sv->priv->sheet->state = SHEET_STATE_NONE;
break;
case SCHEMATIC_TOOL_WIRE:
- cursor_set_widget (GTK_WIDGET (sv->priv->sheet),
- OREGANO_CURSOR_PENCIL);
+ cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_PENCIL);
sv->priv->sheet->state = SHEET_STATE_WIRE;
sheet_initiate_create_wire (sv->priv->sheet);
break;
@@ -1518,8 +1639,7 @@ set_tool (SchematicView *sv, SchematicTool tool)
textbox_item_listen (sv->priv->sheet);
break;
case SCHEMATIC_TOOL_PART:
- cursor_set_widget (GTK_WIDGET (sv->priv->sheet),
- OREGANO_CURSOR_LEFT_PTR);
+ cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_LEFT_PTR);
default:
break;
}
@@ -1527,18 +1647,16 @@ set_tool (SchematicView *sv, SchematicTool tool)
sv->priv->tool = tool;
}
-static void
-reset_tool_cb (Sheet *sheet, SchematicView *sv)
+static void reset_tool_cb (Sheet *sheet, SchematicView *sv)
{
set_tool (sv, SCHEMATIC_TOOL_ARROW);
- gtk_radio_action_set_current_value (GTK_RADIO_ACTION (
- gtk_ui_manager_get_action (sv->priv->ui_manager,
- "/StandardToolbar/Arrow")), 0);
+ gtk_radio_action_set_current_value (GTK_RADIO_ACTION (gtk_ui_manager_get_action (
+ sv->priv->ui_manager, "/StandardToolbar/Arrow")),
+ 0);
}
-gpointer
-schematic_view_get_browser (SchematicView *sv)
+gpointer schematic_view_get_browser (SchematicView *sv)
{
g_return_val_if_fail (sv != NULL, NULL);
g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
@@ -1546,8 +1664,7 @@ schematic_view_get_browser (SchematicView *sv)
return sv->priv->browser;
}
-void
-schematic_view_set_browser (SchematicView *sv, gpointer p)
+void schematic_view_set_browser (SchematicView *sv, gpointer p)
{
g_return_if_fail (sv != NULL);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
@@ -1555,28 +1672,24 @@ schematic_view_set_browser (SchematicView *sv, gpointer p)
sv->priv->browser = p;
}
-static gboolean
-log_window_delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
+static gboolean log_window_delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
{
sv->priv->log_info->log_window = NULL;
return FALSE;
}
-static void
-log_window_destroy_event (GtkWidget *widget, SchematicView *sv)
+static void log_window_destroy_event (GtkWidget *widget, SchematicView *sv)
{
sv->priv->log_info->log_window = NULL;
}
-static void
-log_window_close_cb (GtkWidget *widget, SchematicView *sv)
+static void log_window_close_cb (GtkWidget *widget, SchematicView *sv)
{
gtk_widget_destroy (sv->priv->log_info->log_window);
sv->priv->log_info->log_window = NULL;
}
-static void
-log_window_clear_cb (GtkWidget *widget, SchematicView *sv)
+static void log_window_clear_cb (GtkWidget *widget, SchematicView *sv)
{
GtkTextTagTable *tag;
GtkTextBuffer *buf;
@@ -1586,23 +1699,19 @@ log_window_clear_cb (GtkWidget *widget, SchematicView *sv)
schematic_log_clear (sv->priv->schematic);
- gtk_text_view_set_buffer (GTK_TEXT_VIEW (sv->priv->log_info->log_text),
- GTK_TEXT_BUFFER (buf));
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (sv->priv->log_info->log_text), GTK_TEXT_BUFFER (buf));
}
-static void
-log_updated_callback (Schematic *sm, SchematicView *sv)
+static void log_updated_callback (Schematic *sm, SchematicView *sv)
{
schematic_view_log_show (sv, FALSE);
}
-void
-schematic_view_log_show (SchematicView *sv, gboolean explicit)
+void schematic_view_log_show (SchematicView *sv, gboolean explicit)
{
GtkWidget *w;
- gchar *msg;
Schematic *sm;
- GError *perror = NULL;
+ GError *e = NULL;
g_return_if_fail (sv != NULL);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
@@ -1610,129 +1719,105 @@ schematic_view_log_show (SchematicView *sv, gboolean explicit)
sm = sv->priv->schematic;
if ((sv->priv->log_info->log_gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create the log window."));
+ log_append (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Could not create the log window."));
return;
- }
- else
- gtk_builder_set_translation_domain (sv->priv->log_info->log_gui, NULL);
+ }
+ gtk_builder_set_translation_domain (sv->priv->log_info->log_gui, NULL);
if (sv->priv->log_info->log_window == NULL) {
// Create the log window if not already done.
if (!explicit && !oregano.show_log)
return;
- if (!g_file_test (OREGANO_UIDIR "/log-window.ui", G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/log-window.ui");
- oregano_error_with_title ( _("Could not create the log window"), msg);
- g_free (msg);
- return;
- }
+ if (gtk_builder_add_from_file (sv->priv->log_info->log_gui, OREGANO_UIDIR "/log-window.ui",
+ &e) <= 0) {
- if (gtk_builder_add_from_file (sv->priv->log_info->log_gui,
- OREGANO_UIDIR "/log-window.ui", &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create the log window."), msg);
- g_error_free (perror);
+ log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
+ _ ("Could not create the log window."), e);
+ g_clear_error (&e);
return;
}
- sv->priv->log_info->log_window = GTK_WIDGET (
- gtk_builder_get_object (sv->priv->log_info->log_gui,
- "log-window"));
- sv->priv->log_info->log_text = GTK_TEXT_VIEW (
- gtk_builder_get_object (sv->priv->log_info->log_gui,
- "log-text"));
+ sv->priv->log_info->log_window =
+ GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "log-window"));
+ sv->priv->log_info->log_text =
+ GTK_TEXT_VIEW (gtk_builder_get_object (sv->priv->log_info->log_gui, "log-text"));
- gtk_window_set_default_size (GTK_WINDOW (sv->priv->log_info->log_window),
- 500, 250);
+ gtk_window_set_default_size (GTK_WINDOW (sv->priv->log_info->log_window), 500, 250);
// Delete event.
- g_signal_connect (G_OBJECT (sv->priv->log_info->log_window),
- "delete_event", G_CALLBACK (log_window_delete_event), sv);
-
- g_signal_connect (G_OBJECT (sv->priv->log_info->log_window),
- "destroy_event", G_CALLBACK (log_window_destroy_event), sv);
-
- w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui,
- "close-button"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (log_window_close_cb), sv);
-
- w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui,
- "clear-button"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (log_window_clear_cb), sv);
- g_signal_connect (G_OBJECT (sm), "log_updated",
- G_CALLBACK (log_updated_callback), sv);
- }
- else {
+ g_signal_connect (G_OBJECT (sv->priv->log_info->log_window), "delete_event",
+ G_CALLBACK (log_window_delete_event), sv);
+
+ g_signal_connect (G_OBJECT (sv->priv->log_info->log_window), "destroy_event",
+ G_CALLBACK (log_window_destroy_event), sv);
+
+ w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "close-button"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (log_window_close_cb), sv);
+
+ w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "clear-button"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (log_window_clear_cb), sv);
+ g_signal_connect (G_OBJECT (sm), "log_updated", G_CALLBACK (log_updated_callback), sv);
+ } else {
gdk_window_raise (gtk_widget_get_window (sv->priv->log_info->log_window));
}
- gtk_text_view_set_buffer (sv->priv->log_info->log_text,
- schematic_get_log_text (sm));
+ gtk_text_view_set_buffer (sv->priv->log_info->log_text, schematic_get_log_text (sm));
gtk_widget_show_all (sv->priv->log_info->log_window);
}
-gboolean
-schematic_view_get_log_window_exists (SchematicView *sv)
+gboolean schematic_view_get_log_window_exists (SchematicView *sv)
{
if (sv->priv->log_info->log_window != NULL)
- return TRUE;
+ return TRUE;
else
- return FALSE;
+ return FALSE;
}
-GtkWidget *
-schematic_view_get_toplevel (SchematicView *sv)
-{
- return sv->toplevel;
-}
+GtkWidget *schematic_view_get_toplevel (SchematicView *sv) { return sv->toplevel; }
-Schematic *
-schematic_view_get_schematic_from_sheet (Sheet *sheet)
+Schematic *schematic_view_get_schematic_from_sheet (Sheet *sheet)
{
g_return_val_if_fail ((sheet != NULL), NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
-
- GList *list, *copy;
- copy = g_list_copy (schematic_view_list);
+ GList *iter, *copy;
+ Schematic *s = NULL;
+ copy = g_list_copy (schematic_view_list); // really needed? probably not
- for (list=copy; list; list = list->next) {
- if (SCHEMATIC_VIEW (list->data)->priv->sheet == sheet) {
- return SCHEMATIC_VIEW (list->data)->priv->schematic;
+ for (iter = copy; iter; iter = iter->next) {
+ SchematicView *sv = SCHEMATIC_VIEW (iter->data);
+ if (sv->priv->sheet == sheet) {
+ s = sv->priv->schematic;
+ break;
}
}
g_list_free (copy);
- g_list_free_full (list, g_object_unref);
- return NULL;
+ return s;
}
-SchematicView *
-schematic_view_get_schematicview_from_sheet (Sheet *sheet)
+SchematicView *schematic_view_get_schematicview_from_sheet (Sheet *sheet)
{
- g_return_val_if_fail ((sheet != NULL), NULL);
+ g_return_val_if_fail (sheet, NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
-
- GList *list, *copy;
- copy = g_list_copy (schematic_view_list);
+ GList *iter, *copy;
+ SchematicView *sv = NULL;
+
+ copy = g_list_copy (schematic_view_list); // really needed? probably not
- for (list=copy; list; list = list->next) {
- if (SCHEMATIC_VIEW (list->data)->priv->sheet == sheet)
- return SCHEMATIC_VIEW (list->data);
+ for (iter = copy; iter; iter = iter->next) {
+ sv = SCHEMATIC_VIEW (iter->data);
+ if (sv->priv->sheet == sheet)
+ break;
}
g_list_free (copy);
- g_list_free_full (list, g_object_unref);
- return NULL;
+ return sv;
}
-void
-run_context_menu (SchematicView *sv, GdkEventButton *event)
+void run_context_menu (SchematicView *sv, GdkEventButton *event)
{
GtkWidget *menu;
@@ -1741,6 +1826,5 @@ run_context_menu (SchematicView *sv, GdkEventButton *event)
menu = gtk_ui_manager_get_widget (sv->priv->ui_manager, "/MainPopup");
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, sv, event->button,
- event->time);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, sv, event->button, event->time);
}
diff --git a/src/schematic-view.h b/src/schematic-view.h
index f77bb7d..dd63a08 100644
--- a/src/schematic-view.h
+++ b/src/schematic-view.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,54 +28,67 @@
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SCHEMATIC_VIEW_H
#define __SCHEMATIC_VIEW_H
+// typedefing before including makes circular dependencies possible
+typedef struct _SchematicView SchematicView;
+
#include <gtk/gtk.h>
#include "schematic.h"
#include "sheet.h"
-typedef enum {
- DRAG_URI_INFO,
- DRAG_PART_INFO
-} DragTypes;
+/*
+ * When stretching a schematic to resize
+ * it, increase its width or height of
+ * this percentage (the recommended factor
+ * is 0.15 for a 15% increase).
+ */
+#define SCHEMATIC_STRETCH_FACTOR 0.15
+
+typedef enum { DRAG_URI_INFO, DRAG_PART_INFO } DragTypes;
-#define TYPE_SCHEMATIC_VIEW (schematic_view_get_type ())
-#define SCHEMATIC_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCHEMATIC_VIEW, SchematicView))
-#define SCHEMATIC_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCHEMATIC_VIEW, SchematicViewClass))
-#define IS_SCHEMATIC_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCHEMATIC_VIEW))
-#define IS_SCHEMATIC_VIEW_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCHEMATIC_VIEW, SchematicViewClass))
+#define TYPE_SCHEMATIC_VIEW (schematic_view_get_type ())
+#define SCHEMATIC_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCHEMATIC_VIEW, SchematicView))
+#define SCHEMATIC_VIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCHEMATIC_VIEW, SchematicViewClass))
+#define IS_SCHEMATIC_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCHEMATIC_VIEW))
+#define IS_SCHEMATIC_VIEW_CLASS(klass) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCHEMATIC_VIEW, SchematicViewClass))
-typedef struct _SchematicView SchematicView;
typedef struct _SchematicViewClass SchematicViewClass;
-typedef struct _SchematicViewPriv SchematicViewPriv;
+typedef struct _SchematicViewPriv SchematicViewPriv;
+
+GType schematic_view_get_type (void);
+
+void schematic_view_simulate_cmd (GtkWidget *widget, SchematicView *sv);
-GType schematic_view_get_type (void);
-SchematicView *schematic_view_new (Schematic *schematic);
-Sheet *schematic_view_get_sheet (SchematicView *sv);
-Schematic *schematic_view_get_schematic (SchematicView *sv);
-Schematic *schematic_view_get_schematic_from_sheet (Sheet *sheet);
-SchematicView *schematic_view_get_schematicview_from_sheet (Sheet *sheet);
-void run_context_menu (SchematicView *sv, GdkEventButton *event);
+SchematicView *schematic_view_new (Schematic *schematic);
+Sheet *schematic_view_get_sheet (SchematicView *sv);
+void schematic_view_set_sheet (SchematicView *sv, Sheet *sheet);
+Schematic *schematic_view_get_schematic (SchematicView *sv);
+Schematic *schematic_view_get_schematic_from_sheet (Sheet *sheet);
+SchematicView *schematic_view_get_schematicview_from_sheet (Sheet *sheet);
+void run_context_menu (SchematicView *sv, GdkEventButton *event);
// Signal emission wrappers.
-void schematic_view_reset_tool (SchematicView *sv);
+void schematic_view_reset_tool (SchematicView *sv);
// Misc.
-void schematic_view_set_browser (SchematicView *sv, gpointer p);
-gpointer schematic_view_get_browser (SchematicView *sv);
-void schematic_view_set_parent (SchematicView *sv, GtkDialog *dialog);
+void schematic_view_set_browser (SchematicView *sv, gpointer p);
+gpointer schematic_view_get_browser (SchematicView *sv);
+void schematic_view_set_parent (SchematicView *sv, GtkDialog *dialog);
// Logging.
-void schematic_view_log_show (SchematicView *sv, gboolean explicit);
-gboolean schematic_view_get_log_window_exists (SchematicView *sv);
+void schematic_view_log_show (SchematicView *sv, gboolean explicit);
+gboolean schematic_view_get_log_window_exists (SchematicView *sv);
// Windows services.
-GtkWidget * schematic_view_get_toplevel (SchematicView *sv);
+GtkWidget *schematic_view_get_toplevel (SchematicView *sv);
#endif /* __SCHEMATIC_VIEW_H */
diff --git a/src/settings.c b/src/settings.c
index ca56372..f54f39d 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2008-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <unistd.h>
@@ -44,14 +48,8 @@
#include "oregano-utils.h"
#include "oregano-config.h"
-// Engines Types
-static const gchar*
-engine[] = {
- "gnucap",
- "ngspice"
-};
-
-typedef struct {
+typedef struct
+{
Schematic *sm;
GtkWidget *pbox; // Property box
@@ -62,23 +60,20 @@ typedef struct {
GtkWidget *w_engine;
} Settings;
-#define SETTINGS(x) ((Settings*)(x))
+#define SETTINGS(x) ((Settings *)(x))
-GtkWidget *engine_path;
-GtkWidget *button[2];
+GtkWidget *engine_path;
+GtkWidget *button[OREGANO_ENGINE_COUNT];
-
-static void
-apply_callback (GtkWidget *w, Settings *s)
+static void apply_callback (GtkWidget *w, Settings *s)
{
- oregano.engine = GPOINTER_TO_INT (
- g_object_get_data (G_OBJECT (s->w_engine), "id"));
- oregano.compress_files = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->w_compress_files));
- oregano.show_log = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->w_show_log ));
- oregano.show_splash = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->w_show_splash ));
+ oregano.engine = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (s->w_engine), "id"));
+ oregano.compress_files = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_compress_files));
+ if (s->w_show_log)
+ oregano.show_log = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_show_log));
+ else
+ oregano.show_log = FALSE;
+ oregano.show_splash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_show_splash));
oregano_config_save ();
@@ -86,43 +81,37 @@ apply_callback (GtkWidget *w, Settings *s)
s->pbox = NULL;
}
-static void
-delete_event_callback (GtkWidget *w, GdkEvent *event, Settings *s)
+static void delete_event_callback (GtkWidget *w, GdkEvent *event, Settings *s)
{
- apply_callback(w, s);
+ apply_callback (w, s);
}
-static void
-set_engine_name (GtkWidget *w, Settings *s)
+static void set_engine_name (GtkWidget *w, Settings *s)
{
int engine_id;
-
- s->w_engine = w;
- engine_id = GPOINTER_TO_INT (
- g_object_get_data (G_OBJECT (s->w_engine), "id"));
- if (g_find_program_in_path (engine[engine_id]) == NULL) {
- if (gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (button[engine_id]))) {
- GString *msg = g_string_new (
- _("Engine <span weight=\"bold\" size=\"large\">"));
- msg = g_string_append (msg, engine[engine_id]);
- msg = g_string_append (msg,
- _("</span> not found\nThe engine is unable to locate "
- "the external program."));
- oregano_warning_with_title (_("Warning"), msg->str);
+ gchar *engine_name;
+
+ s->w_engine = w;
+ engine_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (s->w_engine), "id"));
+
+ engine_name = oregano_engine_get_engine_name_by_index (engine_id);
+ if (g_find_program_in_path (engine_name) == NULL) {
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button[engine_id]))) {
+ GString *msg = g_string_new (_ ("Engine <span weight=\"bold\" size=\"large\">"));
+ msg = g_string_append (msg, engine_name);
+ msg = g_string_append (msg, _ ("</span> not found\nThe engine is unable to locate "
+ "the external program."));
+ oregano_warning_with_title (_ ("Warning"), msg->str);
g_string_free (msg, TRUE);
- engine_id = (engine_id +1) % 2;
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]),
- TRUE);
- }
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]),
- FALSE);
+ engine_id = (engine_id + 1) % OREGANO_ENGINE_COUNT;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]), TRUE);
+ } else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]), FALSE);
}
+ g_free (engine_name);
}
-gpointer
-settings_new (Schematic *sm)
+gpointer settings_new (Schematic *sm)
{
Settings *s;
@@ -132,10 +121,11 @@ settings_new (Schematic *sm)
return s;
}
-void
-settings_show (GtkWidget *widget, SchematicView *sv)
+void settings_show (GtkWidget *widget, SchematicView *sv)
{
gint i;
+ gboolean engine_available = FALSE;
+ gchar *engine_name;
GtkWidget *engine_group = NULL;
GtkWidget *w, *pbox, *toplevel;
GtkBuilder *gui;
@@ -145,71 +135,58 @@ settings_show (GtkWidget *widget, SchematicView *sv)
Schematic *sm;
g_return_if_fail (sv != NULL);
-
- // If no engine available, stop oregano
- if ((g_find_program_in_path (engine[0]) == NULL) &&
- (g_find_program_in_path (engine[1]) == NULL)) {
+
+ for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
+ engine_name = oregano_engine_get_engine_name_by_index (i);
+ if (g_find_program_in_path(engine_name) != NULL) {
+ engine_available = TRUE;
+ }
+ g_free (engine_name);
+ }
+
+ if (!engine_available) {
gchar *msg;
- msg = g_strdup_printf (
- _("No engine allowing analysis is available.\n"
- "You might install one, at least! \n"
- "Either ngspice or gnucap."));
- oregano_error_with_title (_("Could not create settings dialog"), msg);
+ msg = g_strdup_printf (_ ("No engine allowing analysis is available.\n"
+ "You need to install at least one engine ! \n"
+ "spice3, ngspice or gnucap."));
+ oregano_error_with_title (_ ("Could not create engine settings dialog"), msg);
g_free (msg);
- return;
}
-
- g_return_if_fail (sv != NULL);
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create settings dialog"));
+ oregano_error (_ ("Could not create settings dialog"));
return;
- }
- else
- gtk_builder_set_translation_domain (gui, NULL);
+ }
+ gtk_builder_set_translation_domain (gui, NULL);
sm = schematic_view_get_schematic (sv);
s = schematic_get_settings (sm);
// Only allow one instance of the property box per schematic.
if (GTK_WIDGET (SETTINGS (s)->pbox)) {
- gdk_window_raise (gtk_widget_get_window (
- GTK_WIDGET (SETTINGS (s)->pbox)));
+ gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (SETTINGS (s)->pbox)));
return;
}
-
- if (!g_file_test (OREGANO_UIDIR "/settings.ui", G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. "
- "You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/settings.ui");
- oregano_error_with_title (_("Could not create settings dialog"), msg);
- g_free (msg);
- return;
- }
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/settings.ui",
- &perror) <= 0) {
+
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/settings.ui", &perror) <= 0) {
msg = perror->message;
- oregano_error_with_title (_("Could not create settings dialog"), msg);
+ oregano_error_with_title (_ ("Could not create settings dialog"), msg);
g_error_free (perror);
return;
- }
+ }
w = toplevel = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
if (!w) {
- oregano_error (_("Could not create settings dialog"));
+ oregano_error (_ ("Could not create settings dialog"));
return;
}
- g_signal_connect (G_OBJECT (w), "delete_event",
- G_CALLBACK (delete_event_callback), s);
+ g_signal_connect (G_OBJECT (w), "delete_event", G_CALLBACK (delete_event_callback), s);
pbox = toplevel;
s->pbox = GTK_WIDGET (pbox);
w = GTK_WIDGET (gtk_builder_get_object (gui, "close_bt"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (apply_callback), s);
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (apply_callback), s);
w = GTK_WIDGET (gtk_builder_get_object (gui, "splash-enable"));
s->w_show_splash = w;
@@ -217,56 +194,51 @@ settings_show (GtkWidget *widget, SchematicView *sv)
w = GTK_WIDGET (gtk_builder_get_object (gui, "compress-enable"));
s->w_compress_files = w;
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
- oregano.compress_files);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "log-enable"));
- s->w_show_log = w;
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.show_log);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.compress_files);
+ if (engine_available) {
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "log-enable"));
+ s->w_show_log = w;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.show_log);
+ } else {
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "log-enable"));
+ s->w_show_log = NULL;
+ gtk_widget_destroy (w);
+ }
- w = GTK_WIDGET (gtk_builder_get_object (gui, "grid-size"));
- gtk_widget_set_sensitive (w, FALSE);
w = GTK_WIDGET (gtk_builder_get_object (gui, "realtime-enable"));
gtk_widget_set_sensitive (w, FALSE);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "engine_table"));
- for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
- if (engine_group)
- button[i] = gtk_radio_button_new_with_label_from_widget (
- GTK_RADIO_BUTTON (engine_group), engine[i]);
- else
- button[i] = engine_group =
- gtk_radio_button_new_with_label_from_widget (NULL, engine[i]);
-
- g_object_set_data (G_OBJECT (button[i]), "id", GUINT_TO_POINTER (i));
-
- gtk_table_attach (GTK_TABLE (w), button[i], 0, 1, i, i+1,
- GTK_EXPAND|GTK_FILL, GTK_SHRINK, 6, 6);
- g_signal_connect (G_OBJECT (button[i]), "clicked",
- G_CALLBACK (set_engine_name), s);
-
+ if (engine_available) {
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "engine_table"));
+ for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
+ engine_name = oregano_engine_get_engine_name_by_index (i);
+ if (engine_group)
+ button[i] = gtk_radio_button_new_with_label_from_widget (
+ GTK_RADIO_BUTTON (engine_group), engine_name);
+ else
+ button[i] = engine_group =
+ gtk_radio_button_new_with_label_from_widget (NULL, engine_name);
+ g_free (engine_name);
+ g_object_set_data (G_OBJECT (button[i]), "id", GUINT_TO_POINTER (i));
+
+ gtk_grid_attach (GTK_GRID (w), button[i], 0, i, 1, 1);
+ g_signal_connect (G_OBJECT (button[i]), "clicked", G_CALLBACK (set_engine_name), s);
+ }
+
+ } else {
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "label50"));
+ gtk_widget_destroy (w);
}
-
+
// Is the engine available?
// In that case the button is active
- if (g_find_program_in_path (engine[oregano.engine]) != NULL)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]),
- TRUE);
+ engine_name = oregano_engine_get_engine_name_by_index (oregano.engine);
+ if (g_find_program_in_path (engine_name) != NULL)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]), TRUE);
// Otherwise the button is inactive
else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]),
- FALSE);
-
- // If no engine available, stop oregano
- if ((g_find_program_in_path (engine[0]) == NULL) &&
- (g_find_program_in_path (engine[1]) == NULL)) {
- gchar *msg;
- msg = g_strdup_printf (
- _("No engine allowing analysis is available.\n"
- "You might install one, at least! \n"
- "Either ngspice or gnucap."));
- oregano_error_with_title (_("Could not create settings dialog"), msg);
- g_free (msg);
- }
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]), FALSE);
+ g_free (engine_name);
gtk_widget_show_all (toplevel);
}
diff --git a/src/settings.h b/src/settings.h
index d5532a6..8d8992d 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -27,8 +27,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SETTINGS_H
diff --git a/src/sheet/Makefile.am b/src/sheet/Makefile.am
deleted file mode 100644
index d83a960..0000000
--- a/src/sheet/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-oreganodir = $(datadir)/oregano
-
-AM_CFLAGS = -Wall -DG_DISABLE_DEPRECATED -DGSEAL_ENABLE \
- -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED \
- -DGTK_DISABLE_DEPRECATED -DG_DISABLE_SINGLE_INCLUDES \
- -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES -DGTK_DISABLE_SINGLE_INCLUDES
-
-INCLUDES = \
- $(OREGANO_CFLAGS) -I$(top_srcdir)/src -I$(top_srcdir)/src/model \
- -I$(top_srcdir)/src/engines \
- -DOREGANO_UIDIR=\""$(oreganodir)/xml"\" \
- -DOREGANO_LIBRARYDIR=\""$(oreganodir)/libraries"\" \
- -DOREGANO_MODELDIR=\""$(oreganodir)/models"\"
-
-noinst_LIBRARIES = libsheet.a
-
-libsheet_a_SOURCES = \
- create-wire.h \
- create-wire.c \
- grid.c \
- grid.h \
- node-item.c \
- node-item.h \
- part-item.c \
- part-item.h \
- plot-add-function.c \
- plot-add-function.h \
- sheet.c \
- sheet.h \
- sheet-item.c \
- sheet-item.h \
- sheet-item-factory.c \
- sheet-item-factory.h \
- sheet-private.h \
- textbox-item.c \
- textbox-item.h \
- wire-item.c \
- wire-item.h
diff --git a/src/sheet/create-wire.c b/src/sheet/create-wire.c
index ca71e7a..60c2e57 100644
--- a/src/sheet/create-wire.c
+++ b/src/sheet/create-wire.c
@@ -1,21 +1,24 @@
/*
* create-wire.c
*
+ *
* Authors:
* Richard Hult <rhult@hem.passagen.se>
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
* Description: Handles the user interaction when creating wires.
* The name is not really right. This part handles creation of wires and
* acts as glue between NodeStore/Wire and Sheet/WireItem.
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2012-2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -29,525 +32,498 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include <stdlib.h>
#include "cursors.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "node-store.h"
#include "wire-item.h"
#include "create-wire.h"
#include "wire.h"
+#include "sheet-private.h"
+
+#include "debug.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-struct _CreateWireContext {
- guint active : 1;
- gint start_handler_id;
- gint draw_handler_id;
- gint create_wire_cancel_id;
- gdouble old_x, old_y;
- Sheet * sheet;
- GooCanvasItem * dot_item;
- CreateWire * create_wire;
-};
-
-static int create_wire_event (Sheet *sheet, const GdkEvent *event,
- CreateWireContext *cwc);
-static int create_wire_pre_create_event (Sheet *sheet, const GdkEvent *event,
- CreateWireContext *cwc);
-static int create_wire_cancel (Sheet *sheet, CreateWireContext *cwc);
-static void fixate_wire (CreateWireContext *cwc, gboolean always_fixate_both,
- gdouble x, gdouble y);
-static Wire * create_wire_and_place_item (Sheet *sheet, SheetPos start_pos,
- SheetPos end_pos);
-static void cancel_wire (CreateWireContext *cwc);
-static void exit_wire_mode (CreateWireContext *cwc);
-
-// Initiates wire creation by disconnecting the signal handler that
-// starts the wire-drawing and then connecting the drawing handler.
-// This is an event handler.
-//
-// @param sheet a sheet (the canvas)
-// @param event the event
-// @param cwc context
-static int
-create_wire_pre_create_event (Sheet *sheet, const GdkEvent *event,
- CreateWireContext *cwc)
+CreateWireInfo *create_wire_info_new (Sheet *sheet)
{
- GooCanvasPoints *points;
+ CreateWireInfo *create_wire_info;
GooCanvasLineDash *dash;
- CreateWire *wire;
- double new_x, new_y;
- if (cwc->active)
- return FALSE;
+ create_wire_info = g_new0 (CreateWireInfo, 1);
- if (event->button.button == 2 || event->button.button > 3)
- return FALSE;
+ create_wire_info->state = WIRE_DISABLED;
- if (event->type == GDK_2BUTTON_PRESS ||
- event->type == GDK_3BUTTON_PRESS)
- return FALSE;
+ create_wire_info->direction = WIRE_DIR_HORIZ;
+ // create_wire_info->direction_auto_toggle =
+ // WIRE_DIRECTION_AUTO_TOGGLE_OFF;
- g_signal_stop_emission_by_name (G_OBJECT (sheet), "event");
+ create_wire_info->points = goo_canvas_points_new (3);
+ create_wire_info->points->coords[0] = 0.;
+ create_wire_info->points->coords[1] = 0.;
+ create_wire_info->points->coords[2] = 0.;
+ create_wire_info->points->coords[3] = 0.;
+ create_wire_info->points->coords[4] = 0.;
+ create_wire_info->points->coords[5] = 0.;
- if (event->type != GDK_BUTTON_PRESS)
- return FALSE;
+ dash = goo_canvas_line_dash_new (2, 5.0, 5.0);
- // Button 3 resets the sheet mode.
- if (event->button.button == 3) {
- exit_wire_mode (cwc);
- return TRUE;
- }
+ create_wire_info->line = GOO_CANVAS_POLYLINE (goo_canvas_polyline_new (
+ GOO_CANVAS_ITEM (sheet->grid), FALSE, 0, "points", create_wire_info->points,
+ "stroke-color-rgba", 0x92BA52C3, "line-dash", dash, "line-width", 2.0, "visibility",
+ GOO_CANVAS_ITEM_INVISIBLE, NULL));
+ goo_canvas_line_dash_unref (dash);
- // Button 1 starts a new wire. Start by deselecting all objects.
- sheet_select_all (sheet, FALSE);
+ create_wire_info->dot = GOO_CANVAS_ELLIPSE (goo_canvas_ellipse_new (
+ GOO_CANVAS_ITEM (sheet->object_group), -3.0, -3.0, 6.0, 6.0, "fill-color", "red",
+ "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL));
- sheet_get_pointer (sheet, &new_x, &new_y);
+ return create_wire_info;
+}
+
+void create_wire_info_destroy (CreateWireInfo *create_wire_info)
+{
+ g_return_if_fail (create_wire_info);
- points = goo_canvas_points_new (3);
- points->coords[0] = new_x;
- points->coords[1] = new_y;
- points->coords[2] = new_x;
- points->coords[3] = new_y;
- points->coords[4] = new_x;
- points->coords[5] = new_y;
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (create_wire_info->dot));
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (create_wire_info->line));
+ goo_canvas_points_unref (create_wire_info->points);
+ g_free (create_wire_info);
+}
- wire = g_new0 (CreateWire, 1);
- cwc->create_wire = wire;
- cwc->old_x = new_x;
- cwc->old_y = new_y;
+inline static gboolean create_wire_start (Sheet *sheet, GdkEvent *event)
+{
+ double x, y;
+ GooCanvasPoints *points;
+ GooCanvasPolyline *line;
+ CreateWireInfo *create_wire_info;
- dash = goo_canvas_line_dash_new (2, 5.0, 5.0);
-
- wire->line = GOO_CANVAS_POLYLINE (
- goo_canvas_polyline_new (GOO_CANVAS_ITEM (sheet->object_group),
- FALSE, 0,
- "points", points,
- "stroke-color", "red",
- "line-dash", dash,
- "line-width", 1.0,
- NULL));
-
- goo_canvas_line_dash_unref (dash);
-
- wire->points = points;
- wire->direction = WIRE_DIR_NONE;
-
- cwc->draw_handler_id = g_signal_connect (sheet, "event",
- G_CALLBACK (create_wire_event), cwc);
-
- cwc->active = TRUE;
+ // g_signal_stop_emission_by_name (sheet, "event");
+ create_wire_info = sheet->priv->create_wire_info;
+#if 0
+ //TODO save and restore the selection?
+ sheet_select_all (sheet, FALSE);
+#endif
+ points = create_wire_info->points;
+ line = create_wire_info->line;
+
+ g_assert (points);
+ g_assert (line);
+
+ x = event->button.x;
+ y = event->button.y;
+
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &x, &y);
+ snap_to_grid (sheet->grid, &x, &y);
+
+#if 0
+ Coords p;
+ sheet_get_pointer (sheet, &p.x, &p.y);
+ NG_DEBUG ("diff_x=%lf; diff_y=%lf;", p.x-x, p.y-y);
+#endif
+
+ // start point
+ points->coords[0] = x;
+ points->coords[1] = y;
+ // mid point
+ points->coords[2] = x;
+ points->coords[3] = y;
+ // end point
+ points->coords[4] = x;
+ points->coords[5] = y;
+
+ g_object_set (G_OBJECT (line), "points", points, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
+
+ goo_canvas_item_raise (GOO_CANVAS_ITEM (create_wire_info->line), NULL);
+ goo_canvas_item_raise (GOO_CANVAS_ITEM (create_wire_info->dot), NULL);
+
+ create_wire_info->state = WIRE_ACTIVE;
+ sheet_pointer_grab (sheet, event);
+ sheet_keyboard_grab (sheet, event);
return TRUE;
}
-// This needs to be called in order to start a wire creation.
-// It sets up the initial event handler that basically just
-// takes care of the first button-1 press that starts the
-// drawing mode. */
-CreateWireContext *
-create_wire_initiate (Sheet *sheet)
+inline static gboolean create_wire_update (Sheet *sheet, GdkEvent *event)
{
- CreateWireContext *cwc;
+ CreateWireInfo *create_wire_info;
+ double new_x, new_y, x1, y1;
+ gint32 snapped_x, snapped_y;
+ Coords pos;
- g_return_val_if_fail (sheet != NULL, NULL);
- g_return_val_if_fail (IS_SHEET (sheet), NULL);
+ Schematic *schematic;
+ NodeStore *store;
- cwc = g_new0 (CreateWireContext, 1);
- cwc->sheet = sheet;
- cwc->active = FALSE;
- cwc->dot_item = NULL;
+ // g_signal_stop_emission_by_name (sheet, "event");
- cwc->start_handler_id = g_signal_connect (sheet, "event",
- G_CALLBACK (create_wire_pre_create_event), cwc);
+ create_wire_info = sheet->priv->create_wire_info;
- cwc->create_wire_cancel_id = g_signal_connect (sheet, "cancel",
- G_CALLBACK (create_wire_cancel), cwc);
+ schematic = schematic_view_get_schematic_from_sheet (sheet);
+ g_assert (schematic);
- return cwc;
+ store = schematic_get_store (schematic);
+ g_assert (store);
+
+ new_x = event->button.x;
+ new_y = event->button.y;
+
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &new_x, &new_y);
+ snap_to_grid (sheet->grid, &new_x, &new_y);
+
+#if 0
+ Coords p;
+ sheet_get_pointer (sheet, &p.x, &p.y);
+ NG_DEBUG ("diff_x=%lf; diff_y=%lf;", p.x-new_x, p.y-new_y);
+#endif
+
+ snapped_x = (gint32)new_x;
+ snapped_y = (gint32)new_y;
+
+ /* start pos (do not update,
+ * was fixed in _start func and will not change
+ * until _discard or _fixate)
+ */
+ x1 = create_wire_info->points->coords[0];
+ y1 = create_wire_info->points->coords[1];
+
+ // mid pos
+ if (create_wire_info->direction == WIRE_DIR_VERT) {
+ create_wire_info->points->coords[2] = x1;
+ create_wire_info->points->coords[3] = snapped_y;
+ } else if (create_wire_info->direction == WIRE_DIR_HORIZ) {
+ create_wire_info->points->coords[2] = snapped_x;
+ create_wire_info->points->coords[3] = y1;
+ } else {
+ create_wire_info->points->coords[2] = x1;
+ create_wire_info->points->coords[3] = y1;
+ }
+ NG_DEBUG ("update ~._.~ start=(%lf,%lf) → end=(%i,%i)", x1, y1, snapped_x, snapped_y);
+ // end pos
+ create_wire_info->points->coords[4] = snapped_x;
+ create_wire_info->points->coords[5] = snapped_y;
+
+ g_assert (create_wire_info->line);
+ // required to trigger goocanvas update of the line object
+ g_object_set (G_OBJECT (create_wire_info->line), "points", create_wire_info->points, NULL);
+ pos.x = (gdouble)snapped_x;
+ pos.y = (gdouble)snapped_y;
+ /* Check if the pre-wire intersect another wire, and
+ * draw a small red circle to indicate the connection
+ */
+ g_assert (create_wire_info->dot);
+
+ const guint8 is_pin = node_store_is_pin_at_pos (store, pos);
+ const guint8 is_wire = node_store_is_wire_at_pos (store, pos);
+
+ if (is_pin || is_wire) {
+ g_object_set (G_OBJECT (create_wire_info->dot), "x", new_x - 3.0, "y", new_y - 3.0, "width",
+ 6.0, "height", 6.0, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
+ } else {
+ g_object_set (G_OBJECT (create_wire_info->dot), "visibility", GOO_CANVAS_ITEM_INVISIBLE,
+ NULL);
+ }
+ goo_canvas_item_raise (GOO_CANVAS_ITEM (create_wire_info->line), NULL);
+ return TRUE;
}
-static int
-create_wire_event (Sheet *sheet, const GdkEvent *event, CreateWireContext *cwc)
+inline static gboolean create_wire_discard (Sheet *sheet, GdkEvent *event)
{
- int x1, y1, x2, y2;
- gdouble snapped_x, snapped_y;
- gboolean diagonal;
- CreateWire *wire = cwc->create_wire;
- Schematic *s;
- NodeStore *store;
- SheetPos pos;
- int intersect;
+ CreateWireInfo *create_wire_info;
- s = schematic_view_get_schematic_from_sheet (cwc->sheet);
- store = schematic_get_store (s);
+ // g_signal_stop_emission_by_name (sheet, "event");
+ NG_DEBUG ("wire got discarded");
+ sheet_keyboard_ungrab (sheet, event);
+ sheet_pointer_ungrab (sheet, event);
- if (event->type == GDK_2BUTTON_PRESS ||
- event->type == GDK_3BUTTON_PRESS) {
- return FALSE;
- }
+ create_wire_info = sheet->priv->create_wire_info;
+ g_object_set (G_OBJECT (create_wire_info->dot), "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- switch (event->button.button) {
- case 2:
- case 4:
- case 5:
- // Don't care about middle button or mouse wheel.
- return FALSE;
- break;
-
- case 1:
-
- // Button-1 fixates the first segment of the wire,
- // letting the user continue drawing wires, with the
- // former second segment as the first segment of the
- // new wire. There are a few exceptions though; if the
- // button press happens at another wire or a pin of a
- // part, then we fixate the wire and cancel the drawing
- // mode.
- g_signal_stop_emission_by_name (sheet, "event");
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
- fixate_wire (cwc, FALSE, snapped_x, snapped_y);
- break;
-
- case 3:
- g_signal_stop_emission_by_name (sheet, "event");
- cancel_wire (cwc);
- break;
- }
- break;
+ g_object_set (G_OBJECT (create_wire_info->line), "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
- case GDK_BUTTON_RELEASE:
- g_signal_stop_emission_by_name (sheet, "event");
-
- switch (event->button.button) {
- case 1:
- case 2:
- case 4:
- case 5:
- // Don't care about middle button or mouse wheel.
- return FALSE;
- break;
- }
- return TRUE;
-
- case GDK_MOTION_NOTIFY:
- g_signal_stop_emission_by_name (sheet, "event");
-
- diagonal = event->button.state & GDK_SHIFT_MASK;
- if (!diagonal && wire->direction == WIRE_DIR_DIAG)
- wire->direction = WIRE_DIR_NONE;
-
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
-
- x1 = wire->points->coords[0];
- y1 = wire->points->coords[1];
-
- if (x1 == snapped_x && y1 == snapped_y) {
- wire->direction = WIRE_DIR_NONE;
- }
- else {
- if (wire->direction == WIRE_DIR_NONE) {
- if (abs (y1 - snapped_y) < abs (x1 - snapped_x)) {
- wire->direction = WIRE_DIR_HORIZ;
- }
- else {
- wire->direction = WIRE_DIR_VERT;
- }
- }
- }
-
- x2 = snapped_x;
- y2 = snapped_y;
-
- if (diagonal) {
- wire->direction = WIRE_DIR_DIAG;
- x2 = x1;
- y2 = y1;
- }
-
- if (wire->direction == WIRE_DIR_HORIZ) {
- y2 = y1;
- }
- else if (wire->direction == WIRE_DIR_VERT) {
- x2 = x1;
- }
-
- if (wire->direction == WIRE_DIR_HORIZ && x2 == x1) {
- x2 = snapped_x;
- y2 = snapped_y;
- }
- else if (wire->direction == WIRE_DIR_VERT && y2 == y1) {
- x2 = snapped_x;
- y2 = snapped_y;
- }
-
- wire->points->coords[2] = x2;
- wire->points->coords[3] = y2;
- wire->points->coords[4] = snapped_x;
- wire->points->coords[5] = snapped_y;
-
- g_object_set (G_OBJECT (wire->line),
- "points", wire->points,
- NULL);
-
- pos.x = snapped_x;
- pos.y = snapped_y;
- // Check if the pre-wire intersect another wire, and
- // draw a small red circle to indicate the connection
- intersect = 0;
- intersect = node_store_is_wire_at_pos (store, pos);
- intersect += node_store_is_pin_at_pos (store, pos);
- if (intersect) {
- if (cwc->dot_item) {
- g_object_set (G_OBJECT (cwc->dot_item),
- "x", -3.0 + snapped_x,
- "y", -3.0 + snapped_y,
- "width", 6.0,
- "height", 6.0,
- NULL);
-
- g_object_set (cwc->dot_item,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
- }
- else {
- cwc->dot_item = goo_canvas_ellipse_new (
- GOO_CANVAS_ITEM (sheet->object_group),
- snapped_x, snapped_y, 3.0, 3.0,
- "fill_color", "red",
- NULL);
-
- g_object_set (cwc->dot_item,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
- }
- }
- else {
- if (cwc->dot_item)
- g_object_set (cwc->dot_item,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
- }
-
- cwc->old_x = snapped_x;
- cwc->old_y = snapped_y;
- break;
+ create_wire_info->state = WIRE_START;
- default:
- return FALSE;
- }
- return TRUE;
+ return TRUE;
}
-static void
-fixate_wire (CreateWireContext *cwc, gboolean always_fixate_both,
- gdouble x, gdouble y)
+inline static Wire *create_wire_spawn (Sheet *sheet, Coords start_pos, Coords end_pos)
{
- CreateWire *create_wire = cwc->create_wire;
- SheetPos p1, p2, start_pos, end_pos, start_pos2, end_pos2;
- gboolean cancel = FALSE;
- NodeStore *store;
- Schematic *schematic;
+ Wire *wire = NULL;
+ Coords length;
- g_return_if_fail (cwc != NULL);
- g_return_if_fail (create_wire != NULL);
+ NG_DEBUG ("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- spawning...");
+ g_assert (sheet);
+ g_assert (IS_SHEET (sheet));
- schematic = schematic_view_get_schematic_from_sheet (cwc->sheet);
- store = schematic_get_store (schematic);
+ wire = wire_new (sheet->grid);
- p1.x = create_wire->points->coords[0];
- p1.y = create_wire->points->coords[1];
- p2.x = create_wire->points->coords[2];
- p2.y = create_wire->points->coords[3];
-
- if (create_wire->direction == WIRE_DIR_DIAG) {
- p1.x = p2.x;
- p1.y = p2.y;
- p2.x = create_wire->points->coords[4];
- p2.y = create_wire->points->coords[5];
- create_wire->points->coords[2] = p2.x;
- create_wire->points->coords[3] = p2.y;
- create_wire->points->num_points = 2;
- }
+ length.x = end_pos.x - start_pos.x;
+ length.y = end_pos.y - start_pos.y;
+ wire_set_length (wire, &length);
- // If the user clicks when wire length is zero, cancel the wire.
- if (p1.x == p2.x && p1.y == p2.y) {
- cancel_wire (cwc);
- return;
- }
+ item_data_set_pos (ITEM_DATA (wire), &start_pos);
+ schematic_add_item (schematic_view_get_schematic_from_sheet (sheet), ITEM_DATA (wire));
- if (create_wire->direction != WIRE_DIR_DIAG) {
- start_pos.x = MIN (p1.x, p2.x);
- start_pos.y = MIN (p1.y, p2.y);
- end_pos.x = MAX (p1.x, p2.x);
- end_pos.y = MAX (p1.y, p2.y);
- }
- else {
- start_pos.x = p1.x;
- start_pos.y = p1.y;
- end_pos.x = p2.x;
- end_pos.y = p2.y;
- }
+ NG_DEBUG ("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- spawning wire %p", wire);
- // If the wire connects to something, then fixate
- // the second segment too and exit wire drawing mode.
- // Also fixate both segments when explicitly asked to. */
- p2.x = x;
- p2.y = y;
- if (always_fixate_both ||
- node_store_get_node (store, p2) ||
- node_store_is_wire_at_pos (store, p2)) {
- if (create_wire->points->num_points == 3) {
- p1.x = create_wire->points->coords[2];
- p1.y = create_wire->points->coords[3];
-
- if (create_wire->direction != WIRE_DIR_DIAG) {
- start_pos2.x = MIN (p1.x, p2.x);
- start_pos2.y = MIN (p1.y, p2.y);
- end_pos2.x = MAX (p1.x, p2.x);
- end_pos2.y = MAX (p1.y, p2.y);
- }
- else {
- start_pos2.x = p1.x;
- start_pos2.y = p1.y;
- end_pos2.x = p2.x;
- end_pos2.y = p2.y;
- }
-
- create_wire_and_place_item (cwc->sheet,
- start_pos2, end_pos2);
- }
- cancel_wire (cwc);
- cancel = TRUE;
- }
+ return wire;
+}
- create_wire_and_place_item (cwc->sheet, start_pos, end_pos);
+#define FINISH_ON_WIRE_CLICK 0
+inline static gboolean create_wire_fixate (Sheet *sheet, GdkEvent *event)
+{
+ NodeStore *store;
+ Schematic *schematic;
- if (cancel)
- return;
+ Coords p1, p2, start_pos, end_pos, mid_pos;
+ CreateWireInfo *create_wire_info;
+ Wire *wire = NULL;
+ gboolean b_start_eq_mid, b_mid_eq_end;
+#if FINISH_ON_WIRE_CLICK
+ gboolean b_finish;
+#endif
+ double x, y;
- // Start a new "floating" wire, using the same CreateWire that was used
- // for the old wire.
- create_wire->points->coords[0] = create_wire->points->coords[2];
- create_wire->points->coords[1] = create_wire->points->coords[3];
- create_wire->points->coords[2] = x;
- create_wire->points->coords[3] = y;
- create_wire->points->num_points = 2;
+ // g_signal_stop_emission_by_name (sheet, "event");
- g_object_set (G_OBJECT (create_wire->line),
- "points", create_wire->points,
- NULL);
+ x = event->button.x;
+ y = event->button.y;
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &x, &y);
+ snap_to_grid (sheet->grid, &x, &y);
- // Raise the floting wire so that we can see it when it is overlapping
- // other wires.
- goo_canvas_item_raise (GOO_CANVAS_ITEM (create_wire->line), NULL);
-}
+ create_wire_info = sheet->priv->create_wire_info;
+ g_assert (create_wire_info);
+ g_assert (create_wire_info->points);
+ g_assert (create_wire_info->line);
-Wire *
-create_wire_and_place_item (Sheet *sheet, SheetPos start_pos,
- SheetPos end_pos)
-{
- Wire *wire;
- SheetPos length;
+ p1.x = create_wire_info->points->coords[0];
+ p1.y = create_wire_info->points->coords[1];
- g_return_val_if_fail (sheet != NULL, NULL);
- g_return_val_if_fail (IS_SHEET (sheet), NULL);
+ p2.x = x;
+ p2.y = y;
- wire = wire_new ();
- item_data_set_pos (ITEM_DATA (wire), &start_pos);
+ NG_DEBUG ("x: %lf ?= %lf | y: %lf ?= %lf", p1.x, p2.x, p1.y, p2.y);
- length.x = end_pos.x - start_pos.x;
- length.y = end_pos.y - start_pos.y;
- wire_set_length (wire, &length);
+ // if we are back at the starting point of our wire,
+ // and the user tries to fixate, just ignore it
+ // and mark the event as handled
+ if (coords_equal (&p1, &p2))
+ return TRUE;
- schematic_add_item (schematic_view_get_schematic_from_sheet (sheet),
- ITEM_DATA (wire));
+ schematic = schematic_view_get_schematic_from_sheet (sheet);
+ g_assert (schematic);
+ store = schematic_get_store (schematic);
+ g_assert (store);
- return wire;
-}
+ start_pos.x = create_wire_info->points->coords[0];
+ start_pos.y = create_wire_info->points->coords[1];
-static void
-cancel_wire (CreateWireContext *cwc)
-{
- CreateWire *create_wire;
+ mid_pos.x = create_wire_info->points->coords[2];
+ mid_pos.y = create_wire_info->points->coords[3];
- create_wire = cwc->create_wire;
+ end_pos.x = create_wire_info->points->coords[4];
+ end_pos.y = create_wire_info->points->coords[5];
- g_return_if_fail (create_wire != NULL);
+ NG_DEBUG ("A(%g, %g) B(%g, %g) -> same = %i", start_pos.x, start_pos.y, mid_pos.x, mid_pos.y,
+ coords_equal (&start_pos, &mid_pos));
+ NG_DEBUG ("A(%g, %g) B(%g, %g) -> same = %i", mid_pos.x, mid_pos.y, end_pos.x, end_pos.y,
+ coords_equal (&mid_pos, &end_pos));
- g_signal_handler_disconnect (G_OBJECT (cwc->sheet), cwc->draw_handler_id);
- cwc->draw_handler_id = 0;
- cwc->active = FALSE;
+#if FINISH_ON_WIRE_CLICK
+ // check for wires _before_ spawning wires
+ // otherwise we will end up with 1 anyways
+ b_finish = node_store_get_node (store, end_pos) || node_store_is_wire_at_pos (store, end_pos);
+#endif
+ b_start_eq_mid = coords_equal (&start_pos, &mid_pos);
+ b_mid_eq_end = coords_equal (&mid_pos, &end_pos);
- goo_canvas_points_unref (create_wire->points);
+ if (!b_mid_eq_end && !b_start_eq_mid) {
+ NG_DEBUG ("we should get exactly 2 wires");
+ }
- if (cwc->dot_item) {
- goo_canvas_item_remove (GOO_CANVAS_ITEM (cwc->dot_item));
- cwc->dot_item = NULL;
+ if (!b_start_eq_mid) {
+ wire = create_wire_spawn (sheet, start_pos, mid_pos);
+ g_assert (wire);
+ g_assert (IS_WIRE (wire));
+ } else {
+ NG_DEBUG ("looks like start == midpos");
}
- goo_canvas_item_remove (GOO_CANVAS_ITEM (create_wire->line));
- g_free (create_wire);
+ if (!b_mid_eq_end) {
+ wire = create_wire_spawn (sheet, mid_pos, end_pos);
+ g_assert (wire);
+ g_assert (IS_WIRE (wire));
+ } else {
+ NG_DEBUG ("looks like midpos == endpos");
+ }
- // Setup the sheet for a new wire creation process.
+/* check if target location is either wire or node,
+ * if so,
+ * set state to START and fixate both ends of the current wire
+ */
+#if FINISH_ON_WIRE_CLICK
+ /*
+ * auto-finish if the target is a wire or node
+ */
+ if (b_finish)
+ return create_wire_discard (sheet, event);
+#endif
+ /*
+ * update all position/cursor data for the next wire
+ * (consider this is a implicit START call, with less bloat)
+ */
+ x = create_wire_info->points->coords[4];
+ y = create_wire_info->points->coords[5];
+ create_wire_info->points->coords[0] = x;
+ create_wire_info->points->coords[1] = y;
+ create_wire_info->points->coords[2] = x;
+ create_wire_info->points->coords[3] = y;
+
+ // required to trigger goocanvas update of the line object
+ g_object_set (G_OBJECT (create_wire_info->line), "points", create_wire_info->points, NULL);
+
+ // toggle wire direction
+ if (create_wire_info->direction == WIRE_DIR_VERT)
+ create_wire_info->direction = WIRE_DIR_HORIZ;
+ else
+ create_wire_info->direction = WIRE_DIR_VERT;
+
+ goo_canvas_item_raise (GOO_CANVAS_ITEM (create_wire_info->line), NULL);
+
+ /*
+ * do NOT ungrab sheet here, as we are still creating another wire
+ * this should be changed if on fixate means that we are back in state
+ * WIRE_START
+ */
+ return TRUE;
}
-static void
-exit_wire_mode (CreateWireContext *cwc)
+gboolean create_wire_setup (Sheet *sheet)
{
- if (cwc->draw_handler_id != 0)
- cancel_wire (cwc);
+ CreateWireInfo *create_wire_info;
- if (cwc->start_handler_id != 0) {
- g_signal_handler_disconnect (G_OBJECT (cwc->sheet),
- cwc->start_handler_id);
- cwc->start_handler_id = 0;
- }
+ g_return_val_if_fail (sheet, FALSE);
+ g_return_val_if_fail (IS_SHEET (sheet), FALSE);
- if (cwc->create_wire_cancel_id != 0) {
- g_signal_handler_disconnect (G_OBJECT (cwc->sheet),
- cwc->create_wire_cancel_id);
- cwc->create_wire_cancel_id = 0;
+ create_wire_info = sheet->priv->create_wire_info;
+ g_return_val_if_fail (create_wire_info, FALSE);
+
+ if (create_wire_info->state == WIRE_DISABLED) {
+ create_wire_info->event_handler_id =
+ g_signal_connect (sheet, "event", G_CALLBACK (create_wire_event), NULL);
+ // this is also handled by event
+ // create_wire_info->cancel_handler_id = g_signal_connect (sheet,
+ //"cancel",
+ // G_CALLBACK
+ //(create_wire_discard), NULL);
}
- schematic_view_reset_tool (
- schematic_view_get_schematicview_from_sheet (cwc->sheet));
- g_free (cwc);
+ create_wire_info->state = WIRE_START;
+ return TRUE;
}
-void
-create_wire_exit (CreateWireContext *cwc)
+gboolean create_wire_orientationtoggle (Sheet *sheet)
{
- if (cwc->draw_handler_id != 0)
- cancel_wire (cwc);
+ CreateWireInfo *create_wire_info;
+ GooCanvasPoints *points;
+ g_return_val_if_fail (sheet, FALSE);
+ g_return_val_if_fail (IS_SHEET (sheet), FALSE);
- if (cwc->start_handler_id != 0) {
- g_signal_handler_disconnect (G_OBJECT (cwc->sheet),
- cwc->start_handler_id);
- cwc->start_handler_id = 0;
+ NG_DEBUG ("toggle orientation")
+ create_wire_info = sheet->priv->create_wire_info;
+ g_return_val_if_fail (create_wire_info, FALSE);
+
+ points = create_wire_info->points;
+
+ switch (create_wire_info->direction) {
+ case WIRE_DIR_HORIZ:
+ create_wire_info->direction = WIRE_DIR_VERT;
+ points->coords[2] = points->coords[0];
+ points->coords[3] = points->coords[5];
+ g_object_set (G_OBJECT (create_wire_info->line), "points", points, NULL);
+ break;
+ case WIRE_DIR_VERT:
+ create_wire_info->direction = WIRE_DIR_HORIZ;
+ points->coords[2] = points->coords[4];
+ points->coords[3] = points->coords[1];
+ g_object_set (G_OBJECT (create_wire_info->line), "points", points, NULL);
+ break;
+ default:
+ break;
}
+ return TRUE;
}
-// Signal handler for the "cancel" signal that the sheet emits
-// when <escape> is pressed.
-static int
-create_wire_cancel (Sheet *sheet, CreateWireContext *cwc)
+gboolean create_wire_event (Sheet *sheet, GdkEvent *event, gpointer data)
{
- g_return_val_if_fail (sheet != NULL, FALSE);
+ CreateWireInfo *create_wire_info;
+ g_return_val_if_fail (sheet, FALSE);
g_return_val_if_fail (IS_SHEET (sheet), FALSE);
- if (cwc->active)
- cancel_wire (cwc);
- else
- exit_wire_mode (cwc);
+ create_wire_info = sheet->priv->create_wire_info;
+ g_return_val_if_fail (create_wire_info, FALSE);
+
+ switch (event->type) {
+ case GDK_3BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ break;
+ case GDK_BUTTON_PRESS:
+ switch (event->button.button) {
+ case 1:
+ if (create_wire_info->state == WIRE_START)
+ return create_wire_start (sheet, event);
+ else if (create_wire_info->state == WIRE_ACTIVE)
+ return create_wire_fixate (sheet, event);
+ break;
+ case 3:
+ if (create_wire_info->state == WIRE_ACTIVE)
+ return create_wire_discard (sheet, event);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (create_wire_info->state == WIRE_ACTIVE)
+ return create_wire_update (sheet, event);
+ break;
+ case GDK_KEY_PRESS:
+ NG_DEBUG ("keypress 0");
+ if (create_wire_info->state != WIRE_ACTIVE)
+ return FALSE;
+ NG_DEBUG ("keypress 1");
+ switch (event->key.keyval) {
+ case GDK_KEY_Escape:
+ return create_wire_discard (sheet, event);
+ case GDK_KEY_R:
+ case GDK_KEY_r:
+ return create_wire_orientationtoggle (sheet);
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+gboolean create_wire_cleanup (Sheet *sheet)
+{
+ CreateWireInfo *create_wire_info;
+
+ create_wire_info = sheet->priv->create_wire_info;
+ if (create_wire_info && create_wire_info->state != WIRE_DISABLED) {
+ g_object_set (G_OBJECT (create_wire_info->line), "visibility", GOO_CANVAS_ITEM_INVISIBLE,
+ NULL);
+ create_wire_info->state = WIRE_DISABLED;
+ g_signal_handler_disconnect (G_OBJECT (sheet), create_wire_info->event_handler_id);
+ // g_signal_handler_disconnect (G_OBJECT (sheet),
+ // create_wire_info->cancel_handler_id);
+ }
return TRUE;
}
diff --git a/src/sheet/create-wire.h b/src/sheet/create-wire.h
index 87c622d..947a98e 100644
--- a/src/sheet/create-wire.h
+++ b/src/sheet/create-wire.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __CREATE_WIRE_H
@@ -40,15 +40,26 @@
#include "wire-item.h"
#include "schematic-view.h"
-typedef struct _CreateWireContext CreateWireContext;
+typedef enum { WIRE_START, WIRE_ACTIVE, WIRE_DISABLED } WireState;
-typedef struct {
+typedef struct _CreateWireInfo CreateWireInfo;
+
+struct _CreateWireInfo
+{
+ WireState state;
GooCanvasPolyline *line;
- GooCanvasPoints * points;
- WireDir direction; // Direction of the first wire segment.
-} CreateWire;
+ GooCanvasPoints *points;
+ GooCanvasEllipse *dot;
+ WireDir direction;
+ gulong event_handler_id;
+ // gulong cancel_handler_id;
+};
-CreateWireContext * create_wire_initiate (Sheet *sheet);
-void create_wire_exit (CreateWireContext *cwc);
+CreateWireInfo *create_wire_info_new (Sheet *sheet);
+void create_wire_destroy (CreateWireInfo *wire_info);
+gboolean create_wire_setup (Sheet *sheet);
+gboolean create_wire_orientationtoggle (Sheet *sheet);
+gboolean create_wire_event (Sheet *sheet, GdkEvent *event, gpointer data);
+gboolean create_wire_cleanup (Sheet *sheet);
#endif
diff --git a/src/sheet/grid.c b/src/sheet/grid.c
index 63cbd8c..f2db618 100644
--- a/src/sheet/grid.c
+++ b/src/sheet/grid.c
@@ -6,12 +6,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
* Web page: https://github.com/marc-lorber/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -25,32 +29,27 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include "grid.h"
+#define ROUND(x) (floor ((x)+0.5))
+#include "debug.h"
-#define ROUND(x) (floor((x)+0.5))
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+enum { ARG_0, ARG_COLOR, ARG_SPACING, ARG_SNAP };
-enum {
- ARG_0,
- ARG_COLOR,
- ARG_SPACING,
- ARG_SNAP
-};
-
-struct _GridPriv{
- GooCanvasItem * canvas_grid;
- guint snap;
- GdkColor color;
- gdouble spacing;
- gdouble cached_zoom;
- cairo_t * cairo;
+struct _GridPriv
+{
+ GooCanvasItem *canvas_grid;
+ guint snap;
+ GdkRGBA color;
+ gdouble spacing;
+ gdouble cached_zoom;
+ cairo_t *cairo;
};
G_DEFINE_TYPE (Grid, grid, GOO_TYPE_CANVAS_GROUP)
@@ -58,14 +57,12 @@ G_DEFINE_TYPE (Grid, grid, GOO_TYPE_CANVAS_GROUP)
static void grid_class_init (GridClass *class);
static void grid_init (Grid *grid);
static void grid_finalize (GObject *object);
-static void grid_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-static void grid_get_property (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec);
+static void grid_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void grid_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *spec);
static void grid_dispose (GObject *object);
-static void
-grid_class_init (GridClass *class)
+static void grid_class_init (GridClass *class)
{
GObjectClass *object_class;
@@ -73,27 +70,26 @@ grid_class_init (GridClass *class)
grid_parent_class = g_type_class_peek_parent (class);
object_class->dispose = grid_dispose;
- object_class->finalize = grid_finalize;
+ object_class->finalize = grid_finalize;
object_class->set_property = grid_set_property;
object_class->get_property = grid_get_property;
- g_object_class_install_property (object_class, ARG_COLOR,
- g_param_spec_string ("color", "Grid::color", "the color",
- "black", G_PARAM_WRITABLE));
-
+ g_object_class_install_property (
+ object_class, ARG_COLOR,
+ g_param_spec_string ("color", "Grid::color", "the color", "black", G_PARAM_WRITABLE));
+
g_object_class_install_property (object_class, ARG_SPACING,
- g_param_spec_double ("spacing", "Grid::spacing",
- "the grid spacing", 0.0f, 100.0f, 10.0f,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, ARG_SNAP,
- g_param_spec_boolean ("snap", "Grid::snap", "snap to grid?",
- TRUE,G_PARAM_READWRITE));
+ g_param_spec_double ("spacing", "Grid::spacing",
+ "the grid spacing", 0.0f, 100.0f, 10.0f,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class, ARG_SNAP,
+ g_param_spec_boolean ("snap", "Grid::snap", "snap to grid?", TRUE, G_PARAM_READWRITE));
}
-static void
-grid_init (Grid *grid)
+static void grid_init (Grid *grid)
{
GridPriv *priv;
@@ -105,14 +101,9 @@ grid_init (Grid *grid)
priv->snap = TRUE;
}
-static void
-grid_dispose (GObject *object)
-{
- G_OBJECT_CLASS (grid_parent_class)->dispose (object);
-}
+static void grid_dispose (GObject *object) { G_OBJECT_CLASS (grid_parent_class)->dispose (object); }
-static void
-grid_finalize (GObject *object)
+static void grid_finalize (GObject *object)
{
Grid *grid;
@@ -122,9 +113,8 @@ grid_finalize (GObject *object)
G_OBJECT_CLASS (grid_parent_class)->finalize (object);
}
-static void
-grid_set_property (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *spec)
+static void grid_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
{
Grid *grid;
GridPriv *priv;
@@ -146,9 +136,7 @@ grid_set_property (GObject *object, guint prop_id, const GValue *value,
}
}
-static void
-grid_get_property (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec)
+static void grid_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *spec)
{
Grid *grid;
GridPriv *priv;
@@ -169,39 +157,25 @@ grid_get_property (GObject *object, guint prop_id, GValue *value,
}
}
-Grid *
-grid_create (GooCanvasItem *root, gdouble width, gdouble height)
+Grid *grid_new (GooCanvasItem *root, gdouble width, gdouble height)
{
- Grid * grid = NULL;
+ Grid *grid = NULL;
grid = g_object_new (TYPE_GRID, NULL);
- g_object_set (G_OBJECT (grid),
- "parent", root,
- NULL);
-
- grid->priv->canvas_grid = goo_canvas_grid_new (GOO_CANVAS_ITEM (grid),
- 0.0,
- 0.0,
- width,
- height,
- 10.0,
- 10.0,
- 0.0,
- 0.0,
- "horz-grid-line-width", 0.05,
- "horz-grid-line-color", "dark gray",
- "vert-grid-line-width", 0.05,
- "vert-grid-line-color", "dark gray",
- NULL);
-
+ g_object_set (G_OBJECT (grid), "parent", root, NULL);
+
+ grid->priv->canvas_grid = goo_canvas_grid_new (
+ GOO_CANVAS_ITEM (grid), 0.0, 0.0, width, height, 10.0, 10.0, 0.0, 0.0,
+ "horz-grid-line-width", 0.05, "horz-grid-line-color", "dark gray", "vert-grid-line-width",
+ 0.05, "vert-grid-line-color", "dark gray", NULL);
+
grid_show (grid, TRUE);
grid_snap (grid, TRUE);
return grid;
}
-inline void
-snap_to_grid (Grid *grid, gdouble *x, gdouble *y)
+inline gboolean snap_to_grid (Grid *grid, gdouble *x, gdouble *y)
{
GridPriv *priv;
gdouble spacing;
@@ -209,27 +183,33 @@ snap_to_grid (Grid *grid, gdouble *x, gdouble *y)
priv = grid->priv;
spacing = priv->spacing;
- if (priv->snap) {
- if (x) *x = ROUND ((*x) / spacing) * spacing;
- if (y) *y = ROUND ((*y) / spacing) * spacing;
+ Coords old = {0., 0.};
+ gboolean moved = FALSE;
+
+ if (G_LIKELY (priv->snap)) {
+ if (G_LIKELY (x)) {
+ old.x = *x;
+ *x = ROUND ((*x) / spacing) * spacing;
+ moved = moved || (fabs ((*x) - old.x) > COORDS_DELTA);
+ }
+ if (G_LIKELY (y)) {
+ old.y = *y;
+ *y = ROUND ((*y) / spacing) * spacing;
+ moved = moved || (fabs ((*y) - old.y) > COORDS_DELTA);
+ }
}
+ return moved;
}
-void
-grid_show (Grid *grid, gboolean show)
+void grid_show (Grid *grid, gboolean show)
{
if (show)
- g_object_set (G_OBJECT (grid),
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
+ g_object_set (G_OBJECT (grid), "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
else
- g_object_set (G_OBJECT (grid),
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+ g_object_set (G_OBJECT (grid), "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
}
-void
-grid_snap (Grid *grid, gboolean snap)
+void grid_snap (Grid *grid, gboolean snap)
{
GridPriv *priv;
diff --git a/src/sheet/grid.h b/src/sheet/grid.h
index 88bba3f..868b7cb 100644
--- a/src/sheet/grid.h
+++ b/src/sheet/grid.h
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __GRID_H
@@ -36,34 +36,36 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <goocanvas.h>
+#include "coords.h"
-#define TYPE_GRID (grid_get_type())
-#define GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, grid_get_type (), Grid))
-#define GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, grid_get_type (), GridClass))
-#define IS_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, grid_get_type ()))
+#define TYPE_GRID (grid_get_type ())
+#define GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, grid_get_type (), Grid))
+#define GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, grid_get_type (), GridClass))
+#define IS_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, grid_get_type ()))
typedef struct _Grid Grid;
typedef struct _GridClass GridClass;
typedef struct _GridPriv GridPriv;
-
-struct _Grid {
+struct _Grid
+{
GooCanvasGroup canvas_group;
- gdouble width;
- gdouble height;
- gdouble x;
- gdouble y;
- GridPriv * priv;
+ gdouble width;
+ gdouble height;
+ gdouble x;
+ gdouble y;
+ GridPriv *priv;
};
-struct _GridClass {
- GooCanvasGroupClass parent_class;
+struct _GridClass
+{
+ GooCanvasGroupClass parent_class;
};
-Grid *grid_create (GooCanvasItem *root, gdouble width, gdouble height);
+Grid *grid_new (GooCanvasItem *root, gdouble width, gdouble height);
GType grid_get_type (void);
-void snap_to_grid (Grid *grid, double *x, double *y);
-void grid_show (Grid *grid, gboolean snap);
-void grid_snap (Grid *grid, gboolean snap);
+gboolean snap_to_grid (Grid *grid, double *x, double *y);
+void grid_show (Grid *grid, gboolean snap);
+void grid_snap (Grid *grid, gboolean snap);
#endif
diff --git a/src/sheet/node-item.c b/src/sheet/node-item.c
index cd20020..d7a6d95 100644
--- a/src/sheet/node-item.c
+++ b/src/sheet/node-item.c
@@ -6,7 +6,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -24,53 +24,65 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
-
+#include "options.h"
#include "node-item.h"
-static void node_item_init (NodeItem *item);
-static void node_item_class_init (NodeItemClass *klass);
+static void node_item_init (NodeItem *item);
+static void node_item_class_init (NodeItemClass *klass);
-struct _NodeItemPriv {
+struct _NodeItemPriv
+{
GooCanvasItem *dot_item;
+ GooCanvasItem *circle_item; // debug
};
-G_DEFINE_TYPE (NodeItem, node_item, GOO_TYPE_CANVAS_GROUP)
+G_DEFINE_TYPE (NodeItem, node_item, GOO_TYPE_CANVAS_GROUP);
+
+static void node_item_dispose (GObject *object)
+{
+ NodeItem *item = NODE_ITEM (object);
+ NodeItemPriv *priv = item->priv;
+
+ g_clear_object (&(priv->dot_item));
+ g_clear_object (&(priv->circle_item));
+ G_OBJECT_CLASS (node_item_parent_class)->dispose (object);
+}
-static void
-node_item_class_init (NodeItemClass *klass)
+static void node_item_finalize (GObject *object)
{
- node_item_parent_class = g_type_class_peek_parent (klass);
+ G_OBJECT_CLASS (node_item_parent_class)->finalize (object);
+}
+
+static void node_item_class_init (NodeItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = node_item_finalize;
+ object_class->dispose = node_item_dispose;
}
-static void
-node_item_init (NodeItem *item)
+static void node_item_init (NodeItem *item)
{
item->priv = g_new0 (NodeItemPriv, 1);
+ item->priv->dot_item =
+ goo_canvas_ellipse_new (GOO_CANVAS_ITEM (item), 0.0, 0.0, 2.0, 2.0, "fill-color", "black",
+ "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+ item->priv->circle_item = goo_canvas_ellipse_new (
+ GOO_CANVAS_ITEM (item), 0.0, 0.0, 3.0, 3.0, "stroke-color-rgba", 0x3399FFFF, "line-width",
+ 1.0, "visibility",
+ oregano_options_debug_dots () ? GOO_CANVAS_ITEM_VISIBLE : GOO_CANVAS_ITEM_INVISIBLE, NULL);
}
-void
-node_item_show_dot (NodeItem *item, gboolean show)
+void node_item_show_dot (NodeItem *item, gboolean show)
{
g_return_if_fail (item != NULL);
g_return_if_fail (IS_NODE_ITEM (item));
- if (show) {
- if (item->priv->dot_item == NULL) {
- item->priv->dot_item = goo_canvas_ellipse_new (
- GOO_CANVAS_ITEM (item),
- 0.0, 0.0, 2.0, 2.0,
- "fill_color", "black",
- NULL);
- }
- g_object_set (item->priv->dot_item,
- "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
- }
- else if (item->priv->dot_item != NULL)
- g_object_set (item->priv->dot_item,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+ g_object_set (item->priv->dot_item, "visibility",
+ show ? GOO_CANVAS_ITEM_VISIBLE : GOO_CANVAS_ITEM_INVISIBLE, NULL);
}
diff --git a/src/sheet/node-item.h b/src/sheet/node-item.h
index f64bba1..c1f5986 100644
--- a/src/sheet/node-item.h
+++ b/src/sheet/node-item.h
@@ -9,7 +9,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -27,8 +27,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __NODE_ITEM_H__
#define __NODE_ITEM_H__
@@ -36,21 +36,20 @@
#include <gtk/gtk.h>
#include <goocanvas.h>
-#define TYPE_NODE_ITEM (node_item_get_type ())
-#define NODE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE_ITEM, NodeItem))
-#define NODE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE_ITEM, NodeItemClass))
-#define IS_NODE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE_ITEM))
+#define TYPE_NODE_ITEM (node_item_get_type ())
+#define NODE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NODE_ITEM, NodeItem))
+#define NODE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NODE_ITEM, NodeItemClass))
+#define IS_NODE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NODE_ITEM))
#define IS_NODE_ITEM_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NODE_ITEM, NodeItemClass))
-
-typedef struct _NodeItem NodeItem;
+typedef struct _NodeItem NodeItem;
typedef struct _NodeItemClass NodeItemClass;
-typedef struct _NodeItemPriv NodeItemPriv;
+typedef struct _NodeItemPriv NodeItemPriv;
struct _NodeItem
{
GooCanvasGroup parent;
- NodeItemPriv *priv;
+ NodeItemPriv *priv;
};
struct _NodeItemClass
@@ -58,9 +57,8 @@ struct _NodeItemClass
GooCanvasGroupClass parent_class;
};
-
-GType node_item_get_type (void);
-GtkWidget *node_item_new (void);
-void node_item_show_dot (NodeItem *item, gboolean show);
+GType node_item_get_type (void);
+GtkWidget *node_item_new (void);
+void node_item_show_dot (NodeItem *item, gboolean show);
#endif /* __NODE_ITEM_H__ */
diff --git a/src/sheet/part-item.c b/src/sheet/part-item.c
index 1d7a3de..90cdd44 100644
--- a/src/sheet/part-item.c
+++ b/src/sheet/part-item.c
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <glib/gi18n.h>
@@ -46,52 +48,46 @@
#include "stock.h"
#include "dialogs.h"
#include "sheet.h"
-
+#include "oregano-utils.h"
+#include "options.h"
#define NORMAL_COLOR "red"
#define LABEL_COLOR "dark cyan"
#define SELECTED_COLOR "green"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-static void part_item_class_init (PartItemClass *klass);
-static void part_item_init (PartItem *gspart);
-static void part_item_finalize (GObject *object);
-static void part_item_moved (SheetItem *sheet_item);
-static void edit_properties (SheetItem *object);
-static void selection_changed (PartItem *item, gboolean select,
- gpointer user_data);
-static int select_idle_callback (PartItem *item);
-static int deselect_idle_callback (PartItem *item);
-static void update_canvas_labels (PartItem *part_item);
-static gboolean is_in_area (SheetItem *object, SheetPos *p1,
- SheetPos *p2);
-inline static void get_cached_bounds (PartItem *item, SheetPos *p1,
- SheetPos *p2);
-static void show_labels (SheetItem *sheet_item, gboolean show);
-static void part_item_paste (Sheet *sheet, ItemData *data);
-static void part_rotated_callback (ItemData *data, int angle,
- SheetItem *item);
-static void part_flipped_callback (ItemData *data,
- gboolean horizontal, SheetItem *sheet_item);
-static void part_moved_callback (ItemData *data, SheetPos *pos,
- SheetItem *item);
-static void part_item_place (SheetItem *item, Sheet *sheet);
-static void part_item_place_ghost (SheetItem *item, Sheet *sheet);
-static void create_canvas_items (GooCanvasGroup *group,
- LibraryPart *library_part);
-static void create_canvas_labels (PartItem *item, Part *part);
-static void create_canvas_label_nodes (PartItem *item, Part *part);
-static PartItem * part_item_canvas_new (Sheet *sheet, Part *part);
-static void part_item_get_property (GObject *object,
- guint prop_id, GValue *value, GParamSpec *spec);
-static void part_item_set_property (GObject *object,
- guint prop_id, const GValue *value,
- GParamSpec *spec);
-static void part_item_dispose (GObject *object);
+#include "debug.h"
+
+static void part_item_class_init (PartItemClass *klass);
+static void part_item_init (PartItem *gspart);
+static void part_item_finalize (GObject *object);
+static void part_item_moved (SheetItem *sheet_item);
+static void edit_properties (SheetItem *object);
+static void selection_changed (PartItem *item, gboolean select, gpointer user_data);
+static int select_idle_callback (PartItem *item);
+static int deselect_idle_callback (PartItem *item);
+static void update_canvas_labels (PartItem *part_item);
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2);
+inline static void get_cached_bounds (PartItem *item, Coords *p1, Coords *p2);
+static void show_labels (SheetItem *sheet_item, gboolean show);
+static void part_item_paste (Sheet *sheet, ItemData *data);
+static void part_rotated_callback (ItemData *data, int angle, SheetItem *item);
+static void part_flipped_callback (ItemData *data, IDFlip direction, SheetItem *sheet_item);
+static void part_moved_callback (ItemData *data, Coords *pos, SheetItem *item);
+static void part_changed_callback (ItemData *data, SheetItem *sheet_item);
+
+static void part_item_place (SheetItem *item, Sheet *sheet);
+static void part_item_place_ghost (SheetItem *item, Sheet *sheet);
+static void create_canvas_items (GooCanvasGroup *group, LibraryPart *library_part);
+static void create_canvas_labels (PartItem *item, Part *part);
+static void create_canvas_label_nodes (PartItem *item, Part *part);
+static PartItem *part_item_canvas_new (Sheet *sheet, Part *part);
+static void part_item_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec);
+static void part_item_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void part_item_dispose (GObject *object);
static GooCanvasAnchorType part_item_get_anchor_from_part (Part *part);
-
enum {
ARG_0,
ARG_DATA,
@@ -105,52 +101,47 @@ enum {
ARG_MODEL
};
-struct _PartItemPriv {
- guint cache_valid : 1;
- GooCanvasItem *label_group;
- GSList *label_items;
- GooCanvasItem *node_group;
- GSList *label_nodes;
+struct _PartItemPriv
+{
+ guint cache_valid : 1;
+ GooCanvasItem *label_group;
+ GSList *label_items;
+ GooCanvasItem *node_group;
+ GSList *label_nodes;
+
+ GooCanvasItem *rect;
// Cached bounding box. This is used to make
// the rubberband selection a bit faster.
- SheetPos bbox_start;
- SheetPos bbox_end;
+ Coords bbox_start;
+ Coords bbox_end;
};
-typedef struct {
+typedef struct
+{
GtkDialog *dialog;
- PartItem *part_item;
+ PartItem *part_item;
// List of GtkEntry's
- GList *widgets;
+ GList *widgets;
} PartPropDialog;
static PartPropDialog *prop_dialog = NULL;
static SheetItemClass *parent_class = NULL;
-static const char *part_item_context_menu =
-"<ui>"
-" <popup name='ItemMenu'>"
-" <menuitem action='ObjectProperties'/>"
-" </popup>"
-"</ui>";
-
-static GtkActionEntry action_entries[] = {
- {"ObjectProperties", GTK_STOCK_PROPERTIES, N_("_Object Properties..."),
- NULL, N_("Modify the object's properties"),
- NULL}
-};
+static const char *part_item_context_menu = "<ui>"
+ " <popup name='ItemMenu'>"
+ " <menuitem action='ObjectProperties'/>"
+ " </popup>"
+ "</ui>";
-enum {
- ANCHOR_NORTH,
- ANCHOR_SOUTH,
- ANCHOR_WEST,
- ANCHOR_EAST
-};
+static GtkActionEntry action_entries[] = {{"ObjectProperties", GTK_STOCK_PROPERTIES,
+ N_ ("_Object Properties..."), NULL,
+ N_ ("Modify object properties"), NULL}};
+
+enum { ANCHOR_NORTH, ANCHOR_SOUTH, ANCHOR_WEST, ANCHOR_EAST };
G_DEFINE_TYPE (PartItem, part_item, TYPE_SHEET_ITEM)
-static void
-part_item_class_init (PartItemClass *part_item_class)
+static void part_item_class_init (PartItemClass *part_item_class)
{
GObjectClass *object_class;
SheetItemClass *sheet_item_class;
@@ -169,33 +160,31 @@ part_item_class_init (PartItemClass *part_item_class)
sheet_item_class->show_labels = show_labels;
sheet_item_class->paste = part_item_paste;
sheet_item_class->edit_properties = edit_properties;
- sheet_item_class->selection_changed = (gpointer) selection_changed;
+ sheet_item_class->selection_changed = (gpointer)selection_changed;
sheet_item_class->place = part_item_place;
sheet_item_class->place_ghost = part_item_place_ghost;
}
-static void
-part_item_init (PartItem *item)
+static void part_item_init (PartItem *item)
{
PartItemPriv *priv;
- priv = g_new0 (PartItemPriv, 1);
-
+ priv = g_slice_new0 (PartItemPriv);
+ priv->rect = NULL;
priv->cache_valid = FALSE;
item->priv = priv;
- sheet_item_add_menu (SHEET_ITEM (item), part_item_context_menu,
- action_entries, G_N_ELEMENTS (action_entries));
+ sheet_item_add_menu (SHEET_ITEM (item), part_item_context_menu, action_entries,
+ G_N_ELEMENTS (action_entries));
}
-static void
-part_item_set_property (GObject *object, guint propety_id, const GValue *value,
- GParamSpec *pspec)
+static void part_item_set_property (GObject *object, guint propety_id, const GValue *value,
+ GParamSpec *pspec)
{
g_return_if_fail (object != NULL);
- g_return_if_fail (IS_PART_ITEM(object));
+ g_return_if_fail (IS_PART_ITEM (object));
switch (propety_id) {
default:
@@ -203,9 +192,8 @@ part_item_set_property (GObject *object, guint propety_id, const GValue *value,
}
}
-static void
-part_item_get_property (GObject *object, guint propety_id, GValue *value,
- GParamSpec *pspec)
+static void part_item_get_property (GObject *object, guint propety_id, GValue *value,
+ GParamSpec *pspec)
{
g_return_if_fail (object != NULL);
g_return_if_fail (IS_PART_ITEM (object));
@@ -217,32 +205,26 @@ part_item_get_property (GObject *object, guint propety_id, GValue *value,
}
}
-static void
-part_item_dispose (GObject *object)
-{
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
+static void part_item_dispose (GObject *object) { G_OBJECT_CLASS (parent_class)->dispose (object); }
-static void
-part_item_finalize (GObject *object)
+static void part_item_finalize (GObject *object)
{
PartItemPriv *priv;
priv = PART_ITEM (object)->priv;
- if (priv->label_nodes) {
- g_slist_free (priv->label_nodes);
- }
- if (priv->label_items) {
- g_slist_free (priv->label_items);
- }
- g_free (priv);
+ g_slist_free (priv->label_nodes);
+ g_slist_free (priv->label_items);
+ g_slice_free (PartItemPriv, priv);
priv = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-part_item_set_label_items (PartItem *item, GSList *item_list)
+////////////////////////////////////////////////////////////////////////////////
+// END BOILER PLATE
+////////////////////////////////////////////////////////////////////////////////
+
+static void part_item_set_label_items (PartItem *item, GSList *item_list)
{
PartItemPriv *priv;
@@ -257,22 +239,16 @@ part_item_set_label_items (PartItem *item, GSList *item_list)
priv->label_items = item_list;
}
-// "moved" signal handler. Invalidates the bounding box cache.
-static void
-part_item_moved (SheetItem *sheet_item)
+static void part_item_moved (SheetItem *sheet_item)
{
- PartItem *part_item;
-
- part_item = PART_ITEM (sheet_item);
- part_item->priv->cache_valid = FALSE;
+ // g_warning ("part MOVED callback called - LEGACY");
}
-PartItem *
-part_item_canvas_new (Sheet *sheet, Part *part)
+PartItem *part_item_canvas_new (Sheet *sheet, Part *part)
{
PartItem *part_item;
PartItemPriv *priv;
- GooCanvasItem *item;
+ GooCanvasItem *goo_item;
ItemData *item_data;
g_return_val_if_fail (sheet != NULL, NULL);
@@ -280,52 +256,43 @@ part_item_canvas_new (Sheet *sheet, Part *part)
g_return_val_if_fail (part != NULL, NULL);
g_return_val_if_fail (IS_PART (part), NULL);
- item = g_object_new (TYPE_PART_ITEM, NULL);
-
- g_object_set (item,
- "parent", sheet->object_group,
- NULL);
-
- part_item = PART_ITEM (item);
- g_object_set (part_item,
- "data", part,
- NULL);
+ part_item = g_object_new (TYPE_PART_ITEM, NULL);
+ goo_item = GOO_CANVAS_ITEM (part_item);
+
+ g_object_set (part_item, "parent", sheet->object_group, NULL);
+
+ g_object_set (part_item, "data", part, NULL);
+
priv = part_item->priv;
-
- priv->label_group = GOO_CANVAS_ITEM (goo_canvas_group_new (
- GOO_CANVAS_ITEM (part_item),
- "width", -1.0,
- "height", -1.0,
- NULL));
- g_object_unref (item);
-
- priv->node_group = GOO_CANVAS_ITEM (goo_canvas_group_new (
- GOO_CANVAS_ITEM (part_item),
- NULL));
-
- g_object_set (GOO_CANVAS_ITEM (priv->node_group),
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+
+ Coords b1, b2;
+ item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
+
+ priv->rect = goo_canvas_rect_new (
+ goo_item, b1.x, b1.y, b2.x - b1.x, b2.y - b1.y, "stroke-color", "green", "line-width", .0,
+ "fill-color-rgba", 0x7733aa66, "radius-x", 1.0, "radius-y", 1.0, "visibility",
+ oregano_options_debug_boxes () ? GOO_CANVAS_ITEM_VISIBLE : GOO_CANVAS_ITEM_INVISIBLE, NULL);
+
+ priv->label_group = goo_canvas_group_new (goo_item, "width", -1.0, "height", -1.0, NULL);
+
+ priv->node_group = goo_canvas_group_new (goo_item, NULL);
+
+ g_object_set (priv->node_group, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
item_data = ITEM_DATA (part);
- item_data->rotated_handler_id = g_signal_connect_object (G_OBJECT (part),
- "rotated",
- G_CALLBACK (part_rotated_callback),
- G_OBJECT (part_item), 0);
- item_data->flipped_handler_id = g_signal_connect_object (G_OBJECT (part),
- "flipped",
- G_CALLBACK (part_flipped_callback),
- G_OBJECT (part_item), 0);
- item_data->moved_handler_id = g_signal_connect_object (G_OBJECT (part),
- "moved",
- G_CALLBACK (part_moved_callback),
- G_OBJECT (part_item), 0);
+ item_data->rotated_handler_id =
+ g_signal_connect_object (part, "rotated", G_CALLBACK (part_rotated_callback), part_item, 0);
+ item_data->flipped_handler_id =
+ g_signal_connect_object (part, "flipped", G_CALLBACK (part_flipped_callback), part_item, 0);
+ item_data->moved_handler_id =
+ g_signal_connect_object (part, "moved", G_CALLBACK (part_moved_callback), part_item, 0);
+ item_data->changed_handler_id =
+ g_signal_connect_object (part, "changed", G_CALLBACK (part_changed_callback), part_item, 0);
return part_item;
}
-static void
-update_canvas_labels (PartItem *item)
+static void update_canvas_labels (PartItem *item)
{
PartItemPriv *priv;
Part *part;
@@ -344,20 +311,17 @@ update_canvas_labels (PartItem *item)
for (labels = part_get_labels (part); labels;
labels = labels->next, label_items = label_items->next) {
char *text;
- PartLabel *label = (PartLabel*) labels->data;
+ PartLabel *label = (PartLabel *)labels->data;
g_assert (label_items != NULL);
canvas_item = label_items->data;
text = part_property_expand_macros (part, label->text);
- g_object_set (canvas_item,
- "text", text,
- NULL);
+ g_object_set (canvas_item, "text", text, NULL);
g_free (text);
}
}
-void
-part_item_update_node_label (PartItem *item)
+void part_item_update_node_label (PartItem *item)
{
PartItemPriv *priv;
Part *part;
@@ -371,60 +335,51 @@ part_item_update_node_label (PartItem *item)
priv = item->priv;
part = PART (sheet_item_get_data (SHEET_ITEM (item)));
- g_return_if_fail (IS_PART (part) );
+ g_return_if_fail (IS_PART (part));
// Put the label of each node
num_pins = part_get_num_pins (part);
-
+
if (num_pins == 1) {
pins = part_get_pins (part);
labels = priv->label_nodes;
- for (labels = priv->label_nodes; labels; labels=labels->next) {
+ for (labels = priv->label_nodes; labels; labels = labels->next) {
char *txt;
txt = g_strdup_printf ("V(%d)", pins[0].node_nr);
canvas_item = labels->data;
if (pins[0].node_nr != 0)
- g_object_set (canvas_item,
- "text", txt,
- "fill_color", LABEL_COLOR,
- "font", "Sans 8",
- NULL);
+ g_object_set (canvas_item, "text", txt, "fill_color", LABEL_COLOR, "font", "Sans 8",
+ NULL);
else
- g_object_set (canvas_item,
- "text", "",
- NULL);
+ g_object_set (canvas_item, "text", "", NULL);
g_free (txt);
}
}
}
-static void
-prop_dialog_destroy (GtkWidget *widget, PartPropDialog *prop_dialog)
+static void prop_dialog_destroy (GtkWidget *widget, PartPropDialog *prop_dialog)
{
g_free (prop_dialog);
}
-static void
-prop_dialog_response (GtkWidget *dialog, gint response,
- PartPropDialog *prop_dialog)
+static void prop_dialog_response (GtkWidget *dialog, gint response, PartPropDialog *prop_dialog)
{
- GSList *props;
- GList *widget;
- Property *prop;
- PartItem *item;
- Part *part;
- gchar *prop_name;
- const gchar *prop_value;
- GtkWidget *w;
+ GSList *props = NULL;
+ GList *widget;
+ Property *prop;
+ PartItem *item;
+ Part *part;
+ gchar *prop_name;
+ const gchar *prop_value;
+ GtkWidget *w;
item = prop_dialog->part_item;
part = PART (sheet_item_get_data (SHEET_ITEM (item)));
- for (widget = prop_dialog->widgets; widget;
- widget = widget->next) {
+ for (widget = prop_dialog->widgets; widget; widget = widget->next) {
w = widget->data;
prop_name = g_object_get_data (G_OBJECT (w), "user");
@@ -433,26 +388,22 @@ prop_dialog_response (GtkWidget *dialog, gint response,
for (props = part_get_properties (part); props; props = props->next) {
prop = props->data;
if (g_ascii_strcasecmp (prop->name, prop_name) == 0) {
- if (prop->value) g_free (prop->value);
+ g_free (prop->value);
prop->value = g_strdup (prop_value);
}
}
g_free (prop_name);
}
- g_slist_free_full (props, g_object_unref);
- g_list_free_full (widget, g_object_unref);
update_canvas_labels (item);
}
-static void
-edit_properties_point (PartItem *item)
+static void edit_properties_point (PartItem *item)
{
GSList *properties;
Part *part;
- char *msg;
GtkBuilder *gui;
- GError *perror = NULL;
+ GError *error = NULL;
GtkRadioButton *radio_v, *radio_c;
GtkRadioButton *ac_r, *ac_m, *ac_i, *ac_p;
GtkCheckButton *chk_db;
@@ -460,38 +411,22 @@ edit_properties_point (PartItem *item)
part = PART (sheet_item_get_data (SHEET_ITEM (item)));
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create part properties dialog."));
- return;
- }
- else
- gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test(
- OREGANO_UIDIR "/clamp-properties-dialog.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall "
- "Oregano to fix this."),
- OREGANO_UIDIR "/clamp-properties-dialog.ui");
- oregano_error_with_title (_("Could not create part properties dialog."), msg);
- g_free (msg);
+ oregano_error (_ ("Could not create part properties dialog."));
return;
}
+ gtk_builder_set_translation_domain (gui, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/clamp-properties-dialog.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create part properties dialog."), msg);
- g_error_free (perror);
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/clamp-properties-dialog.ui", &error) <= 0) {
+ oregano_error_with_title (_ ("Could not create part properties dialog."), error->message);
+ g_error_free (error);
return;
- }
+ }
prop_dialog = g_new0 (PartPropDialog, 1);
prop_dialog->part_item = item;
- prop_dialog->dialog = GTK_DIALOG (gtk_builder_get_object (gui,
- "clamp-properties-dialog"));
+ prop_dialog->dialog = GTK_DIALOG (gtk_builder_get_object (gui, "clamp-properties-dialog"));
radio_v = GTK_RADIO_BUTTON (gtk_builder_get_object (gui, "radio_v"));
radio_c = GTK_RADIO_BUTTON (gtk_builder_get_object (gui, "radio_c"));
@@ -504,10 +439,9 @@ edit_properties_point (PartItem *item)
ac_i = GTK_RADIO_BUTTON (gtk_builder_get_object (gui, "radio_i"));
chk_db = GTK_CHECK_BUTTON (gtk_builder_get_object (gui, "check_db"));
-
+
// Setup GUI from properties
- for (properties = part_get_properties (part); properties;
- properties = properties->next) {
+ for (properties = part_get_properties (part); properties; properties = properties->next) {
Property *prop;
prop = properties->data;
if (prop->name) {
@@ -516,29 +450,21 @@ edit_properties_point (PartItem *item)
if (!g_ascii_strcasecmp (prop->name, "type")) {
if (!g_ascii_strcasecmp (prop->value, "v")) {
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_v),
- TRUE);
- }
- else {
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_c),
- TRUE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_v), TRUE);
+ } else {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_c), TRUE);
}
- }
- else if (!g_ascii_strcasecmp (prop->name, "ac_type")) {
+ } else if (!g_ascii_strcasecmp (prop->name, "ac_type")) {
if (!g_ascii_strcasecmp (prop->value, "m")) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ac_m), TRUE);
- }
- else if (!g_ascii_strcasecmp (prop->value, "i")) {
+ } else if (!g_ascii_strcasecmp (prop->value, "i")) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ac_i), TRUE);
- }
- else if (!g_ascii_strcasecmp (prop->value, "p")) {
+ } else if (!g_ascii_strcasecmp (prop->value, "p")) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ac_p), TRUE);
- }
- else if (!g_ascii_strcasecmp (prop->value, "r")) {
+ } else if (!g_ascii_strcasecmp (prop->value, "r")) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ac_r), TRUE);
}
- }
- else if (!g_ascii_strcasecmp (prop->name, "ac_db")) {
+ } else if (!g_ascii_strcasecmp (prop->name, "ac_db")) {
if (!g_ascii_strcasecmp (prop->value, "true"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chk_db), TRUE);
}
@@ -548,40 +474,33 @@ edit_properties_point (PartItem *item)
gtk_dialog_run (prop_dialog->dialog);
// Save properties from GUI
- for (properties = part_get_properties (part); properties;
- properties = properties->next) {
+ for (properties = part_get_properties (part); properties; properties = properties->next) {
Property *prop;
prop = properties->data;
if (prop->name) {
if (!g_ascii_strcasecmp (prop->name, "internal"))
continue;
-
+
if (!g_ascii_strcasecmp (prop->name, "type")) {
g_free (prop->value);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_v))) {
prop->value = g_strdup ("v");
- }
- else {
+ } else {
prop->value = g_strdup ("i");
}
- }
- else if (!g_ascii_strcasecmp (prop->name, "ac_type")) {
+ } else if (!g_ascii_strcasecmp (prop->name, "ac_type")) {
g_free (prop->value);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_m))) {
prop->value = g_strdup ("m");
- }
- else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_i))) {
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_i))) {
prop->value = g_strdup ("i");
- }
- else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_p))) {
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_p))) {
prop->value = g_strdup ("p");
- }
- else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_r))) {
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ac_r))) {
prop->value = g_strdup ("r");
}
- }
- else if (!g_ascii_strcasecmp (prop->name, "ac_db")) {
+ } else if (!g_ascii_strcasecmp (prop->name, "ac_db")) {
g_free (prop->value);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chk_db)))
prop->value = g_strdup ("true");
@@ -590,20 +509,18 @@ edit_properties_point (PartItem *item)
}
}
}
- g_slist_free_full (properties, g_object_unref);
gtk_widget_destroy (GTK_WIDGET (prop_dialog->dialog));
}
-static void
-edit_properties (SheetItem *object)
+static void edit_properties (SheetItem *object)
{
GSList *properties;
PartItem *item;
Part *part;
char *internal, *msg;
GtkBuilder *gui;
- GError *perror = NULL;
- GtkTable *prop_table;
+ GError *error = NULL;
+ GtkGrid *prop_grid;
GtkNotebook *notebook;
gint response, y = 0;
gboolean has_model;
@@ -630,30 +547,15 @@ edit_properties (SheetItem *object)
g_free (internal);
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create part properties dialog."));
+ oregano_error (_ ("Could not create part properties dialog."));
return;
- }
- else
- gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test(
- OREGANO_UIDIR "/part-properties-dialog.ui", G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall "
- "Oregano to fix this."),
- OREGANO_UIDIR "/part-properties-dialog.ui");
- oregano_error_with_title (_("Could not create part properties dialog."),
- msg);
- g_free (msg);
- return;
- }
+ } else
+ gtk_builder_set_translation_domain (gui, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/part-properties-dialog.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create part properties dialog."),
- msg);
- g_error_free (perror);
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/part-properties-dialog.ui", &error) <= 0) {
+ msg = error->message;
+ oregano_error_with_title (_ ("Could not create part properties dialog."), msg);
+ g_error_free (error);
return;
}
@@ -661,64 +563,57 @@ edit_properties (SheetItem *object)
prop_dialog->part_item = item;
- prop_dialog->dialog = GTK_DIALOG (gtk_builder_get_object (gui,
- "part-properties-dialog"));
+ prop_dialog->dialog = GTK_DIALOG (gtk_builder_get_object (gui, "part-properties-dialog"));
- prop_table = GTK_TABLE (gtk_builder_get_object (gui, "prop_table"));
- notebook = GTK_NOTEBOOK (gtk_builder_get_object (gui, "notebook"));
+ prop_grid = GTK_GRID (gtk_builder_get_object (gui, "prop_grid"));
+ notebook = GTK_NOTEBOOK (gtk_builder_get_object (gui, "notebook"));
- g_signal_connect (prop_dialog->dialog, "destroy",
- G_CALLBACK (prop_dialog_destroy), prop_dialog);
+ g_signal_connect (prop_dialog->dialog, "destroy", G_CALLBACK (prop_dialog_destroy),
+ prop_dialog);
prop_dialog->widgets = NULL;
has_model = FALSE;
- for (properties = part_get_properties (part); properties;
- properties = properties->next) {
+ for (properties = part_get_properties (part); properties; properties = properties->next) {
Property *prop;
-
+
prop = properties->data;
if (prop->name) {
GtkWidget *entry;
GtkWidget *label;
- gchar *temp=NULL;
-
+ gchar *temp = NULL;
+
if (!g_ascii_strcasecmp (prop->name, "internal"))
continue;
- if (!g_ascii_strcasecmp (prop->name, "model")) {
+ if (!g_ascii_strcasecmp (prop->name, "model")) {
has_model = TRUE;
model_name = g_strdup (prop->value);
}
-
+
// Find the Refdes and replace by their real value
temp = prop->name;
- if (!g_ascii_strcasecmp (temp, "Refdes")) temp = _("Designation");
- if (!g_ascii_strcasecmp (temp, "Template")) temp = _("Template");
- if (!g_ascii_strcasecmp (temp, "Res")) temp = _("Resistor");
- if (!g_ascii_strcasecmp (temp, "Cap")) temp = _("Capacitor");
- if (!g_ascii_strcasecmp (temp, "Ind")) temp = _("Inductor");
+ if (!g_ascii_strcasecmp (temp, "Refdes"))
+ temp = _ ("Designation");
+ if (!g_ascii_strcasecmp (temp, "Template"))
+ temp = _ ("Template");
+ if (!g_ascii_strcasecmp (temp, "Res"))
+ temp = _ ("Resistor");
+ if (!g_ascii_strcasecmp (temp, "Cap"))
+ temp = _ ("Capacitor");
+ if (!g_ascii_strcasecmp (temp, "Ind"))
+ temp = _ ("Inductor");
label = gtk_label_new (temp);
entry = gtk_entry_new ();
- gtk_entry_set_text (GTK_ENTRY (entry), prop->value);
- g_object_set_data (G_OBJECT (entry), "user", g_strdup (prop->name));
-
- gtk_table_attach (
- prop_table, label,
- 0, 1, y, y+1,
- GTK_FILL|GTK_SHRINK,
- GTK_FILL|GTK_SHRINK,
- 8, 8);
-
- gtk_table_attach (
- prop_table, entry,
- 1, 2, y, y+1,
- GTK_EXPAND|GTK_FILL,
- GTK_FILL|GTK_SHRINK,
- 8, 8);
-
+ gtk_entry_set_text (GTK_ENTRY (entry), prop->value);
+ g_object_set_data (G_OBJECT (entry), "user", g_strdup (prop->name));
+
+ gtk_grid_attach (prop_grid, label, 0, y, 1, 1);
+
+ gtk_grid_attach (prop_grid, entry, 1, y, 1, 1);
+
y++;
gtk_widget_show (label);
gtk_widget_show (entry);
@@ -728,9 +623,8 @@ edit_properties (SheetItem *object)
}
if (!has_model) {
- gtk_notebook_remove_page (notebook, 1);
- }
- else {
+ gtk_notebook_remove_page (notebook, 1);
+ } else {
GtkTextBuffer *txtbuffer;
GtkTextView *txtmodel;
gchar *filename, *str;
@@ -743,8 +637,7 @@ edit_properties (SheetItem *object)
if (g_file_get_contents (filename, &str, NULL, &read_error)) {
gtk_text_buffer_set_text (txtbuffer, str, -1);
g_free (str);
- }
- else {
+ } else {
gtk_text_buffer_set_text (txtbuffer, read_error->message, -1);
g_error_free (read_error);
}
@@ -761,290 +654,201 @@ edit_properties (SheetItem *object)
prop_dialog_response (GTK_WIDGET (prop_dialog->dialog), response, prop_dialog);
- g_slist_free_full (properties, g_object_unref);
gtk_widget_destroy (GTK_WIDGET (prop_dialog->dialog));
}
-static void
-part_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
+inline static GooCanvasAnchorType angle_to_anchor (int angle)
{
- cairo_matrix_t affine;
- GSList *label_items;
GooCanvasAnchorType anchor;
- GooCanvasGroup *group;
- GooCanvasItem *canvas_item;
- PartItem *item;
- PartItemPriv *priv;
- Part *part;
- int index = 0;
- int angle_anchor;
-
- g_return_if_fail (sheet_item != NULL);
- g_return_if_fail (IS_PART_ITEM (sheet_item));
-
- item = PART_ITEM (sheet_item);
- group = GOO_CANVAS_GROUP (item);
- part = PART (data);
-
- priv = item->priv;
- if (angle != 0)
- cairo_matrix_init_rotate (&affine, (double) angle * M_PI / 180);
- else
- // angle == 0: Nothing has changed, therefore do nothing
- cairo_matrix_init_identity (&affine);
-
- for (index = 0; index < group->items->len; index++) {
- canvas_item = GOO_CANVAS_ITEM (group->items->pdata[index]);
-
- goo_canvas_item_set_transform (GOO_CANVAS_ITEM (canvas_item),
- NULL);
- goo_canvas_item_set_transform (GOO_CANVAS_ITEM (canvas_item),
- &affine);
- }
-
// Get the right anchor for the labels. This is needed since the
- // canvas don't know how to rotate text and since we rotate the
+ // canvas doesn't know how to rotate text and since we rotate the
// label_group instead of the labels directly.
- angle_anchor = part_get_rotation (part);
- switch (angle_anchor) {
- case 90:
+
+ while (angle < 0)
+ angle += 360;
+ angle %= 360;
+
+ if (90 - 45 < angle && angle < 90 + 45) {
anchor = GOO_CANVAS_ANCHOR_NORTH_WEST;
- break;
- case 180:
+ } else if (180 - 45 < angle && angle < 180 + 45) {
anchor = GOO_CANVAS_ANCHOR_NORTH_EAST;
- break;
- case 270:
+ } else if (270 - 45 < angle && angle < 270 + 45) {
anchor = GOO_CANVAS_ANCHOR_SOUTH_EAST;
- break;
- default:
+ } else /* if (360-45 < angle && angle < 0+45) */ {
anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
- break;
}
- for (label_items = priv->label_items; label_items;
- label_items = label_items->next) {
- gdouble x, y;
- g_object_set (label_items->data,
- "anchor", anchor,
- NULL);
- g_object_get (label_items->data,
- "x", &x,
- "y", &y,
- NULL);
-
- goo_canvas_item_set_transform (label_items->data,
- NULL);
- // A bias (1.0, -2.0) is introduced due to ????
- goo_canvas_item_rotate (label_items->data, -angle, x + 1.0, y - 2.0);
- }
-
- for (label_items = priv->label_nodes; label_items;
- label_items = label_items->next) {
- gdouble x, y;
- g_object_set (label_items->data,
- "anchor", anchor,
- NULL);
- g_object_get (label_items->data,
- "x", &x,
- "y", &y,
- NULL);
-
- goo_canvas_item_set_transform (label_items->data,
- NULL);
- // A bias (1.0, -2.0) is introduced due to ????
- goo_canvas_item_rotate (label_items->data, -angle, x + 1.0, y - 2.0);
- }
-
- // Invalidate the bounding box cache.
- priv->cache_valid = FALSE;
-
- g_slist_free_full (label_items, g_object_unref);
+ return anchor;
}
-static void
-part_flipped_callback (ItemData *data, gboolean horizontal,
- SheetItem *sheet_item)
+/**
+ * whenever the model changes, this one gets called to update the view
+ * representation
+ * @attention this recalculates the matrix every time, this makes sure no errors
+ * stack up
+ * @attention further reading on matrix manipulations
+ * @attention http://www.cairographics.org/matrix_transform/
+ * @param data the model item, a bare C struct derived from ItemData
+ * @param sheet_item the view item, derived from goo_canvas_group/item
+ */
+static void part_changed_callback (ItemData *data, SheetItem *sheet_item)
{
- GSList *label;
- GooCanvasAnchorType anchor;
- GooCanvasItem *canvas_item;
- GooCanvasGroup *group;
- PartItem *item;
- PartItemPriv *priv;
- Part *part;
- int index = 0;
- gdouble scale_h = 1.0, scale_v = 1.0, x, y;
- GooCanvasBounds bounds_before, bounds_after;
-
g_return_if_fail (sheet_item != NULL);
g_return_if_fail (IS_PART_ITEM (sheet_item));
- item = PART_ITEM (sheet_item);
- part = PART (data);
- priv = item->priv;
- group = GOO_CANVAS_GROUP (item);
+ // TODO add static vars in order to skip the redraw if nothing changed
+ // TODO may happen once in a while and the check is really cheap
+ PartItem *item = PART_ITEM (sheet_item);
+ PartItemPriv *priv = item->priv;
- if (horizontal)
- scale_v = -1.0;
- else
- scale_h = -1.0;
-
- // Get the group bounds before the flip
- goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (sheet_item),
- &bounds_before);
-
- for (index = 0; index < group->items->len; index++) {
- canvas_item = GOO_CANVAS_ITEM (group->items->pdata[index]);
- goo_canvas_item_scale (canvas_item, scale_h, scale_v);
+ // init the states
+
+ cairo_matrix_t morph, inv;
+ cairo_status_t done;
+
+ inv = *(item_data_get_rotate (data)); // copy
+ cairo_matrix_multiply (&morph, &inv, item_data_get_translate (data));
+
+ done = cairo_matrix_invert (&inv);
+ if (done != CAIRO_STATUS_SUCCESS) {
+ g_warning ("Failed to invert matrix. This should never happen. Ever!");
+ return;
}
+ // no translations
+ inv.y0 = inv.x0 = 0.;
- // Get the group bounds after the flip
- goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (sheet_item),
- &bounds_after);
-
- // Translation to the flip translation
- x = bounds_after.x1 - bounds_before.x1;
- y = bounds_after.y1 - bounds_before.y1;
- goo_canvas_item_translate (GOO_CANVAS_ITEM (sheet_item), -x, -y);
-
- anchor = part_item_get_anchor_from_part (part);
- switch (anchor) {
- case GOO_CANVAS_ANCHOR_NORTH_WEST:
- anchor = GOO_CANVAS_ANCHOR_SOUTH_EAST;
- break;
- case GOO_CANVAS_ANCHOR_NORTH_EAST:
- anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
- break;
- case GOO_CANVAS_ANCHOR_SOUTH_EAST:
- anchor = GOO_CANVAS_ANCHOR_NORTH_WEST;
- break;
- default:
- anchor = GOO_CANVAS_ANCHOR_NORTH_EAST;
+ goo_canvas_item_set_transform (GOO_CANVAS_ITEM (sheet_item), &(morph));
+
+ priv->cache_valid = FALSE;
+ return; /* FIXME */
+#if 0
+ GooCanvasGroup *group = GOO_CANVAS_GROUP (item);
+
+ // rotate all items in the canvas group
+ for (int index = 0; index < group->items->len; index++) {
+ GooCanvasItem *canvas_item = GOO_CANVAS_ITEM (group->items->pdata[index]);
+ goo_canvas_item_set_transform (GOO_CANVAS_ITEM (canvas_item), &morph);
}
-
- for (label = priv->label_items; label; label = label->next) {
- g_object_set (label->data,
+
+ // revert the rotation of all labels and change their anchor to not overlap too badly
+ // this assures that the text is always horizontal and properly aligned
+ GooCanvasAnchorType anchor = angle_to_anchor (rotation);
+
+ for (GSList *iter = priv->label_items; iter; iter = iter->next) {
+ g_object_set (iter->data,
"anchor", anchor,
NULL);
- g_object_get (label->data,
- "x", &x,
- "y", &y,
- NULL);
-
- goo_canvas_item_scale (label->data, scale_h, scale_v);
- if (horizontal)
- goo_canvas_item_translate (label->data, 0, -2 * y);
- else
- goo_canvas_item_translate (label->data, -2 * x, 0);
- }
- for (label = priv->label_nodes; label; label = label->next) {
- g_object_set (label->data,
- "anchor", anchor,
- NULL);
- g_object_get (label->data,
- "x", &x,
- "y", &y,
+ goo_canvas_item_set_transform (iter->data, &inv);
+
+ }
+ // same for label nodes
+ for (GSList *iter = priv->label_nodes; iter; iter = iter->next) {
+ g_object_set (iter->data,
+ "anchor", anchor,
NULL);
-
- goo_canvas_item_scale (label->data, scale_h, scale_v);
- if (horizontal)
- goo_canvas_item_translate (label->data, 0, -2 * y);
- else
- goo_canvas_item_translate (label->data, -2 * x, 0);
+
+ goo_canvas_item_set_transform (iter->data, &inv);
}
-
+
+
// Invalidate the bounding box cache.
priv->cache_valid = FALSE;
+#endif
+}
- g_slist_free_full (label, g_object_unref);
+/**
+ * a part got rotated
+ *
+ * @angle the angle the item is rotated towards the default (0) rotation
+ *
+ */
+static void part_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
+{
+ // g_warning ("ROTATED callback called - LEGACY\n");
}
-void
-part_item_signal_connect_floating (PartItem *item)
+/**
+ * handles the update of the canvas item when a part gets flipped (within the
+ * backend alias model)
+ * @data the part in form of a ItemData pointer
+ * @direction the new flip state
+ * @sheet_item the corresponding sheet_item to the model item @data
+ */
+static void part_flipped_callback (ItemData *data, IDFlip direction, SheetItem *sheet_item)
+{
+ // g_warning ("FLIPPED callback called - LEGACY\n");
+}
+
+void part_item_signal_connect_floating (PartItem *item)
{
Sheet *sheet;
sheet = sheet_item_get_sheet (SHEET_ITEM (item));
sheet->state = SHEET_STATE_FLOAT_START;
- g_signal_connect (G_OBJECT (item), "double_clicked",
- G_CALLBACK (edit_properties), item);
+ g_signal_connect (G_OBJECT (item), "double_clicked", G_CALLBACK (edit_properties), item);
}
-static void
-selection_changed (PartItem *item, gboolean select, gpointer user_data)
+static void selection_changed (PartItem *item, gboolean select, gpointer user_data)
{
g_object_ref (G_OBJECT (item));
if (select)
- g_idle_add ((gpointer) select_idle_callback, item);
+ g_idle_add ((gpointer)select_idle_callback, item);
else
- g_idle_add ((gpointer) deselect_idle_callback, item);
+ g_idle_add ((gpointer)deselect_idle_callback, item);
}
-static int
-select_idle_callback (PartItem *item)
+static int select_idle_callback (PartItem *item)
{
GooCanvasItem *canvas_item = NULL;
int index;
-
+
g_return_val_if_fail (item != NULL, FALSE);
- for (index = 0; index < GOO_CANVAS_GROUP (item)->items->len; index++) {
+ for (index = 0; index < GOO_CANVAS_GROUP (item)->items->len; index++) {
canvas_item = GOO_CANVAS_ITEM (GOO_CANVAS_GROUP (item)->items->pdata[index]);
- g_object_set (canvas_item,
- "stroke-color", SELECTED_COLOR,
- NULL);
+ g_object_set (canvas_item, "stroke-color", SELECTED_COLOR, NULL);
}
g_object_unref (G_OBJECT (item));
return FALSE;
}
-static int
-deselect_idle_callback (PartItem *item)
+static int deselect_idle_callback (PartItem *item)
{
GooCanvasItem *canvas_item = NULL;
int index;
for (index = 0; index < GOO_CANVAS_GROUP (item)->items->len; index++) {
canvas_item = GOO_CANVAS_ITEM (GOO_CANVAS_GROUP (item)->items->pdata[index]);
-
+
if (GOO_IS_CANVAS_TEXT (canvas_item)) {
- g_object_set (canvas_item,
- "stroke-color", LABEL_COLOR,
- NULL);
- }
- else {
- g_object_set (canvas_item,
- "stroke-color", NORMAL_COLOR,
- NULL);
+ g_object_set (canvas_item, "stroke-color", LABEL_COLOR, NULL);
+ } else {
+ g_object_set (canvas_item, "stroke-color", NORMAL_COLOR, NULL);
}
}
g_object_unref (G_OBJECT (item));
return FALSE;
}
-static gboolean
-is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2)
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2)
{
PartItem *item;
- SheetPos bbox_start, bbox_end;
+ Coords bbox_start, bbox_end;
item = PART_ITEM (object);
get_cached_bounds (item, &bbox_start, &bbox_end);
- if ((p1->x < bbox_start.x) &&
- (p2->x > bbox_end.x) &&
- (p1->y < bbox_start.y) &&
- (p2->y > bbox_end.y)) {
- return TRUE;
+ if ((p1->x < bbox_start.x) && (p2->x > bbox_end.x) && (p1->y < bbox_start.y) &&
+ (p2->y > bbox_end.y)) {
+ return TRUE;
}
return FALSE;
}
-static void
-show_labels (SheetItem *sheet_item, gboolean show)
+static void show_labels (SheetItem *sheet_item, gboolean show)
{
PartItem *item;
PartItemPriv *priv;
@@ -1056,27 +860,25 @@ show_labels (SheetItem *sheet_item, gboolean show)
priv = item->priv;
if (show)
- g_object_set (priv->label_group,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
+ g_object_set (priv->label_group, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
else
- g_object_set (priv->label_group,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+ g_object_set (priv->label_group, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
}
// Retrieves the bounding box. We use a caching scheme for this
// since it's too expensive to calculate it every time we need it.
-inline static void
-get_cached_bounds (PartItem *item, SheetPos *p1, SheetPos *p2)
+inline static void get_cached_bounds (PartItem *item, Coords *p1, Coords *p2)
{
PartItemPriv *priv;
priv = item->priv;
- if (!priv->cache_valid) {
- SheetPos start_pos, end_pos;
+ if (G_LIKELY (priv->cache_valid)) {
+ *p1 = priv->bbox_start;
+ *p2 = priv->bbox_end;
+ } else {
+ Coords start_pos, end_pos;
GooCanvasBounds bounds;
-
+
goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (item), &bounds);
start_pos.x = bounds.x1;
@@ -1084,17 +886,13 @@ get_cached_bounds (PartItem *item, SheetPos *p1, SheetPos *p2)
end_pos.x = bounds.x2;
end_pos.y = bounds.y2;
- priv->bbox_start = start_pos;
- priv->bbox_end = end_pos;
+ *p1 = priv->bbox_start = start_pos;
+ *p2 = priv->bbox_end = end_pos;
priv->cache_valid = TRUE;
}
-
- memcpy (p1, &priv->bbox_start, sizeof (SheetPos));
- memcpy (p2, &priv->bbox_end, sizeof (SheetPos));
}
-static void
-part_item_paste (Sheet *sheet, ItemData *data)
+static void part_item_paste (Sheet *sheet, ItemData *data)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -1104,8 +902,7 @@ part_item_paste (Sheet *sheet, ItemData *data)
sheet_add_ghost_item (sheet, data);
}
-PartItem *
-part_item_new (Sheet *sheet, Part *part)
+PartItem *part_item_new (Sheet *sheet, Part *part)
{
Library *library;
LibraryPart *library_part;
@@ -1117,7 +914,7 @@ part_item_new (Sheet *sheet, Part *part)
library = priv->library;
library_part = library_get_part (library, priv->name);
- // Create the PartItem canvas item.
+ // Create the PartItem canvas item
item = part_item_canvas_new (sheet, part);
create_canvas_items (GOO_CANVAS_GROUP (item), library_part);
create_canvas_labels (item, part);
@@ -1126,9 +923,7 @@ part_item_new (Sheet *sheet, Part *part)
return item;
}
-void
-part_item_create_canvas_items_for_preview (GooCanvasGroup *group,
- LibraryPart *library_part)
+void part_item_create_canvas_items_for_preview (GooCanvasGroup *group, LibraryPart *library_part)
{
g_return_if_fail (group != NULL);
g_return_if_fail (library_part != NULL);
@@ -1136,99 +931,75 @@ part_item_create_canvas_items_for_preview (GooCanvasGroup *group,
create_canvas_items (group, library_part);
}
-static void
-create_canvas_items (GooCanvasGroup *group, LibraryPart *library_part)
+static void create_canvas_items (GooCanvasGroup *group, LibraryPart *library_part)
{
- GooCanvasItem *item;
+ GooCanvasItem *item;
GooCanvasPoints *points;
- GSList *objects;
- LibrarySymbol *symbol;
- SymbolObject *object;
- gdouble height, width;
- GooCanvasBounds bounds, group_bounds = {0,0,0,0};
-
+ GSList *objects;
+ LibrarySymbol *symbol;
+ SymbolObject *object;
+ gdouble height, width;
+ GooCanvasBounds bounds, group_bounds = {0, 0, 0, 0};
g_return_if_fail (group != NULL);
g_return_if_fail (library_part != NULL);
symbol = library_get_symbol (library_part->symbol_name);
- if (symbol == NULL) {
+ if (symbol == NULL) {
g_warning ("Couldn't find the requested symbol %s for part %s in "
"library.\n",
- library_part->symbol_name,
- library_part->name);
+ library_part->symbol_name, library_part->name);
return;
}
for (objects = symbol->symbol_objects; objects; objects = objects->next) {
object = (SymbolObject *)(objects->data);
switch (object->type) {
- case SYMBOL_OBJECT_LINE:
- points = object->u.uline.line;
- item = goo_canvas_polyline_new (GOO_CANVAS_ITEM (group),
- FALSE,
- 0,
- "points", points,
- "stroke-color", NORMAL_COLOR,
- "line-width", 0.5,
- NULL);
- if (object->u.uline.spline) {
- g_object_set (item,
- "smooth", TRUE,
- "spline_steps", 5,
- NULL);
- }
- break;
- case SYMBOL_OBJECT_ARC:
- item = goo_canvas_ellipse_new (GOO_CANVAS_ITEM (group),
- (object->u.arc.x2 + object->u.arc.x1) / 2.0,
- (object->u.arc.y1 + object->u.arc.y2) / 2.0,
- (object->u.arc.x2 - object->u.arc.x1) / 2.0,
- (object->u.arc.y1 - object->u.arc.y2) / 2.0,
- "stroke-color", NORMAL_COLOR,
- "line_width", 1.0,
- NULL);
- break;
- case SYMBOL_OBJECT_TEXT:
- item = goo_canvas_text_new (GOO_CANVAS_ITEM (group),
- object->u.text.str,
- (double) object->u.text.x,
- (double) object->u.text.y,
- -1,
- GOO_CANVAS_ANCHOR_NORTH_EAST,
- "fill_color", LABEL_COLOR,
- "font", "Sans 8",
- NULL);
+ case SYMBOL_OBJECT_LINE:
+ points = object->u.uline.line;
+ item = goo_canvas_polyline_new (GOO_CANVAS_ITEM (group), FALSE, 0, "points", points,
+ "stroke-color", NORMAL_COLOR, "line-width", 0.5, NULL);
+ if (object->u.uline.spline) {
+ g_object_set (item, "smooth", TRUE, "spline_steps", 5, NULL);
+ }
break;
- default:
- g_warning ("Unknown symbol object.\n");
- continue;
+ case SYMBOL_OBJECT_ARC:
+ item = goo_canvas_ellipse_new (GOO_CANVAS_ITEM (group),
+ (object->u.arc.x2 + object->u.arc.x1) / 2.0,
+ (object->u.arc.y1 + object->u.arc.y2) / 2.0,
+ (object->u.arc.x2 - object->u.arc.x1) / 2.0,
+ (object->u.arc.y1 - object->u.arc.y2) / 2.0,
+ "stroke-color", NORMAL_COLOR, "line_width", 1.0, NULL);
+ break;
+ case SYMBOL_OBJECT_TEXT:
+ item = goo_canvas_text_new (GOO_CANVAS_ITEM (group), object->u.text.str,
+ (double)object->u.text.x, (double)object->u.text.y, -1,
+ GOO_CANVAS_ANCHOR_NORTH_EAST, "fill_color", LABEL_COLOR,
+ "font", "Sans 8", NULL);
+ break;
+ default:
+ g_warning ("Unknown symbol object.\n");
+ continue;
}
goo_canvas_item_get_bounds (item, &bounds);
- if (group_bounds.x1 > bounds.x1) group_bounds.x1 = bounds.x1;
- if (group_bounds.x2 < bounds.x2) group_bounds.x2 = bounds.x2;
- if (group_bounds.y1 > bounds.y1) group_bounds.y1 = bounds.y1;
- if (group_bounds.y2 < bounds.y2) group_bounds.y2 = bounds.y2;
-
+ if (group_bounds.x1 > bounds.x1)
+ group_bounds.x1 = bounds.x1;
+ if (group_bounds.x2 < bounds.x2)
+ group_bounds.x2 = bounds.x2;
+ if (group_bounds.y1 > bounds.y1)
+ group_bounds.y1 = bounds.y1;
+ if (group_bounds.y2 < bounds.y2)
+ group_bounds.y2 = bounds.y2;
}
-
- g_object_get (group,
- "width", &width,
- "height", &height,
- NULL);
+
+ g_object_get (group, "width", &width, "height", &height, NULL);
width = group_bounds.x2 - group_bounds.x1;
height = group_bounds.y2 - group_bounds.y1;
-
- g_object_set (group,
- "width", width,
- "height", height,
- NULL);
-
- g_slist_free_full (objects, g_object_unref);
+
+ g_object_set (group, "width", width, "height", height, NULL);
}
-static void
-create_canvas_labels (PartItem *item, Part *part)
+static void create_canvas_labels (PartItem *item, Part *part)
{
GooCanvasItem *canvas_item;
GSList *list, *item_list;
@@ -1248,37 +1019,28 @@ create_canvas_labels (PartItem *item, Part *part)
text = part_property_expand_macros (part, label->text);
- canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (group),
- text,
- (double) label->pos.x,
- (double) label->pos.y,
- 0,
- GOO_CANVAS_ANCHOR_SOUTH_WEST,
- "fill_color", LABEL_COLOR,
- "font", "Sans 8",
- NULL);
+ canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (group), text, (double)label->pos.x,
+ (double)label->pos.y, 0, GOO_CANVAS_ANCHOR_SOUTH_WEST,
+ "fill_color", LABEL_COLOR, "font", "Sans 8", NULL);
item_list = g_slist_prepend (item_list, canvas_item);
g_free (text);
}
- g_slist_free_full (list, g_object_unref);
item_list = g_slist_reverse (item_list);
part_item_set_label_items (item, item_list);
}
-
-static void
-create_canvas_label_nodes (PartItem *item, Part *part)
+static void create_canvas_label_nodes (PartItem *item, Part *part)
{
GooCanvasItem *canvas_item;
GSList *item_list;
GooCanvasItem *group;
Pin *pins;
int num_pins, i;
- SheetPos p1, p2;
+ Coords p1, p2;
GooCanvasAnchorType anchor;
-
+
g_return_if_fail (item != NULL);
g_return_if_fail (IS_PART_ITEM (item));
g_return_if_fail (part != NULL);
@@ -1292,20 +1054,20 @@ create_canvas_label_nodes (PartItem *item, Part *part)
get_cached_bounds (item, &p1, &p2);
switch (part_get_rotation (part)) {
- case 0:
- anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
+ case 0:
+ anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
break;
- case 90:
- anchor = GOO_CANVAS_ANCHOR_NORTH_WEST;
+ case 90:
+ anchor = GOO_CANVAS_ANCHOR_NORTH_WEST;
break;
- case 180:
- anchor = GOO_CANVAS_ANCHOR_NORTH_EAST;
+ case 180:
+ anchor = GOO_CANVAS_ANCHOR_NORTH_EAST;
break;
- case 270:
- anchor = GOO_CANVAS_ANCHOR_SOUTH_EAST;
+ case 270:
+ anchor = GOO_CANVAS_ANCHOR_SOUTH_EAST;
break;
- default:
- anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
+ default:
+ anchor = GOO_CANVAS_ANCHOR_SOUTH_WEST;
}
for (i = 0; i < num_pins; i++) {
@@ -1315,17 +1077,11 @@ create_canvas_label_nodes (PartItem *item, Part *part)
y = pins[i].offset.y;
text = g_strdup_printf ("%d", pins[i].node_nr);
- canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (group),
- text,
- (double) x,
- (double) y,
- 0,
- anchor,
- "fill_color", "black",
- "font", "Sans 8",
- NULL);
+ canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (group), text, (double)x, (double)y, 0,
+ anchor, "fill_color", "black", "font", "Sans 8", NULL);
// Shift slightly the label for a Voltmeter
- if (i == 0) goo_canvas_item_translate (canvas_item, -15.0, -10.0);
+ if (i == 0)
+ goo_canvas_item_translate (canvas_item, -15.0, -10.0);
item_list = g_slist_prepend (item_list, canvas_item);
g_free (text);
@@ -1334,79 +1090,41 @@ create_canvas_label_nodes (PartItem *item, Part *part)
item->priv->label_nodes = item_list;
}
-
// This is called when the part data was moved. Update the view accordingly.
-static void
-part_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
+static void part_moved_callback (ItemData *data, Coords *pos, SheetItem *item) {}
+
+static void part_item_place (SheetItem *item, Sheet *sheet)
{
- PartItem *part_item;
-
- g_return_if_fail (data != NULL);
- g_return_if_fail (IS_ITEM_DATA (data));
- g_return_if_fail (item != NULL);
- g_return_if_fail (IS_PART_ITEM (item));
+ g_signal_connect (G_OBJECT (item), "button_press_event", G_CALLBACK (sheet_item_event), sheet);
- if (pos == NULL)
- return;
+ g_signal_connect (G_OBJECT (item), "button_release_event", G_CALLBACK (sheet_item_event),
+ sheet);
- part_item = PART_ITEM (item);
-
- // Move the canvas item and invalidate the bbox cache.
- goo_canvas_item_set_transform (GOO_CANVAS_ITEM (item),
- NULL);
- goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (item),
- pos->x,
- pos->y,
- 1.0,
- 0.0);
-
- part_item->priv->cache_valid = FALSE;
-}
+ g_signal_connect (G_OBJECT (item), "motion_notify_event", G_CALLBACK (sheet_item_event), sheet);
-static void
-part_item_place (SheetItem *item, Sheet *sheet)
-{
- g_signal_connect (G_OBJECT (item), "button_press_event",
- G_CALLBACK (sheet_item_event), sheet);
-
- g_signal_connect (G_OBJECT (item), "button_release_event",
- G_CALLBACK (sheet_item_event), sheet);
-
- g_signal_connect (G_OBJECT (item), "motion_notify_event",
- G_CALLBACK (sheet_item_event), sheet);
-
- g_signal_connect (G_OBJECT (item), "key_press_event",
- G_CALLBACK (sheet_item_event), sheet);
-
- g_signal_connect (G_OBJECT (item), "double_clicked",
- G_CALLBACK (edit_properties), item);
+ g_signal_connect (G_OBJECT (item), "key_press_event", G_CALLBACK (sheet_item_event), sheet);
+
+ g_signal_connect (G_OBJECT (item), "double_clicked", G_CALLBACK (edit_properties), item);
}
-static void
-part_item_place_ghost (SheetItem *item, Sheet *sheet)
+static void part_item_place_ghost (SheetItem *item, Sheet *sheet)
{
-// part_item_signal_connect_placed (PART_ITEM (item));
+ // part_item_signal_connect_placed (PART_ITEM (item));
}
-void
-part_item_show_node_labels (PartItem *part, gboolean show)
+void part_item_show_node_labels (PartItem *part, gboolean show)
{
PartItemPriv *priv;
priv = part->priv;
if (show)
- g_object_set (priv->node_group,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
+ g_object_set (priv->node_group, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
else
- g_object_set (priv->node_group,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+ g_object_set (priv->node_group, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
}
-static GooCanvasAnchorType
-part_item_get_anchor_from_part (Part *part)
+static GooCanvasAnchorType part_item_get_anchor_from_part (Part *part)
{
int anchor_h, anchor_v;
int angle;
@@ -1416,19 +1134,19 @@ part_item_get_anchor_from_part (Part *part)
angle = part_get_rotation (part);
switch (angle) {
- case 0:
- anchor_h = ANCHOR_SOUTH;
- anchor_v = ANCHOR_WEST;
- break;
- case 90:
- anchor_h = ANCHOR_NORTH;
- anchor_v = ANCHOR_WEST;
- // Invert Rotation
- if (flip & ID_FLIP_HORIZ)
- flip = ID_FLIP_VERT;
- else if (flip & ID_FLIP_VERT)
- flip = ID_FLIP_HORIZ;
- break;
+ case 0:
+ anchor_h = ANCHOR_SOUTH;
+ anchor_v = ANCHOR_WEST;
+ break;
+ case 90:
+ anchor_h = ANCHOR_NORTH;
+ anchor_v = ANCHOR_WEST;
+ // Invert Rotation
+ if (flip & ID_FLIP_HORIZ)
+ flip = ID_FLIP_VERT;
+ else if (flip & ID_FLIP_VERT)
+ flip = ID_FLIP_HORIZ;
+ break;
}
if (flip & ID_FLIP_HORIZ) {
diff --git a/src/sheet/part-item.h b/src/sheet/part-item.h
index cf835ac..ddb471e 100644
--- a/src/sheet/part-item.h
+++ b/src/sheet/part-item.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __PART_ITEM_H
@@ -42,26 +44,27 @@ typedef struct _PartItemPriv PartItemPriv;
#include "load-common.h"
#include "part.h"
-#define TYPE_PART_ITEM (part_item_get_type ())
-#define PART_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PART_ITEM, PartItem))
+#define TYPE_PART_ITEM (part_item_get_type ())
+#define PART_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PART_ITEM, PartItem))
#define PART_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PART_ITEM, PartItemClass))
-#define IS_PART_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PART_ITEM))
+#define IS_PART_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PART_ITEM))
#define PART_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_PART_ITEM, PartItemClass))
-struct _PartItem {
- SheetItem parent_object;
+struct _PartItem
+{
+ SheetItem parent_object;
PartItemPriv *priv;
};
-struct _PartItemClass {
+struct _PartItemClass
+{
SheetItemClass parent_class;
};
-GType part_item_get_type (void);
+GType part_item_get_type (void);
PartItem *part_item_new (Sheet *sheet, Part *part);
-void part_item_create_canvas_items_for_preview (GooCanvasGroup *group,
- LibraryPart *library_part);
-void part_item_update_node_label (PartItem *part);
-void part_item_show_node_labels (PartItem *part, gboolean b);
+void part_item_create_canvas_items_for_preview (GooCanvasGroup *group, LibraryPart *library_part);
+void part_item_update_node_label (PartItem *part);
+void part_item_show_node_labels (PartItem *part, gboolean b);
#endif
diff --git a/src/sheet/plot-add-function.c b/src/sheet/plot-add-function.c
index 4f8d43d..853aa7c 100644
--- a/src/sheet/plot-add-function.c
+++ b/src/sheet/plot-add-function.c
@@ -3,15 +3,17 @@
*
*
* Authors:
- * Ricardo Markiewicz <rmarkie@fi.uba.ar>
- * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
- * Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -25,8 +27,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
@@ -34,42 +36,29 @@
#include "plot-add-function.h"
#include "dialogs.h"
+#include "simulation.h"
-void
-plot_add_function_show (OreganoEngine *engine, SimulationData *current)
+void plot_add_function_show (OreganoEngine *engine, SimulationData *current)
{
GtkBuilder *gui;
GError *perror = NULL;
GtkDialog *dialog;
- gchar *msg;
GtkComboBoxText *op1, *op2, *functiontype;
int i;
gint result = 0;
GtkWidget *warning;
GtkWidget *container_temp;
-
+
SimulationFunction *func = g_new0 (SimulationFunction, 1);
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create plot window."));
- return;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/plot-add-function.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall Oregano to fix this"),
- OREGANO_UIDIR "/plot-add-function.ui");
- oregano_error_with_title (_("Could not create plot window."), msg);
- g_free (msg);
+ oregano_error (_ ("Could not create plot window."));
return;
}
+ gtk_builder_set_translation_domain (gui, NULL);
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/plot-add-function.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create plot window."), msg);
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/plot-add-function.ui", &perror) <= 0) {
+ oregano_error_with_title (_ ("Could not create plot window."), perror->message);
g_error_free (perror);
return;
}
@@ -79,7 +68,7 @@ plot_add_function_show (OreganoEngine *engine, SimulationData *current)
op1 = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new ());
gtk_container_add (GTK_CONTAINER (container_temp), GTK_WIDGET (op1));
gtk_widget_show (GTK_WIDGET (op1));
-
+
container_temp = GTK_WIDGET (gtk_builder_get_object (gui, "op2_alignment"));
op2 = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new ());
gtk_container_add (GTK_CONTAINER (container_temp), GTK_WIDGET (op2));
@@ -90,41 +79,39 @@ plot_add_function_show (OreganoEngine *engine, SimulationData *current)
gtk_container_add (GTK_CONTAINER (container_temp), GTK_WIDGET (functiontype));
gtk_widget_show (GTK_WIDGET (functiontype));
- gtk_combo_box_text_append_text (functiontype, _("Substraction"));
- gtk_combo_box_text_append_text (functiontype, _("Division"));
+ for (const gchar **ptr = SimulationFunctionTypeString; *ptr != NULL; ptr++) {
+ gtk_combo_box_text_append_text(functiontype, *ptr);
+ }
for (i = 1; i < current->n_variables; i++) {
- if (current->type != DC_TRANSFER) {
+ if (current->type != ANALYSIS_TYPE_DC_TRANSFER) {
if (strchr (current->var_names[i], '#') == NULL) {
gtk_combo_box_text_append_text (op1, current->var_names[i]);
gtk_combo_box_text_append_text (op2, current->var_names[i]);
}
- }
- else {
+ } else {
gtk_combo_box_text_append_text (op1, current->var_names[i]);
gtk_combo_box_text_append_text (op2, current->var_names[i]);
}
}
- gtk_combo_box_set_active (GTK_COMBO_BOX (op1),0);
- gtk_combo_box_set_active (GTK_COMBO_BOX (op2),1);
- gtk_combo_box_set_active (GTK_COMBO_BOX (functiontype),0);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (op1), 0);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (op2), 1);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (functiontype), 0);
result = gtk_dialog_run (GTK_DIALOG (dialog));
-
+
if ((result == GTK_RESPONSE_OK) &&
((gtk_combo_box_get_active (GTK_COMBO_BOX (op1)) == -1) ||
- (gtk_combo_box_get_active (GTK_COMBO_BOX (op2)) == -1) ||
- (gtk_combo_box_get_active (GTK_COMBO_BOX (functiontype)) == -1)))
- {
+ (gtk_combo_box_get_active (GTK_COMBO_BOX (op2)) == -1) ||
+ (gtk_combo_box_get_active (GTK_COMBO_BOX (functiontype)) == -1))) {
warning = gtk_message_dialog_new_with_markup (
- NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- _("<span weight=\"bold\" size=\"large\">Neither function, nor operators have been chosen</span>\n\n"
- "Please, take care to choose a function and their associated operators"));
-
- if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_OK) {
+ NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+ _ ("<span weight=\"bold\" size=\"large\">Neither function, nor "
+ "operators have been chosen</span>\n\n"
+ "Please, take care to choose a function and their associated "
+ "operators"));
+
+ if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_OK) {
gtk_widget_destroy (GTK_WIDGET (warning));
plot_add_function_show (engine, current);
gtk_widget_destroy (GTK_WIDGET (dialog));
@@ -132,17 +119,19 @@ plot_add_function_show (OreganoEngine *engine, SimulationData *current)
}
}
- if ((result == GTK_RESPONSE_OK) &&
- ((gtk_combo_box_get_active (GTK_COMBO_BOX (op1)) != -1) &&
- (gtk_combo_box_get_active (GTK_COMBO_BOX (op2)) != -1) &&
- (gtk_combo_box_get_active (GTK_COMBO_BOX (functiontype)) != -1))) {
-
+ if ((result == GTK_RESPONSE_OK) &&
+ ((gtk_combo_box_get_active (GTK_COMBO_BOX (op1)) != -1) &&
+ (gtk_combo_box_get_active (GTK_COMBO_BOX (op2)) != -1) &&
+ (gtk_combo_box_get_active (GTK_COMBO_BOX (functiontype)) != -1))) {
+
+ func->type = gtk_combo_box_get_active (GTK_COMBO_BOX (functiontype));
+
for (i = 1; i < current->n_variables; i++) {
if (g_strcmp0 (current->var_names[i], gtk_combo_box_text_get_active_text (op1)) == 0)
func->first = i;
if (g_strcmp0 (current->var_names[i], gtk_combo_box_text_get_active_text (op2)) == 0)
func->second = i;
- }
+ }
current->functions = g_list_append (current->functions, func);
}
diff --git a/src/sheet/plot-add-function.h b/src/sheet/plot-add-function.h
index 35cac1a..1d0961b 100644
--- a/src/sheet/plot-add-function.h
+++ b/src/sheet/plot-add-function.h
@@ -7,7 +7,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
@@ -24,16 +24,17 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-#ifndef __PLOT_ADD__H
+#ifndef __PLOT_ADD_H
#define __PLOT_ADD_H
#include "simulation.h"
#include "engine.h"
void plot_add_function_show (OreganoEngine *engine, SimulationData *current);
+extern const char *SimulationFunctionTypeString[];
#endif
diff --git a/src/sheet/rubberband.c b/src/sheet/rubberband.c
new file mode 100644
index 0000000..6332dfa
--- /dev/null
+++ b/src/sheet/rubberband.c
@@ -0,0 +1,255 @@
+/*
+ * rubberband.c
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
+ *
+ * Description: Handles the user interaction when doing area/rubberband
+ *selections.
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <math.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include "rubberband.h"
+#include "sheet-private.h"
+
+#include "debug.h"
+
+inline static cairo_pattern_t *create_stipple (const char *color_name, guchar stipple_data[])
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ GdkRGBA color;
+ int stride;
+ const int width = 8;
+ const int height = 8;
+
+ gdk_rgba_parse (&color, color_name);
+ /* stipple_data[2] = stipple_data[14] = color.red >> 8;
+ stipple_data[1] = stipple_data[13] = color.green >> 8;
+ stipple_data[0] = stipple_data[12] = color.blue >> 8;
+ */
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
+ g_assert (stride > 0);
+ NG_DEBUG ("stride = %i", stride);
+ surface = cairo_image_surface_create_for_data (stipple_data, CAIRO_FORMAT_ARGB32, width, height,
+ stride);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+ return pattern;
+}
+
+#define COLOR_A 0x3093BA52
+#define COLOR_B 0x30FFFFFF
+#define PREMULTIPLY(argb) \
+ ((argb & 0xFF << 24) | \
+ ((((argb & 0xFF << 16) >> 16) * ((argb & 0xFF << 24) >> 24) / 0xFF) << 16) | \
+ ((((argb & 0xFF << 8) >> 8) * ((argb & 0xFF << 24) >> 24) / 0xFF) << 8) | \
+ ((((argb & 0xFF << 0) >> 0) * ((argb & 0xFF << 24) >> 24) / 0xFF) << 0))
+#define COLOR_A_PRE PREMULTIPLY (COLOR_A)
+#define COLOR_B_PRE PREMULTIPLY (COLOR_B)
+
+RubberbandInfo *rubberband_info_new (Sheet *sheet)
+{
+ RubberbandInfo *rubberband_info;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ NG_DEBUG ("0x%x A", COLOR_A);
+ NG_DEBUG ("0x%x B", COLOR_B);
+ NG_DEBUG ("0x%x A PRE", COLOR_A_PRE);
+ NG_DEBUG ("0x%x B PRE", COLOR_B_PRE);
+ static guint32 stipple_data[8 * 8] = {
+ COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE,
+ COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE,
+ COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE,
+ COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE,
+ COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE,
+
+ COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE,
+ COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE,
+ COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE,
+ COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE, COLOR_A_PRE,
+ COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE, COLOR_B_PRE};
+
+ /* the stipple patten should look like that
+ * 1 1 1 0 0 0 0 1
+ * 1 1 0 0 0 0 1 1
+ * 1 0 0 0 0 1 1 1
+ * 0 0 0 0 1 1 1 1
+ *
+ * 0 0 0 1 1 1 1 0
+ * 0 0 1 1 1 1 0 0
+ * 0 1 1 1 1 0 0 0
+ * 1 1 1 1 0 0 0 0
+ */
+ rubberband_info = g_new (RubberbandInfo, 1);
+ rubberband_info->state = RUBBERBAND_START;
+
+ pattern = create_stipple ("lightgrey", (guchar *)stipple_data);
+
+ // scale 5x, see
+ // http://cairographics.org/manual/cairo-cairo-pattern-t.html#cairo-pattern-t
+ cairo_matrix_init_scale (&matrix, 1.0, 1.0);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ rubberband_info->rectangle = GOO_CANVAS_RECT (goo_canvas_rect_new (
+ GOO_CANVAS_ITEM (sheet->object_group), 10.0, 10.0, 10.0, 10.0, "stroke-color", "black",
+ "line-width", 0.2, "fill-pattern", pattern, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL));
+ cairo_pattern_destroy (pattern);
+ return rubberband_info;
+}
+
+void rubberband_info_destroy (RubberbandInfo *rubberband_info)
+{
+ g_return_if_fail (rubberband_info != NULL);
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (rubberband_info->rectangle));
+ g_free (rubberband_info);
+}
+
+gboolean rubberband_start (Sheet *sheet, GdkEvent *event)
+{
+ GList *list;
+ double x, y;
+ RubberbandInfo *rubberband_info;
+
+ g_assert (event->type == GDK_BUTTON_PRESS);
+ x = event->button.x;
+ y = event->button.y;
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &x, &y);
+
+ rubberband_info = sheet->priv->rubberband_info;
+ rubberband_info->start.x = x;
+ rubberband_info->start.y = y;
+ rubberband_info->end.x = x;
+ rubberband_info->end.y = y;
+ rubberband_info->state = RUBBERBAND_ACTIVE;
+
+ // FIXME TODO recheck
+ g_assert (rubberband_info->rectangle != NULL);
+ g_object_set (rubberband_info->rectangle, "x", x, "y", y, "width", 0., "height", 0.,
+ "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
+#if 1
+ // Mark all the selected objects to preserve their selected state
+ // if SHIFT is pressed while rubberbanding.
+ if (event->button.state & GDK_SHIFT_MASK) {
+ for (list = sheet->priv->selected_objects; list; list = list->next)
+ sheet_item_set_preserve_selection (SHEET_ITEM (list->data), TRUE);
+
+ sheet->priv->preserve_selection_items = g_list_copy (sheet->priv->selected_objects);
+ }
+#endif
+
+ sheet_pointer_grab (sheet, event);
+ return TRUE;
+}
+
+gboolean rubberband_update (Sheet *sheet, GdkEvent *event)
+{
+ GList *iter;
+ Coords cur, cmin, cmax;
+ double dx, dy; // TODO maybe keep track of subpixel changes, make em
+ // global/part of the rubberband_info struct and reset on
+ // finish
+ double width, height, width_ng, height_ng;
+ RubberbandInfo *rubberband_info;
+
+ rubberband_info = sheet->priv->rubberband_info;
+
+ g_assert (event->type == GDK_MOTION_NOTIFY);
+ cur.x = event->motion.x;
+ cur.y = event->motion.y;
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &cur.x, &cur.y);
+
+ width = fabs (rubberband_info->end.x - rubberband_info->start.x);
+ height = fabs (rubberband_info->end.y - rubberband_info->start.y);
+
+ width_ng = fabs (cur.x - rubberband_info->start.x);
+ height_ng = fabs (cur.y - rubberband_info->start.y);
+
+ dx = fabs (width_ng - width);
+ dy = fabs (height_ng - height);
+ NG_DEBUG ("motion :: dx=%lf, dy=%lf :: x=%lf, y=%lf :: w_ng=%lf, h_ng=%lf", dx, dy, cur.x,
+ cur.y, width_ng, height_ng);
+
+ // TODO FIXME scroll window if needed (use
+ // http://developer.gnome.org/goocanvas/stable/GooCanvas.html#goo-canvas-scroll-to)
+
+ if (dx > 0.1 || dy > 0.1) { // a 0.1 change in pixel coords would be the least
+ // visible, silently ignore everything else
+ rubberband_info->end.x = cur.x;
+ rubberband_info->end.y = cur.y;
+ cmin.x = MIN (rubberband_info->start.x, rubberband_info->end.x);
+ cmin.y = MIN (rubberband_info->start.y, rubberband_info->end.y);
+ cmax.x = cmin.x + width_ng;
+ cmax.y = cmin.y + height_ng;
+#if 1
+ for (iter = sheet->priv->items; iter; iter = iter->next) {
+ sheet_item_select_in_area (iter->data, &cmin, &cmax);
+ }
+#endif
+
+ g_object_set (GOO_CANVAS_ITEM (rubberband_info->rectangle), "x", cmin.x, "y", cmin.y,
+ "width", width_ng, "height", height_ng, "visibility", GOO_CANVAS_ITEM_VISIBLE,
+ NULL);
+ goo_canvas_item_raise (GOO_CANVAS_ITEM (rubberband_info->rectangle), NULL);
+ }
+ return TRUE;
+}
+
+gboolean rubberband_finish (Sheet *sheet, GdkEvent *event)
+{
+ RubberbandInfo *rubberband_info;
+
+ rubberband_info = sheet->priv->rubberband_info;
+#if 1
+ GList *iter = NULL;
+ if (sheet->priv->preserve_selection_items) {
+ for (iter = sheet->priv->preserve_selection_items; iter; iter = iter->next)
+ sheet_item_set_preserve_selection (SHEET_ITEM (iter->data), FALSE);
+
+ g_list_free (sheet->priv->preserve_selection_items);
+ sheet->priv->preserve_selection_items = NULL;
+ }
+#endif
+
+ sheet_pointer_ungrab (sheet, event);
+
+ g_object_set (rubberband_info->rectangle, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+
+ rubberband_info->state = RUBBERBAND_START;
+ return TRUE;
+}
diff --git a/src/sheet/rubberband.h b/src/sheet/rubberband.h
new file mode 100644
index 0000000..dc9b165
--- /dev/null
+++ b/src/sheet/rubberband.h
@@ -0,0 +1,66 @@
+/*
+ * rubberband.h
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Description: Handles the user interaction when doing area/rubberband
+ *selections.
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __INPUT_CONTEXT_RUBBERBAND_H
+#define __INPUT_CONTEXT_RUBBERBAND_H
+
+#include <goocanvas.h>
+#include <glib.h>
+
+#include "coords.h"
+
+typedef enum { RUBBERBAND_DISABLED, RUBBERBAND_START, RUBBERBAND_ACTIVE } RubberbandState;
+
+typedef struct _RubberbandInfo RubberbandInfo;
+
+#include "sheet.h"
+
+struct _RubberbandInfo
+{
+ RubberbandState state;
+ Coords start;
+ Coords end;
+ GooCanvasRect *rectangle;
+};
+
+RubberbandInfo *rubberband_info_new (Sheet *sheet);
+void rubberband_info_destroy (RubberbandInfo *rubberband);
+gboolean rubberband_start (Sheet *sheet, GdkEvent *event);
+gboolean rubberband_update (Sheet *sheet, GdkEvent *event);
+gboolean rubberband_finish (Sheet *sheet, GdkEvent *event);
+
+#endif /* __INPUT_CONTEXT_RUBBERBAND_H */
diff --git a/src/sheet/sheet-item-factory.c b/src/sheet/sheet-item-factory.c
index 9a0041f..4d48e8f 100644
--- a/src/sheet/sheet-item-factory.c
+++ b/src/sheet/sheet-item-factory.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "sheet-item-factory.h"
@@ -35,13 +35,12 @@
#include "part-item.h"
#include "textbox-item.h"
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
// Create a SheetItem from an ItemData object. This is a bit ugly.
// It could be beautified by having a method that creates the item.
// E.g. sheet_item->new_from_data (data);
-SheetItem *
-sheet_item_factory_create_sheet_item (Sheet *sheet, ItemData *data)
+SheetItem *sheet_item_factory_create_sheet_item (Sheet *sheet, ItemData *data)
{
SheetItem *item;
@@ -54,19 +53,17 @@ sheet_item_factory_create_sheet_item (Sheet *sheet, ItemData *data)
// Pick the right model.
if (IS_PART (data)) {
- NG_DEBUG ("sheet_item_factory_create_sheet_item part\n\n");
item = SHEET_ITEM (part_item_new (sheet, PART (data)));
- }
- else if (IS_WIRE (data)) {
- NG_DEBUG ("sheet_item_factory_create_sheet_item wire\n\n");
+ NG_DEBUG ("part %p", item);
+ } else if (IS_WIRE (data)) {
item = SHEET_ITEM (wire_item_new (sheet, WIRE (data)));
- }
- else if (IS_TEXTBOX (data)) {
- NG_DEBUG ("sheet_item_factory_create_sheet_item text\n\n");
+ NG_DEBUG ("wire %p", item);
+ } else if (IS_TEXTBOX (data)) {
item = SHEET_ITEM (textbox_item_new (sheet, TEXTBOX (data)));
- }
- else
+ NG_DEBUG ("text %p", item);
+ } else {
g_warning ("Unknown Item type.");
+ }
return item;
}
diff --git a/src/sheet/sheet-item-factory.h b/src/sheet/sheet-item-factory.h
index 12579d9..9ba3990 100644
--- a/src/sheet/sheet-item-factory.h
+++ b/src/sheet/sheet-item-factory.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SHEET_ITEM_FACTORY_H
@@ -35,7 +35,6 @@
#include "sheet-item.h"
-SheetItem *sheet_item_factory_create_sheet_item (Sheet *sheet,
- ItemData *data);
+SheetItem *sheet_item_factory_create_sheet_item (Sheet *sheet, ItemData *data);
#endif /* __SHEET_ITEM_FACTORY_H */
diff --git a/src/sheet/sheet-item.c b/src/sheet/sheet-item.c
index f0c4a12..c61a056 100644
--- a/src/sheet/sheet-item.c
+++ b/src/sheet/sheet-item.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,10 +30,13 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
+// FIXME
+#define FIXME_INCREMENTAL_MOVMENT_DOES_NOT_WORK 1
+
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
@@ -39,29 +46,29 @@
#include "sheet-private.h"
#include "sheet-item.h"
#include "stock.h"
-#include "config.h"
#include "clipboard.h"
+#include "options.h"
-static void sheet_item_class_init (SheetItemClass * klass);
+static void sheet_item_class_init (SheetItemClass *klass);
static void sheet_item_init (SheetItem *item);
-static void sheet_item_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-static void sheet_item_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *spec);
+static void sheet_item_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void sheet_item_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec);
static void sheet_item_finalize (GObject *object);
-static void sheet_item_run_menu (SheetItem *item, Sheet *sheet,
- GdkEventButton *event);
+static void sheet_item_run_menu (SheetItem *item, Sheet *sheet, GdkEventButton *event);
static void sheet_item_reparent (SheetItem *item, GooCanvasGroup *group);
static void sheet_item_dispose (GObject *object);
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
-struct _SheetItemPriv {
- guint selected : 1;
- guint preserve_selection : 1;
- ItemData * data;
- GtkActionGroup * action_group;
- GtkUIManager * ui_manager;
+struct _SheetItemPriv
+{
+ guint selected : 1;
+ guint preserve_selection : 1;
+ ItemData *data;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
};
enum {
@@ -77,56 +84,44 @@ enum {
ARG_ACTION_GROUP
};
-enum {
- MOVED,
- PLACED,
- SELECTION_CHANGED,
- MOUSE_OVER,
- DOUBLE_CLICKED,
- LAST_SIGNAL
-};
+enum { MOVED, PLACED, SELECTION_CHANGED, MOUSE_OVER, DOUBLE_CLICKED, LAST_SIGNAL };
-static guint so_signals[LAST_SIGNAL] = { 0 };
+static guint so_signals[LAST_SIGNAL] = {0};
// This is the upper part of the object popup menu. It contains actions
// that are the same for all objects, e.g. parts and wires.
-static const char *sheet_item_context_menu =
-"<ui>"
-" <popup name='ItemMenu'>"
-" <menuitem action='Copy'/>"
-" <menuitem action='Cut'/>"
-" <menuitem action='Delete'/>"
-" <separator/>"
-" <menuitem action='Rotate'/>"
-" <menuitem action='FlipH'/>"
-" <menuitem action='FlipV'/>"
-" <separator/>"
-" </popup>"
-"</ui>";
+static const char *sheet_item_context_menu = "<ui>"
+ " <popup name='ItemMenu'>"
+ " <menuitem action='Copy'/>"
+ " <menuitem action='Cut'/>"
+ " <menuitem action='Delete'/>"
+ " <separator/>"
+ " <menuitem action='Rotate'/>"
+ " <menuitem action='FlipH'/>"
+ " <menuitem action='FlipV'/>"
+ " <separator/>"
+ " </popup>"
+ "</ui>";
static GtkActionEntry action_entries[] = {
- {"Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C", NULL, NULL},
- {"Cut", GTK_STOCK_CUT, N_("C_ut"), "<control>X", NULL, NULL},
- {"Delete", GTK_STOCK_DELETE, N_("_Delete"), "<control>D",
- N_("Delete the selection"), NULL},
- {"Rotate", STOCK_PIXMAP_ROTATE, N_("_Rotate"), "<control>R",
- N_("Rotate the selection clockwise"), NULL},
- {"FlipH", NULL, N_("Flip _horizontally"), "<control>F",
- N_("Flip the selection horizontally"), NULL},
- {"FlipV", NULL, N_("Flip _vertically"), "<control><shift>F",
- N_("Flip the selection vertically"), NULL}
-};
+ {"Copy", GTK_STOCK_COPY, N_ ("_Copy"), "<control>C", NULL, NULL},
+ {"Cut", GTK_STOCK_CUT, N_ ("C_ut"), "<control>X", NULL, NULL},
+ {"Delete", GTK_STOCK_DELETE, N_ ("_Delete"), "<control>D", N_ ("Delete the selection"), NULL},
+ {"Rotate", STOCK_PIXMAP_ROTATE, N_ ("_Rotate"), "<control>R",
+ N_ ("Rotate the selection clockwise"), NULL},
+ {"FlipH", NULL, N_ ("Flip _horizontally"), "<control>F", N_ ("Flip the selection horizontally"),
+ NULL},
+ {"FlipV", NULL, N_ ("Flip _vertically"), "<control><shift>F",
+ N_ ("Flip the selection vertically"), NULL}};
G_DEFINE_TYPE (SheetItem, sheet_item, GOO_TYPE_CANVAS_GROUP)
-static void
-sheet_item_dispose (GObject *object)
+static void sheet_item_dispose (GObject *object)
{
G_OBJECT_CLASS (sheet_item_parent_class)->dispose (object);
}
-static void
-sheet_item_class_init (SheetItemClass *sheet_item_class)
+static void sheet_item_class_init (SheetItemClass *sheet_item_class)
{
GObjectClass *object_class;
@@ -135,26 +130,27 @@ sheet_item_class_init (SheetItemClass *sheet_item_class)
object_class->dispose = sheet_item_dispose;
object_class->set_property = sheet_item_set_property;
object_class->get_property = sheet_item_get_property;
-
+
sheet_item_parent_class = g_type_class_peek_parent (sheet_item_class);
-
+
// Override from GooCanvasGroup
- g_object_class_override_property (object_class, ARG_X, "x");
- g_object_class_override_property (object_class, ARG_Y, "y");
- g_object_class_override_property (object_class, ARG_WIDTH, "width");
- g_object_class_override_property (object_class, ARG_HEIGHT, "height");
-
- g_object_class_install_property (object_class, ARG_DATA,
- g_param_spec_pointer ("data", "SheetItem::data", "the data",
- G_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, ARG_SHEET,
- g_param_spec_pointer ("sheet", "SheetItem::sheet", "the sheet",
- G_PARAM_READABLE));
-
+ g_object_class_override_property (object_class, ARG_X, "x");
+ g_object_class_override_property (object_class, ARG_Y, "y");
+ g_object_class_override_property (object_class, ARG_WIDTH, "width");
+ g_object_class_override_property (object_class, ARG_HEIGHT, "height");
+
+ g_object_class_install_property (
+ object_class, ARG_DATA,
+ g_param_spec_pointer ("data", "SheetItem::data", "the data", G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class, ARG_SHEET,
+ g_param_spec_pointer ("sheet", "SheetItem::sheet", "the sheet", G_PARAM_READABLE));
+
g_object_class_install_property (object_class, ARG_ACTION_GROUP,
- g_param_spec_pointer ("action_group", "SheetItem::action_group",
- "action group", G_PARAM_READWRITE) );
+ g_param_spec_pointer ("action_group",
+ "SheetItem::action_group",
+ "action group", G_PARAM_READWRITE));
sheet_item_class->is_in_area = NULL;
sheet_item_class->show_labels = NULL;
@@ -164,54 +160,30 @@ sheet_item_class_init (SheetItemClass *sheet_item_class)
sheet_item_class->selection_changed = NULL;
sheet_item_class->mouse_over = NULL;
- so_signals[PLACED] = g_signal_new ("placed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- so_signals[MOVED] = g_signal_new ("moved",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetItemClass, moved),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- so_signals[SELECTION_CHANGED] = g_signal_new ("selection_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetItemClass, selection_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- so_signals[MOUSE_OVER] = g_signal_new ("mouse_over",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetItemClass, mouse_over),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- so_signals[DOUBLE_CLICKED] = g_signal_new ("double_clicked",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ so_signals[PLACED] =
+ g_signal_new ("placed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ so_signals[MOVED] = g_signal_new ("moved", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetItemClass, moved), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ so_signals[SELECTION_CHANGED] =
+ g_signal_new ("selection_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetItemClass, selection_changed), NULL, NULL,
+ g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+
+ so_signals[MOUSE_OVER] =
+ g_signal_new ("mouse_over", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetItemClass, mouse_over), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ so_signals[DOUBLE_CLICKED] =
+ g_signal_new ("double_clicked", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
-static void
-sheet_item_init (SheetItem *item)
+static void sheet_item_init (SheetItem *item)
{
GError *error = NULL;
@@ -224,149 +196,136 @@ sheet_item_init (SheetItem *item)
item->priv->ui_manager = gtk_ui_manager_new ();
item->priv->action_group = gtk_action_group_new ("action_group");
- gtk_action_group_set_translation_domain (item->priv->action_group,
- GETTEXT_PACKAGE);
- gtk_action_group_add_actions (item->priv->action_group,
- action_entries, G_N_ELEMENTS (action_entries), NULL);
- gtk_ui_manager_insert_action_group (item->priv->ui_manager,
- item->priv->action_group, 0);
-
- if (!gtk_ui_manager_add_ui_from_string (item->priv->ui_manager,
- sheet_item_context_menu, -1, &error)) {
- g_message ("building menus failed: %s", error->message);
+ gtk_action_group_set_translation_domain (item->priv->action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (item->priv->action_group, action_entries,
+ G_N_ELEMENTS (action_entries), NULL);
+ gtk_ui_manager_insert_action_group (item->priv->ui_manager, item->priv->action_group, 0);
+
+ if (!gtk_ui_manager_add_ui_from_string (item->priv->ui_manager, sheet_item_context_menu, -1,
+ &error)) {
+ g_warning ("building menus failed: %s", error->message);
g_error_free (error);
}
}
-static void
-sheet_item_set_property (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *spec)
+static void sheet_item_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
{
- GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
- SheetItem *sheet_item;
- SheetPos pos;
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple *)object;
+ SheetItem *sheet_item;
+ Coords pos;
sheet_item = SHEET_ITEM (object);
-
+
switch (prop_id) {
- case ARG_X:
- sheet_item->x = g_value_get_double (value);
- break;
- case ARG_Y:
- sheet_item->y = g_value_get_double (value);
+ case ARG_X:
+ sheet_item->x = g_value_get_double (value);
break;
- case ARG_WIDTH:
- sheet_item->width = g_value_get_double (value);
+ case ARG_Y:
+ sheet_item->y = g_value_get_double (value);
break;
- case ARG_HEIGHT:
- sheet_item->height = g_value_get_double (value);
- break;
- case ARG_DATA:
- if (sheet_item->priv->data) {
- g_warning (_("Cannot set SheetItem after creation."));
- break;
- }
- sheet_item->priv->data = g_value_get_pointer (value);
- item_data_get_pos (sheet_item->priv->data, &pos);
- sheet_item->x = pos.x;
- sheet_item->y = pos.y;
+ case ARG_WIDTH:
+ sheet_item->width = g_value_get_double (value);
+ break;
+ case ARG_HEIGHT:
+ sheet_item->height = g_value_get_double (value);
+ break;
+ case ARG_DATA:
+ if (sheet_item->priv->data) {
+ g_warning (_ ("Cannot set SheetItem after creation."));
break;
- case ARG_ACTION_GROUP:
- sheet_item->priv->action_group = g_value_get_pointer (value);
- gtk_ui_manager_insert_action_group (sheet_item->priv->ui_manager,
+ }
+ sheet_item->priv->data = g_value_get_pointer (value);
+ item_data_get_pos (sheet_item->priv->data, &pos);
+ sheet_item->x = pos.x;
+ sheet_item->y = pos.y;
+ break;
+ case ARG_ACTION_GROUP:
+ sheet_item->priv->action_group = g_value_get_pointer (value);
+ gtk_ui_manager_insert_action_group (sheet_item->priv->ui_manager,
sheet_item->priv->action_group, 0);
- break;
- default:
- break;
+ break;
+ default:
+ break;
}
goo_canvas_item_simple_changed (simple, TRUE);
}
-static void
-sheet_item_get_property (GObject *object, guint prop_id, GValue *value,
- GParamSpec *spec)
+static void sheet_item_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec)
{
SheetItem *sheet_item;
sheet_item = SHEET_ITEM (object);
switch (prop_id) {
- case ARG_X:
- g_value_set_double (value, sheet_item->x);
- break;
- case ARG_Y:
- g_value_set_double (value, sheet_item->y);
- break;
- case ARG_WIDTH:
- g_value_set_double (value, sheet_item->width);
- break;
- case ARG_HEIGHT:
- g_value_set_double (value, sheet_item->height);
- break;
- case ARG_DATA:
- g_value_set_pointer (value, sheet_item->priv->data);
- break;
- case ARG_SHEET:
- g_value_set_pointer (value, sheet_item_get_sheet (sheet_item));
- break;
- case ARG_ACTION_GROUP:
- g_value_set_pointer (value, sheet_item->priv->action_group);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (sheet_item, prop_id, spec);
- break;
+ case ARG_X:
+ g_value_set_double (value, sheet_item->x);
+ break;
+ case ARG_Y:
+ g_value_set_double (value, sheet_item->y);
+ break;
+ case ARG_WIDTH:
+ g_value_set_double (value, sheet_item->width);
+ break;
+ case ARG_HEIGHT:
+ g_value_set_double (value, sheet_item->height);
+ break;
+ case ARG_DATA:
+ g_value_set_pointer (value, sheet_item->priv->data);
+ break;
+ case ARG_SHEET:
+ g_value_set_pointer (value, sheet_item_get_sheet (sheet_item));
+ break;
+ case ARG_ACTION_GROUP:
+ g_value_set_pointer (value, sheet_item->priv->action_group);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (sheet_item, prop_id, spec);
+ break;
}
}
-static void
-sheet_item_finalize (GObject *object)
+static void sheet_item_finalize (GObject *object)
{
- GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
- SheetItem *sheet_item;
+ SheetItem *sheet_item = SHEET_ITEM (object);
+
+ g_free (sheet_item->priv);
+ sheet_item->priv = NULL;
- sheet_item = SHEET_ITEM (object);
- if (simple->simple_data) {
- g_free (sheet_item->priv);
- sheet_item->priv = NULL;
- }
G_OBJECT_CLASS (sheet_item_parent_class)->finalize (object);
}
-static void
-sheet_item_run_menu (SheetItem *item, Sheet *sheet, GdkEventButton *event)
+static void sheet_item_run_menu (SheetItem *item, Sheet *sheet, GdkEventButton *event)
{
GtkWidget *menu;
menu = gtk_ui_manager_get_widget (item->priv->ui_manager, "/ItemMenu");
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, sheet, event->button,
- event->time);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, sheet, event->button, event->time);
}
-
// Event handler for a SheetItem
-gboolean
-sheet_item_event (GooCanvasItem *sheet_item,
- GooCanvasItem *sheet_target_item,
- GdkEvent *event, Sheet *sheet)
+gboolean sheet_item_event (GooCanvasItem *sheet_item, GooCanvasItem *sheet_target_item,
+ GdkEvent *event, Sheet *sheet)
{
// Remember the last position of the mouse cursor.
- static double last_x, last_y;
GooCanvas *canvas;
SheetPriv *priv;
GList *list;
- // Mouse cursor position in window coordinates, snapped to the grid spacing.
- double snapped_x, snapped_y;
- // Move the selected item(s) by this movement.
- double dx, dy;
-
-
+
+ static Coords last, current, snapped;
+ // snapped : Mouse cursor position in window coordinates, snapped to the grid
+ // spacing.
+ // delta : Move the selected item(s) by this movement.
+ Coords delta, after;
+
g_return_val_if_fail (sheet_item != NULL, FALSE);
g_return_val_if_fail (sheet != NULL, FALSE);
priv = sheet->priv;
canvas = GOO_CANVAS (sheet);
-
+
switch (event->type) {
case GDK_BUTTON_PRESS:
// Grab focus to sheet for correct use of events
@@ -375,7 +334,7 @@ sheet_item_event (GooCanvasItem *sheet_item,
case 1:
g_signal_stop_emission_by_name (sheet_item, "button_press_event");
sheet->state = SHEET_STATE_DRAG_START;
- sheet_get_pointer (sheet, &last_x, &last_y);
+ g_assert (sheet_get_pointer (sheet, &last.x, &last.y));
break;
case 3:
g_signal_stop_emission_by_name (sheet_item, "button_press_event");
@@ -385,13 +344,12 @@ sheet_item_event (GooCanvasItem *sheet_item,
// Bring up a context menu for right button clicks.
if (!SHEET_ITEM (sheet_item)->priv->selected &&
- !((event->button.state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK))
- sheet_select_all (sheet, FALSE);
+ !((event->button.state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK))
+ sheet_select_all (sheet, FALSE);
sheet_item_select (SHEET_ITEM (sheet_item), TRUE);
- sheet_item_run_menu (SHEET_ITEM (sheet_item), sheet,
- (GdkEventButton *) event);
+ sheet_item_run_menu (SHEET_ITEM (sheet_item), sheet, (GdkEventButton *)event);
break;
default:
return FALSE;
@@ -423,8 +381,7 @@ sheet_item_event (GooCanvasItem *sheet_item,
case GDK_BUTTON_RELEASE:
switch (event->button.button) {
case 1:
- if (sheet->state != SHEET_STATE_DRAG &&
- sheet->state != SHEET_STATE_DRAG_START)
+ if (sheet->state != SHEET_STATE_DRAG && sheet->state != SHEET_STATE_DRAG_START)
return TRUE;
g_signal_stop_emission_by_name (sheet_item, "button-release-event");
@@ -442,152 +399,143 @@ sheet_item_event (GooCanvasItem *sheet_item,
}
// Get the mouse motion
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
- snapped_x -= last_x;
- snapped_y -= last_y;
+ g_assert (sheet_get_pointer (sheet, &snapped.x, &snapped.y));
+ delta = coords_sub (&snapped, &last);
sheet->state = SHEET_STATE_NONE;
- goo_canvas_pointer_ungrab (canvas, GOO_CANVAS_ITEM (sheet_item),
- event->button.time);
+ goo_canvas_pointer_ungrab (canvas, GOO_CANVAS_ITEM (sheet_item), event->button.time);
// Reparent the selected objects to the normal group
// to have correct behaviour
for (list = priv->selected_objects; list; list = list->next) {
- sheet_item_reparent (SHEET_ITEM (list->data),
- sheet->object_group);
- }
+ sheet_item_reparent (SHEET_ITEM (list->data), sheet->object_group);
+ }
for (list = priv->selected_objects; list; list = list->next) {
- ItemData *item_data;
- SheetPos pos;
-
- item_data = SHEET_ITEM (list->data)->priv->data;
- pos.x = snapped_x;
- pos.y = snapped_y;
- item_data_move (item_data, &pos);
- item_data_register (item_data);
- }
- g_list_free_full (list, g_object_unref);
-
+ ItemData *item_data;
+
+ item_data = SHEET_ITEM (list->data)->priv->data;
+ item_data_move (item_data, &delta);
+ item_data_get_pos (item_data, &after);
+ snap_to_grid (sheet->grid, &after.x, &after.y);
+ item_data_set_pos (item_data, &after);
+ item_data_register (item_data);
+ }
break;
}
-
+
case GDK_KEY_PRESS:
switch (event->key.keyval) {
- case GDK_KEY_r:
- sheet_rotate_selection (sheet);
- {
- gdouble x, y;
- GooCanvasBounds bounds;
-
- sheet_get_pointer (sheet, &x, &y);
-
- // Center the objects around the mouse pointer.
- goo_canvas_item_get_bounds (
- GOO_CANVAS_ITEM (priv->floating_group), &bounds);
-
- dx = x - (bounds.x1 + bounds.x2) / 2;
- dy = y - (bounds.y1 + bounds.y2) / 2;
- snap_to_grid (sheet->grid, &dx, &dy);
-
- goo_canvas_item_translate (
- GOO_CANVAS_ITEM (priv->floating_group), dx, dy);
-
- last_x = snapped_x;
- last_y = snapped_y;
- }
- break;
- default:
- return FALSE;
+ case GDK_KEY_r: {
+#ifndef FIXME_STILL_MINI_OFFSET
+ Coords bbdelta;
+ GooCanvasBounds bounds;
+
+ // Center the objects around the mouse pointer.
+ goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->selected_group), &bounds);
+
+ bbdelta.x = (bounds.x2 - bounds.x1) / 2.;
+ bbdelta.y = (bounds.y2 - bounds.y1) / 2.;
+#endif
+ sheet_rotate_selection (sheet, 90);
+#ifndef FIXME_STILL_MINI_OFFSET
+ // Center the objects around the mouse pointer.
+ goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->selected_group), &bounds);
+
+ bbdelta.x -= (bounds.x2 - bounds.x1) / 2.;
+ bbdelta.y -= (bounds.y2 - bounds.y1) / 2.;
+
+ snap_to_grid (sheet->grid, &bbdelta.x, &bbdelta.y);
+
+ goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->selected_group), bbdelta.x,
+ bbdelta.y);
+#endif
+ } break;
+ default:
+ return FALSE;
}
return TRUE;
case GDK_MOTION_NOTIFY:
- if (sheet->state != SHEET_STATE_DRAG &&
- sheet->state != SHEET_STATE_DRAG_START)
+ if (sheet->state != SHEET_STATE_DRAG && sheet->state != SHEET_STATE_DRAG_START)
return FALSE;
if (sheet->state == SHEET_STATE_DRAG_START) {
sheet->state = SHEET_STATE_DRAG;
-
- // Update the selection if needed.
- if (IS_SHEET_ITEM (sheet_item) &&
- (!SHEET_ITEM (sheet_item)->priv->selected)) {
+
+ // Update the selection if needed.
+ if (IS_SHEET_ITEM (sheet_item) && (!SHEET_ITEM (sheet_item)->priv->selected)) {
if (!(event->button.state & GDK_SHIFT_MASK)) {
sheet_select_all (sheet, FALSE);
}
sheet_item_select (SHEET_ITEM (sheet_item), TRUE);
}
- // Reparent the selected objects so that we can move them
+ // Reparent the selected objects so that we can move them
// efficiently.
for (list = priv->selected_objects; list; list = list->next) {
ItemData *item_data;
item_data = SHEET_ITEM (list->data)->priv->data;
item_data_unregister (item_data);
- sheet_item_reparent (SHEET_ITEM (list->data),
- priv->selected_group);
+ sheet_item_reparent (SHEET_ITEM (list->data), priv->selected_group);
}
- g_list_free_full (list, g_object_unref);
-
goo_canvas_pointer_grab (canvas, GOO_CANVAS_ITEM (sheet_item),
- GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL,
- event->button.time);
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL,
+ event->button.time);
}
// Set last_x & last_y to the pointer position
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
-
- dx = snapped_x - last_x;
- dy = snapped_y - last_y;
-
- // Check that we don't move outside the sheet...
- // Horizontally:
- /*
- if (cx1 <= 0) { // leftmost edge
- dx = dx - x1;
- snap_to_grid (sheet->grid, &dx, NULL);
- snapped_x = last_x + dx;
- }
- else if (cx2 >= sheet_width) { // rightmost edge
- dx = dx - (x2 - sheet_width / priv->zoom);
- snap_to_grid (sheet->grid, &dx, NULL);
- snapped_x = last_x + dx;
- }
+ sheet_get_pointer (sheet, &snapped.x, &snapped.y);
- // And vertically:
- if (cy1 <= 0) { // upper edge
- dy = dy - y1;
- snap_to_grid (sheet->grid, NULL, &dy);
- snapped_y = last_y + dy;
- }
- else if (cy2 >= sheet_height) { // lower edge
- dy = dy - (y2 - sheet_height / priv->zoom);
- snap_to_grid (sheet->grid, NULL, &dy);
- snapped_y = last_y + dy;
- }
- //last_x = snapped_x;
- //last_y = snapped_y;
- */
-
- goo_canvas_item_set_transform (GOO_CANVAS_ITEM (priv->selected_group),
- NULL);
- goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->selected_group),
- dx, dy);
+ delta = coords_sub (&snapped, &last);
+
+// Check that we don't move outside the sheet...
+// Horizontally:
+/*
+if (cx1 <= 0) { // leftmost edge
+ dx = dx - x1;
+ snap_to_grid (sheet->grid, &dx, NULL);
+ snapped_x = last_x + dx;
+}
+else if (cx2 >= sheet_width) { // rightmost edge
+ dx = dx - (x2 - sheet_width / priv->zoom);
+ snap_to_grid (sheet->grid, &dx, NULL);
+ snapped_x = last_x + dx;
+}
+
+// And vertically:
+if (cy1 <= 0) { // upper edge
+ dy = dy - y1;
+ snap_to_grid (sheet->grid, NULL, &dy);
+ snapped_y = last_y + dy;
+}
+else if (cy2 >= sheet_height) { // lower edge
+ dy = dy - (y2 - sheet_height / priv->zoom);
+ snap_to_grid (sheet->grid, NULL, &dy);
+ snapped_y = last_y + dy;
+}
+//last_x = snapped_x;
+//last_y = snapped_y;
+*/
+
+#if !FIXME_INCREMENTAL_MOVMENT_DOES_NOT_WORK
+ last = snapped;
+#else
+ goo_canvas_item_set_transform (GOO_CANVAS_ITEM (priv->selected_group), NULL);
+#endif
+ goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->selected_group), delta.x, delta.y);
return TRUE;
-
+
default:
return FALSE;
}
return TRUE;
}
-// Cancel the placement of floating items and remove them.
-void
-sheet_item_cancel_floating (Sheet *sheet)
+// Cancel the placement of floating items and remove them.
+void sheet_item_cancel_floating (Sheet *sheet)
{
GooCanvasGroup *group;
GList *list;
@@ -595,57 +543,48 @@ sheet_item_cancel_floating (Sheet *sheet)
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
-
group = GOO_CANVAS_GROUP (sheet->priv->floating_group);
if (group == NULL)
return;
- if (sheet->state != SHEET_STATE_FLOAT &&
- sheet->state != SHEET_STATE_FLOAT_START)
+ if (sheet->state != SHEET_STATE_FLOAT && sheet->state != SHEET_STATE_FLOAT_START)
return;
if (g_signal_handler_is_connected (sheet, sheet->priv->float_handler_id))
g_signal_handler_disconnect (sheet, sheet->priv->float_handler_id);
- g_object_unref (G_OBJECT (group));
-
- // If the state is _START, the items are not yet put in the
- // object_group. This means we have to destroy them one by one.
- if (sheet->state == SHEET_STATE_FLOAT_START) {
- for (list = sheet->priv->floating_objects; list; list = list->next) {
- g_object_unref (G_OBJECT (list->data));
- }
+ // TODO verfiy that the following has no nasty sideffects
+ for (list = sheet->priv->floating_objects; list; list = list->next) {
+ goo_canvas_item_remove (list->data); // remove from canvas and free
}
+ g_list_free (sheet->priv->floating_objects);
+ sheet->priv->floating_objects = NULL;
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (group));
// Create a new empty group to prepare next floating group
sheet->priv->floating_group = GOO_CANVAS_GROUP (
- goo_canvas_group_new (GOO_CANVAS_ITEM (sheet->object_group),
- "x", 0.0,
- "y", 0.0,
- NULL));
+ goo_canvas_group_new (GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL));
+ // sheet_clear_ghosts (sheet);
sheet->priv->float_handler_id = 0;
sheet->state = SHEET_STATE_NONE;
- sheet_clear_ghosts (sheet);
}
// Event handler for a "floating" group of objects.
-int
-sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
+int sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
{
SheetPriv *priv;
GList *list;
- static SheetPos pos;
- static int control_key_down = 0;
+ static gboolean keep = FALSE;
- // Remember the last position of the mouse cursor.
- static double last_x, last_y;
+ // Remember the start position of the mouse cursor.
+ static Coords last = {0., 0.};
// Mouse cursor position in window coordinates, snapped to the grid spacing.
- double snapped_x, snapped_y;
+ static Coords snapped = {0., 0.};
// Move the selected item(s) by this movement.
- double dx, dy;
+ Coords delta = {0., 0.};
g_return_val_if_fail (sheet != NULL, FALSE);
g_return_val_if_fail (IS_SHEET (sheet), FALSE);
@@ -669,59 +608,50 @@ sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
return FALSE;
case 1:
- control_key_down = event->button.state & GDK_CONTROL_MASK;
+ // do not free the floating items, but use them like a stamp
+ keep = event->button.state & GDK_CONTROL_MASK;
// Continue adding if CTRL is pressed
- if (!control_key_down) {
+ if (!keep) {
sheet->state = SHEET_STATE_NONE;
g_signal_stop_emission_by_name (sheet, "event");
- if (g_signal_handler_is_connected (sheet,
- sheet->priv->float_handler_id))
- g_signal_handler_disconnect (sheet,
- sheet->priv->float_handler_id);
+ if (g_signal_handler_is_connected (sheet, sheet->priv->float_handler_id))
+ g_signal_handler_disconnect (sheet, sheet->priv->float_handler_id);
sheet->priv->float_handler_id = 0;
}
-
- // Get pointer position independantly of the zoom
- sheet_get_pointer (sheet, &pos.x, &pos.y);
-
+ // FIXME assert that `Coords current` has been set by now!
for (list = priv->floating_objects; list; list = list->next) {
SheetItem *floating_item;
ItemData *floating_data;
-
+
// Create a real item.
floating_item = list->data;
- if (!control_key_down) {
+ if (!keep) {
floating_data = sheet_item_get_data (floating_item);
- g_object_set (floating_item,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
- }
- else
+ g_object_set (floating_item, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+ } else {
+ // FIXME the bounding box of the clone is wrong
floating_data = item_data_clone (sheet_item_get_data (floating_item));
+ }
+
+ NG_DEBUG ("Item Data Pos will be %lf %lf", snapped.x, snapped.y)
+
+ item_data_set_pos (floating_data, &snapped);
+
+ schematic_add_item (schematic_view_get_schematic_from_sheet (sheet), floating_data);
- g_object_ref (G_OBJECT (floating_data));
- item_data_set_pos (floating_data, &pos);
- schematic_add_item (schematic_view_get_schematic_from_sheet (sheet),
- floating_data);
- if (!control_key_down)
+ if (!keep)
g_object_unref (G_OBJECT (floating_item));
}
- g_list_free_full (list, g_object_unref);
- if (!control_key_down) {
- g_list_free (sheet->priv->floating_objects);
- sheet->priv->floating_objects = NULL;
- }
- else
- g_object_set (G_OBJECT (sheet->priv->floating_group),
- "x", pos.x,
- "y", pos.y,
+ if (keep) {
+ g_object_set (G_OBJECT (priv->floating_group), "x", snapped.x, "y", snapped.y,
NULL);
-
- pos.x = 0.0;
- pos.y = 0.0;
+ } else {
+ g_list_free (priv->floating_objects);
+ priv->floating_objects = NULL;
+ }
break;
case 3:
@@ -738,76 +668,86 @@ sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
return TRUE;
case GDK_MOTION_NOTIFY:
- if (sheet->state != SHEET_STATE_FLOAT &&
- sheet->state != SHEET_STATE_FLOAT_START)
+// keep track of the position, as `sheet_get_pointer*()` does not work
+// in other events than MOTION_NOTIFY
+#if 0
+ {
+ Coords tmp;
+ last = current;
+ if (sheet_get_pointer (sheet, &tmp.x, &tmp.y)) {
+ snapped_current = current = tmp;
+ snap_to_grid (sheet->grid, &snapped_current.x, &snapped_current.y);
+ }
+ }
+#endif
+ if (sheet->state != SHEET_STATE_FLOAT && sheet->state != SHEET_STATE_FLOAT_START)
return FALSE;
g_signal_stop_emission_by_name (sheet, "event");
+ // Get pointer position independantly of the zoom
+
if (sheet->state == SHEET_STATE_FLOAT_START) {
sheet->state = SHEET_STATE_FLOAT;
-
- // Reparent the selected objects so that we can move them
+ last.x = last.y = 0.;
+ // Reparent the selected objects so that we can move them
// efficiently.
for (list = priv->floating_objects; list; list = list->next) {
- sheet_item_reparent (SHEET_ITEM (list->data),
- priv->floating_group);
-
+ sheet_item_reparent (SHEET_ITEM (list->data), priv->floating_group);
// Set the floating item visible
- g_object_set (G_OBJECT (list->data),
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
- }
- last_x = 0.0;
- last_y = 0.0;
+ g_object_set (G_OBJECT (list->data), "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
+ }
+#if 0
+ GooCanvasBounds box;
+ goo_canvas_item_get_bounds (priv->floating_group, &box);
+#endif
+ NG_DEBUG ("\n\n\nFLOAT ### START\n\n\n\n");
}
- // Get pointer position independantly of the zoom
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
-
- // Calculate which amount to move the selected objects by.
- dx = snapped_x - last_x;
- dy = snapped_y - last_y;
-
- last_x = snapped_x;
- last_y = snapped_y;
-
- for (list = priv->floating_objects; list; list = list->next) {
- goo_canvas_item_translate (GOO_CANVAS_ITEM (list->data),
- dx, dy);
- }
- g_list_free_full (list, g_object_unref);
+ sheet_get_pointer_snapped (sheet, &snapped.x, &snapped.y);
+
+ delta = coords_sub (&snapped, &last);
+ NG_DEBUG ("drag floating current sx=%lf sy=%lf \n", snapped.x, snapped.y);
+ NG_DEBUG ("drag floating last lx=%lf ly=%lf \n", last.x, last.y);
+ NG_DEBUG ("drag floating delta -> dx=%lf dy=%lf \n", delta.x, delta.y);
+
+#if !FIXME_INCREMENTAL_MOVMENT_DOES_NOT_WORK
+ last = snapped;
+#else
+ goo_canvas_item_set_transform (GOO_CANVAS_ITEM (priv->floating_group), NULL);
+#endif
+ goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->floating_group), delta.x, delta.y);
+
break;
case GDK_KEY_PRESS:
switch (event->key.keyval) {
- case GDK_KEY_r:
- case GDK_KEY_R:
- sheet_rotate_ghosts (sheet);
- {
- gdouble x, y;
- GooCanvasBounds bounds;
-
- sheet_get_pointer (sheet, &x, &y);
-
- // Center the objects around the mouse pointer.
- goo_canvas_item_get_bounds (
- GOO_CANVAS_ITEM (priv->floating_group), &bounds);
-
- snapped_x = x - (bounds.x1 + bounds.x2) / 2;
- snapped_y = y - (bounds.y1 + bounds.y2) / 2;
- snap_to_grid (sheet->grid, &snapped_x, &snapped_y);
-
- goo_canvas_item_translate (
- GOO_CANVAS_ITEM (priv->floating_group), snapped_x,
- snapped_y);
-
- last_x = snapped_x;
- last_y = snapped_y;
- }
- break;
- default:
- return FALSE;
+ case GDK_KEY_r:
+ case GDK_KEY_R: {
+ Coords bbdelta;
+ GooCanvasBounds bounds;
+
+ // Center the objects around the mouse pointer.
+ goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->floating_group), &bounds);
+
+ bbdelta.x = (bounds.x2 - bounds.x1) / 2.;
+ bbdelta.y = (bounds.y2 - bounds.y1) / 2.;
+
+ sheet_rotate_ghosts (sheet);
+
+ // Center the objects around the mouse pointer.
+ goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->floating_group), &bounds);
+
+ bbdelta.x -= (bounds.x2 - bounds.x1) / 2.;
+ bbdelta.y -= (bounds.y2 - bounds.y1) / 2.;
+
+ snap_to_grid (sheet->grid, &bbdelta.x, &bbdelta.y);
+
+ goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->floating_group), bbdelta.x,
+ bbdelta.y);
+ } break;
+ default:
+ return FALSE;
}
default:
return FALSE;
@@ -815,14 +755,12 @@ sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
return TRUE;
}
-gboolean
-sheet_item_select (SheetItem *item, gboolean select)
+gboolean sheet_item_select (SheetItem *item, gboolean select)
{
g_return_val_if_fail (item != NULL, FALSE);
g_return_val_if_fail (IS_SHEET_ITEM (item), FALSE);
- if ((item->priv->selected && select) ||
- (!item->priv->selected && !select)) {
+ if ((item->priv->selected && select) || (!item->priv->selected && !select)) {
return FALSE;
}
@@ -832,8 +770,7 @@ sheet_item_select (SheetItem *item, gboolean select)
return TRUE;
}
-void
-sheet_item_select_in_area (SheetItem *item, SheetPos *p1, SheetPos *p2)
+void sheet_item_select_in_area (SheetItem *item, Coords *p1, Coords *p2)
{
SheetItemClass *sheet_item_class;
gboolean in_area;
@@ -848,28 +785,24 @@ sheet_item_select_in_area (SheetItem *item, SheetPos *p1, SheetPos *p2)
if (in_area && !item->priv->selected)
sheet_item_select (item, TRUE);
- else if (!in_area && item->priv->selected &&
- !item->priv->preserve_selection)
+ else if (!in_area && item->priv->selected && !item->priv->preserve_selection)
sheet_item_select (item, FALSE);
}
// Reparent a sheet object without moving it on the sheet.
-void
-sheet_item_reparent (SheetItem *item, GooCanvasGroup *group)
+void sheet_item_reparent (SheetItem *item, GooCanvasGroup *group)
{
g_return_if_fail (item != NULL);
g_return_if_fail (IS_SHEET_ITEM (item));
g_return_if_fail (group != NULL);
g_object_ref (item);
- goo_canvas_item_remove (GOO_CANVAS_ITEM (item));
- goo_canvas_item_add_child (GOO_CANVAS_ITEM (group),
- GOO_CANVAS_ITEM (item),
- -1);
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (item));
+ goo_canvas_item_add_child (GOO_CANVAS_ITEM (group), GOO_CANVAS_ITEM (item), -1);
+ g_object_unref (item);
}
-void
-sheet_item_edit_properties (SheetItem *item)
+void sheet_item_edit_properties (SheetItem *item)
{
SheetItemClass *sheet_item_class;
@@ -882,8 +815,7 @@ sheet_item_edit_properties (SheetItem *item)
sheet_item_class->edit_properties (item);
}
-void
-sheet_item_rotate (SheetItem *sheet_item, int angle, SheetPos *center)
+void sheet_item_rotate (SheetItem *sheet_item, int angle, Coords *center)
{
g_return_if_fail (sheet_item != NULL);
g_return_if_fail (IS_SHEET_ITEM (sheet_item));
@@ -891,8 +823,7 @@ sheet_item_rotate (SheetItem *sheet_item, int angle, SheetPos *center)
item_data_rotate (sheet_item->priv->data, angle, center);
}
-void
-sheet_item_paste (Sheet *sheet, ClipboardData *data)
+void sheet_item_paste (Sheet *sheet, ClipboardData *data)
{
SheetItemClass *item_class;
ItemDataClass *id_class;
@@ -916,8 +847,7 @@ sheet_item_paste (Sheet *sheet, ClipboardData *data)
}
}
-ItemData *
-sheet_item_get_data (SheetItem *item)
+ItemData *sheet_item_get_data (SheetItem *item)
{
g_return_val_if_fail (item != NULL, NULL);
g_return_val_if_fail (IS_SHEET_ITEM (item), NULL);
@@ -925,8 +855,7 @@ sheet_item_get_data (SheetItem *item)
return item->priv->data;
}
-Sheet *
-sheet_item_get_sheet (SheetItem *item)
+Sheet *sheet_item_get_sheet (SheetItem *item)
{
g_return_val_if_fail (item != NULL, NULL);
g_return_val_if_fail (IS_SHEET_ITEM (item), NULL);
@@ -934,8 +863,7 @@ sheet_item_get_sheet (SheetItem *item)
return SHEET (goo_canvas_item_get_canvas (GOO_CANVAS_ITEM (item)));
}
-gboolean
-sheet_item_get_selected (SheetItem *item)
+gboolean sheet_item_get_selected (SheetItem *item)
{
g_return_val_if_fail (item != NULL, FALSE);
g_return_val_if_fail (IS_SHEET_ITEM (item), FALSE);
@@ -943,8 +871,7 @@ sheet_item_get_selected (SheetItem *item)
return item->priv->selected;
}
-gboolean
-sheet_item_get_preserve_selection (SheetItem *item)
+gboolean sheet_item_get_preserve_selection (SheetItem *item)
{
g_return_val_if_fail (item != NULL, FALSE);
g_return_val_if_fail (IS_SHEET_ITEM (item), FALSE);
@@ -952,8 +879,7 @@ sheet_item_get_preserve_selection (SheetItem *item)
return item->priv->preserve_selection;
}
-void
-sheet_item_set_preserve_selection (SheetItem *item, gboolean set)
+void sheet_item_set_preserve_selection (SheetItem *item, gboolean set)
{
g_return_if_fail (item != NULL);
g_return_if_fail (IS_SHEET_ITEM (item));
@@ -961,8 +887,7 @@ sheet_item_set_preserve_selection (SheetItem *item, gboolean set)
item->priv->preserve_selection = set;
}
-void
-sheet_item_place (SheetItem *item, Sheet *sheet)
+void sheet_item_place (SheetItem *item, Sheet *sheet)
{
SheetItemClass *sheet_item_class;
@@ -975,8 +900,7 @@ sheet_item_place (SheetItem *item, Sheet *sheet)
sheet_item_class->place (item, sheet);
}
-void
-sheet_item_place_ghost (SheetItem *item, Sheet *sheet)
+void sheet_item_place_ghost (SheetItem *item, Sheet *sheet)
{
SheetItemClass *sheet_item_class;
@@ -989,19 +913,14 @@ sheet_item_place_ghost (SheetItem *item, Sheet *sheet)
sheet_item_class->place_ghost (item, sheet);
}
-void
-sheet_item_add_menu (SheetItem *item, const char *menu,
- const GtkActionEntry *action_entries, int nb_entries)
+void sheet_item_add_menu (SheetItem *item, const char *menu, const GtkActionEntry *action_entries,
+ int nb_entries)
{
GError *error = NULL;
- gtk_action_group_add_actions (item->priv->action_group,
- action_entries,
- nb_entries,
- NULL);
-
- if (!gtk_ui_manager_add_ui_from_string (item->priv->ui_manager,
- menu, -1, &error)) {
+ gtk_action_group_add_actions (item->priv->action_group, action_entries, nb_entries, NULL);
+
+ if (!gtk_ui_manager_add_ui_from_string (item->priv->ui_manager, menu, -1, &error)) {
g_message ("building menus failed: %s", error->message);
g_error_free (error);
}
diff --git a/src/sheet/sheet-item.h b/src/sheet/sheet-item.h
index 7814199..df91798 100644
--- a/src/sheet/sheet-item.h
+++ b/src/sheet/sheet-item.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SHEET_ITEM_H
#define __SHEET_ITEM_H
@@ -37,12 +37,13 @@
#include <goocanvas.h>
#include "sheet.h"
-#include "sheet-pos.h"
+#include "coords.h"
-#define TYPE_SHEET_ITEM (sheet_item_get_type())
-#define SHEET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, sheet_item_get_type (), SheetItem))
-#define SHEET_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, sheet_item_get_type (), SheetItemClass))
-#define IS_SHEET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, TYPE_SHEET_ITEM))
+#define TYPE_SHEET_ITEM (sheet_item_get_type ())
+#define SHEET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, sheet_item_get_type (), SheetItem))
+#define SHEET_ITEM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST (klass, sheet_item_get_type (), SheetItemClass))
+#define IS_SHEET_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_SHEET_ITEM))
typedef struct _SheetItemClass SheetItemClass;
typedef struct _SheetItemPriv SheetItemPriv;
@@ -50,55 +51,53 @@ typedef struct _SheetItemPriv SheetItemPriv;
#include "sheet.h"
#include "clipboard.h"
-struct _SheetItem {
+struct _SheetItem
+{
GooCanvasGroup canvas_group;
- gdouble width;
- gdouble height;
- gdouble x;
- gdouble y;
+ gdouble width;
+ gdouble height;
+ gdouble x; // left
+ gdouble y; // top
SheetItemPriv *priv;
};
-struct _SheetItemClass {
+struct _SheetItemClass
+{
GooCanvasGroupClass parent_class;
// Methods.
- gboolean (*is_in_area) (SheetItem *item, SheetPos *p1, SheetPos *p2);
- void (*show_labels) (SheetItem *sheet_item, gboolean show);
- void (*edit_properties) (SheetItem *item);
- void (*paste) (Sheet *sheet, ItemData *data);
- void (*place) (SheetItem *item, Sheet *sheet);
- void (*place_ghost) (SheetItem *item, Sheet *sheet);
+ gboolean (*is_in_area)(SheetItem *item, Coords *p1, Coords *p2);
+ void (*show_labels)(SheetItem *sheet_item, gboolean show);
+ void (*edit_properties)(SheetItem *item);
+ void (*paste)(Sheet *sheet, ItemData *data);
+ void (*place)(SheetItem *item, Sheet *sheet);
+ void (*place_ghost)(SheetItem *item, Sheet *sheet);
// Signal handlers.
- void (*moved) (SheetItem *item);
- void (*selection_changed)(SheetItem *item);
- void (*mouse_over) (SheetItem *item);
+ void (*moved)(SheetItem *item);
+ void (*selection_changed)(SheetItem *item);
+ void (*mouse_over)(SheetItem *item);
};
-GType sheet_item_get_type (void);
-void sheet_item_select_all (Sheet *sheet, gboolean select);
-gboolean sheet_item_select (SheetItem *item, gboolean select);
-Sheet * sheet_item_get_sheet (SheetItem *item);
-gboolean sheet_item_event (GooCanvasItem *sheet_item,
- GooCanvasItem *sheet_target_item, GdkEvent *event,
- Sheet *sheet);
-int sheet_item_floating_event (Sheet *sheet, const GdkEvent *event);
-void sheet_item_cancel_floating (Sheet *sheet);
-void sheet_item_edit_properties (SheetItem *item);
-ItemData * sheet_item_get_data (SheetItem *item);
-void sheet_item_paste (Sheet *sheet,
- ClipboardData *data);
-void sheet_item_rotate (SheetItem *sheet_item, int angle,
- SheetPos *center);
-gboolean sheet_item_get_selected (SheetItem *item);
-gboolean sheet_item_get_preserve_selection (SheetItem *item);
-void sheet_item_set_preserve_selection (SheetItem *item, gboolean set);
-void sheet_item_select_in_area (SheetItem *item, SheetPos *p1,
- SheetPos *p2);
-void sheet_item_place (SheetItem *item, Sheet *sheet);
-void sheet_item_place_ghost (SheetItem *item, Sheet *sheet);
-void sheet_item_add_menu (SheetItem *item, const char *menu,
- const GtkActionEntry *action_entries, int nb_entries);
+GType sheet_item_get_type (void);
+void sheet_item_select_all (Sheet *sheet, gboolean select);
+gboolean sheet_item_select (SheetItem *item, gboolean select);
+Sheet *sheet_item_get_sheet (SheetItem *item);
+gboolean sheet_item_event (GooCanvasItem *sheet_item, GooCanvasItem *sheet_target_item,
+ GdkEvent *event, Sheet *sheet);
+int sheet_item_floating_event (Sheet *sheet, const GdkEvent *event);
+void sheet_item_cancel_floating (Sheet *sheet);
+void sheet_item_edit_properties (SheetItem *item);
+ItemData *sheet_item_get_data (SheetItem *item);
+void sheet_item_paste (Sheet *sheet, ClipboardData *data);
+void sheet_item_rotate (SheetItem *sheet_item, int angle, Coords *center);
+gboolean sheet_item_get_selected (SheetItem *item);
+gboolean sheet_item_get_preserve_selection (SheetItem *item);
+void sheet_item_set_preserve_selection (SheetItem *item, gboolean set);
+void sheet_item_select_in_area (SheetItem *item, Coords *p1, Coords *p2);
+void sheet_item_place (SheetItem *item, Sheet *sheet);
+void sheet_item_place_ghost (SheetItem *item, Sheet *sheet);
+void sheet_item_add_menu (SheetItem *item, const char *menu, const GtkActionEntry *action_entries,
+ int nb_entries);
#endif
diff --git a/src/sheet/sheet-private.h b/src/sheet/sheet-private.h
index 8f53796..5d4e8de 100644
--- a/src/sheet/sheet-private.h
+++ b/src/sheet/sheet-private.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SHEET_PRIVATE_H
@@ -38,47 +38,37 @@
#include "sheet.h"
#include "create-wire.h"
+#include "rubberband.h"
-typedef enum {
- RUBBER_NO = 0,
- RUBBER_YES,
- RUBBER_START
-} RubberState;
-
-typedef struct {
- RubberState state;
- int timeout_id;
- int click_start_state;
- GooCanvasItem *rectangle;
- double start_x, start_y;
-} RubberbandInfo;
-
-struct _SheetPriv {
- // Keeps the current signal handler for wire creation.
- int wire_handler_id;
+struct _SheetPriv
+{
+ // Keeps the current signal handler for wire creation
+ int wire_handler_id;
// Keeps the signal handler for floating objects.
- int float_handler_id;
+ int float_handler_id;
+
+ double zoom;
+ gulong width;
+ gulong height;
- double zoom;
- gulong width;
- gulong height;
+ GooCanvasGroup *selected_group;
+ GooCanvasGroup *floating_group;
+ GList *selected_objects;
+ GList *floating_objects;
- GooCanvasGroup *selected_group;
- GooCanvasGroup *floating_group;
- GList *selected_objects;
- GList *floating_objects;
+ GList *items;
+ RubberbandInfo *rubberband_info;
+ GList *preserve_selection_items;
+ GooCanvasClass *sheet_parent_class;
- GList *items;
- RubberbandInfo *rubberband;
- GList *preserve_selection_items;
- GooCanvasClass *sheet_parent_class;
+ GHashTable *voltmeter_nodes;
- GList *voltmeter_items; // List of GooCanvasItem
- GHashTable *voltmeter_nodes;
+ CreateWireInfo *create_wire_info; // Wire context for each schematic
- CreateWireContext *create_wire_context; // Wire context for each schematic
+ GHashTable *node_dots;
- GHashTable *node_dots;
+ guint8 keyboard_grabbed : 1;
+ guint8 pointer_grabbed : 1;
};
#endif
diff --git a/src/sheet/sheet.c b/src/sheet/sheet.c
index 7d3d0e0..8213430 100644
--- a/src/sheet/sheet.c
+++ b/src/sheet/sheet.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
-
- * Web page: https://github.com/marc-lorber/oregano
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +30,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gdk/gdk.h>
@@ -45,49 +49,39 @@
#include "grid.h"
#include "sheet-item-factory.h"
#include "schematic-view.h"
-
-static void sheet_class_init (SheetClass *klass);
-static void sheet_init (Sheet *sheet);
-static void sheet_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-static void sheet_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *spec);
-static void sheet_set_zoom (const Sheet *sheet, double zoom);
-static GList * sheet_preserve_selection (Sheet *sheet);
-static void rotate_items (Sheet *sheet, GList *items);
-static void flip_items (Sheet *sheet, GList *items, gboolean horizontal);
-static void node_dot_added_callback (Schematic *schematic, SheetPos *pos,
- Sheet *sheet);
-static void node_dot_removed_callback (Schematic *schematic, SheetPos *pos,
- Sheet *sheet);
-static void sheet_finalize (GObject *object);
-static int dot_equal (gconstpointer a, gconstpointer b);
-static guint dot_hash (gconstpointer key);
-
+#include "options.h"
+#include "rubberband.h"
+#include "create-wire.h"
+
+static void sheet_class_init (SheetClass *klass);
+static void sheet_init (Sheet *sheet);
+static void sheet_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+static void sheet_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *spec);
+static void sheet_set_zoom (Sheet *sheet, const double zoom);
+static GList *sheet_preserve_selection (Sheet *sheet);
+static void rotate_items (Sheet *sheet, GList *items, gint angle);
+static void move_items (Sheet *sheet, GList *items, const Coords *delta);
+static void flip_items (Sheet *sheet, GList *items, IDFlip direction);
+static void node_dot_added_callback (Schematic *schematic, Coords *pos, Sheet *sheet);
+static void node_dot_removed_callback (Schematic *schematic, Coords *pos, Sheet *sheet);
+static void sheet_finalize (GObject *object);
+static int dot_equal (gconstpointer a, gconstpointer b);
+static guint dot_hash (gconstpointer key);
#define ZOOM_MIN 0.35
#define ZOOM_MAX 3
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
+#include "debug.h"
-enum {
- SELECTION_CHANGED,
- BUTTON_PRESS,
- CONTEXT_CLICK,
- CANCEL,
- LAST_SIGNAL
-};
-static guint signals[LAST_SIGNAL] = { 0 };
+enum { SELECTION_CHANGED, BUTTON_PRESS, CONTEXT_CLICK, CANCEL, LAST_SIGNAL };
+static guint signals[LAST_SIGNAL] = {0};
-enum {
- ARG_0,
- ARG_ZOOM
-};
+enum { ARG_0, ARG_ZOOM };
G_DEFINE_TYPE (Sheet, sheet, GOO_TYPE_CANVAS)
-static void
-sheet_class_init (SheetClass *sheet_class)
+static void sheet_class_init (SheetClass *sheet_class)
{
GObjectClass *object_class;
@@ -99,246 +93,420 @@ sheet_class_init (SheetClass *sheet_class)
sheet_parent_class = g_type_class_peek (GOO_TYPE_CANVAS);
g_object_class_install_property (object_class, ARG_ZOOM,
- g_param_spec_double ("zoom", "Sheet::zoom", "the zoom factor",
- 0.01f, 10.0f, 1.0f, G_PARAM_READWRITE));
-
- // Signals.
- signals[SELECTION_CHANGED] = g_signal_new ("selection_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetClass, selection_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- signals[BUTTON_PRESS] = g_signal_new ("button_press",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetClass, button_press),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- GDK_TYPE_EVENT);
-
- signals[CONTEXT_CLICK] = g_signal_new ("context_click",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetClass, context_click),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 2,
- G_TYPE_STRING,
- G_TYPE_POINTER);
-
- signals[CONTEXT_CLICK] = g_signal_new ("cancel",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (SheetClass, cancel),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-}
+ g_param_spec_double ("zoom", "Sheet::zoom", "the zoom factor",
+ 0.01f, 10.0f, 1.0f, G_PARAM_READWRITE));
-static
-cairo_pattern_t*
-create_stipple (const char *color_name, guchar stipple_data[16])
-{
- cairo_surface_t *surface;
- cairo_pattern_t *pattern;
- GdkColor color;
-
- gdk_color_parse (color_name, &color);
- stipple_data[2] = stipple_data[14] = color.red >> 8;
- stipple_data[1] = stipple_data[13] = color.green >> 8;
- stipple_data[0] = stipple_data[12] = color.blue >> 8;
- surface = cairo_image_surface_create_for_data (stipple_data,
- CAIRO_FORMAT_ARGB32,
- 2, 2, 8);
- pattern = cairo_pattern_create_for_surface (surface);
- cairo_surface_destroy (surface);
- cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
-
- return pattern;
+ // Signals.
+ signals[SELECTION_CHANGED] =
+ g_signal_new ("selection_changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetClass, selection_changed), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ signals[BUTTON_PRESS] =
+ g_signal_new ("button_press", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetClass, button_press), NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, GDK_TYPE_EVENT);
+
+ signals[CONTEXT_CLICK] = g_signal_new (
+ "context_click", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetClass, context_click), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ signals[CONTEXT_CLICK] =
+ g_signal_new ("cancel", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SheetClass, cancel), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
-static void
-sheet_init (Sheet *sheet)
+static void sheet_init (Sheet *sheet)
{
sheet->priv = g_new0 (SheetPriv, 1);
sheet->priv->zoom = 1.0;
- sheet->priv->selected_objects = NULL;
sheet->priv->selected_group = NULL;
sheet->priv->floating_group = NULL;
+ sheet->priv->floating_objects = NULL;
+ sheet->priv->selected_objects = NULL;
sheet->priv->wire_handler_id = 0;
sheet->priv->float_handler_id = 0;
-
+
sheet->priv->items = NULL;
- sheet->priv->rubberband = g_new0 (RubberbandInfo, 1);
- sheet->priv->rubberband->state = RUBBER_NO;
+ sheet->priv->rubberband_info = NULL;
+ sheet->priv->create_wire_info = NULL;
sheet->priv->preserve_selection_items = NULL;
sheet->priv->sheet_parent_class = g_type_class_ref (GOO_TYPE_CANVAS);
- sheet->priv->voltmeter_items = NULL;
- sheet->priv->voltmeter_nodes = g_hash_table_new_full (g_str_hash,
- g_str_equal, g_free, g_free);
+ sheet->priv->voltmeter_nodes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
sheet->state = SHEET_STATE_NONE;
}
-static void
-sheet_finalize (GObject *object)
-{
+static void sheet_finalize (GObject *object)
+{
Sheet *sheet = SHEET (object);
if (sheet->priv) {
- g_hash_table_destroy (sheet->priv->node_dots);
+ g_list_free (sheet->priv->selected_objects);
+ g_list_free (sheet->priv->floating_objects);
+ g_list_free (sheet->priv->items);
+ g_list_free (sheet->priv->preserve_selection_items);
+
+ if (sheet->priv->voltmeter_nodes)
+ g_hash_table_destroy (sheet->priv->voltmeter_nodes);
+
+ if (sheet->priv->node_dots)
+ g_hash_table_destroy (sheet->priv->node_dots);
+
+ g_free (sheet->priv->rubberband_info);
+ g_free (sheet->priv->create_wire_info);
+
g_free (sheet->priv);
}
+
+ if (sheet->grid)
+ g_object_unref (G_OBJECT (sheet->grid));
+
if (G_OBJECT_CLASS (sheet_parent_class)->finalize)
- (* G_OBJECT_CLASS (sheet_parent_class)->finalize) (object);
+ (*G_OBJECT_CLASS (sheet_parent_class)->finalize)(object);
}
-void
-sheet_get_pointer (Sheet *sheet, gdouble *x, gdouble *y)
+/**
+ * position within the sheet in pixel coordinates
+ *
+ * coordinates are clamped to grid if grid is enabled
+ * see snap_to_grid
+ * zero point : top left corner of the window (not widget!)
+ *
+ * @param x horizontal, left to right
+ * @param y vertical, top to bottom
+ * @returns wether the position could be detected properly
+ *
+ * @attention never call in event handlers!
+ */
+gboolean sheet_get_pointer_pixel (Sheet *sheet, gdouble *x, gdouble *y)
{
- GtkWidget *widget;
- GtkAdjustment *hadjustment;
- GtkAdjustment *vadjustment;
- gdouble value, x1, y1;
+ GtkAdjustment *hadj = NULL, *vadj = NULL;
+ gdouble x1, y1;
gint _x, _y;
+ GdkDevice *device_pointer;
+ GdkRectangle allocation;
+ GdkDisplay *display;
+ GdkWindow *window;
+#if GTK_CHECK_VERSION (3,20,0)
+ GdkSeat *seat;
+#else
+ GdkDeviceManager *device_manager;
+#endif
+
+ // deprecated gtk_widget_get_pointer (GTK_WIDGET (sheet), &_x, &_y);
+ // replaced by a code copied from evince
+
+ if (G_UNLIKELY (!sheet || !gtk_widget_get_realized (GTK_WIDGET (sheet)))) {
+ NG_DEBUG ("Widget is not realized.");
+ return FALSE;
+ }
+
+ display = gtk_widget_get_display (GTK_WIDGET (sheet));
+
+#if GTK_CHECK_VERSION (3,20,0)
+ seat = gdk_display_get_default_seat (display);
+ device_pointer = gdk_seat_get_pointer (seat);
+#else
+ device_manager = gdk_display_get_device_manager (display);
+
+ // gdk_device_manager_get_client_pointer
+ // shall not be used within events
+ device_pointer = gdk_device_manager_get_client_pointer (device_manager);
+#endif
+
+ window = gtk_widget_get_window (GTK_WIDGET (sheet));
+
+ if (!window) {
+ NG_DEBUG ("Window is not realized.");
+ return FALSE;
+ }
+ // even though above is all defined the below will always return NUL for
+ // unknown reason and _x and _y are populated as expected
+ gdk_window_get_device_position (window, device_pointer, &_x, &_y, NULL);
+#if 0
+ if (!window) { //fails always
+ NG_DEBUG ("Window does not seem to be realized yet?");
+ return FALSE;
+ }
+#else
+ #if GTK_CHECK_VERSION (3,20,0)
+ NG_DEBUG ("\n%p %p %p %p %i %i\n\n", display, seat, device_pointer, window, _x, _y);
+ #else
+ NG_DEBUG ("\n%p %p %p %p %i %i\n\n", display, device_manager, device_pointer, window, _x, _y);
+ #endif
+#endif
+
+ gtk_widget_get_allocation (GTK_WIDGET (sheet), &allocation);
+
+ _x -= allocation.x;
+ _y -= allocation.y;
+
+ x1 = (gdouble)_x;
+ y1 = (gdouble)_y;
+
+ if (!sheet_get_adjustments (sheet, &hadj, &vadj))
+ return FALSE;
+
+ x1 += gtk_adjustment_get_value (hadj);
+ y1 += gtk_adjustment_get_value (vadj);
- gtk_widget_get_pointer (GTK_WIDGET (sheet), &_x, &_y);
- x1 = (gdouble) _x;
- y1 = (gdouble) _y;
-
- widget = gtk_widget_get_parent (GTK_WIDGET (sheet));
- hadjustment = gtk_scrolled_window_get_hadjustment (
- GTK_SCROLLED_WINDOW (widget));
- value = gtk_adjustment_get_value (hadjustment);
-
- x1 += value;
- vadjustment = gtk_scrolled_window_get_vadjustment (
- GTK_SCROLLED_WINDOW (widget));
- value = gtk_adjustment_get_value (vadjustment);
- y1 += value;
*x = x1;
*y = y1;
+ return TRUE;
+}
+
+/**
+ * get the pointer position in goocanvas coordinates
+ *
+ * @attention shall not be called in event callbacks,
+ * except for GDK_MOTION_... where it is useless since
+ * the event itself contains the cursor position
+ */
+gboolean sheet_get_pointer (Sheet *sheet, gdouble *x, gdouble *y)
+{
+ if (!sheet_get_pointer_pixel (sheet, x, y))
+ return FALSE;
+ goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), x, y);
+ return TRUE;
+}
+
+gboolean sheet_get_pointer_snapped (Sheet *sheet, gdouble *x, gdouble *y)
+{
+ if (!sheet_get_pointer_pixel (sheet, x, y))
+ return FALSE;
goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), x, y);
snap_to_grid (sheet->grid, x, y);
+ return TRUE;
}
-void
-sheet_get_zoom (const Sheet *sheet, gdouble *zoom)
+void sheet_get_zoom (const Sheet *sheet, gdouble *zoom)
{
+ g_return_if_fail (sheet);
+ g_return_if_fail (IS_SHEET (sheet));
+
*zoom = sheet->priv->zoom;
}
-static void
-sheet_set_zoom (const Sheet *sheet, double zoom)
+static void sheet_set_zoom (Sheet *sheet, const double zoom)
{
- goo_canvas_set_scale (GOO_CANVAS (sheet), zoom);
+ g_return_if_fail (sheet);
+ g_return_if_fail (IS_SHEET (sheet));
+
sheet->priv->zoom = zoom;
}
-void
-sheet_change_zoom (const Sheet *sheet, gdouble rate)
+/*
+ * \brief gets the sheets parent adjustments
+ *
+ * @returns TRUE on success
+ */
+gboolean sheet_get_adjustments (const Sheet *sheet, GtkAdjustment **hadj, GtkAdjustment **vadj)
+{
+ GtkWidget *parent;
+ GtkScrolledWindow *scrolled;
+
+ if (G_UNLIKELY (!sheet))
+ return FALSE;
+ if (G_UNLIKELY (!vadj || !hadj))
+ return FALSE;
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (sheet));
+ if (G_UNLIKELY (!parent || !GTK_IS_SCROLLED_WINDOW (parent)))
+ return FALSE;
+ scrolled = GTK_SCROLLED_WINDOW (parent);
+
+ *hadj = gtk_scrolled_window_get_hadjustment (scrolled);
+ if (G_UNLIKELY (!*hadj || !GTK_IS_ADJUSTMENT (*hadj)))
+ return FALSE;
+
+ *vadj = gtk_scrolled_window_get_vadjustment (scrolled);
+ if (G_UNLIKELY (!*vadj || !GTK_IS_ADJUSTMENT (*vadj)))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * \brief change the zoom by factor (zoom step)
+ *
+ * zoom origin when zooming in is the cursor
+ * zoom origin when zooming out is the center of the current viewport
+ *
+ * @param sheet
+ * @param factor values should be in the range of [0.5 .. 2]
+ */
+void sheet_zoom_step (Sheet *sheet, const gdouble factor)
{
- gdouble scale;
-
- sheet->priv->zoom *= rate;
- scale = goo_canvas_get_scale (GOO_CANVAS (sheet));
- scale = scale * rate;
- goo_canvas_set_scale (GOO_CANVAS (sheet), scale);
+ double zoom;
+
+ g_return_if_fail (sheet);
+ g_return_if_fail (IS_SHEET (sheet));
+
+ sheet_get_zoom (sheet, &zoom);
+ sheet_set_zoom (sheet, zoom * factor);
+
+ Coords adju, r, pointer, delta, center, pagesize;
+ GtkAdjustment *hadj = NULL, *vadj = NULL;
+ GooCanvas *canvas;
+ gboolean b = FALSE;
+
+ canvas = GOO_CANVAS (sheet);
+
+ // if we scroll out, just use the center as focus
+ // mouse curser centered scroll out "feels" awkward
+ if (factor < 1.) {
+ goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas));
+ return;
+ }
+
+ // get pointer position in pixels
+ // just skip the correction if we can not get the pointer
+ if (!sheet_get_pointer_pixel (sheet, &pointer.x, &pointer.y)) {
+ goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas));
+ g_warning ("Failed to get cursor position.");
+ return;
+ }
+
+ // top left corner in pixels
+ b = sheet_get_adjustments (sheet, &hadj, &vadj);
+ if (b) {
+ adju.x = gtk_adjustment_get_value (hadj);
+ adju.y = gtk_adjustment_get_value (vadj);
+ // get the page size in pixels
+ pagesize.x = gtk_adjustment_get_page_size (hadj);
+ pagesize.y = gtk_adjustment_get_page_size (vadj);
+ } else {
+ // FIXME untested codepath, check for variable space conversion
+ // FIXME Pixel vs GooUnits
+ gdouble left, right, top, bottom;
+ goo_canvas_get_bounds (canvas, &left, &top, &right, &bottom);
+ pagesize.x = bottom - top;
+ pagesize.y = right - left;
+ adju.x = adju.y = 0.;
+ }
+
+ // calculate the center of the widget in pixels
+ center.x = adju.x + pagesize.x / 2.;
+ center.y = adju.y + pagesize.y / 2.;
+
+ // calculate the delta between the center and the pointer in pixels
+ // this is required as the center is the zoom target
+ delta.x = pointer.x - center.x;
+ delta.y = pointer.y - center.y;
+
+ // increase the top left position in pixels by our calculated delta
+ adju.x += delta.x;
+ adju.y += delta.y;
+
+ // convert to canvas coords
+ goo_canvas_convert_from_pixels (canvas, &adju.x, &adju.y);
+
+ // the center of the canvas is now our cursor position
+ goo_canvas_scroll_to (canvas, adju.x, adju.y);
+
+ // calculate a correction term
+ // for the case that we can not scroll the pane far enough to
+ // compensate the whole off-due-to-wrong-center-error
+
+ if (b) {
+ r.x = gtk_adjustment_get_value (hadj);
+ r.y = gtk_adjustment_get_value (vadj);
+ goo_canvas_convert_from_pixels (canvas, &r.x, &r.y);
+ // the correction term in goo coordinates, to be subtracted from the
+ // backscroll distance
+ r.x -= adju.x;
+ r.y -= adju.y;
+ } else {
+ r.x = r.y = 0.;
+ }
+
+ // no the center is our cursor position and we can safely call scale
+ goo_canvas_set_scale (canvas, factor * goo_canvas_get_scale (canvas));
+
+ // top left corner in pixels after scaling
+ if (b) {
+ adju.x = gtk_adjustment_get_value (hadj);
+ adju.y = gtk_adjustment_get_value (vadj);
+ } else {
+ adju.x = adju.y = 0.;
+ }
+
+ // gtk_adjustment_get_page_size is constant before and after scale
+ adju.x -= (delta.x) / sheet->priv->zoom;
+ adju.y -= (delta.y) / sheet->priv->zoom;
+ goo_canvas_convert_from_pixels (canvas, &adju.x, &adju.y);
+
+ goo_canvas_scroll_to (canvas, adju.x - r.x, adju.y - r.y);
+
+ gtk_widget_queue_draw (GTK_WIDGET (canvas));
}
-// This function defines the drawing sheet on which schematic will be drawn
-GtkWidget *
-sheet_new (int width, int height)
+/**
+ * \brief defines the drawing widget on which the actual schematic will be drawn
+ *
+ * @param width width of the content area
+ * @param height height of the content area
+ */
+GtkWidget *sheet_new (const gdouble width, const gdouble height)
{
GooCanvas *sheet_canvas;
GooCanvasGroup *sheet_group;
GooCanvasPoints *points;
Sheet *sheet;
GtkWidget *sheet_widget;
- GooCanvasItem *root;
-
+ GooCanvasItem *root;
+
// Creation of the Canvas
sheet = SHEET (g_object_new (TYPE_SHEET, NULL));
sheet_canvas = GOO_CANVAS (sheet);
- g_object_set (G_OBJECT (sheet_canvas),
- "bounds-from-origin", FALSE,
- "bounds-padding", 4.0,
- "background-color-rgb", 0xFFFFFF,
- NULL);
-
- root = goo_canvas_get_root_item (sheet_canvas);
-
- sheet_group = GOO_CANVAS_GROUP (goo_canvas_group_new (
- root,
- NULL));
- sheet_widget = GTK_WIDGET (sheet);
+ g_object_set (G_OBJECT (sheet_canvas), "bounds-from-origin", FALSE, "bounds-padding", 4.0,
+ "background-color-rgb", 0xFFFFFF, NULL);
- goo_canvas_set_bounds (GOO_CANVAS (sheet_canvas), 0, 0,
- width + 20, height + 20);
+ root = goo_canvas_get_root_item (sheet_canvas);
- // Define vicinity around GooCanvasItem
- //sheet_canvas->close_enough = 6.0;
+ sheet_group = GOO_CANVAS_GROUP (goo_canvas_group_new (root, NULL));
+ sheet_widget = GTK_WIDGET (sheet);
+
+ goo_canvas_set_bounds (GOO_CANVAS (sheet_canvas), 0., 0., width + 20., height + 20.);
sheet->priv->width = width;
sheet->priv->height = height;
// Create the dot grid.
- sheet->grid = grid_create (GOO_CANVAS_ITEM (sheet_group),
- width,
- height);
+ sheet->grid = grid_new (GOO_CANVAS_ITEM (sheet_group), width, height);
// Everything outside the sheet should be gray.
// top //
- goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group),
- 0.0,
- 0.0,
- (double) width + 20.0,
- 20.0,
- "fill_color", "gray",
- "line-width", 0.0,
- NULL);
-
- goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group),
- 0.0,
- (double) height,
- (double) width + 20.0,
- (double) height + 20.0,
- "fill_color", "gray",
- "line-width", 0.0,
- NULL);
+ goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, 0.0, width + 20.0, 20.0, "fill_color",
+ "gray", "line-width", 0.0, NULL);
- // right //
- goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group),
- 0.0,
- 0.0,
- 20.0,
- (double) height + 20.0,
- "fill_color", "gray",
- "line-width", 0.0,
- NULL);
-
- goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group),
- (double) width,
- 0.0,
- (double) width + 20.0,
- (double) height + 20.0,
- "fill_color", "gray",
- "line-width", 0.0,
- NULL);
+ goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, height, width + 20.0, height + 20.0,
+ "fill_color", "gray", "line-width", 0.0, NULL);
+ // right //
+ goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, 0.0, 20.0, height + 20.0, "fill_color",
+ "gray", "line-width", 0.0, NULL);
+
+ goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), width, 0.0, width + 20.0, height + 20.0,
+ "fill_color", "gray", "line-width", 0.0, NULL);
+
+ if (oregano_options_debug_directions ()) {
+ goo_canvas_polyline_new_line (GOO_CANVAS_ITEM (sheet_group), 10.0, 10.0, 50.0, 10.0,
+ "stroke-color", "green", "line-width", 2.0, "end-arrow", TRUE,
+ NULL);
+ goo_canvas_text_new (GOO_CANVAS_ITEM (sheet_group), "x", 90.0, 10.0, -1.0,
+ GOO_CANVAS_ANCHOR_WEST, "fill-color", "green", NULL);
+
+ goo_canvas_polyline_new_line (GOO_CANVAS_ITEM (sheet_group), 10.0, 10.0, 10.0, 50.0,
+ "stroke-color", "red", "line-width", 2.0, "end-arrow", TRUE,
+ NULL);
+ goo_canvas_text_new (GOO_CANVAS_ITEM (sheet_group), "y", 10.0, 90.0, -1.0,
+ GOO_CANVAS_ANCHOR_CENTER, "fill-color", "red", NULL);
+ }
// Draw a thin black border around the sheet.
points = goo_canvas_points_new (5);
points->coords[0] = 20.0;
@@ -351,57 +519,94 @@ sheet_new (int width, int height)
points->coords[7] = height;
points->coords[8] = 20.0;
points->coords[9] = 20.0;
-
- goo_canvas_polyline_new (GOO_CANVAS_ITEM (sheet_group),
- FALSE, 0,
- "line-width", 1.0,
- "points", points,
- NULL);
+
+ goo_canvas_polyline_new (GOO_CANVAS_ITEM (sheet_group), FALSE, 0, "line-width", 1.0, "points",
+ points, NULL);
goo_canvas_points_unref (points);
// Finally, create the object group that holds all objects.
- sheet->object_group = GOO_CANVAS_GROUP (goo_canvas_group_new (
- root,
- "x", 0.0,
- "y", 0.0,
- NULL));
-
- sheet->priv->selected_group = GOO_CANVAS_GROUP (goo_canvas_group_new (
- GOO_CANVAS_ITEM (sheet->object_group),
- "x", 0.0,
- "y", 0.0,
- NULL));
-
- sheet->priv->floating_group = GOO_CANVAS_GROUP (goo_canvas_group_new (
- GOO_CANVAS_ITEM (sheet->object_group),
- "x", 0.0,
- "y", 0.0,
- NULL));
-
- // Hash table that keeps maps coordinate to a specific dot.
- sheet->priv->node_dots = g_hash_table_new_full (dot_hash, dot_equal, g_free,
- NULL);
-
+ sheet->object_group = GOO_CANVAS_GROUP (goo_canvas_group_new (root, "x", 0.0, "y", 0.0, NULL));
+ NG_DEBUG ("root group %p", sheet->object_group);
+
+ sheet->priv->selected_group = GOO_CANVAS_GROUP (
+ goo_canvas_group_new (GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL));
+ NG_DEBUG ("selected group %p", sheet->priv->selected_group);
+
+ sheet->priv->floating_group = GOO_CANVAS_GROUP (
+ goo_canvas_group_new (GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL));
+ NG_DEBUG ("floating group %p", sheet->priv->floating_group);
+
+ // Hash table that maps coordinates to a specific dot.
+ sheet->priv->node_dots = g_hash_table_new_full (dot_hash, dot_equal, g_free, NULL);
+
+ // this requires object_group to be setup properly
+ sheet->priv->rubberband_info = rubberband_info_new (sheet);
+ sheet->priv->create_wire_info = create_wire_info_new (sheet);
+
return sheet_widget;
}
-static void
-sheet_set_property (GObject *object,
- guint prop_id, const GValue *value, GParamSpec *spec)
+/*
+ * Replace the current sheet with a new one (eventually
+ * with a different size, i.e. with a different width
+ * and/or height).
+ */
+gboolean sheet_replace (SchematicView *sv)
{
- const Sheet *sheet = SHEET (object);
+ g_return_val_if_fail (sv != NULL, FALSE);
+ g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), FALSE);
+
+ Schematic *sm = schematic_view_get_schematic (sv);
+ Sheet *old_sheet = schematic_view_get_sheet (sv);
+ Sheet *sheet;
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (old_sheet));
+ gdouble zoom;
+
+ g_return_val_if_fail (old_sheet != NULL, FALSE);
+ g_return_val_if_fail (IS_SHEET (old_sheet), FALSE);
+
+ sheet_get_zoom (old_sheet, &zoom);
+ sheet = SHEET (sheet_new ((double) schematic_get_width (sm) + SHEET_BORDER, (double) schematic_get_height (sm) + SHEET_BORDER));
+ if (!sheet)
+ return FALSE;
+
+ sheet_set_zoom (sheet, zoom);
+ goo_canvas_set_scale (GOO_CANVAS (sheet), zoom);
+
+ g_signal_connect (G_OBJECT (sheet), "event", G_CALLBACK (sheet_event_callback),
+ sheet);
+
+ schematic_view_set_sheet (sv, sheet);
+
+ rubberband_info_destroy (old_sheet->priv->rubberband_info);
+ old_sheet->priv->rubberband_info = NULL;
+
+ create_wire_info_destroy (old_sheet->priv->create_wire_info);
+ old_sheet->priv->create_wire_info = NULL;
+
+ gtk_widget_destroy (GTK_WIDGET (old_sheet));
+
+ gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (sheet));
+
+ gtk_widget_grab_focus (GTK_WIDGET (sheet));
+
+ return TRUE;
+}
+
+static void sheet_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
+{
+ Sheet *sheet = SHEET (object);
switch (prop_id) {
case ARG_ZOOM:
- sheet_set_zoom (sheet, g_value_get_double (value));
+ sheet_set_zoom (sheet, (const double) g_value_get_double (value));
break;
}
}
-static void
-sheet_get_property (GObject *object,
- guint prop_id, GValue *value, GParamSpec *spec)
+static void sheet_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *spec)
{
const Sheet *sheet = SHEET (object);
@@ -416,84 +621,82 @@ sheet_get_property (GObject *object,
}
}
-void
-sheet_scroll (const Sheet *sheet, int delta_x, int delta_y)
+/*
+ * scroll to <dx,dy> in pixels relative to the current coords
+ * note that pixels are _not_ affected by zoom
+ */
+void sheet_scroll_pixel (const Sheet *sheet, int delta_x, int delta_y)
{
- GtkAdjustment *hadj, *vadj;
+ GtkAdjustment *hadj = NULL, *vadj = NULL;
GtkAllocation allocation;
gfloat vnew, hnew;
gfloat hmax, vmax;
+ gfloat x1, y1;
const SheetPriv *priv = sheet->priv;
- hadj = gtk_container_get_focus_hadjustment (GTK_CONTAINER (sheet));
- vadj = gtk_container_get_focus_vadjustment (GTK_CONTAINER (sheet));
+ if (sheet_get_adjustments (sheet, &hadj, &vadj)) {
+ x1 = gtk_adjustment_get_value (hadj);
+ y1 = gtk_adjustment_get_value (vadj);
+ } else {
+ x1 = y1 = 0.f;
+ }
gtk_widget_get_allocation (GTK_WIDGET (sheet), &allocation);
if (priv->width > allocation.width)
- hmax = (gfloat) (priv->width - allocation.width);
+ hmax = (gfloat)(priv->width - allocation.width);
else
- hmax = 0.0;
+ hmax = 0.f;
if (priv->height > allocation.height)
- vmax = (gfloat) (priv->height - allocation.height);
+ vmax = (gfloat)(priv->height - allocation.height);
else
- vmax = 0.0;
+ vmax = 0.f;
- hnew = CLAMP (gtk_adjustment_get_value (hadj) + (gfloat) delta_x, 0.0, hmax);
- vnew = CLAMP (gtk_adjustment_get_value (vadj) + (gfloat) delta_y, 0.0, vmax);
+ hnew = CLAMP (x1 + (gfloat)delta_x, 0.f, hmax);
+ vnew = CLAMP (y1 + (gfloat)delta_y, 0.f, vmax);
- if (hnew != gtk_adjustment_get_value (hadj)) {
+ if (hadj && hnew != x1) {
gtk_adjustment_set_value (hadj, hnew);
g_signal_emit_by_name (G_OBJECT (hadj), "value_changed");
}
- if (vnew != gtk_adjustment_get_value (vadj)) {
+ if (vadj && vnew != y1) {
gtk_adjustment_set_value (vadj, vnew);
g_signal_emit_by_name (G_OBJECT (vadj), "value_changed");
}
}
-void
-sheet_get_size_pixels (const Sheet *sheet, guint *width, guint *height)
+void sheet_get_size_pixels (const Sheet *sheet, guint *width, guint *height)
{
*width = sheet->priv->width * sheet->priv->zoom;
*height = sheet->priv->height * sheet->priv->zoom;
}
-void
-sheet_remove_selected_object (const Sheet *sheet, SheetItem *item)
+void sheet_remove_selected_object (const Sheet *sheet, SheetItem *item)
{
- sheet->priv->selected_objects =
- g_list_remove (sheet->priv->selected_objects, item);
+ sheet->priv->selected_objects = g_list_remove (sheet->priv->selected_objects, item);
}
-void
-sheet_prepend_selected_object (Sheet *sheet, SheetItem *item)
+void sheet_prepend_selected_object (Sheet *sheet, SheetItem *item)
{
- sheet->priv->selected_objects =
- g_list_prepend (sheet->priv->selected_objects, item);
+ sheet->priv->selected_objects = g_list_prepend (sheet->priv->selected_objects, item);
}
-void
-sheet_remove_floating_object (const Sheet *sheet, SheetItem *item)
+void sheet_remove_floating_object (const Sheet *sheet, SheetItem *item)
{
- sheet->priv->floating_objects =
- g_list_remove (sheet->priv->floating_objects, item);
+ sheet->priv->floating_objects = g_list_remove (sheet->priv->floating_objects, item);
}
-void
-sheet_prepend_floating_object (Sheet *sheet, SheetItem *item)
+void sheet_prepend_floating_object (Sheet *sheet, SheetItem *item)
{
- sheet->priv->floating_objects =
- g_list_prepend (sheet->priv->floating_objects, item);
+ sheet->priv->floating_objects = g_list_prepend (sheet->priv->floating_objects, item);
}
-void
-sheet_connect_part_item_to_floating_group (Sheet *sheet, gpointer *sv)
+void sheet_connect_part_item_to_floating_group (Sheet *sheet, gpointer *sv)
{
- g_return_if_fail (sheet != NULL);
+ g_return_if_fail (sheet);
g_return_if_fail (IS_SHEET (sheet));
- g_return_if_fail (sv != NULL);
+ g_return_if_fail (sv);
g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
sheet->state = SHEET_STATE_FLOAT_START;
@@ -501,29 +704,25 @@ sheet_connect_part_item_to_floating_group (Sheet *sheet, gpointer *sv)
if (sheet->priv->float_handler_id != 0)
return;
- sheet->priv->float_handler_id = g_signal_connect(G_OBJECT (sheet),
- "event", G_CALLBACK (sheet_item_floating_event),
- sv);
+ sheet->priv->float_handler_id =
+ g_signal_connect (G_OBJECT (sheet), "event", G_CALLBACK (sheet_item_floating_event), sv);
}
-void
-sheet_show_node_labels (Sheet *sheet, gboolean show)
+void sheet_show_node_labels (Sheet *sheet, gboolean show)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- GList *item;
+ GList *item = NULL;
- for (item = sheet->priv->items; item; item=item->next) {
- if (IS_PART_ITEM (item->data))
- if (part_get_num_pins (PART (sheet_item_get_data (SHEET_ITEM(item->data))))==1)
+ for (item = sheet->priv->items; item; item = item->next) {
+ if (IS_PART_ITEM (item->data))
+ if (part_get_num_pins (PART (sheet_item_get_data (SHEET_ITEM (item->data)))) == 1)
part_item_show_node_labels (PART_ITEM (item->data), show);
- }
- g_list_free_full (item, g_object_unref);
+ }
}
-void
-sheet_add_item (Sheet *sheet, SheetItem *item)
+void sheet_add_item (Sheet *sheet, SheetItem *item)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -533,312 +732,185 @@ sheet_add_item (Sheet *sheet, SheetItem *item)
sheet->priv->items = g_list_prepend (sheet->priv->items, item);
}
-int
-sheet_rubberband_timeout_cb (Sheet *sheet)
-{
- static double width_old = 0, height_old = 0;
- double x, y;
- double height, width;
-
- double dx, dy;
- GList *list;
- SheetPos p1, p2;
-
- // Obtains the current pointer position and modifier state.
- // The position is given in coordinates relative to window.
- sheet_get_pointer (sheet, &x, &y);
-
- if (x < sheet->priv->rubberband->start_x) {
- width = sheet->priv->rubberband->start_x - x;
- }
- else {
- double tmp = x;
- x = sheet->priv->rubberband->start_x;
- width = tmp - sheet->priv->rubberband->start_x;
- }
-
- if (y < sheet->priv->rubberband->start_y) {
- height = sheet->priv->rubberband->start_y - y;
- }
- else {
- double tmp = y;
- y = sheet->priv->rubberband->start_y;
- height = tmp - sheet->priv->rubberband->start_y;
- }
-
- p1.x = x;
- p1.y = y;
- p2.x = x + width;
- p2.y = y + height;
-
- // Scroll the sheet if needed.
- // Need FIX
- /*{
- int width, height;
- int dx = 0, dy = 0;
- GtkAllocation allocation;
-
- sheet_get_pointer (sheet, &x, &y);
-
- gtk_widget_get_allocation (GTK_WIDGET (sheet), &allocation);
- width = allocation.width;
- height = allocation.height;
-
- if (_x < 0)
- dx = -1;
- else if (_x > width)
- dx = 1;
-
- if (_y < 0)
- dy = -1;
- else if (_y > height)
- dy = 1;
-
- if (!(_x > 0 && _x < width && _y > 0 && _y < height))
- sheet_scroll (sheet, dx * 5, dy * 5);
- }*/
-
- // Modify the rubberband rectangle if needed
- dx = fabs (width - width_old);
- dy = fabs (height - height_old);
- if (dx > 1.0 || dy > 1.0) {
- // Save old state
- width_old = width;
- height_old = height;
-
- for (list = sheet->priv->items; list; list = list->next) {
- sheet_item_select_in_area (list->data, &p1, &p2);
- }
-
- g_object_set (sheet->priv->rubberband->rectangle,
- "x", (double) x,
- "y", (double) y,
- "width", width,
- "height", height,
- NULL);
- }
- g_list_free_full (list, g_object_unref);
- return TRUE;
-}
-
-void
-sheet_stop_rubberband (Sheet *sheet, GdkEventButton *event)
-{
- GList *list;
-
- g_source_remove (sheet->priv->rubberband->timeout_id);
- sheet->priv->rubberband->state = RUBBER_NO;
-
- if (sheet->priv->preserve_selection_items != NULL) {
- for (list = sheet->priv->preserve_selection_items; list; list = list->next)
- sheet_item_set_preserve_selection (SHEET_ITEM (list->data), FALSE);
-
- g_list_free (sheet->priv->preserve_selection_items);
- sheet->priv->preserve_selection_items = NULL;
- }
-
- goo_canvas_pointer_ungrab (GOO_CANVAS (sheet),
- GOO_CANVAS_ITEM (sheet->grid), event->time);
-
- goo_canvas_item_remove (GOO_CANVAS_ITEM (sheet->priv->rubberband->rectangle));
- g_list_free_full (list, g_object_unref);
-}
-
-void
-sheet_setup_rubberband (Sheet *sheet, GdkEventButton *event)
-{
- double x, y;
- cairo_pattern_t *pattern;
- static guchar stipple_data[16] =
- {0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255 };
-
- x = event->x; //the x coordinate of the pointer relative to the window.
- y = event->y; //the y coordinate of the pointer relative to the window.
- goo_canvas_convert_from_pixels (GOO_CANVAS (sheet), &x, &y);
-
- sheet->priv->rubberband->start_x = x;
- sheet->priv->rubberband->start_y = y;
-
- sheet->priv->rubberband->state = RUBBER_YES;
- sheet->priv->rubberband->click_start_state = event->state;
-
- pattern = create_stipple ("lightgrey", stipple_data);
-
- sheet->priv->rubberband->rectangle = goo_canvas_rect_new (
- GOO_CANVAS_ITEM (sheet->object_group),
- x, y, 0.0, 0.0,
- "stroke-color", "black",
- "line-width", 0.2,
- "fill-pattern", pattern,
- NULL);
-
- goo_canvas_pointer_grab (GOO_CANVAS (sheet), GOO_CANVAS_ITEM (sheet->grid),
- (GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
- NULL, event->time);
-
- // Mark all the selected objects to preserve their selected state
- // if SHIFT is pressed while rubberbanding.
- if (event->state & GDK_SHIFT_MASK) {
- sheet->priv->preserve_selection_items =
- g_list_copy (sheet_preserve_selection (sheet));
- }
-
- sheet->priv->rubberband->timeout_id = g_timeout_add (
- 10,
- (gpointer) sheet_rubberband_timeout_cb,
- (gpointer) sheet);
-}
-
-GList *
-sheet_preserve_selection (Sheet *sheet)
+/**
+ * save the selection
+ * @attention not stackable
+ */
+GList *sheet_preserve_selection (Sheet *sheet)
{
g_return_val_if_fail (sheet != NULL, FALSE);
g_return_val_if_fail (IS_SHEET (sheet), FALSE);
-
- GList *list;
+
+ GList *list = NULL;
for (list = sheet->priv->selected_objects; list; list = list->next) {
sheet_item_set_preserve_selection (SHEET_ITEM (list->data), TRUE);
}
// Return the list so that we can remove the preserve_selection
// flags later.
- g_list_free_full (list, g_object_unref);
return sheet->priv->selected_objects;
}
-int
-sheet_event_callback (GtkWidget *widget, GdkEvent *event, Sheet *sheet)
+int sheet_event_callback (GtkWidget *widget, GdkEvent *event, Sheet *sheet)
{
+ GtkWidgetClass *wklass = GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class);
switch (event->type) {
- case GDK_3BUTTON_PRESS:
- // We don't not care about triple clicks on the sheet.
- return FALSE;
- case GDK_2BUTTON_PRESS:
- // The sheet does not care about double clicks, but invoke the
- // canvas event handler and see if an item picks up the event.
- if ((*GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->button_press_event) (widget, (GdkEventButton *)event))
- return TRUE;
- else
- return FALSE;
- case GDK_BUTTON_PRESS:
- // If we are in the middle of something else, don't interfere
- // with that.
- if (sheet->state != SHEET_STATE_NONE) {
- return FALSE;
- }
- if ((* GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->button_press_event) (widget, (GdkEventButton *) event)) {
- return TRUE;
- }
+ case GDK_3BUTTON_PRESS:
+ // We do not care about triple clicks on the sheet.
+ return FALSE;
- if (event->button.button == 3) {
- run_context_menu (
- schematic_view_get_schematicview_from_sheet (sheet),
- (GdkEventButton *) event);
- return TRUE;
- }
+ case GDK_2BUTTON_PRESS:
+ // The sheet does not care about double clicks, but invoke the
+ // canvas event handler and see if an item picks up the event.
+ return wklass->button_press_event (widget, (GdkEventButton *)event);
- if (event->button.button == 1) {
- if (!(event->button.state & GDK_SHIFT_MASK))
- sheet_select_all (sheet, FALSE);
+ case GDK_BUTTON_PRESS:
+ // If we are in the middle of something else, don't interfere
+ // with that.
+ if (sheet->state != SHEET_STATE_NONE) {
+ return FALSE;
+ }
- sheet_setup_rubberband (sheet, (GdkEventButton *) event);
- return TRUE;
- }
- break;
- case GDK_BUTTON_RELEASE:
- if (event->button.button == 4 || event->button.button == 5)
- return TRUE;
+ if (wklass->button_press_event (widget, (GdkEventButton *)event)) {
+ return TRUE;
+ }
- if (event->button.button == 1 &&
- sheet->priv->rubberband->state == RUBBER_YES) {
- sheet_stop_rubberband (sheet, (GdkEventButton *) event);
- return TRUE;
- }
+ if (event->button.button == 3) {
+ run_context_menu (schematic_view_get_schematicview_from_sheet (sheet),
+ (GdkEventButton *)event);
+ return TRUE;
+ }
- if (GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)->button_release_event != NULL) {
- return GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->button_release_event (widget, (GdkEventButton *) event);
- }
+ if (event->button.button == 1) {
+ if (!(event->button.state & GDK_SHIFT_MASK))
+ sheet_select_all (sheet, FALSE);
- break;
+ rubberband_start (sheet, event);
+ return TRUE;
+ }
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 4 || event->button.button == 5)
+ return TRUE;
+
+ if (event->button.button == 1 && sheet->priv->rubberband_info->state == RUBBERBAND_ACTIVE) {
+ rubberband_finish (sheet, event);
+ return TRUE;
+ }
+ if (wklass->button_release_event != NULL) {
+ return wklass->button_release_event (widget, (GdkEventButton *)event);
+ }
+ break;
- case GDK_SCROLL:
- if (((GdkEventScroll *)event)->direction == GDK_SCROLL_UP) {
+ case GDK_SCROLL: {
+ GdkEventScroll *scr_event = (GdkEventScroll *)event;
+ if (scr_event->state & GDK_SHIFT_MASK) {
+ // Scroll horizontally
+ if (scr_event->direction == GDK_SCROLL_UP)
+ sheet_scroll_pixel (sheet, -30, 0);
+ else if (scr_event->direction == GDK_SCROLL_DOWN)
+ sheet_scroll_pixel (sheet, 30, 0);
+
+ } else if (scr_event->state & GDK_CONTROL_MASK) {
+ // Scroll vertically
+ if (scr_event->direction == GDK_SCROLL_UP)
+ sheet_scroll_pixel (sheet, 0, -30);
+ else if (scr_event->direction == GDK_SCROLL_DOWN)
+ sheet_scroll_pixel (sheet, 0, 30);
+
+ } else {
+ // Zoom
+ if (scr_event->direction == GDK_SCROLL_UP) {
double zoom;
sheet_get_zoom (sheet, &zoom);
if (zoom < ZOOM_MAX)
- sheet_change_zoom (sheet, 1.1);
- }
- else if (((GdkEventScroll *)event)->direction == GDK_SCROLL_DOWN) {
- double zoom;
+ sheet_zoom_step (sheet, 1.1);
+ } else if (scr_event->direction == GDK_SCROLL_DOWN) {
+ double zoom;
sheet_get_zoom (sheet, &zoom);
if (zoom > ZOOM_MIN)
- sheet_change_zoom (sheet, 0.9);
- }
- break;
- case GDK_MOTION_NOTIFY:
- if (GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->motion_notify_event != NULL) {
- return GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->motion_notify_event (widget, (GdkEventMotion *) event);
+ sheet_zoom_step (sheet, 0.9);
}
- case GDK_ENTER_NOTIFY:
- GTK_WIDGET_CLASS (sheet->priv->sheet_parent_class)
- ->enter_notify_event (widget, (GdkEventCrossing *) event);
- case GDK_KEY_PRESS:
- switch (event->key.keyval) {
- case GDK_KEY_R:
- case GDK_KEY_r:
- if (sheet->state == SHEET_STATE_NONE)
- sheet_rotate_selection (sheet);
- break;
- case GDK_KEY_Home:
- case GDK_KEY_End:
- break;
- case GDK_KEY_Left:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, -20, 0);
- break;
- case GDK_KEY_Up:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, 0, -20);
- break;
- case GDK_KEY_Right:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, 20, 0);
- break;
- case GDK_KEY_Down:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, 0, 20);
- break;
- case GDK_KEY_Page_Up:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, 0, -120);
- break;
- case GDK_KEY_Page_Down:
- if (event->key.state & GDK_MOD1_MASK)
- sheet_scroll (sheet, 0, 120);
- break;
- case GDK_KEY_Escape:
- g_signal_emit_by_name (G_OBJECT (sheet), "cancel");
- break;
- case GDK_KEY_Delete:
- sheet_delete_selection (sheet);
- break;
- default:
- return FALSE;
+ }
+ } break;
+
+ case GDK_MOTION_NOTIFY:
+ if (sheet->priv->rubberband_info->state == RUBBERBAND_ACTIVE) {
+ rubberband_update (sheet, event);
+ return TRUE;
+ }
+ if (wklass->motion_notify_event != NULL) {
+ return wklass->motion_notify_event (widget, (GdkEventMotion *)event);
+ }
+ break;
+
+ case GDK_ENTER_NOTIFY:
+ return wklass->enter_notify_event (widget, (GdkEventCrossing *)event);
+
+ case GDK_KEY_PRESS:
+ switch (event->key.keyval) {
+ case GDK_KEY_R:
+ case GDK_KEY_r:
+ if (sheet->state == SHEET_STATE_NONE)
+ sheet_rotate_selection (sheet, 90);
+ break;
+ case GDK_KEY_L:
+ case GDK_KEY_l:
+ if (sheet->state == SHEET_STATE_NONE)
+ sheet_rotate_selection (sheet, -90);
+ break;
+ case GDK_KEY_Home:
+ case GDK_KEY_End:
+ break;
+ case GDK_KEY_Left:
+ if (event->key.state & GDK_MOD1_MASK) {
+ sheet_scroll_pixel (sheet, -20, 0);
+ } else {
+ sheet_move_selection (sheet, -20., 0.);
+ }
+ break;
+ case GDK_KEY_Up:
+ if (event->key.state & GDK_MOD1_MASK) {
+ sheet_scroll_pixel (sheet, 0, -20);
+ } else {
+ sheet_move_selection (sheet, 0., -20.);
+ }
+ break;
+ case GDK_KEY_Right:
+ if (event->key.state & GDK_MOD1_MASK) {
+ sheet_scroll_pixel (sheet, 20, 0);
+ } else {
+ sheet_move_selection (sheet, +20., 0.);
+ }
+ break;
+ case GDK_KEY_Down:
+ if (event->key.state & GDK_MOD1_MASK) {
+ sheet_scroll_pixel (sheet, 0, 20);
+ } else {
+ sheet_move_selection (sheet, 0., +20.);
}
+ break;
+ case GDK_KEY_Escape:
+ g_signal_emit_by_name (G_OBJECT (sheet), "cancel");
+ break;
+ case GDK_KEY_Delete:
+ sheet_delete_selection (sheet);
+ break;
default:
return FALSE;
+ }
+ default:
+ return FALSE;
}
return TRUE;
}
-void
-sheet_select_all (Sheet *sheet, gboolean select)
+/**
+ * select all items on the sheet
+ */
+void sheet_select_all (Sheet *sheet, gboolean select)
{
GList *list;
@@ -850,68 +922,104 @@ sheet_select_all (Sheet *sheet, gboolean select)
if (!select)
sheet_release_selected_objects (sheet);
- g_list_free_full (list, g_object_unref);
}
-void
-sheet_rotate_selection (Sheet *sheet)
+/**
+ * rotate the currently selected on the sheet
+ */
+void sheet_rotate_selection (Sheet *sheet, gint angle)
+{
+ g_return_if_fail (sheet != NULL);
+ g_return_if_fail (IS_SHEET (sheet));
+
+ if (sheet->priv->selected_objects != NULL)
+ rotate_items (sheet, sheet->priv->selected_objects, angle);
+}
+
+/**
+ * move the currently selected on the sheet
+ */
+void sheet_move_selection (Sheet *sheet, gdouble x, gdouble y)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
+ const Coords delta = {x, y};
if (sheet->priv->selected_objects != NULL)
- rotate_items (sheet, sheet->priv->selected_objects);
+ move_items (sheet, sheet->priv->selected_objects, &delta);
}
-void
-sheet_rotate_ghosts (Sheet *sheet)
+/**
+ * rotate floating items
+ */
+void sheet_rotate_ghosts (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
if (sheet->priv->floating_objects != NULL)
- rotate_items (sheet, sheet->priv->floating_objects);
+ rotate_items (sheet, sheet->priv->floating_objects, 90);
}
-static void
-rotate_items (Sheet *sheet, GList *items)
+static void rotate_items (Sheet *sheet, GList *items, gint angle)
{
GList *list, *item_data_list;
- SheetPos center, b1, b2;
+ Coords center, b1, b2;
item_data_list = NULL;
for (list = items; list; list = list->next) {
- item_data_list = g_list_prepend (item_data_list,
- sheet_item_get_data (list->data));
+ item_data_list = g_list_prepend (item_data_list, sheet_item_get_data (list->data));
}
item_data_list_get_absolute_bbox (item_data_list, &b1, &b2);
- center.x = (b2.x - b1.x) / 2 + b1.x;
- center.y = (b2.y - b1.y) / 2 + b1.y;
+ center = coords_average (&b1, &b2);
snap_to_grid (sheet->grid, &center.x, &center.y);
for (list = item_data_list; list; list = list->next) {
ItemData *item_data = list->data;
+ if (item_data == NULL)
+ continue;
if (sheet->state == SHEET_STATE_NONE)
item_data_unregister (item_data);
- item_data_rotate (item_data, 90, &center);
+ item_data_rotate (item_data, angle, &center);
if (sheet->state == SHEET_STATE_NONE)
item_data_register (item_data);
}
g_list_free (item_data_list);
- g_list_free_full (list, g_object_unref);
}
-void
-sheet_delete_selection (Sheet *sheet)
+static void move_items (Sheet *sheet, GList *items, const Coords *trans)
{
- GList *list, *copy;
+ GList *list;
+
+ for (list = items; list; list = list->next) {
+ g_assert (list->data != NULL);
+ ItemData *item_data = sheet_item_get_data (list->data);
+ g_assert (item_data != NULL);
+
+ if (sheet->state == SHEET_STATE_NONE)
+ item_data_unregister (item_data);
+
+ item_data_move (item_data, trans);
+
+ if (sheet->state == SHEET_STATE_NONE)
+ item_data_register (item_data);
+ }
+}
+
+/**
+ * remove the currently selected items from the sheet
+ * (especially their goocanvas representators)
+ */
+void sheet_delete_selection (Sheet *sheet)
+{
+ GList *copy, *iter;
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -920,47 +1028,53 @@ sheet_delete_selection (Sheet *sheet)
return;
copy = g_list_copy (sheet->priv->selected_objects);
- for (list = copy; list; list = list->next) {
- sheet_remove_item_in_sheet (SHEET_ITEM (list->data), sheet);
- goo_canvas_item_remove (GOO_CANVAS_ITEM (list->data));
+
+ for (iter = copy; iter; iter = iter->next) {
+ sheet_remove_item_in_sheet (SHEET_ITEM (iter->data), sheet);
+ goo_canvas_item_remove (GOO_CANVAS_ITEM (iter->data));
+ g_object_unref (iter->data);
}
+ g_list_free (copy);
+ // function <sheet_remove_item_in_sheet>
+ // requires selected_objects, items, floating_objects
+ // to be not NULL!
g_list_free (sheet->priv->selected_objects);
sheet->priv->selected_objects = NULL;
-
- g_list_free (copy);
- g_list_free_full (list, g_object_unref);
}
-void
-sheet_release_selected_objects (Sheet *sheet)
+/**
+ * removes all canvas items in the selected canvas group from their parents
+ * but does NOT delete them
+ */
+void sheet_release_selected_objects (Sheet *sheet)
{
GList *list, *copy;
GooCanvasGroup *group;
- gint item_nbr;
-
+ gint item_nbr;
+
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
group = sheet->priv->selected_group;
copy = g_list_copy (sheet->priv->selected_objects);
-
+
// Remove all the selected_objects into selected_group
for (list = copy; list; list = list->next) {
- item_nbr = goo_canvas_item_find_child (GOO_CANVAS_ITEM (group),
- GOO_CANVAS_ITEM (list->data));
- goo_canvas_item_remove_child (GOO_CANVAS_ITEM (group),
- item_nbr);
+ item_nbr =
+ goo_canvas_item_find_child (GOO_CANVAS_ITEM (group), GOO_CANVAS_ITEM (list->data));
+ goo_canvas_item_remove_child (GOO_CANVAS_ITEM (group), item_nbr);
}
g_list_free (copy);
-
+
g_list_free (sheet->priv->selected_objects);
- g_list_free_full (list, g_object_unref);
sheet->priv->selected_objects = NULL;
}
-GList *
-sheet_get_selection (Sheet *sheet)
+/**
+ * @returns [transfer-none] the list of selected objects
+ */
+GList *sheet_get_selection (Sheet *sheet)
{
g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
@@ -968,8 +1082,10 @@ sheet_get_selection (Sheet *sheet)
return sheet->priv->selected_objects;
}
-void
-sheet_update_parts (Sheet *sheet)
+/**
+ * update the node lables of all parts in the current sheet
+ */
+void sheet_update_parts (Sheet *sheet)
{
GList *list;
@@ -980,93 +1096,83 @@ sheet_update_parts (Sheet *sheet)
if (IS_PART_ITEM (list->data))
part_item_update_node_label (PART_ITEM (list->data));
}
- g_list_free_full (list, g_object_unref);
}
-void
-sheet_flip_selection (Sheet *sheet, gboolean horizontal)
+/**
+ * flip currently selected items
+ */
+void sheet_flip_selection (Sheet *sheet, IDFlip direction)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
if (sheet->priv->selected_objects != NULL)
- flip_items (sheet, sheet->priv->selected_objects, horizontal);
+ flip_items (sheet, sheet->priv->selected_objects, direction);
}
-void
-sheet_flip_ghosts (Sheet *sheet, gboolean horizontal)
+/**
+ * flip currently floating items
+ */
+void sheet_flip_ghosts (Sheet *sheet, IDFlip direction)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
if (sheet->priv->floating_objects != NULL)
- flip_items (sheet, sheet->priv->floating_objects, horizontal);
+ flip_items (sheet, sheet->priv->floating_objects, direction);
}
-static void
-flip_items (Sheet *sheet, GList *items, gboolean horizontal)
+static void flip_items (Sheet *sheet, GList *items, IDFlip direction)
{
- GList *list, *item_data_list;
- SheetPos center, b1, b2;
- SheetPos after;
+ GList *iter, *item_data_list;
+ Coords center, b1, b2;
+ Coords after;
item_data_list = NULL;
- for (list = items; list; list = list->next) {
- item_data_list = g_list_prepend (item_data_list,
- sheet_item_get_data (list->data));
+ for (iter = items; iter; iter = iter->next) {
+ item_data_list = g_list_prepend (item_data_list, sheet_item_get_data (iter->data));
}
item_data_list_get_absolute_bbox (item_data_list, &b1, &b2);
- center.x = (b2.x + b1.x) / 2;
- center.y = (b2.y + b1.y) / 2;
+ // FIXME center is currently not used by item_data_flip (part.c implentation)
+ center.x = b2.x / 2 + b1.x / 2;
+ center.y = b2.y / 2 + b1.y / 2;
- for (list = item_data_list; list; list = list->next) {
- ItemData *item_data = list->data;
+ // FIXME - registering an item after flipping it still creates an offset as
+ // the position is still 0
+ for (iter = item_data_list; iter; iter = iter->next) {
+ ItemData *item_data = iter->data;
if (sheet->state == SHEET_STATE_NONE)
item_data_unregister (item_data);
- item_data_flip (item_data, horizontal, &center);
+ item_data_flip (item_data, direction, &center);
// Make sure we snap to grid.
item_data_get_pos (item_data, &after);
snap_to_grid (sheet->grid, &after.x, &after.y);
- item_data_move (item_data, &after);
+ item_data_set_pos (item_data, &after);
if (sheet->state == SHEET_STATE_NONE)
item_data_register (item_data);
}
g_list_free (item_data_list);
- g_list_free_full (list, g_object_unref);
}
-void
-sheet_clear_op_values (Sheet *sheet)
+void sheet_clear_op_values (Sheet *sheet)
{
- GList *list;
-
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- for (list = sheet->priv->voltmeter_items; list; list = list->next) {
- g_object_unref (G_OBJECT (list->data));
- }
-
- g_list_free (sheet->priv->voltmeter_items);
- sheet->priv->voltmeter_items = NULL;
-
g_hash_table_destroy (sheet->priv->voltmeter_nodes);
- sheet->priv->voltmeter_nodes = g_hash_table_new_full (g_str_hash,
- g_str_equal, g_free, NULL);
- g_list_free_full (list, g_object_unref);
+ sheet->priv->voltmeter_nodes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
-void
-sheet_provide_object_properties (Sheet *sheet)
+void sheet_provide_object_properties (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -1075,15 +1181,18 @@ sheet_provide_object_properties (Sheet *sheet)
sheet_item_edit_properties (sheet->priv->selected_objects->data);
}
-void
-sheet_clear_ghosts (Sheet *sheet)
+/**
+ * get rid of floating items (delete them)
+ */
+void sheet_clear_ghosts (Sheet *sheet)
{
GList *copy, *list;
-
+
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- if (sheet->priv->floating_objects == NULL) return;
+ if (sheet->priv->floating_objects == NULL)
+ return;
g_assert (sheet->state != SHEET_STATE_FLOAT);
copy = g_list_copy (sheet->priv->floating_objects);
@@ -1094,13 +1203,14 @@ sheet_clear_ghosts (Sheet *sheet)
}
g_list_free (copy);
-
+
sheet->priv->floating_objects = NULL;
- g_list_free_full (list, g_object_unref);
}
-guint
-sheet_get_selected_objects_length (Sheet *sheet)
+/**
+ * count selected objects O(n)
+ */
+guint sheet_get_selected_objects_length (Sheet *sheet)
{
g_return_val_if_fail ((sheet != NULL), 0);
g_return_val_if_fail (IS_SHEET (sheet), 0);
@@ -1108,8 +1218,10 @@ sheet_get_selected_objects_length (Sheet *sheet)
return g_list_length (sheet->priv->selected_objects);
}
-GList *
-sheet_get_floating_objects (Sheet *sheet)
+/**
+ * @returns a shallow copy of the floating items list, free with `g_list_free`
+ */
+GList *sheet_get_floating_objects (Sheet *sheet)
{
g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
@@ -1117,8 +1229,12 @@ sheet_get_floating_objects (Sheet *sheet)
return g_list_copy (sheet->priv->floating_objects);
}
-void
-sheet_add_ghost_item (Sheet *sheet, ItemData *data)
+/**
+ * add a recently created item (no view representation yet!)
+ * to the group of floating items and add a SheetItem via
+ * `sheet_item_factory_create_sheet_item()`
+ */
+void sheet_add_ghost_item (Sheet *sheet, ItemData *data)
{
SheetItem *item;
@@ -1127,90 +1243,77 @@ sheet_add_ghost_item (Sheet *sheet, ItemData *data)
item = sheet_item_factory_create_sheet_item (sheet, data);
- g_object_set (G_OBJECT (item),
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+ g_object_set (G_OBJECT (item), "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
sheet_prepend_floating_object (sheet, item);
}
-void
-sheet_stop_create_wire (Sheet *sheet)
+void sheet_stop_create_wire (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
-
- if (sheet->priv->create_wire_context) {
- create_wire_exit (sheet->priv->create_wire_context);
- sheet->priv->create_wire_context = NULL;
- }
+
+ create_wire_cleanup (sheet);
}
-void
-sheet_initiate_create_wire (Sheet *sheet)
+void sheet_initiate_create_wire (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- sheet->priv->create_wire_context = create_wire_initiate (sheet);
+ create_wire_setup (sheet);
}
-static void
-node_dot_added_callback (Schematic *schematic, SheetPos *pos, Sheet *sheet)
+static void node_dot_added_callback (Schematic *schematic, Coords *pos, Sheet *sheet)
{
NodeItem *node_item;
-
- SheetPos *key;
+ Coords *key;
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
node_item = g_hash_table_lookup (sheet->priv->node_dots, pos);
if (node_item == NULL) {
- node_item = NODE_ITEM (g_object_new (TYPE_NODE_ITEM, NULL));
- g_object_set (node_item,
- "parent", goo_canvas_get_root_item (GOO_CANVAS (sheet)),
- "x", pos->x,
- "y", pos->y,
- NULL);
+ node_item = NODE_ITEM (g_object_new (TYPE_NODE_ITEM, NULL));
+ g_object_set (node_item, "parent", goo_canvas_get_root_item (GOO_CANVAS (sheet)), "x",
+ pos->x, "y", pos->y, NULL);
}
node_item_show_dot (node_item, TRUE);
- key = g_new0 (SheetPos, 1);
+ key = g_new0 (Coords, 1);
key->x = pos->x;
key->y = pos->y;
g_hash_table_insert (sheet->priv->node_dots, key, node_item);
}
-static void
-node_dot_removed_callback (Schematic *schematic, SheetPos *pos, Sheet *sheet)
+static void node_dot_removed_callback (Schematic *schematic, Coords *pos, Sheet *sheet)
{
GooCanvasItem *node_item;
- SheetPos * orig_key;
+ Coords *orig_key;
gboolean found;
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- found = g_hash_table_lookup_extended (
- sheet->priv->node_dots,
- pos,
- (gpointer) &orig_key,
- (gpointer) &node_item);
+ found = g_hash_table_lookup_extended (sheet->priv->node_dots, pos, (gpointer)&orig_key,
+ (gpointer)&node_item);
if (found) {
goo_canvas_item_remove (GOO_CANVAS_ITEM (node_item));
g_hash_table_remove (sheet->priv->node_dots, pos);
- }
- else
+ } else {
g_warning ("No dot to remove!");
+ }
}
-static guint
-dot_hash (gconstpointer key)
+/**
+ * hash function for dots (for their position actually)
+ * good enough to get some spread and very lightweight
+ */
+static guint dot_hash (gconstpointer key)
{
- SheetPos *sp = (SheetPos *) key;
+ Coords *sp = (Coords *)key;
int x, y;
x = (int)rint (sp->x) % 256;
@@ -1221,16 +1324,15 @@ dot_hash (gconstpointer key)
#define HASH_EPSILON 1e-2
-static int
-dot_equal (gconstpointer a, gconstpointer b)
+static int dot_equal (gconstpointer a, gconstpointer b)
{
- SheetPos *spa, *spb;
+ Coords *spa, *spb;
- g_return_val_if_fail (a!=NULL, 0);
- g_return_val_if_fail (b!=NULL, 0);
+ g_return_val_if_fail (a != NULL, 0);
+ g_return_val_if_fail (b != NULL, 0);
- spa = (SheetPos *) a;
- spb = (SheetPos *) b;
+ spa = (Coords *)a;
+ spb = (Coords *)b;
if (fabs (spa->y - spb->y) > HASH_EPSILON)
return 0;
@@ -1241,44 +1343,151 @@ dot_equal (gconstpointer a, gconstpointer b)
return 1;
}
-void
-sheet_connect_node_dots_to_signals (Sheet *sheet)
+void sheet_connect_node_dots_to_signals (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
- GList *list;
+ GList *iter, *list;
Schematic *sm;
sm = schematic_view_get_schematic_from_sheet (sheet);
- list = schematic_get_items (sm);
- g_signal_connect_object (G_OBJECT (sm), "node_dot_added",
- G_CALLBACK (node_dot_added_callback), G_OBJECT (sheet), 0);
+ g_signal_connect_object (G_OBJECT (sm), "node_dot_added", G_CALLBACK (node_dot_added_callback),
+ G_OBJECT (sheet), 0);
g_signal_connect_object (G_OBJECT (sm), "node_dot_removed",
- G_CALLBACK (node_dot_removed_callback), G_OBJECT (sheet), 0);
+ G_CALLBACK (node_dot_removed_callback), G_OBJECT (sheet), 0);
list = node_store_get_node_positions (schematic_get_store (sm));
- for (; list; list = list->next)
- node_dot_added_callback (sm, list->data, sheet);
-
- g_list_free_full (list, g_object_unref);
+ for (iter = list; iter; iter = iter->next)
+ node_dot_added_callback (sm, iter->data, sheet);
}
-void
-sheet_remove_item_in_sheet (SheetItem *item, Sheet *sheet)
+/**
+ * remove a single item from the sheet
+ */
+void sheet_remove_item_in_sheet (SheetItem *item, Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
- g_return_if_fail (IS_SHEET (sheet));
- g_return_if_fail (item != NULL);
- g_return_if_fail (IS_SHEET_ITEM (item));
+ g_return_if_fail (IS_SHEET (sheet));
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_SHEET_ITEM (item));
+
+ sheet->priv->items = g_list_remove (sheet->priv->items, item);
- sheet->priv->items = g_list_remove (sheet->priv->items, item);
+ // Remove the object from the selected-list before destroying.
+ sheet_remove_selected_object (sheet, item);
+ sheet_remove_floating_object (sheet, item);
- // Remove the object from the selected-list before destroying.
- sheet_remove_selected_object (sheet, item);
- sheet_remove_floating_object (sheet, item);
+ ItemData *data = sheet_item_get_data (item);
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_ITEM_DATA (data));
+ // properly unregister the itemdata from the sheet
+ item_data_unregister (data);
// Destroy the item-data (model) associated to the sheet-item
- g_object_unref (sheet_item_get_data (item));
+ g_object_unref (data);
+}
+
+inline static guint32 extract_time (GdkEvent *event)
+{
+ if (event) {
+ switch (event->type) {
+ /* only added relevant events */
+ case GDK_MOTION_NOTIFY:
+ return ((GdkEventMotion *)event)->time;
+ case GDK_3BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_BUTTON_PRESS:
+ return ((GdkEventButton *)event)->time;
+ case GDK_KEY_PRESS:
+ return ((GdkEventKey *)event)->time;
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ return ((GdkEventCrossing *)event)->time;
+ case GDK_PROPERTY_NOTIFY:
+ return ((GdkEventProperty *)event)->time;
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DRAG_STATUS:
+ case GDK_DROP_START:
+ case GDK_DROP_FINISHED:
+ return ((GdkEventDND *)event)->time;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * helpful for debugging to not grab all input forever
+ * if oregano segfaults while running inside
+ * a gdb session
+ */
+#ifndef DEBUG_DISABLE_GRABBING
+#define DEBUG_DISABLE_GRABBING 0
+#endif
+
+gboolean sheet_pointer_grab (Sheet *sheet, GdkEvent *event)
+{
+ g_return_val_if_fail (sheet, FALSE);
+ g_return_val_if_fail (IS_SHEET (sheet), FALSE);
+#if !DEBUG_DISABLE_GRABBING
+ if (sheet->priv->pointer_grabbed == 0 &&
+ goo_canvas_pointer_grab (GOO_CANVAS (sheet), GOO_CANVAS_ITEM (sheet->grid),
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK,
+ NULL, extract_time (event)) == GDK_GRAB_SUCCESS) {
+ sheet->priv->pointer_grabbed = 1;
+ }
+ return (sheet->priv->pointer_grabbed == 1);
+#else
+ return TRUE;
+#endif
+}
+
+void sheet_pointer_ungrab (Sheet *sheet, GdkEvent *event)
+{
+ g_return_if_fail (sheet);
+ g_return_if_fail (IS_SHEET (sheet));
+#if !DEBUG_DISABLE_GRABBING
+ if (sheet->priv->pointer_grabbed) {
+ sheet->priv->pointer_grabbed = FALSE;
+ goo_canvas_pointer_ungrab (GOO_CANVAS (sheet), GOO_CANVAS_ITEM (sheet->grid),
+ extract_time (event));
+ }
+#endif
+}
+
+gboolean sheet_keyboard_grab (Sheet *sheet, GdkEvent *event)
+{
+ g_return_val_if_fail (sheet, FALSE);
+ g_return_val_if_fail (IS_SHEET (sheet), FALSE);
+#if !DEBUG_DISABLE_GRABBING
+ if (sheet->priv->keyboard_grabbed == FALSE &&
+ goo_canvas_keyboard_grab (GOO_CANVAS (sheet), GOO_CANVAS_ITEM (sheet->grid),
+ TRUE, /*do not reroute signals through sheet->grid*/
+ extract_time (event)) == GDK_GRAB_SUCCESS) {
+ sheet->priv->keyboard_grabbed = TRUE;
+ }
+ return (sheet->priv->keyboard_grabbed == TRUE);
+#else
+ return TRUE;
+#endif
+}
+
+void sheet_keyboard_ungrab (Sheet *sheet, GdkEvent *event)
+{
+ g_return_if_fail (sheet);
+ g_return_if_fail (IS_SHEET (sheet));
+#if !DEBUG_DISABLE_GRABBING
+ if (sheet->priv->keyboard_grabbed) {
+ sheet->priv->keyboard_grabbed = FALSE;
+ goo_canvas_keyboard_ungrab (GOO_CANVAS (sheet), GOO_CANVAS_ITEM (sheet->grid),
+ extract_time (event));
+ }
+#endif
}
diff --git a/src/sheet/sheet.h b/src/sheet/sheet.h
index 8e8ff43..331c044 100644
--- a/src/sheet/sheet.h
+++ b/src/sheet/sheet.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SHEET_H
@@ -37,17 +39,24 @@
#include <gtk/gtk.h>
#include "grid.h"
+
#include "item-data.h"
-typedef struct _Sheet Sheet;
-typedef struct _SheetPriv SheetPriv;
+// typedef to avoid circular dependency
+typedef struct _SchematicView SchematicView;
+
+// Allow about 200 pixels for the border of the sheet
+#define SHEET_BORDER 200
+
+typedef struct _Sheet Sheet;
+typedef struct _SheetPriv SheetPriv;
typedef struct _SheetClass SheetClass;
-typedef struct _SheetItem SheetItem;
+typedef struct _SheetItem SheetItem;
-#define TYPE_SHEET (sheet_get_type ())
-#define SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_SHEET, Sheet))
-#define SHEET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, TYPE_SHEET, SheetClass))
-#define IS_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_SHEET))
+#define TYPE_SHEET (sheet_get_type ())
+#define SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_SHEET, Sheet))
+#define SHEET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, TYPE_SHEET, SheetClass))
+#define IS_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, TYPE_SHEET))
typedef enum {
SHEET_STATE_NONE,
@@ -61,68 +70,76 @@ typedef enum {
SHEET_STATE_TEXTBOX_CREATING
} SheetState;
-struct _Sheet {
- GooCanvas parent_canvas;
- SheetState state;
- GooCanvasGroup *object_group;
- Grid *grid;
- SheetPriv *priv;
+struct _Sheet
+{
+ GooCanvas parent_canvas;
+ SheetState state;
+ GooCanvasGroup *object_group;
+
+ Grid *grid;
+ SheetPriv *priv;
};
-struct _SheetClass {
- GooCanvasClass parent_class;
+struct _SheetClass
+{
+ GooCanvasClass parent_class;
- void (*selection_changed) (Sheet *sheet);
- gint (*button_press) (Sheet *sheet, GdkEventButton *event);
- void (*context_click) (Sheet *sheet, const char *name, gpointer data);
- void (*cancel) (Sheet *sheet);
+ void (*selection_changed)(Sheet *sheet);
+ gint (*button_press)(Sheet *sheet, GdkEventButton *event);
+ void (*context_click)(Sheet *sheet, const char *name, gpointer data);
+ void (*cancel)(Sheet *sheet);
};
-GType sheet_get_type (void);
-GtkWidget * sheet_new (int width, int height);
-void sheet_scroll (const Sheet *sheet, int dx, int dy);
-void sheet_get_size_pixels (const Sheet *sheet, guint *width,
- guint *height);
-gpointer sheet_get_first_selected_item (const Sheet *sheet);
-void sheet_change_zoom (const Sheet *sheet, double rate);
-void sheet_get_zoom (const Sheet *sheet, gdouble *zoom);
-void sheet_delete_selected_items (const Sheet *sheet);
-void sheet_rotate_selected_items (const Sheet *sheet);
-void sheet_rotate_floating_items (const Sheet *sheet);
-void sheet_reset_floating_items (const Sheet *sheet);
-void sheet_remove_selected_object (const Sheet *sheet, SheetItem *item);
-void sheet_prepend_selected_object (Sheet *sheet, SheetItem *item);
-void sheet_remove_floating_object (const Sheet *sheet, SheetItem *item);
-void sheet_prepend_floating_object (Sheet *sheet, SheetItem *item);
-void sheet_connect_part_item_to_floating_group (Sheet *sheet,
- gpointer *sv);
-void sheet_show_node_labels (Sheet *sheet, gboolean show);
-void sheet_add_item (Sheet *sheet, SheetItem *item);
-void sheet_stop_rubberband (Sheet *sheet, GdkEventButton *event);
-void sheet_setup_rubberband (Sheet *sheet, GdkEventButton *event);
-int sheet_event_callback (GtkWidget *widget, GdkEvent *event,
- Sheet *sheet);
-void sheet_select_all (Sheet *sheet, gboolean select);
-void sheet_rotate_selection (Sheet *sheet);
-void sheet_delete_selection (Sheet *sheet);
-void sheet_release_selected_objects (Sheet *sheet);
-GList * sheet_get_selection (Sheet *sheet);
-void sheet_update_parts (Sheet *sheet);
-void sheet_destroy_sheet_item (SheetItem *item, Sheet *sheet);
-void sheet_rotate_ghosts (Sheet *sheet);
-void sheet_flip_selection (Sheet *sheet, gboolean horizontal);
-void sheet_flip_ghosts (Sheet *sheet, gboolean horizontal);
-void sheet_clear_op_values (Sheet *sheet);
-void sheet_provide_object_properties (Sheet *sheet);
-void sheet_clear_ghosts (Sheet *sheet);
-guint sheet_get_selected_objects_length (Sheet *sheet);
-GList * sheet_get_floating_objects (Sheet *sheet);
-void sheet_add_ghost_item (Sheet *sheet, ItemData *data);
-GList * sheet_get_items (const Sheet *sheet);
-void sheet_stop_create_wire (Sheet *sheet);
-void sheet_initiate_create_wire (Sheet *sheet);
-void sheet_connect_node_dots_to_signals (Sheet *sheet);
-void sheet_remove_item_in_sheet (SheetItem *item, Sheet *sheet);
-void sheet_get_pointer (Sheet *sheet, gdouble *x, gdouble *y);
-
+GType sheet_get_type (void);
+GtkWidget *sheet_new (const gdouble width, const gdouble height);
+gboolean sheet_replace (SchematicView *sv);
+void sheet_scroll_pixel (const Sheet *sheet, int dx, int dy);
+void sheet_get_size_pixels (const Sheet *sheet, guint *width, guint *height);
+gpointer sheet_get_first_selected_item (const Sheet *sheet);
+void sheet_zoom_step (Sheet *sheet, const double rate);
+void sheet_get_zoom (const Sheet *sheet, gdouble *zoom);
+void sheet_delete_selected_items (const Sheet *sheet);
+void sheet_rotate_selected_items (const Sheet *sheet);
+void sheet_rotate_floating_items (const Sheet *sheet);
+void sheet_reset_floating_items (const Sheet *sheet);
+void sheet_remove_selected_object (const Sheet *sheet, SheetItem *item);
+void sheet_prepend_selected_object (Sheet *sheet, SheetItem *item);
+void sheet_remove_floating_object (const Sheet *sheet, SheetItem *item);
+void sheet_prepend_floating_object (Sheet *sheet, SheetItem *item);
+void sheet_connect_part_item_to_floating_group (Sheet *sheet, gpointer *sv);
+void sheet_show_node_labels (Sheet *sheet, gboolean show);
+void sheet_add_item (Sheet *sheet, SheetItem *item);
+void sheet_stop_rubberband (Sheet *sheet, GdkEventButton *event);
+void sheet_setup_rubberband (Sheet *sheet, GdkEventButton *event);
+int sheet_event_callback (GtkWidget *widget, GdkEvent *event, Sheet *sheet);
+void sheet_select_all (Sheet *sheet, gboolean select);
+void sheet_rotate_selection (Sheet *sheet, gint angle);
+void sheet_move_selection (Sheet *sheet, gdouble dx, gdouble dy);
+void sheet_delete_selection (Sheet *sheet);
+void sheet_release_selected_objects (Sheet *sheet);
+GList *sheet_get_selection (Sheet *sheet);
+void sheet_update_parts (Sheet *sheet);
+void sheet_destroy_sheet_item (SheetItem *item, Sheet *sheet);
+void sheet_rotate_ghosts (Sheet *sheet);
+void sheet_flip_selection (Sheet *sheet, IDFlip direction);
+void sheet_flip_ghosts (Sheet *sheet, IDFlip direction);
+void sheet_clear_op_values (Sheet *sheet);
+void sheet_provide_object_properties (Sheet *sheet);
+void sheet_clear_ghosts (Sheet *sheet);
+guint sheet_get_selected_objects_length (Sheet *sheet);
+GList *sheet_get_floating_objects (Sheet *sheet);
+void sheet_add_ghost_item (Sheet *sheet, ItemData *data);
+GList *sheet_get_items (const Sheet *sheet);
+void sheet_stop_create_wire (Sheet *sheet);
+void sheet_initiate_create_wire (Sheet *sheet);
+void sheet_connect_node_dots_to_signals (Sheet *sheet);
+void sheet_remove_item_in_sheet (SheetItem *item, Sheet *sheet);
+gboolean sheet_get_pointer_pixel (Sheet *sheet, gdouble *x, gdouble *y);
+gboolean sheet_get_pointer (Sheet *sheet, gdouble *x, gdouble *y);
+gboolean sheet_get_pointer_snapped (Sheet *sheet, gdouble *x, gdouble *y);
+gboolean sheet_pointer_grab (Sheet *sheet, GdkEvent *event);
+void sheet_pointer_ungrab (Sheet *sheet, GdkEvent *event);
+gboolean sheet_keyboard_grab (Sheet *sheet, GdkEvent *event);
+void sheet_keyboard_ungrab (Sheet *sheet, GdkEvent *event);
+gboolean sheet_get_adjustments (const Sheet *sheet, GtkAdjustment **hadj, GtkAdjustment **vadj);
#endif
diff --git a/src/sheet/textbox-item.c b/src/sheet/textbox-item.c
index b53fcd0..ed618ef 100644
--- a/src/sheet/textbox-item.c
+++ b/src/sheet/textbox-item.c
@@ -2,17 +2,19 @@
* textbox-item.c
*
*
- * Author:
+ * Authors:
* Richard Hult <rhult@hem.passagen.se>
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,15 +28,15 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <glib/gi18n.h>
#include "cursors.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "textbox-item.h"
#include "textbox.h"
#include "dialogs.h"
@@ -43,93 +45,81 @@
#define SELECTED_COLOR "green"
#define TEXTBOX_FONT "Arial 10"
-static void textbox_item_class_init (TextboxItemClass *klass);
-static void textbox_item_init (TextboxItem *item);
-static void textbox_item_finalize (GObject *object);
-static void textbox_item_moved (SheetItem *object);
-static void textbox_rotated_callback (ItemData *data, int angle,
- SheetItem *sheet_item);
-static void textbox_flipped_callback (ItemData *data,
- gboolean horizontal, SheetItem *sheet_item);
-static void textbox_moved_callback (ItemData *data, SheetPos *pos,
- SheetItem *item);
-static void textbox_text_changed_callback (ItemData *data,
- gchar *new_text, SheetItem *item);
-static void textbox_item_paste (Sheet *sheet, ItemData *data);
-static void selection_changed (TextboxItem *item, gboolean select,
- gpointer user_data);
-static int select_idle_callback (TextboxItem *item);
-static int deselect_idle_callback (TextboxItem *item);
-static gboolean is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2);
-inline static void get_cached_bounds (TextboxItem *item, SheetPos *p1,
- SheetPos *p2);
-static void textbox_item_place (SheetItem *item, Sheet *sheet);
-static void textbox_item_place_ghost (SheetItem *item, Sheet *sheet);
-static void edit_textbox (SheetItem *sheet_item);
-static void edit_cmd (GtkWidget *widget, Sheet *sheet);
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-typedef struct {
+static void textbox_item_class_init (TextboxItemClass *klass);
+static void textbox_item_init (TextboxItem *item);
+static void textbox_item_finalize (GObject *object);
+static void textbox_item_moved (SheetItem *object);
+static void textbox_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item);
+static void textbox_flipped_callback (ItemData *data, IDFlip direction, SheetItem *sheet_item);
+static void textbox_moved_callback (ItemData *data, Coords *pos, SheetItem *item);
+static void textbox_text_changed_callback (ItemData *data, gchar *new_text, SheetItem *item);
+static void textbox_item_paste (Sheet *sheet, ItemData *data);
+static void selection_changed (TextboxItem *item, gboolean select, gpointer user_data);
+static int select_idle_callback (TextboxItem *item);
+static int deselect_idle_callback (TextboxItem *item);
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2);
+inline static void get_cached_bounds (TextboxItem *item, Coords *p1, Coords *p2);
+static void textbox_item_place (SheetItem *item, Sheet *sheet);
+static void textbox_item_place_ghost (SheetItem *item, Sheet *sheet);
+static void edit_textbox (SheetItem *sheet_item);
+static void edit_cmd (GtkWidget *widget, Sheet *sheet);
+
+#include "debug.h"
+
+typedef struct
+{
GtkDialog *dialog;
GtkEntry *entry;
} TextboxPropDialog;
static TextboxPropDialog *prop_dialog = NULL;
-static const char *textbox_item_context_menu =
-"<ui>"
-" <popup name='ItemMenu'>"
-" <menuitem action='EditText'/>"
-" </popup>"
-"</ui>";
+static const char *textbox_item_context_menu = "<ui>"
+ " <popup name='ItemMenu'>"
+ " <menuitem action='EditText'/>"
+ " </popup>"
+ "</ui>";
-static GtkActionEntry action_entries[] = {
- {"EditText", GTK_STOCK_PROPERTIES, N_("_Edit the text..."), NULL,
- N_("Edit the text"),G_CALLBACK (edit_cmd)}
-};
+static GtkActionEntry action_entries[] = {{"EditText", GTK_STOCK_PROPERTIES,
+ N_ ("_Edit the text..."), NULL, N_ ("Edit the text"),
+ G_CALLBACK (edit_cmd)}};
-enum {
- TEXTBOX_ITEM_ARG_0,
- TEXTBOX_ITEM_ARG_NAME
-};
+enum { TEXTBOX_ITEM_ARG_0, TEXTBOX_ITEM_ARG_NAME };
-struct _TextboxItemPriv {
+struct _TextboxItemPriv
+{
guint cache_valid : 1;
guint highlight : 1;
GooCanvasItem *text_canvas_item;
// Cached bounding box. This is used to make
// the rubberband selection a bit faster.
- SheetPos bbox_start;
- SheetPos bbox_end;
+ Coords bbox_start;
+ Coords bbox_end;
};
G_DEFINE_TYPE (TextboxItem, textbox_item, TYPE_SHEET_ITEM)
-static void
-textbox_item_class_init (TextboxItemClass *textbox_item_class)
+static void textbox_item_class_init (TextboxItemClass *textbox_item_class)
{
GObjectClass *object_class;
SheetItemClass *sheet_item_class;
object_class = G_OBJECT_CLASS (textbox_item_class);
sheet_item_class = SHEET_ITEM_CLASS (textbox_item_class);
- textbox_item_parent_class =
- g_type_class_peek_parent (textbox_item_class);
+ textbox_item_parent_class = g_type_class_peek_parent (textbox_item_class);
object_class->finalize = textbox_item_finalize;
sheet_item_class->moved = textbox_item_moved;
sheet_item_class->paste = textbox_item_paste;
sheet_item_class->is_in_area = is_in_area;
- sheet_item_class->selection_changed = (gpointer) selection_changed;
+ sheet_item_class->selection_changed = (gpointer)selection_changed;
sheet_item_class->edit_properties = edit_textbox;
sheet_item_class->place = textbox_item_place;
sheet_item_class->place_ghost = textbox_item_place_ghost;
}
-static void
-textbox_item_init (TextboxItem *item)
+static void textbox_item_init (TextboxItem *item)
{
TextboxItemPriv *priv;
@@ -139,26 +129,24 @@ textbox_item_init (TextboxItem *item)
priv->highlight = FALSE;
priv->cache_valid = FALSE;
- sheet_item_add_menu (SHEET_ITEM (item), textbox_item_context_menu,
- action_entries, G_N_ELEMENTS (action_entries));
+ sheet_item_add_menu (SHEET_ITEM (item), textbox_item_context_menu, action_entries,
+ G_N_ELEMENTS (action_entries));
}
-static void
-textbox_item_finalize (GObject *object)
+static void textbox_item_finalize (GObject *object)
{
TextboxItem *item;
item = TEXTBOX_ITEM (object);
- if (item->priv)
- g_free (item->priv);
-
+ g_free (item->priv);
+ item->priv = NULL;
+
G_OBJECT_CLASS (textbox_item_parent_class)->finalize (object);
}
// "moved" signal handler. Invalidates the bounding box cache.
-static void
-textbox_item_moved (SheetItem *object)
+static void textbox_item_moved (SheetItem *object)
{
TextboxItem *item;
TextboxItemPriv *priv;
@@ -169,83 +157,65 @@ textbox_item_moved (SheetItem *object)
priv->cache_valid = FALSE;
}
-TextboxItem *
-textbox_item_new (Sheet *sheet, Textbox *textbox)
+TextboxItem *textbox_item_new (Sheet *sheet, Textbox *textbox)
{
GooCanvasItem *item;
TextboxItem *textbox_item;
TextboxItemPriv *priv;
- SheetPos pos;
+ Coords pos;
ItemData *item_data;
g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
item_data_get_pos (ITEM_DATA (textbox), &pos);
-
+
item = g_object_new (TYPE_TEXTBOX_ITEM, NULL);
-
- g_object_set (item,
- "parent", sheet->object_group,
- NULL);
-
+
+ g_object_set (item, "parent", sheet->object_group, NULL);
+
textbox_item = TEXTBOX_ITEM (item);
- g_object_set (textbox_item,
- "data", textbox,
- NULL);
+ g_object_set (textbox_item, "data", textbox, NULL);
priv = textbox_item->priv;
- priv->text_canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (textbox_item),
- textbox_get_text (textbox), 0.0, 0.0, -1, GOO_CANVAS_ANCHOR_SW,
- "font", TEXTBOX_FONT,
- "fill-color", NORMAL_COLOR,
- NULL);
+ priv->text_canvas_item = goo_canvas_text_new (
+ GOO_CANVAS_ITEM (textbox_item), textbox_get_text (textbox), 0.0, 0.0, -1,
+ GOO_CANVAS_ANCHOR_SW, "font", TEXTBOX_FONT, "fill-color", NORMAL_COLOR, NULL);
item_data = ITEM_DATA (textbox);
- item_data->rotated_handler_id = g_signal_connect_object (G_OBJECT (textbox),
- "rotated",
- G_CALLBACK (textbox_rotated_callback),
- G_OBJECT (textbox_item),
- 0);
- item_data->flipped_handler_id = g_signal_connect_object (G_OBJECT (textbox),
- "flipped",
- G_CALLBACK (textbox_flipped_callback),
- G_OBJECT (textbox_item),
- 0);
- item_data->moved_handler_id = g_signal_connect_object (G_OBJECT (textbox),
- "moved",
- G_CALLBACK (textbox_moved_callback),
- G_OBJECT (textbox_item),
- 0);
- textbox->text_changed_handler_id = g_signal_connect_object (G_OBJECT (textbox),
- "text_changed",
- G_CALLBACK (textbox_text_changed_callback),
- G_OBJECT (textbox_item),
- 0);
+ item_data->rotated_handler_id =
+ g_signal_connect_object (G_OBJECT (textbox), "rotated",
+ G_CALLBACK (textbox_rotated_callback), G_OBJECT (textbox_item), 0);
+ item_data->flipped_handler_id =
+ g_signal_connect_object (G_OBJECT (textbox), "flipped",
+ G_CALLBACK (textbox_flipped_callback), G_OBJECT (textbox_item), 0);
+ item_data->moved_handler_id =
+ g_signal_connect_object (G_OBJECT (textbox), "moved", G_CALLBACK (textbox_moved_callback),
+ G_OBJECT (textbox_item), 0);
+ textbox->text_changed_handler_id = g_signal_connect_object (
+ G_OBJECT (textbox), "text_changed", G_CALLBACK (textbox_text_changed_callback),
+ G_OBJECT (textbox_item), 0);
textbox_update_bbox (textbox);
return textbox_item;
}
-void
-textbox_item_signal_connect_placed (TextboxItem *textbox_item,
- Sheet *sheet)
+void textbox_item_signal_connect_placed (TextboxItem *textbox_item, Sheet *sheet)
{
- g_signal_connect (G_OBJECT (textbox_item), "button_press_event",
- G_CALLBACK (sheet_item_event), sheet);
+ g_signal_connect (G_OBJECT (textbox_item), "button_press_event", G_CALLBACK (sheet_item_event),
+ sheet);
g_signal_connect (G_OBJECT (textbox_item), "button_release_event",
- G_CALLBACK (sheet_item_event), sheet);
-
- g_signal_connect (G_OBJECT (textbox_item), "key_press_event",
- G_CALLBACK (sheet_item_event), sheet);
+ G_CALLBACK (sheet_item_event), sheet);
+
+ g_signal_connect (G_OBJECT (textbox_item), "key_press_event", G_CALLBACK (sheet_item_event),
+ sheet);
}
-static void
-textbox_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
+static void textbox_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
{
TextboxItem *item;
@@ -257,13 +227,11 @@ textbox_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
item->priv->cache_valid = FALSE;
}
-static void
-textbox_flipped_callback (ItemData *data,
- gboolean horizontal, SheetItem *sheet_item)
+static void textbox_flipped_callback (ItemData *data, IDFlip direction, SheetItem *sheet_item)
{
TextboxItem *item;
- g_return_if_fail (sheet_item != NULL);
+ g_return_if_fail (sheet_item);
g_return_if_fail (IS_TEXTBOX_ITEM (sheet_item));
item = TEXTBOX_ITEM (sheet_item);
@@ -271,59 +239,48 @@ textbox_flipped_callback (ItemData *data,
item->priv->cache_valid = FALSE;
}
-static int
-select_idle_callback (TextboxItem *item)
+static int select_idle_callback (TextboxItem *item)
{
- SheetPos bbox_start, bbox_end;
+ Coords bbox_start, bbox_end;
TextboxItemPriv *priv = item->priv;
get_cached_bounds (item, &bbox_start, &bbox_end);
- g_object_set (priv->text_canvas_item,
- "fill_color", SELECTED_COLOR,
- NULL);
+ g_object_set (priv->text_canvas_item, "fill_color", SELECTED_COLOR, NULL);
priv->highlight = TRUE;
return FALSE;
}
-static int
-deselect_idle_callback (TextboxItem *item)
+static int deselect_idle_callback (TextboxItem *item)
{
TextboxItemPriv *priv = item->priv;
- g_object_set (priv->text_canvas_item,
- "fill_color", NORMAL_COLOR,
- NULL);
+ g_object_set (priv->text_canvas_item, "fill_color", NORMAL_COLOR, NULL);
priv->highlight = FALSE;
return FALSE;
}
-static void
-selection_changed (TextboxItem *item, gboolean select, gpointer user_data)
+static void selection_changed (TextboxItem *item, gboolean select, gpointer user_data)
{
if (select)
- g_idle_add ((gpointer) select_idle_callback, item);
+ g_idle_add ((gpointer)select_idle_callback, item);
else
- g_idle_add ((gpointer) deselect_idle_callback, item);
+ g_idle_add ((gpointer)deselect_idle_callback, item);
}
-static gboolean
-is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2)
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2)
{
TextboxItem *item;
- SheetPos bbox_start, bbox_end;
+ Coords bbox_start, bbox_end;
item = TEXTBOX_ITEM (object);
get_cached_bounds (item, &bbox_start, &bbox_end);
- if (p1->x < bbox_start.x &&
- p2->x > bbox_end.x &&
- p1->y < bbox_start.y &&
- p2->y > bbox_end.y)
+ if (p1->x < bbox_start.x && p2->x > bbox_end.x && p1->y < bbox_start.y && p2->y > bbox_end.y)
return TRUE;
return FALSE;
@@ -331,27 +288,25 @@ is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2)
// Retrieves the bounding box. We use a caching scheme for this
// since it's too expensive to calculate it every time we need it.
-inline static void
-get_cached_bounds (TextboxItem *item, SheetPos *p1, SheetPos *p2)
+inline static void get_cached_bounds (TextboxItem *item, Coords *p1, Coords *p2)
{
PangoFontDescription *font;
- SheetPos pos;
+ Coords pos;
TextboxItemPriv *priv;
priv = item->priv;
if (!priv->cache_valid) {
- SheetPos start_pos, end_pos;
+ Coords start_pos, end_pos;
font = pango_font_description_from_string (TEXTBOX_FONT);
- item_data_get_pos (sheet_item_get_data (SHEET_ITEM (item)),
- &pos);
+ item_data_get_pos (sheet_item_get_data (SHEET_ITEM (item)), &pos);
start_pos.x = pos.x;
- start_pos.y = pos.y-5;// - font->ascent;
- end_pos.x = pos.x+5; // + rbearing;
- end_pos.y = pos.y+5; // + font->descent;
+ start_pos.y = pos.y - 5; // - font->ascent;
+ end_pos.x = pos.x + 5; // + rbearing;
+ end_pos.y = pos.y + 5; // + font->descent;
priv->bbox_start = start_pos;
priv->bbox_end = end_pos;
@@ -359,12 +314,11 @@ get_cached_bounds (TextboxItem *item, SheetPos *p1, SheetPos *p2)
pango_font_description_free (font);
}
- memcpy (p1, &priv->bbox_start, sizeof (SheetPos));
- memcpy (p2, &priv->bbox_end, sizeof (SheetPos));
+ memcpy (p1, &priv->bbox_start, sizeof(Coords));
+ memcpy (p2, &priv->bbox_end, sizeof(Coords));
}
-static void
-textbox_item_paste (Sheet *sheet, ItemData *data)
+static void textbox_item_paste (Sheet *sheet, ItemData *data)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -375,8 +329,7 @@ textbox_item_paste (Sheet *sheet, ItemData *data)
}
// This is called when the textbox data was moved. Update the view accordingly.
-static void
-textbox_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
+static void textbox_moved_callback (ItemData *data, Coords *pos, SheetItem *item)
{
TextboxItem *textbox_item;
@@ -395,9 +348,7 @@ textbox_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
textbox_item->priv->cache_valid = FALSE;
}
-static void
-textbox_text_changed_callback (ItemData *data,
- gchar *new_text, SheetItem *item)
+static void textbox_text_changed_callback (ItemData *data, gchar *new_text, SheetItem *item)
{
TextboxItem *textbox_item;
@@ -408,108 +359,96 @@ textbox_text_changed_callback (ItemData *data,
textbox_item = TEXTBOX_ITEM (item);
- g_object_set (textbox_item->priv->text_canvas_item,
- "text", new_text,
- NULL );
+ g_object_set (textbox_item->priv->text_canvas_item, "text", new_text, NULL);
goo_canvas_item_ensure_updated (GOO_CANVAS_ITEM (textbox_item));
}
-static void
-textbox_item_place (SheetItem *item, Sheet *sheet)
+static void textbox_item_place (SheetItem *item, Sheet *sheet)
{
textbox_item_signal_connect_placed (TEXTBOX_ITEM (item), sheet);
- g_signal_connect (G_OBJECT (item), "double_clicked",
- G_CALLBACK (edit_textbox), item);
+ g_signal_connect (G_OBJECT (item), "double_clicked", G_CALLBACK (edit_textbox), item);
}
-static void
-textbox_item_place_ghost (SheetItem *item, Sheet *sheet)
+static void textbox_item_place_ghost (SheetItem *item, Sheet *sheet)
{
-// textbox_item_signal_connect_placed (TEXTBOX_ITEM (item));
+ // textbox_item_signal_connect_placed (TEXTBOX_ITEM (item));
}
-static gboolean
-create_textbox_event (Sheet *sheet, GdkEvent *event)
+static gboolean create_textbox_event (Sheet *sheet, GdkEvent *event)
{
switch (event->type) {
- case GDK_3BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- return TRUE;
+ case GDK_3BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ return TRUE;
- case GDK_BUTTON_PRESS:
- if (event->button.button == 4 || event->button.button == 5)
- return FALSE;
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 4 || event->button.button == 5)
+ return FALSE;
- if (event->button.button == 1) {
- if (sheet->state == SHEET_STATE_TEXTBOX_WAIT)
- sheet->state = SHEET_STATE_TEXTBOX_START;
+ if (event->button.button == 1) {
+ if (sheet->state == SHEET_STATE_TEXTBOX_WAIT)
+ sheet->state = SHEET_STATE_TEXTBOX_START;
- return TRUE;
- }
- else
- return FALSE;
+ return TRUE;
+ } else
+ return FALSE;
- case GDK_BUTTON_RELEASE:
- if (event->button.button == 4 || event->button.button == 5)
- return FALSE;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 4 || event->button.button == 5)
+ return FALSE;
- if (sheet->state == SHEET_STATE_TEXTBOX_START) {
- Textbox *textbox;
- SheetPos pos;
+ if (sheet->state == SHEET_STATE_TEXTBOX_START) {
+ Textbox *textbox;
+ Coords pos;
- sheet->state = SHEET_STATE_NONE;
+ sheet->state = SHEET_STATE_NONE;
- sheet_get_pointer (sheet, &pos.x, &pos.y);
- textbox = textbox_new (NULL);
-
- textbox_set_text (textbox, _("Label"));
+ sheet_get_pointer (sheet, &pos.x, &pos.y);
+ textbox = textbox_new (NULL);
- schematic_add_item (schematic_view_get_schematic_from_sheet (sheet),
- ITEM_DATA (textbox));
- item_data_set_pos (ITEM_DATA (textbox), &pos);
-
- schematic_view_reset_tool (
- schematic_view_get_schematicview_from_sheet (sheet));
- g_signal_handlers_disconnect_by_func (G_OBJECT (sheet),
- G_CALLBACK (create_textbox_event), sheet);
- }
+ textbox_set_text (textbox, _ ("Label"));
- return TRUE;
+ item_data_set_pos (ITEM_DATA (textbox), &pos);
+ schematic_add_item (schematic_view_get_schematic_from_sheet (sheet),
+ ITEM_DATA (textbox));
- default:
- return FALSE;
+ schematic_view_reset_tool (schematic_view_get_schematicview_from_sheet (sheet));
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sheet),
+ G_CALLBACK (create_textbox_event), sheet);
}
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
return TRUE;
}
- void
-textbox_item_cancel_listen (Sheet *sheet)
+void textbox_item_cancel_listen (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
sheet->state = SHEET_STATE_NONE;
- g_signal_handlers_disconnect_by_func (G_OBJECT (sheet),
- G_CALLBACK (create_textbox_event), sheet);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sheet), G_CALLBACK (create_textbox_event),
+ sheet);
}
-void
-textbox_item_listen (Sheet *sheet)
+void textbox_item_listen (Sheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
// Connect to a signal handler that will let the user create a new textbox.
sheet->state = SHEET_STATE_TEXTBOX_WAIT;
- g_signal_connect (G_OBJECT (sheet), "event",
- G_CALLBACK (create_textbox_event), sheet);
+ g_signal_connect (G_OBJECT (sheet), "event", G_CALLBACK (create_textbox_event), sheet);
}
// Go through the properties and commit the changes.
-void
-edit_dialog_ok (TextboxItem *item)
+void edit_dialog_ok (TextboxItem *item)
{
const gchar *value;
Textbox *textbox;
@@ -522,52 +461,37 @@ edit_dialog_ok (TextboxItem *item)
textbox_set_text (textbox, value);
}
-static void
-edit_textbox (SheetItem *sheet_item)
+static void edit_textbox (SheetItem *sheet_item)
{
TextboxItem *item;
Textbox *textbox;
- char *msg;
const char *value;
- GtkBuilder *gui;
- GError *perror = NULL;
+ GtkBuilder *builder;
+ GError *e = NULL;
g_return_if_fail (sheet_item != NULL);
g_return_if_fail (IS_TEXTBOX_ITEM (sheet_item));
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create textbox properties dialog"));
+ if ((builder = gtk_builder_new ()) == NULL) {
+ oregano_error (_ ("Could not create textbox properties dialog"));
return;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
+ }
+ gtk_builder_set_translation_domain (builder, NULL);
item = TEXTBOX_ITEM (sheet_item);
textbox = TEXTBOX (sheet_item_get_data (sheet_item));
- if (!g_file_test (OREGANO_UIDIR "/textbox-properties-dialog.ui",
- G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The file %s could not be found. You might need to reinstall "
- "Oregano to fix this."),
- OREGANO_UIDIR "/textbox-properties-dialog.ui");
- oregano_error (_("Could not create textbox properties dialog"));
- g_free (msg);
- return;
- }
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/textbox-properties-dialog.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create textbox properties dialog"), msg);
- g_error_free (perror);
+ if (!gtk_builder_add_from_file (builder, OREGANO_UIDIR "/textbox-properties-dialog.ui", &e)) {
+ oregano_error_with_title (_ ("Could not create textbox properties dialog."), e->message);
+ g_clear_error (&e);
return;
}
prop_dialog = g_new0 (TextboxPropDialog, 1);
- prop_dialog->dialog = GTK_DIALOG (
- gtk_builder_get_object (gui, "textbox-properties-dialog"));
+ prop_dialog->dialog =
+ GTK_DIALOG (gtk_builder_get_object (builder, "textbox-properties-dialog"));
- prop_dialog->entry = GTK_ENTRY (gtk_builder_get_object (gui, "entry"));
+ prop_dialog->entry = GTK_ENTRY (gtk_builder_get_object (builder, "entry"));
value = textbox_get_text (textbox);
gtk_entry_set_text (GTK_ENTRY (prop_dialog->entry), value);
@@ -575,18 +499,17 @@ edit_textbox (SheetItem *sheet_item)
gtk_dialog_run (GTK_DIALOG (prop_dialog->dialog));
edit_dialog_ok (item);
- // Clean / destroy the dialog
gtk_widget_destroy (GTK_WIDGET (prop_dialog->dialog));
- prop_dialog = NULL;
+ g_free (prop_dialog);
+ g_object_unref (builder);
}
-static void
-edit_cmd (GtkWidget *widget, Sheet *sheet)
+static void edit_cmd (GtkWidget *widget, Sheet *sheet)
{
GList *list;
list = sheet_get_selection (sheet);
- if ((list != NULL) && IS_TEXTBOX_ITEM (list->data))
+ if ((list != NULL) && IS_TEXTBOX_ITEM (list->data))
edit_textbox (list->data);
g_list_free_full (list, g_object_unref);
}
diff --git a/src/sheet/textbox-item.h b/src/sheet/textbox-item.h
index c4f05a7..43a5981 100644
--- a/src/sheet/textbox-item.h
+++ b/src/sheet/textbox-item.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __TEXTBOX_ITEM_H
@@ -39,11 +39,11 @@
#include "sheet-item.h"
#include "textbox.h"
-
-#define TYPE_TEXTBOX_ITEM (textbox_item_get_type ())
-#define TEXTBOX_ITEM(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, textbox_item_get_type (), TextboxItem)
-#define TEXTBOX_ITEM_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, textbox_item_get_type (), TextboxItemClass)
-#define IS_TEXTBOX_ITEM(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, textbox_item_get_type ())
+#define TYPE_TEXTBOX_ITEM (textbox_item_get_type ())
+#define TEXTBOX_ITEM(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, textbox_item_get_type (), TextboxItem)
+#define TEXTBOX_ITEM_CLASS(klass) \
+ G_TYPE_CHECK_CLASS_CAST (klass, textbox_item_get_type (), TextboxItemClass)
+#define IS_TEXTBOX_ITEM(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, textbox_item_get_type ())
typedef struct _TextboxItemPriv TextboxItemPriv;
@@ -54,20 +54,21 @@ typedef enum {
TEXTBOX_DIR_DIAG = 3
} TextboxDir;
-typedef struct {
- SheetItem parent_object;
- TextboxItemPriv * priv;
+typedef struct
+{
+ SheetItem parent_object;
+ TextboxItemPriv *priv;
} TextboxItem;
-typedef struct {
- SheetItemClass parent_class;
+typedef struct
+{
+ SheetItemClass parent_class;
} TextboxItemClass;
-GType textbox_item_get_type (void);
-TextboxItem * textbox_item_new (Sheet *sheet, Textbox *textbox);
-void textbox_item_signal_connect_placed (TextboxItem *textbox_item,
- Sheet *sheet);
-void textbox_item_cancel_listen (Sheet *sheet);
-void textbox_item_listen (Sheet *sheet);
+GType textbox_item_get_type (void);
+TextboxItem *textbox_item_new (Sheet *sheet, Textbox *textbox);
+void textbox_item_signal_connect_placed (TextboxItem *textbox_item, Sheet *sheet);
+void textbox_item_cancel_listen (Sheet *sheet);
+void textbox_item_listen (Sheet *sheet);
#endif
diff --git a/src/sheet/wire-item.c b/src/sheet/wire-item.c
index 8d5e4e8..208710c 100644
--- a/src/sheet/wire-item.c
+++ b/src/sheet/wire-item.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,21 +26,22 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
#include <string.h>
#include "cursors.h"
-#include "sheet-pos.h"
+#include "coords.h"
#include "wire-item.h"
#include "node-store.h"
#include "wire.h"
#include "wire-private.h"
#include "schematic.h"
#include "schematic-view.h"
+#include "options.h"
#define NORMAL_COLOR "blue"
#define SELECTED_COLOR "green"
@@ -48,63 +49,55 @@
#define RESIZER_SIZE 4.0f
-static void wire_item_class_init (WireItemClass *klass);
-static void wire_item_init (WireItem *item);
-static void wire_item_finalize (GObject *object);
-static void wire_item_moved (SheetItem *object);
-static void wire_rotated_callback (ItemData *data, int angle,
- SheetItem *sheet_item);
-static void wire_flipped_callback (ItemData *data, gboolean horizontal,
- SheetItem *sheet_item);
-static void wire_moved_callback (ItemData *data, SheetPos *pos,
- SheetItem *item);
-static void wire_changed_callback (Wire *, WireItem *item);
-static void wire_delete_callback (Wire *, WireItem *item);
-static void wire_item_paste (Sheet *sheet, ItemData *data);
-static void selection_changed (WireItem *item, gboolean select,
- gpointer user_data);
-static int select_idle_callback (WireItem *item);
-static int deselect_idle_callback (WireItem *item);
-static gboolean is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2);
-inline static void get_boundingbox (WireItem *item, SheetPos *p1, SheetPos *p2);
-static void mouse_over_wire_callback (WireItem *item, Sheet *sheet);
-static void highlight_wire_callback (Wire *wire, WireItem *item);
-static int unhighlight_wire (WireItem *item);
-static void wire_item_place (SheetItem *item, Sheet *sheet);
-static void wire_item_place_ghost (SheetItem *item, Sheet *sheet);
-static void wire_item_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *spec);
-static void wire_item_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *spec);
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-enum {
- WIRE_RESIZER_NONE,
- WIRE_RESIZER_1,
- WIRE_RESIZER_2
-};
-
-struct _WireItemPriv {
- guint cache_valid : 1;
- guint resize_state;
- guint highlight : 1;
- WireDir direction; // Direction of the wire.
+static void wire_item_class_init (WireItemClass *klass);
+static void wire_item_init (WireItem *item);
+static void wire_item_dispose (GObject *object);
+static void wire_item_finalize (GObject *object);
+static void wire_item_moved (SheetItem *object);
+static void wire_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item);
+static void wire_flipped_callback (ItemData *data, IDFlip horizontal, SheetItem *sheet_item);
+static void wire_moved_callback (ItemData *data, Coords *pos, SheetItem *item);
+static void wire_changed_callback (Wire *, WireItem *item);
+static void wire_item_paste (Sheet *sheet, ItemData *data);
+static void selection_changed (WireItem *item, gboolean select, gpointer user_data);
+static int select_idle_callback (WireItem *item);
+static int deselect_idle_callback (WireItem *item);
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2);
+inline static void get_boundingbox (WireItem *item, Coords *p1, Coords *p2);
+static void mouse_over_wire_callback (WireItem *item, Sheet *sheet);
+static void highlight_wire_callback (Wire *wire, WireItem *item);
+static int unhighlight_wire (WireItem *item);
+static void wire_item_place (SheetItem *item, Sheet *sheet);
+static void wire_item_place_ghost (SheetItem *item, Sheet *sheet);
+static void wire_item_get_property (GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec);
+static void wire_item_set_property (GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec);
+
+#include "debug.h"
+
+enum { WIRE_RESIZER_NONE, WIRE_RESIZER_1, WIRE_RESIZER_2 };
+
+struct _WireItemPriv
+{
+ guint cache_valid : 1;
+ guint resize_state;
+ guint highlight : 1;
+ WireDir direction; // Direction of the wire.
- GooCanvasPolyline * line;
- GooCanvasRect * resize1; // Resize box of the wire
- GooCanvasRect * resize2; // Resize box of the wire
+ GooCanvasPolyline *line;
+ GooCanvasRect *resize1; // Resize box of the wire
+ GooCanvasRect *resize2; // Resize box of the wire
// Cached bounding box. This is used to make
// the rubberband selection a bit faster.
- SheetPos bbox_start;
- SheetPos bbox_end;
+ Coords bbox_start;
+ Coords bbox_end;
};
G_DEFINE_TYPE (WireItem, wire_item, TYPE_SHEET_ITEM)
-static void
-wire_item_class_init (WireItemClass *wire_item_class)
+static void wire_item_class_init (WireItemClass *wire_item_class)
{
GObjectClass *object_class;
SheetItemClass *sheet_item_class;
@@ -112,48 +105,46 @@ wire_item_class_init (WireItemClass *wire_item_class)
object_class = G_OBJECT_CLASS (wire_item_class);
sheet_item_class = SHEET_ITEM_CLASS (wire_item_class);
wire_item_parent_class = g_type_class_peek_parent (wire_item_class);
-
+
object_class->finalize = wire_item_finalize;
+ object_class->dispose = wire_item_dispose;
object_class->set_property = wire_item_set_property;
- object_class->get_property = wire_item_get_property;
+ object_class->get_property = wire_item_get_property;
sheet_item_class->moved = wire_item_moved;
sheet_item_class->paste = wire_item_paste;
sheet_item_class->is_in_area = is_in_area;
- sheet_item_class->selection_changed = (gpointer) selection_changed;
+ sheet_item_class->selection_changed = selection_changed;
sheet_item_class->place = wire_item_place;
sheet_item_class->place_ghost = wire_item_place_ghost;
}
-static void
-wire_item_set_property (GObject *object, guint property_id, const GValue *value,
- GParamSpec *pspec)
+static void wire_item_set_property (GObject *object, guint property_id, const GValue *value,
+ GParamSpec *pspec)
{
- g_return_if_fail (object != NULL);
- g_return_if_fail (IS_WIRE_ITEM(object));
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_WIRE_ITEM (object));
- switch (property_id) {
- default:
- g_warning ("PartItem: Invalid argument.\n");
- }
+ switch (property_id) {
+ default:
+ g_warning ("PartItem: Invalid argument.\n");
+ }
}
-static void
-wire_item_get_property (GObject *object, guint property_id, GValue *value,
- GParamSpec *pspec)
+static void wire_item_get_property (GObject *object, guint property_id, GValue *value,
+ GParamSpec *pspec)
{
- g_return_if_fail (object != NULL);
- g_return_if_fail (IS_WIRE_ITEM (object));
-
- switch (property_id) {
- default:
- pspec->value_type = G_TYPE_INVALID;
- break;
- }
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_WIRE_ITEM (object));
+
+ switch (property_id) {
+ default:
+ pspec->value_type = G_TYPE_INVALID;
+ break;
+ }
}
-static void
-wire_item_init (WireItem *item)
+static void wire_item_init (WireItem *item)
{
WireItemPriv *priv;
@@ -162,45 +153,48 @@ wire_item_init (WireItem *item)
priv->direction = WIRE_DIR_NONE;
priv->highlight = FALSE;
priv->cache_valid = FALSE;
+ priv->line = NULL;
+ priv->resize1 = NULL;
+ priv->resize2 = NULL;
item->priv = priv;
}
-static void
-wire_item_finalize (GObject *object)
+static void wire_item_dispose (GObject *object)
{
WireItemPriv *priv;
priv = WIRE_ITEM (object)->priv;
- if (priv != NULL) {
- g_free (priv);
- }
-
- G_OBJECT_CLASS (wire_item_parent_class)->finalize (object);
+ G_OBJECT_CLASS (wire_item_parent_class)->dispose (object);
}
-// "moved" signal handler. Invalidates the bounding box cache.
-static void
-wire_item_moved (SheetItem *object)
+static void wire_item_finalize (GObject *object)
{
- WireItem *item;
WireItemPriv *priv;
- item = WIRE_ITEM (object);
- priv = item->priv;
+ priv = WIRE_ITEM (object)->priv;
- priv->cache_valid = FALSE;
+ g_free (priv);
+ priv = NULL;
+
+ G_OBJECT_CLASS (wire_item_parent_class)->finalize (object);
+}
+
+// TODO get rid of this
+static void wire_item_moved (SheetItem *object)
+{
+ // NG_DEBUG ("wire MOVED callback called - LEGACY");
}
-WireItem *
-wire_item_new (Sheet *sheet, Wire *wire)
+WireItem *wire_item_new (Sheet *sheet, Wire *wire)
{
GooCanvasItem *item;
WireItem *wire_item;
+ ItemData *item_data;
GooCanvasPoints *points;
WireItemPriv *priv;
- SheetPos start_pos, length;
+ Coords start_pos, length;
g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (IS_SHEET (sheet), NULL);
@@ -208,276 +202,235 @@ wire_item_new (Sheet *sheet, Wire *wire)
wire_get_pos_and_length (wire, &start_pos, &length);
item = g_object_new (TYPE_WIRE_ITEM, NULL);
-
- g_object_set (item,
- "parent", sheet->object_group,
- NULL);
-
+
+ g_object_set (item, "parent", sheet->object_group, NULL);
+
wire_item = WIRE_ITEM (item);
- g_object_set (wire_item,
- "data", wire,
- NULL);
+ g_object_set (wire_item, "data", wire, NULL);
priv = wire_item->priv;
-
- priv->resize1 = GOO_CANVAS_RECT (goo_canvas_rect_new (
- GOO_CANVAS_ITEM (wire_item),
- -RESIZER_SIZE,
- -RESIZER_SIZE,
- 2 * RESIZER_SIZE,
- 2 * RESIZER_SIZE,
- "stroke-color", "blue",
- "fill-color", "green",
- "line-width", 1.0,
- NULL));
- g_object_set (priv->resize1,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+
+ const int random_color_count = 9;
+ const char *random_color[] = {"blue", "red", "green" /*, "yellow"*/, "orange", "brown",
+ "purple", "pink", "lightblue", "lightgreen"};
+
+ priv->resize1 = GOO_CANVAS_RECT (
+ goo_canvas_rect_new (GOO_CANVAS_ITEM (wire_item), -RESIZER_SIZE, -RESIZER_SIZE,
+ 2 * RESIZER_SIZE, 2 * RESIZER_SIZE, "stroke-color",
+ oregano_options_debug_wires ()
+ ? random_color[g_random_int_range (0, random_color_count - 1)]
+ : "blue",
+ "fill-color", "green", "line-width", 1.0, NULL));
+ g_object_set (priv->resize1, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
priv->resize2 = GOO_CANVAS_RECT (goo_canvas_rect_new (
- GOO_CANVAS_ITEM (wire_item),
- length.x - RESIZER_SIZE,
- length.y - RESIZER_SIZE,
- 2 * RESIZER_SIZE,
- 2 * RESIZER_SIZE,
- "stroke-color", "blue",
- "fill-color", "green",
- "line-width", 1.0,
- NULL));
- g_object_set (priv->resize2,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
-
- points = goo_canvas_points_new (2);
+ GOO_CANVAS_ITEM (wire_item), length.x - RESIZER_SIZE, length.y - RESIZER_SIZE,
+ 2 * RESIZER_SIZE, 2 * RESIZER_SIZE, "stroke-color",
+ oregano_options_debug_wires ()
+ ? random_color[g_random_int_range (0, random_color_count - 1)]
+ : "blue",
+ "fill-color", "green", "line-width", 1.0, NULL));
+ g_object_set (priv->resize2, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+
+ points = goo_canvas_points_new (2);
points->coords[0] = 0;
points->coords[1] = 0;
points->coords[2] = length.x;
points->coords[3] = length.y;
priv->line = GOO_CANVAS_POLYLINE (goo_canvas_polyline_new (
- GOO_CANVAS_ITEM (wire_item),
- FALSE, 0,
- "points", points,
- "stroke-color", "blue",
- "line-width", 1.0,
- NULL));
-
+ GOO_CANVAS_ITEM (wire_item), FALSE, 0, "points", points, "stroke-color",
+ oregano_options_debug_wires ()
+ ? random_color[g_random_int_range (0, random_color_count - 1)]
+ : "blue",
+ "line-width", 1.0, "start-arrow", oregano_options_debug_wires () ? TRUE : FALSE,
+ "end-arrow", oregano_options_debug_wires () ? TRUE : FALSE, NULL));
+
goo_canvas_points_unref (points);
- ITEM_DATA (wire)->rotated_handler_id =
- g_signal_connect_data (wire, "rotated",
- G_CALLBACK (wire_rotated_callback), G_OBJECT (wire_item), NULL, 0);
-
- g_signal_connect_data (wire, "flipped",
- G_CALLBACK (wire_flipped_callback), G_OBJECT (wire_item), NULL, 0);
-
- ITEM_DATA (wire)->moved_handler_id =
- g_signal_connect_object (wire, "moved",
- G_CALLBACK (wire_moved_callback), G_OBJECT (wire_item), 0);
-
- g_signal_connect (wire, "changed",
- G_CALLBACK (wire_changed_callback), wire_item);
-
- g_signal_connect (wire, "delete",
- G_CALLBACK (wire_delete_callback), wire_item);
-
+ item_data = ITEM_DATA (wire);
+ item_data->rotated_handler_id = g_signal_connect_object (
+ G_OBJECT (wire), "rotated", G_CALLBACK (wire_rotated_callback), G_OBJECT (wire_item), 0);
+ item_data->flipped_handler_id = g_signal_connect_object (
+ G_OBJECT (wire), "flipped", G_CALLBACK (wire_flipped_callback), G_OBJECT (wire_item), 0);
+ item_data->moved_handler_id = g_signal_connect_object (
+ G_OBJECT (wire), "moved", G_CALLBACK (wire_moved_callback), G_OBJECT (wire_item), 0);
+ item_data->changed_handler_id = g_signal_connect_object (
+ G_OBJECT (wire), "changed", G_CALLBACK (wire_changed_callback), G_OBJECT (wire_item), 0);
+
wire_update_bbox (wire);
return wire_item;
}
-gboolean
-wire_item_event (WireItem *wire_item,
- GooCanvasItem *sheet_target_item,
- GdkEvent *event, Sheet *sheet)
+gboolean wire_item_event (WireItem *wire_item, GooCanvasItem *sheet_target_item, GdkEvent *event,
+ Sheet *sheet)
{
- SheetPos start_pos, length;
+ Coords start_pos, length;
Wire *wire;
GooCanvas *canvas;
static double last_x, last_y;
double dx, dy, zoom;
// The selected group's bounding box in window resp. canvas coordinates.
double snapped_x, snapped_y;
- SheetPos pos;
+ Coords pos;
-
canvas = GOO_CANVAS (sheet);
- g_object_get (G_OBJECT (wire_item),
- "data", &wire,
- NULL);
+ g_object_get (G_OBJECT (wire_item), "data", &wire, NULL);
wire_get_pos_and_length (WIRE (wire), &start_pos, &length);
sheet_get_zoom (sheet, &zoom);
switch (event->type) {
- case GDK_BUTTON_PRESS:
- switch (event->button.button) {
- case 1: {
- double x, y;
- g_signal_stop_emission_by_name (wire_item,
- "button_press_event");
- sheet_get_pointer (sheet, &x, &y);
- x = x - start_pos.x;
- y = y - start_pos.y;
- if ((x > -RESIZER_SIZE) && (x < RESIZER_SIZE) &&
- (y > -RESIZER_SIZE) && (y < RESIZER_SIZE)) {
- gtk_widget_grab_focus (GTK_WIDGET (sheet));
- sheet->state = SHEET_STATE_DRAG_START;
- wire_item->priv->resize_state = WIRE_RESIZER_1;
-
- sheet_get_pointer (sheet, &x, &y);
- last_x = x;
- last_y = y;
- item_data_unregister (ITEM_DATA (wire));
- return TRUE;
- }
- if ((x > (length.x-RESIZER_SIZE)) &&
- (x < (length.x+RESIZER_SIZE)) &&
- (y > (length.y-RESIZER_SIZE)) &&
- (y < (length.y+RESIZER_SIZE))) {
- gtk_widget_grab_focus (GTK_WIDGET (sheet));
- sheet->state = SHEET_STATE_DRAG_START;
- wire_item->priv->resize_state = WIRE_RESIZER_2;
-
- sheet_get_pointer (sheet, &x, &y);
- last_x = x;
- last_y = y;
- item_data_unregister (ITEM_DATA (wire));
- return TRUE;
- }
- }
- break;
+ case GDK_BUTTON_PRESS:
+ switch (event->button.button) {
+ case 1: {
+ double x, y;
+ g_signal_stop_emission_by_name (wire_item, "button_press_event");
+ sheet_get_pointer_snapped (sheet, &x, &y);
+ x = x - start_pos.x;
+ y = y - start_pos.y;
+ if ((x > -RESIZER_SIZE) && (x < RESIZER_SIZE) && (y > -RESIZER_SIZE) &&
+ (y < RESIZER_SIZE)) {
+ gtk_widget_grab_focus (GTK_WIDGET (sheet));
+ sheet->state = SHEET_STATE_DRAG_START;
+ wire_item->priv->resize_state = WIRE_RESIZER_1;
+
+ sheet_get_pointer_snapped (sheet, &x, &y);
+ last_x = x;
+ last_y = y;
+ item_data_unregister (ITEM_DATA (wire));
+ return TRUE;
}
+ if ((x > (length.x - RESIZER_SIZE)) && (x < (length.x + RESIZER_SIZE)) &&
+ (y > (length.y - RESIZER_SIZE)) && (y < (length.y + RESIZER_SIZE))) {
+ gtk_widget_grab_focus (GTK_WIDGET (sheet));
+ sheet->state = SHEET_STATE_DRAG_START;
+ wire_item->priv->resize_state = WIRE_RESIZER_2;
+
+ sheet_get_pointer_snapped (sheet, &x, &y);
+ last_x = x;
+ last_y = y;
+ item_data_unregister (ITEM_DATA (wire));
+ return TRUE;
+ }
+ } break;
+ }
+ break;
+
+ case GDK_MOTION_NOTIFY:
+ if (sheet->state != SHEET_STATE_DRAG && sheet->state != SHEET_STATE_DRAG_START)
break;
- case GDK_MOTION_NOTIFY:
- if (sheet->state != SHEET_STATE_DRAG &&
- sheet->state != SHEET_STATE_DRAG_START)
- break;
+ if (wire_item->priv->resize_state == WIRE_RESIZER_NONE)
+ break;
- if (wire_item->priv->resize_state == WIRE_RESIZER_NONE)
- break;
+ if (sheet->state == SHEET_STATE_DRAG_START || sheet->state == SHEET_STATE_DRAG) {
- if (sheet->state == SHEET_STATE_DRAG_START ||
- sheet->state == SHEET_STATE_DRAG) {
-
- g_signal_stop_emission_by_name (wire_item,
- "motion-notify-event");
-
- sheet->state = SHEET_STATE_DRAG;
-
- sheet_get_pointer (sheet, &snapped_x, &snapped_y);
-
- dx = snapped_x - last_x;
- dy = snapped_y - last_y;
-
- last_x = snapped_x;
- last_y = snapped_y;
-
- wire_get_pos_and_length (wire, &pos, &length);
-
- if (wire_item->priv->resize_state == WIRE_RESIZER_1) {
- switch (wire->priv->direction) {
- case WIRE_DIR_VERT:
- /* Vertical Wire */
- pos.y = last_y;
- length.y -= dy;
- break;
- case WIRE_DIR_HORIZ:
- /* Horizontal Wire */
- pos.x = last_x;
- length.x -= dx;
- break;
- default:
- pos.y = last_y;
- length.y -= dy;
- pos.x = last_x;
- length.x -= dx;
- }
- }
- else {
- switch (wire->priv->direction) {
- case WIRE_DIR_VERT:
- /* Vertical Wire */
- length.y += dy;
- break;
- case WIRE_DIR_HORIZ:
- /* Horizontal Wire */
- length.x += dx;
- break;
- default:
- length.y += dy;
- length.x += dx;
- }
- }
- snap_to_grid (sheet->grid, &length.x, &length.y);
- item_data_set_pos (sheet_item_get_data (SHEET_ITEM (wire_item)),
- &pos);
+ g_signal_stop_emission_by_name (wire_item, "motion-notify-event");
- wire_set_length (wire, &length);
- return TRUE;
- }
- break;
- case GDK_BUTTON_RELEASE:
- switch (event->button.button) {
- case 1:
- if (sheet->state != SHEET_STATE_DRAG &&
- sheet->state != SHEET_STATE_DRAG_START) {
+ sheet->state = SHEET_STATE_DRAG;
+
+ sheet_get_pointer_snapped (sheet, &snapped_x, &snapped_y);
+
+ dx = snapped_x - last_x;
+ dy = snapped_y - last_y;
+
+ last_x = snapped_x;
+ last_y = snapped_y;
+
+ wire_get_pos_and_length (wire, &pos, &length);
+
+ if (wire_item->priv->resize_state == WIRE_RESIZER_1) {
+ switch (wire->priv->direction) {
+ case WIRE_DIR_VERT:
+ /* Vertical Wire */
+ pos.y = last_y;
+ length.y -= dy;
break;
+ case WIRE_DIR_HORIZ:
+ /* Horizontal Wire */
+ pos.x = last_x;
+ length.x -= dx;
+ break;
+ default:
+ pos.y = last_y;
+ length.y -= dy;
+ pos.x = last_x;
+ length.x -= dx;
}
- if (wire_item->priv->resize_state == WIRE_RESIZER_NONE) {
+ } else {
+ switch (wire->priv->direction) {
+ case WIRE_DIR_VERT:
+ /* Vertical Wire */
+ length.y += dy;
+ break;
+ case WIRE_DIR_HORIZ:
+ /* Horizontal Wire */
+ length.x += dx;
break;
+ default:
+ length.y += dy;
+ length.x += dx;
}
-
- g_signal_stop_emission_by_name (wire_item,
- "button-release-event");
-
- goo_canvas_pointer_ungrab (canvas, GOO_CANVAS_ITEM (wire_item),
- event->button.time);
-
- wire_item->priv->resize_state = WIRE_RESIZER_NONE;
- sheet->state = SHEET_STATE_NONE;
- item_data_register (ITEM_DATA (wire));
- return TRUE;
}
- break;
- default:
- return sheet_item_event (GOO_CANVAS_ITEM (wire_item),
- GOO_CANVAS_ITEM (wire_item), event, sheet);
+ snap_to_grid (sheet->grid, &length.x, &length.y);
+ item_data_set_pos (sheet_item_get_data (SHEET_ITEM (wire_item)), &pos);
+
+ wire_set_length (wire, &length);
+ return TRUE;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ switch (event->button.button) {
+ case 1:
+ if (sheet->state != SHEET_STATE_DRAG && sheet->state != SHEET_STATE_DRAG_START) {
+ break;
+ }
+ if (wire_item->priv->resize_state == WIRE_RESIZER_NONE) {
+ break;
+ }
+
+ g_signal_stop_emission_by_name (wire_item, "button-release-event");
+
+ goo_canvas_pointer_ungrab (canvas, GOO_CANVAS_ITEM (wire_item), event->button.time);
+
+ wire_item->priv->resize_state = WIRE_RESIZER_NONE;
+ sheet->state = SHEET_STATE_NONE;
+ item_data_register (ITEM_DATA (wire));
+ return TRUE;
+ }
+ break;
+ default:
+ return sheet_item_event (GOO_CANVAS_ITEM (wire_item), GOO_CANVAS_ITEM (wire_item), event,
+ sheet);
}
- return sheet_item_event (GOO_CANVAS_ITEM (wire_item),
- GOO_CANVAS_ITEM (wire_item), event, sheet);
+ return sheet_item_event (GOO_CANVAS_ITEM (wire_item), GOO_CANVAS_ITEM (wire_item), event,
+ sheet);
}
-void
-wire_item_signal_connect_placed (WireItem *wire_item, Sheet *sheet)
+void wire_item_signal_connect_placed (WireItem *wire_item, Sheet *sheet)
{
ItemData *item;
item = sheet_item_get_data (SHEET_ITEM (wire_item));
- g_signal_connect (wire_item, "button-press-event",
- G_CALLBACK (wire_item_event), sheet);
+ g_signal_connect (wire_item, "button-press-event", G_CALLBACK (wire_item_event), sheet);
- g_signal_connect (wire_item, "button-release-event",
- G_CALLBACK (wire_item_event), sheet);
-
- g_signal_connect (wire_item, "motion-notify-event",
- G_CALLBACK (wire_item_event), sheet);
-
- g_signal_connect (wire_item, "mouse_over",
- G_CALLBACK (mouse_over_wire_callback), sheet);
+ g_signal_connect (wire_item, "button-release-event", G_CALLBACK (wire_item_event), sheet);
- g_signal_connect (item, "highlight",
- G_CALLBACK (highlight_wire_callback), wire_item);
+ g_signal_connect (wire_item, "motion-notify-event", G_CALLBACK (wire_item_event), sheet);
+
+ g_signal_connect (wire_item, "mouse_over", G_CALLBACK (mouse_over_wire_callback), sheet);
+
+ g_signal_connect (item, "highlight", G_CALLBACK (highlight_wire_callback), wire_item);
}
-static void
-wire_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
+static void wire_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
{
WireItem *wire_item;
GooCanvasPoints *points;
- SheetPos start_pos, length;
+ Coords start_pos, length;
g_return_if_fail (sheet_item != NULL);
g_return_if_fail (IS_WIRE_ITEM (sheet_item));
@@ -492,33 +445,24 @@ wire_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
points->coords[2] = length.x;
points->coords[3] = length.y;
- g_object_set (wire_item->priv->line,
- "points", points,
- NULL);
+ g_object_set (wire_item->priv->line, "points", points, NULL);
goo_canvas_points_unref (points);
- g_object_set (wire_item,
- "x", start_pos.x,
- "y", start_pos.y,
- NULL);
+ g_object_set (wire_item, "x", start_pos.x, "y", start_pos.y, NULL);
- g_object_set (wire_item-> priv->resize2,
- "x", length.x-RESIZER_SIZE,
- "y", length.y-RESIZER_SIZE,
- NULL);
+ g_object_set (wire_item->priv->resize2, "x", length.x - RESIZER_SIZE, "y",
+ length.y - RESIZER_SIZE, NULL);
- //Invalidate the bounding box cache.
+ // Invalidate the bounding box cache.
wire_item->priv->cache_valid = FALSE;
}
-static void
-wire_flipped_callback (ItemData *data,
- gboolean horizontal, SheetItem *sheet_item)
+static void wire_flipped_callback (ItemData *data, IDFlip direction, SheetItem *sheet_item)
{
GooCanvasPoints *points;
WireItem *item;
WireItemPriv *priv;
- SheetPos start_pos, length;
+ Coords start_pos, length;
g_return_if_fail (sheet_item != NULL);
g_return_if_fail (IS_WIRE_ITEM (sheet_item));
@@ -534,34 +478,22 @@ wire_flipped_callback (ItemData *data,
points->coords[2] = length.x;
points->coords[3] = length.y;
- g_object_set (item->priv->line,
- "points", points,
- NULL);
+ g_object_set (item->priv->line, "points", points, NULL);
goo_canvas_points_unref (points);
- g_object_set (item,
- "x", start_pos.x,
- "y", start_pos.y,
- NULL);
+ g_object_set (item, "x", start_pos.x, "y", start_pos.y, NULL);
// Invalidate the bounding box cache.
priv->cache_valid = FALSE;
}
-static int
-select_idle_callback (WireItem *item)
+static int select_idle_callback (WireItem *item)
{
WireItemPriv *priv = item->priv;
- g_object_set (priv->line,
- "stroke-color", SELECTED_COLOR,
- NULL);
- g_object_set (item->priv->resize1,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
- g_object_set (item->priv->resize2,
- "visibility", GOO_CANVAS_ITEM_VISIBLE,
- NULL);
+ g_object_set (priv->line, "stroke-color", SELECTED_COLOR, NULL);
+ g_object_set (item->priv->resize1, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
+ g_object_set (item->priv->resize2, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
priv->highlight = TRUE;
@@ -569,57 +501,43 @@ select_idle_callback (WireItem *item)
return FALSE;
}
-static int
-deselect_idle_callback (WireItem *item)
+static int deselect_idle_callback (WireItem *item)
{
WireItemPriv *priv = item->priv;
- g_object_set (priv->line,
- "stroke_color", NORMAL_COLOR,
- NULL);
- g_object_set (item->priv->resize1,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
- g_object_set (item->priv->resize2,
- "visibility", GOO_CANVAS_ITEM_INVISIBLE,
- NULL);
+ g_object_set (priv->line, "stroke_color", NORMAL_COLOR, NULL);
+ g_object_set (item->priv->resize1, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
+ g_object_set (item->priv->resize2, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
priv->highlight = FALSE;
- g_object_unref(G_OBJECT (item));
+ g_object_unref (G_OBJECT (item));
return FALSE;
}
-static void
-selection_changed ( WireItem *item, gboolean select, gpointer user)
+static void selection_changed (WireItem *item, gboolean select, gpointer user)
{
g_object_ref (G_OBJECT (item));
if (select) {
- g_idle_add ((gpointer) select_idle_callback, item);
- }
- else {
- g_idle_add ((gpointer) deselect_idle_callback, item);
+ g_idle_add ((gpointer)select_idle_callback, item);
+ } else {
+ g_idle_add ((gpointer)deselect_idle_callback, item);
}
}
// This function returns the position of the canvas item. It has
// nothing to do with where the wire is stored in the sheet node store.
-void
-wire_item_get_start_pos (WireItem *item, SheetPos *pos)
+void wire_item_get_start_pos (WireItem *item, Coords *pos)
{
g_return_if_fail (item != NULL);
g_return_if_fail (IS_WIRE_ITEM (item));
g_return_if_fail (pos != NULL);
- g_object_get (G_OBJECT (item),
- "x", &pos->x,
- "y", &pos->y,
- NULL);
+ g_object_get (G_OBJECT (item), "x", &pos->x, "y", &pos->y, NULL);
}
// This function returns the length of the canvas item.
-void
-wire_item_get_length (WireItem *item, SheetPos *pos)
+void wire_item_get_length (WireItem *item, Coords *pos)
{
WireItemPriv *priv;
GooCanvasPoints *points;
@@ -630,9 +548,7 @@ wire_item_get_length (WireItem *item, SheetPos *pos)
priv = item->priv;
- g_object_get (G_OBJECT (priv->line),
- "points", &points,
- NULL);
+ g_object_get (G_OBJECT (priv->line), "points", &points, NULL);
// This is not strictly neccessary, since the first point is always
// (0,0) but it's more correct and good to have if this changes in the
@@ -642,54 +558,50 @@ wire_item_get_length (WireItem *item, SheetPos *pos)
goo_canvas_points_unref (points);
}
-static gboolean
-is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2)
+static gboolean is_in_area (SheetItem *object, Coords *p1, Coords *p2)
{
WireItem *item;
- SheetPos bbox_start, bbox_end;
+ Coords bbox_start, bbox_end;
item = WIRE_ITEM (object);
get_boundingbox (item, &bbox_start, &bbox_end);
- if (p1->x < bbox_start.x &&
- p2->x > bbox_end.x &&
- p1->y < bbox_start.y &&
- p2->y > bbox_end.y) {
- return TRUE;
+ if (p1->x < bbox_start.x && p2->x > bbox_end.x && p1->y < bbox_start.y && p2->y > bbox_end.y) {
+ return TRUE;
}
return FALSE;
}
// Retrieves the bounding box. We use a caching scheme for this
// since it's too expensive to calculate it every time we need it.
-inline static void
-get_boundingbox (WireItem *item, SheetPos *p1, SheetPos *p2)
+inline static void get_boundingbox (WireItem *item, Coords *p1, Coords *p2)
{
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_WIRE_ITEM (item));
+
WireItemPriv *priv;
priv = item->priv;
if (!priv->cache_valid) {
- SheetPos start_pos, end_pos;
GooCanvasBounds bounds; //, canvas_bounds;
goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (item), &bounds);
- start_pos.x = bounds.x1;
- start_pos.y = bounds.y1;
- end_pos.x = bounds.x2;
- end_pos.y = bounds.y2;
+ priv->bbox_start.x = bounds.x1;
+ priv->bbox_start.y = bounds.y1;
+ priv->bbox_end.x = bounds.x2;
+ priv->bbox_end.y = bounds.y2;
- priv->bbox_start = start_pos;
- priv->bbox_end = end_pos;
priv->cache_valid = TRUE;
}
- memcpy (p1, &priv->bbox_start, sizeof (SheetPos));
- memcpy (p2, &priv->bbox_end, sizeof (SheetPos));
+ if (p1)
+ *p1 = priv->bbox_start;
+ if (p2)
+ *p2 = priv->bbox_end;
}
-static void
-wire_item_paste (Sheet *sheet, ItemData *data)
+static void wire_item_paste (Sheet *sheet, ItemData *data)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
@@ -701,10 +613,9 @@ wire_item_paste (Sheet *sheet, ItemData *data)
static void wire_traverse (Wire *wire);
-static void
-node_traverse (Node *node)
+static void node_traverse (Node *node)
{
- GSList *wires;
+ GSList *iter;
g_return_if_fail (node != NULL);
g_return_if_fail (IS_NODE (node));
@@ -714,17 +625,15 @@ node_traverse (Node *node)
node_set_visited (node, TRUE);
- for (wires = node->wires; wires; wires = wires->next) {
- Wire *wire = wires->data;
+ for (iter = node->wires; iter; iter = iter->next) {
+ Wire *wire = iter->data;
wire_traverse (wire);
}
- g_slist_free_full (wires, g_object_unref);
}
-static void
-wire_traverse (Wire *wire)
+static void wire_traverse (Wire *wire)
{
- GSList *nodes;
+ GSList *iter;
g_return_if_fail (wire != NULL);
g_return_if_fail (IS_WIRE (wire));
@@ -736,155 +645,115 @@ wire_traverse (Wire *wire)
g_signal_emit_by_name (wire, "highlight");
- for (nodes = wire_get_nodes (wire); nodes; nodes = nodes->next) {
- Node *node = nodes->data;
-
+ for (iter = wire_get_nodes (wire); iter; iter = iter->next) {
+ Node *node = iter->data;
node_traverse (node);
}
- g_slist_free_full (nodes, g_object_unref);
}
-static void
-node_foreach_reset (gpointer key, gpointer value, gpointer user_data)
+static void node_foreach_reset (gpointer key, gpointer value, gpointer user_data)
{
Node *node = value;
node_set_visited (node, FALSE);
}
-static void
-mouse_over_wire_callback (WireItem *item, Sheet *sheet)
+static void mouse_over_wire_callback (WireItem *item, Sheet *sheet)
{
- GList *wires;
+ GList *iter;
Wire *wire;
NodeStore *store;
if (sheet->state != SHEET_STATE_NONE)
return;
- store = schematic_get_store (
- schematic_view_get_schematic_from_sheet (sheet));
+ store = schematic_get_store (schematic_view_get_schematic_from_sheet (sheet));
- node_store_node_foreach (store, (GHFunc *) node_foreach_reset, NULL);
- for (wires = store->wires; wires; wires = wires->next) {
- wire = wires->data;
+ node_store_node_foreach (store, (GHFunc *)node_foreach_reset, NULL);
+ for (iter = store->wires; iter; iter = iter->next) {
+ wire = iter->data;
wire_set_visited (wire, FALSE);
}
wire = WIRE (sheet_item_get_data (SHEET_ITEM (item)));
wire_traverse (wire);
- g_list_free_full (wires, g_object_unref);
}
-static void
-highlight_wire_callback (Wire *wire, WireItem *item)
+static void highlight_wire_callback (Wire *wire, WireItem *item)
{
WireItemPriv *priv = item->priv;
- g_object_set (priv->line,
- "stroke-color", HIGHLIGHT_COLOR,
- NULL);
+ g_object_set (priv->line, "stroke-color", HIGHLIGHT_COLOR, NULL);
// Guard against removal during the highlighting.
g_object_ref (G_OBJECT (item));
- g_timeout_add (1000, (gpointer) unhighlight_wire, item);
+ g_timeout_add (1000, (gpointer)unhighlight_wire, item); // FIXME XXX wtf???
}
-static int
-unhighlight_wire (WireItem *item)
+static int unhighlight_wire (WireItem *item)
{
char *color;
WireItemPriv *priv = item->priv;
- color = sheet_item_get_selected (SHEET_ITEM (item)) ?
- SELECTED_COLOR : NORMAL_COLOR;
+ color = sheet_item_get_selected (SHEET_ITEM (item)) ? SELECTED_COLOR : NORMAL_COLOR;
- g_object_set (priv->line,
- "stroke-color", color,
- NULL);
+ g_object_set (priv->line, "stroke-color", color, NULL);
g_object_unref (G_OBJECT (item));
return FALSE;
}
-// This is called when the wire data was moved. Update the view accordingly.
-static void
-wire_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
+// FIXME get rid of
+static void wire_moved_callback (ItemData *data, Coords *pos, SheetItem *item)
{
- WireItem *wire_item;
-
- g_return_if_fail (data != NULL);
- g_return_if_fail (IS_ITEM_DATA (data));
- g_return_if_fail (item != NULL);
- g_return_if_fail (IS_WIRE_ITEM (item));
-
- if (pos == NULL)
- return;
-
- wire_item = WIRE_ITEM (item);
-
- // Move the canvas item and invalidate the bbox cache.
- goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (item),
- pos->x,
- pos->y,
- 1.0,
- 0.0);
- wire_item->priv->cache_valid = FALSE;
+ // NG_DEBUG ("wire MOVED callback called - LEGACY");
}
-static void
-wire_item_place (SheetItem *item, Sheet *sheet)
+static void wire_item_place (SheetItem *item, Sheet *sheet)
{
wire_item_signal_connect_placed (WIRE_ITEM (item), sheet);
}
-static void
-wire_item_place_ghost (SheetItem *item, Sheet *sheet)
+// FIXME get rid of
+static void wire_item_place_ghost (SheetItem *item, Sheet *sheet)
{
-// wire_item_signal_connect_placed (WIRE_ITEM (item));
+ // wire_item_signal_connect_placed (WIRE_ITEM (item));
}
-
-static void
-wire_changed_callback (Wire *wire, WireItem *item)
+static void wire_changed_callback (Wire *wire, WireItem *item)
{
- SheetPos start_pos, length;
+ Coords start_pos, length;
GooCanvasPoints *points;
-
+
+ g_return_if_fail (wire != NULL);
+ g_return_if_fail (IS_ITEM_DATA (wire));
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_WIRE_ITEM (item));
+
wire_get_pos_and_length (wire, &start_pos, &length);
+ // Move the canvas item and invalidate the bbox cache.
+ goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (item), start_pos.x, start_pos.y, 1.0,
+ 0.0);
+ item->priv->cache_valid = FALSE;
+
points = goo_canvas_points_new (2);
points->coords[0] = 0;
points->coords[1] = 0;
points->coords[2] = length.x;
points->coords[3] = length.y;
- g_object_set (item->priv->line,
- "points", points,
- NULL);
+ // this does handle cleanup of previous points internally
+ g_object_set (item->priv->line, "points", points, NULL);
goo_canvas_points_unref (points);
- g_object_set (item->priv->resize1,
- "x", -RESIZER_SIZE,
- "y", -RESIZER_SIZE,
- "width", 2 * RESIZER_SIZE,
- "height", 2 * RESIZER_SIZE,
- NULL);
+ g_object_set (item->priv->resize1, "x", -RESIZER_SIZE, "y", -RESIZER_SIZE, "width",
+ 2 * RESIZER_SIZE, "height", 2 * RESIZER_SIZE, NULL);
- g_object_set (item->priv->resize2,
- "x", length.x-RESIZER_SIZE,
- "y", length.y-RESIZER_SIZE,
- "width", 2 * RESIZER_SIZE,
- "height", 2 * RESIZER_SIZE,
- NULL);
+ g_object_set (item->priv->resize2, "x", length.x - RESIZER_SIZE, "y", length.y - RESIZER_SIZE,
+ "width", 2 * RESIZER_SIZE, "height", 2 * RESIZER_SIZE, NULL);
goo_canvas_item_request_update (GOO_CANVAS_ITEM (item->priv->line));
}
-
-static void
-wire_delete_callback (Wire *wire, WireItem *item)
-{
- g_object_unref (G_OBJECT (item));
-}
diff --git a/src/sheet/wire-item.h b/src/sheet/wire-item.h
index ed6d5cf..b7a47be 100644
--- a/src/sheet/wire-item.h
+++ b/src/sheet/wire-item.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __WIRE_ITEM_H
@@ -39,26 +39,29 @@
#include "sheet-item.h"
#include "wire.h"
-#define TYPE_WIRE_ITEM (wire_item_get_type ())
-#define WIRE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, wire_item_get_type (), WireItem))
-#define WIRE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, wire_item_get_type (), WireItemClass))
-#define IS_WIRE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, wire_item_get_type ()))
+#define TYPE_WIRE_ITEM (wire_item_get_type ())
+#define WIRE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, wire_item_get_type (), WireItem))
+#define WIRE_ITEM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST (klass, wire_item_get_type (), WireItemClass))
+#define IS_WIRE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, wire_item_get_type ()))
typedef struct _WireItemPriv WireItemPriv;
-typedef struct {
- SheetItem parent_object;
- WireItemPriv * priv;
+typedef struct
+{
+ SheetItem parent_object;
+ WireItemPriv *priv;
} WireItem;
-typedef struct {
+typedef struct
+{
SheetItemClass parent_class;
} WireItemClass;
-GType wire_item_get_type (void);
-WireItem * wire_item_new (Sheet *sheet, Wire *wire);
-void wire_item_initiate (Sheet *sheet);
-void wire_item_get_start_pos (WireItem *item, SheetPos *pos);
-void wire_item_get_length (WireItem *item, SheetPos *pos);
+GType wire_item_get_type (void);
+WireItem *wire_item_new (Sheet *sheet, Wire *wire);
+void wire_item_initiate (Sheet *sheet);
+void wire_item_get_start_pos (WireItem *item, Coords *pos);
+void wire_item_get_length (WireItem *item, Coords *pos);
#endif
diff --git a/src/sim-settings-gui.c b/src/sim-settings-gui.c
new file mode 100644
index 0000000..75eb6cc
--- /dev/null
+++ b/src/sim-settings-gui.c
@@ -0,0 +1,1217 @@
+/*
+ * sim-settings-gui.c
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "engines/netlist-helper.h"
+#include "schematic-view.h"
+#include "sim-settings-gui.h"
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+static char *scale_types_list[] = {"DEC", "LIN", "OCT", NULL};
+
+static SimOption default_options[] = {{"TEMP", NULL},
+
+ {"GMIN", NULL},
+ {"ABSTOL", NULL},
+ {"CHGTOL", NULL},
+ {"RELTOL", NULL},
+ {"VNTOL", NULL},
+
+ {"ITL1", NULL},
+ {"ITL2", NULL},
+ {"ITL4", NULL},
+
+ {"PIVREL", NULL},
+ {"PIVTOL", NULL},
+
+ {"TNOM", NULL},
+ {"TRTOL", NULL},
+
+ {"DEFAD", NULL},
+ {"DEFAS", NULL},
+ {"DEFL", NULL},
+ {"DEFW", NULL},
+ {NULL, NULL}};
+
+SimSettingsGui *sim_settings_gui_new() {
+ SimSettingsGui *sim_settings_gui = g_new0(SimSettingsGui, 1);
+
+ sim_settings_gui->sim_settings = sim_settings_new();
+
+ return sim_settings_gui;
+}
+
+void sim_settings_gui_finalize(SimSettingsGui *gui) {
+ sim_settings_finalize(gui->sim_settings);
+ g_free(gui);
+}
+
+static void set_options_in_list (gchar *key, gchar *val, GtkTreeView *cl)
+{
+ int i;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ char *name;
+ char *value;
+
+ model = gtk_tree_view_get_model (cl);
+
+ i = 0;
+ while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) {
+ gtk_tree_model_get (model, &iter, 0, &name, 1, &value, -1);
+ if (!strcmp (name, key)) {
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, val, -1);
+ }
+ i++;
+ }
+}
+
+static void get_options_from_list (SimSettingsGui *s_gui)
+{
+ int i;
+ gchar *name, *value;
+ SimOption *so;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeView *cl = s_gui->w_opt_list;
+ SimSettings *s = s_gui->sim_settings;
+
+ // Empty the list
+ while (s->options) {
+ so = s->options->data;
+ if (so) {
+ g_free (so->name);
+ g_free (so->value);
+ s->options = g_list_remove (s->options, so);
+ g_free (so);
+ }
+ if (s->options)
+ s->options = s->options->next;
+ }
+
+ model = gtk_tree_view_get_model (cl);
+ i = 0;
+ while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) {
+ SimOption *so;
+ gtk_tree_model_get (model, &iter, 0, &name, 1, &value, -1);
+
+ so = g_new0 (SimOption, 1);
+ so->name = g_strdup (name);
+ so->value = g_strdup (value);
+ s->options = g_list_append (s->options, so);
+ i++;
+ }
+}
+
+static gboolean select_opt_callback (GtkWidget *widget, GdkEventButton *event, SimSettingsGui *sim)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ char *value;
+
+ if (event->button != 1)
+ return FALSE;
+
+ // Get the current selected row
+ selection = gtk_tree_view_get_selection (sim->w_opt_list);
+ model = gtk_tree_view_get_model (sim->w_opt_list);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ return FALSE;
+ }
+
+ gtk_tree_model_get (model, &iter, 1, &value, -1);
+
+ if (value)
+ gtk_entry_set_text (sim->w_opt_value, value);
+ else
+ gtk_entry_set_text (sim->w_opt_value, "");
+
+ return FALSE;
+}
+
+static void option_setvalue (GtkWidget *w, SimSettingsGui *s)
+{
+ const gchar *value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ value = gtk_entry_get_text (s->w_opt_value);
+ if (!value)
+ return;
+
+ // Get the current selected row
+ selection = gtk_tree_view_get_selection (s->w_opt_list);
+ model = gtk_tree_view_get_model (s->w_opt_list);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ return;
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, value, -1);
+}
+
+static void add_option (GtkWidget *w, SimSettingsGui *s)
+{
+ GtkEntry *entry;
+ GtkWidget *dialog = gtk_dialog_new_with_buttons (
+ _ ("Add new option"), NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ "_Cancel", GTK_RESPONSE_REJECT, "_OK", GTK_RESPONSE_OK, NULL);
+
+ entry = GTK_ENTRY (gtk_entry_new ());
+ gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ GTK_WIDGET (entry));
+ gtk_widget_show (GTK_WIDGET (entry));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ GtkTreeIter iter;
+ SimOption *opt = g_new0 (SimOption, 1);
+ opt->name = g_strdup (gtk_entry_get_text (entry));
+ opt->value = g_strdup ("");
+ // Warning : don't free opt later, is added to the list
+ sim_settings_add_option (s->sim_settings, opt);
+
+ gtk_list_store_append (GTK_LIST_STORE (gtk_tree_view_get_model (s->w_opt_list)),
+ &iter);
+ gtk_list_store_set (GTK_LIST_STORE (gtk_tree_view_get_model (s->w_opt_list)), &iter,
+ 0, opt->name, -1);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void option_remove (GtkWidget *w, SimSettingsGui *s)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ // Get the current selected row
+ selection = gtk_tree_view_get_selection (s->w_opt_list);
+ model = gtk_tree_view_get_model (s->w_opt_list);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ return;
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, "", -1);
+}
+
+static void entry_changed_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ // FIXME?
+}
+
+static int delete_event_cb (GtkWidget *widget, GdkEvent *event, SimSettingsGui *s)
+{
+ s->pbox = NULL;
+ return FALSE;
+}
+
+static void trans_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable;
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+ gtk_widget_set_sensitive (s->w_trans_frame, enable);
+}
+
+static void trans_step_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable, step_enable;
+
+ step_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_trans_enable));
+
+ gtk_widget_set_sensitive (s->w_trans_step, step_enable & enable);
+}
+
+static void ac_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable;
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_set_sensitive (s->w_ac_frame, enable);
+}
+
+static void dc_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable;
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_set_sensitive (s->w_dcsweep_frame, enable);
+}
+
+static void fourier_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable;
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_set_sensitive (s->w_fourier_frame, enable);
+}
+
+static void fourier_add_vout_cb (GtkButton *w, SimSettingsGui *sim)
+{
+ GtkComboBoxText *node_box;
+ guint i;
+ gboolean result = FALSE;
+ gchar *text;
+
+ node_box = GTK_COMBO_BOX_TEXT (sim->w_four_combobox);
+
+ // Get the node identifier
+ for (i = 0; (i < 1000 && result == FALSE); ++i) {
+ text = g_strdup_printf ("V(%d)", i);
+ if (!g_strcmp0 (text, gtk_combo_box_text_get_active_text (node_box)))
+ result = TRUE;
+ g_free (text);
+ }
+
+ text = NULL;
+ if (result == TRUE)
+ text = fourier_add_vout(sim->sim_settings, i);
+
+ if (text)
+ gtk_entry_set_text (GTK_ENTRY (sim->w_four_vout), text);
+ else
+ gtk_entry_set_text (GTK_ENTRY (sim->w_four_vout), "");
+}
+
+static void fourier_remove_vout_cb (GtkButton *w, SimSettingsGui *sim)
+{
+ GtkComboBoxText *node_box;
+ gint result = FALSE;
+ gint i;
+ SimSettings *s = sim->sim_settings;
+
+ node_box = GTK_COMBO_BOX_TEXT (sim->w_four_combobox);
+
+ // Get the node identifier
+ for (i = 0; (i < 1000 && result == FALSE); i++) {
+ if (g_strcmp0 (g_strdup_printf ("V(%d)", i),
+ gtk_combo_box_text_get_active_text (node_box)) == 0)
+ result = TRUE;
+ }
+
+ if (result) {
+ GSList *node_slist;
+ gchar *text = NULL;
+
+ // Remove current data in the g_slist
+ {
+ GSList *tmp, *prev = NULL;
+
+ tmp = s->fourier_vout;
+ while (tmp) {
+ if (atoi (tmp->data) == i - 1) {
+ if (prev)
+ prev->next = tmp->next;
+ else
+ s->fourier_vout = tmp->next;
+
+ g_slist_free_1 (tmp);
+ break;
+ }
+ prev = tmp;
+ tmp = prev->next;
+ }
+ }
+
+ // Update the fourier_vout widget
+ node_slist = g_slist_copy (s->fourier_vout);
+ if (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0)
+ text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
+ node_slist = node_slist->next;
+ }
+ while (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0) {
+ if (text)
+ text = g_strdup_printf ("%s V(%d)", text, atoi (node_slist->data));
+ else
+ text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
+ }
+ node_slist = node_slist->next;
+ }
+ if (text)
+ gtk_entry_set_text (GTK_ENTRY (sim->w_four_vout), text);
+ else
+ gtk_entry_set_text (GTK_ENTRY (sim->w_four_vout), "");
+
+ g_slist_free_full (node_slist, g_free);
+ }
+}
+
+static void noise_enable_cb (GtkWidget *widget, SimSettingsGui *s)
+{
+ gboolean enable;
+ enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_set_sensitive (s->w_noise_frame, enable);
+}
+
+static void response_callback (GtkButton *button, SchematicView *sv)
+{
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+ g_return_if_fail (button != NULL);
+ g_return_if_fail (GTK_IS_BUTTON (button));
+ gint page;
+ gchar *tmp = NULL;
+ gchar **node_ids = NULL;
+
+ Schematic *sm = schematic_view_get_schematic (sv);
+
+ SimSettingsGui *s_gui = schematic_get_sim_settings_gui(sm);
+ SimSettings *s = s_gui->sim_settings;
+
+ g_object_get (s_gui->notebook, "page", &page, NULL);
+
+ // Transient analysis
+ s->trans_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_trans_enable));
+
+ g_free (s->trans_start);
+ s->trans_start = gtk_editable_get_chars (GTK_EDITABLE (s_gui->w_trans_start), 0, -1);
+
+ g_free (s->trans_stop);
+ s->trans_stop = gtk_editable_get_chars (GTK_EDITABLE (s_gui->w_trans_stop), 0, -1);
+
+ g_free (s->trans_step);
+ s->trans_step = gtk_editable_get_chars (GTK_EDITABLE (s_gui->w_trans_step), 0, -1);
+
+ s->trans_step_enable =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_trans_step_enable));
+
+ s->trans_init_cond =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_trans_init_cond));
+
+ s->trans_analyze_all =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_trans_analyze_all));
+
+ // DC
+ s->dc_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_dc_enable));
+
+ g_free (s->dc_vin);
+ s->dc_vin = NULL;
+ tmp = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_dc_vin));
+ if (tmp) {
+ node_ids = g_strsplit (tmp, "V(", 0);
+ tmp = g_strdup (node_ids[1]);
+ g_strfreev (node_ids);
+ if (tmp) {
+ node_ids = g_strsplit (tmp, ")", 0);
+ g_free (tmp);
+ if (node_ids[0])
+ s->dc_vin = g_strdup (node_ids[0]);
+ else
+ s->dc_vin = g_strdup("");
+ g_strfreev (node_ids);
+ }
+ }
+ if (s->dc_vin == NULL)
+ s->dc_vin = g_strdup ("");
+
+ g_free (s->dc_vout);
+ s->dc_vout = NULL;
+ tmp = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_dc_vout));
+ if (tmp) {
+ node_ids = g_strsplit (tmp, "V(", 0);
+ tmp = g_strdup (node_ids[1]);
+ g_strfreev (node_ids);
+ if (tmp) {
+ node_ids = g_strsplit (tmp, ")", 0);
+ g_free (tmp);
+ if (node_ids[0])
+ s->dc_vout = g_strdup (node_ids[0]);
+ else
+ s->dc_vout = g_strdup("");
+ g_strfreev (node_ids);
+ }
+ }
+ if (s->dc_vout == NULL)
+ s->dc_vout = g_strdup("");
+
+ g_free (s->dc_start);
+ s->dc_start = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_dc_start)));
+
+ g_free (s->dc_stop);
+ s->dc_stop = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_dc_stop)));
+
+ g_free (s->dc_step);
+ s->dc_step = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_dc_step)));
+
+ // AC
+ s->ac_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_ac_enable));
+
+ g_free (s->ac_vout);
+ s->ac_vout = NULL;
+ tmp = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_ac_vout));
+ if (tmp) {
+ node_ids = g_strsplit (tmp, "V(", 0);
+ tmp = g_strdup (node_ids[1]);
+ g_strfreev (node_ids);
+ if (tmp) {
+ node_ids = g_strsplit (tmp, ")", 0);
+ g_free (tmp);
+ if (node_ids[0])
+ s->ac_vout = g_strdup (node_ids[0]);
+ else
+ s->ac_vout = g_strdup("");
+ g_strfreev (node_ids);
+ }
+ }
+ if (s->ac_vout == NULL)
+ s->ac_vout = g_strdup("");
+
+ g_free (s->ac_type);
+ s->ac_type = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_ac_type));
+
+ g_free (s->ac_npoints);
+ s->ac_npoints = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_ac_npoints)));
+
+ g_free (s->ac_start);
+ s->ac_start = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_ac_start)));
+
+ g_free (s->ac_stop);
+ s->ac_stop = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_ac_stop)));
+
+ // Fourier analysis
+ s->fourier_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_four_enable));
+
+ g_free (s->fourier_frequency);
+ s->fourier_frequency = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_four_freq)));
+
+ // Noise
+ s->noise_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s_gui->w_noise_enable));
+
+ g_free (s->noise_vin);
+ s->noise_vin = NULL;
+ tmp = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_noise_vin));
+ if (tmp) {
+ node_ids = g_strsplit (tmp, "V(", 0);
+ tmp = g_strdup (node_ids[1]);
+ g_strfreev (node_ids);
+ if (tmp) {
+ node_ids = g_strsplit (tmp, ")", 0);
+ g_free (tmp);
+ if (node_ids[0])
+ s->noise_vin = g_strdup (node_ids[0]);
+ else
+ s->noise_vin = g_strdup("");
+ g_strfreev (node_ids);
+ }
+ }
+ if (s->noise_vin == NULL)
+ s->noise_vin = g_strdup("");
+
+ g_free (s->noise_vout);
+ s->noise_vout = NULL;
+ tmp = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_noise_vout));
+ if (tmp) {
+ node_ids = g_strsplit (tmp, "V(", 0);
+ tmp = g_strdup (node_ids[1]);
+ g_strfreev (node_ids);
+ if (tmp) {
+ node_ids = g_strsplit (tmp, ")", 0);
+ g_free (tmp);
+ if (node_ids[0])
+ s->noise_vout = g_strdup (node_ids[0]);
+ else
+ s->noise_vout = g_strdup("");
+ g_strfreev (node_ids);
+ }
+ }
+ if (s->noise_vout == NULL)
+ s->noise_vout = g_strdup("");
+
+ g_free (s->noise_type);
+ s->noise_type = g_strdup (gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (s_gui->w_noise_type)));
+
+ g_free (s->noise_npoints);
+ s->noise_npoints = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_noise_npoints)));
+
+ g_free (s->noise_start);
+ s->noise_start = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_noise_start)));
+
+ g_free (s->noise_stop);
+ s->noise_stop = g_strdup (gtk_entry_get_text (GTK_ENTRY (s_gui->w_noise_stop)));
+
+ // Options
+ get_options_from_list (s_gui);
+ gtk_widget_hide (GTK_WIDGET (s_gui->pbox));
+ s_gui->pbox = NULL;
+ s_gui->notebook = NULL;
+
+ // Schematic is dirty now ;-)
+ schematic_set_dirty (sm, TRUE);
+
+ s->configured = TRUE;
+
+ // The simulation settings configuration has
+ // been triggered by an attempt to lauch the
+ // simulation for the first time without
+ // configuring it first.
+ if (s->simulation_requested) {
+ s->simulation_requested = FALSE;
+ schematic_view_simulate_cmd (NULL, sv);
+ }
+}
+
+/**
+ * Get the list of voltmeters (test clamps).
+ *
+ * In normal mode, this does not include the
+ * the type of measurement (normal, magnitude,
+ * phase, real, imaginary or dB) and it is used
+ * in DC and Fourier analysis.
+ *
+ * In AC mode, each element includes the type
+ * of measurement (normal, magnitude, phase,
+ * real, imaginary or dB) and it is used in
+ * AC analysis.
+*/
+gint get_voltmeters_list(GList **voltmeters, Schematic *sm, GError *e, gboolean with_type)
+{
+ GSList *siter, *node_list = NULL;
+
+ if (with_type)
+ node_list = netlist_helper_get_voltmeters_list (sm, &e, TRUE);
+ else
+ node_list = netlist_helper_get_voltmeters_list (sm, &e, FALSE);
+ if (e) {
+ log_append_error (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("Failed to create netlist"), e);
+ g_clear_error (&e);
+ return -1;
+ }
+ if (node_list == NULL) {
+ log_append (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("No node in the schematic!"));
+ return -2;
+ }
+
+ *voltmeters = NULL;
+ for (siter = node_list; siter; siter = siter->next) {
+ gchar *tmp;
+ if (with_type)
+ tmp = g_strdup (siter->data);
+ else
+ tmp = g_strdup_printf ("V(%d)", atoi (siter->data));
+ *voltmeters = g_list_prepend (*voltmeters, tmp);
+ }
+
+ return 0;
+}
+
+/**
+ * Get the list of sources (indipendent voltage)
+ */
+gint get_voltage_sources_list(GList **sources, Schematic *sm, GError *e, gboolean ac_only)
+{
+ GSList *siter, *node_list = NULL;
+
+ node_list = netlist_helper_get_voltage_sources_list (sm, &e, ac_only);
+ if (e) {
+ log_append_error (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("Failed to create netlist"), e);
+ g_clear_error (&e);
+ return -1;
+ }
+ if (node_list == NULL) {
+ log_append (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("No node in the schematic!"));
+ return -2;
+ }
+
+ *sources = NULL;
+ for (siter = node_list; siter; siter = siter->next) {
+ gchar *tmp;
+ tmp = g_strdup_printf ("V%d", atoi (siter->data));
+ *sources = g_list_prepend (*sources, tmp);
+ }
+
+ return 0;
+}
+
+/**
+ * FIXME this code is an ugly piece of shit, fix it!
+ */
+void sim_settings_show (GtkWidget *widget, SchematicView *sv)
+{
+ int i;
+ gboolean found;
+ gint rc, active, index;
+ GtkWidget *toplevel, *w, *w1, *pbox, *combo_box;
+ GtkTreeView *opt_list;
+ GtkCellRenderer *cell_option, *cell_value;
+ GtkTreeViewColumn *column_option, *column_value;
+ GtkListStore *opt_model;
+ GtkTreeIter treeiter;
+ GtkBuilder *builder;
+ GError *e = NULL;
+ SimSettings *s;
+ GList *iter;
+ GList *voltmeters = NULL;
+ GList *voltmeters_with_type = NULL;
+ GList *sources = NULL;
+ GList *sources_ac = NULL;
+ GtkComboBox *node_box;
+ GtkListStore *node_list_store;
+ gchar *text, *text2;
+ gchar **node_ids;
+ GSList *slist = NULL;
+
+ g_return_if_fail (sv != NULL);
+
+ Schematic *sm = schematic_view_get_schematic (sv);
+ SimSettingsGui *s_gui = schematic_get_sim_settings_gui (sm);
+ s = s_gui->sim_settings;
+
+ // Only allow one instance of the property box per schematic.
+ if (s_gui->pbox != NULL) {
+ if (gtk_widget_get_visible (s_gui->pbox) == FALSE) {
+ gtk_widget_set_visible (s_gui->pbox, TRUE);
+ }
+ GdkWindow *window = gtk_widget_get_window (s_gui->pbox);
+ g_assert (window != NULL);
+ gdk_window_raise (window);
+ return;
+ }
+
+ if ((builder = gtk_builder_new ()) == NULL) {
+ log_append (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("Could not create simulation settings dialog"));
+ return;
+ }
+ gtk_builder_set_translation_domain (builder, NULL);
+
+ gtk_builder_add_from_file (builder, OREGANO_UIDIR "/sim-settings.ui", &e);
+ if (e) {
+ log_append_error (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("Could not create simulation settings dialog due to "
+ "missing " OREGANO_UIDIR "/sim-settings.ui file"),
+ e);
+ g_clear_error (&e);
+ return;
+ }
+
+ toplevel = GTK_WIDGET (gtk_builder_get_object (builder, "toplevel"));
+ if (toplevel == NULL) {
+ log_append (schematic_get_log_store (sm), _ ("SimulationSettings"),
+ _ ("Could not create simulation settings dialog due to missing "
+ "\"toplevel\" widget in " OREGANO_UIDIR "/sim-settings.ui file"));
+ return;
+ }
+
+ pbox = toplevel;
+ s_gui->pbox = pbox;
+ s_gui->notebook = GTK_NOTEBOOK (gtk_builder_get_object (builder, "notebook"));
+ g_signal_connect (G_OBJECT (pbox), "delete_event", G_CALLBACK (delete_event_cb), s_gui);
+
+ // Prepare options list
+ s_gui->w_opt_value = GTK_ENTRY (gtk_builder_get_object (builder, "opt_value"));
+ opt_list = GTK_TREE_VIEW (gtk_builder_get_object (builder, "option_list"));
+ s_gui->w_opt_list = opt_list;
+
+ // Grab the frames
+ s_gui->w_trans_frame = GTK_WIDGET (gtk_builder_get_object (builder, "trans_frame"));
+ s_gui->w_ac_frame = GTK_WIDGET (gtk_builder_get_object (builder, "ac_frame"));
+ s_gui->w_dcsweep_frame = GTK_WIDGET (gtk_builder_get_object (builder, "dcsweep_frame"));
+ s_gui->w_fourier_frame = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_frame"));
+ s_gui->w_noise_frame = GTK_WIDGET (gtk_builder_get_object (builder, "noise_frame"));
+
+ // Create the Columns
+ cell_option = gtk_cell_renderer_text_new ();
+ cell_value = gtk_cell_renderer_text_new ();
+ column_option =
+ gtk_tree_view_column_new_with_attributes (N_ ("Option"), cell_option, "text", 0, NULL);
+ column_value =
+ gtk_tree_view_column_new_with_attributes (N_ ("Value"), cell_value, "text", 1, NULL);
+
+ // Create the model
+ opt_model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_view_set_model (opt_list, GTK_TREE_MODEL (opt_model));
+ gtk_tree_view_append_column (opt_list, column_option);
+ gtk_tree_view_append_column (opt_list, column_value);
+
+ if (s->options == NULL) {
+ // Load defaults
+ for (i = 0; default_options[i].name; i++) {
+ gtk_list_store_append (opt_model, &treeiter);
+ gtk_list_store_set (opt_model, &treeiter, 0, default_options[i].name, -1);
+ }
+ } else {
+ // Load schematic options
+
+ for (iter = s->options; iter; iter = iter->next) {
+ SimOption *so = iter->data;
+ if (so) {
+ gtk_list_store_append (opt_model, &treeiter);
+ gtk_list_store_set (opt_model, &treeiter, 0, so->name, -1);
+ }
+ }
+ }
+
+ // Set the options already stored
+ for (iter = s->options; iter; iter = iter->next) {
+ SimOption *so = iter->data;
+ if (so)
+ set_options_in_list (so->name, so->value, opt_list);
+ }
+
+ g_signal_connect (G_OBJECT (opt_list), "button_release_event", G_CALLBACK (select_opt_callback),
+ s);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "opt_accept"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (option_setvalue), s_gui);
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "opt_remove"));
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "add_option"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (option_remove), s_gui);
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (add_option), s_gui);
+
+ // Creation of Close Button
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "button1"));
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (response_callback), sv);
+
+ // Get the list of voltmeters (normal mode)
+ rc = get_voltmeters_list(&voltmeters, sm, e, FALSE);
+ if (rc) {
+ sim_settings_set_dc(s, FALSE);
+ sim_settings_set_fourier(s, FALSE);
+ }
+
+ // Get the list of voltmeters (AC mode, i.e. with measurement type)
+ rc = get_voltmeters_list(&voltmeters_with_type, sm, e, TRUE);
+ if (rc) {
+ sim_settings_set_ac(s, FALSE);
+ }
+
+ // Get the list of sources (all types)
+ rc = get_voltage_sources_list(&sources, sm, e, FALSE);
+ if (rc) {
+ sim_settings_set_dc(s, FALSE);
+ }
+
+ // Get the list of AC sources
+ rc = get_voltage_sources_list(&sources_ac, sm, e, TRUE);
+ if (rc) {
+ sim_settings_set_noise(s, FALSE);
+ }
+
+ // Transient //
+ // ********* //
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_start"));
+ s_gui->w_trans_start = w;
+ if (s->trans_start)
+ gtk_entry_set_text (GTK_ENTRY (w), s->trans_start);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_stop"));
+ s_gui->w_trans_stop = w;
+ if (s->trans_stop)
+ gtk_entry_set_text (GTK_ENTRY (w), s->trans_stop);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_step"));
+ s_gui->w_trans_step = w;
+ if (s->trans_step)
+ gtk_entry_set_text (GTK_ENTRY (w), s->trans_step);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_enable"));
+ s_gui->w_trans_enable = w;
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (trans_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->trans_enable);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_step_enable"));
+ s_gui->w_trans_step_enable = w;
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (trans_step_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->trans_step_enable);
+
+ // get the gui element
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_init_cond"));
+ // save the gui element to struct
+ s_gui->w_trans_init_cond = w;
+ // Set checkbox enabled, if trans_init_cond equal true.
+ // trans_init_cond could be set to true because
+ // - user opened the settings dialog some seconds ago and has set the checkbox
+ // - user opened old file in which there was set the checkbox state to true
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->trans_init_cond);
+
+ // get the gui element
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "trans_analyze_all"));
+ // save the gui element to struct
+ s_gui->w_trans_analyze_all = w;
+ // Set checkbox enabled, if trans_analyze_all equal true.
+ // trans_init_cond could be set to true because
+ // - user opened the settings dialog some seconds ago and has set the checkbox
+ // - user opened old file in which there was set the checkbox state to true
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->trans_analyze_all);
+
+ // AC //
+ // *** //
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_enable"));
+ s_gui->w_ac_enable = w;
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (ac_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->ac_enable);
+
+ w1 = GTK_WIDGET (gtk_builder_get_object (builder, "grid14"));
+
+ // FIXME: Should enable more than just one output as in the Fourier analysis
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_vout"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 0, 1, 1);
+ s_gui->w_ac_vout = combo_box;
+ if (voltmeters_with_type) {
+ index = 0;
+ active = 0;
+ for (iter = voltmeters_with_type; iter; iter = iter->next) {
+ if (g_strcmp0 (iter->data, "VM(0)"))
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), iter->data);
+ if (!g_strcmp0(s->ac_vout, iter->data))
+ active = index;
+ index++;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s);
+
+ // Initialisation of the various scale types
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_type"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 1, 1, 1);
+ s_gui->w_ac_type = combo_box;
+
+ {
+ index = 0;
+ active = 0;
+ for (; scale_types_list[index] != NULL; index++) {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), scale_types_list[index]);
+ if (!g_strcmp0(s->ac_type, scale_types_list[index]))
+ active = index;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_assert (GTK_IS_COMBO_BOX (combo_box));
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_npoints"));
+ s_gui->w_ac_npoints = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->ac_npoints);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_start"));
+ s_gui->w_ac_start = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->ac_start);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "ac_stop"));
+ s_gui->w_ac_stop = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->ac_stop);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ // DC //
+ // ***** //
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_enable"));
+ s_gui->w_dc_enable = w;
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (dc_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->dc_enable);
+
+ w1 = GTK_WIDGET (gtk_builder_get_object (builder, "grid13"));
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_vin"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 0, 1, 1);
+ s_gui->w_dc_vin = combo_box;
+ if (sources) {
+ index = 0;
+ active = 0;
+ for (iter = sources; iter; iter = iter->next) {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), iter->data);
+ if (!g_strcmp0(s->dc_vin, iter->data))
+ active = index;
+ index++;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s);
+
+ // FIXME: Should enable more than just one output as in the Fourier analysis
+ // FIXME: Should also allow to print currents through voltage sources
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_vout"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 1, 1, 1);
+ s_gui->w_dc_vout = combo_box;
+ if (voltmeters) {
+ index = 0;
+ active = 0;
+ text = g_strdup_printf("V(%s)", s->dc_vout);
+ for (iter = voltmeters; iter; iter = iter->next) {
+ if (g_strcmp0 (iter->data, "V(0)"))
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), iter->data);
+ if (!g_strcmp0(text, iter->data))
+ active = index;
+ index++;
+ }
+ g_free (text);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_start"));
+ s_gui->w_dc_start = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->dc_start);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_stop"));
+ s_gui->w_dc_stop = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->dc_stop);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "dc_step"));
+ s_gui->w_dc_step = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->dc_step);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ // Fourier //
+ // ******* //
+ g_print ("XXXXXXXXXXXXXXXX\n");
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_enable"));
+ s_gui->w_four_enable = w;
+ g_print ("XXXXXXXXXXXXXXXX %p %s\n", w, s->fourier_enable ? "TRUE" : "FALSE");
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (fourier_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->fourier_enable);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_freq"));
+ s_gui->w_four_freq = w;
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+ gtk_entry_set_text (GTK_ENTRY (w), s->fourier_frequency);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_vout"));
+ s_gui->w_four_vout = w;
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ // Get rid of inexistent output vectors
+ text2 = NULL;
+ if (voltmeters) {
+ text = sim_settings_get_fourier_vout (s);
+ node_ids = g_strsplit (text, " ", 0);
+ g_free (text);
+ for (i = 0; node_ids[i] != NULL; i++) {
+ text = g_strdup_printf ("V(%s)", node_ids[i]);
+ found = FALSE;
+ for (iter = voltmeters; iter; iter = iter->next) {
+ if (!g_strcmp0 (text, iter->data))
+ found = TRUE;
+ }
+ g_free (text);
+ if (found) {
+ if (text2) {
+ text = text2;
+ text2 = g_strdup_printf ("%s %s", text2, node_ids[i]);
+ g_free (text);
+ } else {
+ text2 = g_strdup_printf ("%s", node_ids[i]);
+ }
+ }
+ }
+ if (!text2)
+ text2 = g_strdup ("");
+ sim_settings_set_fourier_vout (s, text2);
+ g_free (text2);
+ g_strfreev (node_ids);
+ }
+
+ text = NULL;
+ slist = g_slist_copy (s->fourier_vout);
+ if (slist) {
+ if (slist->data && atoi (slist->data) > 0)
+ text = g_strdup_printf ("V(%d)", atoi (slist->data));
+ slist = slist->next;
+ }
+ while (slist) {
+ if (slist->data && atoi (slist->data) > 0) {
+ if (text) {
+ text2 = text;
+ text = g_strdup_printf ("%s V(%d)", text, atoi (slist->data));
+ g_free (text2);
+ } else {
+ text = g_strdup_printf ("V(%d)", atoi (slist->data));
+ }
+ }
+ slist = slist->next;
+ }
+
+ if (text)
+ gtk_entry_set_text (GTK_ENTRY (w), text);
+ else
+ gtk_entry_set_text (GTK_ENTRY (w), "");
+
+ g_slist_free_full (slist, g_free);
+
+ // Present in the combo box the nodes of the schematic
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_select_out"));
+ gtk_widget_destroy (w); // FIXME wtf???
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "grid12"));
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w), combo_box, 2, 2, 1, 1);
+
+ s_gui->w_four_combobox = combo_box;
+ node_box = GTK_COMBO_BOX (combo_box);
+ node_list_store = GTK_LIST_STORE (gtk_combo_box_get_model (node_box));
+ gtk_list_store_clear (node_list_store);
+
+ if (voltmeters) {
+ for (iter = voltmeters; iter; iter = iter->next) {
+ if (g_strcmp0 (iter->data, "V(0)"))
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (node_box), iter->data);
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (node_box), 0);
+ }
+ g_signal_connect (G_OBJECT (node_box), "changed", G_CALLBACK (entry_changed_cb), s);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_add"));
+ s_gui->w_four_add = w;
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (fourier_add_vout_cb), s_gui);
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "fourier_rem"));
+ s_gui->w_four_rem = w;
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (fourier_remove_vout_cb), s_gui);
+
+ // Noise //
+ // *** //
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_enable"));
+ s_gui->w_noise_enable = w;
+ g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (noise_enable_cb), s_gui);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->noise_enable);
+
+ w1 = GTK_WIDGET (gtk_builder_get_object (builder, "grid1"));
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_vin"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 0, 1, 1);
+ s_gui->w_noise_vin = combo_box;
+ if (sources_ac) {
+ index = 0;
+ active = 0;
+ for (iter = sources_ac; iter; iter = iter->next) {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), iter->data);
+ if (!g_strcmp0(s->noise_vin, iter->data))
+ active = index;
+ index++;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s);
+
+ // FIXME: Should enable more than just one output as in the Fourier analysis
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_vout"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 1, 1, 1);
+ s_gui->w_noise_vout = combo_box;
+ if (voltmeters) {
+ index = 0;
+ active = 0;
+ text = g_strdup_printf ("V(%s)", s->noise_vout);
+ for (iter = voltmeters; iter; iter = iter->next) {
+ if (g_strcmp0 (iter->data, "V(0)"))
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), iter->data);
+ if (!g_strcmp0(text, iter->data))
+ active = index;
+ index++;
+ }
+ g_free (text);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s);
+
+ // Initialisation of the various scale types
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_type"));
+ gtk_widget_destroy (w); // FIXME wtf??
+ combo_box = gtk_combo_box_text_new ();
+ gtk_grid_attach (GTK_GRID (w1), combo_box, 1, 2, 1, 1);
+ s_gui->w_noise_type = combo_box;
+
+ {
+ index = 0;
+ active = 0;
+ for (; scale_types_list[index] != NULL; index++) {
+ gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), scale_types_list[index]);
+ if (!g_strcmp0(s->noise_type, scale_types_list[index]))
+ active = index;
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active);
+ }
+ g_assert (GTK_IS_COMBO_BOX (combo_box));
+ g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_npoints"));
+ s_gui->w_noise_npoints = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->noise_npoints);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_start"));
+ s_gui->w_noise_start = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->noise_start);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "noise_stop"));
+ s_gui->w_noise_stop = w;
+ gtk_entry_set_text (GTK_ENTRY (w), s->noise_stop);
+ g_signal_connect (G_OBJECT (w), "changed", G_CALLBACK (entry_changed_cb), s_gui);
+
+ gtk_widget_show_all (toplevel);
+
+ trans_enable_cb (s_gui->w_trans_enable, s_gui);
+ trans_step_enable_cb (s_gui->w_trans_step_enable, s_gui);
+ ac_enable_cb (s_gui->w_ac_enable, s_gui);
+ dc_enable_cb (s_gui->w_dc_enable, s_gui);
+ fourier_enable_cb (s_gui->w_four_enable, s_gui);
+ noise_enable_cb (s_gui->w_noise_enable, s_gui);
+
+ g_list_free(sources);
+ g_list_free(voltmeters);
+ g_list_free(voltmeters_with_type);
+}
diff --git a/src/sim-settings-gui.h b/src/sim-settings-gui.h
new file mode 100644
index 0000000..f36dc80
--- /dev/null
+++ b/src/sim-settings-gui.h
@@ -0,0 +1,113 @@
+/*
+ * sim-settings-gui.h
+ *
+ *
+ * Authors:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SIM_SETTINGS_GUI_H_
+#define SIM_SETTINGS_GUI_H_
+
+typedef struct _SimSettingsGui SimSettingsGui;
+
+#include "model/schematic.h"
+#include "sim-settings.h"
+#include "schematic-view.h"
+
+struct _SimSettingsGui {
+ SimSettings *sim_settings;
+
+ GtkWidget *pbox;
+ GtkNotebook *notebook;
+
+ GtkWidget *w_main;
+
+ // Transient analysis.
+ GtkWidget *w_trans_enable,
+ *w_trans_start,
+ *w_trans_stop,
+ *w_trans_step,
+ *w_trans_step_enable,
+ *w_trans_init_cond,
+ *w_trans_analyze_all,
+ *w_trans_frame;
+
+ // AC
+ GtkWidget *w_ac_enable,
+ *w_ac_vout,
+ *w_ac_type,
+ *w_ac_npoints,
+ *w_ac_start,
+ *w_ac_stop,
+ *w_ac_frame;
+
+ // DC
+ GtkWidget *w_dc_enable,
+ *w_dc_vin,
+ *w_dc_vout,
+ *w_dc_start,
+ *w_dc_stop,
+ *w_dc_step,
+ *w_dcsweep_frame;
+
+ // Fourier analysis. Replace with something sane later.
+ GtkWidget *w_four_enable,
+ *w_four_freq,
+ *w_four_vout,
+ *w_four_combobox,
+ *w_four_add,
+ *w_four_rem,
+ *w_fourier_frame;
+
+ // Noise
+ GtkWidget *w_noise_enable,
+ *w_noise_vin,
+ *w_noise_vout,
+ *w_noise_type,
+ *w_noise_npoints,
+ *w_noise_start,
+ *w_noise_stop,
+ *w_noise_frame;
+
+ GtkEntry *w_opt_value;
+ GtkTreeView *w_opt_list;
+};
+
+SimSettingsGui *sim_settings_gui_new();
+void sim_settings_gui_finalize(SimSettingsGui *gui);
+void sim_settings_show (GtkWidget *widget, SchematicView *sm);
+
+gint get_voltmeters_list (GList **voltmeters, Schematic *sm, GError *e, gboolean with_type);
+
+gint get_voltage_sources_list (GList **sources, Schematic *sm, GError *e, gboolean ac_only);
+
+#endif /* SIM_SETTINGS_GUI_H_ */
diff --git a/src/sim-settings.c b/src/sim-settings.c
index 9f4dff3..1b02170 100644
--- a/src/sim-settings.c
+++ b/src/sim-settings.c
@@ -7,12 +7,16 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,1348 +30,580 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-#include <unistd.h>
#include <stdlib.h>
-#include <ctype.h>
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
+#include <string.h>
+#include <glib.h>
-#include "oregano.h"
-#include "sim-settings.h"
-#include "schematic.h"
-#include "schematic-view.h"
-#include "dialogs.h"
#include "oregano-utils.h"
-#include "netlist-helper.h"
-#include "errors.h"
-
-struct _SimSettingsPriv {
- // Transient analysis.
- GtkWidget *w_main;
- GtkWidget *w_trans_enable, *w_trans_start, *w_trans_stop;
- GtkWidget *w_trans_step, *w_trans_step_enable, *w_trans_init_cond,
- *w_trans_frame;
- gboolean trans_enable;
- gboolean trans_init_cond;
- gchar *trans_start;
- gchar *trans_stop;
- gchar *trans_step;
- gboolean trans_step_enable;
-
- // AC
- GtkWidget *w_ac_enable, *w_ac_type, *w_ac_npoints, *w_ac_start, *w_ac_stop,
- *w_ac_frame;
- gboolean ac_enable;
- gchar *ac_type;
- gchar *ac_npoints;
- gchar *ac_start;
- gchar *ac_stop;
+#include "sim-settings.h"
- // DC
- GtkWidget *w_dc_enable,*w_dc_vin,*w_dc_start,*w_dc_stop,*w_dc_step,
- *w_dcsweep_frame;
- gboolean dc_enable;
- gchar *dc_vin;
- gchar *dc_start,*dc_stop,*dc_step;
-
- // Fourier analysis. Replace with something sane later.
- GtkWidget *w_four_enable,*w_four_freq,*w_four_vout,*w_four_combobox,
- *w_four_add,*w_four_rem,*w_fourier_frame;
- gboolean fourier_enable;
- gchar *fourier_frequency;
- gchar *fourier_nb_vout;
- GSList *fourier_vout;
-
- // Options
- GtkEntry *w_opt_value;
- GtkTreeView *w_opt_list;
- GList *options;
-};
-
-static char *AC_types_list[] = {
- "DEC",
- "LIN",
- "OCT",
- NULL
-};
-
-static SimOption default_options[] = {
- {"TEMP" ,NULL},
-
- {"GMIN" ,NULL},
- {"ABSTOL" ,NULL},
- {"CHGTOL" ,NULL},
- {"RELTOL" ,NULL},
- {"VNTOL" ,NULL},
-
- {"ITL1" ,NULL},
- {"ITL2" ,NULL},
- {"ITL4", NULL},
-
- {"PIVREL", NULL},
- {"PIVTOL", NULL},
-
- {"TNOM", NULL},
- {"TRTOL", NULL},
-
- {"DEFAD", NULL},
- {"DEFAS", NULL},
- {"DEFL", NULL},
- {"DEFW", NULL},
- {NULL, NULL}
-};
-
-#define NG_DEBUG(s) if (0) g_print ("%s\n", s)
-
-static void
-fourier_add_vout_cb (GtkButton *w, SimSettings *sim)
+SimSettings *sim_settings_new ()
{
- GtkComboBoxText *node_box;
- GSList *node_slist;
- gint i;
- gint result = FALSE;
-
- node_box = GTK_COMBO_BOX_TEXT (sim->priv->w_four_combobox);
-
- // Get the node identifier
- for (i=0; (i <1000 && result == FALSE); ++i) {
- if (g_strcmp0 (g_strdup_printf ("V(%d)", i),
- gtk_combo_box_text_get_active_text (node_box)) == 0)
- result = TRUE;
- }
- result=FALSE;
-
- // Is the node identifier already available?
- node_slist = g_slist_copy (sim->priv->fourier_vout);
- while (node_slist) {
- if ((i-1) == atoi (node_slist->data)) {
- result = TRUE;
- }
- node_slist=node_slist->next;
- }
- g_slist_free (node_slist);
- if (!result) {
- GSList *node_slist;
- gchar *text = NULL;
+ SimSettings *sim_settings;
- // Add Node (i-1) at the end of fourier_vout
- text = g_strdup_printf ("%d", i-1);
- sim->priv->fourier_vout = g_slist_append (sim->priv->fourier_vout,
- g_strdup_printf ("%d", i-1));
+ sim_settings = g_new0 (SimSettings, 1);
- // Update the fourier_vout widget
- node_slist = g_slist_copy (sim->priv->fourier_vout);
- if (node_slist->data)
- text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
- node_slist=node_slist->next;
- while (node_slist)
- {
- if (node_slist->data)
- text = g_strdup_printf ("%s V(%d)", text,
- atoi (node_slist->data));
- node_slist = node_slist->next;
- }
- if (text)
- gtk_entry_set_text (GTK_ENTRY (sim->priv->w_four_vout), text);
- else gtk_entry_set_text (GTK_ENTRY (sim->priv->w_four_vout), "");
- g_slist_free (node_slist);
- }
-}
+ sim_settings->configured = FALSE;
+ sim_settings->simulation_requested = FALSE;
-static void
-fourier_remove_vout_cb (GtkButton *w, SimSettings *sim)
-{
- GtkComboBoxText *node_box;
- gint result = FALSE;
- gint i;
-
- node_box = GTK_COMBO_BOX_TEXT (sim->priv->w_four_combobox);
+ // Set some default settings.
+ // transient
+ sim_settings->trans_enable = TRUE;
+ sim_settings->trans_start = g_strdup ("0 s");
+ sim_settings->trans_stop = g_strdup ("5 ms");
+ sim_settings->trans_step = g_strdup ("0.1 ms");
+ sim_settings->trans_step_enable = FALSE;
- // Get the node identifier
- for (i=0; (i < 1000 && result == FALSE); i++) {
- if (g_strcmp0 (g_strdup_printf ("V(%d)", i),
- gtk_combo_box_text_get_active_text (node_box)) == 0)
- result = TRUE;
- }
-
- if (result) {
- GSList *node_slist;
- gchar *text = NULL;
-
- // Remove current data in the g_slist
- {
- GSList *tmp, *prev = NULL;
-
- tmp = sim->priv->fourier_vout;
- while (tmp)
- {
- if (atoi (tmp->data) == i-1)
- {
- if (prev) prev->next = tmp->next;
- else sim->priv->fourier_vout = tmp->next;
-
- g_slist_free_1 (tmp);
- break;
- }
- prev = tmp;
- tmp = prev->next;
- }
- }
+ // AC
+ sim_settings->ac_enable = FALSE;
+ sim_settings->ac_vout = g_strdup ("");
+ sim_settings->ac_type = g_strdup ("DEC");
+ sim_settings->ac_npoints = g_strdup ("50");
+ sim_settings->ac_start = g_strdup ("1 Hz");
+ sim_settings->ac_stop = g_strdup ("1 MHz");
- // Update the fourier_vout widget
- node_slist = g_slist_copy (sim->priv->fourier_vout);
- if (node_slist->data)
- text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
- if (node_slist) node_slist=node_slist->next;
- while (node_slist)
- {
- if (node_slist->data)
- text = g_strdup_printf ("%s V(%d)", text,
- atoi (node_slist->data));
- node_slist = node_slist->next;
- }
- if (text) gtk_entry_set_text (GTK_ENTRY (sim->priv->w_four_vout), text);
- else gtk_entry_set_text (GTK_ENTRY (sim->priv->w_four_vout), "");
+ // DC
+ sim_settings->dc_enable = FALSE;
+ sim_settings->dc_vin = g_strdup ("");
+ sim_settings->dc_vout = g_strdup ("");
+ sim_settings->dc_start = g_strdup ("");
+ sim_settings->dc_stop = g_strdup ("");
+ sim_settings->dc_step = g_strdup ("");
- g_slist_free (node_slist);
- }
-}
+ // Fourier
+ sim_settings->fourier_enable = FALSE;
+ sim_settings->fourier_frequency = g_strdup ("1 MHz");
+ sim_settings->fourier_vout = NULL;
-static void
-set_options_in_list (gchar *key, gchar *val, GtkTreeView *cl)
-{
- int i;
- GtkTreeModel *model;
- GtkTreeIter iter;
- char *name;
- char *value;
-
- model = gtk_tree_view_get_model (cl);
-
- i=0;
- while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) {
- gtk_tree_model_get (model, &iter, 0, &name, 1, &value, -1);
- if (!strcmp (name, key)) {
- gtk_list_store_set (GTK_LIST_STORE(model), &iter, 1, val, -1);
- }
- i++;
- }
-}
+ // Noise
+ sim_settings->noise_enable = FALSE;
+ sim_settings->noise_vin = g_strdup ("");
+ sim_settings->noise_vout = g_strdup ("");
+ sim_settings->noise_type = g_strdup ("DEC");
+ sim_settings->noise_npoints = g_strdup ("50");
+ sim_settings->noise_start = g_strdup ("1 Hz");
+ sim_settings->noise_stop = g_strdup ("1 MHz");
-static void
-get_options_from_list (SimSettings *s)
-{
- int i;
- gchar *name,*value;
- SimOption *so;
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeView *cl = s->priv->w_opt_list;
-
- // Empty the list
- while (s->priv->options) {
- so = s->priv->options->data;
- if (so) {
- // Prevent sigfault on NULL
- if (so->name) g_free (so->name);
- if (so->value) g_free (so->value);
- s->priv->options = g_list_remove (s->priv->options,so);
- g_free (so);
- }
- if (s->priv->options) s->priv->options = s->priv->options->next;
- }
+ sim_settings->options = NULL;
- model = gtk_tree_view_get_model (cl);
- i = 0;
- while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) {
- SimOption *so;
- gtk_tree_model_get (model, &iter, 0, &name, 1, &value, -1);
-
- so = g_new0 (SimOption,1);
- so->name = g_strdup (name);
- so->value = g_strdup (value);
- s->priv->options = g_list_append (s->priv->options, so);
- i++;
- }
+ return sim_settings;
}
-static gboolean
-select_opt_callback (GtkWidget *widget,
- GdkEventButton *event, SimSettings *sim)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
- char *value;
-
- if (event->button != 1) return FALSE;
-
- // Get the current selected row
- selection = gtk_tree_view_get_selection (sim->priv->w_opt_list);
- model = gtk_tree_view_get_model (sim->priv->w_opt_list);
-
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
- return FALSE;
- }
-
- gtk_tree_model_get (model, &iter, 1, &value, -1);
-
- if (value)
- gtk_entry_set_text (sim->priv->w_opt_value, value);
- else
- gtk_entry_set_text (sim->priv->w_opt_value, "");
-
- return FALSE;
+static void sim_option_finalize(SimOption *option) {
+ g_free(option->name);
+ g_free(option->value);
+ g_free(option);
}
-static void
-option_setvalue (GtkWidget *w, SimSettings *s)
-{
- const gchar *value;
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
+void sim_settings_finalize(SimSettings *sim_settings) {
- value = gtk_entry_get_text (s->priv->w_opt_value);
- if (!value) return;
+ // Set some default settings.
+ // transient
+ g_free(sim_settings->trans_start);
+ g_free(sim_settings->trans_stop);
+ g_free(sim_settings->trans_step);
- // Get the current selected row
- selection = gtk_tree_view_get_selection (s->priv->w_opt_list);
- model = gtk_tree_view_get_model (s->priv->w_opt_list);
+ // AC
+ g_free(sim_settings->ac_vout);
+ g_free(sim_settings->ac_type);
+ g_free(sim_settings->ac_npoints);
+ g_free(sim_settings->ac_start);
+ g_free(sim_settings->ac_stop);
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
- return;
- }
+ // DC
+ g_free(sim_settings->dc_vin);
+ g_free(sim_settings->dc_vout);
+ g_free(sim_settings->dc_start);
+ g_free(sim_settings->dc_stop);
+ g_free(sim_settings->dc_step);
- gtk_list_store_set(GTK_LIST_STORE (model), &iter, 1, value, -1);
-}
+ // Fourier
+ sim_settings->fourier_enable = FALSE;
+ g_free(sim_settings->fourier_frequency);
+ if (sim_settings->fourier_vout != NULL)
+ g_slist_free_full(sim_settings->fourier_vout, g_free);
+
+ // Noise
+ g_free(sim_settings->noise_vin);
+ g_free(sim_settings->noise_vout);
+ g_free(sim_settings->noise_type);
+ g_free(sim_settings->noise_npoints);
+ g_free(sim_settings->noise_start);
+ g_free(sim_settings->noise_stop);
+
+ if (sim_settings->options != NULL)
+ g_list_free_full(sim_settings->options, (GDestroyNotify)sim_option_finalize);
+
+ g_free(sim_settings);
+}
+
+gchar *fourier_add_vout(SimSettings *sim_settings, guint node_index) {
+ gboolean result;
+ guint i;
+ gchar *ret_val = NULL;
+ gchar *text;
+ gchar **node_ids;
+ GSList *node_slist;
-static void
-add_option (GtkWidget *w, SimSettings *s)
-{
- GtkEntry *entry;
- GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Add new option"),
- NULL,
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_REJECT,
- GTK_STOCK_OK,
- GTK_RESPONSE_OK,
- NULL);
-
- entry = GTK_ENTRY (gtk_entry_new ());
- gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (
- GTK_DIALOG (dialog))), GTK_WIDGET (entry));
- gtk_widget_show (GTK_WIDGET (entry));
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
- GtkTreeIter iter;
- SimOption *opt = g_new0 (SimOption, 1);
- opt->name = g_strdup (gtk_entry_get_text (entry));
- opt->value = g_strdup ("");
- // Warning : don't free opt later, is added to the list
- sim_settings_add_option (s, opt);
-
- gtk_list_store_append (GTK_LIST_STORE (gtk_tree_view_get_model(
- s->priv->w_opt_list)), &iter);
- gtk_list_store_set (GTK_LIST_STORE (gtk_tree_view_get_model(
- s->priv->w_opt_list)), &iter, 0, opt->name, -1);
+ // Is the node identifier for the output vector already
+ // stored in the fourier_vout list ?
+ node_slist = g_slist_copy (sim_settings->fourier_vout);
+ result = FALSE;
+ while (node_slist) {
+ if ((node_index - 1) == atoi (node_slist->data)) {
+ result = TRUE;
+ }
+ node_slist = node_slist->next;
}
- gtk_widget_destroy (dialog);
-}
+ g_slist_free_full (node_slist, g_free);
+ // If the output vector is not already in the fourier_vout list
+ // then add it to the list and return the updated list.
+ // Otherwise, simply return the existing list of output vectors.
+ if (!result) {
+ // Add Node (node_index-1) at the end of fourier_vout
+ text = g_strdup_printf ("%d", node_index - 1);
+ sim_settings->fourier_vout =
+ g_slist_append (sim_settings->fourier_vout, text);
-static void
-option_remove (GtkWidget *w, SimSettings *s)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreeSelection *selection;
+ // Update the fourier_vout widget
+ node_slist = g_slist_copy (sim_settings->fourier_vout);
+ if (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0)
+ ret_val = g_strdup_printf ("V(%d)", atoi (node_slist->data));
+ node_slist = node_slist->next;
+ }
+ while (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0) {
+ if (ret_val) {
+ text = ret_val;
+ ret_val = g_strdup_printf ("%s V(%d)", ret_val, atoi (node_slist->data));
+ g_free (text);
+ } else {
+ ret_val = g_strdup_printf ("V(%d)", atoi (node_slist->data));
+ }
+ }
+ node_slist = node_slist->next;
+ }
- // Get the current selected row
- selection = gtk_tree_view_get_selection (s->priv->w_opt_list);
- model = gtk_tree_view_get_model (s->priv->w_opt_list);
+ g_slist_free_full (node_slist, g_free);
+ } else {
+ text = sim_settings_get_fourier_vout (sim_settings);
+ node_ids = g_strsplit (text, " ", 0);
+
+ for (i = 0; node_ids[i] != NULL; i++) {
+ if (node_ids[i] && atoi (node_ids[i]) > 0) {
+ if (ret_val) {
+ text = ret_val;
+ ret_val = g_strdup_printf ("%s V(%d)", ret_val, atoi (node_ids[i]));
+ g_free (text);
+ } else {
+ ret_val = g_strdup_printf ("V(%d)", atoi (node_ids[i]));
+ }
+ }
+ }
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
- return;
+ g_strfreev (node_ids);
}
- gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, "", -1);
-}
+ if (!ret_val)
+ ret_val = g_strdup ("");
-static void
-trans_enable_cb (GtkWidget *widget, SimSettings *s)
-{
- gboolean enable;
- enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- if (enable)
- gtk_widget_show (s->priv->w_trans_frame);
- else
- gtk_widget_hide (s->priv->w_trans_frame);
- gtk_container_resize_children (GTK_CONTAINER (s->notebook));
+ return ret_val;
}
-static void
-trans_step_enable_cb (GtkWidget *widget, SimSettings *s)
+gboolean sim_settings_get_trans (const SimSettings *sim_settings)
{
- gboolean enable, step_enable;
-
- step_enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
- enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
- s->priv->w_trans_enable));
-
- gtk_widget_set_sensitive (s->priv->w_trans_step, step_enable & enable);
+ return sim_settings->trans_enable;
}
-static void
-entry_changed_cb (GtkWidget *widget, SimSettings *s)
+gboolean sim_settings_get_trans_init_cond (const SimSettings *sim_settings)
{
-
+ return sim_settings->trans_init_cond;
}
-static void
-ac_enable_cb (GtkWidget *widget, SimSettings *s)
+gboolean sim_settings_get_trans_analyze_all (const SimSettings *sim_settings)
{
- gboolean enable;
- enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- if (enable)
- gtk_widget_show (s->priv->w_ac_frame);
- else
- gtk_widget_hide (s->priv->w_ac_frame);
- gtk_container_resize_children (GTK_CONTAINER (s->notebook));
+ return sim_settings->trans_analyze_all;
}
-static void
-fourier_enable_cb (GtkWidget *widget, SimSettings *s)
+gdouble sim_settings_get_trans_start (const SimSettings *sim_settings)
{
- gboolean enable;
- enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- if (enable)
- gtk_widget_show (s->priv->w_fourier_frame);
- else
- gtk_widget_hide (s->priv->w_fourier_frame);
- gtk_container_resize_children (GTK_CONTAINER (s->notebook));
+ gchar *text = sim_settings->trans_start;
+ return oregano_strtod (text, "s");
}
-static void
-dc_enable_cb (GtkWidget *widget, SimSettings *s)
+gdouble sim_settings_get_trans_stop (const SimSettings *sim_settings)
{
- gboolean enable;
- enable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
- if (enable)
- gtk_widget_show (s->priv->w_dcsweep_frame);
- else
- gtk_widget_hide (s->priv->w_dcsweep_frame);
- gtk_container_resize_children (GTK_CONTAINER (s->notebook));
+ gchar *text = sim_settings->trans_stop;
+ return oregano_strtod (text, "s");
}
-static int
-delete_event_cb (GtkWidget *widget, GdkEvent *event, SimSettings *s)
+gdouble sim_settings_get_trans_step (const SimSettings *sim_settings)
{
- s->pbox = NULL;
- return FALSE;
+ gchar *text = sim_settings->trans_step;
+ return oregano_strtod (text, "s");
}
-SimSettings *
-sim_settings_new (Schematic *sm)
+gdouble sim_settings_get_trans_step_enable (const SimSettings *sim_settings)
{
- SimSettings *s;
-
- s = g_new0 (SimSettings, 1);
- s->sm = sm;
-
- s->priv = g_new0 (SimSettingsPriv, 1);
-
- //Set some default settings.
- // transient
- s->priv->trans_enable = TRUE;
- s->priv->trans_start = g_strdup ("0 s");
- s->priv->trans_stop = g_strdup ("5 ms");
- s->priv->trans_step = g_strdup ("0.1 ms");
- s->priv->trans_step_enable = FALSE;
-
- // AC
- s->priv->ac_enable = FALSE;
- s->priv->ac_type = g_strdup ("DEC");
- s->priv->ac_npoints= g_strdup ("50");
- s->priv->ac_start = g_strdup ("1");
- s->priv->ac_stop = g_strdup ("1 Meg");
-
- // DC
- s->priv->dc_enable = FALSE;
- s->priv->dc_vin = g_strdup ("");
- s->priv->dc_start = g_strdup ("");
- s->priv->dc_stop = g_strdup ("");
- s->priv->dc_step = g_strdup ("");
-
- // Fourier
- s->priv->fourier_enable = FALSE;
- s->priv->fourier_frequency = g_strdup ("");
- s->priv->fourier_vout = NULL;
-
- s->priv->options=0;
-
- return s;
+ return sim_settings->trans_step_enable;
}
-gboolean
-sim_settings_get_trans (SimSettings *sim_settings)
+void sim_settings_set_trans (SimSettings *sim_settings, gboolean enable)
{
- return sim_settings->priv->trans_enable;
+ sim_settings->trans_enable = enable;
}
-gboolean
-sim_settings_get_trans_init_cond (SimSettings *sim_settings)
+void sim_settings_set_trans_start (SimSettings *sim_settings, gchar *str)
{
- return sim_settings->priv->trans_init_cond;
+ if (sim_settings->trans_start)
+ g_strdup (sim_settings->trans_start);
+ sim_settings->trans_start = g_strdup (str);
}
-gdouble
-sim_settings_get_trans_start (SimSettings *sim_settings)
+void sim_settings_set_trans_init_cond (SimSettings *sim_settings, gboolean enable)
{
- gchar *text = sim_settings->priv->trans_start;
- return oregano_strtod (text, 's');
+ sim_settings->trans_init_cond = enable;
}
-gdouble
-sim_settings_get_trans_stop (SimSettings *sim_settings)
+void sim_settings_set_trans_analyze_all (SimSettings *sim_settings, gboolean enable)
{
- gchar *text = sim_settings->priv->trans_stop;
- return oregano_strtod (text, 's');
+ sim_settings->trans_analyze_all = enable;
}
-gdouble
-sim_settings_get_trans_step (SimSettings *sim_settings)
+void sim_settings_set_trans_stop (SimSettings *sim_settings, gchar *str)
{
- gchar *text = sim_settings->priv->trans_step;
- return oregano_strtod (text, 's');
+ if (sim_settings->trans_stop)
+ g_strdup (sim_settings->trans_stop);
+ sim_settings->trans_stop = g_strdup (str);
}
-gdouble
-sim_settings_get_trans_step_enable (SimSettings *sim_settings)
+void sim_settings_set_trans_step (SimSettings *sim_settings, gchar *str)
{
- return sim_settings->priv->trans_step_enable;
+ if (sim_settings->trans_step)
+ g_strdup (sim_settings->trans_step);
+ sim_settings->trans_step = g_strdup (str);
}
-void
-sim_settings_set_trans (SimSettings *sim_settings, gboolean enable)
+void sim_settings_set_trans_step_enable (SimSettings *sim_settings, gboolean enable)
{
- sim_settings->priv->trans_enable = enable;
+ sim_settings->trans_step_enable = enable;
}
-void
-sim_settings_set_trans_start (SimSettings *sim_settings, gchar *str)
-{
- if (sim_settings->priv->trans_start)
- g_strdup (sim_settings->priv->trans_start);
- sim_settings->priv->trans_start = g_strdup (str);
-}
+gboolean sim_settings_get_ac (const SimSettings *sim_settings) { return sim_settings->ac_enable; }
-void
-sim_settings_set_trans_init_cond (SimSettings *sim_settings, gboolean enable)
-{
- sim_settings->priv->trans_init_cond = enable;
-}
+gchar *sim_settings_get_ac_vout (const SimSettings *sim_settings) { return sim_settings->ac_vout; }
-void
-sim_settings_set_trans_stop (SimSettings *sim_settings, gchar *str)
-{
- if (sim_settings->priv->trans_stop)
- g_strdup (sim_settings->priv->trans_stop);
- sim_settings->priv->trans_stop = g_strdup (str);
-}
+gchar *sim_settings_get_ac_type (const SimSettings *sim_settings) { return sim_settings->ac_type; }
-void
-sim_settings_set_trans_step (SimSettings *sim_settings, gchar *str)
+gint sim_settings_get_ac_npoints (const SimSettings *sim_settings)
{
- if (sim_settings->priv->trans_step)
- g_strdup (sim_settings->priv->trans_step);
- sim_settings->priv->trans_step = g_strdup (str);
+ return atoi (sim_settings->ac_npoints);
}
-void
-sim_settings_set_trans_step_enable (SimSettings *sim_settings, gboolean enable)
+gdouble sim_settings_get_ac_start (const SimSettings *sim_settings)
{
- sim_settings->priv->trans_step_enable = enable;
+ return oregano_strtod (sim_settings->ac_start, "Hz");
}
-gboolean
-sim_settings_get_ac (SimSettings *sim_settings)
+gdouble sim_settings_get_ac_stop (const SimSettings *sim_settings)
{
- return sim_settings->priv->ac_enable;
+ return oregano_strtod (sim_settings->ac_stop, "Hz");
}
-gchar *
-sim_settings_get_ac_type (SimSettings *sim_settings)
+void sim_settings_set_ac (SimSettings *sim_settings, gboolean enable)
{
- return sim_settings->priv->ac_type;
+ sim_settings->ac_enable = enable;
}
-gint
-sim_settings_get_ac_npoints (SimSettings *sim_settings)
+void sim_settings_set_ac_vout (SimSettings *sim_settings, gchar *str)
{
- return atoi (sim_settings->priv->ac_npoints);
+ g_free (sim_settings->ac_vout);
+ sim_settings->ac_vout = g_strdup (str);
}
-gdouble
-sim_settings_get_ac_start (SimSettings *sim_settings)
+void sim_settings_set_ac_type (SimSettings *sim_settings, gchar *str)
{
- return oregano_strtod (sim_settings->priv->ac_start, 's');
+ g_free (sim_settings->ac_type);
+ sim_settings->ac_type = g_strdup (str);
}
-gdouble
-sim_settings_get_ac_stop (SimSettings *sim_settings)
+void sim_settings_set_ac_npoints (SimSettings *sim_settings, gchar *str)
{
- return oregano_strtod (sim_settings->priv->ac_stop,'s');
+ g_free (sim_settings->ac_npoints);
+ sim_settings->ac_npoints = g_strdup (str);
}
-void
-sim_settings_set_ac (SimSettings *sim_settings,gboolean enable)
+void sim_settings_set_ac_start (SimSettings *sim_settings, gchar *str)
{
- sim_settings->priv->ac_enable = enable;
+ g_free (sim_settings->ac_start);
+ sim_settings->ac_start = g_strdup (str);
}
-void
-sim_settings_set_ac_type (SimSettings *sim_settings,gchar *str)
+void sim_settings_set_ac_stop (SimSettings *sim_settings, gchar *str)
{
- if (sim_settings->priv->ac_type)
- g_free (sim_settings->priv->ac_type);
- sim_settings->priv->ac_type = g_strdup (str);
+ g_free (sim_settings->ac_stop);
+ sim_settings->ac_stop = g_strdup (str);
}
-void
-sim_settings_set_ac_npoints (SimSettings *sim_settings,gchar *str)
-{
- if (sim_settings->priv->ac_npoints)
- g_free (sim_settings->priv->ac_npoints);
- sim_settings->priv->ac_npoints = g_strdup (str);
+gboolean sim_settings_get_dc (const SimSettings *sim_settings) { return sim_settings->dc_enable; }
-}
+gchar *sim_settings_get_dc_vsrc (const SimSettings *sim_settings) { return sim_settings->dc_vin; }
+
+gchar *sim_settings_get_dc_vout (const SimSettings *sim_settings) { return sim_settings->dc_vout; }
-void
-sim_settings_set_ac_start (SimSettings *sim_settings,gchar *str)
+gdouble sim_settings_get_dc_start (const SimSettings *sim_settings)
{
- if (sim_settings->priv->ac_start)
- g_free (sim_settings->priv->ac_start);
- sim_settings->priv->ac_start = g_strdup (str);
+ return oregano_strtod (sim_settings->dc_start, "V");
}
-void
-sim_settings_set_ac_stop (SimSettings *sim_settings,gchar *str)
+gdouble sim_settings_get_dc_stop (const SimSettings *sim_settings)
{
- if (sim_settings->priv->ac_stop)
- g_free (sim_settings->priv->ac_stop);
- sim_settings->priv->ac_stop = g_strdup (str);
+ return oregano_strtod (sim_settings->dc_stop, "V");
}
-gboolean
-sim_settings_get_dc (SimSettings *sim_settings)
+gdouble sim_settings_get_dc_step (const SimSettings *sim_settings)
{
- return sim_settings->priv->dc_enable;
+ return oregano_strtod (sim_settings->dc_step, "V");
}
-gchar*
-sim_settings_get_dc_vsrc (SimSettings *sim_settings)
+void sim_settings_set_dc (SimSettings *sim_settings, gboolean enable)
{
- return sim_settings->priv->dc_vin;
+ sim_settings->dc_enable = enable;
}
-gdouble
-sim_settings_get_dc_start (SimSettings *sim_settings)
+void sim_settings_set_dc_vsrc (SimSettings *sim_settings, gchar *str)
{
- return oregano_strtod (sim_settings->priv->dc_start, 's');
+ g_free (sim_settings->dc_vin);
+ sim_settings->dc_vin = g_strdup (str);
}
-gdouble
-sim_settings_get_dc_stop (SimSettings *sim_settings)
+void sim_settings_set_dc_vout (SimSettings *sim_settings, gchar *str)
{
- return oregano_strtod (sim_settings->priv->dc_stop, 's');
+ g_free (sim_settings->dc_vout);
+ sim_settings->dc_vout = g_strdup (str);
}
-gdouble
-sim_settings_get_dc_step (SimSettings *sim_settings)
+void sim_settings_set_dc_start (SimSettings *sim_settings, gchar *str)
{
- return oregano_strtod (sim_settings->priv->dc_step, 's');
+ g_free (sim_settings->dc_start);
+ sim_settings->dc_start = g_strdup (str);
}
-void
-sim_settings_set_dc (SimSettings *sim_settings, gboolean enable)
+void sim_settings_set_dc_stop (SimSettings *sim_settings, gchar *str)
{
- sim_settings->priv->dc_enable = enable;
+ g_free (sim_settings->dc_stop);
+ sim_settings->dc_stop = g_strdup (str);
}
-void
-sim_settings_set_dc_vsrc (SimSettings *sim_settings, gchar *str)
+void sim_settings_set_dc_step (SimSettings *sim_settings, gchar *str)
{
- if (sim_settings->priv->dc_vin)
- g_free (sim_settings->priv->dc_vin);
- sim_settings->priv->dc_vin = g_strdup (str);
+ g_free (sim_settings->dc_step);
+ sim_settings->dc_step = g_strdup (str);
}
-void
-sim_settings_set_dc_start (SimSettings *sim_settings, gchar *str)
-{
- if (sim_settings->priv->dc_start)
- g_free (sim_settings->priv->dc_start);
- sim_settings->priv->dc_start = g_strdup (str);
+void sim_settings_set_fourier (SimSettings *sim_settings, gboolean enable)
+{
+ sim_settings->fourier_enable = enable;
}
-void
-sim_settings_set_dc_stop (SimSettings *sim_settings, gchar *str)
+void sim_settings_set_fourier_frequency (SimSettings *sim_settings, gchar *str)
{
- if (sim_settings->priv->dc_stop)
- g_free (sim_settings->priv->dc_stop);
- sim_settings->priv->dc_stop = g_strdup (str);
+ g_free (sim_settings->fourier_frequency);
+ sim_settings->fourier_frequency = g_strdup (str);
}
-void
-sim_settings_set_dc_step (SimSettings *sim_settings, gchar *str)
+void sim_settings_set_fourier_vout (SimSettings *sim_settings, gchar *str)
{
- if (sim_settings->priv->dc_step)
- g_free (sim_settings->priv->dc_step);
- sim_settings->priv->dc_step = g_strdup (str);
+ gchar **node_ids = NULL;
+ gint i;
+
+ if (!str)
+ return;
+
+ g_slist_free_full (sim_settings->fourier_vout, g_free);
+ sim_settings->fourier_vout = NULL;
+
+ node_ids = g_strsplit (str, " ", 0);
+ for (i = 0; node_ids[i] != NULL; i++) {
+ if (node_ids[i])
+ sim_settings->fourier_vout =
+ g_slist_append (sim_settings->fourier_vout, g_strdup (node_ids[i]));
+ }
+
+ g_strfreev (node_ids);
}
-void
-sim_settings_set_fourier (SimSettings *sim_settings, gboolean enable)
+gboolean sim_settings_get_fourier (const SimSettings *sim_settings)
{
- sim_settings->priv->fourier_enable = enable;
+ return sim_settings->fourier_enable;
}
-void
-sim_settings_set_fourier_frequency (SimSettings *sim_settings,gchar *str)
+gdouble sim_settings_get_fourier_frequency (const SimSettings *sim_settings)
{
- if (sim_settings->priv->fourier_frequency)
- g_free (sim_settings->priv->fourier_frequency);
- sim_settings->priv->fourier_frequency = g_strdup (str);
+ return oregano_strtod (sim_settings->fourier_frequency, "Hz");
}
-void
-sim_settings_set_fourier_vout (SimSettings *sim_settings,
- gchar *str)
+gchar *sim_settings_get_fourier_vout (const SimSettings *sim_settings)
{
- gchar **node_ids=NULL;
- gint i;
- if (sim_settings->priv->fourier_vout)
- g_free (sim_settings->priv->fourier_vout);
- node_ids = g_strsplit (g_strdup (str), " ", 0);
- for (i=0; node_ids[i]!= NULL; i++) {
- if (node_ids[i])
- sim_settings->priv->fourier_vout =
- g_slist_append (sim_settings->priv->fourier_vout,
- g_strdup (node_ids[i]));
+ GSList *node_slist;
+ gchar *text, *text2;
+ gchar *ret_val = NULL;
+
+ text = NULL;
+ node_slist = g_slist_copy (sim_settings->fourier_vout);
+ if (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0)
+ text = g_strdup_printf ("%d", atoi (node_slist->data));
+ node_slist = node_slist->next;
+ }
+ while (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0) {
+ if (text) {
+ text2 = text;
+ text = g_strdup_printf ("%s %d", text, atoi (node_slist->data));
+ g_free (text2);
+ } else {
+ text = g_strdup_printf ("%d", atoi (node_slist->data));
+ }
+ }
+ node_slist = node_slist->next;
}
-}
+ g_slist_free_full (node_slist, g_free);
-gboolean
-sim_settings_get_fourier (SimSettings *sim_settings)
-{
- return sim_settings->priv->fourier_enable;
-}
+ if (text)
+ ret_val = text;
+ else
+ ret_val = g_strdup ("");
-gint
-sim_settings_get_fourier_frequency (SimSettings *sim_settings)
-{
- return atoi (sim_settings->priv->fourier_frequency);
+ return ret_val;
}
-gchar *
-sim_settings_get_fourier_vout (SimSettings *sim)
+gchar *sim_settings_get_fourier_nodes (const SimSettings *sim_settings)
{
GSList *node_slist;
- gchar *text = NULL;
-
- node_slist = g_slist_copy (sim->priv->fourier_vout);
- if (node_slist) text = g_strdup_printf ("%d", atoi (node_slist->data));
- if (node_slist) node_slist=node_slist->next;
- while (node_slist)
- {
- if (node_slist->data)
- text = g_strdup_printf ("%s %d", text, atoi (node_slist->data));
+ gchar *ret_val = NULL;
+ gchar *text, *text2;
+
+ text = NULL;
+ node_slist = g_slist_copy (sim_settings->fourier_vout);
+ if (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0)
+ text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
node_slist = node_slist->next;
}
- g_slist_free (node_slist);
- return text;
-}
-
-gchar *
-sim_settings_get_fourier_nodes (SimSettings *sim)
-{
- GSList *node_slist;
- gchar *text = NULL;
-
- node_slist = g_slist_copy (sim->priv->fourier_vout);
- if (node_slist->data)
- text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
- if (node_slist) node_slist=node_slist->next;
- while (node_slist)
- {
- if (node_slist->data)
- text = g_strdup_printf ("%s V(%d)", text, atoi (node_slist->data));
+ while (node_slist) {
+ if (node_slist->data && atoi (node_slist->data) > 0) {
+ if (text) {
+ text2 = text;
+ text = g_strdup_printf ("%s V(%d)", text, atoi (node_slist->data));
+ g_free (text2);
+ } else {
+ text = g_strdup_printf ("V(%d)", atoi (node_slist->data));
+ }
+ }
node_slist = node_slist->next;
}
- g_slist_free (node_slist);
- return text;
+
+ if (text)
+ ret_val = text;
+ else
+ ret_val = g_strdup ("");
+
+ g_slist_free_full (node_slist, g_free);
+
+ return ret_val;
}
-static void
-response_callback (GtkButton *button, Schematic *sm)
+gboolean sim_settings_get_noise (const SimSettings *sim_settings) { return sim_settings->noise_enable; }
+
+gchar *sim_settings_get_noise_vsrc (const SimSettings *sim_settings) { return sim_settings->noise_vin; }
+
+gchar *sim_settings_get_noise_vout (const SimSettings *sim_settings) { return sim_settings->noise_vout; }
+
+gchar *sim_settings_get_noise_type (const SimSettings *sim_settings) { return sim_settings->noise_type; }
+
+gint sim_settings_get_noise_npoints (const SimSettings *sim_settings)
{
- gint page;
- SimSettings *s;
- gchar *tmp = NULL, **node_ids= NULL;
-
- s = schematic_get_sim_settings (sm);
-
- g_object_get (s->notebook, "page", &page, NULL);
-
- // Trans
- s->priv->trans_enable = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_trans_enable));
-
- if (s->priv->trans_start)
- g_free (s->priv->trans_start);
- s->priv->trans_start = gtk_editable_get_chars (
- GTK_EDITABLE (s->priv->w_trans_start), 0, -1);
-
- if (s->priv->trans_stop)
- g_free (s->priv->trans_stop);
- s->priv->trans_stop = gtk_editable_get_chars (
- GTK_EDITABLE (s->priv->w_trans_stop), 0, -1);
-
- if (s->priv->trans_step)
- g_free (s->priv->trans_step);
- s->priv->trans_step = gtk_editable_get_chars (
- GTK_EDITABLE (s->priv->w_trans_step), 0, -1);
-
- s->priv->trans_step_enable = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_trans_step_enable));
-
- s->priv->trans_init_cond = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_trans_init_cond));
-
- // DC
- s->priv->dc_enable = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_dc_enable));
- if (s->priv->dc_vin)
- g_free (s->priv->dc_vin);
-
- tmp = gtk_combo_box_text_get_active_text (
- GTK_COMBO_BOX_TEXT (s->priv->w_dc_vin));
- node_ids = g_strsplit (g_strdup (tmp), "V(", 0);
- tmp = node_ids[1];
- node_ids = g_strsplit (g_strdup (tmp), ")", 0);
- s->priv->dc_vin = node_ids[0];
-
- if (s->priv->dc_start)
- g_free (s->priv->dc_start);
- s->priv->dc_start = g_strdup (gtk_entry_get_text (
- GTK_ENTRY (s->priv->w_dc_start)));
-
- if (s->priv->dc_stop)
- g_free (s->priv->dc_stop);
- s->priv->dc_stop = g_strdup (gtk_entry_get_text (
- GTK_ENTRY (s->priv->w_dc_stop)));
-
- if (s->priv->dc_step)
- g_free (s->priv->dc_step);
- s->priv->dc_step = g_strdup (gtk_entry_get_text (
- GTK_ENTRY (s->priv->w_dc_step)));
-
- // AC
- s->priv->ac_enable = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_ac_enable));
-
- if (s->priv->ac_type)
- g_free (s->priv->ac_type);
- s->priv->ac_type = gtk_combo_box_text_get_active_text (
- GTK_COMBO_BOX_TEXT (s->priv->w_ac_type));
-
- if (s->priv->ac_npoints)
- g_free (s->priv->ac_npoints);
- s->priv->ac_npoints = g_strdup(gtk_entry_get_text (
- GTK_ENTRY (s->priv->w_ac_npoints)));
-
- if (s->priv->ac_start)
- g_free (s->priv->ac_start);
- s->priv->ac_start = g_strdup (gtk_entry_get_text(
- GTK_ENTRY (s->priv->w_ac_start)));
-
- if (s->priv->ac_stop)
- g_free (s->priv->ac_stop);
- s->priv->ac_stop = g_strdup (gtk_entry_get_text(
- GTK_ENTRY (s->priv->w_ac_stop)));
-
- // Fourier analysis
- s->priv->fourier_enable = gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (s->priv->w_four_enable));
-
- if (s->priv->fourier_frequency)
- g_free (s->priv->fourier_frequency);
- s->priv->fourier_frequency = g_strdup (gtk_entry_get_text (
- GTK_ENTRY (s->priv->w_four_freq)));
-
- gtk_container_resize_children (GTK_CONTAINER (s->notebook));
-
- // Options
- get_options_from_list (s);
- gtk_widget_hide (GTK_WIDGET(s->pbox));
- s->pbox = NULL;
- s->notebook = NULL;
-
- // Schematic is dirty now ;-)
- schematic_set_dirty (sm, TRUE);
- g_free (tmp);
- g_free (node_ids);
+ return atoi (sim_settings->noise_npoints);
}
-void
-sim_settings_show (GtkWidget *widget, SchematicView *sv)
+gdouble sim_settings_get_noise_start (const SimSettings *sim_settings)
{
- int i;
- GtkWidget *toplevel, *w, *pbox, *combo_box;
- GtkTreeView *opt_list;
- GtkCellRenderer *cell_option, *cell_value;
- GtkTreeViewColumn *column_option, *column_value;
- GtkListStore *opt_model;
- GtkTreeIter iter;
- GtkBuilder *gui;
- GError *perror = NULL;
- gchar * msg;
- SimSettings *s;
- Schematic *sm;
- GList *list;
- GList *sources = NULL, *ltmp;
- GtkComboBox *node_box;
- GtkListStore *node_list_store;
- gchar *text = NULL;
- GSList * slist = NULL, *node_list = NULL;
-
- g_return_if_fail (sv != NULL);
-
- sm = schematic_view_get_schematic (sv);
- s = schematic_get_sim_settings (sm);
-
- // Only allow one instance of the property box per schematic.
- if (s->pbox) {
- gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (s->pbox)));
- return;
- }
-
- if (!g_file_test (OREGANO_UIDIR "/sim-settings.ui", G_FILE_TEST_EXISTS)) {
- gchar *msg;
- msg = g_strdup_printf (
- _("The file %s could not be found."
- "You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/sim-settings.ui");
- oregano_error_with_title (
- _("Could not create simulation settings dialog"), msg);
- g_free (msg);
- return;
- }
+ return oregano_strtod (sim_settings->noise_start, "Hz");
+}
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create simulation settings dialog"));
- return;
- }
- else
- gtk_builder_set_translation_domain (gui, NULL);
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/sim-settings.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (
- _("Could not create simulation settings dialog"), msg);
- g_error_free (perror);
- return;
- }
+gdouble sim_settings_get_noise_stop (const SimSettings *sim_settings)
+{
+ return oregano_strtod (sim_settings->noise_stop, "Hz");
+}
- toplevel = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
- if (!toplevel) {
- oregano_error (_("Could not create simulation settings dialog"));
- return;
- }
+void sim_settings_set_noise (SimSettings *sim_settings, gboolean enable)
+{
+ sim_settings->noise_enable = enable;
+}
- pbox = toplevel;
- s->pbox = pbox;
- s->notebook = GTK_NOTEBOOK (gtk_builder_get_object (gui, "notebook"));
- g_signal_connect (G_OBJECT (pbox), "delete_event",
- G_CALLBACK (delete_event_cb), s);
-
- // Prepare options list
- s->priv->w_opt_value = GTK_ENTRY (gtk_builder_get_object (gui, "opt_value"));
- opt_list = s->priv->w_opt_list = GTK_TREE_VIEW (
- gtk_builder_get_object (gui, "option_list"));
-
- // Grab the frames
- s->priv->w_trans_frame = GTK_WIDGET (gtk_builder_get_object (gui,
- "trans_frame"));
- s->priv->w_ac_frame = GTK_WIDGET (gtk_builder_get_object (gui,
- "ac_frame"));
- s->priv->w_dcsweep_frame = GTK_WIDGET (gtk_builder_get_object (gui,
- "dcsweep_frame"));
- s->priv->w_fourier_frame = GTK_WIDGET (gtk_builder_get_object (gui,
- "fourier_frame"));
-
- // Create the Columns
- cell_option = gtk_cell_renderer_text_new ();
- cell_value = gtk_cell_renderer_text_new ();
- column_option = gtk_tree_view_column_new_with_attributes (N_("Option"),
- cell_option, "text", 0, NULL);
- column_value = gtk_tree_view_column_new_with_attributes (N_("Value"),
- cell_value, "text", 1, NULL);
-
- // Create the model
- opt_model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
- gtk_tree_view_set_model (opt_list, GTK_TREE_MODEL (opt_model));
- gtk_tree_view_append_column (opt_list, column_option);
- gtk_tree_view_append_column (opt_list, column_value);
-
- if (s->priv->options == NULL) {
- // Load defaults
- for (i = 0; default_options[i].name; i++) {
- gtk_list_store_append (opt_model, &iter);
- gtk_list_store_set (opt_model, &iter, 0,
- default_options[i].name, -1);
- }
- }
- else {
- // Load schematic options
- list = s->priv->options;
- while (list) {
- SimOption *so = list->data;
- if (so) {
- gtk_list_store_append (opt_model, &iter);
- gtk_list_store_set (opt_model, &iter, 0, so->name, -1);
- }
- list = list->next;
- }
- }
+void sim_settings_set_noise_vsrc (SimSettings *sim_settings, gchar *str)
+{
+ g_free (sim_settings->noise_vin);
+ sim_settings->noise_vin = g_strdup (str);
+}
- // Set the options already stored
- list = s->priv->options;
- while (list) {
- SimOption *so = list->data;
- if (so)
- set_options_in_list (so->name, so->value, opt_list);
- list = list->next;
- }
+void sim_settings_set_noise_vout (SimSettings *sim_settings, gchar *str)
+{
+ g_free (sim_settings->noise_vout);
+ sim_settings->noise_vout = g_strdup (str);
+}
- g_signal_connect (G_OBJECT (opt_list), "button_release_event",
- G_CALLBACK (select_opt_callback), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "opt_accept"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (option_setvalue), s);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "opt_remove"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (option_remove), s);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "add_option"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (add_option), s);
-
- // Creation of Close Button
- w = GTK_WIDGET (gtk_builder_get_object (gui, "button1"));
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (response_callback), sm);
-
- // Transient //
- // ********* //
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_start"));
- if (s->priv->trans_start) gtk_entry_set_text (GTK_ENTRY (w),
- s->priv->trans_start);
- s->priv->w_trans_start = w;
- g_signal_connect(G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_stop"));
- if (s->priv->trans_stop)
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->trans_stop);
- s->priv->w_trans_stop = w;
- g_signal_connect(G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_step"));
- if (s->priv->trans_step)
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->trans_step);
- s->priv->w_trans_step = w;
- g_signal_connect(G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_enable"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->priv->trans_enable);
- s->priv->w_trans_enable = w;
- g_signal_connect (G_OBJECT (s->priv->w_trans_enable), "clicked",
- G_CALLBACK (trans_enable_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_step_enable"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
- s->priv->trans_step_enable);
- s->priv->w_trans_step_enable = w;
- g_signal_connect (G_OBJECT (s->priv->w_trans_step_enable), "clicked",
- G_CALLBACK (trans_step_enable_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "trans_init_cond"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
- s->priv->trans_init_cond);
- s->priv->w_trans_init_cond = w;
-
- g_signal_connect (G_OBJECT (s->priv->w_trans_enable), "clicked",
- G_CALLBACK (trans_enable_cb), s);
-
- g_signal_connect (G_OBJECT (s->priv->w_trans_step_enable), "clicked",
- G_CALLBACK (trans_step_enable_cb), s);
-
- // AC //
- // *** //
- w = GTK_WIDGET (gtk_builder_get_object (gui, "ac_enable"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->priv->ac_enable);
- s->priv->w_ac_enable=w;
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (ac_enable_cb), s);
-
- // Initialilisation of the various AC types
- w = GTK_WIDGET (gtk_builder_get_object (gui, "ac_type"));
- gtk_widget_destroy (w);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "table14"));
- combo_box = gtk_combo_box_text_new ();
- gtk_table_attach (GTK_TABLE (w),combo_box, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL,
- GTK_SHRINK,
- 0, 0);
- s->priv->w_ac_type = combo_box;
-
- {
- gint index = 0;
- for (index = 0; AC_types_list[index]!= NULL ; index++) {
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box),
- AC_types_list[index]);
- }
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box),0);
- }
- g_signal_connect (G_OBJECT (GTK_COMBO_BOX (combo_box)), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "ac_npoints"));
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->ac_npoints);
- s->priv->w_ac_npoints = w;
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "ac_start"));
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->ac_start);
- s->priv->w_ac_start = w;
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "ac_stop"));
- gtk_entry_set_text(GTK_ENTRY (w), s->priv->ac_stop);
- s->priv->w_ac_stop = w;
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- // DC //
- // ***** //
- w = GTK_WIDGET (gtk_builder_get_object (gui, "dc_enable"));
- s->priv->w_dc_enable = w;
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), s->priv->dc_enable);
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (dc_enable_cb), s);
-
- // Get list of sources
- node_list = netlist_helper_get_voltmeters_list (
- schematic_view_get_schematic (sv), &perror);
- if (perror != NULL) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create a netlist"), msg);
- g_error_free (perror);
- return;
- }
- if (!node_list) {
- oregano_error (_("No node in the schematic!"));
- return;
- }
- for (; node_list; node_list = node_list->next) {
- gchar * tmp;
- tmp = g_strdup_printf ("V(%d)", atoi (node_list->data));
- sources = g_list_prepend (sources, tmp);
- }
- w = GTK_WIDGET (gtk_builder_get_object (gui, "dc_vin1"));
- gtk_widget_destroy (w);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "table13"));
- combo_box = gtk_combo_box_text_new ();
-
- gtk_table_attach (GTK_TABLE (w),combo_box, 1, 2, 0, 1,
- GTK_EXPAND | GTK_FILL,
- GTK_SHRINK,
- 0, 0);
- s->priv->w_dc_vin = combo_box;
- if (sources) {
- for (; sources; sources = sources->next) {
- gtk_combo_box_text_append_text (
- GTK_COMBO_BOX_TEXT (combo_box), sources->data);
- }
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box),0);
- }
- g_signal_connect (G_OBJECT (combo_box), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "dc_start1"));
- s->priv->w_dc_start = w;
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->dc_start);
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "dc_stop1"));
- s->priv->w_dc_stop = w;
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->dc_stop);
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "dc_step1"));
- s->priv->w_dc_step = w;
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->dc_step);
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
-
- for (ltmp = sources; ltmp; ltmp = ltmp->next) g_free (ltmp->data);
- g_list_free (sources);
-
- // Fourier //
- // ******* //
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_enable"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
- s->priv->fourier_enable);
- s->priv->w_four_enable = w;
- g_signal_connect (G_OBJECT(w), "clicked",
- G_CALLBACK (fourier_enable_cb), s);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_freq"));
- s->priv->w_four_freq = w;
- g_signal_connect (G_OBJECT(w), "changed",
- G_CALLBACK (entry_changed_cb), s);
- gtk_entry_set_text (GTK_ENTRY (w), s->priv->fourier_frequency);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_vout"));
- s->priv->w_four_vout = w;
- g_signal_connect (G_OBJECT (w), "changed",
- G_CALLBACK (entry_changed_cb), s);
+void sim_settings_set_noise_type (SimSettings *sim_settings, gchar *str)
+{
+ g_free (sim_settings->noise_type);
+ sim_settings->noise_type = g_strdup (str);
+}
- text = NULL;
- slist = g_slist_copy (s->priv->fourier_vout);
- if (slist) {
- if (atoi (slist->data) != 0)
- text = g_strdup_printf ("V(%d)", atoi (slist->data));
-
- slist = slist->next;
- while (slist)
- {
- if (atoi (slist->data) != 0)
- text = g_strdup_printf ("%s V(%d)", text, atoi (slist->data));
- slist = slist->next;
- }
-
- if (text)
- gtk_entry_set_text (GTK_ENTRY (w), text);
- else
- gtk_entry_set_text (GTK_ENTRY (w), "");
- }
- if (text)
- gtk_entry_set_text (GTK_ENTRY (w), text);
- else
- gtk_entry_set_text (GTK_ENTRY (w), "");
- g_slist_free (slist);
-
- // Present in the combo box the nodes of the schematic
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_select_out"));
- gtk_widget_destroy (w);
-
- w = GTK_WIDGET (gtk_builder_get_object (gui, "table12"));
- combo_box = gtk_combo_box_text_new ();
-
- gtk_table_attach (GTK_TABLE (w),combo_box, 2, 3, 2, 3,
- GTK_EXPAND | GTK_FILL,
- GTK_SHRINK,
- 0, 0);
-
- s->priv->w_four_combobox = combo_box;
- node_box = GTK_COMBO_BOX (combo_box);
- node_list_store = GTK_LIST_STORE (gtk_combo_box_get_model (node_box));
- gtk_list_store_clear (node_list_store);
-
- // Get the identification of the schematic nodes
- node_list = netlist_helper_get_voltmeters_list (
- schematic_view_get_schematic (sv), &perror);
- if (perror != NULL) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create a netlist"), msg);
- g_error_free (perror);
- return;
- }
- if (!node_list)
- oregano_error (_("No node in the schematic!"));
+void sim_settings_set_noise_npoints (SimSettings *sim_settings, gchar *str)
+{
+ g_free (sim_settings->noise_npoints);
+ sim_settings->noise_npoints = g_strdup (str);
+}
- text = NULL;
- while (node_list) {
- if (node_list->data)
- text = g_strdup_printf ("V(%d)", atoi (node_list->data));
- if (text) gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (node_box), text);
- node_list = node_list->next;
- }
- gtk_combo_box_set_active (node_box, 0);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_add"));
- s->priv->w_four_add = w;
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (fourier_add_vout_cb), s);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "fourier_rem"));
- s->priv->w_four_rem = w;
- g_signal_connect (G_OBJECT (w), "clicked",
- G_CALLBACK (fourier_remove_vout_cb), s);
-
- gtk_widget_show_all (toplevel);
-
- ac_enable_cb (s->priv->w_ac_enable,s);
- fourier_enable_cb (s->priv->w_four_enable, s);
- dc_enable_cb (s->priv->w_dc_enable,s);
- trans_enable_cb (s->priv->w_trans_enable, s);
- trans_step_enable_cb (s->priv->w_trans_step_enable, s);
-
- // Cleanup
- g_list_free_full (list, g_object_unref);
+void sim_settings_set_noise_start (SimSettings *sim_settings, gchar *str)
+{
+ g_free (sim_settings->noise_start);
+ sim_settings->noise_start = g_strdup (str);
}
-GList *
-sim_settings_get_options (SimSettings *s)
+void sim_settings_set_noise_stop (SimSettings *sim_settings, gchar *str)
{
- return s->priv->options;
+ g_free (sim_settings->noise_stop);
+ sim_settings->noise_stop = g_strdup (str);
}
-void
-sim_settings_add_option (SimSettings *s, SimOption *opt)
+GList *sim_settings_get_options (const SimSettings *sim_settings)
{
- GList *list=s->priv->options;
+ g_return_val_if_fail (sim_settings != NULL, NULL);
+ return sim_settings->options;
+}
- // Remove the option if already in the list.
- while (list) {
- SimOption *so=list->data;
- if (so && !strcmp (opt->name,so->name)) {
+void sim_settings_add_option (SimSettings *sim_settings, SimOption *opt)
+{
+ GList *iter;
+ // Remove the option if already in the list.
+ for (iter = sim_settings->options; iter; iter = iter->next) {
+ SimOption *so = iter->data;
+ if (so && !strcmp (opt->name, so->name)) {
g_free (so->name);
g_free (so->value);
- s->priv->options = g_list_remove (s->priv->options, so);
- g_free (so);
+ sim_settings->options = g_list_remove (sim_settings->options, so);
+ sim_option_finalize(so);
}
- list = list->next;
}
- s->priv->options = g_list_append (s->priv->options, opt);
- g_list_free_full (list, g_object_unref);
+ sim_settings->options = g_list_append (sim_settings->options, opt);
}
diff --git a/src/sim-settings.h b/src/sim-settings.h
index 5cf0af5..7d9cb53 100644
--- a/src/sim-settings.h
+++ b/src/sim-settings.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,141 +28,193 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SIM_SETTINGS_H
#define __SIM_SETTINGS_H
-#include <gtk/gtk.h>
+typedef struct {
+ gboolean configured;
+ gboolean simulation_requested;
+
+ // Transient analysis.
+ gboolean trans_enable;
+ gboolean trans_init_cond;
+ gboolean trans_analyze_all;
+ gchar *trans_start;
+ gchar *trans_stop;
+ gchar *trans_step;
+ gboolean trans_step_enable;
+
+ // AC
+ gboolean ac_enable;
+ gchar *ac_vout;
+ gchar *ac_type;
+ gchar *ac_npoints;
+ gchar *ac_start;
+ gchar *ac_stop;
+
+ // DC
+ gboolean dc_enable;
+ gchar *dc_vin;
+ gchar *dc_vout;
+ gchar *dc_start, *dc_stop, *dc_step;
+
+ // Fourier analysis. Replace with something sane later.
+ gboolean fourier_enable;
+ gchar *fourier_frequency;
+ gchar *fourier_nb_vout;
+ GSList *fourier_vout;
+
+ // Noise
+ gboolean noise_enable;
+ gchar *noise_vin;
+ gchar *noise_vout;
+ gchar *noise_type;
+ gchar *noise_npoints;
+ gchar *noise_start;
+ gchar *noise_stop;
+
+ // Options
+ GList *options;
+} SimSettings;
+
+typedef struct _SimOption
+{
+ gchar *name;
+ gchar *value;
+} SimOption;
-typedef struct _SimSettings SimSettings;
+SimSettings *sim_settings_new ();
-#include "schematic-view.h"
-#include "schematic.h"
+void sim_settings_finalize(SimSettings *s);
-typedef struct _SimSettingsPriv SimSettingsPriv;
+gdouble sim_settings_get_trans_start (const SimSettings *sim_settings);
-struct _SimSettings {
- Schematic *sm;
- GtkWidget *pbox;
- GtkNotebook *notebook;
- SimSettingsPriv *priv;
-};
+gdouble sim_settings_get_trans_stop (const SimSettings *sim_settings);
-typedef struct _SimOption SimOption;
+gdouble sim_settings_get_trans_step (const SimSettings *sim_settings);
-struct _SimOption {
- gchar *name;
- gchar *value;
-} _SimOption;
+gboolean sim_settings_get_trans (const SimSettings *sim_settings);
+
+gdouble sim_settings_get_trans_step_enable (const SimSettings *sim_settings);
+
+gboolean sim_settings_get_trans_init_cond (const SimSettings *sim_settings);
+
+gboolean sim_settings_get_trans_analyze_all (const SimSettings *sim_settings);
+
+void sim_settings_set_trans_start (SimSettings *sim_settings, gchar *str);
+
+void sim_settings_set_trans_stop (SimSettings *sim_settings, gchar *str);
+
+void sim_settings_set_trans_step (SimSettings *sim_settings, gchar *str);
+
+void sim_settings_set_trans (SimSettings *sim_settings, gboolean enable);
+
+void sim_settings_set_trans_step_enable (SimSettings *sim_settings, gboolean enable);
+
+void sim_settings_set_trans_init_cond (SimSettings *sim_settings, gboolean enable);
+
+void sim_settings_set_trans_analyze_all (SimSettings *sim_settings, gboolean enable);
+
+gboolean sim_settings_get_dc (const SimSettings *);
+
+gchar *sim_settings_get_dc_vsrc (const SimSettings *);
+
+gchar *sim_settings_get_dc_vout (const SimSettings *);
+
+gdouble sim_settings_get_dc_start (const SimSettings *);
+
+gdouble sim_settings_get_dc_start (const SimSettings *);
+
+gdouble sim_settings_get_dc_stop (const SimSettings *);
-void sim_settings_show (GtkWidget *widget,
- SchematicView *sv);
+gdouble sim_settings_get_dc_step (const SimSettings *);
-SimSettings *sim_settings_new (Schematic *sm);
+void sim_settings_set_dc (SimSettings *, gboolean);
-gdouble sim_settings_get_trans_start (SimSettings *sim_settings);
+void sim_settings_set_dc_vsrc (SimSettings *, gchar *);
-gdouble sim_settings_get_trans_stop (SimSettings *sim_settings);
+void sim_settings_set_dc_vout (SimSettings *, gchar *);
-gdouble sim_settings_get_trans_step (SimSettings *sim_settings);
+void sim_settings_set_dc_start (SimSettings *, gchar *);
-gboolean sim_settings_get_trans (SimSettings *sim_settings);
+void sim_settings_set_dc_stop (SimSettings *, gchar *);
-gdouble sim_settings_get_trans_step_enable (SimSettings *sim_settings);
+void sim_settings_set_dc_step (SimSettings *, gchar *);
-gboolean sim_settings_get_trans_init_cond (SimSettings *sim_settings);
+gboolean sim_settings_get_ac (const SimSettings *);
-void sim_settings_set_trans_start (SimSettings *sim_settings,
- gchar *str);
+gchar *sim_settings_get_ac_vout (const SimSettings *);
-void sim_settings_set_trans_stop (SimSettings *sim_settings,
- gchar *str);
+gchar *sim_settings_get_ac_type (const SimSettings *);
-void sim_settings_set_trans_step (SimSettings *sim_settings,
- gchar *str);
+gint sim_settings_get_ac_npoints (const SimSettings *);
-void sim_settings_set_trans (SimSettings *sim_settings,
- gboolean enable);
+gdouble sim_settings_get_ac_start (const SimSettings *);
-void sim_settings_set_trans_step_enable (SimSettings *sim_settings,
- gboolean enable);
+gdouble sim_settings_get_ac_stop (const SimSettings *);
-void sim_settings_set_trans_init_cond (SimSettings *sim_settings,
- gboolean enable);
+void sim_settings_set_ac (SimSettings *, gboolean);
-gboolean sim_settings_get_dc (SimSettings *);
+void sim_settings_set_ac_vout (SimSettings *, gchar *);
-gchar *sim_settings_get_dc_vsrc (SimSettings *);
+void sim_settings_set_ac_type (SimSettings *, gchar *);
-gdouble sim_settings_get_dc_start (SimSettings *);
+void sim_settings_set_ac_npoints (SimSettings *, gchar *);
-gdouble sim_settings_get_dc_stop (SimSettings *);
+void sim_settings_set_ac_start (SimSettings *, gchar *);
-gdouble sim_settings_get_dc_step (SimSettings *);
+void sim_settings_set_ac_stop (SimSettings *, gchar *);
-void sim_settings_set_dc (SimSettings *,
- gboolean);
+void sim_settings_set_fourier (SimSettings *, gboolean);
-void sim_settings_set_dc_vsrc (SimSettings * ,
- gchar *);
+void sim_settings_set_fourier_frequency (SimSettings *, gchar *);
-void sim_settings_set_dc_start (SimSettings *,
- gchar *);
+void sim_settings_set_fourier_vout (SimSettings *, gchar *);
-void sim_settings_set_dc_stop (SimSettings *,
- gchar *);
+gboolean sim_settings_get_fourier (const SimSettings *);
-void sim_settings_set_dc_step (SimSettings *,
- gchar *);
+gdouble sim_settings_get_fourier_frequency (const SimSettings *);
-gboolean sim_settings_get_ac (SimSettings *);
+gchar *sim_settings_get_fourier_vout (const SimSettings *);
-gchar *sim_settings_get_ac_type (SimSettings *);
+gchar *sim_settings_get_fourier_nodes (const SimSettings *);
-gint sim_settings_get_ac_npoints (SimSettings *);
+gboolean sim_settings_get_noise (const SimSettings *);
-gdouble sim_settings_get_ac_start (SimSettings *);
+gchar *sim_settings_get_noise_vsrc (const SimSettings *);
-gdouble sim_settings_get_ac_stop (SimSettings *);
+gchar *sim_settings_get_noise_vout (const SimSettings *);
-void sim_settings_set_ac (SimSettings *,
- gboolean);
+gchar *sim_settings_get_noise_type (const SimSettings *);
-void sim_settings_set_ac_type (SimSettings *,
- gchar *);
+gint sim_settings_get_noise_npoints (const SimSettings *);
-void sim_settings_set_ac_npoints (SimSettings *,
- gchar *);
+gdouble sim_settings_get_noise_start (const SimSettings *);
-void sim_settings_set_ac_start (SimSettings *,
- gchar *);
+gdouble sim_settings_get_noise_stop (const SimSettings *);
-void sim_settings_set_ac_stop (SimSettings *,
- gchar *);
+void sim_settings_set_noise (SimSettings *, gboolean);
-void sim_settings_set_fourier (SimSettings *,
- gboolean);
+void sim_settings_set_noise_vsrc (SimSettings *, gchar *);
-void sim_settings_set_fourier_frequency (SimSettings *,
- gchar *);
+void sim_settings_set_noise_vout (SimSettings *, gchar *);
-void sim_settings_set_fourier_vout (SimSettings *,
- gchar *);
+void sim_settings_set_noise_type (SimSettings *, gchar *);
-gboolean sim_settings_get_fourier (SimSettings *);
+void sim_settings_set_noise_npoints (SimSettings *, gchar *);
-gint sim_settings_get_fourier_frequency (SimSettings *);
+void sim_settings_set_noise_start (SimSettings *, gchar *);
-gchar* sim_settings_get_fourier_vout (SimSettings *);
+void sim_settings_set_noise_stop (SimSettings *, gchar *);
-gchar* sim_settings_get_fourier_nodes (SimSettings *);
+GList *sim_settings_get_options (const SimSettings *sim_settings);
-GList *sim_settings_get_options (SimSettings *sim_settings);
+void sim_settings_add_option (SimSettings *, SimOption *);
-void sim_settings_add_option (SimSettings *,
- SimOption *);
+gchar *fourier_add_vout(SimSettings *sim_settings, guint i);
#endif
diff --git a/src/simulation.c b/src/simulation.c
index dc4872b..20175de 100644
--- a/src/simulation.c
+++ b/src/simulation.c
@@ -3,16 +3,18 @@
*
*
* Authors:
- * Richard Hult <rhult@hem.passagen.se>
- * Ricardo Markiewicz <rmarkie@fi.uba.ar>
- * Andres de Barbara <adebarbara@fi.uba.ar>
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
- * Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013-2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include <gtk/gtk.h>
@@ -43,15 +45,27 @@
#include "oregano-config.h"
#include "plot.h"
#include "gnucap.h"
+#include "log.h"
-typedef struct {
- Schematic *sm;
- SchematicView *sv;
- GtkDialog *dialog;
- OreganoEngine *engine;
- GtkProgressBar *progress;
- GtkLabel *progress_label;
- int progress_timeout_id;
+//NULL terminated
+const char *SimulationFunctionTypeString[] = {
+ "Subtraction",
+ "Division",
+ NULL
+};
+
+typedef struct
+{
+ Schematic *sm;
+ SchematicView *sv;
+ GtkDialog *dialog;
+ OreganoEngine *engine;
+ GtkProgressBar *progress_solver;
+ GtkLabel *progress_label_solver;
+ GtkProgressBar *progress_reader;
+ GtkLabel *progress_label_reader;
+ int progress_timeout_id;
+ Log *logstore;
} Simulation;
static int progress_bar_timeout_cb (Simulation *s);
@@ -60,120 +74,131 @@ static void engine_done_cb (OreganoEngine *engine, Simulation *s);
static void engine_aborted_cb (OreganoEngine *engine, Simulation *s);
static gboolean simulate_cmd (Simulation *s);
-static int
-delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
-{
- return FALSE;
-}
+static int delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; }
-gpointer
-simulation_new (Schematic *sm)
+gpointer simulation_new (Schematic *sm, Log *logstore)
{
Simulation *s;
s = g_new0 (Simulation, 1);
s->sm = sm;
s->sv = NULL;
+ s->logstore = logstore;
return s;
}
-void
-simulation_show (GtkWidget *widget, SchematicView *sv)
+void simulation_show_progress_bar (GtkWidget *widget, SchematicView *sv)
{
GtkWidget *w;
GtkBuilder *gui;
- GError *perror = NULL;
+ GError *e = NULL;
Simulation *s;
Schematic *sm;
g_return_if_fail (sv != NULL);
- if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create simulation dialog"));
+ if (oregano.engine < 0 || oregano.engine >= OREGANO_ENGINE_COUNT)
return;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
+
sm = schematic_view_get_schematic (sv);
s = schematic_get_simulation (sm);
- // Only allow one instance of the dialog box per schematic.
- if (s->dialog) {
- gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (s->dialog)));
+ if ((gui = gtk_builder_new ()) == NULL) {
+ log_append (s->logstore, _ ("Simulation"),
+ _ ("Could not create simulation dialog - Builder creation failed."));
return;
}
+ gtk_builder_set_translation_domain (gui, NULL);
- if (!g_file_test (OREGANO_UIDIR "/simulation.ui",
- G_FILE_TEST_EXISTS)) {
- oregano_error (_("Could not create simulation dialog"));
+ // Only allow one instance of the dialog box per schematic.
+ if (s->dialog) {
+ gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (s->dialog)));
return;
}
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/simulation.ui",
- &perror) <= 0) {
- gchar *msg;
- msg = perror->message;
- oregano_error_with_title (_("Could not create simulation dialog"), msg);
- g_error_free (perror);
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/simulation.ui", &e) <= 0) {
+ log_append_error (s->logstore, _ ("Simulation"), _ ("Could not create simulation dialog"),
+ e);
+ g_clear_error (&e);
return;
}
w = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
if (!w) {
- oregano_error (_("Could not create simulation dialog"));
+ log_append (s->logstore, _ ("Simulation"),
+ _ ("Could not create simulation dialog - .ui file lacks widget "
+ "called \"toplevel\"."));
return;
}
s->dialog = GTK_DIALOG (w);
- g_signal_connect (G_OBJECT (w), "delete_event",
- G_CALLBACK (delete_event_cb), s);
+ g_signal_connect (G_OBJECT (w), "delete_event", G_CALLBACK (delete_event_cb), s);
+
+ /**
+ * progress bars and progress labels
+ */
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "progressbar_solver"));
+ s->progress_solver = GTK_PROGRESS_BAR (w);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_solver), 0.0);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "progressbar"));
- s->progress = GTK_PROGRESS_BAR (w);
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress), 0.0);
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "progress_label_solver"));
+ s->progress_label_solver = GTK_LABEL (w);
- w = GTK_WIDGET (gtk_builder_get_object (gui, "progress_label"));
- s->progress_label = GTK_LABEL (w);
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "progressbar_reader"));
+ s->progress_reader = GTK_PROGRESS_BAR (w);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_reader), 0.0);
- g_signal_connect (G_OBJECT (s->dialog), "response",
- G_CALLBACK (cancel_cb), s);
+ w = GTK_WIDGET (gtk_builder_get_object (gui, "progress_label_reader"));
+ s->progress_label_reader = GTK_LABEL (w);
+
+ g_signal_connect (G_OBJECT (s->dialog), "response", G_CALLBACK (cancel_cb), s);
gtk_widget_show_all (GTK_WIDGET (s->dialog));
s->sv = sv;
+
simulate_cmd (s);
}
-static int
-progress_bar_timeout_cb (Simulation *s)
+static int progress_bar_timeout_cb (Simulation *s)
{
- gchar *str;
- double p;
g_return_val_if_fail (s != NULL, FALSE);
- oregano_engine_get_progress (s->engine, &p);
+ double p = 0;
+ oregano_engine_get_progress_solver (s->engine, &p);
- if (p >= 1) p = 0;
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_solver), p);
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress), p);
+ gchar *current_operation = oregano_engine_get_current_operation_solver(s->engine);
+ gchar *str = g_strdup_printf (_ ("Progress: <b>%s</b>"), current_operation);
+ g_free(current_operation);
- str = g_strdup_printf (_("Progress: <b>%s</b>"),
- oregano_engine_get_current_operation (s->engine));
- gtk_label_set_markup (s->progress_label, str);
+ gtk_label_set_markup (s->progress_label_solver, str);
+ g_free (str);
+
+ p = 0;
+ oregano_engine_get_progress_reader (s->engine, &p);
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_reader), p);
+
+ str = g_strdup_printf (_ ("Progress: <b>%s</b>"),
+ oregano_engine_get_current_operation_reader (s->engine));
+ gtk_label_set_markup (s->progress_label_reader, str);
g_free (str);
return TRUE;
}
-static void
-engine_done_cb (OreganoEngine *engine, Simulation *s)
+static void engine_done_cb (OreganoEngine *engine, Simulation *s)
{
if (s->progress_timeout_id != 0) {
g_source_remove (s->progress_timeout_id);
s->progress_timeout_id = 0;
// Make sure that the progress bar is completed, just for good looks.
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress), 1.0);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_solver), 1.0);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (s->progress_reader), 1.0);
}
gtk_widget_destroy (GTK_WIDGET (s->dialog));
@@ -181,57 +206,46 @@ engine_done_cb (OreganoEngine *engine, Simulation *s)
plot_show (s->engine);
- if (oregano_engine_has_warnings (s->engine))
- schematic_view_log_show (s->sv, FALSE);
+ if (oregano_engine_has_warnings (s->engine)) {
+ log_append (s->logstore, _ ("Simulation"),
+ _ ("Finished with warnings:")); // FIXME add actual warnings
+ } else {
+ log_append (s->logstore, _ ("Simulation"), _ ("Finished."));
+ }
+
+ // show log window if this is enabled in preferences
+ schematic_view_log_show (s->sv, FALSE);
sheet_clear_op_values (schematic_view_get_sheet (s->sv));
- // I don't need the engine anymore. The plot window owns its reference to
+ // I don't need the engine anymore. The plot window owns its reference to
// the engine
g_object_unref (s->engine);
s->engine = NULL;
-
}
-static void
-engine_aborted_cb (OreganoEngine *engine, Simulation *s)
+static void engine_aborted_cb (OreganoEngine *engine, Simulation *s)
{
- GtkWidget *dialog;
- int answer;
-
if (s->progress_timeout_id != 0) {
g_source_remove (s->progress_timeout_id);
s->progress_timeout_id = 0;
}
- gtk_widget_destroy (GTK_WIDGET (s->dialog));
- s->dialog = NULL;
-
- if (!schematic_view_get_log_window_exists (s->sv)) {
- dialog = gtk_message_dialog_new_with_markup (
- GTK_WINDOW (schematic_view_get_toplevel (s->sv)),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_YES_NO,
- _("<span weight=\"bold\" size=\"large\">The simulation was aborted"
- " due to an error.</span>\n\nWould you like to view the error log?"));
-
- answer = gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-
- if (answer == GTK_RESPONSE_YES) {
- schematic_view_log_show (s->sv, TRUE);
- }
- }
- else {
- oregano_error (_("The simulation was aborted due to an error"));
-
- schematic_view_log_show (s->sv, FALSE);
+ // g_clear_object (&(s->dialog));
+ if (s->dialog != NULL) {
+ gtk_widget_destroy (GTK_WIDGET (s->dialog));
+ s->dialog = NULL;
}
+
+ log_append (s->logstore, _ ("Simulation"), _ ("Aborted. See lines below for details."));
+ if (s->sv != NULL)
+ schematic_view_log_show (s->sv, TRUE);
+
+ g_object_unref (s->engine);
+ s->engine = NULL;
}
-static void
-cancel_cb (GtkWidget *widget, gint arg1, Simulation *s)
+static void cancel_cb (GtkWidget *widget, gint arg1, Simulation *s)
{
g_return_if_fail (s != NULL);
@@ -246,31 +260,30 @@ cancel_cb (GtkWidget *widget, gint arg1, Simulation *s)
gtk_widget_destroy (GTK_WIDGET (s->dialog));
s->dialog = NULL;
s->sv = NULL;
+
+ log_append (s->logstore, _ ("Simulation"), _ ("Canceled."));
}
-static gboolean
-simulate_cmd (Simulation *s)
+static gboolean simulate_cmd (Simulation *s)
{
OreganoEngine *engine;
if (s->engine != NULL) {
- g_object_unref (G_OBJECT (s->engine));
- s->engine = NULL;
+ g_clear_object (&(s->engine));
}
engine = oregano_engine_factory_create_engine (oregano.engine, s->sm);
+ if (!engine)
+ return FALSE;
+
s->engine = engine;
- s->progress_timeout_id = g_timeout_add (100,
- (GSourceFunc)progress_bar_timeout_cb, s);
+ s->progress_timeout_id = g_timeout_add (250, (GSourceFunc)progress_bar_timeout_cb, s);
- g_signal_connect (G_OBJECT (engine), "done",
- G_CALLBACK (engine_done_cb), s);
- g_signal_connect (G_OBJECT (engine), "aborted",
- G_CALLBACK (engine_aborted_cb), s);
+ g_signal_connect (G_OBJECT (engine), "done", G_CALLBACK (engine_done_cb), s);
+ g_signal_connect (G_OBJECT (engine), "aborted", G_CALLBACK (engine_aborted_cb), s);
oregano_engine_start (engine);
return TRUE;
}
-
diff --git a/src/simulation.h b/src/simulation.h
index f8ce7cf..4dca06c 100644
--- a/src/simulation.h
+++ b/src/simulation.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Guido Trentalancia <guido@trentalancia.com>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2017 Guido Trentalancia
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __SIMULATION_H
@@ -41,94 +43,112 @@
typedef struct _SimulationData SimulationData;
typedef enum {
- OP_POINT ,
- TRANSIENT ,
- DC_TRANSFER ,
- AC ,
- TRANSFER ,
- DISTORTION ,
- NOISE ,
- POLE_ZERO ,
- SENSITIVITY ,
- FOURIER ,
- ANALYSIS_UNKNOWN
+ ANALYSIS_TYPE_NONE,
+ ANALYSIS_TYPE_OP_POINT,
+ ANALYSIS_TYPE_TRANSIENT,
+ ANALYSIS_TYPE_DC_TRANSFER,
+ ANALYSIS_TYPE_AC,
+ ANALYSIS_TYPE_TRANSFER,
+ ANALYSIS_TYPE_DISTORTION,
+ ANALYSIS_TYPE_NOISE,
+ ANALYSIS_TYPE_POLE_ZERO,
+ ANALYSIS_TYPE_SENSITIVITY,
+ ANALYSIS_TYPE_FOURIER,
+ ANALYSIS_TYPE_UNKNOWN
} AnalysisType;
#define INFINITE 1e50f
+//keep in mind the relation to global variable
+//const char const *SimulationFunctionTypeString[]
+//in simulation.c (strings representing the functions in GUI)
typedef enum {
- FUNCTION_MINUS = 0,
- FUNCTION_TRANSFER
+ FUNCTION_SUBTRACT = 0,
+ FUNCTION_DIVIDE
} SimulationFunctionType;
-typedef struct _SimulationFunction {
+typedef struct _SimulationFunction
+{
SimulationFunctionType type;
guint first;
guint second;
} SimulationFunction;
-struct _SimulationData {
+struct _SimulationData
+{
AnalysisType type;
- gint state;
- gint n_variables;
- gchar **var_names;
- gchar **var_units;
- GArray **data;
- gdouble *min_data;
- gdouble *max_data;
- gint got_var;
- gint got_points;
+ gint n_variables;
+ gchar **var_names;
+ gchar **var_units;
+ GArray **data;
+ gdouble *min_data;
+ gdouble *max_data;
+ gint got_var;
+ gint got_points;
// Functions typeof SimulationFunction
- GList *functions;
+ GList *functions;
};
-
-typedef struct {
+typedef struct
+{
SimulationData sim_data;
- int state;
+ int state;
} SimOp;
-typedef struct {
+typedef struct
+{
SimulationData sim_data;
- double freq;
- gint nb_var;
+ double freq;
+ gint nb_var;
} SimFourier;
-typedef struct {
+typedef struct
+{
SimulationData sim_data;
- int state;
- double sim_length;
- double step_size;
+ int state;
+ double sim_length;
+ double step_size;
} SimTransient;
-typedef struct {
+typedef struct
+{
SimulationData sim_data;
- int state;
- double sim_length;
- double start,stop;
+ int state;
+ double sim_length;
+ double start, stop;
} SimAC;
-typedef struct {
+typedef struct
+{
SimulationData sim_data;
- int state;
- double sim_length;
- double start,stop,step;
+ int state;
+ double sim_length;
+ double start, stop, step;
} SimDC;
-typedef union {
- SimOp op;
+typedef struct
+{
+ SimulationData sim_data;
+ int state;
+ double sim_length;
+ double start, stop;
+} SimNoise;
+
+typedef union
+{
+ SimOp op;
SimTransient transient;
- SimFourier fourier;
- SimAC ac;
- SimDC dc;
+ SimFourier fourier;
+ SimAC ac;
+ SimDC dc;
+ SimNoise noise;
} Analysis;
-void simulation_show (GtkWidget *widget, SchematicView *sv);
-gpointer simulation_new (Schematic *sm);
-gchar *sim_engine_analysis_name (SimulationData *);
+void simulation_show_progress_bar (GtkWidget *widget, SchematicView *sv);
+gpointer simulation_new (Schematic *sm, Log *logstore);
-#define SIM_DATA(obj) ((SimulationData *)(obj))
-#define ANALYSIS(obj) ((Analysis *)(obj))
+#define SIM_DATA(obj) ((SimulationData *)(obj))
+#define ANALYSIS(obj) ((Analysis *)(obj))
#endif /* __SIMULATION_H */
diff --git a/src/splash.c b/src/splash.c
index 8e211d1..367ea4e 100644
--- a/src/splash.c
+++ b/src/splash.c
@@ -2,15 +2,17 @@
* splash.c
*
*
- * Author:
+ * Authors:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2006 Ricardo Markiewicz
+ * Web page: https://ahoi.io/project/oregano
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2013 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -24,19 +26,18 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-
#include <unistd.h>
#include <glib/gi18n.h>
#include "splash.h"
#include "dialogs.h"
+#include "errors.h"
-static void
-oregano_splash_destroy (GtkWidget *w, GdkEvent *event, Splash *sp)
+static void oregano_splash_destroy (GtkWidget *w, GdkEvent *event, Splash *sp)
{
if ((event->type == GDK_BUTTON_PRESS) && (event->button.button == 1)) {
if (sp->can_destroy)
@@ -44,36 +45,20 @@ oregano_splash_destroy (GtkWidget *w, GdkEvent *event, Splash *sp)
}
}
-Splash *
-oregano_splash_new ()
+Splash *oregano_splash_new (GError **error)
{
GtkBuilder *gui;
- GError *perror = NULL;
Splash *sp;
GtkEventBox *event;
- gchar *msg;
-
+
if ((gui = gtk_builder_new ()) == NULL) {
- oregano_error (_("Could not create splash message."));
- return NULL;
- }
- else gtk_builder_set_translation_domain (gui, NULL);
-
- if (!g_file_test (OREGANO_UIDIR "/splash.ui", G_FILE_TEST_EXISTS) ||
- !g_file_test (OREGANO_UIDIR "/splash.xpm", G_FILE_TEST_EXISTS)) {
- msg = g_strdup_printf (
- _("The files %s or %s could not be found. You might need to reinstall Oregano to fix this."),
- OREGANO_UIDIR "/splash.ui", OREGANO_UIDIR "/splash.xpm");
- oregano_error_with_title (_("Could not create splash message."), msg);
- g_free (msg);
+ g_set_error_literal (error, OREGANO_ERROR, OREGANO_UI_ERROR_NO_BUILDER,
+ _ ("Failed to spawn builder"));
return NULL;
}
-
- if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/splash.ui",
- &perror) <= 0) {
- msg = perror->message;
- oregano_error_with_title (_("Could not create splash message."), msg);
- g_error_free (perror);
+ gtk_builder_set_translation_domain (gui, NULL);
+
+ if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/splash.ui", error) <= 0) {
return NULL;
}
@@ -81,6 +66,7 @@ oregano_splash_new ()
sp->can_destroy = FALSE;
sp->win = GTK_WINDOW (gtk_builder_get_object (gui, "splash"));
+ gtk_window_set_keep_above (sp->win, TRUE);
sp->lbl = GTK_LABEL (gtk_builder_get_object (gui, "label"));
sp->progress = GTK_WIDGET (gtk_builder_get_object (gui, "pbar"));
@@ -95,8 +81,7 @@ oregano_splash_new ()
return sp;
}
-gboolean
-oregano_splash_free (Splash *sp)
+gboolean oregano_splash_free (Splash *sp)
{
/* Need to disconnect the EventBox Widget! */
g_signal_handlers_disconnect_by_func (sp->event, oregano_splash_destroy, sp);
@@ -105,8 +90,7 @@ oregano_splash_free (Splash *sp)
return FALSE;
}
-void
-oregano_splash_step (Splash *sp, char *s)
+void oregano_splash_step (Splash *sp, char *s)
{
gtk_label_set_text (sp->lbl, s);
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (sp->progress));
@@ -114,12 +98,9 @@ oregano_splash_step (Splash *sp, char *s)
gtk_main_iteration ();
}
-
-void
-oregano_splash_done (Splash *sp, char *s)
+void oregano_splash_done (Splash *sp, char *s)
{
gtk_label_set_text (sp->lbl, s);
sp->can_destroy = TRUE;
g_timeout_add (2000, (GSourceFunc)(oregano_splash_free), sp);
}
-
diff --git a/src/splash.h b/src/splash.h
index 2075779..90ae445 100644
--- a/src/splash.h
+++ b/src/splash.h
@@ -5,8 +5,8 @@
* Author:
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
- *
- * Web page: https://github.com/marc-lorber/oregano
+ *
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -24,8 +24,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef _OREGANO_SPLASH_H_
@@ -35,15 +35,16 @@
typedef struct _Splash Splash;
-struct _Splash {
+struct _Splash
+{
GtkWindow *win;
GtkWidget *progress;
GtkWidget *event;
- GtkLabel *lbl;
+ GtkLabel *lbl;
gboolean can_destroy;
};
-Splash *oregano_splash_new ();
+Splash *oregano_splash_new (GError **error);
gboolean oregano_splash_free (Splash *);
void oregano_splash_step (Splash *, char *s);
void oregano_splash_done (Splash *, char *s);
diff --git a/src/stock.c b/src/stock.c
index 0564aa1..b86c478 100644
--- a/src/stock.c
+++ b/src/stock.c
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
/*
* Stock icon code, stolen from:
@@ -57,15 +57,14 @@
#include "stock/zoom_pan.xpm"
#include "stock/zoom_region.xpm"
-static void
-add_stock_entry (const gchar *stock_id, char **xpm_data)
+static void add_stock_entry (const gchar *stock_id, char **xpm_data)
{
static GtkIconFactory *factory = NULL;
GdkPixbuf *pixbuf;
GtkIconSet *icon_set;
if (!factory) {
- factory =gtk_icon_factory_new ();
+ factory = gtk_icon_factory_new ();
gtk_icon_factory_add_default (factory);
}
@@ -76,8 +75,7 @@ add_stock_entry (const gchar *stock_id, char **xpm_data)
g_object_unref (G_OBJECT (pixbuf));
}
-void
-stock_init (void)
+void stock_init (void)
{
add_stock_entry (STOCK_PIXMAP_SIM_SETTINGS, sim_settings_xpm);
add_stock_entry (STOCK_PIXMAP_ROTATE, rotate_xpm);
diff --git a/src/stock.h b/src/stock.h
index ff5e396..8fb4b80 100644
--- a/src/stock.h
+++ b/src/stock.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __STOCK_H
diff --git a/src/stock/Makefile.am b/src/stock/Makefile.am
deleted file mode 100644
index e4a0270..0000000
--- a/src/stock/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-EXTRA_DIST = \
- README \
- arrow.xpm \
- grid.xcf \
- grid.xpm \
- part-browser.xcf \
- part-browser.xpm \
- plot.xcf \
- plot.xpm \
- plot2.xcf \
- rotate.xpm \
- sim-settings.xpm \
- text.xpm \
- voltmeter.xpm \
- wire.xpm \
- zoom_in.xpm \
- zoom_out.xpm
-
diff --git a/src/tools/cancel-info.c b/src/tools/cancel-info.c
new file mode 100644
index 0000000..5abeec6
--- /dev/null
+++ b/src/tools/cancel-info.c
@@ -0,0 +1,79 @@
+/*
+ * cancel-info.c
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include "cancel-info.h"
+
+struct _CancelInfo {
+ guint ref_count;
+ GMutex mutex;
+ gboolean is_cancel;
+};
+
+static void cancel_info_finalize(CancelInfo *info);
+
+CancelInfo *cancel_info_new() {
+ CancelInfo *info = g_new0(CancelInfo, 1);
+ info->ref_count = 1;
+ g_mutex_init(&info->mutex);
+
+ return info;
+}
+
+void cancel_info_subscribe(CancelInfo *info) {
+ g_mutex_lock(&info->mutex);
+ info->ref_count++;
+ g_mutex_unlock(&info->mutex);
+}
+
+void cancel_info_unsubscribe(CancelInfo *info) {
+ g_mutex_lock(&info->mutex);
+ info->ref_count--;
+ guint ref_count = info->ref_count;
+ g_mutex_unlock(&info->mutex);
+
+ if (ref_count == 0)
+ cancel_info_finalize(info);
+}
+
+gboolean cancel_info_is_cancel(CancelInfo *info) {
+ g_mutex_lock(&info->mutex);
+ gboolean is_cancel = info->is_cancel;
+ g_mutex_unlock(&info->mutex);
+
+ return is_cancel;
+}
+
+void cancel_info_set_cancel(CancelInfo *info) {
+ g_mutex_lock(&info->mutex);
+ info->is_cancel = TRUE;
+ g_mutex_unlock(&info->mutex);
+}
+
+static void cancel_info_finalize(CancelInfo *info) {
+ g_mutex_clear(&info->mutex);
+ g_free(info);
+}
diff --git a/src/model/sheet-pos.h b/src/tools/cancel-info.h
index bfda9e0..6b99a22 100644
--- a/src/model/sheet-pos.h
+++ b/src/tools/cancel-info.h
@@ -1,18 +1,12 @@
/*
- * sheet-pos.h
+ * cancel-info.h
*
*
* Authors:
- * Richard Hult <rhult@hem.passagen.se>
- * Ricardo Markiewicz <rmarkie@fi.uba.ar>
- * Andres de Barbara <adebarbara@fi.uba.ar>
- * Marc Lorber <lorber.marc@wanadoo.fr>
+ * Michi <st101564@stud.uni-stuttgart.de>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
- * Copyright (C) 1999-2001 Richard Hult
- * Copyright (C) 2003,2004 Ricardo Markiewicz
- * Copyright (C) 2009-2012 Marc Lorber
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,17 +20,19 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
-#ifndef __SHEET_POS_H
-#define __SHEET_POS_H
-#include <gtk/gtk.h>
-typedef struct _SheetPos SheetPos;
-struct _SheetPos {
- gdouble x;
- gdouble y;
-};
+#ifndef TOOLS_CANCEL_INFO_H_
+#define TOOLS_CANCEL_INFO_H_
-#endif
+typedef struct _CancelInfo CancelInfo;
+
+CancelInfo *cancel_info_new();
+void cancel_info_subscribe(CancelInfo *info);
+void cancel_info_unsubscribe(CancelInfo *info);
+gboolean cancel_info_is_cancel(CancelInfo *info);
+void cancel_info_set_cancel(CancelInfo *info);
+
+#endif /* TOOLS_CANCEL_INFO_H_ */
diff --git a/src/tools/thread-pipe.c b/src/tools/thread-pipe.c
new file mode 100644
index 0000000..8f714ef
--- /dev/null
+++ b/src/tools/thread-pipe.c
@@ -0,0 +1,600 @@
+/**
+ * thread-pipe.c
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ *
+ * BASICS
+ * ------
+ * ThreadPipe can be used to efficiently communicate large
+ * or small data between 2 threads, whereas the data pops up
+ * bit by bit (or at once).
+ * It consists of a chain of data blocks. New
+ * data is appended at the one end of the chain, old data
+ * can be read at the other end of the pipe.
+ *
+ * If there is data (chain has more than 1 chain link), the
+ * reader gets to know this by locking a mutex and asking
+ * the state of a shared variable.
+ *
+ * If all data is read and the reader needs more data, he
+ * will wait until new data is available by locking a mutex
+ * and waiting for a conditional signal of the writer.
+ *
+ *
+ * Locking, unlocking and signaling can slow down the
+ * communication process very hard, if the data blocks are
+ * small. To solve this problem, an additional buffer is
+ * introduced.
+ *
+ * BUFFERED VERSION
+ * ----------------
+ * The problem of unbuffered ThreadPipe is that locking
+ * and unlocking is a very heavy work that should not
+ * be done too frequently. Now if the data blocks pushed
+ * to ThreadPipe are too small, the lock operation is
+ * done very often. However the positive side of small blocks
+ * is the real time ability.
+ *
+ * If you need only weak real time or no real time but an
+ * efficient use of time and money, you should use the
+ * buffered version of thread pipe with large (but not too
+ * large) buffer numbers (you can use a buffer by setting
+ * the buffer numbers in the constructor unequal 1).
+ *
+ * There are some approaches how to realize a buffer in the
+ * case of thread pipe:
+ * - melting incoming blocks together with realloc,
+ * counting the number of bytes or melting operations,
+ * release the block for popping when number is large enough,
+ * - appending incoming blocks together,
+ * counting the number of bytes or/and number of blocks not released,
+ * release the block queue if number is large enough,
+ * - counting time instead of space,
+ * - other shit
+ *
+ * Because blocks are structure elements that can be used to
+ * make the code more efficient AND melting operations
+ * can be heavy work, I think that simply appending some
+ * blocks and not locking/releasing every single block is
+ * a good way to go. Counting time instead of space may be
+ * a good approach for real time applications that want to
+ * be also efficient. But because real time is not demanded
+ * in a non real time simulation like ngspice or gnucap, we don't
+ * need to bother. But you can set the buffer numbers to 1
+ * and then you can use thread pipe in real time applications,
+ * that have far too much nop-time and really small amounts of
+ * data workload.
+ *
+ * Furthermore I have decided to count the number of blocks
+ * and the total size of not released blocks. When one of
+ * the counting numbers are larger than their corresponding
+ * buffer constants, the whole pipe queue is released for
+ * popping (what needs a small locking access).
+ *
+ * You have some possibilities to define the buffer constants:
+ * - define statements in thread-pipe.h
+ * - telling the constructor function what are your wishes
+ *
+ * THE FUTURE
+ * ----------
+ * An enhanced version of this could be an adaptive buffer size
+ * decision maker that detects the frequency of collisions
+ * and uses this information to adapt the optimal buffer size
+ * as a function of time, by extrapolating the behavior of
+ * the program like branch prediction technology that is used in
+ * processors. A good version of this could be real time capable
+ * in low workload times and would be optimal for time, space
+ * and money saving in times of high workload.
+ *
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "thread-pipe.h"
+
+typedef struct _ThreadPipeData ThreadPipeData;
+
+/**
+ * chain link/chain element
+ */
+struct _ThreadPipeData {
+ // introduced for efficient string support
+ gpointer malloc_address;
+ // data block
+ gpointer data;
+ // size of data block
+ gsize size;
+ // link to next chain element
+ ThreadPipeData *next;
+};
+
+/**
+ * structuring structure
+ */
+typedef struct {
+ // closing/freeing information
+ gboolean write_eof;
+ gboolean read_eof;
+
+ // buffer state information
+ gsize size_total;
+ gsize block_counter;
+} ThreadPipeBufferData;
+
+struct _ThreadPipe {
+ /**
+ * variables of reading thread
+ */
+ ThreadPipeData *read_data;
+ ThreadPipeBufferData read_buffer_data;
+
+ /**
+ * variables of writing thread
+ */
+ ThreadPipeData *write_data;
+ ThreadPipeBufferData write_buffer_data;
+
+ /**
+ * shared variables
+ */
+ ThreadPipeBufferData ready_buffer_data;
+
+ /**
+ * synchronizing variables
+ */
+ GMutex mutex;
+ GCond cond;
+
+ /**
+ * read-only variables
+ */
+ guint max_block_counter;
+ gsize max_size_total;
+};
+
+static ThreadPipeData *thread_pipe_data_new(gpointer data, gsize size);
+static ThreadPipeData *thread_pipe_data_destroy(ThreadPipe *pipe);
+static void thread_pipe_destroy(ThreadPipe *pipe);
+
+/**
+ * Creates a new ThreadPipe structure.
+ *
+ * I recommend using ThreadPipes like normal FIFO pipes, whereas one thread
+ * uses only read functions and another thread uses only write functions.
+ * The reading thread should make sure that read_eof will be set,
+ * the writing thread should make sure that write_eof will be set,
+ * because:
+ *
+ * ThreadPipes have 3 possibilities to close:
+ * 1. call thread_pipe_set_write_eof and after that read the pipe to the end
+ * 2. call thread_pipe_set_write_eof and after that call thread_pipe_set_read_eof
+ * 3. call thread_pipe_set_read_eof and after that call thread_pipe_set_write_eof
+ *
+ * Now if the creating thread of the ThreadPipe wants to close the ThreadPipe,
+ * and he did not touch any reading or writing functions, he does not know
+ * whether the pipe has been closed already automatically and will cause a
+ * segmentation fault eventually if he tries.
+ *
+ * @max_buffer_block_counter: 1 is the lowest number (you can't push no data).
+ * If 0, the default value from thread-pipe.h will be used.
+ * @max_buffer_block_counter: 1 is the lowest value (ThreadPipe does not allow
+ * to push blocks of size 0). If 0, the default value from thread-pipe.h
+ * will be used.
+ *
+ * returns a new ThreadPipe structure
+ */
+ThreadPipe *thread_pipe_new(
+ guint max_buffer_block_counter,
+ gsize max_buffer_size_total) {
+ ThreadPipe *thread_pipe = g_new0(ThreadPipe, 1);
+
+ g_mutex_init(&thread_pipe->mutex);
+ g_cond_init(&thread_pipe->cond);
+
+ ThreadPipeData *pipe_data = thread_pipe_data_new(NULL, 0);
+ thread_pipe->read_data = pipe_data;
+ thread_pipe->write_data = pipe_data;
+
+ thread_pipe->max_block_counter = max_buffer_block_counter != 0 ? max_buffer_block_counter : THREAD_PIPE_MAX_BUFFER_BLOCK_COUNTER_DEFAULT;
+ thread_pipe->max_size_total = max_buffer_size_total != 0 ? max_buffer_size_total : THREAD_PIPE_MAX_BUFFER_SIZE_TOTAL_DEFAULT;
+
+ return thread_pipe;
+}
+
+/**
+ * Pushes a block of size size to the end of the pipe. The data is copied
+ * to heap.
+ *
+ * Don't push, if you set write_eof already.
+ *
+ * return value will be NULL, if
+ * - read_eof has been set by thread_pipe_set_read_eof or
+ * - write_eof has been set by thread_pipe_set_write_eof (with fail message) or
+ * - pipe is NULL (with fail message).
+ *
+ * If read_eof has been set by thread_pipe_set_read_eof before, you can close
+ * the pipe by setting write_eof and you will save much time and money,
+ * so be sure to check return value every call. But you can also call this
+ * function if it makes no sense. The function recognizes then that
+ * pushing makes no sense and returns fast. The function is not closing the
+ * pipe automatically in this case because it is safer for example if the
+ * programmer does not check the return value.
+ *
+ * returns TRUE or FALSE
+ * - FALSE, if the pipe has been closed by read_eof or other events that
+ * indicate that you can close the pipe by setting write_eof
+ * - TRUE, if the pipe is living further on and it makes sense that it
+ * will live further on
+ */
+gboolean thread_pipe_push(ThreadPipe *pipe, gpointer data, gsize size) {
+ // Give me an object.
+ g_return_val_if_fail(pipe != NULL, FALSE);
+
+ // Don't push, if you set write_eof already.
+ g_return_val_if_fail(pipe->write_buffer_data.write_eof != TRUE, FALSE);
+
+ // Don't push no data to pipe.
+ g_return_val_if_fail(data != NULL, !pipe->write_buffer_data.read_eof);
+ g_return_val_if_fail(size != 0, !pipe->write_buffer_data.read_eof);
+
+ // pipe not active any more because no reader has interest.
+ if (pipe->write_buffer_data.read_eof)
+ return FALSE;
+
+
+ pipe->write_data->next = thread_pipe_data_new(data, size);
+ pipe->write_data = pipe->write_data->next;
+
+ pipe->write_buffer_data.block_counter++;
+ pipe->write_buffer_data.size_total += size;
+
+ if (pipe->write_buffer_data.block_counter < pipe->max_block_counter
+ && pipe->write_buffer_data.size_total < pipe->max_size_total)
+ return TRUE;
+
+
+ g_mutex_lock(&pipe->mutex);
+
+ pipe->ready_buffer_data.block_counter += pipe->write_buffer_data.block_counter;
+ pipe->write_buffer_data.block_counter = 0;
+
+ pipe->ready_buffer_data.size_total += pipe->write_buffer_data.size_total;
+ pipe->write_buffer_data.size_total = 0;
+
+ pipe->write_buffer_data.read_eof = pipe->ready_buffer_data.read_eof;
+
+ g_cond_signal(&pipe->cond);
+ g_mutex_unlock(&pipe->mutex);
+
+ return !pipe->write_buffer_data.read_eof;
+}
+
+/**
+ * Reads a block of memory that has been pushed earlier by thread_pipe_push.
+ * If there is no block that has been pushed earlier, this function will
+ * wait until a block will be pushed or write_eof will be set.
+ *
+ * pipe will be destroyed automatically if write_eof has been set && pipe is
+ * empty, so be sure to check return value always!
+ *
+ * The data, stored to data_out, will be freed in the next thread_pipe_pop call,
+ * so be sure to copy the data, if you need it longer than one thread_pipe_pop
+ * cycle.
+ *
+ * Don't pop, if you set read_eof already.
+ *
+ * returns pipe or NULL
+ * - NULL, if the pipe has been destroyed
+ * - pipe, if the pipe is living further on
+ */
+ThreadPipe *thread_pipe_pop(ThreadPipe *pipe, gpointer *data_out, gsize *size) {
+ g_return_val_if_fail(pipe != NULL, pipe);
+ g_return_val_if_fail(data_out != NULL, pipe);
+ g_return_val_if_fail(size != NULL, pipe);
+ //Don't pop, if you set read_eof already.
+ g_return_val_if_fail(pipe->read_buffer_data.read_eof != TRUE, NULL);
+
+ *data_out = NULL;
+ *size = 0;
+
+ if (pipe->read_buffer_data.block_counter <= 0) {
+
+ g_mutex_lock(&pipe->mutex);
+
+ while (pipe->ready_buffer_data.block_counter <= 0 && !pipe->ready_buffer_data.write_eof)
+ g_cond_wait(&pipe->cond, &pipe->mutex);
+
+ pipe->read_buffer_data.block_counter = pipe->ready_buffer_data.block_counter;
+ pipe->ready_buffer_data.block_counter = 0;
+
+ pipe->read_buffer_data.size_total = pipe->ready_buffer_data.size_total;
+ pipe->ready_buffer_data.size_total = 0;
+
+ pipe->read_buffer_data.write_eof = pipe->ready_buffer_data.write_eof;
+
+ g_mutex_unlock(&pipe->mutex);
+
+ }
+
+ if (!thread_pipe_data_destroy(pipe)) {
+ thread_pipe_destroy(pipe);
+ return NULL;
+ }
+ *data_out = pipe->read_data->data;
+ *size = pipe->read_data->size;
+
+ return pipe;
+}
+
+/**
+ * Reads to the end of a line like fgets and pops it, or reads to the end of pipe.
+ *
+ * size_out will be the length + 1 of the string like strlen.
+ *
+ * Pushed data blocks should be 0 terminated, but don't have to.
+ *
+ * possible independent cases:
+ * - newline at position of block, where position in Po := {nowhere, beginning/middle, end}
+ * - newline at is_first block, where is_first in If := {first, not first}
+ * - newline at is_last block, where is_last in Il := {last, not last}
+ * In total there are 12 pairwise unequal cases by forming the Cartesian product of Po, If and Il
+ * and adding the case where there is no newline at all.
+ *
+ * returns pipe or NULL like thread_pipe_pop
+ */
+ThreadPipe *thread_pipe_pop_line(ThreadPipe *pipe_in, gchar **string_out, gsize *size_out) {
+ g_return_val_if_fail(pipe_in != NULL, pipe_in);
+ g_return_val_if_fail(string_out != NULL, pipe_in);
+ g_return_val_if_fail(size_out != NULL, pipe_in);
+ //Don't pop, if you set read_eof already.
+ g_return_val_if_fail(pipe_in->read_buffer_data.read_eof != TRUE, NULL);
+
+
+ *string_out = NULL;
+ *size_out = 0;
+
+ size_t line_size;
+ gchar *line;
+ FILE *line_file = open_memstream(&line, &line_size);
+
+ ThreadPipeData *current = NULL;
+ gchar *ptr = NULL;
+
+ while (TRUE) {
+
+ ptr = NULL;
+
+ if (pipe_in->read_buffer_data.block_counter <= 0) {
+
+ g_mutex_lock(&pipe_in->mutex);
+
+ while (pipe_in->ready_buffer_data.block_counter <= 0 && !pipe_in->ready_buffer_data.write_eof)
+ g_cond_wait(&pipe_in->cond, &pipe_in->mutex);
+
+ pipe_in->read_buffer_data.block_counter = pipe_in->ready_buffer_data.block_counter;
+ pipe_in->ready_buffer_data.block_counter = 0;
+
+ pipe_in->read_buffer_data.size_total = pipe_in->ready_buffer_data.size_total;
+ pipe_in->ready_buffer_data.size_total = 0;
+
+ pipe_in->read_buffer_data.write_eof = pipe_in->ready_buffer_data.write_eof;
+
+ g_mutex_unlock(&pipe_in->mutex);
+
+ }
+
+ current = pipe_in->read_data->next;
+
+
+ if (current == NULL)
+ break;
+
+ ptr = current->data;
+ while (*ptr != '\n' &&
+ *ptr != 0 &&
+ ptr - (gchar *)current->data < current->size //somebody forgot to close the string with 0?
+ ) {
+ fputc(*ptr, line_file);
+ ptr++;
+ }
+
+ if (ptr - (gchar *)current->data < current->size && *ptr == '\n') {
+ fputc(*ptr, line_file);
+ ptr++;
+ break;
+ }
+
+ thread_pipe_data_destroy(pipe_in);
+ }
+
+ fputc(0, line_file);
+ fclose(line_file);
+
+ if (current == NULL) {
+
+ if (line_size == 1) {
+ g_free(line);
+ thread_pipe_destroy(pipe_in);
+ return NULL;
+ }
+
+ } else {
+
+ gchar **current_data = (gchar **)&current->data;
+ gsize *current_size = &current->size;
+
+ *current_size -= (ptr - *current_data);
+ pipe_in->read_buffer_data.size_total -= (ptr - *current_data);
+ *current_data = ptr;
+
+ if (*current_size == 0 || (*current_size == 1 && *ptr == 0))
+ thread_pipe_data_destroy(pipe_in);
+
+ }
+
+ /**
+ * current == NULL && line_size != 1
+ * ||
+ * current != NULL
+ */
+
+ gchar **old_data = (gchar **)&pipe_in->read_data->malloc_address;
+ gsize *old_size = &pipe_in->read_data->size;
+
+ g_free(*old_data);
+ *old_data = line;
+ *old_size = line_size;
+
+ *string_out = *old_data;
+ *size_out = *old_size;
+
+ return pipe_in;
+}
+
+/**
+ * If you are finished with writing, you have to set write_eof so that the
+ * memory of pipe can be freed. You can set write_eof independent of
+ * - read_eof
+ * - emptiness of pipe
+ * - other shit
+ *
+ * Don't push, after you called thread_pipe_set_write_eof.
+ *
+ * The memory of data and pipe will be freed, if read_eof && write_eof == TRUE.
+ */
+void thread_pipe_set_write_eof(ThreadPipe *pipe) {
+ g_return_if_fail(pipe != NULL);
+ g_return_if_fail(pipe->write_buffer_data.write_eof != TRUE);
+
+ g_mutex_lock(&pipe->mutex);
+ gboolean destroy = pipe->ready_buffer_data.read_eof;
+
+ pipe->ready_buffer_data.write_eof = TRUE;
+// pipe->read_buffer_data.write_eof = TRUE;
+ pipe->write_buffer_data.write_eof = TRUE;
+
+ pipe->ready_buffer_data.block_counter += pipe->write_buffer_data.block_counter;
+ pipe->write_buffer_data.block_counter = 0;
+
+ pipe->ready_buffer_data.size_total += pipe->write_buffer_data.size_total;
+ pipe->write_buffer_data.size_total = 0;
+
+ g_cond_signal(&pipe->cond);
+ g_mutex_unlock(&pipe->mutex);
+
+ if (destroy)
+ thread_pipe_destroy(pipe);
+}
+
+/**
+ * If you are finished with reading, you have to set read_eof so that the
+ * memory of pipe can be freed. You can set read_eof independent of
+ * - write_eof
+ * - emptiness of pipe
+ * - other shit
+ *
+ * Don't pop, after you called thread_pipe_set_read_eof.
+ *
+ * The memory of data waiting in pipe to be popped, will all be freed.
+ *
+ * The memory of pipe will be freed also, if write_eof && write_eof == TRUE.
+ */
+void thread_pipe_set_read_eof(ThreadPipe *pipe) {
+ g_return_if_fail(pipe != NULL);
+ g_return_if_fail(pipe->read_buffer_data.read_eof != TRUE);
+
+ g_mutex_lock(&pipe->mutex);
+ gboolean destroy = pipe->ready_buffer_data.write_eof;
+ pipe->ready_buffer_data.read_eof = TRUE;
+ pipe->read_buffer_data.read_eof = TRUE;
+// pipe->write_buffer_data.read_eof = TRUE;
+
+ pipe->read_buffer_data.write_eof = pipe->ready_buffer_data.write_eof;
+
+ pipe->read_buffer_data.block_counter += pipe->ready_buffer_data.block_counter;
+ pipe->ready_buffer_data.block_counter = 0;
+
+ pipe->read_buffer_data.size_total += pipe->ready_buffer_data.size_total;
+ pipe->ready_buffer_data.size_total = 0;
+
+ while (pipe->read_buffer_data.block_counter)
+ thread_pipe_data_destroy(pipe);
+ g_mutex_unlock(&pipe->mutex);
+
+ if (destroy)
+ thread_pipe_destroy(pipe);
+}
+
+/**
+ * copy data to a new ThreadPipeData structure
+ */
+static ThreadPipeData *thread_pipe_data_new(gpointer data, gsize size) {
+ ThreadPipeData *pipe_data = g_new0(ThreadPipeData, 1);
+ if (data != NULL && size != 0) {
+ pipe_data->malloc_address = g_malloc(size);
+ memcpy(pipe_data->malloc_address, data, size);
+ pipe_data->data = pipe_data->malloc_address;
+ pipe_data->size = size;
+ }
+
+ return pipe_data;
+}
+
+/**
+ * free all memory of a ThreadPipeData structure
+ *
+ * returns
+ * - the next block of the linked list, if there is one
+ * - else NULL
+ */
+static ThreadPipeData *thread_pipe_data_destroy(ThreadPipe *pipe) {
+ ThreadPipeData *pipe_data = pipe->read_data;
+ ThreadPipeData *next = pipe_data->next;
+ g_free(pipe_data->malloc_address);
+ g_free(pipe_data);
+ if (next != NULL) {
+ pipe->read_buffer_data.block_counter--;
+ pipe->read_buffer_data.size_total -= next->size;
+ }
+ pipe->read_data = next;
+ return next;
+}
+
+/**
+ * free all memory of a ThreadPipe structure
+ */
+static void thread_pipe_destroy(ThreadPipe *pipe) {
+ g_return_if_fail(pipe != NULL);
+
+ while (pipe->read_data)
+ thread_pipe_data_destroy(pipe);
+ g_mutex_clear(&pipe->mutex);
+ g_cond_clear(&pipe->cond);
+ g_free(pipe);
+}
diff --git a/src/tools/thread-pipe.h b/src/tools/thread-pipe.h
new file mode 100644
index 0000000..1a93c7f
--- /dev/null
+++ b/src/tools/thread-pipe.h
@@ -0,0 +1,57 @@
+/*
+ * thread-pipe.h
+ *
+ *
+ * Authors:
+ * Michi <st101564@stud.uni-stuttgart.de>
+ *
+ * Web page: https://ahoi.io/project/oregano
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef THREAD_PIPE_H_
+#define THREAD_PIPE_H_
+
+#define THREAD_PIPE_MAX_BUFFER_BLOCK_COUNTER_DEFAULT 20
+#define THREAD_PIPE_MAX_BUFFER_SIZE_TOTAL_DEFAULT 2048
+
+typedef struct _ThreadPipe ThreadPipe;
+
+/**
+ * Constructor
+ */
+ThreadPipe *thread_pipe_new(
+ guint max_buffer_block_counter,
+ gsize max_buffer_size_total);
+
+/**
+ * functions for writing thread
+ */
+gboolean thread_pipe_push(ThreadPipe *pipe, gpointer data, gsize size);
+// Destructor
+void thread_pipe_set_write_eof(ThreadPipe *pipe);
+
+/**
+ * functions for reading thread
+ */
+ThreadPipe *thread_pipe_pop(ThreadPipe *pipe, gpointer *data_out, gsize *size);
+ThreadPipe *thread_pipe_pop_line(ThreadPipe *pipe, gchar **data_out, gsize *size);
+// Destructor
+void thread_pipe_set_read_eof(ThreadPipe *pipe);
+
+#endif /* THREAD_PIPE_H_ */
diff --git a/src/wscript b/src/wscript
new file mode 100644
index 0000000..0243dae
--- /dev/null
+++ b/src/wscript
@@ -0,0 +1,49 @@
+#! /usr/bin/env python3
+# encoding: utf-8
+
+import os
+from waflib import Logs as logs
+from waflib import Utils as utils
+
+def options(opt):
+ pass
+
+def configure(conf):
+ pass
+
+def build(bld):
+ if bld.cmd == 'install' or bld.cmd == 'uninstall':
+ if not os.geteuid()==0:
+ logs.warn ('You most likely need root privileges to install or uninstall properly.')
+
+
+ nodes = bld.path.ant_glob(\
+ ['*.c',
+ 'tools/*.c',
+ 'gplot/*.c',
+ 'engines/*.c',
+ 'sheet/*.c',
+ 'model/*.c'],
+ excl='main.c')
+
+ bld.objects (
+ ['c','glib2'],
+ source = nodes,
+ includes = ['.', 'tools/', 'engines/', 'gplot/', 'model/', 'sheet/'],
+ uselib = 'M XML GOBJECT GLIB GTK3 XML GOOCANVAS GTKSOURCEVIEW3',
+ target = 'shared_objects'
+ )
+
+ exe = bld.program(
+ features = ['c', 'glib2'],
+ target = bld.env.appname,
+ source = ['main.c'],
+ includes = ['.', 'tools/', 'engines/', 'gplot/', 'model/', 'sheet/'],
+ use = 'shared_objects',
+ uselib = 'M XML GOBJECT GLIB GTK3 XML GOOCANVAS GTKSOURCEVIEW3',
+ settings_schema_files = ['../data/settings/'+bld.env.gschema_name ] if not bld.options.no_install_gschema else [],
+ install_path = "${BINDIR}"
+ )
+
+ for item in exe.includes:
+ logs.debug(item)
diff --git a/src/xml-compat.h b/src/xml-compat.h
index 94baf24..a16e8b1 100644
--- a/src/xml-compat.h
+++ b/src/xml-compat.h
@@ -8,7 +8,7 @@
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
@@ -26,8 +26,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __XML_COMPAT_H
@@ -40,4 +40,3 @@
#define childs children
#endif /* __XML_COMPAT_H */
-
diff --git a/src/xml-helper.c b/src/xml-helper.c
index e9da224..24f23c7 100644
--- a/src/xml-helper.c
+++ b/src/xml-helper.c
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
*
- * Web page: https://github.com/marc-lorber/oregano
+ * Web page: https://ahoi.io/project/oregano
*
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2006 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#include "xml-compat.h"
@@ -36,37 +38,43 @@
// A modified version of XmlSAXParseFile in gnome-xml. This one lets us set
// the user_data that is passed to the various callbacks, to make it possible
// to avoid lots of global variables.
-int oreganoXmlSAXParseFile (xmlSAXHandlerPtr sax,
- gpointer user_data, const gchar *filename)
+gboolean oreganoXmlSAXParseFile (xmlSAXHandlerPtr sax, gpointer user_data, const gchar *filename)
{
- int ret = 0;
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ gboolean parser_failed, ret = TRUE;
xmlParserCtxtPtr ctxt;
ctxt = xmlCreateFileParserCtxt (filename);
- if (ctxt == NULL) return -1;
+ if (ctxt == NULL)
+ return FALSE;
+
ctxt->sax = sax;
ctxt->userData = user_data;
#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20000
xmlKeepBlanksDefault (0);
#endif
- xmlParseDocument (ctxt);
+ parser_failed = FALSE;
+ if (xmlParseDocument (ctxt) < 0) {
+ // FIXME post a message to the log buffer with as much details as possible
+ g_message ("Failed to parse \"%s\"", filename);
+ ret = FALSE;
+ parser_failed = TRUE;
+ } else {
+ ret = ctxt->wellFormed ? TRUE : FALSE;
+ if (sax != NULL)
+ ctxt->sax = NULL;
+ }
- if (ctxt->wellFormed)
- ret = 0;
- else
- ret = -1;
- if (sax != NULL)
- ctxt->sax = NULL;
- xmlFreeParserCtxt (ctxt);
+ if (!parser_failed)
+ xmlFreeParserCtxt (ctxt);
return ret;
}
-
// Set coodinate for a node, carried as the content of a child.
-void
-xmlSetCoordinate (xmlNodePtr node, const char *name, double x, double y)
+void xmlSetCoordinate (xmlNodePtr node, const char *name, double x, double y)
{
xmlNodePtr child;
gchar *str;
@@ -91,12 +99,9 @@ xmlSetCoordinate (xmlNodePtr node, const char *name, double x, double y)
g_free (str);
}
-
-
// Set coodinates for a node, carried as the content of a child.
-void
-xmlSetCoordinates (xmlNodePtr node, const char *name,
- double x1, double y1, double x2, double y2)
+void xmlSetCoordinates (xmlNodePtr node, const char *name, double x1, double y1, double x2,
+ double y2)
{
xmlNodePtr child;
gchar *str;
@@ -121,10 +126,9 @@ xmlSetCoordinates (xmlNodePtr node, const char *name,
g_free (str);
}
-// Set a string value for a node either carried as an attibute or as the
+// Set a string value for a node either carried as an attibute or as the
// content of a child.
-void
-xmlSetValue (xmlNodePtr node, const char *name, const char *val)
+void xmlSetValue (xmlNodePtr node, const char *name, const char *val)
{
xmlChar *ret;
xmlNodePtr child;
@@ -147,15 +151,14 @@ xmlSetValue (xmlNodePtr node, const char *name, const char *val)
// Set an integer value for a node either carried as an attibute or as
// the content of a child.
-void
-xmlSetIntValue (xmlNodePtr node, const char *name, int val)
+void xmlSetIntValue (xmlNodePtr node, const char *name, int val)
{
xmlChar *ret;
xmlNodePtr child;
char str[101];
snprintf (str, 100, "%d", val);
- ret = xmlGetProp (node,BAD_CAST name);
+ ret = xmlGetProp (node, BAD_CAST name);
if (ret != NULL) {
xmlSetProp (node, BAD_CAST name, BAD_CAST str);
return;
@@ -171,17 +174,15 @@ xmlSetIntValue (xmlNodePtr node, const char *name, int val)
xmlSetProp (node, BAD_CAST name, BAD_CAST str);
}
-
// Set a double value for a node either carried as an attibute or as
// the content of a child.
-void
-xmlSetDoubleValue (xmlNodePtr node, const char *name, double val)
+void xmlSetDoubleValue (xmlNodePtr node, const char *name, double val)
{
xmlChar *ret;
xmlNodePtr child;
char str[101];
- snprintf (str, 100, "%g", (float) val);
+ snprintf (str, 100, "%g", (float)val);
ret = xmlGetProp (node, BAD_CAST name);
if (ret != NULL) {
xmlSetProp (node, BAD_CAST name, BAD_CAST str);
diff --git a/src/xml-helper.h b/src/xml-helper.h
index 41942d3..6111846 100644
--- a/src/xml-helper.h
+++ b/src/xml-helper.h
@@ -7,12 +7,14 @@
* Ricardo Markiewicz <rmarkie@fi.uba.ar>
* Andres de Barbara <adebarbara@fi.uba.ar>
* Marc Lorber <lorber.marc@wanadoo.fr>
+ * Bernhard Schuster <bernhard@ahoi.io>
+ *
+ * Web page: https://ahoi.io/project/oregano
*
- * Web page: https://github.com/marc-lorber/oregano
- *
* Copyright (C) 1999-2001 Richard Hult
* Copyright (C) 2003,2004 Ricardo Markiewicz
* Copyright (C) 2009-2012 Marc Lorber
+ * Copyright (C) 2014 Bernhard Schuster
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,8 +28,8 @@
*
* 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-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __XML_HELPER_H
#define __XML_HELPER_H
@@ -36,8 +38,7 @@
#include "xml-compat.h"
-int oreganoXmlSAXParseFile (xmlSAXHandlerPtr sax,
- gpointer user_data, const gchar *filename);
+gboolean oreganoXmlSAXParseFile (xmlSAXHandlerPtr sax, gpointer user_data, const gchar *filename);
void xmlSetValue (xmlNodePtr node, const char *name, const char *val);
@@ -47,7 +48,7 @@ void xmlSetDoubleValue (xmlNodePtr node, const char *name, double val);
void xmlSetCoordinate (xmlNodePtr node, const char *name, double x, double y);
-void xmlSetCoordinates (xmlNodePtr node, const char *name,
- double x1, double y1, double x2, double y2);
+void xmlSetCoordinates (xmlNodePtr node, const char *name, double x1, double y1, double x2,
+ double y2);
#endif