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([WEBKIT], [webkit2gtk-4.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])
|
||||
|
||||
LIBGD_INIT([
|
||||
|
@ -32,7 +32,7 @@ AM_CPPFLAGS = -DG_LOG_DOMAIN=\"Astrognome\" -DLOCALEDIR=\"$(localedir)\" -DPKGDA
|
||||
bin_PROGRAMS = astrognome
|
||||
|
||||
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_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 <math.h>
|
||||
#include <string.h>
|
||||
#include <librsvg/rsvg.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "astrognome.h"
|
||||
@ -41,6 +44,10 @@ typedef enum {
|
||||
XML_CONVERT_INT
|
||||
} 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_TYPE_WITH_PRIVATE(AgChart, ag_chart, GSWE_TYPE_MOMENT);
|
||||
@ -1388,7 +1395,11 @@ ag_chart_sort_planets_by_position(GswePlanetData *planet1,
|
||||
}
|
||||
|
||||
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),
|
||||
xslt_doc,
|
||||
@ -1401,7 +1412,8 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err)
|
||||
antiscia_node = NULL,
|
||||
node = NULL;
|
||||
gchar *value,
|
||||
*save_content = NULL;
|
||||
*save_content = NULL,
|
||||
**params;
|
||||
const gchar *xslt_content;
|
||||
GList *houses,
|
||||
*house,
|
||||
@ -1705,15 +1717,22 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err)
|
||||
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
|
||||
// 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
|
||||
// C locale until the SVG is generated.
|
||||
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);
|
||||
xsltFreeStylesheet(xslt_proc);
|
||||
xmlFreeDoc(doc);
|
||||
g_free(params);
|
||||
|
||||
// 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;
|
||||
gsize length;
|
||||
|
||||
if ((svg = ag_chart_create_svg(chart, &length, err)) == NULL) {
|
||||
if ((svg = ag_chart_create_svg(chart, &length, TRUE, err)) == NULL) {
|
||||
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
|
||||
ag_chart_set_note(AgChart *chart, const gchar *note)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ typedef enum {
|
||||
AG_CHART_ERROR_NOT_IMPLEMENTED,
|
||||
AG_CHART_ERROR_INVALID_PLAC_FILE,
|
||||
AG_CHART_ERROR_UNSUPPORTED_PLAC_FILE,
|
||||
AG_CHART_ERROR_RENDERING_ERROR,
|
||||
} AgChartError;
|
||||
|
||||
#define AG_TYPE_CHART (ag_chart_get_type())
|
||||
@ -43,6 +44,8 @@ struct _AgChartClass {
|
||||
GsweMomentClass parent_class;
|
||||
};
|
||||
|
||||
typedef void (*AgChartSaveImageFunc)(AgChart *, GFile *, GError **);
|
||||
|
||||
GType ag_chart_get_type(void) G_GNUC_CONST;
|
||||
|
||||
AgChart *ag_chart_new_full(GsweTimestamp *timestamp,
|
||||
@ -67,6 +70,10 @@ void 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);
|
||||
|
||||
void ag_chart_set_name(AgChart *chart,
|
||||
const gchar *name);
|
||||
|
||||
@ -82,9 +89,10 @@ void ag_chart_set_city(AgChart *chart,
|
||||
|
||||
const gchar *ag_chart_get_city(AgChart *chart);
|
||||
|
||||
gchar *ag_chart_create_svg(AgChart *chart,
|
||||
gsize *length,
|
||||
GError **err);
|
||||
gchar *ag_chart_create_svg(AgChart *chart,
|
||||
gsize *length,
|
||||
gboolean rendering,
|
||||
GError **err);
|
||||
|
||||
GList *ag_chart_get_planets(AgChart *chart);
|
||||
|
||||
|
230
src/ag-window.c
230
src/ag-window.c
@ -496,6 +496,7 @@ ag_window_redraw_chart(AgWindow *window)
|
||||
gchar *svg_content = ag_chart_create_svg(
|
||||
priv->chart,
|
||||
&length,
|
||||
FALSE,
|
||||
&err
|
||||
);
|
||||
|
||||
@ -808,12 +809,12 @@ ag_window_recalculate_chart(AgWindow *window, gboolean set_everything)
|
||||
}
|
||||
|
||||
static void
|
||||
ag_window_export_svg(AgWindow *window, GError **err)
|
||||
ag_window_export_image(AgWindow *window, GError **err)
|
||||
{
|
||||
const gchar *name;
|
||||
gchar *file_name;
|
||||
GtkWidget *fs;
|
||||
gint response;
|
||||
GError *local_err = NULL;
|
||||
AgWindowPrivate *priv = ag_window_get_instance_private(window);
|
||||
|
||||
ag_window_recalculate_chart(window, TRUE);
|
||||
@ -851,41 +852,200 @@ ag_window_export_svg(AgWindow *window, GError **err)
|
||||
return;
|
||||
}
|
||||
|
||||
file_name = g_strdup_printf("%s.svg", name);
|
||||
|
||||
fs = gtk_file_chooser_dialog_new(_("Export Chart as SVG"),
|
||||
GTK_WINDOW(window),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_Save"), GTK_RESPONSE_ACCEPT,
|
||||
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_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), FALSE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), TRUE);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), file_name);
|
||||
g_free(file_name);
|
||||
// Due to file name modifying later (depending on the file type selection),
|
||||
// we must do this manually
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), FALSE);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), name);
|
||||
|
||||
response = gtk_dialog_run(GTK_DIALOG(fs));
|
||||
gtk_widget_hide(fs);
|
||||
while (TRUE) {
|
||||
response = gtk_dialog_run(GTK_DIALOG(fs));
|
||||
gtk_widget_hide(fs);
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(fs));
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
ag_window_export_svg_action(GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
ag_window_export_image_action(GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer 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) {
|
||||
ag_app_message_dialog(
|
||||
@ -898,7 +1058,7 @@ ag_window_export_svg_action(GSimpleAction *action,
|
||||
}
|
||||
|
||||
static void
|
||||
ag_window_export(AgWindow *window, GError **err)
|
||||
ag_window_export_agc(AgWindow *window, GError **err)
|
||||
{
|
||||
const gchar *name;
|
||||
gchar *file_name;
|
||||
@ -968,15 +1128,15 @@ ag_window_export(AgWindow *window, GError **err)
|
||||
}
|
||||
|
||||
static void
|
||||
ag_window_export_action(GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
ag_window_export_agc_action(GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
AgWindow *window = AG_WINDOW(user_data);
|
||||
GError *err = NULL;
|
||||
|
||||
ag_window_recalculate_chart(window, TRUE);
|
||||
ag_window_export(window, &err);
|
||||
ag_window_export_agc(window, &err);
|
||||
|
||||
if (err) {
|
||||
ag_app_message_dialog(
|
||||
@ -1612,19 +1772,19 @@ ag_window_connection_action(GSimpleAction *action,
|
||||
}
|
||||
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "close", ag_window_close_action, NULL, NULL, NULL },
|
||||
{ "save", ag_window_save_action, NULL, NULL, NULL },
|
||||
{ "export", ag_window_export_action, NULL, NULL, NULL },
|
||||
{ "export-svg", ag_window_export_svg_action, NULL, NULL, NULL },
|
||||
{ "view-menu", ag_window_view_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 },
|
||||
{ "new-chart", ag_window_new_chart_action, NULL, NULL, NULL },
|
||||
{ "back", ag_window_back_action, NULL, NULL, NULL },
|
||||
{ "refresh", ag_window_refresh_action, NULL, NULL, NULL },
|
||||
{ "selection", ag_window_selection_mode_action, NULL, "false", NULL },
|
||||
{ "delete", ag_window_delete_action, NULL, NULL, NULL },
|
||||
{ "connection", ag_window_connection_action, "s", "'aspects'", NULL },
|
||||
{ "close", ag_window_close_action, NULL, NULL, NULL },
|
||||
{ "save", ag_window_save_action, NULL, NULL, NULL },
|
||||
{ "export-agc", ag_window_export_agc_action, NULL, NULL, NULL },
|
||||
{ "export-image", ag_window_export_image_action, NULL, NULL, NULL },
|
||||
{ "view-menu", ag_window_view_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 },
|
||||
{ "new-chart", ag_window_new_chart_action, NULL, NULL, NULL },
|
||||
{ "back", ag_window_back_action, NULL, NULL, NULL },
|
||||
{ "refresh", ag_window_refresh_action, NULL, NULL, NULL },
|
||||
{ "selection", ag_window_selection_mode_action, NULL, "false", NULL },
|
||||
{ "delete", ag_window_delete_action, NULL, NULL, NULL },
|
||||
{ "connection", ag_window_connection_action, "s", "'aspects'", NULL },
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -24,6 +24,8 @@ GtkBuilder *builder;
|
||||
GtkFileFilter *filter_all = NULL;
|
||||
GtkFileFilter *filter_chart = NULL;
|
||||
GtkFileFilter *filter_hor = NULL;
|
||||
GtkFileFilter *filter_svg = NULL;
|
||||
GtkFileFilter *filter_jpg = NULL;
|
||||
GtkTreeModel *country_list = NULL;
|
||||
GtkTreeModel *city_list = NULL;
|
||||
GHashTable *xinclude_positions;
|
||||
@ -84,6 +86,18 @@ init_filters(void)
|
||||
gtk_file_filter_set_name(filter_hor, _("Placidus charts"));
|
||||
gtk_file_filter_add_pattern(filter_hor, "*.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
|
||||
|
@ -13,6 +13,8 @@ typedef struct {
|
||||
extern GtkFileFilter *filter_all;
|
||||
extern GtkFileFilter *filter_chart;
|
||||
extern GtkFileFilter *filter_hor;
|
||||
extern GtkFileFilter *filter_svg;
|
||||
extern GtkFileFilter *filter_jpg;
|
||||
extern GtkTreeModel *country_list;
|
||||
extern GtkTreeModel *city_list;
|
||||
extern const GswePlanet used_planets[];
|
||||
|
@ -39,14 +39,14 @@
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Export as SVG</attribute>
|
||||
<attribute name="action">win.export-svg</attribute>
|
||||
<attribute name="label" translatable="yes">Export as image…</attribute>
|
||||
<attribute name="action">win.export-image</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -134,3 +134,7 @@ line.antiscion {
|
||||
stroke: #000000;
|
||||
stroke-dasharray: 20,10;
|
||||
}
|
||||
|
||||
#background {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
method="xml"
|
||||
media-type="image/svg+xml"
|
||||
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"
|
||||
encoding="UTF-8"
|
||||
indent="yes"/>
|
||||
@ -69,6 +69,15 @@
|
||||
version="1.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>
|
||||
|
||||
<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>
|
||||
<xsl:value-of select="concat(
|
||||
'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" />
|
||||
</marker>
|
||||
</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">
|
||||
<xsl:attribute name="transform"><xsl:value-of select="concat('translate(', $image_size div 2, ',', $image_size div 2, ')')" /></xsl:attribute>
|
||||
<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="x2"><xsl:value-of select="$image_size * 0.3125"/></xsl:attribute>
|
||||
</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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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">
|
||||
<xsl:attribute name="x1"><xsl:value-of select="$image_size * 0.3"/></xsl:attribute>
|
||||
|
Loading…
Reference in New Issue
Block a user