summaryrefslogtreecommitdiff
path: root/libgui/src/tkWinPrintText.c
blob: a9ffd36bfb9eb0c43c07d47586f6755e7678c8db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

#ifdef _WIN32

#include <windows.h>

#include "tkInt.h"
#include "tkWinInt.h"
#include "tkPort.h"
#include "tkText.h"

#define MAXINT 32000000

#define HAS_3D_BORDER	1
#define NEW_LAYOUT	2
#define TOP_LINE	4
#define BOTTOM_LINE	8


#define DINFO_OUT_OF_DATE	1
#define REDRAW_PENDING		2
#define REDRAW_BORDERS		4
#define REPICK_NEEDED		8



/*
 * The following structure describes one line of the display, which may
 * be either part or all of one line of the text.
 */

typedef struct DLine {
    TkTextIndex index;		/* Identifies first character in text
				 * that is displayed on this line. */
    int count;			/* Number of characters accounted for by this
				 * display line, including a trailing space
				 * or newline that isn't actually displayed. */
    int y;			/* Y-position at which line is supposed to
				 * be drawn (topmost pixel of rectangular
				 * area occupied by line). */
    int oldY;			/* Y-position at which line currently
				 * appears on display.  -1 means line isn't
				 * currently visible on display and must be
				 * redrawn.  This is used to move lines by
				 * scrolling rather than re-drawing. */
    int height;			/* Height of line, in pixels. */
    int baseline;		/* Offset of text baseline from y, in
				 * pixels. */
    int spaceAbove;		/* How much extra space was added to the
				 * top of the line because of spacing
				 * options.  This is included in height
				 * and baseline. */
    int spaceBelow;		/* How much extra space was added to the
				 * bottom of the line because of spacing
				 * options.  This is included in height. */
    int length;			/* Total length of line, in pixels. */
    TkTextDispChunk *chunkPtr;	/* Pointer to first chunk in list of all
				 * of those that are displayed on this
				 * line of the screen. */
    struct DLine *nextPtr;	/* Next in list of all display lines for
				 * this window.   The list is sorted in
				 * order from top to bottom.  Note:  the
				 * next DLine doesn't always correspond
				 * to the next line of text:  (a) can have
				 * multiple DLines for one text line, and
				 * (b) can have gaps where DLine's have been
				 * deleted because they're out of date. */
    int flags;			/* Various flag bits:  see below for values. */
} DLine;


typedef struct TextDInfo {
    Tcl_HashTable styleTable;	/* Hash table that maps from StyleValues
				 * to TextStyles for this widget. */
    DLine *dLinePtr;		/* First in list of all display lines for
				 * this widget, in order from top to bottom. */
    GC copyGC;			/* Graphics context for copying from off-
				 * screen pixmaps onto screen. */
    GC scrollGC;		/* Graphics context for copying from one place
				 * in the window to another (scrolling):
				 * differs from copyGC in that we need to get
				 * GraphicsExpose events. */
    int x;			/* First x-coordinate that may be used for
				 * actually displaying line information.
				 * Leaves space for border, etc. */
    int y;			/* First y-coordinate that may be used for
				 * actually displaying line information.
				 * Leaves space for border, etc. */
    int maxX;			/* First x-coordinate to right of available
				 * space for displaying lines. */
    int maxY;			/* First y-coordinate below available
				 * space for displaying lines. */
    int topOfEof;		/* Top-most pixel (lowest y-value) that has
				 * been drawn in the appropriate fashion for
				 * the portion of the window after the last
				 * line of the text.  This field is used to
				 * figure out when to redraw part or all of
				 * the eof field. */

    /*
     * Information used for scrolling:
     */

    int newCharOffset;		/* Desired x scroll position, measured as the
				 * number of average-size characters off-screen
				 * to the left for a line with no left
				 * margin. */
    int curPixelOffset;		/* Actual x scroll position, measured as the
				 * number of pixels off-screen to the left. */
    int maxLength;		/* Length in pixels of longest line that's
				 * visible in window (length may exceed window
				 * size).  If there's no wrapping, this will
				 * be zero. */
    double xScrollFirst, xScrollLast;
				/* Most recent values reported to horizontal
				 * scrollbar;  used to eliminate unnecessary
				 * reports. */
    double yScrollFirst, yScrollLast;
				/* Most recent values reported to vertical
				 * scrollbar;  used to eliminate unnecessary
				 * reports. */

    /*
     * The following information is used to implement scanning:
     */

    int scanMarkChar;		/* Character that was at the left edge of
				 * the window when the scan started. */
    int scanMarkX;		/* X-position of mouse at time scan started. */
    int scanTotalScroll;	/* Total scrolling (in screen lines) that has
				 * occurred since scanMarkY was set. */
    int scanMarkY;		/* Y-position of mouse at time scan started. */

    /*
     * Miscellaneous information:
     */

    int dLinesInvalidated;	/* This value is set to 1 whenever something
				 * happens that invalidates information in
				 * DLine structures;  if a redisplay
				 * is in progress, it will see this and
				 * abort the redisplay.  This is needed
				 * because, for example, an embedded window
				 * could change its size when it is first
				 * displayed, invalidating the DLine that
				 * is currently being displayed.  If redisplay
				 * continues, it will use freed memory and
				 * could dump core. */
    int flags;			/* Various flag values:  see below for
				 * definitions. */
} TextDInfo;

/*
 * The following structure describes how to display a range of characters.
 * The information is generated by scanning all of the tags associated
 * with the characters and combining that with default information for
 * the overall widget.  These structures form the hash keys for
 * dInfoPtr->styleTable.
 */

typedef struct StyleValues {
    Tk_3DBorder border;		/* Used for drawing background under text.
				 * NULL means use widget background. */
    int borderWidth;		/* Width of 3-D border for background. */
    int relief;			/* 3-D relief for background. */
    Pixmap bgStipple;		/* Stipple bitmap for background.  None
				 * means draw solid. */
    XColor *fgColor;		/* Foreground color for text. */
    Tk_Font tkfont;		/* Font for displaying text. */
    Pixmap fgStipple;		/* Stipple bitmap for text and other
				 * foreground stuff.   None means draw
				 * solid.*/
    int justify;		/* Justification style for text. */
    int lMargin1;		/* Left margin, in pixels, for first display
				 * line of each text line. */
    int lMargin2;		/* Left margin, in pixels, for second and
				 * later display lines of each text line. */
    int offset;			/* Offset in pixels of baseline, relative to
				 * baseline of line. */
    int overstrike;		/* Non-zero means draw overstrike through
				 * text. */
    int rMargin;		/* Right margin, in pixels. */
    int spacing1;		/* Spacing above first dline in text line. */
    int spacing2;		/* Spacing between lines of dline. */
    int spacing3;		/* Spacing below last dline in text line. */
    TkTextTabArray *tabArrayPtr;/* Locations and types of tab stops (may
				 * be NULL). */
    int underline;		/* Non-zero means draw underline underneath
				 * text. */
    Tk_Uid wrapMode;		/* How to handle wrap-around for this tag.
				 * One of tkTextCharUid, tkTextNoneUid,
				 * or tkTextWordUid. */
} StyleValues;

/*
 * The following structure extends the StyleValues structure above with
 * graphics contexts used to actually draw the characters.  The entries
 * in dInfoPtr->styleTable point to structures of this type.
 */

typedef struct TextStyle {
    int refCount;		/* Number of times this structure is
				 * referenced in Chunks. */
    GC bgGC;			/* Graphics context for background.  None
				 * means use widget background. */
    GC fgGC;			/* Graphics context for foreground. */
    StyleValues *sValuePtr;	/* Raw information from which GCs were
				 * derived. */
    Tcl_HashEntry *hPtr;	/* Pointer to entry in styleTable.  Used
				 * to delete entry. */
} TextStyle;




void DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable);

/*
 *--------------------------------------------------------------
 * 
 * PrintTextCmd -- 
 *      When invoked with the correct args this will bring up a
 *      standard Windows print dialog box and then print the
 *	contence of the text wiget.
 *
 * Results:
 *      Standard Tcl result.
 * 
 *--------------------------------------------------------------
 */

static int
PrintTextCmd(clientData, interp, argc, argv)
     ClientData clientData;
     Tcl_Interp *interp;
     int argc;
     char **argv;
{
    PRINTDLG pd; 
    Tcl_CmdInfo textCmd;
    TkText *textPtr;
    TextDInfo *dInfoPtr;
    DLine *dlPtr;
    TkWinDrawable *PrinterDrawable;
    Tk_Window tkwin;
    Tk_Item *itemPtr;
    int maxHeight;
    DLine *prevPtr;
    Pixmap pixmap;
    int bottomY = 0;		/* Initialization needed only to stop
				 * compiler warnings. */
    DOCINFO *lpdi = malloc(sizeof(DOCINFO));
    TkTextIndex first, last;
    int numLines;
    HDC hDCpixmap;
    TkWinDCState pixmapState;
    DEVMODE dm;
    float Ptr_pixX,Ptr_pixY,Ptr_mmX,Ptr_mmY;
    float canv_pixX,canv_pixY,canv_mmX,canv_mmY;
    int page_Y_size,tiles_high,tile_y;
    int screenX1, screenX2, screenY1, screenY2, width, height;

    int saved_x;
    int saved_y;
    int saved_w;
    int saved_h;
    int saved_maxX;
    int saved_maxY;
    int saved_eof;


    if (argc < 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"",
			 argv[0], " text \"",
			 (char *) NULL);
	return TCL_ERROR;
    }

    /*
     * The second arg is the canvas widget.
     */
    if (!Tcl_GetCommandInfo(interp, argv[1], &textCmd)) {
	Tcl_AppendResult(interp, "couldn't get text information for \"",
			 argv[1], "\"", (char *) NULL);
	return TCL_ERROR;
    }
    
    memset(&dm,0,sizeof(DEVMODE));
    dm.dmSize = sizeof(DEVMODE);
    dm.dmScale = 500;

    memset(lpdi,0,sizeof(DOCINFO));
    lpdi->cbSize=sizeof(DOCINFO);
    lpdi->lpszDocName=malloc(255);
    sprintf((char*)lpdi->lpszDocName,"SN - Printing\0");
    lpdi->lpszOutput=NULL;

    textPtr = (TkText *)(textCmd.clientData);
 
    tkwin = textPtr->tkwin;
    dInfoPtr = textPtr->dInfoPtr;
    dlPtr=dInfoPtr->dLinePtr;
    memset(&pd,0,sizeof( PRINTDLG ));
    pd.lStructSize  = sizeof( PRINTDLG );
    pd.hwndOwner    = NULL;
    pd.hDevMode	    = NULL;
    pd.hDevNames    = NULL;
    pd.Flags	    = PD_RETURNDC|PD_NOSELECTION;

    /*
     * Get printer details.
     */
    if (!PrintDlg(&pd)) {
	goto done;
    }

    PrinterDrawable = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable));
    PrinterDrawable->type = TWD_WINDC;
    PrinterDrawable->winDC.hdc = pd.hDC;

    Ptr_pixX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZRES);
    Ptr_pixY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTRES);
    Ptr_mmX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZSIZE);
    Ptr_mmY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTSIZE);
 
    screenX1=0; screenY1=0;
    screenX2=dInfoPtr->maxX; screenY2=dInfoPtr->maxY;
    pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
	    (screenX2 + 30),
	    (screenY2 + 30),
	    Tk_Depth(tkwin));
    width = screenX2 - screenX1;
    height = screenY2 - screenY1;

    hDCpixmap = TkWinGetDrawableDC(Tk_Display(tkwin), pixmap, &pixmapState);
    canv_pixX=(float)GetDeviceCaps(hDCpixmap,HORZRES);
    canv_pixY=(float)GetDeviceCaps(hDCpixmap,VERTRES);
    canv_mmX=(float)GetDeviceCaps(hDCpixmap,HORZSIZE);
    canv_mmY=(float)GetDeviceCaps(hDCpixmap,VERTSIZE);

    /*
     * Save text widget data.
     */
    dInfoPtr = textPtr->dInfoPtr;
    saved_x = dInfoPtr->x;
    saved_y = dInfoPtr->y;
    saved_w = Tk_Width(textPtr->tkwin);
    saved_h = Tk_Height(textPtr->tkwin);
    saved_maxX = dInfoPtr->maxX;
    saved_maxY = dInfoPtr->maxY;
    saved_eof = dInfoPtr->topOfEof;
    dInfoPtr->maxX = MAXINT;
    Tk_Width(textPtr->tkwin) = MAXINT;
 
    dInfoPtr->maxY  = MAXINT;
    Tk_Height(textPtr->tkwin) = MAXINT;

    /* Make the text widget big enough for all the
    text to be seen. */

    numLines = TkBTreeNumLines(textPtr->tree);
#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1)
    TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);
    TkTextMakeByteIndex(textPtr->tree, numLines, 100, &last);
#else
    TkTextMakeIndex(textPtr->tree, 0, 0, &first);
    TkTextMakeIndex(textPtr->tree, numLines, 100, &last);
#endif
    TkTextChanged(textPtr, &first, &last);

    /*
     * Set the display info flag to out-of-date.
     */

    textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE;

    /*
     *TkTextXviewCmd will call	UpdateDisplayInfo.
     */

    TkTextXviewCmd(textPtr, interp, 2, NULL);
    dInfoPtr = textPtr->dInfoPtr;

    SetMapMode(PrinterDrawable->winDC.hdc,MM_ISOTROPIC);
    SetWindowExtEx(PrinterDrawable->winDC.hdc,(int)((float)canv_pixX),(int)((float)canv_pixY),NULL);
    SetViewportExtEx(PrinterDrawable->winDC.hdc,(int)((float)Ptr_pixX),
			    (int)((float)Ptr_pixY),
			    NULL);

    /*
     * Get max Y for text widget.
     */
    maxHeight = -1;
    for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
	    dlPtr = dlPtr->nextPtr) {
	maxHeight = dlPtr->y + dlPtr->height;
    }

    /*
     * Calculate the number of tiles high.
     */
    page_Y_size = GetDeviceCaps(hDCpixmap,LOGPIXELSY)*(Ptr_mmY/22);

    tiles_high = ( maxHeight / page_Y_size ); /* start at page zero */

    StartDoc(pd.hDC,lpdi);
    for (tile_y = 0; tile_y <= tiles_high;tile_y++) {
	SetViewportOrgEx(pd.hDC,0,-(tile_y*Ptr_pixY),NULL);

	StartPage(pd.hDC);

	if (maxHeight > 0) {
	    for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr;
			(dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY);
			prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) {
	        DisplayDLineToDrawable(textPtr, dlPtr, prevPtr, PrinterDrawable);
	    
	    }
	}

    
	EndPage(pd.hDC);
    }
    EndDoc(pd.hDC);

    /*
     * Restore text widget data.
     */

    dInfoPtr->x = saved_x;
    dInfoPtr->y = saved_y;
    Tk_Width(textPtr->tkwin) = saved_w;
    Tk_Height(textPtr->tkwin) = saved_h;
    dInfoPtr->maxY = saved_maxY;
    dInfoPtr->maxX = saved_maxX;
    dInfoPtr->topOfEof = saved_eof;
    /*
     * Pitch the info again.
     */
    TkTextChanged(textPtr, &first, &last);

    /*
     * Display info not valid anymore.
     */

    textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE;

done:
    return TCL_OK;
 error:
    return TCL_ERROR;
}



static void 
ide_delete_print_text_command(ClientData clientData)
{
  /* destructor code here.*/
}

int
ide_create_print_text_command (Tcl_Interp *interp)
{

    if (Tcl_CreateCommand(interp, "ide_print_text", 
	PrintTextCmd, 
			  NULL, NULL) == NULL)
	return TCL_ERROR;

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * DisplayDLineToDrawable --
 *
 *	This procedure is invoked to draw a single line to a HDC
 *
 *----------------------------------------------------------------------
 */

static void
DisplayDLineToDrawable(textPtr, dlPtr, prevPtr, drawable)
    TkText *textPtr;		/* Text widget in which to draw line. */
    register DLine *dlPtr;	/* Information about line to draw. */
    DLine *prevPtr;		/* Line just before one to draw, or NULL
				 * if dlPtr is the top line. */
    TkWinDrawable *drawable;	/* drawable to use for displaying.
				 * Caller must make sure it's large enough
				 * to hold line. */
{
    register TkTextDispChunk *chunkPtr;
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    Display *display;
    int height, x;

    /*
     * First, clear the area of the line to the background color for the
     * text widget.
     */

    display = Tk_Display(textPtr->tkwin);

    for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL);
	    chunkPtr = chunkPtr->nextPtr) {
	if (chunkPtr->displayProc == TkTextInsertDisplayProc) {
	    /*
	     * Already displayed the insertion cursor above.  Don't
	     * do it again here.
	     */

	    continue;
	} else {
	    x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset;
	    if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) {
	        (*chunkPtr->displayProc)(chunkPtr, -chunkPtr->width,
		    dlPtr->y,
		    dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
		    dlPtr->baseline - dlPtr->spaceAbove, display, (unsigned long)drawable,
		    dlPtr->y + dlPtr->spaceAbove);
	    } else {
	        (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->y,
		    dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
		    dlPtr->baseline - dlPtr->spaceAbove, display, (unsigned long)drawable,
		    dlPtr->y + dlPtr->spaceAbove);
	    }
	}
    }

}

#endif /* _WIN */