Merge pull request #79 from gergelypolonkai/export-image
Export chart as JPEG and viewable SVG
This commit is contained in:
commit
e07d818724
@ -37,6 +37,8 @@ PKG_CHECK_MODULES([LIBXML], [libxml-2.0])
|
|||||||
PKG_CHECK_MODULES([LIBXSLT], [libexslt])
|
PKG_CHECK_MODULES([LIBXSLT], [libexslt])
|
||||||
PKG_CHECK_MODULES([WEBKIT], [webkit2gtk-4.0])
|
PKG_CHECK_MODULES([WEBKIT], [webkit2gtk-4.0])
|
||||||
PKG_CHECK_MODULES([GDA], [libgda-5.0 libgda-sqlite-5.0])
|
PKG_CHECK_MODULES([GDA], [libgda-5.0 libgda-sqlite-5.0])
|
||||||
|
PKG_CHECK_MODULES([PIXBUF], [gdk-pixbuf-2.0])
|
||||||
|
PKG_CHECK_MODULES([RSVG], [librsvg-2.0])
|
||||||
PKG_CHECK_MODULES([SWE_GLIB], [swe-glib >= 2.1.0])
|
PKG_CHECK_MODULES([SWE_GLIB], [swe-glib >= 2.1.0])
|
||||||
|
|
||||||
LIBGD_INIT([
|
LIBGD_INIT([
|
||||||
|
@ -32,7 +32,7 @@ AM_CPPFLAGS = -DG_LOG_DOMAIN=\"Astrognome\" -DLOCALEDIR=\"$(localedir)\" -DPKGDA
|
|||||||
bin_PROGRAMS = astrognome
|
bin_PROGRAMS = astrognome
|
||||||
|
|
||||||
astrognome_SOURCES = $(astrognome_source_files) $(BUILT_SOURCES)
|
astrognome_SOURCES = $(astrognome_source_files) $(BUILT_SOURCES)
|
||||||
astrognome_LDADD = $(SWE_GLIB_LIBS) $(GTK_LIBS) $(LIBXML_LIBS) $(LIBXSLT_LIBS) $(WEBKIT_LIBS) $(GDA_LIBS) $(top_builddir)/libgd/libgd.la
|
astrognome_LDADD = $(SWE_GLIB_LIBS) $(GTK_LIBS) $(LIBXML_LIBS) $(LIBXSLT_LIBS) $(WEBKIT_LIBS) $(GDA_LIBS) $(PIXBUF_LIBS) $(RSVG_LIBS) $(top_builddir)/libgd/libgd.la
|
||||||
astrognome_LDFLAGS = -rdynamic
|
astrognome_LDFLAGS = -rdynamic
|
||||||
astrognome_CFLAGS = $(SWE_GLIB_CFLAGS) $(CFLAGS) $(GTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) $(WEBKIT_CFLAGS) $(GDA_CFLAGS) -Wall
|
astrognome_CFLAGS = $(SWE_GLIB_CFLAGS) $(CFLAGS) $(GTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) $(WEBKIT_CFLAGS) $(GDA_CFLAGS) $(PIXBUF_CFLAGS) $(RSVG_CFLAGS) -Wall
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <librsvg/rsvg.h>
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "astrognome.h"
|
#include "astrognome.h"
|
||||||
@ -41,6 +44,10 @@ typedef enum {
|
|||||||
XML_CONVERT_INT
|
XML_CONVERT_INT
|
||||||
} XmlConvertType;
|
} XmlConvertType;
|
||||||
|
|
||||||
|
#if !LIBRSVG_HAVE_CSS
|
||||||
|
# error "We need RSVG CSS support to export charts as images!"
|
||||||
|
#endif
|
||||||
|
|
||||||
G_DEFINE_QUARK(ag_chart_error_quark, ag_chart_error);
|
G_DEFINE_QUARK(ag_chart_error_quark, ag_chart_error);
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE(AgChart, ag_chart, GSWE_TYPE_MOMENT);
|
G_DEFINE_TYPE_WITH_PRIVATE(AgChart, ag_chart, GSWE_TYPE_MOMENT);
|
||||||
@ -1388,7 +1395,11 @@ ag_chart_sort_planets_by_position(GswePlanetData *planet1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
gchar *
|
||||||
ag_chart_create_svg(AgChart *chart, gsize *length, GError **err)
|
ag_chart_create_svg(
|
||||||
|
AgChart *chart,
|
||||||
|
gsize *length,
|
||||||
|
gboolean rendering,
|
||||||
|
GError **err)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc = create_save_doc(chart),
|
xmlDocPtr doc = create_save_doc(chart),
|
||||||
xslt_doc,
|
xslt_doc,
|
||||||
@ -1401,7 +1412,8 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err)
|
|||||||
antiscia_node = NULL,
|
antiscia_node = NULL,
|
||||||
node = NULL;
|
node = NULL;
|
||||||
gchar *value,
|
gchar *value,
|
||||||
*save_content = NULL;
|
*save_content = NULL,
|
||||||
|
**params;
|
||||||
const gchar *xslt_content;
|
const gchar *xslt_content;
|
||||||
GList *houses,
|
GList *houses,
|
||||||
*house,
|
*house,
|
||||||
@ -1705,15 +1717,22 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params = g_new0(gchar *, 3);
|
||||||
|
params[0] = "rendering";
|
||||||
|
params[1] = (rendering) ? "'yes'" : "'no'";
|
||||||
|
|
||||||
// libxml2 messes up the output, as it prints decimal floating point
|
// libxml2 messes up the output, as it prints decimal floating point
|
||||||
// numbers in a localized format. It is not good in locales that use a
|
// numbers in a localized format. It is not good in locales that use a
|
||||||
// character for decimal separator other than a dot. So let's just use the
|
// character for decimal separator other than a dot. So let's just use the
|
||||||
// C locale until the SVG is generated.
|
// C locale until the SVG is generated.
|
||||||
current_locale = uselocale(newlocale(LC_ALL, "C", 0));
|
current_locale = uselocale(newlocale(LC_ALL, "C", 0));
|
||||||
svg_doc = xsltApplyStylesheet(xslt_proc, doc, NULL);
|
|
||||||
|
svg_doc = xsltApplyStylesheet(xslt_proc, doc, (const char **)params);
|
||||||
|
|
||||||
uselocale(current_locale);
|
uselocale(current_locale);
|
||||||
xsltFreeStylesheet(xslt_proc);
|
xsltFreeStylesheet(xslt_proc);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
g_free(params);
|
||||||
|
|
||||||
// Now, svg_doc contains the generated SVG file
|
// Now, svg_doc contains the generated SVG file
|
||||||
|
|
||||||
@ -1747,7 +1766,7 @@ ag_chart_export_svg_to_file(AgChart *chart, GFile *file, GError **err)
|
|||||||
gchar *svg;
|
gchar *svg;
|
||||||
gsize length;
|
gsize length;
|
||||||
|
|
||||||
if ((svg = ag_chart_create_svg(chart, &length, err)) == NULL) {
|
if ((svg = ag_chart_create_svg(chart, &length, TRUE, err)) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1764,6 +1783,72 @@ ag_chart_export_svg_to_file(AgChart *chart, GFile *file, GError **err)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ag_chart_export_jpg_to_file(AgChart *chart, GFile *file, GError **err)
|
||||||
|
{
|
||||||
|
gchar *svg,
|
||||||
|
*jpg;
|
||||||
|
gsize svg_length,
|
||||||
|
jpg_length;
|
||||||
|
RsvgHandle *svg_handle;
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
|
if ((svg = ag_chart_create_svg(chart, &svg_length, TRUE, err)) == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((svg_handle = rsvg_handle_new_from_data(
|
||||||
|
(const guint8 *)svg,
|
||||||
|
svg_length,
|
||||||
|
err
|
||||||
|
)) == NULL) {
|
||||||
|
g_free(svg);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(svg);
|
||||||
|
|
||||||
|
if ((pixbuf = rsvg_handle_get_pixbuf(svg_handle)) == NULL) {
|
||||||
|
g_set_error(
|
||||||
|
err,
|
||||||
|
AG_CHART_ERROR, AG_CHART_ERROR_RENDERING_ERROR,
|
||||||
|
_("Unknown rendering error")
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gdk_pixbuf_save_to_buffer(
|
||||||
|
pixbuf,
|
||||||
|
&jpg,
|
||||||
|
&jpg_length,
|
||||||
|
"jpeg",
|
||||||
|
err,
|
||||||
|
NULL
|
||||||
|
)) {
|
||||||
|
g_object_unref(pixbuf);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(pixbuf);
|
||||||
|
|
||||||
|
g_file_replace_contents(
|
||||||
|
file,
|
||||||
|
(const gchar *)jpg,
|
||||||
|
jpg_length,
|
||||||
|
NULL,
|
||||||
|
FALSE,
|
||||||
|
G_FILE_CREATE_NONE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(jpg);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ag_chart_set_note(AgChart *chart, const gchar *note)
|
ag_chart_set_note(AgChart *chart, const gchar *note)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@ typedef enum {
|
|||||||
AG_CHART_ERROR_NOT_IMPLEMENTED,
|
AG_CHART_ERROR_NOT_IMPLEMENTED,
|
||||||
AG_CHART_ERROR_INVALID_PLAC_FILE,
|
AG_CHART_ERROR_INVALID_PLAC_FILE,
|
||||||
AG_CHART_ERROR_UNSUPPORTED_PLAC_FILE,
|
AG_CHART_ERROR_UNSUPPORTED_PLAC_FILE,
|
||||||
|
AG_CHART_ERROR_RENDERING_ERROR,
|
||||||
} AgChartError;
|
} AgChartError;
|
||||||
|
|
||||||
#define AG_TYPE_CHART (ag_chart_get_type())
|
#define AG_TYPE_CHART (ag_chart_get_type())
|
||||||
@ -43,6 +44,8 @@ struct _AgChartClass {
|
|||||||
GsweMomentClass parent_class;
|
GsweMomentClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*AgChartSaveImageFunc)(AgChart *, GFile *, GError **);
|
||||||
|
|
||||||
GType ag_chart_get_type(void) G_GNUC_CONST;
|
GType ag_chart_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
AgChart *ag_chart_new_full(GsweTimestamp *timestamp,
|
AgChart *ag_chart_new_full(GsweTimestamp *timestamp,
|
||||||
@ -67,6 +70,10 @@ void ag_chart_export_svg_to_file(AgChart *chart,
|
|||||||
GFile *file,
|
GFile *file,
|
||||||
GError **err);
|
GError **err);
|
||||||
|
|
||||||
|
void ag_chart_export_jpg_to_file(AgChart *chart,
|
||||||
|
GFile *file,
|
||||||
|
GError **err);
|
||||||
|
|
||||||
void ag_chart_set_name(AgChart *chart,
|
void ag_chart_set_name(AgChart *chart,
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
|
|
||||||
@ -84,6 +91,7 @@ const gchar *ag_chart_get_city(AgChart *chart);
|
|||||||
|
|
||||||
gchar *ag_chart_create_svg(AgChart *chart,
|
gchar *ag_chart_create_svg(AgChart *chart,
|
||||||
gsize *length,
|
gsize *length,
|
||||||
|
gboolean rendering,
|
||||||
GError **err);
|
GError **err);
|
||||||
|
|
||||||
GList *ag_chart_get_planets(AgChart *chart);
|
GList *ag_chart_get_planets(AgChart *chart);
|
||||||
|
192
src/ag-window.c
192
src/ag-window.c
@ -496,6 +496,7 @@ ag_window_redraw_chart(AgWindow *window)
|
|||||||
gchar *svg_content = ag_chart_create_svg(
|
gchar *svg_content = ag_chart_create_svg(
|
||||||
priv->chart,
|
priv->chart,
|
||||||
&length,
|
&length,
|
||||||
|
FALSE,
|
||||||
&err
|
&err
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -808,12 +809,12 @@ ag_window_recalculate_chart(AgWindow *window, gboolean set_everything)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ag_window_export_svg(AgWindow *window, GError **err)
|
ag_window_export_image(AgWindow *window, GError **err)
|
||||||
{
|
{
|
||||||
const gchar *name;
|
const gchar *name;
|
||||||
gchar *file_name;
|
|
||||||
GtkWidget *fs;
|
GtkWidget *fs;
|
||||||
gint response;
|
gint response;
|
||||||
|
GError *local_err = NULL;
|
||||||
AgWindowPrivate *priv = ag_window_get_instance_private(window);
|
AgWindowPrivate *priv = ag_window_get_instance_private(window);
|
||||||
|
|
||||||
ag_window_recalculate_chart(window, TRUE);
|
ag_window_recalculate_chart(window, TRUE);
|
||||||
@ -851,41 +852,200 @@ ag_window_export_svg(AgWindow *window, GError **err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_name = g_strdup_printf("%s.svg", name);
|
|
||||||
|
|
||||||
fs = gtk_file_chooser_dialog_new(_("Export Chart as SVG"),
|
fs = gtk_file_chooser_dialog_new(_("Export Chart as SVG"),
|
||||||
GTK_WINDOW(window),
|
GTK_WINDOW(window),
|
||||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||||
_("_Save"), GTK_RESPONSE_ACCEPT,
|
_("_Save"), GTK_RESPONSE_ACCEPT,
|
||||||
NULL);
|
NULL);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), filter_svg);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), filter_jpg);
|
||||||
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg);
|
||||||
gtk_dialog_set_default_response(GTK_DIALOG(fs), GTK_RESPONSE_ACCEPT);
|
gtk_dialog_set_default_response(GTK_DIALOG(fs), GTK_RESPONSE_ACCEPT);
|
||||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), FALSE);
|
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), FALSE);
|
||||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), TRUE);
|
// Due to file name modifying later (depending on the file type selection),
|
||||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), file_name);
|
// we must do this manually
|
||||||
g_free(file_name);
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), FALSE);
|
||||||
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), name);
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
response = gtk_dialog_run(GTK_DIALOG(fs));
|
response = gtk_dialog_run(GTK_DIALOG(fs));
|
||||||
gtk_widget_hide(fs);
|
gtk_widget_hide(fs);
|
||||||
|
|
||||||
if (response == GTK_RESPONSE_ACCEPT) {
|
if (response == GTK_RESPONSE_ACCEPT) {
|
||||||
GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(fs));
|
GFile *file = gtk_file_chooser_get_file(
|
||||||
|
GTK_FILE_CHOOSER(fs)
|
||||||
|
);
|
||||||
|
GtkFileFilter *filter = gtk_file_chooser_get_filter(
|
||||||
|
GTK_FILE_CHOOSER(fs)
|
||||||
|
);
|
||||||
|
gchar *filename = g_file_get_uri(file),
|
||||||
|
*extension,
|
||||||
|
*current_extension;
|
||||||
|
AgChartSaveImageFunc save_func = NULL;
|
||||||
|
gboolean can_save = FALSE;
|
||||||
|
|
||||||
ag_chart_export_svg_to_file(priv->chart, file, err);
|
if (filter == filter_svg) {
|
||||||
|
extension = ".svg";
|
||||||
|
save_func = &ag_chart_export_svg_to_file;
|
||||||
|
} else if (filter == filter_jpg) {
|
||||||
|
extension = ".jpg";
|
||||||
|
save_func = &ag_chart_export_jpg_to_file;
|
||||||
|
} else {
|
||||||
|
g_warning("Unknown file type");
|
||||||
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_extension = g_utf8_strrchr(filename, -1, '.');
|
||||||
|
|
||||||
|
if (current_extension == NULL) {
|
||||||
|
gchar *tmp;
|
||||||
|
|
||||||
|
tmp = filename;
|
||||||
|
filename = g_strdup_printf("%s%s", tmp, extension);
|
||||||
|
g_free(tmp);
|
||||||
|
} else {
|
||||||
|
GFileInfo *fileinfo;
|
||||||
|
GFile *tmp_file;
|
||||||
|
gboolean valid;
|
||||||
|
GtkFileFilterInfo filter_info;
|
||||||
|
|
||||||
|
tmp_file = g_file_new_for_uri(filename);
|
||||||
|
fileinfo = g_file_query_info(
|
||||||
|
tmp_file,
|
||||||
|
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
|
||||||
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
g_object_unref(tmp_file);
|
||||||
|
|
||||||
|
filter_info.contains =
|
||||||
|
GTK_FILE_FILTER_URI
|
||||||
|
| GTK_FILE_FILTER_DISPLAY_NAME;
|
||||||
|
filter_info.uri = filename;
|
||||||
|
filter_info.display_name = g_file_info_get_display_name(
|
||||||
|
fileinfo
|
||||||
|
);
|
||||||
|
|
||||||
|
valid = gtk_file_filter_filter(filter, &filter_info);
|
||||||
|
g_object_unref(fileinfo);
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
GtkResponseType response;
|
||||||
|
gchar *message,
|
||||||
|
*new_filename;
|
||||||
|
|
||||||
|
new_filename = g_strdup_printf("%s%s", filename, extension);
|
||||||
|
|
||||||
|
message = g_strdup_printf(
|
||||||
|
"File extension doesn’t match the chosen format. " \
|
||||||
|
"Do you want Astrognome to append the correct " \
|
||||||
|
"extension (the new filename will be %s) or " \
|
||||||
|
"choose a new name?",
|
||||||
|
new_filename
|
||||||
|
);
|
||||||
|
|
||||||
|
response = ag_app_buttoned_dialog(
|
||||||
|
GTK_WINDOW(window),
|
||||||
|
GTK_MESSAGE_QUESTION,
|
||||||
|
message,
|
||||||
|
"Cancel", GTK_RESPONSE_CANCEL,
|
||||||
|
"Append extension", GTK_RESPONSE_APPLY,
|
||||||
|
"Choose new file", GTK_RESPONSE_NO,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response == GTK_RESPONSE_APPLY) {
|
||||||
|
g_free(filename);
|
||||||
|
filename = new_filename;
|
||||||
|
} else {
|
||||||
|
g_free(filename);
|
||||||
|
g_clear_object(&file);
|
||||||
|
|
||||||
|
if (response == GTK_RESPONSE_NO) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object(&file);
|
||||||
|
file = g_file_new_for_uri(filename);
|
||||||
|
g_free(filename);
|
||||||
|
|
||||||
|
// Now check if a file under the modified name exists
|
||||||
|
if (g_file_query_exists(file, NULL)) {
|
||||||
|
GtkResponseType sub_response;
|
||||||
|
gchar *message;
|
||||||
|
GFileInfo *fileinfo;
|
||||||
|
|
||||||
|
fileinfo = g_file_query_info(
|
||||||
|
file,
|
||||||
|
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
|
||||||
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
message = g_strdup_printf(
|
||||||
|
"File %s already exists. Do you want to overwrite it?",
|
||||||
|
g_file_info_get_display_name(fileinfo)
|
||||||
|
);
|
||||||
|
g_object_unref(fileinfo);
|
||||||
|
|
||||||
|
sub_response = ag_app_buttoned_dialog(
|
||||||
|
GTK_WINDOW(window), GTK_MESSAGE_QUESTION,
|
||||||
|
message,
|
||||||
|
_("No"), GTK_RESPONSE_NO,
|
||||||
|
_("Yes"), GTK_RESPONSE_YES,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(message);
|
||||||
|
|
||||||
|
can_save = (sub_response == GTK_RESPONSE_YES);
|
||||||
|
} else {
|
||||||
|
can_save = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_save) {
|
||||||
|
g_clear_error(&local_err);
|
||||||
|
save_func(priv->chart, file, &local_err);
|
||||||
|
|
||||||
|
if (local_err) {
|
||||||
|
ag_app_message_dialog(
|
||||||
|
GTK_WINDOW(window),
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
"%s",
|
||||||
|
local_err->message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object(&file);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object(&file);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_widget_destroy(fs);
|
gtk_widget_destroy(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ag_window_export_svg_action(GSimpleAction *action,
|
ag_window_export_image_action(GSimpleAction *action,
|
||||||
GVariant *parameter,
|
GVariant *parameter,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
AgWindow *window = AG_WINDOW(user_data);
|
AgWindow *window = AG_WINDOW(user_data);
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
|
||||||
ag_window_export_svg(window, &err);
|
ag_window_export_image(window, &err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
ag_app_message_dialog(
|
ag_app_message_dialog(
|
||||||
@ -898,7 +1058,7 @@ ag_window_export_svg_action(GSimpleAction *action,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ag_window_export(AgWindow *window, GError **err)
|
ag_window_export_agc(AgWindow *window, GError **err)
|
||||||
{
|
{
|
||||||
const gchar *name;
|
const gchar *name;
|
||||||
gchar *file_name;
|
gchar *file_name;
|
||||||
@ -968,7 +1128,7 @@ ag_window_export(AgWindow *window, GError **err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ag_window_export_action(GSimpleAction *action,
|
ag_window_export_agc_action(GSimpleAction *action,
|
||||||
GVariant *parameter,
|
GVariant *parameter,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
@ -976,7 +1136,7 @@ ag_window_export_action(GSimpleAction *action,
|
|||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
|
||||||
ag_window_recalculate_chart(window, TRUE);
|
ag_window_recalculate_chart(window, TRUE);
|
||||||
ag_window_export(window, &err);
|
ag_window_export_agc(window, &err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
ag_app_message_dialog(
|
ag_app_message_dialog(
|
||||||
@ -1614,8 +1774,8 @@ ag_window_connection_action(GSimpleAction *action,
|
|||||||
static GActionEntry win_entries[] = {
|
static GActionEntry win_entries[] = {
|
||||||
{ "close", ag_window_close_action, NULL, NULL, NULL },
|
{ "close", ag_window_close_action, NULL, NULL, NULL },
|
||||||
{ "save", ag_window_save_action, NULL, NULL, NULL },
|
{ "save", ag_window_save_action, NULL, NULL, NULL },
|
||||||
{ "export", ag_window_export_action, NULL, NULL, NULL },
|
{ "export-agc", ag_window_export_agc_action, NULL, NULL, NULL },
|
||||||
{ "export-svg", ag_window_export_svg_action, NULL, NULL, NULL },
|
{ "export-image", ag_window_export_image_action, NULL, NULL, NULL },
|
||||||
{ "view-menu", ag_window_view_menu_action, NULL, "false", NULL },
|
{ "view-menu", ag_window_view_menu_action, NULL, "false", NULL },
|
||||||
{ "gear-menu", ag_window_gear_menu_action, NULL, "false", NULL },
|
{ "gear-menu", ag_window_gear_menu_action, NULL, "false", NULL },
|
||||||
{ "change-tab", ag_window_change_tab_action, "s", "'edit'", NULL },
|
{ "change-tab", ag_window_change_tab_action, "s", "'edit'", NULL },
|
||||||
|
@ -24,6 +24,8 @@ GtkBuilder *builder;
|
|||||||
GtkFileFilter *filter_all = NULL;
|
GtkFileFilter *filter_all = NULL;
|
||||||
GtkFileFilter *filter_chart = NULL;
|
GtkFileFilter *filter_chart = NULL;
|
||||||
GtkFileFilter *filter_hor = NULL;
|
GtkFileFilter *filter_hor = NULL;
|
||||||
|
GtkFileFilter *filter_svg = NULL;
|
||||||
|
GtkFileFilter *filter_jpg = NULL;
|
||||||
GtkTreeModel *country_list = NULL;
|
GtkTreeModel *country_list = NULL;
|
||||||
GtkTreeModel *city_list = NULL;
|
GtkTreeModel *city_list = NULL;
|
||||||
GHashTable *xinclude_positions;
|
GHashTable *xinclude_positions;
|
||||||
@ -84,6 +86,18 @@ init_filters(void)
|
|||||||
gtk_file_filter_set_name(filter_hor, _("Placidus charts"));
|
gtk_file_filter_set_name(filter_hor, _("Placidus charts"));
|
||||||
gtk_file_filter_add_pattern(filter_hor, "*.hor");
|
gtk_file_filter_add_pattern(filter_hor, "*.hor");
|
||||||
g_object_ref_sink(filter_hor);
|
g_object_ref_sink(filter_hor);
|
||||||
|
|
||||||
|
filter_svg = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter_svg, _("SVG image"));
|
||||||
|
gtk_file_filter_add_pattern(filter_svg, "*.svg");
|
||||||
|
g_object_ref_sink(filter_svg);
|
||||||
|
|
||||||
|
filter_jpg = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter_jpg, _("JPEG image"));
|
||||||
|
gtk_file_filter_add_pattern(filter_jpg, "*.jpg");
|
||||||
|
gtk_file_filter_add_pattern(filter_jpg, "*.jpe");
|
||||||
|
gtk_file_filter_add_pattern(filter_jpg, "*.jpeg");
|
||||||
|
g_object_ref_sink(filter_jpg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -13,6 +13,8 @@ typedef struct {
|
|||||||
extern GtkFileFilter *filter_all;
|
extern GtkFileFilter *filter_all;
|
||||||
extern GtkFileFilter *filter_chart;
|
extern GtkFileFilter *filter_chart;
|
||||||
extern GtkFileFilter *filter_hor;
|
extern GtkFileFilter *filter_hor;
|
||||||
|
extern GtkFileFilter *filter_svg;
|
||||||
|
extern GtkFileFilter *filter_jpg;
|
||||||
extern GtkTreeModel *country_list;
|
extern GtkTreeModel *country_list;
|
||||||
extern GtkTreeModel *city_list;
|
extern GtkTreeModel *city_list;
|
||||||
extern const GswePlanet used_planets[];
|
extern const GswePlanet used_planets[];
|
||||||
|
@ -39,14 +39,14 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">Export…</attribute>
|
<attribute name="label" translatable="yes">Export…</attribute>
|
||||||
<attribute name="action">win.export</attribute>
|
<attribute name="action">win.export-agc</attribute>
|
||||||
<attribute name="accel"><Primary><Shift>e</attribute>
|
<attribute name="accel"><Primary><Shift>e</attribute>
|
||||||
</item>
|
</item>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">Export as SVG</attribute>
|
<attribute name="label" translatable="yes">Export as image…</attribute>
|
||||||
<attribute name="action">win.export-svg</attribute>
|
<attribute name="action">win.export-image</attribute>
|
||||||
</item>
|
</item>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
@ -134,3 +134,7 @@ line.antiscion {
|
|||||||
stroke: #000000;
|
stroke: #000000;
|
||||||
stroke-dasharray: 20,10;
|
stroke-dasharray: 20,10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#background {
|
||||||
|
fill: #ffffff;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
method="xml"
|
method="xml"
|
||||||
media-type="image/svg+xml"
|
media-type="image/svg+xml"
|
||||||
doctype-public="-//W3C//DTD SVG 1.0//EN"
|
doctype-public="-//W3C//DTD SVG 1.0//EN"
|
||||||
doctype-system="http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"
|
doctype-system="http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
encoding="UTF-8"
|
encoding="UTF-8"
|
||||||
indent="yes"/>
|
indent="yes"/>
|
||||||
@ -69,6 +69,15 @@
|
|||||||
version="1.0">
|
version="1.0">
|
||||||
<xsl:attribute name="width"><xsl:value-of select="$image_size"/></xsl:attribute>
|
<xsl:attribute name="width"><xsl:value-of select="$image_size"/></xsl:attribute>
|
||||||
<xsl:attribute name="height"><xsl:value-of select="$image_size"/></xsl:attribute>
|
<xsl:attribute name="height"><xsl:value-of select="$image_size"/></xsl:attribute>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$rendering='yes'">
|
||||||
|
<style type="text/css">
|
||||||
|
<xi:include href="gres://ui/chart-default.css" parse="text"/>
|
||||||
|
</style>
|
||||||
|
</xsl:when>
|
||||||
|
</xsl:choose>
|
||||||
|
|
||||||
<title>
|
<title>
|
||||||
<xsl:value-of select="concat(
|
<xsl:value-of select="concat(
|
||||||
'Natal chart of ',
|
'Natal chart of ',
|
||||||
@ -116,6 +125,16 @@
|
|||||||
<polygon points="0.0,0.0 7.0,-2.0 5.0,0.0 7.0,2.0" />
|
<polygon points="0.0,0.0 7.0,-2.0 5.0,0.0 7.0,2.0" />
|
||||||
</marker>
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="$rendering='yes'">
|
||||||
|
<rect id="background" x="0" y="0">
|
||||||
|
<xsl:attribute name="width"><xsl:value-of select="$image_size"/></xsl:attribute>
|
||||||
|
<xsl:attribute name="height"><xsl:value-of select="$image_size"/></xsl:attribute>
|
||||||
|
</rect>
|
||||||
|
</xsl:when>
|
||||||
|
</xsl:choose>
|
||||||
|
|
||||||
<g id="chart">
|
<g id="chart">
|
||||||
<xsl:attribute name="transform"><xsl:value-of select="concat('translate(', $image_size div 2, ',', $image_size div 2, ')')" /></xsl:attribute>
|
<xsl:attribute name="transform"><xsl:value-of select="concat('translate(', $image_size div 2, ',', $image_size div 2, ')')" /></xsl:attribute>
|
||||||
<g id="moonless_chart">
|
<g id="moonless_chart">
|
||||||
@ -185,41 +204,41 @@
|
|||||||
<xsl:attribute name="x1"><xsl:value-of select="$image_size * 0.3"/></xsl:attribute>
|
<xsl:attribute name="x1"><xsl:value-of select="$image_size * 0.3"/></xsl:attribute>
|
||||||
<xsl:attribute name="x2"><xsl:value-of select="$image_size * 0.3125"/></xsl:attribute>
|
<xsl:attribute name="x2"><xsl:value-of select="$image_size * 0.3125"/></xsl:attribute>
|
||||||
</line>
|
</line>
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_15" transform="rotate(-10,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_15" transform="rotate(-10,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_25" transform="rotate(-20,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_25" transform="rotate(-20,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_35" transform="rotate(-30,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_35" transform="rotate(-30,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_45" transform="rotate(-40,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_45" transform="rotate(-40,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_55" transform="rotate(-50,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_55" transform="rotate(-50,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_65" transform="rotate(-60,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_65" transform="rotate(-60,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_75" transform="rotate(-70,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_75" transform="rotate(-70,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_85" transform="rotate(-80,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_85" transform="rotate(-80,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_95" transform="rotate(-90,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_95" transform="rotate(-90,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_105" transform="rotate(-100,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_105" transform="rotate(-100,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_115" transform="rotate(-110,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_115" transform="rotate(-110,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_125" transform="rotate(-120,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_125" transform="rotate(-120,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_135" transform="rotate(-130,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_135" transform="rotate(-130,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_145" transform="rotate(-140,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_145" transform="rotate(-140,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_155" transform="rotate(-150,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_155" transform="rotate(-150,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_165" transform="rotate(-160,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_165" transform="rotate(-160,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_175" transform="rotate(-170,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_175" transform="rotate(-170,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_185" transform="rotate(-180,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_185" transform="rotate(-180,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_195" transform="rotate(-190,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_195" transform="rotate(-190,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_205" transform="rotate(-200,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_205" transform="rotate(-200,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_215" transform="rotate(-210,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_215" transform="rotate(-210,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_225" transform="rotate(-220,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_225" transform="rotate(-220,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_235" transform="rotate(-230,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_235" transform="rotate(-230,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_245" transform="rotate(-240,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_245" transform="rotate(-240,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_255" transform="rotate(-250,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_255" transform="rotate(-250,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_265" transform="rotate(-260,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_265" transform="rotate(-260,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_275" transform="rotate(-270,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_275" transform="rotate(-270,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_285" transform="rotate(-280,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_285" transform="rotate(-280,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_295" transform="rotate(-290,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_295" transform="rotate(-290,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_305" transform="rotate(-300,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_305" transform="rotate(-300,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_315" transform="rotate(-310,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_315" transform="rotate(-310,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_325" transform="rotate(-320,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_325" transform="rotate(-320,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_335" transform="rotate(-330,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_335" transform="rotate(-330,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_345" transform="rotate(-340,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_345" transform="rotate(-340,0,0)" class="degree-thin" />
|
||||||
<use x="0" y="0" xlink:href="#deg_5" id="#deg_355" transform="rotate(-350,0,0)" class="degree-thin" />
|
<use x="0" y="0" xlink:href="#deg_5" id="deg_355" transform="rotate(-350,0,0)" class="degree-thin" />
|
||||||
|
|
||||||
<line id="deg_1" y1="0" y2="0" transform="rotate(-1,0,0)" class="degree-thin">
|
<line id="deg_1" y1="0" y2="0" transform="rotate(-1,0,0)" class="degree-thin">
|
||||||
<xsl:attribute name="x1"><xsl:value-of select="$image_size * 0.3"/></xsl:attribute>
|
<xsl:attribute name="x1"><xsl:value-of select="$image_size * 0.3"/></xsl:attribute>
|
||||||
|
Loading…
Reference in New Issue
Block a user