adjustment.c 6.63 KB
Newer Older
1 2 3 4
/* See LICENSE file for license and copyright information */

#include "adjustment.h"
#include "utils.h"
5 6 7 8
#include <math.h>


double
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
9 10 11
page_calc_height_width(zathura_document_t* document, double height,
                       double width, unsigned int* page_height,
                       unsigned int* page_width, bool rotate)
12 13 14
{
  g_return_val_if_fail(document != NULL && page_height != NULL && page_width != NULL, 0.0);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
15
  double scale = zathura_document_get_scale(document);
16 17 18 19 20 21 22 23

  /* If monitor DPI information is available, use it to match 100% zoom to physical page size */
  double dpi = zathura_document_get_viewport_dpi(document);
  if (fabs(dpi) != DBL_EPSILON) {
    /* real scale = 1 means: 1 point = 1 pixel, and there are 72 points in one inch */
    scale *= dpi / 72.0;
  }

Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
24
  if (rotate == true && zathura_document_get_rotation(document) % 180 != 0) {
25 26
    *page_width  = round(height * scale);
    *page_height = round(width  * scale);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
27
    scale = MAX(*page_width / height, *page_height / width);
28 29 30
  } else {
    *page_width  = round(width  * scale);
    *page_height = round(height * scale);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
31
    scale = MAX(*page_width / width, *page_height / height);
32 33
  }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
34
  return scale;
35 36 37
}

void
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
38 39 40
page_calc_position(zathura_document_t* document, double x, double y, double* xn,
                   double* yn)
{
41 42
  g_return_if_fail(document != NULL && xn != NULL && yn != NULL);

Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
43
  const unsigned int rot = zathura_document_get_rotation(document);
44 45 46
  if (rot == 90) {
    *xn = 1 - y;
    *yn = x;
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
47
  } else if (rot == 180) {
48 49 50 51 52 53 54 55 56 57 58 59
    *xn = 1 - x;
    *yn = 1 - y;
  } else if (rot == 270) {
    *xn = y;
    *yn = 1 - x;
  } else {
    *xn = x;
    *yn = y;
  }
}

unsigned int
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
60 61 62
position_to_page_number(zathura_document_t* document, double pos_x,
                        double pos_y)
{
63 64 65 66 67 68 69 70 71 72 73
  g_return_val_if_fail(document != NULL, 0);

  unsigned int doc_width, doc_height;
  zathura_document_get_document_size(document, &doc_height, &doc_width);

  unsigned int cell_width, cell_height;
  zathura_document_get_cell_size(document, &cell_height, &cell_width);

  unsigned int c0   = zathura_document_get_first_page_column(document);
  unsigned int npag = zathura_document_get_number_of_pages(document);
  unsigned int ncol = zathura_document_get_pages_per_row(document);
74
  unsigned int nrow = 0;
75 76
  unsigned int pad  = zathura_document_get_page_padding(document);

77 78 79 80 81 82 83 84
  if (c0 == 1) {
    /* There is no offset, so this is easy. */
    nrow = (npag + ncol - 1) / ncol;
  } else {
    /* If there is a offset, we handle the first row extra. */
    nrow = 1 + (npag - (ncol - c0 - 1) + (ncol - 1)) / ncol;
  }

85 86 87
  unsigned int col = floor(pos_x * (double)doc_width  / (double)(cell_width + pad));
  unsigned int row = floor(pos_y * (double)doc_height / (double)(cell_height + pad));

88 89 90 91
  unsigned int page = ncol * (row % nrow) + (col % ncol);
  if (page < c0 - 1) {
    return 0;
  } else {
92
    return MIN(page - (c0 - 1), npag - 1);
93
  }
94 95 96 97 98
}


void
page_number_to_position(zathura_document_t* document, unsigned int page_number,
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
99 100 101
                        double xalign, double yalign, double* pos_x,
                        double* pos_y)
{
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  g_return_if_fail(document != NULL);

  unsigned int c0   = zathura_document_get_first_page_column(document);
  unsigned int npag = zathura_document_get_number_of_pages(document);
  unsigned int ncol = zathura_document_get_pages_per_row(document);
  unsigned int nrow = (npag + c0 - 1 + ncol - 1) / ncol;   /* number of rows */

  /* row and column for page_number indexed from 0 */
  unsigned int row  = (page_number + c0 - 1) / ncol;
  unsigned int col  = (page_number + c0 - 1) % ncol;

  /* sizes of page cell, viewport and document */
  unsigned int cell_height = 0, cell_width = 0;
  zathura_document_get_cell_size(document, &cell_height, &cell_width);

  unsigned int view_height = 0, view_width = 0;
  zathura_document_get_viewport_size(document, &view_height, &view_width);

  unsigned int doc_height = 0, doc_width = 0;
  zathura_document_get_document_size(document, &doc_height, &doc_width);

  /* compute the shift to align to the viewport. If the page fits to viewport, just center it. */
  double shift_x = 0.5, shift_y = 0.5;
  if (cell_width > view_width) {
    shift_x = 0.5 + (xalign - 0.5) * ((double)cell_width - (double)view_width) / (double)cell_width;
  }

  if (cell_height > view_height) {
    shift_y = 0.5 + (yalign - 0.5) * ((double)cell_height - (double)view_height) / (double)cell_height;
  }

  /* compute the position */
  *pos_x = ((double)col + shift_x) / (double)ncol;
  *pos_y = ((double)row + shift_y) / (double)nrow;
}


bool
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
140 141
page_is_visible(zathura_document_t *document, unsigned int page_number)
{
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
  g_return_val_if_fail(document != NULL, false);

  /* position at the center of the viewport */
  double pos_x = zathura_document_get_position_x(document);
  double pos_y = zathura_document_get_position_y(document);

  /* get the center of page page_number */
  double page_x, page_y;
  page_number_to_position(document, page_number, 0.5, 0.5, &page_x, &page_y);

  unsigned int cell_width, cell_height;
  zathura_document_get_cell_size(document, &cell_height, &cell_width);

  unsigned int doc_width, doc_height;
  zathura_document_get_document_size(document, &doc_height, &doc_width);

  unsigned int view_width, view_height;
  zathura_document_get_viewport_size(document, &view_height, &view_width);

  return ( fabs(pos_x - page_x) < 0.5 * (double)(view_width + cell_width) / (double)doc_width &&
           fabs(pos_y - page_y) < 0.5 * (double)(view_height + cell_height) / (double)doc_height);
}
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

void
zathura_adjustment_set_value(GtkAdjustment* adjustment, gdouble value)
{
  gtk_adjustment_set_value(adjustment,
                           MAX(gtk_adjustment_get_lower(adjustment),
                               MIN(gtk_adjustment_get_upper(adjustment) -
                                   gtk_adjustment_get_page_size(adjustment),
                                   value)));
}

gdouble
zathura_adjustment_get_ratio(GtkAdjustment* adjustment)
{
  gdouble lower     = gtk_adjustment_get_lower(adjustment);
  gdouble upper     = gtk_adjustment_get_upper(adjustment);
  gdouble page_size = gtk_adjustment_get_page_size(adjustment);
  gdouble value     = gtk_adjustment_get_value(adjustment);

  return (value - lower + page_size / 2.0) / (upper - lower);
}

void
zathura_adjustment_set_value_from_ratio(GtkAdjustment* adjustment,
                                        gdouble ratio)
{
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
190
  if (ratio == 0.0) {
191
    return;
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
192
  }
193 194 195 196 197 198 199 200 201

  gdouble lower = gtk_adjustment_get_lower(adjustment);
  gdouble upper = gtk_adjustment_get_upper(adjustment);
  gdouble page_size = gtk_adjustment_get_page_size(adjustment);

  gdouble value = (upper - lower) * ratio + lower - page_size / 2.0;

  zathura_adjustment_set_value(adjustment, value);
}