Contents of paper-tape/visualisator/lochstreifen.c

  1. /**
  2.  * The Paper Tape Project -- Visualisation sub project
  3.  * lochstreifen.c - Painting Paper Tapes according to ECMA-10, with cairographics.
  4.  * $Id$
  5.  *
  6.  * This is a rewrite from the famous Cairo paper tape drawing routines. This
  7.  * c file implements a (simple) object called "LOCHSTREIFEN".
  8.  *
  9.  *
  10.  *
  11.  *
  12.  *
  13.  * (c) Copyright 2007, 2008 Sven Köppel
  14.  *
  15.  * This program is free software; you can redistribute
  16.  * it and/or modify it under the terms of the GNU General
  17.  * Public License as published by the Free Software
  18.  * Foundation; either version 3 of the License, or (at
  19.  * your option) any later version.
  20.  *
  21.  * This program is distributed in the hope that it will
  22.  * be useful, but WITHOUT ANY WARRANTY; without even the
  23.  * implied warranty of MERCHANTABILITY or FITNESS FOR A
  24.  * PARTICULAR PURPOSE. See the GNU General Public License
  25.  * for more details.
  26.  *
  27.  * You should have received a copy of the GNU General
  28.  * Public License along with this program; if not, see
  29.  * http://www.gnu.org/licenses/
  30.  *
  31.  **/
  32.  
  33. #include <math.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include "lochstreifen.h"
  38.  
  39. /**
  40.  * Create a new LOCHSTREIFEN object and return it. This is a quite light
  41.  * object system implementation, as you get a reference to the object.
  42.  * You are not supposed to manipulate the elements of the LOCHSTREIFEN
  43.  * structure directly.
  44.  *
  45.  * Btw, the german word "LOCHSTREIFEN" only means "PAPER TAPE".
  46.  *
  47.  **/
  48. LOCHSTREIFEN *lochstreifen_new() {
  49. LOCHSTREIFEN *l = malloc (sizeof(LOCHSTREIFEN));
  50.  
  51. // set default values:
  52. l->data_length = 0;
  53. l->data = NULL;
  54. l->highlight_region_start = 0;
  55. l->highlight_region_end = 0;
  56. l->highlight_region_color = NULL;
  57. l->highlight_row_number = 0;
  58. l->highlight_row_color = NULL;
  59. l->highlight_bit_row = 0;
  60. l->highlight_bit_track = 0;
  61. l->highlight_bit_color = NULL;
  62. l->clip = NULL;
  63. l->outer_background_color = LOCHSTREIFEN_DEFAULT_OUTER_BACKGROUND_COLOR;
  64. l->papertape_background_color = LOCHSTREIFEN_DEFAULT_PAPERTAPE_BACKGROUND_COLOR;
  65. l->one_code_hole_color = LOCHSTREIFEN_DEFAULT_ONE_CODE_HOLE_COLOR;
  66. l->zero_code_hole_color = LOCHSTREIFEN_DEFAULT_ZERO_CODE_HOLE_COLOR;
  67. l->feed_hole_color = LOCHSTREIFEN_DEFAULT_FEED_HOLE_COLOR;
  68. cairo_matrix_init(&l->matrix, 1, 0, 0, 1, 0, 0); // default = 1:1 original
  69. l->matrix_inverse = l->matrix;
  70. l->row_callback = NULL;
  71. l->row_callback_user_data = NULL;
  72.  
  73. return l;
  74. }
  75.  
  76. /**
  77.  * Copy everything from the LOCHSTREIFEN template, except the data. They
  78.  * won't be copied, just set, because LOCHSTREIFEN doesn't manage your
  79.  * data. If you want to copy them, call something like
  80.  * LOCHSTREIFEN* copy = lochstreifen_copy(old);
  81.  * byte_t* new_data = malloc(old->data_length);
  82.  * memcpy(new_data, old->data, old->data_length);
  83.  * lochstreifen_set_data(copy, old->data_length, new_data);
  84.  **/
  85. LOCHSTREIFEN* lochstreifen_copy(const LOCHSTREIFEN* template) {
  86. LOCHSTREIFEN *l = malloc (sizeof(LOCHSTREIFEN));
  87. #define COPY_RGBA_PATTERN(name) { double r,g,b,a; \
  88. if(!cairo_pattern_get_rgba(template->name, &r, &g, &b, &a)) \
  89. l->name = cairo_pattern_create_rgba(r,g,b,a); }
  90.  
  91. // make it quite verbose ;-)
  92. l->data_length = template->data_length;
  93. l->data = template->data;
  94. l->highlight_region_start = template->highlight_region_start;
  95. l->highlight_region_end = template->highlight_region_end;
  96. COPY_RGBA_PATTERN(highlight_region_color);
  97. l->highlight_row_number = template->highlight_row_number;
  98. COPY_RGBA_PATTERN(highlight_row_color);
  99. l->highlight_bit_row = template->highlight_bit_row;
  100. l->highlight_bit_track = template->highlight_bit_track;
  101. COPY_RGBA_PATTERN(highlight_bit_color);
  102. l->clip = malloc(sizeof(cairo_rectangle_t));
  103. memcpy(l->clip, template->clip, sizeof(cairo_rectangle_t));
  104. COPY_RGBA_PATTERN(outer_background_color);
  105. COPY_RGBA_PATTERN(papertape_background_color);
  106. COPY_RGBA_PATTERN(one_code_hole_color);
  107. COPY_RGBA_PATTERN(zero_code_hole_color);
  108. COPY_RGBA_PATTERN(feed_hole_color);
  109. l->matrix = template->matrix;
  110. l->matrix_inverse = template->matrix_inverse;
  111. l->row_callback = template->row_callback;
  112. l->row_callback_user_data = template->row_callback_user_data;
  113.  
  114. return l;
  115. }
  116.  
  117. /**
  118.  * Delete every mallocated structure in the LOCHSTREIFEN (colors, etc.),
  119.  * *except* from the data. You have to manage them on your own.
  120.  * In the end, it will free the LOCHSTREIFEN itself.
  121.  * This won't touch your row_callback_user_data.
  122.  * @return Nothing, because there's nothing left. Except your data, okay.
  123.  **/
  124. void lochstreifen_free(LOCHSTREIFEN* l) {
  125. if(l->highlight_region_color != NULL) free(l->highlight_region_color);
  126. if(l->highlight_row_color != NULL) free(l->highlight_row_color);
  127. if(l->highlight_bit_color != NULL) free(l->highlight_bit_color);
  128. if(l->clip != NULL) free(l->clip);
  129. if(l->outer_background_color != NULL) free(l->outer_background_color);
  130. if(l->papertape_background_color != NULL) free(l->papertape_background_color);
  131. if(l->one_code_hole_color != NULL) free(l->one_code_hole_color);
  132. if(l->zero_code_hole_color != NULL) free(l->zero_code_hole_color);
  133. if(l->feed_hole_color != NULL) free(l->feed_hole_color);
  134. }
  135.  
  136. /**
  137.  * A small debug function that will print out all fields of the LOCHSTREIFEN
  138.  * structure well ordered to stderr.
  139.  *
  140.  **/
  141. void lochstreifen_print_debug(LOCHSTREIFEN* l) {
  142. int x;
  143. #define COLORP(color) if(color == NULL) fprintf(stderr, " color ist NULL.\n"); \
  144. else if(cairo_pattern_get_type(color) == CAIRO_PATTERN_TYPE_SOLID) {\
  145. double r,g,b,a; cairo_pattern_get_rgba(color, &r, &g, &b, &a); \
  146. fprintf(stderr, " SOLID: R=%f, G=%f, B=%f, A=%f\n", r, g, b, a); \
  147. } else fprintf(stderr, " NO SOLID PATTERN (special pattern)\n");
  148. #define COLORP_VERBOSE(color1, name) \
  149. fprintf(stderr, " * "name": %s\n", (color1) != NULL ? "ENABLED" : "disabled");\
  150. COLORP(color1);
  151.  
  152.  
  153. if(l != NULL)
  154. fprintf(stderr, "Debugging papertape at %p:\n", l);
  155. else {
  156. fprintf(stderr, "Cannot debug: Papertape is NULL!\n");
  157. return;
  158. }
  159.  
  160. // 1. Point: Print out data.
  161. fprintf(stderr, "1# DATA AND OUTPUT IMAGE SIZE INFORMATION\n");
  162. fprintf(stderr, " * Data: length=%i bytes", l->data_length);
  163. if(l->data_length > 0 && l->data != NULL) {
  164. // there are data
  165. fprintf(stderr, ":\n { ");
  166. for(x=0;;) {
  167. fprintf(stderr, "0x%x", l->data[x]);
  168. if(++x == l->data_length) {
  169. fprintf(stderr, " };\n");
  170. break;
  171. } else if(x == 10) { // magic number: print first 10 bytes.
  172. fprintf(stderr, ", ... };\n");
  173. break;
  174. } else
  175. fprintf(stderr, ", ");
  176. }
  177. } else if(l->data == NULL) {
  178. fprintf(stderr, " BUT data are NULL!\n");
  179. } else // data_length == 0.
  180. fprintf(stderr, " (empty data)\n");
  181. fprintf(stderr, " * Unscaled dimensions:\n");
  182. fprintf(stderr, " width of image (length of papertape) = %f\n", lochstreifen_get_length(l));
  183. fprintf(stderr, " height of image (width of papertape) = 1\n");
  184.  
  185. // 2. Point: Print out colors
  186. fprintf(stderr, "\n2# ELEMENT COLORS\n");
  187. COLORP_VERBOSE(l->outer_background_color, "outer background");
  188. COLORP_VERBOSE(l->papertape_background_color, "papertape background");
  189. COLORP_VERBOSE(l->one_code_hole_color, "one code holes");
  190. COLORP_VERBOSE(l->zero_code_hole_color, "zero code holes");
  191. COLORP_VERBOSE(l->feed_hole_color, "feed holes");
  192.  
  193. // 3. Point: Print out highlighted thingies
  194. fprintf(stderr, "\n3# HIGHLIGHT COLORS\n");
  195. fprintf(stderr, l->highlight_region_color != NULL ? " * Highlight region: start=%i end=%i\n"
  196. : " * Highlight region: disabled\n", l->highlight_region_start, l->highlight_region_end);
  197. COLORP(l->highlight_region_color);
  198. fprintf(stderr, l->highlight_row_color != NULL ? " * Highlight row: number=%i\n"
  199. : " * Highlight row: disabled\n", l->highlight_row_number);
  200. COLORP(l->highlight_row_color);
  201. fprintf(stderr, l->highlight_bit_color != NULL ? " * Higlight bit: row=%i track=%i\n"
  202. : " * Highlight bit: disabled\n", l->highlight_bit_row, l->highlight_bit_track);
  203. COLORP(l->highlight_bit_color);
  204.  
  205. // 4. Point: Print out information about clippings
  206. fprintf(stderr, "\n4# SPECIAL STRUCTURES\n");
  207. if(l->clip == NULL)
  208. fprintf(stderr, " * Clipping: disabled\n");
  209. else {
  210. fprintf(stderr, " * Clipping: ENABLED\n");
  211. fprintf(stderr, " x=%f, y=%f, width=%f, height=%f\n",
  212. l->clip->x, l->clip->y, l->clip->width, l->clip->height);
  213. }
  214.  
  215. // 5. Point: Affine Matrix
  216. fprintf(stderr, " * Current transformation matrix:\n");
  217. fprintf(stderr, " x_new = [xx=%f]*x + [xy=%f]*y + [x0=%f]\n",
  218. l->matrix.xx, l->matrix.xy, l->matrix.x0);
  219. fprintf(stderr, " y_new = [yx=%f]*x + [yy=%f]*y + [y0=%f]\n",
  220. l->matrix.yx, l->matrix.yy, l->matrix.y0);
  221. fprintf(stderr, " source dimensions: x_max = %f x y_max = %f\n",
  222. LOCHSTREIFEN_LENGTH, LOCHSTREIFEN_WIDTH);
  223. fprintf(stderr, " target dimensions: width = %i x height = %i\n",
  224. lochstreifen_get_target_width(l),
  225. lochstreifen_get_target_height(l));
  226.  
  227. // 6. Point: Debugging
  228. fprintf(stderr, " * Debugging: %s\n", l->debug ? "ENABLED" : "disabled");
  229.  
  230. fprintf(stderr, "END OF LOCHSTREIFEN\n");
  231. }
  232.  
  233. /**
  234.  * Set the data which LOCHSTREIFEN is supposed to punch out. You shall give
  235.  * the LOCSTREIFEN object only a copy of your data, never give it a sensible
  236.  * data array. The LOCHSTREIFEN object won't write into your data, but afterwards
  237.  * it will free them. So it treats the data as it's own.
  238.  *
  239.  **/
  240. void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data) {
  241. l->data_length = data_length;
  242. //if(l->data != NULL)
  243. // free(l->data);
  244. l->data = data;
  245. }
  246.  
  247. /**
  248.  * Adds Null Bytes (0x00) at start and/or end of the data array. This dynamically
  249.  * increases the data array.
  250.  *
  251.  *
  252.  **/
  253. void lochstreifen_add_null_bytes(LOCHSTREIFEN *l, int start, int end) {
  254. byte_t *new_data;
  255.  
  256. // only to be sure realloc won't decrease the size of the array:
  257. if(start < 0) start = 0;
  258. if(end < 0) end = 0;
  259.  
  260. // make array bigger to contain new start/end chunks
  261. new_data = realloc(l->data, l->data_length + start + end);
  262. // check wheter realloc exited successfully. We don't want segfaults
  263. if(new_data == NULL)
  264. return;
  265. // move data to the middle
  266. memmove(new_data + start, new_data, l->data_length);
  267. // fill new start chunk with zero bytes
  268. memset(new_data, 0x00, start);
  269. // fill new end chunk with zero bytes
  270. memset(new_data + start + l->data_length, 0x00, end);
  271. // that's it.
  272.  
  273. // fix the data link. Don't free the old data. Don't know exactly
  274. // how realloc works, sorry ;-)
  275. l->data = new_data;
  276. }
  277.  
  278. /**
  279.  * Get the length of a LOCHSTREIFEN. It depends on the length of the data array
  280.  * and the papertape dimension constants.
  281.  *
  282.  *
  283.  **/
  284. double lochstreifen_get_length(LOCHSTREIFEN *l) {
  285. return LOCHSTREIFEN_LENGTH;
  286. }
  287.  
  288.  
  289. /**
  290.  * Tell LOCHSTREIFEN to highlight a region of rows. Start counts from 0 and is already
  291.  * in the selection, end is no more in selection. Example with start = 2; end = 5:
  292.  *
  293.  * 0 1 2 3 4 5 6 <- rows
  294.  * |_________________|
  295.  * highlight region
  296.  **/
  297. void lochstreifen_set_highlight_region(LOCHSTREIFEN *l, row_t start, row_t end) {
  298. l->highlight_region_start = start;
  299. l->highlight_region_end = end;
  300. if(l->highlight_region_color == NULL)
  301. l->highlight_row_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_REGION_COLOR;
  302. }
  303.  
  304. /**
  305.  * Get the selection bounds of the highlighted rows. Give Links to your variables
  306.  * where the function stores the start/end integers.
  307.  * @return TRUE if there is an highlight selection, FALSE otherwiese
  308.  **/
  309. int lochstreifen_get_highlight_region(LOCHSTREIFEN *l, row_t *start, row_t *end) {
  310. if(l->highlight_region_color == NULL || l->highlight_region_start == LOCHSTREIFEN_NO_ROW)
  311. return 0;
  312. if(start != NULL)
  313. *start = l->highlight_region_start;
  314. if(end != NULL)
  315. *end = l->highlight_region_end;
  316. return 1;
  317. }
  318.  
  319. /**
  320.  * Remove the highlighted region (that is, make it no more highlighted).
  321.  **/
  322. void lochstreifen_remove_highlight_region(LOCHSTREIFEN *l) {
  323. //l->highlight_region_color = NULL;
  324. // was stupid, this is more intelligent:
  325. l->highlight_region_start = LOCHSTREIFEN_NO_ROW;
  326. }
  327.  
  328. /**
  329.  * Tell LOCHSTREIFEN to highlight one, only one special row. Starts counting from 0.
  330.  * Example with start = 3:
  331.  *
  332.  * 0 1 2 3 4 5
  333.  * |_____|
  334.  * highlighted row
  335.  *
  336.  * Principally this is the same feature like lochstreifen_set_highlight_region, having
  337.  * (in the above example) start = 3 and end = 4. You can just use another color and
  338.  * use both techniques concurrently, whereby the highlighted row will ALWAYS be ABOVE
  339.  * the highlighted chunk of rows. An application example is e.g.: The highlighted region
  340.  * of rows are selected rows, the highlighted special row is the cursor position row.
  341.  * This would be quite usable with an implementation of the GtkEditable interface, like
  342.  * GtkPaperTape.
  343.  **/
  344. void lochstreifen_set_highlight_row(LOCHSTREIFEN *l, row_t number_of_row) {
  345. l->highlight_row_number = number_of_row;
  346. if(l->highlight_row_color == NULL)
  347. l->highlight_row_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_ROW_COLOR;
  348. }
  349.  
  350. /**
  351.  * Get the highlighted special row. If there is no highlighted row, it will return
  352.  * LOCHSTREIFEN_NO_ROW.
  353.  * @return the number of the special row, counting from zero.
  354.  **/
  355. int lochstreifen_get_highlight_row(LOCHSTREIFEN *l) {
  356. return l->highlight_row_number;
  357. }
  358.  
  359. /**
  360.  * Remove the highlight at the special selected row.
  361.  **/
  362. void lochstreifen_remove_highlight_row(LOCHSTREIFEN *l) {
  363. //l->highlight_row_color = NULL; /// nein, das ist dumm, weil es den highlight komplett entfernen würde.
  364. l->highlight_row_number = LOCHSTREIFEN_NO_ROW; // das ist schlau.
  365. }
  366.  
  367. /**
  368.  * Tell LOCHSTREIFEN to highlight one special bit on the complete papertape. To identify
  369.  * this bit, you give the row and track number (byte id and bit id) for this bit. E.g.
  370.  * with row = 3, bit = 5 you'll get something like:
  371.  *
  372.  * ------- DIRECTION OF MOVEMENT ------->
  373.  * track 8 8 8 8 8 8
  374.  * track 7 7 7 7 7 7
  375.  * track 6 6 6 +-----+ 6 6
  376.  * track 5 5 5 | 5 | 5 5 (of course the highlight won't affect any
  377.  * track 4 4 4 +-----+ 4 4 other bit, row 3, track 6 and track 4
  378.  * feed - - - - - - are not visible due to ASCII limitations
  379.  * track 3 3 3 3 3 3 ;-) )
  380.  * track 2 2 2 2 2 2
  381.  * track 1 1 1 1 1 1
  382.  *
  383.  * row: 0 1 2 3 4 5
  384.  * ^-- this row
  385.  *
  386.  * The bit highlight will appear on top of the row highlight and region highlight. You
  387.  * can combine the bit highlight with row highlight (e.g. in the example above you can
  388.  * highlight row 3, too) and even with the region highlight (e.g. having a region from
  389.  * row 2 to row 5).
  390.  **/
  391. void lochstreifen_set_highlight_bit(LOCHSTREIFEN *l, row_t number_of_row, track_t number_of_bit) {
  392. l->highlight_bit_row = number_of_row;
  393. l->highlight_bit_track = number_of_bit;
  394. if(l->highlight_bit_color == NULL)
  395. l->highlight_bit_color = LOCHSTREIFEN_DEFAULT_HIGHLIGHT_BIT_COLOR;
  396. }
  397.  
  398. /**
  399.  * Get the highlighted special bit. This works exactly like lochstreifen_get_highlight_region,
  400.  * returning FALSE (0) if there's no bit selected.
  401.  *
  402.  **/
  403. int lochstreifen_get_highlight_bit(LOCHSTREIFEN *l, row_t *number_of_row, track_t *number_of_bit) {
  404. if(l->highlight_bit_row == LOCHSTREIFEN_NO_ROW)
  405. return 0;
  406. if(number_of_row != NULL)
  407. *number_of_row = l->highlight_bit_row;
  408. if(number_of_bit != NULL)
  409. *number_of_bit = l->highlight_bit_track;
  410. return 1;
  411. }
  412.  
  413. /**
  414.  * Remove the highlighting of the special bit.
  415.  **/
  416. void lochstreifen_remove_highlight_bit(LOCHSTREIFEN *l) {
  417. //l->highlight_bit_color = NULL; // stupid.
  418. l->highlight_bit_row = LOCHSTREIFEN_NO_ROW; // more intelligent.
  419. }
  420.  
  421. /**
  422.  * Whenever you change the matrix, call this function. It will just perform some
  423.  * cleanup work, espacially calculate the inverse matrix for the other-side calculations.
  424.  **/
  425. void lochstreifen_check_matrix(LOCHSTREIFEN* l) {
  426. l->matrix_inverse = l->matrix; // copy matrix
  427. if(cairo_matrix_invert(&l->matrix_inverse) != CAIRO_STATUS_SUCCESS) { // invert the copy
  428. // there are some matrizes which are not invertable
  429. fprintf(stderr, "lochstreifen_check_matrix: Matrix is not invertable!\n");
  430. }
  431. }
  432.  
  433. /**
  434.  * If you want LOCHSTREIFEN only to paint a small area from the whole papertape, this
  435.  * is the function you can call.
  436.  * If you are using an affine transformation matrix for scaling/rotation/... purpose,
  437.  * this function will automatically transform these values. So don't give here values
  438.  * like "LOCHSTREIFEN_WIDTH" or "LOCHSTREIFEN_HEIGHT" ;-)
  439.  *
  440.  **/
  441. void lochstreifen_set_clip(LOCHSTREIFEN *l, double x, double y, double width, double height) {
  442. if(l->clip == NULL)
  443. l->clip = malloc(sizeof(cairo_rectangle_t));
  444.  
  445. cairo_matrix_transform_point(&l->matrix_inverse, &x, &y);
  446. cairo_matrix_transform_distance(&l->matrix_inverse, &width, &height);
  447. l->clip->x = x;
  448. l->clip->y = y;
  449. l->clip->width = width;
  450. l->clip->height = height;
  451. }
  452.  
  453. /**
  454.  * I fyou want LOCHSTREIFEN no more to paint only a small area but the whole paper tape,
  455.  * simply call this function.
  456.  **/
  457. void lochstreifen_remove_clip(LOCHSTREIFEN *l) {
  458. free(l->clip);
  459. l->clip = NULL; // not neccessary, I suppose.
  460. }
  461.  
  462. /**
  463.  * Affect the current transformation matrix so the papertape finally has a length of
  464.  * exactly the value given in the argument, in pixels. The length depends from the
  465.  * number of rows on the papertape, so the length will increase if you increase the
  466.  * number of rows after calling lochstreifen_set_scaling_by_length.
  467.  **/
  468. void lochstreifen_set_scaling_by_length(LOCHSTREIFEN *l, int length) {
  469. double scale_factor = ((double)length) / LOCHSTREIFEN_LENGTH;
  470. printf("Scaling to length=%i, having length=%f, getting %f as scale factor\n",
  471. length, LOCHSTREIFEN_LENGTH, scale_factor);
  472. cairo_matrix_scale(&l->matrix, scale_factor, scale_factor);
  473. lochstreifen_check_matrix(l);
  474. }
  475.  
  476. void lochstreifen_set_scaling_by_width(LOCHSTREIFEN *l, int width) {
  477. double scale_factor = ((double)width) / LOCHSTREIFEN_WIDTH;
  478. cairo_matrix_scale(&l->matrix, scale_factor, scale_factor);
  479. lochstreifen_check_matrix(l);
  480. }
  481.  
  482. void lochstreifen_set_scaling_by_code_hole(LOCHSTREIFEN *l, int diameter) {
  483. double scale_factor = ((double)diameter)/2 / LOCHSTREIFEN_RADIUS_CODE_HOLE;
  484. cairo_matrix_scale(&l->matrix, scale_factor, scale_factor);
  485. lochstreifen_check_matrix(l);
  486. }
  487.  
  488. /**
  489.  * Get the dimensions of the paper tape in the output image. Be careful: While
  490.  * width/length are well defined in the LOCHSTREIFEN process, hereby width and
  491.  * height mean the dimensions of the rectangular surface picture.
  492.  * If you need only the value of one dimension, use
  493.  * lochstreifen_get_target_width or lochstreifen_get_target_height, respectively.
  494.  *
  495.  * The calculation of these values is quite expensive, so you do well when
  496.  * caching the results.
  497.  * @return nothing, because Call-by-Reference.
  498.  **/
  499. void lochstreifen_get_target_dimensions(LOCHSTREIFEN *l, int *width, int *height) {
  500. int i;
  501. // preset the dimensions to 0
  502. if(width != NULL) *width = 0;
  503. if(height != NULL) *height = 0;
  504. // define the "bounding box" where the papertape resides in
  505. // user space cordinates (like lochstreifen_draw paints)
  506. double x[] = { 0, LOCHSTREIFEN_LENGTH, 0, LOCHSTREIFEN_LENGTH };
  507. double y[] = { 0, 0, LOCHSTREIFEN_WIDTH, LOCHSTREIFEN_WIDTH };
  508. // transform the "bounding box" throught the matrix
  509. for(i=0; i < (sizeof(x) / sizeof(double)); i++) {
  510. cairo_matrix_transform_point(&l->matrix, &x[i], &y[i]);
  511. // store biggest x/y values
  512. if(width != NULL && x[i] > *width)
  513. *width = x[i];
  514. if(height != NULL && y[i] > *height)
  515. *height = y[i];
  516. }
  517. }
  518.  
  519. /**
  520.  * Get width of the output picture. This is only a nicer frontend to
  521.  * lochstreifen_get_target_dimensions that returns the width value.
  522.  **/
  523. int lochstreifen_get_target_width(LOCHSTREIFEN *l) {
  524. int width;
  525. lochstreifen_get_target_dimensions(l, &width, NULL);
  526. return width;
  527. }
  528.  
  529. /**
  530.  * Get height of the output picture. This is only a nicer frontend to
  531.  * lochstreifen_get_target_dimensions that returns the height value.
  532.  **/
  533. int lochstreifen_get_target_height(LOCHSTREIFEN *l) {
  534. int height;
  535. lochstreifen_get_target_dimensions(l, NULL, &height);
  536. return height;
  537. }
  538.  
  539. /**
  540.  * Get a bit tuple from the positions on the target surface. This function
  541.  * translates the points x/y with the inverse current translation matrix. Then
  542.  * it calculates the row number that equals with the x coordinate and afterwards
  543.  * the track number that equals with the y coordinate.
  544.  *
  545.  * If you need only one dimension, set the other NULL.
  546.  *
  547.  * You can use lochstreifen_get_traget_row_from_point and
  548.  * lochstreifen_get_target_track_from_point if you need only one dimension. Furthermore
  549.  * they will nicely return the requested data -- no need for call by reference.
  550.  *
  551.  * @param bit The target lochstreifen_bit_t (call by reference). Should not be NULL.
  552.  * @param x The x coordinate you want to check
  553.  * @param y The y coordinate you want to check
  554.  **/
  555. void lochstreifen_get_target_bit_from_point(LOCHSTREIFEN* l, row_t* row, track_t* track, double x, double y) {
  556. cairo_matrix_transform_point(&l->matrix_inverse, &x, &y); // transform points
  557.  
  558. if(y < 0 || y > LOCHSTREIFEN_WIDTH) {
  559. // we are not at data, at all
  560. if(row != NULL)
  561. *row = LOCHSTREIFEN_NO_ROW;
  562. if(track != NULL)
  563. *track = LOCHSTREIFEN_NO_TRACK;
  564. return;
  565. }
  566.  
  567. if(row == NULL) {
  568. // if only the track was requested, create a temporary row buffer, because
  569. // we need the row number as a basis for the correct track calculation.
  570. row_t row_buffer;
  571. row = &row_buffer;
  572. }
  573.  
  574. // Row calculation is fairly easy:
  575. if(x < LOCHSTREIFEN_TEAR_OFF_LENGTH || x > (LOCHSTREIFEN_LENGTH - LOCHSTREIFEN_TEAR_OFF_LENGTH)) {
  576. // we are not at data
  577. *row = LOCHSTREIFEN_NO_ROW;
  578. } else {
  579. // getting the row from the x value. This is pretty much the same algorithm
  580. // like used in papertape_draw for checking up the rectangle bounding box (clipping).
  581. *row = floor(
  582. (x - LOCHSTREIFEN_TEAR_OFF_LENGTH) / LOCHSTREIFEN_ROW_DISTANCE
  583. );
  584. }
  585.  
  586. // Track calculation is much more complex:
  587. if(track != NULL) {
  588. /* get the track from the y value. This is not simply something like
  589. * *track = floor( y / LOCHSTREIFEN_TRACK_DISTANCE );
  590. * because we must take care that a track is a round thing with a
  591. * specific height.
  592. */
  593. double M_x, M_y; // the centers of the circles
  594. int i; // some iterator
  595. // The center of this circle, fairly complex to calculate, see lochstreifen_draw.
  596. M_x = LOCHSTREIFEN_TEAR_OFF_LENGTH + (*row + 0.5) * LOCHSTREIFEN_ROW_DISTANCE;
  597. M_y = LOCHSTREIFEN_TRACK_DISTANCE; // the first track, to get onto papertape
  598. // this a genious canidate for loop unrolling:
  599. for(i=0; i < 8; i++) {
  600. // simple linear algebra: Check if point is in the circle.
  601. //fprintf(stderr, "bit %d: (%f|%f) <-> P(%f|%f) <= %f\n", i, M_x, M_y, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE);
  602. if(hypot( (x-M_x) , (y-M_y) ) <= LOCHSTREIFEN_RADIUS_CODE_HOLE) {
  603. // the point is in this circle, so we have found the correct track.
  604. //fprintf(stderr, "FOUND %d\n", i);
  605. *track = i;
  606. return;
  607. } else {
  608. // go on, set M for next circle
  609. M_y += LOCHSTREIFEN_TRACK_DISTANCE;
  610. // jump over feed track before i == 3.
  611. if(i == 2)
  612. M_y += LOCHSTREIFEN_TRACK_DISTANCE;
  613. }
  614. } // for tracks
  615.  
  616. // cursor not over circle:
  617. *track = LOCHSTREIFEN_NO_TRACK;
  618. //fprintf(stderr, "NOT FOUND TRACK.\n");
  619. } // y dimension
  620. } // lochstreifen_get_target_bit_on_point
  621.  
  622. /**
  623.  * Get the row number from an x/y target coordinate. That is: At first, translate
  624.  * the points with the current translation matrix, afterwards calculate the row
  625.  * number for the position.
  626.  *
  627.  * @returns Row number, counting from zero. Negative value if point not on papertape data chunk.
  628.  **/
  629. row_t lochstreifen_get_target_row_from_point(LOCHSTREIFEN* l, double x, double y) {
  630. row_t row;
  631. lochstreifen_get_target_bit_from_point(l, &row, NULL, x, y);
  632. return row;
  633. }
  634.  
  635. track_t lochstreifen_get_target_track_from_point(LOCHSTREIFEN* l, double x, double y) {
  636. track_t track;
  637. lochstreifen_get_target_bit_from_point(l, NULL, &track, x, y);
  638. return track;
  639. }
  640.  
  641.  
  642. /**
  643.  * Calculate the rectangle that contains the complete row on the LOCHSTREIFEN,
  644.  * in target surface dimensions (using the transformation matrix). If the operation
  645.  * fails (if the row doesn't exist), the rect is not touched at all.
  646.  *
  647.  * @param row Number of Row you want
  648.  * @param rect Call by reference like rectangle type
  649.  * @return LOCHSTREIFEN_SUCCESS or LOCHSTREIFEN_NO_ROW.
  650.  **/
  651. int lochstreifen_get_target_rect_from_row(LOCHSTREIFEN* l, row_t row, cairo_rectangle_t* rect) {
  652. // check wheter we are in bounds
  653. if(row < 0 || row > l->data_length)
  654. return LOCHSTREIFEN_NO_ROW;
  655.  
  656. // This rectangle is a bit bigger than the real track, so that outlines, etc.
  657. // could be drawn there, too.
  658.  
  659. rect->x = LOCHSTREIFEN_TEAR_OFF_LENGTH + (row) * LOCHSTREIFEN_ROW_DISTANCE;
  660. rect->y = 0;
  661. rect->width = LOCHSTREIFEN_ROW_DISTANCE;
  662. rect->height = LOCHSTREIFEN_WIDTH;
  663.  
  664. // take this as padding:
  665. #define TARGET_RECT_HOW_MUCH_BIGGER (LOCHSTREIFEN_ROW_DISTANCE * 0.1)
  666. rect->x -= TARGET_RECT_HOW_MUCH_BIGGER;
  667. rect->y -= TARGET_RECT_HOW_MUCH_BIGGER;
  668. rect->width += 2*TARGET_RECT_HOW_MUCH_BIGGER;
  669. rect->height += 2*TARGET_RECT_HOW_MUCH_BIGGER;
  670.  
  671. // transform the points
  672. cairo_matrix_transform_point(&l->matrix, &rect->x, &rect->y);
  673. cairo_matrix_transform_distance(&l->matrix, &rect->width, &rect->height);
  674.  
  675. return LOCHSTREIFEN_SUCCESS;
  676. }
  677.  
  678. /**
  679.  * This is just the same like lochstreifen_get_target_rect_from_row, just with
  680.  * bits. This is still a rectangle which contains the complete circle that represents
  681.  * the bit, useful e.g. for GDK expose events.
  682.  *
  683.  * @param row Number of Row
  684.  * @param track Number of Track
  685.  * @param rect Call by reference like rectangle type
  686.  * @return LOCHSTREIFEN_SUCCESS or LOCHSTREIFEN_NO_ROW or LOCHSTREIFEN_NO_TRACK
  687.  **/
  688. int lochstreifen_get_target_rect_from_bit(LOCHSTREIFEN* l, row_t row, track_t track, cairo_rectangle_t* rect) {
  689. // check bounds
  690. if(row < 0 || row > l->data_length)
  691. return LOCHSTREIFEN_NO_ROW;
  692. if(track < 0 || track > 7)
  693. return LOCHSTREIFEN_NO_TRACK;
  694.  
  695. // the rectangle is doesn't touch the circle, but leaves quite a bit space around
  696. // it, so outlines, etc. should not be a problem.
  697.  
  698. // this code is quite like the beginning x/y dimensions in lochstreifen_draw():
  699. rect->x = LOCHSTREIFEN_TEAR_OFF_LENGTH + (row) * LOCHSTREIFEN_ROW_DISTANCE;
  700. //+ (LOCHSTREIFEN_ROW_DISTANCE - LOCHSTREIFEN_RADIUS_CODE_HOLE*2) / 2; // the center
  701. rect->y = LOCHSTREIFEN_TRACK_DISTANCE * (track + (track > 2 ? 1 : 0) );
  702. // The correct values for width/height would be:
  703. // rect->width = LOCHSTREIFEN_RADIUS_CODE_HOLE * 2;
  704. // but that won't at exposures if the hole is painted e.g. with an outline (cairo_stroke).
  705. // We therefore simply take the complete track as width
  706. rect->width = LOCHSTREIFEN_ROW_DISTANCE;
  707. rect->height = LOCHSTREIFEN_TRACK_DISTANCE * 2;
  708.  
  709. // transform to user space
  710. cairo_matrix_transform_point(&l->matrix, &rect->x, &rect->y);
  711. cairo_matrix_transform_distance(&l->matrix, &rect->width, &rect->height);
  712.  
  713. return LOCHSTREIFEN_SUCCESS;
  714. }
  715.  
  716. /**
  717.  *
  718.  * Just to be sure that there are no misunderstandings: Rotation (wiht cairo)
  719.  * principally works like this:
  720.  *
  721.  * | B----D
  722.  * | V |
  723.  * 180° | | V |
  724.  * D--------C | V | 270°
  725.  * |>>>>>>>>| | | V |
  726.  * B--------A A----C
  727.  * |
  728.  * - - - - - -+------------------------> x axis
  729.  * | .
  730.  * C----A | A------------B .
  731.  * | ^ | | |<<<<<<<<<<<<| .
  732.  * 90° | ^ | | C------------D .
  733.  * | ^ | | original . <- borders of the target surface
  734.  * | ^ | |....................+
  735.  * D----B |
  736.  * V
  737.  * y axis
  738.  *
  739.  * Unfortunately every rotated box would be outside of the target surface
  740.  * (e.g. an 200x100px PNG image), thus we must move the matrix inside the
  741.  * positive x/y axis intercept.
  742.  * This can be performed quite simple
  743.  *
  744.  **/
  745. void lochstreifen_set_rotation(LOCHSTREIFEN *l, enum lochstreifen_direction direction) {
  746. switch(direction) {
  747. case LOCHSTREIFEN_MOVEMENT_TO_LEFT:
  748. // standard
  749. case LOCHSTREIFEN_MOVEMENT_TO_TOP:
  750. //cairo_matrix_rotate();
  751. case LOCHSTREIFEN_MOVEMENT_TO_RIGHT:
  752.  
  753. case LOCHSTREIFEN_MOVEMENT_TO_BOTTOM:
  754.  
  755. case LOCHSTREIFEN_MOVEMENT_NONE:
  756. default:
  757. break;
  758. }
  759. lochstreifen_check_matrix(l);
  760. }
  761.  
  762.  
  763. /**
  764.  * The very central main function for the LOCHSTREIFEN object: Drawing.
  765.  * You are supposed to create an adequate cairo context.
  766.  *
  767.  * This basic drawing function will draw relative to the width of the
  768.  * paper tape, like defined as 1 inch in the ECMA-10 standard. This
  769.  * width will have the value "1".
  770.  *
  771.  * Your cropping/... blub shall treat hereby. blabla.
  772.  **/
  773. void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr) {
  774. // complete length of paper tape:
  775. double length = LOCHSTREIFEN_LENGTH;
  776.  
  777. // iterators for the byte/bit loops
  778. int row,track;
  779. // position while iterating
  780. double x,y;
  781. // max positions to iterate to
  782. int row_max, track_min, track_max;
  783.  
  784. // apply the matrix!
  785. cairo_set_matrix(cr, &l->matrix);
  786.  
  787. // check if we need to repaint the papertape
  788. if(l->clip != NULL && (l->clip->y > LOCHSTREIFEN_WIDTH || l->clip->x > LOCHSTREIFEN_LENGTH) ) {
  789. // Clipping region is outside of papertape!
  790. //printf("draw: Outside papertape.\n");
  791. return;
  792. }
  793.  
  794. // paint outer background color.
  795. if(l->outer_background_color != NULL) {
  796. cairo_set_source(cr, l->outer_background_color);
  797. cairo_paint(cr);
  798. }
  799.  
  800. // paint the paper tape outline, including the tear-off
  801. if(l->papertape_background_color != NULL) {
  802. cairo_set_source(cr, l->papertape_background_color);
  803.  
  804. // tear-off at the beginning (0.5 of paper tape width)
  805. cairo_move_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH * 0.8, 0);
  806. cairo_line_to(cr, 0, 4*LOCHSTREIFEN_TRACK_DISTANCE);
  807. cairo_line_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
  808. cairo_line_to(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, 0);
  809. cairo_close_path(cr);
  810. cairo_fill(cr);
  811.  
  812. // long rectangular area over complete paper tape
  813. if(l->clip == NULL) {
  814. cairo_rectangle(cr, LOCHSTREIFEN_TEAR_OFF_LENGTH, 0.0,
  815. length - 2*LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
  816. // irc.gnome.org, #gtk+:
  817. // <owen> sven__: a basic comment is that if you draw a *single* shape with cairo
  818. // that's bigger than 32k pixels in any dimension, it's unlikely to work
  819. // [17:51] <owen> sven__: for the Xlib backend. this is a lot more fixable now
  820. // that Cairo switched to 24.8 fixed point internally, but I don't think anybody
  821. // has done the work to fix it
  822. } else {
  823. // calculate the neccessary width
  824. // if clipping region exceeds lochstreifen width.... make it shorter, else let it.
  825. double width = ( (l->clip->x + l->clip->width) > (LOCHSTREIFEN_LENGTH - LOCHSTREIFEN_TEAR_OFF_LENGTH) )
  826. ? ( LOCHSTREIFEN_LENGTH - LOCHSTREIFEN_TEAR_OFF_LENGTH - l->clip->x )
  827. : l->clip->width;
  828. // don't have the clipping region paint in the tear off
  829. // right, so crop it at the left.
  830. if(l->clip->x < LOCHSTREIFEN_TEAR_OFF_LENGTH)
  831. width -= LOCHSTREIFEN_TEAR_OFF_LENGTH;
  832. cairo_rectangle(cr,
  833. (l->clip->x >= LOCHSTREIFEN_TEAR_OFF_LENGTH) ?
  834. l->clip->x : LOCHSTREIFEN_TEAR_OFF_LENGTH,
  835. 0,
  836. width,
  837. LOCHSTREIFEN_WIDTH);
  838. }
  839. cairo_fill(cr);
  840.  
  841.  
  842. // tear-off at the end (0.5 of paper tape width)
  843. cairo_move_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, 0);
  844. cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, LOCHSTREIFEN_WIDTH);
  845. cairo_line_to(cr, length, LOCHSTREIFEN_WIDTH);
  846. cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH, 4*LOCHSTREIFEN_TRACK_DISTANCE);
  847. cairo_line_to(cr, length-LOCHSTREIFEN_TEAR_OFF_LENGTH * 0.2, 0);
  848. cairo_close_path(cr);
  849. cairo_fill(cr);
  850.  
  851. } // paper tape background finished.
  852.  
  853. // paint feed holes in the tear-off at the beginning
  854. // only if in clipped area
  855. if( ( l->clip == NULL || (l->clip->x <= LOCHSTREIFEN_TEAR_OFF_LENGTH) )
  856. && (l->feed_hole_color != NULL) ) {
  857. cairo_set_source(cr, l->feed_hole_color);
  858. for(y=4*LOCHSTREIFEN_TRACK_DISTANCE,
  859. x=LOCHSTREIFEN_TEAR_OFF_LENGTH - LOCHSTREIFEN_ROW_DISTANCE/2;
  860. x > 0; x -= LOCHSTREIFEN_ROW_DISTANCE)
  861. cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_FEED_HOLE, 0., 2*M_PI);
  862. cairo_fill(cr);
  863. }
  864.  
  865.  
  866. if(l->clip != NULL) {
  867. /* calculate clipping in dimension X (rows, bytes).
  868. * Clipping in this dimension is very important, especially at very long
  869. * papertapes. Application software (like GtkPaperTape) usually zooms the
  870. * papertape, so it won't fit completely on the screen. So skipping bytes
  871. * which are not displayed is very performant.
  872. */
  873. if(l->clip->x < LOCHSTREIFEN_TEAR_OFF_LENGTH) {
  874. // begin before tear off
  875. row = 0;
  876. row_max = floor(
  877. ( l->clip->width - (l->clip->x - LOCHSTREIFEN_TEAR_OFF_LENGTH) )
  878. / LOCHSTREIFEN_ROW_DISTANCE
  879. );
  880. } else {
  881. // after tear off
  882. row = floor (
  883. (l->clip->x - LOCHSTREIFEN_TEAR_OFF_LENGTH) / LOCHSTREIFEN_ROW_DISTANCE
  884. );
  885.  
  886. // end with just one more row as neccessary
  887. row_max = row + 1 + ceil(
  888. ( l->clip->width ) / LOCHSTREIFEN_ROW_DISTANCE
  889. );
  890. }
  891.  
  892. // don't go over the data range
  893. if(row_max > l->data_length)
  894. row_max = l->data_length;
  895. // dont' have row_max smaller than row
  896. //if(row_max < row)
  897. // row_max = row;
  898.  
  899. /* calculate clipping in dimension Y (tracks, bits)
  900. * Y clipping is not as important, because there are only 9 circles
  901. * to paint. The feed hole (which is painted just in the loop for the
  902. * 3. track hole is not counted, therefore the calculations become somewhat
  903. * inneccessary complex, compared to the painting overhead for the complete
  904. * 8 tracks instead of e.g. only 6 tracks. Apart from that, application software
  905. * usually doesn't clip the papertape this way, because users usually want to
  906. * see a complete byte and not only a half byte.
  907. */
  908. // calculation of first track to begin with.
  909. /*
  910. track_min = l->clip->y == 0 ? 0 : floor( l->clip->y / LOCHSTREIFEN_TRACK_DISTANCE );
  911.  
  912.  
  913. // calculation of last track to end with.
  914. if(l->clip->y + l->clip->height > LOCHSTREIFEN_WIDTH)
  915. track_max = 8; // clipping region is *much* bigger than the papertape width
  916. else {
  917. // just paint one more than neccessary
  918. track_max = 1 + 8 - floor(
  919. (LOCHSTREIFEN_WIDTH - (l->clip->y + l->clip->height))
  920. / LOCHSTREIFEN_TRACK_DISTANCE
  921. );
  922. // dont't go over the track range
  923. if(track_max > 8)
  924. track_max = 8;
  925. }*/
  926. track_min = 0;
  927. track_max = 8;
  928. } else {
  929. // no clipping. Paint *everything*.
  930. row = 0;
  931. row_max = l->data_length;
  932.  
  933. track_min = 0;
  934. track_max = 8;
  935. }
  936.  
  937. if(l->clip != NULL) {
  938. double x,y,width,height;
  939. x=l->clip->x; y=l->clip->y; width=l->clip->width; height=l->clip->height;
  940. cairo_user_to_device(cr, &x, &y);
  941. cairo_user_to_device_distance(cr, &width, &height);
  942. printf("draw: %i|%i %ix%i ", (int)x, (int)y, (int)width, (int)height);
  943. } else printf("draw: ");
  944. printf("row %i->%i track %i->%i\n", row, row_max, track_min, track_max);
  945.  
  946. // loop all the rows (bytes)
  947. // x start: tear off + one half row offset + offset rows * length of row
  948. for(x=LOCHSTREIFEN_TEAR_OFF_LENGTH + LOCHSTREIFEN_ROW_DISTANCE/2 + row*LOCHSTREIFEN_ROW_DISTANCE;
  949. row < row_max; row++, x += LOCHSTREIFEN_ROW_DISTANCE) {
  950.  
  951. // call row callback
  952. if(l->row_callback != NULL) {
  953. printf("CALLING ROW CALLBACK!\n");
  954. (*l->row_callback) (&row, cr, l->row_callback_user_data);
  955. // at least now that's all the magic ;)
  956. }
  957.  
  958. // highlight region?
  959. if(l->highlight_region_color != NULL && l->highlight_region_start != LOCHSTREIFEN_NO_ROW &&
  960. (row >= l->highlight_region_start || row < l->highlight_region_end) ) {
  961. cairo_set_source(cr, l->highlight_region_color);
  962. // hier was schlaues schickeres als ein RECHTECK
  963. // einfallen lassen. Vielleicht mit abgerundetem
  964. // Rechteck? Wuerde zu den Löchern passen.
  965. // http://www.cairographics.org/cookbook/roundedrectangles/
  966. cairo_rectangle(cr, x - LOCHSTREIFEN_ROW_DISTANCE / 2, 0,
  967. LOCHSTREIFEN_TRACK_DISTANCE * (l->highlight_region_end - l->highlight_region_start),
  968. LOCHSTREIFEN_WIDTH);
  969. cairo_fill(cr);
  970. }
  971.  
  972. // highlight (only) this row?
  973. if(l->highlight_row_color != NULL && row == l->highlight_row_number) {
  974. // if check again LOCHSTREIFEN_NO_ROW not neccessary because row iterator never
  975. // gets LOCHSTREIFEN_NO_ROW.
  976. cairo_set_source(cr, l->highlight_row_color);
  977. // genauso abgerundetes Rechteck wie bei der region
  978. // überlegen.
  979. cairo_rectangle(cr, x - LOCHSTREIFEN_ROW_DISTANCE/2, 0,
  980. LOCHSTREIFEN_TRACK_DISTANCE, LOCHSTREIFEN_WIDTH);
  981. cairo_fill(cr);
  982. }
  983.  
  984. // loop all the tracks (bits)
  985. // y start: offset tracks * width of track + one track (to get onto the papertape)
  986. for(track=track_min, y = LOCHSTREIFEN_TRACK_DISTANCE*(track+1);
  987. track < track_max; track++, y += LOCHSTREIFEN_TRACK_DISTANCE) {
  988. if(track == 3) {
  989. // the feed hole is at position 3
  990. if(l->feed_hole_color != NULL) {
  991. // we paint a feed hole :-)
  992. cairo_set_source(cr, l->feed_hole_color);
  993. cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_FEED_HOLE, 0., 2*M_PI);
  994. cairo_fill(cr);
  995. }
  996. // jump one track, in every case.
  997. y += 0.1;
  998. }
  999.  
  1000. printf("testing byte\n");
  1001. if( ((l->data[row] >> track) & 0x01) != 0x01) {
  1002. // bit is logical ZERO (0)
  1003. if(l->zero_code_hole_color != NULL) {
  1004. // we want to paint zeros.
  1005. cairo_set_source(cr, l->zero_code_hole_color);
  1006. cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
  1007. cairo_fill(cr);
  1008. }
  1009. } else if(l->one_code_hole_color != NULL) {
  1010. // we want to paint logical ONEs.
  1011. cairo_set_source(cr, l->one_code_hole_color);
  1012. cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
  1013. cairo_fill(cr);
  1014. }
  1015.  
  1016. if(l->highlight_bit_row == row && l->highlight_bit_track == track
  1017. && l->highlight_bit_color != NULL) {
  1018. // if check against l->highlight_bit_row == LOCHSTREIFEN_NO_ROW
  1019. // not neccessary because row never gets LOCHSTREIFEN_NO_ROW.
  1020.  
  1021. // eigentlich wollen wir hier eine Umrahmung zeichnen,
  1022. // damit der Zustand (0/1) nicht unsichtbar wird. Jetzt
  1023. // erst mal aber die Billigversion mit der dümmlichen
  1024. // Vollfarbe ;-)
  1025. cairo_set_source(cr, l->highlight_bit_color);
  1026. cairo_arc(cr, x, y, LOCHSTREIFEN_RADIUS_CODE_HOLE, 0., 2*M_PI);
  1027. cairo_set_line_width(cr, 0.01);
  1028. cairo_stroke(cr); // mal testen :-)
  1029. }
  1030. } // for tracks (bits)
  1031. } // for rows (bytes)
  1032. } // function lochstreifen_draw
  1033.