Logo Search packages:      
Sourcecode: tenace version File versions  Download package

print.c

/*
 *  tenace - bridge hand viewer and editor
 *  Copyright (C) 2005-2009 Christoph Berg <cb@df7cb.de>
 *
 *  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.
 */

#include <assert.h>
#include <cairo-pdf.h>
#include <math.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "functions.h"
#include "window_board.h"

static GtkPrintSettings *settings = NULL;

/* standard printing */

#define STRIDE 0.25 * 72
#define L 1.0 * 72
#define C 2.0 * 72
#define R 3.0 * 72
#define T 1.0 * 72
#define M 2.0 * 72
#define B 3.0 * 72

static void
draw_page (GtkPrintOperation *operation,
           GtkPrintContext   *context,
           gint               page_nr,
           gpointer           user_data)

{
      cairo_t *cr;
      cr = gtk_print_context_get_cairo_context (context);

      board *b = CUR_BOARD;

      cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
      cairo_set_font_size (cr, 12);
      cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);

      cairo_move_to (cr, 0.1 * 72, 0.2 * 72);
      cairo_show_text (cr, b->name->str);
      cairo_stroke (cr);

      cairo_move_to (cr, 0.1 * 72, 0.5 * 72);

      cairo_show_text (cr, contract_string(b->level, b->trumps, b->declarer, b->doubled));
      cairo_stroke (cr);

      cairo_move_to (cr, C, T+1*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, north, spade));
      cairo_move_to (cr, C, T+2*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, north, heart));
      cairo_move_to (cr, C, T+3*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, north, diamond));
      cairo_move_to (cr, C, T+4*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, north, club));

      cairo_move_to (cr, L, M+1*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, west, spade));
      cairo_move_to (cr, L, M+2*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, west, heart));
      cairo_move_to (cr, L, M+3*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, west, diamond));
      cairo_move_to (cr, L, M+4*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, west, club));

      cairo_move_to (cr, R, M+1*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, east, spade));
      cairo_move_to (cr, R, M+2*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, east, heart));
      cairo_move_to (cr, R, M+3*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, east, diamond));
      cairo_move_to (cr, R, M+4*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, east, club));

      cairo_move_to (cr, C, B+1*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, south, spade));
      cairo_move_to (cr, C, B+2*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, south, heart));
      cairo_move_to (cr, C, B+3*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, south, diamond));
      cairo_move_to (cr, C, B+4*STRIDE);
      cairo_show_text (cr, hand_suit_string (b, south, club));
      cairo_stroke (cr);

      cairo_move_to (cr, C, M);
      cairo_line_to (cr, C, R);
      cairo_line_to (cr, B, R);
      cairo_line_to (cr, B, C);
      cairo_close_path (cr);
      cairo_stroke (cr);
}

static void
begin_print (GtkPrintOperation *operation,
           GtkPrintContext   *context,
           gpointer           user_data)
{
      gtk_print_operation_set_n_pages (operation, 1);
}

G_MODULE_EXPORT void
on_menu_print_activate (void)
{
      GtkPrintOperation *print;
      GtkPrintOperationResult res;

      print = gtk_print_operation_new ();

      if (settings != NULL)
            gtk_print_operation_set_print_settings (print, settings);

      g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), NULL);
      g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), NULL);

      res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
                  GTK_WINDOW (win->window), NULL);

      if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
      {
            if (settings != NULL)
                  g_object_unref (settings);
            settings = g_object_ref (gtk_print_operation_get_print_settings (print));
      }

      g_object_unref (print);
}

/* magic cards */

static void
arrow (cairo_t *cr, int n, int background, seat dir, double size)
{
#define ARHEAD 0.0
#define ARWIDTH 0.2
      cairo_save (cr);
      cairo_translate (cr, 0.5*size, 0.5*size);

      /* background box */
      if (background) {
            cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
            cairo_move_to (cr, -0.5*size, -0.5*size);
            cairo_line_to (cr, 0.5*size, -0.5*size);
            cairo_line_to (cr, 0.5*size, 0.5*size);
            cairo_line_to (cr, -0.5*size, 0.5*size);
            cairo_close_path (cr);
            cairo_fill (cr);
      }

      /* arrow */
      cairo_save (cr);
      cairo_rotate (cr, ((int)dir - 2) * M_PI_2);

      if (n % 2)
            cairo_set_source_rgb (cr, 0.7, 0.4, 0.4); /* red */
      else
            cairo_set_source_rgb (cr, 0.4, 0.4, 0.7); /* blue */

      cairo_move_to (cr, 0.0, -0.5*size);
      cairo_line_to (cr, 0.5*size, -ARHEAD*size);
      cairo_line_to (cr, ARWIDTH*size, -ARHEAD*size);
      cairo_line_to (cr, ARWIDTH*size, 0.5*size);
      cairo_line_to (cr, -ARWIDTH*size, 0.5*size);
      cairo_line_to (cr, -ARWIDTH*size, -ARHEAD*size);
      cairo_line_to (cr, -0.5*size, -ARHEAD*size);
      cairo_close_path (cr);
      cairo_fill (cr);

      cairo_restore (cr);

      /* board number */
      char buf[8];
      cairo_text_extents_t ext;
      snprintf (buf, sizeof (buf), "%d", n);
      cairo_select_font_face (cr, "Sans",
            CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
      cairo_set_font_size (cr, size / 2.0);
      cairo_text_extents (cr, buf, &ext);

      cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
      cairo_move_to (cr, -ext.width / 2 - ext.x_bearing, ext.height/2);
      cairo_show_text (cr, buf);

      cairo_restore (cr);
}

static void
cairo_clip_rectangle (cairo_t *cr, double x0, double y0, double x1, double y1)
{
      cairo_move_to (cr, x0, y0);
      cairo_line_to (cr, x1, y0);
      cairo_line_to (cr, x1, y1);
      cairo_line_to (cr, x0, y1);
      cairo_close_path (cr);
      cairo_clip (cr);
}

/*  row_height
 0**************** border
 *xxx   xxx   xxx* arrow_size
 *xxx   xxx   xxx*
 *   xxx   xxx   *
 *   xxx   xxx   * col_width
 * arrow_columns *
 *    TEXTSEP    *
 *               *
 *               *
 *               *
 *               *
 *****************/

#define TEXTSEP 20.0

00229 static struct magic_config_t {
      /* custom print settings */
      /* widgets */
      GtkSpinButton* magic_columns, * magic_rows;
      GtkToggleButton* magic_no_header, * magic_page_header, * magic_suit_header;
      GtkToggleButton* magic_mark_cards;
      GtkSpinButton* magic_from, * magic_to;
      GtkSpinButton* magic_border;
      GtkSpinButton* magic_horiz_margin, * magic_vert_margin;
      GtkSpinButton* magic_horiz_sep, * magic_vert_sep;
      /* data */
      int columns, rows;
      int header;
      int mark_cards;
      int from, to;
      double border;
      double horiz_margin, vert_margin;
      double horiz_sep, vert_sep;
      /* metrics */
      double col_width, row_height;
      int arrow_columns;
      double arrow_size;
} mc;

static void
magic_card_half (cairo_t *cr, window_board_t *win, card c)
{
      int n_boards = mc.to - mc.from + 1;
      int n;
      for (n = 0; n < n_boards; n++) {
            cairo_save (cr);
            int col = n % mc.arrow_columns;
            int row = n / mc.arrow_columns;
            cairo_translate (cr, col * mc.arrow_size + mc.border,
                        row * mc.arrow_size + mc.border);

            board *b = win->boards[n + mc.from - 1];
            arrow (cr, n + mc.from, (col + row) % 2, b->dealt_cards[c], mc.arrow_size);
            cairo_restore (cr);

            /* draw title */
            cairo_text_extents_t ext;
            cairo_save (cr);

            cairo_select_font_face (cr, "Sans",
                  CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
            cairo_set_font_size (cr, 8.0);
            cairo_clip_rectangle (cr, mc.border, mc.border,
                        mc.row_height - mc.border, mc.col_width - mc.border);
            cairo_move_to (cr, mc.border, 0.5 * mc.col_width - 2.0);
            cairo_show_text (cr, win->title);
            cairo_text_extents (cr, win->title, &ext);

            /* clip subtitle to card width - title width */
            cairo_clip_rectangle (cr, mc.border, mc.border,
                  mc.row_height - ext.x_advance - mc.border - 4.0, mc.col_width - mc.border);
            cairo_move_to (cr, mc.border, 0.5 * mc.col_width + 8.0);
            cairo_show_text (cr, win->subtitle);
            cairo_stroke (cr);

            cairo_restore (cr);
      }
}

static void
magic_card (cairo_t *cr, window_board_t *win, card c)
{
      /* upper part */
      magic_card_half (cr, win, c);
      /* lower part */
      cairo_save (cr);
      cairo_translate (cr, mc.row_height, mc.col_width);
      cairo_rotate (cr, M_PI);
      magic_card_half (cr, win, c);
      cairo_restore (cr);
}

static void
magic_draw_page (GtkPrintOperation *operation,
           GtkPrintContext   *context,
           gint               page_nr,
           gpointer           user_data)

{
      cairo_t *cr;
      cr = gtk_print_context_get_cairo_context (context);

      static int cc, print_head;
      if (page_nr == 0) { /* restart printing */
            cc = 51;
            print_head = (mc.header > 0);
      }
      if (mc.header == 1) /* new page */
            print_head = 1;

      int r, c;
      for (c = 0; c < mc.columns; c++) {
            for (r = 0; r < mc.rows && cc >= 0; r++) {
                  if (print_head && mc.header == 1) { /* page heading */
                        cairo_set_font_size (cr, 10.0);

                        int r1, c1;
                        int cc1 = cc;
                        for (c1 = 0; c1 < mc.columns; c1++) {
                              for (r1 = 0; r1 < mc.rows; r1++) {
                                    if (c1 == 0 && r1 == 0 || cc1 < 0)
                                          continue;
                                    cairo_move_to (cr, c1 * (mc.col_width - 2.0*mc.border) / mc.columns + mc.border + mc.horiz_margin,
                                                r1 * (mc.row_height - 2.0*mc.border) / mc.rows + mc.border + mc.vert_margin + 10.0);
                                    cairo_select_font_face (cr, "Symbol",
                                          CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
                                    cairo_show_text (cr, trump_str[SUIT(cc1)]);
                                    cairo_select_font_face (cr, "Sans",
                                          CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
                                    cairo_show_text (cr, rank_string (RANK(cc1)));
                                    cc1--;
                              }
                        }
                        print_head = 0;
                        continue;
                  }
                  if (print_head && mc.header == 2) { /* suit heading */
                        cairo_move_to (cr,
                              (c + 0.5) * mc.col_width + c * mc.horiz_sep + mc.horiz_margin - 15.0,
                              (r + 0.5) * mc.row_height + r * mc.vert_sep + mc.vert_margin + 30.0);
                        cairo_select_font_face (cr, "Symbol",
                              CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
                        cairo_set_font_size (cr, 40.0);
                        cairo_show_text (cr, trump_str[SUIT(cc)]);
                        print_head = 0;
                        continue;
                  }

                  cairo_save (cr);
                  cairo_translate (cr, /* lower left point */
                        c * mc.col_width + c * mc.horiz_sep + mc.horiz_margin,
                        (r + 1) * mc.row_height + r * mc.vert_sep + mc.vert_margin);
                  cairo_rotate (cr, -M_PI_2); /* rotate left */
                  magic_card (cr, win, cc);

                  if (mc.mark_cards) {
                        cairo_move_to (cr, 6, -2);
                        cairo_set_font_size (cr, 10);
                        cairo_select_font_face (cr, "Symbol",
                              CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
                        cairo_show_text (cr, trump_str[SUIT(cc)]);
                        cairo_select_font_face (cr, "Sans",
                              CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
                        cairo_show_text (cr, _(rank_string (RANK(cc))));
                  }

                  cairo_restore (cr);
                  
                  cc--; /* next card */
                  if (RANK(cc) == cardA && mc.header == 2)
                        print_head = 1;
            }
      }
}

static char *magic_xml_files[] = {
      "magic.ui",
#ifndef _WIN32
      PACKAGE_DATA_DIR "/" PACKAGE "/magic.ui",
#endif
};

#define get_magic_widget(x) (GTK_WIDGET (gtk_builder_get_object (builder, (x))))

static GObject *
magic_custom_create (GtkPrintOperation *operation,
           gpointer           user_data)
{
      char *xml_file = NULL;
      int i;
      for (i = 0; i < sizeof (magic_xml_files); i++) {
            struct stat buf;
            if (stat (magic_xml_files[i], &buf) != -1) {
                  xml_file = magic_xml_files[i];
                  break;
            }
      }
      if (! xml_file) {
            fprintf (stderr, _("Could not find interface definition file: %s"), "magic.ui");
            exit (1);
      }

      GtkBuilder *builder;
      GError *error = NULL;
      builder = gtk_builder_new ();
      if (! gtk_builder_add_from_file (builder, xml_file, &error)) {
            g_warning (_("Could not load builder file: %s"), error->message);
            g_error_free (error);
            exit (1);
      }

      gtk_builder_connect_signals (builder, NULL);

      GtkWidget *table = get_magic_widget ("magic_options_table");
      assert (table);
      mc.magic_rows = GTK_SPIN_BUTTON (get_magic_widget ("magic_rows"));
      mc.magic_columns = GTK_SPIN_BUTTON (get_magic_widget ("magic_columns"));
      mc.magic_no_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_no_header"));
      mc.magic_page_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_page_header"));
      mc.magic_suit_header = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_suit_header"));
      mc.magic_mark_cards = GTK_TOGGLE_BUTTON (get_magic_widget ("magic_mark_cards"));
      mc.magic_from = GTK_SPIN_BUTTON (get_magic_widget ("magic_from"));
      gtk_spin_button_set_range (mc.magic_from, 1, win->n_boards);
      mc.magic_to = GTK_SPIN_BUTTON (get_magic_widget ("magic_to"));
      gtk_spin_button_set_range (mc.magic_to, 1, win->n_boards);
      gtk_spin_button_set_value (mc.magic_to, win->n_boards);
      mc.magic_border = GTK_SPIN_BUTTON (get_magic_widget ("magic_border"));
      mc.magic_horiz_margin = GTK_SPIN_BUTTON (get_magic_widget ("magic_horiz_margin"));
      mc.magic_vert_margin = GTK_SPIN_BUTTON (get_magic_widget ("magic_vert_margin"));
      mc.magic_horiz_sep = GTK_SPIN_BUTTON (get_magic_widget ("magic_horiz_sep"));
      mc.magic_vert_sep = GTK_SPIN_BUTTON (get_magic_widget ("magic_vert_sep"));

      g_object_ref (table);
      g_object_unref (builder);
      return (GObject *) table;
}

#define PTMM (72.0 / 25.4)

static void
magic_custom_apply (GtkPrintOperation *operation, GtkWidget *table, gpointer user_data)
{
      mc.columns = gtk_spin_button_get_value_as_int (mc.magic_columns);
      mc.rows = gtk_spin_button_get_value_as_int (mc.magic_rows);
      mc.header = gtk_toggle_button_get_active (mc.magic_no_header) ? 0 :
                        gtk_toggle_button_get_active (mc.magic_page_header) ? 1 : 2;
      mc.mark_cards = gtk_toggle_button_get_active (mc.magic_mark_cards);
      mc.from = gtk_spin_button_get_value_as_int (mc.magic_from);
      mc.to = gtk_spin_button_get_value_as_int (mc.magic_to);
      if (mc.to < mc.from)
            mc.to = mc.from;
      mc.border = PTMM * gtk_spin_button_get_value_as_float (mc.magic_border);
      mc.horiz_margin = PTMM * gtk_spin_button_get_value_as_float (mc.magic_horiz_margin);
      mc.vert_margin = PTMM * gtk_spin_button_get_value_as_float (mc.magic_vert_margin);
      mc.horiz_sep = PTMM * gtk_spin_button_get_value_as_float (mc.magic_horiz_sep);
      mc.vert_sep = PTMM * gtk_spin_button_get_value_as_float (mc.magic_vert_sep);
}

static void
magic_begin_print (GtkPrintOperation *operation,
           GtkPrintContext   *context,
           gpointer           user_data)
{
      if (mc.header == 0) {
            gtk_print_operation_set_n_pages
                  (operation, ceil (52.0 / (mc.columns * mc.rows)));
      } else if (mc.header == 1) {
            gtk_print_operation_set_n_pages
                  (operation, ceil (52.0 / (mc.columns * mc.rows -
                                      (mc.columns == 1 && mc.columns == 1 ? 0 : 1))));
      } else {
            gtk_print_operation_set_n_pages
                  (operation, ceil (56.0 / (mc.columns * mc.rows)));
      }
      gtk_print_operation_set_use_full_page (operation, TRUE);
      gtk_print_operation_set_show_progress (operation, TRUE);
      //gtk_print_operation_set_export_filename (operation, "foo");
      mc.col_width = (gtk_print_context_get_width (context) - 2 * mc.horiz_margin
                  - (mc.columns - 1) * mc.horiz_sep) / mc.columns;
      mc.row_height = (gtk_print_context_get_height (context) - 2 * mc.vert_margin
                  - (mc.rows - 1) * mc.vert_sep) / mc.rows;

      /* find fitting number of arrow columns and corresponding arrow size */
      int n_boards = mc.to - mc.from + 1;
      mc.arrow_columns = 0;
      do {
            mc.arrow_columns++;
            mc.arrow_size = (mc.row_height - 2*mc.border) / mc.arrow_columns;
            int arrow_rows = ceil ((double) n_boards / mc.arrow_columns);
            if (mc.arrow_size * arrow_rows <= mc.col_width/2.0 - mc.border - TEXTSEP/2.0)
                  break;
      } while (mc.arrow_columns <= n_boards);
}

G_MODULE_EXPORT void
on_menu_file_magic_activate (void)
{
      GtkPrintOperation *print;
      GtkPrintOperationResult res;

      print = gtk_print_operation_new ();

      if (settings != NULL) 
            gtk_print_operation_set_print_settings (print, settings);

      gtk_print_operation_set_custom_tab_label (print, _("Labels"));

      g_signal_connect (print, "begin_print", G_CALLBACK (magic_begin_print), NULL);
      g_signal_connect (print, "draw_page", G_CALLBACK (magic_draw_page), NULL);
      g_signal_connect (print, "create-custom-widget", G_CALLBACK (magic_custom_create), NULL);
      g_signal_connect (print, "custom-widget-apply", G_CALLBACK (magic_custom_apply), NULL);

      res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
                  GTK_WINDOW (win->window), NULL);

      if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
      {
            if (settings != NULL)
                  g_object_unref (settings);
            settings = g_object_ref (gtk_print_operation_get_print_settings (print));
      }

      g_object_unref (print);
}


Generated by  Doxygen 1.6.0   Back to index